//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)
}
})
}
}