package hostclaim import ( "errors" "strings" "testing" "time" "github.com/carlosframework/platform/internal/release" ) func TestParkScopeAndHolderlessSweep(t *testing.T) { c := &Claim{V: 2, Host: "shop.bab.example.com", Gen: 1, Op: Op{Kind: KindParking, ID: "sweep", Intent: map[string]string{"park_sweep": "v1"}}} c.Obligations = []Obligation{{ID: "ob", Op: "sweep", Kind: "park-replica", Region: "ie", Retirement: "rt", Owner: "region:ie", Park: &ParkScope{Location: "instances/" + c.Host + "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Incarnation: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", EvidenceAt: time.Now(), RequestLimit: time.Second}}} if err := c.Validate(); err != nil { t.Fatal(err) } for _, change := range []func(*Claim){ func(c *Claim) { c.Obligations[0].Park = nil }, func(c *Claim) { c.Op.Exec = "box" }, func(c *Claim) { c.Obligations[0].Op = "another" }, func(c *Claim) { c.Op.Intent = nil }, func(c *Claim) { c.Obligations[0].Park.RequestLimit = 0 }, func(c *Claim) { c.Obligations[0].Park.EvidenceAt = time.Time{} }, func(c *Claim) { c.Obligations[0].Park.Location = "instances/other.example" }, } { copy := *c copy.Obligations = append([]Obligation(nil), c.Obligations...) scope := *c.Obligations[0].Park copy.Obligations[0].Park = &scope change(©) if err := copy.Validate(); err == nil { t.Fatal("invalid sweep admitted") } } } func TestParkScopeLocationGrammar(t *testing.T) { host := "shop.bab.example.com" inc := strings.Repeat("a", 64) instances, moves := "instances/"+host, "moves/"+host for _, tc := range []struct { location string valid bool }{ {instances, true}, {instances + "/" + inc, true}, {moves, true}, {moves + "/move-1", true}, {moves + "/" + strings.Repeat("b", 64), true}, {instances + "/", false}, {instances + "/" + inc + "/", false}, {instances + "/" + inc + "/x", false}, {instances + "/" + strings.Repeat("b", 64), false}, {moves + "/", false}, {moves + "/move-1/", false}, {moves + "/move-1/x", false}, {moves + "/.", false}, {moves + "/..", false}, {moves + "//move-1", false}, {"moves/other.example/move-1", false}, {"instances/other.example", false}, {"other/" + host, false}, } { t.Run(tc.location, func(t *testing.T) { c := &Claim{V: 2, Host: host, Gen: 1, Op: Op{Kind: KindParking, ID: "sweep", Intent: map[string]string{"park_sweep": "v1"}}} c.Obligations = []Obligation{{ID: "ob", Op: "sweep", Kind: "park-replica", Region: "ie", Retirement: "rt", Owner: "region:ie", Park: &ParkScope{Location: tc.location, Incarnation: inc, EvidenceAt: time.Now(), RequestLimit: time.Second}}} err := c.Validate() if tc.valid && err != nil { t.Fatalf("valid scope rejected: %v", err) } if !tc.valid && !errors.Is(err, ErrMalformed) { t.Fatalf("invalid scope: %v", err) } }) } for _, location := range []string{instances, instances + "/" + strings.ToUpper(inc), moves, moves + "/move-1"} { t.Run("uppercase-archive/"+location, func(t *testing.T) { c := &Claim{V: 2, Host: host, Gen: 1, Op: Op{Kind: KindParking, ID: "sweep", Intent: map[string]string{"park_sweep": "v1"}}} c.Obligations = []Obligation{{ID: "ob", Op: "sweep", Kind: "park-replica", Region: "ie", Retirement: "rt", Owner: "region:ie", Park: &ParkScope{Location: location, Incarnation: strings.ToUpper(inc), EvidenceAt: time.Now(), RequestLimit: time.Second}}} if err := c.Validate(); !errors.Is(err, ErrMalformed) { t.Fatalf("uppercase archive incarnation accepted: %v", err) } }) } } func TestHolderlessSweepJoinsRegion(t *testing.T) { host := "shop.bab.example.com" st := release.NewDirStore(t.TempDir()) chore := Obligation{ID: "ie-ob", Op: "sweep", Kind: "park-replica", Region: "ie", Retirement: "ie-rt", Owner: "region:ie", Park: &ParkScope{Location: "moves/" + host, Incarnation: strings.Repeat("a", 64), EvidenceAt: time.Now(), RequestLimit: time.Second}} obs, err := Update(t.Context(), st, Observed{Host: host, Absent: true}, func(c *Claim) error { c.Op = Op{Kind: KindParking, ID: "sweep", Intent: map[string]string{"park_sweep": "v1"}} c.Obligations = []Obligation{chore} return nil }) if err != nil { t.Fatal(err) } joined := chore joined.ID, joined.Region, joined.Retirement, joined.Owner = "uk-ob", "uk", "uk-rt", "region:uk" obs, err = Update(t.Context(), st, obs, func(c *Claim) error { c.Obligations = append(c.Obligations, joined) return nil }) if err != nil { t.Fatal(err) } if obs.Claim.Free() || obs.Claim.Holder != nil || obs.Claim.Op.ID != "sweep" || len(obs.Claim.Obligations) != 2 { t.Fatalf("invalid joined sweep: %+v", obs.Claim) } _, err = Update(t.Context(), st, obs, func(c *Claim) error { c.Obligations[1].Op = "other-sweep" return nil }) if !errors.Is(err, ErrMalformed) { t.Fatalf("joined region with a different op accepted: %v", err) } }