openapi3_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package data_loader_test
  18. import (
  19. "encoding/json"
  20. "net/http"
  21. "path/filepath"
  22. . "github.com/onsi/ginkgo/v2"
  23. . "github.com/onsi/gomega"
  24. "github.com/savsgio/gotils/bytes"
  25. "github.com/tidwall/gjson"
  26. "github.com/apisix/manager-api/test/e2e/base"
  27. )
  28. var _ = Describe("OpenAPI 3", func() {
  29. DescribeTable("Import cases",
  30. func(f func()) {
  31. f()
  32. },
  33. Entry("default.yaml", func() {
  34. path, err := filepath.Abs("../../testdata/import/default.yaml")
  35. Expect(err).To(BeNil())
  36. req := base.ManagerApiExpect().POST("/apisix/admin/import/routes")
  37. req.WithMultipart().WithForm(map[string]string{
  38. "type": "openapi3",
  39. "task_name": "test_default_yaml",
  40. "_file": "default.yaml",
  41. })
  42. req.WithMultipart().WithFile("file", path)
  43. req.WithHeader("Authorization", base.GetToken())
  44. resp := req.Expect()
  45. resp.Status(http.StatusOK)
  46. r := gjson.ParseBytes([]byte(resp.Body().Raw()))
  47. Expect(r.Get("code").Uint()).To(Equal(uint64(0)))
  48. r = r.Get("data")
  49. for s, result := range r.Map() {
  50. if s == "route" {
  51. Expect(result.Get("total").Uint()).To(Equal(uint64(1)))
  52. Expect(result.Get("failed").Uint()).To(Equal(uint64(0)))
  53. }
  54. }
  55. }),
  56. Entry("default.json", func() {
  57. path, err := filepath.Abs("../../testdata/import/default.json")
  58. Expect(err).To(BeNil())
  59. req := base.ManagerApiExpect().POST("/apisix/admin/import/routes")
  60. req.WithMultipart().WithForm(map[string]string{
  61. "type": "openapi3",
  62. "task_name": "test_default_json",
  63. "_file": "default.json",
  64. })
  65. req.WithMultipart().WithFile("file", path)
  66. req.WithHeader("Authorization", base.GetToken())
  67. resp := req.Expect()
  68. resp.Status(http.StatusOK)
  69. r := gjson.ParseBytes([]byte(resp.Body().Raw()))
  70. Expect(r.Get("code").Uint()).To(Equal(uint64(0)))
  71. r = r.Get("data")
  72. for s, result := range r.Map() {
  73. if s == "route" {
  74. Expect(result.Get("total").Uint()).To(Equal(uint64(1)))
  75. Expect(result.Get("failed").Uint()).To(Equal(uint64(0)))
  76. }
  77. }
  78. }),
  79. Entry("Postman-API101.yaml merge method", func() {
  80. path, err := filepath.Abs("../../testdata/import/Postman-API101.yaml")
  81. Expect(err).To(BeNil())
  82. req := base.ManagerApiExpect().POST("/apisix/admin/import/routes")
  83. req.WithMultipart().WithForm(map[string]string{
  84. "type": "openapi3",
  85. "task_name": "test_postman_api101_yaml_mm",
  86. "_file": "Postman-API101.yaml",
  87. "merge_method": "true",
  88. })
  89. req.WithMultipart().WithFile("file", path)
  90. req.WithHeader("Authorization", base.GetToken())
  91. resp := req.Expect()
  92. resp.Status(http.StatusOK)
  93. r := gjson.ParseBytes([]byte(resp.Body().Raw()))
  94. Expect(r.Get("code").Uint()).To(Equal(uint64(0)))
  95. r = r.Get("data")
  96. for s, result := range r.Map() {
  97. if s == "route" {
  98. Expect(result.Get("total").Uint()).To(Equal(uint64(3)))
  99. Expect(result.Get("failed").Uint()).To(Equal(uint64(0)))
  100. }
  101. if s == "upstream" {
  102. Expect(result.Get("total").Uint()).To(Equal(uint64(1)))
  103. Expect(result.Get("failed").Uint()).To(Equal(uint64(0)))
  104. }
  105. }
  106. }),
  107. Entry("Postman-API101.yaml non-merge method", func() {
  108. // clean routes
  109. base.CleanResource("routes")
  110. path, err := filepath.Abs("../../testdata/import/Postman-API101.yaml")
  111. Expect(err).To(BeNil())
  112. req := base.ManagerApiExpect().POST("/apisix/admin/import/routes")
  113. req.WithMultipart().WithForm(map[string]string{
  114. "type": "openapi3",
  115. "task_name": "test_postman_api101_yaml_nmm",
  116. "_file": "Postman-API101.yaml",
  117. "merge_method": "false",
  118. })
  119. req.WithMultipart().WithFile("file", path)
  120. req.WithHeader("Authorization", base.GetToken())
  121. resp := req.Expect()
  122. resp.Status(http.StatusOK)
  123. r := gjson.ParseBytes([]byte(resp.Body().Raw()))
  124. Expect(r.Get("code").Uint()).To(Equal(uint64(0)))
  125. r = r.Get("data")
  126. for s, result := range r.Map() {
  127. if s == "route" {
  128. Expect(result.Get("total").Uint()).To(Equal(uint64(5)))
  129. Expect(result.Get("failed").Uint()).To(Equal(uint64(0)))
  130. }
  131. if s == "upstream" {
  132. Expect(result.Get("total").Uint()).To(Equal(uint64(1)))
  133. Expect(result.Get("failed").Uint()).To(Equal(uint64(0)))
  134. }
  135. }
  136. }),
  137. Entry("Clean resources", func() {
  138. base.CleanResource("routes")
  139. base.CleanResource("upstreams")
  140. base.CleanResource("services")
  141. }),
  142. )
  143. DescribeTable("Exception cases",
  144. func(f func()) {
  145. f()
  146. },
  147. Entry("Empty upload file", func() {
  148. req := base.ManagerApiExpect().POST("/apisix/admin/import/routes")
  149. req.WithMultipart().WithForm(map[string]string{
  150. "type": "openapi3",
  151. "task_name": "empty_upload",
  152. "_file": "default.yaml",
  153. })
  154. req.WithHeader("Authorization", base.GetToken())
  155. resp := req.Expect()
  156. resp.Status(http.StatusOK)
  157. r := gjson.ParseBytes([]byte(resp.Body().Raw()))
  158. Expect(r.Get("code").Uint()).To(Equal(uint64(10000)))
  159. Expect(r.Get("message").String()).To(Equal("uploaded file is empty"))
  160. }),
  161. Entry("Exceed limit upload file", func() {
  162. req := base.ManagerApiExpect().POST("/apisix/admin/import/routes")
  163. req.WithMultipart().WithForm(map[string]string{
  164. "type": "openapi3",
  165. "task_name": "exceed_limit_upload",
  166. "_file": "default.yaml",
  167. })
  168. req.WithMultipart().WithFileBytes("file", "default.yaml", bytes.Rand(make([]byte, 10*1024*1024+1)))
  169. req.WithHeader("Authorization", base.GetToken())
  170. resp := req.Expect()
  171. resp.Status(http.StatusOK)
  172. r := gjson.ParseBytes([]byte(resp.Body().Raw()))
  173. Expect(r.Get("code").Uint()).To(Equal(uint64(10000)))
  174. Expect(r.Get("message").String()).To(Equal("uploaded file size exceeds the limit, limit is 10485760"))
  175. }),
  176. Entry("Routes duplicate #1", func() {
  177. path, err := filepath.Abs("../../testdata/import/Postman-API101.yaml")
  178. Expect(err).To(BeNil())
  179. req := base.ManagerApiExpect().POST("/apisix/admin/import/routes")
  180. req.WithMultipart().WithForm(map[string]string{
  181. "type": "openapi3",
  182. "task_name": "duplicate",
  183. "_file": "Postman-API101.yaml",
  184. "merge_method": "true",
  185. })
  186. req.WithMultipart().WithFile("file", path)
  187. req.WithHeader("Authorization", base.GetToken())
  188. resp := req.Expect()
  189. resp.Status(http.StatusOK)
  190. r := gjson.ParseBytes([]byte(resp.Body().Raw()))
  191. Expect(r.Get("code").Uint()).To(Equal(uint64(0)))
  192. }),
  193. Entry("Route duplicate #2", func() {
  194. path, err := filepath.Abs("../../testdata/import/Postman-API101.yaml")
  195. Expect(err).To(BeNil())
  196. req := base.ManagerApiExpect().POST("/apisix/admin/import/routes")
  197. req.WithMultipart().WithForm(map[string]string{
  198. "type": "openapi3",
  199. "task_name": "duplicate",
  200. "_file": "Postman-API101.yaml",
  201. "merge_method": "true",
  202. })
  203. req.WithMultipart().WithFile("file", path)
  204. req.WithHeader("Authorization", base.GetToken())
  205. resp := req.Expect()
  206. resp.Status(http.StatusOK)
  207. r := gjson.ParseBytes([]byte(resp.Body().Raw()))
  208. Expect(r.Get("code").Uint()).To(Equal(uint64(0)))
  209. Expect(r.Get("data").Map()["route"].Get("failed").Uint()).To(Equal(uint64(1)))
  210. Expect(r.Get("data").Map()["route"].Get("errors").Array()[0].String()).
  211. To(ContainSubstring("is duplicated with route duplicate_"))
  212. }),
  213. Entry("Clean resources", func() {
  214. base.CleanResource("routes")
  215. base.CleanResource("upstreams")
  216. base.CleanResource("services")
  217. }),
  218. )
  219. DescribeTable("Real API cases",
  220. func(f func()) {
  221. f()
  222. },
  223. Entry("Import httpbin.org YAML", func() {
  224. path, err := filepath.Abs("../../testdata/import/httpbin.yaml")
  225. Expect(err).To(BeNil())
  226. req := base.ManagerApiExpect().POST("/apisix/admin/import/routes")
  227. req.WithMultipart().WithForm(map[string]string{
  228. "type": "openapi3",
  229. "task_name": "httpbin",
  230. "_file": "httpbin.yaml",
  231. })
  232. req.WithMultipart().WithFile("file", path)
  233. req.WithHeader("Authorization", base.GetToken())
  234. resp := req.Expect()
  235. resp.Status(http.StatusOK)
  236. r := gjson.ParseBytes([]byte(resp.Body().Raw()))
  237. Expect(r.Get("code").Uint()).To(Equal(uint64(0)))
  238. r = r.Get("data")
  239. for s, result := range r.Map() {
  240. if s == "route" {
  241. Expect(result.Get("total").Uint()).To(Equal(uint64(1)))
  242. Expect(result.Get("failed").Uint()).To(Equal(uint64(0)))
  243. }
  244. }
  245. }),
  246. Entry("Modify upstream", func() {
  247. body := make(map[string]interface{})
  248. body["nodes"] = []map[string]interface{}{
  249. {
  250. "host": "httpbin.org",
  251. "port": 80,
  252. "weight": 1,
  253. },
  254. }
  255. body["type"] = "roundrobin"
  256. _body, err := json.Marshal(body)
  257. Expect(err).To(BeNil())
  258. base.RunTestCase(base.HttpTestCase{
  259. Object: base.ManagerApiExpect(),
  260. Method: http.MethodPatch,
  261. Path: "/apisix/admin/upstreams/httpbin",
  262. Body: string(_body),
  263. Headers: map[string]string{"Authorization": base.GetToken()},
  264. ExpectStatus: http.StatusOK,
  265. })
  266. }),
  267. Entry("Enable route", func() {
  268. // get route id
  269. req := base.ManagerApiExpect().GET("/apisix/admin/routes")
  270. req.WithHeader("Authorization", base.GetToken())
  271. resp := req.Expect()
  272. resp.Status(http.StatusOK)
  273. r := gjson.ParseBytes([]byte(resp.Body().Raw()))
  274. Expect(r.Get("code").Uint()).To(Equal(uint64(0)))
  275. id := r.Get("data").Get("rows").Array()[0].Get("id").String()
  276. body := make(map[string]interface{})
  277. body["status"] = 1
  278. _body, err := json.Marshal(body)
  279. Expect(err).To(BeNil())
  280. base.RunTestCase(base.HttpTestCase{
  281. Object: base.ManagerApiExpect(),
  282. Method: http.MethodPatch,
  283. Path: "/apisix/admin/routes/" + id,
  284. Body: string(_body),
  285. Headers: map[string]string{"Authorization": base.GetToken()},
  286. ExpectStatus: http.StatusOK,
  287. Sleep: base.SleepTime,
  288. })
  289. }),
  290. Entry("Request API", func() {
  291. req := base.APISIXExpect().GET("/get")
  292. resp := req.Expect()
  293. resp.Status(http.StatusOK)
  294. r := gjson.ParseBytes([]byte(resp.Body().Raw()))
  295. Expect(r.Get("headers").Get("User-Agent").String()).To(Equal("Go-http-client/1.1"))
  296. }),
  297. )
  298. })