carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package seeds
2
3import (
4 "context"
5 "errors"
6 "sync"
7 "testing"
8
9 "github.com/carlosframework/platform/internal/release"
10)
11
12func TestReadFloorAbsentIsNil(t *testing.T) {
13 s := release.NewDirStore(t.TempDir())
14 f, err := ReadFloor(context.Background(), s)
15 if f != nil || err != nil {
16 t.Fatalf("absent floor = %+v, %v; want nil, nil", f, err)
17 }
18 if _, err := s.Put(context.Background(), FloorKey, []byte("{not json"), ""); err != nil {
19 t.Fatal(err)
20 }
21 if _, err := ReadFloor(context.Background(), s); err == nil {
22 t.Fatal("garbage at the floor key read as no floor")
23 }
24}
25
26func TestPublishFloorOnlyRises(t *testing.T) {
27 ctx := context.Background()
28 s := release.NewDirStore(t.TempDir())
29 if err := PublishFloor(ctx, s, Floor{Min: RequiredProtocol, MinRelease: "v0.27.0"}); err != nil {
30 t.Fatal(err)
31 }
32 if err := PublishFloor(ctx, s, Floor{Min: RequiredProtocol, MinRelease: "v0.27.0"}); err != nil {
33 t.Fatalf("the same floor again: %v", err)
34 }
35 var low *FloorLowerError
36 if err := PublishFloor(ctx, s, Floor{Min: RequiredProtocol, MinRelease: "v0.26.9"}); !errors.As(err, &low) || low.Current != "v0.27.0" {
37 t.Fatalf("a lower floor: err = %v, want FloorLowerError naming v0.27.0", err)
38 }
39 if err := PublishFloor(ctx, s, Floor{Min: RequiredProtocol, MinRelease: "v0.28.0"}); err != nil {
40 t.Fatalf("a higher floor: %v", err)
41 }
42 f, err := ReadFloor(ctx, s)
43 if err != nil || f == nil || f.MinRelease != "v0.28.0" || f.Min != RequiredProtocol {
44 t.Fatalf("floor = %+v, %v", f, err)
45 }
46 if err := PublishFloor(ctx, s, Floor{Min: RequiredProtocol, MinRelease: "v0.29.0-rc.1"}); err == nil {
47 t.Fatal("a prerelease floor published")
48 }
49}
50
51func TestPublishFloorLowerProtocolRefused(t *testing.T) {
52 ctx := context.Background()
53 s := release.NewDirStore(t.TempDir())
54 if err := PublishFloor(ctx, s, Floor{Min: 2, MinRelease: "v0.27.0"}); err != nil {
55 t.Fatal(err)
56 }
57 var low *FloorLowerError
58 if err := PublishFloor(ctx, s, Floor{Min: 1, MinRelease: "v0.28.0"}); !errors.As(err, &low) {
59 t.Fatalf("a lower protocol on a higher release: err = %v, want FloorLowerError", err)
60 }
61 if f, err := ReadFloor(ctx, s); err != nil || *f != (Floor{Min: 2, MinRelease: "v0.27.0"}) {
62 t.Fatalf("floor = %+v, %v; want it unchanged", f, err)
63 }
64}
65
66// Concurrent publishes of different floors must leave the highest one, never
67// a lower one that read the object before a higher one landed.
68func TestPublishFloorConcurrentLowerNeverWins(t *testing.T) {
69 ctx := context.Background()
70 for round := 0; round < 20; round++ {
71 s := release.NewDirStore(t.TempDir())
72 versions := []string{"v0.27.0", "v0.28.0", "v0.29.0", "v0.30.0", "v0.31.0"}
73 var wg sync.WaitGroup
74 for _, v := range versions {
75 wg.Add(1)
76 go func() {
77 defer wg.Done()
78 var low *FloorLowerError
79 if err := PublishFloor(ctx, s, Floor{Min: RequiredProtocol, MinRelease: v}); err != nil && !errors.As(err, &low) {
80 t.Errorf("publish %s: %v", v, err)
81 }
82 }()
83 }
84 wg.Wait()
85 f, err := ReadFloor(ctx, s)
86 if err != nil || f == nil || f.MinRelease != "v0.31.0" {
87 t.Fatalf("round %d: floor = %+v, %v; want v0.31.0", round, f, err)
88 }
89 }
90}
91
92func TestReleaseAtOrAbove(t *testing.T) {
93 for _, c := range []struct {
94 v, min string
95 want bool
96 err bool
97 }{
98 {"v0.27.0", "v0.27.0", true, false},
99 {"v0.27.1", "v0.27.0", true, false},
100 {"v0.26.9", "v0.27.0", false, false},
101 {"v0.28.0-rc.1", "v0.27.0", false, true},
102 {"v0.27.0", "garbage", false, true},
103 } {
104 got, err := ReleaseAtOrAbove(c.v, c.min)
105 if got != c.want || (err != nil) != c.err {
106 t.Errorf("ReleaseAtOrAbove(%s, %s) = %v, %v", c.v, c.min, got, err)
107 }
108 }
109}
110
111func TestProtocolMeetsWhatTheConsoleRequires(t *testing.T) {
112 // The floor shipped dark through Plan 7 (preflight M9): spec §5.8's
113 // move refusals, the seeds sweep and the legacy-routes assign door had
114 // to exist before any door opens. Plan 8 built them, and its Task 6
115 // raised ProtocolVersion, so a box built from here can satisfy the
116 // console's check once an operator publishes the seeds floor.
117 if ProtocolVersion < RequiredProtocol {
118 t.Fatalf("ProtocolVersion = %d, RequiredProtocol = %d", ProtocolVersion, RequiredProtocol)
119 }
120}
121