github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/cloudcontroller/ccv3/user_test.go (about) 1 package ccv3_test 2 3 import ( 4 "fmt" 5 "net/http" 6 7 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 8 . "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 9 "code.cloudfoundry.org/cli/resources" 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/gomega" 12 . "github.com/onsi/gomega/ghttp" 13 ) 14 15 var _ = Describe("User", func() { 16 var client *Client 17 18 BeforeEach(func() { 19 client, _ = NewTestClient() 20 }) 21 22 Describe("CreateUser", func() { 23 var ( 24 warnings Warnings 25 executeErr error 26 user resources.User 27 ) 28 29 JustBeforeEach(func() { 30 user, warnings, executeErr = client.CreateUser("some-uaa-guid") 31 }) 32 33 When("no error occurs", func() { 34 BeforeEach(func() { 35 response := `{ 36 "guid": "some-uaa-guid", 37 "username": "some-user-name", 38 "presentation_name": "some-user-name", 39 "origin": "ldap", 40 "created_at": "2016-12-07T18:18:30Z", 41 "updated_at": null 42 43 }` 44 expectedBody := `{"guid":"some-uaa-guid"}` 45 server.AppendHandlers( 46 CombineHandlers( 47 VerifyRequest(http.MethodPost, "/v3/users"), 48 VerifyJSON(expectedBody), 49 RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1, warning-2"}}), 50 ), 51 ) 52 }) 53 54 It("creates and returns the user and all warnings", func() { 55 Expect(executeErr).ToNot(HaveOccurred()) 56 57 Expect(user).To(Equal(resources.User{GUID: "some-uaa-guid", Username: "some-user-name", PresentationName: "some-user-name", Origin: "ldap"})) 58 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 59 }) 60 }) 61 62 When("the cloud controller returns errors and warnings", func() { 63 BeforeEach(func() { 64 response := `{ 65 "errors": [ 66 { 67 "code": 10008, 68 "detail": "The request is semantically invalid: command presence", 69 "title": "CF-UnprocessableEntity" 70 }, 71 { 72 "code": 10010, 73 "detail": "Isolation segment not found", 74 "title": "CF-ResourceNotFound" 75 } 76 ] 77 }` 78 server.AppendHandlers( 79 CombineHandlers( 80 VerifyRequest(http.MethodPost, "/v3/users"), 81 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 82 ), 83 ) 84 }) 85 86 It("returns the error and all warnings", func() { 87 Expect(executeErr).To(MatchError(ccerror.MultiError{ 88 ResponseCode: http.StatusTeapot, 89 Errors: []ccerror.V3Error{ 90 { 91 Code: 10008, 92 Detail: "The request is semantically invalid: command presence", 93 Title: "CF-UnprocessableEntity", 94 }, 95 { 96 Code: 10010, 97 Detail: "Isolation segment not found", 98 Title: "CF-ResourceNotFound", 99 }, 100 }, 101 })) 102 Expect(warnings).To(ConsistOf("this is a warning")) 103 }) 104 }) 105 }) 106 107 Describe("DeleteUser", func() { 108 var ( 109 jobUrl JobURL 110 warnings Warnings 111 executeErr error 112 ) 113 114 JustBeforeEach(func() { 115 jobUrl, warnings, executeErr = client.DeleteUser("some-uaa-guid") 116 }) 117 118 When("no error occurs", func() { 119 BeforeEach(func() { 120 response := `{}` 121 server.AppendHandlers( 122 CombineHandlers( 123 VerifyRequest(http.MethodDelete, "/v3/users/some-uaa-guid"), 124 RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"warning-1, warning-2"}, "Location": []string{"job-url"}}), 125 ), 126 ) 127 }) 128 129 It("deletes and returns all warnings", func() { 130 Expect(executeErr).ToNot(HaveOccurred()) 131 132 Expect(jobUrl).To(Equal(JobURL("job-url"))) 133 Expect(warnings).To(ConsistOf("warning-1", "warning-2")) 134 }) 135 }) 136 137 When("the cloud controller returns errors and warnings", func() { 138 When("the error should be raise", func() { 139 140 BeforeEach(func() { 141 response := `{ 142 "errors": [ 143 { 144 "code": 10008, 145 "detail": "The request is semantically invalid: command presence", 146 "title": "CF-UnprocessableEntity" 147 }, 148 { 149 "code": 10010, 150 "detail": "Isolation segment not found", 151 "title": "CF-ResourceNotFound" 152 } 153 ] 154 }` 155 server.AppendHandlers( 156 CombineHandlers( 157 VerifyRequest(http.MethodDelete, "/v3/users/some-uaa-guid"), 158 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a delete warning"}}), 159 ), 160 ) 161 }) 162 163 It("returns the error and all warnings", func() { 164 Expect(executeErr).To(MatchError(ccerror.MultiError{ 165 ResponseCode: http.StatusTeapot, 166 Errors: []ccerror.V3Error{ 167 { 168 Code: 10008, 169 Detail: "The request is semantically invalid: command presence", 170 Title: "CF-UnprocessableEntity", 171 }, 172 { 173 Code: 10010, 174 Detail: "Isolation segment not found", 175 Title: "CF-ResourceNotFound", 176 }, 177 }, 178 })) 179 Expect(warnings).To(ConsistOf("this is a delete warning")) 180 }) 181 }) 182 }) 183 }) 184 185 Describe("GetUsers", func() { 186 var ( 187 users []resources.User 188 warnings Warnings 189 executeErr error 190 query []Query 191 ) 192 193 BeforeEach(func() { 194 query = []Query{ 195 { 196 Key: UsernamesFilter, 197 Values: []string{"some-user-name"}, 198 }, 199 { 200 Key: OriginsFilter, 201 Values: []string{"uaa"}, 202 }, 203 } 204 }) 205 JustBeforeEach(func() { 206 users, warnings, executeErr = client.GetUsers(query...) 207 }) 208 209 Describe("listing users", func() { 210 When("the request succeeds", func() { 211 BeforeEach(func() { 212 response1 := fmt.Sprintf(`{ 213 "pagination": { 214 "next": { 215 "href": null 216 } 217 }, 218 "resources": [ 219 { 220 "guid": "user-guid-1", 221 "username": "some-user-name", 222 "origin": "uaa" 223 } 224 ] 225 }`) 226 227 server.AppendHandlers( 228 CombineHandlers( 229 VerifyRequest(http.MethodGet, "/v3/users", "usernames=some-user-name&origins=uaa"), 230 RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"warning-1"}}), 231 ), 232 ) 233 }) 234 235 It("returns the given user and all warnings", func() { 236 Expect(executeErr).ToNot(HaveOccurred()) 237 Expect(warnings).To(ConsistOf("warning-1")) 238 239 Expect(users).To(Equal([]resources.User{{ 240 GUID: "user-guid-1", 241 Username: "some-user-name", 242 Origin: "uaa", 243 }, 244 })) 245 }) 246 }) 247 248 When("the cloud controller returns errors and warnings", func() { 249 BeforeEach(func() { 250 response := `{ 251 "errors": [ 252 { 253 "code": 10008, 254 "detail": "The request is semantically invalid: command presence", 255 "title": "CF-UnprocessableEntity" 256 }, 257 { 258 "code": 10010, 259 "detail": "Org not found", 260 "title": "CF-ResourceNotFound" 261 } 262 ] 263 }` 264 server.AppendHandlers( 265 CombineHandlers( 266 VerifyRequest(http.MethodGet, "/v3/users"), 267 RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}), 268 ), 269 ) 270 }) 271 272 It("returns the error and all warnings", func() { 273 Expect(executeErr).To(MatchError(ccerror.MultiError{ 274 ResponseCode: http.StatusTeapot, 275 Errors: []ccerror.V3Error{ 276 { 277 Code: 10008, 278 Detail: "The request is semantically invalid: command presence", 279 Title: "CF-UnprocessableEntity", 280 }, 281 { 282 Code: 10010, 283 Detail: "Org not found", 284 Title: "CF-ResourceNotFound", 285 }, 286 }, 287 })) 288 Expect(warnings).To(ConsistOf("this is a warning")) 289 }) 290 }) 291 }) 292 }) 293 294 Describe("GetUser", func() { 295 var ( 296 user resources.User 297 warnings Warnings 298 executeErr error 299 ) 300 301 JustBeforeEach(func() { 302 user, warnings, executeErr = client.GetUser("some-guid") 303 }) 304 305 When("the request succeeds", func() { 306 BeforeEach(func() { 307 response := `{ 308 "guid": "some-guid", 309 "username": "some-user-name", 310 "origin": "some-origin" 311 }` 312 server.AppendHandlers( 313 CombineHandlers( 314 VerifyRequest(http.MethodGet, "/v3/users/some-guid"), 315 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 316 ), 317 ) 318 }) 319 320 It("returns the given user and all warnings", func() { 321 Expect(executeErr).ToNot(HaveOccurred()) 322 323 Expect(user).To(Equal(resources.User{ 324 GUID: "some-guid", 325 Username: "some-user-name", 326 Origin: "some-origin", 327 })) 328 Expect(warnings).To(ConsistOf("warning-1")) 329 }) 330 }) 331 332 When("cloud controller returns an error", func() { 333 BeforeEach(func() { 334 response := `{ 335 "errors": [ 336 { 337 "code": 10010, 338 "detail": "User not found", 339 "title": "CF-ResourceNotFound" 340 } 341 ] 342 }` 343 server.AppendHandlers( 344 CombineHandlers( 345 VerifyRequest(http.MethodGet, "/v3/users/some-guid"), 346 RespondWith(http.StatusNotFound, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 347 ), 348 ) 349 }) 350 351 It("returns the error", func() { 352 Expect(executeErr).To(MatchError(ccerror.UserNotFoundError{})) 353 Expect(warnings).To(ConsistOf("warning-1")) 354 }) 355 }) 356 }) 357 358 Describe("Who am I", func() { 359 var ( 360 k8sUser resources.K8sUser 361 warnings Warnings 362 executeErr error 363 ) 364 365 JustBeforeEach(func() { 366 k8sUser, warnings, executeErr = client.WhoAmI() 367 }) 368 369 When("the request succeeds", func() { 370 BeforeEach(func() { 371 response := `{ 372 "name": "bob", 373 "kind": "User" 374 }` 375 server.AppendHandlers( 376 CombineHandlers( 377 VerifyRequest(http.MethodGet, "/whoami"), 378 RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 379 ), 380 ) 381 }) 382 383 It("returns the expected user and all warnings", func() { 384 Expect(executeErr).ToNot(HaveOccurred()) 385 Expect(k8sUser.Name).To(Equal("bob")) 386 Expect(k8sUser.Kind).To(Equal("User")) 387 Expect(warnings).To(ConsistOf("warning-1")) 388 }) 389 }) 390 391 When("cloud controller returns an error", func() { 392 BeforeEach(func() { 393 response := `{ 394 "errors": [ 395 { 396 "code": 1000, 397 "detail": "Not authenticated", 398 "title": "CF-InvalidAuthToken" 399 } 400 ] 401 }` 402 server.AppendHandlers( 403 CombineHandlers( 404 VerifyRequest(http.MethodGet, "/whoami"), 405 RespondWith(http.StatusUnauthorized, response, http.Header{"X-Cf-Warnings": {"warning-1"}}), 406 ), 407 ) 408 }) 409 410 It("returns the error", func() { 411 Expect(executeErr).To(MatchError(ccerror.InvalidAuthTokenError{Message: "Not authenticated"})) 412 Expect(warnings).To(ConsistOf("warning-1")) 413 }) 414 }) 415 }) 416 })