1package analysis_test 2 3import ( 4 "flag" 5 "io/ioutil" 6 "net/http" 7 "net/http/httptest" 8 "os" 9 "testing" 10 11 "github.com/go-openapi/analysis" 12 "github.com/go-openapi/loads" 13 "github.com/go-openapi/spec" 14 "github.com/go-openapi/swag" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17) 18 19var enableLongTests bool 20 21func init() { 22 flag.BoolVar(&enableLongTests, "enable-long", false, "enable long runnning tests") 23} 24 25func skipNotify(t *testing.T) { 26 t.Log("To enable this long running test, use -args -enable-long in your go test command line") 27} 28 29func Test_FlattenAzure(t *testing.T) { 30 if !enableLongTests { 31 skipNotify(t) 32 t.SkipNow() 33 } 34 t.Parallel() 35 36 // Local copy of https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specification/network/resource-manager/Microsoft.Network/stable/2020-04-01/publicIpAddress.json 37 url := "fixtures/azure/publicIpAddress.json" 38 byts, err := swag.LoadFromFileOrHTTP(url) 39 assert.NoError(t, err) 40 swagger := &spec.Swagger{} 41 require.NoError(t, swagger.UnmarshalJSON(byts)) 42 43 analyzed := analysis.New(swagger) 44 require.NoError(t, analysis.Flatten(analysis.FlattenOpts{Spec: analyzed, Expand: true, BasePath: url})) 45 46 jazon := asJSON(t, swagger) 47 48 assertRefInJSONRegexp(t, jazon, `^(#/definitions/)|(\./example)`) 49 50 t.Run("resolve local $ref azure", func(t *testing.T) { 51 assertRefResolve(t, jazon, `\./example`, swagger, &spec.ExpandOptions{RelativeBase: url}) 52 }) 53} 54 55func TestRemoteFlattenAzure_Expand(t *testing.T) { 56 if !enableLongTests { 57 skipNotify(t) 58 t.SkipNow() 59 } 60 t.Parallel() 61 62 server := httptest.NewServer(http.FileServer(http.Dir("fixtures/azure"))) 63 defer server.Close() 64 65 basePath := server.URL + "/publicIpAddress.json" 66 67 swagger, err := loads.Spec(basePath) 68 require.NoError(t, err) 69 70 require.NoError(t, analysis.Flatten(analysis.FlattenOpts{Spec: swagger.Analyzer, Expand: true, BasePath: basePath})) 71 72 jazon := asJSON(t, swagger.Spec()) 73 74 assertRefInJSONRegexp(t, jazon, `^(#/definitions/)|(\./example)`) 75 76 t.Run("resolve remote $ref azure [after expansion]", func(t *testing.T) { 77 assertRefResolve(t, jazon, `\./example`, swagger.Spec(), &spec.ExpandOptions{RelativeBase: basePath}) 78 }) 79} 80 81func TestRemoteFlattenAzure_Flatten(t *testing.T) { 82 if !enableLongTests { 83 skipNotify(t) 84 t.SkipNow() 85 } 86 t.Parallel() 87 88 server := httptest.NewServer(http.FileServer(http.Dir("fixtures/azure"))) 89 defer server.Close() 90 91 basePath := server.URL + "/publicIpAddress.json" 92 93 swagger, err := loads.Spec(basePath) 94 require.NoError(t, err) 95 96 require.NoError(t, analysis.Flatten(analysis.FlattenOpts{Spec: swagger.Analyzer, Expand: false, BasePath: basePath})) 97 98 jazon := asJSON(t, swagger.Spec()) 99 100 assertRefInJSONRegexp(t, jazon, `^(#/definitions/)|(\./example)`) 101 102 t.Run("resolve remote $ref azure [minimal flatten]", func(t *testing.T) { 103 assertRefResolve(t, jazon, `\./example`, swagger.Spec(), &spec.ExpandOptions{RelativeBase: basePath}) 104 }) 105} 106 107func TestIssue66(t *testing.T) { 108 // no BasePath provided: assume current working directory 109 file, clean := makeFileSpec(t) 110 defer clean() 111 112 // analyze and expand 113 doc, err := loads.Spec(file) 114 require.NoError(t, err) 115 an := analysis.New(doc.Spec()) // Analyze spec 116 require.NoError(t, analysis.Flatten(analysis.FlattenOpts{ 117 Spec: an, 118 Expand: true, 119 })) 120 jazon := asJSON(t, doc.Spec()) 121 assertNoRef(t, jazon) 122 123 // reload and flatten 124 doc, err = loads.Spec(file) 125 require.NoError(t, err) 126 require.NoError(t, analysis.Flatten(analysis.FlattenOpts{ 127 Spec: an, 128 Expand: false, 129 })) 130 jazon = asJSON(t, doc.Spec()) 131 t.Run("resolve $ref issue66", func(t *testing.T) { 132 assertRefResolve(t, jazon, "", doc.Spec(), &spec.ExpandOptions{}) 133 }) 134} 135 136func makeFileSpec(t testing.TB) (string, func()) { 137 file := "./openapi.yaml" 138 require.NoError(t, ioutil.WriteFile(file, fixtureIssue66(), 0600)) 139 return file, func() { 140 _ = os.Remove(file) 141 } 142} 143 144func fixtureIssue66() []byte { 145 return []byte(` 146 x-google-endpoints: 147 - name: bravo-api.endpoints.dev-srplatform.cloud.goog 148 allowCors: true 149host: bravo-api.endpoints.dev-srplatform.cloud.goog 150swagger: '2.0' 151info: 152 description: Demo API for Bravo team testing 153 title: BRAVO Team API 154 version: 0.0.0 155basePath: /bravo 156x-google-allow: all 157consumes: 158 - application/json 159produces: 160 - application/json 161schemes: 162 - http 163 - https 164paths: 165 /bravo-api: 166 get: 167 description: List expansions 168 operationId: default 169 responses: 170 200: 171 description: Default Path 172 schema: 173 $ref: '#/definitions/heartbeatResponse' 174 403: 175 description: Forbidden 176 500: 177 description: Internal Server Error 178 /bravo-api/healthN: 179 get: 180 description: N Health 181 operationId: healthN 182 responses: 183 200: 184 description: Default Path 185 schema: 186 $ref: '#/definitions/heartbeatResponse' 187 403: 188 description: Forbidden 189 500: 190 description: Internal Server Error 191 /bravo-api/internal/heartbeat: 192 get: 193 description: Heartbeat endpoint 194 operationId: heartbeat 195 produces: 196 - application/json 197 responses: 198 200: 199 description: Health Status 200 schema: 201 $ref: '#/definitions/heartbeatResponse' 202 /bravo-api/internal/version: 203 get: 204 description: Version endpoint 205 operationId: version 206 produces: 207 - application/json 208 responses: 209 200: 210 description: Version Information 211 /bravo-api/internal/cpuload: 212 get: 213 description: CPU Load endpoint 214 operationId: cpuload 215 produces: 216 - application/json 217 responses: 218 200: 219 description: Run a CPU load 220 221definitions: 222 heartbeatResponse: 223 properties: 224 Status: 225 type: string 226 ProjectID: 227 type: string 228 Version: 229 type: string 230securityDefinitions: 231 okta_jwt: 232 authorizationUrl: "http://okta.example.com" 233 flow: "implicit" 234 type: "oauth2" 235 scopes: 236 com.sr.messaging: 'View and manage messaging content, criteria and definitions.' 237 x-google-issuer: "http://okta.example.com" 238 x-google-jwks_uri: "http://okta.example.com/v1/keys" 239 x-google-audiences: "http://api.example.com" 240 `) 241} 242