Skip to content

Commit 261fcce

Browse files
committed
Test API listener split and pipe URL forms
Cover the per-platform refactor of setupUnixSocket. On all platforms, assert socketURL emits unix:// for filesystem addresses and that isNamedPipeAddress detects \.\pipe\ prefixes. On Windows, additionally assert socketURL emits npipe://<name>, that setupUnixSocket against a unique pipe path returns a winio listener that accepts a winio dial within a 2 s timeout (proving the listener is wired to the named-pipe namespace, not AF_UNIX), and that cleanupUnixSocket no-ops for pipe addresses without panicking. Tests are split via build tags so the Windows test file is only compiled on GOOS=windows and pulls in winio there.
1 parent bdfd53e commit 261fcce

2 files changed

Lines changed: 125 additions & 0 deletions

File tree

pkg/api/socket_other_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//go:build !windows
5+
6+
package api
7+
8+
import (
9+
"testing"
10+
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
func TestSocketURL_Unix(t *testing.T) {
15+
t.Parallel()
16+
assert.Equal(t, "unix:///tmp/test.sock", socketURL("/tmp/test.sock"))
17+
}
18+
19+
func TestIsNamedPipeAddress(t *testing.T) {
20+
t.Parallel()
21+
tests := []struct {
22+
name string
23+
address string
24+
want bool
25+
}{
26+
{"plain socket", "/tmp/thv.sock", false},
27+
{"named pipe", `\\.\pipe\thv-api`, true},
28+
{"empty", "", false},
29+
}
30+
for _, tt := range tests {
31+
t.Run(tt.name, func(t *testing.T) {
32+
t.Parallel()
33+
assert.Equal(t, tt.want, isNamedPipeAddress(tt.address))
34+
})
35+
}
36+
}

pkg/api/socket_windows_test.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//go:build windows
5+
6+
package api
7+
8+
import (
9+
"context"
10+
"fmt"
11+
"sync/atomic"
12+
"testing"
13+
"time"
14+
15+
"github.com/Microsoft/go-winio"
16+
"github.com/stretchr/testify/assert"
17+
"github.com/stretchr/testify/require"
18+
)
19+
20+
// pipeNameSeq disambiguates concurrent test pipes so parallel runs don't
21+
// collide on the global Windows pipe namespace.
22+
var pipeNameSeq atomic.Uint64
23+
24+
func uniqueTestPipe() string {
25+
return fmt.Sprintf(`\\.\pipe\thv-api-test-%d`, pipeNameSeq.Add(1))
26+
}
27+
28+
func TestSocketURL_Windows(t *testing.T) {
29+
t.Parallel()
30+
tests := []struct {
31+
name string
32+
address string
33+
want string
34+
}{
35+
{"named pipe", `\\.\pipe\thv-api`, "npipe://thv-api"},
36+
{"af_unix windows path", `C:\path\thv.sock`, `unix://C:\path\thv.sock`},
37+
}
38+
for _, tt := range tests {
39+
t.Run(tt.name, func(t *testing.T) {
40+
t.Parallel()
41+
assert.Equal(t, tt.want, socketURL(tt.address))
42+
})
43+
}
44+
}
45+
46+
func TestSetupUnixSocket_NamedPipe(t *testing.T) {
47+
t.Parallel()
48+
pipePath := uniqueTestPipe()
49+
50+
listener, err := setupUnixSocket(pipePath)
51+
require.NoError(t, err)
52+
t.Cleanup(func() { _ = listener.Close() })
53+
54+
// The listener should accept a winio dial within a short timeout, proving
55+
// it is wired to the named-pipe namespace and not to AF_UNIX.
56+
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
57+
defer cancel()
58+
59+
connCh := make(chan error, 1)
60+
go func() {
61+
conn, dialErr := winio.DialPipeContext(ctx, pipePath)
62+
if conn != nil {
63+
_ = conn.Close()
64+
}
65+
connCh <- dialErr
66+
}()
67+
68+
go func() {
69+
conn, _ := listener.Accept()
70+
if conn != nil {
71+
_ = conn.Close()
72+
}
73+
}()
74+
75+
select {
76+
case err := <-connCh:
77+
require.NoError(t, err)
78+
case <-ctx.Done():
79+
t.Fatal("dial against named-pipe listener timed out")
80+
}
81+
}
82+
83+
func TestCleanupUnixSocket_NamedPipe_NoOp(t *testing.T) {
84+
t.Parallel()
85+
// Passing a pipe address to cleanup must not error or panic. There is no
86+
// file to remove; the assertion here is simply that the call returns
87+
// cleanly.
88+
cleanupUnixSocket(`\\.\pipe\thv-api-cleanup-noop`)
89+
}

0 commit comments

Comments
 (0)