package hostclaim import ( "context" "errors" "reflect" "testing" "time" "github.com/carlosframework/platform/internal/release" ) func TestAdoptAndDiscoveryCompletion(t *testing.T) { ctx := context.Background() s := release.NewDirStore(t.TempDir()) nh := newHolder() obs, err := Read(ctx, s, testHost) if err != nil { t.Fatal(err) } o, err := Update(ctx, s, obs, Adopt(nh, "adi-knitting", []string{"uk"}, []string{"b2"}, "op_adopt", counter())) if err != nil { t.Fatal(err) } c := o.Claim if !reflect.DeepEqual(c.Touched.Regions, []string{"ie"}) || !reflect.DeepEqual(c.Touched.Boxes, []string{"adi-knitting"}) { t.Fatalf("adopted touched locations = %+v", c.Touched) } if c.Holder.Location != "instances/"+testHost || c.Touched.Complete || c.Touched.DiscoveryOp != "op_adopt" || c.Holder.Stamp != c.Gen || c.Op.Exec != "adi-knitting" || len(c.Obligations) != 2 { t.Fatalf("adopt = %+v", c) } // A delete is refused while discovery chores are pending in its write set (CC11). if _, err := Update(ctx, s, o, BeginDelete("op_d", "console", `"e"`, time.Now(), []string{"ie", "uk"}, []string{"adi-knitting", "b2"}, "")); !errors.Is(err, ErrPendingChore) { t.Fatalf("delete during discovery = %v", err) } for _, ob := range c.Obligations { if o, err = Update(ctx, s, o, CompleteObligation(ob.Op, ob.ID)); err != nil { t.Fatal(err) } } if !o.Claim.Touched.Complete || o.Claim.Touched.DiscoveryOp != "" { t.Fatalf("discovery not completed: %+v", o.Claim.Touched) } if _, err := Update(ctx, s, o, Adopt(nh, "adi-knitting", nil, nil, "op_adopt2", counter())); !errors.Is(err, ErrWrongState) { t.Fatalf("re-adopt = %v", err) } o, err = Update(ctx, s, o, BeginDelete("op_d", "console", `"e"`, time.Now(), []string{"ie", "uk"}, []string{"adi-knitting", "b2"}, "")) if err != nil { t.Fatal(err) } o, err = Update(ctx, s, o, ToParking("op_d", []string{"ie", "uk"}, []string{"adi-knitting", "b2"}, counter())) if err != nil { t.Fatal(err) } assertParkingTargets(t, o.Claim.Obligations, []Obligation{ {ParkTarget: "instances/" + testHost, Op: "op_d", Kind: "park-replica", Region: "ie", Owner: "region:ie"}, {Op: "op_d", Kind: "park-local", Box: "adi-knitting", Owner: "box:adi-knitting"}, }) } func TestAdoptRefusesEmptyEffectiveRegion(t *testing.T) { ctx := context.Background() s := release.NewDirStore(t.TempDir()) nh := newHolder() nh.Region = "" obs, err := Read(ctx, s, testHost) if err != nil { t.Fatal(err) } if _, err := Update(ctx, s, obs, Adopt(nh, "B0", nil, nil, "op_adopt", counter())); !errors.Is(err, ErrWrongState) { t.Errorf("empty effective region = %v, want ErrWrongState", err) } after, err := Read(ctx, s, testHost) if err != nil || !after.Absent { t.Fatalf("read after refused adopt = %+v, %v; want absent", after, err) } } func TestAdoptWithoutDiscoveryTargets(t *testing.T) { ctx := context.Background() s := release.NewDirStore(t.TempDir()) obs, err := Read(ctx, s, testHost) if err != nil { t.Fatal(err) } o, err := Update(ctx, s, obs, Adopt(newHolder(), "B0", nil, nil, "op_adopt", counter())) if err != nil { t.Fatal(err) } want := Touched{Complete: true, Regions: []string{"ie"}, Boxes: []string{"B0"}} if !reflect.DeepEqual(o.Claim.Touched, want) || len(o.Claim.Obligations) != 0 { t.Fatalf("adopt without discovery targets = %+v", o.Claim) } o, err = Update(ctx, s, o, BeginDelete("op_d", "console", `"e"`, time.Now(), nil, nil, "")) if err != nil { t.Fatal(err) } o, err = Update(ctx, s, o, ToParking("op_d", nil, nil, counter())) if err != nil { t.Fatal(err) } assertParkingTargets(t, o.Claim.Obligations, []Obligation{ {ParkTarget: "instances/" + testHost, Op: "op_d", Kind: "park-replica", Region: "ie", Owner: "region:ie"}, {Op: "op_d", Kind: "park-local", Box: "B0", Owner: "box:B0"}, }) }