//go:build windows // +build windows package wincmd import ( "errors" "testing" "time" "golang.org/x/sys/windows/svc/mgr" ) func TestNewWinSvcExecuteSetsName(t *testing.T) { exec := NewWinSvcExecute("unit-svc", func() {}, func() {}) if exec.Name != "unit-svc" { t.Fatalf("Name = %q, want %q", exec.Name, "unit-svc") } if exec.Run == nil || exec.Stop == nil { t.Fatal("expected Run and Stop callbacks to be set") } if len(exec.Accepted) == 0 { t.Fatal("expected default accepted command set to be initialized") } } func TestBuildServiceBinaryPathIncludesArgs(t *testing.T) { path, err := buildServiceBinaryPath(`C:\tools\svc.exe`, []string{"-a", "hello world"}) if err != nil { t.Fatalf("buildServiceBinaryPath returned error: %v", err) } if path == "" { t.Fatal("expected non-empty binary path") } } func TestEqualRecoveryActions(t *testing.T) { left := []mgr.RecoveryAction{ {Type: mgr.ServiceRestart, Delay: 5 * time.Second}, } right := []mgr.RecoveryAction{ {Type: mgr.ServiceRestart, Delay: 5 * time.Second}, } if !equalRecoveryActions(left, right) { t.Fatal("expected recovery action slices to be equal") } right[0].Delay = 10 * time.Second if equalRecoveryActions(left, right) { t.Fatal("expected recovery action slices to differ") } } func TestShouldUpdateRecoveryActionsTracksResetPeriod(t *testing.T) { actions := []mgr.RecoveryAction{ {Type: mgr.ServiceRestart, Delay: 5 * time.Second}, } if shouldUpdateRecoveryActions(actions, actions, 30, 30) { t.Fatal("expected identical recovery actions and reset period to skip update") } if !shouldUpdateRecoveryActions(actions, actions, 30, 60) { t.Fatal("expected reset period change to require update") } if !shouldUpdateRecoveryActions(actions, []mgr.RecoveryAction{}, 30, 0) { t.Fatal("expected empty desired recovery actions to require reset") } } func TestRecoveryCommandSpecified(t *testing.T) { if recoveryCommandSpecified(WinSvcInput{}) { t.Fatal("zero-value recovery command should be unspecified") } if !recoveryCommandSpecified(WinSvcInput{RecoveryCommand: "cmd.exe /c exit 0"}) { t.Fatal("non-empty recovery command should stay specified") } if !recoveryCommandSpecified(WinSvcInput{RecoveryCommandSet: true}) { t.Fatal("explicit empty recovery command should be treated as specified") } } func TestCreateServiceRejectsEmptyExecPath(t *testing.T) { _, err := CreateService(WinSvcInput{Name: "unit-svc"}) if err == nil { t.Fatal("expected validation error for empty executable path") } if !errors.Is(err, ErrInvalidInput) { t.Fatalf("expected ErrInvalidInput, got %v", err) } }