82 lines
2.6 KiB
Go
82 lines
2.6 KiB
Go
package agenttask
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestManagerS03S16MultiProjectManualResumeAndParallelTrace(t *testing.T) {
|
|
projectA := testSnapshot(
|
|
"project-a", "shared-workspace",
|
|
testUnit("a-disjoint", WriteSetDisjoint),
|
|
testUnit("a-overlap", WriteSetOverlap),
|
|
)
|
|
projectB := testSnapshot(
|
|
"project-b", "workspace-b",
|
|
testUnit("b-unknown", WriteSetUnknown),
|
|
)
|
|
unselected := testSnapshot(
|
|
"unselected", "workspace-unselected",
|
|
testUnit("must-not-run", WriteSetUnknown),
|
|
)
|
|
harness := newHarness(
|
|
t,
|
|
map[ProjectID]ProjectWorkflowSnapshot{
|
|
"project-a": projectA, "project-b": projectB, "unselected": unselected,
|
|
},
|
|
3,
|
|
)
|
|
for _, workID := range []WorkUnitID{"a-disjoint", "a-overlap", "b-unknown"} {
|
|
harness.invoker.delays[workID] = 20 * time.Millisecond
|
|
}
|
|
harness.start("project-a", "shared-workspace", nil)
|
|
harness.start("project-b", "workspace-b", nil)
|
|
if err := harness.manager.Reconcile(context.Background()); err != nil {
|
|
t.Fatalf("Reconcile: %v", err)
|
|
}
|
|
state := harness.store.snapshot()
|
|
if state.Projects["project-a"].Status != ProjectStatusCompleted ||
|
|
state.Projects["project-b"].Status != ProjectStatusCompleted {
|
|
t.Fatalf(
|
|
"manual projects = %s/%s",
|
|
state.Projects["project-a"].Status, state.Projects["project-b"].Status,
|
|
)
|
|
}
|
|
if state.Projects["unselected"].Status != ProjectStatusObserved {
|
|
t.Fatalf("unselected project status = %s", state.Projects["unselected"].Status)
|
|
}
|
|
if harness.invoker.callCount() != 3 {
|
|
t.Fatalf("invocations = %d, want selected work only", harness.invoker.callCount())
|
|
}
|
|
if harness.invoker.maxConcurrency() < 2 {
|
|
t.Fatalf("max concurrency = %d, want isolated parallel dispatch", harness.invoker.maxConcurrency())
|
|
}
|
|
trace := make([]string, 0)
|
|
for _, event := range harness.events.snapshot() {
|
|
if event.Type != EventDispatchStarted && event.Type != EventIntegrationResult {
|
|
continue
|
|
}
|
|
trace = append(trace, fmt.Sprintf(
|
|
"%s:%s:%s:%d:%s:%s",
|
|
event.Type, event.ProjectID, event.WorkUnitID, event.Ordinal,
|
|
event.WriteSetKind, event.IsolationMode,
|
|
))
|
|
if event.WorkUnitID == "must-not-run" {
|
|
t.Fatalf("unselected work appeared in execution trace: %v", trace)
|
|
}
|
|
}
|
|
joined := strings.Join(trace, "\n")
|
|
for _, expected := range []string{"a-disjoint", "a-overlap", "b-unknown"} {
|
|
if !strings.Contains(joined, expected) {
|
|
t.Fatalf("trace missing %s:\n%s", expected, joined)
|
|
}
|
|
}
|
|
t.Logf(
|
|
"S03 trace: unselected_invocations=0 manual_projects=2 terminal=2; "+
|
|
"S16 trace: explicit_dependency_only=true isolated_parallel_max=%d integration_ordinals=%v\n%s",
|
|
harness.invoker.maxConcurrency(), harness.integrator.ordinals(), joined,
|
|
)
|
|
}
|