Fixed async isues with index #91

The index runs async everywhere, it's kinda impossible to know which path with resolve first, so testing is hard. Sometimes a race condition is hit, well, it was. Now that map has a mutex on it.

Also fully fixed handling files with relative links. A basepath property has been added to the index configuration to allow a local root to be set when resolving files.

Added a full checkout test for digital ocean so that full remote and full local testing is performed.
This commit is contained in:
Dave Shanley
2023-03-06 09:40:50 -05:00
parent 0850ceb272
commit 0f2ac08567
7 changed files with 197 additions and 109 deletions

View File

@@ -8,6 +8,7 @@ import (
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/resolver"
"github.com/pb33f/libopenapi/utils"
"os"
"sync"
)
@@ -37,13 +38,17 @@ func createDocument(info *datamodel.SpecInfo, config *datamodel.DocumentConfigur
version = low.NodeReference[string]{Value: versionNode.Value, KeyNode: labelNode, ValueNode: versionNode}
doc := Document{Version: version}
// get current working directory
cwd, _ := os.Getwd()
// build an index
idx := index.NewSpecIndexWithConfig(info.RootNode, &index.SpecIndexConfig{
BaseURL: config.BaseURL,
BasePath: cwd,
AllowFileLookup: config.AllowFileReferences,
AllowRemoteLookup: config.AllowRemoteReferences,
})
doc.Index = idx
doc.Index = idx
var errs []error

View File

@@ -411,6 +411,7 @@ func (index *SpecIndex) ExtractComponentsFromRefs(refs []*Reference) []*Referenc
for r := range refsToCheck {
// expand our index of all mapped refs
go locate(refsToCheck[r], r, mappedRefsInSequence)
//locate(refsToCheck[r], r, mappedRefsInSequence) // used for sync testing.
}
completedRefs := 0

View File

@@ -11,6 +11,8 @@ import (
"io/ioutil"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"time"
)
@@ -179,6 +181,9 @@ func (index *SpecIndex) lookupFileReference(ref string) (*yaml.Node, *yaml.Node,
file := strings.ReplaceAll(uri[0], "file:", "")
filePath := filepath.Dir(file)
fileName := filepath.Base(file)
var parsedRemoteDocument *yaml.Node
if index.seenRemoteSources[file] != nil {
@@ -186,9 +191,12 @@ func (index *SpecIndex) lookupFileReference(ref string) (*yaml.Node, *yaml.Node,
} else {
base := index.config.BasePath
fileToRead := filepath.Join(base, filePath, fileName)
// try and read the file off the local file system, if it fails
// check for a baseURL and then ask our remote lookup function to go try and get it.
body, err := ioutil.ReadFile(file)
body, err := os.ReadFile(fileToRead)
if err != nil {
@@ -217,7 +225,9 @@ func (index *SpecIndex) lookupFileReference(ref string) (*yaml.Node, *yaml.Node,
}
parsedRemoteDocument = &remoteDoc
if index.seenLocalSources != nil {
index.sourceLock.Lock()
index.seenLocalSources[file] = &remoteDoc
index.sourceLock.Unlock()
}
}
@@ -297,17 +307,34 @@ func (index *SpecIndex) performExternalLookup(uri []string, componentId string,
// cool, cool, lets index this spec also. This is a recursive action and will keep going
// until all remote references have been found.
var j *url.URL
var bp *url.URL
var bd string
if index.config.BaseURL != nil {
j = index.config.BaseURL
} else {
j, _ = url.Parse(uri[0])
bp = index.config.BaseURL
}
path := GenerateCleanSpecConfigBaseURL(j, uri[0], false)
newUrl, _ := url.Parse(path)
if newUrl != nil {
if index.config.BasePath != "" {
bd = index.config.BasePath
}
var path, newBasePath string
var newUrl *url.URL
if bp != nil {
path = GenerateCleanSpecConfigBaseURL(bp, uri[0], false)
newUrl, _ = url.Parse(path)
newBasePath = filepath.Dir(filepath.Join(index.config.BasePath, filepath.Dir(newUrl.Path)))
}
if bd != "" {
newBasePath = filepath.Dir(filepath.Join(bd, uri[0]))
}
if newUrl != nil || newBasePath != "" {
newConfig := &SpecIndexConfig{
BaseURL: newUrl,
BaseURL: newUrl,
BasePath: newBasePath,
AllowRemoteLookup: index.config.AllowRemoteLookup,
AllowFileLookup: index.config.AllowFileLookup,
seenRemoteSources: index.config.seenRemoteSources,
@@ -326,18 +353,20 @@ func (index *SpecIndex) performExternalLookup(uri []string, componentId string,
}
}
foundRef := externalSpecIndex.FindComponentInRoot(uri[1])
if foundRef != nil {
nameSegs := strings.Split(uri[1], "/")
ref := &Reference{
Definition: componentId,
Name: nameSegs[len(nameSegs)-1],
Node: foundRef.Node,
IsRemote: true,
RemoteLocation: componentId,
Path: foundRef.Path,
if externalSpecIndex != nil {
foundRef := externalSpecIndex.FindComponentInRoot(uri[1])
if foundRef != nil {
nameSegs := strings.Split(uri[1], "/")
ref := &Reference{
Definition: componentId,
Name: nameSegs[len(nameSegs)-1],
Node: foundRef.Node,
IsRemote: true,
RemoteLocation: componentId,
Path: foundRef.Path,
}
return ref
}
return ref
}
}
return nil

View File

@@ -8,6 +8,7 @@ import (
"gopkg.in/yaml.v3"
"net/http"
"net/url"
"os"
"sync"
)
@@ -59,6 +60,9 @@ type SpecIndexConfig struct {
// More details on relative references can be found in issue #73: https://github.com/pb33f/libopenapi/issues/73
BaseURL *url.URL // set the Base URL for resolving relative references if the spec is exploded.
// If resolving locally, the BasePath will be the root from which relative references will be resolved from
BasePath string // set the Base Path for resolving relative references if the spec is exploded.
// In an earlier version of libopenapi (pre 0.6.0) the index would automatically resolve all references
// They could have been local, or they could have been remote. This was a problem because it meant
// There was a potential for a remote exploit if a remote reference was malicious. There aren't any known
@@ -68,7 +72,6 @@ type SpecIndexConfig struct {
AllowRemoteLookup bool // Allow remote lookups for references. Defaults to false
AllowFileLookup bool // Allow file lookups for references. Defaults to false
// private fields
seenRemoteSources *syncmap.Map
remoteLock *sync.Mutex
@@ -76,8 +79,12 @@ type SpecIndexConfig struct {
// CreateOpenAPIIndexConfig is a helper function to create a new SpecIndexConfig with the AllowRemoteLookup and
// AllowFileLookup set to true. This is the default behaviour of the index in previous versions of libopenapi. (pre 0.6.0)
//
// The default BasePath is the current working directory.
func CreateOpenAPIIndexConfig() *SpecIndexConfig {
cw, _ := os.Getwd()
return &SpecIndexConfig{
BasePath: cw,
AllowRemoteLookup: true,
AllowFileLookup: true,
seenRemoteSources: &syncmap.Map{},
@@ -86,8 +93,12 @@ func CreateOpenAPIIndexConfig() *SpecIndexConfig {
// CreateClosedAPIIndexConfig is a helper function to create a new SpecIndexConfig with the AllowRemoteLookup and
// AllowFileLookup set to false. This is the default behaviour of the index in versions 0.6.0+
//
// The default BasePath is the current working directory.
func CreateClosedAPIIndexConfig() *SpecIndexConfig {
cw, _ := os.Getwd()
return &SpecIndexConfig{
BasePath: cw,
AllowRemoteLookup: false,
AllowFileLookup: false,
seenRemoteSources: &syncmap.Map{},
@@ -194,6 +205,7 @@ type SpecIndex struct {
seenRemoteSources map[string]*yaml.Node
seenLocalSources map[string]*yaml.Node
refLock sync.Mutex
sourceLock sync.Mutex
circularReferences []*CircularReferenceResult // only available when the resolver has been used.
allowCircularReferences bool // decide if you want to error out, or allow circular references, default is false.
relativePath string // relative path of the spec file.

View File

@@ -32,6 +32,9 @@ func NewSpecIndexWithConfig(rootNode *yaml.Node, config *SpecIndexConfig) *SpecI
}
config.remoteLock = &sync.Mutex{}
index.config = config
if rootNode == nil || len(rootNode.Content) <= 0 {
return index
}
boostrapIndexCollections(rootNode, index)
return createNewIndex(rootNode, index)
}

View File

@@ -6,8 +6,11 @@ package index
import (
"fmt"
"io/ioutil"
"log"
"net/url"
"os"
"os/exec"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
@@ -17,9 +20,9 @@ import (
func TestSpecIndex_ExtractRefsStripe(t *testing.T) {
stripe, _ := ioutil.ReadFile("../test_specs/stripe.yaml")
var rootNode yaml.Node
yaml.Unmarshal(stripe, &rootNode)
_ = yaml.Unmarshal(stripe, &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Len(t, index.allRefs, 385)
assert.Equal(t, 537, len(index.allMappedRefs))
@@ -63,9 +66,9 @@ func TestSpecIndex_ExtractRefsStripe(t *testing.T) {
func TestSpecIndex_Asana(t *testing.T) {
asana, _ := ioutil.ReadFile("../test_specs/asana.yaml")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
_ = yaml.Unmarshal(asana, &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Len(t, index.allRefs, 152)
assert.Len(t, index.allMappedRefs, 171)
@@ -83,9 +86,9 @@ func TestSpecIndex_Asana(t *testing.T) {
}
func TestSpecIndex_DigitalOcean(t *testing.T) {
asana, _ := ioutil.ReadFile("../test_specs/digitalocean.yaml")
do, _ := ioutil.ReadFile("../test_specs/digitalocean.yaml")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
_ = yaml.Unmarshal(do, &rootNode)
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
@@ -98,10 +101,34 @@ func TestSpecIndex_DigitalOcean(t *testing.T) {
assert.NotNil(t, index)
}
func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve(t *testing.T) {
// this is a full checkout of the digitalocean API repo.
tmp, _ := os.MkdirTemp("", "openapi")
cmd := exec.Command("git", "clone", "https://github.com/digitalocean/openapi", tmp)
defer os.RemoveAll(filepath.Join(tmp, "openapi"))
err := cmd.Run()
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
}
spec, _ := filepath.Abs(filepath.Join(tmp, "specification", "DigitalOcean-public.v2.yaml"))
doLocal, _ := ioutil.ReadFile(spec)
var rootNode yaml.Node
_ = yaml.Unmarshal(doLocal, &rootNode)
config := CreateOpenAPIIndexConfig()
config.BasePath = filepath.Join(tmp, "specification")
index := NewSpecIndexWithConfig(&rootNode, config)
assert.Len(t, index.GetAllExternalIndexes(), 291)
assert.NotNil(t, index)
}
func TestSpecIndex_DigitalOcean_LookupsNotAllowed(t *testing.T) {
asana, _ := ioutil.ReadFile("../test_specs/digitalocean.yaml")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
_ = yaml.Unmarshal(asana, &rootNode)
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
@@ -116,7 +143,7 @@ func TestSpecIndex_DigitalOcean_LookupsNotAllowed(t *testing.T) {
func TestSpecIndex_BaseURLError(t *testing.T) {
asana, _ := ioutil.ReadFile("../test_specs/digitalocean.yaml")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
_ = yaml.Unmarshal(asana, &rootNode)
// this should fail because the base url is not a valid url and digital ocean won't be able to resolve
// anything.
@@ -133,9 +160,9 @@ func TestSpecIndex_BaseURLError(t *testing.T) {
func TestSpecIndex_k8s(t *testing.T) {
asana, _ := ioutil.ReadFile("../test_specs/k8s.json")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
_ = yaml.Unmarshal(asana, &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Len(t, index.allRefs, 558)
assert.Equal(t, 563, len(index.allMappedRefs))
@@ -158,9 +185,9 @@ func TestSpecIndex_k8s(t *testing.T) {
func TestSpecIndex_PetstoreV2(t *testing.T) {
asana, _ := ioutil.ReadFile("../test_specs/petstorev2.json")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
_ = yaml.Unmarshal(asana, &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Len(t, index.allRefs, 6)
assert.Len(t, index.allMappedRefs, 6)
@@ -182,9 +209,9 @@ func TestSpecIndex_PetstoreV2(t *testing.T) {
func TestSpecIndex_XSOAR(t *testing.T) {
xsoar, _ := ioutil.ReadFile("../test_specs/xsoar.json")
var rootNode yaml.Node
yaml.Unmarshal(xsoar, &rootNode)
_ = yaml.Unmarshal(xsoar, &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Len(t, index.allRefs, 209)
assert.Equal(t, 85, index.pathCount)
assert.Equal(t, 88, index.operationCount)
@@ -200,9 +227,9 @@ func TestSpecIndex_XSOAR(t *testing.T) {
func TestSpecIndex_PetstoreV3(t *testing.T) {
petstore, _ := ioutil.ReadFile("../test_specs/petstorev3.json")
var rootNode yaml.Node
yaml.Unmarshal(petstore, &rootNode)
_ = yaml.Unmarshal(petstore, &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Len(t, index.allRefs, 7)
assert.Len(t, index.allMappedRefs, 7)
@@ -228,9 +255,9 @@ var mappedRefs = 15
func TestSpecIndex_BurgerShop(t *testing.T) {
burgershop, _ := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml")
var rootNode yaml.Node
yaml.Unmarshal(burgershop, &rootNode)
_ = yaml.Unmarshal(burgershop, &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Len(t, index.allRefs, mappedRefs)
assert.Len(t, index.allMappedRefs, mappedRefs)
@@ -300,9 +327,9 @@ func TestSpecIndex_BurgerShop(t *testing.T) {
func TestSpecIndex_BurgerShop_AllTheComponents(t *testing.T) {
burgershop, _ := ioutil.ReadFile("../test_specs/all-the-components.yaml")
var rootNode yaml.Node
yaml.Unmarshal(burgershop, &rootNode)
_ = yaml.Unmarshal(burgershop, &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Equal(t, 1, len(index.GetAllHeaders()))
assert.Equal(t, 1, len(index.GetAllLinks()))
@@ -320,9 +347,9 @@ responses:
description: hi`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Equal(t, 1, len(index.GetAllResponses()))
}
@@ -341,9 +368,9 @@ func TestSpecIndex_NoNameParam(t *testing.T) {
- in: query`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Equal(t, 2, len(index.GetOperationParametersIndexErrors()))
}
@@ -367,24 +394,27 @@ func TestSpecIndex_NoRoot(t *testing.T) {
}
func TestSpecIndex_BurgerShopMixedRef(t *testing.T) {
spec, _ := ioutil.ReadFile("../test_specs/mixedref-burgershop.openapi.yaml")
var rootNode yaml.Node
yaml.Unmarshal(spec, &rootNode)
spec, _ := ioutil.ReadFile("../test_specs/mixedref-burgershop.openapi.yaml")
var rootNode yaml.Node
_ = yaml.Unmarshal(spec, &rootNode)
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
AllowRemoteLookup: true,
AllowFileLookup: true,
})
cwd, _ := os.Getwd()
assert.Len(t, index.allRefs, 5)
assert.Len(t, index.allMappedRefs, 5)
assert.Equal(t, 5, index.GetPathCount())
assert.Equal(t, 5, index.GetOperationCount())
assert.Equal(t, 1, index.GetComponentSchemaCount())
assert.Equal(t, 2, index.GetGlobalTagsCount())
assert.Equal(t, 3, index.GetTotalTagsCount())
assert.Equal(t, 2, index.GetOperationTagsCount())
assert.Equal(t, 0, index.GetGlobalLinksCount())
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
AllowRemoteLookup: true,
AllowFileLookup: true,
BasePath: cwd,
})
assert.Len(t, index.allRefs, 5)
assert.Len(t, index.allMappedRefs, 5)
assert.Equal(t, 5, index.GetPathCount())
assert.Equal(t, 5, index.GetOperationCount())
assert.Equal(t, 1, index.GetComponentSchemaCount())
assert.Equal(t, 2, index.GetGlobalTagsCount())
assert.Equal(t, 3, index.GetTotalTagsCount())
assert.Equal(t, 2, index.GetOperationTagsCount())
assert.Equal(t, 0, index.GetGlobalLinksCount())
assert.Equal(t, 0, index.GetComponentParameterCount())
assert.Equal(t, 2, index.GetOperationsParameterCount())
assert.Equal(t, 1, index.GetInlineDuplicateParamCount())
@@ -394,9 +424,9 @@ func TestSpecIndex_BurgerShopMixedRef(t *testing.T) {
func TestSpecIndex_TestEmptyBrokenReferences(t *testing.T) {
asana, _ := ioutil.ReadFile("../test_specs/badref-burgershop.openapi.yaml")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
_ = yaml.Unmarshal(asana, &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Equal(t, 5, index.GetPathCount())
assert.Equal(t, 5, index.GetOperationCount())
assert.Equal(t, 5, index.GetComponentSchemaCount())
@@ -418,9 +448,9 @@ func TestTagsNoDescription(t *testing.T) {
- three: three`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Equal(t, 3, index.GetGlobalTagsCount())
}
@@ -460,9 +490,9 @@ paths:
$ref: '#/components/callbacks/CallbackA'`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Equal(t, 4, index.GetGlobalCallbacksCount())
}
@@ -477,9 +507,9 @@ func TestSpecIndex_ExtractComponentsFromRefs(t *testing.T) {
description: something`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Len(t, index.GetReferenceIndexErrors(), 1)
}
@@ -519,9 +549,9 @@ func TestSpecIndex_FindComponent_WithACrazyAssPath(t *testing.T) {
description: Not Found.`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
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)
@@ -540,9 +570,9 @@ func TestSpecIndex_FindComponenth(t *testing.T) {
description: something`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Nil(t, index.FindComponent("I-do-not-exist", nil))
}
@@ -558,9 +588,9 @@ func TestSpecIndex_TestPathsNodeAsArray(t *testing.T) {
description: something`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Nil(t, index.performExternalLookup(nil, "unknown", nil, nil))
}
@@ -596,15 +626,18 @@ func TestSpecIndex_lookupRemoteReference_NoComponent(t *testing.T) {
// Discovered in issue https://github.com/daveshanley/vacuum/issues/225
func TestSpecIndex_lookupFileReference_NoComponent(t *testing.T) {
cwd, _ := os.Getwd()
index := new(SpecIndex)
_ = ioutil.WriteFile("coffee-time.yaml", []byte("time: for coffee"), 0o664)
defer os.Remove("coffee-time.yaml")
index.config = &SpecIndexConfig{BasePath: cwd}
index.seenRemoteSources = make(map[string]*yaml.Node)
a, b, err := index.lookupFileReference("coffee-time.yaml")
assert.NoError(t, err)
assert.NotNil(t, a)
assert.NotNil(t, b)
_ = ioutil.WriteFile("coffee-time.yaml", []byte("time: for coffee"), 0o664)
defer os.Remove("coffee-time.yaml")
index.seenRemoteSources = make(map[string]*yaml.Node)
a, b, err := index.lookupFileReference("coffee-time.yaml")
assert.NoError(t, err)
assert.NotNil(t, a)
assert.NotNil(t, b)
}
func TestSpecIndex_CheckBadURLRef(t *testing.T) {
@@ -617,9 +650,9 @@ paths:
- $ref: 'httpsss://badurl'`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Len(t, index.refErrors, 2)
}
@@ -634,7 +667,7 @@ paths:
- $ref: 'httpsss://badurl'`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
c := CreateClosedAPIIndexConfig()
idx := NewSpecIndexWithConfig(&rootNode, c)
@@ -657,9 +690,9 @@ paths:
- $ref: 'coffee-time.yaml'`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.NotNil(t, index.GetAllParametersFromOperations()["/cakes"]["post"]["coffee-time.yaml"][0].Node)
}
@@ -676,13 +709,13 @@ func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_BadJSON(t *testing
}
func TestSpecIndex_lookupFileReference_BadFileName(t *testing.T) {
index := new(SpecIndex)
index := NewSpecIndexWithConfig(nil, CreateOpenAPIIndexConfig())
_, _, err := index.lookupFileReference("not-a-reference")
assert.Error(t, err)
}
func TestSpecIndex_lookupFileReference_SeenSourceSimulation_Error(t *testing.T) {
index := new(SpecIndex)
index := NewSpecIndexWithConfig(nil, CreateOpenAPIIndexConfig())
index.seenRemoteSources = make(map[string]*yaml.Node)
index.seenRemoteSources["magic-money-file.json"] = &yaml.Node{}
_, _, err := index.lookupFileReference("magic-money-file.json#something")
@@ -690,7 +723,7 @@ func TestSpecIndex_lookupFileReference_SeenSourceSimulation_Error(t *testing.T)
}
func TestSpecIndex_lookupFileReference_BadFile(t *testing.T) {
index := new(SpecIndex)
index := NewSpecIndexWithConfig(nil, CreateOpenAPIIndexConfig())
_, _, err := index.lookupFileReference("chickers.json#no-rice")
assert.Error(t, err)
}
@@ -698,8 +731,8 @@ func TestSpecIndex_lookupFileReference_BadFile(t *testing.T) {
func TestSpecIndex_lookupFileReference_BadFileDataRead(t *testing.T) {
_ = ioutil.WriteFile("chickers.yaml", []byte("broke: the: thing: [again]"), 0o664)
defer os.Remove("chickers.yaml")
index := new(SpecIndex)
var root yaml.Node
index := NewSpecIndexWithConfig(&root, CreateOpenAPIIndexConfig())
_, _, err := index.lookupFileReference("chickers.yaml#no-rice")
assert.Error(t, err)
}
@@ -708,7 +741,7 @@ func TestSpecIndex_lookupFileReference_MultiRes(t *testing.T) {
_ = ioutil.WriteFile("embie.yaml", []byte("naughty:\n - puppy: dog\n - puppy: naughty\npuppy:\n - naughty: puppy"), 0o664)
defer os.Remove("embie.yaml")
index := new(SpecIndex)
index := NewSpecIndexWithConfig(nil, CreateOpenAPIIndexConfig())
index.seenRemoteSources = make(map[string]*yaml.Node)
k, doc, err := index.lookupFileReference("embie.yaml#/.naughty")
assert.NoError(t, err)
@@ -720,7 +753,7 @@ func TestSpecIndex_lookupFileReference(t *testing.T) {
_ = ioutil.WriteFile("fox.yaml", []byte("good:\n - puppy: dog\n - puppy: forever-more"), 0o664)
defer os.Remove("fox.yaml")
index := new(SpecIndex)
index := NewSpecIndexWithConfig(nil, CreateOpenAPIIndexConfig())
index.seenRemoteSources = make(map[string]*yaml.Node)
k, doc, err := index.lookupFileReference("fox.yaml#/good")
assert.NoError(t, err)
@@ -766,9 +799,9 @@ components:
type: string`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
params := index.GetAllParametersFromOperations()
@@ -804,9 +837,9 @@ paths:
- url: https://api.example.com/v3`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
rootServers := index.GetAllRootServers()
@@ -842,9 +875,9 @@ func TestSpecIndex_schemaComponentsHaveParentsAndPaths(t *testing.T) {
type: object`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
schemas := index.GetAllSchemas()
@@ -892,9 +925,9 @@ paths:
description: OK`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
idx := NewSpecIndex(&rootNode)
idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Len(t, idx.paramAllRefs, 4)
assert.Len(t, idx.paramInlineDuplicateNames, 2)
@@ -941,9 +974,9 @@ paths:
description: OK`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
_ = yaml.Unmarshal([]byte(yml), &rootNode)
idx := NewSpecIndex(&rootNode)
idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
assert.Len(t, idx.paramAllRefs, 3)
assert.Len(t, idx.paramInlineDuplicateNames, 2)
@@ -983,7 +1016,7 @@ components:
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
objects := index.GetAllObjectsWithProperties()
assert.Len(t, objects, 3)
@@ -998,10 +1031,10 @@ func ExampleNewSpecIndex() {
stripeSpec, _ := ioutil.ReadFile("../test_specs/stripe.yaml")
// unmarshal spec into our rootNode
yaml.Unmarshal(stripeSpec, &rootNode)
_ = yaml.Unmarshal(stripeSpec, &rootNode)
// create a new specification index.
index := NewSpecIndex(&rootNode)
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
// print out some statistics
fmt.Printf("There are %d references\n"+

View File

@@ -433,7 +433,12 @@ func GenerateCleanSpecConfigBaseURL(baseURL *url.URL, dir string, includeFile bo
if baseURL.Scheme != "" && !strings.HasPrefix(dir, "http") {
p = fmt.Sprintf("%s://%s%s", baseURL.Scheme, baseURL.Host, cleanedPath)
} else {
p = cleanedPath
if !strings.Contains(cleanedPath, "/") {
p = ""
} else {
p = cleanedPath
}
}
if strings.HasSuffix(p, "/") {
p = p[:len(p)-1]