Documentation
¶
Overview ¶
DST (Deterministic Simulation Testing) provides a game-logic-agnostic fuzzer and structural state checker for Cardinal. It generates random commands by introspecting registered command types (via reflection), injects engine operations (tick, restart, snapshot/restore) with randomized weights, and validates structural ECS invariants after every tick. Game logic correctness is irrelevant — only engine correctness matters.
Usage from a game shard's test directory:
func TestDST(t *testing.T) {
cardinal.RunDST(t, func(w *cardinal.World) {
cardinal.RegisterSystem(w, system.MySystem)
// ... register all systems
})
}
E2E test helper with real (in-memory) NATS. Similar to the DST harness in dst.go, but runs the full World.run loop (ticking, snapshotting, restoring) while a separate goroutine sends randomized commands through real NATS subjects.
Index ¶
- Constants
- func RegisterSystem[T any](world *World, system func(*T), opts ...SystemOption)
- func RunDST(t *testing.T, setup DSTSetupFunc)
- func RunE2E(t *testing.T, setup E2ESetupFunc)
- type BaseSystemState
- type Command
- type CommandContext
- type Contains
- type DSTSetupFunc
- type E2ESetupFunc
- type EntityID
- type Event
- type Exact
- type OtherWorld
- type Ref
- type SystemHook
- type SystemOption
- type Tick
- type WithCommand
- type WithEvent
- type WithSystemEventEmitter
- type WithSystemEventReceiver
- type World
- type WorldOptions
Constants ¶
const ( // PreUpdate runs before the main update. PreUpdate = ecs.PreUpdate // Update runs during the main update phase. Update = ecs.Update // PostUpdate runs after the main update. PostUpdate = ecs.PostUpdate // Init runs once during world initialization. Init = ecs.Init )
const MinEpochFrequency = 10
Variables ¶
This section is empty.
Functions ¶
func RegisterSystem ¶
func RegisterSystem[T any](world *World, system func(*T), opts ...SystemOption)
func RunDST ¶ added in v0.10.2
func RunDST(t *testing.T, setup DSTSetupFunc)
RunDST executes a deterministic simulation test. The setup function registers game-specific systems; the harness handles everything else: randomized engine config, command generation, ticking, restart/restore operations, and structural invariant checking.
The number of ticks defaults to 1000 and can be overridden with -dst.ticks:
go test ./pkg/cardinal/... -dst.ticks=5000
func RunE2E ¶ added in v0.10.2
func RunE2E(t *testing.T, setup E2ESetupFunc)
RunE2E executes an end-to-end test. The setup function creates the world the same way production does; the harness transparently injects the in-memory test NATS URL. The harness starts the world's run loop in a background goroutine and sends randomized commands over NATS from the test goroutine.
E2E tests are skipped by default. Use the -e2e.run flag to enable them:
go test ./pkg/cardinal/... -e2e.run
The run duration defaults to 30s and can be overridden with -e2e.duration:
go test ./pkg/cardinal/... -e2e.run -e2e.duration=2m
Types ¶
type BaseSystemState ¶
type BaseSystemState struct {
// contains filtered or unexported fields
}
func (*BaseSystemState) Logger ¶
func (b *BaseSystemState) Logger() *zerolog.Logger
TODO: pass init args (similar to boot info) to get system name in logger. Logger returns the logger for the world.
func (*BaseSystemState) Tick ¶
func (b *BaseSystemState) Tick() uint64
Tick returns the current tick of the world.
func (*BaseSystemState) Timestamp ¶
func (b *BaseSystemState) Timestamp() time.Time
Timestamp returns the current timestamp of the world.
type CommandContext ¶ added in v0.10.0
type DSTSetupFunc ¶ added in v0.10.2
type DSTSetupFunc func(world *World)
DSTSetupFunc registers systems, components, and commands on a World. It is called once during fixture creation, before the first tick.
type E2ESetupFunc ¶ added in v0.10.2
type E2ESetupFunc func() *World
E2ESetupFunc builds and returns the world used by the E2E harness. The harness injects a test NATS URL via environment variables before invoking setup.
type OtherWorld ¶
OtherWorld is a type that represents the address of an external service.
func (OtherWorld) SendCommand ¶ added in v0.10.0
func (o OtherWorld) SendCommand(state *BaseSystemState, cmd command.Payload)
SendCommand sends a command to an external service.
Example:
import external "another-game-shard/system"
// Define a shard address of one of your game shards. const MatchmakingService ecs.ServiceAddress = "world.argus.rampage.matchmaking"
func GameSystem(state *GameSystem) error {
MatchmakingService.Send(state, &external.EndGameCommand{
Winner: "Team 1",
})
}
type SystemHook ¶ added in v0.10.0
type SystemHook = ecs.SystemHook
SystemHook defines when a system should be executed in the update cycle.
type SystemOption ¶ added in v0.10.0
type SystemOption func(*systemConfig)
SystemOption is a function that configures a SystemConfig.
func WithHook ¶
func WithHook(hook SystemHook) SystemOption
WithHook returns an option to set the system hook.
type WithCommand ¶
type WithCommand[T Command] struct { // contains filtered or unexported fields }
func (*WithCommand[T]) Iter ¶ added in v0.10.0
func (c *WithCommand[T]) Iter() iter.Seq[CommandContext[T]]
type WithSystemEventEmitter ¶
type WithSystemEventEmitter[T ecs.SystemEvent] = ecs.WithSystemEventEmitter[T]
type WithSystemEventReceiver ¶
type WithSystemEventReceiver[T ecs.SystemEvent] = ecs.WithSystemEventReceiver[T]
type World ¶
type World struct {
// contains filtered or unexported fields
}
World represents your game world and serves as the main entry point for Cardinal.
func NewWorld ¶
func NewWorld(opts WorldOptions) (*World, error)
NewWorld creates a new game world with the specified configuration.
type WorldOptions ¶
type WorldOptions struct {
Region string // Region the shard is deployed to
Organization string // The organization that owns this world
Project string // Name of the project within the organization
ShardID string // Unique ID for of world's instance
TickRate float64 // Number of ticks per second
SnapshotStorageType snapshot.StorageType // Snapshot storage type
SnapshotRate uint32 // Number of ticks per snapshot
Debug *bool // Enable debug server
NATSConfig *micro.NATSConfig // Optional NATS config override (nil = use env/defaults)
}