1package fetcher
2
3import (
4 "errors"
5 "sync/atomic"
6 "testing"
7 "time"
8
9 "github.com/floatpane/matcha/config"
10)
11
12func TestIdleWatcher_StopAllAndWait_TracksReplacedGoroutines(t *testing.T) {
13 w := NewIdleWatcher(make(chan IdleUpdate))
14 stopCh := make(chan struct{})
15 doneCh := make(chan struct{})
16 var exits atomic.Int64
17
18 w.wg.Add(1)
19 go func() {
20 defer w.wg.Done()
21 defer close(doneCh)
22 <-stopCh
23 exits.Add(1)
24 }()
25
26 w.watchers["acct"] = &accountIdle{
27 account: &config.Account{ID: "acct"},
28 stop: stopCh,
29 done: doneCh,
30 }
31
32 if err := w.StopAllAndWaitTimeout(time.Second); err != nil {
33 t.Fatalf("StopAllAndWaitTimeout returned error: %v", err)
34 }
35 if got := exits.Load(); got != 1 {
36 t.Fatalf("expected synthetic watcher to exit once, got %d", got)
37 }
38}
39
40func TestIdleWatcher_StopAllAndWaitTimeout_ReturnsOnSlowExit(t *testing.T) {
41 w := NewIdleWatcher(make(chan IdleUpdate))
42 stopCh := make(chan struct{})
43 doneCh := make(chan struct{})
44 release := make(chan struct{})
45 exited := make(chan struct{})
46
47 w.wg.Add(1)
48 go func() {
49 defer w.wg.Done()
50 defer close(doneCh)
51 defer close(exited)
52 <-release
53 }()
54
55 w.watchers["acct"] = &accountIdle{
56 account: &config.Account{ID: "acct"},
57 stop: stopCh,
58 done: doneCh,
59 }
60
61 err := w.StopAllAndWaitTimeout(50 * time.Millisecond)
62 if !errors.Is(err, ErrStopTimeout) {
63 t.Fatalf("expected ErrStopTimeout, got %v", err)
64 }
65
66 close(release)
67 select {
68 case <-exited:
69 case <-time.After(time.Second):
70 t.Fatal("synthetic watcher did not exit during cleanup")
71 }
72}