@@ -17,6 +17,37 @@ import (
1717 "github.com/Prescott-Data/nexus-framework/nexus-broker/internal/service"
1818)
1919
20+ func runWorkerUntilSignal (t * testing.T , worker * service.ConnectionHealthWorker , done <- chan struct {}) {
21+ t .Helper ()
22+ ctx , cancel := context .WithCancel (context .Background ())
23+ workerDone := make (chan struct {})
24+
25+ go func () {
26+ defer close (workerDone )
27+ worker .Start (ctx )
28+ }()
29+
30+ select {
31+ case <- done :
32+ case <- time .After (2 * time .Second ):
33+ cancel ()
34+ select {
35+ case <- workerDone :
36+ case <- time .After (2 * time .Second ):
37+ t .Fatal ("timed out waiting for health worker to stop after signal timeout" )
38+ }
39+ t .Fatal ("timed out waiting for health worker signal" )
40+ }
41+
42+ cancel ()
43+
44+ select {
45+ case <- workerDone :
46+ case <- time .After (2 * time .Second ):
47+ t .Fatal ("timed out waiting for health worker to stop" )
48+ }
49+ }
50+
2051// Add missing mock methods to MockConnectionRepository
2152func (m * MockConnectionRepository ) GetForHealthCheck (ctx context.Context , limit int ) ([]* domain.ConnectionWithProvider , error ) {
2253 args := m .Called (ctx , limit )
@@ -126,15 +157,14 @@ func TestConnectionHealthWorker_OAuth2_Healthy(t *testing.T) {
126157 mockSvc .On ("Refresh" , mock .Anything , connID ).Return (& service.RefreshResponse {}, nil ).Once ()
127158
128159 // Should update health to healthy
129- mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "healthy" ).Return (nil ).Once ()
160+ done := make (chan struct {})
161+ mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "healthy" ).
162+ Run (func (args mock.Arguments ) { close (done ) }).
163+ Return (nil ).Once ()
130164
131165 worker := service .NewConnectionHealthWorker (mockRepo , mockSvc , mockHealth , 10 * time .Millisecond )
132-
133- ctx , cancel := context .WithCancel (context .Background ())
134- go worker .Start (ctx )
135-
136- time .Sleep (50 * time .Millisecond ) // Give it time to run at least once
137- cancel ()
166+
167+ runWorkerUntilSignal (t , worker , done )
138168
139169 mockRepo .AssertExpectations (t )
140170 mockSvc .AssertExpectations (t )
@@ -169,15 +199,14 @@ func TestConnectionHealthWorker_OAuth2_Expired(t *testing.T) {
169199 mockRepo .On ("UpdateStatus" , mock .Anything , connID , "expired" ).Return (nil ).Once ()
170200
171201 // Should update health to expired
172- mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "expired" ).Return (nil ).Once ()
202+ done := make (chan struct {})
203+ mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "expired" ).
204+ Run (func (args mock.Arguments ) { close (done ) }).
205+ Return (nil ).Once ()
173206
174207 worker := service .NewConnectionHealthWorker (mockRepo , mockSvc , mockHealth , 10 * time .Millisecond )
175-
176- ctx , cancel := context .WithCancel (context .Background ())
177- go worker .Start (ctx )
178-
179- time .Sleep (50 * time .Millisecond )
180- cancel ()
208+
209+ runWorkerUntilSignal (t , worker , done )
181210
182211 mockRepo .AssertExpectations (t )
183212 mockSvc .AssertExpectations (t )
@@ -213,15 +242,14 @@ func TestConnectionHealthWorker_OAuth2_ProviderDown_ShieldsExpiration(t *testing
213242
214243 // Should NOT call UpdateStatus (no expiration)
215244 // Should update health to "unhealthy" instead of "expired"
216- mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "unhealthy" ).Return (nil ).Once ()
245+ done := make (chan struct {})
246+ mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "unhealthy" ).
247+ Run (func (args mock.Arguments ) { close (done ) }).
248+ Return (nil ).Once ()
217249
218250 worker := service .NewConnectionHealthWorker (mockRepo , mockSvc , mockHealth , 10 * time .Millisecond )
219251
220- ctx , cancel := context .WithCancel (context .Background ())
221- go worker .Start (ctx )
222-
223- time .Sleep (50 * time .Millisecond )
224- cancel ()
252+ runWorkerUntilSignal (t , worker , done )
225253
226254 mockRepo .AssertExpectations (t )
227255 mockSvc .AssertExpectations (t )
@@ -267,15 +295,14 @@ func TestConnectionHealthWorker_APIKey_Expired(t *testing.T) {
267295 mockRepo .On ("UpdateStatus" , mock .Anything , connID , "expired" ).Return (nil ).Once ()
268296
269297 // Should update health to expired
270- mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "expired" ).Return (nil ).Once ()
298+ done := make (chan struct {})
299+ mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "expired" ).
300+ Run (func (args mock.Arguments ) { close (done ) }).
301+ Return (nil ).Once ()
271302
272303 worker := service .NewConnectionHealthWorker (mockRepo , mockSvc , mockHealth , 10 * time .Millisecond )
273-
274- ctx , cancel := context .WithCancel (context .Background ())
275- go worker .Start (ctx )
276-
277- time .Sleep (50 * time .Millisecond )
278- cancel ()
304+
305+ runWorkerUntilSignal (t , worker , done )
279306
280307 mockRepo .AssertExpectations (t )
281308 mockSvc .AssertExpectations (t )
@@ -304,15 +331,14 @@ func TestConnectionHealthWorker_OAuth2_Upstream5xx_MarksUnhealthy(t *testing.T)
304331
305332 // Should set health_status to "unhealthy", NOT "expired"
306333 // Should NOT call UpdateStatus — connection status stays "active"
307- mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "unhealthy" ).Return (nil ).Once ()
334+ done := make (chan struct {})
335+ mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "unhealthy" ).
336+ Run (func (args mock.Arguments ) { close (done ) }).
337+ Return (nil ).Once ()
308338
309339 worker := service .NewConnectionHealthWorker (mockRepo , mockSvc , mockHealth , 10 * time .Millisecond )
310340
311- ctx , cancel := context .WithCancel (context .Background ())
312- go worker .Start (ctx )
313-
314- time .Sleep (50 * time .Millisecond )
315- cancel ()
341+ runWorkerUntilSignal (t , worker , done )
316342
317343 mockRepo .AssertExpectations (t )
318344 mockSvc .AssertExpectations (t )
@@ -340,15 +366,14 @@ func TestConnectionHealthWorker_OAuth2_403_MarksDegraded(t *testing.T) {
340366 mockSvc .On ("Refresh" , mock .Anything , connID ).Return (& service.RefreshResponse {StatusCode : 403 }, errors .New ("forbidden" )).Once ()
341367
342368 // Should set health_status to "degraded", NOT "expired"
343- mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "degraded" ).Return (nil ).Once ()
369+ done := make (chan struct {})
370+ mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "degraded" ).
371+ Run (func (args mock.Arguments ) { close (done ) }).
372+ Return (nil ).Once ()
344373
345374 worker := service .NewConnectionHealthWorker (mockRepo , mockSvc , mockHealth , 10 * time .Millisecond )
346375
347- ctx , cancel := context .WithCancel (context .Background ())
348- go worker .Start (ctx )
349-
350- time .Sleep (50 * time .Millisecond )
351- cancel ()
376+ runWorkerUntilSignal (t , worker , done )
352377
353378 mockRepo .AssertExpectations (t )
354379 mockSvc .AssertExpectations (t )
@@ -376,15 +401,14 @@ func TestConnectionHealthWorker_OAuth2_NetworkError_MarksDegraded(t *testing.T)
376401 mockSvc .On ("Refresh" , mock .Anything , connID ).Return ((* service .RefreshResponse )(nil ), errors .New ("connection refused" )).Once ()
377402
378403 // Should set health_status to "degraded" (we don't know if credential is valid)
379- mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "degraded" ).Return (nil ).Once ()
404+ done := make (chan struct {})
405+ mockRepo .On ("UpdateHealthStatus" , mock .Anything , connID , "degraded" ).
406+ Run (func (args mock.Arguments ) { close (done ) }).
407+ Return (nil ).Once ()
380408
381409 worker := service .NewConnectionHealthWorker (mockRepo , mockSvc , mockHealth , 10 * time .Millisecond )
382410
383- ctx , cancel := context .WithCancel (context .Background ())
384- go worker .Start (ctx )
385-
386- time .Sleep (50 * time .Millisecond )
387- cancel ()
411+ runWorkerUntilSignal (t , worker , done )
388412
389413 mockRepo .AssertExpectations (t )
390414 mockSvc .AssertExpectations (t )
0 commit comments