github.com/google/go-github/v74@v74.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_ListSCIMProvisionedGroups(t *testing.T) { 125 t.Parallel() 126 client, mux, _ := setup(t) 127 128 mux.HandleFunc("/scim/v2/enterprises/o/Groups", func(w http.ResponseWriter, r *http.Request) { 129 testMethod(t, r, "GET") 130 testFormValues(t, r, values{ 131 "startIndex": "1", 132 "excludedAttributes": "members,meta", 133 "count": "3", 134 "filter": `externalId eq "00u1dhhb1fkIGP7RL1d8"`, 135 }) 136 w.WriteHeader(http.StatusOK) 137 _, _ = w.Write([]byte(`{ 138 "schemas": [ 139 "urn:ietf:params:scim:api:messages:2.0:ListResponse" 140 ], 141 "totalResults": 1, 142 "itemsPerPage": 1, 143 "startIndex": 1, 144 "Resources": [ 145 { 146 "schemas": [ 147 "urn:ietf:params:scim:schemas:core:2.0:Group" 148 ], 149 "id": "123e4567-e89b-12d3-a456-426614174000", 150 "externalId": "00u1dhhb1fkIGP7RL1d8", 151 "displayName": "Mona Octocat", 152 "meta": { 153 "resourceType": "Group", 154 "created": "2018-02-13T15:05:24.000-00:00", 155 "lastModified": "2018-02-13T15:05:24.000-00:00", 156 "location": "https://api.github.com/scim/v2/enterprises/octo/Groups/123e4567-e89b-12d3-a456-426614174000" 157 }, 158 "members": [ 159 { 160 "value": "5fc0c238-1112-11e8-8e45-920c87bdbd75", 161 "$ref": "https://api.github.com/scim/v2/enterprises/octo/Users/5fc0c238-1112-11e8-8e45-920c87bdbd75", 162 "display": "Mona Octocat" 163 } 164 ] 165 } 166 ] 167 }`)) 168 }) 169 170 ctx := context.Background() 171 opts := &ListSCIMProvisionedGroupsForEnterpriseOptions{ 172 StartIndex: Ptr(1), 173 ExcludedAttributes: Ptr("members,meta"), 174 Count: Ptr(3), 175 Filter: Ptr(`externalId eq "00u1dhhb1fkIGP7RL1d8"`), 176 } 177 groups, _, err := client.SCIM.ListSCIMProvisionedGroupsForEnterprise(ctx, "o", opts) 178 if err != nil { 179 t.Errorf("SCIM.ListSCIMProvisionedIdentities returned error: %v", err) 180 } 181 182 date := Timestamp{time.Date(2018, time.February, 13, 15, 5, 24, 0, time.UTC)} 183 want := SCIMProvisionedGroups{ 184 Schemas: []string{"urn:ietf:params:scim:api:messages:2.0:ListResponse"}, 185 TotalResults: Ptr(1), 186 ItemsPerPage: Ptr(1), 187 StartIndex: Ptr(1), 188 Resources: []*SCIMGroupAttributes{ 189 { 190 ID: Ptr("123e4567-e89b-12d3-a456-426614174000"), 191 Meta: &SCIMMeta{ 192 ResourceType: Ptr("Group"), 193 Created: &date, 194 LastModified: &date, 195 Location: Ptr("https://api.github.com/scim/v2/enterprises/octo/Groups/123e4567-e89b-12d3-a456-426614174000"), 196 }, 197 198 DisplayName: Ptr("Mona Octocat"), 199 Schemas: []string{"urn:ietf:params:scim:schemas:core:2.0:Group"}, 200 ExternalID: Ptr("00u1dhhb1fkIGP7RL1d8"), 201 Members: []*SCIMDisplayReference{ 202 { 203 Value: "5fc0c238-1112-11e8-8e45-920c87bdbd75", 204 Ref: "https://api.github.com/scim/v2/enterprises/octo/Users/5fc0c238-1112-11e8-8e45-920c87bdbd75", 205 Display: Ptr("Mona Octocat"), 206 }, 207 }, 208 }, 209 }, 210 } 211 212 if !cmp.Equal(groups, &want) { 213 diff := cmp.Diff(groups, want) 214 t.Errorf("SCIM.ListSCIMProvisionedGroupsForEnterprise returned %+v, want %+v: diff %+v", groups, want, diff) 215 } 216 217 const methodName = "ListSCIMProvisionedGroupsForEnterprise" 218 testBadOptions(t, methodName, func() (err error) { 219 _, _, err = client.SCIM.ListSCIMProvisionedGroupsForEnterprise(ctx, "\n", opts) 220 return err 221 }) 222 223 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 224 _, r, err := client.SCIM.ListSCIMProvisionedGroupsForEnterprise(ctx, "o", opts) 225 return r, err 226 }) 227 } 228 229 func TestSCIMService_ProvisionAndInviteSCIMUser(t *testing.T) { 230 t.Parallel() 231 client, mux, _ := setup(t) 232 233 mux.HandleFunc("/scim/v2/organizations/o/Users", func(w http.ResponseWriter, r *http.Request) { 234 testMethod(t, r, "POST") 235 w.WriteHeader(http.StatusCreated) 236 fmt.Fprint(w, `{"id":"1234567890","userName":"userName"}`) 237 }) 238 239 ctx := context.Background() 240 opts := &SCIMUserAttributes{ 241 UserName: "userName", 242 Name: SCIMUserName{ 243 GivenName: "givenName", 244 FamilyName: "familyName", 245 }, 246 Emails: []*SCIMUserEmail{ 247 { 248 Value: "octocat@github.com", 249 }, 250 }, 251 } 252 user, _, err := client.SCIM.ProvisionAndInviteSCIMUser(ctx, "o", opts) 253 if err != nil { 254 t.Errorf("SCIM.ProvisionAndInviteSCIMUser returned error: %v", err) 255 } 256 257 want := &SCIMUserAttributes{ 258 ID: Ptr("1234567890"), 259 UserName: "userName", 260 } 261 if !cmp.Equal(user, want) { 262 t.Errorf("SCIM.ProvisionAndInviteSCIMUser returned %+v, want %+v", user, want) 263 } 264 265 const methodName = "ProvisionAndInviteSCIMUser" 266 testBadOptions(t, methodName, func() (err error) { 267 _, _, err = client.SCIM.ProvisionAndInviteSCIMUser(ctx, "\n", opts) 268 return err 269 }) 270 271 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 272 got, resp, err := client.SCIM.ProvisionAndInviteSCIMUser(ctx, "o", opts) 273 if got != nil { 274 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 275 } 276 return resp, err 277 }) 278 } 279 280 func TestSCIMService_GetSCIMProvisioningInfoForUser(t *testing.T) { 281 t.Parallel() 282 client, mux, _ := setup(t) 283 284 mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) { 285 testMethod(t, r, "GET") 286 w.WriteHeader(http.StatusOK) 287 _, _ = w.Write([]byte(`{ 288 "schemas": [ 289 "urn:ietf:params:scim:schemas:core:2.0:User" 290 ], 291 "id": "edefdfedf-050c-11e7-8d32", 292 "externalId": "a7d0f98382", 293 "userName": "mona.octocat@okta.example.com", 294 "displayName": "Mona Octocat", 295 "name": { 296 "givenName": "Mona", 297 "familyName": "Octocat", 298 "formatted": "Mona Octocat" 299 }, 300 "emails": [ 301 { 302 "value": "mona.octocat@okta.example.com", 303 "primary": true 304 }, 305 { 306 "value": "mona@octocat.github.com" 307 } 308 ], 309 "active": true, 310 "meta": { 311 "resourceType": "User", 312 "created": "2017-03-09T16:11:13-00:00", 313 "lastModified": "2017-03-09T16:11:13-00:00", 314 "location": "https://api.github.com/scim/v2/organizations/octo-org/Users/edefdfedf-050c-11e7-8d32" 315 } 316 }`)) 317 }) 318 319 ctx := context.Background() 320 user, _, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "o", "123") 321 if err != nil { 322 t.Errorf("SCIM.GetSCIMProvisioningInfoForUser returned error: %v", err) 323 } 324 325 date := Timestamp{time.Date(2017, time.March, 9, 16, 11, 13, 0, time.UTC)} 326 want := SCIMUserAttributes{ 327 ID: Ptr("edefdfedf-050c-11e7-8d32"), 328 Meta: &SCIMMeta{ 329 ResourceType: Ptr("User"), 330 Created: &date, 331 LastModified: &date, 332 Location: Ptr("https://api.github.com/scim/v2/organizations/octo-org/Users/edefdfedf-050c-11e7-8d32"), 333 }, 334 UserName: "mona.octocat@okta.example.com", 335 Name: SCIMUserName{ 336 GivenName: "Mona", 337 FamilyName: "Octocat", 338 Formatted: Ptr("Mona Octocat"), 339 }, 340 DisplayName: Ptr("Mona Octocat"), 341 Emails: []*SCIMUserEmail{ 342 { 343 Value: "mona.octocat@okta.example.com", 344 Primary: Ptr(true), 345 }, 346 { 347 Value: "mona@octocat.github.com", 348 }, 349 }, 350 Schemas: []string{"urn:ietf:params:scim:schemas:core:2.0:User"}, 351 ExternalID: Ptr("a7d0f98382"), 352 Groups: nil, 353 Active: Ptr(true), 354 } 355 356 if !cmp.Equal(user, &want) { 357 diff := cmp.Diff(user, want) 358 t.Errorf("SCIM.ListSCIMProvisionedIdentities returned %+v, want %+v: diff %+v", user, want, diff) 359 } 360 361 const methodName = "GetSCIMProvisioningInfoForUser" 362 testBadOptions(t, methodName, func() error { 363 _, _, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "\n", "123") 364 return err 365 }) 366 367 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 368 _, r, err := client.SCIM.GetSCIMProvisioningInfoForUser(ctx, "o", "123") 369 return r, err 370 }) 371 } 372 373 func TestSCIMService_UpdateProvisionedOrgMembership(t *testing.T) { 374 t.Parallel() 375 client, mux, _ := setup(t) 376 377 mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) { 378 testMethod(t, r, "PUT") 379 w.WriteHeader(http.StatusOK) 380 }) 381 382 ctx := context.Background() 383 opts := &SCIMUserAttributes{ 384 UserName: "userName", 385 Name: SCIMUserName{ 386 GivenName: "givenName", 387 FamilyName: "familyName", 388 }, 389 Emails: []*SCIMUserEmail{ 390 { 391 Value: "octocat@github.com", 392 }, 393 }, 394 } 395 _, err := client.SCIM.UpdateProvisionedOrgMembership(ctx, "o", "123", opts) 396 if err != nil { 397 t.Errorf("SCIM.UpdateProvisionedOrgMembership returned error: %v", err) 398 } 399 400 const methodName = "UpdateProvisionedOrgMembership" 401 testBadOptions(t, methodName, func() error { 402 _, err := client.SCIM.UpdateProvisionedOrgMembership(ctx, "\n", "123", opts) 403 return err 404 }) 405 406 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 407 return client.SCIM.UpdateProvisionedOrgMembership(ctx, "o", "123", opts) 408 }) 409 } 410 411 func TestSCIMService_UpdateAttributeForSCIMUser(t *testing.T) { 412 t.Parallel() 413 client, mux, _ := setup(t) 414 415 mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) { 416 testMethod(t, r, "PATCH") 417 w.WriteHeader(http.StatusNoContent) 418 }) 419 420 ctx := context.Background() 421 opts := &UpdateAttributeForSCIMUserOptions{} 422 _, err := client.SCIM.UpdateAttributeForSCIMUser(ctx, "o", "123", opts) 423 if err != nil { 424 t.Errorf("SCIM.UpdateAttributeForSCIMUser returned error: %v", err) 425 } 426 427 const methodName = "UpdateAttributeForSCIMUser" 428 testBadOptions(t, methodName, func() error { 429 _, err := client.SCIM.UpdateAttributeForSCIMUser(ctx, "\n", "123", opts) 430 return err 431 }) 432 433 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 434 return client.SCIM.UpdateAttributeForSCIMUser(ctx, "o", "123", opts) 435 }) 436 } 437 438 func TestSCIMService_DeleteSCIMUserFromOrg(t *testing.T) { 439 t.Parallel() 440 client, mux, _ := setup(t) 441 442 mux.HandleFunc("/scim/v2/organizations/o/Users/123", func(w http.ResponseWriter, r *http.Request) { 443 testMethod(t, r, "DELETE") 444 w.WriteHeader(http.StatusNoContent) 445 }) 446 447 ctx := context.Background() 448 _, err := client.SCIM.DeleteSCIMUserFromOrg(ctx, "o", "123") 449 if err != nil { 450 t.Errorf("SCIM.DeleteSCIMUserFromOrg returned error: %v", err) 451 } 452 453 const methodName = "DeleteSCIMUserFromOrg" 454 testBadOptions(t, methodName, func() error { 455 _, err := client.SCIM.DeleteSCIMUserFromOrg(ctx, "\n", "") 456 return err 457 }) 458 459 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 460 return client.SCIM.DeleteSCIMUserFromOrg(ctx, "o", "123") 461 }) 462 } 463 464 func TestSCIMUserAttributes_Marshal(t *testing.T) { 465 t.Parallel() 466 testJSONMarshal(t, &SCIMUserAttributes{}, `{ 467 "userName":"","name":{"givenName":"","familyName":""},"emails":null 468 }`) 469 470 u := &SCIMUserAttributes{ 471 UserName: "userName1", 472 Name: SCIMUserName{ 473 GivenName: "Name1", 474 FamilyName: "Fname", 475 Formatted: Ptr("formatted name"), 476 }, 477 DisplayName: Ptr("Name"), 478 Emails: []*SCIMUserEmail{ 479 { 480 Value: "value", 481 Primary: Ptr(false), 482 Type: Ptr("type"), 483 }, 484 }, 485 Schemas: []string{"schema1"}, 486 ExternalID: Ptr("id"), 487 Groups: []string{"group1"}, 488 Active: Ptr(true), 489 } 490 491 want := `{ 492 "userName": "userName1", 493 "name": { 494 "givenName": "Name1", 495 "familyName": "Fname", 496 "formatted": "formatted name" 497 }, 498 "displayName": "Name", 499 "emails": [{ 500 "value": "value", 501 "primary": false, 502 "type": "type" 503 }], 504 "schemas": ["schema1"], 505 "externalId": "id", 506 "groups": ["group1"], 507 "active": true 508 }` 509 510 testJSONMarshal(t, u, want) 511 } 512 513 func TestUpdateAttributeForSCIMUserOperations_Marshal(t *testing.T) { 514 t.Parallel() 515 testJSONMarshal(t, &UpdateAttributeForSCIMUserOperations{}, `{}`) 516 517 u := &UpdateAttributeForSCIMUserOperations{ 518 Op: "TestOp", 519 Path: Ptr("path"), 520 } 521 522 want := `{ 523 "op": "TestOp", 524 "path": "path" 525 }` 526 527 testJSONMarshal(t, u, want) 528 } 529 530 func TestUpdateAttributeForSCIMUserOptions_Marshal(t *testing.T) { 531 t.Parallel() 532 testJSONMarshal(t, &UpdateAttributeForSCIMUserOptions{}, `{}`) 533 534 u := &UpdateAttributeForSCIMUserOptions{ 535 Schemas: []string{"test", "schema"}, 536 Operations: UpdateAttributeForSCIMUserOperations{ 537 Op: "TestOp", 538 Path: Ptr("path"), 539 }, 540 } 541 542 want := `{ 543 "schemas": ["test", "schema"], 544 "operations": { 545 "op": "TestOp", 546 "path": "path" 547 } 548 }` 549 550 testJSONMarshal(t, u, want) 551 } 552 553 func TestListSCIMProvisionedIdentitiesOptions_addOptions(t *testing.T) { 554 t.Parallel() 555 testJSONMarshal(t, &ListSCIMProvisionedIdentitiesOptions{}, `{ 556 "StartIndex": null, 557 "Count": null, 558 "Filter": null 559 }`) 560 561 url := "some/path" 562 563 testAddURLOptions(t, url, &ListSCIMProvisionedIdentitiesOptions{}, url) 564 565 testAddURLOptions( 566 t, 567 url, 568 &ListSCIMProvisionedIdentitiesOptions{ 569 StartIndex: Ptr(1), 570 Count: Ptr(10), 571 }, 572 fmt.Sprintf("%s?count=10&startIndex=1", url), 573 ) 574 575 testAddURLOptions( 576 t, 577 url, 578 &ListSCIMProvisionedIdentitiesOptions{ 579 StartIndex: Ptr(1), 580 Count: Ptr(10), 581 Filter: Ptr("test"), 582 }, 583 fmt.Sprintf("%s?count=10&filter=test&startIndex=1", url), 584 ) 585 } 586 587 func TestSCIMUserName_Marshal(t *testing.T) { 588 t.Parallel() 589 testJSONMarshal(t, &SCIMUserName{}, `{ 590 "givenName":"","familyName":"" 591 }`) 592 593 u := &SCIMUserName{ 594 GivenName: "Name1", 595 FamilyName: "Fname", 596 Formatted: Ptr("formatted name"), 597 } 598 599 want := `{ 600 "givenName": "Name1", 601 "familyName": "Fname", 602 "formatted": "formatted name" 603 }` 604 testJSONMarshal(t, u, want) 605 } 606 607 func TestSCIMMeta_Marshal(t *testing.T) { 608 t.Parallel() 609 testJSONMarshal(t, &SCIMMeta{}, `{}`) 610 611 u := &SCIMMeta{ 612 ResourceType: Ptr("test"), 613 Location: Ptr("test"), 614 } 615 616 want := `{ 617 "resourceType": "test", 618 "location": "test" 619 }` 620 621 testJSONMarshal(t, u, want) 622 } 623 624 func TestSCIMProvisionedIdentities_Marshal(t *testing.T) { 625 t.Parallel() 626 testJSONMarshal(t, &SCIMProvisionedIdentities{}, `{}`) 627 628 u := &SCIMProvisionedIdentities{ 629 Schemas: []string{"test", "schema"}, 630 TotalResults: Ptr(1), 631 ItemsPerPage: Ptr(2), 632 StartIndex: Ptr(1), 633 Resources: []*SCIMUserAttributes{ 634 { 635 UserName: "SCIM", 636 Name: SCIMUserName{ 637 GivenName: "scim", 638 FamilyName: "test", 639 Formatted: Ptr("SCIM"), 640 }, 641 DisplayName: Ptr("Test SCIM"), 642 Emails: []*SCIMUserEmail{ 643 { 644 Value: "test", 645 Primary: Ptr(true), 646 Type: Ptr("test"), 647 }, 648 }, 649 Schemas: []string{"schema1"}, 650 ExternalID: Ptr("id"), 651 Groups: []string{"group1"}, 652 Active: Ptr(true), 653 }, 654 }, 655 } 656 657 want := `{ 658 "schemas": ["test", "schema"], 659 "totalResults": 1, 660 "itemsPerPage": 2, 661 "startIndex": 1, 662 "Resources": [{ 663 "userName": "SCIM", 664 "name": { 665 "givenName": "scim", 666 "familyName": "test", 667 "formatted": "SCIM" 668 }, 669 "displayName": "Test SCIM", 670 "emails": [{ 671 "value": "test", 672 "primary": true, 673 "type": "test" 674 }], 675 "schemas": ["schema1"], 676 "externalId": "id", 677 "groups": ["group1"], 678 "active": true 679 }] 680 }` 681 682 testJSONMarshal(t, u, want) 683 }