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