Skip to content

Commit 481181a

Browse files
authored
refactor test suite (#722)
1 parent dfed93d commit 481181a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+4318
-2741
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ GUM = $(BIN_DIR)/gum
99
GH = $(BIN_DIR)/gh
1010
GOLICENSES = $(BIN_DIR)/go-licenses
1111
HELM_BASE_OPTS ?= --set aws.region=${AWS_REGION},serviceAccount.name=${SERVICE_ACCOUNT_NAME},serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn=${SERVICE_ACCOUNT_ROLE_ARN}
12-
GINKGO_BASE_OPTS ?= --coverpkg $(shell head -n 1 $(PROJECT_DIR)/go.mod | cut -s -d ' ' -f 2)/pkg/...
12+
GINKGO_BASE_OPTS ?= -r --coverpkg $(shell head -n 1 $(PROJECT_DIR)/go.mod | cut -s -d ' ' -f 2)/pkg/...
1313
KODATA = \
1414
cmd/controller/kodata/HEAD \
1515
cmd/controller/kodata/refs \

test/reconciler/asg_lifecycle_v1.go

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
Copyright 2022 Amazon.com, Inc. or its affiliates. All rights reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package reconciler
18+
19+
import (
20+
"fmt"
21+
22+
. "github.com/onsi/ginkgo/v2"
23+
. "github.com/onsi/gomega"
24+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
25+
26+
"github.com/aws/aws-node-termination-handler/test/reconciler/mock"
27+
28+
"github.com/aws/aws-sdk-go/aws"
29+
"github.com/aws/aws-sdk-go/service/sqs"
30+
)
31+
32+
var _ = Describe("Reconciliation", func() {
33+
When("the SQS queue contains an ASG Lifecycle Notification v1", func() {
34+
var (
35+
infra *mock.Infrastructure
36+
result reconcile.Result
37+
err error
38+
)
39+
40+
BeforeEach(func() {
41+
infra = mock.NewInfrastructure()
42+
})
43+
44+
JustBeforeEach(func() {
45+
result, err = infra.Reconcile()
46+
})
47+
48+
When("the lifecycle transition is termination", func() {
49+
BeforeEach(func() {
50+
infra.ResizeCluster(3)
51+
52+
infra.SQSQueues[mock.QueueURL] = append(infra.SQSQueues[mock.QueueURL], &sqs.Message{
53+
ReceiptHandle: aws.String("msg-1"),
54+
Body: aws.String(fmt.Sprintf(`{
55+
"source": "aws.autoscaling",
56+
"detail-type": "EC2 Instance-terminate Lifecycle Action",
57+
"version": "1",
58+
"detail": {
59+
"EC2InstanceId": "%s",
60+
"LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING"
61+
}
62+
}`, infra.InstanceIDs[1])),
63+
})
64+
65+
infra.CreatePendingASGLifecycleAction(infra.InstanceIDs[1])
66+
})
67+
68+
It("returns success and requeues the request with the reconciler's configured interval", func() {
69+
Expect(result, err).To(HaveField("RequeueAfter", Equal(infra.Reconciler.RequeueInterval)))
70+
})
71+
72+
It("cordons and drains only the targeted node", func() {
73+
Expect(infra.CordonedNodes).To(SatisfyAll(HaveKey(infra.NodeNames[1]), HaveLen(1)))
74+
Expect(infra.DrainedNodes).To(SatisfyAll(HaveKey(infra.NodeNames[1]), HaveLen(1)))
75+
})
76+
77+
It("completes the ASG lifecycle action", func() {
78+
Expect(infra.ASGLifecycleActions).To(
79+
SatisfyAll(
80+
HaveKeyWithValue(infra.InstanceIDs[1], Equal(mock.StateComplete)),
81+
HaveLen(1),
82+
),
83+
)
84+
})
85+
86+
It("deletes the message from the SQS queue", func() {
87+
Expect(infra.SQSQueues[mock.QueueURL]).To(BeEmpty())
88+
})
89+
})
90+
91+
When("the lifecycle transition is not termination", func() {
92+
BeforeEach(func() {
93+
infra.ResizeCluster(3)
94+
95+
infra.SQSQueues[mock.QueueURL] = append(infra.SQSQueues[mock.QueueURL], &sqs.Message{
96+
ReceiptHandle: aws.String("msg-1"),
97+
Body: aws.String(fmt.Sprintf(`{
98+
"source": "aws.autoscaling",
99+
"detail-type": "EC2 Instance-terminate Lifecycle Action",
100+
"version": "1",
101+
"detail": {
102+
"EC2InstanceId": "%s",
103+
"LifecycleTransition": "test:INVALID"
104+
}
105+
}`, infra.InstanceIDs[1])),
106+
})
107+
108+
infra.CreatePendingASGLifecycleAction(infra.InstanceIDs[1])
109+
})
110+
111+
It("returns success and requeues the request with the reconciler's configured interval", func() {
112+
Expect(result, err).To(HaveField("RequeueAfter", Equal(infra.Reconciler.RequeueInterval)))
113+
})
114+
115+
It("does not cordon or drain any nodes", func() {
116+
Expect(infra.CordonedNodes).To(BeEmpty())
117+
Expect(infra.DrainedNodes).To(BeEmpty())
118+
})
119+
120+
It("does not complete the ASG lifecycle action", func() {
121+
Expect(infra.ASGLifecycleActions).To(
122+
SatisfyAll(
123+
HaveKeyWithValue(infra.InstanceIDs[1], Equal(mock.StatePending)),
124+
HaveLen(1),
125+
),
126+
)
127+
})
128+
129+
It("does not delete the message from the SQS queue", func() {
130+
Expect(infra.SQSQueues[mock.QueueURL]).To(HaveLen(1))
131+
})
132+
})
133+
})
134+
})

test/reconciler/asg_lifecycle_v2.go

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
Copyright 2022 Amazon.com, Inc. or its affiliates. All rights reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package reconciler
18+
19+
import (
20+
"fmt"
21+
22+
. "github.com/onsi/ginkgo/v2"
23+
. "github.com/onsi/gomega"
24+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
25+
26+
"github.com/aws/aws-node-termination-handler/test/reconciler/mock"
27+
28+
"github.com/aws/aws-sdk-go/aws"
29+
"github.com/aws/aws-sdk-go/service/sqs"
30+
)
31+
32+
var _ = Describe("Reconciliation", func() {
33+
When("the SQS queue contains an ASG Lifecycle Notification v2", func() {
34+
var (
35+
infra *mock.Infrastructure
36+
result reconcile.Result
37+
err error
38+
)
39+
40+
BeforeEach(func() {
41+
infra = mock.NewInfrastructure()
42+
})
43+
44+
JustBeforeEach(func() {
45+
result, err = infra.Reconcile()
46+
})
47+
48+
When("the lifecycle transition is termination", func() {
49+
BeforeEach(func() {
50+
infra.ResizeCluster(3)
51+
52+
infra.SQSQueues[mock.QueueURL] = append(infra.SQSQueues[mock.QueueURL], &sqs.Message{
53+
ReceiptHandle: aws.String("msg-1"),
54+
Body: aws.String(fmt.Sprintf(`{
55+
"source": "aws.autoscaling",
56+
"detail-type": "EC2 Instance-terminate Lifecycle Action",
57+
"version": "2",
58+
"detail": {
59+
"EC2InstanceId": "%s",
60+
"LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING"
61+
}
62+
}`, infra.InstanceIDs[1])),
63+
})
64+
65+
infra.CreatePendingASGLifecycleAction(infra.InstanceIDs[1])
66+
})
67+
68+
It("returns success and requeues the request with the reconciler's configured interval", func() {
69+
Expect(result, err).To(HaveField("RequeueAfter", Equal(infra.Reconciler.RequeueInterval)))
70+
})
71+
72+
It("cordons and drains only the targeted node", func() {
73+
Expect(infra.CordonedNodes).To(SatisfyAll(HaveKey(infra.NodeNames[1]), HaveLen(1)))
74+
Expect(infra.DrainedNodes).To(SatisfyAll(HaveKey(infra.NodeNames[1]), HaveLen(1)))
75+
})
76+
77+
It("completes the ASG lifecycle action", func() {
78+
Expect(infra.ASGLifecycleActions).To(
79+
SatisfyAll(
80+
HaveKeyWithValue(infra.InstanceIDs[1], Equal(mock.StateComplete)),
81+
HaveLen(1),
82+
),
83+
)
84+
})
85+
86+
It("deletes the message from the SQS queue", func() {
87+
Expect(infra.SQSQueues[mock.QueueURL]).To(BeEmpty())
88+
})
89+
})
90+
91+
When("the lifecycle transition is not termination", func() {
92+
BeforeEach(func() {
93+
infra.ResizeCluster(3)
94+
95+
infra.SQSQueues[mock.QueueURL] = append(infra.SQSQueues[mock.QueueURL], &sqs.Message{
96+
ReceiptHandle: aws.String("msg-1"),
97+
Body: aws.String(fmt.Sprintf(`{
98+
"source": "aws.autoscaling",
99+
"detail-type": "EC2 Instance-terminate Lifecycle Action",
100+
"version": "2",
101+
"detail": {
102+
"EC2InstanceId": "%s",
103+
"LifecycleTransition": "test:INVALID"
104+
}
105+
}`, infra.InstanceIDs[1])),
106+
})
107+
108+
infra.CreatePendingASGLifecycleAction(infra.InstanceIDs[1])
109+
})
110+
111+
It("returns success and requeues the request with the reconciler's configured interval", func() {
112+
Expect(result, err).To(HaveField("RequeueAfter", Equal(infra.Reconciler.RequeueInterval)))
113+
})
114+
115+
It("does not cordon or drain any nodes", func() {
116+
Expect(infra.CordonedNodes).To(BeEmpty())
117+
Expect(infra.DrainedNodes).To(BeEmpty())
118+
})
119+
120+
It("does not complete the ASG lifecycle action", func() {
121+
Expect(infra.ASGLifecycleActions).To(
122+
SatisfyAll(
123+
HaveKeyWithValue(infra.InstanceIDs[1], Equal(mock.StatePending)),
124+
HaveLen(1),
125+
),
126+
)
127+
})
128+
129+
It("does not delete the message from the SQS queue", func() {
130+
Expect(infra.SQSQueues[mock.QueueURL]).To(HaveLen(1))
131+
})
132+
})
133+
})
134+
})

test/reconciler/asg_v1_err.go

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
Copyright 2022 Amazon.com, Inc. or its affiliates. All rights reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package reconciler
18+
19+
import (
20+
"errors"
21+
"fmt"
22+
23+
. "github.com/onsi/ginkgo/v2"
24+
. "github.com/onsi/gomega"
25+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
26+
27+
"github.com/aws/aws-node-termination-handler/test/reconciler/mock"
28+
29+
"github.com/aws/aws-sdk-go/aws"
30+
awsrequest "github.com/aws/aws-sdk-go/aws/request"
31+
"github.com/aws/aws-sdk-go/service/autoscaling"
32+
"github.com/aws/aws-sdk-go/service/sqs"
33+
)
34+
35+
var _ = Describe("Reconciliation", func() {
36+
When("completing an ASG Lifecycle Action (v1) fails", func() {
37+
const errMsg = "test error"
38+
var (
39+
infra *mock.Infrastructure
40+
result reconcile.Result
41+
err error
42+
)
43+
44+
BeforeEach(func() {
45+
infra = mock.NewInfrastructure()
46+
infra.ResizeCluster(3)
47+
48+
infra.SQSQueues[mock.QueueURL] = append(infra.SQSQueues[mock.QueueURL], &sqs.Message{
49+
ReceiptHandle: aws.String("msg-1"),
50+
Body: aws.String(fmt.Sprintf(`{
51+
"source": "aws.autoscaling",
52+
"detail-type": "EC2 Instance-terminate Lifecycle Action",
53+
"version": "1",
54+
"detail": {
55+
"EC2InstanceId": "%s",
56+
"LifecycleTransition": "autoscaling:EC2_INSTANCE_TERMINATING"
57+
}
58+
}`, infra.InstanceIDs[1])),
59+
})
60+
61+
infra.CompleteASGLifecycleActionFunc = func(_ aws.Context, _ *autoscaling.CompleteLifecycleActionInput, _ ...awsrequest.Option) (*autoscaling.CompleteLifecycleActionOutput, error) {
62+
return nil, errors.New(errMsg)
63+
}
64+
65+
result, err = infra.Reconcile()
66+
})
67+
68+
It("does not requeue the request", func() {
69+
Expect(result).To(BeZero())
70+
})
71+
72+
It("returns an error", func() {
73+
Expect(err).To(MatchError(ContainSubstring(errMsg)))
74+
})
75+
76+
It("cordons and drains only the targeted node", func() {
77+
Expect(infra.CordonedNodes).To(SatisfyAll(HaveKey(infra.NodeNames[1]), HaveLen(1)))
78+
Expect(infra.DrainedNodes).To(SatisfyAll(HaveKey(infra.NodeNames[1]), HaveLen(1)))
79+
})
80+
81+
It("deletes the message from the SQS queue", func() {
82+
Expect(infra.SQSQueues[mock.QueueURL]).To(BeEmpty())
83+
})
84+
})
85+
})

0 commit comments

Comments
 (0)