test: fix macOS and Windows CI test failures

These surfaced once the codec libs let macOS/Windows compile and run tests:

- ipc: bind sockets under a short /tmp dir on macOS (sun_path is capped at 104 bytes; t.TempDir() under /var/folders overflows for long test names).

- plugintrust: skip the 0600 manifest-mode assertion on Windows (no Unix perm bits; Stat reports 0666).

- pluginmgr: verify the installed plugin under the temp HOME instead of os.UserHomeDir(), which ignores HOME on Windows.

- luaplugin: run the exec output test via cmd instead of PowerShell so the process exits and closes stdout promptly, letting on_exit fire.
This commit is contained in:
Bjarne Øverli
2026-07-17 12:53:57 +02:00
parent 5cfef38275
commit 9b0cbb65d4
4 changed files with 34 additions and 11 deletions
+4 -1
View File
@@ -4,6 +4,7 @@ import (
"errors"
"os"
"path/filepath"
"runtime"
"testing"
)
@@ -42,7 +43,9 @@ func TestApprovalLifecycle(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if got := info.Mode().Perm(); got != 0o600 {
// Windows has no Unix permission bits; os.Stat reports 0666 for any
// writable file, so the 0600 check only applies on Unix.
if got := info.Mode().Perm(); runtime.GOOS != "windows" && got != 0o600 {
t.Errorf("manifest mode = %o, want 600", got)
}
}
+24 -6
View File
@@ -3,16 +3,34 @@ package ipc
import (
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"testing"
"time"
)
// shortTempDir returns a temp directory whose path is short enough for a Unix
// socket. macOS caps the socket path (sun_path) at 104 bytes, and t.TempDir()
// under /var/folders overflows that for longer test names; use a short /tmp base
// there. Other platforms keep t.TempDir().
func shortTempDir(t *testing.T) string {
t.Helper()
if runtime.GOOS != "darwin" {
return t.TempDir()
}
d, err := os.MkdirTemp("/tmp", "c")
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = os.RemoveAll(d) })
return d
}
// TestSendRoundTrip spins up a real server bound to a temp socket and exchanges
// one request/response through the client.
func TestSendRoundTrip(t *testing.T) {
sock := filepath.Join(t.TempDir(), "cliamp.sock")
sock := filepath.Join(shortTempDir(t), "cliamp.sock")
disp := &captureDispatcher{autoReply: Response{OK: true}}
srv, err := NewServer(sock, disp)
@@ -34,7 +52,7 @@ func TestSendRoundTrip(t *testing.T) {
}
func TestSendNoServer(t *testing.T) {
sock := filepath.Join(t.TempDir(), "missing.sock")
sock := filepath.Join(shortTempDir(t), "missing.sock")
_, err := Send(sock, Request{Cmd: "status"})
if err == nil {
@@ -47,7 +65,7 @@ func TestSendNoServer(t *testing.T) {
func TestSendInvalidRequestReturnsError(t *testing.T) {
// Server responds to an unknown cmd with OK:false, Error:"unknown command:...".
sock := filepath.Join(t.TempDir(), "cliamp.sock")
sock := filepath.Join(shortTempDir(t), "cliamp.sock")
srv, err := NewServer(sock, &captureDispatcher{})
if err != nil {
t.Fatalf("NewServer: %v", err)
@@ -153,7 +171,7 @@ func TestNewServerLivePIDReturnsError(t *testing.T) {
}
func TestServerCloseRemovesFiles(t *testing.T) {
sock := filepath.Join(t.TempDir(), "cliamp.sock")
sock := filepath.Join(shortTempDir(t), "cliamp.sock")
srv, err := NewServer(sock, &captureDispatcher{})
if err != nil {
t.Fatalf("NewServer: %v", err)
@@ -182,7 +200,7 @@ func TestServerMultipleRequestsSameConnection(t *testing.T) {
// Make sure the server can handle multiple requests over a single socket.
// Each Send opens its own connection, so this really verifies the accept
// loop keeps going beyond the first request.
sock := filepath.Join(t.TempDir(), "cliamp.sock")
sock := filepath.Join(shortTempDir(t), "cliamp.sock")
disp := &captureDispatcher{}
srv, err := NewServer(sock, disp)
if err != nil {
@@ -202,7 +220,7 @@ func TestServerMultipleRequestsSameConnection(t *testing.T) {
}
func TestServerHandlesInvalidJSON(t *testing.T) {
sock := filepath.Join(t.TempDir(), "cliamp.sock")
sock := filepath.Join(shortTempDir(t), "cliamp.sock")
srv, err := NewServer(sock, &captureDispatcher{})
if err != nil {
t.Fatalf("NewServer: %v", err)
+3 -1
View File
@@ -45,7 +45,9 @@ func execTestAllowedBinaries() []string {
func execOutputCommand() (binary string, args []string, wantLine string) {
if runtime.GOOS == "windows" {
return "powershell", []string{"-NoProfile", "-Command", "Write-Output 'hello world'"}, "hello world"
// cmd exits immediately after echo and closes stdout cleanly; PowerShell's
// slower startup and stdout-close timing left on_exit pending on CI.
return "cmd", []string{"/c", "echo", "hello", "world"}, "hello world"
}
return "echo", []string{"hello", "world"}, "hello world"
}
+3 -3
View File
@@ -223,7 +223,7 @@ func TestRemoveMissing(t *testing.T) {
}
func TestInstallFromRawURL(t *testing.T) {
withTempHome(t)
home := withTempHome(t)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !strings.HasSuffix(r.URL.Path, "/example.lua") {
t.Errorf("unexpected path %q", r.URL.Path)
@@ -237,8 +237,8 @@ func TestInstallFromRawURL(t *testing.T) {
t.Fatalf("Install: %v", err)
}
// Verify the installed file exists.
home, _ := os.UserHomeDir()
// Verify the installed file exists. Use the temp HOME (not os.UserHomeDir,
// which ignores HOME on Windows) so this matches where Install wrote it.
dest := filepath.Join(home, ".config", "cliamp", "plugins", "example.lua")
if _, err := os.Stat(dest); err != nil {
t.Errorf("installed plugin missing: %v", err)