Files
libopenapi/index/spec_index_test.go
Dave Shanley e6626fe22e Support for relative links now in place #73
Tests all passing, runs super fast, pulls in every single DigitalOcean spec and parses it. There may be some issues deeper down in the models, but for now high level tests all pass.
2023-02-22 09:14:27 -05:00

953 lines
29 KiB
Go

// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT
package index
import (
"fmt"
"io/ioutil"
"net/url"
"os"
"testing"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
)
func TestSpecIndex_ExtractRefsStripe(t *testing.T) {
stripe, _ := ioutil.ReadFile("../test_specs/stripe.yaml")
var rootNode yaml.Node
yaml.Unmarshal(stripe, &rootNode)
index := NewSpecIndex(&rootNode)
assert.Len(t, index.allRefs, 385)
assert.Equal(t, 537, len(index.allMappedRefs))
combined := index.GetAllCombinedReferences()
assert.Equal(t, 537, len(combined))
assert.Len(t, index.rawSequencedRefs, 1972)
assert.Equal(t, 246, index.pathCount)
assert.Equal(t, 402, index.operationCount)
assert.Equal(t, 537, index.schemaCount)
assert.Equal(t, 0, index.globalTagsCount)
assert.Equal(t, 0, index.globalLinksCount)
assert.Equal(t, 0, index.componentParamCount)
assert.Equal(t, 143, index.operationParamCount)
assert.Equal(t, 88, index.componentsInlineParamDuplicateCount)
assert.Equal(t, 55, index.componentsInlineParamUniqueCount)
assert.Equal(t, 1516, index.enumCount)
assert.Len(t, index.GetAllEnums(), 1516)
assert.Len(t, index.GetPolyAllOfReferences(), 0)
assert.Len(t, index.GetPolyOneOfReferences(), 275)
assert.Len(t, index.GetPolyAnyOfReferences(), 553)
assert.NotNil(t, index.GetRootServersNode())
assert.Len(t, index.GetAllRootServers(), 1)
// 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.Len(t, index.GetRefsByLine(), 537)
assert.Len(t, index.GetLinesWithReferences(), 1972)
assert.Len(t, index.GetAllExternalDocuments(), 0)
assert.Len(t, index.GetAllExternalIndexes(), 0)
}
func TestSpecIndex_Asana(t *testing.T) {
asana, _ := ioutil.ReadFile("../test_specs/asana.yaml")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
index := NewSpecIndex(&rootNode)
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) {
asana, _ := ioutil.ReadFile("../test_specs/digitalocean.yaml")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
BaseURL: baseURL,
AllowRemoteLookup: true,
AllowFileLookup: true,
})
assert.Len(t, index.GetAllExternalIndexes(), 291)
assert.NotNil(t, index)
}
func TestSpecIndex_DigitalOcean_LookupsNotAllowed(t *testing.T) {
asana, _ := ioutil.ReadFile("../test_specs/digitalocean.yaml")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
baseURL, _ := url.Parse("https://raw.githubusercontent.com/digitalocean/openapi/main/specification")
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
BaseURL: baseURL,
})
// 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)
}
func TestSpecIndex_BaseURLError(t *testing.T) {
asana, _ := ioutil.ReadFile("../test_specs/digitalocean.yaml")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
// this should fail because the base url is not a valid url and digital ocean won't be able to resolve
// anything.
baseURL, _ := url.Parse("https://githerbs.com/fresh/herbs/for/you")
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
BaseURL: baseURL,
AllowRemoteLookup: true,
AllowFileLookup: true,
})
assert.Len(t, index.GetAllExternalIndexes(), 0)
}
func TestSpecIndex_k8s(t *testing.T) {
asana, _ := ioutil.ReadFile("../test_specs/k8s.json")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
index := NewSpecIndex(&rootNode)
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, _ := ioutil.ReadFile("../test_specs/petstorev2.json")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
index := NewSpecIndex(&rootNode)
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, _ := ioutil.ReadFile("../test_specs/xsoar.json")
var rootNode yaml.Node
yaml.Unmarshal(xsoar, &rootNode)
index := NewSpecIndex(&rootNode)
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, _ := ioutil.ReadFile("../test_specs/petstorev3.json")
var rootNode yaml.Node
yaml.Unmarshal(petstore, &rootNode)
index := NewSpecIndex(&rootNode)
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)
}
var mappedRefs = 15
func TestSpecIndex_BurgerShop(t *testing.T) {
burgershop, _ := ioutil.ReadFile("../test_specs/burgershop.openapi.yaml")
var rootNode yaml.Node
yaml.Unmarshal(burgershop, &rootNode)
index := NewSpecIndex(&rootNode)
assert.Len(t, index.allRefs, mappedRefs)
assert.Len(t, index.allMappedRefs, mappedRefs)
assert.Equal(t, mappedRefs, len(index.GetMappedReferences()))
assert.Equal(t, mappedRefs, 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, 15, 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_BurgerShop_AllTheComponents(t *testing.T) {
burgershop, _ := ioutil.ReadFile("../test_specs/all-the-components.yaml")
var rootNode yaml.Node
yaml.Unmarshal(burgershop, &rootNode)
index := NewSpecIndex(&rootNode)
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 := NewSpecIndex(&rootNode)
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 := NewSpecIndex(&rootNode)
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", nil))
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 TestSpecIndex_BurgerShopMixedRef(t *testing.T) {
spec, _ := ioutil.ReadFile("../test_specs/mixedref-burgershop.openapi.yaml")
var rootNode yaml.Node
yaml.Unmarshal(spec, &rootNode)
index := NewSpecIndexWithConfig(&rootNode, &SpecIndexConfig{
AllowRemoteLookup: true,
AllowFileLookup: true,
})
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())
}
func TestSpecIndex_TestEmptyBrokenReferences(t *testing.T) {
asana, _ := ioutil.ReadFile("../test_specs/badref-burgershop.openapi.yaml")
var rootNode yaml.Node
yaml.Unmarshal(asana, &rootNode)
index := NewSpecIndex(&rootNode)
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, 7)
}
func TestTagsNoDescription(t *testing.T) {
yml := `tags:
- name: one
- name: two
- three: three`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
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 := NewSpecIndex(&rootNode)
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 := NewSpecIndex(&rootNode)
assert.Len(t, index.GetReferenceIndexErrors(), 1)
}
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 := NewSpecIndex(&rootNode)
assert.Equal(t, "#/paths/~1crazy~1ass~1references/get/parameters/0",
index.FindComponent("#/paths/~1crazy~1ass~1references/get/responses/404/content/application~1xml;%20charset=utf-8/schema", nil).Node.Content[1].Value)
assert.Equal(t, "a param",
index.FindComponent("#/paths/~1crazy~1ass~1references/get/parameters/0", nil).Node.Content[1].Value)
}
func TestSpecIndex_FindComponenth(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 := NewSpecIndex(&rootNode)
assert.Nil(t, index.FindComponent("I-do-not-exist", nil))
}
func TestSpecIndex_performExternalLookup(t *testing.T) {
yml := `{
"openapi": "3.1.0",
"paths": [
{"/": {
"get": {}
}}
]
}`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
assert.Len(t, index.GetPathsNode().Content, 1)
}
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 := NewSpecIndex(&rootNode)
assert.Nil(t, index.performExternalLookup(nil, "unknown", nil, nil))
}
func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_Error(t *testing.T) {
index := new(SpecIndex)
index.seenRemoteSources = make(map[string]*yaml.Node)
index.seenRemoteSources["https://no-hope-for-a-dope.com"] = &yaml.Node{}
_, _, err := index.lookupRemoteReference("https://no-hope-for-a-dope.com#/$.....#[;]something")
assert.Error(t, err)
}
func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_BadFind(t *testing.T) {
index := new(SpecIndex)
index.seenRemoteSources = make(map[string]*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")
assert.Error(t, err)
assert.Nil(t, a)
assert.Nil(t, b)
}
// Discovered in issue https://github.com/pb33f/libopenapi/issues/37
func TestSpecIndex_lookupRemoteReference_NoComponent(t *testing.T) {
index := new(SpecIndex)
index.seenRemoteSources = make(map[string]*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")
assert.NoError(t, err)
assert.NotNil(t, a)
assert.NotNil(t, b)
}
// Discovered in issue https://github.com/daveshanley/vacuum/issues/225
func TestSpecIndex_lookupFileReference_NoComponent(t *testing.T) {
index := new(SpecIndex)
_ = ioutil.WriteFile("coffee-time.yaml", []byte("time: for coffee"), 0o664)
defer os.Remove("coffee-time.yaml")
index.seenRemoteSources = make(map[string]*yaml.Node)
a, b, err := index.lookupFileReference("coffee-time.yaml")
assert.NoError(t, err)
assert.NotNil(t, a)
assert.NotNil(t, b)
}
func TestSpecIndex_CheckBadURLRef(t *testing.T) {
yml := `openapi: 3.1.0
paths:
/cakes:
post:
parameters:
- $ref: 'httpsss://badurl'`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
assert.Len(t, index.refErrors, 2)
}
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, 2)
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) {
_ = ioutil.WriteFile("coffee-time.yaml", []byte("name: time for coffee"), 0o664)
defer os.Remove("coffee-time.yaml")
yml := `openapi: 3.0.3
paths:
/cakes:
post:
parameters:
- $ref: 'coffee-time.yaml'`
var rootNode yaml.Node
yaml.Unmarshal([]byte(yml), &rootNode)
index := NewSpecIndex(&rootNode)
assert.NotNil(t, index.GetAllParametersFromOperations()["/cakes"]["post"]["coffee-time.yaml"].Node)
}
func TestSpecIndex_lookupRemoteReference_SeenSourceSimulation_BadJSON(t *testing.T) {
index := NewSpecIndexWithConfig(nil, &SpecIndexConfig{
AllowRemoteLookup: true,
})
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")
assert.Error(t, err)
assert.Nil(t, a)
assert.Nil(t, b)
}
func TestSpecIndex_lookupFileReference_BadFileName(t *testing.T) {
index := new(SpecIndex)
_, _, err := index.lookupFileReference("not-a-reference")
assert.Error(t, err)
}
func TestSpecIndex_lookupFileReference_SeenSourceSimulation_Error(t *testing.T) {
index := new(SpecIndex)
index.seenRemoteSources = make(map[string]*yaml.Node)
index.seenRemoteSources["magic-money-file.json"] = &yaml.Node{}
_, _, err := index.lookupFileReference("magic-money-file.json#something")
assert.Error(t, err)
}
func TestSpecIndex_lookupFileReference_BadFile(t *testing.T) {
index := new(SpecIndex)
_, _, err := index.lookupFileReference("chickers.json#no-rice")
assert.Error(t, err)
}
func TestSpecIndex_lookupFileReference_BadFileDataRead(t *testing.T) {
_ = ioutil.WriteFile("chickers.yaml", []byte("broke: the: thing: [again]"), 0o664)
defer os.Remove("chickers.yaml")
index := new(SpecIndex)
_, _, err := index.lookupFileReference("chickers.yaml#no-rice")
assert.Error(t, err)
}
func TestSpecIndex_lookupFileReference_MultiRes(t *testing.T) {
_ = ioutil.WriteFile("embie.yaml", []byte("naughty:\n - puppy: dog\n - puppy: naughty\npuppy:\n - naughty: puppy"), 0o664)
defer os.Remove("embie.yaml")
index := new(SpecIndex)
index.seenRemoteSources = make(map[string]*yaml.Node)
k, doc, err := index.lookupFileReference("embie.yaml#/.naughty")
assert.NoError(t, err)
assert.NotNil(t, doc)
assert.Nil(t, k)
}
func TestSpecIndex_lookupFileReference(t *testing.T) {
_ = ioutil.WriteFile("fox.yaml", []byte("good:\n - puppy: dog\n - puppy: forever-more"), 0o664)
defer os.Remove("fox.yaml")
index := new(SpecIndex)
index.seenRemoteSources = make(map[string]*yaml.Node)
k, doc, err := index.lookupFileReference("fox.yaml#/good")
assert.NoError(t, err)
assert.NotNil(t, doc)
assert.NotNil(t, k)
}
func TestSpecIndex_parameterReferencesHavePaths(t *testing.T) {
_ = ioutil.WriteFile("paramour.yaml", []byte(`components:
parameters:
param3:
name: param3
in: query
schema:
type: string`), 0o664)
defer os.Remove("paramour.yaml")
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)
index := NewSpecIndex(&rootNode)
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"].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"].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"].Path)
}
if assert.Contains(t, params["/"]["get"], "test") {
assert.Equal(t, "$.paths./.get.parameters[2]", params["/"]["get"]["test"].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 := NewSpecIndex(&rootNode)
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 := NewSpecIndex(&rootNode)
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_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 := NewSpecIndex(&rootNode)
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, _ := ioutil.ReadFile("../test_specs/stripe.yaml")
// unmarshal spec into our rootNode
yaml.Unmarshal(stripeSpec, &rootNode)
// create a new specification index.
index := NewSpecIndex(&rootNode)
// print out some statistics
fmt.Printf("There are %d references\n"+
"%d paths\n"+
"%d operations\n"+
"%d component 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.GetAllInlineSchemas()),
len(index.GetAllInlineSchemaObjects()),
len(index.GetAllSchemas()),
len(index.GetAllEnums()),
len(index.GetPolyOneOfReferences())+len(index.GetPolyAnyOfReferences()))
// Output: There are 537 references
// 246 paths
// 402 operations
// 537 component schemas
// 1530 inline schemas
// 711 inline schemas that are objects or arrays
// 2067 total schemas
// 1516 enums
// 828 polymorphic references
}