gnostic_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. package main
  2. import (
  3. "io/ioutil"
  4. "os"
  5. "os/exec"
  6. "path/filepath"
  7. "strings"
  8. "testing"
  9. )
  10. func testCompiler(t *testing.T, inputFile string, referenceFile string, expectErrors bool) {
  11. textFile := strings.Replace(filepath.Base(inputFile), filepath.Ext(inputFile), ".text", 1)
  12. errorsFile := strings.Replace(filepath.Base(inputFile), filepath.Ext(inputFile), ".errors", 1)
  13. // remove any preexisting output files
  14. os.Remove(textFile)
  15. os.Remove(errorsFile)
  16. // run the compiler
  17. var err error
  18. var cmd = exec.Command(
  19. "gnostic",
  20. inputFile,
  21. "--text-out=.",
  22. "--errors-out=.",
  23. "--resolve-refs")
  24. //t.Log(cmd.Args)
  25. err = cmd.Run()
  26. if err != nil && !expectErrors {
  27. t.Logf("Compile failed: %+v", err)
  28. t.FailNow()
  29. }
  30. // verify the output against a reference
  31. var outputFile string
  32. if expectErrors {
  33. outputFile = errorsFile
  34. } else {
  35. outputFile = textFile
  36. }
  37. err = exec.Command("diff", outputFile, referenceFile).Run()
  38. if err != nil {
  39. t.Logf("Diff failed: %+v", err)
  40. t.FailNow()
  41. } else {
  42. // if the test succeeded, clean up
  43. os.Remove(textFile)
  44. os.Remove(errorsFile)
  45. }
  46. }
  47. func testNormal(t *testing.T, inputFile string, referenceFile string) {
  48. testCompiler(t, inputFile, referenceFile, false)
  49. }
  50. func testErrors(t *testing.T, inputFile string, referenceFile string) {
  51. testCompiler(t, inputFile, referenceFile, true)
  52. }
  53. func TestPetstoreJSON(t *testing.T) {
  54. testNormal(t,
  55. "examples/v2.0/json/petstore.json",
  56. "test/v2.0/petstore.text")
  57. }
  58. func TestPetstoreYAML(t *testing.T) {
  59. testNormal(t,
  60. "examples/v2.0/yaml/petstore.yaml",
  61. "test/v2.0/petstore.text")
  62. }
  63. func TestSeparateYAML(t *testing.T) {
  64. testNormal(t,
  65. "examples/v2.0/yaml/petstore-separate/spec/swagger.yaml",
  66. "test/v2.0/yaml/petstore-separate/spec/swagger.text")
  67. }
  68. func TestSeparateJSON(t *testing.T) {
  69. testNormal(t,
  70. "examples/v2.0/json/petstore-separate/spec/swagger.json",
  71. "test/v2.0/yaml/petstore-separate/spec/swagger.text") // yaml and json results should be identical
  72. }
  73. func TestRemotePetstoreJSON(t *testing.T) {
  74. testNormal(t,
  75. "https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/json/petstore.json",
  76. "test/v2.0/petstore.text")
  77. }
  78. func TestRemotePetstoreYAML(t *testing.T) {
  79. testNormal(t,
  80. "https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/yaml/petstore.yaml",
  81. "test/v2.0/petstore.text")
  82. }
  83. func TestRemoteSeparateYAML(t *testing.T) {
  84. testNormal(t,
  85. "https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/yaml/petstore-separate/spec/swagger.yaml",
  86. "test/v2.0/yaml/petstore-separate/spec/swagger.text")
  87. }
  88. func TestRemoteSeparateJSON(t *testing.T) {
  89. testNormal(t,
  90. "https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/json/petstore-separate/spec/swagger.json",
  91. "test/v2.0/yaml/petstore-separate/spec/swagger.text")
  92. }
  93. func TestErrorBadProperties(t *testing.T) {
  94. testErrors(t,
  95. "examples/errors/petstore-badproperties.yaml",
  96. "test/errors/petstore-badproperties.errors")
  97. }
  98. func TestErrorUnresolvedRefs(t *testing.T) {
  99. testErrors(t,
  100. "examples/errors/petstore-unresolvedrefs.yaml",
  101. "test/errors/petstore-unresolvedrefs.errors")
  102. }
  103. func TestErrorMissingVersion(t *testing.T) {
  104. testErrors(t,
  105. "examples/errors/petstore-missingversion.yaml",
  106. "test/errors/petstore-missingversion.errors")
  107. }
  108. func testPlugin(t *testing.T, plugin string, inputFile string, outputFile string, referenceFile string) {
  109. // remove any preexisting output files
  110. os.Remove(outputFile)
  111. // run the compiler
  112. var err error
  113. output, err := exec.Command(
  114. "gnostic",
  115. "--"+plugin+"-out=-",
  116. inputFile).Output()
  117. if err != nil {
  118. t.Logf("Compile failed: %+v", err)
  119. t.FailNow()
  120. }
  121. _ = ioutil.WriteFile(outputFile, output, 0644)
  122. err = exec.Command("diff", outputFile, referenceFile).Run()
  123. if err != nil {
  124. t.Logf("Diff failed: %+v", err)
  125. t.FailNow()
  126. } else {
  127. // if the test succeeded, clean up
  128. os.Remove(outputFile)
  129. }
  130. }
  131. func TestSamplePluginWithPetstore(t *testing.T) {
  132. testPlugin(t,
  133. "go-sample",
  134. "examples/v2.0/yaml/petstore.yaml",
  135. "sample-petstore.out",
  136. "test/v2.0/yaml/sample-petstore.out")
  137. }
  138. func TestErrorInvalidPluginInvocations(t *testing.T) {
  139. var err error
  140. output, err := exec.Command(
  141. "gnostic",
  142. "examples/v2.0/yaml/petstore.yaml",
  143. "--errors-out=-",
  144. "--plugin-out=foo=bar,:abc",
  145. "--plugin-out=,foo=bar:abc",
  146. "--plugin-out=foo=:abc",
  147. "--plugin-out==bar:abc",
  148. "--plugin-out=,,:abc",
  149. "--plugin-out=foo=bar=baz:abc",
  150. ).Output()
  151. if err == nil {
  152. t.Logf("Invalid invocations were accepted")
  153. t.FailNow()
  154. }
  155. outputFile := "invalid-plugin-invocation.errors"
  156. _ = ioutil.WriteFile(outputFile, output, 0644)
  157. err = exec.Command("diff", outputFile, "test/errors/invalid-plugin-invocation.errors").Run()
  158. if err != nil {
  159. t.Logf("Diff failed: %+v", err)
  160. t.FailNow()
  161. } else {
  162. // if the test succeeded, clean up
  163. os.Remove(outputFile)
  164. }
  165. }
  166. func TestValidPluginInvocations(t *testing.T) {
  167. var err error
  168. output, err := exec.Command(
  169. "gnostic",
  170. "examples/v2.0/yaml/petstore.yaml",
  171. "--errors-out=-",
  172. // verify an invocation with no parameters
  173. "--go-sample-out=!", // "!" indicates that no output should be generated
  174. // verify single pair of parameters
  175. "--go-sample-out=a=b:!",
  176. // verify multiple parameters
  177. "--go-sample-out=a=b,c=123,xyz=alphabetagammadelta:!",
  178. // verify that special characters / . - _ can be included in parameter keys and values
  179. "--go-sample-out=a/b/c=x/y/z:!",
  180. "--go-sample-out=a.b.c=x.y.z:!",
  181. "--go-sample-out=a-b-c=x-y-z:!",
  182. "--go-sample-out=a_b_c=x_y_z:!",
  183. ).Output()
  184. if len(output) != 0 {
  185. t.Logf("Valid invocations generated invalid errors\n%s", string(output))
  186. t.FailNow()
  187. }
  188. if err != nil {
  189. t.Logf("Valid invocations were not accepted")
  190. t.FailNow()
  191. }
  192. }
  193. func TestExtensionHandlerWithLibraryExample(t *testing.T) {
  194. outputFile := "library-example-with-ext.text.out"
  195. inputFile := "test/library-example-with-ext.json"
  196. referenceFile := "test/library-example-with-ext.text.out"
  197. os.Remove(outputFile)
  198. // run the compiler
  199. var err error
  200. command := exec.Command(
  201. "gnostic",
  202. "--x-sampleone",
  203. "--x-sampletwo",
  204. "--text-out="+outputFile,
  205. "--resolve-refs",
  206. inputFile)
  207. _, err = command.Output()
  208. if err != nil {
  209. t.Logf("Compile failed for command %v: %+v", command, err)
  210. t.FailNow()
  211. }
  212. //_ = ioutil.WriteFile(outputFile, output, 0644)
  213. err = exec.Command("diff", outputFile, referenceFile).Run()
  214. if err != nil {
  215. t.Logf("Diff failed: %+v", err)
  216. t.FailNow()
  217. } else {
  218. // if the test succeeded, clean up
  219. os.Remove(outputFile)
  220. }
  221. }
  222. func TestJSONOutput(t *testing.T) {
  223. inputFile := "test/library-example-with-ext.json"
  224. textFile := "sample.text"
  225. jsonFile := "sample.json"
  226. textFile2 := "sample2.text"
  227. jsonFile2 := "sample2.json"
  228. os.Remove(textFile)
  229. os.Remove(jsonFile)
  230. os.Remove(textFile2)
  231. os.Remove(jsonFile2)
  232. var err error
  233. // Run the compiler once.
  234. command := exec.Command(
  235. "gnostic",
  236. "--text-out="+textFile,
  237. "--json-out="+jsonFile,
  238. inputFile)
  239. _, err = command.Output()
  240. if err != nil {
  241. t.Logf("Compile failed for command %v: %+v", command, err)
  242. t.FailNow()
  243. }
  244. // Run the compiler again, this time on the generated output.
  245. command = exec.Command(
  246. "gnostic",
  247. "--text-out="+textFile2,
  248. "--json-out="+jsonFile2,
  249. jsonFile)
  250. _, err = command.Output()
  251. if err != nil {
  252. t.Logf("Compile failed for command %v: %+v", command, err)
  253. t.FailNow()
  254. }
  255. // Verify that both models have the same internal representation.
  256. err = exec.Command("diff", textFile, textFile2).Run()
  257. if err != nil {
  258. t.Logf("Diff failed: %+v", err)
  259. t.FailNow()
  260. } else {
  261. // if the test succeeded, clean up
  262. os.Remove(textFile)
  263. os.Remove(jsonFile)
  264. os.Remove(textFile2)
  265. os.Remove(jsonFile2)
  266. }
  267. }
  268. func TestYAMLOutput(t *testing.T) {
  269. inputFile := "test/library-example-with-ext.json"
  270. textFile := "sample.text"
  271. yamlFile := "sample.yaml"
  272. textFile2 := "sample2.text"
  273. yamlFile2 := "sample2.yaml"
  274. os.Remove(textFile)
  275. os.Remove(yamlFile)
  276. os.Remove(textFile2)
  277. os.Remove(yamlFile2)
  278. var err error
  279. // Run the compiler once.
  280. command := exec.Command(
  281. "gnostic",
  282. "--text-out="+textFile,
  283. "--yaml-out="+yamlFile,
  284. inputFile)
  285. _, err = command.Output()
  286. if err != nil {
  287. t.Logf("Compile failed for command %v: %+v", command, err)
  288. t.FailNow()
  289. }
  290. // Run the compiler again, this time on the generated output.
  291. command = exec.Command(
  292. "gnostic",
  293. "--text-out="+textFile2,
  294. "--yaml-out="+yamlFile2,
  295. yamlFile)
  296. _, err = command.Output()
  297. if err != nil {
  298. t.Logf("Compile failed for command %v: %+v", command, err)
  299. t.FailNow()
  300. }
  301. // Verify that both models have the same internal representation.
  302. err = exec.Command("diff", textFile, textFile2).Run()
  303. if err != nil {
  304. t.Logf("Diff failed: %+v", err)
  305. t.FailNow()
  306. } else {
  307. // if the test succeeded, clean up
  308. os.Remove(textFile)
  309. os.Remove(yamlFile)
  310. os.Remove(textFile2)
  311. os.Remove(yamlFile2)
  312. }
  313. }
  314. func testBuilder(version string, t *testing.T) {
  315. var err error
  316. pbFile := "petstore-" + version + ".pb"
  317. yamlFile := "petstore.yaml"
  318. jsonFile := "petstore.json"
  319. textFile := "petstore.text"
  320. textReference := "test/" + version + ".0/petstore.text"
  321. os.Remove(pbFile)
  322. os.Remove(textFile)
  323. os.Remove(yamlFile)
  324. os.Remove(jsonFile)
  325. // Generate petstore.pb.
  326. command := exec.Command(
  327. "petstore-builder",
  328. "--"+version)
  329. _, err = command.Output()
  330. if err != nil {
  331. t.Logf("Command %v failed: %+v", command, err)
  332. t.FailNow()
  333. }
  334. // Convert petstore.pb to yaml and json.
  335. command = exec.Command(
  336. "gnostic",
  337. pbFile,
  338. "--json-out="+jsonFile,
  339. "--yaml-out="+yamlFile)
  340. _, err = command.Output()
  341. if err != nil {
  342. t.Logf("Command %v failed: %+v", command, err)
  343. t.FailNow()
  344. }
  345. // Read petstore.yaml, resolve references, and export text.
  346. command = exec.Command(
  347. "gnostic",
  348. yamlFile,
  349. "--resolve-refs",
  350. "--text-out="+textFile)
  351. _, err = command.Output()
  352. if err != nil {
  353. t.Logf("Command %v failed: %+v", command, err)
  354. t.FailNow()
  355. }
  356. // Verify that the generated text matches our reference.
  357. err = exec.Command("diff", textFile, textReference).Run()
  358. if err != nil {
  359. t.Logf("Diff failed: %+v", err)
  360. t.FailNow()
  361. }
  362. // Read petstore.json, resolve references, and export text.
  363. command = exec.Command(
  364. "gnostic",
  365. jsonFile,
  366. "--resolve-refs",
  367. "--text-out="+textFile)
  368. _, err = command.Output()
  369. if err != nil {
  370. t.Logf("Command %v failed: %+v", command, err)
  371. t.FailNow()
  372. }
  373. // Verify that the generated text matches our reference.
  374. err = exec.Command("diff", textFile, textReference).Run()
  375. if err != nil {
  376. t.Logf("Diff failed: %+v", err)
  377. t.FailNow()
  378. }
  379. // if the test succeeded, clean up
  380. os.Remove(pbFile)
  381. os.Remove(textFile)
  382. os.Remove(yamlFile)
  383. os.Remove(jsonFile)
  384. }
  385. func TestBuilderV2(t *testing.T) {
  386. testBuilder("v2", t)
  387. }
  388. func TestBuilderV3(t *testing.T) {
  389. testBuilder("v3", t)
  390. }
  391. // OpenAPI 3.0 tests
  392. func TestPetstoreYAML_30(t *testing.T) {
  393. testNormal(t,
  394. "examples/v3.0/yaml/petstore.yaml",
  395. "test/v3.0/petstore.text")
  396. }
  397. func TestPetstoreJSON_30(t *testing.T) {
  398. testNormal(t,
  399. "examples/v3.0/json/petstore.json",
  400. "test/v3.0/petstore.text")
  401. }