package moves import ( "context" "encoding/json" "testing" "time" "github.com/carlosframework/platform/internal/release" ) func TestFloorReadAndCompare(t *testing.T) { ctx := context.Background() s := release.NewDirStore(t.TempDir()) f, err := ReadFloor(ctx, s) if err != nil || f != nil { t.Fatalf("absent floor read as %+v, %v", f, err) } body, _ := json.Marshal(Floor{Min: ProtocolVersion, MinRelease: "v0.23.0"}) if _, err := s.Put(ctx, FloorKey, body, ""); err != nil { t.Fatal(err) } f, err = ReadFloor(ctx, s) if err != nil || f == nil || f.Min != ProtocolVersion || f.MinRelease != "v0.23.0" { t.Fatalf("written floor read as %+v, %v", f, err) } for _, tc := range []struct { version, min string want bool wantErr bool }{ {"v0.23.0", "v0.23.0", true, false}, {"v0.24.1", "v0.23.0", true, false}, {"v0.22.9", "v0.23.0", false, false}, {"v1.0.0", "v0.23.0", true, false}, {"v0.30.0-rc.1", "v0.23.0", false, true}, // prerelease: fail closed {"v0.30.0-rc.1", "v0.1.0", false, true}, {"", "v0.23.0", false, true}, {"junk", "v0.23.0", false, true}, {"v0.24.1", "", false, true}, // malformed floor: fail closed {"v0.24.1", "v0.23", false, true}, {"v0.24.1", "v0.23.0-rc.1", false, true}, } { got, err := ReleaseAtOrAbove(tc.version, tc.min) if got != tc.want || (err != nil) != tc.wantErr { t.Errorf("ReleaseAtOrAbove(%q, %q) = %v, %v; want %v, err %v", tc.version, tc.min, got, err, tc.want, tc.wantErr) } } } func TestReadFloorGarbageIsAnError(t *testing.T) { ctx := context.Background() s := release.NewDirStore(t.TempDir()) if _, err := s.Put(ctx, FloorKey, []byte("not json"), ""); err != nil { t.Fatal(err) } if f, err := ReadFloor(ctx, s); err == nil || f != nil { t.Fatalf("garbage floor read as %+v, %v", f, err) } } // The console record's wire names are what Task 11's T2 check and any // operator reading the bucket see; the four file names are what the host // writes and the two system units hard-code (host_test.go pins the units // against these same constants). func TestConsoleRecordAndFloorFileNames(t *testing.T) { at := time.Date(2026, 10, 7, 12, 0, 0, 0, time.UTC) b, err := json.Marshal(ConsoleRecord{V: 1, Protocol: ProtocolVersion, SecretsKeyFP: "fp", At: at}) if err != nil { t.Fatal(err) } if want := `{"v":1,"protocol":1,"secrets_key_fp":"fp","at":"2026-10-07T12:00:00Z"}`; string(b) != want { t.Fatalf("console record = %s, want %s", b, want) } if ConsoleKey != "control/moves-console.json" { t.Fatalf("ConsoleKey = %q", ConsoleKey) } if FloorFile != ".moves/floor.json" || FloorMinReleaseFile != ".moves/floor.min-release" { t.Fatalf("floor files = %q, %q", FloorFile, FloorMinReleaseFile) } if PrevVersionFile != "carlos.prev.version" || PrevAllowedFile != "carlos.prev.allowed" { t.Fatalf("prev files = %q, %q", PrevVersionFile, PrevAllowedFile) } }