Class RequestMatchers


public class RequestMatchers extends MockServerMatcherNotifier
Author:
jamesdbloom
  • Constructor Details

  • Method Details

    • setStateBackend

      public void setStateBackend(StateBackend stateBackend)
      Sets the state backend reference and wires the expectation KV store as the source of truth. Called by HttpState after construction. The node-local httpRequestMatchers CPQ becomes a derived cache; all mutations route through the backend first.

      When a backend is wired, the node-local CPQ's maxSize is raised to Integer.MAX_VALUE so that eviction is controlled exclusively by the backend (avoiding insertion-order divergence between two CPQs on update-in-place vs re-insert). reconcileEvictions() trims the node-local cache after each backend mutation.

      Threading contract: all control-plane mutations (add, update, remove, clear, reset, setStateBackend) are assumed to be externally serialized — i.e. a single writer at a time. This is satisfied today because HttpState serializes control-plane calls on the Netty event loop or holds the action lock.

      TODO(jamesdbloom): phase 2c — when remote invalidation events arrive concurrently from a clustered backend, this single-writer assumption must be revisited — likely by introducing an internal lock or event-queue around the node-local cache reconciliation.

    • getStateBackend

      public StateBackend getStateBackend()
      Returns the state backend, or null if none has been set.
    • add

      public Expectation add(Expectation expectation, MockServerMatcherNotifier.Cause cause)
    • update

      public void update(Expectation[] expectations, MockServerMatcherNotifier.Cause cause)
    • size

      public int size()
    • reset

      public void reset(MockServerMatcherNotifier.Cause cause)
    • reset

      public void reset()
    • firstMatchingExpectation

      public Expectation firstMatchingExpectation(RequestDefinition requestDefinition)
    • firstMatchingEarlyExpectation

      public Expectation firstMatchingEarlyExpectation(HttpRequest headersOnlyRequest)
    • clear

      public void clear(RequestDefinition requestDefinition)
    • clear

      public void clear(ExpectationId expectationId, String logCorrelationId)
    • reconcileFromBackend

      public void reconcileFromBackend()
      Reconciles the node-local HttpRequestMatcher cache against the backend KeyValueStore. This handles three cases:
      1. Eviction: cached matchers whose id is no longer in the backend are removed (mirrors maxExpectations eviction).
      2. Remote add: backend entries with no local matcher get a new compiled HttpRequestMatcher (enables cross-node visibility under clustering).
      3. Remote update: backend entries whose version is newer than the locally cached version get their matcher rebuilt.

      In single-node / no-backend mode this method is a no-op. When the backend is LOCAL (non-clustered), only eviction applies because all mutations originate locally and the CPQ is already in sync.

      Threading contract: serialized via synchronized so that concurrent remote invalidation events (from a clustered backend) do not corrupt the node-local CPQ. Local mutations are still single-writer (Netty event loop / action lock); the lock is reentrant-safe for local callers because Java's synchronized is reentrant.

      Concurrent matching (data-plane) note: this method applies incremental per-entry mutations (add/update/remove) to the CPQ — the same granularity as normal control-plane add/remove. The CPQ's toSortedList() provides an eventually-consistent sorted snapshot via ConcurrentSkipListSet + volatile sortedCache + filter(nonNull). A matching thread calling toSortedList() during a reconcile may see a snapshot that lags by one mutation, but will never see a torn/empty view. This matches the pre-existing control-plane / data-plane concurrency contract.

    • postProcess

      public Expectation postProcess(Expectation expectation)
    • retrieveRequestDefinitions

      public Stream<RequestDefinition> retrieveRequestDefinitions(List<ExpectationId> expectationIds)
    • retrieveActiveExpectations

      public List<Expectation> retrieveActiveExpectations(RequestDefinition requestDefinition)
    • peekFirstMatchingExpectation

      public Expectation peekFirstMatchingExpectation(RequestDefinition requestDefinition)
      Side-effect-free probe: returns the first active expectation whose matcher matches the given request, WITHOUT consuming the match. Specifically, this method avoids:
      • Times decrement (consumeMatch())
      • Scenario state transition
      • responseInProgress flag
      • Metrics increment

      Note on logging: the underlying HttpRequestMatcher.matches() call may still emit INFO-level EXPECTATION_MATCHED or EXPECTATION_NOT_MATCHED log entries as a side-effect of the match evaluation. This method does not suppress those match-diagnostic logs. It is the Times/scenario/responseInProgress/metrics side-effects that are avoided.

      Used by the gRPC bidi router to decide the routing path before committing to a handler. Callers that need to actually consume the match (decrement Times, transition scenarios, emit logs) must still call firstMatchingExpectation(RequestDefinition) separately on the committed path.

    • retrieveExpectationsMatchingRequest

      public List<Expectation> retrieveExpectationsMatchingRequest(RequestDefinition requestDefinition)
    • retrieveRequestMatchers

      public List<HttpRequestMatcher> retrieveRequestMatchers(RequestDefinition requestDefinition)
    • findClosestMatchDiff

      public Map<MatchDifference.Field,List<String>> findClosestMatchDiff(HttpRequest httpRequest)
    • isEmpty

      public boolean isEmpty()
    • getScenarioManager

      public ScenarioManager getScenarioManager()
    • notifyListeners

      protected void notifyListeners(RequestMatchers notifier, MockServerMatcherNotifier.Cause cause)
      Overrides:
      notifyListeners in class MockServerMatcherNotifier