Skip to content

Commit f50696a

Browse files
committed
Fix potential test flakes in HPA tests TestEventNotCreated and TestAvoidUncessaryUpdates
Also, re-work the code so that the lock is never held while writing to the chan
1 parent 0889c3e commit f50696a

File tree

2 files changed

+68
-50
lines changed

2 files changed

+68
-50
lines changed

pkg/controller/podautoscaler/horizontal_test.go

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -330,38 +330,43 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa
330330
})
331331

332332
fakeClient.AddReactor("update", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
333-
tc.Lock()
334-
defer tc.Unlock()
335-
336-
obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.HorizontalPodAutoscaler)
337-
assert.Equal(t, namespace, obj.Namespace, "the HPA namespace should be as expected")
338-
assert.Equal(t, hpaName, obj.Name, "the HPA name should be as expected")
339-
assert.Equal(t, tc.expectedDesiredReplicas, obj.Status.DesiredReplicas, "the desired replica count reported in the object status should be as expected")
340-
if tc.verifyCPUCurrent {
341-
if assert.NotNil(t, obj.Status.CurrentCPUUtilizationPercentage, "the reported CPU utilization percentage should be non-nil") {
342-
assert.Equal(t, tc.CPUCurrent, *obj.Status.CurrentCPUUtilizationPercentage, "the report CPU utilization percentage should be as expected")
333+
handled, obj, err := func() (handled bool, ret *autoscalingv1.HorizontalPodAutoscaler, err error) {
334+
tc.Lock()
335+
defer tc.Unlock()
336+
337+
obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.HorizontalPodAutoscaler)
338+
assert.Equal(t, namespace, obj.Namespace, "the HPA namespace should be as expected")
339+
assert.Equal(t, hpaName, obj.Name, "the HPA name should be as expected")
340+
assert.Equal(t, tc.expectedDesiredReplicas, obj.Status.DesiredReplicas, "the desired replica count reported in the object status should be as expected")
341+
if tc.verifyCPUCurrent {
342+
if assert.NotNil(t, obj.Status.CurrentCPUUtilizationPercentage, "the reported CPU utilization percentage should be non-nil") {
343+
assert.Equal(t, tc.CPUCurrent, *obj.Status.CurrentCPUUtilizationPercentage, "the report CPU utilization percentage should be as expected")
344+
}
343345
}
346+
var actualConditions []autoscalingv1.HorizontalPodAutoscalerCondition
347+
if err := json.Unmarshal([]byte(obj.ObjectMeta.Annotations[autoscaling.HorizontalPodAutoscalerConditionsAnnotation]), &actualConditions); err != nil {
348+
return true, nil, err
349+
}
350+
// TODO: it's ok not to sort these becaues statusOk
351+
// contains all the conditions, so we'll never be appending.
352+
// Default to statusOk when missing any specific conditions
353+
if tc.expectedConditions == nil {
354+
tc.expectedConditions = statusOkWithOverrides()
355+
}
356+
// clear the message so that we can easily compare
357+
for i := range actualConditions {
358+
actualConditions[i].Message = ""
359+
actualConditions[i].LastTransitionTime = metav1.Time{}
360+
}
361+
assert.Equal(t, tc.expectedConditions, actualConditions, "the status conditions should have been as expected")
362+
tc.statusUpdated = true
363+
// Every time we reconcile HPA object we are updating status.
364+
return true, obj, nil
365+
}()
366+
if obj != nil {
367+
tc.processed <- obj.Name
344368
}
345-
var actualConditions []autoscalingv1.HorizontalPodAutoscalerCondition
346-
if err := json.Unmarshal([]byte(obj.ObjectMeta.Annotations[autoscaling.HorizontalPodAutoscalerConditionsAnnotation]), &actualConditions); err != nil {
347-
return true, nil, err
348-
}
349-
// TODO: it's ok not to sort these becaues statusOk
350-
// contains all the conditions, so we'll never be appending.
351-
// Default to statusOk when missing any specific conditions
352-
if tc.expectedConditions == nil {
353-
tc.expectedConditions = statusOkWithOverrides()
354-
}
355-
// clear the message so that we can easily compare
356-
for i := range actualConditions {
357-
actualConditions[i].Message = ""
358-
actualConditions[i].LastTransitionTime = metav1.Time{}
359-
}
360-
assert.Equal(t, tc.expectedConditions, actualConditions, "the status conditions should have been as expected")
361-
tc.statusUpdated = true
362-
// Every time we reconcile HPA object we are updating status.
363-
tc.processed <- obj.Name
364-
return true, obj, nil
369+
return handled, obj, err
365370
})
366371

