@@ -246,6 +246,15 @@ func (m *mockStsClient) GetCallerIdentity(*sts.GetCallerIdentityInput) (*sts.Get
246246 }, nil
247247}
248248
249+ // mock elasticache ListTagsForResource output
250+ func (m * mockElasticacheClient ) ListTagsForResource (ctx context.Context , input * elasticache.ListTagsForResourceInput ) (* elasticache.ListTagsForResourceOutput , error ) {
251+ if resources .SafeStringDereference (input .ResourceName ) == "arn:aws:elasticache:tes:test:cluster:test" {
252+ return & elasticache.ListTagsForResourceOutput {}, nil
253+ } else {
254+ return m .listTagsForResourceFn (ctx , input )
255+ }
256+ }
257+
249258func buildTestPrometheusRule () * monitoringv1.PrometheusRule {
250259 return & monitoringv1.PrometheusRule {
251260 ObjectMeta : controllerruntime.ObjectMeta {
@@ -2462,6 +2471,7 @@ func TestAWSRedisProvider_TagElasticache(t *testing.T) {
24622471 },
24632472 }, nil )
24642473 mockElasticache .On ("AddTagsToResource" , mock .Anything , mock .Anything , mock .Anything ).Return (& elasticache.AddTagsToResourceOutput {}, nil )
2474+ mockElasticache .On ("ListTagsForResource" , mock .Anything , mock .Anything , mock .Anything ).Return (& elasticache.ListTagsForResourceOutput {}, nil )
24652475 mockElasticache .On ("DescribeCacheClusters" , mock .Anything , mock .Anything , mock .Anything ).Return (& elasticache.DescribeCacheClustersOutput {
24662476 CacheClusters : buildCacheClusterList (nil ),
24672477 }, nil )
@@ -2507,6 +2517,7 @@ func TestAWSRedisProvider_TagElasticache(t *testing.T) {
25072517 },
25082518 }, & mockSnapshotNotFoundError {})
25092519 mockElasticache .On ("AddTagsToResource" , mock .Anything , mock .Anything , mock .Anything ).Return ((* elasticache .AddTagsToResourceOutput )(nil ), nil )
2520+ mockElasticache .On ("ListTagsForResource" , mock .Anything , mock .Anything , mock .Anything ).Return (& elasticache.ListTagsForResourceOutput {}, nil )
25102521 mockElasticache .On ("DescribeCacheClusters" , mock .Anything , mock .Anything , mock .Anything ).Return (& elasticache.DescribeCacheClustersOutput {
25112522 CacheClusters : buildCacheClusterList (nil ),
25122523 }, nil )
@@ -2541,7 +2552,9 @@ func TestAWSRedisProvider_TagElasticache(t *testing.T) {
25412552 r : buildTestRedisCR (),
25422553 elastiCacheClient : func () ElastiCacheAPI {
25432554 mockElasticache := new (mock_ElasticacheClient )
2544- mockElasticache .On ("DescribeReplicationGroups" , mock .Anything , mock .Anything , mock .Anything ).Return (& elasticache.DescribeReplicationGroupsOutput {}, nil )
2555+ mockElasticache .On ("DescribeReplicationGroups" , mock .Anything , mock .Anything , mock .Anything ).Return (& elasticache.DescribeCacheClustersOutput {
2556+ CacheClusters : buildCacheClusterList (nil ),
2557+ }, nil )
25452558 mockElasticache .On ("DescribeSnapshots" , mock .Anything , mock .Anything , mock .Anything ).Return (& elasticache.DescribeSnapshotsOutput {
25462559 Snapshots : []elasticachetypes.Snapshot {
25472560 {
@@ -2551,6 +2564,7 @@ func TestAWSRedisProvider_TagElasticache(t *testing.T) {
25512564 }, nil )
25522565 mockElasticache .On ("AddTagsToResource" , mock .Anything , mock .Anything , mock .Anything ).Return ((* elasticache .AddTagsToResourceOutput )(nil ), nil ).Once ()
25532566 mockElasticache .On ("AddTagsToResource" , mock .Anything , mock .Anything , mock .Anything ).Return ((* elasticache .AddTagsToResourceOutput )(nil ), genericAWSError )
2567+ mockElasticache .On ("ListTagsForResource" , mock .Anything , mock .Anything , mock .Anything ).Return (& elasticache.ListTagsForResourceOutput {}, nil )
25542568 mockElasticache .On ("DescribeCacheClusters" , mock .Anything , mock .Anything , mock .Anything ).Return (& elasticache.DescribeCacheClustersOutput {
25552569 CacheClusters : buildCacheClusterList (nil ),
25562570 }, nil )
@@ -2597,6 +2611,7 @@ func TestAWSRedisProvider_TagElasticache(t *testing.T) {
25972611 }, errors .New ("SnapshotAlreadyExistsFault" ))
25982612 mockElasticache .On ("AddTagsToResource" , mock .Anything , mock .Anything , mock .Anything ).Return ((* elasticache .AddTagsToResourceOutput )(nil ), nil ).Once ()
25992613 mockElasticache .On ("AddTagsToResource" , mock .Anything , mock .Anything , mock .Anything ).Return ((* elasticache .AddTagsToResourceOutput )(nil ), errors .New ("SnapshotAlreadyExistsFault" )).Once ()
2614+ mockElasticache .On ("ListTagsForResource" , mock .Anything , mock .Anything , mock .Anything ).Return (& elasticache.ListTagsForResourceOutput {}, nil )
26002615 mockElasticache .On ("DescribeCacheClusters" , mock .Anything , mock .Anything , mock .Anything ).Return (& elasticache.DescribeCacheClustersOutput {
26012616 CacheClusters : buildCacheClusterList (nil ),
26022617 }, nil )
@@ -3564,3 +3579,166 @@ func TestRedisProvider_getElasticacheConfig(t *testing.T) {
35643579 })
35653580 }
35663581}
3582+
3583+ // Test_filterAlreadyAppliedTags was generated with the help of Cursor AI IDE.
3584+ func Test_filterAlreadyAppliedTags (t * testing.T ) {
3585+ type args struct {
3586+ ctx context.Context
3587+ client ElastiCacheAPI
3588+ resourceARN string
3589+ desired []elasticachetypes.Tag
3590+ }
3591+ tests := []struct {
3592+ name string
3593+ args args
3594+ want []elasticachetypes.Tag
3595+ wantErr bool
3596+ }{
3597+ {
3598+ name : "error case - ListTagsForResource fails" ,
3599+ args : args {
3600+ ctx : context .TODO (),
3601+ client : func () ElastiCacheAPI {
3602+ mockClient := new (mock_ElasticacheClient )
3603+ mockClient .On ("ListTagsForResource" , mock .Anything , mock .Anything , mock .Anything ).Return (
3604+ (* elasticache .ListTagsForResourceOutput )(nil ),
3605+ errors .New ("API error" ),
3606+ )
3607+ return mockClient
3608+ }(),
3609+ resourceARN : "arn:aws:elasticache:us-east-1:123456789012:cluster:test-cluster" ,
3610+ desired : []elasticachetypes.Tag {
3611+ {Key : aws .String ("Environment" ), Value : aws .String ("test" )},
3612+ },
3613+ },
3614+ want : nil ,
3615+ wantErr : true ,
3616+ },
3617+ {
3618+ name : "success case - no existing tags, all desired tags should be kept" ,
3619+ args : args {
3620+ ctx : context .TODO (),
3621+ client : func () ElastiCacheAPI {
3622+ mockClient := new (mock_ElasticacheClient )
3623+ mockClient .On ("ListTagsForResource" , mock .Anything , mock .Anything , mock .Anything ).Return (
3624+ & elasticache.ListTagsForResourceOutput {
3625+ TagList : []elasticachetypes.Tag {}, // No existing tags
3626+ },
3627+ nil ,
3628+ )
3629+ return mockClient
3630+ }(),
3631+ resourceARN : "arn:aws:elasticache:us-east-1:123456789012:cluster:test-cluster" ,
3632+ desired : []elasticachetypes.Tag {
3633+ {Key : aws .String ("Environment" ), Value : aws .String ("test" )},
3634+ {Key : aws .String ("Team" ), Value : aws .String ("backend" )},
3635+ },
3636+ },
3637+ want : []elasticachetypes.Tag {
3638+ {Key : aws .String ("Environment" ), Value : aws .String ("test" )},
3639+ {Key : aws .String ("Team" ), Value : aws .String ("backend" )},
3640+ },
3641+ wantErr : false ,
3642+ },
3643+ {
3644+ name : "success case - some tags already exist with same values, should be filtered out" ,
3645+ args : args {
3646+ ctx : context .TODO (),
3647+ client : func () ElastiCacheAPI {
3648+ mockClient := new (mock_ElasticacheClient )
3649+ mockClient .On ("ListTagsForResource" , mock .Anything , mock .Anything , mock .Anything ).Return (
3650+ & elasticache.ListTagsForResourceOutput {
3651+ TagList : []elasticachetypes.Tag {
3652+ {Key : aws .String ("Environment" ), Value : aws .String ("test" )},
3653+ {Key : aws .String ("Owner" ), Value : aws .String ("platform" )},
3654+ },
3655+ },
3656+ nil ,
3657+ )
3658+ return mockClient
3659+ }(),
3660+ resourceARN : "arn:aws:elasticache:us-east-1:123456789012:cluster:test-cluster" ,
3661+ desired : []elasticachetypes.Tag {
3662+ {Key : aws .String ("Environment" ), Value : aws .String ("test" )}, // Same value - should be filtered
3663+ {Key : aws .String ("Team" ), Value : aws .String ("backend" )}, // New tag - should be kept
3664+ {Key : aws .String ("Owner" ), Value : aws .String ("engineering" )}, // Different value - should be kept
3665+ },
3666+ },
3667+ want : []elasticachetypes.Tag {
3668+ {Key : aws .String ("Team" ), Value : aws .String ("backend" )},
3669+ {Key : aws .String ("Owner" ), Value : aws .String ("engineering" )},
3670+ },
3671+ wantErr : false ,
3672+ },
3673+ {
3674+ name : "success case - all tags already exist with same values, empty result" ,
3675+ args : args {
3676+ ctx : context .TODO (),
3677+ client : func () ElastiCacheAPI {
3678+ mockClient := new (mock_ElasticacheClient )
3679+ mockClient .On ("ListTagsForResource" , mock .Anything , mock .Anything , mock .Anything ).Return (
3680+ & elasticache.ListTagsForResourceOutput {
3681+ TagList : []elasticachetypes.Tag {
3682+ {Key : aws .String ("Environment" ), Value : aws .String ("test" )},
3683+ {Key : aws .String ("Team" ), Value : aws .String ("backend" )},
3684+ },
3685+ },
3686+ nil ,
3687+ )
3688+ return mockClient
3689+ }(),
3690+ resourceARN : "arn:aws:elasticache:us-east-1:123456789012:cluster:test-cluster" ,
3691+ desired : []elasticachetypes.Tag {
3692+ {Key : aws .String ("Environment" ), Value : aws .String ("test" )},
3693+ {Key : aws .String ("Team" ), Value : aws .String ("backend" )},
3694+ },
3695+ },
3696+ want : []elasticachetypes.Tag {},
3697+ wantErr : false ,
3698+ },
3699+ {
3700+ name : "success case - existing tags with nil values handled gracefully" ,
3701+ args : args {
3702+ ctx : context .TODO (),
3703+ client : func () ElastiCacheAPI {
3704+ mockClient := new (mock_ElasticacheClient )
3705+ // Create tags with valid pointers to test the dereferencing
3706+ existingKey := "Environment"
3707+ existingValue := "production"
3708+ mockClient .On ("ListTagsForResource" , mock .Anything , mock .Anything , mock .Anything ).Return (
3709+ & elasticache.ListTagsForResourceOutput {
3710+ TagList : []elasticachetypes.Tag {
3711+ {Key : & existingKey , Value : & existingValue },
3712+ },
3713+ },
3714+ nil ,
3715+ )
3716+ return mockClient
3717+ }(),
3718+ resourceARN : "arn:aws:elasticache:us-east-1:123456789012:cluster:test-cluster" ,
3719+ desired : []elasticachetypes.Tag {
3720+ {Key : aws .String ("Environment" ), Value : aws .String ("test" )}, // Different value - should be kept
3721+ },
3722+ },
3723+ want : []elasticachetypes.Tag {
3724+ {Key : aws .String ("Environment" ), Value : aws .String ("test" )},
3725+ },
3726+ wantErr : false ,
3727+ },
3728+ }
3729+ for _ , tt := range tests {
3730+ t .Run (tt .name , func (t * testing.T ) {
3731+ got , err := filterAlreadyAppliedTags (tt .args .ctx , tt .args .client , tt .args .resourceARN , tt .args .desired )
3732+ if (err != nil ) != tt .wantErr {
3733+ t .Errorf ("filterAlreadyAppliedTags() error = %v, wantErr %v" , err , tt .wantErr )
3734+ return
3735+ }
3736+ // Handle nil vs empty slice comparison
3737+ if (got == nil && len (tt .want ) == 0 ) || (len (got ) == 0 && len (tt .want ) == 0 ) || reflect .DeepEqual (got , tt .want ) {
3738+ // Test passes - nil slice and empty slice are equivalent for our purposes
3739+ } else {
3740+ t .Errorf ("filterAlreadyAppliedTags() got = %v, want %v" , got , tt .want )
3741+ }
3742+ })
3743+ }
3744+ }
0 commit comments