Added support for unevaluatedProperties as Schema and bool #118

Also ran `gofmt` across the entire project. Things need cleaning up.

Signed-off-by: Dave Shanley <dave@quobix.com>
This commit is contained in:
Dave Shanley
2023-06-15 08:58:20 -04:00
committed by quobix
parent 148822fa2a
commit c3cf5f1e38
142 changed files with 11751 additions and 11577 deletions

View File

@@ -1,170 +1,170 @@
package resolver
import (
"errors"
"fmt"
"io/ioutil"
"net/url"
"testing"
"errors"
"fmt"
"io/ioutil"
"net/url"
"testing"
"github.com/pb33f/libopenapi/index"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
"github.com/pb33f/libopenapi/index"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
)
func TestNewResolver(t *testing.T) {
assert.Nil(t, NewResolver(nil))
assert.Nil(t, NewResolver(nil))
}
func Benchmark_ResolveDocumentStripe(b *testing.B) {
stripe, _ := ioutil.ReadFile("../test_specs/stripe.yaml")
for n := 0; n < b.N; n++ {
var rootNode yaml.Node
yaml.Unmarshal(stripe, &rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
resolver.Resolve()
}
stripe, _ := ioutil.ReadFile("../test_specs/stripe.yaml")
for n := 0; n < b.N; n++ {
var rootNode yaml.Node
yaml.Unmarshal(stripe, &rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
resolver.Resolve()
}
}
func TestResolver_ResolveComponents_CircularSpec(t *testing.T) {
circular, _ := ioutil.ReadFile("../test_specs/circular-tests.yaml")
var rootNode yaml.Node
yaml.Unmarshal(circular, &rootNode)
circular, _ := ioutil.ReadFile("../test_specs/circular-tests.yaml")
var rootNode yaml.Node
yaml.Unmarshal(circular, &rootNode)
index := index.NewSpecIndex(&rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
circ := resolver.Resolve()
assert.Len(t, circ, 3)
circ := resolver.Resolve()
assert.Len(t, circ, 3)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
}
func TestResolver_CheckForCircularReferences(t *testing.T) {
circular, _ := ioutil.ReadFile("../test_specs/circular-tests.yaml")
var rootNode yaml.Node
yaml.Unmarshal(circular, &rootNode)
circular, _ := ioutil.ReadFile("../test_specs/circular-tests.yaml")
var rootNode yaml.Node
yaml.Unmarshal(circular, &rootNode)
index := index.NewSpecIndex(&rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 3)
assert.Len(t, resolver.GetResolvingErrors(), 3)
assert.Len(t, resolver.GetCircularErrors(), 3)
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 3)
assert.Len(t, resolver.GetResolvingErrors(), 3)
assert.Len(t, resolver.GetCircularErrors(), 3)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
}
func TestResolver_CheckForCircularReferences_DigitalOcean(t *testing.T) {
circular, _ := ioutil.ReadFile("../test_specs/digitalocean.yaml")
var rootNode yaml.Node
yaml.Unmarshal(circular, &rootNode)
circular, _ := ioutil.ReadFile("../test_specs/digitalocean.yaml")
var rootNode yaml.Node
yaml.Unmarshal(circular, &rootNode)
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
index := index.NewSpecIndexWithConfig(&rootNode, &index.SpecIndexConfig{
AllowRemoteLookup: true,
AllowFileLookup: true,
BaseURL: baseURL,
})
index := index.NewSpecIndexWithConfig(&rootNode, &index.SpecIndexConfig{
AllowRemoteLookup: true,
AllowFileLookup: true,
BaseURL: baseURL,
})
resolver := NewResolver(index)
assert.NotNil(t, resolver)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
assert.Len(t, resolver.GetResolvingErrors(), 0)
assert.Len(t, resolver.GetCircularErrors(), 0)
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
assert.Len(t, resolver.GetResolvingErrors(), 0)
assert.Len(t, resolver.GetCircularErrors(), 0)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
}
func TestResolver_CircularReferencesRequiredValid(t *testing.T) {
circular, _ := ioutil.ReadFile("../test_specs/swagger-valid-recursive-model.yaml")
var rootNode yaml.Node
yaml.Unmarshal(circular, &rootNode)
circular, _ := ioutil.ReadFile("../test_specs/swagger-valid-recursive-model.yaml")
var rootNode yaml.Node
yaml.Unmarshal(circular, &rootNode)
index := index.NewSpecIndex(&rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
}
func TestResolver_CircularReferencesRequiredInvalid(t *testing.T) {
circular, _ := ioutil.ReadFile("../test_specs/swagger-invalid-recursive-model.yaml")
var rootNode yaml.Node
yaml.Unmarshal(circular, &rootNode)
circular, _ := ioutil.ReadFile("../test_specs/swagger-invalid-recursive-model.yaml")
var rootNode yaml.Node
yaml.Unmarshal(circular, &rootNode)
index := index.NewSpecIndex(&rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 2)
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 2)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
_, err := yaml.Marshal(resolver.resolvedRoot)
assert.NoError(t, err)
}
func TestResolver_DeepJourney(t *testing.T) {
var journey []*index.Reference
for f := 0; f < 200; f++ {
journey = append(journey, nil)
}
index := index.NewSpecIndex(nil)
resolver := NewResolver(index)
assert.Nil(t, resolver.extractRelatives(nil, nil, journey, false))
var journey []*index.Reference
for f := 0; f < 200; f++ {
journey = append(journey, nil)
}
index := index.NewSpecIndex(nil)
resolver := NewResolver(index)
assert.Nil(t, resolver.extractRelatives(nil, nil, journey, false))
}
func TestResolver_ResolveComponents_Stripe(t *testing.T) {
stripe, _ := ioutil.ReadFile("../test_specs/stripe.yaml")
var rootNode yaml.Node
yaml.Unmarshal(stripe, &rootNode)
stripe, _ := ioutil.ReadFile("../test_specs/stripe.yaml")
var rootNode yaml.Node
yaml.Unmarshal(stripe, &rootNode)
index := index.NewSpecIndex(&rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
circ := resolver.Resolve()
assert.Len(t, circ, 3)
circ := resolver.Resolve()
assert.Len(t, circ, 3)
assert.Len(t, resolver.GetNonPolymorphicCircularErrors(), 3)
assert.Len(t, resolver.GetPolymorphicCircularErrors(), 0)
assert.Len(t, resolver.GetNonPolymorphicCircularErrors(), 3)
assert.Len(t, resolver.GetPolymorphicCircularErrors(), 0)
}
func TestResolver_ResolveComponents_BurgerShop(t *testing.T) {
mixedref, _ := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml")
var rootNode yaml.Node
yaml.Unmarshal(mixedref, &rootNode)
mixedref, _ := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml")
var rootNode yaml.Node
yaml.Unmarshal(mixedref, &rootNode)
index := index.NewSpecIndex(&rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
circ := resolver.Resolve()
assert.Len(t, circ, 0)
circ := resolver.Resolve()
assert.Len(t, circ, 0)
}
func TestResolver_ResolveComponents_PolyNonCircRef(t *testing.T) {
yml := `paths:
yml := `paths:
/hey:
get:
responses:
@@ -184,20 +184,20 @@ components:
tea:
description: tea`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
index := index.NewSpecIndex(&rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
circ := resolver.CheckForCircularReferences()
assert.Len(t, circ, 0)
}
func TestResolver_ResolveComponents_PolyCircRef(t *testing.T) {
yml := `openapi: 3.1.0
yml := `openapi: 3.1.0
components:
schemas:
cheese:
@@ -211,24 +211,24 @@ components:
tea:
description: tea`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
index := index.NewSpecIndex(&rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
_ = resolver.CheckForCircularReferences()
resolver.circularReferences[0].IsInfiniteLoop = true // override
assert.Len(t, index.GetCircularReferences(), 1)
assert.Len(t, resolver.GetPolymorphicCircularErrors(), 1)
assert.Equal(t, 2, index.GetCircularReferences()[0].LoopIndex)
_ = resolver.CheckForCircularReferences()
resolver.circularReferences[0].IsInfiniteLoop = true // override
assert.Len(t, index.GetCircularReferences(), 1)
assert.Len(t, resolver.GetPolymorphicCircularErrors(), 1)
assert.Equal(t, 2, index.GetCircularReferences()[0].LoopIndex)
}
func TestResolver_ResolveComponents_Missing(t *testing.T) {
yml := `paths:
yml := `paths:
/hey:
get:
responses:
@@ -247,95 +247,95 @@ components:
butter:
$ref: 'go home, I am drunk'`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
index := index.NewSpecIndex(&rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
err := resolver.Resolve()
assert.Len(t, err, 1)
assert.Equal(t, "cannot resolve reference `go home, I am drunk`, it's missing: $go home, I am drunk [18:11]", err[0].Error())
err := resolver.Resolve()
assert.Len(t, err, 1)
assert.Equal(t, "cannot resolve reference `go home, I am drunk`, it's missing: $go home, I am drunk [18:11]", err[0].Error())
}
func TestResolver_ResolveComponents_MixedRef(t *testing.T) {
mixedref, _ := ioutil.ReadFile("../test_specs/mixedref-burgershop.openapi.yaml")
var rootNode yaml.Node
yaml.Unmarshal(mixedref, &rootNode)
mixedref, _ := ioutil.ReadFile("../test_specs/mixedref-burgershop.openapi.yaml")
var rootNode yaml.Node
yaml.Unmarshal(mixedref, &rootNode)
b := index.CreateOpenAPIIndexConfig()
idx := index.NewSpecIndexWithConfig(&rootNode, b)
b := index.CreateOpenAPIIndexConfig()
idx := index.NewSpecIndexWithConfig(&rootNode, b)
resolver := NewResolver(idx)
assert.NotNil(t, resolver)
resolver := NewResolver(idx)
assert.NotNil(t, resolver)
circ := resolver.Resolve()
assert.Len(t, circ, 0)
assert.Equal(t, 5, resolver.GetIndexesVisited())
circ := resolver.Resolve()
assert.Len(t, circ, 0)
assert.Equal(t, 5, resolver.GetIndexesVisited())
// in v0.8.2 a new check was added when indexing, to prevent re-indexing the same file multiple times.
assert.Equal(t, 191, resolver.GetRelativesSeen())
assert.Equal(t, 35, resolver.GetJourneysTaken())
assert.Equal(t, 62, resolver.GetReferenceVisited())
// in v0.8.2 a new check was added when indexing, to prevent re-indexing the same file multiple times.
assert.Equal(t, 191, resolver.GetRelativesSeen())
assert.Equal(t, 35, resolver.GetJourneysTaken())
assert.Equal(t, 62, resolver.GetReferenceVisited())
}
func TestResolver_ResolveComponents_k8s(t *testing.T) {
k8s, _ := ioutil.ReadFile("../test_specs/k8s.json")
var rootNode yaml.Node
yaml.Unmarshal(k8s, &rootNode)
k8s, _ := ioutil.ReadFile("../test_specs/k8s.json")
var rootNode yaml.Node
yaml.Unmarshal(k8s, &rootNode)
index := index.NewSpecIndex(&rootNode)
index := index.NewSpecIndex(&rootNode)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
resolver := NewResolver(index)
assert.NotNil(t, resolver)
circ := resolver.Resolve()
assert.Len(t, circ, 0)
circ := resolver.Resolve()
assert.Len(t, circ, 0)
}
// Example of how to resolve the Stripe OpenAPI specification, and check for circular reference errors
func ExampleNewResolver() {
// create a yaml.Node reference as a root node.
var rootNode yaml.Node
// create a yaml.Node reference as a root node.
var rootNode yaml.Node
// load in the Stripe OpenAPI spec (lots of polymorphic complexity in here)
stripeBytes, _ := ioutil.ReadFile("../test_specs/stripe.yaml")
// load in the Stripe OpenAPI spec (lots of polymorphic complexity in here)
stripeBytes, _ := ioutil.ReadFile("../test_specs/stripe.yaml")
// unmarshal bytes into our rootNode.
_ = yaml.Unmarshal(stripeBytes, &rootNode)
// unmarshal bytes into our rootNode.
_ = yaml.Unmarshal(stripeBytes, &rootNode)
// create a new spec index (resolver depends on it)
indexConfig := index.CreateClosedAPIIndexConfig()
index := index.NewSpecIndexWithConfig(&rootNode, indexConfig)
// create a new spec index (resolver depends on it)
indexConfig := index.CreateClosedAPIIndexConfig()
index := index.NewSpecIndexWithConfig(&rootNode, indexConfig)
// create a new resolver using the index.
resolver := NewResolver(index)
// create a new resolver using the index.
resolver := NewResolver(index)
// resolve the document, if there are circular reference errors, they are returned/
// WARNING: this is a destructive action and the rootNode will be PERMANENTLY altered and cannot be unresolved
circularErrors := resolver.Resolve()
// resolve the document, if there are circular reference errors, they are returned/
// WARNING: this is a destructive action and the rootNode will be PERMANENTLY altered and cannot be unresolved
circularErrors := resolver.Resolve()
// The Stripe API has a bunch of circular reference problems, mainly from polymorphism.
// So let's print them out.
//
fmt.Printf("There are %d circular reference errors, %d of them are polymorphic errors, %d are not",
len(circularErrors), len(resolver.GetPolymorphicCircularErrors()), len(resolver.GetNonPolymorphicCircularErrors()))
// Output: There are 3 circular reference errors, 0 of them are polymorphic errors, 3 are not
// The Stripe API has a bunch of circular reference problems, mainly from polymorphism.
// So let's print them out.
//
fmt.Printf("There are %d circular reference errors, %d of them are polymorphic errors, %d are not",
len(circularErrors), len(resolver.GetPolymorphicCircularErrors()), len(resolver.GetNonPolymorphicCircularErrors()))
// Output: There are 3 circular reference errors, 0 of them are polymorphic errors, 3 are not
}
func ExampleResolvingError() {
re := ResolvingError{
ErrorRef: errors.New("Je suis une erreur"),
Node: &yaml.Node{
Line: 5,
Column: 21,
},
Path: "#/definitions/JeSuisUneErreur",
CircularReference: &index.CircularReferenceResult{},
}
re := ResolvingError{
ErrorRef: errors.New("Je suis une erreur"),
Node: &yaml.Node{
Line: 5,
Column: 21,
},
Path: "#/definitions/JeSuisUneErreur",
CircularReference: &index.CircularReferenceResult{},
}
fmt.Printf("%s", re.Error())
// Output: Je suis une erreur: #/definitions/JeSuisUneErreur [5:21]
fmt.Printf("%s", re.Error())
// Output: Je suis une erreur: #/definitions/JeSuisUneErreur [5:21]
}