Skip to content

Commit 6041975

Browse files
authored
fix: remove closed socker watcher from slice
Signed-off-by: GitHub <[email protected]>
1 parent 0cc9bb9 commit 6041975

File tree

2 files changed

+64
-1
lines changed

2 files changed

+64
-1
lines changed

cns/deviceplugin/socketwatcher.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ func (s *SocketWatcher) WatchSocket(ctx context.Context, socket string) <-chan s
5656
socketChan := make(chan struct{})
5757
s.socketChans[socket] = socketChan
5858
go func() {
59-
defer close(socketChan)
59+
defer func() {
60+
s.mutex.Lock()
61+
delete(s.socketChans, socket)
62+
s.mutex.Unlock()
63+
close(socketChan)
64+
}()
6065
ticker := time.NewTicker(s.options.statInterval)
6166
defer ticker.Stop()
6267
for {

cns/deviceplugin/socketwatcher_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,61 @@ func TestWatchSocketTwice(t *testing.T) {
134134
t.Fatal("socket watcher is still watching 5 seconds after file is deleted")
135135
}
136136
}
137+
138+
func TestWatchSocketCleanup(t *testing.T) {
139+
// Create a temporary directory
140+
tempDir, err := os.MkdirTemp("", "socket-watcher-test-")
141+
if err != nil {
142+
t.Fatalf("error creating temporary directory: %v", err)
143+
}
144+
defer os.RemoveAll(tempDir) // Ensure the directory is cleaned up
145+
146+
socket := filepath.Join(tempDir, "to-be-deleted.sock")
147+
if _, err := os.Create(socket); err != nil {
148+
t.Fatalf("error creating test file %s: %v", socket, err)
149+
}
150+
151+
logger, _ := zap.NewDevelopment()
152+
// Use a short interval for faster test execution
153+
s := deviceplugin.NewSocketWatcher(logger, deviceplugin.SocketWatcherStatInterval(100*time.Millisecond))
154+
155+
// 1. Watch the socket
156+
ch1 := s.WatchSocket(context.Background(), socket)
157+
158+
// Verify it's open
159+
select {
160+
case <-ch1:
161+
t.Fatal("channel should be open initially")
162+
default:
163+
}
164+
165+
// 2. Delete the socket to trigger watcher exit
166+
if err := os.Remove(socket); err != nil {
167+
t.Fatalf("failed to remove socket: %v", err)
168+
}
169+
170+
// 3. Wait for ch1 to close
171+
select {
172+
case <-ch1:
173+
// Expected
174+
case <-time.After(2 * time.Second):
175+
t.Fatal("timed out waiting for watcher to detect socket deletion")
176+
}
177+
178+
// 4. Recreate the socket
179+
if _, err := os.Create(socket); err != nil {
180+
t.Fatalf("error recreating test file %s: %v", socket, err)
181+
}
182+
183+
// 5. Watch the socket again
184+
// If the bug exists, this will return the OLD closed channel (ch1) or a closed channel
185+
ch2 := s.WatchSocket(context.Background(), socket)
186+
187+
// 6. Verify ch2 is NOT closed immediately
188+
select {
189+
case <-ch2:
190+
t.Fatal("WatchSocket returned a closed channel on the second call! The map entry was likely not cleaned up.")
191+
case <-time.After(200 * time.Millisecond):
192+
// If we wait a bit and it's still open, that's good.
193+
}
194+
}

0 commit comments

Comments
 (0)