From 5266be579501aff5aef56a875325a77550fe3109 Mon Sep 17 00:00:00 2001 From: tr00d Date: Tue, 10 Oct 2023 07:01:17 +0200 Subject: [PATCH 1/2] Fix Application deserialization with Meetings custom webhooks --- Vonage.Test.Unit/ApplicationTests.cs | 48 +------------- .../GetApplication-response.json | 63 +++++++++++++++++++ Vonage.Test.Unit/Vonage.Test.Unit.csproj | 3 + Vonage/Common/Webhook.cs | 9 +++ 4 files changed, 76 insertions(+), 47 deletions(-) create mode 100644 Vonage.Test.Unit/Data/ApplicationTests/GetApplication-response.json diff --git a/Vonage.Test.Unit/ApplicationTests.cs b/Vonage.Test.Unit/ApplicationTests.cs index d946cdbe1..6aa56c714 100644 --- a/Vonage.Test.Unit/ApplicationTests.cs +++ b/Vonage.Test.Unit/ApplicationTests.cs @@ -268,53 +268,7 @@ public async void DeleteApplicationAsync(bool passCreds) public void GetApplication(bool passCreds) { var id = "78d335fa323d01149c3dd6f0d48968cf"; - var expectedResponse = @"{ - ""id"": ""78d335fa323d01149c3dd6f0d48968cf"", - ""name"": ""My Application"", - ""capabilities"": { - ""voice"": { - ""webhooks"": { - ""answer_url"": { - ""address"": ""https://example.com/webhooks/answer"", - ""http_method"": ""GET"" - }, - ""fallback_answer_url"": { - ""address"": ""https://fallback.example.com/webhooks/answer"", - ""http_method"": ""GET"" - }, - ""event_url"": { - ""address"": ""https://example.com/webhooks/event"", - ""http_method"": ""POST"" - } - } - }, - ""messages"": { - ""webhooks"": { - ""inbound_url"": { - ""address"": ""https://example.com/webhooks/inbound"", - ""http_method"": ""POST"" - }, - ""status_url"": { - ""address"": ""https://example.com/webhooks/status"", - ""http_method"": ""POST"" - } - } - }, - ""rtc"": { - ""webhooks"": { - ""event_url"": { - ""address"": ""https://example.com/webhooks/event"", - ""http_method"": ""POST"" - } - } - }, - ""vbc"": { } - }, - ""keys"": { - ""public_key"": ""some public key"", - ""private_key"": ""some private key"" - } - }"; + var expectedResponse = this.GetResponseJson(); var expectedUri = $"{this.ApiUrl}/v2/applications/{id}"; this.Setup(expectedUri, expectedResponse); var creds = Credentials.FromApiKeyAndSecret(this.ApiKey, this.ApiSecret); diff --git a/Vonage.Test.Unit/Data/ApplicationTests/GetApplication-response.json b/Vonage.Test.Unit/Data/ApplicationTests/GetApplication-response.json new file mode 100644 index 000000000..b8bca2078 --- /dev/null +++ b/Vonage.Test.Unit/Data/ApplicationTests/GetApplication-response.json @@ -0,0 +1,63 @@ +{ + "id": "78d335fa323d01149c3dd6f0d48968cf", + "name": "My Application", + "capabilities": { + "voice": { + "webhooks": { + "answer_url": { + "address": "https://example.com/webhooks/answer", + "http_method": "GET" + }, + "fallback_answer_url": { + "address": "https://fallback.example.com/webhooks/answer", + "http_method": "GET" + }, + "event_url": { + "address": "https://example.com/webhooks/event", + "http_method": "POST" + } + } + }, + "messages": { + "webhooks": { + "inbound_url": { + "address": "https://example.com/webhooks/inbound", + "http_method": "POST" + }, + "status_url": { + "address": "https://example.com/webhooks/status", + "http_method": "POST" + } + } + }, + "rtc": { + "webhooks": { + "event_url": { + "address": "https://example.com/webhooks/event", + "http_method": "POST" + } + } + }, + "vbc": {}, + "meetings": { + "webhooks": { + "room_changed": { + "address": "http://example.com", + "http_method": "POST" + }, + "session_changed": { + "address": "http://example.com", + "http_method": "POST" + }, + "recording_changed": { + "address": "https://54eba990d025.ngrok.app/recordings", + "http_method": "POST" + } + } + } + }, + "keys": { + "public_key": "some public key", + "private_key": "some private key" + } +} \ No newline at end of file diff --git a/Vonage.Test.Unit/Vonage.Test.Unit.csproj b/Vonage.Test.Unit/Vonage.Test.Unit.csproj index 248408e71..8f1e3496a 100644 --- a/Vonage.Test.Unit/Vonage.Test.Unit.csproj +++ b/Vonage.Test.Unit/Vonage.Test.Unit.csproj @@ -862,6 +862,9 @@ PreserveNewest + + PreserveNewest + diff --git a/Vonage/Common/Webhook.cs b/Vonage/Common/Webhook.cs index 957ecc9e4..f770d2d7c 100644 --- a/Vonage/Common/Webhook.cs +++ b/Vonage/Common/Webhook.cs @@ -32,6 +32,15 @@ public enum Type [EnumMember(Value = "Unknown")] Unknown = 6, + + [EnumMember(Value = "room_changed")] + RoomChanged =7, + + [EnumMember(Value = "session_changed")] + SessionChanged=8, + + [EnumMember(Value = "recording_changed")] + RecordingChanged = 9, } } \ No newline at end of file From 2dbc360a215f7424ca510592b4f48d81cde952f1 Mon Sep 17 00:00:00 2001 From: tr00d Date: Tue, 10 Oct 2023 07:14:38 +0200 Subject: [PATCH 2/2] Add missing assertions --- Vonage.Test.Unit/ApplicationTests.cs | 70 +++++++++++++++------------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/Vonage.Test.Unit/ApplicationTests.cs b/Vonage.Test.Unit/ApplicationTests.cs index 6aa56c714..90ef7eb95 100644 --- a/Vonage.Test.Unit/ApplicationTests.cs +++ b/Vonage.Test.Unit/ApplicationTests.cs @@ -27,21 +27,21 @@ public void CreateApplication(bool passCreds) //ACT var messagesWebhooks = new Dictionary(); messagesWebhooks.Add(Webhook.Type.InboundUrl, - new Webhook {Address = "https://example.com/webhooks/inbound", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/inbound", Method = "POST" }); messagesWebhooks.Add(Webhook.Type.StatusUrl, - new Webhook {Address = "https://example.com/webhooks/status", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/status", Method = "POST" }); var messagesCapability = new Applications.Capabilities.Messages(messagesWebhooks); var rtcWebhooks = new Dictionary(); rtcWebhooks.Add(Webhook.Type.EventUrl, - new Webhook {Address = "https://example.com/webhooks/events", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/events", Method = "POST" }); var rtcCapability = new Rtc(rtcWebhooks); var voiceWebhooks = new Dictionary(); voiceWebhooks.Add(Webhook.Type.AnswerUrl, - new Webhook {Address = "https://example.com/webhooks/answer", Method = "GET"}); + new Webhook { Address = "https://example.com/webhooks/answer", Method = "GET" }); voiceWebhooks.Add(Webhook.Type.EventUrl, - new Webhook {Address = "https://example.com/webhooks/events", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/events", Method = "POST" }); voiceWebhooks.Add(Webhook.Type.FallbackAnswerUrl, - new Webhook {Address = "https://fallback.example.com/webhooks/answer", Method = "GET"}); + new Webhook { Address = "https://fallback.example.com/webhooks/answer", Method = "GET" }); var voiceCapability = new Applications.Capabilities.Voice(voiceWebhooks); JsonConvert.SerializeObject(voiceCapability, VonageSerialization.SerializerSettings); var vbcCapability = new Vbc(); @@ -154,32 +154,32 @@ public async void CreateApplicationAsync(bool passCreds) //ACT var messagesWebhooks = new Dictionary(); messagesWebhooks.Add(Webhook.Type.InboundUrl, - new Webhook {Address = "https://example.com/webhooks/inbound", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/inbound", Method = "POST" }); messagesWebhooks.Add(Webhook.Type.StatusUrl, - new Webhook {Address = "https://example.com/webhooks/status", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/status", Method = "POST" }); var messagesCapability = new Applications.Capabilities.Messages(messagesWebhooks); var rtcWebhooks = new Dictionary(); rtcWebhooks.Add(Webhook.Type.EventUrl, - new Webhook {Address = "https://example.com/webhooks/events", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/events", Method = "POST" }); var rtcCapability = new Rtc(rtcWebhooks); var voiceWebhooks = new Dictionary(); voiceWebhooks.Add(Webhook.Type.AnswerUrl, - new Webhook {Address = "https://example.com/webhooks/answer", Method = "GET"}); + new Webhook { Address = "https://example.com/webhooks/answer", Method = "GET" }); voiceWebhooks.Add(Webhook.Type.EventUrl, - new Webhook {Address = "https://example.com/webhooks/events", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/events", Method = "POST" }); voiceWebhooks.Add(Webhook.Type.FallbackAnswerUrl, - new Webhook {Address = "https://fallback.example.com/webhooks/answer", Method = "GET"}); + new Webhook { Address = "https://fallback.example.com/webhooks/answer", Method = "GET" }); var voiceCapability = new Applications.Capabilities.Voice(voiceWebhooks); JsonConvert.SerializeObject(voiceCapability); var vbcCapability = new Vbc(); var capabilities = new ApplicationCapabilities - {Messages = messagesCapability, Rtc = rtcCapability, Voice = voiceCapability, Vbc = vbcCapability}; + { Messages = messagesCapability, Rtc = rtcCapability, Voice = voiceCapability, Vbc = vbcCapability }; var keys = new Keys { PublicKey = PublicKey, }; var request = new CreateApplicationRequest - {Capabilities = capabilities, Keys = keys, Name = "My Application"}; + { Capabilities = capabilities, Keys = keys, Name = "My Application" }; var creds = Credentials.FromApiKeyAndSecret(this.ApiKey, this.ApiSecret); var client = this.BuildVonageClient(creds); Application response; @@ -303,6 +303,12 @@ public void GetApplication(bool passCreds) application.Capabilities.Rtc.Webhooks[Webhook.Type.EventUrl].Address); Assert.Equal("POST", application.Capabilities.Rtc.Webhooks[Webhook.Type.EventUrl].Method); Assert.Equal("My Application", application.Name); + Assert.Equal("http://example.com", application.Capabilities.Meetings.Webhooks[Webhook.Type.RoomChanged].Address); + Assert.Equal("POST", application.Capabilities.Meetings.Webhooks[Webhook.Type.RoomChanged].Method); + Assert.Equal("http://example.com", application.Capabilities.Meetings.Webhooks[Webhook.Type.SessionChanged].Address); + Assert.Equal("POST", application.Capabilities.Meetings.Webhooks[Webhook.Type.SessionChanged].Method); + Assert.Equal("https://54eba990d025.ngrok.app/recordings", application.Capabilities.Meetings.Webhooks[Webhook.Type.RecordingChanged].Address); + Assert.Equal("POST", application.Capabilities.Meetings.Webhooks[Webhook.Type.RecordingChanged].Method); } [Theory] @@ -457,7 +463,7 @@ public void ListApplications(bool passCreds, bool passParameters) if (passParameters) { expectedUri = $"{this.ApiUrl}/v2/applications?page_size=10&page=1&"; - request = new ListApplicationsRequest {Page = 1, PageSize = 10}; + request = new ListApplicationsRequest { Page = 1, PageSize = 10 }; } else { @@ -570,7 +576,7 @@ public async void ListApplicationsAsync(bool passCreds, bool passParameters) if (passParameters) { expectedUri = $"{this.ApiUrl}/v2/applications?page_size=10&page=1&"; - request = new ListApplicationsRequest {Page = 1, PageSize = 10}; + request = new ListApplicationsRequest { Page = 1, PageSize = 10 }; } else { @@ -681,32 +687,32 @@ public void UpdateApplication(bool passCredentials) //ACT var messagesWebhooks = new Dictionary(); messagesWebhooks.Add(Webhook.Type.InboundUrl, - new Webhook {Address = "https://example.com/webhooks/inbound", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/inbound", Method = "POST" }); messagesWebhooks.Add(Webhook.Type.StatusUrl, - new Webhook {Address = "https://example.com/webhooks/status", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/status", Method = "POST" }); var messagesCapability = new Applications.Capabilities.Messages(messagesWebhooks); var rtcWebhooks = new Dictionary(); rtcWebhooks.Add(Webhook.Type.EventUrl, - new Webhook {Address = "https://example.com/webhooks/events", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/events", Method = "POST" }); var rtcCapability = new Rtc(rtcWebhooks); var voiceWebhooks = new Dictionary(); voiceWebhooks.Add(Webhook.Type.AnswerUrl, - new Webhook {Address = "https://example.com/webhooks/answer", Method = "GET"}); + new Webhook { Address = "https://example.com/webhooks/answer", Method = "GET" }); voiceWebhooks.Add(Webhook.Type.EventUrl, - new Webhook {Address = "https://example.com/webhooks/events", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/events", Method = "POST" }); voiceWebhooks.Add(Webhook.Type.FallbackAnswerUrl, - new Webhook {Address = "https://fallback.example.com/webhooks/answer", Method = "GET"}); + new Webhook { Address = "https://fallback.example.com/webhooks/answer", Method = "GET" }); var voiceCapability = new Applications.Capabilities.Voice(voiceWebhooks); JsonConvert.SerializeObject(voiceCapability); var vbcCapability = new Vbc(); var capabilities = new ApplicationCapabilities - {Messages = messagesCapability, Rtc = rtcCapability, Voice = voiceCapability, Vbc = vbcCapability}; + { Messages = messagesCapability, Rtc = rtcCapability, Voice = voiceCapability, Vbc = vbcCapability }; var keys = new Keys { PublicKey = PublicKey, }; var application = new CreateApplicationRequest - {Capabilities = capabilities, Keys = keys, Name = "My Application"}; + { Capabilities = capabilities, Keys = keys, Name = "My Application" }; var creds = Credentials.FromApiKeyAndSecret(this.ApiKey, this.ApiSecret); var client = this.BuildVonageClient(creds); Application response; @@ -802,32 +808,32 @@ public async void UpdateApplicationAsync(bool passCredentials) //ACT var messagesWebhooks = new Dictionary(); messagesWebhooks.Add(Webhook.Type.InboundUrl, - new Webhook {Address = "https://example.com/webhooks/inbound", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/inbound", Method = "POST" }); messagesWebhooks.Add(Webhook.Type.StatusUrl, - new Webhook {Address = "https://example.com/webhooks/status", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/status", Method = "POST" }); var messagesCapability = new Applications.Capabilities.Messages(messagesWebhooks); var rtcWebhooks = new Dictionary(); rtcWebhooks.Add(Webhook.Type.EventUrl, - new Webhook {Address = "https://example.com/webhooks/events", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/events", Method = "POST" }); var rtcCapability = new Rtc(rtcWebhooks); var voiceWebhooks = new Dictionary(); voiceWebhooks.Add(Webhook.Type.AnswerUrl, - new Webhook {Address = "https://example.com/webhooks/answer", Method = "GET"}); + new Webhook { Address = "https://example.com/webhooks/answer", Method = "GET" }); voiceWebhooks.Add(Webhook.Type.EventUrl, - new Webhook {Address = "https://example.com/webhooks/events", Method = "POST"}); + new Webhook { Address = "https://example.com/webhooks/events", Method = "POST" }); voiceWebhooks.Add(Webhook.Type.FallbackAnswerUrl, - new Webhook {Address = "https://fallback.example.com/webhooks/answer", Method = "GET"}); + new Webhook { Address = "https://fallback.example.com/webhooks/answer", Method = "GET" }); var voiceCapability = new Applications.Capabilities.Voice(voiceWebhooks); JsonConvert.SerializeObject(voiceCapability); var vbcCapability = new Vbc(); var capabilities = new ApplicationCapabilities - {Messages = messagesCapability, Rtc = rtcCapability, Voice = voiceCapability, Vbc = vbcCapability}; + { Messages = messagesCapability, Rtc = rtcCapability, Voice = voiceCapability, Vbc = vbcCapability }; var keys = new Keys { PublicKey = PublicKey, }; var application = new CreateApplicationRequest - {Capabilities = capabilities, Keys = keys, Name = "My Application"}; + { Capabilities = capabilities, Keys = keys, Name = "My Application" }; var creds = Credentials.FromApiKeyAndSecret(this.ApiKey, this.ApiSecret); var client = this.BuildVonageClient(creds); Application response;