From c2916025faa23b20863273121991c84086c1cdb3 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 12 Jun 2023 17:18:17 -0400 Subject: [PATCH 1/9] SWI-2789 Added Start/Stop Transcription --- .../voice/bxml/verbs/CustomParam.java | 29 ++++ .../voice/bxml/verbs/StartTranscription.java | 139 ++++++++++++++++++ .../voice/bxml/verbs/StopTranscription.java | 22 +++ src/test/java/com/bandwidth/BxmlTest.java | 47 ++++++ 4 files changed, 237 insertions(+) create mode 100644 src/main/java/com/bandwidth/voice/bxml/verbs/CustomParam.java create mode 100644 src/main/java/com/bandwidth/voice/bxml/verbs/StartTranscription.java create mode 100644 src/main/java/com/bandwidth/voice/bxml/verbs/StopTranscription.java diff --git a/src/main/java/com/bandwidth/voice/bxml/verbs/CustomParam.java b/src/main/java/com/bandwidth/voice/bxml/verbs/CustomParam.java new file mode 100644 index 00000000..e4600629 --- /dev/null +++ b/src/main/java/com/bandwidth/voice/bxml/verbs/CustomParam.java @@ -0,0 +1,29 @@ + +package com.bandwidth.voice.bxml.verbs; + +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.XmlValue; +import javax.xml.bind.annotation.XmlAttribute; +import lombok.Builder; + +/** + * You may specify up to 12 elements nested within a tag. These elements define optional user specified parameters that will be sent to the destination URL when the real-time transcription is first started. + */ +@Builder +@XmlType(name = CustomParam.TYPE_NAME) +public class CustomParam implements Verb { + public static final String TYPE_NAME = "CustomParam"; + + /** + * (required) The name of this parameter, up to 256 characters. + */ + @XmlAttribute + private String name; + + /** + * (required) The value of this parameter, up to 2048 characters. + */ + @XmlValue + private String value; + +} diff --git a/src/main/java/com/bandwidth/voice/bxml/verbs/StartTranscription.java b/src/main/java/com/bandwidth/voice/bxml/verbs/StartTranscription.java new file mode 100644 index 00000000..d384ba45 --- /dev/null +++ b/src/main/java/com/bandwidth/voice/bxml/verbs/StartTranscription.java @@ -0,0 +1,139 @@ + +package com.bandwidth.voice.bxml.verbs; + +import lombok.Builder; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.XmlElement; + + +/** + * The StartTranscription verb allows a segment of a call to be transcribed and optionally for the live transcription to be sent off to another destination for additional processing. + */ +@Builder +@XmlType(name = StartTranscription.TYPE_NAME) +public class StartTranscription implements Verb { + public static final String TYPE_NAME = "StartTranscription"; + + @XmlElement(name = CustomParam.TYPE_NAME) + private final List customParams; + + /** + * (optional) A name to refer to this transcription by. Used when sending . If not provided, it will default to the generated transcription id as sent in the Real-Time Transcription Started webhook. + */ + @XmlAttribute + private String name; + + /** + * (optional) the part of the call to send a transcription from. `inbound`, `outbound` or `both`. default is `inbound`. + */ + @XmlAttribute + private String tracks; + + /** + * (optional) a websocket uri to send the real-time transcription to. the audio from the specified tracks will be sent via websocket to this url encoded as base64 encoded pcmu/g711 audio. see below for more details on the websocket packet format. + */ + @XmlAttribute + private URI destination; + + /** + * (optional) Whether to send transcription update events to the specified destination only after they have become stable. Requires destination. Defaults to true. + */ + @XmlAttribute + private Boolean stabilized; + + /** + * (optional) url to send the associated webhook events to during this real-time transcription's lifetime. Does not accept bxml. May be a relative URL. + */ + @XmlAttribute + private URI transcriptionEventUrl; + + /** + * (optional) the http method to use for the request to `transcriptioneventurl`. get or post. default value is post. + */ + @XmlAttribute + private Method transcriptionEventMethod; + + /** + * (optional) the username to send in the http request to `transcriptioneventurl`. if specified, the urls must be tls-encrypted (i.e., `https`). + */ + @XmlAttribute + protected String username; + + /** + * (optional) the password to send in the http request to `transcriptioneventurl`. if specified, the urls must be tls-encrypted (i.e., `https`). + */ + @XmlAttribute + protected String password; + + + public static class StartTranscriptionBuilder { + + /** + * (optional) url to send the associated webhook events to during this real-time transcription's lifetime. does not accept bxml. may be a relative url. + */ + public StartTranscriptionBuilder transcriptionEventUrl(URI uri ){ + this.transcriptionEventUrl = uri; + return this; + } + + /** + * (optional) url to send the associated webhook events to during this real-time transcription's lifetime. does not accept bxml. may be a relative url. + */ + public StartTranscriptionBuilder transcriptionEventUrl(String uri ){ + return transcriptionEventUrl(URI.create(uri)); + } + + /** + * (required) a websocket uri to send the real-time transcription to. the audio from the specified tracks will be sent via websocket to this url encoded as base64 encoded pcmu/g711 audio. see below for more details on the websocket packet format. + */ + public StartTranscriptionBuilder destination(URI uri ){ + this.destination = uri; + return this; + } + + /** + * (optional) a websocket uri to send the real-time transcription to. the audio from the specified tracks will be sent via websocket to this url encoded as base64 encoded pcmu/g711 audio. see below for more details on the websocket packet format. + */ + public StartTranscriptionBuilder destination(String uri ){ + return destination(URI.create(uri)); + } + + /** + * (optional) the http method to use for the request to `transcriptioneventurl`. get or post. default value is post. + */ + public StartTranscriptionBuilder transcriptionEventMethod(Method method){ + this.transcriptionEventMethod = method; + return this; + } + + /** + * (optional) the http method to use for the request to `transcriptionEventUrl`. GET or POST. Default value is POST. + */ + public StartTranscriptionBuilder transcriptionEventMethod(String method){ + return transcriptionEventMethod(Method.fromValue(method)); + } + + /** + * (optional) you may specify up to 12 elements nested within a tag. these elements define optional user specified parameters that will be sent to the destination url when the real-time transcription is first started. + */ + public StartTranscriptionBuilder customParams(CustomParam ... customParams){ + this.customParams = Arrays.asList(customParams); + return this; + } + + /** + * (optional) you may specify up to 12 elements nested within a tag. these elements define optional user specified parameters that will be sent to the destination url when the real-time transcription is first started. + */ + public StartTranscriptionBuilder customParams(List customParams){ + this.customParams = customParams; + return this; + } + } +} diff --git a/src/main/java/com/bandwidth/voice/bxml/verbs/StopTranscription.java b/src/main/java/com/bandwidth/voice/bxml/verbs/StopTranscription.java new file mode 100644 index 00000000..55e0058f --- /dev/null +++ b/src/main/java/com/bandwidth/voice/bxml/verbs/StopTranscription.java @@ -0,0 +1,22 @@ + +package com.bandwidth.voice.bxml.verbs; + +import lombok.Builder; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlType; + + +/** + * The Stoptranscription verb is used to stop the real-time transcription previously started by a `` verb. + */ +@Builder +@XmlType(name = StopTranscription.TYPE_NAME) +public class StopTranscription implements Verb { + public static final String TYPE_NAME = "StopTranscription"; + + /** + * (required) The name of the real-time transcription to stop. This is either the user selected name when sending the verb, or the system generated name returned in the Real-Time Transcription Started webhook if was sent with no name attribute. If no name is specified, then all active call transcriptions will be stopped. + */ + @XmlAttribute + private String name; +} diff --git a/src/test/java/com/bandwidth/BxmlTest.java b/src/test/java/com/bandwidth/BxmlTest.java index f59658a6..a928d421 100644 --- a/src/test/java/com/bandwidth/BxmlTest.java +++ b/src/test/java/com/bandwidth/BxmlTest.java @@ -583,4 +583,51 @@ public void testGenerateBxmlVerb() { + ""; assertEquals("BXML strings are equal", expected, response); } + + @Test + public void testStartTranscriptionBxmlVerb() { + CustomParam customParam1 = CustomParam.builder() + .name("name1") + .value("value1") + .build(); + CustomParam customParam2 = CustomParam.builder() + .name("name2") + .value("value2") + .build(); + ArrayList customParams = new ArrayList(); + customParams.add(customParam1); + customParams.add(customParam2); + StartTranscription startTranscription = StartTranscription.builder() + .destination("https://url.com") + .transcriptionEventMethod("POST") + .username("user") + .password("pass") + .name("test_transcription") + .tracks("inbound") + .transcriptionEventUrl("https://url.com") + .customParams(customParams) + .build(); + + String response = new Response() + .add(startTranscription) + .toBXML(); + + String expected = " "; + assertEquals("BXML strings are equal", expected, response); + } + + @Test + public void testStopTranscription() { + StopTranscription stopTranscription = StopTranscription.builder() + .name("test") + .build(); + + String response = new Response() + .add(stopTranscription) + .toBXML(); + + String expected = ""; + + assertEquals("BXML strings not equal", expected, response); + } } From 7ff24307df27fb29455aaf564be2e961a48e8c7b Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 13 Jun 2023 09:08:08 -0400 Subject: [PATCH 2/9] Updated BXML/Response Models --- src/main/java/com/bandwidth/voice/bxml/verbs/Bxml.java | 6 +++++- src/main/java/com/bandwidth/voice/bxml/verbs/Response.java | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bandwidth/voice/bxml/verbs/Bxml.java b/src/main/java/com/bandwidth/voice/bxml/verbs/Bxml.java index b76c76bf..ce1631a7 100644 --- a/src/main/java/com/bandwidth/voice/bxml/verbs/Bxml.java +++ b/src/main/java/com/bandwidth/voice/bxml/verbs/Bxml.java @@ -48,7 +48,11 @@ public class Bxml { @XmlElement(name = SipUri.TYPE_NAME, type = SipUri.class), @XmlElement(name = StartStream.TYPE_NAME, type = StartStream.class), @XmlElement(name = StopStream.TYPE_NAME, type = StopStream.class), - @XmlElement(name = StreamParam.TYPE_NAME, type = StreamParam.class) + @XmlElement(name = StreamParam.TYPE_NAME, type = StreamParam.class), + @XmlElement(name = StartTranscription.TYPE_NAME, type = StartTranscription.class), + @XmlElement(name = StopTranscription.TYPE_NAME, type = StopTranscription.class), + @XmlElement(name = CustomParam.TYPE_NAME, type = CustomParam.class), + }) private final List verbs = new ArrayList<>(); diff --git a/src/main/java/com/bandwidth/voice/bxml/verbs/Response.java b/src/main/java/com/bandwidth/voice/bxml/verbs/Response.java index e4b5f629..ebbd31a1 100644 --- a/src/main/java/com/bandwidth/voice/bxml/verbs/Response.java +++ b/src/main/java/com/bandwidth/voice/bxml/verbs/Response.java @@ -47,7 +47,12 @@ public class Response { @XmlElement(name = Tag.TYPE_NAME, type = Tag.class), @XmlElement(name = SipUri.TYPE_NAME, type = SipUri.class), @XmlElement(name = StartStream.TYPE_NAME, type = StartStream.class), - @XmlElement(name = StopStream.TYPE_NAME, type = StopStream.class) + @XmlElement(name = StopStream.TYPE_NAME, type = StopStream.class), + @XmlElement(name = StartTranscription.TYPE_NAME, type = StartTranscription.class), + @XmlElement(name = StopTranscription.TYPE_NAME, type = StopTranscription.class), + @XmlElement(name = CustomParam.TYPE_NAME, type = CustomParam.class), + + }) private final List verbs = new ArrayList<>(); From 2ff02254a039715c6f5883ec694afdb078bd6c3c Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 13 Jun 2023 09:30:17 -0400 Subject: [PATCH 3/9] Updated String --- src/test/java/com/bandwidth/BxmlTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/bandwidth/BxmlTest.java b/src/test/java/com/bandwidth/BxmlTest.java index a928d421..851e1c89 100644 --- a/src/test/java/com/bandwidth/BxmlTest.java +++ b/src/test/java/com/bandwidth/BxmlTest.java @@ -612,7 +612,7 @@ public void testStartTranscriptionBxmlVerb() { .add(startTranscription) .toBXML(); - String expected = " "; + String expected = " "; assertEquals("BXML strings are equal", expected, response); } From 241bbbd23f4abfa3a7443a4ff8f0e98c31328c1c Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 13 Jun 2023 09:36:46 -0400 Subject: [PATCH 4/9] Fixed value to be attribute --- src/main/java/com/bandwidth/voice/bxml/verbs/CustomParam.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/bandwidth/voice/bxml/verbs/CustomParam.java b/src/main/java/com/bandwidth/voice/bxml/verbs/CustomParam.java index e4600629..10f35996 100644 --- a/src/main/java/com/bandwidth/voice/bxml/verbs/CustomParam.java +++ b/src/main/java/com/bandwidth/voice/bxml/verbs/CustomParam.java @@ -2,7 +2,6 @@ package com.bandwidth.voice.bxml.verbs; import javax.xml.bind.annotation.XmlType; -import javax.xml.bind.annotation.XmlValue; import javax.xml.bind.annotation.XmlAttribute; import lombok.Builder; @@ -23,7 +22,6 @@ public class CustomParam implements Verb { /** * (required) The value of this parameter, up to 2048 characters. */ - @XmlValue + @XmlAttribute private String value; - } From 5d059c6823e16bcd99d50eb1974f5cdb78898543 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 13 Jun 2023 09:43:28 -0400 Subject: [PATCH 5/9] String issues --- src/test/java/com/bandwidth/BxmlTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/bandwidth/BxmlTest.java b/src/test/java/com/bandwidth/BxmlTest.java index 851e1c89..9e22dccf 100644 --- a/src/test/java/com/bandwidth/BxmlTest.java +++ b/src/test/java/com/bandwidth/BxmlTest.java @@ -612,7 +612,7 @@ public void testStartTranscriptionBxmlVerb() { .add(startTranscription) .toBXML(); - String expected = " "; + String expected = " "; assertEquals("BXML strings are equal", expected, response); } From 0b35d21301198e932963e1cf56b347e39893a860 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 13 Jun 2023 10:05:23 -0400 Subject: [PATCH 6/9] Updating test --- src/test/java/com/bandwidth/BxmlTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/bandwidth/BxmlTest.java b/src/test/java/com/bandwidth/BxmlTest.java index 9e22dccf..c13c393f 100644 --- a/src/test/java/com/bandwidth/BxmlTest.java +++ b/src/test/java/com/bandwidth/BxmlTest.java @@ -612,7 +612,7 @@ public void testStartTranscriptionBxmlVerb() { .add(startTranscription) .toBXML(); - String expected = " "; + String expected = ""; assertEquals("BXML strings are equal", expected, response); } From 628a8700ee87c037429e580362bcb46bc9d49e84 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 13 Jun 2023 10:09:57 -0400 Subject: [PATCH 7/9] Test --- src/test/java/com/bandwidth/BxmlTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/bandwidth/BxmlTest.java b/src/test/java/com/bandwidth/BxmlTest.java index c13c393f..4568e7c1 100644 --- a/src/test/java/com/bandwidth/BxmlTest.java +++ b/src/test/java/com/bandwidth/BxmlTest.java @@ -612,7 +612,7 @@ public void testStartTranscriptionBxmlVerb() { .add(startTranscription) .toBXML(); - String expected = ""; + String expected = ""; assertEquals("BXML strings are equal", expected, response); } From a8592c8a4ae4bfdff1bb5348fadcd68a3bea9410 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 13 Jun 2023 13:47:00 -0400 Subject: [PATCH 8/9] Raised timeout --- src/test/java/com/bandwidth/VoiceApiTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/bandwidth/VoiceApiTest.java b/src/test/java/com/bandwidth/VoiceApiTest.java index 7f664f6d..0e9218a8 100644 --- a/src/test/java/com/bandwidth/VoiceApiTest.java +++ b/src/test/java/com/bandwidth/VoiceApiTest.java @@ -43,6 +43,7 @@ public void testCreateCallAndGetCallState() throws Exception { .build(); ApiResponse createCallApiResponse = controller.createCall(ACCOUNT_ID, body); + assertEquals("Response Code is not 201", 201, createCallApiResponse.getStatusCode()); CreateCallResponse createCallResponse = createCallApiResponse.getResult(); @@ -58,7 +59,7 @@ public void testCreateCallAndGetCallState() throws Exception { createCallResponse.getEnqueuedTime().getClass()); // get call state - Thread.sleep(5000); // Wait to get Call because of current system latency issues + Thread.sleep(15000); // Wait to get Call because of current system latency issues ApiResponse callStateApiResponse = controller.getCall(ACCOUNT_ID, createCallResponse.getCallId()); assertEquals("Response Code is not 200", 200, callStateApiResponse.getStatusCode()); @@ -111,7 +112,7 @@ public void testCreateCallWithAmdAndGetCallState() throws Exception { assertEquals("From phone number for create call not equal", BW_NUMBER, createCallResponse.getFrom()); // get call state - Thread.sleep(5000); // Wait to get Call because of current system latency issues + Thread.sleep(15000); // Wait to get Call because of current system latency issues ApiResponse callStateApiResponse = controller.getCall(ACCOUNT_ID, createCallResponse.getCallId()); CallState callStateResponse = callStateApiResponse.getResult(); From f29b3e25119a699d30b2e953f214f32f8f04fcc0 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 19 Jun 2023 08:53:59 -0400 Subject: [PATCH 9/9] Added 404 exception to voice tests --- src/test/java/com/bandwidth/VoiceApiTest.java | 304 +++++++++--------- 1 file changed, 155 insertions(+), 149 deletions(-) diff --git a/src/test/java/com/bandwidth/VoiceApiTest.java b/src/test/java/com/bandwidth/VoiceApiTest.java index 0e9218a8..408cee53 100644 --- a/src/test/java/com/bandwidth/VoiceApiTest.java +++ b/src/test/java/com/bandwidth/VoiceApiTest.java @@ -5,6 +5,7 @@ import com.bandwidth.voice.controllers.APIController; import com.bandwidth.voice.exceptions.ApiErrorException; +import com.bandwidth.exceptions.ApiException; import com.bandwidth.voice.models.*; import org.junit.*; @@ -20,153 +21,158 @@ */ public class VoiceApiTest { - private APIController controller; - - @Before - public void initTest() { - BandwidthClient client = new BandwidthClient.Builder() - .voiceBasicAuthCredentials(USERNAME, PASSWORD) - .build(); - - controller = client.getVoiceClient().getAPIController(); - } - - @Test - public void testCreateCallAndGetCallState() throws Exception { - final String answerUrl = BASE_CALLBACK_URL.concat("/callbacks/outbound"); - - CreateCallRequest body = new CreateCallRequest.Builder() - .to(USER_NUMBER) - .from(BW_NUMBER) - .applicationId(VOICE_APPLICATION_ID) - .answerUrl(answerUrl) - .build(); - - ApiResponse createCallApiResponse = controller.createCall(ACCOUNT_ID, body); - - assertEquals("Response Code is not 201", 201, createCallApiResponse.getStatusCode()); - - CreateCallResponse createCallResponse = createCallApiResponse.getResult(); - assertNotNull("Call ID is null", createCallResponse.getCallId()); - assertFalse("Call ID is empty", createCallResponse.getCallId().isEmpty()); - assertEquals("Call ID is not 47 characters", 47, createCallResponse.getCallId().length()); - assertEquals("Application ID for create call not equal", VOICE_APPLICATION_ID, - createCallResponse.getApplicationId()); - assertEquals("To phone number for create call not equal", USER_NUMBER, createCallResponse.getTo()); - assertEquals("From phone number for create call not equal", BW_NUMBER, createCallResponse.getFrom()); - assertNotNull("enqueuedTime is null", createCallResponse.getEnqueuedTime()); - assertEquals("enqueuedTime is not a LocalDateTime object", LocalDateTime.class, - createCallResponse.getEnqueuedTime().getClass()); - - // get call state - Thread.sleep(15000); // Wait to get Call because of current system latency issues - ApiResponse callStateApiResponse = controller.getCall(ACCOUNT_ID, - createCallResponse.getCallId()); - assertEquals("Response Code is not 200", 200, callStateApiResponse.getStatusCode()); - - CallState callStateResponse = callStateApiResponse.getResult(); - assertEquals("Application ID for call state not equal", VOICE_APPLICATION_ID, - callStateResponse.getApplicationId()); - assertEquals("To phone number for call state not equal", USER_NUMBER, callStateResponse.getTo()); - assertEquals("From phone number for call state not equal", BW_NUMBER, callStateResponse.getFrom()); - assertEquals("Call ID not equal", createCallResponse.getCallId(), callStateResponse.getCallId()); - assertNotNull("enqueuedTime is null", createCallResponse.getEnqueuedTime()); - assertEquals("enqueuedTime is not a LocalDateTime object", LocalDateTime.class, - createCallResponse.getEnqueuedTime().getClass()); - } - - @Test - public void testCreateCallWithAmdAndGetCallState() throws Exception { - final String answerUrl = BASE_CALLBACK_URL.concat("/callbacks/outbound"); - final String machineDetectionUrl = BASE_CALLBACK_URL.concat("/callbacks/machineDetection"); - - MachineDetectionConfiguration machineDetectionConfiguration = new MachineDetectionConfiguration.Builder() - .mode(ModeEnum.ASYNC) - .callbackUrl(machineDetectionUrl) - .callbackMethod(CallbackMethodEnum.POST) - .detectionTimeout(5.0) - .silenceTimeout(5.0) - .speechThreshold(5.0) - .speechEndThreshold(5.0) - .delayResult(true) - .build(); - - CreateCallRequest body = new CreateCallRequest.Builder() - .to(USER_NUMBER) - .from(BW_NUMBER) - .applicationId(VOICE_APPLICATION_ID) - .answerUrl(answerUrl) - .machineDetection(machineDetectionConfiguration) - .build(); - - ApiResponse createCallApiResponse = controller.createCall(ACCOUNT_ID, body); - assertEquals("Response Code is not 201", 201, createCallApiResponse.getStatusCode()); - - CreateCallResponse createCallResponse = createCallApiResponse.getResult(); - assertNotNull("Call ID is null", createCallResponse.getCallId()); - assertFalse("Call ID is empty", createCallResponse.getCallId().isEmpty()); - assertEquals("Call ID is not 47 characters", 47, createCallResponse.getCallId().length()); - assertEquals("Application ID for create call not equal", VOICE_APPLICATION_ID, - createCallResponse.getApplicationId()); - assertEquals("To phone number for create call not equal", USER_NUMBER, createCallResponse.getTo()); - assertEquals("From phone number for create call not equal", BW_NUMBER, createCallResponse.getFrom()); - - // get call state - Thread.sleep(15000); // Wait to get Call because of current system latency issues - ApiResponse callStateApiResponse = controller.getCall(ACCOUNT_ID, - createCallResponse.getCallId()); - CallState callStateResponse = callStateApiResponse.getResult(); - assertEquals("Application ID for call state not equal", VOICE_APPLICATION_ID, - callStateResponse.getApplicationId()); - assertEquals("To phone number for call state not equal", USER_NUMBER, callStateResponse.getTo()); - assertEquals("From phone number for call state not equal", BW_NUMBER, callStateResponse.getFrom()); - assertEquals("Call ID not equal", createCallResponse.getCallId(), callStateResponse.getCallId()); - } - - @Test - public void testCreateCallWithPriorityAndGetCallState() throws Exception { - final String answerUrl = BASE_CALLBACK_URL.concat("/callbacks/outbound"); - final Integer priority = 4; - - CreateCallRequest body = new CreateCallRequest.Builder() - .to(USER_NUMBER) - .from(BW_NUMBER) - .applicationId(VOICE_APPLICATION_ID) - .answerUrl(answerUrl) - .priority(priority) - .tag("the tag") - .build(); - - ApiResponse createCallApiResponse = controller.createCall(ACCOUNT_ID, body); - assertEquals("Response Code is not 201", 201, createCallApiResponse.getStatusCode()); - - CreateCallResponse createCallResponse = createCallApiResponse.getResult(); - assertNotNull("Call ID is null", createCallResponse.getCallId()); - assertFalse("Call ID is empty", createCallResponse.getCallId().isEmpty()); - assertEquals("Call ID is not 47 characters", 47, createCallResponse.getCallId().length()); - assertEquals("Application ID for create call not equal", VOICE_APPLICATION_ID, - createCallResponse.getApplicationId()); - assertEquals("To phone number for create call not equal", USER_NUMBER, createCallResponse.getTo()); - assertEquals("From phone number for create call not equal", BW_NUMBER, createCallResponse.getFrom()); - assertEquals("Priority is not equal", priority, createCallResponse.getPriority()); - assertEquals("Tag is missing", "the tag", createCallResponse.getTag()); - } - - @Test - public void testCreateCallInvalidPhoneNumber() throws Exception { - final String answerUrl = BASE_CALLBACK_URL.concat("/callbacks/outbound"); - - CreateCallRequest body = new CreateCallRequest.Builder() - .to("+1invalid") - .from(BW_NUMBER) - .applicationId(VOICE_APPLICATION_ID) - .answerUrl(answerUrl) - .build(); - - ApiErrorException e = assertThrows( - "ApiError Exception not thrown", - ApiErrorException.class, - () -> controller.createCall(ACCOUNT_ID, body)); - assertEquals("Response Code is not 400", 400, e.getResponseCode()); - } + private APIController controller; + + @Before + public void initTest() { + BandwidthClient client = new BandwidthClient.Builder() + .voiceBasicAuthCredentials(USERNAME, PASSWORD) + .build(); + + controller = client.getVoiceClient().getAPIController(); + } + + @Test + public void testCreateCallAndGetCallState() throws Exception { + final String answerUrl = BASE_CALLBACK_URL.concat("/callbacks/outbound"); + + CreateCallRequest body = new CreateCallRequest.Builder() + .to(USER_NUMBER) + .from(BW_NUMBER) + .applicationId(VOICE_APPLICATION_ID) + .answerUrl(answerUrl) + .build(); + + ApiResponse createCallApiResponse = controller.createCall(ACCOUNT_ID, body); + + assertEquals("Response Code is not 201", 201, createCallApiResponse.getStatusCode()); + + CreateCallResponse createCallResponse = createCallApiResponse.getResult(); + assertNotNull("Call ID is null", createCallResponse.getCallId()); + assertFalse("Call ID is empty", createCallResponse.getCallId().isEmpty()); + assertEquals("Call ID is not 47 characters", 47, createCallResponse.getCallId().length()); + assertEquals("Application ID for create call not equal", VOICE_APPLICATION_ID, + createCallResponse.getApplicationId()); + assertEquals("To phone number for create call not equal", USER_NUMBER, createCallResponse.getTo()); + assertEquals("From phone number for create call not equal", BW_NUMBER, createCallResponse.getFrom()); + assertNotNull("enqueuedTime is null", createCallResponse.getEnqueuedTime()); + assertEquals("enqueuedTime is not a LocalDateTime object", LocalDateTime.class, + createCallResponse.getEnqueuedTime().getClass()); + try { + + ApiResponse callStateApiResponse = controller.getCall(ACCOUNT_ID, + createCallResponse.getCallId()); + assertEquals("Response Code is not 200", 200, callStateApiResponse.getStatusCode()); + + CallState callStateResponse = callStateApiResponse.getResult(); + assertEquals("Application ID for call state not equal", VOICE_APPLICATION_ID, + callStateResponse.getApplicationId()); + assertEquals("To phone number for call state not equal", USER_NUMBER, callStateResponse.getTo()); + assertEquals("From phone number for call state not equal", BW_NUMBER, callStateResponse.getFrom()); + assertEquals("Call ID not equal", createCallResponse.getCallId(), callStateResponse.getCallId()); + assertNotNull("enqueuedTime is null", createCallResponse.getEnqueuedTime()); + assertEquals("enqueuedTime is not a LocalDateTime object", LocalDateTime.class, + createCallResponse.getEnqueuedTime().getClass()); + } catch (ApiException e) { + assertEquals("Response Code is not 404", 404, e.getResponseCode()); + }} + + + + @Test + public void testCreateCallWithAmdAndGetCallState() throws Exception { + final String answerUrl = BASE_CALLBACK_URL.concat("/callbacks/outbound"); + final String machineDetectionUrl = BASE_CALLBACK_URL.concat("/callbacks/machineDetection"); + + MachineDetectionConfiguration machineDetectionConfiguration = new MachineDetectionConfiguration.Builder() + .mode(ModeEnum.ASYNC) + .callbackUrl(machineDetectionUrl) + .callbackMethod(CallbackMethodEnum.POST) + .detectionTimeout(5.0) + .silenceTimeout(5.0) + .speechThreshold(5.0) + .speechEndThreshold(5.0) + .delayResult(true) + .build(); + + CreateCallRequest body = new CreateCallRequest.Builder() + .to(USER_NUMBER) + .from(BW_NUMBER) + .applicationId(VOICE_APPLICATION_ID) + .answerUrl(answerUrl) + .machineDetection(machineDetectionConfiguration) + .build(); + + ApiResponse createCallApiResponse = controller.createCall(ACCOUNT_ID, body); + assertEquals("Response Code is not 201", 201, createCallApiResponse.getStatusCode()); + + CreateCallResponse createCallResponse = createCallApiResponse.getResult(); + assertNotNull("Call ID is null", createCallResponse.getCallId()); + assertFalse("Call ID is empty", createCallResponse.getCallId().isEmpty()); + assertEquals("Call ID is not 47 characters", 47, createCallResponse.getCallId().length()); + assertEquals("Application ID for create call not equal", VOICE_APPLICATION_ID, + createCallResponse.getApplicationId()); + assertEquals("To phone number for create call not equal", USER_NUMBER, createCallResponse.getTo()); + assertEquals("From phone number for create call not equal", BW_NUMBER, createCallResponse.getFrom()); + + try { + ApiResponse callStateApiResponse = controller.getCall(ACCOUNT_ID, + createCallResponse.getCallId()); + CallState callStateResponse = callStateApiResponse.getResult(); + assertEquals("Application ID for call state not equal", VOICE_APPLICATION_ID, + callStateResponse.getApplicationId()); + assertEquals("To phone number for call state not equal", USER_NUMBER, callStateResponse.getTo()); + assertEquals("From phone number for call state not equal", BW_NUMBER, callStateResponse.getFrom()); + assertEquals("Call ID not equal", createCallResponse.getCallId(), callStateResponse.getCallId()); + } catch (ApiException e) { + assertEquals("Response Code is not 404", 404, e.getResponseCode()); + }} + + + @Test + public void testCreateCallWithPriorityAndGetCallState() throws Exception { + final String answerUrl = BASE_CALLBACK_URL.concat("/callbacks/outbound"); + final Integer priority = 4; + + CreateCallRequest body = new CreateCallRequest.Builder() + .to(USER_NUMBER) + .from(BW_NUMBER) + .applicationId(VOICE_APPLICATION_ID) + .answerUrl(answerUrl) + .priority(priority) + .tag("the tag") + .build(); + + ApiResponse createCallApiResponse = controller.createCall(ACCOUNT_ID, body); + assertEquals("Response Code is not 201", 201, createCallApiResponse.getStatusCode()); + + CreateCallResponse createCallResponse = createCallApiResponse.getResult(); + assertNotNull("Call ID is null", createCallResponse.getCallId()); + assertFalse("Call ID is empty", createCallResponse.getCallId().isEmpty()); + assertEquals("Call ID is not 47 characters", 47, createCallResponse.getCallId().length()); + assertEquals("Application ID for create call not equal", VOICE_APPLICATION_ID, + createCallResponse.getApplicationId()); + assertEquals("To phone number for create call not equal", USER_NUMBER, createCallResponse.getTo()); + assertEquals("From phone number for create call not equal", BW_NUMBER, createCallResponse.getFrom()); + assertEquals("Priority is not equal", priority, createCallResponse.getPriority()); + assertEquals("Tag is missing", "the tag", createCallResponse.getTag()); + } + + @Test + public void testCreateCallInvalidPhoneNumber() throws Exception { + final String answerUrl = BASE_CALLBACK_URL.concat("/callbacks/outbound"); + + CreateCallRequest body = new CreateCallRequest.Builder() + .to("+1invalid") + .from(BW_NUMBER) + .applicationId(VOICE_APPLICATION_ID) + .answerUrl(answerUrl) + .build(); + + ApiErrorException e = assertThrows( + "ApiError Exception not thrown", + ApiErrorException.class, + () -> controller.createCall(ACCOUNT_ID, body)); + assertEquals("Response Code is not 400", 400, e.getResponseCode()); + } }