Skip to content

Commit

Permalink
Merge branch 'main' into NMSHDB-152-Backbone-Administrator-Display-re…
Browse files Browse the repository at this point in the history
…lationships-of-an-identity
  • Loading branch information
mergify[bot] authored Jul 5, 2024
2 parents 1f10be9 + 7c899a2 commit d83c821
Show file tree
Hide file tree
Showing 23 changed files with 215 additions and 184 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.6"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0"/>
<PackageReference Include="Newtonsoft.Json.Schema" Version="4.0.1"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="NJsonSchema.NewtonsoftJson" Version="11.0.1" />
<PackageReference Include="ReHackt.Extensions.Options.Validation" Version="8.0.2" />
<PackageReference Include="SolidToken.SpecFlow.DependencyInjection" Version="3.9.3" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Backbone.AdminApi.Tests.Integration.Validators;
using Backbone.AdminApi.Tests.Integration.Support;
using Backbone.BuildingBlocks.SDK.Endpoints.Common.Types;
using FluentAssertions.Execution;
using FluentAssertions.Primitives;
Expand All @@ -14,17 +14,23 @@ public ApiResponseAssertions(ApiResponse<T> instance) : base(instance)

protected override string Identifier => "ApiResponse";

public void ComplyWithSchema(string because = "", params object[] becauseArgs)
public async Task ComplyWithSchema(string because = "", params object[] becauseArgs)
{
IList<string> errors = [];
Execute.Assertion
var assertion = Execute.Assertion
.BecauseOf(because, becauseArgs)
.Given(() => Subject.Result!)
.ForCondition(result => result != null)
.FailWith("You can't validate the JSON schema of a NULL object")
.Then
.ForCondition(result => JsonValidators.ValidateJsonSchema<T>(JsonConvert.SerializeObject(result), out errors))
.FailWith($"Response content does not comply with the {typeof(T).FullName} schema: {string.Join(", ", errors)}");
.Then;

if (Subject.Result != null)
{
var resultJson = JsonConvert.SerializeObject(Subject.Result);
var (isValid, errors) = await JsonValidator.ValidateJsonSchema<T>(resultJson);

assertion.ForCondition(_ => isValid)
.FailWith($"Response content does not comply with the {typeof(T).FullName} schema: {string.Join(", ", errors)}");
}
}

public void BeASuccess(string because = "", params object[] becauseArgs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@ public async Task WhenAGETRequestIsSentToTheClientsIdEndpoint()
}

[Then("the response contains Client c")]
public void ThenTheResponseContainsAClient()
public async Task ThenTheResponseContainsAClient()
{
_response!.Result!.Should().NotBeNull();
_response!.Result!.ClientId.Should().Be(_clientId);
_response!.Result!.DefaultTier.Should().Be(_tierId);
_response!.Result!.MaxIdentities.Should().Be(_maxIdentities);
_response!.ContentType.Should().StartWith("application/json");
_response!.Should().ComplyWithSchema();
await _response!.Should().ComplyWithSchema();
}

[Then(@"the response status code is (\d+) \(.+\)")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,35 +158,35 @@ public async Task WhenAPatchRequestIsSentToTheClientsEndpointForAnInexistentClie
}

[Then("the response contains a paginated list of Clients")]
public void ThenTheResponseContainsAListOfClients()
public async Task ThenTheResponseContainsAListOfClients()
{
_getClientsResponse!.Should().BeASuccess();
_getClientsResponse!.ContentType.Should().StartWith("application/json");
_getClientsResponse.Should().ComplyWithSchema();
await _getClientsResponse.Should().ComplyWithSchema();
}

[Then("the response contains Client c with the new client secret")]
public void ThenTheResponseContainsAClientWithNewSecret()
public async Task ThenTheResponseContainsAClientWithNewSecret()
{
_changeClientSecretResponse!.Should().BeASuccess();
_changeClientSecretResponse!.ContentType.Should().StartWith("application/json");
_changeClientSecretResponse.Should().ComplyWithSchema();
await _changeClientSecretResponse.Should().ComplyWithSchema();
}

[Then("the response contains Client c with a random secret generated by the backend")]
public void ThenTheResponseContainsAClientWithRandomGeneratedSecret()
public async Task ThenTheResponseContainsAClientWithRandomGeneratedSecret()
{
_changeClientSecretResponse!.Should().BeASuccess();
_changeClientSecretResponse!.ContentType.Should().StartWith("application/json");
_changeClientSecretResponse.Should().ComplyWithSchema();
await _changeClientSecretResponse.Should().ComplyWithSchema();
}

