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
306 lines
8.2 KiB
Go
306 lines
8.2 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/kunchenguid/no-mistakes/internal/db"
|
|
"github.com/kunchenguid/no-mistakes/internal/gate"
|
|
"github.com/kunchenguid/no-mistakes/internal/git"
|
|
"github.com/kunchenguid/no-mistakes/internal/ipc"
|
|
"github.com/kunchenguid/no-mistakes/internal/paths"
|
|
"github.com/kunchenguid/no-mistakes/internal/types"
|
|
"github.com/kunchenguid/no-mistakes/internal/wizard"
|
|
)
|
|
|
|
func TestRootYesRunsWizardNonInteractively(t *testing.T) {
|
|
setupTestRepo(t)
|
|
nmHome := makeSocketSafeTempDir(t)
|
|
t.Setenv("NM_HOME", nmHome)
|
|
p := paths.WithRoot(nmHome)
|
|
|
|
d, err := db.Open(p.DB())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer d.Close()
|
|
|
|
if _, _, err := gate.Init(context.Background(), d, p, "."); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
startTestDaemon(t, p, d)
|
|
|
|
gitRoot, err := git.FindGitRoot(".")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
repo, err := d.GetRepoByPath(gitRoot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
prevAuto := runWizardAuto
|
|
runWizardAuto = func(ctx context.Context, p *paths.Paths, state *repoState, _ []types.StepName, _ waitForRunFunc) (wizard.Result, error) {
|
|
if state == nil {
|
|
t.Fatal("expected repo state")
|
|
}
|
|
if _, err := d.InsertRun(repo.ID, "feat/auto", "head1234", "base5678"); err != nil {
|
|
return wizard.Result{}, err
|
|
}
|
|
return wizard.Result{Success: true, Pushed: true, TargetBranch: "feat/auto"}, nil
|
|
}
|
|
defer func() { runWizardAuto = prevAuto }()
|
|
|
|
prevRunTUI := runTUI
|
|
attached := false
|
|
runTUI = func(string, *ipc.Client, *ipc.RunInfo, string) error {
|
|
attached = true
|
|
return nil
|
|
}
|
|
defer func() { runTUI = prevRunTUI }()
|
|
|
|
if _, err := executeCmd("-y"); err != nil {
|
|
t.Fatalf("executeCmd(-y) error = %v", err)
|
|
}
|
|
if !attached {
|
|
t.Fatal("expected -y run to attach to the created run")
|
|
}
|
|
}
|
|
|
|
func TestRootSkipPassesStepsToWizard(t *testing.T) {
|
|
setupTestRepo(t)
|
|
nmHome := makeSocketSafeTempDir(t)
|
|
t.Setenv("NM_HOME", nmHome)
|
|
p := paths.WithRoot(nmHome)
|
|
|
|
d, err := db.Open(p.DB())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer d.Close()
|
|
|
|
if _, _, err := gate.Init(context.Background(), d, p, "."); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
startTestDaemon(t, p, d)
|
|
|
|
gitRoot, err := git.FindGitRoot(".")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
repo, err := d.GetRepoByPath(gitRoot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
prevAuto := runWizardAuto
|
|
var gotSkip []types.StepName
|
|
runWizardAuto = func(ctx context.Context, p *paths.Paths, state *repoState, skipSteps []types.StepName, _ waitForRunFunc) (wizard.Result, error) {
|
|
gotSkip = append([]types.StepName(nil), skipSteps...)
|
|
if _, err := d.InsertRun(repo.ID, "feat/auto", "head1234", "base5678"); err != nil {
|
|
return wizard.Result{}, err
|
|
}
|
|
return wizard.Result{Success: true, Pushed: true, TargetBranch: "feat/auto"}, nil
|
|
}
|
|
defer func() { runWizardAuto = prevAuto }()
|
|
|
|
prevRunTUI := runTUI
|
|
runTUI = func(string, *ipc.Client, *ipc.RunInfo, string) error { return nil }
|
|
defer func() { runTUI = prevRunTUI }()
|
|
|
|
if _, err := executeCmd("--skip", "test,lint", "-y"); err != nil {
|
|
t.Fatalf("executeCmd(--skip test,lint -y) error = %v", err)
|
|
}
|
|
want := []types.StepName{types.StepTest, types.StepLint}
|
|
if !reflect.DeepEqual(gotSkip, want) {
|
|
t.Fatalf("skip steps = %v, want %v", gotSkip, want)
|
|
}
|
|
}
|
|
|
|
func TestRootYesUsesVisibleWizardWhenInteractive(t *testing.T) {
|
|
setupTestRepo(t)
|
|
nmHome := makeSocketSafeTempDir(t)
|
|
t.Setenv("NM_HOME", nmHome)
|
|
p := paths.WithRoot(nmHome)
|
|
|
|
d, err := db.Open(p.DB())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer d.Close()
|
|
|
|
if _, _, err := gate.Init(context.Background(), d, p, "."); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
startTestDaemon(t, p, d)
|
|
|
|
gitRoot, err := git.FindGitRoot(".")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
repo, err := d.GetRepoByPath(gitRoot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
prevInteractive := terminalInteractive
|
|
terminalInteractive = func() bool { return true }
|
|
defer func() { terminalInteractive = prevInteractive }()
|
|
|
|
prevVisible := runWizardAutoVisible
|
|
visible := false
|
|
runWizardAutoVisible = func(ctx context.Context, p *paths.Paths, state *repoState, _ []types.StepName, _ waitForRunFunc) (wizard.Result, error) {
|
|
visible = true
|
|
if state == nil {
|
|
t.Fatal("expected repo state")
|
|
}
|
|
if _, err := d.InsertRun(repo.ID, "feat/visible", "head1234", "base5678"); err != nil {
|
|
return wizard.Result{}, err
|
|
}
|
|
return wizard.Result{Success: true, Pushed: true, TargetBranch: "feat/visible"}, nil
|
|
}
|
|
defer func() { runWizardAutoVisible = prevVisible }()
|
|
|
|
prevAuto := runWizardAuto
|
|
runWizardAuto = func(context.Context, *paths.Paths, *repoState, []types.StepName, waitForRunFunc) (wizard.Result, error) {
|
|
t.Fatal("expected interactive -y path to show the wizard instead of using headless auto mode")
|
|
return wizard.Result{}, nil
|
|
}
|
|
defer func() { runWizardAuto = prevAuto }()
|
|
|
|
prevRunTUI := runTUI
|
|
attached := false
|
|
runTUI = func(string, *ipc.Client, *ipc.RunInfo, string) error {
|
|
attached = true
|
|
return nil
|
|
}
|
|
defer func() { runTUI = prevRunTUI }()
|
|
|
|
if _, err := executeCmd("-y"); err != nil {
|
|
t.Fatalf("executeCmd(-y) error = %v", err)
|
|
}
|
|
if !visible {
|
|
t.Fatal("expected -y run to launch the visible wizard path")
|
|
}
|
|
if !attached {
|
|
t.Fatal("expected -y run to attach to the created run")
|
|
}
|
|
}
|
|
|
|
func TestRootYesFailsWhenWizardPushProducesNoRun(t *testing.T) {
|
|
setupTestRepo(t)
|
|
nmHome := makeSocketSafeTempDir(t)
|
|
t.Setenv("NM_HOME", nmHome)
|
|
p := paths.WithRoot(nmHome)
|
|
|
|
d, err := db.Open(p.DB())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer d.Close()
|
|
|
|
if _, _, err := gate.Init(context.Background(), d, p, "."); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
startTestDaemon(t, p, d)
|
|
|
|
prevAuto := runWizardAuto
|
|
runWizardAuto = func(ctx context.Context, p *paths.Paths, state *repoState, _ []types.StepName, _ waitForRunFunc) (wizard.Result, error) {
|
|
return wizard.Result{Success: true, Pushed: true, TargetBranch: "feat/missing"}, nil
|
|
}
|
|
defer func() { runWizardAuto = prevAuto }()
|
|
|
|
_, err = executeCmd("-y")
|
|
if err == nil {
|
|
t.Fatal("expected -y to fail when no active run appears after push")
|
|
}
|
|
if !strings.Contains(err.Error(), "no active run") {
|
|
t.Fatalf("error should mention missing active run, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRootYesPassesCommandContextToWizard(t *testing.T) {
|
|
setupTestRepo(t)
|
|
nmHome := makeSocketSafeTempDir(t)
|
|
t.Setenv("NM_HOME", nmHome)
|
|
p := paths.WithRoot(nmHome)
|
|
|
|
d, err := db.Open(p.DB())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer d.Close()
|
|
|
|
if _, _, err := gate.Init(context.Background(), d, p, "."); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
startTestDaemon(t, p, d)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
|
|
prevAuto := runWizardAuto
|
|
runWizardAuto = func(got context.Context, p *paths.Paths, state *repoState, _ []types.StepName, _ waitForRunFunc) (wizard.Result, error) {
|
|
if got == nil {
|
|
t.Fatal("expected command context")
|
|
}
|
|
if err := got.Err(); err != context.Canceled {
|
|
t.Fatalf("wizard context err = %v, want %v", err, context.Canceled)
|
|
}
|
|
return wizard.Result{}, got.Err()
|
|
}
|
|
defer func() { runWizardAuto = prevAuto }()
|
|
|
|
_, err = executeCmdWithContext(ctx, "-y")
|
|
if !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("executeCmdWithContext(-y) error = %v, want %v", err, context.Canceled)
|
|
}
|
|
}
|
|
|
|
func TestRootYesStopsWaitingForRunWhenContextCanceled(t *testing.T) {
|
|
setupTestRepo(t)
|
|
nmHome := makeSocketSafeTempDir(t)
|
|
t.Setenv("NM_HOME", nmHome)
|
|
p := paths.WithRoot(nmHome)
|
|
|
|
d, err := db.Open(p.DB())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer d.Close()
|
|
|
|
if _, _, err := gate.Init(context.Background(), d, p, "."); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
startTestDaemon(t, p, d)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
prevAuto := runWizardAuto
|
|
runWizardAuto = func(got context.Context, p *paths.Paths, state *repoState, _ []types.StepName, _ waitForRunFunc) (wizard.Result, error) {
|
|
cancel()
|
|
return wizard.Result{Success: true, Pushed: true, TargetBranch: "feat/missing"}, nil
|
|
}
|
|
defer func() { runWizardAuto = prevAuto }()
|
|
|
|
start := time.Now()
|
|
_, err = executeCmdWithContext(ctx, "-y")
|
|
if !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("executeCmdWithContext(-y) error = %v, want %v", err, context.Canceled)
|
|
}
|
|
if elapsed := time.Since(start); elapsed >= time.Second {
|
|
t.Fatalf("executeCmdWithContext(-y) took %v after cancellation, want under %v", elapsed, time.Second)
|
|
}
|
|
}
|