mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 04:20:11 +00:00
Every `Build()` method now requires a `context.Context`. This is so the rolodex knows where to resolve from when locating relative links. Without knowing where we are, there is no way to resolve anything. This new mechanism allows the model to recurse across as many files as required to locate references, without loosing track of where we are in the process. Signed-off-by: quobix <dave@quobix.com>
772 lines
25 KiB
Go
772 lines
25 KiB
Go
package v3
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/pb33f/libopenapi/utils"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/pb33f/libopenapi/datamodel"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
var doc *Document
|
|
|
|
func initTest() {
|
|
if doc != nil {
|
|
return
|
|
}
|
|
data, _ := os.ReadFile("../../../test_specs/burgershop.openapi.yaml")
|
|
info, _ := datamodel.ExtractSpecInfo(data)
|
|
var err error
|
|
// deprecated function test.
|
|
doc, err = CreateDocument(info)
|
|
if err != nil {
|
|
panic("broken something")
|
|
}
|
|
}
|
|
|
|
func BenchmarkCreateDocument(b *testing.B) {
|
|
data, _ := os.ReadFile("../../../test_specs/burgershop.openapi.yaml")
|
|
info, _ := datamodel.ExtractSpecInfo(data)
|
|
for i := 0; i < b.N; i++ {
|
|
doc, _ = CreateDocumentFromConfig(info, datamodel.NewClosedDocumentConfiguration())
|
|
}
|
|
}
|
|
|
|
func BenchmarkCreateDocument_Circular(b *testing.B) {
|
|
data, _ := os.ReadFile("../../../test_specs/circular-tests.yaml")
|
|
info, _ := datamodel.ExtractSpecInfo(data)
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := CreateDocumentFromConfig(info, datamodel.NewClosedDocumentConfiguration())
|
|
if err == nil {
|
|
panic("this should error, it has circular references")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCircularReferenceError(t *testing.T) {
|
|
data, _ := os.ReadFile("../../../test_specs/circular-tests.yaml")
|
|
info, _ := datamodel.ExtractSpecInfo(data)
|
|
circDoc, err := CreateDocumentFromConfig(info, datamodel.NewClosedDocumentConfiguration())
|
|
|
|
assert.NotNil(t, circDoc)
|
|
assert.Error(t, err)
|
|
|
|
assert.Len(t, utils.UnwrapErrors(err), 3)
|
|
}
|
|
|
|
func TestCircularReference_IgnoreArray(t *testing.T) {
|
|
spec := `openapi: 3.1.0
|
|
components:
|
|
schemas:
|
|
ProductCategory:
|
|
type: "object"
|
|
properties:
|
|
name:
|
|
type: "string"
|
|
children:
|
|
type: "array"
|
|
items:
|
|
$ref: "#/components/schemas/ProductCategory"
|
|
description: "Array of sub-categories in the same format."
|
|
required:
|
|
- "name"
|
|
- "children"`
|
|
|
|
info, _ := datamodel.ExtractSpecInfo([]byte(spec))
|
|
circDoc, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
IgnoreArrayCircularReferences: true,
|
|
})
|
|
assert.NotNil(t, circDoc)
|
|
assert.Len(t, utils.UnwrapErrors(err), 0)
|
|
}
|
|
|
|
func TestCircularReference_IgnorePoly(t *testing.T) {
|
|
spec := `openapi: 3.1.0
|
|
components:
|
|
schemas:
|
|
ProductCategory:
|
|
type: "object"
|
|
properties:
|
|
name:
|
|
type: "string"
|
|
children:
|
|
type: "object"
|
|
anyOf:
|
|
- $ref: "#/components/schemas/ProductCategory"
|
|
description: "Array of sub-categories in the same format."
|
|
required:
|
|
- "name"
|
|
- "children"`
|
|
|
|
info, _ := datamodel.ExtractSpecInfo([]byte(spec))
|
|
circDoc, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
IgnorePolymorphicCircularReferences: true,
|
|
})
|
|
assert.NotNil(t, circDoc)
|
|
assert.Len(t, utils.UnwrapErrors(err), 0)
|
|
}
|
|
|
|
func BenchmarkCreateDocument_Stripe(b *testing.B) {
|
|
data, _ := os.ReadFile("../../../test_specs/stripe.yaml")
|
|
info, _ := datamodel.ExtractSpecInfo(data)
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
if err != nil {
|
|
panic("this should not error")
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkCreateDocument_Petstore(b *testing.B) {
|
|
data, _ := os.ReadFile("../../../test_specs/petstorev3.json")
|
|
info, _ := datamodel.ExtractSpecInfo(data)
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
if err != nil {
|
|
panic("this should not error")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCreateDocumentStripe(t *testing.T) {
|
|
data, _ := os.ReadFile("../../../test_specs/stripe.yaml")
|
|
info, _ := datamodel.ExtractSpecInfo(data)
|
|
d, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
assert.Len(t, utils.UnwrapErrors(err), 3)
|
|
|
|
assert.Equal(t, "3.0.0", d.Version.Value)
|
|
assert.Equal(t, "Stripe API", d.Info.Value.Title.Value)
|
|
assert.NotEmpty(t, d.Info.Value.Title.Value)
|
|
}
|
|
|
|
func TestCreateDocument(t *testing.T) {
|
|
initTest()
|
|
assert.Equal(t, "3.1.0", doc.Version.Value)
|
|
assert.Equal(t, "Burger Shop", doc.Info.Value.Title.Value)
|
|
assert.NotEmpty(t, doc.Info.Value.Title.Value)
|
|
assert.Equal(t, "https://pb33f.io/schema", doc.JsonSchemaDialect.Value)
|
|
assert.Len(t, doc.GetExtensions(), 1)
|
|
}
|
|
|
|
//func TestCreateDocumentHash(t *testing.T) {
|
|
// data, _ := os.ReadFile("../../../test_specs/all-the-components.yaml")
|
|
// info, _ := datamodel.ExtractSpecInfo(data)
|
|
// d, _ := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
// AllowFileReferences: false,
|
|
// AllowRemoteReferences: false,
|
|
// BasePath: "/here",
|
|
// })
|
|
//
|
|
// dataB, _ := os.ReadFile("../../../test_specs/all-the-components.yaml")
|
|
// infoB, _ := datamodel.ExtractSpecInfo(dataB)
|
|
// e, _ := CreateDocumentFromConfig(infoB, &datamodel.DocumentConfiguration{
|
|
// AllowFileReferences: false,
|
|
// AllowRemoteReferences: false,
|
|
// BasePath: "/here",
|
|
// })
|
|
//
|
|
// assert.Equal(t, d.Hash(), e.Hash())
|
|
//}
|
|
|
|
func TestCreateDocument_Info(t *testing.T) {
|
|
initTest()
|
|
assert.Equal(t, "https://pb33f.io", doc.Info.Value.TermsOfService.Value)
|
|
assert.Equal(t, "pb33f", doc.Info.Value.Contact.Value.Name.Value)
|
|
assert.Equal(t, "buckaroo@pb33f.io", doc.Info.Value.Contact.Value.Email.Value)
|
|
assert.Equal(t, "https://pb33f.io", doc.Info.Value.Contact.Value.URL.Value)
|
|
assert.Equal(t, "pb33f", doc.Info.Value.License.Value.Name.Value)
|
|
assert.Equal(t, "https://pb33f.io/made-up", doc.Info.Value.License.Value.URL.Value)
|
|
}
|
|
|
|
func TestCreateDocument_WebHooks(t *testing.T) {
|
|
initTest()
|
|
assert.Len(t, doc.Webhooks.Value, 1)
|
|
for i := range doc.Webhooks.Value {
|
|
// a nice deep model should be available for us.
|
|
assert.Equal(t, "Information about a new burger",
|
|
doc.Webhooks.Value[i].Value.Post.Value.RequestBody.Value.Description.Value)
|
|
}
|
|
}
|
|
|
|
func TestCreateDocument_WebHooks_Error(t *testing.T) {
|
|
yml := `openapi: 3.0
|
|
webhooks:
|
|
$ref: #bork`
|
|
|
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
|
var err error
|
|
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
assert.Len(t, utils.UnwrapErrors(err), 1)
|
|
}
|
|
|
|
func TestCreateDocument_Servers(t *testing.T) {
|
|
initTest()
|
|
assert.Len(t, doc.Servers.Value, 2)
|
|
server1 := doc.Servers.Value[0].Value
|
|
server2 := doc.Servers.Value[1].Value
|
|
|
|
// server 1
|
|
assert.Equal(t, "{scheme}://api.pb33f.io", server1.URL.Value)
|
|
assert.NotEmpty(t, server1.Description.Value)
|
|
assert.Len(t, server1.Variables.Value, 1)
|
|
assert.Len(t, server1.FindVariable("scheme").Value.Enum, 2)
|
|
assert.Equal(t, server1.FindVariable("scheme").Value.Default.Value, "https")
|
|
assert.NotEmpty(t, server1.FindVariable("scheme").Value.Description.Value)
|
|
|
|
// server 2
|
|
assert.Equal(t, "https://{domain}.{host}.com", server2.URL.Value)
|
|
assert.NotEmpty(t, server2.Description.Value)
|
|
assert.Len(t, server2.Variables.Value, 2)
|
|
assert.Equal(t, "api", server2.FindVariable("domain").Value.Default.Value)
|
|
assert.NotEmpty(t, server2.FindVariable("domain").Value.Description.Value)
|
|
assert.NotEmpty(t, server2.FindVariable("host").Value.Description.Value)
|
|
assert.Equal(t, server2.FindVariable("host").Value.Default.Value, "pb33f.io")
|
|
assert.Equal(t, "1.2", doc.Info.Value.Version.Value)
|
|
}
|
|
|
|
func TestCreateDocument_Tags(t *testing.T) {
|
|
initTest()
|
|
assert.Len(t, doc.Tags.Value, 2)
|
|
|
|
// tag1
|
|
assert.Equal(t, "Burgers", doc.Tags.Value[0].Value.Name.Value)
|
|
assert.NotEmpty(t, doc.Tags.Value[0].Value.Description.Value)
|
|
assert.NotNil(t, doc.Tags.Value[0].Value.ExternalDocs.Value)
|
|
assert.Equal(t, "https://pb33f.io", doc.Tags.Value[0].Value.ExternalDocs.Value.URL.Value)
|
|
assert.NotEmpty(t, doc.Tags.Value[0].Value.ExternalDocs.Value.URL.Value)
|
|
assert.Len(t, doc.Tags.Value[0].Value.Extensions, 7)
|
|
|
|
for key, extension := range doc.Tags.Value[0].Value.Extensions {
|
|
switch key.Value {
|
|
case "x-internal-ting":
|
|
assert.Equal(t, "somethingSpecial", extension.Value)
|
|
case "x-internal-tong":
|
|
assert.Equal(t, int64(1), extension.Value)
|
|
case "x-internal-tang":
|
|
assert.Equal(t, 1.2, extension.Value)
|
|
case "x-internal-tung":
|
|
assert.Equal(t, true, extension.Value)
|
|
case "x-internal-arr":
|
|
assert.Len(t, extension.Value, 2)
|
|
assert.Equal(t, "one", extension.Value.([]interface{})[0].(string))
|
|
case "x-internal-arrmap":
|
|
assert.Len(t, extension.Value, 2)
|
|
assert.Equal(t, "now", extension.Value.([]interface{})[0].(map[string]interface{})["what"])
|
|
case "x-something-else":
|
|
// crazy times in the upside down. this API should be avoided for the higher up use cases.
|
|
// this is why we will need a higher level API to this model, this looks cool and all, but dude.
|
|
assert.Equal(t, "now?", extension.Value.(map[string]interface{})["ok"].([]interface{})[0].(map[string]interface{})["what"])
|
|
}
|
|
}
|
|
|
|
/// tag2
|
|
assert.Equal(t, "Dressing", doc.Tags.Value[1].Value.Name.Value)
|
|
assert.NotEmpty(t, doc.Tags.Value[1].Value.Description.Value)
|
|
assert.NotNil(t, doc.Tags.Value[1].Value.ExternalDocs.Value)
|
|
assert.Equal(t, "https://pb33f.io", doc.Tags.Value[1].Value.ExternalDocs.Value.URL.Value)
|
|
assert.NotEmpty(t, doc.Tags.Value[1].Value.ExternalDocs.Value.URL.Value)
|
|
assert.Len(t, doc.Tags.Value[1].Value.Extensions, 0)
|
|
}
|
|
|
|
func TestCreateDocument_Paths(t *testing.T) {
|
|
initTest()
|
|
assert.Len(t, doc.Paths.Value.PathItems, 5)
|
|
burgerId := doc.Paths.Value.FindPath("/burgers/{burgerId}")
|
|
assert.NotNil(t, burgerId)
|
|
assert.Len(t, burgerId.Value.Get.Value.Parameters.Value, 2)
|
|
param := burgerId.Value.Get.Value.Parameters.Value[1]
|
|
assert.Equal(t, "burgerHeader", param.Value.Name.Value)
|
|
prop := param.Value.Schema.Value.Schema().FindProperty("burgerTheme").Value
|
|
assert.Equal(t, "something about a theme goes in here?", prop.Schema().Description.Value)
|
|
assert.Equal(t, "big-mac", param.Value.Example.Value)
|
|
|
|
// check content
|
|
pContent := param.Value.FindContent("application/json")
|
|
assert.Equal(t, "somethingNice", pContent.Value.Example.Value)
|
|
|
|
encoding := pContent.Value.FindPropertyEncoding("burgerTheme")
|
|
assert.NotNil(t, encoding.Value)
|
|
assert.Len(t, encoding.Value.Headers.Value, 1)
|
|
|
|
header := encoding.Value.FindHeader("someHeader")
|
|
assert.NotNil(t, header.Value)
|
|
assert.Equal(t, "this is a header", header.Value.Description.Value)
|
|
assert.Equal(t, "string", header.Value.Schema.Value.Schema().Type.Value.A)
|
|
|
|
// check request body on operation
|
|
burgers := doc.Paths.Value.FindPath("/burgers")
|
|
assert.NotNil(t, burgers.Value.Post.Value)
|
|
|
|
burgersPost := burgers.Value.Post.Value
|
|
assert.Equal(t, "createBurger", burgersPost.OperationId.Value)
|
|
assert.Equal(t, "Create a new burger", burgersPost.Summary.Value)
|
|
assert.NotEmpty(t, burgersPost.Description.Value)
|
|
|
|
requestBody := burgersPost.RequestBody.Value
|
|
|
|
assert.NotEmpty(t, requestBody.Description.Value)
|
|
content := requestBody.FindContent("application/json").Value
|
|
|
|
assert.NotNil(t, content)
|
|
assert.Len(t, content.Schema.Value.Schema().Properties.Value, 4)
|
|
assert.Len(t, content.GetAllExamples(), 2)
|
|
|
|
ex := content.FindExample("pbjBurger")
|
|
assert.NotNil(t, ex.Value)
|
|
assert.NotEmpty(t, ex.Value.Summary.Value)
|
|
assert.NotNil(t, ex.Value.Value.Value)
|
|
|
|
if n, ok := ex.Value.Value.Value.(map[string]interface{}); ok {
|
|
assert.Len(t, n, 2)
|
|
assert.Equal(t, 3, n["numPatties"])
|
|
} else {
|
|
assert.Fail(t, "should easily be convertable. something changed!")
|
|
}
|
|
|
|
cb := content.FindExample("cakeBurger")
|
|
assert.NotNil(t, cb.Value)
|
|
assert.NotEmpty(t, cb.Value.Summary.Value)
|
|
assert.NotNil(t, cb.Value.Value.Value)
|
|
|
|
if n, ok := cb.Value.Value.Value.(map[string]interface{}); ok {
|
|
assert.Len(t, n, 2)
|
|
assert.Equal(t, "Chocolate Cake Burger", n["name"])
|
|
assert.Equal(t, 5, n["numPatties"])
|
|
} else {
|
|
assert.Fail(t, "should easily be convertable. something changed!")
|
|
}
|
|
|
|
// check responses
|
|
responses := burgersPost.Responses.Value
|
|
assert.NotNil(t, responses)
|
|
assert.Len(t, responses.Codes, 3)
|
|
|
|
okCode := responses.FindResponseByCode("200")
|
|
assert.NotNil(t, okCode.Value)
|
|
assert.Equal(t, "A tasty burger for you to eat.", okCode.Value.Description.Value)
|
|
|
|
// check headers are populated
|
|
assert.Len(t, okCode.Value.Headers.Value, 1)
|
|
okheader := okCode.Value.FindHeader("UseOil")
|
|
assert.NotNil(t, okheader.Value)
|
|
assert.Equal(t, "this is a header example for UseOil", okheader.Value.Description.Value)
|
|
|
|
respContent := okCode.Value.FindContent("application/json").Value
|
|
assert.NotNil(t, respContent)
|
|
|
|
assert.NotNil(t, respContent.Schema.Value)
|
|
assert.Len(t, respContent.Schema.Value.Schema().Required.Value, 2)
|
|
|
|
respExample := respContent.FindExample("quarterPounder")
|
|
assert.NotNil(t, respExample.Value)
|
|
assert.NotNil(t, respExample.Value.Value.Value)
|
|
|
|
if n, ok := respExample.Value.Value.Value.(map[string]interface{}); ok {
|
|
assert.Len(t, n, 2)
|
|
assert.Equal(t, "Quarter Pounder with Cheese", n["name"])
|
|
assert.Equal(t, 1, n["numPatties"])
|
|
} else {
|
|
assert.Fail(t, "should easily be convertable. something changed!")
|
|
}
|
|
|
|
// check links
|
|
links := okCode.Value.Links
|
|
assert.NotNil(t, links.Value)
|
|
assert.Len(t, links.Value, 2)
|
|
assert.Equal(t, "locateBurger", okCode.Value.FindLink("LocateBurger").Value.OperationId.Value)
|
|
|
|
locateBurger := okCode.Value.FindLink("LocateBurger").Value
|
|
|
|
burgerIdParam := locateBurger.FindParameter("burgerId")
|
|
assert.NotNil(t, burgerIdParam)
|
|
assert.Equal(t, "$response.body#/id", burgerIdParam.Value)
|
|
|
|
// check security requirements
|
|
oAuthReq := burgersPost.FindSecurityRequirement("OAuthScheme")
|
|
assert.Len(t, oAuthReq, 2)
|
|
assert.Equal(t, "read:burgers", oAuthReq[0].Value)
|
|
|
|
servers := burgersPost.Servers.Value
|
|
assert.NotNil(t, servers)
|
|
assert.Len(t, servers, 1)
|
|
assert.Equal(t, "https://pb33f.io", servers[0].Value.URL.Value)
|
|
}
|
|
|
|
func TestCreateDocument_Components_Schemas(t *testing.T) {
|
|
initTest()
|
|
|
|
components := doc.Components.Value
|
|
assert.NotNil(t, components)
|
|
assert.Len(t, components.Schemas.Value, 6)
|
|
|
|
burger := components.FindSchema("Burger").Value
|
|
assert.NotNil(t, burger)
|
|
assert.Equal(t, "The tastiest food on the planet you would love to eat everyday", burger.Schema().Description.Value)
|
|
|
|
er := components.FindSchema("Error")
|
|
assert.NotNil(t, er.Value)
|
|
assert.Equal(t, "Error defining what went wrong when providing a specification. The message should help "+
|
|
"indicate the issue clearly.", er.Value.Schema().Description.Value)
|
|
|
|
fries := components.FindSchema("Fries")
|
|
assert.NotNil(t, fries.Value)
|
|
|
|
assert.Len(t, fries.Value.Schema().Properties.Value, 3)
|
|
p := fries.Value.Schema().FindProperty("favoriteDrink")
|
|
assert.Equal(t, "a frosty cold beverage can be coke or sprite",
|
|
p.Value.Schema().Description.Value)
|
|
}
|
|
|
|
func TestCreateDocument_Components_SecuritySchemes(t *testing.T) {
|
|
initTest()
|
|
components := doc.Components.Value
|
|
securitySchemes := components.SecuritySchemes.Value
|
|
assert.Len(t, securitySchemes, 3)
|
|
|
|
apiKey := components.FindSecurityScheme("APIKeyScheme").Value
|
|
assert.NotNil(t, apiKey)
|
|
assert.Equal(t, "an apiKey security scheme", apiKey.Description.Value)
|
|
|
|
oAuth := components.FindSecurityScheme("OAuthScheme").Value
|
|
assert.NotNil(t, oAuth)
|
|
assert.Equal(t, "an oAuth security scheme", oAuth.Description.Value)
|
|
assert.NotNil(t, oAuth.Flows.Value.Implicit.Value)
|
|
assert.NotNil(t, oAuth.Flows.Value.AuthorizationCode.Value)
|
|
|
|
scopes := oAuth.Flows.Value.Implicit.Value.Scopes.Value
|
|
assert.NotNil(t, scopes)
|
|
|
|
readScope := oAuth.Flows.Value.Implicit.Value.FindScope("write:burgers")
|
|
assert.NotNil(t, readScope)
|
|
assert.Equal(t, "modify and add new burgers", readScope.Value)
|
|
|
|
readScope = oAuth.Flows.Value.AuthorizationCode.Value.FindScope("write:burgers")
|
|
assert.NotNil(t, readScope)
|
|
assert.Equal(t, "modify burgers and stuff", readScope.Value)
|
|
}
|
|
|
|
func TestCreateDocument_Components_Responses(t *testing.T) {
|
|
initTest()
|
|
components := doc.Components.Value
|
|
responses := components.Responses.Value
|
|
assert.Len(t, responses, 1)
|
|
|
|
dressingResponse := components.FindResponse("DressingResponse")
|
|
assert.NotNil(t, dressingResponse.Value)
|
|
assert.Equal(t, "all the dressings for a burger.", dressingResponse.Value.Description.Value)
|
|
assert.Len(t, dressingResponse.Value.Content.Value, 1)
|
|
}
|
|
|
|
func TestCreateDocument_Components_Examples(t *testing.T) {
|
|
initTest()
|
|
components := doc.Components.Value
|
|
examples := components.Examples.Value
|
|
assert.Len(t, examples, 1)
|
|
|
|
quarterPounder := components.FindExample("QuarterPounder")
|
|
assert.NotNil(t, quarterPounder.Value)
|
|
assert.Equal(t, "A juicy two hander sammich", quarterPounder.Value.Summary.Value)
|
|
assert.NotNil(t, quarterPounder.Value.Value.Value)
|
|
}
|
|
|
|
func TestCreateDocument_Components_RequestBodies(t *testing.T) {
|
|
initTest()
|
|
components := doc.Components.Value
|
|
requestBodies := components.RequestBodies.Value
|
|
assert.Len(t, requestBodies, 1)
|
|
|
|
burgerRequest := components.FindRequestBody("BurgerRequest")
|
|
assert.NotNil(t, burgerRequest.Value)
|
|
assert.Equal(t, "Give us the new burger!", burgerRequest.Value.Description.Value)
|
|
assert.Len(t, burgerRequest.Value.Content.Value, 1)
|
|
}
|
|
|
|
func TestCreateDocument_Components_Headers(t *testing.T) {
|
|
initTest()
|
|
components := doc.Components.Value
|
|
headers := components.Headers.Value
|
|
assert.Len(t, headers, 1)
|
|
|
|
useOil := components.FindHeader("UseOil")
|
|
assert.NotNil(t, useOil.Value)
|
|
assert.Equal(t, "this is a header example for UseOil", useOil.Value.Description.Value)
|
|
assert.Equal(t, "string", useOil.Value.Schema.Value.Schema().Type.Value.A)
|
|
}
|
|
|
|
func TestCreateDocument_Components_Links(t *testing.T) {
|
|
initTest()
|
|
components := doc.Components.Value
|
|
links := components.Links.Value
|
|
assert.Len(t, links, 2)
|
|
|
|
locateBurger := components.FindLink("LocateBurger")
|
|
assert.NotNil(t, locateBurger.Value)
|
|
assert.Equal(t, "Go and get a tasty burger", locateBurger.Value.Description.Value)
|
|
|
|
anotherLocateBurger := components.FindLink("AnotherLocateBurger")
|
|
assert.NotNil(t, anotherLocateBurger.Value)
|
|
assert.Equal(t, "Go and get another really tasty burger", anotherLocateBurger.Value.Description.Value)
|
|
}
|
|
|
|
func TestCreateDocument_Doc_Security(t *testing.T) {
|
|
initTest()
|
|
d := doc
|
|
oAuth := d.FindSecurityRequirement("OAuthScheme")
|
|
assert.Len(t, oAuth, 2)
|
|
}
|
|
|
|
func TestCreateDocument_Callbacks(t *testing.T) {
|
|
initTest()
|
|
callbacks := doc.Components.Value.Callbacks.Value
|
|
assert.Len(t, callbacks, 1)
|
|
|
|
bCallback := doc.Components.Value.FindCallback("BurgerCallback")
|
|
assert.NotNil(t, bCallback.Value)
|
|
assert.Len(t, callbacks, 1)
|
|
|
|
exp := bCallback.Value.FindExpression("{$request.query.queryUrl}")
|
|
assert.NotNil(t, exp.Value)
|
|
assert.NotNil(t, exp.Value.Post.Value)
|
|
assert.Equal(t, "Callback payload", exp.Value.Post.Value.RequestBody.Value.Description.Value)
|
|
}
|
|
|
|
func TestCreateDocument_Component_Discriminator(t *testing.T) {
|
|
initTest()
|
|
|
|
components := doc.Components.Value
|
|
dsc := components.FindSchema("Drink").Value.Schema().Discriminator.Value
|
|
assert.NotNil(t, dsc)
|
|
assert.Equal(t, "drinkType", dsc.PropertyName.Value)
|
|
assert.Equal(t, "some value", dsc.FindMappingValue("drink").Value)
|
|
assert.Nil(t, dsc.FindMappingValue("don't exist"))
|
|
assert.NotNil(t, doc.GetExternalDocs())
|
|
assert.Nil(t, doc.FindSecurityRequirement("scooby doo"))
|
|
}
|
|
|
|
func TestCreateDocument_CheckAdditionalProperties_Schema(t *testing.T) {
|
|
initTest()
|
|
components := doc.Components.Value
|
|
d := components.FindSchema("Dressing")
|
|
assert.NotNil(t, d.Value.Schema().AdditionalProperties.Value)
|
|
|
|
assert.True(t, d.Value.Schema().AdditionalProperties.Value.IsA(), "should be a schema")
|
|
}
|
|
|
|
func TestCreateDocument_CheckAdditionalProperties_Bool(t *testing.T) {
|
|
initTest()
|
|
components := doc.Components.Value
|
|
d := components.FindSchema("Drink")
|
|
assert.NotNil(t, d.Value.Schema().AdditionalProperties.Value)
|
|
assert.True(t, d.Value.Schema().AdditionalProperties.Value.B)
|
|
}
|
|
|
|
func TestCreateDocument_Components_Error(t *testing.T) {
|
|
yml := `openapi: 3.0
|
|
components:
|
|
schemas:
|
|
bork:
|
|
properties:
|
|
bark:
|
|
$ref: #bork`
|
|
|
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
|
var err error
|
|
doc, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
ob := doc.Components.Value.FindSchema("bork").Value
|
|
ob.Schema()
|
|
assert.Error(t, ob.GetBuildError())
|
|
}
|
|
|
|
func TestCreateDocument_Webhooks_Error(t *testing.T) {
|
|
yml := `openapi: 3.0
|
|
webhooks:
|
|
aHook:
|
|
$ref: #bork`
|
|
|
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
|
var err error
|
|
doc, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
assert.Equal(t, "flat map build failed: reference cannot be found: reference at line 4, column 5 is empty, it cannot be resolved",
|
|
err.Error())
|
|
}
|
|
|
|
func TestCreateDocument_Components_Error_Extract(t *testing.T) {
|
|
yml := `openapi: 3.0
|
|
components:
|
|
parameters:
|
|
bork:
|
|
$ref: #bork`
|
|
|
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
|
var err error
|
|
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
assert.Equal(t, "reference at line 5, column 7 is empty, it cannot be resolved", err.Error())
|
|
}
|
|
|
|
func TestCreateDocument_Paths_Errors(t *testing.T) {
|
|
yml := `openapi: 3.0
|
|
paths:
|
|
/p:
|
|
$ref: #bork`
|
|
|
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
|
var err error
|
|
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
assert.Equal(t,
|
|
"path item build failed: cannot find reference: at line 4, col 10", err.Error())
|
|
}
|
|
|
|
func TestCreateDocument_Tags_Errors(t *testing.T) {
|
|
yml := `openapi: 3.0
|
|
tags:
|
|
- $ref: #bork`
|
|
|
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
|
var err error
|
|
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
assert.Equal(t,
|
|
"object extraction failed: reference at line 3, column 5 is empty, it cannot be resolved", err.Error())
|
|
}
|
|
|
|
func TestCreateDocument_Security_Error(t *testing.T) {
|
|
yml := `openapi: 3.0
|
|
security:
|
|
$ref: #bork`
|
|
|
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
|
var err error
|
|
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
assert.Equal(t,
|
|
"array build failed: reference cannot be found: reference at line 3, column 3 is empty, it cannot be resolved",
|
|
err.Error())
|
|
}
|
|
|
|
func TestCreateDocument_ExternalDoc_Error(t *testing.T) {
|
|
yml := `openapi: 3.0
|
|
externalDocs:
|
|
$ref: #bork`
|
|
|
|
info, _ := datamodel.ExtractSpecInfo([]byte(yml))
|
|
var err error
|
|
_, err = CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
assert.Equal(t, "object extraction failed: reference at line 3, column 3 is empty, it cannot be resolved", err.Error())
|
|
}
|
|
|
|
func TestCreateDocument_YamlAnchor(t *testing.T) {
|
|
// load petstore into bytes
|
|
anchorDocument, _ := os.ReadFile("../../../test_specs/yaml-anchor.yaml")
|
|
|
|
// read in specification
|
|
info, _ := datamodel.ExtractSpecInfo(anchorDocument)
|
|
|
|
// build low-level document model
|
|
document, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
|
|
if err != nil {
|
|
fmt.Printf("error: %s\n", err.Error())
|
|
panic("cannot build document")
|
|
}
|
|
|
|
examplePath := document.Paths.GetValue().FindPath("/system/examples/{id}")
|
|
assert.NotNil(t, examplePath)
|
|
|
|
// Check tag reference
|
|
getOp := examplePath.GetValue().Get.GetValue()
|
|
assert.NotNil(t, getOp)
|
|
postOp := examplePath.GetValue().Get.GetValue()
|
|
assert.NotNil(t, postOp)
|
|
assert.Equal(t, 1, len(getOp.GetTags().GetValue()))
|
|
assert.Equal(t, 1, len(postOp.GetTags().GetValue()))
|
|
assert.Equal(t, getOp.GetTags().GetValue(), postOp.GetTags().GetValue())
|
|
|
|
// Check parameter reference
|
|
getParams := examplePath.Value.Get.Value.Parameters.Value
|
|
assert.NotNil(t, getParams)
|
|
postParams := examplePath.Value.Post.Value.Parameters.Value
|
|
assert.NotNil(t, postParams)
|
|
assert.Equal(t, 1, len(getParams))
|
|
assert.Equal(t, 1, len(postParams))
|
|
assert.Equal(t, getParams, postParams)
|
|
|
|
// check post request body
|
|
responses := examplePath.GetValue().Get.GetValue().GetResponses().Value.(*Responses)
|
|
assert.NotNil(t, responses)
|
|
jsonGet := responses.FindResponseByCode("200").GetValue().FindContent("application/json")
|
|
assert.NotNil(t, jsonGet)
|
|
|
|
// Should this work? It doesn't
|
|
// update from quobix 10/14/2023: It does now!
|
|
postJsonType := examplePath.GetValue().Post.GetValue().RequestBody.GetValue().FindContent("application/json")
|
|
assert.NotNil(t, postJsonType)
|
|
}
|
|
|
|
func ExampleCreateDocument() {
|
|
// How to create a low-level OpenAPI 3 Document
|
|
|
|
// load petstore into bytes
|
|
petstoreBytes, _ := os.ReadFile("../../../test_specs/petstorev3.json")
|
|
|
|
// read in specification
|
|
info, _ := datamodel.ExtractSpecInfo(petstoreBytes)
|
|
|
|
// build low-level document model
|
|
document, err := CreateDocumentFromConfig(info, &datamodel.DocumentConfiguration{
|
|
AllowFileReferences: false,
|
|
AllowRemoteReferences: false,
|
|
})
|
|
|
|
if err != nil {
|
|
fmt.Printf("error: %s\n", err.Error())
|
|
panic("cannot build document")
|
|
}
|
|
|
|
// print out email address from the info > contact object.
|
|
fmt.Print(document.Info.Value.Contact.Value.Email.Value)
|
|
// Output: apiteam@swagger.io
|
|
}
|