Files
goyco/cmd/goyco/commands/daemon_test.go

342 lines
7.9 KiB
Go

package commands
import (
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"goyco/internal/config"
"goyco/internal/testutils"
)
func TestHandleStartCommand(t *testing.T) {
cfg := testutils.NewTestConfig()
t.Run("help requested", func(t *testing.T) {
err := HandleStartCommand(cfg, []string{"--help"})
if err != nil {
t.Errorf("unexpected error for help: %v", err)
}
})
t.Run("unexpected arguments", func(t *testing.T) {
err := HandleStartCommand(cfg, []string{"extra", "args"})
if err == nil {
t.Error("expected error for unexpected arguments")
}
expectedErr := "unexpected arguments for start command"
if err.Error() != expectedErr {
t.Errorf("expected error %q, got %q", expectedErr, err.Error())
}
})
}
func TestHandleStopCommand(t *testing.T) {
cfg := testutils.NewTestConfig()
t.Run("help requested", func(t *testing.T) {
err := HandleStopCommand(cfg, []string{"--help"})
if err != nil {
t.Errorf("unexpected error for help: %v", err)
}
})
t.Run("unexpected arguments", func(t *testing.T) {
err := HandleStopCommand(cfg, []string{"extra", "args"})
if err == nil {
t.Error("expected error for unexpected arguments")
}
expectedErr := "unexpected arguments for stop command"
if err.Error() != expectedErr {
t.Errorf("expected error %q, got %q", expectedErr, err.Error())
}
})
}
func TestHandleStatusCommand(t *testing.T) {
cfg := testutils.NewTestConfig()
t.Run("help requested", func(t *testing.T) {
err := HandleStatusCommand(cfg, "status", []string{"--help"})
if err != nil {
t.Errorf("unexpected error for help: %v", err)
}
})
t.Run("unexpected arguments", func(t *testing.T) {
err := HandleStatusCommand(cfg, "status", []string{"extra", "args"})
if err == nil {
t.Error("expected error for unexpected arguments")
}
expectedErr := "unexpected arguments for status command"
if err.Error() != expectedErr {
t.Errorf("expected error %q, got %q", expectedErr, err.Error())
}
})
}
func TestRunStatusCommand(t *testing.T) {
cfg := testutils.NewTestConfig()
t.Run("daemon not running", func(t *testing.T) {
tempDir := t.TempDir()
cfg.PIDDir = tempDir
err := runStatusCommand(cfg)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
})
t.Run("daemon not running with JSON output", func(t *testing.T) {
SetJSONOutput(true)
defer SetJSONOutput(false)
tempDir := t.TempDir()
cfg.PIDDir = tempDir
err := runStatusCommand(cfg)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
})
t.Run("daemon running with valid PID", func(t *testing.T) {
tempDir := t.TempDir()
cfg.PIDDir = tempDir
pidFile := filepath.Join(tempDir, "goyco.pid")
currentPID := os.Getpid()
err := os.WriteFile(pidFile, []byte(strconv.Itoa(currentPID)), 0644)
if err != nil {
t.Fatalf("Failed to create PID file: %v", err)
}
err = runStatusCommand(cfg)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
})
t.Run("daemon running with valid PID and JSON output", func(t *testing.T) {
SetJSONOutput(true)
defer SetJSONOutput(false)
tempDir := t.TempDir()
cfg.PIDDir = tempDir
pidFile := filepath.Join(tempDir, "goyco.pid")
currentPID := os.Getpid()
err := os.WriteFile(pidFile, []byte(strconv.Itoa(currentPID)), 0644)
if err != nil {
t.Fatalf("Failed to create PID file: %v", err)
}
err = runStatusCommand(cfg)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
})
t.Run("daemon running with invalid PID file", func(t *testing.T) {
tempDir := t.TempDir()
cfg.PIDDir = tempDir
pidFile := filepath.Join(tempDir, "goyco.pid")
err := os.WriteFile(pidFile, []byte("invalid-pid"), 0644)
if err != nil {
t.Fatalf("Failed to create PID file: %v", err)
}
err = runStatusCommand(cfg)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
})
}
func TestIsDaemonRunning(t *testing.T) {
t.Run("PID file does not exist", func(t *testing.T) {
pidFile := "/non/existent/pid/file"
result := isDaemonRunning(pidFile)
if result {
t.Error("expected false for non-existent PID file")
}
})
t.Run("PID file exists but contains invalid PID", func(t *testing.T) {
tempDir := t.TempDir()
pidFile := filepath.Join(tempDir, "goyco.pid")
err := os.WriteFile(pidFile, []byte("invalid-pid"), 0644)
if err != nil {
t.Fatalf("Failed to create PID file: %v", err)
}
result := isDaemonRunning(pidFile)
if result {
t.Error("expected false for invalid PID")
}
})
t.Run("PID file exists with valid PID", func(t *testing.T) {
tempDir := t.TempDir()
pidFile := filepath.Join(tempDir, "goyco.pid")
currentPID := os.Getpid()
err := os.WriteFile(pidFile, []byte(strconv.Itoa(currentPID)), 0644)
if err != nil {
t.Fatalf("Failed to create PID file: %v", err)
}
result := isDaemonRunning(pidFile)
if !result {
t.Error("expected true for valid PID")
}
})
}
func TestWritePIDFile(t *testing.T) {
t.Run("successful write", func(t *testing.T) {
tempDir := t.TempDir()
pidFile := filepath.Join(tempDir, "goyco.pid")
pid := 12345
err := writePIDFile(pidFile, pid)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
content, err := os.ReadFile(pidFile)
if err != nil {
t.Fatalf("Failed to read PID file: %v", err)
}
expectedContent := strconv.Itoa(pid)
if string(content) != expectedContent {
t.Errorf("expected PID file content %q, got %q", expectedContent, string(content))
}
})
t.Run("write to non-existent directory", func(t *testing.T) {
pidFile := "/non/existent/directory/goyco.pid"
pid := 12345
err := writePIDFile(pidFile, pid)
if err == nil {
t.Error("expected error for non-existent directory")
}
})
}
func TestSetupDaemonLogging(t *testing.T) {
cfg := testutils.NewTestConfig()
tempDir := t.TempDir()
t.Run("successful setup", func(t *testing.T) {
err := SetupDaemonLogging(cfg, tempDir)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
logFile := filepath.Join(tempDir, "goyco.log")
if _, err := os.Stat(logFile); os.IsNotExist(err) {
t.Error("expected log file to be created")
}
})
t.Run("setup with non-existent directory", func(t *testing.T) {
nonExistentDir := "/non/existent/directory"
err := SetupDaemonLogging(cfg, nonExistentDir)
if err == nil {
t.Error("expected error for non-existent directory")
}
})
}
func TestRunDaemonProcessDirect(t *testing.T) {
SetRunServer(func(_ *config.Config, _ bool) error {
return nil
})
defer SetRunServer(nil)
SetDaemonize(func() (int, error) {
return 999, nil
})
defer SetDaemonize(nil)
SetSetupDaemonLogging(func(_ *config.Config, _ string) error {
return nil
})
defer SetSetupDaemonLogging(nil)
t.Run("missing DB_PASSWORD", func(t *testing.T) {
t.Setenv("DB_PASSWORD", "")
t.Setenv("SMTP_HOST", "")
t.Setenv("SMTP_FROM", "")
t.Setenv("ADMIN_EMAIL", "")
t.Setenv("LOG_DIR", "/tmp/test-logs")
err := RunDaemonProcessDirect([]string{})
if err == nil {
t.Error("expected error for missing DB_PASSWORD")
}
expectedErr := "load configuration: DB_PASSWORD is required"
if err.Error() != expectedErr {
t.Errorf("expected error %q, got %q", expectedErr, err.Error())
}
})
t.Run("empty LOG_DIR returns error", func(t *testing.T) {
t.Setenv("DB_PASSWORD", "test-password")
t.Setenv("SMTP_HOST", "smtp.example.com")
t.Setenv("SMTP_FROM", "test@example.com")
t.Setenv("ADMIN_EMAIL", "admin@example.com")
t.Setenv("JWT_SECRET", "this-is-a-very-secure-jwt-secret-key-that-is-long-enough")
t.Setenv("LOG_DIR", "")
err := RunDaemonProcessDirect([]string{})
if err == nil {
t.Skip("LOG_DIR empty doesn't return error (may be handled by config defaults)")
return
}
errMsg := err.Error()
if !strings.Contains(errMsg, "LOG_DIR environment variable is required") &&
!strings.Contains(errMsg, "permission denied") &&
!strings.Contains(errMsg, "setup daemon logging") {
t.Logf("Got error (may be acceptable): %q", errMsg)
}
})
}