mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-11 04:20:24 +00:00
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:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"+
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user