Skip to content

Commit

Permalink
Merge branch 'master' into issue-1217
Browse files Browse the repository at this point in the history
  • Loading branch information
StefH committed Dec 23, 2024
2 parents 3bec9be + 485f7ad commit 50c9820
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 40 deletions.
12 changes: 9 additions & 3 deletions src/WireMock.Net.Abstractions/Server/IWireMockServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Specialized;
using WireMock.Admin.Mappings;
using WireMock.Logging;
using WireMock.Matchers.Request;
using WireMock.Types;

namespace WireMock.Server;
Expand All @@ -27,12 +28,12 @@ public interface IWireMockServer : IDisposable
/// <summary>
/// Gets the request logs.
/// </summary>
IEnumerable<ILogEntry> LogEntries { get; }
IReadOnlyList<ILogEntry> LogEntries { get; }

/// <summary>
/// Gets the mappings as MappingModels.
/// </summary>
IEnumerable<MappingModel> MappingModels { get; }
IReadOnlyList<MappingModel> MappingModels { get; }

// <summary>
// Gets the mappings.
Expand Down Expand Up @@ -109,7 +110,12 @@ public interface IWireMockServer : IDisposable
/// <param name="guid">The unique identifier.</param>
bool DeleteMapping(Guid guid);

//IEnumerable<LogEntry> FindLogEntries([NotNull] params IRequestMatcher[] matchers);
/// <summary>
/// Search log-entries based on matchers.
/// </summary>
/// <param name="matchers">The request matchers to use.</param>
/// <returns>The <see cref="IReadOnlyList{ILogEntry}"/>.</returns>
IReadOnlyList<ILogEntry> FindLogEntries(params IRequestMatcher[] matchers);

// IRespondWithAProvider Given(IRequestMatcher requestMatcher, bool saveToFile = false);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Copyright © WireMock.Net

#pragma warning disable CS1591
using System;
using WireMock.Extensions;
using WireMock.Matchers;

// ReSharper disable once CheckNamespace
namespace WireMock.FluentAssertions;
Expand All @@ -11,7 +12,17 @@ public partial class WireMockAssertions
[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> AtAbsoluteUrl(string absoluteUrl, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request => string.Equals(request.AbsoluteUrl, absoluteUrl, StringComparison.OrdinalIgnoreCase));
_ = AtAbsoluteUrl(new ExactMatcher(true, absoluteUrl), because, becauseArgs);

return new AndWhichConstraint<WireMockAssertions, string>(this, absoluteUrl);
}

