mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 12:37:49 +00:00
938 lines
29 KiB
Go
938 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_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
|
|
}
|