github.com/google/go-github/v68@v68.0.0/github/scim_test.go (about) 1 // Copyright 2021 The go-github AUTHORS. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 package github 7 8 import ( 9 "context" 10 "fmt" 11 "net/http" 12 "testing" 13 "time" 14 15 "github.com/google/go-cmp/cmp" 16 ) 17 18 func TestSCIMService_ListSCIMProvisionedIdentities(t *testing.T) { 19 t.Parallel() 20 client, mux, _ := setup(t) 21 22 mux.HandleFunc("/scim/v2/organizations/o/Users", func(w http.ResponseWriter, r *http.Request) { 23 testMethod(t, r, "GET") 24 w.WriteHeader(http.StatusOK) 25 _, _ = w.Write([]byte(`{ 26 "schemas": [ 27 "urn:ietf:params:scim:api:messages:2.0:ListResponse" 28 ], 29 "totalResults": 1, 30 "itemsPerPage": 1, 31 "startIndex": 1, 32 "Resources": [ 33 { 34 "schemas": [ 35 "urn:ietf:params:scim:schemas:core:2.0:User" 36 ], 37 "id": "5fc0c238-1112-11e8-8e45-920c87bdbd75", 38 "externalId": "00u1dhhb1fkIGP7RL1d8", 39 "userName": "octocat@github.com", 40 "displayName": "Mona Octocat", 41 "name": { 42 "givenName": "Mona", 43 "familyName": "Octocat", 44 "formatted": "Mona Octocat" 45 }, 46 "emails": [ 47 { 48 "value": "octocat@github.com", 49 "primary": true 50 } 51 ], 52 "active": true, 53 "meta": { 54 "resourceType": "User", 55 "created": "2018-02-13T15:05:24.000-00:00", 56 "lastModified": "2018-02-13T15:05:24.000-00:00", 57 "location": "https://api.github.com/scim/v2/organizations/octo-org/Users/5fc0c238-1112-11e8-8e45-920c87bdbd75" 58 } 59 } 60 ] 61 }`)) 62 }) 63 64 ctx := context.Background() 65 opts := &ListSCIMProvisionedIdentitiesOptions{} 66 identities, _, err := client.SCIM.ListSCIMProvisionedIdentities(ctx, "o", opts) 67 if err != nil { 68 t.Errorf("SCIM.ListSCIMProvisionedIdentities returned error: %v", err) 69 } 70 71 date := Timestamp{time.Date(2018, time.February, 13, 15, 5, 24, 0, time.UTC)} 72 want := SCIMProvisionedIdentities{ 73 Schemas: []string{"urn:ietf:params:scim:api:messages:2.0:ListResponse"}, 74 TotalResults: Ptr(1), 75 ItemsPerPage: Ptr(1), 76 StartIndex: Ptr(1), 77 Resources: []*SCIMUserAttributes{ 78 { 79 ID: Ptr("5fc0c238-1112-11e8-8e45-920c87bdbd75"), 80 Meta: &SCIMMeta{ 81 ResourceType: Ptr("User"), 82 Created: &date, 83 LastModified: &date, 84 Location: Ptr("https://api.github.com/scim/v2/organizations/octo-org/Users/5fc0c238-1112-11e8-8e45-920c87bdbd75"), 85 }, 86 UserName: "octocat@github.com", 87 Name: SCIMUserName{ 88 GivenName: "Mona", 89 FamilyName: "Octocat", 90 Formatted: Ptr("Mona Octocat"), 91 }, 92 DisplayName: Ptr("Mona Octocat"), 93 Emails: []*SCIMUserEmail{ 94 { 95 Value: "octocat@github.com", 96 Primary: Ptr(true), 97 }, 98 }, 99 Schemas: []string{"urn:ietf:params:scim:schemas:core:2.0:User"}, 100 ExternalID: Ptr("00u1dhhb1fkIGP7RL1d8"), 101 Groups: nil, 102 Active: Ptr(true), 103 }, 104 }, 105 } 106 107 if !cmp.Equal(identities, &want) { 108 diff := cmp.Diff(identities, want) 109 t.Errorf("SCIM.ListSCIMProvisionedIdentities returned %+v, want %+v: diff %+v", identities, want, diff) 110 } 111 112 const methodName = "ListSCIMProvisionedIdentities" 113 testBadOptions(t, methodName, func() (err error) { 114 _, _, err = client.SCIM.ListSCIMProvisionedIdentities(ctx, "\n", opts) 115 return err 116 }) 117 118 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 119 _, r, err := client.SCIM.ListSCIMProvisionedIdentities(ctx, "o", opts) 120 return r, err 121 }) 122 } 123 124 func TestSCIMService_ProvisionAndInviteSCIMUser(t *testing.T) { 125 t.Parallel() 126 client, mux, _ := setup(t) 127 128 mux.HandleFunc("/scim/v2/organizations/o/Users", func(w http.ResponseWriter, r *http.Request) { 129 testMethod(t, r, "POST") 130 w.WriteHeader(http.StatusCreated) 131 fmt.Fprint(w, `{"id":"1234567890","userName":"userName"}`) 132 }) 133 134 ctx := context.Background() 135 opts := &SCIMUserAttributes{ 136 UserName: "userName", 137 Name: SCIMUserName{ 138 GivenName: "givenName", 139 FamilyName: "familyName", 140 }, 141 Emails: []*SCIMUserEmail{ 142 { 143 Value: "octocat@github.com", 144 }, 145 }, 146 } 147 user, _, err := client.SCIM.ProvisionAndInviteSCIMUser(ctx, "o", opts) 148 if err != nil { 149 t.Errorf("SCIM.ProvisionAndInviteSCIMUser returned error: %v", err) 150 } 151 152 want := &SCIMUserAttributes{ 153 ID: Ptr("1234567890"), 154 UserName: "userName", 155 } 156 if !cmp.Equal(user, want) { 157 t.Errorf("SCIM.ProvisionAndInviteSCIMUser returned %+v, want %+v", user, want) 158 } 159 160 const methodName = "ProvisionAndInviteSCIMUser" 161 testBadOptions(t, methodName, func() (err error) { 162 _, _, err = client.SCIM.ProvisionAndInviteSCIMUser(ctx, "\n", opts) 163 return err 164 }) 165 166 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 167 got, resp, err := client.SCIM.ProvisionAndInviteSCIMUser(ctx, "o", opts) 168 if got != nil { 169 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 170 } 171 return resp, err 172 }) 173 } 174 175 func TestSCIMService_GetSCIMProvisioningInfoForUser(t *testing.T) { 176 t.Parallel() 177 client, mux, _ := setup(t) 178 179 mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) { 180 testMethod(t, r, "GET") 181 w.WriteHeader(http.StatusOK) 182 _, _ = w.Write([]byte(`{ 183 "schemas": [ 184 "urn:ietf:params:scim:schemas:core:2.0:User" 185 ], 186 "id": "edefdfedf-050c-11e7-8d32", 187 "externalId": "a7d0f98382", 188 "userName": "mona.octocat@okta.example.com", 189 "displayName": "Mona Octocat", 190 "name": { 191 "givenName": "Mona", 192 "familyName": "Octocat", 193 "formatted": "Mona Octocat" 194 }, 195 "emails": [ 196 { 197 "value": "mona.octocat@okta.example.com", 198 "primary": true 199 }, 200 { 201 "value": "mona@octocat.github.com" 202 } 203 ], 204 "active": true, 205 "meta": { 206 "resourceType": "User", 207 "created": "2017-03-09T16:11:13-00:00", 208 "lastModified": "2017-03-09T16:11:13-00:00", 209 "location": "https://api.github.com/scim/v2/organizations/octo-org/Users/edefdfedf-050c-11e7-8d32" 210 } 211 }`)) 212 }) 213 214 ctx := context.Background() 215 user, _, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "o", "123") 216 if err != nil { 217 t.Errorf("SCIM.GetSCIMProvisioningInfoForUser returned error: %v", err) 218 } 219 220 date := Timestamp{time.Date(2017, time.March, 9, 16, 11, 13, 0, time.UTC)} 221 want := SCIMUserAttributes{ 222 ID: Ptr("edefdfedf-050c-11e7-8d32"), 223 Meta: &SCIMMeta{ 224 ResourceType: Ptr("User"), 225 Created: &date, 226 LastModified: &date, 227 Location: Ptr("https://api.github.com/scim/v2/organizations/octo-org/Users/edefdfedf-050c-11e7-8d32"), 228 }, 229 UserName: "mona.octocat@okta.example.com", 230 Name: SCIMUserName{ 231 GivenName: "Mona", 232 FamilyName: "Octocat", 233 Formatted: Ptr("Mona Octocat"), 234 }, 235 DisplayName: Ptr("Mona Octocat"), 236 Emails: []*SCIMUserEmail{ 237 { 238 Value: "mona.octocat@okta.example.com", 239 Primary: Ptr(true), 240 }, 241 { 242 Value: "mona@octocat.github.com", 243 }, 244 }, 245 Schemas: []string{"urn:ietf:params:scim:schemas:core:2.0:User"}, 246 ExternalID: Ptr("a7d0f98382"), 247 Groups: nil, 248 Active: Ptr(true), 249 } 250 251 if !cmp.Equal(user, &want) { 252 diff := cmp.Diff(user, want) 253 t.Errorf("SCIM.ListSCIMProvisionedIdentities returned %+v, want %+v: diff %+v", user, want, diff) 254 } 255 256 const methodName = "GetSCIMProvisioningInfoForUser" 257 testBadOptions(t, methodName, func() error { 258 _, _, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "\n", "123") 259 return err 260 }) 261 262 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 263 _, r, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "o", "123") 264 return r, err 265 }) 266 } 267 268 func TestSCIMService_UpdateProvisionedOrgMembership(t *testing.T) { 269 t.Parallel() 270 client, mux, _ := setup(t) 271 272 mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) { 273 testMethod(t, r, "PUT") 274 w.WriteHeader(http.StatusOK) 275 }) 276 277 ctx := context.Background() 278 opts := &SCIMUserAttributes{ 279 UserName: "userName", 280 Name: SCIMUserName{ 281 GivenName: "givenName", 282 FamilyName: "familyName", 283 }, 284 Emails: []*SCIMUserEmail{ 285 { 286 Value: "octocat@github.com", 287 }, 288 }, 289 } 290 _, err := client.SCIM.UpdateProvisionedOrgMembership(ctx, "o", "123", opts) 291 if err != nil { 292 t.Errorf("SCIM.UpdateProvisionedOrgMembership returned error: %v", err) 293 } 294 295 const methodName = "UpdateProvisionedOrgMembership" 296 testBadOptions(t, methodName, func() error { 297 _, err := client.SCIM.UpdateProvisionedOrgMembership(ctx, "\n", "123", opts) 298 return err 299 }) 300 301 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 302 return client.SCIM.UpdateProvisionedOrgMembership(ctx, "o", "123", opts) 303 }) 304 } 305 306 func TestSCIMService_UpdateAttributeForSCIMUser(t *testing.T) { 307 t.Parallel() 308 client, mux, _ := setup(t) 309 310 mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) { 311 testMethod(t, r, "PATCH") 312 w.WriteHeader(http.StatusNoContent) 313 }) 314 315 ctx := context.Background() 316 opts := &UpdateAttributeForSCIMUserOptions{} 317 _, err := client.SCIM.UpdateAttributeForSCIMUser(ctx, "o", "123", opts) 318 if err != nil { 319 t.Errorf("SCIM.UpdateAttributeForSCIMUser returned error: %v", err) 320 } 321 322 const methodName = "UpdateAttributeForSCIMUser" 323 testBadOptions(t, methodName, func() error { 324 _, err := client.SCIM.UpdateAttributeForSCIMUser(ctx, "\n", "123", opts) 325 return err 326 }) 327 328 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 329 return client.SCIM.UpdateAttributeForSCIMUser(ctx, "o", "123", opts) 330 }) 331 } 332 333 func TestSCIMService_DeleteSCIMUserFromOrg(t *testing.T) { 334 t.Parallel() 335 client, mux, _ := setup(t) 336 337 mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) { 338 testMethod(t, r, "DELETE") 339 w.WriteHeader(http.StatusNoContent) 340 }) 341 342 ctx := context.Background() 343 _, err := client.SCIM.DeleteSCIMUserFromOrg(ctx, "o", "123") 344 if err != nil { 345 t.Errorf("SCIM.DeleteSCIMUserFromOrg returned error: %v", err) 346 } 347 348 const methodName = "DeleteSCIMUserFromOrg" 349 testBadOptions(t, methodName, func() error { 350 _, err := client.SCIM.DeleteSCIMUserFromOrg(ctx, "\n", "") 351 return err 352 }) 353 354 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 355 return client.SCIM.DeleteSCIMUserFromOrg(ctx, "o", "123") 356 }) 357 } 358 359 func TestSCIMUserAttributes_Marshal(t *testing.T) { 360 t.Parallel() 361 testJSONMarshal(t, &SCIMUserAttributes{}, `{ 362 "userName":"","name":{"givenName":"","familyName":""},"emails":null 363 }`) 364 365 u := &SCIMUserAttributes{ 366 UserName: "userName1", 367 Name: SCIMUserName{ 368 GivenName: "Name1", 369 FamilyName: "Fname", 370 Formatted: Ptr("formatted name"), 371 }, 372 DisplayName: Ptr("Name"), 373 Emails: []*SCIMUserEmail{ 374 { 375 Value: "value", 376 Primary: Ptr(false), 377 Type: Ptr("type"), 378 }, 379 }, 380 Schemas: []string{"schema1"}, 381 ExternalID: Ptr("id"), 382 Groups: []string{"group1"}, 383 Active: Ptr(true), 384 } 385 386 want := `{ 387 "userName": "userName1", 388 "name": { 389 "givenName": "Name1", 390 "familyName": "Fname", 391 "formatted": "formatted name" 392 }, 393 "displayName": "Name", 394 "emails": [{ 395 "value": "value", 396 "primary": false, 397 "type": "type" 398 }], 399 "schemas": ["schema1"], 400 "externalId": "id", 401 "groups": ["group1"], 402 "active": true 403 }` 404 405 testJSONMarshal(t, u, want) 406 } 407 408 func TestUpdateAttributeForSCIMUserOperations_Marshal(t *testing.T) { 409 t.Parallel() 410 testJSONMarshal(t, &UpdateAttributeForSCIMUserOperations{}, `{}`) 411 412 u := &UpdateAttributeForSCIMUserOperations{ 413 Op: "TestOp", 414 Path: Ptr("path"), 415 } 416 417 want := `{ 418 "op": "TestOp", 419 "path": "path" 420 }` 421 422 testJSONMarshal(t, u, want) 423 } 424 425 func TestUpdateAttributeForSCIMUserOptions_Marshal(t *testing.T) { 426 t.Parallel() 427 testJSONMarshal(t, &UpdateAttributeForSCIMUserOptions{}, `{}`) 428 429 u := &UpdateAttributeForSCIMUserOptions{ 430 Schemas: []string{"test", "schema"}, 431 Operations: UpdateAttributeForSCIMUserOperations{ 432 Op: "TestOp", 433 Path: Ptr("path"), 434 }, 435 } 436 437 want := `{ 438 "schemas": ["test", "schema"], 439 "operations": { 440 "op": "TestOp", 441 "path": "path" 442 } 443 }` 444 445 testJSONMarshal(t, u, want) 446 } 447 448 func TestListSCIMProvisionedIdentitiesOptions_addOptions(t *testing.T) { 449 t.Parallel() 450 testJSONMarshal(t, &ListSCIMProvisionedIdentitiesOptions{}, `{ 451 "StartIndex": null, 452 "Count": null, 453 "Filter": null 454 }`) 455 456 url := "some/path" 457 458 testAddURLOptions(t, url, &ListSCIMProvisionedIdentitiesOptions{}, url) 459 460 testAddURLOptions( 461 t, 462 url, 463 &ListSCIMProvisionedIdentitiesOptions{ 464 StartIndex: Ptr(1), 465 Count: Ptr(10), 466 }, 467 fmt.Sprintf("%s?count=10&startIndex=1", url), 468 ) 469 470 testAddURLOptions( 471 t, 472 url, 473 &ListSCIMProvisionedIdentitiesOptions{ 474 StartIndex: Ptr(1), 475 Count: Ptr(10), 476 Filter: Ptr("test"), 477 }, 478 fmt.Sprintf("%s?count=10&filter=test&startIndex=1", url), 479 ) 480 } 481 482 func TestSCIMUserName_Marshal(t *testing.T) { 483 t.Parallel() 484 testJSONMarshal(t, &SCIMUserName{}, `{ 485 "givenName":"","familyName":"" 486 }`) 487 488 u := &SCIMUserName{ 489 GivenName: "Name1", 490 FamilyName: "Fname", 491 Formatted: Ptr("formatted name"), 492 } 493 494 want := `{ 495 "givenName": "Name1", 496 "familyName": "Fname", 497 "formatted": "formatted name" 498 }` 499 testJSONMarshal(t, u, want) 500 } 501 502 func TestSCIMMeta_Marshal(t *testing.T) { 503 t.Parallel() 504 testJSONMarshal(t, &SCIMMeta{}, `{}`) 505 506 u := &SCIMMeta{ 507 ResourceType: Ptr("test"), 508 Location: Ptr("test"), 509 } 510 511 want := `{ 512 "resourceType": "test", 513 "location": "test" 514 }` 515 516 testJSONMarshal(t, u, want) 517 } 518 519 func TestSCIMProvisionedIdentities_Marshal(t *testing.T) { 520 t.Parallel() 521 testJSONMarshal(t, &SCIMProvisionedIdentities{}, `{}`) 522 523 u := &SCIMProvisionedIdentities{ 524 Schemas: []string{"test", "schema"}, 525 TotalResults: Ptr(1), 526 ItemsPerPage: Ptr(2), 527 StartIndex: Ptr(1), 528 Resources: []*SCIMUserAttributes{ 529 { 530 UserName: "SCIM", 531 Name: SCIMUserName{ 532 GivenName: "scim", 533 FamilyName: "test", 534 Formatted: Ptr("SCIM"), 535 }, 536 DisplayName: Ptr("Test SCIM"), 537 Emails: []*SCIMUserEmail{ 538 { 539 Value: "test", 540 Primary: Ptr(true), 541 Type: Ptr("test"), 542 }, 543 }, 544 Schemas: []string{"schema1"}, 545 ExternalID: Ptr("id"), 546 Groups: []string{"group1"}, 547 Active: Ptr(true), 548 }, 549 }, 550 } 551 552 want := `{ 553 "schemas": ["test", "schema"], 554 "totalResults": 1, 555 "itemsPerPage": 2, 556 "startIndex": 1, 557 "Resources": [{ 558 "userName": "SCIM", 559 "name": { 560 "givenName": "scim", 561 "familyName": "test", 562 "formatted": "SCIM" 563 }, 564 "displayName": "Test SCIM", 565 "emails": [{ 566 "value": "test", 567 "primary": true, 568 "type": "test" 569 }], 570 "schemas": ["schema1"], 571 "externalId": "id", 572 "groups": ["group1"], 573 "active": true 574 }] 575 }` 576 577 testJSONMarshal(t, u, want) 578 }