diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 97d5e735e8..845584e4de 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,4 +1,4 @@ -name: Publish Helm Chart +name: Publish on: push: diff --git a/AdminApi.Sdk/Client.cs b/AdminApi.Sdk/Client.cs index c961e3a593..48e63098d5 100644 --- a/AdminApi.Sdk/Client.cs +++ b/AdminApi.Sdk/Client.cs @@ -10,7 +10,6 @@ using Backbone.AdminApi.Sdk.Endpoints.Relationships; using Backbone.AdminApi.Sdk.Endpoints.Tiers; using Backbone.BuildingBlocks.SDK.Endpoints.Common; -using Backbone.Tooling.JsonConverters; namespace Backbone.AdminApi.Sdk; @@ -21,7 +20,6 @@ private Client(HttpClient httpClient, string apiKey) var authenticator = new XsrfAndApiKeyAuthenticator(apiKey, httpClient); var jsonSerializerOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; - jsonSerializerOptions.Converters.Add(new UrlSafeBase64ToByteArrayJsonConverter()); var endpointClient = new EndpointClient(httpClient, authenticator, jsonSerializerOptions); diff --git a/AdminApi/test/AdminApi.Tests.Integration/Features/Clients/DELETE.feature b/AdminApi/test/AdminApi.Tests.Integration/Features/Clients/DELETE.feature index f7d7a05c81..c90c84b5db 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/Features/Clients/DELETE.feature +++ b/AdminApi/test/AdminApi.Tests.Integration/Features/Clients/DELETE.feature @@ -12,4 +12,4 @@ Scenario: Deleting a non-existent Client Given a non-existent Client c When a DELETE request is sent to the /Clients endpoint Then the response status code is 404 (Not Found) - And the response content includes an error with the error code "error.platform.recordNotFound" + And the response content contains an error with the error code "error.platform.recordNotFound" diff --git a/AdminApi/test/AdminApi.Tests.Integration/Features/Clients/PATCH.feature b/AdminApi/test/AdminApi.Tests.Integration/Features/Clients/PATCH.feature index d038e9dd34..d54d0272ab 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/Features/Clients/PATCH.feature +++ b/AdminApi/test/AdminApi.Tests.Integration/Features/Clients/PATCH.feature @@ -18,4 +18,4 @@ Scenario: Changing the client secret of an existing Client with an empty secret Scenario: Changing the client secret of a non-existent Client When a PATCH request is sent to the /Clients/{clientId}/ChangeSecret endpoint Then the response status code is 404 (Not Found) - And the response content includes an error with the error code "error.platform.recordNotFound" + And the response content contains an error with the error code "error.platform.recordNotFound" diff --git a/AdminApi/test/AdminApi.Tests.Integration/Features/Clients/PUT.feature b/AdminApi/test/AdminApi.Tests.Integration/Features/Clients/PUT.feature index 14cd1efe29..3be484eca6 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/Features/Clients/PUT.feature +++ b/AdminApi/test/AdminApi.Tests.Integration/Features/Clients/PUT.feature @@ -21,9 +21,9 @@ Scenario: Changing the default tier of an existing Client with a non-existent ti Given a Client c When a PUT request is sent to the /Clients/{c.ClientId} endpoint with a non-existent tier id Then the response status code is 400 (Bad request) - And the response content includes an error with the error code "error.platform.validation.device.tierIdInvalidOrDoesNotExist" + And the response content contains an error with the error code "error.platform.validation.device.tierIdInvalidOrDoesNotExist" Scenario: Changing the default tier of a non-existing Client When a PUT request is sent to the /Clients/{c.clientId} endpoint with a non-existing clientId Then the response status code is 404 (Not Found) - And the response content includes an error with the error code "error.platform.recordNotFound" + And the response content contains an error with the error code "error.platform.recordNotFound" diff --git a/AdminApi/test/AdminApi.Tests.Integration/Features/IdentityDeletionProcess/POST.feature b/AdminApi/test/AdminApi.Tests.Integration/Features/IdentityDeletionProcess/POST.feature index ed0b7c0e40..a3f7b7cf05 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/Features/IdentityDeletionProcess/POST.feature +++ b/AdminApi/test/AdminApi.Tests.Integration/Features/IdentityDeletionProcess/POST.feature @@ -14,4 +14,4 @@ Scenario: There can only be one active deletion process And an active deletion process for Identity i exists When a POST request is sent to the /Identities/{i.id}/DeletionProcesses endpoint Then the response status code is 400 (Bad Request) - And the response content includes an error with the error code "error.platform.validation.device.onlyOneActiveDeletionProcessAllowed" + And the response content contains an error with the error code "error.platform.validation.device.onlyOneActiveDeletionProcessAllowed" diff --git a/AdminApi/test/AdminApi.Tests.Integration/Features/IndividualQuotas/DELETE.feature b/AdminApi/test/AdminApi.Tests.Integration/Features/IndividualQuotas/DELETE.feature index 61426a32c3..ba11d4510f 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/Features/IndividualQuotas/DELETE.feature +++ b/AdminApi/test/AdminApi.Tests.Integration/Features/IndividualQuotas/DELETE.feature @@ -12,4 +12,4 @@ Scenario: Deleting an inexistent Individual Quota Given an Identity i When a DELETE request is sent to the /Identities/{i.address}/Quotas/inexistentQuotaId endpoint Then the response status code is 404 (Not Found) - And the response content includes an error with the error code "error.platform.recordNotFound" + And the response content contains an error with the error code "error.platform.recordNotFound" diff --git a/AdminApi/test/AdminApi.Tests.Integration/Features/IndividualQuotas/POST.feature b/AdminApi/test/AdminApi.Tests.Integration/Features/IndividualQuotas/POST.feature index e10af97ff4..cf06f96531 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/Features/IndividualQuotas/POST.feature +++ b/AdminApi/test/AdminApi.Tests.Integration/Features/IndividualQuotas/POST.feature @@ -12,4 +12,4 @@ Scenario: Creating an Individual Quota for existing Identity Scenario: Creating an Individual Quota for inexistent Identity When a POST request is sent to the /Identity/{address}/Quotas endpoint with an inexistent identity address Then the response status code is 404 (Not Found) - And the response content includes an error with the error code "error.platform.recordNotFound" + And the response content contains an error with the error code "error.platform.recordNotFound" diff --git a/AdminApi/test/AdminApi.Tests.Integration/Features/Logs/POST.feature b/AdminApi/test/AdminApi.Tests.Integration/Features/Logs/POST.feature index 930dd165df..59dd07a9c2 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/Features/Logs/POST.feature +++ b/AdminApi/test/AdminApi.Tests.Integration/Features/Logs/POST.feature @@ -10,4 +10,4 @@ Scenario: Creating a Log Scenario: Creating a Log with an invalid Log Level fails When a POST request is sent to the /Logs endpoint with an invalid Log Level Then the response status code is 400 (Bad Request) - And the response content includes an error with the error code "error.platform.validation.invalidPropertyValue" + And the response content contains an error with the error code "error.platform.validation.invalidPropertyValue" diff --git a/AdminApi/test/AdminApi.Tests.Integration/Features/MessageOverviews/GET.feature b/AdminApi/test/AdminApi.Tests.Integration/Features/MessageOverviews/GET.feature index b37a333591..fe7588bb7a 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/Features/MessageOverviews/GET.feature +++ b/AdminApi/test/AdminApi.Tests.Integration/Features/MessageOverviews/GET.feature @@ -19,4 +19,4 @@ Scenario: Requesting an invalid type Message List of an Identity Given an Identity i When a GET request is sent to the /Messages endpoint with type 'InvalidType' and participant i.Address Then the response status code is 400 (Bad request) - And the response content includes an error with the error code "error.platform.validation.invalidPropertyValue" + And the response content contains an error with the error code "error.platform.validation.invalidPropertyValue" diff --git a/AdminApi/test/AdminApi.Tests.Integration/Features/TierQuotas/DELETE.feature b/AdminApi/test/AdminApi.Tests.Integration/Features/TierQuotas/DELETE.feature index a2cbfa5e2f..47162184f0 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/Features/TierQuotas/DELETE.feature +++ b/AdminApi/test/AdminApi.Tests.Integration/Features/TierQuotas/DELETE.feature @@ -12,4 +12,4 @@ Scenario: Deleting an inexistent Tier Quota Given a Tier t When a DELETE request is sent to the /Tiers/{t.id}/Quotas/{quotaId} endpoint with an inexistent quota id Then the response status code is 404 (Not Found) - And the response content includes an error with the error code "error.platform.recordNotFound" + And the response content contains an error with the error code "error.platform.recordNotFound" diff --git a/AdminApi/test/AdminApi.Tests.Integration/Features/TierQuotas/POST.feature b/AdminApi/test/AdminApi.Tests.Integration/Features/TierQuotas/POST.feature index e43656f193..5a7d2b391c 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/Features/TierQuotas/POST.feature +++ b/AdminApi/test/AdminApi.Tests.Integration/Features/TierQuotas/POST.feature @@ -12,4 +12,4 @@ Scenario: Creating a Tier Quota for existing Tier Scenario: Creating a Tier Quota for inexistent Tier When a POST request is sent to the /Tiers/{tierId}/Quotas endpoint with an inexistent tier id Then the response status code is 404 (Not Found) - And the response content includes an error with the error code "error.platform.recordNotFound" + And the response content contains an error with the error code "error.platform.recordNotFound" diff --git a/AdminApi/test/AdminApi.Tests.Integration/Features/Tiers/POST.feature b/AdminApi/test/AdminApi.Tests.Integration/Features/Tiers/POST.feature index c04a1964b2..be62495436 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/Features/Tiers/POST.feature +++ b/AdminApi/test/AdminApi.Tests.Integration/Features/Tiers/POST.feature @@ -12,4 +12,4 @@ Scenario: Creating a Tier with a name that already exists Given a Tier t When a POST request is sent to the /Tiers endpoint with the name t.Name Then the response status code is 400 (Bad Request) - And the response content includes an error with the error code "error.platform.validation.device.tierNameAlreadyExists" + And the response content contains an error with the error code "error.platform.validation.device.tierNameAlreadyExists" diff --git a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/ClientsStepDefinitions.cs b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/ClientsStepDefinitions.cs index 30d97abb02..45eda12578 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/ClientsStepDefinitions.cs +++ b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/ClientsStepDefinitions.cs @@ -224,7 +224,7 @@ public void ThenTheResponseStatusCodeIs(int expectedStatusCode) ((int)_updateClientResponse!.Status).Should().Be(expectedStatusCode); } - [Then(@"the response content includes an error with the error code ""([^""]+)""")] + [Then(@"the response content contains an error with the error code ""([^""]+)""")] public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCode) { if (_getClientsResponse != null) diff --git a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/IdentitiesApiStepDefinitions.cs b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/IdentitiesApiStepDefinitions.cs index 19e1cccdee..7c7bc1b96c 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/IdentitiesApiStepDefinitions.cs +++ b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/IdentitiesApiStepDefinitions.cs @@ -99,7 +99,7 @@ public void ThenTheResponseStatusCodeIs(int expectedStatusCode) ((int)_identityDeletionProcessResponse!.Status).Should().Be(expectedStatusCode); } - [Then(@"the response content includes an error with the error code ""([^""]+)""")] + [Then(@"the response content contains an error with the error code ""([^""]+)""")] public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCode) { if (_identityResponse != null) diff --git a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/IndividualQuotaStepDefinitions.cs b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/IndividualQuotaStepDefinitions.cs index fc5ba1a071..b5d97b3079 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/IndividualQuotaStepDefinitions.cs +++ b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/IndividualQuotaStepDefinitions.cs @@ -98,7 +98,7 @@ public void ThenTheResponseContainsAnIndividualQuota() _createQuotaResponse.Should().ComplyWithSchema(); } - [Then(@"the response content includes an error with the error code ""([^""]+)""")] + [Then(@"the response content contains an error with the error code ""([^""]+)""")] public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCode) { if (_createQuotaResponse != null) diff --git a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/LogsStepDefinitions.cs b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/LogsStepDefinitions.cs index b5ff42a98f..783320df09 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/LogsStepDefinitions.cs +++ b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/LogsStepDefinitions.cs @@ -46,7 +46,7 @@ public void ThenTheResponseStatusCodeIs(int expectedStatusCode) ((int)_postResponse!.Status).Should().Be(expectedStatusCode); } - [Then(@"the response content includes an error with the error code ""([^""]+)""")] + [Then(@"the response content contains an error with the error code ""([^""]+)""")] public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCode) { _postResponse!.Error.Should().NotBeNull(); diff --git a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/MessagesStepDefinitions.cs b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/MessagesStepDefinitions.cs index feb7dbc9fc..f802d80e54 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/MessagesStepDefinitions.cs +++ b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/MessagesStepDefinitions.cs @@ -47,7 +47,7 @@ public void ThenTheResponseContainsAListOfMessages() _messagesResponse.Should().ComplyWithSchema(); } - [Then(@"the response content includes an error with the error code ""([^""]+)""")] + [Then(@"the response content contains an error with the error code ""([^""]+)""")] public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCode) { if (_messagesResponse != null) diff --git a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/TierQuotaStepDefinitions.cs b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/TierQuotaStepDefinitions.cs index 9cc6d86272..67362f38bc 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/TierQuotaStepDefinitions.cs +++ b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/TierQuotaStepDefinitions.cs @@ -107,7 +107,7 @@ public void ThenTheResponseContainsATierQuotaDefinition() _createTierQuotaResponse.Should().ComplyWithSchema(); } - [Then(@"the response content includes an error with the error code ""([^""]+)""")] + [Then(@"the response content contains an error with the error code ""([^""]+)""")] public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCode) { if (_createTierQuotaResponse != null) diff --git a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/TiersStepDefinitions.cs b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/TiersStepDefinitions.cs index f5819fd295..386ab93328 100644 --- a/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/TiersStepDefinitions.cs +++ b/AdminApi/test/AdminApi.Tests.Integration/StepDefinitions/TiersStepDefinitions.cs @@ -113,7 +113,7 @@ public void ThenTheResponseStatusCodeIs(int expectedStatusCode) ((int)_deleteResponse!.Status).Should().Be(expectedStatusCode); } - [Then(@"the response content includes an error with the error code ""([^""]+)""")] + [Then(@"the response content contains an error with the error code ""([^""]+)""")] public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCode) { _tierResponse!.Error.Should().NotBeNull(); diff --git a/BuildingBlocks/src/BuildingBlocks.SDK/BuildingBlocks.SDK.csproj b/BuildingBlocks/src/BuildingBlocks.SDK/BuildingBlocks.SDK.csproj index a27447d636..d68b4da464 100644 --- a/BuildingBlocks/src/BuildingBlocks.SDK/BuildingBlocks.SDK.csproj +++ b/BuildingBlocks/src/BuildingBlocks.SDK/BuildingBlocks.SDK.csproj @@ -4,4 +4,7 @@ + + + diff --git a/BuildingBlocks/src/BuildingBlocks.SDK/Endpoints/Common/EndpointClient.cs b/BuildingBlocks/src/BuildingBlocks.SDK/Endpoints/Common/EndpointClient.cs index 49c9e18a0d..ff1dd1aad1 100644 --- a/BuildingBlocks/src/BuildingBlocks.SDK/Endpoints/Common/EndpointClient.cs +++ b/BuildingBlocks/src/BuildingBlocks.SDK/Endpoints/Common/EndpointClient.cs @@ -5,6 +5,7 @@ using System.Text.Json; using System.Web; using Backbone.BuildingBlocks.SDK.Endpoints.Common.Types; +using Backbone.Tooling.JsonConverters; using JsonSerializer = System.Text.Json.JsonSerializer; namespace Backbone.BuildingBlocks.SDK.Endpoints.Common; @@ -33,6 +34,7 @@ public EndpointClient(HttpClient httpClient, IAuthenticator authenticator, JsonS _httpClient = httpClient; _authenticator = authenticator; _jsonSerializerOptions = jsonSerializerOptions; + jsonSerializerOptions.Converters.Add(new UrlSafeBase64ToByteArrayJsonConverter()); } public async Task> Post(string url, object? requestContent = null) diff --git a/ConsumerApi.Sdk/Endpoints/Tokens/TokensEndpoint.cs b/ConsumerApi.Sdk/Endpoints/Tokens/TokensEndpoint.cs index 8323bc4093..4d34e3d79f 100644 --- a/ConsumerApi.Sdk/Endpoints/Tokens/TokensEndpoint.cs +++ b/ConsumerApi.Sdk/Endpoints/Tokens/TokensEndpoint.cs @@ -13,6 +13,11 @@ public async Task> CreateToken(CreateTokenReque return await _client.Post($"api/{API_VERSION}/Tokens", request); } + public async Task> CreateTokenUnauthenticated(CreateTokenRequest request) + { + return await _client.PostUnauthenticated($"api/{API_VERSION}/Tokens", request); + } + public async Task> ListTokens(PaginationFilter? pagination = null) { return await _client.Get($"api/{API_VERSION}/Tokens", null, pagination); diff --git a/ConsumerApi.Tests.Integration/API/BaseApi.cs b/ConsumerApi.Tests.Integration/API/BaseApi.cs deleted file mode 100644 index 7d1ad9ae63..0000000000 --- a/ConsumerApi.Tests.Integration/API/BaseApi.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System.Net; -using System.Net.Http.Headers; -using System.Text.Json; -using Backbone.BuildingBlocks.API; -using Backbone.ConsumerApi.Tests.Integration.Models; -using Newtonsoft.Json; -using JsonSerializer = System.Text.Json.JsonSerializer; - -namespace Backbone.ConsumerApi.Tests.Integration.API; - -internal class BaseApi -{ - protected const string ROUTE_PREFIX = "/api/v1"; - private readonly HttpClient _httpClient; - private AccessTokenResponse? _accessTokenResponse; - - protected BaseApi(HttpClientFactory factory) - { - _httpClient = factory.CreateClient(); - - ServicePointManager.ServerCertificateValidationCallback += - (_, _, _, _) => true; - } - - protected async Task> Get(string endpoint, RequestConfiguration requestConfiguration) - { - return await ExecuteRequest(HttpMethod.Get, endpoint, requestConfiguration); - } - - protected async Task> Post(string endpoint, RequestConfiguration requestConfiguration) - { - return await ExecuteRequest(HttpMethod.Post, endpoint, requestConfiguration); - } - - protected async Task Post(string endpoint, RequestConfiguration requestConfiguration) - { - return await ExecuteRequest(HttpMethod.Post, endpoint, requestConfiguration); - } - - protected async Task> Put(string endpoint, RequestConfiguration requestConfiguration) - { - return await ExecuteRequest(HttpMethod.Put, endpoint, requestConfiguration); - } - - protected async Task Delete(string endpoint, RequestConfiguration requestConfiguration) - { - return await ExecuteRequest(HttpMethod.Delete, endpoint, requestConfiguration); - } - - private async Task ExecuteRequest(HttpMethod method, string endpoint, RequestConfiguration requestConfiguration) - { - var request = new HttpRequestMessage(method, ROUTE_PREFIX + endpoint); - - if (string.IsNullOrEmpty(requestConfiguration.ContentType)) - throw new ArgumentNullException(nameof(requestConfiguration.ContentType)); - - if (!string.IsNullOrEmpty(requestConfiguration.Content)) - request.Content = new StringContent(requestConfiguration.Content, MediaTypeHeaderValue.Parse(requestConfiguration.ContentType)); - - if (!string.IsNullOrEmpty(requestConfiguration.AcceptHeader)) - request.Headers.Add("Accept", requestConfiguration.AcceptHeader); - - if (requestConfiguration.Authenticate) - { - var tokenResponse = await GetAccessToken(requestConfiguration.AuthenticationParameters); - request.Headers.Add("Authorization", $"Bearer {tokenResponse.AccessToken}"); - } - - var httpResponse = await _httpClient.SendAsync(request); - var responseRawContent = await httpResponse.Content.ReadAsStringAsync(); - var responseData = JsonConvert.DeserializeObject(await httpResponse.Content.ReadAsStringAsync())!; - - var response = new HttpResponse - { - IsSuccessStatusCode = httpResponse.IsSuccessStatusCode, - StatusCode = httpResponse.StatusCode, - Content = responseData, - ContentType = httpResponse.Content.Headers.ContentType?.MediaType, - RawContent = responseRawContent - }; - - return response; - } - - private async Task> ExecuteRequest(HttpMethod method, string endpoint, RequestConfiguration requestConfiguration) - { - var request = new HttpRequestMessage(method, ROUTE_PREFIX + endpoint); - - if (string.IsNullOrEmpty(requestConfiguration.ContentType)) - throw new ArgumentNullException(nameof(requestConfiguration.ContentType)); - - if (!string.IsNullOrEmpty(requestConfiguration.Content)) - request.Content = new StringContent(requestConfiguration.Content, MediaTypeHeaderValue.Parse(requestConfiguration.ContentType)); - - if (!string.IsNullOrEmpty(requestConfiguration.AcceptHeader)) - request.Headers.Add("Accept", requestConfiguration.AcceptHeader); - - if (requestConfiguration.Authenticate) - { - var tokenResponse = await GetAccessToken(requestConfiguration.AuthenticationParameters); - request.Headers.Add("Authorization", $"Bearer {tokenResponse.AccessToken}"); - } - - var httpResponse = await _httpClient.SendAsync(request); - var responseRawContent = await httpResponse.Content.ReadAsStringAsync(); - var responseData = JsonConvert.DeserializeObject>(responseRawContent); - - var response = new HttpResponse - { - IsSuccessStatusCode = httpResponse.IsSuccessStatusCode, - StatusCode = httpResponse.StatusCode, - Content = responseData!, - ContentType = httpResponse.Content.Headers.ContentType?.MediaType, - RawContent = responseRawContent - }; - - return response; - } - - private async Task GetAccessToken(AuthenticationParameters authenticationParams) - { - if (_accessTokenResponse is { IsExpired: false }) - { - return _accessTokenResponse; - } - - var form = new Dictionary() - { - { "grant_type", authenticationParams.GrantType }, - { "username", authenticationParams.Username }, - { "password", authenticationParams.Password }, - { "client_id", authenticationParams.ClientId }, - { "client_secret", authenticationParams.ClientSecret } - }; - - var request = new HttpRequestMessage(HttpMethod.Post, "/connect/token") { Content = new FormUrlEncodedContent(form) }; - var httpResponse = await _httpClient.SendAsync(request); - - var responseRawContent = await httpResponse.Content.ReadAsStringAsync(); - if (!httpResponse.IsSuccessStatusCode) - { - var errorMessage = JsonSerializer.Deserialize(responseRawContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true })?.Message!; - throw new AccessTokenRequestException(httpResponse.StatusCode, errorMessage); - } - - _accessTokenResponse = JsonSerializer.Deserialize(responseRawContent, new JsonSerializerOptions { PropertyNameCaseInsensitive = true })!; - - return _accessTokenResponse; - } -} diff --git a/ConsumerApi.Tests.Integration/API/ChallengesApi.cs b/ConsumerApi.Tests.Integration/API/ChallengesApi.cs deleted file mode 100644 index 692ff0cea6..0000000000 --- a/ConsumerApi.Tests.Integration/API/ChallengesApi.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Backbone.ConsumerApi.Tests.Integration.Models; - -namespace Backbone.ConsumerApi.Tests.Integration.API; - -internal class ChallengesApi : BaseApi -{ - public ChallengesApi(HttpClientFactory factory) : base(factory) { } - - internal async Task> CreateChallenge(RequestConfiguration requestConfiguration) - { - return await Post("/Challenges", requestConfiguration); - } -} diff --git a/ConsumerApi.Tests.Integration/API/DevicesApi.cs b/ConsumerApi.Tests.Integration/API/DevicesApi.cs deleted file mode 100644 index 0b71c31727..0000000000 --- a/ConsumerApi.Tests.Integration/API/DevicesApi.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Backbone.ConsumerApi.Tests.Integration.Models; - -namespace Backbone.ConsumerApi.Tests.Integration.API; - -internal class DevicesApi : BaseApi -{ - public DevicesApi(HttpClientFactory factory) : base(factory) { } - - public async Task> ListDevices(RequestConfiguration requestConfiguration) - { - return await Get("/Devices", requestConfiguration); - } - - public async Task> RegisterDevice(RequestConfiguration requestConfiguration) - { - return await Post("/Devices", requestConfiguration); - } - - internal async Task DeleteDevice(RequestConfiguration requestConfiguration, string id) - { - return await Delete($"/Devices/{id}", requestConfiguration); - } -} diff --git a/ConsumerApi.Tests.Integration/API/IdentitiesApi.cs b/ConsumerApi.Tests.Integration/API/IdentitiesApi.cs deleted file mode 100644 index 215aafae9a..0000000000 --- a/ConsumerApi.Tests.Integration/API/IdentitiesApi.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Backbone.ConsumerApi.Tests.Integration.Models; - -namespace Backbone.ConsumerApi.Tests.Integration.API; - -internal class IdentitiesApi : BaseApi -{ - public IdentitiesApi(HttpClientFactory factory) : base(factory) { } - - internal async Task> StartDeletionProcess(RequestConfiguration requestConfiguration) - { - return await Post("/Identities/Self/DeletionProcesses", requestConfiguration); - } - - internal async Task> CreateIdentity(RequestConfiguration requestConfiguration) - { - return await Post("/Identities", requestConfiguration); - } -} diff --git a/ConsumerApi.Tests.Integration/API/PushNotificationsApi.cs b/ConsumerApi.Tests.Integration/API/PushNotificationsApi.cs deleted file mode 100644 index 53fb569a84..0000000000 --- a/ConsumerApi.Tests.Integration/API/PushNotificationsApi.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Backbone.ConsumerApi.Tests.Integration.Models; -using Backbone.Modules.Devices.Application.PushNotifications.Commands.UpdateDeviceRegistration; - -namespace Backbone.ConsumerApi.Tests.Integration.API; -internal class PushNotificationsApi : BaseApi -{ - public PushNotificationsApi(HttpClientFactory factory) : base(factory) { } - - internal async Task> RegisterForPushNotifications(RequestConfiguration requestConfiguration) - { - return await Put("/Devices/Self/PushNotifications", requestConfiguration); - } -} diff --git a/ConsumerApi.Tests.Integration/API/TokensApi.cs b/ConsumerApi.Tests.Integration/API/TokensApi.cs deleted file mode 100644 index 5d1a5db33b..0000000000 --- a/ConsumerApi.Tests.Integration/API/TokensApi.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Backbone.ConsumerApi.Tests.Integration.Models; - -namespace Backbone.ConsumerApi.Tests.Integration.API; - -internal class TokensApi : BaseApi -{ - public TokensApi(HttpClientFactory factory) : base(factory) { } - - internal async Task> CreateToken(RequestConfiguration requestConfiguration) - { - return await Post("/Tokens", requestConfiguration); - } - - internal async Task> GetTokenById(RequestConfiguration requestConfiguration, string id) - { - return await Get($"/Tokens/{id}", requestConfiguration); - } - - internal async Task>> GetTokensByIds(RequestConfiguration requestConfiguration, IEnumerable ids) - { - var endpoint = "/Tokens"; - var queryString = string.Join("&", ids.Select(id => $"ids={id}")); - endpoint = $"{endpoint}?{queryString}"; - - return await Get>(endpoint, requestConfiguration); - } -} diff --git a/ConsumerApi.Tests.Integration/Configuration/Settings.cs b/ConsumerApi.Tests.Integration/Configuration/Settings.cs index c8e4c782ec..552b8f946d 100644 --- a/ConsumerApi.Tests.Integration/Configuration/Settings.cs +++ b/ConsumerApi.Tests.Integration/Configuration/Settings.cs @@ -4,9 +4,6 @@ namespace Backbone.ConsumerApi.Tests.Integration.Configuration; public class HttpConfiguration { - [Required] - public string BaseUrl { get; set; } = string.Empty; - [Required] public ClientCredentialsConfiguration ClientCredentials { get; set; } = new(); } diff --git a/ConsumerApi.Tests.Integration/Extensions/HttpResponseExtensions.cs b/ConsumerApi.Tests.Integration/Extensions/HttpResponseExtensions.cs deleted file mode 100644 index 186d563eb3..0000000000 --- a/ConsumerApi.Tests.Integration/Extensions/HttpResponseExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Backbone.ConsumerApi.Tests.Integration.Models; - -namespace Backbone.ConsumerApi.Tests.Integration.Extensions; - -public static class HttpResponseExtensions -{ - public static void AssertContentCompliesWithSchema(this HttpResponse response) - { - // JsonValidators.ValidateJsonSchema>(response.RawContent!, out var errors) - // .Should().BeTrue($"Response content does not comply with the {typeof(T).FullName} schema: {string.Join(", ", errors)}"); - } -} diff --git a/ConsumerApi.Tests.Integration/Features/Challenges/{id}/GET.feature b/ConsumerApi.Tests.Integration/Features/Challenges/{id}/GET.feature index 50d4eb1ec6..0d642bfd87 100644 --- a/ConsumerApi.Tests.Integration/Features/Challenges/{id}/GET.feature +++ b/ConsumerApi.Tests.Integration/Features/Challenges/{id}/GET.feature @@ -27,7 +27,7 @@ Scenario: Requesting a nonexistent Challenge as an authenticated user # Given the user is authenticated # When a GET request is sent to the Challenges/{id} endpoint with # Then the response status code is 400 (Bad Request) -# And the response content includes an error with the error code "error.platform.invalidId" +# And the response content contains an error with the error code "error.platform.invalidId" #Examples: # | id | description | # | CHLthishastoomanycharacters | More than 20 characters | diff --git a/ConsumerApi.Tests.Integration/Features/Devices/{id}/DELETE.feature b/ConsumerApi.Tests.Integration/Features/Devices/{id}/DELETE.feature index 7402bd7ff8..c7badb4554 100644 --- a/ConsumerApi.Tests.Integration/Features/Devices/{id}/DELETE.feature +++ b/ConsumerApi.Tests.Integration/Features/Devices/{id}/DELETE.feature @@ -5,7 +5,6 @@ User deletes an un-onboarded Device Scenario: Deleting an un-onboarded Device Given an Identity i with a device d1 - And the current user uses d1 And an un-onboarded device d2 When a DELETE request is sent to the Devices/{id} endpoint with d2.Id Then the response status code is 204 (Ok) @@ -13,18 +12,16 @@ Scenario: Deleting an un-onboarded Device Scenario: Deleting an onboarded Device is not possible Given an Identity i with a device d - And the current user uses d When a DELETE request is sent to the Devices/{id} endpoint with d.Id Then the response status code is 400 (Bad Request) - And the error code is "error.platform.validation.device.deviceCannotBeDeleted" + And the response content contains an error with the error code "error.platform.validation.device.deviceCannotBeDeleted" And d is not deleted Scenario: Deleting a non existent Device Given an Identity i with a device d1 - And the current user uses d1 When a DELETE request is sent to the Devices/{id} endpoint with a non existent id Then the response status code is 404 (Not Found) - And the error code is "error.platform.recordNotFound" + And the response content contains an error with the error code "error.platform.recordNotFound" And d1 is not deleted # baseApi is not capable to handle multiple identities diff --git a/ConsumerApi.Tests.Integration/Features/Identities/Self/DeletionProcess/POST.feature b/ConsumerApi.Tests.Integration/Features/Identities/Self/DeletionProcess/POST.feature index a97618bc07..9a4a1bf064 100644 --- a/ConsumerApi.Tests.Integration/Features/Identities/Self/DeletionProcess/POST.feature +++ b/ConsumerApi.Tests.Integration/Features/Identities/Self/DeletionProcess/POST.feature @@ -3,14 +3,16 @@ Feature: POST Identities/Self/DeletionProcess User starts a deletion process -// Scenario: Starting a deletion process -// Given no active deletion process for the identity exists -// When a POST request is sent to the /Identities/Self/DeletionProcesses endpoint -// Then the response status code is 201 (Created) -// And the response contains a Deletion Process +Scenario: Starting a deletion process + Given an Identity i + And no active deletion process for the identity exists + When a POST request is sent to the /Identities/Self/DeletionProcesses endpoint + Then the response status code is 201 (Created) + And the response contains a Deletion Process -// Scenario: There can only be one active deletion process -// Given an active deletion process for the identity exists -// When a POST request is sent to the /Identities/Self/DeletionProcesses endpoint -// Then the response status code is 400 (Bad Request) -// And the response content includes an error with the error code "error.platform.validation.device.onlyOneActiveDeletionProcessAllowed" +Scenario: There can only be one active deletion process + Given an Identity i + And an active deletion process for the identity exists + When a POST request is sent to the /Identities/Self/DeletionProcesses endpoint + Then the response status code is 400 (Bad Request) + And the response content contains an error with the error code "error.platform.validation.device.onlyOneActiveDeletionProcessAllowed" diff --git a/ConsumerApi.Tests.Integration/Features/Tokens/POST.feature b/ConsumerApi.Tests.Integration/Features/Tokens/POST.feature index ac9a9e70a5..b1803c369c 100644 --- a/ConsumerApi.Tests.Integration/Features/Tokens/POST.feature +++ b/ConsumerApi.Tests.Integration/Features/Tokens/POST.feature @@ -5,19 +5,13 @@ User creates a Token Scenario: Creating a Token as an authenticated user Given the user is authenticated - When a POST request is sent to the Tokens endpoint with - | Key | Value | - | ContentType | application/json | - | Content | {"content": "QQ==","expiresAt": ""} | + When a POST request is sent to the Tokens endpoint Then the response status code is 201 (Created) And the response contains a CreateTokenResponse Scenario: Creating a Token as an anonymous user Given the user is unauthenticated - When a POST request is sent to the Tokens endpoint with - | Key | Value | - | ContentType | application/json | - | Content | {"content": "QQ==","expiresAt": ""} | + When a POST request is sent to the Tokens endpoint Then the response status code is 401 (Unauthorized) #@ignore("skipping_due_to_required_backbone_changes") @@ -27,7 +21,7 @@ Scenario: Creating a Token as an anonymous user # | Key | Value | # | Content | {"expiresAt": ""} | # Then the response status code is 400 (Bad Request) -# And the response content includes an error with the error code "error.platform.validation.invalidPropertyValue" +# And the response content contains an error with the error code "error.platform.validation.invalidPropertyValue" # #@ignore("skipping_due_to_required_backbone_changes") #Scenario: Creating a Token with an empty "Content" request content property @@ -36,7 +30,7 @@ Scenario: Creating a Token as an anonymous user # | Key | Value | # | Content | {"content": "","expiresAt": ""} | # Then the response status code is 400 (Bad Request) -# And the response content includes an error with the error code "error.platform.validation.invalidPropertyValue" +# And the response content contains an error with the error code "error.platform.validation.invalidPropertyValue" # #@ignore("skipping_due_to_required_backbone_changes") #Scenario: Creating a Token with an invalid base64 in the "Content" property @@ -45,7 +39,7 @@ Scenario: Creating a Token as an anonymous user # | Key | Value | # | Content | {"content": "","expiresAt": ""} | # Then the response status code is 400 (Bad Request) -# And the response content includes an error with the error code "error.platform.validation.invalidPropertyValue" +# And the response content contains an error with the error code "error.platform.validation.invalidPropertyValue" # #@ignore("skipping_due_to_required_backbone_changes") #Scenario: Creating a Token without the "expiresAt" request content property @@ -54,7 +48,7 @@ Scenario: Creating a Token as an anonymous user # | Key | Value | # | Content | {"content": "QQ=="} | # Then the response status code is 400 (Bad Request) -# And the response content includes an error with the error code "error.platform.validation.invalidPropertyValue" +# And the response content contains an error with the error code "error.platform.validation.invalidPropertyValue" # #@ignore("skipping_due_to_required_backbone_changes") #Scenario: Creating a Token with a date in the past in the "expiresAt" request content property @@ -63,29 +57,21 @@ Scenario: Creating a Token as an anonymous user # | Key | Value | # | Content | {"content": "QQ==","expiresAt": ""} | # Then the response status code is 400 (Bad Request) -# And the response content includes an error with the error code "error.platform.validation.invalidPropertyValue" +# And the response content contains an error with the error code "error.platform.validation.invalidPropertyValue" # #@ignore("skipping_due_to_required_backbone_changes") #Scenario: Creating a Token without a request content # Given the user is authenticated # When a POST request is sent to the Tokens endpoint with no request content # Then the response status code is 400 (Bad Request) -# And the response content includes an error with the error code "error.platform.inputCannotBeParsed" - -Scenario: Creating a Token with an unsupported Content-Type - Given the user is authenticated - When a POST request is sent to the Tokens endpoint with - | Key | Value | - | ContentType | application/xml | - | Content | is some arbitrary xml | - Then the response status code is 415 (Unsupported Media Type) - +# And the response content contains an error with the error code "error.platform.inputCannotBeParsed" +# #@ignore("skipping_due_to_required_backbone_changes") #Scenario Outline: Creating a Token with an invalid DateTime format in the "expiresAt" request content property # Given the user is authenticated # When a POST request is sent to the Tokens endpoint with '', '' # Then the response status code is 400 (Bad Request) -# And the response content includes an error with the error code "error.platform.validation.invalidPropertyValue" +# And the response content contains an error with the error code "error.platform.validation.invalidPropertyValue" #Examples: # | Content | ExpiresAt | # | QQ== | 31/12/9999 | diff --git a/ConsumerApi.Tests.Integration/Features/Tokens/{id}/GET.feature b/ConsumerApi.Tests.Integration/Features/Tokens/{id}/GET.feature index 9f3202fb69..2b35631568 100644 --- a/ConsumerApi.Tests.Integration/Features/Tokens/{id}/GET.feature +++ b/ConsumerApi.Tests.Integration/Features/Tokens/{id}/GET.feature @@ -28,7 +28,7 @@ Scenario: Requesting a nonexistent Token as an authenticated user Given the user is authenticated When a GET request is sent to the Tokens/{id} endpoint with "TOKthisisnonexisting" Then the response status code is 404 (Not Found) - And the response content includes an error with the error code "error.platform.recordNotFound" + And the response content contains an error with the error code "error.platform.recordNotFound" #@ignore("skipping_due_to_required_backbone_changes") #Scenario: Requesting a Token with an unsupported Accept Header @@ -40,7 +40,7 @@ Scenario: Requesting a nonexistent Token as an authenticated user #Scenario Outline: Requesting a Token with an invalid id # When a GET request is sent to the Tokens/{id} endpoint with # Then the response status code is 400 (Bad Request) -# And the response content includes an error with the error code "error.platform.invalidId" +# And the response content contains an error with the error code "error.platform.invalidId" #Examples: # | id | description | # | TOKthishastoomanycharacters | More than 20 characters | diff --git a/ConsumerApi.Tests.Integration/Models/AccessTokenRequestException .cs b/ConsumerApi.Tests.Integration/Models/AccessTokenRequestException .cs deleted file mode 100644 index a2b7431fee..0000000000 --- a/ConsumerApi.Tests.Integration/Models/AccessTokenRequestException .cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Net; - -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class AccessTokenRequestException : Exception -{ - public HttpStatusCode StatusCode { get; set; } - public string? ErrorMessage { get; set; } - - public AccessTokenRequestException(HttpStatusCode statusCode, string errorMessage) - { - StatusCode = statusCode; - ErrorMessage = errorMessage; - } -} diff --git a/ConsumerApi.Tests.Integration/Models/AccessTokenResponse.cs b/ConsumerApi.Tests.Integration/Models/AccessTokenResponse.cs deleted file mode 100644 index 044beca71c..0000000000 --- a/ConsumerApi.Tests.Integration/Models/AccessTokenResponse.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class AccessTokenResponse -{ - public AccessTokenResponse( - string accessToken, - string tokenType, - int expiresIn) - { - AccessToken = accessToken; - TokenType = tokenType; - ExpiresIn = expiresIn; - ExpiresAt = DateTime.UtcNow.AddSeconds(expiresIn); - } - - [JsonPropertyName("access_token")] - public string AccessToken { get; set; } - [JsonPropertyName("token_type")] - public string TokenType { get; set; } - [JsonPropertyName("expires_in")] - public int ExpiresIn { get; set; } - public DateTime ExpiresAt { get; } - public bool IsExpired => (ExpiresAt - DateTime.UtcNow).TotalSeconds <= 15; -} diff --git a/ConsumerApi.Tests.Integration/Models/AuthenticationParameters.cs b/ConsumerApi.Tests.Integration/Models/AuthenticationParameters.cs deleted file mode 100644 index bbe1505031..0000000000 --- a/ConsumerApi.Tests.Integration/Models/AuthenticationParameters.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class AuthenticationParameters -{ - public string GrantType { get; set; } = null!; - public string ClientId { get; set; } = null!; - public string ClientSecret { get; set; } = null!; - public string Username { get; set; } = null!; - public string Password { get; set; } = null!; -} diff --git a/ConsumerApi.Tests.Integration/Models/Challenge.cs b/ConsumerApi.Tests.Integration/Models/Challenge.cs deleted file mode 100644 index 883e32812f..0000000000 --- a/ConsumerApi.Tests.Integration/Models/Challenge.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class Challenge -{ - [Required] - public required string Id { get; set; } - [Required] - public required DateTime ExpiresAt { get; set; } - public string? CreatedBy { get; set; } - public string? CreatedByDevice { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/CreateIdentityRequest.cs b/ConsumerApi.Tests.Integration/Models/CreateIdentityRequest.cs deleted file mode 100644 index b01f66fa57..0000000000 --- a/ConsumerApi.Tests.Integration/Models/CreateIdentityRequest.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class CreateIdentityRequest -{ - public required string ClientId { get; set; } - public required string ClientSecret { get; set; } - public required byte[] IdentityPublicKey { get; set; } - public required string DevicePassword { get; set; } - public required byte IdentityVersion { get; set; } - public required CreateIdentityRequestSignedChallenge SignedChallenge { get; set; } -} - -public class CreateIdentityRequestSignedChallenge -{ - public required string Challenge { get; set; } - public required string Signature { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/CreateIdentityResponse.cs b/ConsumerApi.Tests.Integration/Models/CreateIdentityResponse.cs deleted file mode 100644 index 5ef4bf66cc..0000000000 --- a/ConsumerApi.Tests.Integration/Models/CreateIdentityResponse.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class CreateIdentityResponse -{ - public required string Address { get; set; } - public DateTime CreatedAt { get; set; } - - public required CreateIdentityResponseDevice Device { get; set; } -} - -public class CreateIdentityResponseDevice -{ - public required string Id { get; set; } - public required string Username { get; set; } - public DateTime CreatedAt { get; set; } -} - diff --git a/ConsumerApi.Tests.Integration/Models/CreateTokenRequest.cs b/ConsumerApi.Tests.Integration/Models/CreateTokenRequest.cs deleted file mode 100644 index 2c49dc2fb8..0000000000 --- a/ConsumerApi.Tests.Integration/Models/CreateTokenRequest.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class CreateTokenRequest -{ - public string? Content { get; set; } - public string? ExpiresAt { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/CreateTokenResponse.cs b/ConsumerApi.Tests.Integration/Models/CreateTokenResponse.cs deleted file mode 100644 index e33d87629b..0000000000 --- a/ConsumerApi.Tests.Integration/Models/CreateTokenResponse.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class CreateTokenResponse -{ - public required string Id { get; set; } - public required string CreatedAt { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/Device.cs b/ConsumerApi.Tests.Integration/Models/Device.cs deleted file mode 100644 index 8056b821e4..0000000000 --- a/ConsumerApi.Tests.Integration/Models/Device.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class Device -{ - public required string Id { get; set; } - - public required string Username { get; set; } - - public required DateTime CreatedAt { get; set; } - - public required string CreatedByDevice { get; set; } - - public required LastLoginInformation LastLogin { get; set; } -} - -public class LastLoginInformation -{ - public DateTime? Time { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/EnumerableResponseBase.cs b/ConsumerApi.Tests.Integration/Models/EnumerableResponseBase.cs deleted file mode 100644 index 3cf0c090b7..0000000000 --- a/ConsumerApi.Tests.Integration/Models/EnumerableResponseBase.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections; - -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public abstract class EnumerableResponseBase : ICollection -{ - private readonly ICollection _items = new List(); - - public IEnumerator GetEnumerator() - { - return _items.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _items.GetEnumerator(); - } - - public void Add(TItem item) - { - _items.Add(item); - } - - public void Clear() - { - _items.Clear(); - } - - public bool Contains(TItem item) - { - return _items.Contains(item); - } - - public void CopyTo(TItem[] array, int arrayIndex) - { - _items.CopyTo(array, arrayIndex); - } - - public bool Remove(TItem item) - { - return _items.Remove(item); - } - - public int Count => _items.Count; - public bool IsReadOnly => _items.IsReadOnly; -} diff --git a/ConsumerApi.Tests.Integration/Models/Error.cs b/ConsumerApi.Tests.Integration/Models/Error.cs deleted file mode 100644 index b32e2885dd..0000000000 --- a/ConsumerApi.Tests.Integration/Models/Error.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class Error -{ - public required string Id { get; set; } - public required string Code { get; set; } - public required string Message { get; set; } - public required string Docs { get; set; } - public required DateTime Time { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/HttpResponse.cs b/ConsumerApi.Tests.Integration/Models/HttpResponse.cs deleted file mode 100644 index ff65bfc8b9..0000000000 --- a/ConsumerApi.Tests.Integration/Models/HttpResponse.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Net; - -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class HttpResponse -{ - public required ResponseContent Content { get; set; } - public string? HttpMethod { get; set; } - public required HttpStatusCode StatusCode { get; set; } - public required bool IsSuccessStatusCode { get; set; } - public string? ContentType { get; set; } - public string? RawContent { get; set; } -} - -public class HttpResponse -{ - public required ErrorResponseContent? Content { get; set; } - public string? HttpMethod { get; set; } - public required HttpStatusCode StatusCode { get; set; } - public required bool IsSuccessStatusCode { get; set; } - public string? ContentType { get; set; } - public string? RawContent { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/ListDevicesResponse.cs b/ConsumerApi.Tests.Integration/Models/ListDevicesResponse.cs deleted file mode 100644 index 7ae60a0ab3..0000000000 --- a/ConsumerApi.Tests.Integration/Models/ListDevicesResponse.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class ListDevicesResponse : PagedResponse; diff --git a/ConsumerApi.Tests.Integration/Models/PagedResponse.cs b/ConsumerApi.Tests.Integration/Models/PagedResponse.cs deleted file mode 100644 index 59411ad7ec..0000000000 --- a/ConsumerApi.Tests.Integration/Models/PagedResponse.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class PagedResponse : EnumerableResponseBase -{ - public PaginationData? Pagination { get; set; } -} - -public class PaginationData -{ - public int PageNumber { get; set; } - public int PageSize { get; set; } - public int TotalPages { get; set; } - public int TotalRecords { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/PnsRegistrationRequest.cs b/ConsumerApi.Tests.Integration/Models/PnsRegistrationRequest.cs deleted file mode 100644 index 4bd7394c57..0000000000 --- a/ConsumerApi.Tests.Integration/Models/PnsRegistrationRequest.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Backbone.ConsumerApi.Tests.Integration.Models; -internal class PnsRegistrationRequest -{ - public required string Platform { get; set; } - public required string Handle { get; set; } - public required string AppId { get; set; } - public string? Environment { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/RegisterDeviceRequest.cs b/ConsumerApi.Tests.Integration/Models/RegisterDeviceRequest.cs deleted file mode 100644 index ba4353cadb..0000000000 --- a/ConsumerApi.Tests.Integration/Models/RegisterDeviceRequest.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class RegisterDeviceRequest -{ - public required string DevicePassword { get; set; } - public required RegisterDeviceRequestSignedChallenge SignedChallenge { get; set; } -} - -public class RegisterDeviceRequestSignedChallenge -{ - public required string Challenge { get; set; } - public required string Signature { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/RegisterDeviceResponse.cs b/ConsumerApi.Tests.Integration/Models/RegisterDeviceResponse.cs deleted file mode 100644 index cd2e2e69e5..0000000000 --- a/ConsumerApi.Tests.Integration/Models/RegisterDeviceResponse.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Backbone.DevelopmentKit.Identity.ValueObjects; - -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class RegisterDeviceResponse -{ - public required DeviceId Id { get; set; } - public required string Username { get; set; } - public required DateTime CreatedAt { get; set; } - public required DeviceId CreatedByDevice { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/RequestConfiguration.cs b/ConsumerApi.Tests.Integration/Models/RequestConfiguration.cs deleted file mode 100644 index abb8220577..0000000000 --- a/ConsumerApi.Tests.Integration/Models/RequestConfiguration.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Newtonsoft.Json; - -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class RequestConfiguration -{ - public AuthenticationParameters AuthenticationParameters { get; set; } = new(); - public bool Authenticate { get; set; } - public string? ContentType { get; set; } - public string? AcceptHeader { get; set; } - public string? Content { get; set; } - - public void SupplementWith(RequestConfiguration other) - { - AuthenticationParameters = other.AuthenticationParameters; - Authenticate = other.Authenticate; - AcceptHeader ??= other.AcceptHeader; - ContentType ??= other.ContentType; - Content ??= other.Content; - } - - public RequestConfiguration Clone() - { - var requestConfiguration = new RequestConfiguration(); - requestConfiguration.SupplementWith(this); - return requestConfiguration; - } - - public void SetContent(object obj) - { - Content = JsonConvert.SerializeObject(obj); - } -} diff --git a/ConsumerApi.Tests.Integration/Models/ResponseContent.cs b/ConsumerApi.Tests.Integration/Models/ResponseContent.cs deleted file mode 100644 index 5abfb81ed3..0000000000 --- a/ConsumerApi.Tests.Integration/Models/ResponseContent.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Newtonsoft.Json; - -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class ResponseContent -{ - public T? Result { get; set; } - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public Error? Error { get; set; } -} - -public class ErrorResponseContent -{ - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public Error? Error { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/StartDeletionProcessAsSupportResponse.cs b/ConsumerApi.Tests.Integration/Models/StartDeletionProcessAsSupportResponse.cs deleted file mode 100644 index e16517752d..0000000000 --- a/ConsumerApi.Tests.Integration/Models/StartDeletionProcessAsSupportResponse.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Backbone.Modules.Devices.Domain.Entities.Identities; - -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class StartDeletionProcessAsSupportResponse -{ - public required string Id { get; set; } - public required DeletionProcessStatus Status { get; set; } - public required DateTime CreatedAt { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/StartDeletionProcessResponse.cs b/ConsumerApi.Tests.Integration/Models/StartDeletionProcessResponse.cs deleted file mode 100644 index f22329b932..0000000000 --- a/ConsumerApi.Tests.Integration/Models/StartDeletionProcessResponse.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class StartDeletionProcessResponse -{ - public required string Id { get; set; } - public required string Status { get; set; } - public required DateTime CreatedAt { get; set; } - - public required DateTime ApprovedAt { get; set; } - public required string ApprovedByDevice { get; set; } - - public required DateTime GracePeriodEndsAt { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/Models/Token.cs b/ConsumerApi.Tests.Integration/Models/Token.cs deleted file mode 100644 index 10a49fb07c..0000000000 --- a/ConsumerApi.Tests.Integration/Models/Token.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Backbone.ConsumerApi.Tests.Integration.Models; - -public class Token -{ - [Required] - public required string Id { get; set; } - public DateTime? ExpiresAt { get; set; } - [Required] - public required DateTime CreatedAt { get; set; } - public string? CreatedBy { get; set; } - public string? CreatedByDevice { get; set; } - public string? Content { get; set; } -} diff --git a/ConsumerApi.Tests.Integration/StepDefinitions/BaseStepDefinitions.cs b/ConsumerApi.Tests.Integration/StepDefinitions/BaseStepDefinitions.cs deleted file mode 100644 index 64a2ffef9d..0000000000 --- a/ConsumerApi.Tests.Integration/StepDefinitions/BaseStepDefinitions.cs +++ /dev/null @@ -1,122 +0,0 @@ -using Backbone.ConsumerApi.Tests.Integration.API; -using Backbone.ConsumerApi.Tests.Integration.Configuration; -using Backbone.ConsumerApi.Tests.Integration.Models; -using Backbone.Crypto; -using Backbone.Crypto.Abstractions; -using Microsoft.Extensions.Options; -using Newtonsoft.Json; - -namespace Backbone.ConsumerApi.Tests.Integration.StepDefinitions; - -[Binding] -internal class BaseStepDefinitions -{ - protected readonly RequestConfiguration _requestConfiguration; - protected readonly ISignatureHelper _signatureHelper; - protected readonly ChallengesApi _challengesApi; - protected readonly IdentitiesApi _identitiesApi; - protected readonly DevicesApi _devicesApi; - - public BaseStepDefinitions(IOptions httpConfiguration, ISignatureHelper signatureHelper, ChallengesApi challengesApi, IdentitiesApi identitiesApi, DevicesApi devicesApi) - { - _requestConfiguration = new RequestConfiguration - { - AuthenticationParameters = new AuthenticationParameters - { - GrantType = "password", - ClientId = httpConfiguration.Value.ClientCredentials.ClientId, - ClientSecret = httpConfiguration.Value.ClientCredentials.ClientSecret, - Username = "USRa", - Password = "a" - }, - ContentType = "application/json" - }; - - _signatureHelper = signatureHelper; - _challengesApi = challengesApi; - _identitiesApi = identitiesApi; - _devicesApi = devicesApi; - } - - #region StepDefinitions - - [Given("the user is authenticated")] - public void GivenTheUserIsAuthenticated() - { - _requestConfiguration.Authenticate = true; - } - - [Given("the user is unauthenticated")] - public void GivenTheUserIsUnauthenticated() - { - _requestConfiguration.Authenticate = false; - } - - [Given("the Accept header is '([^']*)'")] - public void GivenTheAcceptHeaderIs(string acceptHeader) - { - _requestConfiguration.AcceptHeader = acceptHeader; - } - - #endregion - - protected async Task> CreateChallenge() - { - var challengeResponse = await _challengesApi.CreateChallenge(_requestConfiguration); - challengeResponse.IsSuccessStatusCode.Should().BeTrue(); - - return challengeResponse; - } - - protected async Task> CreateIdentity(Challenge? challenge = null, KeyPair? keyPair = null) - { - challenge ??= (await CreateChallenge()).Content.Result!; - keyPair ??= _signatureHelper.CreateKeyPair(); - - var serializedChallenge = JsonConvert.SerializeObject(challenge); - - var signature = _signatureHelper.CreateSignature(keyPair.PrivateKey, ConvertibleString.FromUtf8(serializedChallenge)); - - dynamic publicKey = new - { - pub = keyPair.PublicKey.Base64Representation, - alg = 3 - }; - - dynamic signedChallenge = new - { - sig = signature.BytesRepresentation, - alg = 2 - }; - - var createIdentityRequest = new CreateIdentityRequest() - { - ClientId = "test", - ClientSecret = "test", - DevicePassword = "test", - IdentityPublicKey = (ConvertibleString.FromUtf8(JsonConvert.SerializeObject(publicKey)) as ConvertibleString)!.BytesRepresentation, - IdentityVersion = 1, - SignedChallenge = new CreateIdentityRequestSignedChallenge() - { - Challenge = serializedChallenge, - Signature = (ConvertibleString.FromUtf8(JsonConvert.SerializeObject(signedChallenge)) as ConvertibleString)!.Base64Representation - } - }; - - var requestConfiguration = _requestConfiguration.Clone(); - requestConfiguration.ContentType = "application/json"; - requestConfiguration.SetContent(createIdentityRequest); - - var identityResponse = await _identitiesApi.CreateIdentity(requestConfiguration); - identityResponse.IsSuccessStatusCode.Should().BeTrue(); - - return identityResponse; - } - - protected void Authenticate(string username, string password) - { - _requestConfiguration.Authenticate = true; - _requestConfiguration.AuthenticationParameters.Username = username; - _requestConfiguration.AuthenticationParameters.Password = password; - } -} diff --git a/ConsumerApi.Tests.Integration/StepDefinitions/ChallengesApiStepDefinitions.cs b/ConsumerApi.Tests.Integration/StepDefinitions/ChallengesApiStepDefinitions.cs index 41b0cf6b47..ee9d4a71d8 100644 --- a/ConsumerApi.Tests.Integration/StepDefinitions/ChallengesApiStepDefinitions.cs +++ b/ConsumerApi.Tests.Integration/StepDefinitions/ChallengesApiStepDefinitions.cs @@ -4,7 +4,7 @@ using Backbone.ConsumerApi.Sdk.Endpoints.Challenges.Types; using Backbone.ConsumerApi.Tests.Integration.Configuration; using Backbone.ConsumerApi.Tests.Integration.Extensions; -using Backbone.Tooling; +using Backbone.ConsumerApi.Tests.Integration.Support; using Microsoft.Extensions.Options; namespace Backbone.ConsumerApi.Tests.Integration.StepDefinitions; @@ -16,7 +16,7 @@ internal class ChallengesApiStepDefinitions { private string _challengeId; private ApiResponse? _response; - private Client? _sdk; + private Client _sdk = null!; private bool _isAuthenticated; private readonly HttpClient _httpClient; private readonly ClientCredentials _clientCredentials; @@ -31,7 +31,7 @@ public ChallengesApiStepDefinitions(IOptions httpConfiguratio [Given("the user is authenticated")] public async Task GivenTheUserIsAuthenticated() { - _sdk = await Client.CreateForNewIdentity(_httpClient, _clientCredentials, PasswordHelper.GeneratePassword(20, 26)); + _sdk = await Client.CreateForNewIdentity(_httpClient, _clientCredentials, Constants.DEVICE_PASSWORD); _isAuthenticated = true; } @@ -42,27 +42,20 @@ public void GivenTheUserIsUnauthenticated() _isAuthenticated = false; } - [Given("a Challenge c")] public async Task GivenAChallengeC() { - var challengeResponse = !_isAuthenticated ? await _sdk!.Challenges.CreateChallengeUnauthenticated() : await _sdk!.Challenges.CreateChallenge(); + var challengeResponse = !_isAuthenticated ? await _sdk.Challenges.CreateChallengeUnauthenticated() : await _sdk.Challenges.CreateChallenge(); challengeResponse.Should().BeASuccess(); _challengeId = challengeResponse.Result!.Id; _challengeId.Should().NotBeNullOrEmpty(); } - [When("a POST request is sent to the Challenges endpoint with")] - public async Task WhenAPOSTRequestIsSentToTheChallengesEndpointWith(Table table) - { - _response = await _sdk!.Challenges.CreateChallenge(); - } - [When("a POST request is sent to the Challenges endpoint")] public async Task WhenAPOSTRequestIsSentToTheChallengesEndpoint() { - _response = _isAuthenticated ? await _sdk!.Challenges.CreateChallenge() : await _sdk!.Challenges.CreateChallengeUnauthenticated(); + _response = _isAuthenticated ? await _sdk.Challenges.CreateChallenge() : await _sdk.Challenges.CreateChallengeUnauthenticated(); } [When(@"a GET request is sent to the Challenges/{id} endpoint with ""?(.*?)""?")] @@ -77,7 +70,8 @@ public async Task WhenAGETRequestIsSentToTheChallengesIdEndpointWith(string id) id = "CHLjVPS6h1082AuBVBaR"; break; } - _response = await _sdk!.Challenges.GetChallenge(id); + + _response = await _sdk.Challenges.GetChallenge(id); } [Then("the response contains a Challenge")] @@ -111,7 +105,7 @@ public void ThenTheResponseStatusCodeIs(int expectedStatusCode) actualStatusCode.Should().Be(expectedStatusCode); } - [Then(@"the response content includes an error with the error code ""([^""]+)""")] + [Then(@"the response content contains an error with the error code ""([^""]+)""")] public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCode) { _response!.Error.Should().NotBeNull(); diff --git a/ConsumerApi.Tests.Integration/StepDefinitions/DevicesStepDefinitions.cs b/ConsumerApi.Tests.Integration/StepDefinitions/DevicesStepDefinitions.cs index 5f2f400434..9ccdfbf2dd 100644 --- a/ConsumerApi.Tests.Integration/StepDefinitions/DevicesStepDefinitions.cs +++ b/ConsumerApi.Tests.Integration/StepDefinitions/DevicesStepDefinitions.cs @@ -1,222 +1,105 @@ -using Backbone.ConsumerApi.Tests.Integration.API; +using Backbone.BuildingBlocks.SDK.Endpoints.Common.Types; +using Backbone.ConsumerApi.Sdk; +using Backbone.ConsumerApi.Sdk.Authentication; +using Backbone.ConsumerApi.Sdk.Endpoints.Devices.Types.Responses; using Backbone.ConsumerApi.Tests.Integration.Configuration; -using Backbone.ConsumerApi.Tests.Integration.Models; -using Backbone.Crypto; -using Backbone.Crypto.Abstractions; +using Backbone.ConsumerApi.Tests.Integration.Extensions; +using Backbone.ConsumerApi.Tests.Integration.Support; using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using static Backbone.ConsumerApi.Tests.Integration.Helpers.ThrowHelpers; namespace Backbone.ConsumerApi.Tests.Integration.StepDefinitions; [Binding] [Scope(Feature = "DELETE Device")] -internal class DevicesStepDefinitions : BaseStepDefinitions +internal class DevicesStepDefinitions { - private readonly KeyPair _keyPair1; - private readonly KeyPair _keyPair2; + private Client _sdk = null!; + private readonly ClientCredentials _clientCredentials; + private readonly HttpClient _httpClient; - private HttpResponse? _createIdentityResponse1; - private HttpResponse? _createIdentityResponse2; - private HttpResponse? _deletionResponse; + private ApiResponse? _deletionResponse; private string? _deviceIdD1; private string? _deviceIdD2; - private string? _deviceIdD3; private const string NON_EXISTENT_DEVICE_ID = "DVC00000000000000000"; - public DevicesStepDefinitions(IOptions httpConfiguration, ISignatureHelper signatureHelper, ChallengesApi challengesApi, IdentitiesApi identitiesApi, DevicesApi devicesApi) : - base(httpConfiguration, signatureHelper, challengesApi, identitiesApi, devicesApi) + public DevicesStepDefinitions(HttpClientFactory factory, IOptions httpConfiguration) { - _keyPair1 = signatureHelper.CreateKeyPair(); - _keyPair2 = signatureHelper.CreateKeyPair(); + _httpClient = factory.CreateClient(); + _clientCredentials = new ClientCredentials(httpConfiguration.Value.ClientCredentials.ClientId, httpConfiguration.Value.ClientCredentials.ClientSecret); } - #region StepDefinitions - - [Given("an Identity i1? with a device d1?")] - public async Task GivenAnIdentityIWithADeviceD() + [Given("an Identity i with a device d1?")] + public async Task GivenAnIdentityIWithADevice() { - _createIdentityResponse1 = await CreateIdentity(keyPair: _keyPair1); - _createIdentityResponse1.Should().NotBeNull(); - - _deviceIdD1 = _createIdentityResponse1.Content.Result!.Device.Id; - } - - [Given("an Identity i2 with a device d2")] - public async Task GivenAnIdentityI2WithADeviceD2() - { - _createIdentityResponse2 = await CreateIdentity(keyPair: _keyPair2); - _createIdentityResponse2.Should().NotBeNull(); - - _deviceIdD2 = _createIdentityResponse2.Content.Result!.Device.Id; - } - - [Given("the current user uses d1?")] - public void GivenTheCurrentUserUsesD1() - { - var username = _createIdentityResponse1!.Content.Result!.Device.Username; - Authenticate(username, "test"); + _sdk = await Client.CreateForNewIdentity(_httpClient, _clientCredentials, Constants.DEVICE_PASSWORD); + _deviceIdD1 = _sdk.DeviceData!.DeviceId; } [Given("an un-onboarded device d2")] public async Task GivenAnUnOnboardedDeviceD2() { - var deviceResponse = await RegisterDevice(_keyPair1); - _deviceIdD2 = deviceResponse.Content.Result!.Id; - } - - - [Given("an un-onboarded device d3 belonging to i2")] - public async Task GivenAnUnOnboardedDeviceD3BelongingToI2() - { - var usernameD2 = _createIdentityResponse2!.Content.Result!.Device.Username; - var deviceResponse = await RegisterDevice(_keyPair2, usernameD2); - _deviceIdD3 = deviceResponse.Content.Result!.Id; + var client = await _sdk.OnboardNewDevice("deviceTwoPassword"); + _deviceIdD2 = client.DeviceData!.DeviceId; } - [When("a DELETE request is sent to the Devices/{id} endpoint with d.Id")] - public async Task WhenADELETERequestIsSentToTheDeviceIdEndpointWithDId() + [When("a DELETE request is sent to the Devices/{id} endpoint with d1?.Id")] + public async Task WhenADeleteRequestIsSentToTheDeviceIdEndpointWithTheDeviceId() { - ThrowIfNull(_deviceIdD1); - _deletionResponse = await DeleteOnboardedDevice(_deviceIdD1); + _deletionResponse = await _sdk.Devices.DeleteDevice(_deviceIdD1!); } [When("a DELETE request is sent to the Devices/{id} endpoint with d2.Id")] - public async Task WhenADELETERequestIsSentToTheDeviceIdEndpointWithD2Id() + public async Task WhenADeleteRequestIsSentToTheDeviceIdEndpointWithD2Id() { - ThrowIfNull(_deviceIdD2); - _deletionResponse = await DeleteUnOnboardedDevice(_deviceIdD2); - } - - [When("a DELETE request is sent to the Devices/{id} endpoint with d3.Id")] - public async Task WhenADELETERequestIsSentToTheDeviceIdEndpointWithD3Id() - { - ThrowIfNull(_createIdentityResponse1); - ThrowIfNull(_deviceIdD3); - Authenticate(_createIdentityResponse1.Content.Result!.Device.Username, "test"); - _deletionResponse = await DeleteUnOnboardedDevice(_deviceIdD3); + _deletionResponse = await _sdk.Devices.DeleteDevice(_deviceIdD2!); } [When("a DELETE request is sent to the Devices/{id} endpoint with a non existent id")] - public async Task WhenADELETERequestIsSentToTheDeviceIdEndpointWithNonExistantId() + public async Task WhenADeleteRequestIsSentToTheDeviceIdEndpointWithNonExistentId() { - _deletionResponse = await DeleteNonExistentDevice(NON_EXISTENT_DEVICE_ID); + _deletionResponse = await _sdk.Devices.DeleteDevice(NON_EXISTENT_DEVICE_ID); } [Then(@"the response status code is (\d\d\d) \(.+\)")] public void ThenTheResponseStatusCodeIs(int expectedStatusCode) { - var actualStatusCode = (int)_deletionResponse!.StatusCode; - actualStatusCode.Should().Be(expectedStatusCode); + ((int)_deletionResponse!.Status).Should().Be(expectedStatusCode); } - [Then(@"the error code is ""([^""]*)""")] - public void ThenTheErrorCodeIs(string errorCode) + [Then(@"the response content contains an error with the error code ""([^""]*)""")] + public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCode) { - ThrowIfNull(_deletionResponse); - var actualErrorCode = _deletionResponse.Content!.Error?.Code; - actualErrorCode.Should().Be(errorCode); + _deletionResponse!.Error.Should().NotBeNull(); + _deletionResponse.Error!.Code.Should().Be(errorCode); } [Then("d is not deleted")] public async Task ThenDIsNotDeleted() { var response = await ListDevices(); - response.Content.Result!.Where(d => d.Id == _deviceIdD1).Should().NotBeEmpty(); + response.Result!.Where(d => d.Id == _deviceIdD1).Should().NotBeEmpty(); } [Then("d1 is not deleted")] public async Task ThenD1IsNotDeleted() { var response = await ListDevices(); - response.Content.Result!.Where(d => d.Id == _deviceIdD1).Should().NotBeEmpty(); + response.Result!.Where(d => d.Id == _deviceIdD1).Should().NotBeEmpty(); } [Then("d2 is deleted")] public async Task ThenD2IsDeleted() { var response = await ListDevices(); - response.Content.Result!.Count.Should().Be(1); - response.Content.Result!.First().Id.Should().NotBe(_deviceIdD2); - } - - [Then("d3 is not deleted")] - public async Task ThenD3IsNotDeleted() - { - var response = await ListDevices(); - response.Content.Result!.Should().Contain(d => d.Id == _deviceIdD3); - } - - #endregion - - private async Task> RegisterDevice(KeyPair keyPair, string? username = null) - { - var challenge = (await CreateChallenge()).Content.Result!; - - var serializedChallenge = JsonConvert.SerializeObject(challenge); - - var signature = _signatureHelper.CreateSignature(keyPair.PrivateKey, ConvertibleString.FromUtf8(serializedChallenge)); - - dynamic signedChallenge = new - { - sig = signature.BytesRepresentation, - alg = 2 - }; - - var registerDeviceRequest = new RegisterDeviceRequest() - { - DevicePassword = "test", - - SignedChallenge = new RegisterDeviceRequestSignedChallenge() - { - Challenge = serializedChallenge, - Signature = (ConvertibleString.FromUtf8(JsonConvert.SerializeObject(signedChallenge)) as ConvertibleString)!.Base64Representation - } - }; - - var requestConfiguration = _requestConfiguration.Clone(); - requestConfiguration.ContentType = "application/json"; - - if (username != null) - requestConfiguration.AuthenticationParameters.Username = username; - - requestConfiguration.SetContent(registerDeviceRequest); - - var deviceResponse = await _devicesApi.RegisterDevice(requestConfiguration); - deviceResponse.IsSuccessStatusCode.Should().BeTrue(); - - return deviceResponse; - } - - protected async Task DeleteUnOnboardedDevice(string id) - { - var response = await _devicesApi.DeleteDevice(_requestConfiguration, id); - response.IsSuccessStatusCode.Should().BeTrue(); - - return response; - } - - protected async Task DeleteOnboardedDevice(string id) - { - var response = await _devicesApi.DeleteDevice(_requestConfiguration, id); - response.IsSuccessStatusCode.Should().BeFalse(); - - return response; - } - - protected async Task DeleteNonExistentDevice(string id) - { - var response = await _devicesApi.DeleteDevice(_requestConfiguration, id); - response.IsSuccessStatusCode.Should().BeFalse(); - - return response; + response.Result!.Count.Should().Be(1); + response.Result!.First().Id.Should().NotBe(_deviceIdD2); } - protected async Task> ListDevices() + protected async Task> ListDevices() { - var response = await _devicesApi.ListDevices(_requestConfiguration); - response.IsSuccessStatusCode.Should().BeTrue(); + var response = await _sdk.Devices.ListDevices(); + response.Should().BeASuccess(); return response; } diff --git a/ConsumerApi.Tests.Integration/StepDefinitions/IdentitiesApiStepDefinitions.cs b/ConsumerApi.Tests.Integration/StepDefinitions/IdentitiesApiStepDefinitions.cs index dfd9a56d00..309ecc813a 100644 --- a/ConsumerApi.Tests.Integration/StepDefinitions/IdentitiesApiStepDefinitions.cs +++ b/ConsumerApi.Tests.Integration/StepDefinitions/IdentitiesApiStepDefinitions.cs @@ -1,25 +1,38 @@ -using Backbone.ConsumerApi.Tests.Integration.API; +using Backbone.BuildingBlocks.SDK.Crypto; +using Backbone.BuildingBlocks.SDK.Endpoints.Common.Types; +using Backbone.ConsumerApi.Sdk; +using Backbone.ConsumerApi.Sdk.Authentication; +using Backbone.ConsumerApi.Sdk.Endpoints.Challenges.Types; +using Backbone.ConsumerApi.Sdk.Endpoints.Devices.Types; +using Backbone.ConsumerApi.Sdk.Endpoints.Identities.Types.Requests; +using Backbone.ConsumerApi.Sdk.Endpoints.Identities.Types.Responses; using Backbone.ConsumerApi.Tests.Integration.Configuration; using Backbone.ConsumerApi.Tests.Integration.Extensions; -using Backbone.ConsumerApi.Tests.Integration.Models; -using Backbone.Crypto.Abstractions; +using Backbone.ConsumerApi.Tests.Integration.Support; +using Backbone.Crypto; +using Backbone.Crypto.Implementations; using Microsoft.Extensions.Options; -using static Backbone.ConsumerApi.Tests.Integration.Helpers.ThrowHelpers; +using Newtonsoft.Json; namespace Backbone.ConsumerApi.Tests.Integration.StepDefinitions; [Binding] [Scope(Feature = "POST Identities/Self/DeletionProcess")] [Scope(Feature = "POST Identity")] -internal class IdentitiesApiStepDefinitions : BaseStepDefinitions +internal class IdentitiesApiStepDefinitions { - private HttpResponse? _response; - private HttpResponse? _identityResponse; - private HttpResponse? _challengeResponse; - - public IdentitiesApiStepDefinitions(IOptions httpConfiguration, IdentitiesApi identitiesApi, ChallengesApi challengesApi, ISignatureHelper signatureHelper, DevicesApi devicesApi) : - base(httpConfiguration, signatureHelper, challengesApi, identitiesApi, devicesApi) - { } + private Client _sdk = null!; + private readonly ClientCredentials _clientCredentials; + private readonly HttpClient _httpClient; + private ApiResponse? _startDeletionProcessResponse; + private ApiResponse? _identityResponse; + private ApiResponse? _challengeResponse; + + public IdentitiesApiStepDefinitions(HttpClientFactory factory, IOptions httpConfiguration) + { + _httpClient = factory.CreateClient(); + _clientCredentials = new ClientCredentials(httpConfiguration.Value.ClientCredentials.ClientId, httpConfiguration.Value.ClientCredentials.ClientSecret); + } [Given("no active deletion process for the identity exists")] public void GivenNoActiveDeletionProcessForTheUserExists() @@ -29,84 +42,85 @@ public void GivenNoActiveDeletionProcessForTheUserExists() [Given("an active deletion process for the identity exists")] public async Task GivenAnActiveDeletionProcessForTheUserExists() { - var requestConfiguration = new RequestConfiguration(); - requestConfiguration.SupplementWith(_requestConfiguration); - requestConfiguration.Authenticate = true; - requestConfiguration.AuthenticationParameters.Username = "USRa"; - requestConfiguration.AuthenticationParameters.Password = "a"; - - await _identitiesApi.StartDeletionProcess(requestConfiguration); + await _sdk.Identities.StartDeletionProcess(); } - [When("a POST request is sent to the /Identities/Self/DeletionProcesses endpoint")] - public async Task WhenAPOSTRequestIsSentToTheIdentitiesSelfDeletionProcessEndpoint() + [Given("an Identity i")] + public async Task GivenAnIdentityI() { - var requestConfiguration = new RequestConfiguration(); - requestConfiguration.SupplementWith(_requestConfiguration); - requestConfiguration.Authenticate = true; - requestConfiguration.AuthenticationParameters.Username = "USRa"; - requestConfiguration.AuthenticationParameters.Password = "a"; - - _response = await _identitiesApi.StartDeletionProcess(requestConfiguration); + _sdk = await Client.CreateForNewIdentity(_httpClient, _clientCredentials, Constants.DEVICE_PASSWORD); } - [Then(@"the response content includes an error with the error code ""([^""]*)""")] - public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCode) + [Given("a Challenge c")] + public async Task GivenAChallengeC() { - ThrowIfNull(_response); - _response.Content.Error.Should().NotBeNull(); - _response.Content.Error!.Code.Should().Be(errorCode); + _sdk = Client.CreateUnauthenticated(_httpClient, _clientCredentials); + _challengeResponse = await _sdk.Challenges.CreateChallengeUnauthenticated(); } - [Then("the response contains a Deletion Process")] - public void ThenTheResponseContainsADeletionProcess() + [When("a POST request is sent to the /Identities/Self/DeletionProcesses endpoint")] + public async Task WhenAPOSTRequestIsSentToTheIdentitiesSelfDeletionProcessEndpoint() { - _response!.Content.Should().NotBeNull(); - _response!.Content.Result.Should().NotBeNull(); - _response!.AssertContentCompliesWithSchema(); + _startDeletionProcessResponse = await _sdk.Identities.StartDeletionProcess(); } - [Given("a Challenge c")] - public async Task GivenAChallengeC() + [When("a POST request is sent to the /Identities endpoint with a valid signature on c")] + public async Task WhenAPOSTRequestIsSentToTheIdentitiesEndpoint() { - _challengeResponse = await CreateChallenge(); + var signatureHelper = SignatureHelper.CreateEd25519WithRawKeyFormat(); + var identityKeyPair = signatureHelper.CreateKeyPair(); + + var serializedChallenge = JsonConvert.SerializeObject(_challengeResponse!.Result); + var challengeSignature = signatureHelper.CreateSignature(identityKeyPair.PrivateKey, ConvertibleString.FromUtf8(serializedChallenge)); + var signedChallenge = new SignedChallenge(serializedChallenge, challengeSignature); + + var createIdentityPayload = new CreateIdentityRequest + { + ClientId = "test", + ClientSecret = "test", + IdentityVersion = 1, + SignedChallenge = signedChallenge, + IdentityPublicKey = ConvertibleString.FromUtf8(JsonConvert.SerializeObject(new CryptoSignaturePublicKey + { + alg = CryptoExchangeAlgorithm.ECDH_X25519, + pub = identityKeyPair.PublicKey.Base64Representation + })).BytesRepresentation, + DevicePassword = "some-device-password" + }; + + _identityResponse = await _sdk.Identities.CreateIdentity(createIdentityPayload); } - [When("a POST request is sent to the /Identities endpoint with a valid signature on c")] - public async Task WhenAPOSTRequestIsSentToTheIdentitiesEndpoint() + [Then(@"the response content contains an error with the error code ""([^""]*)""")] + public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCode) { - _identityResponse = await CreateIdentity(_challengeResponse!.Content.Result); + _startDeletionProcessResponse!.Error.Should().NotBeNull(); + _startDeletionProcessResponse.Error!.Code.Should().Be(errorCode); } - [Given("an Identity i")] - public async Task GivenAnIdentityI() + [Then("the response contains a Deletion Process")] + public void ThenTheResponseContainsADeletionProcess() { - _challengeResponse = await CreateChallenge(); - _identityResponse = await CreateIdentity(_challengeResponse.Content.Result); + _startDeletionProcessResponse!.Result.Should().NotBeNull(); + _startDeletionProcessResponse.Should().BeASuccess(); + _startDeletionProcessResponse.Should().ComplyWithSchema(); } [Then("the response contains a CreateIdentityResponse")] public void ThenTheResponseContainsACreateIdentityResponse() { _identityResponse!.Should().NotBeNull(); - _identityResponse!.IsSuccessStatusCode.Should().BeTrue(); - _identityResponse!.ContentType.Should().Be("application/json"); - _identityResponse!.AssertContentCompliesWithSchema(); + _identityResponse!.Should().BeASuccess(); + _identityResponse!.Should().ComplyWithSchema(); } [Then(@"the response status code is (\d+) \(.+\)")] public void ThenTheResponseStatusCodeIs(int expectedStatusCode) { if (_identityResponse != null) - { - var actualStatusCode = (int)_identityResponse!.StatusCode; - actualStatusCode.Should().Be(expectedStatusCode); - } + ((int)_identityResponse!.Status).Should().Be(expectedStatusCode); - if (_response != null) - { - var actualStatusCode = (int)_response!.StatusCode; - actualStatusCode.Should().Be(expectedStatusCode); - } + if (_startDeletionProcessResponse != null) + ((int)_startDeletionProcessResponse!.Status).Should().Be(expectedStatusCode); } } diff --git a/ConsumerApi.Tests.Integration/StepDefinitions/PnsRegistrationStepDefinitions.cs b/ConsumerApi.Tests.Integration/StepDefinitions/PnsRegistrationStepDefinitions.cs index beb393f3c6..984915d55c 100644 --- a/ConsumerApi.Tests.Integration/StepDefinitions/PnsRegistrationStepDefinitions.cs +++ b/ConsumerApi.Tests.Integration/StepDefinitions/PnsRegistrationStepDefinitions.cs @@ -1,62 +1,57 @@ -using System.Net; -using Backbone.ConsumerApi.Tests.Integration.API; +using Backbone.BuildingBlocks.SDK.Endpoints.Common.Types; +using Backbone.ConsumerApi.Sdk; +using Backbone.ConsumerApi.Sdk.Authentication; +using Backbone.ConsumerApi.Sdk.Endpoints.PushNotifications.Types.Requests; +using Backbone.ConsumerApi.Sdk.Endpoints.PushNotifications.Types.Responses; using Backbone.ConsumerApi.Tests.Integration.Configuration; -using Backbone.ConsumerApi.Tests.Integration.Helpers; -using Backbone.ConsumerApi.Tests.Integration.Models; -using Backbone.Crypto.Abstractions; -using Backbone.Modules.Devices.Application.PushNotifications.Commands.UpdateDeviceRegistration; +using Backbone.ConsumerApi.Tests.Integration.Support; using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using RequestConfiguration = Backbone.ConsumerApi.Tests.Integration.Models.RequestConfiguration; namespace Backbone.ConsumerApi.Tests.Integration.StepDefinitions; [Binding] [Scope(Feature = "PUT /Devices/Self/PushNotifications")] -internal class PnsRegistrationStepDefinitions : BaseStepDefinitions +internal class PnsRegistrationStepDefinitions { - // keep in mind: these tests use DummyPushService so they will not execute the implemented code + private Client _sdk = null!; + private readonly ClientCredentials _clientCredentials; + private readonly HttpClient _httpClient; + private ApiResponse? _response; - private readonly PushNotificationsApi _pnsRegistrationsApi; - private HttpResponse? _response; + public PnsRegistrationStepDefinitions(HttpClientFactory factory, IOptions httpConfiguration) + { + _httpClient = factory.CreateClient(); + _clientCredentials = new ClientCredentials(httpConfiguration.Value.ClientCredentials.ClientId, httpConfiguration.Value.ClientCredentials.ClientSecret); + } - public PnsRegistrationStepDefinitions( - IOptions httpConfiguration, ISignatureHelper signatureHelper, ChallengesApi challengesApi, IdentitiesApi identitiesApi, DevicesApi devicesApi, PushNotificationsApi pnsRegistrationsApi) : - base(httpConfiguration, signatureHelper, challengesApi, identitiesApi, devicesApi) + [Given("the user is authenticated")] + public async Task GivenTheUserIsAuthenticated() { - _pnsRegistrationsApi = pnsRegistrationsApi; + _sdk = await Client.CreateForNewIdentity(_httpClient, _clientCredentials, Constants.DEVICE_PASSWORD); } [When("a PUT request is sent to the /Devices/Self/PushNotifications endpoint")] - public async Task WhenAPUTRequestIsSentToTheDevicesSelfPushNotificationsEndpoint() + public async Task WhenAPutRequestIsSentToTheDevicesSelfPushNotificationsEndpoint() { - var requestConfiguration = new RequestConfiguration(); - requestConfiguration.SupplementWith(_requestConfiguration); - requestConfiguration.AuthenticationParameters.Username = "USRa"; - requestConfiguration.AuthenticationParameters.Password = "a"; - - requestConfiguration.ContentType = "application/json"; - - requestConfiguration.Content = JsonConvert.SerializeObject(new PnsRegistrationRequest() + var request = new UpdateDeviceRegistrationRequest { Platform = "fcm", Handle = "eXYs0v3XT9w:APA91bHal6RzkPdjiFmoXvtVRJlfN81OCyzVIbXx4bTQupfcUQmDY9eAdUABLntZzO4M5rv7jmcj3Mk6", AppId = "someAppId" - }); + }; - _response = await _pnsRegistrationsApi.RegisterForPushNotifications(requestConfiguration); + _response = await _sdk.PushNotifications.RegisterForPushNotifications(request); } [Then(@"the response status code is (\d\d\d) \(.+\)")] - public void ThenTheResponseStatusCodeIs(int statusCode) + public void ThenTheResponseStatusCodeIs(int expectedStatusCode) { - ThrowHelpers.ThrowIfNull(_response); - _response.StatusCode.Should().Be((HttpStatusCode)statusCode); + ((int)_response!.Status).Should().Be(expectedStatusCode); } [Then("the response contains the push identifier for the device")] public void ThenTheResponseContainsThePushIdentifierForTheDevice() { - _response!.Content.Result!.DevicePushIdentifier.Should().NotBeNullOrEmpty(); + _response!.Result!.DevicePushIdentifier.Should().NotBeNullOrEmpty(); } } diff --git a/ConsumerApi.Tests.Integration/StepDefinitions/TokensApiStepDefinitions.cs b/ConsumerApi.Tests.Integration/StepDefinitions/TokensApiStepDefinitions.cs index c328d44922..f5cabb7432 100644 --- a/ConsumerApi.Tests.Integration/StepDefinitions/TokensApiStepDefinitions.cs +++ b/ConsumerApi.Tests.Integration/StepDefinitions/TokensApiStepDefinitions.cs @@ -1,12 +1,15 @@ -using System.Net; -using Backbone.ConsumerApi.Tests.Integration.API; +using Backbone.BuildingBlocks.SDK.Endpoints.Common.Types; +using Backbone.ConsumerApi.Sdk; +using Backbone.ConsumerApi.Sdk.Authentication; +using Backbone.ConsumerApi.Sdk.Endpoints.Tokens.Types; +using Backbone.ConsumerApi.Sdk.Endpoints.Tokens.Types.Requests; +using Backbone.ConsumerApi.Sdk.Endpoints.Tokens.Types.Responses; using Backbone.ConsumerApi.Tests.Integration.Configuration; using Backbone.ConsumerApi.Tests.Integration.Extensions; -using Backbone.ConsumerApi.Tests.Integration.Models; -using Backbone.Crypto.Abstractions; +using Backbone.ConsumerApi.Tests.Integration.Support; +using Backbone.Crypto; using Microsoft.Extensions.Options; using Newtonsoft.Json; -using TechTalk.SpecFlow.Assist; namespace Backbone.ConsumerApi.Tests.Integration.StepDefinitions; @@ -14,27 +17,51 @@ namespace Backbone.ConsumerApi.Tests.Integration.StepDefinitions; [Scope(Feature = "POST Token")] [Scope(Feature = "GET Token")] [Scope(Feature = "GET Tokens")] -internal class TokensApiStepDefinitions : BaseStepDefinitions +internal class TokensApiStepDefinitions { - private readonly TokensApi _tokensApi; private string _tokenId; private string _peerTokenId; private readonly List _givenOwnTokens; private readonly List _responseTokens; - private HttpResponse? _createTokenResponse; - private HttpResponse? _tokenResponse; - private HttpResponse>? _tokensResponse; - private static readonly string TOMORROW_AS_STRING = DateTime.Now.AddDays(1).ToString("yyyy-MM-dd"); - private static readonly string YESTERDAY_AS_STRING = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd"); - - public TokensApiStepDefinitions(IOptions httpConfiguration, TokensApi tokensApi, ISignatureHelper signatureHelper, ChallengesApi challengesApi, IdentitiesApi identitiesApi, DevicesApi devicesApi) : - base(httpConfiguration, signatureHelper, challengesApi, identitiesApi, devicesApi) + private ApiResponse? _createTokenResponse; + private ApiResponse? _createTokenResponse401; + private ApiResponse? _tokenResponse; + private ApiResponse? _tokensResponse; + private readonly HttpClient _httpClient; + private readonly ClientCredentials _clientCredentials; + private bool _isAuthenticated; + private Client _sdk = null!; + + private static readonly DateTime TOMORROW = DateTime.Now.AddDays(1); + + private static readonly byte[] CONTENT = ConvertibleString.FromUtf8(JsonConvert.SerializeObject(new + { + key = "some-value" + })).BytesRepresentation; + + public TokensApiStepDefinitions(IOptions httpConfiguration, HttpClientFactory factory) { - _tokensApi = tokensApi; + _isAuthenticated = false; _tokenId = string.Empty; _peerTokenId = string.Empty; _givenOwnTokens = []; _responseTokens = []; + _httpClient = factory.CreateClient(); + _clientCredentials = new ClientCredentials(httpConfiguration.Value.ClientCredentials.ClientId, httpConfiguration.Value.ClientCredentials.ClientSecret); + } + + [Given("the user is authenticated")] + public async Task GivenTheUserIsAuthenticated() + { + _sdk = await Client.CreateForNewIdentity(_httpClient, _clientCredentials, Constants.DEVICE_PASSWORD); + _isAuthenticated = true; + } + + [Given("the user is unauthenticated")] + public void GivenTheUserIsUnauthenticated() + { + _sdk = Client.CreateUnauthenticated(_httpClient, _clientCredentials); + _isAuthenticated = false; } [Given("an own Token t")] @@ -42,21 +69,15 @@ public async Task GivenAnOwnTokenT() { var createTokenRequest = new CreateTokenRequest { - Content = "QQ==", - ExpiresAt = TOMORROW_AS_STRING + Content = CONTENT, + ExpiresAt = TOMORROW }; - var requestConfiguration = new RequestConfiguration(); - requestConfiguration.SupplementWith(_requestConfiguration); - requestConfiguration.Authenticate = true; - requestConfiguration.Content = JsonConvert.SerializeObject(createTokenRequest); - requestConfiguration.ContentType = "application/json"; - - var response = await _tokensApi.CreateToken(requestConfiguration); - response.IsSuccessStatusCode.Should().BeTrue(); + var client = await Client.CreateForNewIdentity(_httpClient, _clientCredentials, Constants.DEVICE_PASSWORD); + var response = await client.Tokens.CreateToken(createTokenRequest); + response.Should().BeASuccess(); - var token = response.Content.Result!; - _tokenId = token.Id; + _tokenId = response.Result!.Id; _tokenId.Should().NotBeNullOrEmpty(); } @@ -65,23 +86,14 @@ public async Task GivenAPeerTokenP() { var createTokenRequest = new CreateTokenRequest { - Content = "QQ==", - ExpiresAt = TOMORROW_AS_STRING + Content = CONTENT, + ExpiresAt = TOMORROW }; - var requestConfiguration = new RequestConfiguration(); - requestConfiguration.SupplementWith(_requestConfiguration); - requestConfiguration.Authenticate = true; - requestConfiguration.AuthenticationParameters.Username = "USRb"; - requestConfiguration.AuthenticationParameters.Password = "b"; - requestConfiguration.Content = JsonConvert.SerializeObject(createTokenRequest); - requestConfiguration.ContentType = "application/json"; + var response = await _sdk.Tokens.CreateToken(createTokenRequest); + response.Should().BeASuccess(); - var response = await _tokensApi.CreateToken(requestConfiguration); - response.IsSuccessStatusCode.Should().BeTrue(); - - var token = response.Content.Result!; - _peerTokenId = token.Id; + _peerTokenId = response.Result!.Id; _peerTokenId.Should().NotBeNullOrEmpty(); } @@ -92,22 +104,15 @@ public async Task GivenTheUserCreatedMultipleTokens() { var createTokenRequest = new CreateTokenRequest { - Content = "QQ==", - ExpiresAt = TOMORROW_AS_STRING + Content = CONTENT, + ExpiresAt = TOMORROW }; - var requestConfiguration = new RequestConfiguration - { - Content = JsonConvert.SerializeObject(createTokenRequest), - ContentType = "application/json" - }; - requestConfiguration.SupplementWith(_requestConfiguration); - var response = await _tokensApi.CreateToken(requestConfiguration); + var response = await _sdk.Tokens.CreateToken(createTokenRequest); - response.Should().NotBeNull(); - response.StatusCode.Should().Be(HttpStatusCode.Created); + response.Should().BeASuccess(); - _givenOwnTokens.Add(response.Content.Result!); + _givenOwnTokens.Add(response.Result!); } } @@ -116,42 +121,44 @@ public async Task WhenAGETRequestIsSentToTheTokensEndpointWithAListOfIdsOfOwnTok { var tokenIds = _givenOwnTokens.Select(t => t.Id); - _tokensResponse = await _tokensApi.GetTokensByIds(_requestConfiguration, tokenIds); + _tokensResponse = await _sdk.Tokens.ListTokens(tokenIds); _tokensResponse.Should().NotBeNull(); - var tokens = _tokensResponse.Content.Result!.ToArray(); + var tokens = _tokensResponse.Result!.ToArray(); tokens.Should().HaveCount(_givenOwnTokens.Count); _responseTokens.AddRange(tokens); } - [When("a POST request is sent to the Tokens endpoint with")] - public async Task WhenAPOSTRequestIsSentToTheTokensEndpointWith(Table table) + [When("a POST request is sent to the Tokens endpoint")] + public async Task WhenAPOSTRequestIsSentToTheTokensEndpointWith() { - var requestConfiguration = table.CreateInstance(); - requestConfiguration.SupplementWith(_requestConfiguration); + var request = new CreateTokenRequest + { + Content = CONTENT, + ExpiresAt = TOMORROW + }; - if (!string.IsNullOrEmpty(requestConfiguration.Content)) + if (_isAuthenticated) { - switch (requestConfiguration.Content) - { - case var c when c.Contains(""): - requestConfiguration.Content = requestConfiguration.Content.Replace("", TOMORROW_AS_STRING); - break; - case var c when c.Contains(""): - requestConfiguration.Content = requestConfiguration.Content.Replace("", YESTERDAY_AS_STRING); - break; - } + _createTokenResponse = await _sdk.Tokens.CreateToken(request); + } + else + { + _createTokenResponse401 = await _sdk.Tokens.CreateTokenUnauthenticated(request); } - - _createTokenResponse = await _tokensApi.CreateToken(requestConfiguration); } - [When("a POST request is sent to the Tokens endpoint with no request content")] + [When("a POST request is sent to the Tokens endpoint with invalid Content Type")] public async Task WhenAPOSTRequestIsSentToTheTokensEndpointWithNoRequestContent() { - _requestConfiguration.Content = null; - _createTokenResponse = await _tokensApi.CreateToken(_requestConfiguration); + var request = new CreateTokenRequest + { + Content = CONTENT, + ExpiresAt = TOMORROW + }; + + _createTokenResponse = await _sdk.Tokens.CreateToken(request); } [When(@"a GET request is sent to the Tokens/{id} endpoint with ""?(.*?)""?")] @@ -170,37 +177,16 @@ public async Task WhenAGETRequestIsSentToTheTokensIdEndpointWith(string id) break; } - _tokenResponse = await _tokensApi.GetTokenById(_requestConfiguration, id); - } - - [When("a POST request is sent to the Tokens endpoint with '([^']*)', '([^']*)'")] - public async Task WhenAPOSTRequestIsSentToTheTokensEndpointWith(string content, string expiresAt) - { - var createTokenRequest = new CreateTokenRequest - { - Content = content, - ExpiresAt = expiresAt - }; - - var requestConfiguration = new RequestConfiguration - { - Content = JsonConvert.SerializeObject(createTokenRequest), - ContentType = "application/json" - }; - - requestConfiguration.SupplementWith(_requestConfiguration); - - _createTokenResponse = await _tokensApi.CreateToken(requestConfiguration); + _tokenResponse = await _sdk.Tokens.GetToken(id); } [When(@"a GET request is sent to the Tokens endpoint with a list containing t\.Id, p\.Id")] public async Task WhenAGETRequestIsSentToTheTokensEndpointWithAListContainingT_IdP_Id() { var tokenIds = new List { _tokenId, _peerTokenId }; - _tokensResponse = await _tokensApi.GetTokensByIds(_requestConfiguration, tokenIds); + _tokensResponse = await _sdk.Tokens.ListTokens(tokenIds); - var tokens = _tokensResponse.Content.Result!; - _responseTokens.AddRange(tokens); + _responseTokens.AddRange(_tokensResponse.Result!); } [Then("the response contains both Tokens")] @@ -211,7 +197,6 @@ public void ThenTheResponseOnlyContainsTheOwnToken() .And.Contain(token => token.Id == _peerTokenId); } - [Then("the response contains all Tokens with the given ids")] public void ThenTheResponseContainsAllTokensWithTheGivenIds() { @@ -225,46 +210,40 @@ public void ThenTheResponseContainsAllTokensWithTheGivenIds() public void ThenTheResponseContainsACreateTokenResponse() { _createTokenResponse!.Should().NotBeNull(); - _createTokenResponse!.IsSuccessStatusCode.Should().BeTrue(); + _createTokenResponse!.Should().BeASuccess(); _createTokenResponse!.ContentType.Should().Be("application/json"); - _createTokenResponse!.AssertContentCompliesWithSchema(); + _createTokenResponse!.Should().ComplyWithSchema(); } [Then("the response contains a Token")] public void ThenTheResponseContainsAToken() { _tokenResponse!.Should().NotBeNull(); - _tokenResponse!.IsSuccessStatusCode.Should().BeTrue(); + _tokenResponse!.Should().BeASuccess(); _tokenResponse!.ContentType.Should().Be("application/json"); - _tokenResponse!.AssertContentCompliesWithSchema(); + _tokenResponse!.Should().ComplyWithSchema(); } [Then(@"the response status code is (\d+) \(.+\)")] public void ThenTheResponseStatusCodeIs(int expectedStatusCode) { if (_tokensResponse != null) - { - var actualStatusCode = (int)_tokensResponse.StatusCode; - actualStatusCode.Should().Be(expectedStatusCode); - } + ((int)_tokensResponse.Status).Should().Be(expectedStatusCode); if (_tokenResponse != null) - { - var actualStatusCode = (int)_tokenResponse.StatusCode; - actualStatusCode.Should().Be(expectedStatusCode); - } + ((int)_tokenResponse.Status).Should().Be(expectedStatusCode); if (_createTokenResponse != null) - { - var actualStatusCode = (int)_createTokenResponse.StatusCode; - actualStatusCode.Should().Be(expectedStatusCode); - } + ((int)_createTokenResponse.Status).Should().Be(expectedStatusCode); + + if (_createTokenResponse401 != null) + ((int)_createTokenResponse401.Status).Should().Be(expectedStatusCode); } - [Then(@"the response content includes an error with the error code ""([^""]+)""")] + [Then(@"the response content contains an error with the error code ""([^""]+)""")] public void ThenTheResponseContentIncludesAnErrorWithTheErrorCode(string errorCode) { - _tokenResponse!.Content.Error.Should().NotBeNull(); - _tokenResponse.Content.Error!.Code.Should().Be(errorCode); + _tokenResponse!.Error.Should().NotBeNull(); + _tokenResponse.Error!.Code.Should().Be(errorCode); } } diff --git a/ConsumerApi.Tests.Integration/Support/Constants.cs b/ConsumerApi.Tests.Integration/Support/Constants.cs new file mode 100644 index 0000000000..3baeae4188 --- /dev/null +++ b/ConsumerApi.Tests.Integration/Support/Constants.cs @@ -0,0 +1,6 @@ +namespace Backbone.ConsumerApi.Tests.Integration.Support; + +public static class Constants +{ + public const string DEVICE_PASSWORD = "someDevicePassword"; +} diff --git a/ConsumerApi.Tests.Integration/Support/Dependencies.cs b/ConsumerApi.Tests.Integration/Support/Dependencies.cs index f9da564f24..dce1929853 100644 --- a/ConsumerApi.Tests.Integration/Support/Dependencies.cs +++ b/ConsumerApi.Tests.Integration/Support/Dependencies.cs @@ -1,7 +1,4 @@ -using Backbone.ConsumerApi.Tests.Integration.API; using Backbone.ConsumerApi.Tests.Integration.Configuration; -using Backbone.Crypto.Abstractions; -using Backbone.Crypto.Implementations; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using SolidToken.SpecFlow.DependencyInjection; @@ -24,13 +21,6 @@ public static IServiceCollection CreateServices() services.ConfigureAndValidate(options => config.GetSection("Http").Bind(options)); services.AddSingleton(new HttpClientFactory(new CustomWebApplicationFactory())); - services.AddSingleton(SignatureHelper.CreateEd25519WithRawKeyFormat()); - - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); return services; } diff --git a/ConsumerApi.Tests.Integration/appsettings.json b/ConsumerApi.Tests.Integration/appsettings.json index 18bd1d20a8..a4217a74b4 100644 --- a/ConsumerApi.Tests.Integration/appsettings.json +++ b/ConsumerApi.Tests.Integration/appsettings.json @@ -1,6 +1,5 @@ { "Http": { - "BaseUrl": "http://localhost:5000", "ClientCredentials": { "ClientId": "test", "ClientSecret": "test" diff --git a/Modules/Devices/src/Devices.Application/DTOs/IdentityDeletionProcessDetailsDTO.cs b/Modules/Devices/src/Devices.Application/DTOs/IdentityDeletionProcessDetailsDTO.cs index 5bf90736aa..ebdb58e32c 100644 --- a/Modules/Devices/src/Devices.Application/DTOs/IdentityDeletionProcessDetailsDTO.cs +++ b/Modules/Devices/src/Devices.Application/DTOs/IdentityDeletionProcessDetailsDTO.cs @@ -13,21 +13,29 @@ public IdentityDeletionProcessDetailsDTO(IdentityDeletionProcess process) .ToList(); Status = process.Status; CreatedAt = process.CreatedAt; + ApprovalPeriodEndsAt = process.ApprovalPeriodEndsAt; + ApprovalReminder1SentAt = process.ApprovalReminder1SentAt; ApprovalReminder2SentAt = process.ApprovalReminder2SentAt; ApprovalReminder3SentAt = process.ApprovalReminder3SentAt; + ApprovedAt = process.ApprovedAt; ApprovedByDevice = process.ApprovedByDevice; + GracePeriodEndsAt = process.GracePeriodEndsAt; + GracePeriodReminder1SentAt = process.GracePeriodReminder1SentAt; GracePeriodReminder2SentAt = process.GracePeriodReminder2SentAt; GracePeriodReminder3SentAt = process.GracePeriodReminder3SentAt; } + public string Id { get; set; } public List AuditLog { get; set; } public DeletionProcessStatus Status { get; set; } public DateTime CreatedAt { get; set; } + public DateTime ApprovalPeriodEndsAt { get; set; } + public DateTime? ApprovalReminder1SentAt { get; set; } public DateTime? ApprovalReminder2SentAt { get; set; } diff --git a/Modules/Devices/src/Devices.Application/DTOs/IdentityDeletionProcessOverviewDTO.cs b/Modules/Devices/src/Devices.Application/DTOs/IdentityDeletionProcessOverviewDTO.cs index 603f2d497b..4771fa0382 100644 --- a/Modules/Devices/src/Devices.Application/DTOs/IdentityDeletionProcessOverviewDTO.cs +++ b/Modules/Devices/src/Devices.Application/DTOs/IdentityDeletionProcessOverviewDTO.cs @@ -10,12 +10,17 @@ public IdentityDeletionProcessOverviewDTO(IdentityDeletionProcess process) Id = process.Id; Status = process.Status; CreatedAt = process.CreatedAt; + ApprovalPeriodEndsAt = process.ApprovalPeriodEndsAt; + ApprovalReminder1SentAt = process.ApprovalReminder1SentAt; ApprovalReminder2SentAt = process.ApprovalReminder2SentAt; ApprovalReminder3SentAt = process.ApprovalReminder3SentAt; + ApprovedAt = process.ApprovedAt; ApprovedByDevice = process.ApprovedByDevice; + GracePeriodEndsAt = process.GracePeriodEndsAt; + GracePeriodReminder1SentAt = process.GracePeriodReminder1SentAt; GracePeriodReminder2SentAt = process.GracePeriodReminder2SentAt; GracePeriodReminder3SentAt = process.GracePeriodReminder3SentAt; @@ -24,6 +29,7 @@ public IdentityDeletionProcessOverviewDTO(IdentityDeletionProcess process) public string Id { get; set; } public DeletionProcessStatus Status { get; set; } public DateTime CreatedAt { get; set; } + public DateTime ApprovalPeriodEndsAt { get; set; } public DateTime? ApprovalReminder1SentAt { get; set; } public DateTime? ApprovalReminder2SentAt { get; set; } diff --git a/Modules/Devices/src/Devices.Application/Identities/Commands/SendDeletionProcessApprovalReminders/Handler.cs b/Modules/Devices/src/Devices.Application/Identities/Commands/SendDeletionProcessApprovalReminders/Handler.cs index 04f448bee0..77847b189e 100644 --- a/Modules/Devices/src/Devices.Application/Identities/Commands/SendDeletionProcessApprovalReminders/Handler.cs +++ b/Modules/Devices/src/Devices.Application/Identities/Commands/SendDeletionProcessApprovalReminders/Handler.cs @@ -33,8 +33,7 @@ public async Task Handle(SendDeletionProcessApprovalRemindersCommand request, Ca foreach (var identity in identities) { var deletionProcess = identity.GetDeletionProcessInStatus(DeletionProcessStatus.WaitingForApproval) ?? throw new NotFoundException(nameof(IdentityDeletionProcess)); - var endOfApprovalPeriod = deletionProcess.GetEndOfApprovalPeriod(); - var daysUntilApprovalPeriodEnds = (endOfApprovalPeriod - SystemTime.UtcNow).Days; + var daysUntilApprovalPeriodEnds = (deletionProcess.ApprovalPeriodEndsAt - SystemTime.UtcNow).Days; if (deletionProcess.ApprovalReminder3SentAt != null) { @@ -77,6 +76,7 @@ private async Task SendReminder2(Identity identity, int daysUntilApprovalPeriodE await _identitiesRepository.Update(identity, cancellationToken); _logger.ApprovalReminder2Sent(identity.Address, deletionProcessId); } + private async Task SendReminder1(Identity identity, int daysUntilApprovalPeriodEnds, IdentityDeletionProcessId deletionProcessId, CancellationToken cancellationToken) { await _pushNotificationSender.SendNotification(identity.Address, new DeletionProcessWaitingForApprovalReminderPushNotification(daysUntilApprovalPeriodEnds), cancellationToken); diff --git a/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionConfiguration.cs b/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionConfiguration.cs index 652c764eef..560c99b61f 100644 --- a/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionConfiguration.cs +++ b/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionConfiguration.cs @@ -2,40 +2,40 @@ namespace Backbone.Modules.Devices.Domain.Entities.Identities; public class IdentityDeletionConfiguration { - public static int MaxApprovalTime { get; set; } = 10; - public static int LengthOfGracePeriod { get; set; } = 30; + public static int LengthOfApprovalPeriod { get; } = 7; + public static int LengthOfGracePeriod { get; } = 14; - public static GracePeriodNotificationConfiguration GracePeriodNotification1 { get; set; } = new() + public static GracePeriodNotificationConfiguration GracePeriodNotification1 { get; } = new() { - Time = 20 + Time = 12 }; - public static GracePeriodNotificationConfiguration GracePeriodNotification2 { get; set; } = new() + public static GracePeriodNotificationConfiguration GracePeriodNotification2 { get; } = new() { Time = 10 }; - public static GracePeriodNotificationConfiguration GracePeriodNotification3 { get; set; } = new() + public static GracePeriodNotificationConfiguration GracePeriodNotification3 { get; } = new() { Time = 5 }; - public static ApprovalReminderNotificationConfiguration ApprovalReminder1 { get; set; } = new() + public static ApprovalReminderNotificationConfiguration ApprovalReminder1 { get; } = new() { - Time = 10 + Time = 6 }; - public static ApprovalReminderNotificationConfiguration ApprovalReminder2 { get; set; } = new() + public static ApprovalReminderNotificationConfiguration ApprovalReminder2 { get; } = new() { - Time = 5 + Time = 4 }; - public static ApprovalReminderNotificationConfiguration ApprovalReminder3 { get; set; } = new() + public static ApprovalReminderNotificationConfiguration ApprovalReminder3 { get; } = new() { Time = 2 }; - public static DeletionStartsNotification DeletionStartsNotification { get; set; } = new() + public static DeletionStartsNotification DeletionStartsNotification { get; } = new() { Text = "The grace period for the deletion of your identity has expired. The deletion starts now." }; @@ -43,15 +43,15 @@ public class IdentityDeletionConfiguration public class GracePeriodNotificationConfiguration { - public int Time { get; set; } + public int Time { get; init; } } public class ApprovalReminderNotificationConfiguration { - public int Time { get; set; } + public int Time { get; init; } } public class DeletionStartsNotification { - public string Text { get; set; } = ""; + public string Text { get; init; } = ""; } diff --git a/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionProcess.cs b/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionProcess.cs index 1760a23fa8..c927edeba4 100644 --- a/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionProcess.cs +++ b/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionProcess.cs @@ -40,6 +40,7 @@ private IdentityDeletionProcess(IdentityAddress createdBy, DeviceId createdByDev public DeletionProcessStatus Status { get; private set; } public DateTime DeletionStartedAt { get; private set; } public DateTime CreatedAt { get; } + public DateTime ApprovalPeriodEndsAt => CreatedAt.AddDays(IdentityDeletionConfiguration.LengthOfApprovalPeriod); public DateTime? ApprovalReminder1SentAt { get; private set; } public DateTime? ApprovalReminder2SentAt { get; private set; } @@ -60,7 +61,7 @@ private IdentityDeletionProcess(IdentityAddress createdBy, DeviceId createdByDev public DateTime? GracePeriodReminder2SentAt { get; private set; } public DateTime? GracePeriodReminder3SentAt { get; private set; } - public bool HasApprovalPeriodExpired => Status == DeletionProcessStatus.WaitingForApproval && SystemTime.UtcNow >= GetEndOfApprovalPeriod(); + public bool HasApprovalPeriodExpired => Status == DeletionProcessStatus.WaitingForApproval && SystemTime.UtcNow >= ApprovalPeriodEndsAt; public bool HasGracePeriodExpired => Status == DeletionProcessStatus.Approved && SystemTime.UtcNow >= GracePeriodEndsAt; @@ -87,11 +88,6 @@ public bool IsActive() return Status is DeletionProcessStatus.Approved or DeletionProcessStatus.WaitingForApproval or DeletionProcessStatus.Deleting; } - public DateTime GetEndOfApprovalPeriod() - { - return CreatedAt.AddDays(IdentityDeletionConfiguration.MaxApprovalTime); - } - public void ApprovalReminder1Sent(IdentityAddress address) { ApprovalReminder1SentAt = SystemTime.UtcNow; diff --git a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/ApproveDeletionProcess/HandlerTests.cs b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/ApproveDeletionProcess/HandlerTests.cs index 76d4bb1963..5df7dec508 100644 --- a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/ApproveDeletionProcess/HandlerTests.cs +++ b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/ApproveDeletionProcess/HandlerTests.cs @@ -46,7 +46,7 @@ public async Task Happy_path() && i.Status == IdentityStatus.ToBeDeleted && i.TierId == Tier.QUEUED_FOR_DELETION.Id && i.DeletionProcesses.FirstOrDefault(d => d.Status == DeletionProcessStatus.Approved)!.ApprovedAt == DateTime.Parse("2000-01-01") - && i.DeletionProcesses.FirstOrDefault(d => d.Status == DeletionProcessStatus.Approved)!.GracePeriodEndsAt == DateTime.Parse("2000-01-31") + && i.DeletionProcesses.FirstOrDefault(d => d.Status == DeletionProcessStatus.Approved)!.GracePeriodEndsAt == DateTime.Parse("2000-01-15") && i.DeletionProcesses.FirstOrDefault(d => d.Status == DeletionProcessStatus.Approved)!.ApprovedByDevice == device.Id ), A._)) .MustHaveHappenedOnceExactly(); diff --git a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/SendDeletionProcessApprovalReminders/HandlerTests.cs b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/SendDeletionProcessApprovalReminders/HandlerTests.cs index 074bf6b54a..7374339150 100644 --- a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/SendDeletionProcessApprovalReminders/HandlerTests.cs +++ b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/SendDeletionProcessApprovalReminders/HandlerTests.cs @@ -71,7 +71,7 @@ public async Task Sends_second_reminder() var identity = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval(deletionProcessStartedAt: DateTime.Parse("2000-01-01")); identity.DeletionProcessApprovalReminder1Sent(); - var utcNow = DateTime.Parse("2000-01-06"); + var utcNow = DateTime.Parse("2000-01-04"); SystemTime.Set(utcNow); var mockIdentitiesRepository = A.Fake(); @@ -103,7 +103,7 @@ public async Task Sends_third_reminder() identity.DeletionProcessApprovalReminder1Sent(); identity.DeletionProcessApprovalReminder2Sent(); - var utcNow = DateTime.Parse("2000-01-09"); + var utcNow = DateTime.Parse("2000-01-06"); SystemTime.Set(utcNow); var mockIdentitiesRepository = A.Fake(); @@ -133,7 +133,7 @@ public async Task Does_not_send_reminder_1_when_2_has_to_be_sent_as_well() // Arrange var identity = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval(deletionProcessStartedAt: DateTime.Parse("2000-01-01")); - var utcNow = DateTime.Parse("2000-01-06"); + var utcNow = DateTime.Parse("2000-01-04"); SystemTime.Set(utcNow); var mockIdentitiesRepository = A.Fake(); @@ -164,7 +164,7 @@ public async Task Does_not_send_reminder_1_and_2_when_3_has_to_be_sent_as_well() // Arrange var identity = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval(deletionProcessStartedAt: DateTime.Parse("2000-01-01")); - var utcNow = DateTime.Parse("2000-01-09"); + var utcNow = DateTime.Parse("2000-01-06"); SystemTime.Set(utcNow); var mockIdentitiesRepository = A.Fake(); diff --git a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/SendDeletionProcessGracePeriodReminders/HandlerTests.cs b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/SendDeletionProcessGracePeriodReminders/HandlerTests.cs index 17b78ca376..d39503e4be 100644 --- a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/SendDeletionProcessGracePeriodReminders/HandlerTests.cs +++ b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/SendDeletionProcessGracePeriodReminders/HandlerTests.cs @@ -41,7 +41,7 @@ public async Task Sends_first_reminder() // Arrange var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(approvalDate: DateTime.Parse("2000-01-01")); - var utcNow = DateTime.Parse("2000-01-11"); + var utcNow = DateTime.Parse("2000-01-03"); SystemTime.Set(utcNow); var mockIdentitiesRepository = A.Fake(); @@ -71,7 +71,7 @@ public async Task Sends_second_reminder() var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(approvalDate: DateTime.Parse("2000-01-01")); identity.DeletionGracePeriodReminder1Sent(); - var utcNow = DateTime.Parse("2000-01-21"); + var utcNow = DateTime.Parse("2000-01-05"); SystemTime.Set(utcNow); var mockIdentitiesRepository = A.Fake(); @@ -103,7 +103,7 @@ public async Task Sends_third_reminder() identity.DeletionGracePeriodReminder1Sent(); identity.DeletionGracePeriodReminder2Sent(); - var utcNow = DateTime.Parse("2000-01-26"); + var utcNow = DateTime.Parse("2000-01-10"); SystemTime.Set(utcNow); var mockIdentitiesRepository = A.Fake(); @@ -133,7 +133,7 @@ public async Task Does_not_send_reminder_1_when_2_has_to_be_sent_as_well() // Arrange var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(approvalDate: DateTime.Parse("2000-01-01")); - var utcNow = DateTime.Parse("2000-01-21"); + var utcNow = DateTime.Parse("2000-01-05"); SystemTime.Set(utcNow); var mockIdentitiesRepository = A.Fake(); @@ -162,7 +162,7 @@ public async Task Does_not_send_reminder_1_when_2_has_to_be_sent_as_well() public async Task Does_not_send_reminder_1_and_2_when_3_has_to_be_sent_as_well() { // Arrange - var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(approvalDate: DateTime.Parse("2000-01-01")); + var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(approvalDate: DateTime.Parse("2000-01-09")); var utcNow = DateTime.Parse("2000-01-26"); SystemTime.Set(utcNow); diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/ApproveDeletionProcessTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/ApproveDeletionProcessTests.cs index f6bbcdb5a2..23389f3976 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/Identities/ApproveDeletionProcessTests.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/ApproveDeletionProcessTests.cs @@ -25,7 +25,7 @@ public void Approve_deletion_process_waiting_for_approval() // Assert identity.Status.Should().Be(IdentityStatus.ToBeDeleted); - identity.DeletionGracePeriodEndsAt.Should().Be(DateTime.Parse("2000-01-31")); + identity.DeletionGracePeriodEndsAt.Should().Be(DateTime.Parse("2000-01-15")); identity.TierId.Should().Be(Tier.QUEUED_FOR_DELETION.Id); var deletionProcess = identity.DeletionProcesses.FirstOrDefault(d => d.Status == DeletionProcessStatus.Approved)!; AssertAuditLogEntryWasCreated(deletionProcess); diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelStaleDeletionProcessTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelStaleDeletionProcessTests.cs index 5d67d7d953..20812222a1 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelStaleDeletionProcessTests.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelStaleDeletionProcessTests.cs @@ -48,11 +48,9 @@ public void Cancel_deletion_process_that_is_past_due_approval() var identity = TestDataGenerator.CreateIdentity(); identity.StartDeletionProcessAsSupport(); - var utcNow = DateTime.Parse("2020-01-11T00:00:00"); + var utcNow = DateTime.Parse("2020-01-08T00:00:00"); SystemTime.Set(utcNow); - IdentityDeletionConfiguration.MaxApprovalTime = 10; - // Act var result = identity.CancelStaleDeletionProcess(); @@ -70,9 +68,7 @@ public void Canceling_stale_deletion_process_creates_audit_log_entry_when_execut // Arrange SystemTime.Set(DateTime.Parse("2020-01-01T00:00:00")); var identity = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval(); - SystemTime.Set(DateTime.Parse("2020-01-11T00:00:00")); - - IdentityDeletionConfiguration.MaxApprovalTime = 10; + SystemTime.Set(DateTime.Parse("2020-01-08T00:00:00")); // Act var result = identity.CancelStaleDeletionProcess(); diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionProcessApprovalPeriodEndsAtTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionProcessApprovalPeriodEndsAtTests.cs new file mode 100644 index 0000000000..c9aa5b1f39 --- /dev/null +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionProcessApprovalPeriodEndsAtTests.cs @@ -0,0 +1,26 @@ +using Backbone.Tooling; +using Backbone.UnitTestTools.Extensions; +using FluentAssertions; +using Xunit; +using static Backbone.Modules.Devices.Domain.Tests.TestDataGenerator; + +namespace Backbone.Modules.Devices.Domain.Tests.Identities; + +public class DeletionProcessApprovalPeriodEndsAtTests +{ + [Fact] + public void Deletion_process_ApprovalPeriodEndsAt_returns_expected_date() + { + // Arrange + SystemTime.Set("2024-01-01"); + + var identity = CreateIdentityWithDeletionProcessWaitingForApproval(); + var deletionProcess = identity.DeletionProcesses[0]; + + // Act + var approvalPeriodEndsAt = deletionProcess.ApprovalPeriodEndsAt; + + // Assert + approvalPeriodEndsAt.Should().Be("2024-01-08"); + } +} diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionProcessApprovalReminderTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionProcessApprovalReminderTests.cs index a112385d3d..3daa787594 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionProcessApprovalReminderTests.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionProcessApprovalReminderTests.cs @@ -6,7 +6,6 @@ using Backbone.Tooling; using FluentAssertions; using Xunit; -using static Backbone.UnitTestTools.Data.TestDataGenerator; namespace Backbone.Modules.Devices.Domain.Tests.Identities; @@ -107,22 +106,6 @@ public void DeletionProcessApprovalReminder3Sent_fails_when_no_deletion_process_ acting.Should().Throw().Which.Code.Should().Be("error.platform.validation.device.deletionProcessIsNotInRequiredStatus"); } - [Fact] - public void GetEndOfApprovalPeriod_returns_expected_date() - { - // Arrange - SystemTime.Set(DateTime.Parse("2000-01-01")); - IdentityDeletionConfiguration.MaxApprovalTime = 10; - - var deletionProcess = IdentityDeletionProcess.StartAsOwner(CreateRandomIdentityAddress(), CreateRandomDeviceId()); - - // Act - var endOfApprovalPeriod = deletionProcess.GetEndOfApprovalPeriod(); - - // Assert - endOfApprovalPeriod.Should().Be(DateTime.Parse("2000-01-11")); - } - private static void AssertAuditLogEntryWasCreated(IdentityDeletionProcess deletionProcess) { deletionProcess.AuditLog.Should().HaveCount(2); diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/IdentityDeletionProcessTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/IdentityDeletionProcessTests.cs index 6e797c839a..e7fcffe5d9 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/Identities/IdentityDeletionProcessTests.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/IdentityDeletionProcessTests.cs @@ -1,5 +1,4 @@ -using Backbone.Modules.Devices.Domain.Entities.Identities; -using Backbone.Tooling; +using Backbone.Tooling; using FluentAssertions; using Xunit; @@ -10,7 +9,7 @@ public class IdentityDeletionProcessTests [Theory] [InlineData("2020-01-01T00:00:00")] [InlineData("2020-01-01T00:00:01")] - [InlineData("2020-01-09T23:59:59")] + [InlineData("2020-01-06T23:59:59")] public void HasApprovalPeriodExpired_is_false_for_deletion_process_still_in_approval_period(string utcNow) { // Arrange @@ -18,8 +17,6 @@ public void HasApprovalPeriodExpired_is_false_for_deletion_process_still_in_appr var identity = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval(); SystemTime.Set(utcNow); - IdentityDeletionConfiguration.MaxApprovalTime = 10; - // Act var result = identity.DeletionProcesses[0].HasApprovalPeriodExpired; @@ -28,9 +25,9 @@ public void HasApprovalPeriodExpired_is_false_for_deletion_process_still_in_appr } [Theory] - [InlineData("2020-01-11T00:00:00")] - [InlineData("2020-01-21T08:45:15")] - [InlineData("2025-01-01T00:00:00")] + [InlineData("2020-01-08T00:00:00")] + [InlineData("2020-02-07T08:45:15")] + [InlineData("2025-01-07T00:00:00")] public void HasApprovalPeriodExpired_is_true_for_stale_deletion_process(string utcNow) { // Arrange @@ -38,8 +35,6 @@ public void HasApprovalPeriodExpired_is_true_for_stale_deletion_process(string u var identity = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval(); SystemTime.Set(utcNow); - IdentityDeletionConfiguration.MaxApprovalTime = 10; - // Act var result = identity.DeletionProcesses[0].HasApprovalPeriodExpired; diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/StartDeletionProcessAsOwnerTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/StartDeletionProcessAsOwnerTests.cs index 48a2a17bb8..e0b965274d 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/Identities/StartDeletionProcessAsOwnerTests.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/StartDeletionProcessAsOwnerTests.cs @@ -31,7 +31,7 @@ public void Start_deletion_process() var deletionProcess = activeIdentity.StartDeletionProcessAsOwner(activeDevice.Id); // Assert - activeIdentity.DeletionGracePeriodEndsAt.Should().Be(DateTime.Parse("2000-01-31")); + activeIdentity.DeletionGracePeriodEndsAt.Should().Be(DateTime.Parse("2000-01-15")); activeIdentity.TierId.Value.Should().Be(Tier.QUEUED_FOR_DELETION.Id.Value); activeIdentity.Status.Should().Be(IdentityStatus.ToBeDeleted); @@ -39,7 +39,7 @@ public void Start_deletion_process() deletionProcess.Status.Should().Be(DeletionProcessStatus.Approved); deletionProcess.ApprovedAt.Should().Be(SystemTime.UtcNow); deletionProcess.ApprovedByDevice.Should().Be(activeDevice.Id); - deletionProcess.GracePeriodEndsAt.Should().Be(DateTime.Parse("2000-01-31")); + deletionProcess.GracePeriodEndsAt.Should().Be(DateTime.Parse("2000-01-15")); AssertAuditLogEntryWasCreated(deletionProcess); var auditLogEntry = deletionProcess.AuditLog[0]; diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/GetPeerTests.cs b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/GetPeerTests.cs new file mode 100644 index 0000000000..60d798d5f2 --- /dev/null +++ b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/GetPeerTests.cs @@ -0,0 +1,36 @@ +// using FluentAssertions; +// using Xunit; +// using static Backbone.Modules.Relationships.Domain.Tests.TestHelpers.TestData; +// +// namespace Backbone.Modules.Relationships.Domain.Tests.Tests.Aggregates.Relationships; +// +// public class GetPeerTests +// { +// [Fact] +// public void Returns_from_if_to_is_passed() +// { +// // Arrange +// var relationship = CreatePendingRelationship(); +// +// // Act +// var peer = relationship.GetPeer(relationship.From); +// +// // Assert +// peer.Should().Be(relationship.To); +// } +// +// [Fact] +// public void Returns_to_if_from_is_passed() +// { +// // Arrange +// var relationship = CreatePendingRelationship(); +// +// // Act +// var peer = relationship.GetPeer(relationship.To); +// +// // Assert +// peer.Should().Be(relationship.From); +// } +// } + + diff --git a/helm/templates/eventhandler/deployment.yaml b/helm/templates/eventhandler/deployment.yaml index 57c9ce8cf1..db3bcfd456 100644 --- a/helm/templates/eventhandler/deployment.yaml +++ b/helm/templates/eventhandler/deployment.yaml @@ -6,12 +6,12 @@ metadata: {{- include "global.labels" . | nindent 4 }} app: {{ .Values.eventhandler.name }} spec: - replicas: 1 + replicas: {{ .Values.eventhandler.replicas }} strategy: type: RollingUpdate rollingUpdate: - maxSurge: {{ .Values.maxSurge }} - maxUnavailable: {{ .Values.maxUnavailable }} + maxSurge: {{ .Values.eventhandler.maxSurge }} + maxUnavailable: {{ .Values.eventhandler.maxUnavailable }} selector: matchLabels: app: {{ .Values.eventhandler.name }} diff --git a/helm/templates/eventhandler/hpa.yaml b/helm/templates/eventhandler/hpa.yaml new file mode 100644 index 0000000000..61095e6efb --- /dev/null +++ b/helm/templates/eventhandler/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.eventhandler.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ .Values.eventhandler.name }} + labels: + {{- include "global.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ .Values.eventhandler.name }} + minReplicas: {{ .Values.eventhandler.autoscaling.minReplicas }} + maxReplicas: {{ .Values.eventhandler.autoscaling.maxReplicas }} + metrics: + {{- if .Values.eventhandler.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.eventhandler.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.eventhandler.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.eventhandler.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }}