From 1cdd88db54cc7425ae5b2b6df3bd40a454f575e0 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Portier Date: Thu, 19 Dec 2024 12:00:41 +0100 Subject: [PATCH] feat (SMS/Inbounds): inbounds API --- .../domains/sms/api/v1/InboundsService.java | 13 ++ .../sdk/domains/sms/api/v1/SMSService.java | 2 + .../sms/api/v1/adapters/BatchesService.java | 6 +- .../sms/api/v1/adapters/InboundsService.java | 50 ++++++ .../sms/api/v1/adapters/SMSService.java | 12 +- .../models/v1/inbounds/InboundMessage.java | 7 + .../response/ListInboundsResponse.java | 54 ++++++ .../api/v1/adapters/InboundsServiceTest.java | 162 ++++++++++++++++++ .../sms/api/v1/internal/InboundsApiTest.java | 141 +++++++++++++++ .../sdk/e2e/domains/sms/v1/InboundsSteps.java | 113 ++++++++++++ .../sinch/sdk/e2e/domains/sms/v1/SmsIT.java | 1 + .../CollectionStringToCommaSerializer.java | 27 +++ .../InstantToIso8601Serializer.java | 1 - ...CollectionStringToCommaSerializerTest.java | 49 ++++++ .../v1/inbounds/InboundMessageDtoTest.java | 89 ++++++++++ .../domains/sms/v1/inbounds/MOMediaDto.json | 22 +++ .../com/sinch/sample/sms/v1/inbounds/Get.java | 35 ++++ .../sinch/sample/sms/v1/inbounds/List.java | 41 +++++ 18 files changed, 818 insertions(+), 7 deletions(-) create mode 100644 client/src/main/com/sinch/sdk/domains/sms/api/v1/InboundsService.java create mode 100644 client/src/main/com/sinch/sdk/domains/sms/api/v1/adapters/InboundsService.java create mode 100644 client/src/main/com/sinch/sdk/domains/sms/models/v1/inbounds/InboundMessage.java create mode 100644 client/src/main/com/sinch/sdk/domains/sms/models/v1/inbounds/response/ListInboundsResponse.java create mode 100644 client/src/test/java/com/sinch/sdk/domains/sms/api/v1/adapters/InboundsServiceTest.java create mode 100644 client/src/test/java/com/sinch/sdk/domains/sms/api/v1/internal/InboundsApiTest.java create mode 100644 client/src/test/java/com/sinch/sdk/e2e/domains/sms/v1/InboundsSteps.java create mode 100644 core/src/main/com/sinch/sdk/core/databind/query_parameter/CollectionStringToCommaSerializer.java create mode 100644 core/src/test/java/com/sinch/sdk/core/databind/query_parameter/CollectionStringToCommaSerializerTest.java create mode 100644 openapi-contracts/src/test/java/com/sinch/sdk/domains/sms/models/v1/inbounds/InboundMessageDtoTest.java create mode 100644 openapi-contracts/src/test/resources/domains/sms/v1/inbounds/MOMediaDto.json create mode 100644 sample-app/src/main/java/com/sinch/sample/sms/v1/inbounds/Get.java create mode 100644 sample-app/src/main/java/com/sinch/sample/sms/v1/inbounds/List.java diff --git a/client/src/main/com/sinch/sdk/domains/sms/api/v1/InboundsService.java b/client/src/main/com/sinch/sdk/domains/sms/api/v1/InboundsService.java new file mode 100644 index 00000000..4861622b --- /dev/null +++ b/client/src/main/com/sinch/sdk/domains/sms/api/v1/InboundsService.java @@ -0,0 +1,13 @@ +package com.sinch.sdk.domains.sms.api.v1; + +import com.sinch.sdk.core.exceptions.ApiException; +import com.sinch.sdk.domains.sms.models.v1.inbounds.InboundMessage; +import com.sinch.sdk.domains.sms.models.v1.inbounds.request.ListInboundMessagesQueryParameters; +import com.sinch.sdk.domains.sms.models.v1.inbounds.response.ListInboundsResponse; + +public interface InboundsService { + + ListInboundsResponse list(ListInboundMessagesQueryParameters parameters) throws ApiException; + + InboundMessage get(String inboundId) throws ApiException; +} diff --git a/client/src/main/com/sinch/sdk/domains/sms/api/v1/SMSService.java b/client/src/main/com/sinch/sdk/domains/sms/api/v1/SMSService.java index b9bfd936..1df50d22 100644 --- a/client/src/main/com/sinch/sdk/domains/sms/api/v1/SMSService.java +++ b/client/src/main/com/sinch/sdk/domains/sms/api/v1/SMSService.java @@ -3,4 +3,6 @@ public interface SMSService { BatchesService batches(); + + InboundsService inbounds(); } diff --git a/client/src/main/com/sinch/sdk/domains/sms/api/v1/adapters/BatchesService.java b/client/src/main/com/sinch/sdk/domains/sms/api/v1/adapters/BatchesService.java index e189c948..cad45698 100644 --- a/client/src/main/com/sinch/sdk/domains/sms/api/v1/adapters/BatchesService.java +++ b/client/src/main/com/sinch/sdk/domains/sms/api/v1/adapters/BatchesService.java @@ -42,16 +42,12 @@ public BatchResponse send(BatchRequest batch) throws ApiException { public ListBatchesResponse list(ListBatchesQueryParameters parameters) throws ApiException { - ListBatchesQueryParameters guardParameters = - null != parameters ? parameters : ListBatchesQueryParameters.builder().build(); - ApiBatchList response = getApi().list(parameters); SMSCursorPageNavigator navigator = new SMSCursorPageNavigator(response.getPage(), response.getPageSize()); - return new ListBatchesResponse( - this, new Page<>(guardParameters, response.getBatches(), navigator)); + return new ListBatchesResponse(this, new Page<>(parameters, response.getBatches(), navigator)); } public DryRunResponse dryRun(DryRunQueryParameters queryParameters, BatchRequest batch) { diff --git a/client/src/main/com/sinch/sdk/domains/sms/api/v1/adapters/InboundsService.java b/client/src/main/com/sinch/sdk/domains/sms/api/v1/adapters/InboundsService.java new file mode 100644 index 00000000..831fa359 --- /dev/null +++ b/client/src/main/com/sinch/sdk/domains/sms/api/v1/adapters/InboundsService.java @@ -0,0 +1,50 @@ +package com.sinch.sdk.domains.sms.api.v1.adapters; + +import com.sinch.sdk.core.exceptions.ApiException; +import com.sinch.sdk.core.http.AuthManager; +import com.sinch.sdk.core.http.HttpClient; +import com.sinch.sdk.core.http.HttpMapper; +import com.sinch.sdk.core.models.pagination.Page; +import com.sinch.sdk.domains.sms.api.v1.internal.InboundsApi; +import com.sinch.sdk.domains.sms.models.v1.batches.internal.SMSCursorPageNavigator; +import com.sinch.sdk.domains.sms.models.v1.inbounds.InboundMessage; +import com.sinch.sdk.domains.sms.models.v1.inbounds.request.ListInboundMessagesQueryParameters; +import com.sinch.sdk.domains.sms.models.v1.inbounds.response.ListInboundsResponse; +import com.sinch.sdk.domains.sms.models.v1.inbounds.response.internal.ApiInboundList; +import com.sinch.sdk.models.SmsContext; +import java.util.Map; + +public class InboundsService implements com.sinch.sdk.domains.sms.api.v1.InboundsService { + + private final InboundsApi api; + + public InboundsService( + String uriUUID, + SmsContext context, + HttpClient httpClient, + Map authManagers) { + this.api = + new InboundsApi( + httpClient, context.getSmsServer(), authManagers, new HttpMapper(), uriUUID); + } + + protected InboundsApi getApi() { + return this.api; + } + + public ListInboundsResponse list(ListInboundMessagesQueryParameters parameters) + throws ApiException { + + ApiInboundList response = getApi().list(parameters); + + SMSCursorPageNavigator navigator = + new SMSCursorPageNavigator(response.getPage(), response.getPageSize()); + + return new ListInboundsResponse( + this, new Page<>(parameters, response.getInbounds(), navigator)); + } + + public InboundMessage get(String inboundId) throws ApiException { + return getApi().get(inboundId); + } +} diff --git a/client/src/main/com/sinch/sdk/domains/sms/api/v1/adapters/SMSService.java b/client/src/main/com/sinch/sdk/domains/sms/api/v1/adapters/SMSService.java index 84bde85f..8820f305 100644 --- a/client/src/main/com/sinch/sdk/domains/sms/api/v1/adapters/SMSService.java +++ b/client/src/main/com/sinch/sdk/domains/sms/api/v1/adapters/SMSService.java @@ -25,9 +25,11 @@ public class SMSService implements com.sinch.sdk.domains.sms.api.v1.SMSService { private final String uriUUID; private final SmsContext context; private final HttpClient httpClient; - private BatchesService batches; private final Map authManagers; + private BatchesService batches; + private InboundsService inbounds; + public SMSService( UnifiedCredentials credentials, SmsContext context, @@ -85,4 +87,12 @@ public BatchesService batches() { } return this.batches; } + + @Override + public InboundsService inbounds() { + if (null == this.inbounds) { + this.inbounds = new InboundsService(uriUUID, context, httpClient, authManagers); + } + return this.inbounds; + } } diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/v1/inbounds/InboundMessage.java b/client/src/main/com/sinch/sdk/domains/sms/models/v1/inbounds/InboundMessage.java new file mode 100644 index 00000000..d3100622 --- /dev/null +++ b/client/src/main/com/sinch/sdk/domains/sms/models/v1/inbounds/InboundMessage.java @@ -0,0 +1,7 @@ +package com.sinch.sdk.domains.sms.models.v1.inbounds; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.sinch.sdk.domains.sms.models.v1.inbounds.response.internal.InboundInternalImpl; + +@JsonDeserialize(using = InboundInternalImpl.Deserializer.class) +public interface InboundMessage {} diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/v1/inbounds/response/ListInboundsResponse.java b/client/src/main/com/sinch/sdk/domains/sms/models/v1/inbounds/response/ListInboundsResponse.java new file mode 100644 index 00000000..5f433bbb --- /dev/null +++ b/client/src/main/com/sinch/sdk/domains/sms/models/v1/inbounds/response/ListInboundsResponse.java @@ -0,0 +1,54 @@ +package com.sinch.sdk.domains.sms.models.v1.inbounds.response; + +import com.sinch.sdk.core.models.pagination.ListResponse; +import com.sinch.sdk.core.models.pagination.Page; +import com.sinch.sdk.domains.sms.api.v1.InboundsService; +import com.sinch.sdk.domains.sms.models.v1.inbounds.InboundMessage; +import com.sinch.sdk.domains.sms.models.v1.inbounds.request.ListInboundMessagesQueryParameters; +import java.util.Collection; +import java.util.NoSuchElementException; + +public class ListInboundsResponse extends ListResponse { + + private final Page page; + private final InboundsService service; + private ListInboundsResponse nextPage; + + public ListInboundsResponse( + InboundsService service, + Page page) { + this.service = service; + this.page = page; + } + + public boolean hasNextPage() { + + if (null == nextPage) { + ListInboundMessagesQueryParameters.Builder newParameters = + ListInboundMessagesQueryParameters.builder(page.getParameters()); + newParameters.setPage(page.getNextPageToken()); + nextPage = service.list(newParameters.build()); + } + return (null != nextPage.getContent() && !nextPage.getContent().isEmpty()); + } + + public ListInboundsResponse nextPage() { + + if (!hasNextPage()) { + throw new NoSuchElementException("Reached the last page of the API response"); + } + + ListInboundsResponse response = nextPage; + nextPage = null; + return response; + } + + public Collection getContent() { + return page.getEntities(); + } + + @Override + public String toString() { + return "ListInboundsResponse{" + "page=" + page + '}'; + } +} diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/api/v1/adapters/InboundsServiceTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/api/v1/adapters/InboundsServiceTest.java new file mode 100644 index 00000000..60370e45 --- /dev/null +++ b/client/src/test/java/com/sinch/sdk/domains/sms/api/v1/adapters/InboundsServiceTest.java @@ -0,0 +1,162 @@ +package com.sinch.sdk.domains.sms.api.v1.adapters; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import com.adelean.inject.resources.junit.jupiter.GivenJsonResource; +import com.adelean.inject.resources.junit.jupiter.TestWithResources; +import com.sinch.sdk.BaseTest; +import com.sinch.sdk.core.TestHelpers; +import com.sinch.sdk.core.exceptions.ApiException; +import com.sinch.sdk.core.http.AuthManager; +import com.sinch.sdk.core.http.HttpClient; +import com.sinch.sdk.domains.sms.api.v1.internal.InboundsApi; +import com.sinch.sdk.domains.sms.models.v1.inbounds.BinaryMessage; +import com.sinch.sdk.domains.sms.models.v1.inbounds.InboundMessage; +import com.sinch.sdk.domains.sms.models.v1.inbounds.TextMessage; +import com.sinch.sdk.domains.sms.models.v1.inbounds.request.ListInboundMessagesQueryParameters; +import com.sinch.sdk.domains.sms.models.v1.inbounds.response.ListInboundsResponse; +import com.sinch.sdk.domains.sms.models.v1.inbounds.response.internal.ApiInboundList; +import com.sinch.sdk.models.SmsContext; +import java.time.Instant; +import java.util.Iterator; +import java.util.Map; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; + +@TestWithResources +class InboundsServiceTest extends BaseTest { + + @Mock SmsContext context; + @Mock HttpClient httpClient; + @Mock Map authManagers; + @Mock InboundsApi api; + InboundsService service; + + String uriPartID = "foovalue"; + + @GivenJsonResource("/domains/sms/v1/inbounds/MOBinaryDto.json") + InboundMessage binary; + + @GivenJsonResource("/domains/sms/v1/inbounds/MOTextDto.json") + InboundMessage text; + + @GivenJsonResource("/domains/sms/v1/inbounds/MOMediaDto.json") + InboundMessage media; + + @GivenJsonResource("/domains/sms/v1/inbounds/response/internal/InboundsListResponseDtoPage0.json") + ApiInboundList inboundsLisResponseDtoPage0; + + @GivenJsonResource("/domains/sms/v1/inbounds/response/internal/InboundsListResponseDtoPage1.json") + ApiInboundList inboundsLisResponseDtoPage1; + + @GivenJsonResource("/domains/sms/v1/inbounds/response/internal/InboundsListResponseDtoPage2.json") + ApiInboundList inboundsLisResponseDtoPage2; + + @BeforeEach + public void initMocks() { + service = spy(new InboundsService(uriPartID, context, httpClient, authManagers)); + doReturn(api).when(service).getApi(); + } + + @Test + void getBinary() throws ApiException { + + when(api.get(eq("foo inbound ID"))).thenReturn(binary); + + InboundMessage response = service.get("foo inbound ID"); + + TestHelpers.recursiveEquals(response, binary); + } + + @Test + void getText() throws ApiException { + + when(api.get(eq("foo inbound ID"))).thenReturn(text); + + InboundMessage response = service.get("foo inbound ID"); + + TestHelpers.recursiveEquals(response, text); + } + + @Test + void getMedia() throws ApiException { + + when(api.get(eq("foo inbound ID"))).thenReturn(media); + + InboundMessage response = service.get("foo inbound ID"); + + TestHelpers.recursiveEquals(response, media); + } + + @Test + void list() throws ApiException { + + ListInboundMessagesQueryParameters initialRequest = + ListInboundMessagesQueryParameters.builder().build(); + ListInboundMessagesQueryParameters page1 = + ListInboundMessagesQueryParameters.builder().setPage(1).build(); + ListInboundMessagesQueryParameters page2 = + ListInboundMessagesQueryParameters.builder().setPage(2).build(); + + when(api.list(initialRequest)).thenReturn(inboundsLisResponseDtoPage0); + when(api.list(page1)).thenReturn(inboundsLisResponseDtoPage1); + when(api.list(page2)).thenReturn(inboundsLisResponseDtoPage2); + + ListInboundsResponse response = service.list(initialRequest); + + Iterator iterator = response.iterator(); + InboundMessage item = iterator.next(); + Assertions.assertThat(item) + .usingRecursiveComparison() + .isEqualTo( + BinaryMessage.builder() + .setBody("a body") + .setClientReference("a client reference") + .setFrom("+11203494390") + .setId("01FC66621XXXXX119Z8PMV1QPA") + .setOperatorId("35000") + .setReceivedAt(Instant.parse("2019-08-24T14:17:22Z")) + .setSentAt(Instant.parse("2019-08-24T14:15:22Z")) + .setTo("11203453453") + .setUdh("foo udh") + .build()); + + item = iterator.next(); + Assertions.assertThat(iterator.hasNext()).isEqualTo(true); + Assertions.assertThat(item) + .usingRecursiveComparison() + .isEqualTo( + TextMessage.builder() + .setBody("a body") + .setClientReference("a client reference") + .setFrom("+11203494390") + .setId("01FC66621XXXXX119Z8PMV1QPA") + .setOperatorId("35000") + .setReceivedAt(Instant.parse("2019-08-24T14:17:22Z")) + .setSentAt(Instant.parse("2019-08-24T14:15:22Z")) + .setTo("11203453453") + .build()); + + item = iterator.next(); + Assertions.assertThat(iterator.hasNext()).isEqualTo(false); + Assertions.assertThat(item) + .usingRecursiveComparison() + .isEqualTo( + BinaryMessage.builder() + .setBody("a body") + .setClientReference("a client reference") + .setFrom("+11203494390") + .setId("01FC66621XXXXX119Z8PMV1QPA") + .setOperatorId("35000") + .setReceivedAt(Instant.parse("2019-08-24T14:17:22Z")) + .setSentAt(Instant.parse("2019-08-24T14:15:22Z")) + .setTo("11203453453") + .setUdh("foo udh") + .build()); + } +} diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/api/v1/internal/InboundsApiTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/api/v1/internal/InboundsApiTest.java new file mode 100644 index 00000000..17d63616 --- /dev/null +++ b/client/src/test/java/com/sinch/sdk/domains/sms/api/v1/internal/InboundsApiTest.java @@ -0,0 +1,141 @@ +package com.sinch.sdk.domains.sms.api.v1.internal; + +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import com.adelean.inject.resources.junit.jupiter.GivenJsonResource; +import com.adelean.inject.resources.junit.jupiter.GivenTextResource; +import com.adelean.inject.resources.junit.jupiter.TestWithResources; +import com.sinch.sdk.BaseTest; +import com.sinch.sdk.core.TestHelpers; +import com.sinch.sdk.core.exceptions.ApiException; +import com.sinch.sdk.core.http.AuthManager; +import com.sinch.sdk.core.http.HttpClient; +import com.sinch.sdk.core.http.HttpContentType; +import com.sinch.sdk.core.http.HttpMapper; +import com.sinch.sdk.core.http.HttpMethod; +import com.sinch.sdk.core.http.HttpRequest; +import com.sinch.sdk.core.http.HttpRequestTest.HttpRequestMatcher; +import com.sinch.sdk.core.http.HttpResponse; +import com.sinch.sdk.core.http.URLParameter; +import com.sinch.sdk.core.http.URLParameter.STYLE; +import com.sinch.sdk.core.models.ServerConfiguration; +import com.sinch.sdk.domains.sms.models.v1.inbounds.InboundMessage; +import com.sinch.sdk.domains.sms.models.v1.inbounds.TextMessage; +import com.sinch.sdk.domains.sms.models.v1.inbounds.request.ListInboundMessagesQueryParameters; +import com.sinch.sdk.domains.sms.models.v1.inbounds.response.internal.ApiInboundList; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; + +@TestWithResources +public class InboundsApiTest extends BaseTest { + + static final String SMS_AUTH_NAMES = "BearerAuth"; + + @GivenTextResource("/domains/sms/v1/inbounds/MOTextDto.json") + String jsonTextMessageDto; + + @GivenJsonResource("/domains/sms/v1/inbounds/MOTextDto.json") + TextMessage textMessageDto; + + @GivenTextResource("/domains/sms/v1/inbounds/response/internal/InboundsListResponseDtoPage0.json") + String jsonInboundsListResponseDto; + + @GivenJsonResource("/domains/sms/v1/inbounds/response/internal/InboundsListResponseDtoPage0.json") + ApiInboundList listInboundsListResponseDto; + + @Mock HttpClient httpClient; + @Mock ServerConfiguration serverConfiguration; + + HttpMapper httpMapper = new HttpMapper(); + @Mock Map authManagers; + InboundsApi api; + String uriPartID = "foovalue"; + + @BeforeEach + public void initMocks() { + api = + spy(new InboundsApi(httpClient, serverConfiguration, authManagers, httpMapper, uriPartID)); + } + + @Test + void get() throws ApiException { + + HttpRequest httpRequest = + new HttpRequest( + "/xms/v1/foovalue/inbounds/foo%20binary%20batch%20id", + HttpMethod.GET, + Collections.emptyList(), + null, + Collections.emptyMap(), + Collections.singletonList(HttpContentType.APPLICATION_JSON), + Collections.emptyList(), + Collections.singletonList(SMS_AUTH_NAMES)); + HttpResponse httpResponse = + new HttpResponse(200, null, Collections.emptyMap(), jsonTextMessageDto.getBytes()); + + when(httpClient.invokeAPI( + eq(serverConfiguration), + eq(authManagers), + argThat(new HttpRequestMatcher(httpRequest)))) + .thenReturn(httpResponse); + + InboundMessage response = api.get("foo binary batch id"); + + TestHelpers.recursiveEquals(response, textMessageDto); + } + + @Test + void list() throws ApiException { + + Collection urlParameters = + Arrays.asList( + new URLParameter("page", 1, STYLE.FORM, true), + new URLParameter("page_size", 2, STYLE.FORM, true), + new URLParameter("to", "+1234567890", STYLE.FORM, true), + new URLParameter("start_date", "2023-11-03T15:21:21.113Z", STYLE.FORM, true), + new URLParameter("end_date", "2023-12-12T15:54:21.321Z", STYLE.FORM, true), + new URLParameter("client_reference", "client reference", STYLE.FORM, true)); + + HttpRequest httpRequest = + new HttpRequest( + "/xms/v1/foovalue/inbounds", + HttpMethod.GET, + urlParameters, + null, + Collections.emptyMap(), + Collections.singletonList(HttpContentType.APPLICATION_JSON), + Collections.emptyList(), + Collections.singletonList(SMS_AUTH_NAMES)); + HttpResponse httpResponse = + new HttpResponse(200, null, Collections.emptyMap(), jsonInboundsListResponseDto.getBytes()); + + when(httpClient.invokeAPI( + eq(serverConfiguration), + eq(authManagers), + argThat(new HttpRequestMatcher(httpRequest)))) + .thenReturn(httpResponse); + + ListInboundMessagesQueryParameters initialRequest = + ListInboundMessagesQueryParameters.builder() + .setPage(1) + .setPageSize(2) + .setTo(Arrays.asList("+1234567890")) + .setClientReference("client reference") + .setStartDate(Instant.parse("2023-11-03T15:21:21.113Z")) + .setEndDate(Instant.parse("2023-12-12T15:54:21.321Z")) + .build(); + + ApiInboundList response = api.list(initialRequest); + + TestHelpers.recursiveEquals(response, listInboundsListResponseDto); + } +} diff --git a/client/src/test/java/com/sinch/sdk/e2e/domains/sms/v1/InboundsSteps.java b/client/src/test/java/com/sinch/sdk/e2e/domains/sms/v1/InboundsSteps.java new file mode 100644 index 00000000..0a031143 --- /dev/null +++ b/client/src/test/java/com/sinch/sdk/e2e/domains/sms/v1/InboundsSteps.java @@ -0,0 +1,113 @@ +package com.sinch.sdk.e2e.domains.sms.v1; + +import com.sinch.sdk.core.TestHelpers; +import com.sinch.sdk.domains.sms.api.v1.InboundsService; +import com.sinch.sdk.domains.sms.models.v1.inbounds.InboundMessage; +import com.sinch.sdk.domains.sms.models.v1.inbounds.TextMessage; +import com.sinch.sdk.domains.sms.models.v1.inbounds.request.ListInboundMessagesQueryParameters; +import com.sinch.sdk.domains.sms.models.v1.inbounds.response.ListInboundsResponse; +import com.sinch.sdk.e2e.Config; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import java.time.Instant; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Assertions; + +public class InboundsSteps { + + InboundsService service; + InboundMessage getResponse; + ListInboundsResponse listOnePageResponse; + ListInboundsResponse listAllResponse; + ListInboundsResponse listAllByPageResponse; + + @Given("^the SMS service \"Inbounds\" is available") + public void serviceAvailable() { + + service = Config.getSinchClient().sms().v1().inbounds(); + } + + @When("^I send a request to retrieve an inbound message") + public void get() { + + getResponse = service.get("inboundid"); + } + + @When("^I send a request to list the inbound messages$") + public void listOnePage() { + ListInboundMessagesQueryParameters request = + ListInboundMessagesQueryParameters.builder() + .setTo(Arrays.asList("12017777777", "12018888888")) + .setPageSize(2) + .build(); + + listOnePageResponse = service.list(request); + } + + @When("^I send a request to list all the inbound messages$") + public void listAll() { + ListInboundMessagesQueryParameters request = + ListInboundMessagesQueryParameters.builder() + .setTo(Arrays.asList("12017777777", "12018888888")) + .setPageSize(2) + .build(); + + listAllResponse = service.list(request); + } + + @When("^I iterate manually over the inbound messages pages$") + public void listAllByPage() { + ListInboundMessagesQueryParameters request = + ListInboundMessagesQueryParameters.builder() + .setTo(Arrays.asList("12017777777", "12018888888")) + .setPageSize(2) + .build(); + + listAllByPageResponse = service.list(request); + } + + @Then("the response contains the inbound message details") + public void getResult() { + TextMessage expected = + TextMessage.builder() + .setBody("Hello John!") + .setFrom("12015555555") + .setId("01W4FFL35P4NC4K35INBOUND01") + .setOperatorId("311071") + .setReceivedAt(Instant.parse("2024-06-06T14:16:54.777Z")) + .setTo("12017777777") + .build(); + + TestHelpers.recursiveEquals(getResponse, expected); + } + + @Then("the response contains \"{int}\" inbound messages") + public void onePageResult(int expected) { + + Assertions.assertEquals(listOnePageResponse.getContent().size(), expected); + } + + @Then("the inbound messages list contains \"{int}\" inbound messages") + public void listAllResult(int expected) { + ListInboundsResponse response = + null != listAllResponse ? listAllResponse : listAllByPageResponse; + + AtomicInteger count = new AtomicInteger(); + response.iterator().forEachRemaining(_unused -> count.getAndIncrement()); + + Assertions.assertEquals(count.get(), expected); + } + + @Then("the inbound messages iteration result contains the data from \"{int}\" pages") + public void listAllByPageResult(int expected) { + + int count = listAllByPageResponse.getContent().isEmpty() ? 0 : 1; + while (listAllByPageResponse.hasNextPage()) { + count++; + listAllByPageResponse = listAllByPageResponse.nextPage(); + } + Assertions.assertEquals(count, expected); + } +} diff --git a/client/src/test/java/com/sinch/sdk/e2e/domains/sms/v1/SmsIT.java b/client/src/test/java/com/sinch/sdk/e2e/domains/sms/v1/SmsIT.java index 4229a276..4519cbf5 100644 --- a/client/src/test/java/com/sinch/sdk/e2e/domains/sms/v1/SmsIT.java +++ b/client/src/test/java/com/sinch/sdk/e2e/domains/sms/v1/SmsIT.java @@ -12,5 +12,6 @@ @SuiteDisplayName("SMS V1") @IncludeEngines("cucumber") @SelectClasspathResource("features/sms/batches.feature") +@SelectClasspathResource("features/sms/inbounds.feature") @ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.sinch.sdk.e2e.domains.sms.v1") public class SmsIT {} diff --git a/core/src/main/com/sinch/sdk/core/databind/query_parameter/CollectionStringToCommaSerializer.java b/core/src/main/com/sinch/sdk/core/databind/query_parameter/CollectionStringToCommaSerializer.java new file mode 100644 index 00000000..3255642b --- /dev/null +++ b/core/src/main/com/sinch/sdk/core/databind/query_parameter/CollectionStringToCommaSerializer.java @@ -0,0 +1,27 @@ +package com.sinch.sdk.core.databind.query_parameter; + +import com.sinch.sdk.core.databind.QueryParameterSerializer; +import java.util.Collection; + +public class CollectionStringToCommaSerializer + implements QueryParameterSerializer, String> { + + public static CollectionStringToCommaSerializer getInstance() { + return CollectionStringToCommaSerializer.LazyHolder.INSTANCE; + } + + @Override + public String apply(Collection collection) { + if (null == collection) { + return null; + } + return String.join(",", collection); + } + + private static class LazyHolder { + private static final CollectionStringToCommaSerializer INSTANCE = + new CollectionStringToCommaSerializer(); + } + + private CollectionStringToCommaSerializer() {} +} diff --git a/core/src/main/com/sinch/sdk/core/databind/query_parameter/InstantToIso8601Serializer.java b/core/src/main/com/sinch/sdk/core/databind/query_parameter/InstantToIso8601Serializer.java index 1381407a..b41c9fd9 100644 --- a/core/src/main/com/sinch/sdk/core/databind/query_parameter/InstantToIso8601Serializer.java +++ b/core/src/main/com/sinch/sdk/core/databind/query_parameter/InstantToIso8601Serializer.java @@ -22,5 +22,4 @@ private static class LazyHolder { } private InstantToIso8601Serializer() {} - ; } diff --git a/core/src/test/java/com/sinch/sdk/core/databind/query_parameter/CollectionStringToCommaSerializerTest.java b/core/src/test/java/com/sinch/sdk/core/databind/query_parameter/CollectionStringToCommaSerializerTest.java new file mode 100644 index 00000000..d90add52 --- /dev/null +++ b/core/src/test/java/com/sinch/sdk/core/databind/query_parameter/CollectionStringToCommaSerializerTest.java @@ -0,0 +1,49 @@ +package com.sinch.sdk.core.databind.query_parameter; + +import com.sinch.sdk.core.TestHelpers; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class CollectionStringToCommaSerializerTest { + + CollectionStringToCommaSerializer serializer = CollectionStringToCommaSerializer.getInstance(); + + @Test + void serialize() { + + List list = Arrays.asList("foo1", "foo2"); + + String serialized = serializer.apply(list); + + TestHelpers.recursiveEquals("foo1,foo2", serialized); + } + + @Test + void serializeSingle() { + + List list = Collections.singletonList("foo1"); + + String serialized = serializer.apply(list); + + TestHelpers.recursiveEquals("foo1", serialized); + } + + @Test + void serializeEmpty() { + + String serialized = serializer.apply(Collections.emptyList()); + + Assertions.assertEquals("", serialized); + } + + @Test + void serializeNull() { + + String serialized = serializer.apply(null); + + Assertions.assertNull(serialized); + } +} diff --git a/openapi-contracts/src/test/java/com/sinch/sdk/domains/sms/models/v1/inbounds/InboundMessageDtoTest.java b/openapi-contracts/src/test/java/com/sinch/sdk/domains/sms/models/v1/inbounds/InboundMessageDtoTest.java new file mode 100644 index 00000000..a0abda16 --- /dev/null +++ b/openapi-contracts/src/test/java/com/sinch/sdk/domains/sms/models/v1/inbounds/InboundMessageDtoTest.java @@ -0,0 +1,89 @@ +package com.sinch.sdk.domains.sms.models.v1.inbounds; + +import com.adelean.inject.resources.junit.jupiter.GivenJsonResource; +import com.adelean.inject.resources.junit.jupiter.TestWithResources; +import com.sinch.sdk.BaseTest; +import java.time.Instant; +import java.util.Arrays; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +@TestWithResources +class InboundMessageDtoTest extends BaseTest { + + @GivenJsonResource("/domains/sms/v1/inbounds/MOBinaryDto.json") + InboundMessage loadedBinaryMessage; + + @GivenJsonResource("/domains/sms/v1/inbounds/MOTextDto.json") + InboundMessage loadedTextMessage; + + @GivenJsonResource("/domains/sms/v1/inbounds/MOMediaDto.json") + InboundMessage loadedMediaMessage; + + BinaryMessage binaryDTO = + BinaryMessage.builder() + .setClientReference("a client reference") + .setFrom("+11203494390") + .setId("01FC66621XXXXX119Z8PMV1QPA") + .setOperatorId("35000") + .setReceivedAt(Instant.parse("2019-08-24T14:17:22Z")) + .setSentAt(Instant.parse("2019-08-24T14:15:22Z")) + .setTo("11203453453") + .setBody("a body") + .setUdh("foo udh") + .build(); + + TextMessage textDTO = + TextMessage.builder() + .setClientReference("a client reference") + .setFrom("+11203494390") + .setId("01FC66621XXXXX119Z8PMV1QPA") + .setOperatorId("35000") + .setReceivedAt(Instant.parse("2019-08-24T14:17:22Z")) + .setSentAt(Instant.parse("2019-08-24T14:15:22Z")) + .setTo("11203453453") + .setBody("a body") + .build(); + + MediaMessage mediaDTO = + MediaMessage.builder() + .setClientReference("a client reference") + .setFrom("+11203494390") + .setId("01FC66621XXXXX119Z8PMV1QPA") + .setOperatorId("35000") + .setReceivedAt(Instant.parse("2019-08-24T14:17:22Z")) + .setSentAt(Instant.parse("2019-08-24T14:15:22Z")) + .setTo("11203453453") + .setBody( + MediaMessageBody.builder() + .setMessage("my message") + .setSubject("mmy subject") + .setMedia( + Arrays.asList( + MediaMessageBodyDetails.builder() + .setCode(1234) + .setContentType("content/type") + .setStatus("a status") + .setUrl("https://foo.url") + .build())) + .build()) + .build(); + + @Test + void deserializeBinaryMessage() { + + Assertions.assertThat(loadedBinaryMessage).usingRecursiveComparison().isEqualTo(binaryDTO); + } + + @Test + void deserializeTextMessage() { + + Assertions.assertThat(loadedTextMessage).usingRecursiveComparison().isEqualTo(textDTO); + } + + @Test + void deserializeMediaMessage() { + + Assertions.assertThat(loadedMediaMessage).usingRecursiveComparison().isEqualTo(mediaDTO); + } +} diff --git a/openapi-contracts/src/test/resources/domains/sms/v1/inbounds/MOMediaDto.json b/openapi-contracts/src/test/resources/domains/sms/v1/inbounds/MOMediaDto.json new file mode 100644 index 00000000..36459ad8 --- /dev/null +++ b/openapi-contracts/src/test/resources/domains/sms/v1/inbounds/MOMediaDto.json @@ -0,0 +1,22 @@ +{ + "body": { + "subject": "mmy subject", + "message": "my message", + "media": [ + { + "url": "https://foo.url", + "contentType": "content/type", + "status": "a status", + "code": 1234 + } + ] + }, + "client_reference": "a client reference", + "from": "+11203494390", + "id": "01FC66621XXXXX119Z8PMV1QPA", + "operator_id": "35000", + "received_at": "2019-08-24T14:17:22Z", + "sent_at": "2019-08-24T14:15:22Z", + "to": "11203453453", + "type": "mo_media" +} diff --git a/sample-app/src/main/java/com/sinch/sample/sms/v1/inbounds/Get.java b/sample-app/src/main/java/com/sinch/sample/sms/v1/inbounds/Get.java new file mode 100644 index 00000000..ad35bd61 --- /dev/null +++ b/sample-app/src/main/java/com/sinch/sample/sms/v1/inbounds/Get.java @@ -0,0 +1,35 @@ +package com.sinch.sample.sms.v1.inbounds; + +import com.sinch.sample.BaseApplication; +import com.sinch.sdk.domains.sms.api.v1.InboundsService; +import com.sinch.sdk.domains.sms.models.v1.inbounds.InboundMessage; +import java.io.IOException; +import java.util.logging.Logger; + +public class Get extends BaseApplication { + private static final Logger LOGGER = + Logger.getLogger(com.sinch.sample.sms.deliveryReports.Get.class.getName()); + + public Get() throws IOException {} + + public static void main(String[] args) { + try { + new Get().run(); + } catch (Exception e) { + LOGGER.severe(e.getMessage()); + e.printStackTrace(); + } + } + + public void run() { + + InboundsService service = client.sms().v1().inbounds(); + + String inboundId = "01JFFMTMJ1AY6TAYEPDR4CYG3S"; + LOGGER.info("Get for: " + inboundId); + + InboundMessage response = service.get(inboundId); + + LOGGER.info("Response :" + response); + } +} diff --git a/sample-app/src/main/java/com/sinch/sample/sms/v1/inbounds/List.java b/sample-app/src/main/java/com/sinch/sample/sms/v1/inbounds/List.java new file mode 100644 index 00000000..267b48f4 --- /dev/null +++ b/sample-app/src/main/java/com/sinch/sample/sms/v1/inbounds/List.java @@ -0,0 +1,41 @@ +package com.sinch.sample.sms.v1.inbounds; + +import com.sinch.sample.BaseApplication; +import com.sinch.sdk.domains.sms.api.v1.InboundsService; +import com.sinch.sdk.domains.sms.models.v1.inbounds.request.ListInboundMessagesQueryParameters; +import java.io.IOException; +import java.time.Instant; +import java.time.Period; +import java.util.logging.Logger; + +public class List extends BaseApplication { + + private static final Logger LOGGER = Logger.getLogger(List.class.getName()); + + public List() throws IOException {} + + public static void main(String[] args) { + try { + new List().run(); + } catch (Exception e) { + LOGGER.severe(e.getMessage()); + e.printStackTrace(); + } + } + + public void run() { + + InboundsService service = client.sms().v1().inbounds(); + + LOGGER.info("List inbounds"); + + ListInboundMessagesQueryParameters queryParameters = + ListInboundMessagesQueryParameters.builder() + .setPageSize(1) + .setStartDate(Instant.now().minus(Period.ofWeeks(3))) + .build(); + + LOGGER.info("Response:"); + service.list(queryParameters).iterator().forEachRemaining(f -> LOGGER.info(f.toString())); + } +}