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  }