1package app
2
3import (
4 "context"
5 "errors"
6 "testing"
7 "time"
8
9 "github.com/stretchr/testify/require"
10
11 "github.com/bnema/vev/internal/adapters/lifecycle"
12 "github.com/bnema/vev/pkg/safedir"
13)
14
15func TestWaitForTargetOrLifecycleNamesAHeldLock(t *testing.T) {
16 cfg := backoffConfig{initial: time.Millisecond, max: 2 * time.Millisecond, total: 200 * time.Millisecond}
17 refuse := func(context.Context) (struct{}, error) { return struct{}{}, errors.New("no carriage") }
18 tests := []struct {
19 name string
20 held bool
21 release bool
22 wantHeld bool
23 }{
24 {name: "lock held by a silent owner", held: true, wantHeld: true},
25 {name: "free lock is acquired", held: false, wantHeld: false},
26 {name: "lock released during the budget is acquired", held: true, release: true, wantHeld: false},
27 }
28 for _, tt := range tests {
29 t.Run(tt.name, func(t *testing.T) {
30 dir := t.TempDir() + "/runtime"
31 require.NoError(t, safedir.EnsurePrivate(dir))
32 if tt.held {
33 owner, err := lifecycle.TryAcquire(dir)
34 require.NoError(t, err)
35 if tt.release {
36 time.AfterFunc(5*time.Millisecond, func() { _ = owner.Release() })
37 } else {
38 t.Cleanup(func() { _ = owner.Release() })
39 }
40 }
41
42 _, owner, err := waitForTargetOrLifecycle(context.Background(), dir, refuse, cfg)
43
44 if tt.wantHeld {
45 require.ErrorIs(t, err, ErrLifecycleHeldByOther)
46 require.ErrorIs(t, err, ErrDaemonUnreachable)
47 return
48 }
49 require.NoError(t, err)
50 require.NoError(t, owner.Release())
51 })
52 }
53}