diff --git a/cluster-autoscaler/cloudprovider/aws/aws_manager_test.go b/cluster-autoscaler/cloudprovider/aws/aws_manager_test.go index 8eddd7eb53a9..16d5d5c54b6c 100644 --- a/cluster-autoscaler/cloudprovider/aws/aws_manager_test.go +++ b/cluster-autoscaler/cloudprovider/aws/aws_manager_test.go @@ -18,6 +18,9 @@ package aws import ( "fmt" + "reflect" + "sort" + "strings" "testing" "github.com/aws/aws-sdk-go/aws" @@ -199,21 +202,21 @@ func TestBuildInstanceType(t *testing.T) { assert.Equal(t, instanceType, builtInstanceType) } -/* Disabled due to flakiness. See https://github.com/kubernetes/autoscaler/issues/608 func TestFetchAutoAsgs(t *testing.T) { min, max := 1, 10 groupname, tags := "coolasg", []string{"tag", "anothertag"} s := &AutoScalingMock{} // Lookup groups associated with tags - s.On("DescribeTagsPages", - &autoscaling.DescribeTagsInput{ - Filters: []*autoscaling.Filter{ - {Name: aws.String("key"), Values: aws.StringSlice([]string{tags[0]})}, - {Name: aws.String("key"), Values: aws.StringSlice([]string{tags[1]})}, - }, - MaxRecords: aws.Int64(maxRecordsReturnedByAPI), + expectedTagsInput := &autoscaling.DescribeTagsInput{ + Filters: []*autoscaling.Filter{ + {Name: aws.String("key"), Values: aws.StringSlice([]string{tags[0]})}, + {Name: aws.String("key"), Values: aws.StringSlice([]string{tags[1]})}, }, + MaxRecords: aws.Int64(maxRecordsReturnedByAPI), + } + // Use MatchedBy pattern to avoid list order issue https://github.com/kubernetes/autoscaler/issues/1346 + s.On("DescribeTagsPages", mock.MatchedBy(tagsMatcher(expectedTagsInput)), mock.AnythingOfType("func(*autoscaling.DescribeTagsOutput, bool) bool"), ).Run(func(args mock.Arguments) { fn := args.Get(1).(func(*autoscaling.DescribeTagsOutput, bool) bool) @@ -247,30 +250,41 @@ func TestFetchAutoAsgs(t *testing.T) { } // fetchAutoASGs is called at manager creation time, via forceRefresh - m, err := createAWSManagerInternal(nil, do, &autoScalingWrapper{s}) + m, err := createAWSManagerInternal(nil, do, &autoScalingWrapper{s}, nil) assert.NoError(t, err) - asgs := m.asgCache.get() + asgs := m.asgCache.Get() assert.Equal(t, 1, len(asgs)) - validateAsg(t, asgs[0].config, groupname, min, max) + validateAsg(t, asgs[0], groupname, min, max) // Simulate the previously discovered ASG disappearing - s.On("DescribeTagsPages", - &autoscaling.DescribeTagsInput{ - Filters: []*autoscaling.Filter{ - {Name: aws.String("key"), Values: aws.StringSlice([]string{tags[0]})}, - {Name: aws.String("key"), Values: aws.StringSlice([]string{tags[1]})}, - }, - MaxRecords: aws.Int64(maxRecordsReturnedByAPI), - }, + s.On("DescribeTagsPages", mock.MatchedBy(tagsMatcher(expectedTagsInput)), mock.AnythingOfType("func(*autoscaling.DescribeTagsOutput, bool) bool"), ).Run(func(args mock.Arguments) { fn := args.Get(1).(func(*autoscaling.DescribeTagsOutput, bool) bool) fn(&autoscaling.DescribeTagsOutput{Tags: []*autoscaling.TagDescription{}}, false) }).Return(nil).Once() - err = m.fetchAutoAsgs() + err = m.asgCache.regenerate() assert.NoError(t, err) - assert.Empty(t, m.asgCache.get()) + assert.Empty(t, m.asgCache.Get()) +} + +func tagsMatcher(expected *autoscaling.DescribeTagsInput) func(*autoscaling.DescribeTagsInput) bool { + return func(actual *autoscaling.DescribeTagsInput) bool { + expectedTags := flatTagSlice(expected.Filters) + actualTags := flatTagSlice(actual.Filters) + + return *expected.MaxRecords == *actual.MaxRecords && reflect.DeepEqual(expectedTags, actualTags) + } +} + +func flatTagSlice(filters []*autoscaling.Filter) []string { + tags := []string{} + for _, filter := range filters { + tags = append(tags, aws.StringValueSlice(filter.Values)...) + } + // Sort slice for compare + sort.Strings(tags) + return tags } -*/