Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions chasm/chasmtest/test_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ type (
// allExecutions maps (namespaceID, businessID, runID) to any run, for lookups by specific RunID.
allExecutions map[runKey]*execution
notifier *executionNotifier
// decorateBackend, if set, is applied to each execution's MockNodeBackend at
// creation time, before the tree is built. It lets callers supply handlers the
// default backend leaves unset (e.g. HandleGetNamespaceEntry).
decorateBackend func(*chasm.MockNodeBackend)
}

execution struct {
Expand Down Expand Up @@ -72,6 +76,17 @@ func WithTimeSource(ts clock.TimeSource) EngineOption {
}
}

// WithNodeBackendDecorator registers a function applied to every execution's
// [chasm.MockNodeBackend] at creation time, before its tree is built. Use it to
// supply backend handlers the default leaves unset — most commonly
// HandleGetNamespaceEntry, which components that read namespace-scoped config
// (e.g. the scheduler's Tweakables) require.
func WithNodeBackendDecorator(fn func(*chasm.MockNodeBackend)) EngineOption {
return func(e *Engine) {
e.decorateBackend = fn
}
}

var defaultTransitionOptions = chasm.TransitionOptions{
ReusePolicy: chasm.BusinessIDReusePolicyAllowDuplicate,
ConflictPolicy: chasm.BusinessIDConflictPolicyFail,
Expand Down Expand Up @@ -559,6 +574,9 @@ func (e *Engine) newExecution(key chasm.ExecutionKey) *execution {
return changed, nil
},
}
if e.decorateBackend != nil {
e.decorateBackend(backend)
}
return &execution{
key: key,
backend: backend,
Expand All @@ -573,6 +591,29 @@ func (e *Engine) newExecution(key chasm.ExecutionKey) *execution {
}
}

// NodeForRef returns the CHASM tree node backing the execution identified by ref.
// It is intended for test drivers that need to invoke node-level task dispatch
// ([chasm.Node.EachPureTask], [chasm.Node.ExecuteSideEffectTask]) or close
// transactions directly, which the [Engine] API does not expose.
func (e *Engine) NodeForRef(ref chasm.ComponentRef) (*chasm.Node, error) {
exec, err := e.executionForRef(ref)
if err != nil {
return nil, err
}
return exec.node, nil
}

// BackendForRef returns the [chasm.MockNodeBackend] backing the execution
// identified by ref. Test drivers use it to inspect the physical tasks
// ([chasm.MockNodeBackend.TasksByCategory]) the engine has accumulated.
func (e *Engine) BackendForRef(ref chasm.ComponentRef) (*chasm.MockNodeBackend, error) {
exec, err := e.executionForRef(ref)
if err != nil {
return nil, err
}
return exec.backend, nil
}

// executionForRef looks up an execution by the ref's RunID when present, or falls back
// to the current run for the business ID when RunID is empty.
func (e *Engine) executionForRef(ref chasm.ComponentRef) (*execution, error) {
Expand Down
10 changes: 9 additions & 1 deletion chasm/lib/scheduler/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,19 @@ func CreateSchedulerFromMigration(
) (*Scheduler, error) {
state := req.GetState()

// Default to a non-nil empty result, matching NewScheduler. Migrated state
// may carry no completion result (e.g. a schedule migrated before its first
// action), and startWorkflow dereferences LastCompletionResult unconditionally.
lastCompletion := state.GetLastCompletionResult()
if lastCompletion == nil {
lastCompletion = &schedulerpb.LastCompletionResult{}
}

sched := &Scheduler{
SchedulerState: state.GetSchedulerState(),
cacheConflictToken: state.GetSchedulerState().GetConflictToken(),
Backfillers: make(chasm.Map[string, *Backfiller]),
LastCompletionResult: chasm.NewDataField(ctx, state.GetLastCompletionResult()),
LastCompletionResult: chasm.NewDataField(ctx, lastCompletion),
EventLog: chasm.NewComponentField(ctx, NewEventLog(ctx)),
}
sched.setNullableFields()
Expand Down
Loading
Loading