165 lines
5.7 KiB
Go
165 lines
5.7 KiB
Go
//go:build integration
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/catalogue"
|
|
"github.com/novox/mesh-controller/internal/link"
|
|
)
|
|
|
|
func TestToolsAnswersTheSeatsRecords(t *testing.T) {
|
|
handlers, behind, err := seatToolHandlers()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(behind) != 0 {
|
|
t.Fatalf("this build cannot run %v of its own seat's verbs", behind)
|
|
}
|
|
if len(handlers) != len(catalogue.ControllerVerbs) {
|
|
t.Fatalf("%d handlers for %d verbs", len(handlers), len(catalogue.ControllerVerbs))
|
|
}
|
|
answer := seatTools()
|
|
seats, _ := answer["seats"].([]map[string]any)
|
|
var found bool
|
|
for _, s := range seats {
|
|
if s["seat"] == catalogue.ControllerSeatName {
|
|
found = true
|
|
tools, _ := s["tools"].([]map[string]any)
|
|
if len(tools) != len(catalogue.ControllerVerbs) || tools[0]["input"] == nil {
|
|
t.Fatalf("the controller seat's tools are not listed in full: %v", tools)
|
|
}
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatal("the mesh-controller seat is not in the listing")
|
|
}
|
|
// And what a verb replaces travels with it (novox/hq ADR 0245): the console and the agent's
|
|
// instructions read it from here.
|
|
var journal []string
|
|
for _, s := range seats {
|
|
if s["seat"] != catalogue.ServiceManagerSeat {
|
|
continue
|
|
}
|
|
tools, _ := s["tools"].([]map[string]any)
|
|
for _, tool := range tools {
|
|
if tool["name"] == "journal" {
|
|
journal, _ = tool["replaces"].([]string)
|
|
}
|
|
}
|
|
}
|
|
if len(journal) == 0 || journal[0] != "journalctl" {
|
|
t.Fatalf("the service manager's journal does not say it replaces journalctl: %v", journal)
|
|
}
|
|
}
|
|
|
|
func TestAJSONVerbsAnswerIsItsStandardOutput(t *testing.T) {
|
|
jsonVerbs["-test.run"] = true
|
|
t.Cleanup(func() { delete(jsonVerbs, "-test.run") })
|
|
answer, err := runVerb(t.Context(), []string{"-test.run", "TestAnswerEcho", "-test.v"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !answer.OK {
|
|
t.Fatalf("the command failed: %s", answer.Output)
|
|
}
|
|
if !strings.Contains(answer.Output, "PASS") {
|
|
t.Fatalf("stderr and stdout are both what the command said: %s", answer.Output)
|
|
}
|
|
}
|
|
|
|
func TestARowAheadOfThisBuildIsServedAnyway(t *testing.T) {
|
|
seat, known := catalogue.SeatNamed(catalogue.ControllerSeatName)
|
|
if !known {
|
|
t.Fatal("no controller seat")
|
|
}
|
|
// The row as a newer control plane would have written it: every verb this build knows, and one
|
|
// it does not.
|
|
widened := seat
|
|
widened.Serves = append(append([]catalogue.Verb{}, seat.Serves...),
|
|
catalogue.Verb{Name: "teleport", Description: "a verb from a build that does not exist yet"})
|
|
rows := catalogue.DefaultSeats()
|
|
for i := range rows {
|
|
if rows[i].Name == catalogue.ControllerSeatName {
|
|
rows[i] = widened
|
|
}
|
|
}
|
|
catalogue.UseSeats(rows)
|
|
t.Cleanup(func() { catalogue.UseSeats(catalogue.DefaultSeats()) })
|
|
|
|
handlers, behind, err := seatToolHandlers()
|
|
if err != nil {
|
|
t.Fatalf("a row with one unknown verb refused to serve at all: %v", err)
|
|
}
|
|
if len(behind) != 1 || behind[0] != "teleport" {
|
|
t.Fatalf("the verbs this build cannot run were reported as %v", behind)
|
|
}
|
|
if len(handlers) != len(widened.Serves) {
|
|
t.Fatalf("%d handlers for %d verbs in the row", len(handlers), len(widened.Serves))
|
|
}
|
|
for _, known := range []string{"status", "nodes", "push"} {
|
|
if handlers[known] == nil {
|
|
t.Errorf("%s is not served although this build knows it", known)
|
|
}
|
|
}
|
|
_, err = handlers["teleport"](context.Background(), nil)
|
|
if err == nil {
|
|
t.Fatal("the unknown verb answered as though it had run")
|
|
}
|
|
for _, want := range []string{"teleport", "cannot run it", "behind"} {
|
|
if !strings.Contains(err.Error(), want) {
|
|
t.Errorf("the answer does not say %q: %v", want, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTheControllerAnnouncesTheVerbsItServes(t *testing.T) {
|
|
handlers, _, err := seatToolHandlers()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
info := seatAnnouncement(handlers)
|
|
if info.Name != catalogue.ControllerSeatName || info.ID == "" || info.Version == "" {
|
|
t.Fatalf("the service is not named for the seat: %+v", info.ServiceIdentity)
|
|
}
|
|
if len(info.Endpoints) != len(handlers) {
|
|
t.Fatalf("%d endpoints announced for %d verbs served", len(info.Endpoints), len(handlers))
|
|
}
|
|
for _, e := range info.Endpoints {
|
|
verb := e.Metadata["tool"]
|
|
if _, served := handlers[verb]; !served || e.Name != catalogue.ControllerSeatName+"__"+verb {
|
|
t.Errorf("%s (%s) is announced and not served under that name", e.Name, verb)
|
|
}
|
|
if e.Metadata["kind"] != "seat" || e.Metadata["seat"] != catalogue.ControllerSeatName {
|
|
t.Errorf("%s is not announced as the seat's verb: %v", e.Name, e.Metadata)
|
|
}
|
|
if e.Subject != link.SeatToolSubject(catalogue.ControllerSeatName, verb) || e.QueueGroup != "seat."+catalogue.ControllerSeatName {
|
|
t.Errorf("%s is announced on %s/%s, not where it is served", e.Name, e.Subject, e.QueueGroup)
|
|
}
|
|
if e.Metadata["description"] == "" || e.Metadata["schema"] == "" || e.Metadata["scope"] != "mesh" {
|
|
t.Errorf("%s is announced without its description, schema or scope: %v", e.Name, e.Metadata)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNoVerbSetsTheOperatorsKeyOrRevealsASecret(t *testing.T) {
|
|
for _, argv := range [][]string{
|
|
{"operator", "key", "set"}, {"operator", "issue"}, {"identity"}, {"token", "issue"}, {"broker", "users"},
|
|
{"api"}, {"licence"}, {"secret", "export", "x"}, {"secret", "recover", "x"}, {"secret", "accept", "x"}, {"secret"},
|
|
} {
|
|
if err := terminalOnly(argv); err == nil {
|
|
t.Errorf("%v passed", argv)
|
|
}
|
|
}
|
|
if err := terminalOnly([]string{"secret", "rotate", "n", "m", "s"}); err != nil {
|
|
t.Errorf("rotating seals to the machine that uses the secret, and stays a verb's: %v", err)
|
|
}
|
|
// A policy refusal is not a verb this binary is behind on: every verb is still served.
|
|
if _, behind, err := seatToolHandlers(); err != nil || len(behind) != 0 {
|
|
t.Fatalf("behind %v: %v", behind, err)
|
|
}
|
|
}
|