github.com/google/go-github/v65@v65.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 client, mux, _, teardown := setup() 20 defer teardown() 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: Int(1), 75 ItemsPerPage: Int(1), 76 StartIndex: Int(1), 77 Resources: []*SCIMUserAttributes{ 78 { 79 ID: String("5fc0c238-1112-11e8-8e45-920c87bdbd75"), 80 Meta: &SCIMMeta{ 81 ResourceType: String("User"), 82 Created: &date, 83 LastModified: &date, 84 Location: String("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: String("Mona Octocat"), 91 }, 92 DisplayName: String("Mona Octocat"), 93 Emails: []*SCIMUserEmail{ 94 { 95 Value: "octocat@github.com", 96 Primary: Bool(true), 97 }, 98 }, 99 Schemas: []string{"urn:ietf:params:scim:schemas:core:2.0:User"}, 100 ExternalID: String("00u1dhhb1fkIGP7RL1d8"), 101 Groups: nil, 102 Active: Bool(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 client, mux, _, teardown := setup() 126 defer teardown() 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: String("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 client, mux, _, teardown := setup() 177 defer teardown() 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: String("edefdfedf-050c-11e7-8d32"), 223 Meta: &SCIMMeta{ 224 ResourceType: String("User"), 225 Created: &date, 226 LastModified: &date, 227 Location: String("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: String("Mona Octocat"), 234 }, 235 DisplayName: String("Mona Octocat"), 236 Emails: []*SCIMUserEmail{ 237 { 238 Value: "mona.octocat@okta.example.com", 239 Primary: Bool(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: String("a7d0f98382"), 247 Groups: nil, 248 Active: Bool(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 client, mux, _, teardown := setup() 270 defer teardown() 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 client, mux, _, teardown := setup() 308 defer teardown() 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 client, mux, _, teardown := setup() 335 defer teardown() 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 testJSONMarshal(t, &SCIMUserAttributes{}, `{ 361 "userName":"","name":{"givenName":"","familyName":""},"emails":null 362 }`) 363 364 u := &SCIMUserAttributes{ 365 UserName: "userName1", 366 Name: SCIMUserName{ 367 GivenName: "Name1", 368 FamilyName: "Fname", 369 Formatted: String("formatted name"), 370 }, 371 DisplayName: String("Name"), 372 Emails: []*SCIMUserEmail{ 373 { 374 Value: "value", 375 Primary: Bool(false), 376 Type: String("type"), 377 }, 378 }, 379 Schemas: []string{"schema1"}, 380 ExternalID: String("id"), 381 Groups: []string{"group1"}, 382 Active: Bool(true), 383 } 384 385 want := `{ 386 "userName": "userName1", 387 "name": { 388 "givenName": "Name1", 389 "familyName": "Fname", 390 "formatted": "formatted name" 391 }, 392 "displayName": "Name", 393 "emails": [{ 394 "value": "value", 395 "primary": false, 396 "type": "type" 397 }], 398 "schemas": ["schema1"], 399 "externalId": "id", 400 "groups": ["group1"], 401 "active": true 402 }` 403 404 testJSONMarshal(t, u, want) 405 } 406 407 func TestUpdateAttributeForSCIMUserOperations_Marshal(t *testing.T) { 408 testJSONMarshal(t, &UpdateAttributeForSCIMUserOperations{}, `{}`) 409 410 u := &UpdateAttributeForSCIMUserOperations{ 411 Op: "TestOp", 412 Path: String("path"), 413 } 414 415 want := `{ 416 "op": "TestOp", 417 "path": "path" 418 }` 419 420 testJSONMarshal(t, u, want) 421 } 422 423 func TestUpdateAttributeForSCIMUserOptions_Marshal(t *testing.T) { 424 testJSONMarshal(t, &UpdateAttributeForSCIMUserOptions{}, `{}`) 425 426 u := &UpdateAttributeForSCIMUserOptions{ 427 Schemas: []string{"test", "schema"}, 428 Operations: UpdateAttributeForSCIMUserOperations{ 429 Op: "TestOp", 430 Path: String("path"), 431 }, 432 } 433 434 want := `{ 435 "schemas": ["test", "schema"], 436 "operations": { 437 "op": "TestOp", 438 "path": "path" 439 } 440 }` 441 442 testJSONMarshal(t, u, want) 443 } 444 445 func TestListSCIMProvisionedIdentitiesOptions_addOptions(t *testing.T) { 446 testJSONMarshal(t, &ListSCIMProvisionedIdentitiesOptions{}, `{ 447 "StartIndex": null, 448 "Count": null, 449 "Filter": null 450 }`) 451 452 url := "some/path" 453 454 testAddURLOptions(t, url, &ListSCIMProvisionedIdentitiesOptions{}, url) 455 456 testAddURLOptions( 457 t, 458 url, 459 &ListSCIMProvisionedIdentitiesOptions{ 460 StartIndex: Int(1), 461 Count: Int(10), 462 }, 463 fmt.Sprintf("%s?count=10&startIndex=1", url), 464 ) 465 466 testAddURLOptions( 467 t, 468 url, 469 &ListSCIMProvisionedIdentitiesOptions{ 470 StartIndex: Int(1), 471 Count: Int(10), 472 Filter: String("test"), 473 }, 474 fmt.Sprintf("%s?count=10&filter=test&startIndex=1", url), 475 ) 476 } 477 478 func TestSCIMUserName_Marshal(t *testing.T) { 479 testJSONMarshal(t, &SCIMUserName{}, `{ 480 "givenName":"","familyName":"" 481 }`) 482 483 u := &SCIMUserName{ 484 GivenName: "Name1", 485 FamilyName: "Fname", 486 Formatted: String("formatted name"), 487 } 488 489 want := `{ 490 "givenName": "Name1", 491 "familyName": "Fname", 492 "formatted": "formatted name" 493 }` 494 testJSONMarshal(t, u, want) 495 } 496 497 func TestSCIMMeta_Marshal(t *testing.T) { 498 testJSONMarshal(t, &SCIMMeta{}, `{}`) 499 500 u := &SCIMMeta{ 501 ResourceType: String("test"), 502 Location: String("test"), 503 } 504 505 want := `{ 506 "resourceType": "test", 507 "location": "test" 508 }` 509 510 testJSONMarshal(t, u, want) 511 } 512 513 func TestSCIMProvisionedIdentities_Marshal(t *testing.T) { 514 testJSONMarshal(t, &SCIMProvisionedIdentities{}, `{}`) 515 516 u := &SCIMProvisionedIdentities{ 517 Schemas: []string{"test", "schema"}, 518 TotalResults: Int(1), 519 ItemsPerPage: Int(2), 520 StartIndex: Int(1), 521 Resources: []*SCIMUserAttributes{ 522 { 523 UserName: "SCIM", 524 Name: SCIMUserName{ 525 GivenName: "scim", 526 FamilyName: "test", 527 Formatted: String("SCIM"), 528 }, 529 DisplayName: String("Test SCIM"), 530 Emails: []*SCIMUserEmail{ 531 { 532 Value: "test", 533 Primary: Bool(true), 534 Type: String("test"), 535 }, 536 }, 537 Schemas: []string{"schema1"}, 538 ExternalID: String("id"), 539 Groups: []string{"group1"}, 540 Active: Bool(true), 541 }, 542 }, 543 } 544 545 want := `{ 546 "schemas": ["test", "schema"], 547 "totalResults": 1, 548 "itemsPerPage": 2, 549 "startIndex": 1, 550 "Resources": [{ 551 "userName": "SCIM", 552 "name": { 553 "givenName": "scim", 554 "familyName": "test", 555 "formatted": "SCIM" 556 }, 557 "displayName": "Test SCIM", 558 "emails": [{ 559 "value": "test", 560 "primary": true, 561 "type": "test" 562 }], 563 "schemas": ["schema1"], 564 "externalId": "id", 565 "groups": ["group1"], 566 "active": true 567 }] 568 }` 569 570 testJSONMarshal(t, u, want) 571 }