@@ -227,3 +227,112 @@ func TestTracker_Healthy_IfBothTasksAndConsulChecksAreHealthy(t *testing.T) {
227
227
require .Fail (t , "expected a health status" )
228
228
}
229
229
}
230
+
231
+ // TestTracker_Checks_Healthy_Before_TaskHealth asserts that we mark an alloc
232
+ // healthy, if the checks pass before task health pass
233
+ func TestTracker_Checks_Healthy_Before_TaskHealth (t * testing.T ) {
234
+ t .Parallel ()
235
+
236
+ alloc := mock .Alloc ()
237
+ alloc .Job .TaskGroups [0 ].Migrate .MinHealthyTime = 1 // let's speed things up
238
+ task := alloc .Job .TaskGroups [0 ].Tasks [0 ]
239
+
240
+ // new task starting unhealthy, without services
241
+ task2 := task .Copy ()
242
+ task2 .Name = task2 .Name + "2"
243
+ task2 .Services = nil
244
+ alloc .Job .TaskGroups [0 ].Tasks = append (alloc .Job .TaskGroups [0 ].Tasks , task2 )
245
+
246
+ // Synthesize running alloc and tasks
247
+ alloc .ClientStatus = structs .AllocClientStatusRunning
248
+ alloc .TaskStates = map [string ]* structs.TaskState {
249
+ task .Name : {
250
+ State : structs .TaskStateRunning ,
251
+ StartedAt : time .Now (),
252
+ },
253
+ task2 .Name : {
254
+ State : structs .TaskStatePending ,
255
+ },
256
+ }
257
+
258
+ // Make Consul response
259
+ check := & consulapi.AgentCheck {
260
+ Name : task .Services [0 ].Checks [0 ].Name ,
261
+ Status : consulapi .HealthPassing ,
262
+ }
263
+ taskRegs := map [string ]* agentconsul.ServiceRegistrations {
264
+ task .Name : {
265
+ Services : map [string ]* agentconsul.ServiceRegistration {
266
+ task .Services [0 ].Name : {
267
+ Service : & consulapi.AgentService {
268
+ ID : "foo" ,
269
+ Service : task .Services [0 ].Name ,
270
+ },
271
+ Checks : []* consulapi.AgentCheck {check },
272
+ },
273
+ },
274
+ },
275
+ }
276
+
277
+ logger := testlog .HCLogger (t )
278
+ b := cstructs .NewAllocBroadcaster (logger )
279
+ defer b .Close ()
280
+
281
+ // Don't reply on the first call
282
+ var called uint64
283
+ consul := consul .NewMockConsulServiceClient (t , logger )
284
+ consul .AllocRegistrationsFn = func (string ) (* agentconsul.AllocRegistration , error ) {
285
+ if atomic .AddUint64 (& called , 1 ) == 1 {
286
+ return nil , nil
287
+ }
288
+
289
+ reg := & agentconsul.AllocRegistration {
290
+ Tasks : taskRegs ,
291
+ }
292
+
293
+ return reg , nil
294
+ }
295
+
296
+ ctx , cancelFn := context .WithCancel (context .Background ())
297
+ defer cancelFn ()
298
+
299
+ checkInterval := 10 * time .Millisecond
300
+ tracker := NewTracker (ctx , logger , alloc , b .Listen (), consul ,
301
+ time .Millisecond , true )
302
+ tracker .checkLookupInterval = checkInterval
303
+ tracker .Start ()
304
+
305
+ // assert that we don't get marked healthy
306
+ select {
307
+ case <- time .After (4 * checkInterval ):
308
+ // still unhealthy, good
309
+ case h := <- tracker .HealthyCh ():
310
+ require .Fail (t , "unexpected health event" , h )
311
+ }
312
+ require .False (t , tracker .tasksHealthy )
313
+ require .False (t , tracker .checksHealthy )
314
+
315
+ // now set task to healthy
316
+ runningAlloc := alloc .Copy ()
317
+ runningAlloc .TaskStates = map [string ]* structs.TaskState {
318
+ task .Name : {
319
+ State : structs .TaskStateRunning ,
320
+ StartedAt : time .Now (),
321
+ },
322
+ task2 .Name : {
323
+ State : structs .TaskStateRunning ,
324
+ StartedAt : time .Now (),
325
+ },
326
+ }
327
+ err := b .Send (runningAlloc )
328
+ require .NoError (t , err )
329
+
330
+ // eventually, it is marked as healthy
331
+ select {
332
+ case <- time .After (4 * checkInterval ):
333
+ require .Fail (t , "timed out while waiting for health" )
334
+ case h := <- tracker .HealthyCh ():
335
+ require .True (t , h )
336
+ }
337
+
338
+ }
0 commit comments