diff --git a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs index dd8f83cb..027bd35d 100644 --- a/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs +++ b/src/WireMock.Net.FluentAssertions/Assertions/WireMockAssertions.cs @@ -16,8 +16,7 @@ namespace WireMock.FluentAssertions } [CustomAssertion] - public AndConstraint AtAbsoluteUrl(string absoluteUrl, string because = "", - params object[] becauseArgs) + public AndConstraint AtAbsoluteUrl(string absoluteUrl, string because = "", params object[] becauseArgs) { Execute.Assertion .BecauseOf(because, becauseArgs) @@ -36,13 +35,11 @@ namespace WireMock.FluentAssertions } [CustomAssertion] - public AndConstraint WithHeader(string expectedKey, string value, - string because = "", params object[] becauseArgs) + public AndConstraint WithHeader(string expectedKey, string value, string because = "", params object[] becauseArgs) => WithHeader(expectedKey, new[] {value}, because, becauseArgs); [CustomAssertion] - public AndConstraint WithHeader(string expectedKey, string[] expectedValues, - string because = "", params object[] becauseArgs) + public AndConstraint WithHeader(string expectedKey, string[] expectedValues, string because = "", params object[] becauseArgs) { var headersDictionary = _subject.LogEntries.SelectMany(x => x.RequestMessage.Headers) .ToDictionary(x => x.Key, x => x.Value); @@ -72,5 +69,62 @@ namespace WireMock.FluentAssertions return new AndConstraint(this); } + + [CustomAssertion] + public AndConstraint AtUrl(string url, string because = "", params object[] becauseArgs) + { + Execute.Assertion + .BecauseOf(because, becauseArgs) + .Given(() => _subject.LogEntries.Select(x => x.RequestMessage).ToList()) + .ForCondition(requests => requests.Any()) + .FailWith( + "Expected {context:wiremockserver} to have been called at address matching the url {0}{reason}, but no calls were made.", + url) + .Then + .ForCondition(x => x.Any(y => y.Url == url)) + .FailWith( + "Expected {context:wiremockserver} to have been called at address matching the url {0}{reason}, but didn't find it among the calls to {1}.", + _ => url, requests => requests.Select(request => request.Url)); + + return new AndConstraint(this); + } + + [CustomAssertion] + public AndConstraint WithProxyUrl(string proxyUrl, string because = "", params object[] becauseArgs) + { + Execute.Assertion + .BecauseOf(because, becauseArgs) + .Given(() => _subject.LogEntries.Select(x => x.RequestMessage).ToList()) + .ForCondition(requests => requests.Any()) + .FailWith( + "Expected {context:wiremockserver} to have been called with proxy url {0}{reason}, but no calls were made.", + proxyUrl) + .Then + .ForCondition(x => x.Any(y => y.ProxyUrl == proxyUrl)) + .FailWith( + "Expected {context:wiremockserver} to have been called with proxy url {0}{reason}, but didn't find it among the calls with {1}.", + _ => proxyUrl, requests => requests.Select(request => request.ProxyUrl)); + + return new AndConstraint(this); + } + + [CustomAssertion] + public AndConstraint FromClientIP(string clientIP, string because = "", params object[] becauseArgs) + { + Execute.Assertion + .BecauseOf(because, becauseArgs) + .Given(() => _subject.LogEntries.Select(x => x.RequestMessage).ToList()) + .ForCondition(requests => requests.Any()) + .FailWith( + "Expected {context:wiremockserver} to have been called from client IP {0}{reason}, but no calls were made.", + clientIP) + .Then + .ForCondition(x => x.Any(y => y.ClientIP == clientIP)) + .FailWith( + "Expected {context:wiremockserver} to have been called from client IP {0}{reason}, but didn't find it among the calls from IP(s) {1}.", + _ => clientIP, requests => requests.Select(request => request.ClientIP)); + + return new AndConstraint(this); + } } } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs index e9b45a30..86c42499 100644 --- a/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs +++ b/test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs @@ -9,6 +9,7 @@ using WireMock.Server; using Xunit; using WireMock.FluentAssertions; using System.Threading.Tasks; +using WireMock.Settings; using static System.Environment; namespace WireMock.Net.Tests.FluentAssertions @@ -23,10 +24,10 @@ namespace WireMock.Net.Tests.FluentAssertions { _server = WireMockServer.Start(); _server.Given(Request.Create().UsingAnyMethod()) - .RespondWith(Response.Create().WithStatusCode(200)); + .RespondWith(Response.Create().WithSuccess()); _portUsed = _server.Ports.First(); - _httpClient = new HttpClient { BaseAddress = new Uri($"http://localhost:{_portUsed}") }; + _httpClient = new HttpClient { BaseAddress = new Uri(_server.Urls[0]) }; } [Fact] @@ -155,6 +156,134 @@ namespace WireMock.Net.Tests.FluentAssertions .And.Message.Should() .Be($"{string.Join(NewLine, missingValue1Message, missingValue2Message)}{NewLine}"); } + + [Fact] + public async Task AtUrl_WhenACallWasMadeToUrl_Should_BeOK() + { + await _httpClient.GetAsync("anyurl"); + + _server.Should() + .HaveReceivedACall() + .AtUrl($"http://localhost:{_portUsed}/anyurl"); + } + + [Fact] + public void AtUrl_Should_ThrowWhenNoCallsWereMade() + { + Action act = () => _server.Should() + .HaveReceivedACall() + .AtUrl("anyurl"); + + act.Should().Throw() + .And.Message.Should() + .Be( + "Expected _server to have been called at address matching the url \"anyurl\", but no calls were made."); + } + + [Fact] + public async Task AtUrl_Should_ThrowWhenNoCallsMatchingTheUrlWereMade() + { + await _httpClient.GetAsync(""); + + Action act = () => _server.Should() + .HaveReceivedACall() + .AtUrl("anyurl"); + + act.Should().Throw() + .And.Message.Should() + .Be( + $"Expected _server to have been called at address matching the url \"anyurl\", but didn't find it among the calls to {{\"http://localhost:{_portUsed}/\"}}."); + } + + [Fact] + public async Task WithProxyUrl_WhenACallWasMadeWithProxyUrl_Should_BeOK() + { + _server.ResetMappings(); + _server.Given(Request.Create().UsingAnyMethod()) + .RespondWith(Response.Create().WithProxy(new ProxyAndRecordSettings {Url = "http://localhost:9999"})); + + await _httpClient.GetAsync(""); + + _server.Should() + .HaveReceivedACall() + .WithProxyUrl($"http://localhost:9999"); + } + + [Fact] + public void WithProxyUrl_Should_ThrowWhenNoCallsWereMade() + { + _server.ResetMappings(); + _server.Given(Request.Create().UsingAnyMethod()) + .RespondWith(Response.Create().WithProxy(new ProxyAndRecordSettings {Url = "http://localhost:9999"})); + + Action act = () => _server.Should() + .HaveReceivedACall() + .WithProxyUrl("anyurl"); + + act.Should().Throw() + .And.Message.Should() + .Be( + "Expected _server to have been called with proxy url \"anyurl\", but no calls were made."); + } + + [Fact] + public async Task WithProxyUrl_Should_ThrowWhenNoCallsWithTheProxyUrlWereMade() + { + _server.ResetMappings(); + _server.Given(Request.Create().UsingAnyMethod()) + .RespondWith(Response.Create().WithProxy(new ProxyAndRecordSettings {Url = "http://localhost:9999"})); + + await _httpClient.GetAsync(""); + + Action act = () => _server.Should() + .HaveReceivedACall() + .WithProxyUrl("anyurl"); + + act.Should().Throw() + .And.Message.Should() + .Be( + $"Expected _server to have been called with proxy url \"anyurl\", but didn't find it among the calls with {{\"http://localhost:9999\"}}."); + } + + [Fact] + public async Task FromClientIP_whenACallWasMadeFromClientIP_Should_BeOK() + { + await _httpClient.GetAsync(""); + var clientIP = _server.LogEntries.Last().RequestMessage.ClientIP; + + _server.Should() + .HaveReceivedACall() + .FromClientIP(clientIP); + } + + [Fact] + public void FromClientIP_Should_ThrowWhenNoCallsWereMade() + { + Action act = () => _server.Should() + .HaveReceivedACall() + .FromClientIP("different-ip"); + + act.Should().Throw() + .And.Message.Should() + .Be( + "Expected _server to have been called from client IP \"different-ip\", but no calls were made."); + } + + [Fact] + public async Task FromClientIP_Should_ThrowWhenNoCallsFromClientIPWereMade() + { + await _httpClient.GetAsync(""); + var clientIP = _server.LogEntries.Last().RequestMessage.ClientIP; + + Action act = () => _server.Should() + .HaveReceivedACall() + .FromClientIP("different-ip"); + + act.Should().Throw() + .And.Message.Should() + .Be( + $"Expected _server to have been called from client IP \"different-ip\", but didn't find it among the calls from IP(s) {{\"{clientIP}\"}}."); + } public void Dispose() {