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