package main // postgres handed to the provisioner still serves the consumers the controller's grant file gives (issue 937): a // consumer not moved has no plan naming postgres, only its grant, until R1 (issue 682). import ( "encoding/json" "os" "path/filepath" "reflect" "testing" "time" ) // granting gives the moved world a grant file, as the controller writes it for the consumers not moved. func (w *movedWorld) granting(given ...map[string]any) { if w.h.Receives == "" { w.h.Receives = filepath.Join(w.t.TempDir(), "mesh.json") } dir := filepath.Dir(w.h.Receives) for _, g := range given { secret := filepath.Join(dir, g["as"].(string)+".secret") if err := os.WriteFile(secret, []byte("pw-"+g["as"].(string)+"\n"), 0o600); err != nil { w.t.Fatal(err) } g["secret"] = secret } if given == nil { given = []map[string]any{} } raw, _ := json.Marshal(map[string]any{"requirement": ProvisionName, "given": given}) if err := os.WriteFile(w.h.Receives, raw, 0o600); err != nil { w.t.Fatal(err) } } // settled is enough passes and time for a retirement to be stable. func (w *movedWorld) settled() { for i := 0; i < 8; i++ { w.pass() } w.now = w.now.Add(15 * time.Minute) w.pass() w.pass() } // The logins the grant file gives are asked for: made as the grant path makes them, never offered for retirement, // beside a moved consumer the helper makes from its plan. func TestAConsumerOnlyTheGrantFileGivesIsAskedForAndMade(t *testing.T) { bound, logins := bindings(1) w := newMovedWorld(t, bound) w.a.inv.Active = []string{"mesh_ace_baserow", "mesh_ace_letta", logins[0]} w.bus.bind("ace", "app1", nil) w.granting( map[string]any{"as": "mesh_ace_baserow", "node": "ace", "values": map[string]any{"name": "baserow"}}, map[string]any{"as": "mesh_ace_letta", "node": "ace", "values": map[string]any{"name": "letta", "extensions": []any{"vector"}}}, ) w.settled() if len(w.a.removed) != 0 || w.h.r.waiting != nil { t.Fatalf("retired %v, waiting %+v: the grant file's logins were counted unasked", w.a.removed, w.h.r.waiting) } made := map[string]Provision{} for _, c := range w.a.created { made[c.As] = c } letta := made["mesh_ace_letta"] if letta.Password != "pw-mesh_ace_letta" || letta.Consumer != "ace" || !reflect.DeepEqual(letta.Values, map[string]any{"name": "letta", "extensions": []any{"vector"}}) { t.Fatalf("made %+v for letta, as its grant gives it", letta) } if _, ok := made["mesh_ace_baserow"]; !ok { t.Fatalf("baserow not made: %+v", w.a.created) } if _, ok := made[logins[0]]; !ok { t.Fatalf("the moved consumer not made: %+v", w.a.created) } } // A login both a plan and the grant file name is the plan's: made once, with the plan's credential. func TestALoginAPlanNamesIsNotMadeFromTheGrantFile(t *testing.T) { bound, logins := bindings(1) w := newMovedWorld(t, bound) w.bus.bind("ace", "app1", nil) w.granting(map[string]any{"as": logins[0], "node": "ace", "values": map[string]any{"name": "app1"}}) w.pass() w.pass() for _, c := range w.a.created { if c.As == logins[0] && c.Password != "pw-app1" { t.Fatalf("made %s with the grant's password %q, not the plan's", c.As, c.Password) } } } // An unreadable grant file is not nobody asking (issue 241): nothing is retired while it cannot be read. func TestAnUnreadableGrantFileRetiresNothing(t *testing.T) { bound, logins := bindings(1) w := newMovedWorld(t, bound) w.a.inv.Active = []string{"mesh_ace_baserow", logins[0]} w.bus.bind("ace", "app1", nil) w.h.Receives = filepath.Join(t.TempDir(), "absent.json") w.settled() if len(w.a.removed) != 0 || w.h.r.waiting != nil { t.Fatalf("retired %v, waiting %+v with the grant file unreadable", w.a.removed, w.h.r.waiting) } } // A login the grant file stops giving is retired by the usual rules: stable, then retired, never dropped. func TestALoginTheGrantFileStopsGivingIsRetired(t *testing.T) { bound, _ := bindings(1) w := newMovedWorld(t, bound) w.bus.bind("ace", "app1", nil) w.granting( map[string]any{"as": "mesh_ace_baserow", "node": "ace", "values": map[string]any{"name": "baserow"}}, map[string]any{"as": "mesh_ace_letta", "node": "ace", "values": map[string]any{"name": "letta"}}, ) w.pass() w.granting(map[string]any{"as": "mesh_ace_baserow", "node": "ace", "values": map[string]any{"name": "baserow"}}) w.settled() if !reflect.DeepEqual(w.a.removed, []string{"mesh_ace_letta"}) || len(w.a.deleted) != 0 { t.Fatalf("retired %v, deleted %v", w.a.removed, w.a.deleted) } }