package catalogue import ( "strings" "testing" ) // The verbs an agent works around most say what they replace (novox/hq ADR 0245): the journal, a // restart, a unit's status, the hosts file — each the command the agent would otherwise type over ssh. func TestTheVerbsWorkedAroundSayWhatTheyReplace(t *testing.T) { want := map[string]string{ ServiceManagerSeat + ".journal": "journalctl", ServiceManagerSeat + ".restart": "systemctl restart", ServiceManagerSeat + ".status": "systemctl status", "node-hostname.add": "edit /etc/hosts", ControllerSeatName + ".node": "hostnamectl", } for _, s := range DefaultSeats() { for _, v := range s.Serves { cmd, ok := want[s.Name+"."+v.Name] if !ok { continue } delete(want, s.Name+"."+v.Name) found := false for _, r := range v.Replaces { found = found || r == cmd } if !found { t.Errorf("%s.%s does not say it replaces %q: %v", s.Name, v.Name, cmd, v.Replaces) } } } for verb := range want { t.Errorf("%s is not a verb of the compiled seats", verb) } } // Every command a seat's verb replaces is one short line, said once — what the guard and the search match. func TestEveryReplacedCommandIsOneShortLine(t *testing.T) { for _, s := range DefaultSeats() { for _, v := range s.Serves { seen := map[string]bool{} for _, r := range v.Replaces { if strings.TrimSpace(r) == "" || strings.ContainsAny(r, "\n\r") || len(r) > MaxReplaced || seen[r] { t.Errorf("%s.%s replaces %q, which is not one short line said once", s.Name, v.Name, r) } seen[r] = true } } } } // A verb's definition in a manifest may say what it replaces, like the mesh's own. func TestAVerbDefinitionCarriesWhatItReplaces(t *testing.T) { m, err := ParseManifest([]byte(`{"module":"till","version":"1","tools":["refund"],` + `"seats":[{"name":"shop-till","serves":[{"name":"refund","replaces":["psql -c refund"]}]}],` + `"claims":[{"name":"shop-till","scope":"mesh"}]}`)) if err != nil { t.Fatal(err) } if got := m.DefinesSeats[0].Serves[0].Replaces; len(got) != 1 || got[0] != "psql -c refund" { t.Fatalf("replaces not read: %v", got) } } // A module says what its own tools replace, and only for a tool it declares. func TestAModuleSaysWhatItsOwnToolsReplace(t *testing.T) { m, err := ParseManifest([]byte(`{"module":"docker","version":"1","tools":["docker_logs","docker_list"],` + `"replaces":{"docker_logs":["docker logs"],"docker_list":["docker ps"]}}`)) if err != nil { t.Fatal(err) } if m.Replaces["docker_logs"][0] != "docker logs" || m.Replaces["docker_list"][0] != "docker ps" { t.Fatalf("replaces not read: %v", m.Replaces) } for _, c := range []struct{ manifest, says string }{ {`{"module":"docker","version":"1","tools":["docker_logs"],"replaces":{"docker_lgos":["docker logs"]}}`, "declares no such tool"}, {`{"module":"docker","version":"1","tools":["docker_logs"],"replaces":{"docker_logs":[]}}`, "replaces nothing"}, {`{"module":"docker","version":"1","tools":["docker_logs"],"replaces":{"docker_logs":[" "]}}`, "empty command"}, {`{"module":"docker","version":"1","tools":["docker_logs"],"replaces":{"docker_logs":["docker logs\nrm -rf /"]}}`, "more than one line"}, {`{"module":"docker","version":"1","tools":["docker_logs"],"replaces":{"docker_logs":["docker logs","docker logs"]}}`, "twice"}, {`{"module":"docker","version":"1","tools":["docker_logs"],"replaces":{"docker_logs":["` + strings.Repeat("x", MaxReplaced+1) + `"]}}`, "longer than"}, } { if _, err := ParseManifest([]byte(c.manifest)); err == nil || !strings.Contains(err.Error(), c.says) { t.Errorf("%s: want a refusal saying %q, got %v", c.manifest, c.says, err) } } } // A seat row the store seeded before `replaces` existed carries none; the working set takes the compiled // one, so the `tools` answer says it on a mesh whose rows exist. func TestASeededRowTakesWhatItsVerbsReplaceFromTheCompiledSeat(t *testing.T) { was := Seats() t.Cleanup(func() { UseSeats(was) }) var row Seat for _, s := range DefaultSeats() { if s.Name == ServiceManagerSeat { row = s } } stored := make([]Verb, len(row.Serves)) for i, v := range row.Serves { v.Replaces = nil stored[i] = v } row.Serves = stored UseSeats([]Seat{row}) got, _ := SeatNamed(ServiceManagerSeat) for _, v := range got.Serves { if v.Name == "journal" && (len(v.Replaces) == 0 || v.Replaces[0] != "journalctl") { t.Fatalf("the seeded journal verb says it replaces %v", v.Replaces) } } }