[Then("the response contains Client c")]
public void ThenTheResponseContainsAClient()
public async Task ThenTheResponseContainsAClient()
{
_updateClientResponse!.Should().BeASuccess();
_updateClientResponse!.ContentType.Should().StartWith("application/json");
_updateClientResponse!.Should().ComplyWithSchema();
await _updateClientResponse!.Should().ComplyWithSchema();
}

[Then("the Client in the Backend was successfully updated")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,35 +71,35 @@ public async Task WhenAGETRequestIsSentToTheIdentitiesAddressEndpointForAnInexis
}

[Then("the response contains a list of Identities")]
public void ThenTheResponseContainsAListOfIdentities()
public async Task ThenTheResponseContainsAListOfIdentities()
{
_identityOverviewsResponse!.Result!.Should().NotBeNull();
_identityOverviewsResponse!.ContentType.Should().StartWith("application/json");
_identityOverviewsResponse.Should().ComplyWithSchema();
await _identityOverviewsResponse.Should().ComplyWithSchema();
}

[Then("the response contains a list of Identity Deletion Process Audit Logs")]
public void ThenTheResponseContainsAListOfIdentityDeletionProcessAuditLogs()
public async Task ThenTheResponseContainsAListOfIdentityDeletionProcessAuditLogs()
{
_identityDeletionProcessAuditLogsResponse!.Result!.Should().NotBeNull();
_identityDeletionProcessAuditLogsResponse!.ContentType.Should().StartWith("application/json");
_identityDeletionProcessAuditLogsResponse.Should().ComplyWithSchema();
await _identityDeletionProcessAuditLogsResponse.Should().ComplyWithSchema();
}

[Then("the response contains a Deletion Process")]
public void ThenTheResponseContainsADeletionProcess()
public async Task ThenTheResponseContainsADeletionProcess()
{
_identityDeletionProcessResponse!.Result!.Should().NotBeNull();
_identityDeletionProcessResponse!.ContentType.Should().StartWith("application/json");
_identityDeletionProcessResponse.Should().ComplyWithSchema();
await _identityDeletionProcessResponse.Should().ComplyWithSchema();
}

[Then("the response contains Identity i")]
public void ThenTheResponseContainsAnIdentity()
public async Task ThenTheResponseContainsAnIdentity()
{
_identityResponse!.Result!.Should().NotBeNull();
_identityResponse!.ContentType.Should().StartWith("application/json");
_identityResponse.Should().ComplyWithSchema();
await _identityResponse.Should().ComplyWithSchema();
}

[Then(@"the response status code is (\d+) \(.+\)")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ public void ThenTheResponseStatusCodeIs(int expectedStatusCode)
}

[Then("the response contains an IndividualQuota")]
public void ThenTheResponseContainsAnIndividualQuota()
public async Task ThenTheResponseContainsAnIndividualQuota()
{
_createQuotaResponse!.Result!.Should().NotBeNull();
_createQuotaResponse!.ContentType.Should().StartWith("application/json");
_createQuotaResponse.Should().ComplyWithSchema();
await _createQuotaResponse.Should().ComplyWithSchema();
}

[Then(@"the response content contains an error with the error code ""([^""]+)""")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ public void ThenTheResponseStatusCodeIs(int expectedStatusCode)
}

[Then(@"the response contains a paginated list of Messages")]
public void ThenTheResponseContainsAListOfMessages()
public async Task ThenTheResponseContainsAListOfMessages()
{
_messagesResponse!.Result.Should().NotBeNull();
_messagesResponse!.Should().BeASuccess();
_messagesResponse!.ContentType.Should().StartWith("application/json");
_messagesResponse.Should().ComplyWithSchema();
await _messagesResponse.Should().ComplyWithSchema();
}

[Then(@"the response content contains an error with the error code ""([^""]+)""")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ public async Task WhenAGETRequestIsSentToTheMetricsEndpoint()
}

[Then("the response contains a list of Metrics")]
public void ThenTheResponseContainsAListOfMetrics()
public async Task ThenTheResponseContainsAListOfMetrics()
{
_metricsResponse!.Result!.Should().NotBeNullOrEmpty();
_metricsResponse!.ContentType.Should().StartWith("application/json");
_metricsResponse.Should().ComplyWithSchema();
await _metricsResponse.Should().ComplyWithSchema();
}

