Skip to content

Add near-miss diagnostics and request count/unmatched endpoints to the admin API - #1521

Merged
StefH merged 2 commits into
wiremock:masterfrom
Quattordici:feature/near-misses-and-request-count
Oct 23, 2026
Merged

StefH merged 2 commits into
wiremock:masterfrom
Quattordici:feature/near-misses-and-request-count

Conversation

@Quattordici

Copy link
Copy Markdown
Contributor

Relates to #171

Before

When a request don't match the stub you expect, WireMock.Net only tell you "No matching mapping found". The log entry hold at most one partial match. There is no way to ask "which mappings came closest, and which matcher failed?", to list only the unmatched requests, or to count requests matching a pattern without downloading them all (#171).

A near miss is a mapping that partially matches a request: at least one matcher scores above 0, but it isn't a perfect match.

After

New admin endpoints:

Method Path Returns
POST /__admin/requests/count { "Count": n } for a RequestModel filter (same filter as /requests/find)
GET /__admin/requests/unmatched Log entries for requests that didn't fully match any mapping
GET /__admin/requests/unmatched/near-misses?maxResults=3 For each unmatched request, its near misses with per-matcher scores
GET /__admin/requests/{guid}/near-misses?maxResults=3 The near misses for one logged request
// GET /__admin/requests/unmatched/near-misses
[
  {
    "LogEntryGuid": "…",
    "Request": { "Path": "/orders", "Method": "PUT", … },
    "MappingGuid": "…",
    "MappingTitle": "Create order",
    "RequestMatchResult": {
      "IsPerfectMatch": false,
      "AverageTotalScore": 0.5,
      "MatchDetails": [
        { "Name": "PathMatcher", "Score": 1.0 },
        { "Name": "MethodMatcher", "Score": 0.0 }
      ]
    }
  }
]

The same functionality is available in code on IWireMockServer:

IReadOnlyList<ILogEntry> unmatched = server.FindUnmatchedLogEntries();
IReadOnlyList<NearMiss> forEntry = server.FindNearMisses(logEntry, maxResults: 3);
IReadOnlyList<NearMiss> forRequest = server.FindNearMisses(requestMessage);
IReadOnlyList<NearMiss> all = server.FindNearMissesForUnmatchedRequests();

The RestClient (IWireMockAdminApi) gets CountRequestsAsync, GetUnmatchedRequestsAsync, GetNearMissesForUnmatchedRequestsAsync and GetNearMissesForRequestAsync. The admin OpenAPI document (wiremock.net-openapi.yml) describes the new endpoints and the NearMissModel and RequestCountModel schemas.

How

  • IMappingMatcher.FindNearMisses(IRequestMessage, int) scores every non-admin, enabled, time-valid mapping against the request, using the existing IMapping.GetRequestMatchResult and the current scenario state. It ignores Probability, so a mapping skipped by chance still shows up, and it skips mappings whose matchers throw. It excludes perfect matches and mappings scoring 0, then orders the rest best first, using the existing RequestMatchResult comparison, then priority, then most recently updated.
  • WireMockServer implements the new IWireMockServer members by mapping those results to NearMiss. A log entry counts as unmatched when its request isn't an admin request and it has no perfect match. This is the same rule SaveUnmatchedRequests already uses, so requests served by a partial match under AllowPartialMapping count as unmatched too.
  • New models: NearMiss (WireMock.Net.Abstractions, WireMock.Matchers.Request), plus NearMissModel and RequestCountModel (WireMock.Admin.Requests).
  • LogEntryMapper gains Map(NearMiss). Its request mapping is extracted into MapRequest, so log entries and near misses serialize requests the same way.
  • /requests/find and /requests/count share one FindLogEntriesByRequestModel helper. /requests/find behaves the same as before.
  • maxResults defaults to 3. A value that isn't a positive integer returns 400 from the admin API and throws ArgumentException from the C# API. An unknown request GUID returns 404.

Notes:

  • Scores reflect the mappings and scenario states at the time you query, not at the time of the request.
  • Adding members to IWireMockServer breaks any custom implementation of that interface. In this repository only WireMockServer implements it.

Open question for reviewers:

  • requests/unmatched/near-misses returns one flat item per near miss, so each request (including its body) is repeated once per near miss. With 1000 unmatched requests and 200 mappings the response was about 5.7 MB. Would you prefer the admin responses grouped by request instead (one item per request, holding its NearMisses)? These endpoints aren't released yet, so changing the shape now wouldn't be a breaking change. The C# API would stay flat either way, since there the request is shared by reference rather than copied.

Tests

  • MappingMatcherTests: near misses exclude perfect matches and mismatches and are ordered best first; maxResults; Probability is ignored; mappings that throw are skipped.
  • WireMockServerTests.NearMisses: unmatched filtering, including partial matches under AllowPartialMapping; ordering and match details; perfect matches excluded; disabled mappings excluded; maxResults; invalid maxResults throws; the log-entry overload; near misses per unmatched request.
  • WireMockAdminApiTests.NearMisses: all four endpoints through IWireMockAdminApi, including perfect matches excluded, admin requests not counted, 400 for an invalid maxResults, and 404 for an unknown request.
  • Constants.NumAdminMappings goes from 39 to 43 for the four new admin routes.

Also in this PR: scenario delay test fix

A separate commit fixes two existing tests, Scenarios_FirstRequestWithDelay_StateTransitions_BeforeDelayCompletes and Scenarios_WithGlobalRequestProcessingDelay_StateTransitions_BeforeDelayCompletes. They waited a fixed 100 ms for the scenario state to change, so they failed whenever they ran on a cold server, for example when run on their own (on master too). They now poll server.Scenarios until the expected state is reached, with a 5 second timeout, and assert that the first request is still being delayed. Only test code changes.

…wiremock#171)

Add IWireMockServer.FindUnmatchedLogEntries, FindNearMisses and
FindNearMissesForUnmatchedRequests, which rank the mappings that
partially match a request by score.

Expose them through the admin API (POST requests/count,
GET requests/unmatched, GET requests/unmatched/near-misses and
GET requests/{guid}/near-misses), the RestClient and the OpenAPI document.
The two *_StateTransitions_BeforeDelayCompletes tests waited a fixed
100 ms for the scenario state to change, which fails on a cold server.
Poll server.Scenarios until the expected state is reached instead.
@StefH StefH added the feature label Oct 19, 2026
@StefH

StefH commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator

@Quattordici
Thanks for the PR and thanks for the fixes for Scenarios_FirstRequestWithDelay_StateTransitions_BeforeDelayCompletes


Just curious ; which AI did you use to create this PR?

@StefH

StefH commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator

@StefH
StefH merged commit dc14136 into wiremock:master Oct 23, 2026
6 checks passed
This was referenced Oct 24, 2026
This was referenced Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants