Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DMS-376] Implementing Consumer Driven Tests, Initial Tests #331

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,6 @@
<PackageVersion Include="Reqnroll" Version="2.1.0" />
<PackageVersion Include="Reqnroll.NUnit" Version="2.1.0" />
<PackageVersion Include="Testcontainers" Version="3.10.0" />
<PackageVersion Include="PactNet" Version="5.0.0" />
</ItemGroup>
</Project>
18 changes: 16 additions & 2 deletions src/config/EdFi.DmsConfigurationService.sln
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EdFi.DmsConfigurationServic
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "datamodel", "datamodel", "{F90FF019-91D3-462E-94A4-96B52681DB16}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EdFi.DmsConfigurationService.DataModel", "datamodel\EdFi.DmsConfigurationService.DataModel\EdFi.DmsConfigurationService.DataModel.csproj", "{E97DCC9F-C27F-497D-94FE-3DD39038C38B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EdFi.DmsConfigurationService.DataModel", "datamodel\EdFi.DmsConfigurationService.DataModel\EdFi.DmsConfigurationService.DataModel.csproj", "{E97DCC9F-C27F-497D-94FE-3DD39038C38B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EdFi.DmsConfigurationService.Backend.Postgresql.Test.Integration", "backend\EdFi.DmsConfigurationService.Backend.Postgresql.Test.Integration\EdFi.DmsConfigurationService.Backend.Postgresql.Test.Integration.csproj", "{EE23DFFB-C61D-48FE-B821-2442D67D7AF9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EdFi.DmsConfigurationService.Backend.Postgresql.Test.Integration", "backend\EdFi.DmsConfigurationService.Backend.Postgresql.Test.Integration\EdFi.DmsConfigurationService.Backend.Postgresql.Test.Integration.csproj", "{EE23DFFB-C61D-48FE-B821-2442D67D7AF9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EdFi.DmsConfigurationService.Frontend.AspNetCore.ContractTest.ConsumerTests", "frontend\EdFi.DmsConfigurationService.Frontend.AspNetCore.ContractTest.ConsumerTests\EdFi.DmsConfigurationService.Frontend.AspNetCore.ContractTest.ConsumerTests.csproj", "{84FB1ECB-E944-4161-A179-73E176DFB9F6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EdFi.DmsConfigurationService.Frontend.AspNetCore.ContractTest.ProviderTests", "frontend\EdFi.DmsConfigurationService.Frontend.AspNetCore.ContractTest.ProviderTests\EdFi.DmsConfigurationService.Frontend.AspNetCore.ContractTest.ProviderTests.csproj", "{077502CE-1C1E-41D5-A30B-FF820B77B104}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -68,6 +72,14 @@ Global
{EE23DFFB-C61D-48FE-B821-2442D67D7AF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EE23DFFB-C61D-48FE-B821-2442D67D7AF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EE23DFFB-C61D-48FE-B821-2442D67D7AF9}.Release|Any CPU.Build.0 = Release|Any CPU
{84FB1ECB-E944-4161-A179-73E176DFB9F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{84FB1ECB-E944-4161-A179-73E176DFB9F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{84FB1ECB-E944-4161-A179-73E176DFB9F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{84FB1ECB-E944-4161-A179-73E176DFB9F6}.Release|Any CPU.Build.0 = Release|Any CPU
{077502CE-1C1E-41D5-A30B-FF820B77B104}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{077502CE-1C1E-41D5-A30B-FF820B77B104}.Debug|Any CPU.Build.0 = Debug|Any CPU
{077502CE-1C1E-41D5-A30B-FF820B77B104}.Release|Any CPU.ActiveCfg = Release|Any CPU
{077502CE-1C1E-41D5-A30B-FF820B77B104}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -82,6 +94,8 @@ Global
{5F62ACE6-B44A-40AE-B5EC-AF2BBA9FF1E3} = {82B01A63-4B8A-4965-9806-001128050FB5}
{E97DCC9F-C27F-497D-94FE-3DD39038C38B} = {F90FF019-91D3-462E-94A4-96B52681DB16}
{EE23DFFB-C61D-48FE-B821-2442D67D7AF9} = {82B01A63-4B8A-4965-9806-001128050FB5}
{84FB1ECB-E944-4161-A179-73E176DFB9F6} = {68E345E9-E50F-482A-8AFF-9E1156C448C9}
{077502CE-1C1E-41D5-A30B-FF820B77B104} = {68E345E9-E50F-482A-8AFF-9E1156C448C9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB22426B-6AA8-4C58-9557-376F107B547B}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="NUnit" />
<PackageReference Include="NUnit.Analyzers" />
<PackageReference Include="NUnit3TestAdapter" />

<PackageReference Include="FakeItEasy" />
<PackageReference Include="FluentAssertions" />
<PackageReference Include="FluentValidation" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" />
<PackageReference Include="PactNet" />
</ItemGroup>

<ItemGroup>
<Using Include="NUnit.Framework" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Consumer Tests

Pact is a consumer-driven contract testing tool, meaning the API consumer
defines a test outlining its expectations and requirements from the API
provider(s). By unit testing the API client with Pact, we generate a contract
that can be shared with the provider to validate these expectations and help
prevent breaking changes.

## Running The Consumer Tests

Run the tests how you run any other test suite. For example:

- Visual Studio Test Explorer
- from `/src/config/frontend/...ConsumerTests/tests` run: `dotnet test`.
- Once the test are executed you will find a new file inside the `/pacts/`
folder, this folder contains a json file which is the contract used for the
provider tests

## Generate the Contract

PactNet will automatically generate a Pact file after running the test,
typically saved to the `/pacts/` folder. This Pact file is the contract your
consumer expects from the provider.

## Share the Pact file with the Provider

Share the generated Pact file with the provider for their own verification,
often by storing it in a Pact Broker or a shared repository.

This approach allows you to create a consumer-driven contract that the provider
can validate to prevent any breaking changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
{
"consumer": {
"name": "ConfigurationService-API"
},
"interactions": [
{
"description": "A request for an access token with a valid credentials",
"request": {
"body": {
"clientid": "CSClient1",
"clientsecret": "test123@Puiu"
},
"headers": {
"Content-Type": "application/json"
},
"method": "POST",
"path": "/connect/token"
},
"response": {
"body": {
"access_token": "input123token",
"expires_in": 900,
"token_type": "bearer"
},
"headers": {
"Content-Type": "application/json"
},
"status": 200
}
},
{
"description": "A request for an access token with empty client credentials",
"request": {
"body": {
"clientid": "",
"clientsecret": ""
},
"headers": {
"Content-Type": "application/json"
},
"method": "POST",
"path": "/connect/token"
},
"response": {
"body": {
"errors": {
"ClientId": [
"'Client Id' must not be empty."
],
"ClientSecret": [
"'Client Secret' must not be empty."
]
},
"title": "Validation failed"
},
"headers": {
"Content-Type": "application/json"
},
"status": 400
}
},
{
"description": "A request for an access token with invalid credentials that throws an error from Keycloak",
"providerStates": [
{
"name": "A request for an access token with invalid credentials that throws an error from Keycloak"
}
],
"request": {
"body": {
"clientid": "client123",
"clientsecret": "clientsecret123"
},
"headers": {
"Content-Type": "application/json"
},
"method": "POST",
"path": "/connect/token"
},
"response": {
"body": "Client token generation failed with: Error from Keycloak",
"headers": {
"Content-Type": "application/json"
},
"status": 401
}
}
],
"metadata": {
"pactRust": {
"ffi": "0.4.0",
"models": "1.0.4"
},
"pactSpecification": {
"version": "3.0.0"
}
},
"provider": {
"name": "DMS-API"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"consumer": {
"name": "ConfigurationService-API"
},
"interactions": [
{
"description": "A register request when registration is disabled",
"request": {
"body": {
"clientid": "CSClient2",
"clientsecret": "test123@Puiu",
"displayname": "[email protected]"
},
"headers": {
"Content-Type": "application/json"
},
"method": "POST",
"path": "/connect/register"
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 404
}
},
{
"description": "A request for an access token with a valid credentials",
"request": {
"body": {
"clientid": "CSClient1",
"clientsecret": "test123@Puiu",
"displayname": "CSClient1"
},
"headers": {
"Content-Type": "application/json"
},
"method": "POST",
"path": "/connect/register"
},
"response": {
"headers": {
"Content-Type": "application/json"
},
"status": 200
}
}
],
"metadata": {
"pactRust": {
"ffi": "0.4.0",
"models": "1.0.4"
},
"pactSpecification": {
"version": "3.0.0"
}
},
"provider": {
"name": "Register"
}
}
Loading
Loading