diff --git a/src/Voice/Bxml/Connect.php b/src/Voice/Bxml/Connect.php new file mode 100644 index 0000000..1cd34e9 --- /dev/null +++ b/src/Voice/Bxml/Connect.php @@ -0,0 +1,54 @@ +endpoints = $endpoints; + } + + /** + * Add an Endpoint to the Connect verb + * + * @param Endpoint $endpoint + * @return $this + */ + public function addEndpoint(Endpoint $endpoint): Connect { + $this->endpoints[] = $endpoint; + return $this; + } + + /** + * Converts the Connect verb into a DOMElement + * + * @param DOMDocument $doc + * @return DOMElement + */ + public function toBxml(DOMDocument $doc): DOMElement { + $element = $doc->createElement("Connect"); + foreach ($this->endpoints as $endpoint) { + $element->appendChild($endpoint->toBxml($doc)); + } + return $element; + } +} diff --git a/src/Voice/Bxml/Endpoint.php b/src/Voice/Bxml/Endpoint.php new file mode 100644 index 0000000..445dff2 --- /dev/null +++ b/src/Voice/Bxml/Endpoint.php @@ -0,0 +1,41 @@ +id = $id; + } + + /** + * Converts the Endpoint verb into a DOMElement + * + * @param DOMDocument $doc + * @return DOMElement + */ + public function toBxml(DOMDocument $doc): DOMElement { + $element = $doc->createElement("Endpoint"); + $element->setAttribute("id", $this->id); + return $element; + } +} diff --git a/src/Voice/Controllers/APIController.php b/src/Voice/Controllers/APIController.php index 82a7461..3af06fd 100644 --- a/src/Voice/Controllers/APIController.php +++ b/src/Voice/Controllers/APIController.php @@ -929,7 +929,7 @@ public function getDownloadCallRecording( ) { //prepare query string for API call - $_queryBuilder = + $_queryBuilder = '/api/v2/accounts/{accountId}/calls/{callId}/recordings/{recordingId}/media'; //process optional query parameters @@ -1040,7 +1040,7 @@ public function deleteRecordingMedia( ) { //prepare query string for API call - $_queryBuilder = + $_queryBuilder = '/api/v2/accounts/{accountId}/calls/{callId}/recordings/{recordingId}/media'; //process optional query parameters @@ -1149,7 +1149,7 @@ public function getCallTranscription( ) { //prepare query string for API call - $_queryBuilder = + $_queryBuilder = '/api/v2/accounts/{accountId}/calls/{callId}/recordings/{recordingId}/transcription'; //process optional query parameters @@ -1266,7 +1266,7 @@ public function createTranscribeCallRecording( ) { //prepare query string for API call - $_queryBuilder = + $_queryBuilder = '/api/v2/accounts/{accountId}/calls/{callId}/recordings/{recordingId}/transcription'; //process optional query parameters @@ -1386,7 +1386,7 @@ public function deleteCallTranscription( ) { //prepare query string for API call - $_queryBuilder = + $_queryBuilder = '/api/v2/accounts/{accountId}/calls/{callId}/recordings/{recordingId}/transcription'; //process optional query parameters @@ -1952,7 +1952,7 @@ public function getConferenceMember( ) { //prepare query string for API call - $_queryBuilder = + $_queryBuilder = '/api/v2/accounts/{accountId}/conferences/{conferenceId}/members/{memberId}'; //process optional query parameters @@ -2179,7 +2179,7 @@ public function getConferenceRecording( ) { //prepare query string for API call - $_queryBuilder = + $_queryBuilder = '/api/v2/accounts/{accountId}/conferences/{conferenceId}/recordings/{recordingId}'; //process optional query parameters @@ -2294,7 +2294,7 @@ public function getDownloadConferenceRecording( ) { //prepare query string for API call - $_queryBuilder = + $_queryBuilder = '/api/v2/accounts/{accountId}/conferences/{conferenceId}/recordings/{recordingId}/media'; //process optional query parameters @@ -2514,4 +2514,204 @@ public function getQueryCallRecordings( ); return new ApiResponse($response->code, $response->headers, $deserializedResponse); } + + /** + * Creates a BRTC endpoint. + * + * @param string $accountId + * @param Models\CreateEndpointRequest $body + * @return ApiResponse response from the API call + * @throws APIException Thrown if API call fails + */ + public function createEndpoint( + string $accountId, + Models\CreateEndpointRequest $body + ) { + $_queryBuilder = '/accounts/{accountId}/endpoints'; + $_queryBuilder = APIHelper::appendUrlWithTemplateParameters($_queryBuilder, array( + 'accountId' => $accountId, + )); + $_queryUrl = APIHelper::cleanUrl($this->config->getBaseUri(Servers::PHONENUMBERLOOKUPDEFAULT) . $_queryBuilder); + $_headers = array( + 'user-agent' => BaseController::USER_AGENT, + 'Accept' => 'application/json', + 'content-type' => 'application/json; charset=utf-8' + ); + $_bodyJson = Request\Body::Json($body); + $this->configureAuth($_headers, 'voice'); + $_httpRequest = new HttpRequest(HttpMethod::POST, $_headers, $_queryUrl); + if ($this->getHttpCallBack() != null) { + $this->getHttpCallBack()->callOnBeforeRequest($_httpRequest); + } + Request::timeout($this->config->getTimeout()); + $response = Request::post($_queryUrl, $_headers, $_bodyJson); + $_httpResponse = new HttpResponse($response->code, $response->headers, $response->raw_body); + $_httpContext = new HttpContext($_httpRequest, $_httpResponse); + if ($this->getHttpCallBack() != null) { + $this->getHttpCallBack()->callOnAfterRequest($_httpContext); + } + $this->validateResponse($_httpResponse, $_httpContext); + $mapper = $this->getJsonMapper(); + $deserializedResponse = $mapper->mapClass($response->body, 'BandwidthLib\\Voice\\Models\\CreateEndpointResponse'); + return new ApiResponse($response->code, $response->headers, $deserializedResponse); + } + + /** + * Lists BRTC endpoints for an account. + * + * @param string $accountId + * @param array $queryParams Optional filter/pagination params + * @return ApiResponse response from the API call + * @throws APIException Thrown if API call fails + */ + public function listEndpoints( + string $accountId, + array $queryParams = [] + ) { + $_queryBuilder = '/accounts/{accountId}/endpoints'; + $_queryBuilder = APIHelper::appendUrlWithTemplateParameters($_queryBuilder, array( + 'accountId' => $accountId, + )); + if (!empty($queryParams)) { + $_queryBuilder = APIHelper::appendUrlWithQueryParameters($_queryBuilder, $queryParams); + } + $_queryUrl = APIHelper::cleanUrl($this->config->getBaseUri(Servers::PHONENUMBERLOOKUPDEFAULT) . $_queryBuilder); + $_headers = array( + 'user-agent' => BaseController::USER_AGENT, + 'Accept' => 'application/json' + ); + $this->configureAuth($_headers, 'voice'); + $_httpRequest = new HttpRequest(HttpMethod::GET, $_headers, $_queryUrl); + if ($this->getHttpCallBack() != null) { + $this->getHttpCallBack()->callOnBeforeRequest($_httpRequest); + } + Request::timeout($this->config->getTimeout()); + $response = Request::get($_queryUrl, $_headers); + $_httpResponse = new HttpResponse($response->code, $response->headers, $response->raw_body); + $_httpContext = new HttpContext($_httpRequest, $_httpResponse); + if ($this->getHttpCallBack() != null) { + $this->getHttpCallBack()->callOnAfterRequest($_httpContext); + } + $this->validateResponse($_httpResponse, $_httpContext); + $mapper = $this->getJsonMapper(); + $deserializedResponse = $mapper->mapClassArray($response->body, 'BandwidthLib\\Voice\\Models\\Endpoint'); + return new ApiResponse($response->code, $response->headers, $deserializedResponse); + } + + /** + * Gets details for a specific BRTC endpoint. + * + * @param string $accountId + * @param string $endpointId + * @return ApiResponse response from the API call + * @throws APIException Thrown if API call fails + */ + public function getEndpoint( + string $accountId, + string $endpointId + ) { + $_queryBuilder = '/accounts/{accountId}/endpoints/{endpointId}'; + $_queryBuilder = APIHelper::appendUrlWithTemplateParameters($_queryBuilder, array( + 'accountId' => $accountId, + 'endpointId' => $endpointId, + )); + $_queryUrl = APIHelper::cleanUrl($this->config->getBaseUri(Servers::PHONENUMBERLOOKUPDEFAULT) . $_queryBuilder); + $_headers = array( + 'user-agent' => BaseController::USER_AGENT, + 'Accept' => 'application/json' + ); + $this->configureAuth($_headers, 'voice'); + $_httpRequest = new HttpRequest(HttpMethod::GET, $_headers, $_queryUrl); + if ($this->getHttpCallBack() != null) { + $this->getHttpCallBack()->callOnBeforeRequest($_httpRequest); + } + Request::timeout($this->config->getTimeout()); + $response = Request::get($_queryUrl, $_headers); + $_httpResponse = new HttpResponse($response->code, $response->headers, $response->raw_body); + $_httpContext = new HttpContext($_httpRequest, $_httpResponse); + if ($this->getHttpCallBack() != null) { + $this->getHttpCallBack()->callOnAfterRequest($_httpContext); + } + $this->validateResponse($_httpResponse, $_httpContext); + $mapper = $this->getJsonMapper(); + $deserializedResponse = $mapper->mapClass($response->body, 'BandwidthLib\\Voice\\Models\\Endpoint'); + return new ApiResponse($response->code, $response->headers, $deserializedResponse); + } + + /** + * Deletes a BRTC endpoint. + * + * @param string $accountId + * @param string $endpointId + * @return ApiResponse response from the API call + * @throws APIException Thrown if API call fails + */ + public function deleteEndpoint( + string $accountId, + string $endpointId + ) { + $_queryBuilder = '/accounts/{accountId}/endpoints/{endpointId}'; + $_queryBuilder = APIHelper::appendUrlWithTemplateParameters($_queryBuilder, array( + 'accountId' => $accountId, + 'endpointId' => $endpointId, + )); + $_queryUrl = APIHelper::cleanUrl($this->config->getBaseUri(Servers::PHONENUMBERLOOKUPDEFAULT) . $_queryBuilder); + $_headers = array( + 'user-agent' => BaseController::USER_AGENT + ); + $this->configureAuth($_headers, 'voice'); + $_httpRequest = new HttpRequest(HttpMethod::DELETE, $_headers, $_queryUrl); + if ($this->getHttpCallBack() != null) { + $this->getHttpCallBack()->callOnBeforeRequest($_httpRequest); + } + Request::timeout($this->config->getTimeout()); + $response = Request::delete($_queryUrl, $_headers); + $_httpResponse = new HttpResponse($response->code, $response->headers, $response->raw_body); + $_httpContext = new HttpContext($_httpRequest, $_httpResponse); + if ($this->getHttpCallBack() != null) { + $this->getHttpCallBack()->callOnAfterRequest($_httpContext); + } + $this->validateResponse($_httpResponse, $_httpContext); + return new ApiResponse($response->code, $response->headers, null); + } + + /** + * Updates the BXML for a BRTC endpoint. + * + * @param string $accountId + * @param string $endpointId + * @param string $body Valid BXML string + * @return ApiResponse response from the API call + * @throws APIException Thrown if API call fails + */ + public function updateEndpointBxml( + string $accountId, + string $endpointId, + string $body + ) { + $_queryBuilder = '/accounts/{accountId}/endpoints/{endpointId}/bxml'; + $_queryBuilder = APIHelper::appendUrlWithTemplateParameters($_queryBuilder, array( + 'accountId' => $accountId, + 'endpointId' => $endpointId, + )); + $_queryUrl = APIHelper::cleanUrl($this->config->getBaseUri(Servers::PHONENUMBERLOOKUPDEFAULT) . $_queryBuilder); + $_headers = array( + 'user-agent' => BaseController::USER_AGENT, + 'content-type' => 'application/xml; charset=utf-8' + ); + $this->configureAuth($_headers, 'voice'); + $_httpRequest = new HttpRequest(HttpMethod::PUT, $_headers, $_queryUrl); + if ($this->getHttpCallBack() != null) { + $this->getHttpCallBack()->callOnBeforeRequest($_httpRequest); + } + Request::timeout($this->config->getTimeout()); + $response = Request::put($_queryUrl, $_headers, $body); + $_httpResponse = new HttpResponse($response->code, $response->headers, $response->raw_body); + $_httpContext = new HttpContext($_httpRequest, $_httpResponse); + if ($this->getHttpCallBack() != null) { + $this->getHttpCallBack()->callOnAfterRequest($_httpContext); + } + $this->validateResponse($_httpResponse, $_httpContext); + return new ApiResponse($response->code, $response->headers, null); + } } diff --git a/src/Voice/Models/CreateEndpointRequest.php b/src/Voice/Models/CreateEndpointRequest.php new file mode 100644 index 0000000..26a5caa --- /dev/null +++ b/src/Voice/Models/CreateEndpointRequest.php @@ -0,0 +1,34 @@ +type = $type; + $this->direction = $direction; + $this->eventCallbackUrl = $eventCallbackUrl; + $this->eventFallbackUrl = $eventFallbackUrl; + $this->tag = $tag; + $this->connectionMetadata = $connectionMetadata; + } +} diff --git a/src/Voice/Models/CreateEndpointResponse.php b/src/Voice/Models/CreateEndpointResponse.php new file mode 100644 index 0000000..eae422a --- /dev/null +++ b/src/Voice/Models/CreateEndpointResponse.php @@ -0,0 +1,40 @@ +endpointId = $endpointId; + $this->type = $type; + $this->status = $status; + $this->createdTime = $createdTime; + $this->updatedTime = $updatedTime; + $this->tag = $tag; + $this->devices = $devices; + $this->token = $token; + } +} diff --git a/src/Voice/Models/Device.php b/src/Voice/Models/Device.php new file mode 100644 index 0000000..5ae0687 --- /dev/null +++ b/src/Voice/Models/Device.php @@ -0,0 +1,31 @@ +id = $id; + $this->status = $status; + $this->type = $type; + $this->createdTime = $createdTime; + $this->updatedTime = $updatedTime; + } +} diff --git a/src/Voice/Models/Endpoint.php b/src/Voice/Models/Endpoint.php new file mode 100644 index 0000000..f6b1a92 --- /dev/null +++ b/src/Voice/Models/Endpoint.php @@ -0,0 +1,46 @@ +id = $id; + $this->type = $type; + $this->status = $status; + $this->direction = $direction; + $this->eventCallbackUrl = $eventCallbackUrl; + $this->eventFallbackUrl = $eventFallbackUrl; + $this->tag = $tag; + $this->devices = $devices; + $this->createdTime = $createdTime; + $this->updatedTime = $updatedTime; + } +} diff --git a/src/Voice/Models/EndpointEvent.php b/src/Voice/Models/EndpointEvent.php new file mode 100644 index 0000000..2360f74 --- /dev/null +++ b/src/Voice/Models/EndpointEvent.php @@ -0,0 +1,34 @@ +eventType = $eventType; + $this->endpointId = $endpointId; + $this->timestamp = $timestamp; + $this->status = $status; + $this->reason = $reason; + $this->details = $details; + } +} diff --git a/src/Voice/Models/Enums.php b/src/Voice/Models/Enums.php new file mode 100644 index 0000000..0060c21 --- /dev/null +++ b/src/Voice/Models/Enums.php @@ -0,0 +1,38 @@ +message = $message; + $this->code = $code; + $this->details = $details; + } +} diff --git a/src/Voice/Models/Page.php b/src/Voice/Models/Page.php new file mode 100644 index 0000000..b400d2e --- /dev/null +++ b/src/Voice/Models/Page.php @@ -0,0 +1,28 @@ +page = $page; + $this->size = $size; + $this->total = $total; + $this->totalPages = $totalPages; + } +} diff --git a/src/Voice/VoiceClient.php b/src/Voice/VoiceClient.php index 089b842..c79a0bd 100644 --- a/src/Voice/VoiceClient.php +++ b/src/Voice/VoiceClient.php @@ -34,4 +34,5 @@ public function getClient() } return $this->client; } + } diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 44c9bc9..26a0515 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -14,7 +14,7 @@ final class ApiTest extends TestCase { protected static $bandwidthClient; protected static $messagingMFAClient; - + protected static $endpointClient; public static function setUpBeforeClass(): void { $config = new BandwidthLib\Configuration( array( @@ -37,6 +37,14 @@ public static function setUpBeforeClass(): void { ) ); self::$messagingMFAClient = new BandwidthLib\BandwidthClient($messagingMFAConfig); + + $endpointConfig = new BandwidthLib\Configuration( + array( + 'clientId' => getenv("BW_CLIENT_ID"), + 'clientSecret' => getenv("BW_CLIENT_SECRET"), + ) + ); + self::$endpointClient = new BandwidthLib\BandwidthClient($endpointConfig); } public function testCreateMessage() { @@ -72,7 +80,7 @@ public function testUploadDownloadMedia() { $mediaId = "text-media-id-" . uniqid() . ".txt"; $content = "Hello world"; $contentType = 'text/plain'; - + //media upload self::$messagingMFAClient->getMessaging()->getClient()->uploadMedia(getenv("BW_ACCOUNT_ID"), $mediaId, $content, $contentType); @@ -130,7 +138,7 @@ public function testCreateCallWithAmdAndGetCallState() { //get phone call information // $response = self::$bandwidthClient->getVoice()->getClient()->getCall(getenv("BW_ACCOUNT_ID"), $callId); - // if (($response->getStatus() == 404) ) { + // if (($response->getStatus() == 404) ) { // $this->assertTrue(is_a($response->getResult()->enqueuedTime, 'DateTime')); // } } @@ -230,7 +238,7 @@ public function testAsyncTnLookup() { $this->assertIsString($statusResponse->getResult()->data->results[0]->countryCodeA3); $this->assertIsArray($statusResponse->getResult()->errors); } - + public function testSyncTnLookup() { $body = new BandwidthLib\PhoneNumberLookup\Models\CreateLookupRequest(); $body->phoneNumbers = [getenv("USER_NUMBER")]; @@ -251,4 +259,218 @@ public function testSyncTnLookup() { $this->assertIsString($response->getResult()->data->results[0]->countryCodeA3); $this->assertIsArray($response->getResult()->errors); } + + public function testCreateListGetDeleteEndpoint() { + $accountId = getenv("BW_ACCOUNT_ID"); + $voiceClient = self::$endpointClient->getVoice()->getClient(); + + // Create endpoint + $createReq = new BandwidthLib\Voice\Models\CreateEndpointRequest( + 'WEBRTC', + 'INBOUND', + getenv("BASE_CALLBACK_URL") . "/brtc/events", + null, + 'php-sdk-test', + ["meta" => "data"] + ); + try { + $createResp = $voiceClient->createEndpoint($accountId, $createReq)->getResult(); + } catch (BandwidthLib\APIException $e) { + $this->fail('createEndpoint failed with HTTP ' . $e->getCode() . ': ' . $e->getContext()->getResponse()->getRawBody()); + } + $this->assertNotNull($createResp->endpointId); + $this->assertEquals('WEBRTC', $createResp->type); + + // List endpoints + $endpoints = $voiceClient->listEndpoints($accountId)->getResult(); + $this->assertIsArray($endpoints); + $ids = array_map(fn($ep) => $ep->id, $endpoints); + $this->assertContains($createResp->endpointId, $ids, 'Created endpoint should be in list'); + + // Get endpoint + $endpoint = $voiceClient->getEndpoint($accountId, $createResp->endpointId)->getResult(); + $this->assertEquals($createResp->endpointId, $endpoint->id); + $this->assertEquals('WEBRTC', $endpoint->type); + + // Update endpoint BXML + // TODO: This endpoint currently is not implemented, commenting out until it is + // $bxml = 'Test BRTC'; + // $voiceClient->updateEndpointBxml($accountId, $createResp->endpointId, $bxml); + + // Delete endpoint + $deleteResp = $voiceClient->deleteEndpoint($accountId, $createResp->endpointId); + $this->assertEquals(204, $deleteResp->getStatusCode()); + } + + public function testCreateEndpointResponseFields() { + $accountId = getenv("BW_ACCOUNT_ID"); + $voiceClient = self::$endpointClient->getVoice()->getClient(); + + $createReq = new BandwidthLib\Voice\Models\CreateEndpointRequest( + 'WEBRTC', + 'INBOUND', + getenv("BASE_CALLBACK_URL") . "/brtc/events", + getenv("BASE_CALLBACK_URL") . "/brtc/fallback", + 'php-sdk-fields-test' + ); + try { + $createResp = $voiceClient->createEndpoint($accountId, $createReq)->getResult(); + } catch (BandwidthLib\APIException $e) { + $this->fail('createEndpoint failed with HTTP ' . $e->getCode() . ': ' . $e->getContext()->getResponse()->getRawBody()); + } + + $this->assertNotNull($createResp->endpointId); + $this->assertIsString($createResp->endpointId); + $this->assertEquals('WEBRTC', $createResp->type); + $this->assertNotNull($createResp->status); + $this->assertNotNull($createResp->createdTime); + $this->assertNotNull($createResp->updatedTime); + $this->assertEquals('php-sdk-fields-test', $createResp->tag); + + // Cleanup + $voiceClient->deleteEndpoint($accountId, $createResp->endpointId); + } + + public function testGetEndpointFields() { + $accountId = getenv("BW_ACCOUNT_ID"); + $voiceClient = self::$endpointClient->getVoice()->getClient(); + + $createReq = new BandwidthLib\Voice\Models\CreateEndpointRequest( + 'WEBRTC', + 'INBOUND', + getenv("BASE_CALLBACK_URL") . "/brtc/events", + null, + 'php-sdk-get-test' + ); + try { + $endpointId = $voiceClient->createEndpoint($accountId, $createReq)->getResult()->endpointId; + } catch (BandwidthLib\APIException $e) { + $this->fail('createEndpoint failed with HTTP ' . $e->getCode() . ': ' . $e->getContext()->getResponse()->getRawBody()); + } + + $endpoint = $voiceClient->getEndpoint($accountId, $endpointId)->getResult(); + $this->assertInstanceOf(BandwidthLib\Voice\Models\Endpoint::class, $endpoint); + $this->assertEquals($endpointId, $endpoint->id); + $this->assertEquals('WEBRTC', $endpoint->type); + $this->assertNotNull($endpoint->status); + $this->assertNotNull($endpoint->direction); + $this->assertNotNull($endpoint->createdTime); + $this->assertNotNull($endpoint->updatedTime); + $this->assertEquals('php-sdk-get-test', $endpoint->tag); + + // Cleanup + $voiceClient->deleteEndpoint($accountId, $endpointId); + } + + public function testListEndpointsContainsCreated() { + $accountId = getenv("BW_ACCOUNT_ID"); + $voiceClient = self::$endpointClient->getVoice()->getClient(); + + $createReq = new BandwidthLib\Voice\Models\CreateEndpointRequest( + 'WEBRTC', + 'INBOUND', + getenv("BASE_CALLBACK_URL") . "/brtc/events", + null, + 'php-sdk-list-test' + ); + try { + $endpointId = $voiceClient->createEndpoint($accountId, $createReq)->getResult()->endpointId; + } catch (BandwidthLib\APIException $e) { + $this->fail('createEndpoint failed with HTTP ' . $e->getCode() . ': ' . $e->getContext()->getResponse()->getRawBody()); + } + + $endpoints = $voiceClient->listEndpoints($accountId)->getResult(); + $this->assertIsArray($endpoints); + $this->assertNotEmpty($endpoints); + + $ids = array_map(fn($ep) => $ep->id, $endpoints); + $this->assertContains($endpointId, $ids, 'Newly created endpoint should appear in list'); + + // Cleanup + $voiceClient->deleteEndpoint($accountId, $endpointId); + } + + public function testListEndpointsEachItemIsEndpointInstance() { + $accountId = getenv("BW_ACCOUNT_ID"); + $voiceClient = self::$endpointClient->getVoice()->getClient(); + + $createReq = new BandwidthLib\Voice\Models\CreateEndpointRequest( + 'WEBRTC', + 'INBOUND', + getenv("BASE_CALLBACK_URL") . "/brtc/events" + ); + try { + $endpointId = $voiceClient->createEndpoint($accountId, $createReq)->getResult()->endpointId; + } catch (BandwidthLib\APIException $e) { + $this->fail('createEndpoint failed with HTTP ' . $e->getCode() . ': ' . $e->getContext()->getResponse()->getRawBody()); + } + + $endpoints = $voiceClient->listEndpoints($accountId)->getResult(); + foreach ($endpoints as $ep) { + $this->assertInstanceOf(BandwidthLib\Voice\Models\Endpoint::class, $ep); + $this->assertNotNull($ep->id); + $this->assertNotNull($ep->type); + $this->assertNotNull($ep->status); + } + + // Cleanup + $voiceClient->deleteEndpoint($accountId, $endpointId); + } + + public function testCreateMultipleEndpointsAndDeleteAll() { + $accountId = getenv("BW_ACCOUNT_ID"); + $voiceClient = self::$endpointClient->getVoice()->getClient(); + + $createdIds = []; + for ($i = 0; $i < 3; $i++) { + $createReq = new BandwidthLib\Voice\Models\CreateEndpointRequest( + 'WEBRTC', + 'INBOUND', + getenv("BASE_CALLBACK_URL") . "/brtc/events", + null, + "php-sdk-multi-{$i}" + ); + try { + $endpointId = $voiceClient->createEndpoint($accountId, $createReq)->getResult()->endpointId; + } catch (BandwidthLib\APIException $e) { + $this->fail('createEndpoint failed with HTTP ' . $e->getCode() . ': ' . $e->getContext()->getResponse()->getRawBody()); + } + $this->assertNotNull($endpointId); + $createdIds[] = $endpointId; + } + + $this->assertCount(3, $createdIds); + + // Delete all created endpoints + foreach ($createdIds as $id) { + $deleteResp = $voiceClient->deleteEndpoint($accountId, $id); + $this->assertEquals(204, $deleteResp->getStatusCode()); + } + } + + public function testDeleteEndpointRemovedFromList() { + $accountId = getenv("BW_ACCOUNT_ID"); + $voiceClient = self::$endpointClient->getVoice()->getClient(); + + $createReq = new BandwidthLib\Voice\Models\CreateEndpointRequest( + 'WEBRTC', + 'INBOUND', + getenv("BASE_CALLBACK_URL") . "/brtc/events", + null, + 'php-sdk-delete-check' + ); + try { + $endpointId = $voiceClient->createEndpoint($accountId, $createReq)->getResult()->endpointId; + } catch (BandwidthLib\APIException $e) { + $this->fail('createEndpoint failed with HTTP ' . $e->getCode() . ': ' . $e->getContext()->getResponse()->getRawBody()); + } + + // Delete it + $voiceClient->deleteEndpoint($accountId, $endpointId); + + // Should no longer appear in list + $endpoints = $voiceClient->listEndpoints($accountId)->getResult(); + $ids = array_map(fn($ep) => $ep->id, $endpoints); + $this->assertNotContains($endpointId, $ids, 'Deleted endpoint should not appear in list'); + } } diff --git a/tests/BxmlTest.php b/tests/BxmlTest.php index 44bdb2f..e9f1b85 100644 --- a/tests/BxmlTest.php +++ b/tests/BxmlTest.php @@ -540,4 +540,18 @@ public function testStopTranscription() { $responseXml = $response->toBxml(); $this->assertEquals($expectedXml, $responseXml); } + + public function testConnectAndEndpoint() { + $endpoint1 = new BandwidthLib\Voice\Bxml\Endpoint("endpoint-123"); + $endpoint2 = new BandwidthLib\Voice\Bxml\Endpoint("endpoint-456"); + $connect = new BandwidthLib\Voice\Bxml\Connect([ + $endpoint1, + $endpoint2 + ]); + $response = new BandwidthLib\Voice\Bxml\Response(); + $response->addVerb($connect); + $expectedXml = ''; + $responseXml = $response->toBxml(); + $this->assertEquals($expectedXml, $responseXml); + } }