Skip to content

Commit 5885324

Browse files
StefHCopilot
andauthored
Fix WithProbability logic (#1367)
* Fix WithProbability logic * . * FIX * Update src/WireMock.Net.Minimal/Owin/MappingMatcher.cs Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]>
1 parent e3f3e0a commit 5885324

File tree

5 files changed

+107
-54
lines changed

5 files changed

+107
-54
lines changed

examples/WireMock.Net.Console.NET8/MainApp.cs

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ private static void RunOnLocal()
267267
}
268268
}
269269

270-
public static void Run()
270+
public static async Task RunAsync()
271271
{
272272
//RunSse();
273273
//RunOnLocal();
@@ -290,25 +290,56 @@ public static void Run()
290290

291291
var server = WireMockServer.Start();
292292

293+
//server
294+
// .Given(Request.Create()
295+
// .WithPath("todos")
296+
// .UsingGet()
297+
// )
298+
// .RespondWith(Response.Create()
299+
// .WithBodyAsJson(todos.Values)
300+
// );
301+
302+
//server
303+
// .Given(Request.Create()
304+
// .UsingGet()
305+
// .WithPath("todos")
306+
// .WithParam("id")
307+
// )
308+
// .RespondWith(Response.Create()
309+
// .WithBodyAsJson(rm => todos[int.Parse(rm.Query!["id"].ToString())])
310+
// );
311+
312+
var pX = 0.80;
293313
server
294-
.Given(Request.Create()
295-
.WithPath("todos")
296-
.UsingGet()
297-
)
298-
.RespondWith(Response.Create()
299-
.WithBodyAsJson(todos.Values)
300-
);
314+
.Given(Request.Create().UsingGet().WithPath("/p"))
315+
.WithProbability(pX)
316+
.RespondWith(Response.Create().WithStatusCode(200).WithBody("X"));
301317

302318
server
303-
.Given(Request.Create()
304-
.UsingGet()
305-
.WithPath("todos")
306-
.WithParam("id")
307-
)
308-
.RespondWith(Response.Create()
309-
.WithBodyAsJson(rm => todos[int.Parse(rm.Query!["id"].ToString())])
310-
);
319+
.Given(Request.Create().UsingGet().WithPath("/p"))
320+
.RespondWith(Response.Create().WithStatusCode(200).WithBody("default"));
311321

322+
// Act
323+
var requestUri = new Uri($"http://localhost:{server.Port}/p");
324+
var c = server.CreateClient();
325+
var xCount = 0;
326+
var defaultCount = 0;
327+
var tot = 1000;
328+
for (var i = 0; i < tot; i++)
329+
{
330+
var response = await c.GetAsync(requestUri);
331+
var value = await response.Content.ReadAsStringAsync();
332+
if (value == "X")
333+
{
334+
xCount++;
335+
}
336+
else if (value == "default")
337+
{
338+
defaultCount++;
339+
}
340+
}
341+
System.Console.WriteLine("X = {0} ; default = {1} ; pX = {2:0.00} ; valueX = {3:0.00}", xCount, defaultCount, pX, 1.0 * xCount / tot);
342+
return;
312343
using var httpAndHttpsWithPort = WireMockServer.Start(new WireMockServerSettings
313344
{
314345
HostingScheme = HostingScheme.HttpAndHttps,

examples/WireMock.Net.Console.NET8/Program.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using System.IO;
44
using System.Reflection;
5+
using System.Threading.Tasks;
56
using log4net;
67
using log4net.Config;
78
using log4net.Repository;
@@ -14,10 +15,10 @@ static class Program
1415
private static readonly ILoggerRepository LogRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
1516
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
1617

17-
static void Main(params string[] args)
18+
static async Task Main(params string[] args)
1819
{
1920
XmlConfigurator.Configure(LogRepository, new FileInfo("log4net.config"));
2021

21-
MainApp.Run();
22+
await MainApp.RunAsync();
2223
}
2324
}

src/WireMock.Net.Minimal/Owin/MappingMatcher.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,10 @@
99

1010
namespace WireMock.Owin;
1111

12-
internal class MappingMatcher : IMappingMatcher
12+
internal class MappingMatcher(IWireMockMiddlewareOptions options, IRandomizerDoubleBetween0And1 randomizerDoubleBetween0And1) : IMappingMatcher
1313
{
14-
private readonly IWireMockMiddlewareOptions _options;
15-
private readonly IRandomizerDoubleBetween0And1 _randomizerDoubleBetween0And1;
16-
17-
public MappingMatcher(IWireMockMiddlewareOptions options, IRandomizerDoubleBetween0And1 randomizerDoubleBetween0And1)
18-
{
19-
_options = Guard.NotNull(options);
20-
_randomizerDoubleBetween0And1 = Guard.NotNull(randomizerDoubleBetween0And1);
21-
}
14+
private readonly IWireMockMiddlewareOptions _options = Guard.NotNull(options);
15+
private readonly IRandomizerDoubleBetween0And1 _randomizerDoubleBetween0And1 = Guard.NotNull(randomizerDoubleBetween0And1);
2216

2317
public (MappingMatcherResult? Match, MappingMatcherResult? Partial) FindBestMatch(RequestMessage request)
2418
{
@@ -28,7 +22,7 @@ public MappingMatcher(IWireMockMiddlewareOptions options, IRandomizerDoubleBetwe
2822

2923
var mappings = _options.Mappings.Values
3024
.Where(m => m.TimeSettings.IsValid())
31-
.Where(m => m.Probability is null || m.Probability <= _randomizerDoubleBetween0And1.Generate())
25+
.Where(m => m.Probability is null || _randomizerDoubleBetween0And1.Generate() <= m.Probability)
3226
.ToArray();
3327

3428
foreach (var mapping in mappings)
@@ -41,18 +35,18 @@ public MappingMatcher(IWireMockMiddlewareOptions options, IRandomizerDoubleBetwe
4135

4236
var exceptions = mappingMatcherResult.RequestMatchResult.MatchDetails
4337
.Where(md => md.Exception != null)
44-
.Select(md => md.Exception)
38+
.Select(md => md.Exception!)
4539
.ToArray();
4640

47-
if (!exceptions.Any())
41+
if (exceptions.Length == 0)
4842
{
4943
possibleMappings.Add(mappingMatcherResult);
5044
}
5145
else if (!request.AbsolutePath.StartsWith("/__admin", StringComparison.OrdinalIgnoreCase))
5246
{
5347
foreach (var ex in exceptions)
5448
{
55-
LogException(mapping, ex!);
49+
LogException(mapping, ex);
5650
}
5751
}
5852
}
@@ -62,14 +56,16 @@ public MappingMatcher(IWireMockMiddlewareOptions options, IRandomizerDoubleBetwe
6256
}
6357
}
6458

65-
var partialMappings = possibleMappings
59+
var partialMatches = possibleMappings
6660
.Where(pm => (pm.Mapping.IsAdminInterface && pm.RequestMatchResult.IsPerfectMatch) || !pm.Mapping.IsAdminInterface)
6761
.OrderBy(m => m.RequestMatchResult)
6862
.ThenBy(m => m.RequestMatchResult.TotalNumber)
6963
.ThenBy(m => m.Mapping.Priority)
64+
.ThenByDescending(m => m.Mapping.Probability)
7065
.ThenByDescending(m => m.Mapping.UpdatedAt)
71-
.ToList();
72-
var partialMatch = partialMappings.FirstOrDefault(pm => pm.RequestMatchResult.AverageTotalScore > 0.0);
66+
.Where(pm => pm.RequestMatchResult.AverageTotalScore > 0.0)
67+
.ToArray();
68+
var partialMatch = partialMatches.FirstOrDefault();
7369

7470
if (_options.AllowPartialMapping == true)
7571
{
@@ -78,7 +74,11 @@ public MappingMatcher(IWireMockMiddlewareOptions options, IRandomizerDoubleBetwe
7874

7975
var match = possibleMappings
8076
.Where(m => m.RequestMatchResult.IsPerfectMatch)
81-
.OrderBy(m => m.Mapping.Priority).ThenBy(m => m.RequestMatchResult).ThenByDescending(m => m.Mapping.UpdatedAt)
77+
.OrderBy(m => m.Mapping.Priority)
78+
.ThenBy(m => m.RequestMatchResult)
79+
.ThenBy(m => m.RequestMatchResult.TotalNumber)
80+
.ThenByDescending(m => m.Mapping.Probability)
81+
.ThenByDescending(m => m.Mapping.UpdatedAt)
8282
.FirstOrDefault();
8383

8484
return (match, partialMatch);

test/WireMock.Net.Tests/Owin/MappingMatcherTests.cs

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using WireMock.Models;
1010
using WireMock.Owin;
1111
using WireMock.Services;
12-
using WireMock.Util;
1312
using Xunit;
1413

1514
namespace WireMock.Net.Tests.Owin;
@@ -26,7 +25,7 @@ public MappingMatcherTests()
2625
_optionsMock = new Mock<IWireMockMiddlewareOptions>();
2726
_optionsMock.SetupAllProperties();
2827
_optionsMock.Setup(o => o.Mappings).Returns(new ConcurrentDictionary<Guid, IMapping>());
29-
_optionsMock.Setup(o => o.LogEntries).Returns(new ConcurrentObservableCollection<LogEntry>());
28+
_optionsMock.Setup(o => o.LogEntries).Returns([]);
3029
_optionsMock.Setup(o => o.Scenarios).Returns(new ConcurrentDictionary<string, ScenarioState>());
3130

3231
var loggerMock = new Mock<IWireMockLogger>();
@@ -35,7 +34,7 @@ public MappingMatcherTests()
3534
_optionsMock.Setup(o => o.Logger).Returns(loggerMock.Object);
3635

3736
_randomizerDoubleBetween0And1Mock = new Mock<IRandomizerDoubleBetween0And1>();
38-
_randomizerDoubleBetween0And1Mock.Setup(r => r.Generate()).Returns(0.0);
37+
_randomizerDoubleBetween0And1Mock.Setup(r => r.Generate()).Returns(0.5);
3938

4039
_sut = new MappingMatcher(_optionsMock.Object, _randomizerDoubleBetween0And1Mock.Object);
4140
}
@@ -84,8 +83,8 @@ public void MappingMatcher_FindBestMatch_WhenAllowPartialMappingIsFalse_ShouldRe
8483
var guid2 = Guid.Parse("00000000-0000-0000-0000-000000000002");
8584
var mappings = InitMappings
8685
(
87-
(guid1, new[] { 0.1 }, null),
88-
(guid2, new[] { 1.0 }, null)
86+
(guid1, [0.1], null),
87+
(guid2, [1.0], null)
8988
);
9089
_optionsMock.Setup(o => o.Mappings).Returns(mappings);
9190

@@ -112,8 +111,8 @@ public void MappingMatcher_FindBestMatch_WhenAllowPartialMappingIsFalse_AndNoExa
112111
var guid2 = Guid.Parse("00000000-0000-0000-0000-000000000002");
113112
var mappings = InitMappings
114113
(
115-
(guid1, new[] { 0.1 }, null),
116-
(guid2, new[] { 0.9 }, null)
114+
(guid1, [0.1], null),
115+
(guid2, [0.9], null)
117116
);
118117
_optionsMock.Setup(o => o.Mappings).Returns(mappings);
119118

@@ -139,8 +138,8 @@ public void MappingMatcher_FindBestMatch_WhenAllowPartialMappingIsTrue_ShouldRet
139138

140139
_optionsMock.SetupGet(o => o.AllowPartialMapping).Returns(true);
141140
var mappings = InitMappings(
142-
(guid1, new[] { 0.1 }, null),
143-
(guid2, new[] { 0.9 }, null)
141+
(guid1, [0.1], null),
142+
(guid2, [0.9], null)
144143
);
145144
_optionsMock.Setup(o => o.Mappings).Returns(mappings);
146145

@@ -166,8 +165,8 @@ public void MappingMatcher_FindBestMatch_WhenAllowPartialMappingIsFalse_And_With
166165
var guid1 = Guid.Parse("00000000-0000-0000-0000-000000000001");
167166
var guid2 = Guid.Parse("00000000-0000-0000-0000-000000000002");
168167
var mappings = InitMappings(
169-
(guid1, new[] { 1.0 }, null),
170-
(guid2, new[] { 1.0, 1.0 }, null)
168+
(guid1, [1.0], null),
169+
(guid2, [1.0, 1.0], null)
171170
);
172171
_optionsMock.Setup(o => o.Mappings).Returns(mappings);
173172

@@ -187,15 +186,15 @@ public void MappingMatcher_FindBestMatch_WhenAllowPartialMappingIsFalse_And_With
187186
}
188187

189188
[Fact]
190-
public void MappingMatcher_FindBestMatch_WhenProbabilityFailsFirst_ShouldReturnSecondMatch()
189+
public void MappingMatcher_FindBestMatch_WhenProbabilityDoesNotMatch_ShouldReturnNormalMatch()
191190
{
192191
// Assign
193-
var guid1 = Guid.Parse("00000000-0000-0000-0000-000000000001");
194-
var guid2 = Guid.Parse("00000000-0000-0000-0000-000000000002");
192+
var withProbability = Guid.Parse("00000000-0000-0000-0000-000000000001");
193+
var noProbability = Guid.Parse("00000000-0000-0000-0000-000000000002");
195194
var mappings = InitMappings
196195
(
197-
(guid1, new[] { 1.0 }, 1.0),
198-
(guid2, new[] { 1.0 }, null)
196+
(withProbability, [1.0], 0.4),
197+
(noProbability, [1.0], null)
199198
);
200199
_optionsMock.Setup(o => o.Mappings).Returns(mappings);
201200

@@ -206,8 +205,30 @@ public void MappingMatcher_FindBestMatch_WhenProbabilityFailsFirst_ShouldReturnS
206205

207206
// Assert
208207
result.Match.Should().NotBeNull();
209-
result.Match!.Mapping.Guid.Should().Be(guid2);
210-
result.Match.RequestMatchResult.AverageTotalScore.Should().Be(1.0);
208+
result.Match!.Mapping.Guid.Should().Be(noProbability);
209+
}
210+
211+
[Fact]
212+
public void MappingMatcher_FindBestMatch_WhenProbabilityDoesMatch_ShouldReturnProbabilityMatch()
213+
{
214+
// Assign
215+
var withProbability = Guid.Parse("00000000-0000-0000-0000-000000000001");
216+
var noProbability = Guid.Parse("00000000-0000-0000-0000-000000000002");
217+
var mappings = InitMappings
218+
(
219+
(withProbability, [1.0], 0.6),
220+
(noProbability, [1.0], null)
221+
);
222+
_optionsMock.Setup(o => o.Mappings).Returns(mappings);
223+
224+
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1");
225+
226+
// Act
227+
var result = _sut.FindBestMatch(request);
228+
229+
// Assert
230+
result.Match.Should().NotBeNull();
231+
result.Match!.Mapping.Guid.Should().Be(withProbability);
211232
}
212233

213234
private static ConcurrentDictionary<Guid, IMapping> InitMappings(params (Guid guid, double[] scores, double? probability)[] matches)

test/WireMock.Net.Tests/WireMockServerTests.WithProbability.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public async Task WireMockServer_WithProbability()
3232
var response = await server.CreateClient().GetAsync(requestUri).ConfigureAwait(false);
3333

3434
// Assert
35-
Assert.True(new[] { HttpStatusCode.OK, HttpStatusCode.InternalServerError }.Contains(response.StatusCode));
35+
Assert.Contains(response.StatusCode, [HttpStatusCode.OK, HttpStatusCode.InternalServerError]);
3636

3737
server.Stop();
3838
}

0 commit comments

Comments
 (0)