Skip to content

Commit

Permalink
feat: Support v4 specification for consumer tests
Browse files Browse the repository at this point in the history
  • Loading branch information
adamrodger committed Apr 28, 2023
1 parent 9eb58b3 commit 23698a3
Show file tree
Hide file tree
Showing 23 changed files with 1,224 additions and 76 deletions.
3 changes: 2 additions & 1 deletion PactNet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
src\NuGet.targets = src\NuGet.targets
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PactNet.Output.Xunit", "src\PactNet.Output.Xunit\PactNet.Output.Xunit.csproj", "{02E265A1-A7A2-4106-8F6A-5027FDC3FC50}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PactNet.Output.Xunit", "src\PactNet.Output.Xunit\PactNet.Output.Xunit.csproj", "{02E265A1-A7A2-4106-8F6A-5027FDC3FC50}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,16 @@ Pact tests have a few key properties. We'll demonstrate a common example using t
```csharp
public class SomethingApiConsumerTests
{
private readonly IPactBuilderV3 pactBuilder;
private readonly IPactBuilderV4 pactBuilder;

public SomethingApiConsumerTests()
{
// Use default pact directory ..\..\pacts and default log
// directory ..\..\logs
var pact = Pact.V3("Something API Consumer", "Something API", new PactConfig());
var pact = Pact.V4("Something API Consumer", "Something API", new PactConfig());

// or specify custom log and pact directories
pact = Pact.V3("Something API Consumer", "Something API", new PactConfig
pact = Pact.V4("Something API Consumer", "Something API", new PactConfig
{
PactDir = $"{Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName}{Path.DirectorySeparatorChar}pacts"
});
Expand Down Expand Up @@ -238,7 +238,7 @@ Due to using a shared native library instead of C# for the main Pact logic only

| Version | Stable | [Spec] Compatibility | Install |
| ------- | ---------- | -------------------- | ------------------ |
| 4.x | Stable | 2, 3 | See [installation] |
| 4.x | Stable | 2, 3, 4 | See [installation] |
| 3.x | Deprecated | 2 | |

## Roadmap
Expand All @@ -253,8 +253,6 @@ See [CONTRIBUTING](CONTRIBUTING.md).
[pact wiki]: https://github.com/pact-foundation/pact-ruby/wiki
[getting started with pact]: http://dius.com.au/2016/02/03/microservices-pact/
[pact website]: http://docs.pact.io/
[pact specification v2]: https://github.com/pact-foundation/pact-specification/tree/version-2
[pact specification v3]: https://github.com/pact-foundation/pact-specification/tree/version-3
[libraries]: https://github.com/pact-foundation/pact-reference/releases
[cli tools]: https://github.com/pact-foundation/pact-reference/releases
[installation]: #installation
Expand Down
16 changes: 8 additions & 8 deletions samples/ReadMe/Consumer.Tests/SomethingApiConsumerTests.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using PactNet;
using PactNet.Matchers;
using Xunit;

namespace ReadMe.Consumer.Tests
{
public class SomethingApiConsumerTests
{
private readonly IPactBuilderV3 pactBuilder;
private readonly IPactBuilderV4 pactBuilder;

public SomethingApiConsumerTests()
{
// Use default pact directory ..\..\pacts and default log
// directory ..\..\logs
var pact = Pact.V3("Something API Consumer", "Something API", new PactConfig());
var pact = Pact.V4("Something API Consumer", "Something API", new PactConfig());

// or specify custom log and pact directories
pact = Pact.V3("Something API Consumer", "Something API", new PactConfig
pact = Pact.V4("Something API Consumer", "Something API", new PactConfig
{
PactDir = $"{Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName}{Path.DirectorySeparatorChar}pacts"
PactDir = "../../../pacts/"
});

// Initialize Rust backend
Expand All @@ -41,9 +41,9 @@ public async Task GetSomething_WhenTheTesterSomethingExists_ReturnsTheSomething(
.WithHeader("Content-Type", "application/json; charset=utf-8")
.WithJsonBody(new
{
id = "tester",
firstName = "Totally",
lastName = "Awesome"
id = Match.Type("tester"),
firstName = Match.Type("Totally"),
lastName = Match.Type("Awesome")
});

await this.pactBuilder.VerifyAsync(async ctx =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"consumer": {
"name": "Something API Consumer"
},
"interactions": [
{
"description": "A GET request to retrieve the something",
"key": "cfbd01b3cf82d200",
"pending": false,
"providerStates": [
{
"name": "There is a something with id 'tester'"
}
],
"request": {
"headers": {
"Accept": [
"application/json"
]
},
"method": "GET",
"path": "/somethings/tester"
},
"response": {
"body": {
"content": {
"firstName": "Totally",
"id": "tester",
"lastName": "Awesome"
},
"contentType": "application/json",
"encoded": false
},
"headers": {
"Content-Type": [
"application/json; charset=utf-8"
]
},
"matchingRules": {
"body": {
"$.firstName": {
"combine": "AND",
"matchers": [
{
"match": "type"
}
]
},
"$.id": {
"combine": "AND",
"matchers": [
{
"match": "type"
}
]
},
"$.lastName": {
"combine": "AND",
"matchers": [
{
"match": "type"
}
]
}
},
"header": {}
},
"status": 200
},
"type": "Synchronous/HTTP"
}
],
"metadata": {
"pactRust": {
"ffi": "0.4.3",
"models": "1.0.9"
},
"pactSpecification": {
"version": "4.0"
}
},
"provider": {
"name": "Something API"
}
}
1 change: 1 addition & 0 deletions samples/ReadMe/Provider.Tests/SomethingApiTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public void EnsureSomethingApiHonoursPactWithConsumer()
"..",
"..",
"..",
"Consumer.Tests",
"pacts",
"Something API Consumer-Something API.json");

Expand Down
45 changes: 0 additions & 45 deletions samples/ReadMe/pacts/Something API Consumer-Something API.json

This file was deleted.

44 changes: 44 additions & 0 deletions src/PactNet.Abstractions/IMessageBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,48 @@ public interface IMessageBuilderV3
/// <returns>Configured message</returns>
IConfiguredMessageVerifier WithJsonContent(dynamic body, JsonSerializerSettings settings);
}

/// <summary>
/// Build up a mock message for a v4 message message pact
/// </summary>
public interface IMessageBuilderV4
{
/// <summary>
/// Add a provider state
/// </summary>
/// <param name="providerState">Provider state description</param>
/// <returns>Fluent builder</returns>
IMessageBuilderV4 Given(string providerState);

/// <summary>
/// Add a provider state with one or more parameters
/// </summary>
/// <param name="providerState">Provider state description</param>
/// <param name="parameters">Provider state parameters</param>
/// <returns>Fluent builder</returns>
IMessageBuilderV4 Given(string providerState, IDictionary<string, string> parameters);

/// <summary>
/// Set the metadata
/// </summary>
/// <param name="key">the metadata key</param>
/// <param name="value">the metadata value</param>
/// <returns>Fluent builder</returns>
IMessageBuilderV4 WithMetadata(string key, string value);

/// <summary>
/// Set message content which is serialised as JSON
/// </summary>
/// <param name="body">Message body</param>
/// <returns>Configured message</returns>
IConfiguredMessageVerifier WithJsonContent(dynamic body);

/// <summary>
/// Set message content which is serialised as JSON
/// </summary>
/// <param name="body">Message body</param>
/// <param name="settings">Custom JSON serializer settings</param>
/// <returns>Configured message</returns>
IConfiguredMessageVerifier WithJsonContent(dynamic body, JsonSerializerSettings settings);
}
}
22 changes: 22 additions & 0 deletions src/PactNet.Abstractions/IMessagePactBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,26 @@ public interface IMessagePactBuilderV3
/// <returns>Fluent builder</returns>
IMessagePactBuilderV3 WithPactMetadata(string @namespace, string name, string value);
}

/// <summary>
/// Message pact v4 Builder
/// </summary>
public interface IMessagePactBuilderV4
{
/// <summary>
/// Add a new message to the pact
/// </summary>
/// <param name="description">Message description</param>
/// <returns>Fluent builder</returns>
IMessageBuilderV4 ExpectsToReceive(string description);

/// <summary>
/// Add metadata information to message pact
/// </summary>
/// <param name="namespace">the parent configuration section</param>
/// <param name="name">the metadata field value</param>
/// <param name="value">the metadata field value</param>
/// <returns>Fluent builder</returns>
IMessagePactBuilderV4 WithPactMetadata(string @namespace, string name, string value);
}
}
7 changes: 7 additions & 0 deletions src/PactNet.Abstractions/IPact.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,11 @@ public interface IPactV2 : IPact
public interface IPactV3 : IPact
{
}

/// <summary>
/// Marker interface for a v4 Pact
/// </summary>
public interface IPactV4 : IPact
{
}
}
13 changes: 13 additions & 0 deletions src/PactNet.Abstractions/IPactBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,17 @@ public interface IPactBuilderV3 : IPactBuilder
/// <returns>Fluent builder</returns>
IRequestBuilderV3 UponReceiving(string description);
}

/// <summary>
/// Pact v4 Builder
/// </summary>
public interface IPactBuilderV4 : IPactBuilder
{
/// <summary>
/// Add a new interaction to the pact
/// </summary>
/// <param name="description">Interaction description</param>
/// <returns>Fluent builder</returns>
IRequestBuilderV4 UponReceiving(string description);
}
}
Loading

0 comments on commit 23698a3

Please sign in to comment.