Vijaykumar Patel
04/06/2023, 7:57 AMGitHub
04/06/2023, 10:13 AMProviderState value as System.Text.Json does not deserialise non-string values into string properties. https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft?pivots=dotnet-6-0#non-string-values-for-string-properties.
For example:
using <http://System.Net|System.Net>;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using PactNet;
var config = new PactConfig
{
    PactDir = Path.Join("..", "..", "..", "pacts"),
    DefaultJsonSettings = new JsonSerializerSettings
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
    }
};
var pact = Pact.V3("consumer", "provider", config).WithHttpInteractions();
pact.UponReceiving("A valid request")
    .Given("state with parameter", new Dictionary<string, string>() {["id"] = "10", ["name"] = "Fred"})
    .WithRequest(HttpMethod.Get, "/api/endpoint")
    .WillRespond()
    .WithStatus(HttpStatusCode.OK);
await pact.VerifyAsync(async ctx =>
{
    using var apiClient = new ApiClient(ctx.MockServerUri);
    await apiClient.TestRequestAsync();
});
public class ApiClient: IDisposable
{
    private readonly HttpClient _httpClient;
    public ApiClient(Uri baseUri)
    {
        _httpClient = new HttpClient { BaseAddress = baseUri };
    }
    public async Task TestRequestAsync()
    {
        await _httpClient.GetAsync("api/endpoint");
    }
    public void Dispose()
    {
        _httpClient.Dispose();
    }
}
generates this pact. Note that parameter "id" is serialised as 10 not "10".
{
  "consumer": {
    "name": "consumer"
  },
  "interactions": [
    {
      "description": "A valid request",
      "providerStates": [
        {
          "name": "state with parameter",
          "params": {
            "id": 10,
            "name": "Fred"
          }
        }
      ],
      "request": {
        "method": "GET",
        "path": "/api/endpoint"
      },
      "response": {
        "status": 200
      }
    }
  ],
  "metadata": {
    "pactRust": {
      "ffi": "0.4.0",
      "models": "1.0.4"
    },
    "pactSpecification": {
      "version": "3.0.0"
    }
  },
  "provider": {
    "name": "provider"
  }
}
pact-foundation/pact-netPallavi Anirban Bose
04/06/2023, 10:54 AMGitHub
04/06/2023, 5:01 PMWithQuery(string key, IMatcher matcher), similar to WithHeader(string key, IMatcher matcher)
pact-foundation/pact-net
GitHub Actions: release
âś… 4 other checks have passed
4/5 successful checksGitHub
04/06/2023, 8:01 PM<https://github.com/pact-foundation/pact-net/tree/master|master> by adamrodger
<https://github.com/pact-foundation/pact-net/commit/cd012ebe54574a9d07b758c44e23f45e6ac1444d|cd012ebe> - feat: WithQuery overload with matcher parameter
pact-foundation/pact-netPallavi Anirban Bose
04/07/2023, 8:44 AMGitHub
04/09/2023, 4:12 PM<https://github.com/pact-foundation/pact-net/tree/master|master> by adamrodger
<https://github.com/pact-foundation/pact-net/commit/7d8ca42ca6be43ca558e154af15833340113bd20|7d8ca42c> - feat: xUnit output project
pact-foundation/pact-netGitHub
04/09/2023, 4:12 PMPactNet.Abstractions
pact-foundation/pact-net
GitHub Actions: release
GitHub Actions: release
âś… 7 other checks have passed
7/9 successful checksGitHub
04/09/2023, 6:46 PM<https://github.com/pact-foundation/pact-net/tree/master|master> by adamrodger
<https://github.com/pact-foundation/pact-net/commit/746a8fbb0b3637da574ee383261676e131262189|746a8fbb> - ci: Add PactNet.Output.Xunit to publish CI
pact-foundation/pact-netGitHub
04/09/2023, 6:49 PM1.88.70
• Add an appropriately prefixed "branch" property to the user facing interface (make it match the existing provider name, tag, and version properties)
• Pass the branch through to the pact provider verifier CLI using the parameter --provider-version-branch
pact-foundation/pact-netGitHub
04/09/2023, 7:15 PM<https://github.com/pact-foundation/pact-net/tree/master|master> by adamrodger
<https://github.com/pact-foundation/pact-net/commit/6c34bc6c54185f0e988db44ca1c242a1a06a5029|6c34bc6c> - chore: Bump version to 4.5.0
pact-foundation/pact-netGitHub
04/09/2023, 7:21 PM<https://github.com/pact-foundation/pact-net/tree/master|master> by adamrodger
<https://github.com/pact-foundation/pact-net/commit/4e41eb8d4c46a8cc420920d7211a08305a05728d|4e41eb8d> - chore: Bump version to 4.6.0
pact-foundation/pact-netGitHub
04/09/2023, 7:29 PMGitHub
04/09/2023, 7:45 PMGitHub
04/09/2023, 7:48 PM<https://github.com/pact-foundation/pact-net/tree/master|master> by adamrodger
<https://github.com/pact-foundation/pact-net/commit/222c347c414a1092a2a5fb39b01afd14c76053c1|222c347c> - docs: Link to tracking issue for Apple Sillicon support
pact-foundation/pact-netVijaykumar Patel
04/11/2023, 6:24 AMGitHub
04/12/2023, 9:21 AMnew PactVerifier(config)
            .ServiceProvider("Test", _fixture.ServerUri)
            .WithPactBrokerSource(new Uri(pactBrokerUri), opts =>
            {
                opts
                    .TokenAuthentication(apiToken)
                    .ConsumerVersionSelectors(new ConsumerVersionSelector { MainBranch = true, Latest = true })
                    .PublishResults(providerVersion, results =>
                    {
                        results
                            .ProviderBranch(branchName);
                    });
            })
            .WithProviderStateUrl(new Uri(_fixture.ServerUri, "/provider-states"))
            .Verify();
