genselect: check the selection against litestream's pinned planner (claim Plan 7b Task 3)
Co-Authored-By: Codex <noreply@openai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+66
−0
internal/genselect/compatibility_test.go+66 −0
CI passed — run details
diff --git a/internal/genselect/compatibility_test.go b/internal/genselect/compatibility_test.go| new file mode 100644 |
| index 000000000..dfa60d848 |
| --- /dev/null |
| +++ b/internal/genselect/compatibility_test.go |
| @@ -0,0 +1,66 @@ |
| +package genselect |
| + |
| +import ( |
| + "io" |
| + "log/slog" |
| + "os" |
| + "path/filepath" |
| + "testing" |
| + "time" |
| + |
| + "github.com/benbjohnson/litestream" |
| + filereplica "github.com/benbjohnson/litestream/file" |
| + "github.com/superfly/ltx" |
| +) |
| + |
| +func TestCalcRestorePlanCompatibility(t *testing.T) { |
| + type coords struct { |
| + level int |
| + min, max uint64 |
| + } |
| + tests := []struct { |
| + name string |
| + files []coords |
| + }{ |
| + {"compacted_overlap", []coords{{9, 1, 11}, {1, 10, 13}}}, |
| + {"genuine_gap", []coords{{9, 1, 11}, {0, 13, 13}}}, |
| + {"successor_snapshot", []coords{{9, 1, 11}, {9, 1, 20}, {0, 13, 13}, {0, 21, 21}}}, |
| + {"origin", []coords{{0, 1, 1}, {1, 2, 5}}}, |
| + {"tie_breaks", []coords{{9, 1, 11}, {8, 12, 19}, {8, 12, 20}, {1, 10, 20}, {2, 10, 20}}}, |
| + {"anchor_is_not_continuation", []coords{{9, 1, 11}, {0, 11, 11}, {0, 12, 12}}}, |
| + } |
| + for _, tt := range tests { |
| + t.Run(tt.name, func(t *testing.T) { |
| + f := newFixture(t) |
| + f.origin() |
| + client := filereplica.NewReplicaClient(t.TempDir()) |
| + for _, c := range tt.files { |
| + f.file("", c.level, c.min, c.max) |
| + path := client.LTXFilePath(c.level, ltx.TXID(c.min), ltx.TXID(c.max)) |
| + if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil { |
| + t.Fatal(err) |
| + } |
| + if err := os.WriteFile(path, header(t, c.min, c.max), 0600); err != nil { |
| + t.Fatal(err) |
| + } |
| + } |
| + want, wantErr := litestream.CalcRestorePlan(t.Context(), client, 0, time.Time{}, slog.New(slog.NewTextHandler(io.Discard, nil))) |
| + got, err := Select(t.Context(), f.b, f.req) |
| + if (err != nil) != (wantErr != nil) { |
| + t.Fatalf("selector %v; litestream %v", err, wantErr) |
| + } |
| + if err != nil { |
| + return |
| + } |
| + if len(got.Files) != len(want) { |
| + t.Fatalf("length %d != %d", len(got.Files), len(want)) |
| + } |
| + for i, v := range want { |
| + x := got.Files[i] |
| + if x.Level != v.Level || x.MinTXID != uint64(v.MinTXID) || x.MaxTXID != uint64(v.MaxTXID) { |
| + t.Fatalf("file %d: %+v != %+v", i, x, v) |
| + } |
| + } |
| + }) |
| + } |
| +} |