[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, IStringMatcher> AtAbsoluteUrl(IStringMatcher absoluteUrlMatcher, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request => absoluteUrlMatcher.IsPerfectMatch(request.AbsoluteUrl));

var absoluteUrl = absoluteUrlMatcher.GetPatterns().FirstOrDefault().GetPattern();

Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand All @@ -31,13 +42,23 @@ public AndWhichConstraint<WireMockAssertions, string> AtAbsoluteUrl(string absol

FilterRequestMessages(filter);

return new AndWhichConstraint<WireMockAssertions, string>(this, absoluteUrl);
return new AndWhichConstraint<WireMockAssertions, IStringMatcher>(this, absoluteUrlMatcher);
}

[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, string> AtUrl(string url, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request => string.Equals(request.Url, url, StringComparison.OrdinalIgnoreCase));
_ = AtUrl(new ExactMatcher(true, url), because, becauseArgs);

return new AndWhichConstraint<WireMockAssertions, string>(this, url);
}

[CustomAssertion]
public AndWhichConstraint<WireMockAssertions, IStringMatcher> AtUrl(IStringMatcher urlMatcher, string because = "", params object[] becauseArgs)
{
var (filter, condition) = BuildFilterAndCondition(request => urlMatcher.IsPerfectMatch(request.Url));

var url = urlMatcher.GetPatterns().FirstOrDefault().GetPattern();

Execute.Assertion
.BecauseOf(because, becauseArgs)
Expand All @@ -57,6 +78,6 @@ public AndWhichConstraint<WireMockAssertions, string> AtUrl(string url, string b

FilterRequestMessages(filter);

return new AndWhichConstraint<WireMockAssertions, string>(this, url);
return new AndWhichConstraint<WireMockAssertions, IStringMatcher>(this, urlMatcher);
}
}
12 changes: 7 additions & 5 deletions src/WireMock.Net/Http/WebhookSender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ IResponseMessage originalResponseMessage

IBodyData? bodyData;
IDictionary<string, WireMockList<string>>? headers;
string webhookRequestUrl;
string requestUrl;
if (webhookRequest.UseTransformer == true)
{
ITransformer transformer;
Expand All @@ -69,18 +69,20 @@ IResponseMessage originalResponseMessage

bodyData = transformer.TransformBody(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.BodyData, webhookRequest.TransformerReplaceNodeOptions);
headers = transformer.TransformHeaders(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.Headers);
webhookRequestUrl = transformer.TransformString(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.Url);
requestUrl = transformer.TransformString(mapping, originalRequestMessage, originalResponseMessage, webhookRequest.Url);

mapping.Settings.WebhookSettings?.PostTransform(mapping, requestUrl, bodyData, headers);
}
else
{
bodyData = webhookRequest.BodyData;
headers = webhookRequest.Headers;
webhookRequestUrl = webhookRequest.Url;
requestUrl = webhookRequest.Url;
}

// Create RequestMessage
var requestMessage = new RequestMessage(
new UrlDetails(webhookRequestUrl),
new UrlDetails(requestUrl),
webhookRequest.Method,
ClientIp,
bodyData,
Expand All @@ -91,7 +93,7 @@ IResponseMessage originalResponseMessage
};

// Create HttpRequestMessage
var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, webhookRequestUrl);
var httpRequestMessage = HttpRequestMessageHelper.Create(requestMessage, requestUrl);

// Delay (if required)
if (TryGetDelay(webhookRequest, out var delay))
Expand Down
20 changes: 20 additions & 0 deletions src/WireMock.Net/Matchers/MatcherExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright © WireMock.Net

namespace WireMock.Matchers;