This all works fine in 4.3.0, but as soon as i upgrade to 4.4.0 without changing any configuration I suddenly start getting these errors:
Request Failed - One or more of the setup state change handlers has failed
...
MismatchResult::Error("Invalid status code: 405", Some("793d03f1cf58ea18516c4e41492e368e905a5cd3"))
It seems as though the provider states HTTP method has changed or it is no longer being called as a post
pact-foundation/pact-netGitHub
04/12/2023, 2:37 PM<https://github.com/pact-foundation/pact-net/tree/master|master> by adamrodger
<https://github.com/pact-foundation/pact-net/commit/9eb58b3057eea281fbbd123880c7d327665d17bd|9eb58b30> - chore(ffi): Upgrade FFI to 0.4.3
pact-foundation/pact-netomri e
04/13/2023, 1:23 PMPallavi Anirban Bose
04/14/2023, 10:41 AMGitHub
04/17/2023, 8:03 AMGitHub
04/17/2023, 10:57 AMnet472 and netcoreapp3.1) containing PACT Consumer tests. The tests fail to run for the net472 on our Ubuntu-based build image. The image has dotnet SDK 3.1 and 6.0 and Mono 6.6.0 installed.
Minimal viable repro:
PactMultitargetTest.csproj:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net472;netcoreapp3.1</TargetFrameworks>
    <LangVersion>10.0</LangVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
    <PackageReference Include="NUnit" Version="3.13.3" />
    <PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
    <PackageReference Include="PactNet" Version="4.5.0" />
  </ItemGroup>
