diff --git a/PactNet.Tests/Core/MockProviderHostConfigTests.cs b/PactNet.Tests/Core/MockProviderHostConfigTests.cs index d41ddf31..37127a7b 100644 --- a/PactNet.Tests/Core/MockProviderHostConfigTests.cs +++ b/PactNet.Tests/Core/MockProviderHostConfigTests.cs @@ -148,7 +148,7 @@ public void Ctor_WhenCalled_SetsWaitForExitToFalse() { var config = GetSubject(); - Assert.Equal(false, config.WaitForExit); + Assert.False(config.WaitForExit); } [Fact] diff --git a/PactNet.Tests/Core/PactVerifierHostConfigTests.cs b/PactNet.Tests/Core/PactVerifierHostConfigTests.cs index 840ac61f..0a92fb9c 100644 --- a/PactNet.Tests/Core/PactVerifierHostConfigTests.cs +++ b/PactNet.Tests/Core/PactVerifierHostConfigTests.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using PactNet.Core; using Xunit; @@ -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] @@ -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("Authorization", "Basic VGVzdA=="), +#pragma warning restore CS0618 // Type or member is obsolete ProviderVersion = "1.0.0" }); @@ -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 expectedEnv, IDictionary actualEnv) diff --git a/PactNet.Tests/IntegrationTests/XunitIntegrationTests.cs b/PactNet.Tests/IntegrationTests/XunitIntegrationTests.cs new file mode 100644 index 00000000..e1cc92da --- /dev/null +++ b/PactNet.Tests/IntegrationTests/XunitIntegrationTests.cs @@ -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 + { + 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() + { + ["Content-Type"] = "application/json; charset=utf-8", + }, + Body = new + { + left = 1, + right = 1, + }, + }; + + var response = new ProviderServiceResponse() + { + Status = 200, + Headers = new Dictionary() + { + ["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() + { + ["Content-Type"] = "application/json; charset=utf-8", + }, + Body = new + { + left = 2, + right = 3, + }, + }; + + var response = new ProviderServiceResponse() + { + Status = 200, + Headers = new Dictionary() + { + ["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 : IClassFixture + 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; + } + } + } +} diff --git a/PactNet.Tests/Mocks/MockHttpService/Host/RubyHttpHostTests.cs b/PactNet.Tests/Mocks/MockHttpService/Host/RubyHttpHostTests.cs index 8bbc1330..408df586 100644 --- a/PactNet.Tests/Mocks/MockHttpService/Host/RubyHttpHostTests.cs +++ b/PactNet.Tests/Mocks/MockHttpService/Host/RubyHttpHostTests.cs @@ -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); diff --git a/PactNet.Tests/Mocks/MockHttpService/MockProviderServiceTests.cs b/PactNet.Tests/Mocks/MockHttpService/MockProviderServiceTests.cs index efb26513..95b04f48 100644 --- a/PactNet.Tests/Mocks/MockHttpService/MockProviderServiceTests.cs +++ b/PactNet.Tests/Mocks/MockHttpService/MockProviderServiceTests.cs @@ -298,7 +298,7 @@ public void WillRespondWith_WhenHostIsNull_DoNotThrowsInvalidOperationException( mockService.Stop(); - Assert.Equal(1, _fakeHttpMessageHandler.RequestsReceived.Count()); + Assert.Single(_fakeHttpMessageHandler.RequestsReceived); } [Fact] @@ -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()); } @@ -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()); } diff --git a/PactNet.Tests/PactNet.Tests.csproj b/PactNet.Tests/PactNet.Tests.csproj index 785c728e..915d55c3 100644 --- a/PactNet.Tests/PactNet.Tests.csproj +++ b/PactNet.Tests/PactNet.Tests.csproj @@ -1,10 +1,10 @@  - netcoreapp1.1 + netcoreapp3.1 - net46; netcoreapp1.1 + net46; netcoreapp3.1 @@ -19,10 +19,10 @@ - - - - + + + + diff --git a/PactNet.Tests/PactPublisherTests.cs b/PactNet.Tests/PactPublisherTests.cs index 52d73be0..8af3cee1 100644 --- a/PactNet.Tests/PactPublisherTests.cs +++ b/PactNet.Tests/PactPublisherTests.cs @@ -2,10 +2,10 @@ using System.IO; using System.Linq; using System.Net.Http; +using System.Threading.Tasks; using Newtonsoft.Json; using PactNet.Models; using PactNet.Tests.Fakes; -using System.Threading.Tasks; using Xunit; namespace PactNet.Tests @@ -70,7 +70,7 @@ public async Task PublishToBrokerAsync_WithNoAuthentication_PublishesPact() await pactPublisher.PublishToBrokerAsync(PactFilePath, ConsumerVersion); var requestsReceived = _fakeHttpMessageHandler.RequestsReceived; - Assert.Equal(1, requestsReceived.Count()); + Assert.Single(requestsReceived); this.AssertPactPublishRequest(requestsReceived.ElementAt(0), _fakeHttpMessageHandler.RequestContentReceived.ElementAt(0), BrokerBaseUriHttp, pactDetails, pactFileText, ConsumerVersion); } @@ -84,7 +84,7 @@ public async Task PublishToBrokerAsync_WithAuthentication_PublishesPact() await pactPublisher.PublishToBrokerAsync(PactFilePath, ConsumerVersion); var requestsReceived = _fakeHttpMessageHandler.RequestsReceived; - Assert.Equal(1, requestsReceived.Count()); + Assert.Single(requestsReceived); this.AssertPactPublishRequest(requestsReceived.ElementAt(0), _fakeHttpMessageHandler.RequestContentReceived.ElementAt(0), BrokerBaseUriHttps, pactDetails, pactFileText, ConsumerVersion, AuthOptions); } @@ -98,7 +98,7 @@ public async Task PublishToBrokerAsync_WhenCalledWithoutTags_PublishesPactWithou await pactPublisher.PublishToBrokerAsync(PactFilePath, ConsumerVersion); var requestsReceived = _fakeHttpMessageHandler.RequestsReceived; - Assert.Equal(1, requestsReceived.Count()); + Assert.Single(requestsReceived); this.AssertPactPublishRequest(requestsReceived.ElementAt(0), _fakeHttpMessageHandler.RequestContentReceived.ElementAt(0), BrokerBaseUriHttps, pactDetails, pactFileText, ConsumerVersion); } @@ -129,7 +129,7 @@ public void PublishToBroker_WithNoAuthentication_PublishesPact() pactPublisher.PublishToBroker(PactFilePath, ConsumerVersion); var requestsReceived = _fakeHttpMessageHandler.RequestsReceived; - Assert.Equal(1, requestsReceived.Count()); + Assert.Single(requestsReceived); this.AssertPactPublishRequest(requestsReceived.ElementAt(0), _fakeHttpMessageHandler.RequestContentReceived.ElementAt(0), BrokerBaseUriHttp, pactDetails, pactFileText, ConsumerVersion); } diff --git a/PactNet/Core/Async.cs b/PactNet/Core/Async.cs index 1c7d2bd5..52838c72 100644 --- a/PactNet/Core/Async.cs +++ b/PactNet/Core/Async.cs @@ -18,5 +18,12 @@ public static void RunSync(Func task) .Unwrap() .GetAwaiter() .GetResult(); + + public static TResult RunSync(Func> task) + => _taskFactory + .StartNew(task) + .Unwrap() + .GetAwaiter() + .GetResult(); } } diff --git a/PactNet/Mocks/MockHttpService/MockProviderService.cs b/PactNet/Mocks/MockHttpService/MockProviderService.cs index 1cf56288..2268bda8 100644 --- a/PactNet/Mocks/MockHttpService/MockProviderService.cs +++ b/PactNet/Mocks/MockHttpService/MockProviderService.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; +using PactNet.Core; using PactNet.Mocks.MockHttpService.Host; using PactNet.Mocks.MockHttpService.Models; using PactNet.Models; using static System.String; -using PactNet.Core; namespace PactNet.Mocks.MockHttpService { @@ -129,7 +129,7 @@ public void VerifyInteractions() public string SendAdminHttpRequest(HttpVerb method, string path, Dictionary headers = null) { - return _adminHttpClient.SendAdminHttpRequest(method, path, headers:headers).Result; + return Async.RunSync(() => _adminHttpClient.SendAdminHttpRequest(method, path, headers: headers)); } public void Start() @@ -163,7 +163,6 @@ public void ClearInteractions() { ClearAllInteractions(); } - } private void ClearAllInteractions() @@ -198,7 +197,7 @@ private void RegisterInteraction() Async.RunSync(() => _adminHttpClient.SendAdminHttpRequest(HttpVerb.Post, Constants.InteractionsPath, interaction)); - ClearTrasientState(); + ClearTransientState(); } private void StopRunningHost() @@ -212,11 +211,11 @@ private void StopRunningHost() private void ClearAllState() { - ClearTrasientState(); + ClearTransientState(); ClearInteractions(); } - private void ClearTrasientState() + private void ClearTransientState() { _request = null; _response = null; diff --git a/PactNet/PactBuilder.cs b/PactNet/PactBuilder.cs index 7ea682a6..0c7b2a25 100644 --- a/PactNet/PactBuilder.cs +++ b/PactNet/PactBuilder.cs @@ -116,7 +116,7 @@ public void Build() if (_mockProviderService == null) { throw new InvalidOperationException( - "The Pact file could not be saved because the mock provider service is not initialized. Please initialise by calling the MockService() method."); + $"The Pact file could not be saved because the mock provider service is not initialized. Please initialize by calling the {nameof(MockService)}() method."); } PersistPactFile(); @@ -129,8 +129,9 @@ private void PersistPactFile() if (_mockProviderService.UseRemoteMockService) { - File.WriteAllText($"{_pactDir}\\{ConsumerName.ToLower()}{ProviderName.ToLower()}.json", responsePact); + string fileName = ConsumerName.ToLower() + ProviderName.ToLower() + ".json"; + File.WriteAllText(Path.Combine(_pactDir, fileName), responsePact); } } } -} \ No newline at end of file +} diff --git a/PactNet/PactNet.csproj b/PactNet/PactNet.csproj index 0bb4837d..1d90eeb5 100644 --- a/PactNet/PactNet.csproj +++ b/PactNet/PactNet.csproj @@ -1,10 +1,10 @@  - netstandard1.5 + netstandard1.5; netstandard2.0 - net45; netstandard1.5 + net45; netstandard1.5; netstandard2.0 true diff --git a/appveyor.yml b/appveyor.yml index ff098b23..086cd07c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,6 @@ version: "{build}" -os: Visual Studio 2017 +os: Visual Studio 2019 install: - git submodule update --init --recursive