Skip to content

Commit

Permalink
Merge pull request #293 from martincostello/Fix-Deadlock
Browse files Browse the repository at this point in the history
fix: Resolve deadlock introduced in 2.6.2
  • Loading branch information
mefellows authored May 14, 2021
2 parents ffa6ab8 + 8cc587a commit c2b8dfe
Show file tree
Hide file tree
Showing 12 changed files with 286 additions and 31 deletions.
2 changes: 1 addition & 1 deletion PactNet.Tests/Core/MockProviderHostConfigTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public void Ctor_WhenCalled_SetsWaitForExitToFalse()
{
var config = GetSubject();

Assert.Equal(false, config.WaitForExit);
Assert.False(config.WaitForExit);
}

[Fact]
Expand Down
7 changes: 4 additions & 3 deletions PactNet.Tests/Core/PactVerifierHostConfigTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using PactNet.Core;
using Xunit;

Expand Down Expand Up @@ -221,7 +220,7 @@ public void Ctor_WhenCalledWithNoProviderStateSetupUri_SetsTheCorrectArgs()
public void Ctor_WhenCalled_SetsWaitForExitToTrue()
{
var config = GetSubject();
Assert.Equal(true, config.WaitForExit);
Assert.True(config.WaitForExit);
}

[Fact]
Expand Down Expand Up @@ -256,7 +255,9 @@ public void Ctor_WhenCalledWithCustomHeader_SetsTheCorrectArgs()
providerStateSetupUri: new Uri("http://127.0.0.1/states/"),
verifierConfig: new PactVerifierConfig
{
#pragma warning disable CS0618 // Type or member is obsolete
CustomHeader = new KeyValuePair<string, string>("Authorization", "Basic VGVzdA=="),
#pragma warning restore CS0618 // Type or member is obsolete
ProviderVersion = "1.0.0"
});

Expand Down Expand Up @@ -345,7 +346,7 @@ public void Ctor_WhenVerifierConfigIsNull_SetsOutputtersToNull()
{
var config = GetSubject();

Assert.Equal(null, config.Outputters);
Assert.Null(config.Outputters);
}

private void AssertEnvironmentIsCorrectlySet(IDictionary<string, string> expectedEnv, IDictionary<string, string> actualEnv)
Expand Down
247 changes: 247 additions & 0 deletions PactNet.Tests/IntegrationTests/XunitIntegrationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using PactNet.Matchers;
using PactNet.Mocks.MockHttpService;
using PactNet.Mocks.MockHttpService.Models;
using Xunit;

namespace PactNet.Tests.IntegrationTests
{
public class XunitIntegrationTests : PactTests<CalculatorApiPact>
{
public XunitIntegrationTests(CalculatorApiPact pact)
: base(pact)
{
}

[Fact]
public async Task Add_Numbers()
{
// Arrange
var request = new ProviderServiceRequest()
{
Method = HttpVerb.Post,
Path = "/calculator/add",
Headers = new Dictionary<string, object>()
{
["Content-Type"] = "application/json; charset=utf-8",
},
Body = new
{
left = 1,
right = 1,
},
};

var response = new ProviderServiceResponse()
{
Status = 200,
Headers = new Dictionary<string, object>()
{
["Content-Type"] = "application/json",
},
Body = new
{
result = Match.Type(2),
},
};

Pact.PactProvider
.Given("I want to add two integers numbers")
.UponReceiving("An HTTP POST request to add two numbers")
.With(request)
.WillRespondWith(response);

// Act
using (var httpClient = CreateHttpClient())
{
using (var httpContent = new StringContent(@"{""left"":1,""right"":1}", Encoding.UTF8, "application/json"))
{
using (var httpResponse = await httpClient.PostAsync("/calculator/add", httpContent))
{
Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode);

string json = await httpResponse.Content.ReadAsStringAsync();

Assert.Equal(@"{""result"":2}", json);
}
}
}

// Assert
Pact.PactProvider.VerifyInteractions();
}

[Fact]
public async Task Subtract_Numbers()
{
// Arrange
var request = new ProviderServiceRequest()
{
Method = HttpVerb.Post,
Path = "/calculator/subtract",
Headers = new Dictionary<string, object>()
{
["Content-Type"] = "application/json; charset=utf-8",
},
Body = new
{
left = 2,
right = 3,
},
};

var response = new ProviderServiceResponse()
{
Status = 200,
Headers = new Dictionary<string, object>()
{
["Content-Type"] = "application/json",
},
Body = new
{
result = Match.Type(-1),
},
};

Pact.PactProvider
.Given("I want to subtract two integers numbers")
.UponReceiving("An HTTP POST request to subtract two numbers")
.With(request)
.WillRespondWith(response);

// Act
using (var httpClient = CreateHttpClient())
{
using (var httpContent = new StringContent(@"{""left"":2,""right"":3}", Encoding.UTF8, "application/json"))
{
using (var httpResponse = await httpClient.PostAsync("/calculator/subtract", httpContent))
{
Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode);

string json = await httpResponse.Content.ReadAsStringAsync();

Assert.Equal(@"{""result"":-1}", json);
}
}
}

// Assert
Pact.PactProvider.VerifyInteractions();
}
}

