github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/okta_test.go (about) 1 /* 2 Copyright 2023 Gravitational, Inc. 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 types 18 19 import ( 20 "fmt" 21 "testing" 22 "time" 23 24 "github.com/gravitational/trace" 25 "github.com/stretchr/testify/require" 26 27 "github.com/gravitational/teleport/api/constants" 28 ) 29 30 func TestOktaAssignments_SetStatus(t *testing.T) { 31 tests := []struct { 32 startStatus string 33 nextStatus string 34 invalid bool 35 }{ 36 37 // PENDING transitions 38 {startStatus: constants.OktaAssignmentStatusPending, nextStatus: constants.OktaAssignmentStatusPending, invalid: true}, 39 {startStatus: constants.OktaAssignmentStatusPending, nextStatus: constants.OktaAssignmentStatusProcessing}, 40 {startStatus: constants.OktaAssignmentStatusPending, nextStatus: constants.OktaAssignmentStatusSuccessful, invalid: true}, 41 {startStatus: constants.OktaAssignmentStatusPending, nextStatus: constants.OktaAssignmentStatusFailed, invalid: true}, 42 43 // PROCESSING transitions 44 {startStatus: constants.OktaAssignmentStatusProcessing, nextStatus: constants.OktaAssignmentStatusPending, invalid: true}, 45 {startStatus: constants.OktaAssignmentStatusProcessing, nextStatus: constants.OktaAssignmentStatusProcessing}, 46 {startStatus: constants.OktaAssignmentStatusProcessing, nextStatus: constants.OktaAssignmentStatusSuccessful}, 47 {startStatus: constants.OktaAssignmentStatusProcessing, nextStatus: constants.OktaAssignmentStatusFailed}, 48 49 // SUCCESSFUL transitions 50 {startStatus: constants.OktaAssignmentStatusSuccessful, nextStatus: constants.OktaAssignmentStatusPending, invalid: true}, 51 {startStatus: constants.OktaAssignmentStatusSuccessful, nextStatus: constants.OktaAssignmentStatusProcessing}, 52 {startStatus: constants.OktaAssignmentStatusSuccessful, nextStatus: constants.OktaAssignmentStatusSuccessful, invalid: true}, 53 {startStatus: constants.OktaAssignmentStatusSuccessful, nextStatus: constants.OktaAssignmentStatusFailed, invalid: true}, 54 55 // FAILED transitions 56 {startStatus: constants.OktaAssignmentStatusFailed, nextStatus: constants.OktaAssignmentStatusPending, invalid: true}, 57 {startStatus: constants.OktaAssignmentStatusFailed, nextStatus: constants.OktaAssignmentStatusProcessing}, 58 {startStatus: constants.OktaAssignmentStatusFailed, nextStatus: constants.OktaAssignmentStatusSuccessful, invalid: true}, 59 {startStatus: constants.OktaAssignmentStatusFailed, nextStatus: constants.OktaAssignmentStatusFailed, invalid: true}, 60 61 // UNKNOWN transitions 62 {startStatus: constants.OktaAssignmentStatusUnknown, nextStatus: constants.OktaAssignmentStatusPending}, 63 {startStatus: constants.OktaAssignmentStatusUnknown, nextStatus: constants.OktaAssignmentStatusProcessing}, 64 {startStatus: constants.OktaAssignmentStatusUnknown, nextStatus: constants.OktaAssignmentStatusSuccessful}, 65 {startStatus: constants.OktaAssignmentStatusUnknown, nextStatus: constants.OktaAssignmentStatusFailed}, 66 } 67 68 for _, test := range tests { 69 t.Run(fmt.Sprintf("%s -> %s", test.startStatus, test.nextStatus), func(t *testing.T) { 70 var errAssertionFunc require.ErrorAssertionFunc 71 if test.invalid { 72 errAssertionFunc = invalidTransition(test.startStatus, test.nextStatus) 73 } else { 74 errAssertionFunc = require.NoError 75 } 76 77 assignment := newOktaAssignment(t, test.startStatus) 78 errAssertionFunc(t, assignment.SetStatus(test.nextStatus)) 79 }) 80 } 81 } 82 83 func TestOktAssignmentIsEqual(t *testing.T) { 84 newAssignment := func(changeFns ...func(*OktaAssignmentV1)) *OktaAssignmentV1 { 85 assignment := &OktaAssignmentV1{ 86 ResourceHeader: ResourceHeader{ 87 Kind: KindOktaAssignment, 88 Version: V1, 89 Metadata: Metadata{ 90 Name: "name", 91 }, 92 }, 93 Spec: OktaAssignmentSpecV1{ 94 User: "user", 95 Targets: []*OktaAssignmentTargetV1{ 96 {Id: "1", Type: OktaAssignmentTargetV1_APPLICATION}, 97 {Id: "2", Type: OktaAssignmentTargetV1_GROUP}, 98 }, 99 CleanupTime: time.Time{}, 100 Status: OktaAssignmentSpecV1_PENDING, 101 LastTransition: time.Time{}, 102 Finalized: true, 103 }, 104 } 105 require.NoError(t, assignment.CheckAndSetDefaults()) 106 107 for _, fn := range changeFns { 108 fn(assignment) 109 } 110 111 return assignment 112 } 113 tests := []struct { 114 name string 115 o1 *OktaAssignmentV1 116 o2 *OktaAssignmentV1 117 expected bool 118 }{ 119 { 120 name: "empty equals", 121 o1: &OktaAssignmentV1{}, 122 o2: &OktaAssignmentV1{}, 123 expected: true, 124 }, 125 { 126 name: "nil equals", 127 o1: nil, 128 o2: (*OktaAssignmentV1)(nil), 129 expected: true, 130 }, 131 { 132 name: "one is nil", 133 o1: &OktaAssignmentV1{}, 134 o2: (*OktaAssignmentV1)(nil), 135 expected: false, 136 }, 137 { 138 name: "populated equals", 139 o1: newAssignment(), 140 o2: newAssignment(), 141 expected: true, 142 }, 143 { 144 name: "resource header is different", 145 o1: newAssignment(), 146 o2: newAssignment(func(o *OktaAssignmentV1) { 147 o.ResourceHeader.Kind = "different-kind" 148 }), 149 expected: false, 150 }, 151 { 152 name: "user is different", 153 o1: newAssignment(), 154 o2: newAssignment(func(o *OktaAssignmentV1) { 155 o.Spec.User = "different-user" 156 }), 157 expected: false, 158 }, 159 { 160 name: "targets different id", 161 o1: newAssignment(), 162 o2: newAssignment(func(o *OktaAssignmentV1) { 163 o.Spec.Targets = []*OktaAssignmentTargetV1{ 164 {Id: "2", Type: OktaAssignmentTargetV1_APPLICATION}, 165 {Id: "2", Type: OktaAssignmentTargetV1_GROUP}, 166 } 167 }), 168 expected: false, 169 }, 170 { 171 name: "targets different type", 172 o1: newAssignment(), 173 o2: newAssignment(func(o *OktaAssignmentV1) { 174 o.Spec.Targets = []*OktaAssignmentTargetV1{ 175 {Id: "1", Type: OktaAssignmentTargetV1_GROUP}, 176 {Id: "2", Type: OktaAssignmentTargetV1_GROUP}, 177 } 178 }), 179 expected: false, 180 }, 181 { 182 name: "targets different sizes", 183 o1: newAssignment(), 184 o2: newAssignment(func(o *OktaAssignmentV1) { 185 o.Spec.Targets = []*OktaAssignmentTargetV1{ 186 {Id: "1", Type: OktaAssignmentTargetV1_APPLICATION}, 187 } 188 }), 189 expected: false, 190 }, 191 { 192 name: "targets both nil", 193 o1: newAssignment(func(o *OktaAssignmentV1) { 194 o.Spec.Targets = nil 195 }), 196 o2: newAssignment(func(o *OktaAssignmentV1) { 197 o.Spec.Targets = nil 198 }), 199 expected: true, 200 }, 201 { 202 name: "targets o1 is nil", 203 o1: newAssignment(func(o *OktaAssignmentV1) { 204 o.Spec.Targets = nil 205 }), 206 o2: newAssignment(), 207 expected: false, 208 }, 209 { 210 name: "targets o2 is nil", 211 o1: newAssignment(), 212 o2: newAssignment(func(o *OktaAssignmentV1) { 213 o.Spec.Targets = nil 214 }), 215 expected: false, 216 }, 217 { 218 name: "cleanup time is different", 219 o1: newAssignment(), 220 o2: newAssignment(func(o *OktaAssignmentV1) { 221 o.Spec.CleanupTime = time.Date(1, 2, 3, 4, 5, 6, 7, time.UTC) 222 }), 223 expected: false, 224 }, 225 { 226 name: "status is different", 227 o1: newAssignment(), 228 o2: newAssignment(func(o *OktaAssignmentV1) { 229 o.Spec.Status = OktaAssignmentSpecV1_PROCESSING 230 }), 231 expected: false, 232 }, 233 { 234 name: "last transition is different", 235 o1: newAssignment(), 236 o2: newAssignment(func(o *OktaAssignmentV1) { 237 o.Spec.CleanupTime = time.Date(1, 2, 3, 4, 5, 6, 7, time.UTC) 238 }), 239 expected: false, 240 }, 241 { 242 name: "finalized is different", 243 o1: newAssignment(), 244 o2: newAssignment(func(o *OktaAssignmentV1) { 245 o.Spec.Finalized = false 246 }), 247 expected: false, 248 }, 249 } 250 251 for _, test := range tests { 252 t.Run(test.name, func(t *testing.T) { 253 require.Equal(t, test.expected, test.o1.IsEqual(test.o2)) 254 }) 255 } 256 } 257 258 func newOktaAssignment(t *testing.T, status string) OktaAssignment { 259 assignment := &OktaAssignmentV1{} 260 261 require.NoError(t, assignment.SetStatus(status)) 262 return assignment 263 } 264 265 func invalidTransition(startStatus, nextStatus string) require.ErrorAssertionFunc { 266 return func(t require.TestingT, err error, _ ...interface{}) { 267 require.ErrorIs(t, trace.BadParameter("invalid transition: %s -> %s", startStatus, nextStatus), err) 268 } 269 }