Package-level declarations

Types

Link copied to clipboard
class Answer(val status: Int, val headers: Map<String, List<String>>, val text: String)

A server's answer: its status, headers and body, as text and, when it is JSON, as body; when it is an RFC 9457 problem, as problem too, and when it answers a command, as its result.

Link copied to clipboard

A fake of the peer service of context (fakePeer): it records each call it takes (calls), decoded as the peer's node would decode it, and answers it as answer says, a success by default. It refuses a request that names no service (Wow-Service) or no root command (Wow-Call) with 403 wow.auth.forbidden, as a peer's internal port does, and records none. Closing it stops its port.

Link copied to clipboard
enum class LocalPorts : Enum<LocalPorts>

The ports of the services of a WowLocal: each its own fixed ones, or every one a port the system chooses.

Link copied to clipboard

How a FakePeer answers a call (FakePeer.answer): it succeeded (the default), was rejected, or timedOut. A problem is the one the peer's own routes answer: its status from the peer's contract (a code its error tables declare takes their status, an undeclared domain rejection 422), its title, its result and what a retry may do.

Link copied to clipboard
class PeerCall

A call a FakePeer took: the command it sends, decoded to its class when the class path has it (else its JSON), by its commandType (context.aggregate.Command), the aggregateId it names (its route's, or its body's id property; null for a creation that names none), the service that sent it (Wow-Service), its requestId, and the root command it acts for (call, Wow-Call): its tenant, scope and operator.

Link copied to clipboard
class WowHttp(val base: URI, timeout: Duration = Duration.ofSeconds(30)) : AutoCloseable

A JSON client of a server's port at base, over HTTP/1.1: each call answers with the status, headers and body the server gave, waiting at most timeout for it.

Link copied to clipboard

Wow services started in this JVM (wowLocal): its servers by their names, in the order they started, and their publicPorts. Closing it closes them, the last started first.

Link copied to clipboard
class WowServer(val context: ConfigurableApplicationContext) : AutoCloseable

A Wow application a test started (wowServer): its context, the publicPort and internalPort it bound, and clients of them. A test drives the service as its users do, with the typed clients of the public port: commands sends command objects and queries reads states, both as a caller, through the wow-client a peer calls with. The JSON clients (http, internal) are for what the wire itself must show: a route's shape, a header, a problem's members (Answer.problem). Closing it closes the application and every client.

Properties

Link copied to clipboard

How long eventually sleeps between two polls by default.

Link copied to clipboard

How long eventually polls by default: a saga across a few commands on a loaded build machine, and then some.

Link copied to clipboard

The properties a test server starts with: its public and internal ports on the loopback interface, each at a port the system chooses, so no other process takes a port picked before it binds it, and the timeouts a node waits on at its close short, as a test's few commands need.

Functions

Link copied to clipboard
inline fun eventually(what: String, timeout: Duration = EVENTUALLY_TIMEOUT, poll: Duration = EVENTUALLY_POLL, noinline detail: () -> String? = null, condition: () -> Boolean)

Polls condition until it holds, every poll, for at most timeout, and fails saying what was not reached, with detail then, when one is given (the services' output, the state seen last), and the last failure of condition as its cause: a condition that throws, an assertion among them, has not held yet.

Link copied to clipboard
fun fakePeer(context: String): FakePeer

Starts a fake of the peer service that serves context, on a port of the loopback interface the system chooses: the call routes of its internal port, which a saga's synchronous call and a service's wow-client send its commands to. Its commands and their routes are the ones its api module's contract on the class path declares, as the caller finds them. Give it to the server under test (wowServer's peers), which then calls it at its FakePeer.url.

Link copied to clipboard
fun runWowLocal(ports: LocalPorts = LocalPorts.of(System.getProperty(LocalPorts.PROPERTY)), partitions: Int = WowLocal.DEFAULT_PARTITIONS, services: WowLocal.Builder.() -> Unit)

Runs services as wowLocal starts them, from a main function: it prints WowLocal.readyLine once every service listens, and stops them when the JVM exits. With the system property wow-local.exit-on-stdin-eof set to true, the JVM exits when its standard input closes, so a process that started it, a test of a web front end say, never leaves it running. A service that fails to start makes it print why and exit with status 1.

Link copied to clipboard
fun wowLocal(ports: LocalPorts = LocalPorts.of(System.getProperty(LocalPorts.PROPERTY)), partitions: Int = WowLocal.DEFAULT_PARTITIONS, services: WowLocal.Builder.() -> Unit): WowLocal

Starts several Wow services in this JVM, on the memory backend and without a broker, for a local run: development, a front end against its back ends, a demo. Each service serves its own contexts alone (wow.contexts.include) in a development profile (dev), so a request names its caller in the development identity headers, and they share one InMemoryTopics of partitions partitions, their logs' too: each one's sagas send other contexts' commands through it, its published streams are written to it, and it executes the commands sent to its own command topics, so a flow across the services runs as it does on Kafka.

Link copied to clipboard
inline fun <reified App : Any> wowServer(vararg profiles: String, properties: Map<String, Any?> = emptyMap(), sources: List<Class<*>> = emptyList(), clock: Clock? = null, topics: InMemoryTopics? = null, peers: List<FakePeer> = emptyList()): WowServer

Starts the Wow application App for a test, with profiles active, as wowServer of its class does.

fun wowServer(application: Class<*>, profiles: List<String> = emptyList(), properties: Map<String, Any?> = emptyMap(), sources: List<Class<*>> = emptyList(), clock: Clock? = null, topics: InMemoryTopics? = null, peers: List<FakePeer> = emptyList()): WowServer

Starts the Wow application of application and sources for a test, with profiles active, and gives it back running: both its ports bound on the loopback interface, at ports the system chooses, and its drain, stop and wait timeouts short (TEST_PROPERTIES), so the test reaches it at once and closing it (WowServer.close) is quick. properties add to them and override them, as command-line arguments, over the application's own configuration; a null value leaves a key out. A clock is the node's: every wall time it and its stores read, so a test fixes or moves time in one place.