FlakyLifecycleSeam

class FlakyLifecycleSeam(delegate: Seam, scope: CoroutineScope) : Seam

A Seam wrapper that owns its own state and gates the contract on it, enabling lifecycle-flap scenarios in tests.

Unlike FaultySeam (which delegates state and injects per-frame faults), this wrapper can simulate a transport link that drops and recovers: Woven → Weaving → Woven (transient reconnect) or escalates to Torn (permanent failure).

Behaviour while SeamState.Weaving

  • peers collapses to {selfId} — this peer is momentarily alone.

  • broadcast is the contract's defined no-op (no other peers; returns immediately without throwing).

  • sendTo throws PeerNotConnected for any absent peer (as always).

  • Inbound frames from the delegate are dropped while weaving — they are not buffered and will not appear on incoming after recover.

Behaviour on recover

state → Woven, peers refills from the delegate, inbound delivery resumes.

Behaviour on tear

state → Torn(reason) (terminal), incoming completes, subsequent sends throw IllegalStateException.

Composition

Lifecycle wrapper outer, frame-fault inner: FlakyLifecycleSeam(FaultySeam(realSeam), scope). The lifecycle wrapper gates the consumer-facing contract on its own state; the inner FaultySeam applies frame-level faults to whatever flows while SeamState.Woven.

Determinism guarantee: all timing goes through kotlinx.coroutines.delay so kotlinx.coroutines.test.runTest controls virtual time. FlapSchedule jitter is seeded — same seed, same flap pattern.

Constructors

Link copied to clipboard
constructor(delegate: Seam, scope: CoroutineScope)

Properties

Link copied to clipboard
open val capability: StateFlow<TransportCapability>
Link copied to clipboard
open override val incoming: Flow<Swatch>

Frames from delegate.incoming, filtered by this seam's lifecycle state.

Link copied to clipboard
open val maxPayloadBytes: Int?
Link copied to clipboard
open override val peers: StateFlow<Set<PeerId>>
Link copied to clipboard
open val plies: StateFlow<Map<PlyId, SeamState>>
Link copied to clipboard
open override val selfId: PeerId
Link copied to clipboard
open override val state: StateFlow<SeamState>

Functions

Link copied to clipboard
suspend fun blip(weavingFor: Duration)

Suspend through weavingFor in SeamState.Weaving then return to SeamState.Woven — one atomic blip.

Link copied to clipboard
open suspend override fun broadcast(payload: ByteArray)
Link copied to clipboard
open suspend override fun close(reason: CloseReason)
Link copied to clipboard
fun drive(schedule: FlapSchedule): Job

Launch a FlapSchedule loop in scope and return the running Job.

Link copied to clipboard

Transition Woven → Weaving. Held until recover or tear is called.

Link copied to clipboard
suspend fun flapThenTear(flaps: Int, weavingFor: Duration, reason: CloseReason = CloseReason.Unreachable)

Perform flaps blips (each SeamState.Weaving for weavingFor), then tear with reason. After this call completes the seam is terminal.

Link copied to clipboard
fun recover()

Transition Weaving → Woven. Inbound delivery and peers resume from the delegate.

Link copied to clipboard
open suspend override fun sendTo(peer: PeerId, payload: ByteArray)
Link copied to clipboard
fun tear(reason: CloseReason = CloseReason.Unreachable)

Transition to SeamState.Torn (terminal). incoming completes; subsequent sends throw IllegalStateException.