diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d3b8d1a4..2588f6a4 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -23,11 +23,19 @@ jobs: BW_ACCOUNT_ID: ${{ secrets.BW_ACCOUNT_ID }} BW_USERNAME: ${{ secrets.BW_USERNAME }} BW_PASSWORD: ${{ secrets.BW_PASSWORD }} + BW_USERNAME_FORBIDDEN: ${{ secrets.BW_USERNAME_FORBIDDEN}} + BW_PASSWORD_FORBIDDEN: ${{ secrets.BW_PASSWORD_FORBIDDEN}} BW_VOICE_APPLICATION_ID: ${{ secrets.BW_VOICE_APPLICATION_ID }} BW_MESSAGING_APPLICATION_ID: ${{ secrets.BW_MESSAGING_APPLICATION_ID }} BW_NUMBER: ${{ secrets.BW_NUMBER }} USER_NUMBER: ${{ secrets.USER_NUMBER }} BASE_CALLBACK_URL: ${{ secrets.BASE_CALLBACK_URL }} + MANTECA_ACTIVE_NUMBER: ${{ secrets.MANTECA_ACTIVE_NUMBER }} + MANTECA_APPLICATION_ID: ${{ secrets.MANTECA_APPLICATION_ID }} + MANTECA_BASE_URL: ${{ secrets.MANTECA_BASE_URL }} + MANTECA_IDLE_NUMBER: ${{ secrets.MANTECA_IDLE_NUMBER }} + OPERATING_SYSTEM: ${{ matrix.os }} + CSHARP_VERSION: ${{ matrix.dotnet }} run: dotnet test $BW_PROJECT_TEST_NAME - name: Pack NuGet package run: dotnet pack --configuration Release $BW_PROJECT_NAME -p:PackageVersion=$RELEASE_VERSION diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2093af49..07bc97df 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,11 +27,19 @@ jobs: BW_ACCOUNT_ID: ${{ secrets.BW_ACCOUNT_ID }} BW_USERNAME: ${{ secrets.BW_USERNAME }} BW_PASSWORD: ${{ secrets.BW_PASSWORD }} + BW_USERNAME_FORBIDDEN: ${{ secrets.BW_USERNAME_FORBIDDEN}} + BW_PASSWORD_FORBIDDEN: ${{ secrets.BW_PASSWORD_FORBIDDEN}} BW_VOICE_APPLICATION_ID: ${{ secrets.BW_VOICE_APPLICATION_ID }} BW_MESSAGING_APPLICATION_ID: ${{ secrets.BW_MESSAGING_APPLICATION_ID }} BW_NUMBER: ${{ secrets.BW_NUMBER }} USER_NUMBER: ${{ secrets.USER_NUMBER }} BASE_CALLBACK_URL: ${{ secrets.BASE_CALLBACK_URL }} + MANTECA_ACTIVE_NUMBER: ${{ secrets.MANTECA_ACTIVE_NUMBER }} + MANTECA_APPLICATION_ID: ${{ secrets.MANTECA_APPLICATION_ID }} + MANTECA_BASE_URL: ${{ secrets.MANTECA_BASE_URL }} + MANTECA_IDLE_NUMBER: ${{ secrets.MANTECA_IDLE_NUMBER }} + OPERATING_SYSTEM: ${{ matrix.os }} + CSHARP_VERSION: ${{ matrix.dotnet }} # Required for multiple target frameworks in the StandardTests project. DOTNET: ${{ matrix.dotnet }} run: dotnet test src/Bandwidth.Standard.Test diff --git a/src/Bandwidth.Standard.Test/Api/MFAApiTests.cs b/src/Bandwidth.Standard.Test/Api/MFAApiTests.cs index 770b37cd..7a8f4841 100644 --- a/src/Bandwidth.Standard.Test/Api/MFAApiTests.cs +++ b/src/Bandwidth.Standard.Test/Api/MFAApiTests.cs @@ -9,12 +9,6 @@ */ using System; -using System.IO; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Reflection; -using RestSharp; using Xunit; using Bandwidth.Standard.Client; @@ -91,7 +85,7 @@ public void GenerateVoiceCodeTest() var response = instance.GenerateVoiceCodeWithHttpInfo(accountId, codeRequest); Assert.IsType>(response); - Assert.Equal(HttpStatusCode.OK, apiResponse.StatusCode); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); } /// diff --git a/src/Bandwidth.Standard.Test/Api/StatisticsApiTests.cs b/src/Bandwidth.Standard.Test/Api/StatisticsApiTests.cs index 830c7539..ee6d2caf 100644 --- a/src/Bandwidth.Standard.Test/Api/StatisticsApiTests.cs +++ b/src/Bandwidth.Standard.Test/Api/StatisticsApiTests.cs @@ -40,7 +40,7 @@ public StatisticsApiTests() mockClient = new Mock(); mockAsynchronousClient = new Mock(); fakeConfiguration = new Configuration(); - fakeConfiguration.BasePath = "https://numbers.bandwidth.com/api/v1"; + fakeConfiguration.BasePath = "https://voice.bandwidth.com/api/v2"; fakeConfiguration.Username = "username"; fakeConfiguration.Password = "password"; instance = new StatisticsApi(mockClient.Object, mockAsynchronousClient.Object, fakeConfiguration); diff --git a/src/Bandwidth.Standard.Test/Integration/CallsIntegrationTests.cs b/src/Bandwidth.Standard.Test/Integration/CallsIntegrationTests.cs new file mode 100644 index 00000000..d5850758 --- /dev/null +++ b/src/Bandwidth.Standard.Test/Integration/CallsIntegrationTests.cs @@ -0,0 +1,388 @@ +using System; +using Xunit; + +using Bandwidth.Standard.Client; +using Bandwidth.Standard.Api; +using Bandwidth.Standard.Model; +using System.Net; + +namespace Bandwidth.Standard.Test.Integration +{ + /// + /// Class for testing CallsApi + /// + public class CallsIntegrationTests : IDisposable + { + private string accountId; + private CreateCall createCallBody; + private Configuration fakeConfiguration; + private UpdateCall fakeUpdateCall; + private CallsApi forbiddenInstance; + private CallsApi instance; + private CreateCall mantecaCallBody; + private string testCallId; + private int testSleep; + private CallsApi unauthorizedInstance; + public CallsIntegrationTests() + { + accountId = Environment.GetEnvironmentVariable("BW_ACCOUNT_ID"); + testSleep = 5000; + testCallId = "testCallId"; + + // Authorized API Client + fakeConfiguration = new Configuration(); + fakeConfiguration.BasePath = "https://voice.bandwidth.com/api/v2"; + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME"); + fakeConfiguration.Password = Environment.GetEnvironmentVariable("BW_PASSWORD"); + instance = new CallsApi(fakeConfiguration); + + // Unauthorized API Client + fakeConfiguration.Username = "badUsername"; + fakeConfiguration.Password = "badPassword"; + unauthorizedInstance = new CallsApi(fakeConfiguration); + + // Forbidden API Client + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME_FORBIDDEN"); + fakeConfiguration.Password = Environment.GetEnvironmentVariable("BW_PASSWORD_FORBIDDEN"); + forbiddenInstance = new CallsApi(fakeConfiguration); + + createCallBody = new CreateCall( + to: Environment.GetEnvironmentVariable("USER_NUMBER"), + from: Environment.GetEnvironmentVariable("BW_NUMBER"), + displayName: "Test Call", + applicationId: Environment.GetEnvironmentVariable("BW_VOICE_APPLICATION_ID"), + answerUrl: Environment.GetEnvironmentVariable("BASE_CALLBACK_URL"), + answerMethod: CallbackMethodEnum.POST, + username: "mySecretUsername", + password: "mySecretPassword!", + answerFallbackUrl: "https://www.myFallbackServer.com/webhooks/answer", + answerFallbackMethod: CallbackMethodEnum.POST, + fallbackUsername: "mySecretUsername", + fallbackPassword: "mySecretPassword!", + disconnectUrl: "https://myServer.com/bandwidth/webhooks/disconnectUrl", + disconnectMethod: CallbackMethodEnum.POST, + callTimeout: 30, + callbackTimeout: 15, + machineDetection: new MachineDetectionConfiguration( + mode: MachineDetectionModeEnum.Async, + detectionTimeout: 15, + silenceTimeout: 10, + speechThreshold: 10, + speechEndThreshold: 5, + machineSpeechEndThreshold: 5, + delayResult: false, + callbackUrl: "https://myServer.com/bandwidth/webhooks/machineDetectionComplete", + callbackMethod: CallbackMethodEnum.POST, + username: "MySecretUsername", + password: "MySecretPassword!", + fallbackUrl: "https://myFallbackServer.com/bandwidth/webhooks/machineDetectionComplete", + fallbackMethod: CallbackMethodEnum.POST, + fallbackUsername: "MySecretUsername", + fallbackPassword: "MySecretPassword!" + ), + priority: 5, + tag: "tag Example" + ); + + mantecaCallBody = new CreateCall( + to: Environment.GetEnvironmentVariable("MANTECA_IDLE_NUMBER"), + from: Environment.GetEnvironmentVariable("MANTECA_ACTIVE_NUMBER"), + applicationId: Environment.GetEnvironmentVariable("MANTECA_APPLICATION_ID"), + answerUrl: Environment.GetEnvironmentVariable("MANTECA_BASE_URL") + "/bxml/pause" + ); + + fakeUpdateCall = new UpdateCall( + state: CallStateEnum.Active, + redirectUrl: "https://www.myCallbackServer.example/webhooks/redirect", + redirectMethod: RedirectMethodEnum.POST, + username: Environment.GetEnvironmentVariable("BW_USERNAME"), + password: Environment.GetEnvironmentVariable("BW_PASSWORD"), + redirectFallbackUrl: "https://myFallbackServer.example/bandwidth/webhooks/redirect", + redirectFallbackMethod: RedirectMethodEnum.POST, + fallbackUsername: "fallbackUsername", + fallbackPassword: "fallbackPassword", + tag: "My Custom Tag" + ); + } + + public void Dispose() + { + // Cleanup when everything is done. + } + + /// + /// Test successful CreateCall request + /// + [Fact] + public void CreateCallTest() + { + ApiResponse response = instance.CreateCallWithHttpInfo(accountId, createCallBody); + Assert.Equal(HttpStatusCode.Created, response.StatusCode); + Assert.IsType(response.Data.CallId); + Assert.Equal(accountId, response.Data.AccountId); + Assert.Equal(Environment.GetEnvironmentVariable("BW_VOICE_APPLICATION_ID"), response.Data.ApplicationId); + Assert.Equal(Environment.GetEnvironmentVariable("USER_NUMBER"), response.Data.To); + Assert.Equal(Environment.GetEnvironmentVariable("BW_NUMBER"), response.Data.From); + } + + /// + /// Test CreateCall with a bad phone number + /// + [Fact] + public void CreateCallBadRequest() + { + createCallBody.To = "not a phone number"; + ApiException Exception = Assert.Throws(() => instance.CreateCallWithHttpInfo(accountId, createCallBody)); + Assert.Equal(400, Exception.ErrorCode); + } + + /// + /// Test CreateCall with an unauthorized client + /// + [Fact] + public void CreateCallUnauthorizedRequest() + { + ApiException Exception = Assert.Throws(() => unauthorizedInstance.CreateCallWithHttpInfo(accountId, createCallBody)); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test CreateCall with a forbidden client + /// + [Fact] + public void CreateCallForbiddenRequest() + { + ApiException Exception = Assert.Throws(() => forbiddenInstance.CreateCallWithHttpInfo(accountId, createCallBody)); + Assert.Equal(403, Exception.ErrorCode); + } + + /// + /// Test successful GetCallState request + /// + [Fact] + public void GetCallStateTest() + { + CreateCallResponse createCallResponse = instance.CreateCall(accountId, createCallBody); + var callId = createCallResponse.CallId; + + System.Threading.Thread.Sleep(testSleep); + + ApiResponse response = instance.GetCallStateWithHttpInfo(accountId, callId); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal(callId, response.Data.CallId); + Assert.IsType(response.Data.CallId); + Assert.Equal(CallDirectionEnum.Outbound, response.Data.Direction); + Assert.IsType(response.Data.EnqueuedTime); + Assert.IsType(response.Data.LastUpdate); + Assert.IsType(response.Data.StartTime); + } + + /// + /// Test GetCallState with an unauthorized client + /// + [Fact] + public void GetCallStateUnauthorizedRequest() + { + ApiException Exception = Assert.Throws(() => unauthorizedInstance.GetCallStateWithHttpInfo(accountId, testCallId)); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test GetCallState with a forbidden client + /// + [Fact] + public void GetCallStateForbiddenRequest() + { + ApiException Exception = Assert.Throws(() => forbiddenInstance.GetCallStateWithHttpInfo(accountId, testCallId)); + Assert.Equal(403, Exception.ErrorCode); + } + + /// + /// Test GetCallState with a fake call-id + /// + [Fact] + public void GetCallStateNotFoundRequest() + { + ApiException Exception = Assert.Throws(() => instance.GetCallStateWithHttpInfo(accountId, testCallId)); + Assert.Equal(404, Exception.ErrorCode); + } + + /// + /// Test successful UpdateCall request + /// + [Fact] + public void UpdateCallTest() + { + CreateCallResponse createCallResponse = instance.CreateCall(accountId, mantecaCallBody); + string callId = createCallResponse.CallId; + + var updateCallBody = new UpdateCall( + state: CallStateEnum.Active, + redirectUrl: Environment.GetEnvironmentVariable("MANTECA_BASE_URL") + "/bxml/pause", + redirectMethod: RedirectMethodEnum.POST, + username: "mySecretUsername", + password: "mySecretPassword!", + redirectFallbackUrl: Environment.GetEnvironmentVariable("MANTECA_BASE_URL") + "/bxml/pause", + redirectFallbackMethod: RedirectMethodEnum.POST, + fallbackUsername: "mySecretUsername", + fallbackPassword: "mySecretPassword!", + tag: "My Custom Tag" + ); + + System.Threading.Thread.Sleep(testSleep); + + ApiResponse response = instance.UpdateCallWithHttpInfo(accountId, callId, updateCallBody); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + System.Threading.Thread.Sleep(testSleep); + + //Hanging up the call + updateCallBody.State = CallStateEnum.Completed; + response = instance.UpdateCallWithHttpInfo(accountId, callId, updateCallBody); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + /// + /// Test UpdateCall with a bad request + /// + [Fact] + public void UpdateCallBadRequest() + { + CreateCallResponse createCallResponse = instance.CreateCall(accountId, mantecaCallBody); + string callId = createCallResponse.CallId; + + System.Threading.Thread.Sleep(testSleep); + + fakeUpdateCall.State = null; + ApiException Exception = Assert.Throws(() => instance.UpdateCall(accountId, callId, fakeUpdateCall)); + Assert.Equal(400, Exception.ErrorCode); + + //Hanging up the call + fakeUpdateCall.State = CallStateEnum.Completed; + var updateCallResponse = instance.UpdateCallWithHttpInfo(accountId, callId, fakeUpdateCall); + Assert.Equal(HttpStatusCode.OK, updateCallResponse.StatusCode); + } + + /// + /// Test UpdateCall with an unauthorized client + /// + [Fact] + public void UpdateCallUnauthorizedRequest() + { + fakeUpdateCall.State = CallStateEnum.Completed; + ApiException Exception = Assert.Throws(() => unauthorizedInstance.UpdateCallWithHttpInfo(accountId, testCallId, fakeUpdateCall)); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test UpdateCall with a forbidden client + /// + [Fact] + public void UpdateCallForbiddenRequest() + { + CreateCallResponse createCallResponse = instance.CreateCall(accountId, mantecaCallBody); + string callId = createCallResponse.CallId; + + System.Threading.Thread.Sleep(testSleep); + + fakeUpdateCall.State = CallStateEnum.Completed; + ApiException Exception = Assert.Throws(() => forbiddenInstance.UpdateCall(accountId, callId, fakeUpdateCall)); + Assert.Equal(403, Exception.ErrorCode); + + System.Threading.Thread.Sleep(testSleep); + + ApiResponse response = instance.UpdateCallWithHttpInfo(accountId, callId, fakeUpdateCall); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + /// + /// Test UpdateCall with a fake call-id + /// + [Fact] + public void UpdateCallNotFoundRequest() + { + fakeUpdateCall.State = CallStateEnum.Completed; + ApiException Exception = Assert.Throws(() => instance.UpdateCallWithHttpInfo(accountId, testCallId, fakeUpdateCall)); + Assert.Equal(404, Exception.ErrorCode); + } + + /// + /// Test successful UpdateCallBxml request + /// + [Fact] + public void UpdateCallBxml() + { + CreateCallResponse createCallResponse = instance.CreateCall(accountId, mantecaCallBody); + string callId = createCallResponse.CallId; + + System.Threading.Thread.Sleep(testSleep); + + ApiResponse updateCallBxmlResponse = instance.UpdateCallBxmlWithHttpInfo(accountId, callId, " This is a test sentence."); + Assert.Equal(HttpStatusCode.NoContent, updateCallBxmlResponse.StatusCode); + + System.Threading.Thread.Sleep(testSleep); + + // hangup call + fakeUpdateCall.State = CallStateEnum.Completed; + ApiResponse updateCallResponse = instance.UpdateCallWithHttpInfo(accountId, callId, fakeUpdateCall); + Assert.Equal(HttpStatusCode.OK, updateCallResponse.StatusCode); + } + + /// + /// Test UpdateCallBxml with invalid BXML + /// + [Fact] + public void UpdateCallBxmlBadRequest() + { + ApiResponse createCallResponse = instance.CreateCallWithHttpInfo(accountId, mantecaCallBody); + string callId = createCallResponse.Data.CallId; + + System.Threading.Thread.Sleep(testSleep); + + ApiException Exception = Assert.Throws(() => instance.UpdateCallBxmlWithHttpInfo(accountId, callId, "invalid BXML")); + Assert.Equal(400, Exception.ErrorCode); + + System.Threading.Thread.Sleep(testSleep); + + // hangup call + fakeUpdateCall.State = CallStateEnum.Completed; + ApiResponse updateCallResponse = instance.UpdateCallWithHttpInfo(accountId, callId, fakeUpdateCall); + Assert.Equal(HttpStatusCode.OK, updateCallResponse.StatusCode); + } + + /// + /// Test UpdateCallBxml with an unauthorized client + /// + [Fact] + public void UpdateCallBxmlUnauthorizedRequest() + { + ApiException Exception = Assert.Throws(() => unauthorizedInstance.UpdateCallBxmlWithHttpInfo(accountId, testCallId, " This is a test sentence.")); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test UpdateCallBxml with a forbidden client + /// + [Fact] + public void UpdateCallBxmlForbiddenRequest() + { + CreateCallResponse createCallResponse = instance.CreateCall(accountId, mantecaCallBody); + string callId = createCallResponse.CallId; + + System.Threading.Thread.Sleep(testSleep); + + ApiException Exception = Assert.Throws(() => forbiddenInstance.UpdateCallBxmlWithHttpInfo(accountId, callId, " This is a test sentence.")); + Assert.Equal(403, Exception.ErrorCode); + } + + /// + /// Test UpdateCallBxml with a fake call-id + /// + [Fact] + public void UpdateCallBxmlNotFoundRequest() + { + ApiException Exception = Assert.Throws(() => instance.UpdateCallBxmlWithHttpInfo(accountId, testCallId, " This is a test sentence.")); + Assert.Equal(404, Exception.ErrorCode); + } + } +} diff --git a/src/Bandwidth.Standard.Test/Integration/ConferencesIntegrationTests.cs b/src/Bandwidth.Standard.Test/Integration/ConferencesIntegrationTests.cs new file mode 100644 index 00000000..88e08b4e --- /dev/null +++ b/src/Bandwidth.Standard.Test/Integration/ConferencesIntegrationTests.cs @@ -0,0 +1,500 @@ +using System; +using Xunit; + +using Bandwidth.Standard.Client; +using Bandwidth.Standard.Api; +using Bandwidth.Standard.Model; +using System.Net; +using System.Text.Json; +using Newtonsoft.Json.Linq; + +namespace Bandwidth.Standard.Test.Integration +{ + /// + /// Class for testing ConferencesApi + /// + public class ConferencesIntegrationTests : IDisposable + { + private ConferencesApi conferenceApiInstance; + private ConferencesApi unauthorizedInstance; + private ConferencesApi forbiddenInstance; + private ApiClient restClient; + private UpdateConference updateConferenceBody; + private CallsApi callsApiInstance; + private Configuration fakeConfiguration; + private CreateCall mantecaCallBody; + private UpdateConferenceMember updateConferenceMember; + private string accountId; + private string testConferenceId; + private string testMemberId; + private string testRecordingId; + private string testUpdateBxml; + + public ConferencesIntegrationTests() + { + accountId = Environment.GetEnvironmentVariable("BW_ACCOUNT_ID"); + testConferenceId = "Conf-Id"; + testMemberId = "Member-Id"; + testRecordingId = "Recording-Id"; + testUpdateBxml = "This is test BXML."; + + // Authorized API Client + fakeConfiguration = new Configuration(); + fakeConfiguration.BasePath = "https://voice.bandwidth.com/api/v2"; + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME"); + fakeConfiguration.Password = Environment.GetEnvironmentVariable("BW_PASSWORD"); + conferenceApiInstance = new ConferencesApi(fakeConfiguration); + callsApiInstance = new CallsApi(fakeConfiguration); + + // Unauthorized API Client + fakeConfiguration.Username = "badUsername"; + fakeConfiguration.Password = "badPassword"; + unauthorizedInstance = new ConferencesApi(fakeConfiguration); + + // Forbidden API Client + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME_FORBIDDEN"); + fakeConfiguration.Password = Environment.GetEnvironmentVariable("BW_PASSWORD_FORBIDDEN"); + forbiddenInstance = new ConferencesApi(fakeConfiguration); + + restClient = new ApiClient(basePath: "https://voice.bandwidth.com/api/v2"); + + updateConferenceBody = new UpdateConference( + status: ConferenceStateEnum.Active, + redirectUrl: Environment.GetEnvironmentVariable("MANTECA_BASE_URL") + "/bxml/pause", + redirectMethod: RedirectMethodEnum.POST, + username: "mySecretUsername", + password: "mySecretPassword!", + redirectFallbackUrl: Environment.GetEnvironmentVariable("MANTECA_BASE_URL") + "/bxml/pause", + redirectFallbackMethod: RedirectMethodEnum.POST, + fallbackUsername: "mySecretUsername", + fallbackPassword: "mySecretPassword!" + ); + + mantecaCallBody = new CreateCall( + to: Environment.GetEnvironmentVariable("MANTECA_IDLE_NUMBER"), + from: Environment.GetEnvironmentVariable("MANTECA_ACTIVE_NUMBER"), + applicationId: Environment.GetEnvironmentVariable("MANTECA_APPLICATION_ID"), + answerUrl: Environment.GetEnvironmentVariable("MANTECA_BASE_URL") + "/bxml/joinConferencePause" + ); + + updateConferenceMember = new UpdateConferenceMember(mute: false); + } + + public void Dispose() + { + // Cleanup when everything is done. + } + + /// + /// Create and validate a call between two bandwidth numbers. Initializes the call with the Manteca + /// system. + /// + /// + /// A tuple containing the test id created in Manteca to track this call, as well as the conference and call id for the created call. + /// + [Fact] + public Tuple CreateConferenceTest() + { + // set up request options for creating a call + var jsonBody = JsonSerializer.Serialize(new + { + os = Environment.GetEnvironmentVariable("OPERATING_SYSTEM"), + language = "csharp" + Environment.GetEnvironmentVariable("CSHARP_VERSION"), + type = "CONFERENCE" + }); + var options = new RequestOptions + { + Data = jsonBody, + HeaderParameters = new Multimap + { + { "Content-Type", "application/json" } + } + }; + + // initialize call with Manteca + var response = restClient.Post( + path: Environment.GetEnvironmentVariable("MANTECA_BASE_URL") + "/tests", + options: options + ); + var testId = response.RawContent; + mantecaCallBody.Tag = testId; + + CreateCallResponse callResponse = callsApiInstance.CreateCall(accountId, mantecaCallBody); + var callId = callResponse.CallId; + + Assert.IsType(callId); + Assert.Equal(Environment.GetEnvironmentVariable("BW_ACCOUNT_ID"), callResponse.AccountId); + Assert.Equal(Environment.GetEnvironmentVariable("MANTECA_APPLICATION_ID"), callResponse.ApplicationId); + Assert.Equal(Environment.GetEnvironmentVariable("MANTECA_IDLE_NUMBER"), callResponse.To); + Assert.Equal(Environment.GetEnvironmentVariable("MANTECA_ACTIVE_NUMBER"), callResponse.From); + + System.Threading.Thread.Sleep(5000); + + var listConferencesResponse = conferenceApiInstance.ListConferencesWithHttpInfo( + accountId: accountId, + name: testId + ); + Assert.Equal(HttpStatusCode.OK, listConferencesResponse.StatusCode); + + // TODO: This is not deterministic; our latest conference may not always be the one we just created due to parallelism. + // This new solution should guarantee the right conference id is grabbed. + var conferenceId = listConferencesResponse.Data[0].Id; + + var getConferenceResponse = conferenceApiInstance.GetConferenceWithHttpInfo( + accountId: accountId, + conferenceId: conferenceId + ); + Assert.Equal(HttpStatusCode.OK, getConferenceResponse.StatusCode); + Assert.Equal(conferenceId, getConferenceResponse.Data.Id); + Assert.Equal(testId, getConferenceResponse.Data.Name); + + + return Tuple.Create(testId, conferenceId); + } + + /// + /// Get the status of the specified test by its id value from Manteca services. + /// + /// The test id associated with the test to get the status of. + /// + /// A string containing the status of the test requested. + /// + + public string GetTestStatus(string testId) + { + var options = new RequestOptions + { + HeaderParameters = new Multimap + { + { "Content-Type", "text/plain" } + } + }; + + // get test status from Manteca + var response = restClient.Get( + path: Environment.GetEnvironmentVariable("MANTECA_BASE_URL") + "/tests/" + testId, + options: options + ); + + return response.Content.ToString(); + } + + /// + /// Tests a successful flow of creating and ending a conference. + /// + [Fact] + public void testConferenceAndMembers() + { + Tuple createCoferenceResponse = CreateConferenceTest(); + var testId = createCoferenceResponse.Item1; + var conferenceId = createCoferenceResponse.Item2; + + var listConferencesResponse = conferenceApiInstance.ListConferencesWithHttpInfo(accountId); + Assert.Equal(HttpStatusCode.OK, listConferencesResponse.StatusCode); + Assert.IsType(listConferencesResponse.Data[0].Name); + Assert.IsType(listConferencesResponse.Data[0].Id); + + var getConferenceResponse = conferenceApiInstance.GetConferenceWithHttpInfo(accountId, conferenceId); + Assert.Equal(HttpStatusCode.OK, getConferenceResponse.StatusCode); + Assert.Equal(conferenceId, getConferenceResponse.Data.Id); + Assert.IsType(getConferenceResponse.Data.Name); + + var callId = getConferenceResponse.Data.ActiveMembers[0].CallId; + + var GetConferenceMemberResponse = conferenceApiInstance.GetConferenceMemberWithHttpInfo(accountId, conferenceId, callId); + Assert.Equal(HttpStatusCode.OK, GetConferenceMemberResponse.StatusCode); + Assert.Equal(conferenceId, GetConferenceMemberResponse.Data.ConferenceId); + Assert.Equal(callId, GetConferenceMemberResponse.Data.CallId); + + var updateConferenceMemberResponse = conferenceApiInstance.UpdateConferenceMemberWithHttpInfo(accountId, conferenceId, callId, updateConferenceMember); + Assert.Equal(HttpStatusCode.NoContent, updateConferenceMemberResponse.StatusCode); + + var updateConferenceResponse = conferenceApiInstance.UpdateConferenceWithHttpInfo(accountId, conferenceId, updateConferenceBody); + Assert.Equal(HttpStatusCode.NoContent, updateConferenceResponse.StatusCode); + + testUpdateBxml = "This is a test bxml response"; + + var updateConferenceBxmlResponse = conferenceApiInstance.UpdateConferenceBxmlWithHttpInfo(accountId, conferenceId, testUpdateBxml); + Assert.Equal(HttpStatusCode.NoContent, updateConferenceBxmlResponse.StatusCode); + + var updateCall = new UpdateCall( + state: CallStateEnum.Completed + ); + // hang up call + callsApiInstance.UpdateCall(accountId, callId, updateCall); + } + + /// + /// Test Conference Recordings + /// Tests a successful flow of creating a call with a recording. + /// + [Fact] + public void testConferenceRecordings() + { + Tuple createCoferenceResponse = CreateConferenceTest(); + var testId = createCoferenceResponse.Item1; + var conferenceId = createCoferenceResponse.Item2; + var listConferencesResponse = conferenceApiInstance.ListConferencesWithHttpInfo(accountId); + Assert.Equal(HttpStatusCode.OK, listConferencesResponse.StatusCode); + + testUpdateBxml = "This should be a conference recording."; + + var updateConferenceBxmlResponse = conferenceApiInstance.UpdateConferenceBxmlWithHttpInfo(accountId, conferenceId, testUpdateBxml); + Assert.Equal(HttpStatusCode.NoContent, updateConferenceBxmlResponse.StatusCode); + + var callStatus = GetTestStatus(testId); + var retryCounter = 0; + JObject callStatusJson = JObject.Parse(callStatus); + + while (!(Boolean)callStatusJson["callRecorded"] && retryCounter < 10) + { + System.Threading.Thread.Sleep(5000); + callStatus = GetTestStatus(testId); + callStatusJson = JObject.Parse(callStatus); + retryCounter++; + } + Assert.True((Boolean)callStatusJson["callRecorded"]); + + var listConferenceRecordingsResponse = conferenceApiInstance.ListConferenceRecordingsWithHttpInfo(accountId, conferenceId); + Assert.Equal(HttpStatusCode.OK, listConferenceRecordingsResponse.StatusCode); + Assert.NotEmpty(listConferenceRecordingsResponse.Data); + + ConferenceRecordingMetadata firstRecording = listConferenceRecordingsResponse.Data[0]; + Assert.Equal("complete", firstRecording.Status); + Assert.Equal(FileFormatEnum.Wav, firstRecording.FileFormat); + + var firstRecordingId = firstRecording.RecordingId; + var getConferenceRecordingResponse = conferenceApiInstance.GetConferenceRecordingWithHttpInfo(accountId, conferenceId, firstRecordingId); + Assert.Equal(HttpStatusCode.OK, getConferenceRecordingResponse.StatusCode); + Assert.Equal(conferenceId, getConferenceRecordingResponse.Data.ConferenceId); + Assert.Equal(firstRecordingId, getConferenceRecordingResponse.Data.RecordingId); + Assert.IsType(getConferenceRecordingResponse.Data.Name); + Assert.Equal("complete", getConferenceRecordingResponse.Data.Status); + Assert.Equal(FileFormatEnum.Wav, getConferenceRecordingResponse.Data.FileFormat); + + var recordingMediaResponse = conferenceApiInstance.DownloadConferenceRecordingWithHttpInfo(accountId, conferenceId, firstRecordingId); + Assert.Equal(HttpStatusCode.OK, recordingMediaResponse.StatusCode); + } + + /// + /// Test List Conferences Unauthorized + /// + [Fact] + public void ListConferencesUnauthorizedRequest() + { + ApiException Exception = Assert.Throws(() => unauthorizedInstance.ListConferencesWithHttpInfo(accountId)); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test List Conferences Forbidden + /// + [Fact] + public void ListConferenceForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.ListConferencesWithHttpInfo(accountId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test Get Conferences Unauthorized + /// + [Fact] + public void GetConferencesUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.ListConferencesWithHttpInfo(accountId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test Get Conferences Forbidden + /// + [Fact] + public void GetConferencesForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.GetConferenceWithHttpInfo(accountId, testConferenceId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test Get Conferences Not Found + /// + [Fact] + public void GetConferencesNotFound() + { + ApiException exception = Assert.Throws(() => conferenceApiInstance.GetConferenceWithHttpInfo(accountId, testConferenceId)); + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test Get Conference Member Unauthorized + /// + [Fact] + public void GetConferenceMemberUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.GetConferenceMemberWithHttpInfo(accountId, testConferenceId, testMemberId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test Get Conference Member Forbidden + /// + [Fact] + public void GetConferenceMemberForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.GetConferenceMemberWithHttpInfo(accountId, testConferenceId, testMemberId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test Get Conference Member Not Found + /// + [Fact] + public void GetConferenceMemberNotFoundRequest() + { + ApiException exception = Assert.Throws(() => conferenceApiInstance.GetConferenceMemberWithHttpInfo(accountId, testConferenceId, testMemberId)); + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test List Conference Recordings Unauthorized + /// + [Fact] + public void ListConferenceRecordingsUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.ListConferenceRecordingsWithHttpInfo(accountId, testConferenceId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test List Conference Recordings Forbidden + /// + [Fact] + public void ListConferenceRecordingsForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.ListConferenceRecordingsWithHttpInfo(accountId, testConferenceId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test Get Conference Recording Unauthorized + /// + [Fact] + public void GetConferenceRecordingUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.GetConferenceRecordingWithHttpInfo(accountId, testConferenceId, testRecordingId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test Get Conference Recording Forbidden + /// + [Fact] + public void GetConferenceRecordingForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.GetConferenceRecordingWithHttpInfo(accountId, testConferenceId, testRecordingId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test Get Conference Recording not found + /// + [Fact(Skip = "Actually throws a 500 error and needs to be fixed by the voice team")] + public void GetConferenceRecordingNotFound() + { + ApiException exception = Assert.Throws(() => conferenceApiInstance.GetConferenceRecordingWithHttpInfo(accountId, testConferenceId, testRecordingId)); + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test Update Conference Unauthorized Request + /// + [Fact] + public void UpdateConferenceUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.UpdateConferenceWithHttpInfo(accountId, testConferenceId, updateConferenceBody)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test Update Conference Forbidden Request + /// + [Fact] + public void UpdateConferenceForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.UpdateConferenceWithHttpInfo(accountId, testConferenceId, updateConferenceBody)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test Update Conference Not Found + /// + [Fact] + public void UpdateConferenceNotFoundRequest() + { + ApiException exception = Assert.Throws(() => conferenceApiInstance.UpdateConferenceWithHttpInfo(accountId, testConferenceId, updateConferenceBody)); + + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test Update Conference BXML Unauthorized + /// + [Fact] + public void UpdateConferenceBxmlUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.UpdateConferenceBxmlWithHttpInfo(accountId, testConferenceId, testUpdateBxml)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test Update Conference BXML Forbidden + /// + [Fact] + public void UpdateConferenceBxmlForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.UpdateConferenceBxmlWithHttpInfo(accountId, testConferenceId, testUpdateBxml)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test Update Conference BXML Not Found + /// + [Fact] + public void UpdateConferenceBxmlNotFoundRequest() + { + ApiException exception = Assert.Throws(() => conferenceApiInstance.UpdateConferenceBxmlWithHttpInfo(accountId, testConferenceId, testUpdateBxml)); + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test Update Conference Member Unauthorized + /// + [Fact] + public void UpdateConferenceMemberUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.UpdateConferenceMemberWithHttpInfo(accountId, testConferenceId, testMemberId, updateConferenceMember)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test Update Conference Member Forbidden + /// + [Fact] + public void UpdateConferenceMemberForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.UpdateConferenceMemberWithHttpInfo(accountId, testConferenceId, testMemberId, updateConferenceMember)); + Assert.Equal(403, exception.ErrorCode); // not erroring out + } + + /// + /// Test Update Conference Member Not Found + /// + [Fact] + public void UpdateConferenceMemberNotFoundRequest() + { + ApiException exception = Assert.Throws(() => conferenceApiInstance.UpdateConferenceMember(accountId, testConferenceId, testMemberId, updateConferenceMember)); + Assert.Equal(404, exception.ErrorCode); + } + } +} diff --git a/src/Bandwidth.Standard.Test/Integration/MFAIntegrationTests.cs b/src/Bandwidth.Standard.Test/Integration/MFAIntegrationTests.cs new file mode 100644 index 00000000..11291990 --- /dev/null +++ b/src/Bandwidth.Standard.Test/Integration/MFAIntegrationTests.cs @@ -0,0 +1,269 @@ +using System; +using Xunit; + +using Bandwidth.Standard.Client; +using Bandwidth.Standard.Api; +using Bandwidth.Standard.Model; +using System.Net; +using System.Linq; +using System.Diagnostics; + +namespace Bandwidth.Standard.Test.Integration +{ + /// + /// Class for testing MFAApi + /// + public class MFAIntegrationTests : IDisposable + { + private string accountId; + private CodeRequest badCodeRequest; + private string BW_NUMBER; + private Configuration fakeConfiguration; + private MFAApi forbiddenInstance; + private MFAApi instance; + private CodeRequest messagingCodeRequest; + private MFAApi unauthorizedInstance; + private string USER_NUMBER; + private VerifyCodeRequest verifyCodeRequest; + private CodeRequest voiceCodeRequest; + + public MFAIntegrationTests() + { + accountId = Environment.GetEnvironmentVariable("BW_ACCOUNT_ID"); + BW_NUMBER = Environment.GetEnvironmentVariable("BW_NUMBER"); + USER_NUMBER = Environment.GetEnvironmentVariable("USER_NUMBER"); + + // Authorized API Client + fakeConfiguration = new Configuration(); + fakeConfiguration.BasePath = "https://mfa.bandwidth.com/api/v1"; + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME"); + fakeConfiguration.Password = Environment.GetEnvironmentVariable("BW_PASSWORD"); + instance = new MFAApi(fakeConfiguration); + + // Unauthorized API Client + unauthorizedInstance = new MFAApi(); + + // Forbidden API Client + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME_FORBIDDEN"); + fakeConfiguration.Password = "badPassword"; + forbiddenInstance = new MFAApi(fakeConfiguration); + + // Code Request for generating a messaging code + messagingCodeRequest = new CodeRequest( + to: USER_NUMBER, + from: BW_NUMBER, + applicationId: Environment.GetEnvironmentVariable("BW_MESSAGING_APPLICATION_ID"), + message: "Your temporary {NAME} {SCOPE} code is {CODE}", + scope: "2FA", + digits: 6 + ); + + // Code Request for generating a voice code + voiceCodeRequest = new CodeRequest( + to: USER_NUMBER, + from: BW_NUMBER, + applicationId: Environment.GetEnvironmentVariable("BW_VOICE_APPLICATION_ID"), + message: "Your temporary {NAME} {SCOPE} code is {CODE}", + scope: "2FA", + digits: 6 + ); + + // Bad Code Request + badCodeRequest = new CodeRequest( + to: USER_NUMBER, + from: BW_NUMBER, + applicationId: "not an application id", + message: "Your temporary {NAME} {SCOPE} code is {CODE}", + scope: "2FA", + digits: 6 + ); + + // Verify Code Request to a random number + verifyCodeRequest = new VerifyCodeRequest( + to: "+1", + scope: "2FA", + expirationTimeInMinutes: 3, + code: "123456" + ); + } + + public void Dispose() + { + // Cleanup when everything is done. + } + + /// + /// Test an instance of MFAApi + /// + [Fact] + public void InstanceTest() + { + Assert.IsType(instance); + } + + /// + /// Test a successful GenerateMessagingCode request + /// + [Fact] + public void GenerateMessagingCodeTest() + { + var response = instance.GenerateMessagingCodeWithHttpInfo(accountId, messagingCodeRequest); + Assert.IsType>(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + /// + /// Test GenerateMessagingCode with a bad code request + /// + [Fact] + public void GenerateMessagingCodeBadRequest() + { + ApiException Exception = Assert.Throws(() => instance.GenerateMessagingCode(accountId, badCodeRequest)); + Assert.Equal(400, Exception.ErrorCode); + } + + /// + /// Test GenerateMessagingCode with an unauthorized client + /// + [Fact] + public void GenerateMessagingCodeUnauthorizedRequest() + { + ApiException Exception = Assert.Throws(() => unauthorizedInstance.GenerateMessagingCode(accountId, messagingCodeRequest)); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test GenerateMessagingCode with a forbidden client + /// + [Fact] + public void GenerateMessagingCodeForbiddenRequest() + { + ApiException Exception = Assert.Throws(() => forbiddenInstance.GenerateMessagingCode(accountId, messagingCodeRequest)); + Assert.Equal(403, Exception.ErrorCode); + } + + /// + /// Test a successful GenerateVoiceCode request + /// + [Fact] + public void GenerateVoiceCodeTest() + { + var response = instance.GenerateVoiceCodeWithHttpInfo(accountId, voiceCodeRequest); + Assert.IsType>(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + /// + /// Test GenerateVoiceCode with a bad code request + /// + [Fact] + public void GenerateVoiceCodeBadRequest() + { + ApiException Exception = Assert.Throws(() => instance.GenerateVoiceCode(accountId, badCodeRequest)); + Assert.Equal(400, Exception.ErrorCode); + } + + /// + /// Test GenerateVoiceCode with an unauthorized client + /// + [Fact] + public void GenerateVoiceCodeUnauthorizedRequest() + { + ApiException Exception = Assert.Throws(() => unauthorizedInstance.GenerateVoiceCode(accountId, voiceCodeRequest)); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test GenerateVoiceCode with a forbidden client + /// + [Fact] + public void GenerateVoiceCodeForbiddenRequest() + { + ApiException Exception = Assert.Throws(() => forbiddenInstance.GenerateVoiceCode(accountId, voiceCodeRequest)); + Assert.Equal(403, Exception.ErrorCode); + } + + /// + /// Test a successful VerifyCode request + /// Will always have to test against False codes unless we incorporate the Manteca project into MFA + /// + [Fact] + public void VerifyCodeTest() + { + for(int i = 0; i < 10; i++) + { + verifyCodeRequest.To = verifyCodeRequest.To + new Random().Next(10).ToString(); + } + var responseWithHttpInfo = instance.VerifyCodeWithHttpInfo(accountId, verifyCodeRequest); + Assert.Equal(HttpStatusCode.OK, responseWithHttpInfo.StatusCode); + + var response = instance.VerifyCode(accountId, verifyCodeRequest); + Assert.IsType(response); + Assert.IsType(response.Valid); + Assert.False(response.Valid); + } + + /// + /// Test VerifyCode with an unauthorized client + /// + [Fact] + public void VerifyCodeUnauthorizedRequest() + { + ApiException Exception = Assert.Throws(() => unauthorizedInstance.VerifyCode(accountId, verifyCodeRequest)); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test VerifyCode with a forbidden client + /// + [Fact] + public void VerifyCodeForbiddenRequest() + { + ApiException Exception = Assert.Throws(() => forbiddenInstance.VerifyCode(accountId, verifyCodeRequest)); + Assert.Equal(403, Exception.ErrorCode); + } + + /// + /// Test VerifyCode rate limiting + /// + [Fact] + public void VerifyCodeRateLimiting() + { + for(int i = 0; i < 10; i++) + { + verifyCodeRequest.To = verifyCodeRequest.To + new Random().Next(10).ToString(); + } + var callCount = 1; + while (true) + { + try + { + Trace.WriteLine($"Testing rate limit, attempt #{callCount}"); + var response = instance.VerifyCodeWithHttpInfo(accountId, verifyCodeRequest); + callCount++; + } + catch (ApiException e) + { + if (e.ErrorCode == 429) + { + Trace.WriteLine($"Rate limit reached"); + System.Threading.Thread.Sleep(35000); + var response = instance.VerifyCodeWithHttpInfo(accountId, verifyCodeRequest); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + break; + } + else + { + throw e; + } + } + catch (Exception) + { + Trace.WriteLine($"Unexpected exception while testing rate limit"); + throw; + } + } + } + + } +} diff --git a/src/Bandwidth.Standard.Test/Integration/MediaIntegrationTests.cs b/src/Bandwidth.Standard.Test/Integration/MediaIntegrationTests.cs new file mode 100644 index 00000000..e23752ed --- /dev/null +++ b/src/Bandwidth.Standard.Test/Integration/MediaIntegrationTests.cs @@ -0,0 +1,230 @@ +using System; +using System.IO; +using System.Collections.Generic; +using Xunit; + +using Bandwidth.Standard.Client; +using Bandwidth.Standard.Api; +using Bandwidth.Standard.Model; +using System.Net; + +namespace Bandwidth.Standard.Test.Integration +{ + /// + /// Class for testing MediaApi + /// + public class MediaIntegrationTests : IDisposable + { + private string accountId; + private Configuration fakeConfiguration; + private MediaApi instance; + private string testMediaId; + private string testContentType; + private string filePath; + private MediaApi unauthorizedInstance; + + + public MediaIntegrationTests() + { + accountId = Environment.GetEnvironmentVariable("BW_ACCOUNT_ID"); + testContentType = "image/jpeg"; + testMediaId = $"test-media-id-{Guid.NewGuid()}"; + + // Authorized API Client + fakeConfiguration = new Configuration(); + fakeConfiguration.BasePath = "https://voice.bandwidth.com/api/v2"; + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME"); + fakeConfiguration.Password = Environment.GetEnvironmentVariable("BW_PASSWORD"); + instance = new MediaApi(fakeConfiguration); + + // Unauthorized API Client + fakeConfiguration = new Configuration(); + fakeConfiguration.BasePath = "https://messaging.bandwidth.com/api/v2"; + fakeConfiguration.Username = "badUsername"; + fakeConfiguration.Password = "badPassword"; + unauthorizedInstance = new MediaApi(fakeConfiguration); + + // Create a media file to use for testing + string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; + string relativePath = "../../../Fixtures/csharp_cat.jpeg"; + filePath = Path.Combine(baseDirectory, relativePath); + } + + public void Dispose() + { + // Cleanup when everything is done. + } + + /// + /// Test an instance of MediaApi + /// + [Fact] + public void InstanceTest() + { + Assert.IsType(instance); + } + + /// + /// Test successful UploadMedia Request + /// + [Fact] + public void UploadMediaTest() + { + var testMediaBody = new System.IO.FileStream(filePath, FileMode.Open); + var responseWithHttpInfo = instance.UploadMediaWithHttpInfo(accountId, testMediaId, testMediaBody, testContentType); + Assert.IsType>(responseWithHttpInfo); + Assert.Equal(HttpStatusCode.NoContent, responseWithHttpInfo.StatusCode); + testMediaBody.Close(); + } + + /// + /// Test UploadMedia with an unauthorized client + /// /// + [Fact] + public void UploadMediaUnauthorized() + { + var testMediaBody = new System.IO.FileStream(filePath, FileMode.Open); + ApiException exception = Assert.Throws(() => unauthorizedInstance.UploadMediaWithHttpInfo(accountId, testMediaId, testMediaBody, testContentType)); + Assert.Equal(401, exception.ErrorCode); + testMediaBody.Close(); + } + + /// + /// Test UploadMedia with a forbidden client + /// + [Fact] + public void UploadMediaForbidden() + { + var testMediaBody = new System.IO.FileStream(filePath, FileMode.Open); + ApiException exception = Assert.Throws(() => instance.UploadMediaWithHttpInfo("not-an-account-id", testMediaId, testMediaBody, testContentType)); + Assert.Equal(403, exception.ErrorCode); + testMediaBody.Close(); + } + + /// + /// Test successful ListMedia Request + /// + [Fact] + public void ListMediaTest() + { + var responseWithHttpInfo = instance.ListMediaWithHttpInfo(accountId); + Assert.Equal(HttpStatusCode.OK, responseWithHttpInfo.StatusCode); + + var response = instance.ListMedia(accountId); + Assert.IsType>(response); + Assert.IsType(response[0]); + } + + /// + /// Test ListMedia with an unauthorized client + /// + [Fact] + public void ListMediaUnauthorized() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.ListMediaWithHttpInfo(accountId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test ListMedia with a forbidden client + /// + [Fact] + public void ListMediaForbidden() + { + ApiException exception = Assert.Throws(() => instance.ListMediaWithHttpInfo("not-an-account-id")); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test successful GetMedia Request + /// + [Fact] + public void GetMediaTest() + { + var testMediaBody = new System.IO.FileStream(filePath, FileMode.Open); + var uploadResponse = instance.UploadMediaWithHttpInfo(accountId, testMediaId, testMediaBody, testContentType); + + var responseWithHttpInfo = instance.GetMediaWithHttpInfo(accountId, testMediaId); + Assert.Equal(HttpStatusCode.OK, responseWithHttpInfo.StatusCode); + + var response = instance.GetMedia(accountId, testMediaId); + Assert.IsAssignableFrom(response); + testMediaBody.Close(); + } + + /// + /// Test GetMedia with an unauthorized client + /// + [Fact] + public void GetMediaUnauthorized() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.GetMediaWithHttpInfo(accountId, testMediaId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test GetMedia with a forbidden client + /// + [Fact] + public void GetMediaForbidden() + { + ApiException exception = Assert.Throws(() => instance.GetMediaWithHttpInfo("not-an-account-id", testMediaId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test GetMedia with a fake media id + /// + [Fact] + public void GetMediaNotFound() + { + ApiException exception = Assert.Throws(() => instance.GetMediaWithHttpInfo(accountId, "not-a-media-id.jpg")); + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test successful DeleteMedia Request + /// + [Fact] + public void DeleteMediaTest() + { + var testMediaBody = new System.IO.FileStream(filePath, FileMode.Open); + var uploadResponse = instance.UploadMediaWithHttpInfo(accountId, testMediaId, testMediaBody, testContentType); + + var responseWithHttpInfo = instance.DeleteMediaWithHttpInfo(accountId, testMediaId); + Assert.Equal(HttpStatusCode.NoContent, responseWithHttpInfo.StatusCode); + testMediaBody.Close(); + } + + /// + /// Test DeleteMedia with an unauthorized client + /// + [Fact] + public void DeleteMediaUnauthorized() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.DeleteMediaWithHttpInfo(accountId, testMediaId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test DeleteMedia with a forbidden client + /// + [Fact] + public void DeleteMediaForbidden() + { + ApiException exception = Assert.Throws(() => instance.DeleteMediaWithHttpInfo("not-an-account-id", testMediaId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test DeleteMedia with a fake media id + /// API does not throw an exception + /// + [Fact (Skip = "API does not throw an exception")] + public void DeleteMediaNotFound() + { + ApiException exception = Assert.Throws(() => instance.DeleteMediaWithHttpInfo(accountId, "not-a-media-id.jpg")); + Assert.Equal(404, exception.ErrorCode); + } + } +} diff --git a/src/Bandwidth.Standard.Test/Integration/MessagesIntegrationTests.cs b/src/Bandwidth.Standard.Test/Integration/MessagesIntegrationTests.cs new file mode 100644 index 00000000..6f3fcbb8 --- /dev/null +++ b/src/Bandwidth.Standard.Test/Integration/MessagesIntegrationTests.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using Xunit; + +using Bandwidth.Standard.Client; +using Bandwidth.Standard.Api; +using Bandwidth.Standard.Model; +using System.Net; + +namespace Bandwidth.Standard.Test.Integration +{ + /// + /// Class for testing MessagesApi + /// + public class MessagesIntegrationTests : IDisposable + { + private string accountId; + private Configuration fakeConfiguration; + private MessagesApi forbiddenInstance; + private MessagesApi instance; + private MessageRequest messageRequest; + private MessagesApi unauthorizedInstance; + + public MessagesIntegrationTests() + { + accountId = Environment.GetEnvironmentVariable("BW_ACCOUNT_ID"); + + // Authorized API Client + fakeConfiguration = new Configuration(); + fakeConfiguration.BasePath = "https://messaging.bandwidth.com/api/v2"; + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME"); + fakeConfiguration.Password = Environment.GetEnvironmentVariable("BW_PASSWORD"); + instance = new MessagesApi(fakeConfiguration); + + // Unauthorized API Client + fakeConfiguration = new Configuration(); + fakeConfiguration.BasePath = "https://messaging.bandwidth.com/api/v2"; + fakeConfiguration.Username = "badUsername"; + fakeConfiguration.Password = "badPassword"; + unauthorizedInstance = new MessagesApi(fakeConfiguration); + + // Forbidden API Client + fakeConfiguration = new Configuration(); + fakeConfiguration.BasePath = "https://messaging.bandwidth.com/api/v2"; + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME_FORBIDDEN"); + fakeConfiguration.Password = Environment.GetEnvironmentVariable("BW_PASSWORD_FORBIDDEN"); + forbiddenInstance = new MessagesApi(fakeConfiguration); + + // Message Request + messageRequest = new MessageRequest( + applicationId: Environment.GetEnvironmentVariable("BW_MESSAGING_APPLICATION_ID"), + to: new List {Environment.GetEnvironmentVariable("USER_NUMBER") }, + from: Environment.GetEnvironmentVariable("BW_NUMBER"), + text: "c# integration test", + media: new List { "https://cdn2.thecatapi.com/images/MTY3ODIyMQ.jpg" }, + tag: "c# integration test", + priority: PriorityEnum.Default + ); + } + + public void Dispose() + { + // Cleanup when everything is done. + } + + /// + /// Test an instance of MessagesApi + /// + [Fact] + public void InstanceTest() + { + Assert.IsType(instance); + } + + /// + /// Test CreateMessage + /// + [Fact] + public void CreateMessageTest() + { + var response = instance.CreateMessageWithHttpInfo(accountId, messageRequest); + Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); + Assert.NotNull(response.Data.ApplicationId); + Assert.NotNull(response.Data.To); + Assert.NotNull(response.Data.From); + Assert.NotNull(response.Data.Owner); + Assert.NotNull(response.Data.Text); + Assert.NotNull(response.Data.Media); + Assert.NotNull(response.Data.Tag); + Assert.IsType(response.Data.Priority); + Assert.NotNull(response.Data.Priority); + Assert.Equal(1, response.Data.SegmentCount); + Assert.IsType(response.Data.Time); + } + + /// + /// Test CreateMessage with an invalid message request + /// + [Fact] + public void CreateMessageBadRequest() + { + messageRequest.ApplicationId = null; + ApiException Exception = Assert.Throws(() => instance.CreateMessage(accountId, messageRequest)); + Assert.Equal(400, Exception.ErrorCode); + } + + /// + /// Test CreateMessage with invalid media + /// + [Fact] + public void CreateMessageInvalidMedia() + { + messageRequest.Media = new List { "not media" }; + ApiException Exception = Assert.Throws(() => instance.CreateMessageWithHttpInfo(accountId, messageRequest)); + Assert.Equal(400, Exception.ErrorCode); + } + + /// + /// Test CreateMessage with an unauthorized client + /// + [Fact] + public void CreateMessageUnauthorizedRequest() + { + ApiException Exception = Assert.Throws(() => unauthorizedInstance.CreateMessage(accountId, messageRequest)); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test create message with a forbidden client + /// API does not throw an error + /// + [Fact (Skip = "API does not throw an error")] + public void CreateMessageForbiddenRequest() + { + ApiException Exception = Assert.Throws(() => forbiddenInstance.CreateMessage(accountId, messageRequest)); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test a successful ListMessages request + /// + [Fact] + public void ListMessagesTest() + { + var response = instance.ListMessagesWithHttpInfo( + accountId: accountId, + messageDirection: ListMessageDirectionEnum.OUTBOUND, + messageStatus: MessageStatusEnum.DELIVERED, + messageType: MessageTypeEnum.Sms + ); + Assert.IsType>(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotEqual(0, response.Data.TotalCount); + Assert.IsType>(response.Data.Messages); + Assert.IsType(response.Data.Messages[0]); + + var message = response.Data.Messages[0]; + Assert.Equal(accountId, message.AccountId); + Assert.Matches("^\\+[1-9]\\d{1,14}$", message.DestinationTn); + Assert.Equal(ListMessageDirectionEnum.OUTBOUND, message.MessageDirection); + Assert.Matches("^.+$", message.MessageId); + Assert.IsType(message.MessageStatus); + Assert.IsType(message.MessageType); + Assert.NotEqual(0, message.SegmentCount); + Assert.Matches("^\\+[1-9]\\d{1,14}$", message.SourceTn); + Assert.IsType(message.ReceiveTime); + } + + /// + /// Test ListMessages without any messages + /// + [Fact] + public void ListMessagesBadRequest() + { + ApiException Exception = Assert.Throws(() => instance.ListMessages(accountId)); + Assert.Equal(400, Exception.ErrorCode); + } + + /// + /// Test ListMessages with an unauthorized client + /// + [Fact] + public void ListMessagesUnauthorizedRequest() + { + ApiException Exception = Assert.Throws(() => unauthorizedInstance.ListMessages(accountId)); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test ListMessages with a forbidden client + /// API throws a 400 rather than a 401 + /// + [Fact (Skip = "API throws a 400 rather than a 401")] + public void ListMessagesForbiddenRequest() + { + ApiException Exception = Assert.Throws(() => forbiddenInstance.ListMessages(accountId)); + Assert.Equal(401, Exception.ErrorCode); + } + } +} diff --git a/src/Bandwidth.Standard.Test/Integration/PhoneNumberLookupIntegrationTests.cs b/src/Bandwidth.Standard.Test/Integration/PhoneNumberLookupIntegrationTests.cs new file mode 100644 index 00000000..864bdab0 --- /dev/null +++ b/src/Bandwidth.Standard.Test/Integration/PhoneNumberLookupIntegrationTests.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using Xunit; + +using Bandwidth.Standard.Client; +using Bandwidth.Standard.Api; +using Bandwidth.Standard.Model; +using System.Net; + +namespace Bandwidth.Standard.Test.Integration +{ + /// + /// Class for testing PhoneNumberLookupApi + /// + public class PhoneNumberLookupIntegrationTests : IDisposable + { + private string accountId; + private string BW_NUMBER; + private Configuration fakeConfiguration; + private PhoneNumberLookupApi forbiddenInstance; + private PhoneNumberLookupApi instance; + private string testRequestId; + private PhoneNumberLookupApi unauthorizedInstance; + + public PhoneNumberLookupIntegrationTests() + { + accountId = Environment.GetEnvironmentVariable("BW_ACCOUNT_ID"); + testRequestId = "test-request-id"; + BW_NUMBER = Environment.GetEnvironmentVariable("BW_NUMBER"); + + // Authorized API Client + fakeConfiguration = new Configuration(); + fakeConfiguration.BasePath = "https://voice.bandwidth.com/api/v2"; + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME"); + fakeConfiguration.Password = Environment.GetEnvironmentVariable("BW_PASSWORD"); + instance = new PhoneNumberLookupApi(fakeConfiguration); + + // Unauthorized API Client + fakeConfiguration.Username = "badUsername"; + fakeConfiguration.Password = "badPassword"; + unauthorizedInstance = new PhoneNumberLookupApi(fakeConfiguration); + + // Forbidden API Client + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME_FORBIDDEN"); + fakeConfiguration.Password = Environment.GetEnvironmentVariable("BW_PASSWORD_FORBIDDEN"); + forbiddenInstance = new PhoneNumberLookupApi(fakeConfiguration); + } + + public void Dispose() + { + // Cleanup when everything is done. + } + + /// + /// Test an instance of PhoneNumberLookupApi + /// + [Fact] + public void InstanceTest() + { + Assert.IsType(instance); + } + + /// + /// Test successful GetLookupStatus request + /// + [Fact] + public void GetLookupStatusTest() + { + LookupRequest lookupRequest = new LookupRequest(new List { BW_NUMBER }); + var response = instance.CreateLookupWithHttpInfo(accountId, lookupRequest); + + var lookupStatus = instance.GetLookupStatus(accountId, response.Data.RequestId); + Assert.IsType(lookupStatus); + Assert.Equal(response.Data.RequestId, lookupStatus.RequestId); + Assert.Equal(BW_NUMBER, lookupStatus.Result[0].E164Format); + } + + /// + /// Test GetLookupStatus with an unauthorized client + /// + [Fact] + public void GetLookupStatusUnauthorizedRequest() + { + ApiException Exception = Assert.Throws(() => unauthorizedInstance.GetLookupStatus(accountId, testRequestId)); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test GetLookupStatus with a forbidden client + /// API throws a 401 rather than the expected 403 + /// + [Fact] + public void GetLookupStatusForbiddenRequest() + { + ApiException Exception = Assert.Throws(() => forbiddenInstance.GetLookupStatus(accountId, testRequestId)); + // Assert.Equal(403, Exception.ErrorCode); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test successful CreateLookup request + /// + [Fact] + public void CreateLookupTest() + { + LookupRequest lookupRequest = new LookupRequest(new List { BW_NUMBER }); + var response = instance.CreateLookupWithHttpInfo(accountId, lookupRequest); + Assert.IsType>(response); + Assert.Equal(LookupStatusEnum.INPROGRESS, response.Data.Status); + Assert.IsType(response.Data.RequestId); + Assert.Matches("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", response.Data.RequestId); + Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); + + var lookupStatus = instance.GetLookupStatus(accountId, response.Data.RequestId); + Assert.IsType(lookupStatus); + Assert.Equal(response.Data.RequestId, lookupStatus.RequestId); + Assert.Equal(BW_NUMBER, lookupStatus.Result[0].E164Format); + + } + + /// + /// Test CreateLookup with a bad request + /// + [Fact] + public void CreateLookupBadRequest() + { + LookupRequest lookupRequest = new LookupRequest(new List { "not a number" }); + ApiException exception = Assert.Throws(() => instance.CreateLookup(accountId, lookupRequest)); + var error = new TnLookupRequestError(exception.Message); + Assert.IsType(error); + Assert.Equal(400, exception.ErrorCode); + + } + + /// + /// Test CreateLookup with a duplicate phone number lookup + /// + [Fact] + public void CreateLookupDuplicateRequest() + { + LookupRequest lookupRequest = new LookupRequest(new List { BW_NUMBER, BW_NUMBER }); + ApiException Exception = Assert.Throws(() => instance.CreateLookup(accountId, lookupRequest)); + Assert.Equal(400, Exception.ErrorCode); + Assert.IsType(Exception.Message); + } + + /// + /// Test CreateLookup with an unauthorized client + /// + [Fact] + public void CreateLookupUnauthorizedRequest() + { + LookupRequest lookupRequest = new LookupRequest(new List { BW_NUMBER }); + ApiException Exception = Assert.Throws(() => unauthorizedInstance.CreateLookup(accountId, lookupRequest)); + Assert.Equal(401, Exception.ErrorCode); + } + + /// + /// Test CreateLookup with a forbidden client + /// + [Fact] + public void CreateLookupForbiddenRequest() + { + LookupRequest lookupRequest = new LookupRequest(new List { BW_NUMBER }); + ApiException Exception = Assert.Throws(() => forbiddenInstance.CreateLookup(accountId, lookupRequest)); + //This API throws a 401 when a user provides valid credentials with the `TN Lookup` role disabled + // Assert.Equal(403, Exception.ErrorCode); + Assert.Equal(401, Exception.ErrorCode); + } + } +} diff --git a/src/Bandwidth.Standard.Test/Integration/RecordingsIntegrationTests.cs b/src/Bandwidth.Standard.Test/Integration/RecordingsIntegrationTests.cs new file mode 100644 index 00000000..c3bde7f3 --- /dev/null +++ b/src/Bandwidth.Standard.Test/Integration/RecordingsIntegrationTests.cs @@ -0,0 +1,605 @@ +using System; +using System.Collections.Generic; +using Xunit; + +using Bandwidth.Standard.Client; +using Bandwidth.Standard.Api; +using Bandwidth.Standard.Model; +using System.Net; +using System.Text.Json; +using Newtonsoft.Json.Linq; + +namespace Bandwidth.Standard.Test.Integration +{ + /// + /// Class for testing RecordingsApi + /// + public class RecordingsIntegrationTests : IDisposable + { + private RecordingsApi recordingApiInstance; + private CallsApi callsApiInstance; + private RecordingsApi unauthorizedInstance; + private RecordingsApi forbiddenInstance; + private Configuration fakeConfiguration; + private ApiClient restClient; + private CreateCall mantecaCallBody; + private TranscribeRecording testTranscribeRecording; + private string accountId; + private string testCallId; + private string testRecordingId; + private string BW_USERNAME; + private string BW_PASSWORD; + private string MANTECA_ACTIVE_NUMBER; + private string MANTECA_IDLE_NUMBER; + private string MANTECA_APPLICATION_ID; + private string MANTECA_BASE_URL; + private string BW_FORBIDDEN_USERNAME; + private string BW_FORBIDDEN_PASSWORD; + + public RecordingsIntegrationTests() + { + accountId = Environment.GetEnvironmentVariable("BW_ACCOUNT_ID"); + testCallId = "callId"; + testRecordingId = "recordingId"; + BW_USERNAME = Environment.GetEnvironmentVariable("BW_USERNAME"); + BW_PASSWORD = Environment.GetEnvironmentVariable("BW_PASSWORD"); + MANTECA_ACTIVE_NUMBER = Environment.GetEnvironmentVariable("MANTECA_ACTIVE_NUMBER"); + MANTECA_IDLE_NUMBER = Environment.GetEnvironmentVariable("MANTECA_IDLE_NUMBER"); + MANTECA_APPLICATION_ID = Environment.GetEnvironmentVariable("MANTECA_APPLICATION_ID"); + MANTECA_BASE_URL = Environment.GetEnvironmentVariable("MANTECA_BASE_URL"); + BW_FORBIDDEN_USERNAME = Environment.GetEnvironmentVariable("BW_USERNAME_FORBIDDEN"); + BW_FORBIDDEN_PASSWORD = Environment.GetEnvironmentVariable("BW_PASSWORD_FORBIDDEN"); + + //API Client + fakeConfiguration = new Configuration(); + fakeConfiguration.BasePath = "https://voice.bandwidth.com/api/v2"; + fakeConfiguration.Username = BW_USERNAME; + fakeConfiguration.Password = BW_PASSWORD; + recordingApiInstance = new RecordingsApi(fakeConfiguration); + callsApiInstance = new CallsApi(fakeConfiguration); + + // Unauthorized API Client + fakeConfiguration.Username = "badUsername"; + fakeConfiguration.Password = "badPassword"; + unauthorizedInstance = new RecordingsApi(fakeConfiguration); + + // Forbidden API Client + fakeConfiguration.Username = BW_FORBIDDEN_USERNAME; + fakeConfiguration.Password = BW_FORBIDDEN_PASSWORD; + forbiddenInstance = new RecordingsApi(fakeConfiguration); + + restClient = new ApiClient(basePath: "https://voice.bandwidth.com/api/v2"); + + mantecaCallBody = new CreateCall( + to: MANTECA_IDLE_NUMBER, + from: MANTECA_ACTIVE_NUMBER, + applicationId: MANTECA_APPLICATION_ID, + answerUrl: MANTECA_BASE_URL + "/bxml/joinConferencePause" + ); + + testTranscribeRecording = new TranscribeRecording( + callbackUrl: MANTECA_BASE_URL + "/transcriptions", + tag: "test" + ); + } + + public void Dispose() + { + // Cleanup when everything is done. + } + + /// + /// Test an instance of RecordingsApi + /// + [Fact] + public void InstanceTest() + { + Assert.IsType(recordingApiInstance); + } + + /// + /// Create and validate a call between two bandwidth numbers. Initializes the call with the Manteca system. + /// + /// + /// A tuple containing the test id created in Manteca to track this call, as well as the call id for the created call. + /// + [Fact] + public Tuple CreateAndValidateCall() + { + var jsonBody = JsonSerializer.Serialize(new + { + os = Environment.GetEnvironmentVariable("OPERATING_SYSTEM"), + language = "csharp" + Environment.GetEnvironmentVariable("CSHARP_VERSION"), + type = "CALL" + }); + var options = new RequestOptions + { + Data = jsonBody, + HeaderParameters = new Multimap + { + { "Content-Type", "application/json" } + } + }; + + // initialize call with Manteca + var response = restClient.Post( + path: Environment.GetEnvironmentVariable("MANTECA_BASE_URL") + "/tests", + options: options + ); + + var testId = response.RawContent; + mantecaCallBody.Tag = testId; + + var createCallResponse = callsApiInstance.CreateCallWithHttpInfo(accountId, mantecaCallBody); + Assert.Equal(47, createCallResponse.Data.CallId.Length); + Assert.Equal(accountId, createCallResponse.Data.AccountId); + Assert.Equal(MANTECA_APPLICATION_ID, createCallResponse.Data.ApplicationId); + Assert.Equal(MANTECA_IDLE_NUMBER, createCallResponse.Data.To); + Assert.Equal(MANTECA_ACTIVE_NUMBER, createCallResponse.Data.From); + Assert.Equal("https://voice.bandwidth.com/api/v2/accounts/" + accountId + "/calls/" + createCallResponse.Data.CallId, createCallResponse.Data.CallUrl); + + return new Tuple(testId, createCallResponse.Data.CallId); + } + + /// + /// Creates and completes an entire recorded call lifecycle. A call should be completed and fully recorded. + /// + /// + /// A tuple containing the test id to track this call in the Manteca system and the call id associated with the call in Bandwidth services. + /// + public Tuple CompleteRecordedCall() + { + mantecaCallBody.AnswerUrl = MANTECA_BASE_URL + "/bxml/startRecording"; + Tuple createCallResponse = CreateAndValidateCall(); + var testId = createCallResponse.Item1; + var callId = createCallResponse.Item2; + + System.Threading.Thread.Sleep(12000); + var callStatus = GetTestStatus(testId); + JObject callStatusJson = JObject.Parse(callStatus); + var retryCounter = 0; + + while(!(Boolean)callStatusJson["callRecorded"] && retryCounter < 40) + { + System.Threading.Thread.Sleep(5000); + callStatus = GetTestStatus(testId); + callStatusJson = JObject.Parse(callStatus); + retryCounter++; + } + + Assert.True((Boolean)callStatusJson["callRecorded"]); + + return(new Tuple (testId,callId)); + + } + + /// + /// Get the status of the specified test by its id value from Manteca services. + /// + /// The test id associated with the test to get the status of. + /// + /// A string containing the status of the test requested. + /// + public string GetTestStatus(string testId) + { + var options = new RequestOptions + { + HeaderParameters = new Multimap + { + { "Content-Type", "text/plain" } + } + }; + + // get test status from Manteca + var response = restClient.Get( + path: Environment.GetEnvironmentVariable("MANTECA_BASE_URL") + "/tests/" + testId, + options: options + ); + + return response.Content.ToString(); + } + + /// + /// Tests a successful flow of creating a call with a recording. + /// + [Fact] + public void TestSuccessfulCallRecording() + { + Tuple recordedCallResponse = CompleteRecordedCall(); + var testId = recordedCallResponse.Item1; + var callId = recordedCallResponse.Item2; + + var listCallResponse = recordingApiInstance.ListCallRecordingsWithHttpInfo(accountId,callId); + Assert.Equal(HttpStatusCode.OK, listCallResponse.StatusCode); + + List callRecording = listCallResponse.Data; + Assert.Single(callRecording); + + var firstRecording = callRecording[0]; + Assert.Equal(accountId, firstRecording.AccountId); + Assert.Equal(callId, firstRecording.CallId); + Assert.Equal(MANTECA_APPLICATION_ID, firstRecording.ApplicationId); + Assert.Equal("complete", firstRecording.Status); + Assert.Equal(FileFormatEnum.Wav, firstRecording.FileFormat); + + var firstRecordingId = firstRecording.RecordingId; + + var getCallRecordingResponse = recordingApiInstance.GetCallRecordingWithHttpInfo(accountId, callId, firstRecordingId); + Assert.Equal(HttpStatusCode.OK, getCallRecordingResponse.StatusCode); + + var recording = getCallRecordingResponse.Data; + Assert.Equal(firstRecordingId, recording.RecordingId); + Assert.Equal(accountId, recording.AccountId); + Assert.Equal(callId, recording.CallId); + Assert.Equal(MANTECA_APPLICATION_ID, recording.ApplicationId); + Assert.Equal("complete", recording.Status); + Assert.Equal(FileFormatEnum.Wav, recording.FileFormat); + + var downloadCallRecordingResponse = recordingApiInstance.DownloadCallRecordingWithHttpInfo(accountId, callId, firstRecordingId); + var transcribeRecordingRequest = new TranscribeRecording( + callbackUrl: MANTECA_BASE_URL + "/transcriptions", + tag: testId + ); + var transcribeCallRecording = recordingApiInstance.TranscribeCallRecordingWithHttpInfo(accountId, callId, firstRecordingId, transcribeRecordingRequest); + Assert.Equal(HttpStatusCode.NoContent, transcribeCallRecording.StatusCode); + + var callStatus = GetTestStatus(testId); + var retries = 0; + JObject callStatusJson = JObject.Parse(callStatus); + while(!(Boolean)callStatusJson["callTranscribed"] && retries < 40) + { + System.Threading.Thread.Sleep(5000); + callStatus = GetTestStatus(testId); + callStatusJson = JObject.Parse(callStatus); + retries++; + } + Assert.True((Boolean)callStatusJson["callTranscribed"]); + var transcriptionResponse = recordingApiInstance.GetCallTranscriptionWithHttpInfo(accountId, callId, firstRecordingId); + Assert.Equal(HttpStatusCode.OK, transcriptionResponse.StatusCode); + + var transcription = transcriptionResponse.Data; + Assert.Single(transcription.Transcripts); + + var firstTranscript = transcription.Transcripts[0]; + Assert.IsType(firstTranscript); + Assert.IsType(firstTranscript.Text); + Assert.IsType(firstTranscript.Confidence); + + // delete transcription + var deleteTranscriptionResponse = recordingApiInstance.DeleteCallTranscriptionWithHttpInfo(accountId, callId, firstRecordingId); + Assert.Equal(HttpStatusCode.NoContent, deleteTranscriptionResponse.StatusCode); + + // making sure transcription is deleted + ApiException exception = Assert.Throws(() => recordingApiInstance.GetCallTranscription(accountId, callId, firstRecordingId)); + Assert.Equal(404, exception.ErrorCode); + + var deleteRecordingMediaResponse = recordingApiInstance.DeleteRecordingMediaWithHttpInfo(accountId, callId, firstRecordingId); + Assert.Equal(HttpStatusCode.NoContent, deleteRecordingMediaResponse.StatusCode); + + // Delete recording + var deleteRecordingResponse = recordingApiInstance.DeleteRecordingWithHttpInfo(accountId, callId, firstRecordingId); + Assert.Equal(HttpStatusCode.NoContent, deleteRecordingResponse.StatusCode); + var callRecordings = recordingApiInstance.ListCallRecordings(accountId, callId); + Assert.Empty(callRecordings); + } + + /// + /// Tests a successful UpdateCallRecordingState request + /// + [Fact] + public void TestSuccessfulUpdateActiveRecording() + { + mantecaCallBody.AnswerUrl = MANTECA_BASE_URL + "/bxml/startLongRecording"; + Tuple createCallResponse = CreateAndValidateCall(); + var testId = createCallResponse.Item1; + var callId = createCallResponse.Item2; + + + var callStatus = GetTestStatus(testId); + JObject callStatusJson = JObject.Parse(callStatus); + var retryCounter = 0; + + while((string)callStatusJson["status"] == "DEAD" && retryCounter < 40) + { + System.Threading.Thread.Sleep(5000); + callStatus = GetTestStatus(testId); + callStatusJson = JObject.Parse(callStatus); + retryCounter++; + } + + Assert.Equal("ALIVE", (string)callStatusJson["status"]); + + System.Threading.Thread.Sleep(5000); + + var updateCallRecording = new UpdateCallRecording(state: RecordingStateEnum.Paused); + var updateCallRecordingResponse = recordingApiInstance.UpdateCallRecordingStateWithHttpInfo(accountId, callId, updateCallRecording); + Assert.Equal(HttpStatusCode.OK, updateCallRecordingResponse.StatusCode); + + // Update the call to resume the recording + updateCallRecording.State = RecordingStateEnum.Recording; + updateCallRecordingResponse = recordingApiInstance.UpdateCallRecordingStateWithHttpInfo(accountId, callId, updateCallRecording); + Assert.Equal(HttpStatusCode.OK, updateCallRecordingResponse.StatusCode); + + // End the call + var updateCallBody = new UpdateCall(state: CallStateEnum.Completed); + callsApiInstance.UpdateCall(accountId, callId, updateCallBody); + } + + /// + /// Test ListCallRecordings with an unauthorized client + /// + [Fact] + public void ListCallRecordingsUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.ListCallRecordingsWithHttpInfo(accountId, testCallId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test ListCallRecordings with a forbidden client + /// + [Fact] + public void ListCallRecordingsForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.ListCallRecordingsWithHttpInfo(accountId, testCallId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test ListCallRecordings with a nonexistent call id + /// The API returns an empty list rather than a 404 + /// + [Fact] + public void listCallRecordingsNotFound() + { + // exception = Assert.Throws(() => recordingApiInstance.ListCallRecordingsWithHttpInfo(accountId, "not-a-call-id")); + // Assert.Equal(404, exception.ErrorCode); + var callRecordings = recordingApiInstance.ListCallRecordings(accountId, "not-a-call-id"); + Assert.Empty(callRecordings); + } + + /// + /// Test GetCallRecording with an unauthorized client + /// + [Fact] + public void GetCallRecordingUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.GetCallRecordingWithHttpInfo(accountId, testCallId, testRecordingId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test GetCallRecording with a forbidden client + /// + [Fact] + public void GetCallRecordingForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.GetCallRecordingWithHttpInfo(accountId, testCallId, testRecordingId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test GetCallRecording with a nonexistent call id + /// + [Fact] + public void GetCallRecordingNotFound() + { + ApiException exception = Assert.Throws(() => recordingApiInstance.GetCallRecordingWithHttpInfo(accountId, testCallId, "not-a-recording-id")); + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test DownloadCallRecording with an unauthorized client + /// + [Fact] + public void DownloadCallRecordingUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.DownloadCallRecordingWithHttpInfo(accountId, testCallId, testRecordingId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test DownloadCallRecording with a forbidden client + /// + [Fact] + public void DownloadCallRecordingForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.DownloadCallRecordingWithHttpInfo(accountId, testCallId, testRecordingId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test DownloadCallRecording with a nonexistent recording id + /// + [Fact] + public void DownloadCallRecordingNotFound() + { + ApiException exception = Assert.Throws(() => recordingApiInstance.DownloadCallRecordingWithHttpInfo(accountId, testCallId, "not-a-recording-id")); + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test TranscribeCallRecording with an unauthorized client + /// + [Fact] + public void TranscribeCallRecordingUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.TranscribeCallRecordingWithHttpInfo(accountId, testCallId, testRecordingId, testTranscribeRecording)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test TranscribeCallRecording with a forbidden client + /// + [Fact] + public void TranscribeCallRecordingForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.TranscribeCallRecordingWithHttpInfo(accountId, testCallId, testRecordingId, testTranscribeRecording)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test TranscribeCallRecording with a nonexistent recording id + /// The API returns a 500 error rather than a 404 + /// + [Fact(Skip = "This test returns a 500 error rather than a 404")] + public void TranscribeCallRecordingNotFound() + { + ApiException exception = Assert.Throws(() => recordingApiInstance.TranscribeCallRecordingWithHttpInfo(accountId, testCallId, "not-a-recording-id", testTranscribeRecording)); + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test GetCallTranscription with an unauthorized client + /// + [Fact] + public void GetCallTranscriptionUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.GetCallTranscriptionWithHttpInfo(accountId, testCallId, testRecordingId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test GetCallTranscription with a forbidden client + /// + [Fact] + public void GetCallTranscriptionForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.GetCallTranscriptionWithHttpInfo(accountId, testCallId, testRecordingId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test GetCallTranscription with a nonexistent recording id + /// + [Fact] + public void GetCallTranscriptionNotFound() + { + ApiException exception = Assert.Throws(() => recordingApiInstance.GetCallTranscriptionWithHttpInfo(accountId, testCallId, "not-a-recording-id")); + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test DeleteCallTranscription with an unauthorized client + /// + [Fact] + public void DeleteCallTranscriptionUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.DeleteCallTranscriptionWithHttpInfo(accountId, testCallId, testRecordingId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test DeleteCallTranscription with a forbidden client + /// + [Fact] + public void DeleteCallTranscriptionForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.DeleteCallTranscriptionWithHttpInfo(accountId, testCallId, testRecordingId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test DeleteCallTranscription with a nonexistent recording id + /// + [Fact] + public void DeleteCallTranscriptionNotFound() + { + ApiException exception = Assert.Throws(() => recordingApiInstance.DeleteCallTranscriptionWithHttpInfo(accountId, testCallId, "not-a-recording-id")); + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test DeleteRecordingMedia with an unauthorized client + /// + [Fact] + public void DeleteRecordingMediaUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.DeleteRecordingMediaWithHttpInfo(accountId, testCallId, testRecordingId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test DeleteRecordingMedia with a forbidden client + /// + [Fact] + public void DeleteRecordingMediaForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.DeleteRecordingMediaWithHttpInfo(accountId, testCallId, testRecordingId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test DeleteRecordingMedia with a nonexistent recording id + /// + [Fact] + public void DeleteRecordingMediaNotFound() + { + ApiException exception = Assert.Throws(() => recordingApiInstance.DeleteRecordingMediaWithHttpInfo(accountId, testCallId, "not-a-recording-id")); + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test DeleteRecording with an unauthorized client + /// + [Fact] + public void DeleteRecordingUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.DeleteRecordingWithHttpInfo(accountId, testCallId, testRecordingId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test DeleteRecording with a forbidden client + /// + [Fact] + public void DeleteRecordingForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.DeleteRecordingWithHttpInfo(accountId, testCallId, testRecordingId)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test DeleteRecording with a nonexistent recording id + /// + [Fact] + public void DeleteRecordingNotFound() + { + ApiException exception = Assert.Throws(() => recordingApiInstance.DeleteRecordingWithHttpInfo(accountId, testCallId, "not-a-recording-id")); + Assert.Equal(404, exception.ErrorCode); + } + + /// + /// Test UpdateCallRecordingState with an unauthorized client + /// + [Fact] + public void UpdateCallRecordingStateUnauthorizedRequest() + { + var updateCallRecording = new UpdateCallRecording(state: RecordingStateEnum.Paused); + ApiException exception = Assert.Throws(() => unauthorizedInstance.UpdateCallRecordingStateWithHttpInfo(accountId, testCallId, updateCallRecording)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Test UpdateCallRecordingState with a forbidden client + /// + [Fact] + public void UpdateCallRecordingStateForbiddenRequest() + { + var updateCallRecording = new UpdateCallRecording(state: RecordingStateEnum.Paused); + ApiException exception = Assert.Throws(() => forbiddenInstance.UpdateCallRecordingStateWithHttpInfo(accountId, testCallId, updateCallRecording)); + Assert.Equal(403, exception.ErrorCode); + } + + /// + /// Test UpdateCallRecordingState with a nonexistent call id + /// + [Fact] + public void UpdateCallRecordingStateNotFound() + { + var updateCallRecording = new UpdateCallRecording(state: RecordingStateEnum.Paused); + ApiException exception = Assert.Throws(() => recordingApiInstance.UpdateCallRecordingStateWithHttpInfo(accountId, "not-a-call-id", updateCallRecording)); + Assert.Equal(404, exception.ErrorCode); + } + } +} diff --git a/src/Bandwidth.Standard.Test/Integration/StatisticsIntegrationTests.cs b/src/Bandwidth.Standard.Test/Integration/StatisticsIntegrationTests.cs new file mode 100644 index 00000000..1aeba693 --- /dev/null +++ b/src/Bandwidth.Standard.Test/Integration/StatisticsIntegrationTests.cs @@ -0,0 +1,99 @@ +/* + * Bandwidth + * + * Bandwidth's Communication APIs + * + * The version of the OpenAPI document: 1.0.0 + * Contact: letstalk@bandwidth.com + * Generated by: https://github.com/openapitools/openapi-generator.git + */ + +using System; +using Xunit; + +using Bandwidth.Standard.Client; +using Bandwidth.Standard.Api; +using Bandwidth.Standard.Model; +using System.Net; + +namespace Bandwidth.Standard.Test.Integration +{ + /// + /// Class for testing StatisticsApi + /// + public class StatisticsIntegrationTests : IDisposable + { + private string accountId; + private Configuration fakeConfiguration; + private StatisticsApi forbiddenInstance; + private StatisticsApi instance; + private StatisticsApi unauthorizedInstance; + + public StatisticsIntegrationTests() + { + accountId = Environment.GetEnvironmentVariable("BW_ACCOUNT_ID"); + + // Authorized API Client + fakeConfiguration = new Configuration(); + fakeConfiguration.BasePath = "https://voice.bandwidth.com/api/v2"; + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME"); + fakeConfiguration.Password = Environment.GetEnvironmentVariable("BW_PASSWORD"); + instance = new StatisticsApi(fakeConfiguration); + + // Unauthorized API Client + fakeConfiguration.Username = "badUsername"; + fakeConfiguration.Password = "badPassword"; + unauthorizedInstance = new StatisticsApi(fakeConfiguration); + + // Forbidden API Client + fakeConfiguration.Username = Environment.GetEnvironmentVariable("BW_USERNAME_FORBIDDEN"); + fakeConfiguration.Password = Environment.GetEnvironmentVariable("BW_PASSWORD_FORBIDDEN"); + forbiddenInstance = new StatisticsApi(fakeConfiguration); + } + + public void Dispose() + { + // Cleanup when everything is done. + } + + /// + /// Test an instance of StatisticsApi + /// + [Fact] + public void InstanceTest() + { + Assert.IsType(instance); + } + + /// + /// Test successful GetStatistics + /// + [Fact] + public void GetStatisticsTest() + { + var response = instance.GetStatisticsWithHttpInfo(accountId); + Assert.IsType>(response); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + /// + /// Tests GetStatistics with an unauthorized client + /// + [Fact] + public void GetStatisticsUnauthorizedRequest() + { + ApiException exception = Assert.Throws(() => unauthorizedInstance.GetStatisticsWithHttpInfo(accountId)); + Assert.Equal(401, exception.ErrorCode); + } + + /// + /// Tests GetStatistics with a forbidden client + /// + [Fact] + public void GetStatisticsForbiddenRequest() + { + ApiException exception = Assert.Throws(() => forbiddenInstance.GetStatisticsWithHttpInfo(accountId)); + Assert.Equal(403, exception.ErrorCode); + } + } +}