367372
fakeScaleClient := &scalefake.FakeScaleClient{}
@@ -701,15 +706,25 @@ func (tc *testCase) runTestWithController(t *testing.T, hpaController *Horizonta
701706
go hpaController.Run(stop)
702707

703708
tc.Lock()
704-
if tc.verifyEvents {
705-
tc.Unlock()
709+
shouldWait := tc.verifyEvents
710+
tc.Unlock()
711+
712+
if shouldWait {
706713
// We need to wait for events to be broadcasted (sleep for longer than record.sleepDuration).
707-
time.Sleep(2 * time.Second)
714+
timeoutTime := time.Now().Add(2 * time.Second)
715+
for now := time.Now(); timeoutTime.After(now); now = time.Now() {
716+
sleepUntil := timeoutTime.Sub(now)
717+
select {
718+
case <-tc.processed:
719+
// drain the chan of any sent events to keep it from filling before the timeout
720+
case <-time.After(sleepUntil):
721+
// timeout reached, ready to verifyResults
722+
}
723+
}
708724
} else {
709-
tc.Unlock()
725+
// Wait for HPA to be processed.
726+
<-tc.processed
710727
}
711-
// Wait for HPA to be processed.
712-
<-tc.processed
713728
tc.verifyResults(t)
714729
}
715730

@@ -2418,7 +2433,9 @@ func TestAvoidUncessaryUpdates(t *testing.T) {
24182433
// wait a tick and then mark that we're finished (otherwise, we have no
24192434
// way to indicate that we're finished, because the function decides not to do anything)
24202435
time.Sleep(1 * time.Second)
2436+
tc.Lock()
24212437
tc.statusUpdated = true
2438+
tc.Unlock()
24222439
tc.processed <- "test-hpa"
24232440
}()
24242441

@@ -2493,8 +2510,6 @@ func TestAvoidUncessaryUpdates(t *testing.T) {
24932510
return true, objv1, nil
24942511
})
24952512
testClient.PrependReactor("update", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
2496-
tc.Lock()
2497-
defer tc.Unlock()
24982513
assert.Fail(t, "should not have attempted to update the HPA when nothing changed")
24992514
// mark that we've processed this HPA
25002515
tc.processed <- ""

pkg/controller/podautoscaler/legacy_horizontal_test.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -332,19 +332,22 @@ func (tc *legacyTestCase) prepareTestClient(t *testing.T) (*fake.Clientset, *sca
332332
})
333333

334334
fakeClient.AddReactor("update", "horizontalpodautoscalers", func(action core.Action) (handled bool, ret runtime.Object, err error) {
335-
tc.Lock()
336-
defer tc.Unlock()
337-
338-
obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.HorizontalPodAutoscaler)
339-
assert.Equal(t, namespace, obj.Namespace, "the HPA namespace should be as expected")
340-
assert.Equal(t, hpaName, obj.Name, "the HPA name should be as expected")
341-
assert.Equal(t, tc.desiredReplicas, obj.Status.DesiredReplicas, "the desired replica count reported in the object status should be as expected")
342-
if tc.verifyCPUCurrent {
343-
if assert.NotNil(t, obj.Status.CurrentCPUUtilizationPercentage, "the reported CPU utilization percentage should be non-nil") {
344-
assert.Equal(t, tc.CPUCurrent, *obj.Status.CurrentCPUUtilizationPercentage, "the report CPU utilization percentage should be as expected")
335+
obj := func() *autoscalingv1.HorizontalPodAutoscaler {
336+
tc.Lock()
337+
defer tc.Unlock()
338+
339+
obj := action.(core.UpdateAction).GetObject().(*autoscalingv1.HorizontalPodAutoscaler)
340+
assert.Equal(t, namespace, obj.Namespace, "the HPA namespace should be as expected")
341+
assert.Equal(t, hpaName, obj.Name, "the HPA name should be as expected")
342+
assert.Equal(t, tc.desiredReplicas, obj.Status.DesiredReplicas, "the desired replica count reported in the object status should be as expected")
343+
if tc.verifyCPUCurrent {
344+
if assert.NotNil(t, obj.Status.CurrentCPUUtilizationPercentage, "the reported CPU utilization percentage should be non-nil") {
345+
assert.Equal(t, tc.CPUCurrent, *obj.Status.CurrentCPUUtilizationPercentage, "the report CPU utilization percentage should be as expected")
346+
}
345347
}
346-
}
347-
tc.statusUpdated = true
348+
tc.statusUpdated = true
349+
return obj
350+
}()
348351
// Every time we reconcile HPA object we are updating status.
349352
tc.processed <- obj.Name
350353
return true, obj, nil

0 commit comments

Comments
 (0)