| 1 | package genselect |
| 2 | |
| 3 | import ( |
| 4 | "io" |
| 5 | "log/slog" |
| 6 | "os" |
| 7 | "path/filepath" |
| 8 | "testing" |
| 9 | "time" |
| 10 | |
| 11 | "github.com/benbjohnson/litestream" |
| 12 | filereplica "github.com/benbjohnson/litestream/file" |
| 13 | "github.com/superfly/ltx" |
| 14 | ) |
| 15 | |
| 16 | func TestCalcRestorePlanCompatibility(t *testing.T) { |
| 17 | type coords struct { |
| 18 | level int |
| 19 | min, max uint64 |
| 20 | } |
| 21 | tests := []struct { |
| 22 | name string |
| 23 | files []coords |
| 24 | }{ |
| 25 | {"compacted_overlap", []coords{{9, 1, 11}, {1, 10, 13}}}, |
| 26 | {"genuine_gap", []coords{{9, 1, 11}, {0, 13, 13}}}, |
| 27 | {"successor_snapshot", []coords{{9, 1, 11}, {9, 1, 20}, {0, 13, 13}, {0, 21, 21}}}, |
| 28 | {"origin", []coords{{0, 1, 1}, {1, 2, 5}}}, |
| 29 | {"tie_breaks", []coords{{9, 1, 11}, {8, 12, 19}, {8, 12, 20}, {1, 10, 20}, {2, 10, 20}}}, |
| 30 | {"anchor_is_not_continuation", []coords{{9, 1, 11}, {0, 11, 11}, {0, 12, 12}}}, |
| 31 | } |
| 32 | for _, tt := range tests { |
| 33 | t.Run(tt.name, func(t *testing.T) { |
| 34 | f := newFixture(t) |
| 35 | f.origin() |
| 36 | client := filereplica.NewReplicaClient(t.TempDir()) |
| 37 | for _, c := range tt.files { |
| 38 | f.file("", c.level, c.min, c.max) |
| 39 | path := client.LTXFilePath(c.level, ltx.TXID(c.min), ltx.TXID(c.max)) |
| 40 | if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil { |
| 41 | t.Fatal(err) |
| 42 | } |
| 43 | if err := os.WriteFile(path, header(t, c.min, c.max), 0600); err != nil { |
| 44 | t.Fatal(err) |
| 45 | } |
| 46 | } |
| 47 | want, wantErr := litestream.CalcRestorePlan(t.Context(), client, 0, time.Time{}, slog.New(slog.NewTextHandler(io.Discard, nil))) |
| 48 | got, err := Select(t.Context(), f.b, f.req) |
| 49 | if (err != nil) != (wantErr != nil) { |
| 50 | t.Fatalf("selector %v; litestream %v", err, wantErr) |
| 51 | } |
| 52 | if err != nil { |
| 53 | return |
| 54 | } |
| 55 | if len(got.Files) != len(want) { |
| 56 | t.Fatalf("length %d != %d", len(got.Files), len(want)) |
| 57 | } |
| 58 | for i, v := range want { |
| 59 | x := got.Files[i] |
| 60 | if x.Level != v.Level || x.MinTXID != uint64(v.MinTXID) || x.MaxTXID != uint64(v.MaxTXID) { |
| 61 | t.Fatalf("file %d: %+v != %+v", i, x, v) |
| 62 | } |
| 63 | } |
| 64 | }) |
| 65 | } |
| 66 | } |
| 67 | |