| // Copyright (c) HashiCorp, Inc. |
| // SPDX-License-Identifier: MPL-2.0 |
| package tpgiamresource |
| |
| import ( |
| "reflect" |
| "testing" |
| |
| "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" |
| "google.golang.org/api/cloudresourcemanager/v1" |
| ) |
| |
| func TestIamMergeBindings(t *testing.T) { |
| testCases := []struct { |
| input []*cloudresourcemanager.Binding |
| expect []*cloudresourcemanager.Binding |
| }{ |
| // Nothing to merge - return same list |
| { |
| input: []*cloudresourcemanager.Binding{}, |
| expect: []*cloudresourcemanager.Binding{}, |
| }, |
| // No members returns no binding |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-2"}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-2", |
| Members: []string{"member-2"}, |
| }, |
| }, |
| }, |
| // Nothing to merge - return same list |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1"}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1"}, |
| }, |
| }, |
| }, |
| // Nothing to merge - return same list |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-2"}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-2"}, |
| }, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"member-2"}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"member-3"}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2", "member-3"}, |
| }, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-3", "member-4"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"member-2", "member-1"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"member-5"}, |
| }, |
| { |
| Role: "role-3", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-2"}, |
| }, |
| {Role: "empty-role", Members: []string{}}, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2", "member-3", "member-4", "member-5"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| { |
| Role: "role-3", |
| Members: []string{"member-1"}, |
| }, |
| }, |
| }, |
| // Same role+members, different condition |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| Condition: &cloudresourcemanager.Expr{ |
| Title: "condition-1", |
| }, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| Condition: &cloudresourcemanager.Expr{ |
| Title: "condition-1", |
| }, |
| }, |
| }, |
| }, |
| // Same role, same condition |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| Condition: &cloudresourcemanager.Expr{ |
| Title: "condition-1", |
| }, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"member-3"}, |
| Condition: &cloudresourcemanager.Expr{ |
| Title: "condition-1", |
| }, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2", "member-3"}, |
| Condition: &cloudresourcemanager.Expr{ |
| Title: "condition-1", |
| }, |
| }, |
| }, |
| }, |
| // Different roles, same condition |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| Condition: &cloudresourcemanager.Expr{ |
| Title: "condition-1", |
| }, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-3"}, |
| Condition: &cloudresourcemanager.Expr{ |
| Title: "condition-1", |
| }, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| Condition: &cloudresourcemanager.Expr{ |
| Title: "condition-1", |
| }, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-3"}, |
| Condition: &cloudresourcemanager.Expr{ |
| Title: "condition-1", |
| }, |
| }, |
| }, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| got := MergeBindings(tc.input) |
| if !CompareBindings(got, tc.expect) { |
| t.Errorf("Unexpected value for MergeBindings(%s).\nActual: %s\nExpected: %s\n", |
| DebugPrintBindings(tc.input), DebugPrintBindings(got), DebugPrintBindings(tc.expect)) |
| } |
| } |
| } |
| |
| func TestIamFilterBindingsWithRoleAndCondition(t *testing.T) { |
| testCases := []struct { |
| input []*cloudresourcemanager.Binding |
| role string |
| conditionTitle string |
| expect []*cloudresourcemanager.Binding |
| }{ |
| // No-op |
| { |
| input: []*cloudresourcemanager.Binding{}, |
| role: "role-1", |
| expect: []*cloudresourcemanager.Binding{}, |
| }, |
| // Remove one binding |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| }, |
| role: "role-1", |
| expect: []*cloudresourcemanager.Binding{}, |
| }, |
| // Remove multiple bindings |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"member-3"}, |
| }, |
| }, |
| role: "role-1", |
| expect: []*cloudresourcemanager.Binding{}, |
| }, |
| // Remove multiple bindings and leave some. |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-3", |
| Members: []string{"member-1", "member-3"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"member-2"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| }, |
| role: "role-1", |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-2", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-3", |
| Members: []string{"member-1", "member-3"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| }, |
| }, |
| // Remove one binding with condition |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"member-3", "member-4"}, |
| Condition: &cloudresourcemanager.Expr{Title: "condition-1"}, |
| }, |
| }, |
| role: "role-1", |
| conditionTitle: "condition-1", |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| }, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| got := filterBindingsWithRoleAndCondition(tc.input, tc.role, &cloudresourcemanager.Expr{Title: tc.conditionTitle}) |
| if !CompareBindings(got, tc.expect) { |
| t.Errorf("Got unexpected value for removeAllBindingsWithRole(%s, %s).\nActual: %s\nExpected: %s", |
| DebugPrintBindings(tc.input), tc.role, DebugPrintBindings(got), DebugPrintBindings(tc.expect)) |
| } |
| } |
| } |
| |
| func TestIamSubtractFromBindings(t *testing.T) { |
| testCases := []struct { |
| input []*cloudresourcemanager.Binding |
| remove []*cloudresourcemanager.Binding |
| expect []*cloudresourcemanager.Binding |
| }{ |
| { |
| input: []*cloudresourcemanager.Binding{}, |
| remove: []*cloudresourcemanager.Binding{}, |
| expect: []*cloudresourcemanager.Binding{}, |
| }, |
| // Empty input should no-op return empty |
| { |
| input: []*cloudresourcemanager.Binding{}, |
| remove: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{}, |
| }, |
| // Empty removal should return original expect |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| }, |
| remove: []*cloudresourcemanager.Binding{}, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| }, |
| }, |
| // Removal not in input should no-op |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-1+"}, |
| }, |
| }, |
| remove: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-2", |
| Members: []string{"member-2"}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-1+"}, |
| }, |
| }, |
| }, |
| // Same input/remove should return empty |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| }, |
| remove: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{}, |
| }, |
| // Single removal |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-2"}, |
| }, |
| }, |
| remove: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1"}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-2"}, |
| }, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-2", "member-3"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-3", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-2"}, |
| }, |
| }, |
| remove: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-2", "member-4"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-2"}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-3"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-3", |
| Members: []string{"member-1"}, |
| }, |
| }, |
| }, |
| // With conditions |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-2", "member-3"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-3", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-1"}, |
| Condition: &cloudresourcemanager.Expr{Title: "condition-1"}, |
| }, |
| }, |
| remove: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-2", "member-4"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-1"}, |
| Condition: &cloudresourcemanager.Expr{Title: "condition-1"}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"member-1", "member-3"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"member-1"}, |
| }, |
| { |
| Role: "role-3", |
| Members: []string{"member-1"}, |
| }, |
| }, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| got := subtractFromBindings(tc.input, tc.remove...) |
| if !CompareBindings(got, tc.expect) { |
| t.Errorf("Unexpected value for subtractFromBindings(%s, %s).\nActual: %s\nExpected: %s\n", |
| DebugPrintBindings(tc.input), DebugPrintBindings(tc.remove), DebugPrintBindings(got), DebugPrintBindings(tc.expect)) |
| } |
| } |
| } |
| |
| func TestIamCreateIamBindingsMap(t *testing.T) { |
| testCases := []struct { |
| input []*cloudresourcemanager.Binding |
| expect map[iamBindingKey]map[string]struct{} |
| }{ |
| { |
| input: []*cloudresourcemanager.Binding{}, |
| expect: map[iamBindingKey]map[string]struct{}{}, |
| }, |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"user-1", "user-2"}, |
| }, |
| }, |
| expect: map[iamBindingKey]map[string]struct{}{ |
| {"role-1", conditionKey{}}: {"user-1": {}, "user-2": {}}, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"user-1", "user-2"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"user-3"}, |
| }, |
| }, |
| expect: map[iamBindingKey]map[string]struct{}{ |
| {"role-1", conditionKey{}}: {"user-1": {}, "user-2": {}, "user-3": {}}, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"user-1", "user-2"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"user-1"}, |
| }, |
| }, |
| expect: map[iamBindingKey]map[string]struct{}{ |
| {"role-1", conditionKey{}}: {"user-1": {}, "user-2": {}}, |
| {"role-2", conditionKey{}}: {"user-1": {}}, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"user-1", "user-2"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"user-1"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"user-3"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"user-2"}, |
| }, |
| { |
| Role: "role-3", |
| Members: []string{"user-3"}, |
| }, |
| }, |
| expect: map[iamBindingKey]map[string]struct{}{ |
| {"role-1", conditionKey{}}: {"user-1": {}, "user-2": {}, "user-3": {}}, |
| {"role-2", conditionKey{}}: {"user-1": {}, "user-2": {}}, |
| {"role-3", conditionKey{}}: {"user-3": {}}, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"deleted:serviceAccount:useR-1", "user-2"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"deleted:user:user-1"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"serviceAccount:user-3"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"user-2"}, |
| }, |
| { |
| Role: "role-3", |
| Members: []string{"user-3"}, |
| }, |
| { |
| Role: "role-4", |
| Members: []string{"deleted:principal:useR-1"}, |
| }, |
| }, |
| expect: map[iamBindingKey]map[string]struct{}{ |
| {"role-1", conditionKey{}}: {"deleted:serviceAccount:user-1": {}, "user-2": {}, "serviceAccount:user-3": {}}, |
| {"role-2", conditionKey{}}: {"deleted:user:user-1": {}, "user-2": {}}, |
| {"role-3", conditionKey{}}: {"user-3": {}}, |
| {"role-4", conditionKey{}}: {"deleted:principal:useR-1": {}}, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"principalSet://iam.googleapis.com/projects/1066737951711/locations/global/workloadIdentityPools/example-pool/attribute.aws_role/arn:aws:sts::999999999999:assumed-role/some-eu-central-1-lambdaRole"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"principal://iam.googleapis.com/projects/1066737951711/locations/global/workloadIdentityPools/example-pool/attribute.aws_role/arn:aws:sts::999999999999:assumed-role/some-eu-central-1-lambdaRole"}, |
| }, |
| { |
| Role: "role-1", |
| Members: []string{"serviceAccount:useR-3"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"user-2"}, |
| }, |
| { |
| Role: "role-3", |
| Members: []string{"user-3"}, |
| }, |
| { |
| Role: "role-3", |
| Members: []string{"principalHierarchy://iam.googleapis.com/projects/1066737951711/locations/global/workloadIdentityPools"}, |
| }, |
| }, |
| expect: map[iamBindingKey]map[string]struct{}{ |
| {"role-1", conditionKey{}}: {"principalSet://iam.googleapis.com/projects/1066737951711/locations/global/workloadIdentityPools/example-pool/attribute.aws_role/arn:aws:sts::999999999999:assumed-role/some-eu-central-1-lambdaRole": {}, "serviceAccount:user-3": {}}, |
| {"role-2", conditionKey{}}: {"principal://iam.googleapis.com/projects/1066737951711/locations/global/workloadIdentityPools/example-pool/attribute.aws_role/arn:aws:sts::999999999999:assumed-role/some-eu-central-1-lambdaRole": {}, "user-2": {}}, |
| {"role-3", conditionKey{}}: {"principalHierarchy://iam.googleapis.com/projects/1066737951711/locations/global/workloadIdentityPools": {}, "user-3": {}}, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"user-1", "user-2"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"user-1"}, |
| Condition: &cloudresourcemanager.Expr{ |
| Title: "condition-1", |
| Description: "condition-1-desc", |
| Expression: "condition-1-expr", |
| }, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"user-2"}, |
| Condition: &cloudresourcemanager.Expr{ |
| Title: "condition-1", |
| Description: "condition-1-desc", |
| Expression: "condition-1-expr", |
| }, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"user-1"}, |
| Condition: &cloudresourcemanager.Expr{ |
| Title: "condition-2", |
| Description: "condition-2-desc", |
| Expression: "condition-2-expr", |
| }, |
| }, |
| }, |
| expect: map[iamBindingKey]map[string]struct{}{ |
| {"role-1", conditionKey{}}: {"user-1": {}, "user-2": {}}, |
| { |
| Role: "role-2", |
| Condition: conditionKey{ |
| Title: "condition-1", |
| Description: "condition-1-desc", |
| Expression: "condition-1-expr", |
| }, |
| }: {"user-1": {}, "user-2": {}}, |
| { |
| Role: "role-2", |
| Condition: conditionKey{ |
| Title: "condition-2", |
| Description: "condition-2-desc", |
| Expression: "condition-2-expr", |
| }, |
| }: {"user-1": {}}, |
| }, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| got := createIamBindingsMap(tc.input) |
| if !reflect.DeepEqual(got, tc.expect) { |
| t.Errorf("Unexpected value for createIamBindingsMap(%s).\nActual: %#v\nExpected: %#v\n", |
| DebugPrintBindings(tc.input), got, tc.expect) |
| } |
| } |
| } |
| |
| func TestIamMember_MemberDiffSuppress(t *testing.T) { |
| type IamMemberTestcase struct { |
| name string |
| old string |
| new string |
| equal bool |
| } |
| var iamMemberTestcases = []IamMemberTestcase{ |
| { |
| name: "control", |
| old: "somevalue", |
| new: "somevalue", |
| equal: true, |
| }, |
| { |
| name: "principal same casing", |
| old: "principal:someValueHere", |
| new: "principal:someValueHere", |
| equal: true, |
| }, |
| { |
| name: "principal not same casing", |
| old: "principal:somevalueHere", |
| new: "principal:someValuehere", |
| equal: false, |
| }, |
| { |
| name: "principalSet same casing", |
| old: "principalSet:someValueHere", |
| new: "principalSet:someValueHere", |
| equal: true, |
| }, |
| { |
| name: "principalSet not same casing", |
| old: "principalSet:somevalueHere", |
| new: "principalSet:someValuehere", |
| equal: false, |
| }, |
| { |
| name: "principalHierarchy same casing", |
| old: "principalHierarchy:someValueHere", |
| new: "principalHierarchy:someValueHere", |
| equal: true, |
| }, |
| { |
| name: "principalHierarchy not same casing", |
| old: "principalHierarchy:somevalueHere", |
| new: "principalHierarchy:someValuehere", |
| equal: false, |
| }, |
| { |
| name: "serviceAccount same casing", |
| old: "serviceAccount:same@case.com", |
| new: "serviceAccount:same@case.com", |
| equal: true, |
| }, |
| { |
| name: "serviceAccount diff casing", |
| old: "serviceAccount:sAme@casE.com", |
| new: "serviceAccount:same@case.com", |
| equal: true, |
| }, |
| { |
| name: "random diff", |
| old: "serviasfsfljJKLSD", |
| new: "servicsFDJKLSFJdfjdlkfsf", |
| equal: false, |
| }, |
| } |
| |
| for _, testcase := range iamMemberTestcases { |
| areEqual := iamMemberCaseDiffSuppress("", testcase.old, testcase.new, &schema.ResourceData{}) |
| if areEqual != testcase.equal { |
| t.Errorf("Testcase %s failed: expected equality to be %t but got %t", testcase.name, testcase.equal, areEqual) |
| } |
| } |
| } |
| |
| func TestIamListFromIamBindingMap(t *testing.T) { |
| testCases := []struct { |
| input map[iamBindingKey]map[string]struct{} |
| expect []*cloudresourcemanager.Binding |
| }{ |
| { |
| input: map[iamBindingKey]map[string]struct{}{}, |
| expect: []*cloudresourcemanager.Binding{}, |
| }, |
| { |
| input: map[iamBindingKey]map[string]struct{}{ |
| {"role-1", conditionKey{}}: {"user-1": {}, "user-2": {}}, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"user-1", "user-2"}, |
| }, |
| }, |
| }, |
| { |
| input: map[iamBindingKey]map[string]struct{}{ |
| {"role-1", conditionKey{}}: {"user-1": {}}, |
| {"role-2", conditionKey{}}: {"user-1": {}, "user-2": {}}, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"user-1"}, |
| }, |
| { |
| Role: "role-2", |
| Members: []string{"user-1", "user-2"}, |
| }, |
| }, |
| }, |
| { |
| input: map[iamBindingKey]map[string]struct{}{ |
| {"role-1", conditionKey{}}: {"user-1": {}, "user-2": {}}, |
| {"role-2", conditionKey{}}: {}, |
| }, |
| expect: []*cloudresourcemanager.Binding{ |
| { |
| Role: "role-1", |
| Members: []string{"user-1", "user-2"}, |
| }, |
| }, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| got := listFromIamBindingMap(tc.input) |
| if !CompareBindings(got, tc.expect) { |
| t.Errorf("Unexpected value for subtractFromBindings(%v).\nActual: %#v\nExpected: %#v\n", |
| tc.input, DebugPrintBindings(got), DebugPrintBindings(tc.expect)) |
| } |
| } |
| } |
| |
| func TestIamRemoveAllAuditConfigsWithService(t *testing.T) { |
| testCases := []struct { |
| input []*cloudresourcemanager.AuditConfig |
| service string |
| expect []*cloudresourcemanager.AuditConfig |
| }{ |
| // No-op |
| { |
| service: "foo.googleapis.com", |
| input: []*cloudresourcemanager.AuditConfig{}, |
| expect: []*cloudresourcemanager.AuditConfig{}, |
| }, |
| // No-op - service not in audit configs |
| { |
| service: "bar.googleapis.com", |
| input: []*cloudresourcemanager.AuditConfig{ |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| }, |
| }, |
| }, |
| }, |
| expect: []*cloudresourcemanager.AuditConfig{ |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| }, |
| }, |
| }, |
| }, |
| }, |
| // Single removal |
| { |
| service: "foo.googleapis.com", |
| input: []*cloudresourcemanager.AuditConfig{ |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| }, |
| }, |
| }, |
| }, |
| expect: []*cloudresourcemanager.AuditConfig{}, |
| }, |
| // Multiple removal/merge |
| { |
| service: "kms.googleapis.com", |
| input: []*cloudresourcemanager.AuditConfig{ |
| { |
| Service: "kms.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| }, |
| { |
| LogType: "DATA_WRITE", |
| ExemptedMembers: []string{"user-1"}, |
| }, |
| }, |
| }, |
| { |
| Service: "iam.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| ExemptedMembers: []string{"user-1"}, |
| }, |
| }, |
| }, |
| { |
| Service: "kms.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "DATA_WRITE", |
| ExemptedMembers: []string{"user-2"}, |
| }, |
| }, |
| }, |
| { |
| Service: "iam.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| ExemptedMembers: []string{"user-2"}, |
| }, |
| }, |
| }, |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "DATA_WRITE", |
| ExemptedMembers: []string{"user-1"}, |
| }, |
| }, |
| }, |
| { |
| Service: "kms.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "DATA_WRITE", |
| ExemptedMembers: []string{"user-3", "user-4"}, |
| }, |
| { |
| LogType: "DATA_READ", |
| ExemptedMembers: []string{"user-1", "user-2"}, |
| }, |
| }, |
| }, |
| }, |
| expect: []*cloudresourcemanager.AuditConfig{ |
| { |
| Service: "iam.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| ExemptedMembers: []string{"user-1", "user-2"}, |
| }, |
| }, |
| }, |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "DATA_WRITE", |
| ExemptedMembers: []string{"user-1"}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| got := removeAllAuditConfigsWithService(tc.input, tc.service) |
| if !CompareAuditConfigs(got, tc.expect) { |
| t.Errorf("Got unexpected value for removeAllAuditConfigsWithService(%s, %s).\nActual: %s\nExpected: %s", |
| DebugPrintAuditConfigs(tc.input), tc.service, DebugPrintAuditConfigs(got), DebugPrintAuditConfigs(tc.expect)) |
| } |
| } |
| } |
| |
| func TestIamCreateIamAuditConfigsMap(t *testing.T) { |
| testCases := []struct { |
| input []*cloudresourcemanager.AuditConfig |
| expect map[string]map[string]map[string]struct{} |
| }{ |
| { |
| input: []*cloudresourcemanager.AuditConfig{}, |
| expect: make(map[string]map[string]map[string]struct{}), |
| }, |
| { |
| input: []*cloudresourcemanager.AuditConfig{ |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| }, |
| }, |
| }, |
| }, |
| expect: map[string]map[string]map[string]struct{}{ |
| "foo.googleapis.com": { |
| "ADMIN_READ": map[string]struct{}{}, |
| }, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.AuditConfig{ |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| ExemptedMembers: []string{"user-1", "user-2"}, |
| }, |
| { |
| LogType: "DATA_WRITE", |
| ExemptedMembers: []string{"user-1"}, |
| }, |
| }, |
| }, |
| }, |
| expect: map[string]map[string]map[string]struct{}{ |
| "foo.googleapis.com": { |
| "ADMIN_READ": map[string]struct{}{"user-1": {}, "user-2": {}}, |
| "DATA_WRITE": map[string]struct{}{"user-1": {}}, |
| }, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.AuditConfig{ |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| ExemptedMembers: []string{"user-1", "user-2"}, |
| }, |
| { |
| LogType: "DATA_WRITE", |
| ExemptedMembers: []string{"user-1"}, |
| }, |
| }, |
| }, |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "DATA_READ", |
| ExemptedMembers: []string{"user-2"}, |
| }, |
| }, |
| }, |
| }, |
| expect: map[string]map[string]map[string]struct{}{ |
| "foo.googleapis.com": { |
| "ADMIN_READ": map[string]struct{}{"user-1": {}, "user-2": {}}, |
| "DATA_WRITE": map[string]struct{}{"user-1": {}}, |
| "DATA_READ": map[string]struct{}{"user-2": {}}, |
| }, |
| }, |
| }, |
| { |
| input: []*cloudresourcemanager.AuditConfig{ |
| { |
| Service: "kms.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| }, |
| }, |
| }, |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| ExemptedMembers: []string{"user-1", "user-2"}, |
| }, |
| { |
| LogType: "DATA_WRITE", |
| ExemptedMembers: []string{"user-1"}, |
| }, |
| }, |
| }, |
| { |
| Service: "kms.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| ExemptedMembers: []string{"user-1", "user-2"}, |
| }, |
| }, |
| }, |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "DATA_READ", |
| ExemptedMembers: []string{"user-2"}, |
| }, |
| }, |
| }, |
| }, |
| expect: map[string]map[string]map[string]struct{}{ |
| "kms.googleapis.com": { |
| "ADMIN_READ": map[string]struct{}{"user-1": {}, "user-2": {}}, |
| }, |
| "foo.googleapis.com": { |
| "ADMIN_READ": map[string]struct{}{"user-1": {}, "user-2": {}}, |
| "DATA_WRITE": map[string]struct{}{"user-1": {}}, |
| "DATA_READ": map[string]struct{}{"user-2": {}}, |
| }, |
| }, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| got := createIamAuditConfigsMap(tc.input) |
| if !reflect.DeepEqual(got, tc.expect) { |
| t.Errorf("Unexpected value for createIamAuditConfigsMap(%s).\nActual: %#v\nExpected: %#v\n", |
| DebugPrintAuditConfigs(tc.input), got, tc.expect) |
| } |
| } |
| } |
| |
| func TestIamListFromIamAuditConfigsMap(t *testing.T) { |
| testCases := []struct { |
| input map[string]map[string]map[string]struct{} |
| expect []*cloudresourcemanager.AuditConfig |
| }{ |
| { |
| input: make(map[string]map[string]map[string]struct{}), |
| expect: []*cloudresourcemanager.AuditConfig{}, |
| }, |
| { |
| input: map[string]map[string]map[string]struct{}{ |
| "foo.googleapis.com": {"ADMIN_READ": map[string]struct{}{}}, |
| }, |
| expect: []*cloudresourcemanager.AuditConfig{ |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| input: map[string]map[string]map[string]struct{}{ |
| "foo.googleapis.com": { |
| "ADMIN_READ": map[string]struct{}{"user-1": {}, "user-2": {}}, |
| "DATA_WRITE": map[string]struct{}{"user-1": {}}, |
| "DATA_READ": map[string]struct{}{}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.AuditConfig{ |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| ExemptedMembers: []string{"user-1", "user-2"}, |
| }, |
| { |
| LogType: "DATA_WRITE", |
| ExemptedMembers: []string{"user-1"}, |
| }, |
| { |
| LogType: "DATA_READ", |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| input: map[string]map[string]map[string]struct{}{ |
| "kms.googleapis.com": { |
| "ADMIN_READ": map[string]struct{}{}, |
| "DATA_READ": map[string]struct{}{"user-1": {}, "user-2": {}}, |
| }, |
| "foo.googleapis.com": { |
| "ADMIN_READ": map[string]struct{}{"user-1": {}, "user-2": {}}, |
| "DATA_WRITE": map[string]struct{}{"user-1": {}}, |
| "DATA_READ": map[string]struct{}{"user-2": {}}, |
| }, |
| }, |
| expect: []*cloudresourcemanager.AuditConfig{ |
| { |
| Service: "kms.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| }, |
| { |
| LogType: "DATA_READ", |
| ExemptedMembers: []string{"user-1", "user-2"}, |
| }, |
| }, |
| }, |
| { |
| Service: "foo.googleapis.com", |
| AuditLogConfigs: []*cloudresourcemanager.AuditLogConfig{ |
| { |
| LogType: "ADMIN_READ", |
| ExemptedMembers: []string{"user-1", "user-2"}, |
| }, |
| { |
| LogType: "DATA_WRITE", |
| ExemptedMembers: []string{"user-1"}, |
| }, |
| { |
| LogType: "DATA_READ", |
| ExemptedMembers: []string{"user-2"}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| got := listFromIamAuditConfigMap(tc.input) |
| if !CompareAuditConfigs(got, tc.expect) { |
| t.Errorf("Unexpected value for listFromIamAuditConfigMap(%+v).\nActual: %s\nExpected: %s\n", |
| tc.input, DebugPrintAuditConfigs(got), DebugPrintAuditConfigs(tc.expect)) |
| } |
| } |
| } |