Make Run runtime state authoritative

This commit is contained in:
npc0-hue
2026-08-06 10:07:01 +08:00
parent d8d07914da
commit 0875a1b17e
10 changed files with 324 additions and 12 deletions
+33 -8
View File
@@ -88,6 +88,21 @@ func TestCoreServiceServerLifecycleWorkflows(t *testing.T) {
}
}
func TestLifecycleProjectedStateUsesRunProcessFacts(t *testing.T) {
if state, ok := lifecycleProjectedState(domain.LifecycleCapabilityStart, domain.JobStateSucceeded, domain.JobExecutionResult{Kind: "process", ProcessState: "stopped"}); !ok || state == domain.ServerInstanceStateRunning {
t.Fatalf("start success without running process fact must not mark running, state=%q ok=%v", state, ok)
}
if state, ok := lifecycleProjectedState(domain.LifecycleCapabilityStatus, domain.JobStateSucceeded, domain.JobExecutionResult{Kind: "process", ProcessState: "not-started"}); !ok || state != domain.ServerInstanceStateStopped {
t.Fatalf("status not-started should project stopped, state=%q ok=%v", state, ok)
}
if state, ok := lifecycleProjectedState(domain.LifecycleCapabilityStatus, domain.JobStateSucceeded, domain.JobExecutionResult{Kind: "process", ProcessState: "exited", ExitClassification: "unexpected-exit"}); !ok || state != domain.ServerInstanceStateFailed {
t.Fatalf("unexpected exit should project failed, state=%q ok=%v", state, ok)
}
if state, ok := lifecycleProjectedState(domain.LifecycleCapabilityStop, domain.JobStateSucceeded, domain.JobExecutionResult{Kind: "process", ProcessState: "not-started"}); !ok || state != domain.ServerInstanceStateStopped {
t.Fatalf("stop not-started should project stopped, state=%q ok=%v", state, ok)
}
}
func TestCoreServiceCreatesTargetBoundDraftAndRequiresDedicatedRunRegistration(t *testing.T) {
svc, _ := newLifecycleRunService(t)
plugin := createLifecyclePlugin(t, svc)
@@ -430,15 +445,25 @@ func claimAndCompleteLifecycleJobForServer(t *testing.T, svc *CoreService, sessi
if serverInstanceID != "" && claim.Job.ServerInstanceID != serverInstanceID {
t.Fatalf("expected claimed lifecycle job for %s, got %+v", serverInstanceID, claim.Job)
}
executionResult := domain.JobExecutionResult{}
if state == domain.JobStateSucceeded {
switch capability {
case domain.LifecycleCapabilityStart, domain.LifecycleCapabilityStatus:
executionResult = domain.JobExecutionResult{Kind: "process", ProcessState: "running", AuditSummary: "bounded process state"}
case domain.LifecycleCapabilityStop:
executionResult = domain.JobExecutionResult{Kind: "process", ProcessState: "stopped", ExitClassification: "requested-stop", AuditSummary: "bounded process state"}
}
}
if _, err := svc.CompleteRunJob(domain.RunJobResult{
RunEndpointID: "run-local",
SessionToken: sessionToken,
JobID: claim.Job.JobID,
LeaseToken: claim.Job.LeaseToken,
Attempt: claim.Job.Attempt,
State: state,
Progress: domain.RunJobProgressReport{Percent: 100, Message: string(state)},
Message: string(state),
RunEndpointID: "run-local",
SessionToken: sessionToken,
JobID: claim.Job.JobID,
LeaseToken: claim.Job.LeaseToken,
Attempt: claim.Job.Attempt,
State: state,
Progress: domain.RunJobProgressReport{Percent: 100, Message: string(state)},
Message: string(state),
ExecutionResult: executionResult,
}); err != nil {
t.Fatalf("complete lifecycle job %s: %v", capability, err)
}