</Project>
SimpleTest.cs:
using <http://System.Net|System.Net>;
using System.Net.Http;
using System.Threading.Tasks;
using NUnit.Framework;
using PactNet;
namespace PactMultitargetTest;
public class SimpleTest
{
    [Test]
    public async Task TestConsumerPactExecution()
    {
        var pact = Pact.V3("Consumer", "Provider").WithHttpInteractions();
        pact.UponReceiving("A request").WithRequest(HttpMethod.Get, "/")
            .WillRespond().WithStatus(HttpStatusCode.OK);
        await pact.VerifyAsync(async ctx =>
            {
                using var http = new HttpClient();
                await http.GetAsync(ctx.MockServerUri);
            });
    }
}
This runs as expected on Windows:
> dotnet test
<snip>
Test run for C:\my-repo-dir\PactMultitargetTest\bin\Debug\net472\PactMultitargetTest.dll (.NETFramework,Version=v4.7.2)
Microsoft (R) Test Execution Command Line Tool Version 17.4.0 (x64)
Copyright (c) Microsoft Corporation.  All rights reserved.
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Passed!  - Failed:     0, Passed:     1, Skipped:     0, Total:     1, Duration: 696 ms - PactMultitargetTest.dll (net472)
Test run for C:\my-repo-dir\PactMultitargetTest\bin\Debug\netcoreapp3.1\PactMultitargetTest.dll (.NETCoreApp,Version=v3.1)
Microsoft (R) Test Execution Command Line Tool Version 17.4.0 (x64)
Copyright (c) Microsoft Corporation.  All rights reserved.
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Passed!  - Failed:     0, Passed:     1, Skipped:     0, Total:     1, Duration: 100 ms - PactMultitargetTest.dll (netcoreapp3.1)
On Ubuntu I get this:
$ dotnet test
  Determining projects to restore...
  All projects are up-to-date for restore.
  PactMultitargetTest -> /mnt/c/Users/andrew.cooper/repos/test/PactMultitargetTest/bin/Debug/net472/PactMultitargetTest.dll
  PactMultitargetTest -> /mnt/c/Users/andrew.cooper/repos/test/PactMultitargetTest/bin/Debug/netcoreapp3.1/PactMultitargetTest.dll
  PactMultitargetTest -> /mnt/c/Users/andrew.cooper/repos/test/PactMultitargetTest/bin/Debug/net6.0/PactMultitargetTest.dll
