Skip to content

chore(deps): update dependency org.mock-server:mockserver-netty-no-dependencies to v7.1.0#2224

Merged
renovate[bot] merged 1 commit into
mainfrom
renovate/org.mock-server-mockserver-netty-no-dependencies-7.x
Jun 16, 2026
Merged

chore(deps): update dependency org.mock-server:mockserver-netty-no-dependencies to v7.1.0#2224
renovate[bot] merged 1 commit into
mainfrom
renovate/org.mock-server-mockserver-netty-no-dependencies-7.x

Conversation

@renovate

@renovate renovate Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
org.mock-server:mockserver-netty-no-dependencies (source) 7.0.07.1.0 age confidence

Release Notes

mock-server/mockserver-monorepo (org.mock-server:mockserver-netty-no-dependencies)

v7.1.0

Added
Verification
  • Verify responses received from proxied/forwarded systems — verification now optionally matches the response of a recorded request-response exchange, not just the request. Add an httpResponse matcher to a verification (PUT /mockserver/verify with {httpRequest?, httpResponse, times}) and MockServer counts recorded request-response pairs (proxied/forwarded exchanges) whose response matches — by status code, reason phrase (regex), headers, and body (JSON, JSON schema, JSONPath, XML, XPath, regex, etc., reusing the existing request body matchers). When httpRequest is also supplied, both must match. verifySequence gains an index-aligned httpResponses list so an ordered sequence can assert on responses too. The verify/verifySequence call shape and VerificationTimes are unchanged — the presence of a response matcher is what switches verification from "request received" to "response received". When no response matcher is supplied, behaviour is identical to before.
