carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package rootstate
2
3import (
4 "context"
5 "errors"
6 "os"
7 "path/filepath"
8 "sync/atomic"
9 "testing"
10 "time"
11)
12
13func TestPlan14ConcurrentAdoptionPublicationOrder(t *testing.T) {
14 path, release := fixture(t)
15 _, host := fixture(t)
16 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
17 defer cancel()
18 entered, finish := make(chan struct{}), make(chan struct{})
19 done := make(chan error, 2)
20 var effects atomic.Int32
21 go func() {
22 done <- WithRelease(ctx, release, func() error {
23 unlock, err := host.Lock(ctx, "host.lock")
24 if err != nil {
25 return err
26 }
27 defer unlock()
28 close(entered)
29 select {
30 case <-finish:
31 case <-ctx.Done():
32 return ctx.Err()
33 }
34 effects.Add(1)
35 return nil
36 })
37 }()
38 select {
39 case <-entered:
40 case <-ctx.Done():
41 t.Fatal(ctx.Err())
42 }
43 // A separate open is a distinct flock description, as in two root processes.
44 parent, err := os.Open(filepath.Dir(path))
45 if err != nil {
46 t.Fatal(err)
47 }
48 defer parent.Close()
49 other, err := descend(parent, []string{filepath.Base(path)}, false, false, uint32(os.Geteuid()))
50 if err != nil {
51 t.Fatal(err)
52 }
53 defer other.Close()
54 short, stop := context.WithCancel(ctx)
55 stop()
56 if err := WithRelease(short, other, func() error { effects.Add(100); return nil }); !errors.Is(err, context.Canceled) {
57 t.Fatalf("canceled contender: %v", err)
58 }
59 go func() {
60 done <- WithRelease(ctx, other, func() error {
61 unlock, err := host.Lock(ctx, "host.lock")
62 if err != nil {
63 return err
64 }
65 defer unlock()
66 effects.Add(1)
67 return nil
68 })
69 }()
70 close(finish)
71 for i := 0; i < 2; i++ {
72 select {
73 case err := <-done:
74 if err != nil {
75 t.Fatal(err)
76 }
77 case <-ctx.Done():
78 t.Fatal("release/host lock deadlock")
79 }
80 }
81 if effects.Load() != 2 {
82 t.Fatalf("effects = %d", effects.Load())
83 }
84 // The stable lock survives completion; neither caller unlinks it.
85 if _, err := os.Stat(filepath.Join(path, "release.lock")); err != nil {
86 t.Fatal(err)
87 }
88}
89