From b700c791b13196b065f6a1cbec1c4b63214bb1e2 Mon Sep 17 00:00:00 2001 From: Weinan Qiu Date: Mon, 29 Jun 2020 14:45:21 +0800 Subject: [PATCH] fix(pkg, cmd): Fix bug where compiling a path to schema extension fields fails Compilation to schema extension field paths fail because we didn't call crud.Register for the respective resource type during initialization. This was fixed now in the context setup, and various tests involving parsing of the resource type also got everything correctly registered. Closes 72 --- cmd/api/context.go | 3 ++ pkg/v2/crud/crud_test.go | 39 +++++++++++++++++- pkg/v2/groupsync/sync_test.go | 10 +++++ pkg/v2/json/adapt_test.go | 19 ++++++++- pkg/v2/service/create_test.go | 9 +++++ pkg/v2/service/delete_test.go | 9 +++++ pkg/v2/service/filter/meta_test.go | 9 +++++ pkg/v2/service/get_test.go | 9 +++++ pkg/v2/service/patch_test.go | 63 ++++++++++++++++++++++++++++++ pkg/v2/service/query_test.go | 8 ++++ pkg/v2/service/replace_test.go | 9 +++++ 11 files changed, 185 insertions(+), 2 deletions(-) diff --git a/cmd/api/context.go b/cmd/api/context.go index abe3fe00..69816f97 100644 --- a/cmd/api/context.go +++ b/cmd/api/context.go @@ -4,6 +4,7 @@ import ( "context" "github.com/imulab/go-scim/cmd/internal/groupsync" scimmongo "github.com/imulab/go-scim/mongo/v2" + "github.com/imulab/go-scim/pkg/v2/crud" "github.com/imulab/go-scim/pkg/v2/db" "github.com/imulab/go-scim/pkg/v2/service" "github.com/imulab/go-scim/pkg/v2/service/filter" @@ -73,6 +74,7 @@ func (ctx *applicationContext) UserResourceType() *spec.ResourceType { panic(err) } ctx.userResourceType = u + crud.Register(ctx.userResourceType) ctx.logInitialized("user resource type") } return ctx.userResourceType @@ -87,6 +89,7 @@ func (ctx *applicationContext) GroupResourceType() *spec.ResourceType { panic(err) } ctx.groupResourceType = g + crud.Register(ctx.groupResourceType) ctx.logInitialized("group resource type") } return ctx.groupResourceType diff --git a/pkg/v2/crud/crud_test.go b/pkg/v2/crud/crud_test.go index 23c64b50..48ea87d9 100644 --- a/pkg/v2/crud/crud_test.go +++ b/pkg/v2/crud/crud_test.go @@ -159,6 +159,18 @@ func (s *CrudTestSuite) TestAdd() { }, r.Navigator().Dot("emails").Current().Raw()) }, }, + { + name: "add to an extension schema field", + getResource: func(t *testing.T) *prop.Resource { + return prop.NewResource(s.resourceType) + }, + path: "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeNumber", + value: "6546579", + expect: func(t *testing.T, r *prop.Resource, err error) { + assert.Nil(t, err) + assert.Equal(t, "6546579", r.Navigator().Dot("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User").Dot("employeeNumber").Current().Raw()) + }, + }, } for _, test := range tests { @@ -460,6 +472,10 @@ func (s *CrudTestSuite) SetupSuite() { require.Nil(s.T(), json.Unmarshal([]byte(testMainSchema), schema)) spec.Schemas().Register(schema) + schemaExtension := new(spec.Schema) + require.Nil(s.T(), json.Unmarshal([]byte(testSchemaExtension), schemaExtension)) + spec.Schemas().Register(schemaExtension) + s.resourceType = new(spec.ResourceType) require.Nil(s.T(), json.Unmarshal([]byte(testResourceType), s.resourceType)) Register(s.resourceType) @@ -562,12 +578,33 @@ const ( } ] } +` + testSchemaExtension = ` +{ + "id": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", + "name": "Enterprise User", + "attributes": [ + { + "id": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeNumber", + "name": "employeeNumber", + "type": "string", + "_index": 100, + "_path": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeNumber" + } + ] +} ` testResourceType = ` { "id": "Test", "name": "Test", - "schema": "main" + "schema": "main", + "schemaExtensions": [ + { + "schema": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", + "required": false + } + ] } ` ) diff --git a/pkg/v2/groupsync/sync_test.go b/pkg/v2/groupsync/sync_test.go index 54725f80..cb84c433 100644 --- a/pkg/v2/groupsync/sync_test.go +++ b/pkg/v2/groupsync/sync_test.go @@ -3,6 +3,7 @@ package groupsync import ( "context" "encoding/json" + "github.com/imulab/go-scim/pkg/v2/crud" "github.com/imulab/go-scim/pkg/v2/db" "github.com/imulab/go-scim/pkg/v2/prop" "github.com/imulab/go-scim/pkg/v2/spec" @@ -136,6 +137,13 @@ func (s *SyncServiceTestSuite) SetupSuite() { spec.Schemas().Register(parsed.(*spec.Schema)) }, }, + { + filepath: "../../../public/schemas/user_enterprise_extension_schema.json", + structure: new(spec.Schema), + post: func(parsed interface{}) { + spec.Schemas().Register(parsed.(*spec.Schema)) + }, + }, { filepath: "../../../public/schemas/group_schema.json", structure: new(spec.Schema), @@ -148,6 +156,7 @@ func (s *SyncServiceTestSuite) SetupSuite() { structure: new(spec.ResourceType), post: func(parsed interface{}) { s.userResourceType = parsed.(*spec.ResourceType) + crud.Register(s.userResourceType) }, }, { @@ -155,6 +164,7 @@ func (s *SyncServiceTestSuite) SetupSuite() { structure: new(spec.ResourceType), post: func(parsed interface{}) { s.groupResourceType = parsed.(*spec.ResourceType) + crud.Register(s.groupResourceType) }, }, } { diff --git a/pkg/v2/json/adapt_test.go b/pkg/v2/json/adapt_test.go index 80405172..4f89208d 100644 --- a/pkg/v2/json/adapt_test.go +++ b/pkg/v2/json/adapt_test.go @@ -2,6 +2,7 @@ package json import ( "encoding/json" + "github.com/imulab/go-scim/pkg/v2/crud" "github.com/imulab/go-scim/pkg/v2/spec" "github.com/stretchr/testify/assert" "os" @@ -17,6 +18,14 @@ func TestResourceTypeToSerializable(t *testing.T) { assert.Nil(t, err) spec.Schemas().Register(sch) + f, err = os.Open("../../../public/schemas/user_enterprise_extension_schema.json") + assert.Nil(t, err) + + schExt := new(spec.Schema) + err = json.NewDecoder(f).Decode(schExt) + assert.Nil(t, err) + spec.Schemas().Register(schExt) + f, err = os.Open("../../../public/resource_types/user_resource_type.json") assert.Nil(t, err) @@ -24,6 +33,8 @@ func TestResourceTypeToSerializable(t *testing.T) { err = json.NewDecoder(f).Decode(rt) assert.Nil(t, err) + crud.Register(rt) + raw, err := Serialize(ResourceTypeToSerializable(rt)) assert.Nil(t, err) @@ -39,7 +50,13 @@ func TestResourceTypeToSerializable(t *testing.T) { }, "name": "User", "endpoint": "/Users", - "schema": "urn:ietf:params:scim:schemas:core:2.0:User" + "schema": "urn:ietf:params:scim:schemas:core:2.0:User", + "schemaExtensions": [ + { + "schema": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", + "required": false + } + ] } ` diff --git a/pkg/v2/service/create_test.go b/pkg/v2/service/create_test.go index 5807c077..ca2f0bc0 100644 --- a/pkg/v2/service/create_test.go +++ b/pkg/v2/service/create_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "github.com/imulab/go-scim/pkg/v2/crud" "github.com/imulab/go-scim/pkg/v2/db" "github.com/imulab/go-scim/pkg/v2/prop" "github.com/imulab/go-scim/pkg/v2/service/filter" @@ -182,11 +183,19 @@ func (s *CreateServiceTestSuite) SetupSuite() { spec.Schemas().Register(parsed.(*spec.Schema)) }, }, + { + filepath: "../../../public/schemas/user_enterprise_extension_schema.json", + structure: new(spec.Schema), + post: func(parsed interface{}) { + spec.Schemas().Register(parsed.(*spec.Schema)) + }, + }, { filepath: "../../../public/resource_types/user_resource_type.json", structure: new(spec.ResourceType), post: func(parsed interface{}) { s.resourceType = parsed.(*spec.ResourceType) + crud.Register(s.resourceType) }, }, } { diff --git a/pkg/v2/service/delete_test.go b/pkg/v2/service/delete_test.go index 8c5e153b..f184e7e3 100644 --- a/pkg/v2/service/delete_test.go +++ b/pkg/v2/service/delete_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "github.com/imulab/go-scim/pkg/v2/crud" "github.com/imulab/go-scim/pkg/v2/db" "github.com/imulab/go-scim/pkg/v2/prop" "github.com/imulab/go-scim/pkg/v2/spec" @@ -103,11 +104,19 @@ func (s *DeleteServiceTestSuite) SetupSuite() { spec.Schemas().Register(parsed.(*spec.Schema)) }, }, + { + filepath: "../../../public/schemas/user_enterprise_extension_schema.json", + structure: new(spec.Schema), + post: func(parsed interface{}) { + spec.Schemas().Register(parsed.(*spec.Schema)) + }, + }, { filepath: "../../../public/resource_types/user_resource_type.json", structure: new(spec.ResourceType), post: func(parsed interface{}) { s.resourceType = parsed.(*spec.ResourceType) + crud.Register(s.resourceType) }, }, } { diff --git a/pkg/v2/service/filter/meta_test.go b/pkg/v2/service/filter/meta_test.go index 6bffd45e..77c45cd7 100644 --- a/pkg/v2/service/filter/meta_test.go +++ b/pkg/v2/service/filter/meta_test.go @@ -3,6 +3,7 @@ package filter import ( "context" "encoding/json" + "github.com/imulab/go-scim/pkg/v2/crud" "github.com/imulab/go-scim/pkg/v2/prop" "github.com/imulab/go-scim/pkg/v2/spec" "github.com/stretchr/testify/assert" @@ -186,11 +187,19 @@ func (s *MetaFilterTestSuite) SetupSuite() { spec.Schemas().Register(parsed.(*spec.Schema)) }, }, + { + filepath: "../../../../public/schemas/user_enterprise_extension_schema.json", + structure: new(spec.Schema), + post: func(parsed interface{}) { + spec.Schemas().Register(parsed.(*spec.Schema)) + }, + }, { filepath: "../../../../public/resource_types/user_resource_type.json", structure: new(spec.ResourceType), post: func(parsed interface{}) { s.resourceType = parsed.(*spec.ResourceType) + crud.Register(s.resourceType) }, }, } { diff --git a/pkg/v2/service/get_test.go b/pkg/v2/service/get_test.go index 30aad3da..c62562f3 100644 --- a/pkg/v2/service/get_test.go +++ b/pkg/v2/service/get_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "github.com/imulab/go-scim/pkg/v2/crud" "github.com/imulab/go-scim/pkg/v2/db" "github.com/imulab/go-scim/pkg/v2/prop" "github.com/imulab/go-scim/pkg/v2/spec" @@ -104,11 +105,19 @@ func (s *GetServiceTestSuite) SetupSuite() { spec.Schemas().Register(parsed.(*spec.Schema)) }, }, + { + filepath: "../../../public/schemas/user_enterprise_extension_schema.json", + structure: new(spec.Schema), + post: func(parsed interface{}) { + spec.Schemas().Register(parsed.(*spec.Schema)) + }, + }, { filepath: "../../../public/resource_types/user_resource_type.json", structure: new(spec.ResourceType), post: func(parsed interface{}) { s.resourceType = parsed.(*spec.ResourceType) + crud.Register(s.resourceType) }, }, } { diff --git a/pkg/v2/service/patch_test.go b/pkg/v2/service/patch_test.go index ae5bbb56..22ee09d7 100644 --- a/pkg/v2/service/patch_test.go +++ b/pkg/v2/service/patch_test.go @@ -3,6 +3,7 @@ package service import ( "context" "encoding/json" + "github.com/imulab/go-scim/pkg/v2/crud" "github.com/imulab/go-scim/pkg/v2/db" "github.com/imulab/go-scim/pkg/v2/prop" "github.com/imulab/go-scim/pkg/v2/service/filter" @@ -262,6 +263,60 @@ func (s *PatchServiceTestSuite) TestDo() { )) }, }, + { + name: "patch a field in the schema extension", + setup: func(t *testing.T) Patch { + database := db.Memory() + err := database.Insert(context.TODO(), s.resourceOf(t, map[string]interface{}{ + "schemas": []interface{}{ + "urn:ietf:params:scim:schemas:core:2.0:User", + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", + }, + "id": "foo", + "userName": "foo", + "emails": []interface{}{ + map[string]interface{}{ + "value": "foo@bar.com", + "type": "home", + }, + }, + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": map[string]interface{}{ + "employeeNumber": "1234567", + }, + })) + require.Nil(t, err) + return PatchService(s.config, database, nil, []filter.ByResource{ + filter.ByPropertyToByResource( + filter.ReadOnlyFilter(), + filter.BCryptFilter(), + ), + filter.ByPropertyToByResource(filter.ValidationFilter(database)), + filter.MetaFilter(), + }) + }, + getRequest: func() *PatchRequest { + return &PatchRequest{ + ResourceID: "foo", + PayloadSource: strings.NewReader(` + { + "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], + "Operations": [ + { + "op": "add", + "path": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeNumber", + "value": "6546579" + } + ] + } + `), + } + }, + expect: func(t *testing.T, resp *PatchResponse, err error) { + assert.Nil(t, err) + assert.True(t, resp.Patched) + assert.Equal(t, "6546579", resp.Resource.Navigator().Dot("urn:ietf:params:scim:schemas:extension:enterprise:2.0:User").Dot("employeeNumber").Current().Raw()) + }, + }, } for _, test := range tests { @@ -299,11 +354,19 @@ func (s *PatchServiceTestSuite) SetupSuite() { spec.Schemas().Register(parsed.(*spec.Schema)) }, }, + { + filepath: "../../../public/schemas/user_enterprise_extension_schema.json", + structure: new(spec.Schema), + post: func(parsed interface{}) { + spec.Schemas().Register(parsed.(*spec.Schema)) + }, + }, { filepath: "../../../public/resource_types/user_resource_type.json", structure: new(spec.ResourceType), post: func(parsed interface{}) { s.resourceType = parsed.(*spec.ResourceType) + crud.Register(s.resourceType) }, }, } { diff --git a/pkg/v2/service/query_test.go b/pkg/v2/service/query_test.go index 7b83d20e..51d2b4e4 100644 --- a/pkg/v2/service/query_test.go +++ b/pkg/v2/service/query_test.go @@ -197,11 +197,19 @@ func (s *QueryServiceTestSuite) SetupSuite() { spec.Schemas().Register(parsed.(*spec.Schema)) }, }, + { + filepath: "../../../public/schemas/user_enterprise_extension_schema.json", + structure: new(spec.Schema), + post: func(parsed interface{}) { + spec.Schemas().Register(parsed.(*spec.Schema)) + }, + }, { filepath: "../../../public/resource_types/user_resource_type.json", structure: new(spec.ResourceType), post: func(parsed interface{}) { s.resourceType = parsed.(*spec.ResourceType) + crud.Register(s.resourceType) }, }, } { diff --git a/pkg/v2/service/replace_test.go b/pkg/v2/service/replace_test.go index 4c4b5825..03f6d249 100644 --- a/pkg/v2/service/replace_test.go +++ b/pkg/v2/service/replace_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "github.com/imulab/go-scim/pkg/v2/crud" "github.com/imulab/go-scim/pkg/v2/db" "github.com/imulab/go-scim/pkg/v2/prop" "github.com/imulab/go-scim/pkg/v2/service/filter" @@ -209,11 +210,19 @@ func (s *ReplaceServiceTestSuite) SetupSuite() { spec.Schemas().Register(parsed.(*spec.Schema)) }, }, + { + filepath: "../../../public/schemas/user_enterprise_extension_schema.json", + structure: new(spec.Schema), + post: func(parsed interface{}) { + spec.Schemas().Register(parsed.(*spec.Schema)) + }, + }, { filepath: "../../../public/resource_types/user_resource_type.json", structure: new(spec.ResourceType), post: func(parsed interface{}) { s.resourceType = parsed.(*spec.ResourceType) + crud.Register(s.resourceType) }, }, } {