返回 DeepSeek-Reasonix
catalog_watcher_lifecycle_test.go
根目录 / internal / skill / catalog_watcher_lifecycle_test.go
1 package skill
2
3 import (
4 "context"
5 "errors"
6 "testing"
7 "time"
8
9 "github.com/fsnotify/fsnotify"
10 )
11
12 func TestCatalogWatchDrainsBackendErrorsDuringRegistrationAndClose(t *testing.T) {
13 ctx, cancel := context.WithCancel(context.Background())
14 defer cancel()
15 events := make(chan fsnotify.Event)
16 backendErrors := make(chan error)
17 ready, done := make(chan struct{}), make(chan struct{})
18 registering := make(chan struct{}, 1)
19 release := make(chan struct{})
20 register := func() {
21 registering <- struct{}{}
22 <-release
23 // Model inotify holding its backend mutex while reporting an error.
24 // Add cannot finish until the event consumer accepts this send.
25 backendErrors <- errors.New("directory renamed while registering")
26 }
27 closeBackend := func() error {
28 backendErrors <- errors.New("backend closing")
29 close(events)
30 close(backendErrors)
31 return nil
32 }
33 go func() {
34 defer close(done)
35 runCatalogWatch(ctx, events, backendErrors, ready, register, closeBackend, func(string) {})
36 }()
37 select {
38 case <-registering:
39 case <-time.After(5 * time.Second):
40 t.Fatal("registration did not start")
41 }
42 // Cancel while Add is blocked: the consumer must still drain backend
43 // errors before the worker can finish registration and close the backend.
44 cancel()
45 close(release)
46 select {
47 case <-done:
48 case <-time.After(5 * time.Second):
49 t.Fatal("watcher stopped draining errors during shutdown")
50 }
51 select {
52 case <-ready:
53 default:
54 t.Fatal("initial registration did not finish")
55 }
56 }
57
57 lines GO