package hostrelocate import ( "context" "encoding/json" "strings" "testing" "time" "github.com/carlosframework/platform/internal/genselect" "github.com/carlosframework/platform/internal/hostfiles" "github.com/carlosframework/platform/internal/lease/leasetest" "github.com/carlosframework/platform/internal/release" "github.com/superfly/ltx" ) // Stage B Task 10's binding: the pass's StorePinner selects the database // with genselect.Select over the region's versioned data bucket. The pin // names exactly the versions the bucket holds for the holder's generation // (its marker's snapshot and the level-0 file after it), the plan's MaxTXID, // and the release the pinner's Release answers. func TestRelocationPinnerSelectsOverTheVersionedBucket(t *testing.T) { ctx := context.Background() hdr := func(min, max uint64) []byte { b, err := (<x.Header{Version: ltx.Version, Flags: ltx.HeaderFlagNoChecksum, PageSize: 4096, MinTXID: ltx.TXID(min), MaxTXID: ltx.TXID(max)}).MarshalBinary() if err != nil { t.Fatal(err) } return b } b := leasetest.NewVersionedBucket() b.AddBucket("data") snap := pinLocation + "/g-g3/0009/" + ltx.FormatFilename(1, 40) snapVersion := b.Put("data", snap, hdr(1, 40)) tail := pinLocation + "/g-g3/0000/" + ltx.FormatFilename(41, 41) tailVersion := b.Put("data", tail, hdr(41, 41)) marker, _ := json.Marshal(genselect.Marker{Op: "g3", Incarnation: "inc", Host: host, Box: "src", InstalledAt: time.Date(2026, 10, 7, 8, 0, 0, 0, time.UTC), ManifestSHA256: strings.Repeat("a", 64), Pin: genselect.Pin{SnapshotKey: snap, SnapshotVersion: snapVersion, SnapshotTXID: 40, SnapshotCRC64: 1}}) b.Put("data", pinLocation+"/generation.json", marker) claims, data := release.NewDirStore(t.TempDir()), release.NewDirStore(t.TempDir()) putManifest(t, data, "g3", keyed(hostfiles.Manifest{V: hostfiles.ManifestVersion, Seq: 5, Entries: map[string]hostfiles.Entry{}, Platform: map[string]hostfiles.Entry{}})) p := StorePinner{Claims: claims, Data: data, Release: routeRelease, Bucket: "data", Region: "ie", SelectDB: func(ctx context.Context, r genselect.Request) (*genselect.Plan, error) { return genselect.Select(ctx, b, r) }} obs := pinClaim() obs.Claim.Holder.Incarnation = "inc" pin, err := p.Pin(ctx, obs, time.Date(2026, 10, 7, 9, 0, 0, 0, time.UTC)) if err != nil { t.Fatal(err) } if pin.Generation != "g3" || pin.MaxTXID != 41 || pin.Release != "v1.4.2" || pin.FilesSeq != 5 || pin.Empty { t.Fatalf("pin %+v", pin) } obj, err := ReadPin(ctx, claims, pin) if err != nil { t.Fatal(err) } got := map[string]string{} for _, f := range obj.DB.Files { got[f.Key] = f.VersionID } if obj.DB.MaxTXID != 41 || got[snap] != snapVersion || got[tail] != tailVersion || len(got) != 2 { t.Fatalf("pinned files %v (max %d)", got, obj.DB.MaxTXID) } }