Fixed message channels#3440
Merged
Merged
Conversation
Introduces named fixed channels that abstract an underlying messaging technology via a channel provider/driver model. A stub action can now target a fixed channel using sendMessage().onChannel(providerName, channelName), which is recorded in the message journal for verification. Includes an in-memory built-in driver, admin API endpoints for registering providers (POST /channel-providers) and creating channels (POST /channels), and corresponding WireMock client DSL (channelProvider(), fixedChannel(), registerChannelProvider(), createFixedChannel()). Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…pe.FIXED Stubs can now be triggered by messages arriving on a fixed channel using triggeredByMessageOnChannel(providerName, channelName), with an optional body pattern via withBody(). The new FixedChannelMessageTrigger stores a MessagePattern rather than a raw ContentPattern. Sending messages to fixed channels is unified under the existing Admin.sendChannelMessage overload and POST /channels/send endpoint, using the new ChannelType.FIXED value and extended SendChannelMessageRequest (providerName/channelName fields). The separate sendMessageToFixedChannel method and SendFixedChannelMessageTask/Request are removed. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
… model ChannelProvider registrations are now backed by ChannelProviderStore (InMemoryChannelProviderStore), wired through Stores/DefaultStores. Fixed channels are unified with the existing MessageChannel model rather than kept in a separate store: FixedMessageChannel implements MessageChannel and lives in the existing MessageChannelStore alongside WebSocket channels. MessageChannels.findFixed(providerName, channelName) provides lookup. ChannelProviderRegistry no longer holds channel state or a send() method; createChannel() now returns a FixedMessageChannel which WireMockApp adds to MessageChannels. HttpStubServeEventListener drops its registry dependency and resolves fixed channel sends via messageChannels.findFixed() instead. InMemoryStringKeyedStore<T> is a shared base for string-keyed ConcurrentHashMap stores; FixedChannelStore and InMemoryFixedChannelStore are removed. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
… drivers CustomChannelProviderDriver extends both ChannelProviderDriver and Extension, letting implementors register a custom driver via WireMockConfiguration.extensions(). WireMockApp picks up all CustomChannelProviderDriver instances at startup and registers them with ChannelProviderRegistry. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Restructured WireMockApp.sendChannelMessage to perform stub matching before recording the journal event, so wasMatched correctly reflects whether a stub was found. Also sets channelType=FIXED on the event. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
receivedOnFixedChannel now has an overload that accepts a stub mapping. WireMockApp.sendChannelMessage passes the first matching stub when recording the journal event, consistent with the WebSocket path. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
MessageChannels.add() throws ConflictException when a FixedMessageChannel with the same providerName/channelName already exists, surfacing as a 409 to the caller rather than silently creating a duplicate entry. Test setup moved to @BeforeAll so provider and channel are registered once per suite run rather than before every test. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
MessageChannels.requireFixed() throws NotFoundException when the target channel doesn't exist, returning HTTP 404 rather than doing nothing. Both WireMockApp.sendChannelMessage and HttpStubServeEventListener now use requireFixed() so missing channels are a hard failure in both paths. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…tion ChannelProviderRegistry now throws InvalidInputException (HTTP 400) for both unknown driver type and unregistered provider name, giving callers a clear client error instead of a server 500. Provider re-registration with the same name is idempotent (overwrites) and is now explicitly documented by test. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…atch Fixed channel message triggers now behave consistently with HTTP stubs: only the first (highest-priority) matching stub fires. Previously all matching stubs were executed, which was inconsistent and confusing. findMatchingFixedChannelStubs renamed to findMatchingFixedChannelStub and returns Optional<MessageStubMapping> to make the single-match semantics explicit. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…hierarchy; createFixedChannel returns LoggedFixedChannel FixedChannel (DTO) → FixedChannelDefinition; FixedMessageChannel (live channel) → FixedChannel, following the Definition/Instance pattern used elsewhere in WireMock. LoggedMessageChannel is now a sealed interface with two concrete types: - LoggedFixedChannel: carries providerName, channelName - LoggedRequestInitiatedChannel: carries initiatingRequest Both have Builder and transform(), and use @JsonTypeInfo with the existing "type" field as the polymorphic discriminator so round-trip JSON works cleanly. Admin.createFixedChannel now returns LoggedFixedChannel (via LoggedMessageChannel), which CreateFixedChannelTask returns as HTTP 201. WireMock.createFixedChannel returns the channel UUID. FixedMessageChannelAcceptanceTest stores the UUID and asserts channelType/channelId on the resulting journal event. MessageServeEvent factory methods for fixed channels now accept MessageChannel so channelId is populated from the live channel's UUID. NonEmptyFieldsSerializer strips empty containers, false booleans, and -1 integers — applied to LoggedRequestInitiatedChannel.getInitiatingRequest() so the initiating request JSON omits default/sentinel fields without modifying LoggedRequest. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…l in MessageServeEvent
The three flat fields are replaced by a single nested LoggedMessageChannel,
using the sealed polymorphic hierarchy. JSON changes from:
"channelType": "websocket", "channelId": "...", "channelRequest": {...}
to:
"channel": { "type": "websocket", "id": "...", "open": true, ... }
Derived @JsonIgnore getters for getChannelType(), getChannelId(), and
getChannelRequest() preserve backward-compat for all Java callers.
Factory methods simplified: ChannelType+UUID+Request overloads removed;
sentToFixedChannel and receivedOnFixedChannel removed — all callers now
use the unified sent/receivedMatched/receivedUnmatched factories which
each have two overloads (MessageChannel and LoggedMessageChannel).
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
GetMessageChannelTask serves GET /channels/{id}, returning the channel
as a LoggedMessageChannel JSON payload (200) or 404 if not found.
Admin.getMessageChannel(UUID) returns SingleMessageChannelResult,
consistent with the wrapper pattern used by other single-resource
methods on this interface (getMessageServeEvent, getStubMapping, etc.).
HttpAdminClient catches ClientError (from the 404) and returns an
empty result rather than propagating.
AdminApiTest.getChannelByIdReturnsCorrectPayload asserts the full JSON
payload of the response.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Closes a request-initiated channel before removal so the WebSocket connection is properly terminated. Also exposes removeMessageChannel on WireMock, WireMockServer, HttpAdminClient and DslWrapper. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add support for fixed message channels.
These are intended to allow integration with message brokers/queues etc. via a new extension point.
There is also an in-memory type included.