mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-07 20:47:45 +00:00
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.
953 lines
29 KiB
Go
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
|
|
}
|