github.com/josephspurrier/go-swagger@v0.2.1-0.20221129144919-1f672a142a00/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.Equal(t, 2, len(po.Post.Parameters))
   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.Equal(t, true, p.Required)
   244  	assert.Equal(t, false, p.AllowEmptyValue)
   245  
   246  	po = ops.Paths["/orders"]
   247  	assert.Equal(t, 2, len(po.Post.Parameters))
   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.Equal(t, false, p.Required)
   255  	assert.Equal(t, true, 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.Equal(t, 6, len(po.Post.Parameters))
   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.Equal(t, true, 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.Equal(t, false, 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.Equal(t, false, p.Required)
   296  	assert.Equal(t, "boolean", p.Type)
   297  	assert.Equal(t, true, p.Default)
   298  	assert.Nil(t, p.Schema)
   299  
   300  	// Testing that "min", "max", "minLength" and "maxLength" constraints will only be considered if the right type is provided
   301  	p = po.Post.Parameters[3]
   302  	assert.Equal(t, "constraintsOnInvalidType", p.Name)
   303  	assert.Equal(t, "test constraints on invalid types", p.Description)
   304  	assert.Equal(t, "query", p.In)
   305  	assert.Equal(t, "boolean", p.Type)
   306  	assert.Nil(t, p.Maximum)
   307  	assert.Nil(t, p.Minimum)
   308  	assert.Nil(t, p.MaxLength)
   309  	assert.Nil(t, p.MinLength)
   310  	assert.Equal(t, "abcde", p.Format)
   311  	assert.Equal(t, false, p.Default)
   312  	assert.Nil(t, p.Schema)
   313  
   314  	// Testing that when "type" is not provided, a schema will not be created
   315  	p = po.Post.Parameters[4]
   316  	assert.Equal(t, "noType", p.Name)
   317  	assert.Equal(t, "test no type", p.Description)
   318  	assert.Equal(t, "", p.Type)
   319  	assert.Nil(t, p.Schema)
   320  
   321  	// Testing a request body that takes a string value defined by a list of possible values in "enum"
   322  	p = po.Post.Parameters[5]
   323  	assert.Equal(t, "request", p.Name)
   324  	assert.Equal(t, "The request model.", p.Description)
   325  	assert.Equal(t, "body", p.In)
   326  	assert.Equal(t, "string", p.Schema.Type[0])
   327  	assert.Equal(t, "orange", p.Schema.Default)
   328  	assert.Equal(t, []interface{}{"apple", "orange", "pineapple", "peach", "plum"}, p.Schema.Enum)
   329  	assert.Empty(t, "", p.Type)
   330  }
   331  
   332  func assertOperation(t *testing.T, op *spec.Operation, id, summary, description string, tags, scopes []string, extensions spec.Extensions) {
   333  	assert.NotNil(t, op)
   334  	assert.Equal(t, summary, op.Summary)
   335  	assert.Equal(t, description, op.Description)
   336  	assert.Equal(t, id, op.ID)
   337  	assert.EqualValues(t, tags, op.Tags)
   338  	assert.EqualValues(t, []string{"application/json", "application/x-protobuf"}, op.Consumes)
   339  	assert.EqualValues(t, []string{"application/json", "application/x-protobuf"}, op.Produces)
   340  	assert.EqualValues(t, []string{"http", "https", "ws", "wss"}, op.Schemes)
   341  	assert.Len(t, op.Security, 2)
   342  	akv, ok := op.Security[0]["api_key"]
   343  	assert.True(t, ok)
   344  	// akv must be defined & not empty
   345  	assert.NotNil(t, akv)
   346  	assert.Empty(t, akv)
   347  
   348  	vv, ok := op.Security[1]["oauth"]
   349  	assert.True(t, ok)
   350  	assert.EqualValues(t, scopes, vv)
   351  
   352  	assert.NotNil(t, op.Responses.Default)
   353  	assert.Equal(t, "#/responses/genericError", op.Responses.Default.Ref.String())
   354  
   355  	rsp, ok := op.Responses.StatusCodeResponses[200]
   356  	assert.True(t, ok)
   357  	assert.Equal(t, "#/responses/someResponse", rsp.Ref.String())
   358  	rsp, ok = op.Responses.StatusCodeResponses[422]
   359  	assert.True(t, ok)
   360  	assert.Equal(t, "#/responses/validationError", rsp.Ref.String())
   361  
   362  	ext := op.Extensions
   363  	assert.Equal(t, extensions, ext)
   364  }
   365  
   366  func assertOperationBody(t *testing.T, op *spec.Operation, id, summary, description string, tags, scopes []string) {
   367  	assert.NotNil(t, op)
   368  	assert.Equal(t, summary, op.Summary)
   369  	assert.Equal(t, description, op.Description)
   370  	assert.Equal(t, id, op.ID)
   371  	assert.EqualValues(t, tags, op.Tags)
   372  	assert.EqualValues(t, []string{"application/json", "application/x-protobuf"}, op.Consumes)
   373  	assert.EqualValues(t, []string{"application/json", "application/x-protobuf"}, op.Produces)
   374  	assert.EqualValues(t, []string{"http", "https", "ws", "wss"}, op.Schemes)
   375  	assert.Len(t, op.Security, 2)
   376  	akv, ok := op.Security[0]["api_key"]
   377  	assert.True(t, ok)
   378  	// akv must be defined & not empty
   379  	assert.NotNil(t, akv)
   380  	assert.Empty(t, akv)
   381  
   382  	vv, ok := op.Security[1]["oauth"]
   383  	assert.True(t, ok)
   384  	assert.EqualValues(t, scopes, vv)
   385  
   386  	assert.NotNil(t, op.Responses.Default)
   387  	assert.Equal(t, "", op.Responses.Default.Ref.String())
   388  	assert.Equal(t, "#/definitions/genericError", op.Responses.Default.Schema.Ref.String())
   389  
   390  	rsp, ok := op.Responses.StatusCodeResponses[200]
   391  	assert.True(t, ok)
   392  	assert.Equal(t, "", rsp.Ref.String())
   393  	assert.Equal(t, "#/definitions/someResponse", rsp.Schema.Ref.String())
   394  	rsp, ok = op.Responses.StatusCodeResponses[422]
   395  	assert.True(t, ok)
   396  	assert.Equal(t, "", rsp.Ref.String())
   397  	assert.Equal(t, "#/definitions/validationError", rsp.Schema.Ref.String())
   398  }