Skip to content

Commit 9bf93af

Browse files
Fix misleading mock sort comment and use stable sort in MockGeneratorPlugin. Closes #1974 (#1997)
The comment claimed mocks are sorted by URL length so that the most specific comes first, but the code sorts by descending ordinal URL. Generated mocks use exact URLs, so the order doesn't affect matching. Update the comment to reflect this and replace the unstable List.Sort with a stable OrderByDescending so repeated requests to the same URL keep their recorded order. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: e010e7fb-27f1-4b60-b3a6-1717b55ced91
1 parent 0e694ec commit 9bf93af

2 files changed

Lines changed: 47 additions & 2 deletions

File tree

‎DevProxy.Integration.Tests/GenerationPluginsIntegrationTests.cs‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,49 @@ public async Task MockGenerator_WritesMockFile()
161161
}
162162
}
163163

164+
[Fact]
165+
public async Task MockGenerator_PreservesRecordedOrderForSameUrl()
166+
{
167+
var plugin = new MockGeneratorPlugin(NullLogger<MockGeneratorPlugin>.Instance, Watch);
168+
169+
// enough entries to exceed the insertion-sort threshold of an unstable sort
170+
const int count = 40;
171+
var logs = Enumerable.Range(0, count)
172+
.Select(i => TestExchange
173+
.Request("GET", i % 2 == 0 ? "https://api.contoso.com/a" : "https://api.contoso.com/b")
174+
.WithResponse(
175+
HttpStatusCode.OK,
176+
headers: [("Content-Type", "application/json")],
177+
body: $$"""{ "seq": {{i}} }""")
178+
.AsRequestLog(MessageType.InterceptedResponse))
179+
.ToList();
180+
181+
var args = Recording(logs);
182+
var dir = await InTempCwdAsync(() => plugin.AfterRecordingStopAsync(args, CancellationToken.None));
183+
try
184+
{
185+
var mockFile = dir.GetFiles("mocks-*.json").Single();
186+
using var doc = JsonDocument.Parse(await File.ReadAllTextAsync(mockFile.FullName));
187+
var mocks = doc.RootElement.GetProperty("mocks").EnumerateArray()
188+
.Select(m => (
189+
Url: m.GetProperty("request").GetProperty("url").GetString(),
190+
Seq: m.GetProperty("response").GetProperty("body").GetProperty("seq").GetInt32()))
191+
.ToArray();
192+
193+
Assert.Equal(count, mocks.Length);
194+
195+
var expected = Enumerable.Range(0, count).Where(i => i % 2 == 1)
196+
.Select(i => ("https://api.contoso.com/b", i))
197+
.Concat(Enumerable.Range(0, count).Where(i => i % 2 == 0)
198+
.Select(i => ("https://api.contoso.com/a", i)));
199+
Assert.Equal(expected, mocks.Select(m => (m.Url!, m.Seq)));
200+
}
201+
finally
202+
{
203+
dir.Delete(recursive: true);
204+
}
205+
}
206+
164207
[Fact]
165208
public async Task HttpFileGenerator_WritesHttpFile()
166209
{

‎DevProxy.Plugins/Generation/MockGeneratorPlugin.cs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,10 @@ request.Context.Session is null ||
8181
}
8282

8383
Logger.LogDebug("Sorting mocks...");
84-
// sort mocks descending by url length so that most specific mocks are first
85-
mocks.Sort((a, b) => string.CompareOrdinal(b.Request!.Url, a.Request!.Url));
84+
// group mocks by URL (descending ordinal order) for readability. Generated
85+
// mocks use exact URLs, so this order doesn't affect matching. The sort is
86+
// stable so that repeated requests to the same URL keep their recorded order.
87+
mocks = [.. mocks.OrderByDescending(m => m.Request!.Url, StringComparer.Ordinal)];
8688

8789
var mocksFile = new MockResponseConfiguration { Mocks = mocks };
8890

0 commit comments

Comments
 (0)