/// <summary>
/// Provides some extension methods for matchers.
/// </summary>
public static class MatcherExtensions
{
/// <summary>
/// Determines if the match result is a perfect match.
/// </summary>
/// <param name="matcher">The string matcher.</param>
/// <param name="input">The input string to match.</param>
/// <returns><c>true</c>> if the match is perfect; otherwise, <c>false</c>>.</returns>
public static bool IsPerfectMatch(this IStringMatcher matcher, string? input)
{
return matcher.IsMatch(input).IsPerfect();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ internal class RequestMessageMethodMatcher : IRequestMatcher
/// </summary>
public string[] Methods { get; }

/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageMethodMatcher"/> class.
/// </summary>
/// <param name="methods">The methods.</param>
public RequestMessageMethodMatcher(params string[] methods) : this(MatchBehaviour.AcceptOnMatch, MatchOperator.Or, methods)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="RequestMessageMethodMatcher"/> class.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/WireMock.Net/Server/WireMockServer.AdminFiles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace WireMock.Server;

public partial class WireMockServer
{
private static readonly Encoding[] FileBodyIsString = { Encoding.UTF8, Encoding.ASCII };
private static readonly Encoding[] FileBodyIsString = [Encoding.UTF8, Encoding.ASCII];

#region Files/{filename}
private IResponseMessage FilePost(IRequestMessage requestMessage)
Expand Down
2 changes: 1 addition & 1 deletion src/WireMock.Net/Server/WireMockServer.ConvertMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ private static IResponseBuilder InitResponseBuilder(ResponseModel responseModel)
}
else if (responseModel.HeadersRaw != null)
{
foreach (string headerLine in responseModel.HeadersRaw.Split(new[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
foreach (string headerLine in responseModel.HeadersRaw.Split(["\n", "\r\n"], StringSplitOptions.RemoveEmptyEntries))
{
int indexColon = headerLine.IndexOf(":", StringComparison.Ordinal);
string key = headerLine.Substring(0, indexColon).TrimStart(' ', '\t');
Expand Down
22 changes: 10 additions & 12 deletions src/WireMock.Net/Server/WireMockServer.LogEntries.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// Copyright © WireMock.Net

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using JetBrains.Annotations;
Expand All @@ -24,23 +22,20 @@ public event NotifyCollectionChangedEventHandler LogEntriesChanged
remove => _logEntriesChanged -= value;
}

/// <inheritdoc cref="IWireMockServer.LogEntries" />
/// <inheritdoc />
[PublicAPI]
public IEnumerable<ILogEntry> LogEntries => new ReadOnlyCollection<LogEntry>(_options.LogEntries.ToList());
public IReadOnlyList<ILogEntry> LogEntries => _options.LogEntries.ToArray();


/// <summary>
/// The search log-entries based on matchers.
/// </summary>
/// <param name="matchers">The matchers.</param>
/// <returns>The <see cref="IEnumerable"/>.</returns>
/// <inheritdoc />
[PublicAPI]
public IEnumerable<LogEntry> FindLogEntries(params IRequestMatcher[] matchers)
public IReadOnlyList<ILogEntry> FindLogEntries(params IRequestMatcher[] matchers)
{
Guard.NotNull(matchers);

var results = new Dictionary<LogEntry, RequestMatchResult>();

foreach (var log in _options.LogEntries.ToList())
foreach (var log in _options.LogEntries.ToArray())
{
var requestMatchResult = new RequestMatchResult();
foreach (var matcher in matchers)
Expand All @@ -54,7 +49,10 @@ public IEnumerable<LogEntry> FindLogEntries(params IRequestMatcher[] matchers)
}
}

return new ReadOnlyCollection<LogEntry>(results.OrderBy(x => x.Value).Select(x => x.Key).ToList());
return results
.OrderBy(x => x.Value)
.Select(x => x.Key)
.ToArray();
}

/// <inheritdoc cref="IWireMockServer.ResetLogEntries" />
Expand Down
4 changes: 2 additions & 2 deletions src/WireMock.Net/Server/WireMockServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ public partial class WireMockServer : IWireMockServer
/// Gets the mappings.
/// </summary>
[PublicAPI]
public IEnumerable<IMapping> Mappings => _options.Mappings.Values.ToArray();
public IReadOnlyList<IMapping> Mappings => _options.Mappings.Values.ToArray();

/// <inheritdoc cref="IWireMockServer.MappingModels" />
[PublicAPI]
public IEnumerable<MappingModel> MappingModels => ToMappingModels();
public IReadOnlyList<MappingModel> MappingModels => ToMappingModels();

/// <summary>
/// Gets the scenarios.
Expand Down
14 changes: 14 additions & 0 deletions src/WireMock.Net/Settings/WebhookSettings.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
// Copyright © WireMock.Net

using System.Collections.Generic;
using WireMock.Types;
using WireMock.Util;

namespace WireMock.Settings;

/// <summary>
/// WebhookSettings
/// </summary>
public class WebhookSettings : HttpClientSettings
{
/// <summary>
/// Executes an action after the transformation of the request body.
/// </summary>
/// <param name="mapping">The mapping used for the request.</param>
/// <param name="requestUrl">The request Url.</param>
/// <param name="bodyData">The body data of the request. [Optional]</param>
/// <param name="headers">The headers of the request. [Optional]</param>
public virtual void PostTransform(IMapping mapping, string requestUrl, IBodyData? bodyData = null, IDictionary<string, WireMockList<string>>? headers = null)
{
}
}
48 changes: 38 additions & 10 deletions test/WireMock.Net.Tests/FluentAssertions/WireMockAssertionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ public async Task HaveReceivedACall_AtAbsoluteUrl_WhenACallWasMadeToAbsoluteUrl_
{
await _httpClient.GetAsync("anyurl").ConfigureAwait(false);

_server.Should()
.HaveReceivedACall()
.AtAbsoluteUrl(new WildcardMatcher($"http://localhost:{_portUsed}/any*"));
}

[Fact]
public async Task HaveReceivedACall_AtAbsoluteUrlWilcardMAtcher_WhenACallWasMadeToAbsoluteUrl_Should_BeOK()
{
await _httpClient.GetAsync("anyurl").ConfigureAwait(false);

_server.Should()
.HaveReceivedACall()
.AtAbsoluteUrl($"http://localhost:{_portUsed}/anyurl");
Expand Down Expand Up @@ -231,7 +241,7 @@ public async Task HaveReceivedACall_WithHeader_ShouldCheckAllRequests()
using var client2 = server.CreateClient(handler);

// Act 1
await client1.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/")
var task1 = client1.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/")
{
Headers =
{
Expand All @@ -240,14 +250,16 @@ await client1.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/")
});

// Act 2
await client2.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/")
var task2 = client2.SendAsync(new HttpRequestMessage(HttpMethod.Get, "/")
{
Headers =
{
Authorization = new AuthenticationHeaderValue("Bearer", "validToken")
}
});

await Task.WhenAll(task1, task2);

// Assert
server.Should()
.HaveReceivedACall()
Expand All @@ -268,6 +280,16 @@ public async Task HaveReceivedACall_AtUrl_WhenACallWasMadeToUrl_Should_BeOK()
.AtUrl($"http://localhost:{_portUsed}/anyurl");
}

[Fact]
public async Task HaveReceivedACall_AtUrlWildcardMatcher_WhenACallWasMadeToUrl_Should_BeOK()
{
await _httpClient.GetAsync("anyurl").ConfigureAwait(false);

_server.Should()
.HaveReceivedACall()
.AtUrl(new WildcardMatcher($"http://localhost:{_portUsed}/AN*", true));
}

[Fact]
public void HaveReceivedACall_AtUrl_Should_ThrowWhenNoCallsWereMade()
{
Expand Down Expand Up @@ -393,11 +415,14 @@ public async Task HaveReceivedNoCalls_UsingPost_WhenACallWasNotMadeUsingPost_Sho
[Fact]
public async Task HaveReceived2Calls_UsingDelete_WhenACallWasMadeUsingDelete_Should_BeOK()
{
await _httpClient.DeleteAsync("anyurl").ConfigureAwait(false);

await _httpClient.DeleteAsync("anyurl").ConfigureAwait(false);
var tasks = new[]
{
_httpClient.DeleteAsync("anyurl"),
_httpClient.DeleteAsync("anyurl"),
_httpClient.GetAsync("anyurl")
};

await _httpClient.GetAsync("anyurl").ConfigureAwait(false);
await Task.WhenAll(tasks);

_server.Should()
.HaveReceived(2).Calls()
Expand Down Expand Up @@ -521,11 +546,14 @@ public async Task HaveReceived1Calls_AtAbsoluteUrlUsingPost_ShouldChain()
// Act
var httpClient = new HttpClient();

await httpClient.GetAsync($"{server.Url}/a");

await httpClient.PostAsync($"{server.Url}/b", new StringContent("B"));
var tasks = new[]
{
httpClient.GetAsync($"{server.Url}/a"),
httpClient.PostAsync($"{server.Url}/b", new StringContent("B")),
httpClient.PostAsync($"{server.Url}/c", new StringContent("C"))
};

await httpClient.PostAsync($"{server.Url}/c", new StringContent("C"));
await Task.WhenAll(tasks);

// Assert
server
Expand Down
Loading

0 comments on commit 50c9820

Please sign in to comment.