Skip to content

Missing DurableStateBehaviorTestKit #3236

Description

@He-Pin

Motivation

EventSourcedBehaviorTestKit provides a high-level, async actor-based testing API for EventSourcedBehavior with CommandResult types, built-in serialization verification, and restart testing support. No equivalent DurableStateBehaviorTestKit exists for DurableStateBehavior, creating a significant testing API asymmetry. Users of DurableStateBehavior cannot perform the same style of high-level behavioral testing.

The internal infrastructure for the testkit is already in place (internal signals GetPersistenceId and GetState), but the public API was never implemented. The existing PersistenceProbeBehavior.fromDurableState is a different tool—it uses synchronous BehaviorTestKit (no real actors), not the async actor-based approach of EventSourcedBehaviorTestKit.

Current behavior

  • No DurableStateBehaviorTestKit class exists anywhere in the codebase (neither javadsl nor scaladsl).
  • Internal API hooks in DurableStateBehaviorImpl (GetPersistenceId, GetState) are defined but never consumed by any testkit.
  • Stale Scaladoc comments reference the non-existent DurableStateBehaviorTestKit at three locations.

Expected behavior

A DurableStateBehaviorTestKit should exist in persistence-testkit, mirroring the EventSourcedBehaviorTestKit API (both javadsl and scaladsl), providing:

  • runCommand methods returning typed CommandResult (with state and optional reply)
  • Built-in serialization verification for commands and state
  • Restart behavior testing
  • getState and persistence ID retrieval using the existing internal signals

The stale comments should also be updated to accurately reflect implementation status.

Code evidence

Stale comment references:

  • persistence-typed/src/main/scala/org/apache/pekko/persistence/typed/state/internal/DurableStateBehaviorImpl.scala:46:
    /**
     * Used by DurableStateBehaviorTestKit to retrieve the `persistenceId`.
     */
    final case class GetPersistenceId(replyTo: ActorRef[PersistenceId]) extends Signal
  • persistence-typed/src/main/scala/org/apache/pekko/persistence/typed/state/internal/DurableStateBehaviorImpl.scala:51:
    /**
     * Used by DurableStateBehaviorTestKit to retrieve the state.
     */
    final case class GetState[State](replyTo: ActorRef[State]) extends InternalProtocol
  • persistence-typed/src/main/scala/org/apache/pekko/persistence/typed/state/internal/Running.scala:177:
    // Used by DurableStateBehaviorTestKit to retrieve the state.
    def onGetState(get: GetState[S]): Behavior[InternalProtocol] = { ... }

Existing counterpart for EventSourcedBehavior:

  • persistence-testkit/src/main/scala/org/apache/pekko/persistence/testkit/scaladsl/EventSourcedBehaviorTestKit.scala
  • persistence-testkit/src/main/scala/org/apache/pekko/persistence/testkit/javadsl/EventSourcedBehaviorTestKit.scala
  • persistence-testkit/src/main/scala/org/apache/pekko/persistence/testkit/internal/EventSourcedBehaviorTestKitImpl.scala

No equivalent for DurableStateBehavior:
No DurableStateBehaviorTestKit.scala or DurableStateBehaviorTestKitImpl.scala exists.

Reproduction

Attempt to write a test for a DurableStateBehavior using the same pattern as EventSourcedBehaviorTestKit:

// This works for EventSourcedBehavior:
val testKit = EventSourcedBehaviorTestKit[Command, Event, State](system, behavior)
val result = testKit.runCommand(MyCommand)
result.event shouldBe MyEvent
result.state shouldBe expectedState

// No equivalent exists for DurableStateBehavior:
// val testKit = DurableStateBehaviorTestKit[Command, State](system, behavior) // does not exist

Impact

  • Module: pekko-persistence-testkit
  • Affected users: All users of DurableStateBehavior who need high-level behavioral testing (async, real actors, serialization checks).
  • Workaround: Users must either use the lower-level PersistenceProbeBehavior.fromDurableState (synchronous, no real actors) or build ad-hoc test infrastructure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions