Files
wehub-resource-sync 26f897c1ec
release / release-please (push) Failing after 1m49s
docs / build (push) Failing after 6m34s
release / build-and-upload (arm64, linux) (push) Has been cancelled
release / build-and-upload (arm64, windows) (push) Has been cancelled
release / build-darwin (amd64, darwin) (push) Has been cancelled
release / checksums (push) Has been cancelled
release / finalize (push) Has been cancelled
release / build-darwin (arm64, darwin) (push) Has been cancelled
release / build-and-upload (amd64, linux) (push) Has been cancelled
release / build-and-upload (amd64, windows) (push) Has been cancelled
docs / deploy (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:34:16 +08:00

179 lines
4.7 KiB
Go

package cli
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/kunchenguid/no-mistakes/internal/db"
"github.com/kunchenguid/no-mistakes/internal/paths"
"github.com/kunchenguid/no-mistakes/internal/types"
)
func TestDaemonStopRefusesWithActiveRunsAndListsThem(t *testing.T) {
nmHome := t.TempDir()
t.Setenv("NM_HOME", nmHome)
createLifecycleGuardRuns(t, paths.WithRoot(nmHome))
stopCalled := false
prevStop := daemonStopFn
daemonStopFn = func(*paths.Paths) error {
stopCalled = true
return nil
}
t.Cleanup(func() { daemonStopFn = prevStop })
out, err := executeCmd("daemon", "stop")
if err == nil {
t.Fatal("daemon stop should refuse while active runs exist")
}
if stopCalled {
t.Fatal("daemon stop should not stop the daemon after refusing")
}
for _, want := range []string{
"refusing daemon stop",
"2 active pipeline runs",
"feature-a",
"aaa111",
"feature-b",
"bbb222",
"--force",
} {
if !strings.Contains(out+err.Error(), want) {
t.Fatalf("daemon stop refusal should contain %q, got output %q error %v", want, out, err)
}
}
}
func TestDaemonStopForceOverridesActiveRunGuard(t *testing.T) {
nmHome := t.TempDir()
t.Setenv("NM_HOME", nmHome)
createLifecycleGuardRuns(t, paths.WithRoot(nmHome))
stopCalled := false
prevStop := daemonStopFn
daemonStopFn = func(*paths.Paths) error {
stopCalled = true
return nil
}
t.Cleanup(func() { daemonStopFn = prevStop })
out, err := executeCmd("daemon", "stop", "--force")
if err != nil {
t.Fatalf("daemon stop --force failed: %v\n%s", err, out)
}
if !stopCalled {
t.Fatal("daemon stop --force should stop the daemon")
}
if !strings.Contains(out, "FORCE: daemon stop") {
t.Fatalf("force output should be loud, got %q", out)
}
}
func TestDaemonRestartRefusesWithActiveRuns(t *testing.T) {
nmHome := t.TempDir()
t.Setenv("NM_HOME", nmHome)
createLifecycleGuardRuns(t, paths.WithRoot(nmHome))
stopCalled := false
startCalled := false
prevStop := daemonStopFn
prevStart := daemonStartFn
daemonStopFn = func(*paths.Paths) error {
stopCalled = true
return nil
}
daemonStartFn = func(*paths.Paths) error {
startCalled = true
return nil
}
t.Cleanup(func() {
daemonStopFn = prevStop
daemonStartFn = prevStart
})
out, err := executeCmd("daemon", "restart")
if err == nil {
t.Fatal("daemon restart should refuse while active runs exist")
}
if stopCalled || startCalled {
t.Fatalf("daemon restart should not stop/start after refusing; stop=%t start=%t", stopCalled, startCalled)
}
if !strings.Contains(out+err.Error(), "refusing daemon restart") || !strings.Contains(out+err.Error(), "feature-a") {
t.Fatalf("daemon restart refusal should list active runs, got output %q error %v", out, err)
}
}
func TestLifecycleCommandsWriteCallerAttributionToCLILog(t *testing.T) {
nmHome := t.TempDir()
t.Setenv("NM_HOME", nmHome)
prevStop := daemonStopFn
prevStart := daemonStartFn
daemonStopFn = func(*paths.Paths) error { return nil }
daemonStartFn = func(*paths.Paths) error { return nil }
t.Cleanup(func() {
daemonStopFn = prevStop
daemonStartFn = prevStart
})
out, err := executeCmd("daemon", "stop", "--force")
if err != nil {
t.Fatalf("daemon stop --force failed: %v\n%s", err, out)
}
out, err = executeCmd("daemon", "restart", "--force")
if err != nil {
t.Fatalf("daemon restart --force failed: %v\n%s", err, out)
}
out, err = executeCmd("update", "--force")
if err != nil {
t.Fatalf("update --force failed: %v\n%s", err, out)
}
data, err := os.ReadFile(filepath.Join(nmHome, "logs", "cli.log"))
if err != nil {
t.Fatalf("read cli.log: %v", err)
}
log := string(data)
for _, want := range []string{
"lifecycle FORCE command=daemon.stop",
"lifecycle FORCE command=daemon.restart",
"lifecycle FORCE command=update",
"force=true",
"pid=",
"ppid=",
"parent_cmdline=",
} {
if !strings.Contains(log, want) {
t.Fatalf("cli.log should contain %q, got %q", want, log)
}
}
}
func createLifecycleGuardRuns(t *testing.T, p *paths.Paths) {
t.Helper()
if err := p.EnsureDirs(); err != nil {
t.Fatalf("ensure dirs: %v", err)
}
database, err := db.Open(p.DB())
if err != nil {
t.Fatalf("open db: %v", err)
}
defer database.Close()
repo, err := database.InsertRepo("/tmp/project", "git@github.com:user/project.git", "main")
if err != nil {
t.Fatalf("insert repo: %v", err)
}
if _, err := database.InsertRun(repo.ID, "feature-a", "aaa111", "000"); err != nil {
t.Fatalf("insert pending run: %v", err)
}
running, err := database.InsertRun(repo.ID, "feature-b", "bbb222", "000")
if err != nil {
t.Fatalf("insert running run: %v", err)
}
if err := database.UpdateRunStatus(running.ID, types.RunRunning); err != nil {
t.Fatalf("mark running: %v", err)
}
}