From a87d9236d86d2c314f2e9c07ea746c6879ad4197 Mon Sep 17 00:00:00 2001 From: quobix Date: Wed, 25 Oct 2023 08:09:33 -0400 Subject: [PATCH] bumping test coverage more to go, more cleaning inbound also Signed-off-by: quobix --- datamodel/low/serializing.go | 4 -- index/extract_refs.go | 2 +- index/find_component.go | 12 ++-- index/find_component_test.go | 84 +++++++++++++++++++++++++ index/resolver.go | 51 +++++---------- index/resolver_test.go | 109 +++++++++++++++++++++++++++++++++ index/rolodex.go | 2 + index/rolodex_remote_loader.go | 5 -- index/rolodex_test.go | 17 +++++ index/search_index.go | 2 +- index/spec_index_test.go | 8 +-- 11 files changed, 238 insertions(+), 58 deletions(-) delete mode 100644 datamodel/low/serializing.go diff --git a/datamodel/low/serializing.go b/datamodel/low/serializing.go deleted file mode 100644 index e58d4df6..00000000 --- a/datamodel/low/serializing.go +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley -// SPDX-License-Identifier: MIT - -package low diff --git a/index/extract_refs.go b/index/extract_refs.go index 5d38a50d..a5b68dcd 100644 --- a/index/extract_refs.go +++ b/index/extract_refs.go @@ -556,7 +556,7 @@ func (index *SpecIndex) ExtractComponentsFromRefs(refs []*Reference) []*Referenc c := make(chan bool) locate := func(ref *Reference, refIndex int, sequence []*ReferenceMapped) { - located := index.FindComponent(ref.FullDefinition, ref.Node) + located := index.FindComponent(ref.FullDefinition) if located != nil { index.refLock.Lock() diff --git a/index/find_component.go b/index/find_component.go index b5dbf4a8..83e795f3 100644 --- a/index/find_component.go +++ b/index/find_component.go @@ -17,7 +17,7 @@ import ( // FindComponent will locate a component by its reference, returns nil if nothing is found. // This method will recurse through remote, local and file references. For each new external reference // a new index will be created. These indexes can then be traversed recursively. -func (index *SpecIndex) FindComponent(componentId string, parent *yaml.Node) *Reference { +func (index *SpecIndex) FindComponent(componentId string) *Reference { if index.root == nil { return nil } @@ -43,7 +43,6 @@ func (index *SpecIndex) FindComponent(componentId string, parent *yaml.Node) *Re // root search return index.FindComponentInRoot(componentId) - } } @@ -55,6 +54,9 @@ func FindComponent(root *yaml.Node, componentId, absoluteFilePath string, index } name, friendlySearch := utils.ConvertComponentIdIntoFriendlyPathSearch(componentId) + if friendlySearch == "$." { + friendlySearch = "$" + } path, err := yamlpath.NewPath(friendlySearch) if path == nil || err != nil { return nil // no component found @@ -63,12 +65,7 @@ func FindComponent(root *yaml.Node, componentId, absoluteFilePath string, index if len(res) == 1 { resNode := res[0] - if res[0].Kind == yaml.DocumentNode { - resNode = res[0].Content[0] - } - fullDef := fmt.Sprintf("%s%s", absoluteFilePath, componentId) - // extract properties ref := &Reference{ FullDefinition: fullDef, @@ -80,7 +77,6 @@ func FindComponent(root *yaml.Node, componentId, absoluteFilePath string, index Index: index, RequiredRefProperties: extractDefinitionRequiredRefProperties(resNode, map[string][]string{}, fullDef), } - return ref } return nil diff --git a/index/find_component_test.go b/index/find_component_test.go index 41fc2eaa..c16cff51 100644 --- a/index/find_component_test.go +++ b/index/find_component_test.go @@ -253,3 +253,87 @@ paths: index := NewSpecIndexWithConfig(&rootNode, c) assert.Len(t, index.GetReferenceIndexErrors(), 1) } + +func TestFindComponent_LookupRolodex_GrabRoot(t *testing.T) { + + spec := `openapi: 3.0.2 +info: + title: Test + version: 1.0.0 +components: + schemas: + thang: + type: object +` + + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(spec), &rootNode) + + c := CreateOpenAPIIndexConfig() + + index := NewSpecIndexWithConfig(&rootNode, c) + r := NewRolodex(c) + index.rolodex = r + + n := index.lookupRolodex([]string{"bingobango"}) + + // if the reference is not found, it should return the root. + assert.NotNil(t, n) + +} + +func TestFindComponentInRoot_GrabDocRoot(t *testing.T) { + + spec := `openapi: 3.0.2 +info: + title: Test + version: 1.0.0 +components: + schemas: + thang: + type: object +` + + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(spec), &rootNode) + + c := CreateOpenAPIIndexConfig() + + index := NewSpecIndexWithConfig(&rootNode, c) + r := NewRolodex(c) + index.rolodex = r + + n := index.FindComponentInRoot("#/") + + // if the reference is not found, it should return the root. + assert.NotNil(t, n) + +} + +func TestFindComponent_LookupRolodex_NoURL(t *testing.T) { + + spec := `openapi: 3.0.2 +info: + title: Test + version: 1.0.0 +components: + schemas: + thang: + type: object +` + + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(spec), &rootNode) + + c := CreateOpenAPIIndexConfig() + + index := NewSpecIndexWithConfig(&rootNode, c) + r := NewRolodex(c) + index.rolodex = r + + n := index.lookupRolodex(nil) + + // no url, no ref. + assert.Nil(t, n) + +} diff --git a/index/resolver.go b/index/resolver.go index 90f591d9..38efc23b 100644 --- a/index/resolver.go +++ b/index/resolver.go @@ -260,7 +260,7 @@ func (resolver *Resolver) VisitReference(ref *Reference, seen map[string]bool, j seen = make(map[string]bool) seen[ref.Definition] = true - for i, r := range relatives { + for _, r := range relatives { // check if we have seen this on the journey before, if so! it's circular skip := false for i, j := range journey { @@ -311,10 +311,6 @@ func (resolver *Resolver) VisitReference(ref *Reference, seen map[string]bool, j if foundRef != nil { original = foundRef } - if original == nil { - panic(i) - } - resolved := resolver.VisitReference(original, seen, journey, resolve) if resolve && !original.Circular { r.Node.Content = resolved // this is where we perform the actual resolving. @@ -422,47 +418,32 @@ func (resolver *Resolver) extractRelatives(ref *Reference, node, parent *yaml.No } } else { - if strings.HasPrefix(exp[0], "http") { - fullDef = value // remote component, full def is based on value - - } else { - - if filepath.IsAbs(value) { - fullDef = value - } else { - - // local component, full def is based on passed in ref - if strings.HasPrefix(ref.FullDefinition, "http") { - - // split the http URI into parts - httpExp := strings.Split(ref.FullDefinition, "#/") - - // parse an URL from the full def - u, _ := url.Parse(httpExp[0]) - - // extract the location of the ref and build a full def path. - fullDef = fmt.Sprintf("%s#/%s", u.String(), exp[1]) + // local component, full def is based on passed in ref + if strings.HasPrefix(ref.FullDefinition, "http") { - } else { + // split the http URI into parts + httpExp := strings.Split(ref.FullDefinition, "#/") - // split the full def into parts - fileDef := strings.Split(ref.FullDefinition, "#/") + // parse a URL from the full def + u, _ := url.Parse(httpExp[0]) - // extract the location of the ref and build a full def path. - //loc, _ := filepath.Abs(fileDef[0]), exp[1])) + // extract the location of the ref and build a full def path. + fullDef = fmt.Sprintf("%s#/%s", u.String(), exp[1]) - fullDef = fmt.Sprintf("%s#/%s", fileDef[0], exp[1]) + } else { - } + // split the full def into parts + fileDef := strings.Split(ref.FullDefinition, "#/") + fullDef = fmt.Sprintf("%s#/%s", fileDef[0], exp[1]) - } } + } } else { definition = value - // if the reference is an http link + // if the reference is a http link if strings.HasPrefix(value, "http") { fullDef = value } else { @@ -474,7 +455,7 @@ func (resolver *Resolver) extractRelatives(ref *Reference, node, parent *yaml.No // split the full def into parts fileDef := strings.Split(ref.FullDefinition, "#/") - // is the file def an http link? + // is the file def a http link? if strings.HasPrefix(fileDef[0], "http") { u, _ := url.Parse(fileDef[0]) diff --git a/index/resolver_test.go b/index/resolver_test.go index d5f31f54..f0a06493 100644 --- a/index/resolver_test.go +++ b/index/resolver_test.go @@ -662,3 +662,112 @@ func ExampleResolvingError() { fmt.Printf("%s", re.Error()) // Output: je suis une erreur: #/definitions/JeSuisUneErreur [5:21] } + +func TestDocument_IgnoreArrayCircularReferences(t *testing.T) { + + var d = `openapi: 3.1.0 +components: + schemas: + ProductCategory: + type: "object" + properties: + name: + type: "string" + children: + type: "array" + items: + $ref: "#/components/schemas/ProductCategory" + description: "Array of sub-categories in the same format." + required: + - "name" + - "children"` + + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(d), &rootNode) + + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + + resolver := NewResolver(idx) + resolver.IgnoreArrayCircularReferences() + assert.NotNil(t, resolver) + + circ := resolver.Resolve() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetIgnoredCircularArrayReferences(), 1) + +} + +func TestDocument_IgnorePolyCircularReferences(t *testing.T) { + + var d = `openapi: 3.1.0 +components: + schemas: + ProductCategory: + type: "object" + properties: + name: + type: "string" + children: + type: "object" + anyOf: + - $ref: "#/components/schemas/ProductCategory" + description: "Array of sub-categories in the same format." + required: + - "name" + - "children"` + + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(d), &rootNode) + + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + + resolver := NewResolver(idx) + resolver.IgnorePolymorphicCircularReferences() + assert.NotNil(t, resolver) + + circ := resolver.Resolve() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetIgnoredCircularPolyReferences(), 1) + +} + +func TestDocument_IgnorePolyCircularReferences_NoArrayForRef(t *testing.T) { + + var d = `openapi: 3.1.0 +components: + schemas: + bingo: + type: object + properties: + bango: + $ref: "#/components/schemas/ProductCategory" + ProductCategory: + type: "object" + properties: + name: + type: "string" + children: + type: "object" + items: + anyOf: + items: + $ref: "#/components/schemas/ProductCategory" + description: "Array of sub-categories in the same format." + required: + - "name" + - "children"` + + var rootNode yaml.Node + _ = yaml.Unmarshal([]byte(d), &rootNode) + + idx := NewSpecIndexWithConfig(&rootNode, CreateClosedAPIIndexConfig()) + + resolver := NewResolver(idx) + resolver.IgnorePolymorphicCircularReferences() + assert.NotNil(t, resolver) + + circ := resolver.Resolve() + assert.Len(t, circ, 0) + assert.Len(t, resolver.GetIgnoredCircularPolyReferences(), 1) + +} diff --git a/index/rolodex.go b/index/rolodex.go index 88545a8e..8801c656 100644 --- a/index/rolodex.go +++ b/index/rolodex.go @@ -174,10 +174,12 @@ func (rf *rolodexFile) Size() int64 { } func (rf *rolodexFile) IsDir() bool { + // always false. return false } func (rf *rolodexFile) Sys() interface{} { + // not implemented. return nil } diff --git a/index/rolodex_remote_loader.go b/index/rolodex_remote_loader.go index 8605e529..643ae6be 100644 --- a/index/rolodex_remote_loader.go +++ b/index/rolodex_remote_loader.go @@ -293,11 +293,6 @@ func (i *RemoteFS) Open(remoteURL string) (fs.File, error) { i.logger.Debug("loading remote file", "file", remoteURL, "remoteURL", remoteParsedURL.String()) - //// no handler func? use the default client. - //if i.RemoteHandlerFunc == nil { - // i.RemoteHandlerFunc = i.defaultClient.Get - //} - response, clientErr := i.RemoteHandlerFunc(remoteParsedURL.String()) if clientErr != nil { diff --git a/index/rolodex_test.go b/index/rolodex_test.go index 432ecaae..831af3a3 100644 --- a/index/rolodex_test.go +++ b/index/rolodex_test.go @@ -5,7 +5,9 @@ package index import ( "github.com/stretchr/testify/assert" + "io/fs" "os" + "strings" "testing" "testing/fstest" "time" @@ -78,4 +80,19 @@ func TestRolodex_SimpleTest_OneDoc(t *testing.T) { assert.NoError(t, err) assert.Len(t, rolo.indexes, 9) + // open components.yaml + f, rerr := rolo.Open("components.yaml") + assert.NoError(t, rerr) + assert.Equal(t, "components.yaml", f.Name()) + + idx, ierr := f.(*rolodexFile).Index(cf) + assert.NoError(t, ierr) + assert.NotNil(t, idx) + assert.Equal(t, YAML, f.GetFileExtension()) + assert.True(t, strings.HasSuffix(f.GetFullPath(), "rolodex_test_data/components.yaml")) + assert.Equal(t, "2023-10-12", f.ModTime().Format("2006-01-02")) + assert.Equal(t, int64(283), f.Size()) + assert.False(t, f.IsDir()) + assert.Nil(t, f.Sys()) + assert.Equal(t, fs.FileMode(0), f.Mode()) } diff --git a/index/search_index.go b/index/search_index.go index 30af2898..06336298 100644 --- a/index/search_index.go +++ b/index/search_index.go @@ -138,7 +138,7 @@ func (index *SpecIndex) SearchIndexForReferenceByReferenceWithContext(ctx contex // does component exist in the root? node, _ := rFile.GetContentAsYAMLNode() if node != nil { - found := idx.FindComponent(ref, node) + found := idx.FindComponent(ref) if found != nil { idx.cache.Store(ref, found) index.cache.Store(ref, found) diff --git a/index/spec_index_test.go b/index/spec_index_test.go index 168f7b2b..e0b3d2c9 100644 --- a/index/spec_index_test.go +++ b/index/spec_index_test.go @@ -563,7 +563,7 @@ func TestSpecIndex_NoRoot(t *testing.T) { docs := index.ExtractExternalDocuments(nil) assert.Nil(t, docs) assert.Nil(t, refs) - assert.Nil(t, index.FindComponent("nothing", nil)) + assert.Nil(t, index.FindComponent("nothing")) assert.Equal(t, -1, index.GetOperationCount()) assert.Equal(t, -1, index.GetPathCount()) assert.Equal(t, -1, index.GetGlobalTagsCount()) @@ -798,10 +798,10 @@ func TestSpecIndex_FindComponent_WithACrazyAssPath(t *testing.T) { index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) assert.Equal(t, "#/paths/~1crazy~1ass~1references/get/parameters/0", - index.FindComponent("#/paths/~1crazy~1ass~1references/get/responses/404/content/application~1xml;%20charset=utf-8/schema", nil).Node.Content[1].Value) + index.FindComponent("#/paths/~1crazy~1ass~1references/get/responses/404/content/application~1xml;%20charset=utf-8/schema").Node.Content[1].Value) assert.Equal(t, "a param", - index.FindComponent("#/paths/~1crazy~1ass~1references/get/parameters/0", nil).Node.Content[1].Value) + index.FindComponent("#/paths/~1crazy~1ass~1references/get/parameters/0").Node.Content[1].Value) } func TestSpecIndex_FindComponent(t *testing.T) { @@ -818,7 +818,7 @@ func TestSpecIndex_FindComponent(t *testing.T) { _ = yaml.Unmarshal([]byte(yml), &rootNode) index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) - assert.Nil(t, index.FindComponent("I-do-not-exist", nil)) + assert.Nil(t, index.FindComponent("I-do-not-exist")) } func TestSpecIndex_TestPathsNodeAsArray(t *testing.T) {