mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 12:37:49 +00:00
1804 lines
52 KiB
Go
1804 lines
52 KiB
Go
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package index
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"log"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/pb33f/libopenapi/utils"
|
|
"github.com/stretchr/testify/assert"
|
|
"gopkg.in/yaml.v3"
|
|
"sync"
|
|
)
|
|
|
|
const (
|
|
digitalOceanCommitID = "d8d390155b515cdd94555478bbcdf5682460c52e"
|
|
)
|
|
|
|
func TestSpecIndex_GetCache(t *testing.T) {
|
|
petstore, _ := os.ReadFile("../test_specs/petstorev3.json")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(petstore, &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
extCache := index.GetCache()
|
|
assert.NotNil(t, extCache)
|
|
extCache.Store("test", "test")
|
|
loaded, ok := extCache.Load("test")
|
|
assert.Equal(t, "test", loaded)
|
|
assert.True(t, ok)
|
|
|
|
// create a new cache
|
|
newCache := new(sync.Map)
|
|
index.SetCache(newCache)
|
|
|
|
// check that the cache has been set.
|
|
assert.Equal(t, newCache, index.GetCache())
|
|
|
|
// add an item to the new cache and check it exists
|
|
newCache.Store("test2", "test2")
|
|
loaded, ok = newCache.Load("test2")
|
|
assert.Equal(t, "test2", loaded)
|
|
assert.True(t, ok)
|
|
|
|
// now check that the new item in the new cache does not exist in the old cache.
|
|
loaded, ok = extCache.Load("test2")
|
|
assert.Nil(t, loaded)
|
|
assert.False(t, ok)
|
|
|
|
assert.Len(t, index.GetIgnoredPolymorphicCircularReferences(), 0)
|
|
assert.Len(t, index.GetIgnoredArrayCircularReferences(), 0)
|
|
assert.Equal(t, len(index.GetRawReferencesSequenced()), 42)
|
|
assert.Equal(t, len(index.GetNodeMap()), 824)
|
|
}
|
|
|
|
func TestSpecIndex_ExtractRefsStripe(t *testing.T) {
|
|
stripe, _ := os.ReadFile("../test_specs/stripe.yaml")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(stripe, &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
assert.Equal(t, 626, len(index.allRefs))
|
|
assert.Equal(t, 871, len(index.allMappedRefs))
|
|
combined := index.GetAllCombinedReferences()
|
|
assert.Equal(t, 871, len(combined))
|
|
|
|
assert.Equal(t, len(index.rawSequencedRefs), 2712)
|
|
assert.Equal(t, 336, index.pathCount)
|
|
assert.Equal(t, 494, index.operationCount)
|
|
assert.Equal(t, 871, index.schemaCount)
|
|
assert.Equal(t, 0, index.globalTagsCount)
|
|
assert.Equal(t, 0, index.globalLinksCount)
|
|
assert.Equal(t, 0, index.componentParamCount)
|
|
assert.Equal(t, 162, index.operationParamCount)
|
|
assert.Equal(t, 102, index.componentsInlineParamDuplicateCount)
|
|
assert.Equal(t, 60, index.componentsInlineParamUniqueCount)
|
|
assert.Equal(t, 2579, index.enumCount)
|
|
assert.Equal(t, len(index.GetAllEnums()), 2579)
|
|
assert.Len(t, index.GetPolyAllOfReferences(), 0)
|
|
assert.Len(t, index.GetPolyOneOfReferences(), 315)
|
|
assert.Len(t, index.GetPolyAnyOfReferences(), 708)
|
|
assert.Len(t, index.GetAllReferenceSchemas(), 2712)
|
|
assert.NotNil(t, index.GetRootServersNode())
|
|
assert.Len(t, index.GetAllRootServers(), 1)
|
|
assert.Equal(t, "", index.GetSpecAbsolutePath())
|
|
assert.NotNil(t, index.GetLogger())
|
|
|
|
// not required, but flip the circular result switch on and off.
|
|
assert.False(t, index.AllowCircularReferenceResolving())
|
|
index.SetAllowCircularReferenceResolving(true)
|
|
assert.True(t, index.AllowCircularReferenceResolving())
|
|
|
|
// simulate setting of circular references, also pointless but needed for coverage.
|
|
assert.Nil(t, index.GetCircularReferences())
|
|
index.SetCircularReferences([]*CircularReferenceResult{new(CircularReferenceResult)})
|
|
assert.Len(t, index.GetCircularReferences(), 1)
|
|
|
|
assert.Equal(t, 871, len(index.GetRefsByLine()))
|
|
assert.Equal(t, 2712, len(index.GetLinesWithReferences()), 1972)
|
|
assert.Equal(t, 0, len(index.GetAllExternalDocuments()))
|
|
}
|
|
|
|
func TestSpecIndex_Asana(t *testing.T) {
|
|
asana, _ := os.ReadFile("../test_specs/asana.yaml")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(asana, &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
assert.Len(t, index.allRefs, 152)
|
|
assert.Len(t, index.allMappedRefs, 171)
|
|
combined := index.GetAllCombinedReferences()
|
|
assert.Equal(t, 171, len(combined))
|
|
assert.Equal(t, 118, index.pathCount)
|
|
assert.Equal(t, 152, index.operationCount)
|
|
assert.Equal(t, 135, index.schemaCount)
|
|
assert.Equal(t, 26, index.globalTagsCount)
|
|
assert.Equal(t, 0, index.globalLinksCount)
|
|
assert.Equal(t, 30, index.componentParamCount)
|
|
assert.Equal(t, 107, index.operationParamCount)
|
|
assert.Equal(t, 8, index.componentsInlineParamDuplicateCount)
|
|
assert.Equal(t, 69, index.componentsInlineParamUniqueCount)
|
|
}
|
|
|
|
func TestSpecIndex_DigitalOcean(t *testing.T) {
|
|
do, _ := os.ReadFile("../test_specs/digitalocean.yaml")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(do, &rootNode)
|
|
|
|
location := "https://raw.githubusercontent.com/digitalocean/openapi/8ce96ef186fe938bdce26fb2f5d63ac53ca9d06f/specification"
|
|
baseURL, _ := url.Parse(location)
|
|
|
|
// create a new config that allows remote lookups.
|
|
cf := &SpecIndexConfig{}
|
|
cf.AvoidBuildIndex = 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)
|
|
|
|
// 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.
|
|
if os.Getenv("GH_PAT") != "" {
|
|
fmt.Println("GH_PAT found, setting remote handler func")
|
|
client := &http.Client{
|
|
Timeout: time.Second * 120,
|
|
}
|
|
remoteFS.SetRemoteHandlerFunc(func(url string) (*http.Response, error) {
|
|
request, _ := http.NewRequest(http.MethodGet, url, nil)
|
|
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("GH_PAT")))
|
|
return client.Do(request)
|
|
})
|
|
}
|
|
|
|
// add remote filesystem
|
|
rolo.AddRemoteFS(location, remoteFS)
|
|
|
|
// index the rolodex.
|
|
indexedErr := rolo.IndexTheRolodex()
|
|
assert.NoError(t, indexedErr)
|
|
|
|
// get all the files!
|
|
files := remoteFS.GetFiles()
|
|
fileLen := len(files)
|
|
assert.Equal(t, 1660, fileLen)
|
|
assert.Len(t, remoteFS.GetErrors(), 0)
|
|
|
|
// check circular references
|
|
rolo.CheckForCircularReferences()
|
|
assert.Len(t, rolo.GetCaughtErrors(), 0)
|
|
assert.Len(t, rolo.GetIgnoredCircularReferences(), 0)
|
|
}
|
|
|
|
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("git clone failed with %s\n", err)
|
|
}
|
|
|
|
if err := exec.Command("git", "-C", tmp, "reset", "--hard", digitalOceanCommitID).Run(); err != nil {
|
|
log.Fatalf("git reset failed with %s\n", err)
|
|
}
|
|
|
|
spec, _ := filepath.Abs(filepath.Join(tmp, "specification", "DigitalOcean-public.v2.yaml"))
|
|
doLocal, _ := os.ReadFile(spec)
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(doLocal, &rootNode)
|
|
|
|
basePath := filepath.Join(tmp, "specification")
|
|
|
|
// create a new config that allows local and remote to be mixed up.
|
|
cf := CreateOpenAPIIndexConfig()
|
|
cf.ExtractRefsSequentially = true
|
|
cf.AllowRemoteLookup = true
|
|
cf.AvoidCircularReferenceCheck = true
|
|
cf.BasePath = basePath
|
|
cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
|
Level: slog.LevelError,
|
|
}))
|
|
|
|
// 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),
|
|
Logger: cf.Logger,
|
|
}
|
|
|
|
// create a new local filesystem.
|
|
fileFS, fsErr := NewLocalFSWithConfig(&fsCfg)
|
|
assert.NoError(t, fsErr)
|
|
|
|
files := fileFS.GetFiles()
|
|
fileLen := len(files)
|
|
|
|
assert.Equal(t, 1716, fileLen)
|
|
|
|
rolo.AddLocalFS(basePath, fileFS)
|
|
|
|
rErr := rolo.IndexTheRolodex()
|
|
|
|
assert.NoError(t, rErr)
|
|
|
|
index := rolo.GetRootIndex()
|
|
|
|
assert.NotNil(t, index)
|
|
|
|
assert.Len(t, index.GetMappedReferencesSequenced(), 303)
|
|
assert.Len(t, index.GetMappedReferences(), 303)
|
|
assert.Len(t, fileFS.GetErrors(), 0)
|
|
|
|
// check circular references
|
|
rolo.CheckForCircularReferences()
|
|
assert.Len(t, rolo.GetCaughtErrors(), 0)
|
|
assert.Len(t, rolo.GetIgnoredCircularReferences(), 0)
|
|
|
|
if runtime.GOOS != "windows" {
|
|
assert.Equal(t, "1.3 MB", rolo.RolodexFileSizeAsString())
|
|
} else {
|
|
assert.Equal(t, "1.35 MB", rolo.RolodexFileSizeAsString())
|
|
}
|
|
assert.Equal(t, 1716, rolo.RolodexTotalFiles())
|
|
}
|
|
|
|
func TestSpecIndex_DigitalOcean_FullCheckoutLocalResolve_RecursiveLookup(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("git clone failed with %s\n", err)
|
|
}
|
|
|
|
if err := exec.Command("git", "-C", tmp, "reset", "--hard", digitalOceanCommitID).Run(); err != nil {
|
|
log.Fatalf("git reset failed with %s\n", err)
|
|
}
|
|
|
|
spec, _ := filepath.Abs(filepath.Join(tmp, "specification", "DigitalOcean-public.v2.yaml"))
|
|
doLocal, _ := os.ReadFile(spec)
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(doLocal, &rootNode)
|
|
|
|
basePath := filepath.Join(tmp, "specification")
|
|
|
|
// create a new config that allows local and remote to be mixed up.
|
|
cf := CreateOpenAPIIndexConfig()
|
|
cf.AllowRemoteLookup = true
|
|
cf.AvoidCircularReferenceCheck = true
|
|
cf.BasePath = basePath
|
|
cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
|
Level: slog.LevelError,
|
|
}))
|
|
|
|
// 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,
|
|
IndexConfig: cf,
|
|
Logger: cf.Logger,
|
|
}
|
|
|
|
// create a new local filesystem.
|
|
fileFS, fsErr := NewLocalFSWithConfig(&fsCfg)
|
|
assert.NoError(t, fsErr)
|
|
|
|
rolo.AddLocalFS(basePath, fileFS)
|
|
|
|
rErr := rolo.IndexTheRolodex()
|
|
files := fileFS.GetFiles()
|
|
fileLen := len(files)
|
|
|
|
assert.Equal(t, 1702, fileLen)
|
|
|
|
assert.NoError(t, rErr)
|
|
|
|
index := rolo.GetRootIndex()
|
|
|
|
assert.NotNil(t, index)
|
|
|
|
assert.Len(t, index.GetMappedReferencesSequenced(), 303)
|
|
assert.Len(t, index.GetMappedReferences(), 303)
|
|
assert.Len(t, fileFS.GetErrors(), 0)
|
|
|
|
// check circular references
|
|
rolo.CheckForCircularReferences()
|
|
assert.Len(t, rolo.GetCaughtErrors(), 0)
|
|
assert.Len(t, rolo.GetIgnoredCircularReferences(), 0)
|
|
if runtime.GOOS == "windows" {
|
|
assert.Equal(t, "1.29 MB", rolo.RolodexFileSizeAsString())
|
|
} else {
|
|
assert.Equal(t, "1.24 MB", rolo.RolodexFileSizeAsString())
|
|
}
|
|
assert.Equal(t, 1702, rolo.RolodexTotalFiles())
|
|
}
|
|
|
|
func TestSpecIndex_DigitalOcean_LookupsNotAllowed(t *testing.T) {
|
|
do, _ := os.ReadFile("../test_specs/digitalocean.yaml")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(do, &rootNode)
|
|
|
|
location := "https://raw.githubusercontent.com/digitalocean/openapi/tree/" + digitalOceanCommitID + "/specification"
|
|
baseURL, _ := url.Parse(location)
|
|
|
|
// create a new config that does not allow remote lookups.
|
|
cf := &SpecIndexConfig{}
|
|
cf.AvoidBuildIndex = true
|
|
cf.AvoidCircularReferenceCheck = true
|
|
var op []byte
|
|
buf := bytes.NewBuffer(op)
|
|
cf.Logger = slog.New(slog.NewJSONHandler(buf, &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.
|
|
assert.True(t, len(index.GetReferenceIndexErrors()) > 0)
|
|
}
|
|
|
|
func TestSpecIndex_BaseURLError(t *testing.T) {
|
|
do, _ := os.ReadFile("../test_specs/digitalocean.yaml")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(do, &rootNode)
|
|
|
|
location := "https://githerbsandcoffeeandcode.com/fresh/herbs/for/you" // not gonna work bro.
|
|
baseURL, _ := url.Parse(location)
|
|
|
|
// create a new config that allows remote lookups.
|
|
cf := &SpecIndexConfig{}
|
|
cf.AvoidBuildIndex = true
|
|
cf.AllowRemoteLookup = true
|
|
cf.AvoidCircularReferenceCheck = true
|
|
var op []byte
|
|
buf := bytes.NewBuffer(op)
|
|
cf.Logger = slog.New(slog.NewJSONHandler(buf, &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)
|
|
|
|
// create a handler that uses an env variable to capture any GH_PAT in the OS ENV
|
|
// and inject it into the request header, so this does not fail when running lots of local tests.
|
|
if os.Getenv("GH_PAT") != "" {
|
|
fmt.Println("GH_PAT found, setting remote handler func")
|
|
client := &http.Client{
|
|
Timeout: time.Second * 120,
|
|
}
|
|
remoteFS.SetRemoteHandlerFunc(func(url string) (*http.Response, error) {
|
|
request, _ := http.NewRequest(http.MethodGet, url, nil)
|
|
request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", os.Getenv("GH_PAT")))
|
|
return client.Do(request)
|
|
})
|
|
}
|
|
|
|
// 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()), 155)
|
|
}
|
|
|
|
func TestSpecIndex_k8s(t *testing.T) {
|
|
asana, _ := os.ReadFile("../test_specs/k8s.json")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(asana, &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
assert.Len(t, index.allRefs, 558)
|
|
assert.Equal(t, 563, len(index.allMappedRefs))
|
|
combined := index.GetAllCombinedReferences()
|
|
assert.Equal(t, 563, len(combined))
|
|
assert.Equal(t, 436, index.pathCount)
|
|
assert.Equal(t, 853, index.operationCount)
|
|
assert.Equal(t, 563, index.schemaCount)
|
|
assert.Equal(t, 0, index.globalTagsCount)
|
|
assert.Equal(t, 58, index.operationTagsCount)
|
|
assert.Equal(t, 0, index.globalLinksCount)
|
|
assert.Equal(t, 0, index.componentParamCount)
|
|
assert.Equal(t, 36, index.operationParamCount)
|
|
assert.Equal(t, 26, index.componentsInlineParamDuplicateCount)
|
|
assert.Equal(t, 10, index.componentsInlineParamUniqueCount)
|
|
assert.Equal(t, 58, index.GetTotalTagsCount())
|
|
assert.Equal(t, 2524, index.GetRawReferenceCount())
|
|
}
|
|
|
|
func TestSpecIndex_PetstoreV2(t *testing.T) {
|
|
asana, _ := os.ReadFile("../test_specs/petstorev2.json")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(asana, &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
assert.Len(t, index.allRefs, 6)
|
|
assert.Len(t, index.allMappedRefs, 6)
|
|
assert.Equal(t, 14, index.pathCount)
|
|
assert.Equal(t, 20, index.operationCount)
|
|
assert.Equal(t, 6, index.schemaCount)
|
|
assert.Equal(t, 3, index.globalTagsCount)
|
|
assert.Equal(t, 3, index.operationTagsCount)
|
|
assert.Equal(t, 0, index.globalLinksCount)
|
|
assert.Equal(t, 1, index.componentParamCount)
|
|
assert.Equal(t, 1, index.GetComponentParameterCount())
|
|
assert.Equal(t, 11, index.operationParamCount)
|
|
assert.Equal(t, 5, index.componentsInlineParamDuplicateCount)
|
|
assert.Equal(t, 6, index.componentsInlineParamUniqueCount)
|
|
assert.Equal(t, 3, index.GetTotalTagsCount())
|
|
assert.Equal(t, 2, len(index.GetSecurityRequirementReferences()))
|
|
}
|
|
|
|
func TestSpecIndex_XSOAR(t *testing.T) {
|
|
xsoar, _ := os.ReadFile("../test_specs/xsoar.json")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(xsoar, &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
assert.Len(t, index.allRefs, 209)
|
|
assert.Equal(t, 85, index.pathCount)
|
|
assert.Equal(t, 88, index.operationCount)
|
|
assert.Equal(t, 245, index.schemaCount)
|
|
assert.Equal(t, 207, len(index.allMappedRefs))
|
|
assert.Equal(t, 0, index.globalTagsCount)
|
|
assert.Equal(t, 0, index.operationTagsCount)
|
|
assert.Equal(t, 0, index.globalLinksCount)
|
|
assert.Len(t, index.GetRootSecurityReferences(), 1)
|
|
assert.NotNil(t, index.GetRootSecurityNode())
|
|
}
|
|
|
|
func TestSpecIndex_PetstoreV3(t *testing.T) {
|
|
petstore, _ := os.ReadFile("../test_specs/petstorev3.json")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(petstore, &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
assert.Len(t, index.allRefs, 7)
|
|
assert.Len(t, index.allMappedRefs, 7)
|
|
assert.Equal(t, 13, index.pathCount)
|
|
assert.Equal(t, 19, index.operationCount)
|
|
assert.Equal(t, 8, index.schemaCount)
|
|
assert.Equal(t, 3, index.globalTagsCount)
|
|
assert.Equal(t, 3, index.operationTagsCount)
|
|
assert.Equal(t, 0, index.globalLinksCount)
|
|
assert.Equal(t, 0, index.componentParamCount)
|
|
assert.Equal(t, 9, index.operationParamCount)
|
|
assert.Equal(t, 4, index.componentsInlineParamDuplicateCount)
|
|
assert.Equal(t, 5, index.componentsInlineParamUniqueCount)
|
|
assert.Equal(t, 3, index.GetTotalTagsCount())
|
|
assert.Equal(t, 90, index.GetAllDescriptionsCount())
|
|
assert.Equal(t, 19, index.GetAllSummariesCount())
|
|
assert.Len(t, index.GetAllDescriptions(), 90)
|
|
assert.Len(t, index.GetAllSummaries(), 19)
|
|
|
|
index.SetAbsolutePath("/rooty/rootster")
|
|
assert.Equal(t, "/rooty/rootster", index.GetSpecAbsolutePath())
|
|
}
|
|
|
|
var mappedRefs = 15
|
|
|
|
func TestSpecIndex_BurgerShop(t *testing.T) {
|
|
burgershop, _ := os.ReadFile("../test_specs/burgershop.openapi.yaml")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(burgershop, &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
assert.Len(t, index.allRefs, mappedRefs)
|
|
assert.Len(t, index.allMappedRefs, mappedRefs)
|
|
assert.Equal(t, mappedRefs, len(index.GetMappedReferences()))
|
|
assert.Equal(t, mappedRefs+1, len(index.GetMappedReferencesSequenced()))
|
|
|
|
assert.Equal(t, 6, index.pathCount)
|
|
assert.Equal(t, 6, index.GetPathCount())
|
|
|
|
assert.Equal(t, 6, len(index.GetAllComponentSchemas()))
|
|
assert.Equal(t, 56, len(index.GetAllSchemas()))
|
|
|
|
assert.Equal(t, 34, len(index.GetAllSequencedReferences()))
|
|
assert.NotNil(t, index.GetSchemasNode())
|
|
assert.NotNil(t, index.GetParametersNode())
|
|
|
|
assert.Equal(t, 5, index.operationCount)
|
|
assert.Equal(t, 5, index.GetOperationCount())
|
|
|
|
assert.Equal(t, 6, index.schemaCount)
|
|
assert.Equal(t, 6, index.GetComponentSchemaCount())
|
|
|
|
assert.Equal(t, 2, index.globalTagsCount)
|
|
assert.Equal(t, 2, index.GetGlobalTagsCount())
|
|
assert.Equal(t, 2, index.GetTotalTagsCount())
|
|
|
|
assert.Equal(t, 2, index.operationTagsCount)
|
|
assert.Equal(t, 2, index.GetOperationTagsCount())
|
|
|
|
assert.Equal(t, 3, index.globalLinksCount)
|
|
assert.Equal(t, 3, index.GetGlobalLinksCount())
|
|
|
|
assert.Equal(t, 1, index.globalCallbacksCount)
|
|
assert.Equal(t, 1, index.GetGlobalCallbacksCount())
|
|
|
|
assert.Equal(t, 2, index.componentParamCount)
|
|
assert.Equal(t, 2, index.GetComponentParameterCount())
|
|
|
|
assert.Equal(t, 4, index.operationParamCount)
|
|
assert.Equal(t, 4, index.GetOperationsParameterCount())
|
|
|
|
assert.Equal(t, 0, index.componentsInlineParamDuplicateCount)
|
|
assert.Equal(t, 0, index.GetInlineDuplicateParamCount())
|
|
|
|
assert.Equal(t, 2, index.componentsInlineParamUniqueCount)
|
|
assert.Equal(t, 2, index.GetInlineUniqueParamCount())
|
|
|
|
assert.Equal(t, 1, len(index.GetAllRequestBodies()))
|
|
assert.NotNil(t, index.GetRootNode())
|
|
assert.NotNil(t, index.GetGlobalTagsNode())
|
|
assert.NotNil(t, index.GetPathsNode())
|
|
assert.NotNil(t, index.GetDiscoveredReferences())
|
|
assert.Equal(t, 1, len(index.GetPolyReferences()))
|
|
assert.NotNil(t, index.GetOperationParameterReferences())
|
|
assert.Equal(t, 3, len(index.GetAllSecuritySchemes()))
|
|
assert.Equal(t, 2, len(index.GetAllParameters()))
|
|
assert.Equal(t, 1, len(index.GetAllResponses()))
|
|
assert.Equal(t, 2, len(index.GetInlineOperationDuplicateParameters()))
|
|
assert.Equal(t, 0, len(index.GetReferencesWithSiblings()))
|
|
assert.Equal(t, mappedRefs, len(index.GetAllReferences()))
|
|
assert.Equal(t, 0, len(index.GetOperationParametersIndexErrors()))
|
|
assert.Equal(t, 5, len(index.GetAllPaths()))
|
|
assert.Equal(t, 5, len(index.GetOperationTags()))
|
|
assert.Equal(t, 3, len(index.GetAllParametersFromOperations()))
|
|
}
|
|
|
|
func TestSpecIndex_GetAllParametersFromOperations(t *testing.T) {
|
|
yml := `openapi: 3.0.0
|
|
servers:
|
|
- url: http://localhost:8080
|
|
paths:
|
|
/test:
|
|
get:
|
|
parameters:
|
|
- name: action
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: action
|
|
in: query
|
|
schema:
|
|
type: string`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
assert.Equal(t, 1, len(index.GetAllParametersFromOperations()))
|
|
assert.Equal(t, 1, len(index.GetOperationParametersIndexErrors()))
|
|
}
|
|
|
|
func TestSpecIndex_BurgerShop_AllTheComponents(t *testing.T) {
|
|
burgershop, _ := os.ReadFile("../test_specs/all-the-components.yaml")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(burgershop, &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
assert.Equal(t, 1, len(index.GetAllHeaders()))
|
|
assert.Equal(t, 1, len(index.GetAllLinks()))
|
|
assert.Equal(t, 1, len(index.GetAllCallbacks()))
|
|
assert.Equal(t, 1, len(index.GetAllExamples()))
|
|
assert.Equal(t, 1, len(index.GetAllResponses()))
|
|
assert.Equal(t, 2, len(index.GetAllRootServers()))
|
|
assert.Equal(t, 2, len(index.GetAllOperationsServers()))
|
|
}
|
|
|
|
func TestSpecIndex_SwaggerResponses(t *testing.T) {
|
|
yml := `swagger: 2.0
|
|
responses:
|
|
niceResponse:
|
|
description: hi`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
assert.Equal(t, 1, len(index.GetAllResponses()))
|
|
}
|
|
|
|
func TestSpecIndex_NoNameParam(t *testing.T) {
|
|
yml := `paths:
|
|
/users/{id}:
|
|
parameters:
|
|
- in: path
|
|
name: id
|
|
- in: query
|
|
get:
|
|
parameters:
|
|
- in: path
|
|
name: id
|
|
- in: query`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
assert.Equal(t, 2, len(index.GetOperationParametersIndexErrors()))
|
|
}
|
|
|
|
func TestSpecIndex_NoRoot(t *testing.T) {
|
|
index := NewSpecIndex(nil)
|
|
refs := index.ExtractRefs(nil, nil, nil, 0, false, "")
|
|
docs := index.ExtractExternalDocuments(nil)
|
|
assert.Nil(t, docs)
|
|
assert.Nil(t, refs)
|
|
assert.Nil(t, index.FindComponent("nothing"))
|
|
assert.Equal(t, -1, index.GetOperationCount())
|
|
assert.Equal(t, -1, index.GetPathCount())
|
|
assert.Equal(t, -1, index.GetGlobalTagsCount())
|
|
assert.Equal(t, -1, index.GetOperationTagsCount())
|
|
assert.Equal(t, -1, index.GetTotalTagsCount())
|
|
assert.Equal(t, -1, index.GetOperationsParameterCount())
|
|
assert.Equal(t, -1, index.GetComponentParameterCount())
|
|
assert.Equal(t, -1, index.GetComponentSchemaCount())
|
|
assert.Equal(t, -1, index.GetGlobalLinksCount())
|
|
}
|
|
|
|
func test_buildMixedRefServer() *httptest.Server {
|
|
bs, _ := os.ReadFile("../test_specs/burgershop.openapi.yaml")
|
|
return httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
|
rw.Header().Set("Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT")
|
|
_, _ = rw.Write(bs)
|
|
}))
|
|
}
|
|
|
|
func TestSpecIndex_BurgerShopMixedRef(t *testing.T) {
|
|
// create a test server.
|
|
server := test_buildMixedRefServer()
|
|
defer server.Close()
|
|
|
|
// 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 = "../test_specs"
|
|
cf.Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
|
Level: slog.LevelError,
|
|
}))
|
|
|
|
// setting this baseURL will override the base
|
|
cf.BaseURL, _ = url.Parse(server.URL)
|
|
|
|
cFile := "../test_specs/mixedref-burgershop.openapi.yaml"
|
|
yml, _ := os.ReadFile(cFile)
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
// 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, _ := NewRemoteFSWithRootURL(server.URL)
|
|
remoteFS.SetIndexConfig(cf)
|
|
|
|
// set our remote handler func
|
|
|
|
c := http.Client{}
|
|
|
|
remoteFS.RemoteHandlerFunc = c.Get
|
|
|
|
// configure the local filesystem.
|
|
fsCfg := LocalFSConfig{
|
|
BaseDirectory: cf.BasePath,
|
|
FileFilters: []string{"burgershop.openapi.yaml"},
|
|
DirFS: os.DirFS(cf.BasePath),
|
|
}
|
|
|
|
// create a new local filesystem.
|
|
fileFS, err := NewLocalFSWithConfig(&fsCfg)
|
|
assert.NoError(t, err)
|
|
|
|
// add file systems to the rolodex
|
|
rolo.AddLocalFS(cf.BasePath, fileFS)
|
|
rolo.AddRemoteFS(server.URL, remoteFS)
|
|
|
|
// index the rolodex.
|
|
indexedErr := rolo.IndexTheRolodex()
|
|
rolo.BuildIndexes()
|
|
|
|
assert.NoError(t, indexedErr)
|
|
|
|
index := rolo.GetRootIndex()
|
|
rolo.CheckForCircularReferences()
|
|
|
|
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())
|
|
assert.Equal(t, 1, index.GetInlineUniqueParamCount())
|
|
assert.Len(t, index.refErrors, 0)
|
|
assert.Len(t, index.GetCircularReferences(), 0)
|
|
|
|
// get the size of the rolodex.
|
|
|
|
if runtime.GOOS != "windows" {
|
|
assert.Equal(t, int64(60226), rolo.RolodexFileSize()+int64(len(yml)))
|
|
assert.Equal(t, "50.48 KB", rolo.RolodexFileSizeAsString())
|
|
} else {
|
|
assert.Equal(t, int64(62128), rolo.RolodexFileSize()+int64(len(yml)))
|
|
assert.Equal(t, "52.09 KB", rolo.RolodexFileSizeAsString())
|
|
}
|
|
assert.Equal(t, 3, rolo.RolodexTotalFiles())
|
|
}
|
|
|
|
func TestCalcSizeAsString(t *testing.T) {
|
|
assert.Equal(t, "345 B", HumanFileSize(345))
|
|
assert.Equal(t, "1 KB", HumanFileSize(1024))
|
|
assert.Equal(t, "1 KB", HumanFileSize(1025))
|
|
assert.Equal(t, "1.98 KB", HumanFileSize(2025))
|
|
assert.Equal(t, "1 MB", HumanFileSize(1025*1024))
|
|
assert.Equal(t, "1 GB", HumanFileSize(1025*1025*1025))
|
|
}
|
|
|
|
func TestSpecIndex_TestEmptyBrokenReferences(t *testing.T) {
|
|
badref, _ := os.ReadFile("../test_specs/badref-burgershop.openapi.yaml")
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal(badref, &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
assert.Equal(t, 5, index.GetPathCount())
|
|
assert.Equal(t, 5, index.GetOperationCount())
|
|
assert.Equal(t, 5, index.GetComponentSchemaCount())
|
|
assert.Equal(t, 2, index.GetGlobalTagsCount())
|
|
assert.Equal(t, 3, index.GetTotalTagsCount())
|
|
assert.Equal(t, 2, index.GetOperationTagsCount())
|
|
assert.Equal(t, 2, index.GetGlobalLinksCount())
|
|
assert.Equal(t, 0, index.GetComponentParameterCount())
|
|
assert.Equal(t, 2, index.GetOperationsParameterCount())
|
|
assert.Equal(t, 1, index.GetInlineDuplicateParamCount())
|
|
assert.Equal(t, 1, index.GetInlineUniqueParamCount())
|
|
assert.Len(t, index.refErrors, 6)
|
|
}
|
|
|
|
func TestTagsNoDescription(t *testing.T) {
|
|
yml := `tags:
|
|
- name: one
|
|
- name: two
|
|
- three: three`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
assert.Equal(t, 3, index.GetGlobalTagsCount())
|
|
}
|
|
|
|
func TestGlobalCallbacksNoIndexTest(t *testing.T) {
|
|
idx := new(SpecIndex)
|
|
assert.Equal(t, -1, idx.GetGlobalCallbacksCount())
|
|
}
|
|
|
|
func TestMultipleCallbacksPerOperationVerb(t *testing.T) {
|
|
yml := `components:
|
|
callbacks:
|
|
callbackA:
|
|
"{$request.query.queryUrl}":
|
|
post:
|
|
description: callbackAPost
|
|
get:
|
|
description: callbackAGet
|
|
callbackB:
|
|
"{$request.query.queryUrl}":
|
|
post:
|
|
description: callbackBPost
|
|
get:
|
|
description: callbackBGet
|
|
paths:
|
|
/pb33f/arriving-soon:
|
|
post:
|
|
callbacks:
|
|
callbackA:
|
|
$ref: '#/components/callbacks/CallbackA'
|
|
callbackB:
|
|
$ref: '#/components/callbacks/CallbackB'
|
|
get:
|
|
callbacks:
|
|
callbackB:
|
|
$ref: '#/components/callbacks/CallbackB'
|
|
callbackA:
|
|
$ref: '#/components/callbacks/CallbackA'`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
assert.Equal(t, 4, index.GetGlobalCallbacksCount())
|
|
}
|
|
|
|
func TestSpecIndex_ExtractComponentsFromRefs(t *testing.T) {
|
|
yml := `components:
|
|
schemas:
|
|
pizza:
|
|
properties:
|
|
something:
|
|
$ref: '#/components/\schemas/\something'
|
|
something:
|
|
description: something`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
assert.Len(t, index.GetReferenceIndexErrors(), 0)
|
|
}
|
|
|
|
func TestSpecIndex_FindComponent_WithACrazyAssPath(t *testing.T) {
|
|
yml := `paths:
|
|
/crazy/ass/references:
|
|
get:
|
|
parameters:
|
|
- name: a param
|
|
schema:
|
|
type: string
|
|
description: Show information about one architecture.
|
|
responses:
|
|
"200":
|
|
content:
|
|
application/xml; charset=utf-8:
|
|
schema:
|
|
example:
|
|
name: x86_64
|
|
description: OK. The request has succeeded.
|
|
"404":
|
|
content:
|
|
application/xml; charset=utf-8:
|
|
example:
|
|
code: unknown_architecture
|
|
summary: "Architecture does not exist: x999"
|
|
schema:
|
|
$ref: "#/paths/~1crazy~1ass~1references/get/parameters/0"
|
|
"400":
|
|
content:
|
|
application/xml; charset=utf-8:
|
|
example:
|
|
code: unknown_architecture
|
|
summary: "Architecture does not exist: x999"
|
|
schema:
|
|
$ref: "#/paths/~1crazy~1ass~1references/get/responses/404/content/application~1xml;%20charset=utf-8/schema"
|
|
description: Not Found.`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &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").Node.Content[1].Value)
|
|
|
|
assert.Equal(t, "a param",
|
|
index.FindComponent("#/paths/~1crazy~1ass~1references/get/parameters/0").Node.Content[1].Value)
|
|
}
|
|
|
|
func TestSpecIndex_FindComponent(t *testing.T) {
|
|
yml := `components:
|
|
schemas:
|
|
pizza:
|
|
properties:
|
|
something:
|
|
$ref: '#/components/schemas/something'
|
|
something:
|
|
description: something`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
assert.Nil(t, index.FindComponent("I-do-not-exist"))
|
|
}
|
|
|
|
func TestSpecIndex_TestPathsNodeAsArray(t *testing.T) {
|
|
yml := `components:
|
|
schemas:
|
|
pizza:
|
|
properties:
|
|
something:
|
|
$ref: '#/components/schemas/something'
|
|
something:
|
|
description: something`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
assert.Nil(t, index.lookupRolodex(nil))
|
|
}
|
|
|
|
func TestSpecIndex_CheckBadURLRefNoRemoteAllowed(t *testing.T) {
|
|
yml := `openapi: 3.1.0
|
|
paths:
|
|
/cakes:
|
|
post:
|
|
parameters:
|
|
- $ref: 'httpsss://badurl'`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
c := CreateClosedAPIIndexConfig()
|
|
idx := NewSpecIndexWithConfig(&rootNode, c)
|
|
|
|
assert.Len(t, idx.refErrors, 1)
|
|
}
|
|
|
|
func TestSpecIndex_CheckIndexDiscoversNoComponentLocalFileReference(t *testing.T) {
|
|
c := []byte("name: time for coffee")
|
|
|
|
_ = os.WriteFile("coffee-time.yaml", c, 0o664)
|
|
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
|
|
paths:
|
|
/cakes:
|
|
post:
|
|
parameters:
|
|
- $ref: 'coffee-time.yaml'`
|
|
|
|
var coffee yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &coffee)
|
|
|
|
// 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)
|
|
}
|
|
|
|
func TestSpecIndex_lookupFileReference_MultiRes(t *testing.T) {
|
|
embie := []byte("naughty:\n - puppy: dog\n - puppy: naughty\npuppy:\n - naughty: puppy")
|
|
|
|
_ = os.WriteFile("embie.yaml", embie, 0o664)
|
|
defer os.Remove("embie.yaml")
|
|
|
|
// create a new config that allows local and remote to be mixed up.
|
|
cf := CreateOpenAPIIndexConfig()
|
|
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)
|
|
|
|
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) {
|
|
pup := []byte("good:\n - puppy: dog\n - puppy: forever-more")
|
|
|
|
var myPuppy yaml.Node
|
|
_ = yaml.Unmarshal(pup, &myPuppy)
|
|
|
|
_ = os.WriteFile("fox.yaml", pup, 0o664)
|
|
defer os.Remove("fox.yaml")
|
|
|
|
// create a new config that allows local and remote to be mixed up.
|
|
cf := CreateOpenAPIIndexConfig()
|
|
cf.AvoidBuildIndex = true
|
|
cf.AvoidCircularReferenceCheck = true
|
|
cf.BasePath = "."
|
|
|
|
// create a new rolodex
|
|
rolo := NewRolodex(cf)
|
|
|
|
// 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{"fox.yaml"},
|
|
DirFS: os.DirFS(cf.BasePath),
|
|
}
|
|
|
|
// create a new local filesystem.
|
|
fileFS, err := NewLocalFSWithConfig(&fsCfg)
|
|
assert.NoError(t, err)
|
|
|
|
rolo.AddLocalFS(cf.BasePath, fileFS)
|
|
rErr := rolo.IndexTheRolodex()
|
|
|
|
assert.NoError(t, rErr)
|
|
|
|
fox, fErr := rolo.Open("fox.yaml")
|
|
assert.NoError(t, fErr)
|
|
assert.Equal(t, "fox.yaml", fox.Name())
|
|
assert.Equal(t, "good:\n - puppy: dog\n - puppy: forever-more", string(fox.GetContent()))
|
|
}
|
|
|
|
func TestSpecIndex_parameterReferencesHavePaths(t *testing.T) {
|
|
_ = os.WriteFile("paramour.yaml", []byte(`components:
|
|
parameters:
|
|
param3:
|
|
name: param3
|
|
in: query
|
|
schema:
|
|
type: string`), 0o664)
|
|
defer os.Remove("paramour.yaml")
|
|
|
|
// 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 = "."
|
|
|
|
yml := `paths:
|
|
/:
|
|
parameters:
|
|
- $ref: '#/components/parameters/param1'
|
|
- $ref: '#/components/parameters/param1'
|
|
- $ref: 'paramour.yaml#/components/parameters/param3'
|
|
get:
|
|
parameters:
|
|
- $ref: '#/components/parameters/param2'
|
|
- $ref: '#/components/parameters/param2'
|
|
- name: test
|
|
in: query
|
|
schema:
|
|
type: string
|
|
components:
|
|
parameters:
|
|
param1:
|
|
name: param1
|
|
in: query
|
|
schema:
|
|
type: string
|
|
param2:
|
|
name: param2
|
|
in: query
|
|
schema:
|
|
type: string`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
// 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,
|
|
FileFilters: []string{"paramour.yaml"},
|
|
DirFS: os.DirFS(cf.BasePath),
|
|
}
|
|
|
|
// create a new local filesystem.
|
|
fileFS, err := NewLocalFSWithConfig(&fsCfg)
|
|
assert.NoError(t, err)
|
|
|
|
// add file system
|
|
rolo.AddLocalFS(cf.BasePath, fileFS)
|
|
|
|
// index the rolodex.
|
|
indexedErr := rolo.IndexTheRolodex()
|
|
assert.NoError(t, indexedErr)
|
|
rolo.BuildIndexes()
|
|
|
|
index := rolo.GetRootIndex()
|
|
|
|
params := index.GetAllParametersFromOperations()
|
|
|
|
if assert.Contains(t, params, "/") {
|
|
if assert.Contains(t, params["/"], "top") {
|
|
if assert.Contains(t, params["/"]["top"], "#/components/parameters/param1") {
|
|
assert.Equal(t, "$.components.parameters['param1']", params["/"]["top"]["#/components/parameters/param1"][0].Path)
|
|
}
|
|
if assert.Contains(t, params["/"]["top"], "paramour.yaml#/components/parameters/param3") {
|
|
assert.Equal(t, "$.components.parameters['param3']", params["/"]["top"]["paramour.yaml#/components/parameters/param3"][0].Path)
|
|
}
|
|
}
|
|
if assert.Contains(t, params["/"], "get") {
|
|
if assert.Contains(t, params["/"]["get"], "#/components/parameters/param2") {
|
|
assert.Equal(t, "$.components.parameters['param2']", params["/"]["get"]["#/components/parameters/param2"][0].Path)
|
|
}
|
|
if assert.Contains(t, params["/"]["get"], "test") {
|
|
assert.Equal(t, "$.paths['/'].get.parameters[2]", params["/"]["get"]["test"][0].Path)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSpecIndex_serverReferencesHaveParentNodesAndPaths(t *testing.T) {
|
|
yml := `servers:
|
|
- url: https://api.example.com/v1
|
|
paths:
|
|
/:
|
|
servers:
|
|
- url: https://api.example.com/v2
|
|
get:
|
|
servers:
|
|
- url: https://api.example.com/v3`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
rootServers := index.GetAllRootServers()
|
|
|
|
for i, server := range rootServers {
|
|
assert.NotNil(t, server.ParentNode)
|
|
assert.Equal(t, fmt.Sprintf("$.servers[%d]", i), server.Path)
|
|
}
|
|
|
|
opServers := index.GetAllOperationsServers()
|
|
|
|
for path, ops := range opServers {
|
|
for op, servers := range ops {
|
|
for i, server := range servers {
|
|
assert.NotNil(t, server.ParentNode)
|
|
|
|
opPath := fmt.Sprintf(".%s", op)
|
|
if op == "top" {
|
|
opPath = ""
|
|
}
|
|
|
|
assert.Equal(t, fmt.Sprintf("$.paths['%s']%s.servers[%d]", path, opPath, i), server.Path)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSpecIndex_schemaComponentsHaveParentsAndPaths(t *testing.T) {
|
|
yml := `components:
|
|
schemas:
|
|
Pet:
|
|
type: object
|
|
Dog:
|
|
type: object`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
schemas := index.GetAllSchemas()
|
|
|
|
for _, schema := range schemas {
|
|
assert.NotNil(t, schema.ParentNode)
|
|
assert.Equal(t, fmt.Sprintf("$.components.schemas['%s']", schema.Name), schema.Path)
|
|
}
|
|
}
|
|
|
|
func TestSpecIndex_ParamsWithDuplicateNamesButUniqueInTypes(t *testing.T) {
|
|
yml := `openapi: 3.1.0
|
|
info:
|
|
title: Test
|
|
version: 0.0.1
|
|
servers:
|
|
- url: http://localhost:35123
|
|
paths:
|
|
/example/{action}:
|
|
parameters:
|
|
- name: fastAction
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
- name: fastAction
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
get:
|
|
operationId: example
|
|
parameters:
|
|
- name: action
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
- name: action
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: OK`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
assert.Len(t, idx.paramAllRefs, 4)
|
|
assert.Len(t, idx.paramInlineDuplicateNames, 2)
|
|
assert.Len(t, idx.operationParamErrors, 0)
|
|
assert.Len(t, idx.refErrors, 0)
|
|
}
|
|
|
|
func TestSpecIndex_ParamsWithDuplicateNamesAndSameInTypes(t *testing.T) {
|
|
yml := `openapi: 3.1.0
|
|
info:
|
|
title: Test
|
|
version: 0.0.1
|
|
servers:
|
|
- url: http://localhost:35123
|
|
paths:
|
|
/example/{action}:
|
|
parameters:
|
|
- name: fastAction
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
- name: fastAction
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
get:
|
|
operationId: example
|
|
parameters:
|
|
- name: action
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
- name: action
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: OK`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
assert.Len(t, idx.paramAllRefs, 3)
|
|
assert.Len(t, idx.paramInlineDuplicateNames, 2)
|
|
assert.Len(t, idx.operationParamErrors, 1)
|
|
assert.Len(t, idx.refErrors, 0)
|
|
}
|
|
|
|
func TestSpecIndex_foundObjectsWithProperties(t *testing.T) {
|
|
yml := `paths:
|
|
/test:
|
|
get:
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
content:
|
|
application/json:
|
|
type: object
|
|
properties:
|
|
test:
|
|
type: string
|
|
components:
|
|
schemas:
|
|
test:
|
|
type: object
|
|
properties:
|
|
test:
|
|
type: string
|
|
test2:
|
|
type: [object, null]
|
|
properties:
|
|
test:
|
|
type: string
|
|
test3:
|
|
type: object
|
|
additionalProperties: true`
|
|
|
|
var rootNode yaml.Node
|
|
yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
objects := index.GetAllObjectsWithProperties()
|
|
assert.Len(t, objects, 3)
|
|
}
|
|
|
|
// Example of how to load in an OpenAPI Specification and index it.
|
|
func ExampleNewSpecIndex() {
|
|
// define a rootNode to hold our raw spec AST.
|
|
var rootNode yaml.Node
|
|
|
|
// load in the stripe OpenAPI specification into bytes (it's pretty meaty)
|
|
stripeSpec, _ := os.ReadFile("../test_specs/stripe.yaml")
|
|
|
|
// unmarshal spec into our rootNode
|
|
_ = yaml.Unmarshal(stripeSpec, &rootNode)
|
|
|
|
// create a new specification index.
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
// print out some statistics
|
|
fmt.Printf("There are %d references\n"+
|
|
"%d paths\n"+
|
|
"%d operations\n"+
|
|
"%d component schemas\n"+
|
|
"%d reference schemas\n"+
|
|
"%d inline schemas\n"+
|
|
"%d inline schemas that are objects or arrays\n"+
|
|
"%d total schemas\n"+
|
|
"%d enums\n"+
|
|
"%d polymorphic references",
|
|
len(index.GetAllCombinedReferences()),
|
|
len(index.GetAllPaths()),
|
|
index.GetOperationCount(),
|
|
len(index.GetAllComponentSchemas()),
|
|
len(index.GetAllReferenceSchemas()),
|
|
len(index.GetAllInlineSchemas()),
|
|
len(index.GetAllInlineSchemaObjects()),
|
|
len(index.GetAllSchemas()),
|
|
len(index.GetAllEnums()),
|
|
len(index.GetPolyOneOfReferences())+len(index.GetPolyAnyOfReferences()))
|
|
// Output: There are 871 references
|
|
// 336 paths
|
|
// 494 operations
|
|
// 871 component schemas
|
|
// 2712 reference schemas
|
|
// 15928 inline schemas
|
|
// 3857 inline schemas that are objects or arrays
|
|
// 19511 total schemas
|
|
// 2579 enums
|
|
// 1023 polymorphic references
|
|
}
|
|
|
|
func TestSpecIndex_GetAllPathsHavePathAndParent(t *testing.T) {
|
|
yml := `openapi: 3.1.0
|
|
info:
|
|
title: Test
|
|
version: 0.0.1
|
|
servers:
|
|
- url: http://localhost:35123
|
|
paths:
|
|
/test:
|
|
get:
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
post:
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
/test2:
|
|
delete:
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
put:
|
|
responses:
|
|
"200":
|
|
description: OK`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
paths := idx.GetAllPaths()
|
|
|
|
assert.Equal(t, "$.paths['/test'].get", paths["/test"]["get"].Path)
|
|
assert.Equal(t, 9, paths["/test"]["get"].ParentNode.Line)
|
|
assert.Equal(t, "$.paths['/test'].post", paths["/test"]["post"].Path)
|
|
assert.Equal(t, 13, paths["/test"]["post"].ParentNode.Line)
|
|
assert.Equal(t, "$.paths['/test2'].delete", paths["/test2"]["delete"].Path)
|
|
assert.Equal(t, 18, paths["/test2"]["delete"].ParentNode.Line)
|
|
assert.Equal(t, "$.paths['/test2'].put", paths["/test2"]["put"].Path)
|
|
assert.Equal(t, 22, paths["/test2"]["put"].ParentNode.Line)
|
|
}
|
|
|
|
func TestSpecIndex_TestInlineSchemaPaths(t *testing.T) {
|
|
yml := `openapi: 3.1.0
|
|
info:
|
|
title: Test
|
|
version: 0.0.1
|
|
servers:
|
|
- url: http://localhost:35123
|
|
paths:
|
|
/test:
|
|
get:
|
|
operationId: TestSomething
|
|
parameters:
|
|
- name: test
|
|
in: query
|
|
description: test param for duplicate inline schema
|
|
required: false
|
|
schema:
|
|
type: object
|
|
required:
|
|
- code
|
|
- message
|
|
properties:
|
|
code:
|
|
type: integer
|
|
format: int32
|
|
message:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
'5XX':
|
|
description: test response for slightly different inline schema
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required:
|
|
- code
|
|
- messages
|
|
properties:
|
|
code:
|
|
type: integer
|
|
format: int32
|
|
messages:
|
|
type: string
|
|
default:
|
|
description: test response for duplicate inline schema
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required:
|
|
- code
|
|
- message
|
|
properties:
|
|
code:
|
|
type: integer
|
|
format: int32
|
|
message:
|
|
type: string`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
|
|
schemas := idx.GetAllInlineSchemas()
|
|
assert.Equal(t, "$.paths['/test'].get.parameters['schema']", schemas[0].Path)
|
|
assert.Equal(t, "$.paths['/test'].get.parameters['schema'].properties['code']", schemas[1].Path)
|
|
assert.Equal(t, "$.paths['/test'].get.parameters['schema'].properties['message']", schemas[2].Path)
|
|
}
|
|
|
|
func TestSpecIndex_TestPathsAsRef(t *testing.T) {
|
|
yml := `paths:
|
|
/test:
|
|
$ref: '#/paths/~1test-2'
|
|
/test-2:
|
|
parameters:
|
|
- $ref: '#/components/parameters/test-2'
|
|
get:
|
|
parameters:
|
|
- $ref: '#/components/parameters/test-3'
|
|
components:
|
|
parameters:
|
|
test-2:
|
|
name: test-2
|
|
in: query
|
|
description: bing bong
|
|
schema:
|
|
type: string
|
|
test-3:
|
|
name: test-3
|
|
in: query
|
|
description: ding a ling
|
|
schema:
|
|
type: string`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
params := index.GetOperationParameterReferences()
|
|
assert.Equal(t, "$.components.parameters['test-2']", params["/test"]["top"]["#/components/parameters/test-2"][0].Path)
|
|
assert.Equal(t, "$.components.parameters['test-3']", params["/test-2"]["get"]["#/components/parameters/test-3"][0].Path)
|
|
assert.Equal(t, "bing bong", params["/test"]["top"]["#/components/parameters/test-2"][0].Node.Content[5].Value)
|
|
assert.Equal(t, "ding a ling", params["/test"]["get"]["#/components/parameters/test-3"][0].Node.Content[5].Value)
|
|
}
|
|
|
|
func TestSpecIndex_CheckPropertiesFromExamplesIgnored(t *testing.T) {
|
|
yml := `paths:
|
|
/test:
|
|
get:
|
|
responses:
|
|
'200':
|
|
description: OK
|
|
x-properties:
|
|
properties:
|
|
name: not a schema
|
|
x-example:
|
|
properties:
|
|
name: not a schema
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Object"
|
|
examples:
|
|
Example1:
|
|
value:
|
|
properties:
|
|
name: not a schema
|
|
Example2:
|
|
value:
|
|
properties:
|
|
name: another one
|
|
components:
|
|
schemas:
|
|
Object:
|
|
type: object
|
|
x-properties:
|
|
properties:
|
|
name: not a schema
|
|
properties:
|
|
properties:
|
|
type: object
|
|
properties:
|
|
name:
|
|
type: string
|
|
example:
|
|
properties:
|
|
name: not a schema`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
schemas := index.GetAllSchemas()
|
|
assert.Equal(t, 6, len(schemas))
|
|
}
|
|
|
|
func TestSpecIndex_CheckIgnoreDescriptionsInExamples(t *testing.T) {
|
|
yml := `openapi: 3.1.0
|
|
components:
|
|
examples:
|
|
example1:
|
|
description: this should be ignored`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
schemas := index.GetAllDescriptions()
|
|
assert.Equal(t, 0, len(schemas))
|
|
}
|
|
|
|
func TestSpecIndex_CheckIgnoreSchemaLikeObjectsInExamples(t *testing.T) {
|
|
yml := `openapi: 3.1.0
|
|
paths:
|
|
'/test':
|
|
get:
|
|
responses:
|
|
'200':
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
examples:
|
|
test example:
|
|
value:
|
|
type: Object
|
|
description: test
|
|
properties:
|
|
lineItems:
|
|
type: Array
|
|
description: test
|
|
properties:
|
|
description:
|
|
required: false
|
|
taxRateRef:
|
|
type: Object
|
|
description: test
|
|
properties:
|
|
effectiveTaxRate:
|
|
type: Number
|
|
description: test
|
|
required: false
|
|
required: true
|
|
paymentAllocations:
|
|
type: Array
|
|
description: test
|
|
properties:
|
|
payment:
|
|
type: Object
|
|
description: test
|
|
properties:
|
|
accountRef:
|
|
type: Object`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
schemas := index.GetAllSchemas()
|
|
|
|
assert.Equal(t, 1, len(schemas))
|
|
}
|
|
|
|
func TestSpecIndex_Issue481(t *testing.T) {
|
|
yml := `openapi: 3.0.1
|
|
components:
|
|
schemas:
|
|
PetPot:
|
|
type: object
|
|
properties:
|
|
value:
|
|
oneOf:
|
|
- type: array
|
|
items:
|
|
type: object
|
|
required:
|
|
- $ref
|
|
- value`
|
|
|
|
var rootNode yaml.Node
|
|
_ = yaml.Unmarshal([]byte(yml), &rootNode)
|
|
|
|
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
|
schemas := index.GetAllReferences()
|
|
assert.Equal(t, 0, len(schemas))
|
|
}
|