public abstract class PactTests<T> : IClassFixture<T>
where T : ApiPact
{
protected PactTests(T pact)
{
Pact = pact;
}

protected T Pact { get; }

public HttpClient CreateHttpClient()
{
return new HttpClient()
{
BaseAddress = Pact.PactBrokerUri,
};
}
}

public sealed class CalculatorApiPact : ApiPact
{
public CalculatorApiPact()
: base("Calculator")
{
}
}

public abstract class ApiPact : IAsyncLifetime, IDisposable
{
private bool _disposed;
private IMockProviderService _provider;

protected ApiPact(string providerName)
{
PactBuilder = new PactBuilder(
new PactConfig()
{
LogDir = "logs",
PactDir = "pacts",
SpecificationVersion = "2.0.0",
});

PactBuilder
.ServiceConsumer("Calculator")
.HasPactWith(providerName);

PactBrokerUri = new UriBuilder()
{
Host = "localhost",
Port = 4322,
Scheme = "http",
}.Uri;
}

~ApiPact()
{
Dispose(false);
}

public Uri PactBrokerUri { get; }

public IMockProviderService PactProvider
{
get
{
if (_provider == null)
{
_provider = PactBuilder.MockService(PactBrokerUri.Port);
}

return _provider;
}
}

private IPactBuilder PactBuilder { get; }

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

public Task DisposeAsync()
{
Dispose();
return Task.CompletedTask;
}

public Task InitializeAsync()
{
return Task.CompletedTask;
}

protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (_provider != null)
{
PactBuilder?.Build();
}
}

_disposed = true;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void Start_WhenCalledAndTheCoreHostStartsQuickly_ShouldStartTheCoreHostAn
host.Start();

_mockCoreHost.Received(1).Start();
Assert.Equal(1, _fakeHttpMessageHandler.RequestsReceived.Count());
Assert.Single(_fakeHttpMessageHandler.RequestsReceived);
var receivedRequest = _fakeHttpMessageHandler.RequestsReceived.ElementAt(0);
Assert.Equal(HttpMethod.Get, receivedRequest.Method);
Assert.Equal("/", receivedRequest.RequestUri.PathAndQuery);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ public void WillRespondWith_WhenHostIsNull_DoNotThrowsInvalidOperationException(

mockService.Stop();

Assert.Equal(1, _fakeHttpMessageHandler.RequestsReceived.Count());
Assert.Single(_fakeHttpMessageHandler.RequestsReceived);
}

[Fact]
Expand Down Expand Up @@ -379,7 +379,7 @@ public void VerifyInteractions_WhenHostIsNotNull_PerformsAdminInteractionsVerifi
#if USE_NET4X
testContext = "MockProviderServiceTests.VerifyInteractions_WhenHostIsNotNull_PerformsAdminInteractionsVerificationGetRequest";
# endif
Assert.Equal(1, _fakeHttpMessageHandler.RequestsReceived.Count());
Assert.Single(_fakeHttpMessageHandler.RequestsReceived);
Assert.Equal(HttpMethod.Get, _fakeHttpMessageHandler.RequestsReceived.First().Method);
Assert.Equal($"http://localhost:1234/interactions/verification?example_description={testContext}", _fakeHttpMessageHandler.RequestsReceived.First().RequestUri.ToString());
}
Expand Down Expand Up @@ -420,7 +420,7 @@ public void ClearInteractions_WhenHostIsNotNull_PerformsAdminInteractionsDeleteR
#if USE_NET4X
testContext = "MockProviderServiceTests.ClearInteractions_WhenHostIsNotNull_PerformsAdminInteractionsDeleteRequest";
# endif
Assert.Equal(1, _fakeHttpMessageHandler.RequestsReceived.Count());
Assert.Single(_fakeHttpMessageHandler.RequestsReceived);
Assert.Equal(HttpMethod.Delete, _fakeHttpMessageHandler.RequestsReceived.First().Method);
Assert.Equal($"http://localhost:1234/interactions?example_description={testContext}", _fakeHttpMessageHandler.RequestsReceived.First().RequestUri.ToString());
}
Expand Down
12 changes: 6 additions & 6 deletions PactNet.Tests/PactNet.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' " >
netcoreapp1.1
netcoreapp3.1
</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">
net46; netcoreapp1.1
net46; netcoreapp3.1
</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
Expand All @@ -19,10 +19,10 @@
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="NSubstitute" Version="2.0.3" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="NSubstitute" Version="4.2.2" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
</ItemGroup>

<ItemGroup Condition=" '$(OS)' == 'Windows_NT' ">
Expand Down
Loading

0 comments on commit c2b8dfe

Please sign in to comment.