github.com/rzurga/go-swagger@v0.28.1-0.20211109195225-5d1f453ffa3a/scan/routes_test.go (about)

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