bumping test coverage

more to go, more cleaning inbound also

Signed-off-by: quobix <dave@quobix.com>
This commit is contained in:
quobix
2023-10-25 08:09:33 -04:00
parent b82b46eb02
commit a87d9236d8
11 changed files with 240 additions and 60 deletions

View File

@@ -1,4 +0,0 @@
// Copyright 2023 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT
package low

View File

@@ -556,7 +556,7 @@ func (index *SpecIndex) ExtractComponentsFromRefs(refs []*Reference) []*Referenc
c := make(chan bool) c := make(chan bool)
locate := func(ref *Reference, refIndex int, sequence []*ReferenceMapped) { locate := func(ref *Reference, refIndex int, sequence []*ReferenceMapped) {
located := index.FindComponent(ref.FullDefinition, ref.Node) located := index.FindComponent(ref.FullDefinition)
if located != nil { if located != nil {
index.refLock.Lock() index.refLock.Lock()

View File

@@ -17,7 +17,7 @@ import (
// FindComponent will locate a component by its reference, returns nil if nothing is found. // 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 // 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. // 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 { if index.root == nil {
return nil return nil
} }
@@ -43,7 +43,6 @@ func (index *SpecIndex) FindComponent(componentId string, parent *yaml.Node) *Re
// root search // root search
return index.FindComponentInRoot(componentId) return index.FindComponentInRoot(componentId)
} }
} }
@@ -55,6 +54,9 @@ func FindComponent(root *yaml.Node, componentId, absoluteFilePath string, index
} }
name, friendlySearch := utils.ConvertComponentIdIntoFriendlyPathSearch(componentId) name, friendlySearch := utils.ConvertComponentIdIntoFriendlyPathSearch(componentId)
if friendlySearch == "$." {
friendlySearch = "$"
}
path, err := yamlpath.NewPath(friendlySearch) path, err := yamlpath.NewPath(friendlySearch)
if path == nil || err != nil { if path == nil || err != nil {
return nil // no component found return nil // no component found
@@ -63,12 +65,7 @@ func FindComponent(root *yaml.Node, componentId, absoluteFilePath string, index
if len(res) == 1 { if len(res) == 1 {
resNode := res[0] resNode := res[0]
if res[0].Kind == yaml.DocumentNode {
resNode = res[0].Content[0]
}
fullDef := fmt.Sprintf("%s%s", absoluteFilePath, componentId) fullDef := fmt.Sprintf("%s%s", absoluteFilePath, componentId)
// extract properties // extract properties
ref := &Reference{ ref := &Reference{
FullDefinition: fullDef, FullDefinition: fullDef,
@@ -80,7 +77,6 @@ func FindComponent(root *yaml.Node, componentId, absoluteFilePath string, index
Index: index, Index: index,
RequiredRefProperties: extractDefinitionRequiredRefProperties(resNode, map[string][]string{}, fullDef), RequiredRefProperties: extractDefinitionRequiredRefProperties(resNode, map[string][]string{}, fullDef),
} }
return ref return ref
} }
return nil return nil

View File

@@ -253,3 +253,87 @@ paths:
index := NewSpecIndexWithConfig(&rootNode, c) index := NewSpecIndexWithConfig(&rootNode, c)
assert.Len(t, index.GetReferenceIndexErrors(), 1) 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)
}

View File

@@ -260,7 +260,7 @@ func (resolver *Resolver) VisitReference(ref *Reference, seen map[string]bool, j
seen = make(map[string]bool) seen = make(map[string]bool)
seen[ref.Definition] = true 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 // check if we have seen this on the journey before, if so! it's circular
skip := false skip := false
for i, j := range journey { for i, j := range journey {
@@ -311,10 +311,6 @@ func (resolver *Resolver) VisitReference(ref *Reference, seen map[string]bool, j
if foundRef != nil { if foundRef != nil {
original = foundRef original = foundRef
} }
if original == nil {
panic(i)
}
resolved := resolver.VisitReference(original, seen, journey, resolve) resolved := resolver.VisitReference(original, seen, journey, resolve)
if resolve && !original.Circular { if resolve && !original.Circular {
r.Node.Content = resolved // this is where we perform the actual resolving. 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 { } else {
if strings.HasPrefix(exp[0], "http") { // local component, full def is based on passed in ref
fullDef = value // remote component, full def is based on value if strings.HasPrefix(ref.FullDefinition, "http") {
// split the http URI into parts
httpExp := 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.
fullDef = fmt.Sprintf("%s#/%s", u.String(), exp[1])
} else { } else {
if filepath.IsAbs(value) { // split the full def into parts
fullDef = value fileDef := strings.Split(ref.FullDefinition, "#/")
} else { fullDef = fmt.Sprintf("%s#/%s", fileDef[0], exp[1])
// 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])
} else {
// split the full def into parts
fileDef := strings.Split(ref.FullDefinition, "#/")
// extract the location of the ref and build a full def path.
//loc, _ := filepath.Abs(fileDef[0]), exp[1]))
fullDef = fmt.Sprintf("%s#/%s", fileDef[0], exp[1])
}
}
} }
} }
} else { } else {
definition = value definition = value
// if the reference is an http link // if the reference is a http link
if strings.HasPrefix(value, "http") { if strings.HasPrefix(value, "http") {
fullDef = value fullDef = value
} else { } else {
@@ -474,7 +455,7 @@ func (resolver *Resolver) extractRelatives(ref *Reference, node, parent *yaml.No
// split the full def into parts // split the full def into parts
fileDef := strings.Split(ref.FullDefinition, "#/") 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") { if strings.HasPrefix(fileDef[0], "http") {
u, _ := url.Parse(fileDef[0]) u, _ := url.Parse(fileDef[0])

View File

@@ -662,3 +662,112 @@ func ExampleResolvingError() {
fmt.Printf("%s", re.Error()) fmt.Printf("%s", re.Error())
// Output: je suis une erreur: #/definitions/JeSuisUneErreur [5:21] // 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)
}

View File

@@ -174,10 +174,12 @@ func (rf *rolodexFile) Size() int64 {
} }
func (rf *rolodexFile) IsDir() bool { func (rf *rolodexFile) IsDir() bool {
// always false.
return false return false
} }
func (rf *rolodexFile) Sys() interface{} { func (rf *rolodexFile) Sys() interface{} {
// not implemented.
return nil return nil
} }

View File

@@ -293,11 +293,6 @@ func (i *RemoteFS) Open(remoteURL string) (fs.File, error) {
i.logger.Debug("loading remote file", "file", remoteURL, "remoteURL", remoteParsedURL.String()) 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()) response, clientErr := i.RemoteHandlerFunc(remoteParsedURL.String())
if clientErr != nil { if clientErr != nil {

View File

@@ -5,7 +5,9 @@ package index
import ( import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"io/fs"
"os" "os"
"strings"
"testing" "testing"
"testing/fstest" "testing/fstest"
"time" "time"
@@ -78,4 +80,19 @@ func TestRolodex_SimpleTest_OneDoc(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, rolo.indexes, 9) 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())
} }

View File

@@ -138,7 +138,7 @@ func (index *SpecIndex) SearchIndexForReferenceByReferenceWithContext(ctx contex
// does component exist in the root? // does component exist in the root?
node, _ := rFile.GetContentAsYAMLNode() node, _ := rFile.GetContentAsYAMLNode()
if node != nil { if node != nil {
found := idx.FindComponent(ref, node) found := idx.FindComponent(ref)
if found != nil { if found != nil {
idx.cache.Store(ref, found) idx.cache.Store(ref, found)
index.cache.Store(ref, found) index.cache.Store(ref, found)

View File

@@ -563,7 +563,7 @@ func TestSpecIndex_NoRoot(t *testing.T) {
docs := index.ExtractExternalDocuments(nil) docs := index.ExtractExternalDocuments(nil)
assert.Nil(t, docs) assert.Nil(t, docs)
assert.Nil(t, refs) 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.GetOperationCount())
assert.Equal(t, -1, index.GetPathCount()) assert.Equal(t, -1, index.GetPathCount())
assert.Equal(t, -1, index.GetGlobalTagsCount()) assert.Equal(t, -1, index.GetGlobalTagsCount())
@@ -798,10 +798,10 @@ func TestSpecIndex_FindComponent_WithACrazyAssPath(t *testing.T) {
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Equal(t, "#/paths/~1crazy~1ass~1references/get/parameters/0", 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", 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) { func TestSpecIndex_FindComponent(t *testing.T) {
@@ -818,7 +818,7 @@ func TestSpecIndex_FindComponent(t *testing.T) {
_ = yaml.Unmarshal([]byte(yml), &rootNode) _ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig()) 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) { func TestSpecIndex_TestPathsNodeAsArray(t *testing.T) {