//go:build darwin package daemon import ( "strings" "testing" ) func TestGeneratePlist(t *testing.T) { plist := generatePlist() // Verify it is valid-looking XML with the expected plist header. if !strings.HasPrefix(plist, ``) { t.Error("plist should start with XML declaration") } if !strings.Contains(plist, ``) { t.Error("plist should contain plist version tag") } // Verify the label matches the constant. expectedLabel := "" + LaunchDaemonLabel + "" if !strings.Contains(plist, expectedLabel) { t.Errorf("plist should contain label %q", LaunchDaemonLabel) } // Verify program arguments. if !strings.Contains(plist, ""+InstallBinaryPath+"") { t.Errorf("plist should reference binary path %q", InstallBinaryPath) } if !strings.Contains(plist, "daemon") { t.Error("plist should contain 'daemon' argument") } if !strings.Contains(plist, "run") { t.Error("plist should contain 'run' argument") } // Verify RunAtLoad and KeepAlive. if !strings.Contains(plist, "RunAtLoad") { t.Error("plist should have RunAtLoad set to true") } if !strings.Contains(plist, "KeepAlive") { t.Error("plist should have KeepAlive set to true") } // Verify log paths. if !strings.Contains(plist, "/var/log/greywall.log") { t.Error("plist should reference /var/log/greywall.log for stdout/stderr") } } func TestGeneratePlistProgramArguments(t *testing.T) { plist := generatePlist() // Verify the ProgramArguments array contains exactly 3 entries in order. // The array should be: /usr/local/bin/greywall, daemon, run argStart := strings.Index(plist, "ProgramArguments") if argStart == -1 { t.Fatal("plist should contain ProgramArguments key") } // Extract the array section. arrayStart := strings.Index(plist[argStart:], "") arrayEnd := strings.Index(plist[argStart:], "") if arrayStart == -1 || arrayEnd == -1 { t.Fatal("ProgramArguments should contain an array") } arrayContent := plist[argStart+arrayStart : argStart+arrayEnd] expectedArgs := []string{InstallBinaryPath, "daemon", "run"} for _, arg := range expectedArgs { if !strings.Contains(arrayContent, ""+arg+"") { t.Errorf("ProgramArguments array should contain %q", arg) } } } func TestIsInstalledReturnsFalse(t *testing.T) { // On a test machine without the daemon installed, this should return false. // We cannot guarantee the daemon is not installed, but on most dev machines // it will not be. This test verifies the function runs without panicking. result := IsInstalled() // We only validate the function returns a bool without error. // On CI/dev machines the plist should not exist. _ = result } func TestIsRunningReturnsFalse(t *testing.T) { // On a test machine without the daemon running, this should return false. // Similar to TestIsInstalledReturnsFalse, we verify it runs cleanly. result := IsRunning() _ = result } func TestConstants(t *testing.T) { // Verify constants have expected values. tests := []struct { name string got string expected string }{ {"LaunchDaemonLabel", LaunchDaemonLabel, "co.greyhaven.greywall"}, {"LaunchDaemonPlistPath", LaunchDaemonPlistPath, "/Library/LaunchDaemons/co.greyhaven.greywall.plist"}, {"InstallBinaryPath", InstallBinaryPath, "/usr/local/bin/greywall"}, {"InstallLibDir", InstallLibDir, "/usr/local/lib/greywall"}, {"SandboxUserName", SandboxUserName, "_greywall"}, {"SandboxUserUID", SandboxUserUID, "399"}, {"SandboxGroupName", SandboxGroupName, "_greywall"}, {"SudoersFilePath", SudoersFilePath, "/etc/sudoers.d/greywall"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.got != tt.expected { t.Errorf("%s = %q, want %q", tt.name, tt.got, tt.expected) } }) } }