| index 923e302bc..577116b41 100644 |
| --- a/internal/hostclaim/generation_test.go |
| +++ b/internal/hostclaim/generation_test.go |
| @@ -33,7 +33,7 @@ func TestAdmitWriterWarmColdAdmissions(t *testing.T) { |
| t.Fatalf("zero %s must be omitted", name) |
| } |
| } |
| - o, err = Update(ctx, s, o, AdmitWriter(Admission{Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a", PredecessorCertified: true})) |
| + o, err = Update(ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a", PredecessorCertified: true})) |
| if err != nil { |
| t.Fatal(err) |
| } |
| @@ -41,7 +41,7 @@ func TestAdmitWriterWarmColdAdmissions(t *testing.T) { |
| if o.Claim.Holder.WriterBox != "adi-knitting" || o.Claim.Holder.Generation != "gen_a" || o.Claim.Holder.Stamp != cold || o.Claim.Holder.Session != cold || cold <= stamp { |
| t.Fatalf("cold holder = %+v, gen = %d", o.Claim.Holder, cold) |
| } |
| - first := AdmissionRecord{Session: cold, Box: "adi-knitting", Generation: "gen_a", Mode: "cold"} |
| + first := AdmissionRecord{Region: "ie", PredecessorRegion: "ie", Session: cold, Box: "adi-knitting", Generation: "gen_a", Mode: "cold"} |
| assertAdmissions(t, o.Claim, []AdmissionRecord{first}) |
| o, err = Update(ctx, s, o, func(c *Claim) error { |
| c.Op.Exec = "boxT" |
| @@ -50,7 +50,7 @@ func TestAdmitWriterWarmColdAdmissions(t *testing.T) { |
| if err != nil { |
| t.Fatal(err) |
| } |
| - o, err = Update(ctx, s, o, AdmitWriter(Admission{ObservedSession: cold, ObservedGeneration: "gen_a", Box: "boxT", Mode: "warm", PredecessorCertified: true})) |
| + o, err = Update(ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedSession: cold, ObservedGeneration: "gen_a", Box: "boxT", Mode: "warm", PredecessorCertified: true})) |
| if err != nil { |
| t.Fatal(err) |
| } |
| @@ -58,16 +58,16 @@ func TestAdmitWriterWarmColdAdmissions(t *testing.T) { |
| if o.Claim.Holder.WriterBox != "boxT" || o.Claim.Holder.Session != warm || warm <= cold || o.Claim.Holder.Generation != "gen_a" || o.Claim.Holder.Stamp != cold { |
| t.Fatalf("warm holder = %+v, gen = %d", o.Claim.Holder, warm) |
| } |
| - second := AdmissionRecord{Session: warm, Box: "boxT", Generation: "gen_a", Mode: "warm", Predecessor: "gen_a"} |
| + second := AdmissionRecord{Region: "ie", PredecessorRegion: "ie", Session: warm, Box: "boxT", Generation: "gen_a", Mode: "warm", Predecessor: "gen_a"} |
| assertAdmissions(t, o.Claim, []AdmissionRecord{first, second}) |
| - o, err = Update(ctx, s, o, AdmitWriter(Admission{ObservedSession: warm, ObservedGeneration: "gen_a", Box: "boxT", Mode: "cold", NewGeneration: "gen_b", PredecessorCertified: true})) |
| + o, err = Update(ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedSession: warm, ObservedGeneration: "gen_a", Box: "boxT", Mode: "cold", NewGeneration: "gen_b", PredecessorCertified: true})) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if o.Claim.Holder.Generation != "gen_b" || o.Claim.Holder.Stamp != o.Claim.Gen || o.Claim.Holder.Session != o.Claim.Gen { |
| t.Fatalf("second cold holder = %+v, gen = %d", o.Claim.Holder, o.Claim.Gen) |
| } |
| - third := AdmissionRecord{Session: o.Claim.Gen, Box: "boxT", Generation: "gen_b", Mode: "cold", Predecessor: "gen_a"} |
| + third := AdmissionRecord{Region: "ie", PredecessorRegion: "ie", Session: o.Claim.Gen, Box: "boxT", Generation: "gen_b", Mode: "cold", Predecessor: "gen_a"} |
| assertAdmissions(t, o.Claim, []AdmissionRecord{first, second, third}) |
| stored, err := Read(ctx, s, testHost) |
| if err != nil { |
| @@ -109,7 +109,7 @@ func TestAdmitWriterPreservesOperation(t *testing.T) { |
| if mode == "cold" { |
| generation = "gen_a" |
| } |
| - next, err := Update(ctx, s, o, AdmitWriter(Admission{ObservedOpID: "m1", ObservedPhase: "probe", Box: "boxT", Mode: mode, NewGeneration: generation, PredecessorCertified: true})) |
| + next, err := Update(ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedOpID: "m1", ObservedPhase: "probe", Box: "boxT", Mode: mode, NewGeneration: generation, PredecessorCertified: true})) |
| if err != nil { |
| t.Fatal(err) |
| } |
| @@ -123,7 +123,7 @@ func TestAdmitWriterPreservesOperation(t *testing.T) { |
| want.Holder.Generation = generation |
| want.Holder.Stamp = want.Gen |
| } |
| - want.Holder.Admissions = []AdmissionRecord{{Session: want.Gen, Box: "boxT", Generation: generation, Mode: mode}} |
| + want.Holder.Admissions = []AdmissionRecord{{Region: "ie", PredecessorRegion: "ie", Session: want.Gen, Box: "boxT", Generation: generation, Mode: mode}} |
| if !reflect.DeepEqual(next.Claim, &want) { |
| t.Fatalf("admission changed fields outside holder writer fields and admissions: got %+v, want %+v", next.Claim, &want) |
| } |
| @@ -178,7 +178,7 @@ func TestAdmitWriterRefusals(t *testing.T) { |
| case "empty mode": |
| mode = "" |
| } |
| - in := Admission{ObservedOpID: o.Claim.Op.ID, ObservedPhase: o.Claim.Op.Phase, ObservedSession: session, ObservedGeneration: generation, Box: box, Mode: mode, NewGeneration: newGeneration, PredecessorCertified: true} |
| + in := Admission{Region: "ie", PredecessorRegion: "ie", ObservedOpID: o.Claim.Op.ID, ObservedPhase: o.Claim.Op.Phase, ObservedSession: session, ObservedGeneration: generation, Box: box, Mode: mode, NewGeneration: newGeneration, PredecessorCertified: true} |
| switch name { |
| case "warm without certificate": |
| in.Mode, in.NewGeneration, in.PredecessorCertified = "warm", "", false |
| @@ -207,7 +207,7 @@ func TestAdmitWriterCompetingAdmissions(t *testing.T) { |
| ctx := context.Background() |
| s := release.NewDirStore(t.TempDir()) |
| before := servingClaim(t, ctx, s) |
| - in := Admission{Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a"} |
| + in := Admission{Region: "ie", PredecessorRegion: "ie", Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a"} |
| first := AdmitWriter(in) |
| in.NewGeneration = "gen_b" |
| second := AdmitWriter(in) |
| @@ -229,7 +229,7 @@ func TestAdmitWriterLostResponse(t *testing.T) { |
| ctx := context.Background() |
| s := release.NewDirStore(t.TempDir()) |
| before := servingClaim(t, ctx, s) |
| - admit := AdmitWriter(Admission{Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a"}) |
| + admit := AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a"}) |
| admitted, err := Update(ctx, s, before, admit) |
| if err != nil { |
| t.Fatal(err) |
| @@ -246,7 +246,7 @@ func TestAdmitWriterBoundToOperationAndPhase(t *testing.T) { |
| ctx := context.Background() |
| s := release.NewDirStore(t.TempDir()) |
| o := servingClaim(t, ctx, s) |
| - stale := AdmitWriter(Admission{Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a"}) |
| + stale := AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a"}) |
| var err error |
| if change == "delete" { |
| o, err = Update(ctx, s, o, BeginDelete("d1", "console", "etag", time.Now(), nil, nil)) |
| @@ -268,7 +268,7 @@ func TestAdmitWriterBoundToOperationAndPhase(t *testing.T) { |
| } |
| assertAdmissionStored(t, ctx, s, o) |
| if change == "delete" { |
| - fresh := AdmitWriter(Admission{ObservedOpID: "d1", Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a"}) |
| + fresh := AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedOpID: "d1", Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a"}) |
| if _, err := Update(ctx, s, o, fresh); !errors.Is(err, ErrWrongState) { |
| t.Fatalf("deleting admission = %v", err) |
| } |
| @@ -293,7 +293,7 @@ func TestAdmitWriterSurvivesOperationReplacement(t *testing.T) { |
| ctx := context.Background() |
| s := release.NewDirStore(t.TempDir()) |
| o := servingClaim(t, ctx, s) |
| - o, err := Update(ctx, s, o, AdmitWriter(Admission{Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a"})) |
| + o, err := Update(ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a"})) |
| if err != nil { |
| t.Fatal(err) |
| } |
| @@ -319,11 +319,11 @@ func TestAdmitWriterSurvivesOperationReplacement(t *testing.T) { |
| if transition == "delete" { |
| return |
| } |
| - o, err = Update(ctx, s, o, AdmitWriter(Admission{ObservedOpID: "m1", ObservedPhase: "probe", ObservedSession: writer.Session, ObservedGeneration: writer.Generation, Box: "boxT", Mode: "cold", NewGeneration: "gen_b", RemoteMaxTXID: 42})) |
| + o, err = Update(ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedOpID: "m1", ObservedPhase: "probe", ObservedSession: writer.Session, ObservedGeneration: writer.Generation, Box: "boxT", Mode: "cold", NewGeneration: "gen_b", RemoteMaxTXID: 42})) |
| if err != nil { |
| t.Fatal(err) |
| } |
| - want := append(append([]AdmissionRecord(nil), writer.Admissions...), AdmissionRecord{ |
| + want := append(append([]AdmissionRecord(nil), writer.Admissions...), AdmissionRecord{Region: "ie", PredecessorRegion: "ie", |
| Session: o.Claim.Gen, Box: "boxT", Generation: "gen_b", Mode: "cold", Predecessor: "gen_a", |
| WritesLost: &WritesLost{Box: "adi-knitting", Generation: "gen_a", Session: writer.Session, RemoteMaxTXID: 42}, |
| }) |
| @@ -354,7 +354,7 @@ func TestAdmitWriterKeepStamp(t *testing.T) { |
| ctx := context.Background() |
| s := release.NewDirStore(t.TempDir()) |
| o := servingClaim(t, ctx, s) |
| - o, err := Update(ctx, s, o, AdmitWriter(Admission{Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a", PredecessorCertified: true})) |
| + o, err := Update(ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a", PredecessorCertified: true})) |
| if err != nil { |
| t.Fatal(err) |
| } |
| @@ -365,13 +365,13 @@ func TestAdmitWriterKeepStamp(t *testing.T) { |
| return nil |
| }) |
| } else if name == "later session" { |
| - o, err = Update(ctx, s, o, AdmitWriter(Admission{ObservedSession: o.Claim.Holder.Session, ObservedGeneration: "gen_a", Box: "adi-knitting", Mode: "warm", PredecessorCertified: true})) |
| + o, err = Update(ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedSession: o.Claim.Holder.Session, ObservedGeneration: "gen_a", Box: "adi-knitting", Mode: "warm", PredecessorCertified: true})) |
| } |
| if err != nil { |
| t.Fatal(err) |
| } |
| before := *o.Claim.Holder |
| - in := Admission{ObservedOpID: o.Claim.Op.ID, ObservedPhase: o.Claim.Op.Phase, ObservedSession: before.Session, ObservedGeneration: before.Generation, Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "gen_b", KeepStamp: true, PredecessorCertified: true} |
| + in := Admission{Region: "ie", PredecessorRegion: "ie", ObservedOpID: o.Claim.Op.ID, ObservedPhase: o.Claim.Op.Phase, ObservedSession: before.Session, ObservedGeneration: before.Generation, Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "gen_b", KeepStamp: true, PredecessorCertified: true} |
| if name == "warm" { |
| in.Mode, in.NewGeneration = "warm", "" |
| } |
| @@ -389,7 +389,7 @@ func TestAdmitWriterKeepStamp(t *testing.T) { |
| if next.Claim.Holder.Stamp != before.Stamp || next.Claim.Holder.Session != next.Claim.Gen || next.Claim.Holder.Generation != "gen_b" { |
| t.Fatalf("landing admission holder = %+v, prior stamp = %d", next.Claim.Holder, before.Stamp) |
| } |
| - want := append(append([]AdmissionRecord(nil), before.Admissions...), AdmissionRecord{ |
| + want := append(append([]AdmissionRecord(nil), before.Admissions...), AdmissionRecord{Region: "ie", PredecessorRegion: "ie", |
| Session: next.Claim.Gen, Box: "boxT", Generation: "gen_b", Mode: "cold", Predecessor: "gen_a", |
| }) |
| assertAdmissions(t, next.Claim, want) |
| @@ -414,15 +414,15 @@ func TestAdmitWriterCoverage(t *testing.T) { |
| ctx := context.Background() |
| s := release.NewDirStore(t.TempDir()) |
| o := servingClaim(t, ctx, s) |
| - o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a", PredecessorCertified: true})) |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", Box: "adi-knitting", Mode: "cold", NewGeneration: "gen_a", PredecessorCertified: true})) |
| before := *o.Claim.Holder |
| - in := Admission{ObservedSession: before.Session, ObservedGeneration: before.Generation, Box: "adi-knitting", Mode: mode, PredecessorCertified: certified, Coverage: coverage, RemoteMaxTXID: 42} |
| + in := Admission{Region: "ie", PredecessorRegion: "ie", ObservedSession: before.Session, ObservedGeneration: before.Generation, Box: "adi-knitting", Mode: mode, PredecessorCertified: certified, Coverage: coverage, RemoteMaxTXID: 42} |
| generation := before.Generation |
| if mode == "cold" { |
| in.NewGeneration, generation = "gen_b", "gen_b" |
| } |
| o = updateGenerationTest(t, ctx, s, o, AdmitWriter(in)) |
| - last := AdmissionRecord{Session: o.Claim.Gen, Box: "adi-knitting", Generation: generation, Predecessor: "gen_a", Mode: mode, Coverage: coverage} |
| + last := AdmissionRecord{Region: "ie", PredecessorRegion: "ie", Session: o.Claim.Gen, Box: "adi-knitting", Generation: generation, Predecessor: "gen_a", Mode: mode, Coverage: coverage} |
| if mode == "cold" && !certified && coverage == "" { |
| last.WritesLost = &WritesLost{Box: "adi-knitting", Generation: "gen_a", Session: before.Session, RemoteMaxTXID: 42} |
| } |
| @@ -453,15 +453,15 @@ func TestAdmitWriterCleanReturnPredecessor(t *testing.T) { |
| c.Op = Op{Kind: KindLanding, ID: "move", Phase: "probe", Exec: "boxT"} |
| return nil |
| }) |
| - o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{ObservedOpID: "move", ObservedPhase: "probe", Box: "boxT", Mode: "cold", NewGeneration: "GT"})) |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedOpID: "move", ObservedPhase: "probe", Box: "boxT", Mode: "cold", NewGeneration: "GT"})) |
| target := o.Claim.Holder.Admissions[0] |
| o = updateGenerationTest(t, ctx, s, o, func(c *Claim) error { |
| c.Holder.Generation = "GS" |
| c.Op = Op{Kind: KindServing, Exec: "boxS"} |
| return nil |
| }) |
| - o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{ObservedSession: target.Session, ObservedGeneration: "GS", Box: "boxS", Mode: "cold", NewGeneration: "GS2", Coverage: coverage, RemoteMaxTXID: 42})) |
| - last := AdmissionRecord{Session: o.Claim.Gen, Box: "boxS", Generation: "GS2", Predecessor: "GT", Mode: "cold", Coverage: coverage} |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedSession: target.Session, ObservedGeneration: "GS", Box: "boxS", Mode: "cold", NewGeneration: "GS2", Coverage: coverage, RemoteMaxTXID: 42})) |
| + last := AdmissionRecord{Region: "ie", PredecessorRegion: "ie", Session: o.Claim.Gen, Box: "boxS", Generation: "GS2", Predecessor: "GT", Mode: "cold", Coverage: coverage} |
| if coverage == "" { |
| last.WritesLost = &WritesLost{Box: "boxT", Generation: "GT", Session: target.Session, RemoteMaxTXID: 42} |
| } |
| @@ -500,8 +500,8 @@ func TestAdoptAdmitPublishRootGeneration(t *testing.T) { |
| return nil |
| }) |
| } |
| - o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "G1", RemoteMaxTXID: 42})) |
| - assertAdmissions(t, o.Claim, []AdmissionRecord{{ |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "G1", RemoteMaxTXID: 42})) |
| + assertAdmissions(t, o.Claim, []AdmissionRecord{{Region: "ie", PredecessorRegion: "ie", |
| Session: o.Claim.Gen, Box: o.Claim.Op.Exec, Generation: "G1", Mode: "cold", |
| WritesLost: &WritesLost{Box: "boxS", Session: 0, Generation: "", RemoteMaxTXID: 42}, |
| }}) |
| @@ -539,7 +539,7 @@ func TestPublishGenerationChain(t *testing.T) { |
| }) |
| } |
| for _, generation := range []string{"G1", "G2"} { |
| - o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{ObservedOpID: o.Claim.Op.ID, ObservedPhase: o.Claim.Op.Phase, |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedOpID: o.Claim.Op.ID, ObservedPhase: o.Claim.Op.Phase, |
| ObservedSession: o.Claim.Holder.Session, ObservedGeneration: o.Claim.Holder.Generation, |
| Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: generation})) |
| } |
| @@ -582,7 +582,7 @@ func TestPublishGenerationRefusals(t *testing.T) { |
| ctx := context.Background() |
| s := release.NewDirStore(t.TempDir()) |
| o := servingClaim(t, ctx, s) |
| - o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Box: "adi-knitting", Mode: "cold", NewGeneration: "G1"})) |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", Box: "adi-knitting", Mode: "cold", NewGeneration: "G1"})) |
| o = updateGenerationTest(t, ctx, s, o, func(c *Claim) error { |
| c.Op = Op{Kind: KindLanding, ID: "move", Phase: "probe", Exec: "boxT"} |
| if name == "no holder" { |
| @@ -626,12 +626,12 @@ func TestPublishGenerationCoverageBoundary(t *testing.T) { |
| o = updateGenerationTest(t, ctx, s, o, func(c *Claim) error { |
| c.Holder.Generation = "G2" |
| c.Holder.Admissions = []AdmissionRecord{ |
| - {Generation: "old", Predecessor: "already-covered", Covered: true}, |
| - {Generation: "G1", Predecessor: ""}, |
| - {Generation: "G1", Predecessor: RootGeneration}, |
| - {Generation: "G2", Predecessor: "G1"}, |
| - {Generation: "G2", Predecessor: "G2", Mode: "warm"}, |
| - {Generation: "later", Predecessor: "G2"}, |
| + {Region: "ie", PredecessorRegion: "ie", Generation: "old", Predecessor: "already-covered", Covered: true}, |
| + {Region: "ie", PredecessorRegion: "ie", Generation: "G1", Predecessor: ""}, |
| + {Region: "ie", PredecessorRegion: "ie", Generation: "G1", Predecessor: RootGeneration}, |
| + {Region: "ie", PredecessorRegion: "ie", Generation: "G2", Predecessor: "G1"}, |
| + {Region: "ie", PredecessorRegion: "ie", Generation: "G2", Predecessor: "G2", Mode: "warm"}, |
| + {Region: "ie", PredecessorRegion: "ie", Generation: "later", Predecessor: "G2"}, |
| } |
| c.Obligations = []Obligation{ |
| {ID: "existing", Op: "old-op", Kind: "park-generation", Region: "ie", Generation: "G1", Retirement: "ret1", Owner: "region:ie"}, |
| @@ -660,7 +660,7 @@ func TestPublishGenerationActiveRoot(t *testing.T) { |
| ctx := context.Background() |
| s := release.NewDirStore(t.TempDir()) |
| o := servingClaim(t, ctx, s) |
| - o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Box: "adi-knitting", Mode: "warm", PredecessorCertified: true})) |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", Box: "adi-knitting", Mode: "warm", PredecessorCertified: true})) |
| o = updateGenerationTest(t, ctx, s, o, PublishGeneration("", "", o.Claim.Holder.Session, "", "ie", func() string { |
| t.Fatal("active root must not be retired") |
| return "" |
| @@ -677,7 +677,7 @@ func TestAdmitWriterTrimsCoveredPrefix(t *testing.T) { |
| s := release.NewDirStore(t.TempDir()) |
| o := servingClaim(t, ctx, s) |
| for i := 1; i <= 10; i++ { |
| - o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{ObservedSession: o.Claim.Holder.Session, ObservedGeneration: o.Claim.Holder.Generation, |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedSession: o.Claim.Holder.Session, ObservedGeneration: o.Claim.Holder.Generation, |
| Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: fmt.Sprintf("G%d", i)})) |
| } |
| if len(o.Claim.Holder.Admissions) != 10 { |
| @@ -695,7 +695,7 @@ func TestAdmitWriterTrimsCoveredPrefix(t *testing.T) { |
| }) |
| } |
| before := o.Claim.Holder.Admissions |
| - o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{ObservedSession: o.Claim.Holder.Session, ObservedGeneration: "G10", |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedSession: o.Claim.Holder.Session, ObservedGeneration: "G10", |
| Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "G11", PredecessorCertified: true})) |
| drop := 3 |
| if name == "uncovered first" { |
| @@ -703,7 +703,7 @@ func TestAdmitWriterTrimsCoveredPrefix(t *testing.T) { |
| } else if name == "uncovered middle" { |
| drop = 1 |
| } |
| - want := append(append([]AdmissionRecord(nil), before[drop:]...), AdmissionRecord{Session: o.Claim.Gen, Box: o.Claim.Op.Exec, Generation: "G11", Predecessor: "G10", Mode: "cold"}) |
| + want := append(append([]AdmissionRecord(nil), before[drop:]...), AdmissionRecord{Region: "ie", PredecessorRegion: "ie", Session: o.Claim.Gen, Box: o.Claim.Op.Exec, Generation: "G11", Predecessor: "G10", Mode: "cold"}) |
| assertAdmissions(t, o.Claim, want) |
| }) |
| } |
| @@ -713,8 +713,8 @@ func TestAdmissionRecordJSON(t *testing.T) { |
| ctx := context.Background() |
| s := release.NewDirStore(t.TempDir()) |
| o := servingClaim(t, ctx, s) |
| - o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Box: "adi-knitting", Mode: "cold", NewGeneration: "G1", RemoteMaxTXID: 42})) |
| - o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{ObservedSession: o.Claim.Holder.Session, ObservedGeneration: "G1", Box: "adi-knitting", Mode: "cold", NewGeneration: "G2", Coverage: "sealed", PredecessorCertified: true})) |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", Box: "adi-knitting", Mode: "cold", NewGeneration: "G1", RemoteMaxTXID: 42})) |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", ObservedSession: o.Claim.Holder.Session, ObservedGeneration: "G1", Box: "adi-knitting", Mode: "cold", NewGeneration: "G2", Coverage: "sealed", PredecessorCertified: true})) |
| o = updateGenerationTest(t, ctx, s, o, PublishGeneration("", "", o.Claim.Holder.Session, "G2", "ie", counter())) |
| raw, err := json.Marshal(o.Claim.Holder) |
| if err != nil { |
| @@ -729,9 +729,9 @@ func TestAdmissionRecordJSON(t *testing.T) { |
| t.Fatal(err) |
| } |
| want := []map[string]any{ |
| - {"session": float64(o.Claim.Holder.Admissions[0].Session), "box": "adi-knitting", "generation": "G1", "mode": "cold", "covered": true, |
| + {"region": "ie", "predecessor_region": "ie", "session": float64(o.Claim.Holder.Admissions[0].Session), "box": "adi-knitting", "generation": "G1", "mode": "cold", "covered": true, |
| "writes_lost": map[string]any{"box": "", "generation": "", "session": float64(0), "remote_max_txid": float64(42)}}, |
| - {"session": float64(o.Claim.Holder.Session), "box": "adi-knitting", "generation": "G2", "predecessor": "G1", "mode": "cold", "coverage": "sealed", "covered": true}, |
| + {"region": "ie", "predecessor_region": "ie", "session": float64(o.Claim.Holder.Session), "box": "adi-knitting", "generation": "G2", "predecessor": "G1", "mode": "cold", "coverage": "sealed", "covered": true}, |
| } |
| if !reflect.DeepEqual(got, want) { |
| t.Fatalf("admissions JSON = %s, want %+v", holder["admissions"], want) |
| @@ -747,8 +747,206 @@ func TestAdmitWriterIgnoresLegacyWriterJournal(t *testing.T) { |
| return nil |
| }) |
| before := o.Claim.Op |
| - o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Box: "adi-knitting", Mode: "cold", NewGeneration: "G1"})) |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", Box: "adi-knitting", Mode: "cold", NewGeneration: "G1"})) |
| if !reflect.DeepEqual(o.Claim.Op, before) || len(o.Claim.Holder.Admissions) != 1 { |
| t.Fatalf("legacy journal affected admission: %+v", o.Claim) |
| } |
| } |
| + |
| +func TestPublishGenerationForeignRegion(t *testing.T) { |
| + ctx := context.Background() |
| + s := release.NewDirStore(t.TempDir()) |
| + o := servingClaim(t, ctx, s) |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", PredecessorRegion: "ie", Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "G1"})) |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "uk", ObservedSession: o.Claim.Holder.Session, ObservedGeneration: "G1", Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "G2"})) |
| + newID := func() string { t.Fatal("foreign-region publication allocated an ID"); return "" } |
| + publish := PublishGeneration("", "", o.Claim.Holder.Session, "G2", "uk", newID) |
| + o = updateGenerationTest(t, ctx, s, o, publish) |
| + for _, record := range o.Claim.Holder.Admissions { |
| + if record.Covered || record.PredecessorRegion != "ie" { |
| + t.Fatalf("foreign predecessor = %+v", record) |
| + } |
| + } |
| + if len(o.Claim.Obligations) != 0 { |
| + t.Fatalf("foreign publication queued chores: %+v", o.Claim.Obligations) |
| + } |
| + o = updateGenerationTest(t, ctx, s, o, CoverRegionPredecessors("", "", "ie")) |
| + for _, record := range o.Claim.Holder.Admissions { |
| + if !record.Covered { |
| + t.Fatalf("source cleanup left predecessor uncovered: %+v", record) |
| + } |
| + } |
| + before := *o.Claim |
| + o = updateGenerationTest(t, ctx, s, o, publish) |
| + before.Gen++ |
| + if len(o.Claim.Obligations) != 0 || !reflect.DeepEqual(o.Claim, &before) { |
| + t.Fatalf("publication after source coverage changed claim: %+v", o.Claim) |
| + } |
| +} |
| + |
| +func TestPublishGenerationHoldsNone(t *testing.T) { |
| + ctx := context.Background() |
| + s := release.NewDirStore(t.TempDir()) |
| + o := servingClaim(t, ctx, s) |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "G1"})) |
| + o = updateGenerationTest(t, ctx, s, o, PublishGeneration("", "", o.Claim.Holder.Session, "G1", "ie", func() string { |
| + t.Fatal("predecessor with no objects allocated an ID") |
| + return "" |
| + })) |
| + if !o.Claim.Holder.Admissions[0].Covered || len(o.Claim.Obligations) != 0 { |
| + t.Fatalf("empty predecessor publication = %+v", o.Claim) |
| + } |
| + raw, err := json.Marshal(o.Claim.Holder.Admissions[0]) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + var fields map[string]json.RawMessage |
| + if err := json.Unmarshal(raw, &fields); err != nil { |
| + t.Fatal(err) |
| + } |
| + if string(fields["region"]) != `"ie"` || fields["predecessor_region"] != nil { |
| + t.Fatalf("region JSON = %s", raw) |
| + } |
| +} |
| + |
| +func TestAdmitWriterRegionRules(t *testing.T) { |
| + for _, name := range []string{"empty region", "warm other region", "warm same region", "recorded predecessor region", "first predecessor region", "first warm other region"} { |
| + t.Run(name, func(t *testing.T) { |
| + ctx := context.Background() |
| + s := release.NewDirStore(t.TempDir()) |
| + o := servingClaim(t, ctx, s) |
| + if name != "first predecessor region" && name != "empty region" && name != "first warm other region" { |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "ie", Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "G1"})) |
| + } |
| + in := Admission{Region: "uk", PredecessorRegion: "fr", ObservedSession: o.Claim.Holder.Session, ObservedGeneration: o.Claim.Holder.Generation, |
| + Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: "G2", PredecessorCertified: true} |
| + switch name { |
| + case "empty region": |
| + in.Region = "" |
| + case "warm other region", "warm same region", "first warm other region": |
| + in.Mode, in.NewGeneration = "warm", "" |
| + if name == "warm same region" { |
| + in.Region = "ie" |
| + } |
| + } |
| + next, err := Update(ctx, s, o, AdmitWriter(in)) |
| + if name == "empty region" || name == "warm other region" || name == "first warm other region" { |
| + if !errors.Is(err, ErrWrongState) { |
| + t.Fatalf("admission = %v, want ErrWrongState", err) |
| + } |
| + assertAdmissionStored(t, ctx, s, o) |
| + return |
| + } |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + assertAdmissionStored(t, ctx, s, next) |
| + record := next.Claim.Holder.Admissions[len(next.Claim.Holder.Admissions)-1] |
| + wantPredecessorRegion := "ie" |
| + if name == "first predecessor region" { |
| + wantPredecessorRegion = "fr" |
| + } |
| + if record.Region != in.Region || record.PredecessorRegion != wantPredecessorRegion { |
| + t.Fatalf("admission regions = %+v, want %q / %q", record, in.Region, wantPredecessorRegion) |
| + } |
| + }) |
| + } |
| +} |
| + |
| +func TestAdmitWriterNeverTrimsForeignUncovered(t *testing.T) { |
| + ctx := context.Background() |
| + s := release.NewDirStore(t.TempDir()) |
| + o := servingClaim(t, ctx, s) |
| + newID := counter() |
| + for i := 1; i <= 12; i++ { |
| + o = updateGenerationTest(t, ctx, s, o, AdmitWriter(Admission{Region: "uk", PredecessorRegion: "ie", |
| + ObservedSession: o.Claim.Holder.Session, ObservedGeneration: o.Claim.Holder.Generation, |
| + Box: o.Claim.Op.Exec, Mode: "cold", NewGeneration: fmt.Sprintf("G%d", i)})) |
| + o = updateGenerationTest(t, ctx, s, o, PublishGeneration("", "", o.Claim.Holder.Session, o.Claim.Holder.Generation, "uk", newID)) |
| + } |
| + if len(o.Claim.Holder.Admissions) != 12 || o.Claim.Holder.Admissions[0].Generation != "G1" || o.Claim.Holder.Admissions[0].Covered { |
| + t.Fatalf("foreign uncovered head was trimmed or covered: %+v", o.Claim.Holder.Admissions) |
| + } |
| + for _, record := range o.Claim.Holder.Admissions[1:] { |
| + if !record.Covered { |
| + t.Fatalf("publication stopped at foreign predecessor: %+v", record) |
| + } |
| + } |
| +} |
| + |
| +func TestCoverRegionPredecessors(t *testing.T) { |
| + ctx := context.Background() |
| + s := release.NewDirStore(t.TempDir()) |
| + o := servingClaim(t, ctx, s) |
| + o = updateGenerationTest(t, ctx, s, o, func(c *Claim) error { |
| + c.Op = Op{Kind: KindLanding, ID: "move", Phase: "cleanup", Exec: c.Op.Exec} |
| + c.Holder.Admissions = []AdmissionRecord{ |
| + {Region: "ie", PredecessorRegion: "ie", Covered: true}, |
| + {Region: "uk", PredecessorRegion: "uk"}, |
| + {Region: "uk", PredecessorRegion: "ie"}, |
| + {Region: "ie"}, |
| + {Region: "ie", PredecessorRegion: "ie"}, |
| + } |
| + c.Obligations = []Obligation{{ID: "source", Op: "move", Kind: "park-replica", Region: "ie", Retirement: "ret", Owner: "region:ie"}} |
| + return nil |
| + }) |
| + want := *o.Claim |
| + holder := *want.Holder |
| + want.Holder = &holder |
| + holder.Admissions = append([]AdmissionRecord(nil), holder.Admissions...) |
| + holder.Admissions[2].Covered, holder.Admissions[4].Covered = true, true |
| + for i := 0; i < 2; i++ { |
| + o = updateGenerationTest(t, ctx, s, o, CoverRegionPredecessors("move", "cleanup", "ie")) |
| + want.Gen++ |
| + if !reflect.DeepEqual(o.Claim, &want) { |
| + t.Fatalf("region coverage = %+v, want %+v", o.Claim, &want) |
| + } |
| + } |
| +} |
| + |
| +func TestCoverRegionPredecessorsRefusals(t *testing.T) { |
| + for _, name := range []string{"stale op", "stale phase", "nil holder", "empty region"} { |
| + t.Run(name, func(t *testing.T) { |
| + ctx := context.Background() |
| + s := release.NewDirStore(t.TempDir()) |
| + o := servingClaim(t, ctx, s) |
| + o = updateGenerationTest(t, ctx, s, o, func(c *Claim) error { |
| + c.Op = Op{Kind: KindLanding, ID: "move", Phase: "cleanup", Exec: c.Op.Exec} |
| + c.Holder.Admissions = []AdmissionRecord{{Region: "uk", PredecessorRegion: "ie"}} |
| + if name == "nil holder" { |
| + c.Holder, c.Op = nil, Op{} |
| + } |
| + return nil |
| + }) |
| + op, phase, region := o.Claim.Op.ID, o.Claim.Op.Phase, "ie" |
| + switch name { |
| + case "stale op": |
| + op = "" |
| + case "stale phase": |
| + phase = "" |
| + case "empty region": |
| + region = "" |
| + } |
| + if _, err := Update(ctx, s, o, CoverRegionPredecessors(op, phase, region)); !errors.Is(err, ErrWrongState) { |
| + t.Fatalf("region coverage = %v, want ErrWrongState", err) |
| + } |
| + assertAdmissionStored(t, ctx, s, o) |
| + }) |
| + } |
| +} |
| + |
| +func TestValidateAdmissionRegion(t *testing.T) { |
| + ctx := context.Background() |
| + s := release.NewDirStore(t.TempDir()) |
| + o := servingClaim(t, ctx, s) |
| + for _, records := range [][]AdmissionRecord{ |
| + {{Region: ""}}, |
| + {{Region: "ie"}, {Region: ""}}, |
| + {{Region: "", Covered: true}, {Region: "ie"}}, |
| + } { |
| + o.Claim.Holder.Admissions = records |
| + if err := o.Claim.Validate(); !errors.Is(err, ErrMalformed) { |
| + t.Fatalf("admissions %+v: Validate = %v, want ErrMalformed", records, err) |
| + } |
| + } |
| +} |