package cli import ( "bytes" "os" "path/filepath" "testing" ) func TestCollectorCmdRegistered(t *testing.T) { found := false for _, cmd := range rootCmd.Commands() { if cmd.Name() == "collector" { found = true break } } if !found { t.Fatal("collector command not registered on root") } } func TestCollectorSubcommandsRegistered(t *testing.T) { want := map[string]bool{"start": false, "stop": false, "status": false} for _, cmd := range collectorCmd.Commands() { if _, ok := want[cmd.Name()]; ok { want[cmd.Name()] = true } } for name, found := range want { if !found { t.Errorf("collector subcommand %q not registered", name) } } } func runCollectorCmd(t *testing.T, root string, dryRun bool, args ...string) (string, error) { t.Helper() resetRootFlags(t) full := append([]string{"collector"}, args...) if root != "" { full = append(full, "--root", root) } if dryRun && (len(args) > 0 && (args[0] == "start" || args[0] == "stop")) { full = append(full, "--dry-run") } var buf bytes.Buffer rootCmd.SetOut(&buf) rootCmd.SetErr(&buf) rootCmd.SetArgs(full) err := rootCmd.Execute() return buf.String(), err } func TestCollectorStartEmitsArtifacts(t *testing.T) { root := t.TempDir() out, err := runCollectorCmd(t, root, true, "start") if err != nil { t.Fatalf("orca collector start: %v\n%s", err, out) } wantFiles := []string{ filepath.Join(root, collectorScriptDir, collectorAggregateSh), filepath.Join(root, collectorScriptDir, collectorWatchdogSh), filepath.Join(root, collectorUnitDir, collectorAggregateSvc), filepath.Join(root, collectorUnitDir, collectorAggregateTmr), filepath.Join(root, collectorUnitDir, collectorWatchdogSvc), filepath.Join(root, collectorUnitDir, collectorWatchdogTmr), } for _, p := range wantFiles { if _, err := os.Stat(p); err != nil { t.Errorf("expected emitted file %s: %v", p, err) } } for _, p := range []string{ filepath.Join(root, collectorScriptDir, collectorAggregateSh), filepath.Join(root, collectorScriptDir, collectorWatchdogSh), } { info, err := os.Stat(p) if err != nil { t.Fatalf("stat %s: %v", p, err) } if perm := info.Mode().Perm(); perm&0o111 == 0 { t.Errorf("expected executable bit on %s, got %o", p, perm) } } } func TestCollectorStartStatusRunning(t *testing.T) { root := t.TempDir() if _, err := runCollectorCmd(t, root, true, "start"); err != nil { t.Fatalf("start: %v", err) } agg, wd := collectorRunning(root) if !agg || !wd { t.Errorf("expected both running, got agg=%t wd=%t", agg, wd) } out, err := runCollectorCmd(t, root, true, "status") if err != nil { t.Fatalf("status: %v", err) } if !contains(out, "running") { t.Errorf("status output should say running, got %q", out) } } func TestCollectorStopRemovesArtifacts(t *testing.T) { root := t.TempDir() if _, err := runCollectorCmd(t, root, true, "start"); err != nil { t.Fatalf("start: %v", err) } out, err := runCollectorCmd(t, root, true, "stop") if err != nil { t.Fatalf("stop: %v\n%s", err, out) } wantFiles := []string{ filepath.Join(root, collectorScriptDir, collectorAggregateSh), filepath.Join(root, collectorScriptDir, collectorWatchdogSh), filepath.Join(root, collectorUnitDir, collectorAggregateSvc), filepath.Join(root, collectorUnitDir, collectorAggregateTmr), filepath.Join(root, collectorUnitDir, collectorWatchdogSvc), filepath.Join(root, collectorUnitDir, collectorWatchdogTmr), } for _, p := range wantFiles { if _, err := os.Stat(p); !os.IsNotExist(err) { t.Errorf("expected %s removed, got %v", p, err) } } } func TestCollectorStatusWhenStopped(t *testing.T) { root := t.TempDir() out, err := runCollectorCmd(t, root, true, "status") if err != nil { t.Fatalf("status: %v", err) } if !contains(out, "stopped") { t.Errorf("expected stopped, got %q", out) } agg, wd := collectorRunning(root) if agg || wd { t.Errorf("expected neither running, got agg=%t wd=%t", agg, wd) } } func TestCollectorResolveRootRejectsRelative(t *testing.T) { collectorRoot = "tmp/relative" _, err := collectorResolveRoot() if err == nil { t.Error("expected error for relative root") } collectorRoot = "/" r, err := collectorResolveRoot() if err != nil || r != "/" { t.Errorf("expected / for default, got %q err=%v", r, err) } } func contains(haystack, needle string) bool { return bytes.Contains([]byte(haystack), []byte(needle)) }