carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package moves
2
3import (
4 "context"
5 "encoding/json"
6 "testing"
7 "time"
8
9 "github.com/carlosframework/platform/internal/release"
10)
11
12func TestFloorReadAndCompare(t *testing.T) {
13 ctx := context.Background()
14 s := release.NewDirStore(t.TempDir())
15
16 f, err := ReadFloor(ctx, s)
17 if err != nil || f != nil {
18 t.Fatalf("absent floor read as %+v, %v", f, err)
19 }
20
21 body, _ := json.Marshal(Floor{Min: ProtocolVersion, MinRelease: "v0.23.0"})
22 if _, err := s.Put(ctx, FloorKey, body, ""); err != nil {
23 t.Fatal(err)
24 }
25 f, err = ReadFloor(ctx, s)
26 if err != nil || f == nil || f.Min != ProtocolVersion || f.MinRelease != "v0.23.0" {
27 t.Fatalf("written floor read as %+v, %v", f, err)
28 }
29
30 for _, tc := range []struct {
31 version, min string
32 want bool
33 wantErr bool
34 }{
35 {"v0.23.0", "v0.23.0", true, false},
36 {"v0.24.1", "v0.23.0", true, false},
37 {"v0.22.9", "v0.23.0", false, false},
38 {"v1.0.0", "v0.23.0", true, false},
39 {"v0.30.0-rc.1", "v0.23.0", false, true}, // prerelease: fail closed
40 {"v0.30.0-rc.1", "v0.1.0", false, true},
41 {"", "v0.23.0", false, true},
42 {"junk", "v0.23.0", false, true},
43 {"v0.24.1", "", false, true}, // malformed floor: fail closed
44 {"v0.24.1", "v0.23", false, true},
45 {"v0.24.1", "v0.23.0-rc.1", false, true},
46 } {
47 got, err := ReleaseAtOrAbove(tc.version, tc.min)
48 if got != tc.want || (err != nil) != tc.wantErr {
49 t.Errorf("ReleaseAtOrAbove(%q, %q) = %v, %v; want %v, err %v", tc.version, tc.min, got, err, tc.want, tc.wantErr)
50 }
51 }
52}
53
54func TestReadFloorGarbageIsAnError(t *testing.T) {
55 ctx := context.Background()
56 s := release.NewDirStore(t.TempDir())
57 if _, err := s.Put(ctx, FloorKey, []byte("not json"), ""); err != nil {
58 t.Fatal(err)
59 }
60 if f, err := ReadFloor(ctx, s); err == nil || f != nil {
61 t.Fatalf("garbage floor read as %+v, %v", f, err)
62 }
63}
64
65// The console record's wire names are what Task 11's T2 check and any
66// operator reading the bucket see; the four file names are what the host
67// writes and the two system units hard-code (host_test.go pins the units
68// against these same constants).
69func TestConsoleRecordAndFloorFileNames(t *testing.T) {
70 at := time.Date(2026, 10, 7, 12, 0, 0, 0, time.UTC)
71 b, err := json.Marshal(ConsoleRecord{V: 1, Protocol: ProtocolVersion, SecretsKeyFP: "fp", At: at})
72 if err != nil {
73 t.Fatal(err)
74 }
75 if want := `{"v":1,"protocol":1,"secrets_key_fp":"fp","at":"2026-10-07T12:00:00Z"}`; string(b) != want {
76 t.Fatalf("console record = %s, want %s", b, want)
77 }
78 if ConsoleKey != "control/moves-console.json" {
79 t.Fatalf("ConsoleKey = %q", ConsoleKey)
80 }
81 if FloorFile != ".moves/floor.json" || FloorMinReleaseFile != ".moves/floor.min-release" {
82 t.Fatalf("floor files = %q, %q", FloorFile, FloorMinReleaseFile)
83 }
84 if PrevVersionFile != "carlos.prev.version" || PrevAllowedFile != "carlos.prev.allowed" {
85 t.Fatalf("prev files = %q, %q", PrevVersionFile, PrevAllowedFile)
86 }
87}
88