github.com/go-swagger/go-swagger@v0.31.0/codescan/routes_test.go (about) 1 package codescan 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/require" 7 8 "github.com/go-openapi/spec" 9 "github.com/stretchr/testify/assert" 10 ) 11 12 func TestRouteExpression(t *testing.T) { 13 assert.Regexp(t, rxRoute, "swagger:route DELETE /orders/{id} deleteOrder") 14 assert.Regexp(t, rxRoute, "swagger:route GET /v1.2/something deleteOrder") 15 } 16 17 func TestRoutesParser(t *testing.T) { 18 sctx := loadClassificationPkgsCtx(t) 19 var ops spec.Paths 20 for _, apiPath := range sctx.app.Routes { 21 prs := &routesBuilder{ 22 ctx: sctx, 23 route: apiPath, 24 operations: make(map[string]*spec.Operation), 25 } 26 require.NoError(t, prs.Build(&ops)) 27 } 28 29 assert.Len(t, ops.Paths, 3) 30 31 po, ok := ops.Paths["/pets"] 32 ext := make(spec.Extensions) 33 ext.Add("x-some-flag", "true") 34 assert.True(t, ok) 35 assert.NotNil(t, po.Get) 36 assertOperation(t, 37 po.Get, 38 "listPets", 39 "Lists pets filtered by some parameters.", 40 "This will show all available pets by default.\nYou can get the pets that are out of stock", 41 []string{"pets", "users"}, 42 []string{"read", "write"}, 43 ext, 44 ) 45 assertOperation(t, 46 po.Post, 47 "createPet", 48 "Create a pet based on the parameters.", 49 "", 50 []string{"pets", "users"}, 51 []string{"read", "write"}, 52 nil, 53 ) 54 55 po, ok = ops.Paths["/orders"] 56 ext = make(spec.Extensions) 57 ext.Add("x-some-flag", "false") 58 ext.Add("x-some-list", []string{"item1", "item2", "item3"}) 59 ext.Add("x-some-object", map[string]interface{}{ 60 "key1": "value1", 61 "key2": "value2", 62 "subobject": map[string]interface{}{ 63 "subkey1": "subvalue1", 64 "subkey2": "subvalue2", 65 }, 66 "key3": "value3", 67 }) 68 assert.True(t, ok) 69 assert.NotNil(t, po.Get) 70 assertOperation(t, 71 po.Get, 72 "listOrders", 73 "lists orders filtered by some parameters.", 74 "", 75 []string{"orders"}, 76 []string{"orders:read", "https://www.googleapis.com/auth/userinfo.email"}, 77 ext, 78 ) 79 assertOperation(t, 80 po.Post, 81 "createOrder", 82 "create an order based on the parameters.", 83 "", 84 []string{"orders"}, 85 []string{"read", "write"}, 86 nil, 87 ) 88 89 po, ok = ops.Paths["/orders/{id}"] 90 assert.True(t, ok) 91 assert.NotNil(t, po.Get) 92 assertOperation(t, 93 po.Get, 94 "orderDetails", 95 "gets the details for an order.", 96 "", 97 []string{"orders"}, 98 []string{"read", "write"}, 99 nil, 100 ) 101 102 assertOperation(t, 103 po.Put, 104 "updateOrder", 105 "Update the details for an order.", 106 "When the order doesn't exist this will return an error.", 107 []string{"orders"}, 108 []string{"read", "write"}, 109 nil, 110 ) 111 112 assertOperation(t, 113 po.Delete, 114 "deleteOrder", 115 "delete a particular order.", 116 "", 117 nil, 118 []string{"read", "write"}, 119 nil, 120 ) 121 122 // additional check description tag at Responses 123 rsp, ok := po.Delete.Responses.StatusCodeResponses[202] 124 assert.True(t, ok) 125 assert.Equal(t, "Some description", rsp.Description) 126 assert.Equal(t, "", rsp.Ref.String()) 127 } 128 129 func TestRoutesParserBody(t *testing.T) { 130 sctx, err := newScanCtx(&Options{ 131 Packages: []string{ 132 "github.com/go-swagger/go-swagger/fixtures/goparsing/classification", 133 "github.com/go-swagger/go-swagger/fixtures/goparsing/classification/models", 134 "github.com/go-swagger/go-swagger/fixtures/goparsing/classification/operations", 135 "github.com/go-swagger/go-swagger/fixtures/goparsing/classification/operations_body", 136 }, 137 }) 138 require.NoError(t, err) 139 var ops spec.Paths 140 for _, apiPath := range sctx.app.Routes { 141 prs := &routesBuilder{ 142 ctx: sctx, 143 route: apiPath, 144 operations: make(map[string]*spec.Operation), 145 } 146 require.NoError(t, prs.Build(&ops)) 147 } 148 149 assert.Len(t, ops.Paths, 4) 150 151 po, ok := ops.Paths["/pets"] 152 assert.True(t, ok) 153 assert.NotNil(t, po.Get) 154 assertOperationBody(t, 155 po.Get, 156 "listPets", 157 "Lists pets filtered by some parameters.", 158 "This will show all available pets by default.\nYou can get the pets that are out of stock", 159 []string{"pets", "users"}, 160 []string{"read", "write"}, 161 ) 162 assert.NotNil(t, po.Post) 163 164 assertOperationBody(t, 165 po.Post, 166 "createPet", 167 "Create a pet based on the parameters.", 168 "", 169 []string{"pets", "users"}, 170 []string{"read", "write"}, 171 ) 172 173 po, ok = ops.Paths["/orders"] 174 assert.True(t, ok) 175 assert.NotNil(t, po.Get) 176 assertOperationBody(t, 177 po.Get, 178 "listOrders", 179 "lists orders filtered by some parameters.", 180 "", 181 []string{"orders"}, 182 []string{"orders:read", "https://www.googleapis.com/auth/userinfo.email"}, 183 ) 184 assert.NotNil(t, po.Post) 185 186 assertOperationBody(t, 187 po.Post, 188 "createOrder", 189 "create an order based on the parameters.", 190 "", 191 []string{"orders"}, 192 []string{"read", "write"}, 193 ) 194 195 po, ok = ops.Paths["/orders/{id}"] 196 assert.True(t, ok) 197 assert.NotNil(t, po.Get) 198 assertOperationBody(t, 199 po.Get, 200 "orderDetails", 201 "gets the details for an order.", 202 "", 203 []string{"orders"}, 204 []string{"read", "write"}, 205 ) 206 207 assertOperationBody(t, 208 po.Put, 209 "updateOrder", 210 "Update the details for an order.", 211 "When the order doesn't exist this will return an error.", 212 []string{"orders"}, 213 []string{"read", "write"}, 214 ) 215 216 assertOperationBody(t, 217 po.Delete, 218 "deleteOrder", 219 "delete a particular order.", 220 "", 221 nil, 222 []string{"read", "write"}, 223 ) 224 225 validateRoutesParameters(t, ops) 226 } 227 228 func validateRoutesParameters(t *testing.T, ops spec.Paths) { 229 po := ops.Paths["/pets"] 230 assert.Len(t, po.Post.Parameters, 2) 231 232 // Testing standard param properties 233 p := po.Post.Parameters[0] 234 assert.Equal(t, "request", p.Name) 235 assert.Equal(t, "body", p.In) 236 assert.Equal(t, "The request model.", p.Description) 237 238 // Testing "required" and "allowEmpty" 239 p = po.Post.Parameters[1] 240 assert.Equal(t, "id", p.Name) 241 assert.Equal(t, "The pet id", p.Description) 242 assert.Equal(t, "path", p.In) 243 assert.True(t, p.Required) 244 assert.False(t, p.AllowEmptyValue) 245 246 po = ops.Paths["/orders"] 247 assert.Len(t, po.Post.Parameters, 2) 248 249 // Testing invalid value for "in" 250 p = po.Post.Parameters[0] 251 assert.Equal(t, "id", p.Name) 252 assert.Equal(t, "The order id", p.Description) 253 assert.Equal(t, "", p.In) // Invalid value should not be set 254 assert.False(t, p.Required) 255 assert.True(t, p.AllowEmptyValue) 256 257 p = po.Post.Parameters[1] 258 assert.Equal(t, "request", p.Name) 259 assert.Equal(t, "body", p.In) 260 assert.Equal(t, "The request model.", p.Description) 261 262 po = ops.Paths["/param-test"] 263 assert.Len(t, po.Post.Parameters, 6) 264 265 // Testing number param with "max" and "min" constraints 266 p = po.Post.Parameters[0] 267 assert.Equal(t, "someNumber", p.Name) 268 assert.Equal(t, "some number", p.Description) 269 assert.Equal(t, "path", p.In) 270 assert.True(t, p.Required) 271 assert.Equal(t, "number", p.Type) 272 min, max, def := float64(10), float64(20), float64(15) 273 assert.Equal(t, &max, p.Maximum) 274 assert.Equal(t, &min, p.Minimum) 275 assert.Equal(t, def, p.Default) 276 assert.Nil(t, p.Schema) 277 278 // Testing array param provided as query string. Testing "minLength" and "maxLength" constraints for "array" types 279 p = po.Post.Parameters[1] 280 assert.Equal(t, "someQuery", p.Name) 281 assert.Equal(t, "some query values", p.Description) 282 assert.Equal(t, "query", p.In) 283 assert.False(t, p.Required) 284 assert.Equal(t, "array", p.Type) 285 minLen, maxLen := int64(5), int64(20) 286 assert.Equal(t, &maxLen, p.MaxLength) 287 assert.Equal(t, &minLen, p.MinLength) 288 assert.Nil(t, p.Schema) 289 290 // Testing boolean param with default value 291 p = po.Post.Parameters[2] 292 assert.Equal(t, "someBoolean", p.Name) 293 assert.Equal(t, "some boolean", p.Description) 294 assert.Equal(t, "path", p.In) 295 assert.False(t, p.Required) 296 assert.Equal(t, "boolean", p.Type) 297 someBoolean, ok := p.Default.(bool) 298 assert.True(t, ok) 299 assert.True(t, someBoolean) 300 assert.Nil(t, p.Schema) 301 302 // Testing that "min", "max", "minLength" and "maxLength" constraints will only be considered if the right type is provided 303 p = po.Post.Parameters[3] 304 assert.Equal(t, "constraintsOnInvalidType", p.Name) 305 assert.Equal(t, "test constraints on invalid types", p.Description) 306 assert.Equal(t, "query", p.In) 307 assert.Equal(t, "boolean", p.Type) 308 assert.Nil(t, p.Maximum) 309 assert.Nil(t, p.Minimum) 310 assert.Nil(t, p.MaxLength) 311 assert.Nil(t, p.MinLength) 312 assert.Equal(t, "abcde", p.Format) 313 constraintsOnInvalidType, ok2 := p.Default.(bool) 314 assert.True(t, ok2) 315 assert.False(t, constraintsOnInvalidType) 316 assert.Nil(t, p.Schema) 317 318 // Testing that when "type" is not provided, a schema will not be created 319 p = po.Post.Parameters[4] 320 assert.Equal(t, "noType", p.Name) 321 assert.Equal(t, "test no type", p.Description) 322 assert.Equal(t, "", p.Type) 323 assert.Nil(t, p.Schema) 324 325 // Testing a request body that takes a string value defined by a list of possible values in "enum" 326 p = po.Post.Parameters[5] 327 assert.Equal(t, "request", p.Name) 328 assert.Equal(t, "The request model.", p.Description) 329 assert.Equal(t, "body", p.In) 330 assert.Equal(t, "string", p.Schema.Type[0]) 331 assert.Equal(t, "orange", p.Schema.Default) 332 assert.Equal(t, []interface{}{"apple", "orange", "pineapple", "peach", "plum"}, p.Schema.Enum) 333 assert.Empty(t, "", p.Type) 334 } 335 336 func assertOperation(t *testing.T, op *spec.Operation, id, summary, description string, tags, scopes []string, extensions spec.Extensions) { 337 assert.NotNil(t, op) 338 assert.Equal(t, summary, op.Summary) 339 assert.Equal(t, description, op.Description) 340 assert.Equal(t, id, op.ID) 341 assert.EqualValues(t, tags, op.Tags) 342 assert.EqualValues(t, []string{"application/json", "application/x-protobuf"}, op.Consumes) 343 assert.EqualValues(t, []string{"application/json", "application/x-protobuf"}, op.Produces) 344 assert.EqualValues(t, []string{"http", "https", "ws", "wss"}, op.Schemes) 345 assert.Len(t, op.Security, 2) 346 akv, ok := op.Security[0]["api_key"] 347 assert.True(t, ok) 348 // akv must be defined & not empty 349 assert.NotNil(t, akv) 350 assert.Empty(t, akv) 351 352 vv, ok := op.Security[1]["oauth"] 353 assert.True(t, ok) 354 assert.EqualValues(t, scopes, vv) 355 356 assert.NotNil(t, op.Responses.Default) 357 assert.Equal(t, "#/responses/genericError", op.Responses.Default.Ref.String()) 358 359 rsp, ok := op.Responses.StatusCodeResponses[200] 360 assert.True(t, ok) 361 assert.Equal(t, "#/responses/someResponse", rsp.Ref.String()) 362 rsp, ok = op.Responses.StatusCodeResponses[422] 363 assert.True(t, ok) 364 assert.Equal(t, "#/responses/validationError", rsp.Ref.String()) 365 366 ext := op.Extensions 367 assert.Equal(t, extensions, ext) 368 } 369 370 func assertOperationBody(t *testing.T, op *spec.Operation, id, summary, description string, tags, scopes []string) { 371 assert.NotNil(t, op) 372 assert.Equal(t, summary, op.Summary) 373 assert.Equal(t, description, op.Description) 374 assert.Equal(t, id, op.ID) 375 assert.EqualValues(t, tags, op.Tags) 376 assert.EqualValues(t, []string{"application/json", "application/x-protobuf"}, op.Consumes) 377 assert.EqualValues(t, []string{"application/json", "application/x-protobuf"}, op.Produces) 378 assert.EqualValues(t, []string{"http", "https", "ws", "wss"}, op.Schemes) 379 assert.Len(t, op.Security, 2) 380 akv, ok := op.Security[0]["api_key"] 381 assert.True(t, ok) 382 // akv must be defined & not empty 383 assert.NotNil(t, akv) 384 assert.Empty(t, akv) 385 386 vv, ok := op.Security[1]["oauth"] 387 assert.True(t, ok) 388 assert.EqualValues(t, scopes, vv) 389 390 assert.NotNil(t, op.Responses.Default) 391 assert.Equal(t, "", op.Responses.Default.Ref.String()) 392 assert.Equal(t, "#/definitions/genericError", op.Responses.Default.Schema.Ref.String()) 393 394 rsp, ok := op.Responses.StatusCodeResponses[200] 395 assert.True(t, ok) 396 assert.Equal(t, "", rsp.Ref.String()) 397 assert.Equal(t, "#/definitions/someResponse", rsp.Schema.Ref.String()) 398 rsp, ok = op.Responses.StatusCodeResponses[422] 399 assert.True(t, ok) 400 assert.Equal(t, "", rsp.Ref.String()) 401 assert.Equal(t, "#/definitions/validationError", rsp.Schema.Ref.String()) 402 }