[Then(@"the response status code is (\d+) \(.+\)")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ public async Task WhenAGETRequestIsSentToTheTiersIdEndpoint()
}

[Then("the response contains Tier t")]
public void ThenTheResponseContainsATier()
public async Task ThenTheResponseContainsATier()
{
_tierDetailsResponse!.Result!.Should().NotBeNull();
_tierDetailsResponse!.Result!.Id.Should().Be(_tierId);
_tierDetailsResponse!.ContentType.Should().StartWith("application/json");
_tierDetailsResponse.Should().ComplyWithSchema();
await _tierDetailsResponse.Should().ComplyWithSchema();
}

[Then(@"the response status code is (\d+) \(.+\)")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ public void ThenTheResponseStatusCodeIs(int expectedStatusCode)
}

[Then("the response contains a TierQuota")]
public void ThenTheResponseContainsATierQuotaDefinition()
public async Task ThenTheResponseContainsATierQuotaDefinition()
{
_createTierQuotaResponse!.Should().BeASuccess();
_createTierQuotaResponse!.ContentType.Should().StartWith("application/json");
_createTierQuotaResponse.Should().ComplyWithSchema();
await _createTierQuotaResponse.Should().ComplyWithSchema();
}

[Then(@"the response content contains an error with the error code ""([^""]+)""")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,19 @@ public async Task WhenADeleteRequestIsSentToTheTiersT_IdEndpointWithAnInexistent
}

[Then("the response contains a paginated list of Tiers")]
public void ThenTheResponseContainsAListOfTiers()
public async Task ThenTheResponseContainsAListOfTiers()
{
_tiersResponse!.Should().BeASuccess();
_tiersResponse!.ContentType.Should().StartWith("application/json");
_tiersResponse.Should().ComplyWithSchema();
await _tiersResponse.Should().ComplyWithSchema();
}

[Then("the response contains a Tier")]
public void ThenTheResponseContainsATier()
public async Task ThenTheResponseContainsATier()
{
_tierResponse!.Should().BeASuccess();
_tierResponse!.ContentType.Should().StartWith("application/json");
_tierResponse.Should().ComplyWithSchema();
await _tierResponse.Should().ComplyWithSchema();
}

[Then(@"the response status code is (\d+) \(.+\)")]
Expand Down
65 changes: 65 additions & 0 deletions AdminApi/test/AdminApi.Tests.Integration/Support/JsonValidator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NJsonSchema;
using NJsonSchema.NewtonsoftJson.Generation;
using JsonSchemaGenerator = NJsonSchema.Generation.JsonSchemaGenerator;

namespace Backbone.AdminApi.Tests.Integration.Support;

public class JsonValidator
{
private static readonly Dictionary<Type, JsonSchema> CACHED_SCHEMAS = new();

public static async Task<(bool IsValid, IList<string> Errors)> ValidateJsonSchema<T>(string json)
{
var errors = new List<string>();

if (CACHED_SCHEMAS.TryGetValue(typeof(T), out var schema))
{
try
{
var parsedJson = JObject.Parse(json);
return CreateValueTupleResult(schema, parsedJson, errors);
}
catch (JsonReaderException)
{
var parsedJson = JArray.Parse(json);
return CreateValueTupleResult(schema, parsedJson, errors);
}
}

var settings = new NewtonsoftJsonSchemaGeneratorSettings();

var generator = new JsonSchemaGenerator(settings);

var schemaJson = generator.Generate(typeof(T));

var generatedSchema = schemaJson.ToJson();

schema = await JsonSchema.FromJsonAsync(generatedSchema);

schema.AllowAdditionalProperties = true;

CACHED_SCHEMAS.Add(typeof(T), schema);

try
{
var responseJson = JObject.Parse(json);
return CreateValueTupleResult(schema, responseJson, errors);
}
catch (JsonReaderException)
{
var responseJson = JArray.Parse(json);
return CreateValueTupleResult(schema, responseJson, errors);
}
}

private static (bool IsValid, IList<string> Errors) CreateValueTupleResult(JsonSchema schema, JToken parsedJson, List<string> errors)
{
var validationResults = schema.Validate(parsedJson);

errors.AddRange(validationResults.Select(validationResult => validationResult.ToString()));

return (validationResults.Count == 0, errors);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Newtonsoft.Json.Schema" Version="4.0.1"/>
<PackageReference Include="NJsonSchema.NewtonsoftJson" Version="11.0.1" />
</ItemGroup>
<ItemGroup>
Expand Down
Loading

0 comments on commit d83c821

Please sign in to comment.