Skip to content

fix(core): Imposter.uri() reports the admin host, not the host the imposter is bound to - #246

Merged
EtaCassiopeia merged 1 commit into
masterfrom
fix/rift-243-imposter-uri-host
Sep 23, 2026
Merged

EtaCassiopeia merged 1 commit into
masterfrom
fix/rift-243-imposter-uri-host

Conversation

@EtaCassiopeia

Copy link
Copy Markdown
Collaborator

Closes #243

The engine binds an imposter on its own host, defaulting to 0.0.0.0 (IPv4 only), whatever interface the admin API uses (crates/rift-mock-core/src/imposter/manager.rs:836). Imposter.uri() always reported the admin host. So an imposter bound elsewhere was unreachable at its uri(), and so was a default imposter behind an IPv6 admin host. Found by #232's live IT.

Changes

  • RiftImpl records whether the SDK runs the engine itself: spawned and embedded do, connect doesn't. testcontainers goes through connect, so it keeps its gateway resolver.
    • For a connected engine, an imposter's bind host is an address on another machine, so the resolver stays in charge.
    • A user-supplied hostResolver can't be set on spawn or embedded anyway: both build their ConnectOptions internally.
  • Where the host comes from:
    • create reads it from the JSON the SDK posted. The engine's create response doesn't echo it.
    • imposter(port) and imposters() on a local engine read the replayable list. The engine's single-imposter GET never includes host, and neither does the non-replayable list. This was caught in review. The cost is one replayable list per lookup on a local engine. A connected engine is unchanged.
  • ImposterImpl.uri() uses HostAuthority.httpUri(host, port) for a concrete host. Any spelling of the wildcard (0.0.0.0, ::, [::], 0:0:0:0:0:0:0:0) falls back to the resolver, as does an absent host.
  • Docs: Javadoc on Imposter.uri() states the rule. It also says to set ImposterSpec.host("::1") when the admin host is IPv6, since a host-less imposter is IPv4-only.

Tests

  • ImposterUriHostTest (4):
    • a concrete host wins on spawned and embedded engines (IPv4, ::1, [::1], localhost);
    • every wildcard spelling, and an absent host, falls back to the admin host;
    • lookups read the replayable list;
    • an unknown port is empty.
  • RemoteTransportCoverageTest: a connected engine keeps its resolver whatever host the imposter names.
  • Live Ipv6HostIT, new case on a default spawned engine (admin 127.0.0.1) with an imposter on ::1:
    • uri(), imposter(port).uri() and imposters().get(0).uri() all report [::1], and a GET succeeds.
    • With the local-engine flag forced off, the same case fails with 127.0.0.1.
    • The existing spawn and embedded cases still pass. Embedded was run on JDK 25 with the 0.18.0 dylib.
  • ./mvnw verify passes on all modules.
  • The full spawn conformance IT suite passes locally, apart from three tests that need the downloaded corpus and one that asserts the engine version against a local dev binary. CI provides both.

🤖 Generated with Claude Code

The engine binds an imposter on its own host, defaulting to 0.0.0.0
(IPv4 only), whatever interface the admin API uses. uri() always
reported the admin host, so an imposter bound elsewhere, or a default
imposter behind an IPv6 admin host, was not reachable at its uri().

On an engine the SDK runs itself (spawn, embedded) a concrete imposter
host now wins: create reads it from the posted definition, and lookups
read the replayable list, the only shape that carries it. A connected
engine keeps its resolver, since there the host is an address on
another machine; so does any wildcard host.

Closes #243
@EtaCassiopeia
EtaCassiopeia merged commit 5c70505 into master Sep 23, 2026
16 checks passed
@EtaCassiopeia
EtaCassiopeia deleted the fix/rift-243-imposter-uri-host branch September 23, 2026 04:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(core): Imposter.uri() reports the admin host, not the host the imposter is bound to

1 participant