package hostbox import ( "context" "errors" "reflect" "testing" "github.com/carlosframework/platform/internal/park" ) type recordedLease struct { name string checks, releases int closed int checkErr, releaseErr error } func (l *recordedLease) Check(context.Context) error { l.checks++; return l.checkErr } func (l *recordedLease) Release(context.Context) error { l.releases++; return l.releaseErr } func (l *recordedLease) Close() { l.closed++ } type recordingLeases struct { names []string held map[string]*recordedLease failAt string } func (l *recordingLeases) Acquire(_ context.Context, _, name string) (park.HeldLease, error) { l.names = append(l.names, name) if name == l.failAt { return nil, errors.New("acquire failed") } h := &recordedLease{name: name} l.held[name] = h return h, nil } func TestAggregateLeasesOrderHealthReleaseAndClose(t *testing.T) { base := &recordingLeases{held: map[string]*recordedLease{}} a := AggregateLeases{Leases: base, Resolve: func(context.Context, string, string) ([]string, error) { return []string{"moves/h/op", "instances/h/inc", "moves/h/op"}, nil }} held, err := a.Acquire(t.Context(), "data", "instances/h/inc") if err != nil { t.Fatal(err) } if want := []string{"instances/h/inc", "moves/h/op"}; !reflect.DeepEqual(base.names, want) { t.Fatalf("acquire order = %v, want %v", base.names, want) } base.held["moves/h/op"].checkErr = errors.New("lost") if err := held.Check(t.Context()); err == nil || base.held["instances/h/inc"].checks != 1 || base.held["moves/h/op"].checks != 1 { t.Fatalf("aggregate check = %v", err) } if err := held.Release(t.Context()); err != nil { t.Fatal(err) } held.Close() for name, h := range base.held { if h.releases != 1 || h.closed != 1 { t.Fatalf("%s: releases=%d closes=%d", name, h.releases, h.closed) } } } func TestAggregateLeasesPartialAcquireUnwindsOnlyAcquired(t *testing.T) { base := &recordingLeases{held: map[string]*recordedLease{}, failAt: "b"} a := AggregateLeases{Leases: base, Resolve: func(context.Context, string, string) ([]string, error) { return []string{"scope", "b", "a"}, nil }} if _, err := a.Acquire(t.Context(), "data", "scope"); err == nil { t.Fatal("acquire succeeded") } if want := []string{"a", "b"}; !reflect.DeepEqual(base.names, want) { t.Fatalf("attempts = %v, want %v", base.names, want) } if h := base.held["a"]; h.releases != 1 || h.closed != 1 { t.Fatalf("acquired lease not unwound: %+v", h) } if _, ok := base.held["scope"]; ok { t.Fatal("unattempted lease was acquired") } }