package moves import ( "math" "testing" "time" ) // Ported from internal/sim/hostlife/budget_test.go at 9c417aaa (the model of // moves spec §7.3 T11, rev 7.7 with rev 7.11's per-attempt pricing). The // model's fitsRev73 helper is dropped: it priced a rule the spec retired. func TestReadinessBudget(t *testing.T) { // a tiny instance: every fixed cost at the floor of its measured rate tiny := Estimate(1, 0, ExampleRates) // rev 7.3 required three attempts always: 150 s of probing alone, which // the default window never held if old := tiny.Fixed() + ProbeAttemptsMax*(tiny.Probe+tiny.Settle); old <= CutWindowDefault { t.Fatalf("rev 7.3's formula admits a tiny instance in the default window (%.1f s): R3-7 is stale", old) } if n := tiny.AttemptsAdmitted(CutWindowDefault); n != 2 { t.Fatalf("rev 7.4's formula admits %d attempts for a tiny instance in %.0f s, want 2", n, CutWindowDefault) } // the boundary: fixed costs of 70 s leave exactly one attempt; 71 s none edge := CutEstimate{Stop: 70 - OpenBudget, Open: OpenBudget, Probe: ProbeSeconds, Settle: SettleSeconds} if n := edge.AttemptsAdmitted(CutWindowDefault); n != 1 { t.Fatalf("fixed costs of 70 s admit %d attempts, want 1", n) } edge.Stop++ if n := edge.AttemptsAdmitted(CutWindowDefault); n != 0 { t.Fatalf("fixed costs of 71 s admit %d attempts, want 0 (refused)", n) } // a generous window never permits more than three if n := tiny.AttemptsAdmitted(600); n != ProbeAttemptsMax { t.Fatalf("a 600 s window admits %d attempts, want %d", n, ProbeAttemptsMax) } // R5-5: the spec's example, a 2 GiB database at the example rates. Rev // 7.5's full-snapshot transfer alone takes 205 s and could never fit; // the delta within the bar and the target's build do, with one attempt big := Estimate(2048, 0, ExampleRates) fullTransfer := 2048.0 / ExampleRates.Cross if fullTransfer < CutWindowDefault { t.Fatalf("the example no longer illustrates R5-5") } if n := big.AttemptsAdmitted(CutWindowDefault); n != 1 { t.Fatalf("a 2 GiB database at the example rates admits %d attempts, want 1 (fixed %.1f s, first attempt %.1f s)", n, big.Fixed(), big.Attempt(1)) } if math.Abs(big.Fixed()-53.6) > 0.1 { t.Fatalf("the example's fixed costs are %.1f s; the spec says 53.6 s", big.Fixed()) } // rev 7.11 (R10-8): the first attempt restores the prepared generation // again and pays the admission: 12.3 + 2 + 30 + 20 = 64.3 s, so the // example runs to 117.9 s and admits one attempt by 2.1 s; a second // attempt would add 76.6 s (a fresh generation's full upload too) if a := big.Attempt(1); math.Abs(a-64.3) > 0.1 { t.Fatalf("the example's first attempt costs %.1f s; the spec says 64.3 s", a) } if tot := big.Fixed() + big.Attempt(1); math.Abs(tot-117.9) > 0.1 { t.Fatalf("the example runs to %.1f s with one attempt; the spec says 117.9 s", tot) } if a := big.Attempt(2); math.Abs(a-76.6) > 0.1 { t.Fatalf("the example's second attempt would cost %.1f s; the spec says 76.6 s", a) } // the review's 2.5 GiB (R10-8): rev 7.10's arithmetic admitted it at // 113.8 s; with the probe's own restore it is 129.2 s, past the window, // and refused bigger := Estimate(2560, 0, ExampleRates) old := bigger.Fixed() + ProbeSeconds + SettleSeconds if math.Abs(old-113.8) > 0.1 { t.Fatalf("rev 7.10's arithmetic for 2.5 GiB is %.1f s; the review says 113.8 s", old) } if n := bigger.AttemptsAdmitted(CutWindowDefault); n != 0 { t.Fatalf("2.5 GiB at the example rates admits %d attempts, want 0 (%.1f s with one attempt)", n, bigger.Fixed()+bigger.Attempt(1)) } // and a cross-region snapshot transfer, if a builder did that instead, // is refused by the same arithmetic naive := big naive.Mirror, naive.RestoreStaged, naive.SnapshotBuild = fullTransfer, 0, 0 if n := naive.AttemptsAdmitted(CutWindowDefault); n != 0 { t.Fatalf("a full cross-region snapshot transfer admits %d attempts, want 0", n) } // R6-3: rev 7.6 priced three passes at one local rate and then restored // the generation cold a fourth time, unpriced. The review's workload: 3 // GiB, 200 MiB/s local, 10 MiB/s across regions, one probe. Three passes // admit one attempt (108.68 s with the probe); the fourth pass takes the // same workload to 124.04 s, past the window r := Rates{Cross: 10, S3: 200, Disk: 200} three := Estimate(3072, 0, r) three.RestoreStaged, three.SnapshotBuild, three.Anchor, three.Verify = 3072/200.0, 3072/200.0, 3072/200.0, 0 // rev 7.6's arithmetic three.RestoreAttempt, three.Admit, three.FreshUpload = 0, 0, 0 // rev 7.6's arithmetic knew no per-attempt restore if n := three.AttemptsAdmitted(CutWindowDefault); n != 1 { t.Fatalf("rev 7.6's three passes admit %d attempts for the review's workload, want 1 (the finding's premise; fixed %.2f s)", n, three.Fixed()) } four := three four.Verify = 3072 / 200.0 // the unpriced cold restore, at the same rate if n := four.AttemptsAdmitted(CutWindowDefault); n != 0 || four.Fixed()+ProbeSeconds+SettleSeconds < 124 { t.Fatalf("with the fourth pass priced the review's workload admits %d attempts at %.2f s with one probe, want 0 past 124 s", n, four.Fixed()+ProbeSeconds+SettleSeconds) } // rev 7.7 verifies the built database instead of restoring it again: // the same workload is refused honestly, by its own arithmetic if n := Estimate(3072, 0, r).AttemptsAdmitted(CutWindowDefault); n != 0 { t.Fatalf("rev 7.7 admits %d attempts for the review's workload, want 0 (fixed %.1f s)", n, Estimate(3072, 0, r).Fixed()) } } func TestBudgetTotalAndDeadline(t *testing.T) { e := Estimate(2048, 0, ExampleRates) n := e.AttemptsAdmitted(CutWindowDefault) if n != 1 || math.Abs(e.Total(n)-117.9) > 0.1 { t.Fatalf("attempts %d total %.1f", n, e.Total(n)) } // cut_deadline = cut_at + cut_budget - open_budget (§7.4). at := time.Date(2026, 10, 6, 9, 0, 0, 0, time.UTC) if d := CutDeadline(at, CutWindowDefault); !d.Equal(at.Add(115 * time.Second)) { t.Fatal(d) } } // The mirror bar is the one input Task 11 overrides // (CARLOS_MOVE_READY_DELTA_BYTES, Ruling F28(e)): zero means the default, // and the bar scales only the mirror. func TestEstimateMirrorBar(t *testing.T) { def := Estimate(2048, 0, ExampleRates) if want := MirrorBarMiB / ExampleRates.Cross; def.Mirror != want { t.Fatalf("default mirror %.2f s, want %.2f s", def.Mirror, want) } explicit := ExampleRates explicit.MirrorBar = MirrorBarMiB if got := Estimate(2048, 0, explicit); got != def { t.Fatalf("an explicit default bar changed the estimate: %+v vs %+v", got, def) } wide := ExampleRates wide.MirrorBar = 64 w := Estimate(2048, 0, wide) if math.Abs(w.Mirror-6.4) > 1e-9 { t.Fatalf("a 64 MiB bar at 10 MiB/s mirrors in %.2f s, want 6.4", w.Mirror) } if math.Abs((w.Fixed()-def.Fixed())-(6.4-1.6)) > 1e-9 { t.Fatalf("the bar moved more than the mirror: fixed %.2f vs %.2f", w.Fixed(), def.Fixed()) } if w.Attempt(1) != def.Attempt(1) { t.Fatalf("the bar changed a per-attempt cost") } // the open phase is the §7.4 open budget, not a second literal if def.Open != OpenBudget { t.Fatalf("Open %.1f, want OpenBudget %.1f", def.Open, OpenBudget) } } // An unusable input prices the cut at infinity: refused, never admitted. A // negative rate would otherwise price a phase below zero and let a move in. func TestEstimateInvalidInputsRefuse(t *testing.T) { nan, inf := math.NaN(), math.Inf(1) good := ExampleRates with := func(f func(r *Rates)) Rates { r := good; f(&r); return r } cases := map[string]struct { db float64 r Rates }{ "cross zero": {1, with(func(r *Rates) { r.Cross = 0 })}, "cross negative": {1, with(func(r *Rates) { r.Cross = -10 })}, "cross NaN": {1, with(func(r *Rates) { r.Cross = nan })}, "cross Inf": {1, with(func(r *Rates) { r.Cross = inf })}, "s3 zero": {1, with(func(r *Rates) { r.S3 = 0 })}, "s3 negative": {1, with(func(r *Rates) { r.S3 = -250 })}, "s3 NaN": {1, with(func(r *Rates) { r.S3 = nan })}, "s3 Inf": {1, with(func(r *Rates) { r.S3 = inf })}, "disk zero": {1, with(func(r *Rates) { r.Disk = 0 })}, "disk negative": {1, with(func(r *Rates) { r.Disk = -500 })}, "disk NaN": {1, with(func(r *Rates) { r.Disk = nan })}, "disk Inf": {1, with(func(r *Rates) { r.Disk = inf })}, "bar negative": {1, with(func(r *Rates) { r.MirrorBar = -16 })}, "bar NaN": {1, with(func(r *Rates) { r.MirrorBar = nan })}, "bar Inf": {1, with(func(r *Rates) { r.MirrorBar = inf })}, "db negative": {-2048, good}, "db NaN": {nan, good}, "db Inf": {inf, good}, // a negative database against a negative rate: the quotient is // positive, and must still be refused "db and s3 negative": {-1, with(func(r *Rates) { r.S3 = -250 })}, } for name, c := range cases { e := Estimate(c.db, 0, c.r) if n := e.AttemptsAdmitted(CutWindowDefault); n != 0 { t.Errorf("%s admits %d attempts, want 0", name, n) } if n := e.AttemptsAdmitted(1e9); n != 0 { t.Errorf("%s admits %d attempts in a huge window, want 0", name, n) } if f := e.Fixed(); !math.IsInf(f, 1) { t.Errorf("%s fixed cost %v, want +Inf", name, f) } } // the boundary the refusals must not touch: an empty database is valid if n := Estimate(0, 0, ExampleRates).AttemptsAdmitted(CutWindowDefault); n != 2 { t.Errorf("an empty database admits %d attempts, want 2", n) } } // Ruling T7-budget: the landing's fsync scales with the archive's entry // count, so the Archive term is max(2, entries/FsyncRate) seconds. Every // new input keeps the invalid-input refusal. func TestEstimateArchiveScalesWithEntries(t *testing.T) { r := ExampleRates if got := Estimate(2048, 0, r).Archive; got != 2 { t.Fatalf("no entries: Archive %v, want 2", got) } if got := Estimate(2048, 100, r).Archive; got != 2 { t.Fatalf("a few entries: Archive %v, want the 2 s floor", got) } want := 32000 / r.FsyncRate if got := Estimate(2048, 32000, r).Archive; got != want || got <= 2 { t.Fatalf("32000 entries: Archive %v, want %v", got, want) } if Estimate(2048, 32000, r).Fixed() <= Estimate(2048, 0, r).Fixed() { t.Fatal("entries did not reach the fixed cost") } // No entries needs no fsync rate. noRate := r noRate.FsyncRate = 0 if got := Estimate(2048, 0, noRate).Archive; got != 2 { t.Fatalf("no entries, no rate: Archive %v, want 2", got) } nan, inf := math.NaN(), math.Inf(1) for name, c := range map[string]struct { entries int fsync float64 }{ "negative entries": {-1, r.FsyncRate}, "entries and no rate": {10, 0}, "negative rate": {10, -1600}, "negative rate, no files": {0, -1600}, "NaN rate": {10, nan}, "NaN rate, no files": {0, nan}, "Inf rate": {10, inf}, } { rr := r rr.FsyncRate = c.fsync e := Estimate(2048, c.entries, rr) if !math.IsInf(e.Fixed(), 1) || e.AttemptsAdmitted(1e9) != 0 { t.Errorf("%s: fixed %v, %d attempts; want refused", name, e.Fixed(), e.AttemptsAdmitted(1e9)) } } }