|
|
|
|
@@ -60,6 +60,7 @@ func TestWorker_PicksUpAndCompletes(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorker.Run(ctx) }()
|
|
|
|
|
|
|
|
|
|
require.Eventually(
|
|
|
|
|
@@ -92,6 +93,7 @@ func TestWorker_StopAndResume(t *testing.T) {
|
|
|
|
|
func(_ context.Context, _ struct{}) (agent.ToolResult, error) {
|
|
|
|
|
close(toolReady)
|
|
|
|
|
<-toolRelease
|
|
|
|
|
|
|
|
|
|
return agent.ToolResult{Content: "work done"}, nil
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
@@ -122,6 +124,7 @@ func TestWorker_StopAndResume(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctx1, cancel1 := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
|
defer cancel1()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorker.Run(ctx1) }()
|
|
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
@@ -164,6 +167,7 @@ func TestWorker_StopAndResume(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctx2, cancel2 := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
|
defer cancel2()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorker2.Run(ctx2) }()
|
|
|
|
|
|
|
|
|
|
require.Eventually(
|
|
|
|
|
@@ -200,6 +204,7 @@ func TestWorker_StopAndResumeAcrossHandoff(t *testing.T) {
|
|
|
|
|
func(_ context.Context, _ struct{}) (agent.ToolResult, error) {
|
|
|
|
|
close(toolReady)
|
|
|
|
|
<-toolRelease
|
|
|
|
|
|
|
|
|
|
return agent.ToolResult{Content: "child work done"}, nil
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
@@ -250,6 +255,7 @@ func TestWorker_StopAndResumeAcrossHandoff(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctx1, cancel1 := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
|
defer cancel1()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorker.Run(ctx1) }()
|
|
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
@@ -295,6 +301,7 @@ func TestWorker_StopAndResumeAcrossHandoff(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctx2, cancel2 := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
|
defer cancel2()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorker2.Run(ctx2) }()
|
|
|
|
|
|
|
|
|
|
require.Eventually(
|
|
|
|
|
@@ -329,6 +336,7 @@ func TestWorker_StopAndResumeNestedSubAgent(t *testing.T) {
|
|
|
|
|
func(_ context.Context, _ struct{}) (agent.ToolResult, error) {
|
|
|
|
|
readyOnce.Do(func() { close(toolReady) })
|
|
|
|
|
<-toolRelease
|
|
|
|
|
|
|
|
|
|
return agent.ToolResult{Content: "inner work done"}, nil
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
@@ -379,6 +387,7 @@ func TestWorker_StopAndResumeNestedSubAgent(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctx1, cancel1 := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
|
defer cancel1()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorker.Run(ctx1) }()
|
|
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
@@ -425,6 +434,7 @@ func TestWorker_StopAndResumeNestedSubAgent(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctx2, cancel2 := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
|
defer cancel2()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorker2.Run(ctx2) }()
|
|
|
|
|
|
|
|
|
|
require.Eventually(
|
|
|
|
|
@@ -459,6 +469,7 @@ func TestWorker_StopAndResumeNestedSubAgentMultiLevel(t *testing.T) {
|
|
|
|
|
func(_ context.Context, _ struct{}) (agent.ToolResult, error) {
|
|
|
|
|
readyOnce.Do(func() { close(toolReady) })
|
|
|
|
|
<-toolRelease
|
|
|
|
|
|
|
|
|
|
return agent.ToolResult{Content: "grandchild work done"}, nil
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
@@ -524,6 +535,7 @@ func TestWorker_StopAndResumeNestedSubAgentMultiLevel(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctx1, cancel1 := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
|
defer cancel1()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorker.Run(ctx1) }()
|
|
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
@@ -574,6 +586,7 @@ func TestWorker_StopAndResumeNestedSubAgentMultiLevel(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctx2, cancel2 := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
|
defer cancel2()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorker2.Run(ctx2) }()
|
|
|
|
|
|
|
|
|
|
require.Eventually(
|
|
|
|
|
@@ -697,6 +710,7 @@ func TestWorker_ReclaimedRunDoesNotClobberWinner(t *testing.T) {
|
|
|
|
|
func(_ context.Context, _ struct{}) (agent.ToolResult, error) {
|
|
|
|
|
close(toolReady)
|
|
|
|
|
<-toolRelease
|
|
|
|
|
|
|
|
|
|
return agent.ToolResult{Content: "work done"}, nil
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
@@ -735,6 +749,7 @@ func TestWorker_ReclaimedRunDoesNotClobberWinner(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctxA, cancelA := context.WithTimeout(context.Background(), 30*time.Second)
|
|
|
|
|
defer cancelA()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorkerA.Run(ctxA) }()
|
|
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
@@ -754,6 +769,7 @@ func TestWorker_ReclaimedRunDoesNotClobberWinner(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctxB, cancelB := context.WithTimeout(context.Background(), 30*time.Second)
|
|
|
|
|
defer cancelB()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorkerB.Run(ctxB) }()
|
|
|
|
|
|
|
|
|
|
require.Eventually(
|
|
|
|
|
@@ -777,6 +793,7 @@ func TestWorker_ReclaimedRunDoesNotClobberWinner(t *testing.T) {
|
|
|
|
|
func() bool {
|
|
|
|
|
provider.mu.Lock()
|
|
|
|
|
defer provider.mu.Unlock()
|
|
|
|
|
|
|
|
|
|
return provider.calls >= 3
|
|
|
|
|
},
|
|
|
|
|
15*time.Second,
|
|
|
|
|
@@ -815,6 +832,7 @@ func TestWorker_UnknownAgentFails(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorker.Run(ctx) }()
|
|
|
|
|
|
|
|
|
|
require.Eventually(
|
|
|
|
|
@@ -858,6 +876,7 @@ func TestWorker_InvalidInputMessagesFails(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
go func() { _ = runWorker.Run(ctx) }()
|
|
|
|
|
|
|
|
|
|
require.Eventually(
|
|
|
|
|
@@ -882,33 +901,49 @@ func TestWorker_SIGTERM(t *testing.T) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skip when the test database is unreachable so the parent does not
|
|
|
|
|
// wait on a subprocess that skips itself for the same reason and never
|
|
|
|
|
// prints READY.
|
|
|
|
|
test.PGClient(t)
|
|
|
|
|
|
|
|
|
|
cmd := exec.Command(os.Args[0], "-test.run=^TestWorker_SIGTERM$")
|
|
|
|
|
|
|
|
|
|
cmd.Env = append(os.Environ(), "TEST_SIGTERM_SUBPROCESS=1")
|
|
|
|
|
|
|
|
|
|
stdout, err := cmd.StdoutPipe()
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
cmd.Stderr = cmd.Stdout
|
|
|
|
|
|
|
|
|
|
require.NoError(t, cmd.Start())
|
|
|
|
|
|
|
|
|
|
ready := make(chan struct{})
|
|
|
|
|
scanDone := make(chan struct{})
|
|
|
|
|
var linesMu sync.Mutex
|
|
|
|
|
var lines []string
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
linesMu sync.Mutex
|
|
|
|
|
lines []string
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
snapshotLines := func() string {
|
|
|
|
|
linesMu.Lock()
|
|
|
|
|
defer linesMu.Unlock()
|
|
|
|
|
|
|
|
|
|
return strings.Join(lines, "\n")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
defer close(scanDone)
|
|
|
|
|
|
|
|
|
|
scanner := bufio.NewScanner(stdout)
|
|
|
|
|
for scanner.Scan() {
|
|
|
|
|
line := scanner.Text()
|
|
|
|
|
|
|
|
|
|
linesMu.Lock()
|
|
|
|
|
|
|
|
|
|
lines = append(lines, line)
|
|
|
|
|
linesMu.Unlock()
|
|
|
|
|
|
|
|
|
|
if line == "READY" {
|
|
|
|
|
close(ready)
|
|
|
|
|
}
|
|
|
|
|
@@ -919,13 +954,16 @@ func TestWorker_SIGTERM(t *testing.T) {
|
|
|
|
|
case <-ready:
|
|
|
|
|
case <-time.After(20 * time.Second):
|
|
|
|
|
_ = cmd.Process.Kill()
|
|
|
|
|
|
|
|
|
|
t.Fatalf("subprocess did not become ready for SIGTERM\n%s", snapshotLines())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require.NoError(t, cmd.Process.Signal(syscall.SIGTERM))
|
|
|
|
|
|
|
|
|
|
if err := cmd.Wait(); err != nil {
|
|
|
|
|
t.Fatalf("subprocess failed: %v\n%s", err, snapshotLines())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<-scanDone
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -967,7 +1005,7 @@ func runSIGTERMSubprocess(t *testing.T) {
|
|
|
|
|
t.Fatal("tool did not start before SIGTERM")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Fprintln(os.Stdout, "READY")
|
|
|
|
|
_, _ = fmt.Fprintln(os.Stdout, "READY")
|
|
|
|
|
|
|
|
|
|
select {
|
|
|
|
|
case <-runWorker.ShutdownBroadcast():
|
|
|
|
|
@@ -995,6 +1033,7 @@ func makeBattleTools(workStarted chan<- struct{}) []agent.Tool {
|
|
|
|
|
func(ctx context.Context, _ workInput) (agent.ToolResult, error) {
|
|
|
|
|
close(workStarted)
|
|
|
|
|
<-ctx.Done()
|
|
|
|
|
|
|
|
|
|
return agent.ToolResult{Content: "interrupted"}, ctx.Err()
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
|