github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/client/events_test.go (about) 1 // Copyright 2023 Gravitational, Inc 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package client 16 17 import ( 18 "testing" 19 20 "github.com/jonboulle/clockwork" 21 "github.com/stretchr/testify/require" 22 "google.golang.org/protobuf/proto" 23 24 authpb "github.com/gravitational/teleport/api/client/proto" 25 "github.com/gravitational/teleport/api/types" 26 "github.com/gravitational/teleport/api/types/accesslist" 27 accesslistv1conv "github.com/gravitational/teleport/api/types/accesslist/convert/v1" 28 "github.com/gravitational/teleport/api/types/header" 29 ) 30 31 // TestEventEqual will test an event object against a google proto.Equal. This is 32 // primarily to catch potential issues with using our "mixed" gogo + regular protobuf 33 // strategy. 34 func TestEventEqual(t *testing.T) { 35 clock := clockwork.NewFakeClock() 36 app1, err := types.NewAppV3(types.Metadata{ 37 Name: "app1", 38 }, types.AppSpecV3{ 39 URI: "https://uri.com", 40 PublicAddr: "https://public-addr.com", 41 }) 42 require.NoError(t, err) 43 44 app1Dupe, err := types.NewAppV3(types.Metadata{ 45 Name: "app1", 46 }, types.AppSpecV3{ 47 URI: "https://uri.com", 48 PublicAddr: "https://public-addr.com", 49 }) 50 require.NoError(t, err) 51 52 app2, err := types.NewAppV3(types.Metadata{ 53 Name: "app2", 54 }, types.AppSpecV3{ 55 URI: "https://uri.com", 56 PublicAddr: "https://public-addr.com", 57 }) 58 require.NoError(t, err) 59 60 accessList1 := newAccessList(t, "1", clock) 61 accessList2 := newAccessList(t, "2", clock) 62 63 tests := []struct { 64 name string 65 event1 *authpb.Event 66 event2 *authpb.Event 67 expected bool 68 }{ 69 { 70 name: "empty equal", 71 event1: &authpb.Event{}, 72 event2: &authpb.Event{}, 73 expected: true, 74 }, 75 { 76 name: "empty not equal", 77 event1: &authpb.Event{}, 78 event2: &authpb.Event{ 79 Type: authpb.Operation_PUT, 80 Resource: &authpb.Event_App{ 81 App: app1, 82 }, 83 }, 84 expected: false, 85 }, 86 { 87 name: "gogo oneof equal", 88 event1: &authpb.Event{ 89 Type: authpb.Operation_PUT, 90 Resource: &authpb.Event_App{ 91 App: app1, 92 }, 93 }, 94 event2: &authpb.Event{ 95 Type: authpb.Operation_PUT, 96 Resource: &authpb.Event_App{ 97 App: app1Dupe, 98 }, 99 }, 100 expected: true, 101 }, 102 { 103 name: "gogo oneof not equal", 104 event1: &authpb.Event{ 105 Type: authpb.Operation_PUT, 106 Resource: &authpb.Event_App{ 107 App: app1, 108 }, 109 }, 110 event2: &authpb.Event{ 111 Type: authpb.Operation_PUT, 112 Resource: &authpb.Event_App{ 113 App: app2, 114 }, 115 }, 116 expected: false, 117 }, 118 { 119 name: "regular protobuf oneof equal", 120 event1: &authpb.Event{ 121 Type: authpb.Operation_PUT, 122 Resource: &authpb.Event_AccessList{ 123 AccessList: accesslistv1conv.ToProto(accessList1), 124 }, 125 }, 126 event2: &authpb.Event{ 127 Type: authpb.Operation_PUT, 128 Resource: &authpb.Event_AccessList{ 129 AccessList: accesslistv1conv.ToProto(accessList1), 130 }, 131 }, 132 expected: true, 133 }, 134 { 135 name: "regular protobuf oneof not equal", 136 event1: &authpb.Event{ 137 Type: authpb.Operation_PUT, 138 Resource: &authpb.Event_AccessList{ 139 AccessList: accesslistv1conv.ToProto(accessList1), 140 }, 141 }, 142 event2: &authpb.Event{ 143 Type: authpb.Operation_PUT, 144 Resource: &authpb.Event_AccessList{ 145 AccessList: accesslistv1conv.ToProto(accessList2), 146 }, 147 }, 148 expected: false, 149 }, 150 } 151 152 for _, test := range tests { 153 test := test 154 t.Run(test.name, func(t *testing.T) { 155 event1 := test.event1 156 event2 := test.event2 157 require.Equal(t, test.expected, proto.Equal(event1, event2)) 158 }) 159 } 160 } 161 162 func newAccessList(t *testing.T, name string, clock clockwork.Clock) *accesslist.AccessList { 163 t.Helper() 164 165 accessList, err := accesslist.NewAccessList( 166 header.Metadata{ 167 Name: name, 168 }, 169 accesslist.Spec{ 170 Title: "title", 171 Description: "test access list", 172 Owners: []accesslist.Owner{ 173 { 174 Name: "test-user1", 175 Description: "test user 1", 176 }, 177 { 178 Name: "test-user2", 179 Description: "test user 2", 180 }, 181 }, 182 Audit: accesslist.Audit{ 183 NextAuditDate: clock.Now(), 184 }, 185 MembershipRequires: accesslist.Requires{ 186 Roles: []string{"mrole1", "mrole2"}, 187 Traits: map[string][]string{ 188 "mtrait1": {"mvalue1", "mvalue2"}, 189 "mtrait2": {"mvalue3", "mvalue4"}, 190 }, 191 }, 192 OwnershipRequires: accesslist.Requires{ 193 Roles: []string{"orole1", "orole2"}, 194 Traits: map[string][]string{ 195 "otrait1": {"ovalue1", "ovalue2"}, 196 "otrait2": {"ovalue3", "ovalue4"}, 197 }, 198 }, 199 Grants: accesslist.Grants{ 200 Roles: []string{"grole1", "grole2"}, 201 Traits: map[string][]string{ 202 "gtrait1": {"gvalue1", "gvalue2"}, 203 "gtrait2": {"gvalue3", "gvalue4"}, 204 }, 205 }, 206 }, 207 ) 208 require.NoError(t, err) 209 210 return accessList 211 }