github.com/google/go-github/v64@v64.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.StatusOK) 131 }) 132 133 ctx := context.Background() 134 opts := &SCIMUserAttributes{ 135 UserName: "userName", 136 Name: SCIMUserName{ 137 GivenName: "givenName", 138 FamilyName: "familyName", 139 }, 140 Emails: []*SCIMUserEmail{ 141 { 142 Value: "octocat@github.com", 143 }, 144 }, 145 } 146 _, err := client.SCIM.ProvisionAndInviteSCIMUser(ctx, "o", opts) 147 if err != nil { 148 t.Errorf("SCIM.ListSCIMProvisionedIdentities returned error: %v", err) 149 } 150 151 const methodName = "ProvisionAndInviteSCIMUser" 152 testBadOptions(t, methodName, func() (err error) { 153 _, err = client.SCIM.ProvisionAndInviteSCIMUser(ctx, "\n", opts) 154 return err 155 }) 156 157 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 158 return client.SCIM.ProvisionAndInviteSCIMUser(ctx, "o", opts) 159 }) 160 } 161 162 func TestSCIMService_GetSCIMProvisioningInfoForUser(t *testing.T) { 163 client, mux, _, teardown := setup() 164 defer teardown() 165 166 mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) { 167 testMethod(t, r, "GET") 168 w.WriteHeader(http.StatusOK) 169 _, _ = w.Write([]byte(`{ 170 "schemas": [ 171 "urn:ietf:params:scim:schemas:core:2.0:User" 172 ], 173 "id": "edefdfedf-050c-11e7-8d32", 174 "externalId": "a7d0f98382", 175 "userName": "mona.octocat@okta.example.com", 176 "displayName": "Mona Octocat", 177 "name": { 178 "givenName": "Mona", 179 "familyName": "Octocat", 180 "formatted": "Mona Octocat" 181 }, 182 "emails": [ 183 { 184 "value": "mona.octocat@okta.example.com", 185 "primary": true 186 }, 187 { 188 "value": "mona@octocat.github.com" 189 } 190 ], 191 "active": true, 192 "meta": { 193 "resourceType": "User", 194 "created": "2017-03-09T16:11:13-00:00", 195 "lastModified": "2017-03-09T16:11:13-00:00", 196 "location": "https://api.github.com/scim/v2/organizations/octo-org/Users/edefdfedf-050c-11e7-8d32" 197 } 198 }`)) 199 }) 200 201 ctx := context.Background() 202 user, _, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "o", "123") 203 if err != nil { 204 t.Errorf("SCIM.GetSCIMProvisioningInfoForUser returned error: %v", err) 205 } 206 207 date := Timestamp{time.Date(2017, time.March, 9, 16, 11, 13, 0, time.UTC)} 208 want := SCIMUserAttributes{ 209 ID: String("edefdfedf-050c-11e7-8d32"), 210 Meta: &SCIMMeta{ 211 ResourceType: String("User"), 212 Created: &date, 213 LastModified: &date, 214 Location: String("https://api.github.com/scim/v2/organizations/octo-org/Users/edefdfedf-050c-11e7-8d32"), 215 }, 216 UserName: "mona.octocat@okta.example.com", 217 Name: SCIMUserName{ 218 GivenName: "Mona", 219 FamilyName: "Octocat", 220 Formatted: String("Mona Octocat"), 221 }, 222 DisplayName: String("Mona Octocat"), 223 Emails: []*SCIMUserEmail{ 224 { 225 Value: "mona.octocat@okta.example.com", 226 Primary: Bool(true), 227 }, 228 { 229 Value: "mona@octocat.github.com", 230 }, 231 }, 232 Schemas: []string{"urn:ietf:params:scim:schemas:core:2.0:User"}, 233 ExternalID: String("a7d0f98382"), 234 Groups: nil, 235 Active: Bool(true), 236 } 237 238 if !cmp.Equal(user, &want) { 239 diff := cmp.Diff(user, want) 240 t.Errorf("SCIM.ListSCIMProvisionedIdentities returned %+v, want %+v: diff %+v", user, want, diff) 241 } 242 243 const methodName = "GetSCIMProvisioningInfoForUser" 244 testBadOptions(t, methodName, func() error { 245 _, _, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "\n", "123") 246 return err 247 }) 248 249 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 250 _, r, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "o", "123") 251 return r, err 252 }) 253 } 254 255 func TestSCIMService_UpdateProvisionedOrgMembership(t *testing.T) { 256 client, mux, _, teardown := setup() 257 defer teardown() 258 259 mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) { 260 testMethod(t, r, "PUT") 261 w.WriteHeader(http.StatusOK) 262 }) 263 264 ctx := context.Background() 265 opts := &SCIMUserAttributes{ 266 UserName: "userName", 267 Name: SCIMUserName{ 268 GivenName: "givenName", 269 FamilyName: "familyName", 270 }, 271 Emails: []*SCIMUserEmail{ 272 { 273 Value: "octocat@github.com", 274 }, 275 }, 276 } 277 _, err := client.SCIM.UpdateProvisionedOrgMembership(ctx, "o", "123", opts) 278 if err != nil { 279 t.Errorf("SCIM.UpdateProvisionedOrgMembership returned error: %v", err) 280 } 281 282 const methodName = "UpdateProvisionedOrgMembership" 283 testBadOptions(t, methodName, func() error { 284 _, err := client.SCIM.UpdateProvisionedOrgMembership(ctx, "\n", "123", opts) 285 return err 286 }) 287 288 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 289 return client.SCIM.UpdateProvisionedOrgMembership(ctx, "o", "123", opts) 290 }) 291 } 292 293 func TestSCIMService_UpdateAttributeForSCIMUser(t *testing.T) { 294 client, mux, _, teardown := setup() 295 defer teardown() 296 297 mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) { 298 testMethod(t, r, "PATCH") 299 w.WriteHeader(http.StatusNoContent) 300 }) 301 302 ctx := context.Background() 303 opts := &UpdateAttributeForSCIMUserOptions{} 304 _, err := client.SCIM.UpdateAttributeForSCIMUser(ctx, "o", "123", opts) 305 if err != nil { 306 t.Errorf("SCIM.UpdateAttributeForSCIMUser returned error: %v", err) 307 } 308 309 const methodName = "UpdateAttributeForSCIMUser" 310 testBadOptions(t, methodName, func() error { 311 _, err := client.SCIM.UpdateAttributeForSCIMUser(ctx, "\n", "123", opts) 312 return err 313 }) 314 315 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 316 return client.SCIM.UpdateAttributeForSCIMUser(ctx, "o", "123", opts) 317 }) 318 } 319 320 func TestSCIMService_DeleteSCIMUserFromOrg(t *testing.T) { 321 client, mux, _, teardown := setup() 322 defer teardown() 323 324 mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) { 325 testMethod(t, r, "DELETE") 326 w.WriteHeader(http.StatusNoContent) 327 }) 328 329 ctx := context.Background() 330 _, err := client.SCIM.DeleteSCIMUserFromOrg(ctx, "o", "123") 331 if err != nil { 332 t.Errorf("SCIM.DeleteSCIMUserFromOrg returned error: %v", err) 333 } 334 335 const methodName = "DeleteSCIMUserFromOrg" 336 testBadOptions(t, methodName, func() error { 337 _, err := client.SCIM.DeleteSCIMUserFromOrg(ctx, "\n", "") 338 return err 339 }) 340 341 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 342 return client.SCIM.DeleteSCIMUserFromOrg(ctx, "o", "123") 343 }) 344 } 345 346 func TestSCIMUserAttributes_Marshal(t *testing.T) { 347 testJSONMarshal(t, &SCIMUserAttributes{}, `{ 348 "userName":"","name":{"givenName":"","familyName":""},"emails":null 349 }`) 350 351 u := &SCIMUserAttributes{ 352 UserName: "userName1", 353 Name: SCIMUserName{ 354 GivenName: "Name1", 355 FamilyName: "Fname", 356 Formatted: String("formatted name"), 357 }, 358 DisplayName: String("Name"), 359 Emails: []*SCIMUserEmail{ 360 { 361 Value: "value", 362 Primary: Bool(false), 363 Type: String("type"), 364 }, 365 }, 366 Schemas: []string{"schema1"}, 367 ExternalID: String("id"), 368 Groups: []string{"group1"}, 369 Active: Bool(true), 370 } 371 372 want := `{ 373 "userName": "userName1", 374 "name": { 375 "givenName": "Name1", 376 "familyName": "Fname", 377 "formatted": "formatted name" 378 }, 379 "displayName": "Name", 380 "emails": [{ 381 "value": "value", 382 "primary": false, 383 "type": "type" 384 }], 385 "schemas": ["schema1"], 386 "externalId": "id", 387 "groups": ["group1"], 388 "active": true 389 }` 390 391 testJSONMarshal(t, u, want) 392 } 393 394 func TestUpdateAttributeForSCIMUserOperations_Marshal(t *testing.T) { 395 testJSONMarshal(t, &UpdateAttributeForSCIMUserOperations{}, `{}`) 396 397 u := &UpdateAttributeForSCIMUserOperations{ 398 Op: "TestOp", 399 Path: String("path"), 400 } 401 402 want := `{ 403 "op": "TestOp", 404 "path": "path" 405 }` 406 407 testJSONMarshal(t, u, want) 408 } 409 410 func TestUpdateAttributeForSCIMUserOptions_Marshal(t *testing.T) { 411 testJSONMarshal(t, &UpdateAttributeForSCIMUserOptions{}, `{}`) 412 413 u := &UpdateAttributeForSCIMUserOptions{ 414 Schemas: []string{"test", "schema"}, 415 Operations: UpdateAttributeForSCIMUserOperations{ 416 Op: "TestOp", 417 Path: String("path"), 418 }, 419 } 420 421 want := `{ 422 "schemas": ["test", "schema"], 423 "operations": { 424 "op": "TestOp", 425 "path": "path" 426 } 427 }` 428 429 testJSONMarshal(t, u, want) 430 } 431 432 func TestListSCIMProvisionedIdentitiesOptions_addOptions(t *testing.T) { 433 testJSONMarshal(t, &ListSCIMProvisionedIdentitiesOptions{}, `{ 434 "StartIndex": null, 435 "Count": null, 436 "Filter": null 437 }`) 438 439 url := "some/path" 440 441 testAddURLOptions(t, url, &ListSCIMProvisionedIdentitiesOptions{}, url) 442 443 testAddURLOptions( 444 t, 445 url, 446 &ListSCIMProvisionedIdentitiesOptions{ 447 StartIndex: Int(1), 448 Count: Int(10), 449 }, 450 fmt.Sprintf("%s?count=10&startIndex=1", url), 451 ) 452 453 testAddURLOptions( 454 t, 455 url, 456 &ListSCIMProvisionedIdentitiesOptions{ 457 StartIndex: Int(1), 458 Count: Int(10), 459 Filter: String("test"), 460 }, 461 fmt.Sprintf("%s?count=10&filter=test&startIndex=1", url), 462 ) 463 } 464 465 func TestSCIMUserName_Marshal(t *testing.T) { 466 testJSONMarshal(t, &SCIMUserName{}, `{ 467 "givenName":"","familyName":"" 468 }`) 469 470 u := &SCIMUserName{ 471 GivenName: "Name1", 472 FamilyName: "Fname", 473 Formatted: String("formatted name"), 474 } 475 476 want := `{ 477 "givenName": "Name1", 478 "familyName": "Fname", 479 "formatted": "formatted name" 480 }` 481 testJSONMarshal(t, u, want) 482 } 483 484 func TestSCIMMeta_Marshal(t *testing.T) { 485 testJSONMarshal(t, &SCIMMeta{}, `{}`) 486 487 u := &SCIMMeta{ 488 ResourceType: String("test"), 489 Location: String("test"), 490 } 491 492 want := `{ 493 "resourceType": "test", 494 "location": "test" 495 }` 496 497 testJSONMarshal(t, u, want) 498 } 499 500 func TestSCIMProvisionedIdentities_Marshal(t *testing.T) { 501 testJSONMarshal(t, &SCIMProvisionedIdentities{}, `{}`) 502 503 u := &SCIMProvisionedIdentities{ 504 Schemas: []string{"test", "schema"}, 505 TotalResults: Int(1), 506 ItemsPerPage: Int(2), 507 StartIndex: Int(1), 508 Resources: []*SCIMUserAttributes{ 509 { 510 UserName: "SCIM", 511 Name: SCIMUserName{ 512 GivenName: "scim", 513 FamilyName: "test", 514 Formatted: String("SCIM"), 515 }, 516 DisplayName: String("Test SCIM"), 517 Emails: []*SCIMUserEmail{ 518 { 519 Value: "test", 520 Primary: Bool(true), 521 Type: String("test"), 522 }, 523 }, 524 Schemas: []string{"schema1"}, 525 ExternalID: String("id"), 526 Groups: []string{"group1"}, 527 Active: Bool(true), 528 }, 529 }, 530 } 531 532 want := `{ 533 "schemas": ["test", "schema"], 534 "totalResults": 1, 535 "itemsPerPage": 2, 536 "startIndex": 1, 537 "Resources": [{ 538 "userName": "SCIM", 539 "name": { 540 "givenName": "scim", 541 "familyName": "test", 542 "formatted": "SCIM" 543 }, 544 "displayName": "Test SCIM", 545 "emails": [{ 546 "value": "test", 547 "primary": true, 548 "type": "test" 549 }], 550 "schemas": ["schema1"], 551 "externalId": "id", 552 "groups": ["group1"], 553 "active": true 554 }] 555 }` 556 557 testJSONMarshal(t, u, want) 558 }