| 134 | } |
| 135 | |
| 136 | func TestWatcher_WaitReady(t *testing.T) { |
| 137 | t.Run("should return nil when watcher is ready", func(t *testing.T) { |
| 138 | watcher := &Watcher{ |
| 139 | readyCh: make(chan struct{}), |
| 140 | watchingFunc: func() error { |
| 141 | return nil |
| 142 | }, |
| 143 | isReady: false, |
| 144 | } |
| 145 | |
| 146 | // Start watcher in background |
| 147 | go func() { |
| 148 | err := watcher.Run() |
| 149 | assert.NoError(t, err) |
| 150 | }() |
| 151 | |
| 152 | // WaitReady should return nil quickly |
| 153 | err := watcher.WaitReady(5 * time.Second) |
| 154 | assert.NoError(t, err) |
| 155 | }) |
| 156 | |
| 157 | t.Run("should return timeout error when timeout expires", func(t *testing.T) { |
| 158 | watcher := &Watcher{ |
| 159 | readyCh: make(chan struct{}), // Never closed |
| 160 | watchingFunc: func() error { |
| 161 | return nil |
| 162 | }, |
| 163 | isReady: false, |
| 164 | } |
| 165 | |
| 166 | // Don't start the watcher, so readyCh never closes |
| 167 | start := time.Now() |
| 168 | err := watcher.WaitReady(100 * time.Millisecond) |
| 169 | |
| 170 | elapsed := time.Since(start) |
| 171 | assert.Error(t, err) |
| 172 | assert.Contains(t, err.Error(), "timeout") |
| 173 | assert.GreaterOrEqual(t, elapsed, 100*time.Millisecond) |
| 174 | }) |
| 175 | |
| 176 | t.Run("should return immediately if already ready", func(t *testing.T) { |
| 177 | readyCh := make(chan struct{}) |
| 178 | close(readyCh) // Pre-close the channel |
| 179 | |
| 180 | watcher := &Watcher{ |
| 181 | readyCh: readyCh, |
| 182 | watchingFunc: func() error { |
| 183 | return nil |
| 184 | }, |
| 185 | isReady: true, |
| 186 | } |
| 187 | |
| 188 | start := time.Now() |
| 189 | err := watcher.WaitReady(5 * time.Second) |
| 190 | elapsed := time.Since(start) |
| 191 | |
| 192 | assert.NoError(t, err) |
| 193 | assert.Less(t, elapsed, 100*time.Millisecond, "should return immediately") |