Breakpoints & request replay
  • Matcher-driven breakpoints — breakpoints are toggled per-request via a matcher rather than by global config flags. You register a request matcher (works exactly like an expectation request matcher) together with the phases to break at: PUT /mockserver/breakpoint/matcher with {httpRequest, phases:["REQUEST"|"RESPONSE"|"RESPONSE_STREAM"|"INBOUND_STREAM"], clientId:"..."}. A forwarded/proxied exchange whose request matches a registered breakpoint pauses at the selected phase(s). Manage matchers via GET/PUT /mockserver/breakpoint/matchers, PUT /mockserver/breakpoint/matcher/remove ({id}), and PUT /mockserver/breakpoint/matcher/clear; the registry is cleared on /mockserver/reset. The breakpointTimeoutMillis (30000) and breakpointMaxHeld (50) safety rails are retained.
  • clientId required for breakpoint registration; callback WebSocket is the resolution transportPUT /mockserver/breakpoint/matcher requires a clientId field (the callback WebSocket client id); omitting it returns 400. Breakpoints are resolved interactively over the callback WebSocket only — all clients (including the dashboard) resolve breakpoints over that channel.
  • Interactive breakpoint resolution over the callback WebSocket — a matching forwarded REQUEST or RESPONSE exchange is dispatched to the owning callback-WebSocket client (the same /_mockserver_callback_websocket channel forwardObject/responseObject clients use) for interactive resolution: the client replies with a modified request (forward), a response (abort/replace), or the original (continue). Shares the breakpointTimeoutMillis auto-continue and breakpointMaxHeld cap rails; a client disconnect removes its breakpoints and auto-continues anything it was holding.
  • Per-frame streaming breakpoints over the callback WebSocket — RESPONSE_STREAM (outbound) and INBOUND_STREAM (client→server) breakpoints resolve interactively over the callback WebSocket across all nine streaming hold points (SSE/chunked, HTTP/3 gRPC, gRPC server-streaming, WebSocket eager/bidi, GraphQL-subscription, and the WebSocket/GraphQL/gRPC-bidi inbound paths). Two WS message types form the frozen per-frame protocol: a server→client PausedStreamFrameDTO (correlationId, streamId, sequenceNumber, direction, phase, base64 body, request method/path) and a client→server StreamFrameDecisionDTO (correlationId, action ∈ CONTINUE/MODIFY/DROP/INJECT/CLOSE, optional base64 body). Event-loop safe (decisions marshalled onto the channel event loop, frame bytes copied to byte[]), with ordering and backpressure preserved and the shared timeout/max-held rails + client-disconnect auto-continue. The per-server WebSocket registry is injected per-channel (no process-global state).
  • Java client breakpoint API (matcher + callback handlers)MockServerClient.addBreakpoint(matcher, phases…, handlers…) registers a breakpoint matcher and resolves paused exchanges interactively over the callback WebSocket, with typed handlers per phase: BreakpointRequestHandler (return a request to forward/modify or a response to abort), BreakpointResponseHandler (return the response to write), and BreakpointStreamFrameHandler (return a CONTINUE/MODIFY/DROP/INJECT/CLOSE decision). Plus listBreakpointMatchers(), removeBreakpointMatcher(id), clearBreakpointMatchers(). The client lazily opens one callback-WS connection (reused across breakpoints) and tears it down on stop/reset. Per-matcher handler routing: each pushed paused item carries the matched breakpoint's id (a new X-MockServer-BreakpointId header for request/response and a breakpointId field on the stream-frame message), so each breakpoint routes to its own handler rather than a single shared per-phase handler. This is the reference API the other language clients mirror.
  • Node, Python & Ruby client breakpoint APIs — the Node, Python, and Ruby clients gain the same matcher-driven breakpoint API as the Java client (addBreakpoint/add_breakpoint + convenience overloads, list/remove/clear breakpoint matchers), resolving paused request/response/stream-frame exchanges interactively over each client's existing callback WebSocket with per-matcher handler routing (by the X-MockServer-BreakpointId header / breakpointId frame field). Idiomatic per language (typed objects in Node, dicts in Python, hashes in Ruby); handlers auto-continue on error or missing handler so a buggy handler can't hang the exchange.
  • Go, .NET & Rust client breakpoint APIs (new callback-WebSocket stacks) — the Go, .NET, and Rust clients gain a full callback-WebSocket stack (Go gorilla/websocket, .NET built-in ClientWebSocket, Rust tungstenite) plus the matcher-driven breakpoint API (addBreakpoint/AddBreakpoint/add_breakpoint + convenience overloads, list/remove/clear breakpoint matchers). Each connects to /_mockserver_callback_websocket, registers a clientId, and resolves paused request/response/stream-frame exchanges over the callback WebSocket with per-matcher handler routing, auto-continuing on handler error/panic. Concurrency-safe (serialised WS writes + lazy init; Go verified with -race) and reconnect-on-dead-connection. PHP is excluded (no WebSocket support). This completes breakpoint support across seven clients (Java, Node, Python, Ruby, Go, .NET, Rust).
  • Stream frame breakpoints (backend) — per-frame hold/modify/drop/inject/close for all streaming response types: forwarded SSE/HTTP/1.1 chunked, gRPC server-streaming, WebSocket, GraphQL-subscription, and HTTP/3 gRPC. Each frame is intercepted at its hold point, parked in StreamFrameBreakpointRegistry, and resolved over the callback WebSocket. Fully non-blocking (event-loop safe), with backpressure, ordered frame resolution, stream-close eviction, timeout auto-continue, and the shared breakpointMaxHeld cap. Activated when a matching RESPONSE_STREAM breakpoint matcher is registered (zero overhead otherwise).
  • Inbound (client→server) breakpoints for gRPC bidi over HTTP/3 (QUIC) — extends INBOUND_STREAM breakpoints to bidirectional gRPC streaming over HTTP/3, the QUIC analogue of the HTTP/2 gRPC-bidi inbound path (Http3GrpcBidiStreamHandler). Each inbound gRPC DATA frame is parked before decoding and resolved over the callback WebSocket (continue/modify/drop/inject/close); default-off (only when an INBOUND_STREAM matcher matches the stream). Because the QUIC driver copies each frame to byte[] and releases it before handing off, no ByteBuf is held and the QUIC flow-control window is never pinned; per-frame ordering is preserved by dispatching one frame at a time and buffering the rest (bounded by maxRequestBodySize). This completes interactive breakpoints across HTTP/1.1, HTTP/2, and HTTP/3.
  • Dashboard Breakpoints panel (callback-WebSocket client) — the dashboard is a real callback client: it connects to /_mockserver_callback_websocket (the server assigns it a clientId, since a browser WebSocket can't send the registration header) and resolves paused exchanges live over the callback WebSocket — no REST polling. The panel has three tabs: Matchers (register a breakpoint matcher with a method/path matcher + phase checkboxes; list/remove/clear), Live Exchanges (paused requests/responses arrive in real time — Continue / Modify the JSON / Abort), and Live Streams (paused stream frames — Continue / Modify / Drop / Inject / Close; direction badge distinguishes INBOUND from OUTBOUND frames). A connection-state indicator shows the callback-WS status.
  • Request replay from the dashboard — a new PUT /mockserver/replay control-plane endpoint re-issues a previously recorded/proxied request to its original target and returns the upstream response (reuses the existing NettyHttpClient/forward client; 10 MB body-size cap; behind control-plane auth). The dashboard Traffic view gains a Replay button on every selected request that opens a dialog to re-issue the request with one click and inspect the live response. The Java client exposes a typed replay(HttpRequest) method wrapping the endpoint.
  • Inbound bidirectional frame breakpoints (backend) — intercepts client-to-server frames on WebSocket, GraphQL-subscription, and gRPC-bidi connections before MockServer processes them. Each inbound frame is copied to byte[], the original ByteBuf/Http2DataFrame is released immediately (refunding the HTTP/2 flow-control window), and the copy is parked in StreamFrameBreakpointRegistry with direction=INBOUND. Resolved over the callback WebSocket. Fully non-blocking with backpressure (autoRead paused for WebSocket/GraphQL; pull-based ctx.read() withholding for gRPC-bidi), channel-close eviction. Activated when a matching INBOUND_STREAM breakpoint matcher is registered (zero overhead otherwise).
OpenAPI
  • Full OpenAPI 3.1 support — MockServer now fully supports OpenAPI 3.1 specifications, including the three constructs previously documented as partially handled: type as an array (e.g. type: [string, "null"]) now generates correct example values for the primary non-null type; $ref siblings (description alongside $ref) are resolved by the parser; and the webhooks top-level key is parsed and its operations are included when generating expectations, matching requests, and validating responses. No specification changes or version downgrades are required.
Chaos engineering
  • Scheduled multi-stage chaos experiments — a new PUT /mockserver/chaosExperiment endpoint starts an ordered sequence of chaos stages, each applying service-scoped chaos profiles for a configurable duration before automatically advancing to the next stage. Supports looping, status polling via GET /mockserver/chaosExperiment, graceful stop via DELETE /mockserver/chaosExperiment, and integrates with the C1 auto-halt circuit-breaker (an experiment halts if the safety threshold is exceeded mid-stage). Max 50 stages, 24 h per stage, one active experiment at a time.
  • Chaos auto-halt circuit-breaker — when enabled (chaosAutoHaltEnabled=true), MockServer automatically disables all active service-scoped chaos profiles if the number of chaos-injected errors within a sliding window exceeds a configurable threshold, preventing chaos experiments from causing cascading outages. Reflected in the mock_server_chaos_auto_halt_total Prometheus counter and a WARN log event.
  • Dashboard Chaos tab — full HTTP fault-type controls — the HTTP Service Chaos register/edit form now exposes every HttpChaosProfile field: Retry-After header, body truncation fraction, malformed body toggle, slow (dribbled) response chunk size/delay, quota rate-limiting (name/limit/window/error status), degradation ramp, and outage time window — so users can configure the complete fault set without writing JSON.
LLM observability & cost control
  • LLM proxy/forward observability — observability that previously fired only for mocked LLM responses now also covers LLM traffic forwarded/proxied through MockServer. With otelTracesEnabled, MockServer emits a GenAI OpenTelemetry span (provider, model, token usage, finish reason) for forwarded LLM responses, using a new provider sniffer that detects the upstream from the target host (with a path-gated fallback to llmProvider); all forward paths (matched-forward, unmatched proxy-pass, breakpoint-continuation) now also emit the generic request span consistently. The agent-run analysis tools (explain_agent_run, verify_tool_call) accept provider:"AUTO" for provider auto-detection from recorded request paths, and the dashboard Sessions view renders the call graph for proxy-only sessions, grouping unscoped traffic by upstream host. Off by default; fully fail-soft (telemetry never affects the forwarded response).
  • LLM token/cost Prometheus metrics — when llmMetricsEnabled=true (alongside metricsEnabled), three new Prometheus counters track cumulative LLM token usage and estimated cost across all served and forwarded completions: mock_server_llm_input_tokens, mock_server_llm_output_tokens, mock_server_llm_cost_usd, each labeled by provider and model. The forward-path response parse is gated on metrics OR tracing OR budget, so token tracking works without requiring full OTLP tracing. Default off to avoid parsing forwarded response bodies unless asked.
  • LLM cost-budget circuit-breakermockserver.llmCostBudgetUsd sets a cumulative USD ceiling across all LLM completions (mocked + forwarded). When the running cost total exceeds the budget, unmatched LLM proxy forwards are blocked with a 429 response including the cumulative and budget amounts (mocked LLM responses are never blocked). Deterministic and fail-open (a negative, unset, or malformed budget never blocks traffic). Resets on HttpState.reset(). Tracked by the mock_server_llm_cost_budget_tripped Prometheus counter.
  • Per-session token/cost totals in Sessions view — the dashboard Sessions view now displays per-session aggregate token usage (total input/output tokens) and estimated USD cost as chips in each session lane header, computed purely client-side from the already-parsed response bodies.
  • First-class LLM failover/retry scenario builderLlmFailoverBuilder and the mock_llm_failover MCP tool generate an ordered set of expectations that simulate a provider returning failures (e.g. 503, 429) for the first N attempts, then succeeding with a provider-correct httpLlmResponse. Uses Times.exactly(n) on failure expectations so they are consumed in order before falling through to the unlimited success expectation. Consecutive same-status failures are coalesced for efficiency. Point LiteLLM, Envoy AI Gateway, or an SDK's retry config at MockServer and assert failover logic deterministically.
  • Token-based (TPM/TPD) LLM rate-limit simulationLlmChaosProfile now supports token-based quota enforcement via tokenQuotaLimit and tokenQuotaWindowMillis, modelling real provider TPM/TPD limits. Each response's token count (from Usage or estimated from text length) is charged against an independent fixed-window counter in LlmQuotaRegistry; when the cumulative in-window total exceeds the limit, a 429 (token_quota_exceeded) is returned. Both request-count and token quotas can coexist on the same profile.
  • Provider-correct LLM rate-limit response headers — when MockServer returns a rate-limit or quota error on the LLM response path (probabilistic chaos errorStatus or stateful quota 429), it now emits the provider-correct rate-limit HTTP headers that real LLM providers send (OpenAI x-ratelimit-limit-requests/x-ratelimit-remaining-requests/x-ratelimit-reset-requests, Anthropic anthropic-ratelimit-requests-* with RFC 3339 timestamps, Gemini/Bedrock retry-after). Successful responses also carry the headers when a quota is configured, so client SDK retry/backoff logic can be exercised against a mock. Ollama returns no rate-limit headers (local inference). Implemented by the pure helper LlmRateLimitHeaders (org.mockserver.llm).
Mock creation & matching feedback
  • Generalised capture-to-expectation — the dashboard "Capture as Mock" dialog now works for any recorded or proxied request (plain HTTP, gRPC, GraphQL), not just LLM traffic. A three-level matcher precision toggle (Exact / Moderate / Loose) controls how tightly the generated httpRequest matcher binds: from method+path+query+headers+body down to method+path only. Generic captures register via PUT /mockserver/expectation with httpResponse; the existing LLM capture path is unchanged.
  • Create expectation from unmatched request — the "Why Didn't This Match?" mismatch diagnostic dialog now includes a "Create Expectation" button that opens the capture-as-mock dialog pre-filled with the unmatched request, letting users turn a near-miss into a working stub in one click.
  • Client-visible match feedback — new opt-in config property attachMismatchDiagnosticToResponse (default false) attaches closest-match diagnostic info (header x-mockserver-closest-match + JSON body with per-field diffs) to 404 responses for unmatched requests, so test authors can see why their mock didn't match without checking the dashboard or logs.
  • Opt-in realistic OpenAPI example data — new config property generateRealisticExampleValues (default false) makes OpenAPI example generation produce schema/format-aware values via Datafaker (email, UUID, date, date-time, URI, hostname, IPv4/IPv6, byte, password, integers/numbers respecting min/max) instead of static placeholders, with a fixed seed for deterministic output. Existing behaviour is unchanged when the flag is off.
Response templates
  • Templates can be loaded from a filehttpResponseTemplate and httpForwardTemplate accept a new templateFile field (a classpath-or-filesystem path) as an alternative to the inline template, keeping large templates out of the expectation JSON. When both are set the inline template takes precedence. Works with all three engines (Velocity, Mustache, JavaScript).
  • Templated response body files — a static httpResponse whose body is a FILE body can set a templateType of MUSTACHE or VELOCITY, in which case the file contents are rendered as a template against the request before being returned (the status code, headers and content type still come from the static response). This combines externally stored response bodies (issue #​2163) with response templating, as requested in discussion #​2350. JavaScript is not supported for body files (its templates return a full response object rather than text) — use httpResponseTemplate for that.
  • Client-library support for templateFile and templated FILE bodies — the Node, Python, Go, .NET, Ruby and Rust clients gain templateFile on their template models and templateType on FILE response bodies, so the two features above can be driven from each client (the PHP client, which has no template model, gains a fileBody() helper).
Dashboard & UI
  • Editable runtime config in the dashboard — the Configuration dialog now exposes editable controls for devMode, generateRealisticExampleValues, attachMismatchDiagnosticToResponse, validateProxyOpenAPISpec, validateProxyEnforce, chaosAutoHaltEnabled, chaosAutoHaltErrorThreshold, and chaosAutoHaltWindowMillis (booleans as switches, strings and numbers as text/number fields), driven by a declarative descriptor list in configuration.ts. Existing logLevel/detailedMatchFailures/metricsEnabled controls are unchanged; properties not in the descriptor list remain visible read-only.
  • Dashboard Composer — template snippet palette — the Response Template and Forward Template panels now include an "Insert snippet" button that opens a categorised palette of curated template snippets (request echoes, dynamic data, structure patterns). The palette is engine-aware, showing the correct Velocity / Mustache / JavaScript syntax for the selected template engine and including a live preview of each snippet's output.
  • Dashboard Composer — multi-language code preview — the Review step's read-only code preview now generates idiomatic client snippets for Node.js, Python, Go, C#, Ruby and Rust alongside Java, with JSON and curl shown last. Each client-library tab hydrates the same expectation JSON through that client's native facility (Node mockAnyResponse, Python Expectation.from_dict, Go/Rust deserialize-and-Upsert, C# Deserialize<Expectation>, Ruby Expectation.from_hash), so every action type is representable without reimplementing each language's builder API. The Composer also gains a "Load template from file" field on the template panels and a "Body source: from file" option (with an optional template engine) on the static-response panel, surfacing the templateFile and templated-FILE-body features.
  • Dashboard Library view — Import tab — the Library view now opens on an Import tab (alongside Export) that lets users paste, upload, or URL-import specs and collections directly from the dashboard (Expectation JSON, OpenAPI, WSDL, HAR, Postman), wiring to the existing server endpoints without any new backend changes.
  • Dashboard "Get Started" onboarding panel — new users land on a guided first-run view with action cards to import an OpenAPI spec, set up proxy recording, try docker-compose quick-start recipes, and explore the dashboard docs. The view is the default when no expectations or traffic exist; it auto-transitions to the dashboard once data arrives and remains accessible via the nav bar.
  • Dashboard request diffing from the Traffic view — a "Compare" toggle in the Traffic inspector lets you pick two recorded or proxied requests and open the field-level diff inline (reusing the existing PUT /mockserver/diff endpoint and diff dialog), pre-populated with the two selected requests.
  • LLM streaming-physics controls in the Composer — the conversation builder now exposes streaming-physics fields (time-to-first-token, tokens-per-second, jitter) when a turn is marked as streaming, so users can shape the timing of mocked streamed completions without hand-writing the streaming block.
  • LLM structured-output field in the Composer — the conversation builder now has an outputSchema field so a mocked completion can declare a JSON schema for structured/tool-style output.
  • WASM rule body matcher in the Composer — the expectation Composer now offers a wasm body-matcher option with a module-name dropdown sourced from the uploaded WASM modules, so a custom WASM rule can be wired into an expectation from the dashboard (it previously could only be uploaded, not referenced).
  • Chaos auto-halt controls in the Chaos tab — the dashboard Chaos tab now surfaces the auto-halt circuit-breaker inline (arm/disarm switch, error threshold, and sliding-window size) so users can see and adjust the safety cut-off where they configure chaos, rather than only in the Configuration dialog.
CLI & self-contained binary
  • Redesigned command-line interface — a mockserver CLI (built on picocli) with run (default), proxy, openapi, version and help subcommands, per-command --help, short flags (-p/--port, --proxy-to, --openapi, --init, --persist, -l/--log-level) and scheme-aware proxy targets (--proxy-to https://host infers the port). The org.mockserver.cli.Main entry point, all existing flags (-serverPort, -proxyRemotePort, -proxyRemoteHost, -logLevel) and the configuration precedence (command line > system property > environment variable > properties file) remain fully supported. Documented in docs/code/cli.md and the Running MockServer site page.
  • CLI validation-proxy flags--validate-openapi <spec> and --validate-enforce on the run and proxy subcommands let users launch a validating proxy in one command, wiring directly to the existing validateProxyOpenAPISpec / validateProxyEnforce configuration properties.
  • Developer-friendly --dev mode — opt-in --dev CLI flag (or MOCKSERVER_DEV_MODE=true / -Dmockserver.devMode=true) applies laptop-appropriate defaults: maxLogEntries=1000 and maxExpectations=1000, reducing memory usage for local development and test suites. Explicit configuration always overrides dev-mode defaults. Default behaviour (without --dev) is completely unchanged.
  • ui subcommandmockserver ui [-p <port>] starts MockServer (default port 1080) and opens the dashboard (/mockserver/dashboard) in the default browser, printing the URL and degrading gracefully to just the URL on a headless host (server/CI/SSH). To start without opening a browser, use run.
  • -D<key>=<value> CLI property passthroughrun/ui/proxy/openapi accept repeatable -D options (e.g. mockserver run -p 1080 -Dmockserver.metricsEnabled=true), applied as JVM system properties before startup, so the launcher and jar can set any configuration property without a JVM -D before -jar.
  • Clearer CLI errors & help — starting without a resolvable port (no -p/--port, MOCKSERVER_SERVER_PORT, mockserver.serverPort, or properties file) now prints a concise picocli usage plus a one-line actionable error instead of the legacy java -jar … block and an empty configuration dump. Usage text reflects how MockServer was launched (mockserver … from the binary bundle, java -jar … otherwise), and -help/-version now behave the same as --help/--version (top-level overview).
  • Self-contained binary distribution (no JVM, no Docker) — every release now publishes downloadable MockServer bundles (a jlink-trimmed Java runtime + the server + a mockserver launcher) for Linux, macOS and Windows (x86_64 + aarch64) as assets on the GitHub Release, each with a SHA-256. Download, extract, and run bin/mockserver run -p 1080 — no pre-installed JVM or Docker required. Built from one host via scripts/build-binary-bundle.sh / scripts/build-all-bundles.sh.
  • mockserver-node binary launchernpx -p mockserver-node mockserver run -p 1080 downloads the JVM-less binary bundle for the current platform (no Java, no Docker), verifies its SHA-256, caches it per-user, and runs it. Honours MOCKSERVER_BINARY_BASE_URL (mirror), MOCKSERVER_SKIP_BINARY_DOWNLOAD, MOCKSERVER_BINARY_CACHE and NODE_EXTRA_CA_CERTS. Reference implementation of the on-demand-binary pattern for the client libraries.
Client libraries & integrations
  • Multi-language client libraries — hand-written idiomatic clients for the MockServer control plane in Go (mockserver-client-go, pkg.go.dev), .NET (MockServerClient, NuGet), Rust (mockserver-client, crates.io) and PHP (mock-server/mockserver-client, Packagist), covering create-expectation, verify/verifySequence, clear, reset and retrieve. Each ships unit tests plus a skippable integration test.
  • Testcontainers modules — a MockServerContainer for Node, Python, .NET, Go and Rust (under mockserver-testcontainers/) that starts the mockserver/mockserver image, waits on /mockserver/status and exposes the mapped URL.
  • Editor integrations — a VS Code extension (mockserver-vscode: start/stop the Docker container, open the dashboard, expectation snippets) and an initial JetBrains/IntelliJ Platform plugin scaffold (mockserver-jetbrains).
Packaging & distribution channels
  • GHCR image mirror — every release now mirrors the multi-arch images to ghcr.io/mock-server/mockserver (copied from Docker Hub by digest, cosign-signed). Error-isolated: a GHCR failure never affects the Docker Hub / ECR publish.
  • Automated MCP registry publishing — the release pipeline publishes server.json to registry.modelcontextprotocol.io under the DNS-verified com.mock-server/mockserver namespace (non-interactive auth via an ed25519 key in Secrets Manager + an apex TXT record). Soft-fail — never blocks a release.
  • Release pipeline distribution channels — soft-fail release components that publish the new clients, Testcontainers modules and editor extensions (NuGet, crates.io, Packagist, pkg.go.dev, npm, PyPI, VS Code Marketplace / Open VSX, JetBrains Marketplace), with post-release liveness checks.
  • mockserver-bom (Bill of Materials) — a new published artifact consumers can import into their dependencyManagement to pin every MockServer module and every third-party dependency MockServer relies on to a single, mutually consistent version. This makes downstream builds reproducible and satisfies strict version-alignment checks such as the Maven Enforcer dependencyConvergence rule, which previously flagged the differing transitive versions MockServer resolves internally (via its parent POM's dependencyManagement) but did not export to consumers. Usage: import org.mock-server:mockserver-bom with <type>pom</type> and <scope>import</scope>.
Onboarding & guides
  • One-command quick-start recipes — curated docker compose up recipes under examples/docker-compose/ for the most common use cases (mock-from-openapi, record-replay-proxy, validation-proxy, chaos-proxy), each self-contained with a short README and a "Getting started in 60 seconds" path in the repository README.
  • Consolidated "Self-Hosting MockServer" guide — a single task-oriented site page (/mock_server/self_hosting_mockserver.html) that brings together every way to run MockServer yourself with copy-paste commands: Docker and the one-command docker-compose recipes, the mockserver CLI and the JVM-less binary bundle, Helm/Kubernetes, the executable JAR, Testcontainers, initializers/persistence, and bootstrapping from a browser HAR. Linked from the repository README.
  • MockServer UI docs — Traffic compare/diff and full Chaos fault set — the MockServer UI site page (/mock_server/mockserver_ui.html) now documents the Traffic view's "Compare" toggle for diffing two captured requests (PUT /mockserver/diff) and the Chaos tab's complete HTTP service-chaos fault set wired to PUT /mockserver/serviceChaos (error/connection faults, body corruption, slow-response chunking, quota/rate limit, count and time windows, gradual degradation, GraphQL error envelope, and TTL).
Changed
  • CI — the build pipeline now runs unit tests for the new Go, .NET, Rust and PHP libraries, the five Testcontainers modules and the editor extensions (each in its language toolchain Docker image), triggered by changes under their paths.
  • Slimmer mockserver-client-java classpath — the Java client no longer drags the server-only engines (Velocity/Mustache templating, GraalVM JavaScript, WASM/Chicory, DataFaker, protobuf/gRPC transcoding and the Swagger/OpenAPI parser) onto a consumer's classpath when it is the only MockServer artifact depended upon. Those all run inside the server, never in the client JVM, so they are excluded from the client's mockserver-core dependency. mockserver-core's object mapper now registers its Swagger-coupled serializers only when swagger-core is present (see Fixed), so the client serialises OpenAPI expectations as plain spec strings without the parser on its classpath. In-process-server usages (e.g. mockserver-junit-jupitermockserver-netty) are unaffected — the engines still arrive via the server module. Verified by the full 155-test client suite, 718 core serialization/OpenAPI tests, and a runtime check that round-trips expectations with swagger genuinely absent.
Fixed
  • Dashboard rendered a blank page when the server ran on a non-UTF-8 platform (#​2347) — the dashboard's static assets (JS/CSS/HTML) are always written to the wire as UTF-8, but the Content-Length header was computed with the JVM's default charset. On a platform whose default charset is not UTF-8 (e.g. Windows, where the legacy default is windows-1252), any asset containing multi-byte characters got a Content-Length shorter than the actual body, so the browser truncated the bundle and the dashboard showed a white page. A JAR built on macOS (UTF-8) therefore worked there but failed on Windows. Content-Length is now computed from the UTF-8 byte length, matching the bytes sent.
  • Diagnostic match endpoints flooded the dashboard log with spurious unmatched entries — the "Why Didn't This Match?" debug-mismatch path and the explain_unmatched_requests MCP tool re-ran the live request matchers purely to compute field-level diffs, but that match wrote one EXPECTATION_NOT_MATCHED event per expectation into the event log as a side-effect. Those entries had no request correlationId, so the dashboard could not group them, and repeated calls filled the bounded dashboard log window and evicted matched/response/received entries — making the dashboard appear to show only unmatched traffic. Read-only diagnostics now suppress match-result logging (a request-scoped flag on MatchDifference), so they no longer mutate the log they inspect.
  • Dashboard Library → Import format radios mis-aligned — the format radio buttons (Expectation JSON / OpenAPI / WSDL / HAR / Postman) now top-align with their option titles instead of centring on the whole title+description block.
  • Dashboard Composer connection-options row clipping/overlap — in the response "Connection options (advanced)" row the "Content-Length override" field no longer clips its label and the "Close socket" dropdown arrow no longer overlaps the text; the "Suppress Content-Length"/"Suppress Connection" switches now have clear spacing from the override field instead of crowding it.
  • Build-time guard for global-state-mutating tests missing from sequential Surefire phase — added GlobalStateMutationGuardTest that scans all test classes for high-signal static-state mutation patterns (ConfigurationProperties setter calls, System.setProperty/clearProperty, singleton .getInstance().reset()/.clear(), Metrics.resetAdditionalMetricsForTesting, PrometheusRegistry.defaultRegistry) and fails the build if any matched class is not in the sequential phase. Moved 17 test classes that were running in the parallel phase despite mutating global state to sequential (with symmetric exclude/include, validated by ParallelStaticStateGuardTest). This closes the gap where ParallelStaticStateGuardTest only checked list symmetry but could not detect a new stateful test missing from both lists — the root cause of 4 separate CI flake incidents.
  • LLM config-mutating tests flake under parallel SurefireLlmBackendResolverTest, LlmProviderSnifferTest, and ForwardPathGenAiSpansTest mutate JVM-global ConfigurationProperties.llm* statics but were not in the sequential Surefire phase, causing intermittent cross-test contamination under parallel=classes. Moved all three to the sequential phase (symmetric exclude/include lists, validated by ParallelStaticStateGuardTest).
  • Chaos auto-halt unbounded accumulation when threshold is non-positive — when chaosAutoHaltEnabled=true but chaosAutoHaltErrorThreshold was 0 or negative, recordError() appended timestamps to the sliding window without ever evicting them (the early-return skipped eviction but ran after the addLast). The threshold check now runs before recording, so a non-positive threshold is a no-op (no timestamps accumulated, no halt). Also removed dead Sparkline.tsx component (zero production imports) and corrected stale consumer docs that said gRPC-bidi inbound breakpoints were "not yet intercepted (future work)" — they shipped in a8f4bb0e2.
  • Dashboard Chaos/Composer polish + demo Experiments — the Chaos → Experiments stage fields (Error status, Error prob, Latency ms, Drop prob) were widened so their labels are no longer truncated; the Composer "Editing … changes update this expectation." info box now vertically centres its text with the (i) icon; the operating-mode (SPY/SIMULATE/CAPTURE) dropdown tooltip suppresses itself while the menu is open so it no longer overlays the menu items; and the demo-data populate script (npm run demo) now registers a multi-stage looping chaos experiment so the Chaos → Experiments section shows live data out of the box.
  • Dashboard correctness and UX fixes — a batch of dashboard fixes: the action-type / LLM-provider filter chips are now labelled "expectations only" so they no longer look like a no-op on the request and traffic panels; request-panel row numbers are correct while a search filter is active (numbered against the filtered list, not the full list); the "Generate Stub" dialog now shows all returned suggestions instead of silently keeping only the first; panel count chips show the post-filter count (e.g. 2 / 50) when a filter or search is active; clearing server logs no longer blanks the local expectations/recorded lists without refetching them; panel search now matches field values rather than serialised JSON keys (so searching value/id/type no longer matches every row); the ⌘L "clear logs" shortcut now asks for confirmation like the menu action; copy-to-clipboard failures surface a "Copy failed" tooltip instead of failing silently; the dashboard honours a ?secure=true|false query-param override so it can target an HTTPS MockServer when itself served over HTTP; the Traffic "Replay" dialog warns that it makes a real, side-effecting call to the original target (with an extra warning for non-GET methods); and the Drift, Breakpoints and Chaos panels degrade gracefully (an "unavailable on this server" notice) instead of showing a raw error when pointed at an older MockServer that lacks those endpoints. Editing an existing LLM conversation and changing the number of turns no longer leaves a duplicate orphaned scenario on the server — the old turns are now cleared before the replacement is registered, and the action is clearly labelled as a replacement. The dashboard service-chaos form now validates errorStatus (100–599) and errorProbability (0.0–1.0) inline and blocks submission of out-of-range values rather than failing with a server 400.
  • Dashboard adversarial-review correctness fixes (batch 1) — five defensive fixes from a full adversarial review of the dashboard UI: (1) the Breakpoints panel held paused exchanges in an unbounded list that was never cleared on reconnect, so a broad breakpoint matcher (e.g. path .*) could exhaust browser memory — the list is now capped (oldest dropped) and cleared when the callback WebSocket disconnects, since held items reference a clientId the server replaces on reconnect; (2) the SSE parser split only on \n, so real CRLF-terminated streams mishandled the [DONE] sentinel and leaked stray carriage returns into reassembled text — line endings are now normalised first; (3) the Prometheus metrics parser retained non-finite (+Inf/-Inf/NaN) sample values that poisoned chart auto-scaling and numeric formatting (toFixed"Infinity") — non-finite values are now skipped (histogram le="+Inf" is unaffected, as it lives in the label, not the value); (4) the TCP and gRPC service-chaos TTL countdowns decremented against the HTTP poll's timestamp (a different poll loop that kept advancing while those sections were collapsed and their data frozen), making the countdowns drift — each dataset now tracks its own poll timestamp; (5) the Traffic detail pane is wrapped in an error boundary so a parser exception on a malformed captured body shows an inline error instead of unmounting the whole inspector.
  • Dashboard Composer round-trip + validation fixes (batch 2) — editing an existing expectation in the Mocks composer silently lost some body matchers: a GraphQL matcher was read back from the non-existent JSON field graphql instead of query (the actual wire field), so the query was wiped on every edit; and a WASM body matcher had no read-back branch at all, so it fell through to a raw JSON dump. Both now round-trip correctly (covered by a new reader↔writer round-trip test). In addition, the Register button now validates base64 inline for the binary body matcher, the Error action's response bytes, and the Binary response action — malformed base64 is blocked with a clear reason instead of failing as an opaque server 400 (or throwing in the generated Java Base64.getDecoder().decode(...)).
  • Dashboard performance fixes (batch 3) — three rendering/polling efficiency fixes from the adversarial UI review: (1) the Log Messages panel re-ran its grouped-entry text computation for every log group on every ~1/sec WebSocket snapshot because LogGroup was not memoised and received a fresh per-row toggle closure — it's now React.memo-wrapped and the panel passes a single stable toggle callback, so unchanged groups skip the work; (2) all interval-polling views (Metrics, Drift, Chaos, Breakpoints, AsyncAPI) now pause while the browser tab is hidden and resume on return, instead of scraping/parsing in the background indefinitely (with an in-flight guard so returning to the tab can't fork a duplicate poll loop); (3) the Traffic inspector caches each captured request's parsed summary (SSE reassembly + base64 decode) keyed on the item reference, so it no longer re-parses every row on every snapshot and every search keystroke.
  • Dashboard accessibility fixes (batch 4a) — keyboard and screen-reader fixes from the adversarial UI review: the expand/collapse chevrons on log entries, request/expectation rows, log groups, and match-failure ("because") sections are now real focusable controls with aria-label (Expand/Collapse) and aria-expanded, so they are keyboard-operable and announce their state (previously they were unlabelled icons inside mouse-only rows); the AppBar clear/reset button gained an aria-label; the connection-error banner and notification toasts are now role="alert" live regions; and ten Tools-menu dialogs (Clock, Configuration, OIDC, CRUD, AsyncAPI, OpenAPI/WSDL import, Pact, Explain-unmatched, Generate-stub) now expose an accessible name via aria-labelledby.
  • Dashboard destructive-action confirmations + dialog reset (batch 4b) — bulk/irreversible dashboard actions that previously fired on a single click now route through the existing confirmation dialog: clear-all breakpoint matchers (which orphans paused exchanges), clear-all HTTP/TCP/gRPC service chaos, clear drift records, delete a server-filesystem file, and delete a WASM module / clear gRPC descriptors. Per-item Remove on low-stakes lists is unchanged. Separately, several Tools-menu dialogs (AsyncAPI, OIDC, CRUD, File store, and a stale-error clear on Clock/Configuration) now reset their form fields and success/error banners on close, so reopening no longer shows stale pasted content or outcome messages.
  • Dashboard Composer generated-Java formatting (batch 6) — the "Forward with override" action produced badly mis-indented Java in the Composer's Java preview (the inner request() landed at column 0 with its builder calls jammed far to the right) because the override block was indented once when built and again by the outer re-indent pass. It now emits cleanly nested, consistently-indented Java. Added a compile-time exhaustiveness guard to the action-to-Java generator so a future action type can't silently emit undefined.
  • Dashboard text-clipping / truncation fixes (batch 7) — across the dense data views, values that were silently clipped with no way to read the full text now ellipsis-truncate with a tooltip showing the complete value, via a new reusable TruncatedText component. Sites fixed: the Breakpoints panel's stream-frame body (which was double-truncated — cut to 40 chars and CSS-clipped) plus its id / clientId / matcher / stream-id cells (full UUIDs now recoverable), the Sessions request chips / lane headers / token-cost chips, the Drift expected/actual value cells, the Traffic master-list host+path, the Conversation model/predicate chips, and the collapsed log-entry summary. Also added minWidth:0 flex fixes so a long host/FQDN in the service-chaos rows and the filter panel no longer forces controls to wrap.
  • Dashboard Composer feature completeness (batch 8) — the Mocks composer can now author expectation fields that previously could only be set via JSON/the API (and were silently dropped when editing such an expectation in place): a static response delay, reason phrase, and response cookies; a dedicated JSON body matcher with a STRICT / all-matching-fields match type; and a substring toggle for string body matchers. Each is wired through the form, the Java/JSON/curl preview, and the edit-existing round-trip, with the correct server field names. Editing an existing JSON-body expectation stored in the server's default form (a bare JSON object) now correctly comes back as a JSON matcher instead of an exact string.
  • Dashboard responsive form layouts — the dense multi-field forms that previously went ragged and clipped on narrow viewports now reflow cleanly: the HTTP/TCP/gRPC service-chaos register & edit forms, and the Composer's chaos and side-effect panels, lay their fields out in a responsive CSS grid (auto-fit equal columns) instead of fixed-width flex-wrap rows, so columns stay aligned and fields fill the available width at any size. The AppBar's 12-view toggle strip now scrolls horizontally as a unit on narrow windows instead of wrapping mid-group.
  • Dashboard review polish — four UI fixes from a full review pass: the "Diff two requests" dialog now shows the diff result at the top (above the editable request JSON) so it's the most visible thing, and runs the diff automatically when opened from the Traffic inspector's Compare flow (both requests already selected) instead of requiring a second button press; the Mocks composer's Body type dropdown is wider so "String (exact / subString)" is no longer truncated; and the Sessions view now shows a collapsible Conversation transcript per session (reusing the Traffic tab's provider chat-bubble views, rendering the last request in the session which carries the full accumulated message history), with a compact Show Mermaid link beneath it that opens the correlated agent-run call graph on demand.
  • ReDoS in the Ruby client binary launcher (CodeQL rb/polynomial-redos, CWE-1333) — the trailing-slash strip in BinaryLauncher.asset_url used base.sub(%r{/+\z}, ''), whose /+\z sub-expression can restart at every / and backtrack quadratically on a base URL with a long slash run that doesn't end in / (relevant on Ruby < 3.2, which lacks the regex match cache). The base URL is operator-supplied via MOCKSERVER_BINARY_BASE_URL, so real-world exploitability is low. The trailing-slash strip is now done with a single linear non-regex scan (the regex is removed entirely), eliminating the ReDoS surface — an earlier attempt that merely anchored the regex with a negative look-behind (%r{(?<!/)/+\z}) kept the strip linear but did not clear the CodeQL alert. Behaviour is unchanged; added regression tests for interior-slash preservation and a 100k-slash pathological input.
  • Parallel-test isolation for new singleton tests + post-review polish for streaming breakpoints and chaos experiments — moved StreamFrameBreakpointRegistryTest, ChaosExperimentOrchestratorTest, and BreakpointRegistryTest into the sequential Surefire phase (they mutate JVM-global singletons and flaked under parallel=classes); added a default case to the stream-frame decision switch in NettyResponseWriter to prevent unrecognised actions from hanging the stream; moved streamId/reqMethod/reqPath allocation inside the streamBreakpointsActive guard for zero overhead on the default-off path; added lastTerminatedStatus to ChaosExperimentOrchestrator so getStatus() reports completed/stopped/halted_by_auto_halt after an experiment ends; added stream breakpoint and chaos experiment endpoints to the OpenAPI spec; added consumer-facing docs for chaos experiments; fixed the BreakpointsPanel response "Path / Reason" column to show '-' instead of the request path when reasonPhrase is absent.
  • Startup crash when a properties file has entries (#​2338) — MockServer 7.0.0 failed to start with NoClassDefFoundError: Could not initialize class org.mockserver.configuration.ConfigurationProperties (caused by a NullPointerException during static initialisation) whenever a mockserver.properties file — or the Helm chart's app.config.properties — contained any entries. The startup property-dump redaction added in 7.0.0 read its SENSITIVE_SUBSTRINGS set from the PROPERTIES static initialiser but declared it ~3000 lines later in the class, so it was still null when class initialisation ran (a static-init ordering bug). The redaction fields are now initialised before the property file is read, with a regression test that initialises ConfigurationProperties afresh against a populated property file.
  • Downstream dependencyConvergence failures — consuming MockServer (e.g. mockserver-client-java with MockServerContainer) under the Maven Enforcer dependencyConvergence rule failed with multiple version-conflict errors, because MockServer's transitive version pins lived in the parent POM's dependencyManagement, which Maven does not export to consumers. Three changes address this: a new mockserver-bom to import (above); the slimmer client classpath (above); and pruning the stale velocity-engine-core 2.3 that velocity-tools-generic dragged in alongside the 2.4.1 the build already uses (all 21 Velocity engine tests still pass). With the BOM imported, a client-only consumer's convergence errors drop from 17 to 0.
  • Latent undefined ${jetty.version} in the parent POM — three Jetty HTTP-client dependencyManagement entries referenced a jetty.version property that was only ever defined in the examples/java module, so the managed versions were unresolved for any other consumer of the published parent POM. The dead entries were removed from the parent and the examples module now declares its Jetty client versions explicitly.
  • Object mapper Swagger coupling made optionalObjectMapperFactory registered its Swagger/OpenAPI-coupled serializers (the schema serializers and the OpenAPI-derived HttpRequestsPropertiesMatcher serializer) unconditionally, so initialising the object mapper loaded io.swagger.v3.oas.models.* even on a client that never produces those objects. They are now isolated in a SwaggerSerializers helper and registered only when swagger-core is on the classpath, which is what lets mockserver-client-java exclude the Swagger/OpenAPI parser (eliminating the bulk of a client-only consumer's remaining dependencyConvergence conflicts). The single com.github.fge (json-tools) pretty-print call on the client-reachable path was replaced with a small JsonPrettyPrinter, and jackson-datatype-jsr310 — used directly by the object mapper but previously only arriving transitively via the Swagger parser — is now a direct mockserver-core dependency. Server behaviour is unchanged (swagger-core is always present there).
  • Remaining non-Swagger convergence conflicts pruned — with the Swagger parser excluded from the client, three transitive version splits remained for a client-only consumer: slf4j-api (older versions via java-uuid-generator, json-path and com.networknt:json-schema-validator), jackson-annotations (2.21 via the validator's Jackson 3 transitive) and jakarta.xml.bind-api (2.3.3 via xmlunit-core). mockserver-core now excludes those stale transitive edges; in every case it already declares the winning version directly (slf4j-api 2.0.18, jackson-annotations 2.22, jakarta.xml.bind-api 4.0.5), so its own resolved classpath is unchanged (255 XML/JSON-schema/JSON-path core tests still pass). A consumer depending only on mockserver-client-java now passes the Maven Enforcer dependencyConvergence rule with zero errors even without importing the BOM.
Documentation
  • Interactive Breakpoints guide rewritten for the matcher + callback-WebSocket model — the Interactive Breakpoints consumer page now documents the final feature: registering a request matcher with phases, resolving paused request/response/stream-frame exchanges interactively over the callback WebSocket (with the per-frame PausedStreamFrameDTO/StreamFrameDecisionDTO protocol and the X-MockServer-BreakpointId routing), the dashboard Breakpoints panel, the safety rails, and idiomatic examples for all seven supported clients (Java, Node, Python, Ruby, Go, .NET, Rust — PHP is not supported). The OpenAPI spec carries clientId on the matcher endpoints, and docs/code/breakpoints.md was consolidated (TL;DR + flow diagram, WS-callback-only resolution).
  • New consumer guides for the newest features — added three site pages: LLM Response Mocking (/mock_server/llm_response_mocking.html) showing how to mock OpenAI / Anthropic / Gemini / Bedrock / Azure OpenAI / Ollama responses via plain expectations — including conversations, streaming and cost budgets — without needing an AI agent or MCP; Interactive Breakpoints (/mock_server/interactive_breakpoints.html) walking through pausing, inspecting, modifying and resuming requests/responses; and Observability (/mock_server/observability.html) covering Prometheus metrics (including LLM token/cost counters) and OpenTelemetry trace export with W3C context propagation. Each is linked into the site navigation.
  • Consumer doc corrections — corrected the HTTPS & TLS page to state the real default TLS protocols (TLSv1,TLSv1.1,TLSv1.2, not "TLS 1.2 and 1.3"), matching the configuration-properties page; clarified that disableLogging disables all logging (not just system-out) on the Performance page; fixed the Running MockServer meta description ("Grunt", not "Gradle"); noted that the Kubernetes httpGet liveness probe example requires MOCKSERVER_LIVENESS_HTTP_GET_PATH to be set (the path is off by default); reordered Getting Started so the common-path "Next Steps" precede the upgrade notes; and simplified the configuration-property precedence wording. Also corrected the internal docs/code/configuration-reference.md precedence order (properties file beats environment variable) to match the code.
  • Internal docs — added docs/code/chaos.md (chaos experiments: ChaosExperimentOrchestrator, ordered stages, looping, auto-halt integration, safety limits, endpoints); documented PUT /mockserver/replay (request replay) and PUT/GET/DELETE /mockserver/chaosExperiment in docs/code/request-processing.md; updated docs/code/dashboard-ui.md to reflect twelve views (Breakpoints + Get-Started), the Breakpoints panel (request/response/stream phases), the Get-Started onboarding view, Traffic-view Replay and Compare buttons, and the Composer snippet palette; added generateRealisticExampleValues/SampleDataGenerator coverage to docs/code/domain-model.md; added chaos.md and breakpoints.md rows to docs/README.md; added chaos.md and broadened breakpoints row in AGENTS.md.
  • Internal docs corrections — corrected docs/code/breakpoints.md: removed stale "Future work" section (all four items shipped — HTTP/3-gRPC, gRPC-bidi inbound, and both dashboard UI features); added GrpcBidiStreamHandler.handleData and `GrpcBidiRouterHand

Note

PR body was truncated to here.


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Enabled.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate renovate Bot added the dependencies Pull requests that update a dependency file label Jun 15, 2026
@renovate renovate Bot added the dependencies Pull requests that update a dependency file label Jun 15, 2026
@renovate renovate Bot enabled auto-merge (squash) June 15, 2026 23:41
@renovate renovate Bot merged commit 9c45878 into main Jun 16, 2026
24 checks passed
@renovate renovate Bot deleted the renovate/org.mock-server-mockserver-netty-no-dependencies-7.x branch June 16, 2026 10:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant