...

Source file src/github.com/go-openapi/spec/swagger_test.go

Documentation: github.com/go-openapi/spec

     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 spec
    16  
    17  import (
    18  	"encoding/json"
    19  	"testing"
    20  
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  var spec = Swagger{
    26  	SwaggerProps: SwaggerProps{
    27  		ID:          "http://localhost:3849/api-docs",
    28  		Swagger:     "2.0",
    29  		Consumes:    []string{"application/json", "application/x-yaml"},
    30  		Produces:    []string{"application/json"},
    31  		Schemes:     []string{"http", "https"},
    32  		Info:        &info,
    33  		Host:        "some.api.out.there",
    34  		BasePath:    "/",
    35  		Paths:       &paths,
    36  		Definitions: map[string]Schema{"Category": {SchemaProps: SchemaProps{Type: []string{"string"}}}},
    37  		Parameters: map[string]Parameter{
    38  			"categoryParam": {ParamProps: ParamProps{Name: "category", In: "query"}, SimpleSchema: SimpleSchema{Type: "string"}},
    39  		},
    40  		Responses: map[string]Response{
    41  			"EmptyAnswer": {
    42  				ResponseProps: ResponseProps{
    43  					Description: "no data to return for this operation",
    44  				},
    45  			},
    46  		},
    47  		SecurityDefinitions: map[string]*SecurityScheme{
    48  			"internalApiKey": APIKeyAuth("api_key", "header"),
    49  		},
    50  		Security: []map[string][]string{
    51  			{"internalApiKey": {}},
    52  		},
    53  		Tags:         []Tag{NewTag("pets", "", nil)},
    54  		ExternalDocs: &ExternalDocumentation{Description: "the name", URL: "the url"},
    55  	},
    56  	VendorExtensible: VendorExtensible{Extensions: map[string]interface{}{
    57  		"x-some-extension": "vendor",
    58  		"x-schemes":        []interface{}{"unix", "amqp"},
    59  	}},
    60  }
    61  
    62  const specJSON = `{
    63  	"id": "http://localhost:3849/api-docs",
    64  	"consumes": ["application/json", "application/x-yaml"],
    65  	"produces": ["application/json"],
    66  	"schemes": ["http", "https"],
    67  	"swagger": "2.0",
    68  	"info": {
    69  		"contact": {
    70  			"name": "wordnik api team",
    71  			"url": "http://developer.wordnik.com"
    72  		},
    73  		"description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0` +
    74  	` specification",
    75  		"license": {
    76  			"name": "Creative Commons 4.0 International",
    77  			"url": "http://creativecommons.org/licenses/by/4.0/"
    78  		},
    79  		"termsOfService": "http://helloreverb.com/terms/",
    80  		"title": "Swagger Sample API",
    81  		"version": "1.0.9-abcd",
    82  		"x-framework": "go-swagger"
    83  	},
    84  	"host": "some.api.out.there",
    85  	"basePath": "/",
    86  	"paths": {"x-framework":"go-swagger","/":{"$ref":"cats"}},
    87  	"definitions": { "Category": { "type": "string"} },
    88  	"parameters": {
    89  		"categoryParam": {
    90  			"name": "category",
    91  			"in": "query",
    92  			"type": "string"
    93  		}
    94  	},
    95  	"responses": { "EmptyAnswer": { "description": "no data to return for this operation" } },
    96  	"securityDefinitions": {
    97  		"internalApiKey": {
    98  			"type": "apiKey",
    99  			"in": "header",
   100  			"name": "api_key"
   101  		}
   102  	},
   103  	"security": [{"internalApiKey":[]}],
   104  	"tags": [{"name":"pets"}],
   105  	"externalDocs": {"description":"the name","url":"the url"},
   106  	"x-some-extension": "vendor",
   107  	"x-schemes": ["unix","amqp"]
   108  }`
   109  
   110  // func verifySpecSerialize(specJSON []byte, spec Swagger) {
   111  // 	expected := map[string]interface{}{}
   112  // 	json.Unmarshal(specJSON, &expected)
   113  // 	b, err := json.MarshalIndent(spec, "", "  ")
   114  // 	So(err, ShouldBeNil)
   115  // 	var actual map[string]interface{}
   116  // 	err = json.Unmarshal(b, &actual)
   117  // 	So(err, ShouldBeNil)
   118  // 	compareSpecMaps(actual, expected)
   119  // }
   120  
   121  /*
   122  	// assertEquivalent is currently unused
   123  	func assertEquivalent(t testing.TB, actual, expected interface{}) bool {
   124  		if actual == nil || expected == nil || reflect.DeepEqual(actual, expected) {
   125  			return true
   126  		}
   127  
   128  		actualType := reflect.TypeOf(actual)
   129  		expectedType := reflect.TypeOf(expected)
   130  		if reflect.TypeOf(actual).ConvertibleTo(expectedType) {
   131  			expectedValue := reflect.ValueOf(expected)
   132  			if swag.IsZero(expectedValue) && swag.IsZero(reflect.ValueOf(actual)) {
   133  				return true
   134  			}
   135  
   136  			// Attempt comparison after type conversion
   137  			if reflect.DeepEqual(actual, expectedValue.Convert(actualType).Interface()) {
   138  				return true
   139  			}
   140  		}
   141  
   142  		// Last ditch effort
   143  		if fmt.Sprintf("%#v", expected) == fmt.Sprintf("%#v", actual) {
   144  			return true
   145  		}
   146  		errFmt := "Expected: '%[1]T(%[1]#v)'\nActual:   '%[2]T(%[2]#v)'\n(Should be equivalent)!"
   147  		return assert.Fail(t, errFmt, expected, actual)
   148  	}
   149  
   150  	// ShouldBeEquivalentTo is currently unused
   151  	func ShouldBeEquivalentTo(actual interface{}, expecteds ...interface{}) string {
   152  		expected := expecteds[0]
   153  		if actual == nil || expected == nil {
   154  			return ""
   155  		}
   156  
   157  		if reflect.DeepEqual(expected, actual) {
   158  			return ""
   159  		}
   160  
   161  		actualType := reflect.TypeOf(actual)
   162  		expectedType := reflect.TypeOf(expected)
   163  		if reflect.TypeOf(actual).ConvertibleTo(expectedType) {
   164  			expectedValue := reflect.ValueOf(expected)
   165  			if swag.IsZero(expectedValue) && swag.IsZero(reflect.ValueOf(actual)) {
   166  				return ""
   167  			}
   168  
   169  			// Attempt comparison after type conversion
   170  			if reflect.DeepEqual(actual, expectedValue.Convert(actualType).Interface()) {
   171  				return ""
   172  			}
   173  		}
   174  
   175  		// Last ditch effort
   176  		if fmt.Sprintf("%#v", expected) == fmt.Sprintf("%#v", actual) {
   177  			return ""
   178  		}
   179  		errFmt := "Expected: '%[1]T(%[1]#v)'\nActual:   '%[2]T(%[2]#v)'\n(Should be equivalent)!"
   180  		return fmt.Sprintf(errFmt, expected, actual)
   181  	}
   182  
   183  	// assertSpecMaps is currently unused
   184  	func assertSpecMaps(t testing.TB, actual, expected map[string]interface{}) bool {
   185  		res := true
   186  		if id, ok := expected["id"]; ok {
   187  			res = assert.Equal(t, id, actual["id"])
   188  		}
   189  		res = res && assert.Equal(t, expected["consumes"], actual["consumes"])
   190  		res = res && assert.Equal(t, expected["produces"], actual["produces"])
   191  		res = res && assert.Equal(t, expected["schemes"], actual["schemes"])
   192  		res = res && assert.Equal(t, expected["swagger"], actual["swagger"])
   193  		res = res && assert.Equal(t, expected["info"], actual["info"])
   194  		res = res && assert.Equal(t, expected["host"], actual["host"])
   195  		res = res && assert.Equal(t, expected["basePath"], actual["basePath"])
   196  		res = res && assert.Equal(t, expected["paths"], actual["paths"])
   197  		res = res && assert.Equal(t, expected["definitions"], actual["definitions"])
   198  		res = res && assert.Equal(t, expected["responses"], actual["responses"])
   199  		res = res && assert.Equal(t, expected["securityDefinitions"], actual["securityDefinitions"])
   200  		res = res && assert.Equal(t, expected["tags"], actual["tags"])
   201  		res = res && assert.Equal(t, expected["externalDocs"], actual["externalDocs"])
   202  		res = res && assert.Equal(t, expected["x-some-extension"], actual["x-some-extension"])
   203  		res = res && assert.Equal(t, expected["x-schemes"], actual["x-schemes"])
   204  
   205  		return res
   206  	}
   207  */
   208  
   209  func assertSpecs(t testing.TB, actual, expected Swagger) bool {
   210  	expected.Swagger = "2.0"
   211  	return assert.Equal(t, expected, actual)
   212  }
   213  
   214  /*
   215  // assertSpecJSON is currently unused
   216  func assertSpecJSON(t testing.TB, specJSON []byte) bool {
   217  	var expected map[string]interface{}
   218  	if !assert.NoError(t, json.Unmarshal(specJSON, &expected)) {
   219  		return false
   220  	}
   221  
   222  	obj := Swagger{}
   223  	if !assert.NoError(t, json.Unmarshal(specJSON, &obj)) {
   224  		return false
   225  	}
   226  
   227  	cb, err := json.MarshalIndent(obj, "", "  ")
   228  	if assert.NoError(t, err) {
   229  		return false
   230  	}
   231  	var actual map[string]interface{}
   232  	if !assert.NoError(t, json.Unmarshal(cb, &actual)) {
   233  		return false
   234  	}
   235  	return assertSpecMaps(t, expected, actual )
   236  }
   237  */
   238  
   239  func TestSwaggerSpec_Serialize(t *testing.T) {
   240  	expected := make(map[string]interface{})
   241  	_ = json.Unmarshal([]byte(specJSON), &expected)
   242  	b, err := json.MarshalIndent(spec, "", "  ")
   243  	require.NoError(t, err)
   244  	var actual map[string]interface{}
   245  	require.NoError(t, json.Unmarshal(b, &actual))
   246  	assert.EqualValues(t, expected, actual)
   247  }
   248  
   249  func TestSwaggerSpec_Deserialize(t *testing.T) {
   250  	var actual Swagger
   251  	require.NoError(t, json.Unmarshal([]byte(specJSON), &actual))
   252  	assert.EqualValues(t, actual, spec)
   253  }
   254  
   255  func TestVendorExtensionStringSlice(t *testing.T) {
   256  	var actual Swagger
   257  	require.NoError(t, json.Unmarshal([]byte(specJSON), &actual))
   258  	schemes, ok := actual.Extensions.GetStringSlice("x-schemes")
   259  	require.True(t, ok)
   260  	assert.EqualValues(t, []string{"unix", "amqp"}, schemes)
   261  
   262  	notSlice, ok := actual.Extensions.GetStringSlice("x-some-extension")
   263  	assert.Nil(t, notSlice)
   264  	assert.False(t, ok)
   265  
   266  	actual.AddExtension("x-another-ext", 100)
   267  	notString, ok := actual.Extensions.GetStringSlice("x-another-ext")
   268  	assert.Nil(t, notString)
   269  	assert.False(t, ok)
   270  
   271  	actual.AddExtension("x-another-slice-ext", []interface{}{100, 100})
   272  	notStringSlice, ok := actual.Extensions.GetStringSlice("x-another-slice-ext")
   273  	assert.Nil(t, notStringSlice)
   274  	assert.False(t, ok)
   275  
   276  	_, ok = actual.Extensions.GetStringSlice("x-notfound-ext")
   277  	assert.False(t, ok)
   278  }
   279  
   280  func TestOptionalSwaggerProps_Serialize(t *testing.T) {
   281  	minimalJSONSpec := []byte(`{
   282  	"swagger": "2.0",
   283  	"info": {
   284  		"version": "0.0.0",
   285  		"title": "Simple API"
   286  	},
   287  	"paths": {
   288  		"/": {
   289  			"get": {
   290  				"responses": {
   291  					"200": {
   292  						"description": "OK"
   293  					}
   294  				}
   295  			}
   296  		}
   297  	}
   298  }`)
   299  
   300  	var minimalSpec Swagger
   301  	err := json.Unmarshal(minimalJSONSpec, &minimalSpec)
   302  	require.NoError(t, err)
   303  	bytes, err := json.Marshal(&minimalSpec)
   304  	require.NoError(t, err)
   305  
   306  	var ms map[string]interface{}
   307  	require.NoError(t, json.Unmarshal(bytes, &ms))
   308  
   309  	assert.NotContains(t, ms, "consumes")
   310  	assert.NotContains(t, ms, "produces")
   311  	assert.NotContains(t, ms, "schemes")
   312  	assert.NotContains(t, ms, "host")
   313  	assert.NotContains(t, ms, "basePath")
   314  	assert.NotContains(t, ms, "definitions")
   315  	assert.NotContains(t, ms, "parameters")
   316  	assert.NotContains(t, ms, "responses")
   317  	assert.NotContains(t, ms, "securityDefinitions")
   318  	assert.NotContains(t, ms, "security")
   319  	assert.NotContains(t, ms, "tags")
   320  	assert.NotContains(t, ms, "externalDocs")
   321  }
   322  
   323  var minimalJSONSpec = []byte(`{
   324  		"swagger": "2.0",
   325  		"info": {
   326  			"version": "0.0.0",
   327  			"title": "Simple API"
   328  		},
   329  		"securityDefinitions": {
   330  			"basic": {
   331  				"type": "basic"
   332  			},
   333  			"apiKey": {
   334  				"type": "apiKey",
   335  				"in": "header",
   336  				"name": "X-API-KEY"
   337  			},
   338  			"queryKey": {
   339  				"type": "apiKey",
   340  				"in": "query",
   341  				"name": "api_key"
   342  			}
   343  		},
   344  		"paths": {
   345  			"/": {
   346  				"get": {
   347  					"security": [
   348  						{
   349  							"apiKey": [],
   350  							"basic": []
   351  						},
   352  						{},
   353  						{
   354  							"queryKey": [],
   355  							"basic": []
   356  						}
   357  					],
   358  					"responses": {
   359  						"200": {
   360  							"description": "OK"
   361  						}
   362  					}
   363  				}
   364  			}
   365  		}
   366  	}`)
   367  
   368  func TestSecurityRequirements(t *testing.T) {
   369  	var minimalSpec Swagger
   370  	require.NoError(t, json.Unmarshal(minimalJSONSpec, &minimalSpec))
   371  
   372  	sec := minimalSpec.Paths.Paths["/"].Get.Security
   373  	require.Len(t, sec, 3)
   374  	assert.Contains(t, sec[0], "basic")
   375  	assert.Contains(t, sec[0], "apiKey")
   376  	assert.NotNil(t, sec[1])
   377  	assert.Empty(t, sec[1])
   378  	assert.Contains(t, sec[2], "queryKey")
   379  }
   380  
   381  func TestSwaggerGobEncoding(t *testing.T) {
   382  	doTestSwaggerGobEncoding(t, specJSON)
   383  
   384  	doTestSwaggerGobEncoding(t, string(minimalJSONSpec))
   385  }
   386  
   387  func doTestSwaggerGobEncoding(t *testing.T, fixture string) {
   388  	var src, dst Swagger
   389  	require.NoError(t, json.Unmarshal([]byte(fixture), &src))
   390  
   391  	doTestAnyGobEncoding(t, &src, &dst)
   392  }
   393  

View as plain text