detached d7fe461

Fix swarm tests on Windows CI

commit
d7fe46191050b45b02b23a9d0d4c6b1a78972f9a
author
patriceckhart · · 2026-05-16 12:12 UTC
parent
37526a6
signature
unsigned
3 files · +13 -1
M internal/agent/swarm_agent_test.go +2 -0
@@ -31,6 +31,7 @@ func TestSwarmEmitterMirrorDormantUntilStdoutBreaks(t *testing.T) {
3131 if err != nil {
3232 t.Fatalf("create stdout file: %v", err)
3333 }
34+ defer stdoutFile.Close()
3435
3536 // Mirror writes go to a separate events.jsonl that we can read
3637 // at the end to assert how many events the mirror emitted.
@@ -39,6 +40,7 @@ func TestSwarmEmitterMirrorDormantUntilStdoutBreaks(t *testing.T) {
3940 if err != nil {
4041 t.Fatalf("open mirror: %v", err)
4142 }
43+ defer mirror.Close()
4244
4345 em := newSwarmEmitter(stdoutFile, mirror)
4446
@@ -31,6 +31,7 @@ func TestSwarmEmitterMirrorDormantUntilStdoutBreaks(t *testing.T) {
31 if err != nil {31 if err != nil {
32 t.Fatalf("create stdout file: %v", err)32 t.Fatalf("create stdout file: %v", err)
33 }33 }
34+ defer stdoutFile.Close()
34 35
35 // Mirror writes go to a separate events.jsonl that we can read36 // Mirror writes go to a separate events.jsonl that we can read
36 // at the end to assert how many events the mirror emitted.37 // at the end to assert how many events the mirror emitted.
@@ -39,6 +40,7 @@ func TestSwarmEmitterMirrorDormantUntilStdoutBreaks(t *testing.T) {
39 if err != nil {40 if err != nil {
40 t.Fatalf("open mirror: %v", err)41 t.Fatalf("open mirror: %v", err)
41 }42 }
43+ defer mirror.Close()
42 44
43 em := newSwarmEmitter(stdoutFile, mirror)45 em := newSwarmEmitter(stdoutFile, mirror)
44 46
M internal/swarm/event.go +7 -1
@@ -234,6 +234,7 @@ type EventFollower struct {
234234 interval time.Duration
235235 out chan Event
236236 done chan struct{}
237+ closed chan struct{}
237238 once sync.Once
238239 }
239240
@@ -249,6 +250,7 @@ func FollowEventLog(path string, interval time.Duration) *EventFollower {
249250 interval: interval,
250251 out: make(chan Event, 256),
251252 done: make(chan struct{}),
253+ closed: make(chan struct{}),
252254 }
253255 go f.loop()
254256 return f
@@ -257,14 +259,18 @@ func FollowEventLog(path string, interval time.Duration) *EventFollower {
257259 // Events returns the receive end of the event stream.
258260 func (f *EventFollower) Events() <-chan Event { return f.out }
259261
260-// Close stops polling and closes the events channel.
262+// Close stops polling and closes the events channel. It waits for
263+// the polling goroutine to exit so tests on Windows can remove the
264+// temp directory without racing an open file handle.
261265 func (f *EventFollower) Close() {
262266 f.once.Do(func() {
263267 close(f.done)
268+ <-f.closed
264269 })
265270 }
266271
267272 func (f *EventFollower) loop() {
273+ defer close(f.closed)
268274 defer close(f.out)
269275 var offset int64
270276 tick := time.NewTicker(f.interval)
@@ -234,6 +234,7 @@ type EventFollower struct {
234 interval time.Duration234 interval time.Duration
235 out chan Event235 out chan Event
236 done chan struct{}236 done chan struct{}
237+ closed chan struct{}
237 once sync.Once238 once sync.Once
238 }239 }
239 240
@@ -249,6 +250,7 @@ func FollowEventLog(path string, interval time.Duration) *EventFollower {
249 interval: interval,250 interval: interval,
250 out: make(chan Event, 256),251 out: make(chan Event, 256),
251 done: make(chan struct{}),252 done: make(chan struct{}),
253+ closed: make(chan struct{}),
252 }254 }
253 go f.loop()255 go f.loop()
254 return f256 return f
@@ -257,14 +259,18 @@ func FollowEventLog(path string, interval time.Duration) *EventFollower {
257 // Events returns the receive end of the event stream.259 // Events returns the receive end of the event stream.
258 func (f *EventFollower) Events() <-chan Event { return f.out }260 func (f *EventFollower) Events() <-chan Event { return f.out }
259 261
260-// Close stops polling and closes the events channel.262+// Close stops polling and closes the events channel. It waits for
263+// the polling goroutine to exit so tests on Windows can remove the
264+// temp directory without racing an open file handle.
261 func (f *EventFollower) Close() {265 func (f *EventFollower) Close() {
262 f.once.Do(func() {266 f.once.Do(func() {
263 close(f.done)267 close(f.done)
268+ <-f.closed
264 })269 })
265 }270 }
266 271
267 func (f *EventFollower) loop() {272 func (f *EventFollower) loop() {
273+ defer close(f.closed)
268 defer close(f.out)274 defer close(f.out)
269 var offset int64275 var offset int64
270 tick := time.NewTicker(f.interval)276 tick := time.NewTicker(f.interval)
M internal/swarm/inbox_test.go +4 -0
@@ -5,6 +5,7 @@ import (
55 "fmt"
66 "os"
77 "path/filepath"
8+ "runtime"
89 "sync"
910 "syscall"
1011 "testing"
@@ -18,6 +19,9 @@ import (
1819 // can't use it.
1920 func shortSocketDir(t *testing.T) string {
2021 t.Helper()
22+ if runtime.GOOS == "windows" {
23+ t.Skip("swarm inbox transport uses Unix-domain sockets; Windows support will use a named-pipe backend")
24+ }
2125 dir, err := os.MkdirTemp("/tmp", "zot-in-")
2226 if err != nil {
2327 t.Fatalf("mkdir: %v", err)
@@ -5,6 +5,7 @@ import (
5 "fmt"5 "fmt"
6 "os"6 "os"
7 "path/filepath"7 "path/filepath"
8+ "runtime"
8 "sync"9 "sync"
9 "syscall"10 "syscall"
10 "testing"11 "testing"
@@ -18,6 +19,9 @@ import (
18 // can't use it.19 // can't use it.
19 func shortSocketDir(t *testing.T) string {20 func shortSocketDir(t *testing.T) string {
20 t.Helper()21 t.Helper()
22+ if runtime.GOOS == "windows" {
23+ t.Skip("swarm inbox transport uses Unix-domain sockets; Windows support will use a named-pipe backend")
24+ }
21 dir, err := os.MkdirTemp("/tmp", "zot-in-")25 dir, err := os.MkdirTemp("/tmp", "zot-in-")
22 if err != nil {26 if err != nil {
23 t.Fatalf("mkdir: %v", err)27 t.Fatalf("mkdir: %v", err)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close