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 15package spec 16 17import ( 18 "bytes" 19 "encoding/gob" 20 "encoding/json" 21 "testing" 22 23 "github.com/stretchr/testify/assert" 24) 25 26var operation = Operation{ 27 VendorExtensible: VendorExtensible{ 28 Extensions: map[string]interface{}{ 29 "x-framework": "go-swagger", 30 }, 31 }, 32 OperationProps: OperationProps{ 33 Description: "operation description", 34 Consumes: []string{"application/json", "application/x-yaml"}, 35 Produces: []string{"application/json", "application/x-yaml"}, 36 Schemes: []string{"http", "https"}, 37 Tags: []string{"dogs"}, 38 Summary: "the summary of the operation", 39 ID: "sendCat", 40 Deprecated: true, 41 Security: []map[string][]string{ 42 { 43 "apiKey": {}, 44 }, 45 }, 46 Parameters: []Parameter{ 47 {Refable: Refable{Ref: MustCreateRef("Cat")}}, 48 }, 49 Responses: &Responses{ 50 ResponsesProps: ResponsesProps{ 51 Default: &Response{ 52 ResponseProps: ResponseProps{ 53 Description: "void response", 54 }, 55 }, 56 }, 57 }, 58 }, 59} 60 61const operationJSON = `{ 62 "description": "operation description", 63 "x-framework": "go-swagger", 64 "consumes": [ "application/json", "application/x-yaml" ], 65 "produces": [ "application/json", "application/x-yaml" ], 66 "schemes": ["http", "https"], 67 "tags": ["dogs"], 68 "summary": "the summary of the operation", 69 "operationId": "sendCat", 70 "deprecated": true, 71 "security": [ { "apiKey": [] } ], 72 "parameters": [{"$ref":"Cat"}], 73 "responses": { 74 "default": { 75 "description": "void response" 76 } 77 } 78}` 79 80func TestSuccessResponse(t *testing.T) { 81 ope := &Operation{} 82 resp, n, f := ope.SuccessResponse() 83 assert.Nil(t, resp) 84 assert.Equal(t, 0, n) 85 assert.Equal(t, false, f) 86 87 resp, n, f = operation.SuccessResponse() 88 if assert.NotNil(t, resp) { 89 assert.Equal(t, "void response", resp.Description) 90 } 91 assert.Equal(t, 0, n) 92 assert.Equal(t, false, f) 93 94 err := json.Unmarshal([]byte(operationJSON), ope) 95 if !assert.Nil(t, err) { 96 t.FailNow() 97 } 98 ope = ope.RespondsWith(301, &Response{ 99 ResponseProps: ResponseProps{ 100 Description: "failure", 101 }, 102 }) 103 resp, n, f = ope.SuccessResponse() 104 if assert.NotNil(t, resp) { 105 assert.Equal(t, "void response", resp.Description) 106 } 107 assert.Equal(t, 0, n) 108 assert.Equal(t, false, f) 109 110 ope = ope.RespondsWith(200, &Response{ 111 ResponseProps: ResponseProps{ 112 Description: "success", 113 }, 114 }) 115 116 resp, n, f = ope.SuccessResponse() 117 if assert.NotNil(t, resp) { 118 assert.Equal(t, "success", resp.Description) 119 } 120 assert.Equal(t, 200, n) 121 assert.Equal(t, true, f) 122} 123 124func TestOperationBuilder(t *testing.T) { 125 ope := NewOperation("").WithID("operationID") 126 ope = ope.RespondsWith(200, &Response{ 127 ResponseProps: ResponseProps{ 128 Description: "success", 129 }, 130 }). 131 WithDefaultResponse(&Response{ 132 ResponseProps: ResponseProps{ 133 Description: "default", 134 }, 135 }). 136 SecuredWith("scheme-name", "scope1", "scope2"). 137 WithConsumes("application/json"). 138 WithProduces("application/json"). 139 Deprecate(). 140 WithTags("this", "that"). 141 AddParam(nil). 142 AddParam(QueryParam("myQueryParam").Typed("integer", "int32")). 143 AddParam(QueryParam("myQueryParam").Typed("string", "hostname")). 144 AddParam(PathParam("myPathParam").Typed("string", "uuid")). 145 WithDescription("test operation"). 146 WithSummary("my summary"). 147 WithExternalDocs("some doc", "https://www.example.com") 148 149 jazon, _ := json.MarshalIndent(ope, "", " ") 150 assert.JSONEq(t, `{ 151 "operationId": "operationID", 152 "description": "test operation", 153 "summary": "my summary", 154 "externalDocs": { 155 "description": "some doc", 156 "url": "https://www.example.com" 157 }, 158 "security": [ 159 { 160 "scheme-name": [ 161 "scope1", 162 "scope2" 163 ] 164 } 165 ], 166 "consumes": [ 167 "application/json" 168 ], 169 "produces": [ 170 "application/json" 171 ], 172 "tags": [ 173 "this", 174 "that" 175 ], 176 "deprecated": true, 177 "parameters": [ 178 { 179 "type": "string", 180 "format": "hostname", 181 "name": "myQueryParam", 182 "in": "query" 183 }, 184 { 185 "type": "string", 186 "format": "uuid", 187 "name": "myPathParam", 188 "in": "path", 189 "required": true 190 } 191 ], 192 "responses": { 193 "200": { 194 "description": "success" 195 }, 196 "default": { 197 "description": "default" 198 } 199 } 200 }`, string(jazon)) 201 202 // check token lookup 203 token, err := ope.JSONLookup("responses") 204 assert.NoError(t, err) 205 jazon, _ = json.MarshalIndent(token, "", " ") 206 assert.JSONEq(t, `{ 207 "200": { 208 "description": "success" 209 }, 210 "default": { 211 "description": "default" 212 } 213 }`, string(jazon)) 214 215 // check delete methods 216 ope = ope.RespondsWith(200, nil). 217 RemoveParam("myQueryParam", "query"). 218 RemoveParam("myPathParam", "path"). 219 RemoveParam("fakeParam", "query"). 220 Undeprecate(). 221 WithExternalDocs("", "") 222 jazon, _ = json.MarshalIndent(ope, "", " ") 223 assert.JSONEq(t, `{ 224 "security": [ 225 { 226 "scheme-name": [ 227 "scope1", 228 "scope2" 229 ] 230 } 231 ], 232 "description": "test operation", 233 "consumes": [ 234 "application/json" 235 ], 236 "produces": [ 237 "application/json" 238 ], 239 "tags": [ 240 "this", 241 "that" 242 ], 243 "summary": "my summary", 244 "operationId": "operationID", 245 "responses": { 246 "default": { 247 "description": "default" 248 } 249 } 250 }`, string(jazon)) 251} 252 253func TestIntegrationOperation(t *testing.T) { 254 var actual Operation 255 if assert.NoError(t, json.Unmarshal([]byte(operationJSON), &actual)) { 256 assert.EqualValues(t, actual, operation) 257 } 258 259 assertParsesJSON(t, operationJSON, operation) 260} 261 262func TestSecurityProperty(t *testing.T) { 263 // Ensure we omit security key when unset 264 securityNotSet := OperationProps{} 265 jsonResult, err := json.Marshal(securityNotSet) 266 if assert.NoError(t, err) { 267 assert.NotContains(t, string(jsonResult), "security", "security key should be omitted when unset") 268 } 269 270 // Ensure we preserve the security key when it contains an empty (zero length) slice 271 securityContainsEmptyArray := OperationProps{ 272 Security: []map[string][]string{}, 273 } 274 jsonResult, err = json.Marshal(securityContainsEmptyArray) 275 if assert.NoError(t, err) { 276 var props OperationProps 277 if assert.NoError(t, json.Unmarshal(jsonResult, &props)) { 278 assert.Equal(t, securityContainsEmptyArray, props) 279 } 280 } 281} 282 283func TestOperationGobEncoding(t *testing.T) { 284 // 1. empty scope in security requirements: "security": [ { "apiKey": [] } ], 285 doTestOperationGobEncoding(t, operationJSON) 286 287 // 2. nil security requirements 288 doTestOperationGobEncoding(t, `{ 289 "description": "operation description", 290 "x-framework": "go-swagger", 291 "consumes": [ "application/json", "application/x-yaml" ], 292 "produces": [ "application/json", "application/x-yaml" ], 293 "schemes": ["http", "https"], 294 "tags": ["dogs"], 295 "summary": "the summary of the operation", 296 "operationId": "sendCat", 297 "deprecated": true, 298 "parameters": [{"$ref":"Cat"}], 299 "responses": { 300 "default": { 301 "description": "void response" 302 } 303 } 304 }`) 305 306 // 3. empty security requirement 307 doTestOperationGobEncoding(t, `{ 308 "description": "operation description", 309 "x-framework": "go-swagger", 310 "consumes": [ "application/json", "application/x-yaml" ], 311 "produces": [ "application/json", "application/x-yaml" ], 312 "schemes": ["http", "https"], 313 "tags": ["dogs"], 314 "security": [], 315 "summary": "the summary of the operation", 316 "operationId": "sendCat", 317 "deprecated": true, 318 "parameters": [{"$ref":"Cat"}], 319 "responses": { 320 "default": { 321 "description": "void response" 322 } 323 } 324 }`) 325 326 // 4. non-empty security requirements 327 doTestOperationGobEncoding(t, `{ 328 "description": "operation description", 329 "x-framework": "go-swagger", 330 "consumes": [ "application/json", "application/x-yaml" ], 331 "produces": [ "application/json", "application/x-yaml" ], 332 "schemes": ["http", "https"], 333 "tags": ["dogs"], 334 "summary": "the summary of the operation", 335 "security": [ { "scoped-auth": [ "phone", "email" ] , "api-key": []} ], 336 "operationId": "sendCat", 337 "deprecated": true, 338 "parameters": [{"$ref":"Cat"}], 339 "responses": { 340 "default": { 341 "description": "void response" 342 } 343 } 344 }`) 345} 346 347func doTestOperationGobEncoding(t *testing.T, fixture string) { 348 var src, dst Operation 349 350 if !assert.NoError(t, json.Unmarshal([]byte(fixture), &src)) { 351 t.FailNow() 352 } 353 354 doTestAnyGobEncoding(t, &src, &dst) 355} 356 357func doTestAnyGobEncoding(t *testing.T, src, dst interface{}) { 358 expectedJSON, _ := json.MarshalIndent(src, "", " ") 359 360 var b bytes.Buffer 361 err := gob.NewEncoder(&b).Encode(src) 362 if !assert.NoError(t, err) { 363 t.FailNow() 364 } 365 366 err = gob.NewDecoder(&b).Decode(dst) 367 if !assert.NoError(t, err) { 368 t.FailNow() 369 } 370 371 jazon, err := json.MarshalIndent(dst, "", " ") 372 if !assert.NoError(t, err) { 373 t.FailNow() 374 } 375 assert.JSONEq(t, string(expectedJSON), string(jazon)) 376} 377