query_test.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. /*
  2. * EliasDB
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. */
  10. package graphql
  11. import (
  12. "encoding/json"
  13. "fmt"
  14. "testing"
  15. "devt.de/krotik/eliasdb/graph"
  16. "devt.de/krotik/eliasdb/graph/data"
  17. "devt.de/krotik/eliasdb/graph/graphstorage"
  18. )
  19. func TestErrorCases(t *testing.T) {
  20. gm, _ := songGraphGroups()
  21. query := map[string]interface{}{
  22. "operationName": "foo",
  23. "variables": nil,
  24. }
  25. _, err := RunQuery("test", "main", query, gm, nil, false)
  26. if err == nil || err.Error() != "Mandatory field 'query' missing from query object" {
  27. t.Error("Unexpected result:", err)
  28. return
  29. }
  30. query = map[string]interface{}{
  31. "query": nil,
  32. "variables": nil,
  33. }
  34. _, err = RunQuery("test", "main", query, gm, nil, false)
  35. if err == nil || err.Error() != "Mandatory field 'operationName' missing from query object" {
  36. t.Error("Unexpected result:", err)
  37. return
  38. }
  39. query = map[string]interface{}{
  40. "operationName": "foo",
  41. "query": nil,
  42. }
  43. _, err = RunQuery("test", "main", query, gm, nil, false)
  44. if err == nil || err.Error() != "Mandatory field 'variables' missing from query object" {
  45. t.Error("Unexpected result:", err)
  46. return
  47. }
  48. }
  49. func TestSimpleQueries(t *testing.T) {
  50. gm, _ := songGraphGroups()
  51. ast, err := ParseQuery("test", "{ name }")
  52. if err != nil || ast.String() != `
  53. Document
  54. ExecutableDefinition
  55. OperationDefinition
  56. SelectionSet
  57. Field
  58. Name: name
  59. `[1:] {
  60. t.Error("Unexpected result:", ast, err)
  61. }
  62. ast, err = ParseQuery("test", "{ name ")
  63. if err == nil || err.Error() != "Parse error in test: Unexpected end (Line:1 Pos:7)" {
  64. t.Error("Unexpected result:", ast, err)
  65. }
  66. query := map[string]interface{}{
  67. "operationName": "foo",
  68. "query": `
  69. {
  70. Song {
  71. key
  72. }
  73. }
  74. `,
  75. "variables": nil,
  76. }
  77. _, err = RunQuery("test", "main", query, gm, nil, false)
  78. if err == nil || err.Error() != "Fatal GraphQL operation error in test: Missing operation (Operation foo not found) (Line:2 Pos:2)" {
  79. t.Error("Unexpected result:", err)
  80. return
  81. }
  82. query = map[string]interface{}{
  83. "operationName": nil,
  84. "query": nil,
  85. "variables": nil,
  86. }
  87. _, err = RunQuery("test", "main", query, gm, nil, false)
  88. if err == nil || err.Error() != "Fatal GraphQL operation error in test: Missing operation (No executable expression found) (Line:1 Pos:0)" {
  89. t.Error("Unexpected result:", err)
  90. return
  91. }
  92. query = map[string]interface{}{
  93. "operationName": nil,
  94. "query": `
  95. fragment friendFields on User {
  96. id
  97. name
  98. profilePic(size: 50)
  99. }
  100. `,
  101. "variables": nil,
  102. }
  103. res, err := RunQuery("test", "main", query, gm, nil, false)
  104. if err == nil || err.Error() != "Fatal GraphQL operation error in test: Missing operation (No executable expression found) (Line:2 Pos:2)" {
  105. t.Error("Unexpected result:", res, err)
  106. return
  107. }
  108. query = map[string]interface{}{
  109. "operationName": nil,
  110. "query": `
  111. {
  112. Song1 : Song {
  113. song_key : key
  114. song_key1 : key
  115. song_key1 : name # This is illegal and will be ignored
  116. song_key1 : key
  117. name
  118. name
  119. }
  120. group {
  121. key
  122. },
  123. }
  124. `,
  125. "variables": nil,
  126. }
  127. if rerr := checkResult(`
  128. {
  129. "data": {
  130. "Song1": [
  131. {
  132. "name": "StrangeSong1",
  133. "song_key": "StrangeSong1",
  134. "song_key1": "StrangeSong1"
  135. },
  136. {
  137. "name": "FightSong4",
  138. "song_key": "FightSong4",
  139. "song_key1": "FightSong4"
  140. },
  141. {
  142. "name": "DeadSong2",
  143. "song_key": "DeadSong2",
  144. "song_key1": "DeadSong2"
  145. },
  146. {
  147. "name": "LoveSong3",
  148. "song_key": "LoveSong3",
  149. "song_key1": "LoveSong3"
  150. },
  151. {
  152. "name": "MyOnlySong3",
  153. "song_key": "MyOnlySong3",
  154. "song_key1": "MyOnlySong3"
  155. },
  156. {
  157. "name": "Aria1",
  158. "song_key": "Aria1",
  159. "song_key1": "Aria1"
  160. },
  161. {
  162. "name": "Aria2",
  163. "song_key": "Aria2",
  164. "song_key1": "Aria2"
  165. },
  166. {
  167. "name": "Aria3",
  168. "song_key": "Aria3",
  169. "song_key1": "Aria3"
  170. },
  171. {
  172. "name": "Aria4",
  173. "song_key": "Aria4",
  174. "song_key1": "Aria4"
  175. }
  176. ],
  177. "group": [
  178. {
  179. "key": "Best"
  180. }
  181. ]
  182. },
  183. "errors": [
  184. {
  185. "locations": [
  186. {
  187. "column": 17,
  188. "line": 3
  189. }
  190. ],
  191. "message": "Field identifier song_key1 used multiple times",
  192. "path": [
  193. "Song1"
  194. ]
  195. },
  196. {
  197. "locations": [
  198. {
  199. "column": 17,
  200. "line": 3
  201. }
  202. ],
  203. "message": "Field identifier name used multiple times",
  204. "path": [
  205. "Song1"
  206. ]
  207. }
  208. ]
  209. }`[1:], query, gm); rerr != nil {
  210. t.Error(rerr)
  211. return
  212. }
  213. query = map[string]interface{}{
  214. "operationName": nil,
  215. "query": `
  216. fragment Song on Song {
  217. key
  218. name1 : name
  219. ...SongKind
  220. }
  221. query b { # This should be executed
  222. Song {
  223. key
  224. ...Song
  225. }
  226. }
  227. query a {
  228. Song1 {
  229. key1
  230. }
  231. }
  232. fragment SongKind on Song {
  233. kind
  234. name2 : name
  235. key
  236. }
  237. `,
  238. "variables": nil,
  239. }
  240. if rerr := checkResult(`
  241. {
  242. "data": {
  243. "Song": [
  244. {
  245. "key": "StrangeSong1",
  246. "kind": "Song",
  247. "name1": "StrangeSong1",
  248. "name2": "StrangeSong1"
  249. },
  250. {
  251. "key": "FightSong4",
  252. "kind": "Song",
  253. "name1": "FightSong4",
  254. "name2": "FightSong4"
  255. },
  256. {
  257. "key": "DeadSong2",
  258. "kind": "Song",
  259. "name1": "DeadSong2",
  260. "name2": "DeadSong2"
  261. },
  262. {
  263. "key": "LoveSong3",
  264. "kind": "Song",
  265. "name1": "LoveSong3",
  266. "name2": "LoveSong3"
  267. },
  268. {
  269. "key": "MyOnlySong3",
  270. "kind": "Song",
  271. "name1": "MyOnlySong3",
  272. "name2": "MyOnlySong3"
  273. },
  274. {
  275. "key": "Aria1",
  276. "kind": "Song",
  277. "name1": "Aria1",
  278. "name2": "Aria1"
  279. },
  280. {
  281. "key": "Aria2",
  282. "kind": "Song",
  283. "name1": "Aria2",
  284. "name2": "Aria2"
  285. },
  286. {
  287. "key": "Aria3",
  288. "kind": "Song",
  289. "name1": "Aria3",
  290. "name2": "Aria3"
  291. },
  292. {
  293. "key": "Aria4",
  294. "kind": "Song",
  295. "name1": "Aria4",
  296. "name2": "Aria4"
  297. }
  298. ]
  299. },
  300. "errors": [
  301. {
  302. "locations": [
  303. {
  304. "column": 9,
  305. "line": 8
  306. }
  307. ],
  308. "message": "Field identifier key used multiple times",
  309. "path": [
  310. "Song"
  311. ]
  312. }
  313. ]
  314. }`[1:], query, gm); rerr != nil {
  315. t.Error(rerr)
  316. return
  317. }
  318. }
  319. func checkResult(expectedResult string, query map[string]interface{}, gm *graph.Manager) error {
  320. actualResultObject, err := RunQuery("test", "main", query, gm, nil, false)
  321. if err == nil {
  322. var actualResultBytes []byte
  323. actualResultBytes, err = json.MarshalIndent(actualResultObject, "", " ")
  324. actualResult := string(actualResultBytes)
  325. if err == nil {
  326. if expectedResult != actualResult {
  327. err = fmt.Errorf("Unexpected result:\nExpected:\n%s\nActual:\n%s",
  328. expectedResult, actualResult)
  329. }
  330. }
  331. }
  332. if err != nil {
  333. fmt.Println(ParseQuery("test", fmt.Sprint(query["query"])))
  334. }
  335. return err
  336. }
  337. func songGraph() (*graph.Manager, *graphstorage.MemoryGraphStorage) {
  338. mgs := graphstorage.NewMemoryGraphStorage("mystorage")
  339. gm := graph.NewGraphManager(mgs)
  340. constructEdge := func(key string, node1 data.Node, node2 data.Node, number int) data.Edge {
  341. edge := data.NewGraphEdge()
  342. edge.SetAttr("key", key)
  343. edge.SetAttr("kind", "Wrote")
  344. edge.SetAttr(data.EdgeEnd1Key, node1.Key())
  345. edge.SetAttr(data.EdgeEnd1Kind, node1.Kind())
  346. edge.SetAttr(data.EdgeEnd1Role, "Author")
  347. edge.SetAttr(data.EdgeEnd1Cascading, true)
  348. edge.SetAttr(data.EdgeEnd2Key, node2.Key())
  349. edge.SetAttr(data.EdgeEnd2Kind, node2.Kind())
  350. edge.SetAttr(data.EdgeEnd2Role, "Song")
  351. edge.SetAttr(data.EdgeEnd2Cascading, false)
  352. edge.SetAttr("number", number)
  353. return edge
  354. }
  355. storeSong := func(node data.Node, name string, ranking int, number int) {
  356. node3 := data.NewGraphNode()
  357. node3.SetAttr("key", name)
  358. node3.SetAttr("kind", "Song")
  359. node3.SetAttr("name", name)
  360. node3.SetAttr("ranking", ranking)
  361. gm.StoreNode("main", node3)
  362. gm.StoreEdge("main", constructEdge(name, node, node3, number))
  363. }
  364. node0 := data.NewGraphNode()
  365. node0.SetAttr("key", "000")
  366. node0.SetAttr("kind", "Author")
  367. node0.SetAttr("name", "John")
  368. gm.StoreNode("main", node0)
  369. storeSong(node0, "Aria1", 8, 1)
  370. storeSong(node0, "Aria2", 2, 2)
  371. storeSong(node0, "Aria3", 4, 3)
  372. storeSong(node0, "Aria4", 18, 4)
  373. node1 := data.NewGraphNode()
  374. node1.SetAttr("key", "123")
  375. node1.SetAttr("kind", "Author")
  376. node1.SetAttr("name", "Mike")
  377. gm.StoreNode("main", node1)
  378. storeSong(node1, "LoveSong3", 1, 3)
  379. storeSong(node1, "FightSong4", 3, 4)
  380. storeSong(node1, "DeadSong2", 6, 2)
  381. storeSong(node1, "StrangeSong1", 5, 1)
  382. node2 := data.NewGraphNode()
  383. node2.SetAttr("key", "456")
  384. node2.SetAttr("kind", "Author")
  385. node2.SetAttr("name", "Hans")
  386. gm.StoreNode("main", node2)
  387. storeSong(node2, "MyOnlySong3", 19, 3)
  388. return gm, mgs.(*graphstorage.MemoryGraphStorage)
  389. }
  390. func songGraphGroups() (*graph.Manager, *graphstorage.MemoryGraphStorage) {
  391. gm, mgs := songGraph()
  392. node0 := data.NewGraphNode()
  393. node0.SetAttr("key", "Best")
  394. node0.SetAttr("kind", "group")
  395. gm.StoreNode("main", node0)
  396. constructEdge := func(songkey string) data.Edge {
  397. edge := data.NewGraphEdge()
  398. edge.SetAttr("key", songkey)
  399. edge.SetAttr("kind", "Contains")
  400. edge.SetAttr(data.EdgeEnd1Key, node0.Key())
  401. edge.SetAttr(data.EdgeEnd1Kind, node0.Kind())
  402. edge.SetAttr(data.EdgeEnd1Role, "group")
  403. edge.SetAttr(data.EdgeEnd1Cascading, false)
  404. edge.SetAttr(data.EdgeEnd2Key, songkey)
  405. edge.SetAttr(data.EdgeEnd2Kind, "Song")
  406. edge.SetAttr(data.EdgeEnd2Role, "Song")
  407. edge.SetAttr(data.EdgeEnd2Cascading, false)
  408. return edge
  409. }
  410. gm.StoreEdge("main", constructEdge("LoveSong3"))
  411. gm.StoreEdge("main", constructEdge("Aria3"))
  412. gm.StoreEdge("main", constructEdge("MyOnlySong3"))
  413. gm.StoreEdge("main", constructEdge("StrangeSong1"))
  414. return gm, mgs
  415. }