Skip to content

Commit 9550745

Browse files
committed
Add cron install regression coverage for CLI and TUI
Close the remaining cron-install test gaps after aligning CLI and TUI scheduling behavior. Add a TUI wizard regression test that proves blank cron input resolves to the installer default (02:00) even when CRON_SCHEDULE is set in the environment, and add a CLI wizard regression test that aborting exactly at the cron prompt propagates the interactive abort and leaves backup.env unwritten. Introduce minimal test seams for the install wizard runner and cron prompt boundary to exercise the real command/wizard paths without changing production semantics.
1 parent dfa28e0 commit 9550745

4 files changed

Lines changed: 67 additions & 4 deletions

File tree

cmd/proxsave/install.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ var (
2525
newInstallConfirmTUI = wizard.ConfirmNewInstall
2626
newInstallRunInstall = runInstall
2727
newInstallRunInstallTUI = runInstallTUI
28+
configureCronTimeFunc = configureCronTime
2829
)
2930

3031
type installConfigResult struct {
@@ -484,7 +485,7 @@ func runConfigWizardCLI(ctx context.Context, reader *bufio.Reader, configPath, t
484485
}
485486

486487
logging.DebugStepBootstrap(bootstrap, "install config wizard (cli)", "configuring cron time")
487-
cronTime, err := configureCronTime(ctx, reader, cronutil.DefaultTime)
488+
cronTime, err := configureCronTimeFunc(ctx, reader, cronutil.DefaultTime)
488489
if err != nil {
489490
return installConfigResult{}, wrapInstallError(err)
490491
}

cmd/proxsave/install_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,31 @@ func TestRunConfigWizardCLISkipLeavesCronScheduleEmpty(t *testing.T) {
629629
}
630630
}
631631

632+
func TestRunConfigWizardCLIAbortAtCronPromptDoesNotWriteConfig(t *testing.T) {
633+
configPath := filepath.Join(t.TempDir(), "env", "backup.env")
634+
tmpConfigPath := configPath + ".tmp"
635+
636+
originalConfigureCronTime := configureCronTimeFunc
637+
t.Cleanup(func() { configureCronTimeFunc = originalConfigureCronTime })
638+
639+
configureCronTimeFunc = func(ctx context.Context, reader *bufio.Reader, defaultCron string) (string, error) {
640+
return "", errInteractiveAborted
641+
}
642+
643+
reader := bufio.NewReader(strings.NewReader("n\nn\nn\nn\nn\nn\n"))
644+
645+
_, err := runConfigWizardCLI(context.Background(), reader, configPath, tmpConfigPath, "/opt/proxsave", nil)
646+
if !errors.Is(err, errInteractiveAborted) {
647+
t.Fatalf("expected errInteractiveAborted, got %v", err)
648+
}
649+
if _, statErr := os.Stat(configPath); !os.IsNotExist(statErr) {
650+
t.Fatalf("expected config file not to exist, got err=%v", statErr)
651+
}
652+
if _, statErr := os.Stat(tmpConfigPath); !os.IsNotExist(statErr) {
653+
t.Fatalf("expected temp config file not to exist, got err=%v", statErr)
654+
}
655+
}
656+
632657
func createTempFile(t *testing.T, content string) string {
633658
t.Helper()
634659
f, err := os.CreateTemp(t.TempDir(), "config-*.env")

internal/tui/wizard/install.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ const (
5959

6060
var (
6161
// ErrInstallCancelled is returned when the user aborts the install wizard.
62-
ErrInstallCancelled = errors.New("installation aborted by user")
62+
ErrInstallCancelled = errors.New("installation aborted by user")
63+
runInstallWizardRunner = func(app *tui.App, root, focus tview.Primitive) error {
64+
return app.SetRoot(root, true).SetFocus(focus).Run()
65+
}
6366
checkExistingConfigRunner = func(app *tui.App, root, focus tview.Primitive) error {
6467
return app.SetRoot(root, true).SetFocus(focus).Run()
6568
}
@@ -451,8 +454,9 @@ func RunInstallWizard(ctx context.Context, configPath string, baseDir string, bu
451454
SetBorderColor(tui.ProxmoxOrange).
452455
SetBackgroundColor(tcell.ColorBlack)
453456

454-
// Run the app - ignore errors from normal app termination
455-
_ = app.SetRoot(flex, true).SetFocus(form.Form).Run()
457+
if err := runInstallWizardRunner(app, flex, form.Form); err != nil {
458+
return nil, err
459+
}
456460

457461
if data == nil {
458462
return nil, ErrInstallCancelled

internal/tui/wizard/install_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import (
77
"strings"
88
"testing"
99

10+
"github.com/gdamore/tcell/v2"
1011
"github.com/rivo/tview"
1112

13+
cronutil "github.com/tis24dev/proxsave/internal/cron"
1214
"github.com/tis24dev/proxsave/internal/tui"
1315
)
1416

@@ -223,6 +225,37 @@ func TestApplyInstallDataCronAndNotifications(t *testing.T) {
223225
assertContains("ENCRYPT_ARCHIVE", "false")
224226
}
225227

228+
func TestRunInstallWizardBlankCronIgnoresEnvOverride(t *testing.T) {
229+
t.Setenv("CRON_SCHEDULE", "5 1 * * *")
230+
231+
originalRunner := runInstallWizardRunner
232+
t.Cleanup(func() { runInstallWizardRunner = originalRunner })
233+
234+
runInstallWizardRunner = func(app *tui.App, root, focus tview.Primitive) error {
235+
form, ok := focus.(*tview.Form)
236+
if !ok {
237+
t.Fatalf("focus primitive = %T, want *tview.Form", focus)
238+
}
239+
button := form.GetButton(0)
240+
if button == nil {
241+
t.Fatal("expected install button")
242+
}
243+
button.InputHandler()(tcell.NewEventKey(tcell.KeyEnter, 0, tcell.ModNone), nil)
244+
return nil
245+
}
246+
247+
data, err := RunInstallWizard(t.Context(), "/tmp/proxsave/backup.env", "/opt/proxsave", "sig", "")
248+
if err != nil {
249+
t.Fatalf("RunInstallWizard returned error: %v", err)
250+
}
251+
if data == nil {
252+
t.Fatal("expected wizard data")
253+
}
254+
if data.CronTime != cronutil.DefaultTime {
255+
t.Fatalf("CronTime = %q, want %q", data.CronTime, cronutil.DefaultTime)
256+
}
257+
}
258+
226259
func TestCheckExistingConfigActions(t *testing.T) {
227260
tmp := t.TempDir()
228261
configPath := filepath.Join(tmp, "prox.env")

0 commit comments

Comments
 (0)