operation_test.go 9.5 KB

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