github.com/sallysalary/go-swagger@v0.19.0/scan/routes_test.go (about)

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