mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 12:37:49 +00:00
bashing through usecases and updating tests as we go.
so many things that can go wrong. have to catch them all. Signed-off-by: quobix <dave@quobix.com>
This commit is contained in:
@@ -189,6 +189,7 @@ func (index *SpecIndex) ExtractRefs(node, parent *yaml.Node, seenPath []string,
|
|||||||
|
|
||||||
var p string
|
var p string
|
||||||
uri := strings.Split(value, "#/")
|
uri := strings.Split(value, "#/")
|
||||||
|
|
||||||
if strings.HasPrefix(value, "http") || filepath.IsAbs(value) {
|
if strings.HasPrefix(value, "http") || filepath.IsAbs(value) {
|
||||||
if len(uri) == 2 {
|
if len(uri) == 2 {
|
||||||
_, p = utils.ConvertComponentIdIntoFriendlyPathSearch(fmt.Sprintf("#/%s", uri[1]))
|
_, p = utils.ConvertComponentIdIntoFriendlyPathSearch(fmt.Sprintf("#/%s", uri[1]))
|
||||||
|
|||||||
@@ -62,8 +62,17 @@ func (index *SpecIndex) FindComponent(componentId string, parent *yaml.Node) *Re
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !strings.Contains(componentId, "#") {
|
if !strings.Contains(componentId, "#") {
|
||||||
|
|
||||||
|
// does it contain a file extension?
|
||||||
|
fileExt := filepath.Ext(componentId)
|
||||||
|
if fileExt != "" {
|
||||||
return index.lookupRolodex(uri)
|
return index.lookupRolodex(uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// root search
|
||||||
|
return index.FindComponentInRoot(componentId)
|
||||||
|
|
||||||
|
}
|
||||||
return index.FindComponentInRoot(fmt.Sprintf("#/%s", uri[0]))
|
return index.FindComponentInRoot(fmt.Sprintf("#/%s", uri[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,6 +377,7 @@ func (index *SpecIndex) lookupRolodex(uri []string) *Reference {
|
|||||||
if index.specAbsolutePath != "" {
|
if index.specAbsolutePath != "" {
|
||||||
if index.config.BaseURL != nil {
|
if index.config.BaseURL != nil {
|
||||||
|
|
||||||
|
// consider the file remote.
|
||||||
//if strings.Contains(file, "../../") {
|
//if strings.Contains(file, "../../") {
|
||||||
|
|
||||||
// extract the base path from the specAbsolutePath for this index.
|
// extract the base path from the specAbsolutePath for this index.
|
||||||
@@ -384,8 +394,11 @@ func (index *SpecIndex) lookupRolodex(uri []string) *Reference {
|
|||||||
//absoluteFileLocation = loc
|
//absoluteFileLocation = loc
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
panic("nooooooo")
|
|
||||||
absoluteFileLocation, _ = filepath.Abs(filepath.Join(index.config.BaseURL.Path, file))
|
// consider the file local
|
||||||
|
|
||||||
|
dir := filepath.Dir(index.config.SpecAbsolutePath)
|
||||||
|
absoluteFileLocation, _ = filepath.Abs(filepath.Join(dir, file))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
absoluteFileLocation = file
|
absoluteFileLocation = file
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func TestSpecIndex_CheckCircularIndex(t *testing.T) {
|
|||||||
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
||||||
|
|
||||||
cf := CreateOpenAPIIndexConfig()
|
cf := CreateOpenAPIIndexConfig()
|
||||||
cf.AvoidBuildIndex = true
|
cf.AvoidCircularReferenceCheck = true
|
||||||
cf.BasePath = "../test_specs"
|
cf.BasePath = "../test_specs"
|
||||||
|
|
||||||
rolo := NewRolodex(cf)
|
rolo := NewRolodex(cf)
|
||||||
|
|||||||
@@ -268,8 +268,8 @@ type SpecIndex struct {
|
|||||||
enumCount int
|
enumCount int
|
||||||
descriptionCount int
|
descriptionCount int
|
||||||
summaryCount int
|
summaryCount int
|
||||||
seenRemoteSources map[string]*yaml.Node
|
//seenRemoteSources map[string]*yaml.Node
|
||||||
seenLocalSources map[string]*yaml.Node
|
//seenLocalSources map[string]*yaml.Node
|
||||||
refLock sync.Mutex
|
refLock sync.Mutex
|
||||||
componentLock sync.RWMutex
|
componentLock sync.RWMutex
|
||||||
errorLock sync.RWMutex
|
errorLock sync.RWMutex
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ func boostrapIndexCollections(rootNode *yaml.Node, index *SpecIndex) {
|
|||||||
index.securityRequirementRefs = make(map[string]map[string][]*Reference)
|
index.securityRequirementRefs = make(map[string]map[string][]*Reference)
|
||||||
index.polymorphicRefs = make(map[string]*Reference)
|
index.polymorphicRefs = make(map[string]*Reference)
|
||||||
index.refsWithSiblings = make(map[string]Reference)
|
index.refsWithSiblings = make(map[string]Reference)
|
||||||
index.seenRemoteSources = make(map[string]*yaml.Node)
|
//index.seenRemoteSources = make(map[string]*yaml.Node)
|
||||||
index.seenLocalSources = make(map[string]*yaml.Node)
|
//index.seenLocalSources = make(map[string]*yaml.Node)
|
||||||
index.opServersRefs = make(map[string]map[string][]*Reference)
|
index.opServersRefs = make(map[string]map[string][]*Reference)
|
||||||
index.httpClient = &http.Client{Timeout: time.Duration(5) * time.Second}
|
index.httpClient = &http.Client{Timeout: time.Duration(5) * time.Second}
|
||||||
index.componentIndexChan = make(chan bool)
|
index.componentIndexChan = make(chan bool)
|
||||||
|
|||||||
@@ -258,10 +258,6 @@ func (r *Rolodex) IndexTheRolodex() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable index building, it will need to be run after the rolodex indexed
|
|
||||||
// at a high level.
|
|
||||||
r.indexConfig.AvoidBuildIndex = true
|
|
||||||
|
|
||||||
var caughtErrors []error
|
var caughtErrors []error
|
||||||
|
|
||||||
var indexBuildQueue []*SpecIndex
|
var indexBuildQueue []*SpecIndex
|
||||||
@@ -373,6 +369,19 @@ func (r *Rolodex) IndexTheRolodex() error {
|
|||||||
|
|
||||||
if r.rootNode != nil {
|
if r.rootNode != nil {
|
||||||
|
|
||||||
|
// if there is a base path, then we need to set the root spec config to point to a theoretical root.yaml
|
||||||
|
// which does not exist, but is used to formulate the absolute path to root references correctly.
|
||||||
|
if r.indexConfig.BasePath != "" && r.indexConfig.BaseURL == nil {
|
||||||
|
|
||||||
|
basePath := r.indexConfig.BasePath
|
||||||
|
if !filepath.IsAbs(basePath) {
|
||||||
|
basePath, _ = filepath.Abs(basePath)
|
||||||
|
}
|
||||||
|
r.indexConfig.SpecAbsolutePath = filepath.Join(basePath, "root.yaml")
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: variation with no base path, but a base URL.
|
||||||
|
|
||||||
index := NewSpecIndexWithConfig(r.rootNode, r.indexConfig)
|
index := NewSpecIndexWithConfig(r.rootNode, r.indexConfig)
|
||||||
resolver := NewResolver(index)
|
resolver := NewResolver(index)
|
||||||
if r.indexConfig.IgnoreArrayCircularReferences {
|
if r.indexConfig.IgnoreArrayCircularReferences {
|
||||||
@@ -382,9 +391,7 @@ func (r *Rolodex) IndexTheRolodex() error {
|
|||||||
resolver.IgnorePolymorphicCircularReferences()
|
resolver.IgnorePolymorphicCircularReferences()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !r.indexConfig.AvoidBuildIndex {
|
|
||||||
index.BuildIndex()
|
index.BuildIndex()
|
||||||
}
|
|
||||||
|
|
||||||
if !r.indexConfig.AvoidCircularReferenceCheck {
|
if !r.indexConfig.AvoidCircularReferenceCheck {
|
||||||
resolvingErrors := resolver.CheckForCircularReferences()
|
resolvingErrors := resolver.CheckForCircularReferences()
|
||||||
@@ -393,10 +400,14 @@ func (r *Rolodex) IndexTheRolodex() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.rootIndex = index
|
r.rootIndex = index
|
||||||
|
if len(index.refErrors) > 0 {
|
||||||
|
caughtErrors = append(caughtErrors, index.refErrors...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
r.indexingDuration = time.Since(started)
|
r.indexingDuration = time.Since(started)
|
||||||
r.indexed = true
|
r.indexed = true
|
||||||
r.caughtErrors = caughtErrors
|
r.caughtErrors = caughtErrors
|
||||||
|
r.built = true
|
||||||
return errors.Join(caughtErrors...)
|
return errors.Join(caughtErrors...)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type LocalFS struct {
|
type LocalFS struct {
|
||||||
|
indexConfig *SpecIndexConfig
|
||||||
entryPointDirectory string
|
entryPointDirectory string
|
||||||
baseDirectory string
|
baseDirectory string
|
||||||
Files map[string]RolodexFile
|
Files map[string]RolodexFile
|
||||||
@@ -28,7 +29,18 @@ func (l *LocalFS) GetFiles() map[string]RolodexFile {
|
|||||||
return l.Files
|
return l.Files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *LocalFS) GetErrors() []error {
|
||||||
|
return l.readingErrors
|
||||||
|
}
|
||||||
|
|
||||||
func (l *LocalFS) Open(name string) (fs.File, error) {
|
func (l *LocalFS) Open(name string) (fs.File, error) {
|
||||||
|
|
||||||
|
if l.indexConfig != nil && !l.indexConfig.AllowFileLookup {
|
||||||
|
return nil, &fs.PathError{Op: "open", Path: name,
|
||||||
|
Err: fmt.Errorf("file lookup for '%s' not allowed, set the index configuration "+
|
||||||
|
"to AllowFileLookup to be true", name)}
|
||||||
|
}
|
||||||
|
|
||||||
if !filepath.IsAbs(name) {
|
if !filepath.IsAbs(name) {
|
||||||
var absErr error
|
var absErr error
|
||||||
name, absErr = filepath.Abs(filepath.Join(l.baseDirectory, name))
|
name, absErr = filepath.Abs(filepath.Join(l.baseDirectory, name))
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ type RemoteFS struct {
|
|||||||
rootURLParsed *url.URL
|
rootURLParsed *url.URL
|
||||||
RemoteHandlerFunc RemoteURLHandler
|
RemoteHandlerFunc RemoteURLHandler
|
||||||
Files syncmap.Map
|
Files syncmap.Map
|
||||||
|
ProcessingFiles syncmap.Map
|
||||||
FetchTime int64
|
FetchTime int64
|
||||||
FetchChannel chan *RemoteFile
|
FetchChannel chan *RemoteFile
|
||||||
remoteWg sync.WaitGroup
|
remoteWg sync.WaitGroup
|
||||||
@@ -235,6 +236,10 @@ func (i *RemoteFS) GetFiles() map[string]RolodexFile {
|
|||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *RemoteFS) GetErrors() []error {
|
||||||
|
return i.remoteErrors
|
||||||
|
}
|
||||||
|
|
||||||
func (i *RemoteFS) seekRelatives(file *RemoteFile) {
|
func (i *RemoteFS) seekRelatives(file *RemoteFile) {
|
||||||
|
|
||||||
extractedRefs := ExtractRefs(string(file.data))
|
extractedRefs := ExtractRefs(string(file.data))
|
||||||
@@ -288,6 +293,11 @@ func (i *RemoteFS) seekRelatives(file *RemoteFile) {
|
|||||||
|
|
||||||
func (i *RemoteFS) Open(remoteURL string) (fs.File, error) {
|
func (i *RemoteFS) Open(remoteURL string) (fs.File, error) {
|
||||||
|
|
||||||
|
if i.indexConfig != nil && !i.indexConfig.AllowRemoteLookup {
|
||||||
|
return nil, fmt.Errorf("remote lookup for '%s' is not allowed, please set "+
|
||||||
|
"AllowRemoteLookup to true as part of the index configuration", remoteURL)
|
||||||
|
}
|
||||||
|
|
||||||
remoteParsedURL, err := url.Parse(remoteURL)
|
remoteParsedURL, err := url.Parse(remoteURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -298,6 +308,20 @@ func (i *RemoteFS) Open(remoteURL string) (fs.File, error) {
|
|||||||
return r.(*RemoteFile), nil
|
return r.(*RemoteFile), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we're processing, we need to block and wait for the file to be processed
|
||||||
|
// try path first
|
||||||
|
if _, ok := i.ProcessingFiles.Load(remoteParsedURL.Path); ok {
|
||||||
|
i.logger.Debug("waiting for existing fetch to complete", "file", remoteURL, "remoteURL", remoteParsedURL.String())
|
||||||
|
for {
|
||||||
|
if wf, ko := i.Files.Load(remoteParsedURL.Path); ko {
|
||||||
|
return wf.(*RemoteFile), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to processing
|
||||||
|
i.ProcessingFiles.Store(remoteParsedURL.Path, true)
|
||||||
|
|
||||||
fileExt := ExtractFileType(remoteParsedURL.Path)
|
fileExt := ExtractFileType(remoteParsedURL.Path)
|
||||||
|
|
||||||
if fileExt == UNSUPPORTED {
|
if fileExt == UNSUPPORTED {
|
||||||
@@ -314,7 +338,7 @@ 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.
|
// no handler func? use the default client.
|
||||||
if i.RemoteHandlerFunc == nil {
|
if i.RemoteHandlerFunc == nil {
|
||||||
@@ -323,20 +347,32 @@ func (i *RemoteFS) Open(remoteURL string) (fs.File, error) {
|
|||||||
|
|
||||||
response, clientErr := i.RemoteHandlerFunc(remoteParsedURL.String())
|
response, clientErr := i.RemoteHandlerFunc(remoteParsedURL.String())
|
||||||
if clientErr != nil {
|
if clientErr != nil {
|
||||||
|
|
||||||
|
i.remoteErrors = append(i.remoteErrors, clientErr)
|
||||||
|
// remove from processing
|
||||||
|
i.ProcessingFiles.Delete(remoteParsedURL.Path)
|
||||||
if response != nil {
|
if response != nil {
|
||||||
i.logger.Error("client error", "error", clientErr, "status", response.StatusCode)
|
i.logger.Error("client error", "error", clientErr, "status", response.StatusCode)
|
||||||
} else {
|
} else {
|
||||||
i.logger.Error("no response for request", "error", clientErr.Error())
|
i.logger.Error("client error, empty body", "error", clientErr.Error())
|
||||||
}
|
}
|
||||||
return nil, clientErr
|
return nil, clientErr
|
||||||
}
|
}
|
||||||
|
|
||||||
responseBytes, readError := io.ReadAll(response.Body)
|
responseBytes, readError := io.ReadAll(response.Body)
|
||||||
if readError != nil {
|
if readError != nil {
|
||||||
|
|
||||||
|
// remove from processing
|
||||||
|
i.ProcessingFiles.Delete(remoteParsedURL.Path)
|
||||||
|
|
||||||
return nil, readError
|
return nil, readError
|
||||||
}
|
}
|
||||||
|
|
||||||
if response.StatusCode >= 400 {
|
if response.StatusCode >= 400 {
|
||||||
|
|
||||||
|
// remove from processing
|
||||||
|
i.ProcessingFiles.Delete(remoteParsedURL.Path)
|
||||||
|
|
||||||
i.logger.Error("Unable to fetch remote document",
|
i.logger.Error("Unable to fetch remote document",
|
||||||
"file", remoteParsedURL.Path, "status", response.StatusCode, "resp", string(responseBytes))
|
"file", remoteParsedURL.Path, "status", response.StatusCode, "resp", string(responseBytes))
|
||||||
return nil, fmt.Errorf("unable to fetch remote document: %s", string(responseBytes))
|
return nil, fmt.Errorf("unable to fetch remote document: %s", string(responseBytes))
|
||||||
@@ -344,6 +380,8 @@ func (i *RemoteFS) Open(remoteURL string) (fs.File, error) {
|
|||||||
|
|
||||||
absolutePath, pathErr := filepath.Abs(remoteParsedURL.Path)
|
absolutePath, pathErr := filepath.Abs(remoteParsedURL.Path)
|
||||||
if pathErr != nil {
|
if pathErr != nil {
|
||||||
|
// remove from processing
|
||||||
|
i.ProcessingFiles.Delete(remoteParsedURL.Path)
|
||||||
return nil, pathErr
|
return nil, pathErr
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,11 +432,16 @@ func (i *RemoteFS) Open(remoteURL string) (fs.File, error) {
|
|||||||
|
|
||||||
i.Files.Store(absolutePath, remoteFile)
|
i.Files.Store(absolutePath, remoteFile)
|
||||||
|
|
||||||
|
if len(remoteFile.data) > 0 {
|
||||||
i.logger.Debug("successfully loaded file", "file", absolutePath)
|
i.logger.Debug("successfully loaded file", "file", absolutePath)
|
||||||
|
}
|
||||||
i.seekRelatives(remoteFile)
|
i.seekRelatives(remoteFile)
|
||||||
|
|
||||||
idx.BuildIndex()
|
idx.BuildIndex()
|
||||||
|
|
||||||
|
// remove from processing
|
||||||
|
i.ProcessingFiles.Delete(remoteParsedURL.Path)
|
||||||
|
|
||||||
if !i.remoteRunning {
|
if !i.remoteRunning {
|
||||||
return remoteFile, errors.Join(i.remoteErrors...)
|
return remoteFile, errors.Join(i.remoteErrors...)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -24,12 +24,27 @@ func (index *SpecIndex) SearchIndexForReferenceByReference(fullRef *Reference) *
|
|||||||
if strings.HasPrefix(uri[0], "http") {
|
if strings.HasPrefix(uri[0], "http") {
|
||||||
roloLookup = fullRef.FullDefinition
|
roloLookup = fullRef.FullDefinition
|
||||||
} else {
|
} else {
|
||||||
|
if filepath.IsAbs(uri[0]) {
|
||||||
|
roloLookup = uri[0]
|
||||||
|
} else {
|
||||||
|
if filepath.Ext(absPath) != "" {
|
||||||
|
absPath = filepath.Dir(absPath)
|
||||||
|
}
|
||||||
roloLookup, _ = filepath.Abs(filepath.Join(absPath, uri[0]))
|
roloLookup, _ = filepath.Abs(filepath.Join(absPath, uri[0]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ref = fmt.Sprintf("#/%s", uri[1])
|
ref = fmt.Sprintf("#/%s", uri[1])
|
||||||
} else {
|
} else {
|
||||||
|
if filepath.IsAbs(uri[0]) {
|
||||||
|
roloLookup = uri[0]
|
||||||
|
} else {
|
||||||
|
if filepath.Ext(absPath) != "" {
|
||||||
|
absPath = filepath.Dir(absPath)
|
||||||
|
}
|
||||||
roloLookup, _ = filepath.Abs(filepath.Join(absPath, uri[0]))
|
roloLookup, _ = filepath.Abs(filepath.Join(absPath, uri[0]))
|
||||||
|
}
|
||||||
|
|
||||||
ref = uri[0]
|
ref = uri[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +80,15 @@ func (index *SpecIndex) SearchIndexForReferenceByReference(fullRef *Reference) *
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// does component exist in the root?
|
||||||
|
node, _ := rFile.GetContentAsYAMLNode()
|
||||||
|
if node != nil {
|
||||||
|
found := idx.FindComponent(ref, node)
|
||||||
|
if found != nil {
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -430,10 +430,10 @@ func (index *SpecIndex) GetAllOperationsServers() map[string]map[string][]*Refer
|
|||||||
return index.opServersRefs
|
return index.opServersRefs
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllExternalIndexes will return all indexes for external documents
|
//// GetAllExternalIndexes will return all indexes for external documents
|
||||||
func (index *SpecIndex) GetAllExternalIndexes() map[string]*SpecIndex {
|
//func (index *SpecIndex) GetAllExternalIndexes() map[string]*SpecIndex {
|
||||||
return index.externalSpecIndex
|
// return index.externalSpecIndex
|
||||||
}
|
//}
|
||||||
|
|
||||||
// SetAllowCircularReferenceResolving will flip a bit that can be used by any consumers to determine if they want
|
// SetAllowCircularReferenceResolving will flip a bit that can be used by any consumers to determine if they want
|
||||||
// to allow or disallow circular references to be resolved or visited
|
// to allow or disallow circular references to be resolved or visited
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package index
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/pb33f/libopenapi/utils"
|
||||||
"log"
|
"log"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -64,7 +65,6 @@ func TestSpecIndex_ExtractRefsStripe(t *testing.T) {
|
|||||||
assert.Len(t, index.GetRefsByLine(), 537)
|
assert.Len(t, index.GetRefsByLine(), 537)
|
||||||
assert.Len(t, index.GetLinesWithReferences(), 1972)
|
assert.Len(t, index.GetLinesWithReferences(), 1972)
|
||||||
assert.Len(t, index.GetAllExternalDocuments(), 0)
|
assert.Len(t, index.GetAllExternalDocuments(), 0)
|
||||||
assert.Len(t, index.GetAllExternalIndexes(), 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_Asana(t *testing.T) {
|
func TestSpecIndex_Asana(t *testing.T) {
|
||||||
@@ -97,7 +97,7 @@ func TestSpecIndex_DigitalOcean(t *testing.T) {
|
|||||||
location := "https://raw.githubusercontent.com/digitalocean/openapi/main/specification"
|
location := "https://raw.githubusercontent.com/digitalocean/openapi/main/specification"
|
||||||
baseURL, _ := url.Parse(location)
|
baseURL, _ := url.Parse(location)
|
||||||
|
|
||||||
// create a new config that allows local and remote to be mixed up.
|
// create a new config that allows remote lookups.
|
||||||
cf := &SpecIndexConfig{}
|
cf := &SpecIndexConfig{}
|
||||||
cf.AvoidBuildIndex = true
|
cf.AvoidBuildIndex = true
|
||||||
cf.AllowRemoteLookup = true
|
cf.AllowRemoteLookup = true
|
||||||
@@ -121,7 +121,6 @@ func TestSpecIndex_DigitalOcean(t *testing.T) {
|
|||||||
// create a handler that uses an env variable to capture any GITHUB_TOKEN in the OS ENV
|
// create a handler that uses an env variable to capture any GITHUB_TOKEN in the OS ENV
|
||||||
// and inject it into the request header, so this does not fail when running lots of local tests.
|
// and inject it into the request header, so this does not fail when running lots of local tests.
|
||||||
if os.Getenv("GITHUB_TOKEN") != "" {
|
if os.Getenv("GITHUB_TOKEN") != "" {
|
||||||
|
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Timeout: time.Second * 60,
|
Timeout: time.Second * 60,
|
||||||
}
|
}
|
||||||
@@ -130,7 +129,6 @@ func TestSpecIndex_DigitalOcean(t *testing.T) {
|
|||||||
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("GITHUB_TOKEN")))
|
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("GITHUB_TOKEN")))
|
||||||
return client.Do(request)
|
return client.Do(request)
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add remote filesystem
|
// add remote filesystem
|
||||||
@@ -143,19 +141,7 @@ func TestSpecIndex_DigitalOcean(t *testing.T) {
|
|||||||
files := remoteFS.GetFiles()
|
files := remoteFS.GetFiles()
|
||||||
fileLen := len(files)
|
fileLen := len(files)
|
||||||
assert.Equal(t, 1646, fileLen)
|
assert.Equal(t, 1646, fileLen)
|
||||||
|
assert.Len(t, remoteFS.GetErrors(), 0)
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//assert.NoError(t, indexedErr)
|
|
||||||
//
|
|
||||||
//index := rolo.GetRootIndex()
|
|
||||||
//rolo.CheckForCircularReferences()
|
|
||||||
//
|
|
||||||
//assert.Len(t, index.GetAllExternalIndexes(), 291)
|
|
||||||
//assert.NotNil(t, index)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve(t *testing.T) {
|
func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve(t *testing.T) {
|
||||||
@@ -163,69 +149,153 @@ func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve(t *testing.T) {
|
|||||||
tmp, _ := os.MkdirTemp("", "openapi")
|
tmp, _ := os.MkdirTemp("", "openapi")
|
||||||
cmd := exec.Command("git", "clone", "https://github.com/digitalocean/openapi", tmp)
|
cmd := exec.Command("git", "clone", "https://github.com/digitalocean/openapi", tmp)
|
||||||
defer os.RemoveAll(filepath.Join(tmp, "openapi"))
|
defer os.RemoveAll(filepath.Join(tmp, "openapi"))
|
||||||
|
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("cmd.Run() failed with %s\n", err)
|
log.Fatalf("cmd.Run() failed with %s\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
spec, _ := filepath.Abs(filepath.Join(tmp, "specification", "DigitalOcean-public.v2.yaml"))
|
spec, _ := filepath.Abs(filepath.Join(tmp, "specification", "DigitalOcean-public.v2.yaml"))
|
||||||
doLocal, _ := os.ReadFile(spec)
|
doLocal, _ := os.ReadFile(spec)
|
||||||
|
|
||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(doLocal, &rootNode)
|
_ = yaml.Unmarshal(doLocal, &rootNode)
|
||||||
|
|
||||||
config := CreateOpenAPIIndexConfig()
|
basePath := filepath.Join(tmp, "specification")
|
||||||
config.BasePath = filepath.Join(tmp, "specification")
|
|
||||||
|
|
||||||
index := NewSpecIndexWithConfig(&rootNode, config)
|
// create a new config that allows local and remote to be mixed up.
|
||||||
|
cf := CreateOpenAPIIndexConfig()
|
||||||
|
cf.AvoidBuildIndex = true
|
||||||
|
cf.AllowRemoteLookup = true
|
||||||
|
cf.AvoidCircularReferenceCheck = true
|
||||||
|
cf.BasePath = basePath
|
||||||
|
|
||||||
|
// create a new rolodex
|
||||||
|
rolo := NewRolodex(cf)
|
||||||
|
|
||||||
|
// set the rolodex root node to the root node of the spec.
|
||||||
|
rolo.SetRootNode(&rootNode)
|
||||||
|
|
||||||
|
// configure the local filesystem.
|
||||||
|
fsCfg := LocalFSConfig{
|
||||||
|
BaseDirectory: cf.BasePath,
|
||||||
|
DirFS: os.DirFS(cf.BasePath),
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new local filesystem.
|
||||||
|
fileFS, fsErr := NewLocalFSWithConfig(&fsCfg)
|
||||||
|
assert.NoError(t, fsErr)
|
||||||
|
|
||||||
|
files := fileFS.GetFiles()
|
||||||
|
fileLen := len(files)
|
||||||
|
|
||||||
|
assert.Equal(t, 1684, fileLen)
|
||||||
|
|
||||||
|
rolo.AddLocalFS(basePath, fileFS)
|
||||||
|
|
||||||
|
rErr := rolo.IndexTheRolodex()
|
||||||
|
|
||||||
|
assert.NoError(t, rErr)
|
||||||
|
|
||||||
|
index := rolo.GetRootIndex()
|
||||||
|
|
||||||
assert.NotNil(t, index)
|
assert.NotNil(t, index)
|
||||||
assert.Len(t, index.GetAllExternalIndexes(), 296)
|
|
||||||
|
|
||||||
ref := index.SearchIndexForReference("resources/apps/apps_list_instanceSizes.yml")
|
assert.Len(t, index.GetMappedReferencesSequenced(), 296)
|
||||||
assert.NotNil(t, ref)
|
assert.Len(t, index.GetMappedReferences(), 296)
|
||||||
assert.Equal(t, "operationId", ref.Node.Content[0].Value)
|
assert.Len(t, fileFS.GetErrors(), 0)
|
||||||
|
|
||||||
ref = index.SearchIndexForReference("examples/ruby/domains_create.yml")
|
|
||||||
assert.NotNil(t, ref)
|
|
||||||
assert.Equal(t, "lang", ref.Node.Content[0].Value)
|
|
||||||
|
|
||||||
ref = index.SearchIndexForReference("../../shared/responses/server_error.yml")
|
|
||||||
assert.NotNil(t, ref)
|
|
||||||
assert.Equal(t, "description", ref.Node.Content[0].Value)
|
|
||||||
|
|
||||||
ref = index.SearchIndexForReference("../models/options.yml")
|
|
||||||
assert.NotNil(t, ref)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_DigitalOcean_LookupsNotAllowed(t *testing.T) {
|
func TestSpecIndex_DigitalOcean_LookupsNotAllowed(t *testing.T) {
|
||||||
asana, _ := os.ReadFile("../test_specs/digitalocean.yaml")
|
do, _ := os.ReadFile("../test_specs/digitalocean.yaml")
|
||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(asana, &rootNode)
|
_ = yaml.Unmarshal(do, &rootNode)
|
||||||
|
|
||||||
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
|
location := "https://raw.githubusercontent.com/digitalocean/openapi/main/specification"
|
||||||
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
|
baseURL, _ := url.Parse(location)
|
||||||
BaseURL: baseURL,
|
|
||||||
})
|
// create a new config that does not allow remote lookups.
|
||||||
|
cf := &SpecIndexConfig{}
|
||||||
|
cf.AvoidBuildIndex = true
|
||||||
|
cf.AvoidCircularReferenceCheck = true
|
||||||
|
cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
||||||
|
Level: slog.LevelError,
|
||||||
|
}))
|
||||||
|
|
||||||
|
// setting this baseURL will override the base
|
||||||
|
cf.BaseURL = baseURL
|
||||||
|
|
||||||
|
// create a new rolodex
|
||||||
|
rolo := NewRolodex(cf)
|
||||||
|
|
||||||
|
// set the rolodex root node to the root node of the spec.
|
||||||
|
rolo.SetRootNode(&rootNode)
|
||||||
|
|
||||||
|
// create a new remote fs and set the config for indexing.
|
||||||
|
remoteFS, _ := NewRemoteFSWithConfig(cf)
|
||||||
|
|
||||||
|
// add remote filesystem
|
||||||
|
rolo.AddRemoteFS(location, remoteFS)
|
||||||
|
|
||||||
|
// index the rolodex.
|
||||||
|
indexedErr := rolo.IndexTheRolodex()
|
||||||
|
assert.Error(t, indexedErr)
|
||||||
|
assert.Len(t, utils.UnwrapErrors(indexedErr), 291)
|
||||||
|
|
||||||
|
index := rolo.GetRootIndex()
|
||||||
|
|
||||||
|
files := remoteFS.GetFiles()
|
||||||
|
fileLen := len(files)
|
||||||
|
assert.Equal(t, 0, fileLen)
|
||||||
|
assert.Len(t, remoteFS.GetErrors(), 0)
|
||||||
|
|
||||||
// no lookups allowed, bits have not been set, so there should just be a bunch of errors.
|
// no lookups allowed, bits have not been set, so there should just be a bunch of errors.
|
||||||
assert.Len(t, index.GetAllExternalIndexes(), 0)
|
|
||||||
assert.True(t, len(index.GetReferenceIndexErrors()) > 0)
|
assert.True(t, len(index.GetReferenceIndexErrors()) > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_BaseURLError(t *testing.T) {
|
func TestSpecIndex_BaseURLError(t *testing.T) {
|
||||||
asana, _ := os.ReadFile("../test_specs/digitalocean.yaml")
|
|
||||||
|
do, _ := os.ReadFile("../test_specs/digitalocean.yaml")
|
||||||
var rootNode yaml.Node
|
var rootNode yaml.Node
|
||||||
_ = yaml.Unmarshal(asana, &rootNode)
|
_ = yaml.Unmarshal(do, &rootNode)
|
||||||
|
|
||||||
// this should fail because the base url is not a valid url and digital ocean won't be able to resolve
|
location := "https://githerbsandcoffeeandcode.com/fresh/herbs/for/you" // not gonna work bro.
|
||||||
// anything.
|
baseURL, _ := url.Parse(location)
|
||||||
baseURL, _ := url.Parse("https://githerbs.com/fresh/herbs/for/you")
|
|
||||||
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
|
// create a new config that allows remote lookups.
|
||||||
BaseURL: baseURL,
|
cf := &SpecIndexConfig{}
|
||||||
//AllowRemoteLookup: true,
|
cf.AvoidBuildIndex = true
|
||||||
//AllowFileLookup: true,
|
cf.AllowRemoteLookup = true
|
||||||
})
|
cf.AvoidCircularReferenceCheck = true
|
||||||
|
cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
||||||
|
Level: slog.LevelError,
|
||||||
|
}))
|
||||||
|
|
||||||
|
// setting this baseURL will override the base
|
||||||
|
cf.BaseURL = baseURL
|
||||||
|
|
||||||
|
// create a new rolodex
|
||||||
|
rolo := NewRolodex(cf)
|
||||||
|
|
||||||
|
// set the rolodex root node to the root node of the spec.
|
||||||
|
rolo.SetRootNode(&rootNode)
|
||||||
|
|
||||||
|
// create a new remote fs and set the config for indexing.
|
||||||
|
remoteFS, _ := NewRemoteFSWithConfig(cf)
|
||||||
|
|
||||||
|
// add remote filesystem
|
||||||
|
rolo.AddRemoteFS(location, remoteFS)
|
||||||
|
|
||||||
|
// index the rolodex.
|
||||||
|
indexedErr := rolo.IndexTheRolodex()
|
||||||
|
assert.Error(t, indexedErr)
|
||||||
|
assert.Len(t, utils.UnwrapErrors(indexedErr), 291)
|
||||||
|
|
||||||
|
files := remoteFS.GetFiles()
|
||||||
|
fileLen := len(files)
|
||||||
|
assert.Equal(t, 0, fileLen)
|
||||||
|
assert.GreaterOrEqual(t, len(remoteFS.GetErrors()), 200)
|
||||||
|
|
||||||
assert.Len(t, index.GetAllExternalIndexes(), 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_k8s(t *testing.T) {
|
func TestSpecIndex_k8s(t *testing.T) {
|
||||||
@@ -494,13 +564,9 @@ func test_buildMixedRefServer() *httptest.Server {
|
|||||||
|
|
||||||
bs, _ := os.ReadFile("../test_specs/burgershop.openapi.yaml")
|
bs, _ := os.ReadFile("../test_specs/burgershop.openapi.yaml")
|
||||||
return httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
return httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
if req.URL.String() == "/daveshanley/vacuum/main/model/test_files/burgershop.openapi.yaml" {
|
|
||||||
rw.Header().Set("Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT")
|
rw.Header().Set("Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT")
|
||||||
_, _ = rw.Write(bs)
|
_, _ = rw.Write(bs)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _ = rw.Write([]byte(`OK`))
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,6 +582,9 @@ func TestSpecIndex_BurgerShopMixedRef(t *testing.T) {
|
|||||||
cf.AllowRemoteLookup = true
|
cf.AllowRemoteLookup = true
|
||||||
cf.AvoidCircularReferenceCheck = true
|
cf.AvoidCircularReferenceCheck = true
|
||||||
cf.BasePath = "../test_specs"
|
cf.BasePath = "../test_specs"
|
||||||
|
cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
||||||
|
Level: slog.LevelError,
|
||||||
|
}))
|
||||||
|
|
||||||
// setting this baseURL will override the base
|
// setting this baseURL will override the base
|
||||||
cf.BaseURL, _ = url.Parse(server.URL)
|
cf.BaseURL, _ = url.Parse(server.URL)
|
||||||
@@ -720,7 +789,7 @@ func TestSpecIndex_FindComponent_WithACrazyAssPath(t *testing.T) {
|
|||||||
index.FindComponent("#/paths/~1crazy~1ass~1references/get/parameters/0", nil).Node.Content[1].Value)
|
index.FindComponent("#/paths/~1crazy~1ass~1references/get/parameters/0", nil).Node.Content[1].Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_FindComponenth(t *testing.T) {
|
func TestSpecIndex_FindComponent(t *testing.T) {
|
||||||
yml := `components:
|
yml := `components:
|
||||||
schemas:
|
schemas:
|
||||||
pizza:
|
pizza:
|
||||||
@@ -754,34 +823,34 @@ func TestSpecIndex_TestPathsNodeAsArray(t *testing.T) {
|
|||||||
assert.Nil(t, index.lookupRolodex(nil))
|
assert.Nil(t, index.lookupRolodex(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_Error(t *testing.T) {
|
//func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_Error(t *testing.T) {
|
||||||
index := new(SpecIndex)
|
// index := new(SpecIndex)
|
||||||
index.seenRemoteSources = make(map[string]*yaml.Node)
|
// index.seenRemoteSources = make(map[string]*yaml.Node)
|
||||||
index.seenRemoteSources["https://no-hope-for-a-dope.com"] = &yaml.Node{}
|
// index.seenRemoteSources["https://no-hope-for-a-dope.com"] = &yaml.Node{}
|
||||||
_, _, err := index.lookupRemoteReference("https://no-hope-for-a-dope.com#/$.....#[;]something")
|
// _, _, err := index.lookupRemoteReference("https://no-hope-for-a-dope.com#/$.....#[;]something")
|
||||||
assert.Error(t, err)
|
// assert.Error(t, err)
|
||||||
}
|
//}
|
||||||
|
|
||||||
func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_BadFind(t *testing.T) {
|
//func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_BadFind(t *testing.T) {
|
||||||
index := new(SpecIndex)
|
// index := new(SpecIndex)
|
||||||
index.seenRemoteSources = make(map[string]*yaml.Node)
|
// index.seenRemoteSources = make(map[string]*yaml.Node)
|
||||||
index.seenRemoteSources["https://no-hope-for-a-dope.com"] = &yaml.Node{}
|
// index.seenRemoteSources["https://no-hope-for-a-dope.com"] = &yaml.Node{}
|
||||||
a, b, err := index.lookupRemoteReference("https://no-hope-for-a-dope.com#/hey")
|
// a, b, err := index.lookupRemoteReference("https://no-hope-for-a-dope.com#/hey")
|
||||||
assert.Error(t, err)
|
// assert.Error(t, err)
|
||||||
assert.Nil(t, a)
|
// assert.Nil(t, a)
|
||||||
assert.Nil(t, b)
|
// assert.Nil(t, b)
|
||||||
}
|
//}
|
||||||
|
|
||||||
// Discovered in issue https://github.com/pb33f/libopenapi/issues/37
|
// Discovered in issue https://github.com/pb33f/libopenapi/issues/37
|
||||||
func TestSpecIndex_lookupRemoteReference_NoComponent(t *testing.T) {
|
//func TestSpecIndex_lookupRemoteReference_NoComponent(t *testing.T) {
|
||||||
index := new(SpecIndex)
|
// index := new(SpecIndex)
|
||||||
index.seenRemoteSources = make(map[string]*yaml.Node)
|
// index.seenRemoteSources = make(map[string]*yaml.Node)
|
||||||
index.seenRemoteSources["https://api.rest.sh/schemas/ErrorModel.json"] = &yaml.Node{}
|
// index.seenRemoteSources["https://api.rest.sh/schemas/ErrorModel.json"] = &yaml.Node{}
|
||||||
a, b, err := index.lookupRemoteReference("https://api.rest.sh/schemas/ErrorModel.json")
|
// a, b, err := index.lookupRemoteReference("https://api.rest.sh/schemas/ErrorModel.json")
|
||||||
assert.NoError(t, err)
|
// assert.NoError(t, err)
|
||||||
assert.NotNil(t, a)
|
// assert.NotNil(t, a)
|
||||||
assert.NotNil(t, b)
|
// assert.NotNil(t, b)
|
||||||
}
|
//}
|
||||||
|
|
||||||
// Discovered in issue https://github.com/daveshanley/vacuum/issues/225
|
// Discovered in issue https://github.com/daveshanley/vacuum/issues/225
|
||||||
func TestSpecIndex_lookupFileReference_NoComponent(t *testing.T) {
|
func TestSpecIndex_lookupFileReference_NoComponent(t *testing.T) {
|
||||||
@@ -792,29 +861,13 @@ func TestSpecIndex_lookupFileReference_NoComponent(t *testing.T) {
|
|||||||
_ = os.WriteFile("coffee-time.yaml", []byte("time: for coffee"), 0o664)
|
_ = os.WriteFile("coffee-time.yaml", []byte("time: for coffee"), 0o664)
|
||||||
defer os.Remove("coffee-time.yaml")
|
defer os.Remove("coffee-time.yaml")
|
||||||
|
|
||||||
index.seenRemoteSources = make(map[string]*yaml.Node)
|
//index.seenRemoteSources = make(map[string]*yaml.Node)
|
||||||
a, b, err := index.lookupFileReference("coffee-time.yaml")
|
a, b, err := index.lookupFileReference("coffee-time.yaml")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, a)
|
assert.NotNil(t, a)
|
||||||
assert.NotNil(t, b)
|
assert.NotNil(t, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_CheckBadURLRef(t *testing.T) {
|
|
||||||
yml := `openapi: 3.1.0
|
|
||||||
paths:
|
|
||||||
/cakes:
|
|
||||||
post:
|
|
||||||
parameters:
|
|
||||||
- $ref: 'httpsss://badurl'`
|
|
||||||
|
|
||||||
var rootNode yaml.Node
|
|
||||||
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
||||||
|
|
||||||
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
||||||
|
|
||||||
assert.Len(t, index.refErrors, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSpecIndex_CheckBadURLRefNoRemoteAllowed(t *testing.T) {
|
func TestSpecIndex_CheckBadURLRefNoRemoteAllowed(t *testing.T) {
|
||||||
yml := `openapi: 3.1.0
|
yml := `openapi: 3.1.0
|
||||||
paths:
|
paths:
|
||||||
@@ -829,15 +882,34 @@ paths:
|
|||||||
c := CreateClosedAPIIndexConfig()
|
c := CreateClosedAPIIndexConfig()
|
||||||
idx := NewSpecIndexWithConfig(&rootNode, c)
|
idx := NewSpecIndexWithConfig(&rootNode, c)
|
||||||
|
|
||||||
assert.Len(t, idx.refErrors, 2)
|
assert.Len(t, idx.refErrors, 1)
|
||||||
assert.Equal(t, "remote lookups are not permitted, "+
|
|
||||||
"please set AllowRemoteLookup to true in the configuration", idx.refErrors[0].Error())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_CheckIndexDiscoversNoComponentLocalFileReference(t *testing.T) {
|
func TestSpecIndex_CheckIndexDiscoversNoComponentLocalFileReference(t *testing.T) {
|
||||||
_ = os.WriteFile("coffee-time.yaml", []byte("name: time for coffee"), 0o664)
|
c := []byte("name: time for coffee")
|
||||||
|
|
||||||
|
_ = os.WriteFile("coffee-time.yaml", c, 0o664)
|
||||||
defer os.Remove("coffee-time.yaml")
|
defer os.Remove("coffee-time.yaml")
|
||||||
|
|
||||||
|
// create a new config that allows local and remote to be mixed up.
|
||||||
|
cf := CreateOpenAPIIndexConfig()
|
||||||
|
cf.AvoidCircularReferenceCheck = true
|
||||||
|
cf.BasePath = "."
|
||||||
|
|
||||||
|
// create a new rolodex
|
||||||
|
rolo := NewRolodex(cf)
|
||||||
|
|
||||||
|
// configure the local filesystem.
|
||||||
|
fsCfg := LocalFSConfig{
|
||||||
|
BaseDirectory: cf.BasePath,
|
||||||
|
FileFilters: []string{"coffee-time.yaml"},
|
||||||
|
DirFS: os.DirFS(cf.BasePath),
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new local filesystem.
|
||||||
|
fileFS, err := NewLocalFSWithConfig(&fsCfg)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
yml := `openapi: 3.0.3
|
yml := `openapi: 3.0.3
|
||||||
paths:
|
paths:
|
||||||
/cakes:
|
/cakes:
|
||||||
@@ -845,24 +917,32 @@ paths:
|
|||||||
parameters:
|
parameters:
|
||||||
- $ref: 'coffee-time.yaml'`
|
- $ref: 'coffee-time.yaml'`
|
||||||
|
|
||||||
var rootNode yaml.Node
|
var coffee yaml.Node
|
||||||
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
_ = yaml.Unmarshal([]byte(yml), &coffee)
|
||||||
|
|
||||||
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
// set the rolodex root node to the root node of the spec.
|
||||||
|
rolo.SetRootNode(&coffee)
|
||||||
|
|
||||||
|
rolo.AddLocalFS(cf.BasePath, fileFS)
|
||||||
|
rErr := rolo.IndexTheRolodex()
|
||||||
|
|
||||||
|
assert.NoError(t, rErr)
|
||||||
|
|
||||||
|
index := rolo.GetRootIndex()
|
||||||
|
|
||||||
assert.NotNil(t, index.GetAllParametersFromOperations()["/cakes"]["post"]["coffee-time.yaml"][0].Node)
|
assert.NotNil(t, index.GetAllParametersFromOperations()["/cakes"]["post"]["coffee-time.yaml"][0].Node)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_BadJSON(t *testing.T) {
|
//func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_BadJSON(t *testing.T) {
|
||||||
index := NewSpecIndexWithConfig(nil, &SpecIndexConfig{
|
// index := NewSpecIndexWithConfig(nil, &SpecIndexConfig{
|
||||||
//AllowRemoteLookup: true,
|
// //AllowRemoteLookup: true,
|
||||||
})
|
// })
|
||||||
index.seenRemoteSources = make(map[string]*yaml.Node)
|
// index.seenRemoteSources = make(map[string]*yaml.Node)
|
||||||
a, b, err := index.lookupRemoteReference("https://google.com//logos/doodles/2022/labor-day-2022-6753651837109490.3-l.png#/hey")
|
// a, b, err := index.lookupRemoteReference("https://google.com//logos/doodles/2022/labor-day-2022-6753651837109490.3-l.png#/hey")
|
||||||
assert.Error(t, err)
|
// assert.Error(t, err)
|
||||||
assert.Nil(t, a)
|
// assert.Nil(t, a)
|
||||||
assert.Nil(t, b)
|
// assert.Nil(t, b)
|
||||||
}
|
//}
|
||||||
|
|
||||||
func TestSpecIndex_lookupFileReference_BadFileName(t *testing.T) {
|
func TestSpecIndex_lookupFileReference_BadFileName(t *testing.T) {
|
||||||
index := NewSpecIndexWithConfig(nil, CreateOpenAPIIndexConfig())
|
index := NewSpecIndexWithConfig(nil, CreateOpenAPIIndexConfig())
|
||||||
@@ -870,39 +950,79 @@ func TestSpecIndex_lookupFileReference_BadFileName(t *testing.T) {
|
|||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_lookupFileReference_SeenSourceSimulation_Error(t *testing.T) {
|
//
|
||||||
index := NewSpecIndexWithConfig(nil, CreateOpenAPIIndexConfig())
|
//func TestSpecIndex_lookupFileReference_SeenSourceSimulation_Error(t *testing.T) {
|
||||||
index.seenRemoteSources = make(map[string]*yaml.Node)
|
// index := NewSpecIndexWithConfig(nil, CreateOpenAPIIndexConfig())
|
||||||
index.seenRemoteSources["magic-money-file.json"] = &yaml.Node{}
|
// index.seenRemoteSources = make(map[string]*yaml.Node)
|
||||||
_, _, err := index.lookupFileReference("magic-money-file.json#something")
|
// index.seenRemoteSources["magic-money-file.json"] = &yaml.Node{}
|
||||||
assert.Error(t, err)
|
// _, _, err := index.lookupFileReference("magic-money-file.json#something")
|
||||||
}
|
// assert.Error(t, err)
|
||||||
|
//}
|
||||||
func TestSpecIndex_lookupFileReference_BadFile(t *testing.T) {
|
//
|
||||||
index := NewSpecIndexWithConfig(nil, CreateOpenAPIIndexConfig())
|
//func TestSpecIndex_lookupFileReference_BadFile(t *testing.T) {
|
||||||
_, _, err := index.lookupFileReference("chickers.json#no-rice")
|
// index := NewSpecIndexWithConfig(nil, CreateOpenAPIIndexConfig())
|
||||||
assert.Error(t, err)
|
// _, _, err := index.lookupFileReference("chickers.json#no-rice")
|
||||||
}
|
// assert.Error(t, err)
|
||||||
|
//}
|
||||||
func TestSpecIndex_lookupFileReference_BadFileDataRead(t *testing.T) {
|
//
|
||||||
_ = os.WriteFile("chickers.yaml", []byte("broke: the: thing: [again]"), 0o664)
|
//func TestSpecIndex_lookupFileReference_BadFileDataRead(t *testing.T) {
|
||||||
defer os.Remove("chickers.yaml")
|
// _ = os.WriteFile("chickers.yaml", []byte("broke: the: thing: [again]"), 0o664)
|
||||||
var root yaml.Node
|
// defer os.Remove("chickers.yaml")
|
||||||
index := NewSpecIndexWithConfig(&root, CreateOpenAPIIndexConfig())
|
// var root yaml.Node
|
||||||
_, _, err := index.lookupFileReference("chickers.yaml#no-rice")
|
// index := NewSpecIndexWithConfig(&root, CreateOpenAPIIndexConfig())
|
||||||
assert.Error(t, err)
|
// _, _, err := index.lookupFileReference("chickers.yaml#no-rice")
|
||||||
}
|
// assert.Error(t, err)
|
||||||
|
//}
|
||||||
|
|
||||||
func TestSpecIndex_lookupFileReference_MultiRes(t *testing.T) {
|
func TestSpecIndex_lookupFileReference_MultiRes(t *testing.T) {
|
||||||
_ = os.WriteFile("embie.yaml", []byte("naughty:\n - puppy: dog\n - puppy: naughty\npuppy:\n - naughty: puppy"), 0o664)
|
|
||||||
|
embie := []byte("naughty:\n - puppy: dog\n - puppy: naughty\npuppy:\n - naughty: puppy")
|
||||||
|
|
||||||
|
_ = os.WriteFile("embie.yaml", embie, 0o664)
|
||||||
defer os.Remove("embie.yaml")
|
defer os.Remove("embie.yaml")
|
||||||
|
|
||||||
index := NewSpecIndexWithConfig(nil, CreateOpenAPIIndexConfig())
|
// create a new config that allows local and remote to be mixed up.
|
||||||
index.seenRemoteSources = make(map[string]*yaml.Node)
|
cf := CreateOpenAPIIndexConfig()
|
||||||
k, doc, err := index.lookupFileReference("embie.yaml#/.naughty")
|
cf.AvoidBuildIndex = true
|
||||||
|
cf.AvoidCircularReferenceCheck = true
|
||||||
|
cf.BasePath = "."
|
||||||
|
|
||||||
|
// create a new rolodex
|
||||||
|
rolo := NewRolodex(cf)
|
||||||
|
|
||||||
|
var myPuppy yaml.Node
|
||||||
|
_ = yaml.Unmarshal(embie, &myPuppy)
|
||||||
|
|
||||||
|
// set the rolodex root node to the root node of the spec.
|
||||||
|
rolo.SetRootNode(&myPuppy)
|
||||||
|
|
||||||
|
// configure the local filesystem.
|
||||||
|
fsCfg := LocalFSConfig{
|
||||||
|
BaseDirectory: cf.BasePath,
|
||||||
|
FileFilters: []string{"embie.yaml"},
|
||||||
|
DirFS: os.DirFS(cf.BasePath),
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new local filesystem.
|
||||||
|
fileFS, err := NewLocalFSWithConfig(&fsCfg)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, doc)
|
|
||||||
assert.Nil(t, k)
|
rolo.AddLocalFS(cf.BasePath, fileFS)
|
||||||
|
rErr := rolo.IndexTheRolodex()
|
||||||
|
|
||||||
|
assert.NoError(t, rErr)
|
||||||
|
|
||||||
|
embieRoloFile, fErr := rolo.Open("embie.yaml")
|
||||||
|
|
||||||
|
assert.NoError(t, fErr)
|
||||||
|
assert.NotNil(t, embieRoloFile)
|
||||||
|
|
||||||
|
index := rolo.GetRootIndex()
|
||||||
|
//index.seenRemoteSources = make(map[string]*yaml.Node)
|
||||||
|
absoluteRef, _ := filepath.Abs("embie.yaml#/naughty")
|
||||||
|
fRef := index.SearchIndexForReference(absoluteRef)
|
||||||
|
assert.NotNil(t, fRef)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSpecIndex_lookupFileReference(t *testing.T) {
|
func TestSpecIndex_lookupFileReference(t *testing.T) {
|
||||||
@@ -918,7 +1038,6 @@ func TestSpecIndex_lookupFileReference(t *testing.T) {
|
|||||||
// create a new config that allows local and remote to be mixed up.
|
// create a new config that allows local and remote to be mixed up.
|
||||||
cf := CreateOpenAPIIndexConfig()
|
cf := CreateOpenAPIIndexConfig()
|
||||||
cf.AvoidBuildIndex = true
|
cf.AvoidBuildIndex = true
|
||||||
cf.AllowRemoteLookup = true
|
|
||||||
cf.AvoidCircularReferenceCheck = true
|
cf.AvoidCircularReferenceCheck = true
|
||||||
cf.BasePath = "."
|
cf.BasePath = "."
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user