AggregateSpec

Constructors

Link copied to clipboard
constructor(model: AggregateModel<S>, ref: AggregateRef, start: Instant = DEFAULT_START)

Properties

Link copied to clipboard

The time the specification is at.

Link copied to clipboard

Functions

Link copied to clipboard
fun advanceTime(duration: Duration, expect: Expectations<S>.() -> Unit? = null)

Moves the time on by duration, then sends the aggregate each command it scheduled for itself that is due by then, earliest first, as the runtime would. Without expect it never fails, whether or not a command was due. expect checks the outcome of the last one sent, and fails when none was due: use expectNothingDue to show that none is, after a schedule was cancelled, say.

Link copied to clipboard
fun asCaller(caller: Caller, block: AggregateSpec<S>.() -> Unit)

Runs block with caller sending the commands that name no caller of their own, as aggregateSpec's caller does for the whole specification: a scenario of several callers, the owner then another user, say.

Link copied to clipboard

Moves the time on by within, and fails when a command the aggregate scheduled for itself is due by then: a cancelled schedule, say, does not fire. Nothing is sent.

Link copied to clipboard
fun fork(name: String = "", from: String? = null, block: AggregateSpec<S>.() -> Unit)

Runs block on a copy of the aggregate as it is at the ref from (ref), or now when from is null, so that several scenarios share a prefix: what block does stays in the fork, and the specification goes on from where it was. A failure in the fork names it (name, or from).

fun fork(name: String = "", from: String? = null, model: AggregateModel<S>, block: AggregateSpec<S>.() -> Unit)

Runs block on a copy of the aggregate as fork does, with model deciding from there on: the same aggregate built with other services, as a domain module's generated factory builds it (orderModel(name, OutOfStockInventory)), so that one branch of a scenario sees a service answer otherwise. The copy keeps the log, which model reads as its own, so model is of the same aggregate type; the services the commands before the fork called are not called again.

Link copied to clipboard
fun given(vararg events: Any, scope: Scope? = null, operator: Operator? = null, commitTime: Instant = now)

Commits events as one stream, as if an earlier command had produced them, leaving the aggregate in scope (by default the scope it already has, at first none, or the owner its id is of an aggregate whose id is its owner's). The stream is committed at commitTime, the specification's time by default, in the name of operator, none by default: the commit a sourcing function reads (me.ahoo.wow.api.read.EventStream).

Link copied to clipboard
fun givenCommands(vararg commands: Any, scope: Scope? = null, headers: Map<String, String> = emptyMap(), operator: Operator? = null, caller: Caller? = null)

Sends commands in order, as whenCommand sends one (by caller, in scope, with headers, in the name of operator), as the setup of a scenario: each commits, or changes nothing. A command that is rejected, or whose decide function throws, fails the specification, naming the command and what it was.

Link copied to clipboard
fun givenRecords(vararg records: EventRecord, scope: Scope? = null, operator: Operator? = null, commitTime: Instant = now)

Commits records as one stream, as the log holds them, leaving the aggregate in scope, in the name of operator at commitTime as given does: a history the model's classes can no longer write, such as an event the aggregate retired, whose record the kernel skips, or a record of an older revision, read through its upgrades.

Link copied to clipboard
fun givenReservation(namespace: String, key: String, owner: AggregateRef = model.type.ref(ref.tenantId, ANOTHER_AGGREGATE), tenancy: ReservationTenancy = ReservationTenancy.TENANT)

Gives key in namespace, reserved with tenancy, to owner, another aggregate of this type (another-aggregate by default: a key is unique within its aggregate type), as a command of it that committed would: a command reserving it is then refused, and holds says the aggregate does not hold it.

Link copied to clipboard
fun givenState(state: S, version: Int = 1, scope: Scope = unscoped)

Starts the aggregate in state at version, as if its first version streams had left it there (9.x's givenState), in scope: the commands after it are decided on that state, and their streams continue from version; an aggregate whose id is its owner's is given in that owner's scope by default. It is the first step of a specification, before any event or command. The state is copied through its JSON, as a snapshot would be, so changing state afterwards changes nothing.

fun givenState(version: Int = 1, scope: Scope = unscoped, build: S.() -> Unit)

Starts the aggregate in its initial state changed by build, at version, as givenState does.

Link copied to clipboard
fun holds(namespace: String, key: String, tenancy: ReservationTenancy = ReservationTenancy.TENANT): Boolean

Whether the aggregate holds key in namespace, reserved with tenancy: reserved by a command that committed and not released since (me.ahoo.wow.api.decide.DecideScope.release), as a rename releases its old key.

Link copied to clipboard
fun ref(name: String)

Marks the current point as name: a later fork from it starts the aggregate where it is now, whatever the specification does in between. The mark is a copy of the aggregate, its log, timers, reservations, ids and time.

Link copied to clipboard
fun timer(key: String): Timer?

The timers the aggregate keeps, in whatever status, by key.

Link copied to clipboard
fun whenCommand(command: Any, requestId: String = "request-", expectedVersion: Int? = null, scope: Scope? = null, headers: Map<String, String> = emptyMap(), operator: Operator? = null, caller: Caller? = null, expect: Expectations<S>.() -> Unit)

Sends command through the kernel and checks its outcome in expect. An exception the decide function throws fails the specification, unless expect checks it with Expectations.expectError.