DST (Distributed System Test) lets you describe end-to-end scenarios in YAML and generate strongly-typed Go runners. Each scenario is a sequence of steps; within a step, actor calls run in parallel and the step waits for all calls to finish.
This doc shows how to define a DST spec, generate code, and wire it into E2E tests.
Use the hybrid spec version dst/hybrid/v1alpha1.
Key parts:
interfaces: method signatures your actors must implement.instances: named actor instances used in scenarios.scenarios: ordered steps; each step contains aparallelmap keyed by actor name.
Example (trimmed from pkg/taskcore/e2e/e2e.yaml):
version: dst/hybrid/v1alpha1
package: taskcoree2e
interfaces:
Worker:
methods:
- Claim(ctx context.Context) error
- CompleteLast(ctx context.Context) error
TaskStore:
methods:
- Enqueue(ctx context.Context, task string, priority int32, weight int32, labels []string) error
instances:
worker1: Worker
worker2: Worker
taskStore: TaskStore
scenarios:
- name: strict_priority_and_weighted_groups
description: strict tasks claim by priority; normal grouped claim uses weight order.
steps:
- id: s1
parallel:
taskStore:
- Enqueue(ctx, "S_LOW", 1, 1, []string{})
- Enqueue(ctx, "S_HIGH", 9, 1, []string{})
- id: s2
parallel:
worker1:
- Claim(ctx)
- CompleteLast(ctx)Notes:
stepsare sequential; actors inside eachparallelblock run concurrently.- Calls must match methods defined under
interfaces.
You can embed Go snippets in a step using script. Script steps run sequentially and cannot be combined with parallel in the same step.
The script has access to:
ctx(context)actors(all actor instances)set(name, value)/get(name)for cross-step variablestforrequire.*assertions (e.g.,require.NoError(t, err))
Example:
- id: s3
script: |
taskAId, err := actors.TaskStore.Enqueue(ctx, "A", 1, 1, nil)
require.NoError(t, err)
set("taskAId", taskAId)Add a dst section to anclax.yaml:
# anclax.yaml
# DST generation is built into `anclax gen`.
dst:
- path: pkg/taskcore/e2e/e2e.yaml
out: pkg/taskcore/e2e/gen/taskstore_gen.go
package: taskcoree2eRun:
anclax gengo run ./cmd/dst validate -f pkg/taskcore/e2e/e2e.yaml
go run ./cmd/dst gen -f pkg/taskcore/e2e/e2e.yaml -o pkg/taskcore/e2e/gen/taskstore_gen.go -pkg taskcoree2eThe generated file provides:
- interfaces for each actor (
Worker,TaskStore, ...) Actorsstruct (named fields matchinstanceskeys)- per-scenario runner +
RunAll
Example usage (see pkg/taskcore/e2e/dst_e2e_smoke_test.go):
err := taskcoree2e.RunAll(ctx, func(ctx context.Context) (taskcoree2e.Actors, error) {
return taskcoree2e.Actors{
TaskStore: env.taskStore,
Worker1: env.worker1,
Worker2: env.worker2,
}, nil
})Your actor types should implement the generated interfaces (methods listed in the YAML).
The taskcore E2E tests use the smoke build tag:
go test -tags smoke ./pkg/taskcore/e2e -count=1 -v- Keep step IDs stable (
s1,s2, …) for easier diffs. - Prefer small, focused scenarios to keep failures localized.
- Use
parallelblocks for true concurrency; separate steps for ordered sequences.