Test run for /mnt/c/Users/andrew.cooper/repos/test/PactMultitargetTest/bin/Debug/net472/PactMultitargetTest.dll (.NETFramework,Version=v4.7.2)
Microsoft (R) Test Execution Command Line Tool Version 17.5.0 (x64)
Copyright (c) Microsoft Corporation.  All rights reserved.
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
  Failed TestConsumerPactExecution [126 ms]
  Error Message:
   System.DllNotFoundException : pact_ffi assembly:<unknown assembly> type:<unknown type> member:(null)
  Stack Trace:
    at (wrapper managed-to-native) PactNet.Interop.NativeInterop.LogToBuffer(PactNet.Interop.LevelFilter)
  at PactNet.PactExtensions.InitialiseLogging (PactNet.PactLogLevel level) [0x00067] in <c3835e33e6c34624a3900fd28f0ae514>:0
  at PactNet.PactExtensions.WithHttpInteractions (PactNet.IPactV3 pact, System.Nullable`1[T] port, PactNet.Models.IPAddress host) [0x0000b] in <c3835e33e6c34624a3900fd28f0ae514>:0
  at PactMultitargetTest.SimpleTest.TestConsumerPactExecution () [0x00022] in <25f0af484314489ebafdc4e264ba94be>:0
  at NUnit.Framework.Internal.TaskAwaitAdapter+GenericAdapter`1[T].GetResult () [0x00008] in <c804c596ec8e46f396062449e02bacdd>:0
  at NUnit.Framework.Internal.AsyncToSyncAdapter.Await (System.Func`1[TResult] invoke) [0x0003d] in <c804c596ec8e46f396062449e02bacdd>:0
  at NUnit.Framework.Internal.Commands.TestMethodCommand.RunTestMethod (NUnit.Framework.Internal.TestExecutionContext context) [0x00031] in <c804c596ec8e46f396062449e02bacdd>:0
  at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute (NUnit.Framework.Internal.TestExecutionContext context) [0x00001] in <c804c596ec8e46f396062449e02bacdd>:0
  at NUnit.Framework.Internal.Execution.SimpleWorkItem+<>c__DisplayClass4_0.<PerformWork>b__0 () [0x00011] in <c804c596ec8e46f396062449e02bacdd>:0
  at NUnit.Framework.Internal.ContextUtils+<>c__DisplayClass1_0`1[T].<DoIsolated>b__0 (System.Object _) [0x00000] in <c804c596ec8e46f396062449e02bacdd>:0
  at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00071] in <de882a77e7c14f8ba5d298093dde82b2>:0
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <de882a77e7c14f8ba5d298093dde82b2>:0
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) [0x0002b] in <de882a77e7c14f8ba5d298093dde82b2>:0
  at NUnit.Framework.Internal.ContextUtils.DoIsolated (System.Threading.ContextCallback callback, System.Object state) [0x00025] in <c804c596ec8e46f396062449e02bacdd>:0
  at NUnit.Framework.Internal.ContextUtils.DoIsolated[T] (System.Func`1[TResult] func) [0x0001a] in <c804c596ec8e46f396062449e02bacdd>:0
  at NUnit.Framework.Internal.Execution.SimpleWorkItem.PerformWork () [0x0001b] in <c804c596ec8e46f396062449e02bacdd>:0
Failed!  - Failed:     1, Passed:     0, Skipped:     0, Total:     1, Duration: 126 ms - PactMultitargetTest.dll (net472)
Test run for /mnt/c/Users/andrew.cooper/repos/test/PactMultitargetTest/bin/Debug/netcoreapp3.1/PactMultitargetTest.dll (.NETCoreApp,Version=v3.1)
Microsoft (R) Test Execution Command Line Tool Version 17.5.0 (x64)
Copyright (c) Microsoft Corporation.  All rights reserved.
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Passed!  - Failed:     0, Passed:     1, Skipped:     0, Total:     1, Duration: 428 ms - PactMultitargetTest.dll (netcoreapp3.1)
pact-foundation/pact-netMegha Agarwal
04/19/2023, 10:58 AMPallavi Anirban Bose
04/19/2023, 11:57 AMRavinder Kadiyan
04/20/2023, 10:05 AMEddie Stanley
04/20/2023, 8:48 PMHttpRequestMessage / HttpResponseMessage pairs.
NB: I'm aware of pact-stub-server (link) however it's not quite what I'm looking for.
i.e. assume we've got some shared code to define the "Foo" interaction
private static void PopulateFooInteraction(IPactBuilderV3 pactBuilder)
{
    pactBuilder
        .UponReceiving("Request For Foo")
        .WithRequest(HttpMethod.Get, "/foo/endpoint")
        .WithHeader("x-correlation-id", "55dbb0b0-b0a0-4b2c-bee2-1cc77e8fba56")
        .WillRespond()
        .WithStatus(HttpStatusCode.OK)
        .WithHeader("Content-Type", "application/json")
        .WithJsonBody(Match.Type(new
        {
            Foo = "Bar"
        }));
}
Then we exercise the client code that depends on the Foo interaction - it calls PopulateFooInteraction()
[Fact]
public async Task CheckFooInteraction()
{
    var pact = Pact.V3("The.Consumer", "The.Provider", new PactConfig());
    var pactBuilder = pact.UsingNativeBackend();
    PopulateFooInteraction(pactBuilder);
    await PactBuilder.VerifyAsync(async ctx =>
    {
        // .. code that consumes the stubbed responses coming back for Foo
    });
}
Finally (somehow!) we harvest the messages implied by PopulateFooInteraction()
This is the missing bit
[Fact]
public void GetMessages()
{
    var messageCapture = new MessageCapture();
    PopulateFooInteraction(messageCapture);
    IEnumerable<(HttpRequestMessage, HttpResponseMessage)> messages = messageCapture.CollectInteractions();
}
The end goal being to use these messages with something like mockhttp.Eddie Stanley
04/24/2023, 12:59 AMYousaf Nabi (pactflow.io)
pact-workshop-dotnet
• canonical example from https://github.com/DiUS/pact-workshop-dotnet-core-v3/pull/8 becomes the main course
• sub foldered (probably easier than branches) workshop for https://github.com/pact-foundation/pact-workshop-dotnet-core-v1/pull/25
• we can then add additional examples for x framework
    â—¦ Minimal API https://github.com/DiUS/pact-workshop-dotnet-core-v3/pulls
• Update all the links to point at the renamed https://github.com/pact-foundation/pact-workshop-dotnet
PS. I have to say, the DSL is pact-net 4.x is quite nice, and the delta between 3.x -> 4.x isn't bad at all, especially once you've got one test converted, the rest is relatively plain sailing.Bo Damgaard Mortensen
04/26/2023, 12:39 PMMegha Agarwal
04/26/2023, 1:13 PM