Repository: kubernetes-sigs/cluster-api-provider-aws
Pull request #3117 (2022-01-28 16:57:51)

Add unit tests for package pkg/cloud/tags
**What type of PR is this?**
/area testing

**What this PR does / why we need it**:
This PR increases the unit tests coverage for package pkg/cloud/tags. The coverage of package has increased from 3.9% to 98%

**Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*:
Part of #2910 

**Checklist**:

- [X] squashed commits
- [ ] includes documentation
- [X] adds unit tests
- [ ] adds or updates e2e tests

**Release note**:
```release-note
Add unit tests for package pkg/cloud/tags
```


k8s-ci-robot: @Ankitasw: This issue is currently awaiting triage.

If CAPA/CAPI contributors determines this is a relevant issue, they will accept it by applying the `triage/accepted` label and provide further guidance.

The `triage/accepted` label can be added by org members by writing `/triage accepted` in a comment.


<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **justinsb** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @justinsb` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fcluster-api-provider-aws).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes-sigs/cluster-api-provider-aws/blob/main/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["justinsb"]} -->
Ankitasw: /test pull-cluster-api-provider-aws-e2e
k8s-ci-robot: @Ankitasw: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
k8s-ci-robot: @Ankitasw: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cluster-api-provider-aws-verify | f6c61c75b4eafcb2ee77066c28ff34944ef64693 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_cluster-api-provider-aws/3117/pull-cluster-api-provider-aws-verify/1488741098300903424) | true | `/test pull-cluster-api-provider-aws-verify`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cluster-api-provider-aws&pr=3117). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3AAnkitasw). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cluster-api-provider-aws/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->

Patch:
diff --git a/pkg/cloud/tags/tags.go b/pkg/cloud/tags/tags.go
index bf08033d7..722d2cf3c 100644
--- a/pkg/cloud/tags/tags.go
+++ b/pkg/cloud/tags/tags.go
@@ -78,6 +78,9 @@ func (b *Builder) Apply() error {
 
 // Ensure applies the tags if the current tags differ from the params.
 func (b *Builder) Ensure(current infrav1.Tags) error {
+	if b.params == nil {
+		return ErrBuildParamsRequired
+	}
 	if diff := computeDiff(current, *b.params); len(diff) > 0 {
 		return b.Apply()
 	}


Test patch:
diff --git a/pkg/cloud/tags/tags_test.go b/pkg/cloud/tags/tags_test.go
index 164658d80..3f6b37189 100644
--- a/pkg/cloud/tags/tags_test.go
+++ b/pkg/cloud/tags/tags_test.go
@@ -20,7 +20,44 @@ import (
 	"reflect"
 	"testing"
 
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/service/ec2"
+	"github.com/aws/aws-sdk-go/service/eks"
+	"github.com/golang/mock/gomock"
+	. "github.com/onsi/gomega"
+	"github.com/pkg/errors"
+
 	infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1"
+	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/ec2/mock_ec2iface"
+	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/eks/mock_eksiface"
+)
+
+var (
+	bp = infrav1.BuildParams{
+		Lifecycle:   infrav1.ResourceLifecycleOwned,
+		ClusterName: "testcluster",
+		Name:        aws.String("test"),
+		Role:        aws.String("testrole"),
+		Additional:  map[string]string{"k1": "v1"},
+	}
+	tags = []*ec2.Tag{
+		{
+			Key:   aws.String("Name"),
+			Value: aws.String("test"),
+		},
+		{
+			Key:   aws.String("k1"),
+			Value: aws.String("v1"),
+		},
+		{
+			Key:   aws.String("sigs.k8s.io/cluster-api-provider-aws/cluster/testcluster"),
+			Value: aws.String("owned"),
+		},
+		{
+			Key:   aws.String("sigs.k8s.io/cluster-api-provider-aws/role"),
+			Value: aws.String("testrole"),
+		},
+	}
 )
 
 func TestTags_ComputeDiff(t *testing.T) {
@@ -94,3 +131,121 @@ func TestTags_ComputeDiff(t *testing.T) {
 		})
 	}
 }
+
+func TestTags_EnsureWithEC2(t *testing.T) {
+	tests := []struct {
+		name    string
+		builder Builder
+		expect  func(m *mock_ec2iface.MockEC2APIMockRecorder)
+	}{
+		{
+			name:    "Should return error when create tag fails",
+			builder: Builder{params: &bp},
+			expect: func(m *mock_ec2iface.MockEC2APIMockRecorder) {
+				m.CreateTags(gomock.Eq(&ec2.CreateTagsInput{
+					Resources: aws.StringSlice([]string{""}),
+					Tags:      tags,
+				})).Return(nil, errors.New("failed to create tag"))
+			},
+		},
+		{
+			name:    "Should return error when optional configuration for builder is nil",
+			builder: Builder{params: &bp, applyFunc: nil},
+		},
+		{
+			name:    "Should return error when build params is nil",
+			builder: Builder{params: nil},
+		},
+		{
+			name:    "Should ensure tags successfully",
+			builder: Builder{params: &bp},
+			expect: func(m *mock_ec2iface.MockEC2APIMockRecorder) {
+				m.CreateTags(gomock.Eq(&ec2.CreateTagsInput{
+					Resources: aws.StringSlice([]string{""}),
+					Tags:      tags,
+				})).Return(nil, nil)
+			},
+		},
+	}
+
+	g := NewWithT(t)
+	mockCtrl := gomock.NewController(t)
+	ec2Mock := mock_ec2iface.NewMockEC2API(mockCtrl)
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			var builder *Builder
+			if tc.expect != nil {
+				tc.expect(ec2Mock.EXPECT())
+				builder = New(tc.builder.params, WithEC2(ec2Mock))
+			} else {
+				builder = New(tc.builder.params, func(builder *Builder) {})
+			}
+			err := builder.Ensure(nil)
+			if err != nil {
+				g.Expect(err).To(Not(BeNil()))
+			} else {
+				g.Expect(err).To(BeNil())
+			}
+		})
+	}
+}
+
+func TestTags_EnsureWithEKS(t *testing.T) {
+	tests := []struct {
+		name    string
+		builder Builder
+		expect  func(m *mock_eksiface.MockEKSAPIMockRecorder)
+	}{
+		{
+			name:    "Should return error when tag resources fails",
+			builder: Builder{params: &bp},
+			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
+				m.TagResource(gomock.Eq(&eks.TagResourceInput{
+					ResourceArn: aws.String(""),
+					Tags:        map[string]*string{"Name": aws.String("test"), "k1": aws.String("v1"), "sigs.k8s.io/cluster-api-provider-aws/cluster/testcluster": aws.String("owned"), "sigs.k8s.io/cluster-api-provider-aws/role": aws.String("testrole")},
+				})).Return(nil, errors.New("failed to tag resource"))
+			},
+		},
+		{
+			name:    "Should ensure tags successfully",
+			builder: Builder{params: &bp},
+			expect: func(m *mock_eksiface.MockEKSAPIMockRecorder) {
+				m.TagResource(gomock.Eq(&eks.TagResourceInput{
+					ResourceArn: aws.String(""),
+					Tags:        map[string]*string{"Name": aws.String("test"), "k1": aws.String("v1"), "sigs.k8s.io/cluster-api-provider-aws/cluster/testcluster": aws.String("owned"), "sigs.k8s.io/cluster-api-provider-aws/role": aws.String("testrole")},
+				})).Return(nil, nil)
+			},
+		},
+	}
+
+	g := NewWithT(t)
+	mockCtrl := gomock.NewController(t)
+	eksMock := mock_eksiface.NewMockEKSAPI(mockCtrl)
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			var builder *Builder
+			if tc.expect != nil {
+				tc.expect(eksMock.EXPECT())
+				builder = New(tc.builder.params, WithEKS(eksMock))
+			} else {
+				builder = New(tc.builder.params, func(builder *Builder) {})
+			}
+			err := builder.Ensure(nil)
+			if err != nil {
+				g.Expect(err).To(Not(BeNil()))
+			} else {
+				g.Expect(err).To(BeNil())
+			}
+		})
+	}
+}
+
+func TestTags_BuildParamsToTagSpecification(t *testing.T) {
+	g := NewWithT(t)
+	tagSpec := BuildParamsToTagSpecification("test-resource", bp)
+	expectedTagSpec := &ec2.TagSpecification{
+		ResourceType: aws.String("test-resource"),
+		Tags:         tags,
+	}
+	g.Expect(expectedTagSpec).To(Equal(tagSpec))
+}