Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

95 lines
2.3 KiB
Go

package agenthost
import (
"context"
"errors"
"sync"
"testing"
"time"
)
func TestRunSupervisedWorkersStartsAllAndStopsOnContextCancel(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
started := make(chan struct{}, 3)
worker := func(ctx context.Context) error {
started <- struct{}{}
<-ctx.Done()
return ctx.Err()
}
done := make(chan error, 1)
go func() {
done <- runSupervisedWorkers(ctx, []func(context.Context) error{worker, worker, worker})
}()
for range 3 {
select {
case <-started:
case <-time.After(time.Second):
t.Fatal("not every Host worker started")
}
}
cancel()
select {
case err := <-done:
if !errors.Is(err, context.Canceled) {
t.Fatalf("Run() error = %v, want context canceled", err)
}
case <-time.After(time.Second):
t.Fatal("Run() did not stop after context cancellation")
}
}
func TestRunSupervisedWorkersCancelsSiblingsWhenOneWorkerFails(t *testing.T) {
wantErr := errors.New("worker infrastructure failed")
started := make(chan struct{}, 2)
var canceled sync.WaitGroup
canceled.Add(2)
sibling := func(ctx context.Context) error {
started <- struct{}{}
<-ctx.Done()
canceled.Done()
return ctx.Err()
}
failing := func(context.Context) error {
for range 2 {
<-started
}
return wantErr
}
err := runSupervisedWorkers(context.Background(), []func(context.Context) error{sibling, failing, sibling})
if !errors.Is(err, wantErr) {
t.Fatalf("Run() error = %v, want %v", err, wantErr)
}
done := make(chan struct{})
go func() {
canceled.Wait()
close(done)
}()
select {
case <-done:
case <-time.After(time.Second):
t.Fatal("worker failure did not cancel sibling workers")
}
}
func TestNilHostRunIsNoop(t *testing.T) {
var host *Host
if err := host.Run(context.Background()); err != nil {
t.Fatalf("Run() error = %v, want nil", err)
}
}
func TestHostRunPropagatesWorkerInfrastructureFailure(t *testing.T) {
wantErr := errors.New("scheduler unavailable")
host := New(Config{Scheduler: failingRunScheduler{err: wantErr}})
if err := host.Run(context.Background()); !errors.Is(err, wantErr) {
t.Fatalf("Run() error = %v, want %v", err, wantErr)
}
}
type failingRunScheduler struct{ err error }
func (scheduler failingRunScheduler) Sleep(context.Context, time.Duration) error {
return scheduler.err
}