edge_test.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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 rumble
  11. import (
  12. "fmt"
  13. "testing"
  14. "devt.de/krotik/eliasdb/api"
  15. "devt.de/krotik/eliasdb/graph"
  16. "devt.de/krotik/eliasdb/graph/data"
  17. "devt.de/krotik/eliasdb/graph/graphstorage"
  18. )
  19. func TestStoreAndRemoveEdge(t *testing.T) {
  20. mr := &mockRuntime{}
  21. mgs := graphstorage.NewMemoryGraphStorage("mystorage")
  22. gm := graph.NewGraphManager(mgs)
  23. api.GM = gm
  24. se := &StoreEdgeFunc{}
  25. if se.Name() != "db.storeEdge" {
  26. t.Error("Unexpected result:", se.Name())
  27. return
  28. }
  29. if err := se.Validate(2, mr); err != nil {
  30. t.Error(err)
  31. return
  32. }
  33. if err := se.Validate(3, mr); err != nil {
  34. t.Error(err)
  35. return
  36. }
  37. if err := se.Validate(1, mr); err == nil || err.Error() != "Invalid construct Function storeEdge requires 2 or 3 parameters: partition, edge map and optionally a transaction" {
  38. t.Error(err)
  39. return
  40. }
  41. if _, err := se.Execute([]interface{}{"main", map[interface{}]interface{}{
  42. "key": "foo",
  43. }}, nil, mr); err == nil || err.Error() != "Invalid state Cannot store edge: GraphError: Invalid data (Edge is missing a kind value)" {
  44. t.Error(err)
  45. return
  46. }
  47. if _, err := se.Execute([]interface{}{"main", "x"}, nil, mr); err == nil || err.Error() != "Operand is not a map Second parameter must be a map" {
  48. t.Error(err)
  49. return
  50. }
  51. if _, err := se.Execute([]interface{}{"main", map[interface{}]interface{}{
  52. "key": "foo",
  53. }, "x"}, nil, mr); err == nil || err.Error() != "Invalid construct Third parameter must be a transaction" {
  54. t.Error(err)
  55. return
  56. }
  57. gm.StoreNode("main", data.NewGraphNodeFromMap(map[string]interface{}{
  58. "key": "a",
  59. "kind": "b",
  60. }))
  61. gm.StoreNode("main", data.NewGraphNodeFromMap(map[string]interface{}{
  62. "key": "c",
  63. "kind": "d",
  64. }))
  65. _, err := se.Execute([]interface{}{"main", map[interface{}]interface{}{
  66. "key": "123",
  67. "kind": "e",
  68. "end1cascading": true,
  69. "end1key": "a",
  70. "end1kind": "b",
  71. "end1role": "role1",
  72. "end2cascading": false,
  73. "end2key": "c",
  74. "end2kind": "d",
  75. "end2role": "role2",
  76. }}, nil, mr)
  77. if err != nil {
  78. t.Error(err)
  79. return
  80. }
  81. _, err = se.Execute([]interface{}{"main", map[interface{}]interface{}{
  82. "key": "123",
  83. "kind": "e",
  84. "end1cascading": true,
  85. "end1key": "a",
  86. "end1kind": "b1",
  87. "end1role": "role1",
  88. "end2cascading": false,
  89. "end2key": "c",
  90. "end2kind": "d",
  91. "end2role": "role2",
  92. }}, nil, mr)
  93. if err == nil || err.Error() != "Invalid state Cannot store edge: GraphError: Invalid data (Can't store edge to non-existend node kind: b1)" {
  94. t.Error(err)
  95. return
  96. }
  97. fe := &FetchEdgeFunc{}
  98. if fe.Name() != "db.fetchEdge" {
  99. t.Error("Unexpected result:", fe.Name())
  100. return
  101. }
  102. if err := fe.Validate(3, mr); err != nil {
  103. t.Error(err)
  104. return
  105. }
  106. if err := fe.Validate(1, mr); err == nil || err.Error() != "Invalid construct Function fetchEdge requires 3 parameters: partition, edge key and edge kind" {
  107. t.Error(err)
  108. return
  109. }
  110. if _, err := fe.Execute([]interface{}{"mai n", "123", "e"}, nil, mr); err == nil || err.Error() !=
  111. "Invalid state Cannot fetch edge: GraphError: Invalid data (Partition name mai n is not alphanumeric - can only contain [a-zA-Z0-9_])" {
  112. t.Error(err)
  113. return
  114. }
  115. res, err := fe.Execute([]interface{}{"main", "123", "e"}, nil, mr)
  116. if fmt.Sprint(data.NewGraphEdgeFromNode(NewGraphNodeFromRumbleMap(res.(map[interface{}]interface{})))) != `
  117. GraphEdge:
  118. key : 123
  119. kind : e
  120. end1cascading : true
  121. end1key : a
  122. end1kind : b
  123. end1role : role1
  124. end2cascading : false
  125. end2key : c
  126. end2kind : d
  127. end2role : role2
  128. `[1:] || err != nil {
  129. t.Error("Unexpected result:", fmt.Sprint(data.NewGraphEdgeFromNode(NewGraphNodeFromRumbleMap(res.(map[interface{}]interface{})))), err)
  130. return
  131. }
  132. tr := &TraverseFunc{}
  133. if tr.Name() != "db.traverse" {
  134. t.Error("Unexpected result:", tr.Name())
  135. return
  136. }
  137. if err := tr.Validate(4, mr); err != nil {
  138. t.Error(err)
  139. return
  140. }
  141. if err := tr.Validate(1, mr); err == nil || err.Error() != "Invalid construct Function traverse requires 4 parameters: partition, node key, node kind and a traversal spec" {
  142. t.Error(err)
  143. return
  144. }
  145. res, err = tr.Execute([]interface{}{"main", "c", "d", "::"}, nil, mr)
  146. if err == nil || err.Error() != "Invalid state Cannot traverse: GraphError: Invalid data (Invalid spec: ::)" {
  147. t.Error(err)
  148. return
  149. }
  150. res, err = tr.Execute([]interface{}{"main", "c", "d", ":::"}, nil, mr)
  151. if err != nil {
  152. t.Error(err)
  153. return
  154. }
  155. if fmt.Sprint(data.NewGraphEdgeFromNode(NewGraphNodeFromRumbleMap(res.([]interface{})[1].([]interface{})[0].(map[interface{}]interface{})))) != `
  156. GraphEdge:
  157. key : 123
  158. kind : e
  159. end1cascading : false
  160. end1key : c
  161. end1kind : d
  162. end1role : role2
  163. end2cascading : true
  164. end2key : a
  165. end2kind : b
  166. end2role : role1
  167. `[1:] || err != nil {
  168. t.Error("Unexpected result:", fmt.Sprint(data.NewGraphEdgeFromNode(NewGraphNodeFromRumbleMap(res.([]interface{})[1].([]interface{})[0].(map[interface{}]interface{})))), err)
  169. return
  170. }
  171. if fmt.Sprint(NewGraphNodeFromRumbleMap(res.([]interface{})[0].([]interface{})[0].(map[interface{}]interface{}))) != `
  172. GraphNode:
  173. key : a
  174. kind : b
  175. `[1:] || err != nil {
  176. t.Error("Unexpected result:", fmt.Sprint(NewGraphNodeFromRumbleMap(res.([]interface{})[0].([]interface{})[0].(map[interface{}]interface{}))), err)
  177. return
  178. }
  179. re := &RemoveEdgeFunc{}
  180. if re.Name() != "db.removeEdge" {
  181. t.Error("Unexpected result:", re.Name())
  182. return
  183. }
  184. if err := re.Validate(3, mr); err != nil {
  185. t.Error(err)
  186. return
  187. }
  188. if err := re.Validate(1, mr); err == nil || err.Error() !=
  189. "Invalid construct Function removeEdge requires 3 or 4 parameters: partition, edge key, edge kind and optionally a transaction" {
  190. t.Error(err)
  191. return
  192. }
  193. if _, err := re.Execute([]interface{}{"mai n", "123", "e"}, nil, mr); err == nil || err.Error() !=
  194. "Invalid state Cannot remove edge: GraphError: Invalid data (Partition name mai n is not alphanumeric - can only contain [a-zA-Z0-9_])" {
  195. t.Error(err)
  196. return
  197. }
  198. if _, err := re.Execute([]interface{}{"mai n", "123", "e", "bla"}, nil, mr); err == nil || err.Error() !=
  199. "Invalid construct Fourth parameter must be a transaction" {
  200. t.Error(err)
  201. return
  202. }
  203. if _, err := re.Execute([]interface{}{"main", "123", "e"}, nil, mr); err != nil {
  204. t.Error(err)
  205. return
  206. }
  207. res, err = fe.Execute([]interface{}{"main", "123", "e"}, nil, mr)
  208. if res != nil || err != nil {
  209. t.Error("Unexpected result:", res, err)
  210. return
  211. }
  212. }
  213. func TestStoreEdgeTrans(t *testing.T) {
  214. mr := &mockRuntime{}
  215. mgs := graphstorage.NewMemoryGraphStorage("mystorage")
  216. gm := graph.NewGraphManager(mgs)
  217. api.GM = gm
  218. sn := &StoreNodeFunc{}
  219. se := &StoreEdgeFunc{}
  220. tc := &CommitTransFunc{}
  221. trans := graph.NewGraphTrans(gm)
  222. if _, err := sn.Execute([]interface{}{"main", map[interface{}]interface{}{
  223. "key": "a",
  224. "kind": "b",
  225. }, trans}, nil, mr); err != nil {
  226. t.Error(err)
  227. return
  228. }
  229. if _, err := sn.Execute([]interface{}{"main", map[interface{}]interface{}{
  230. "key": "c",
  231. "kind": "d",
  232. }, trans}, nil, mr); err != nil {
  233. t.Error(err)
  234. return
  235. }
  236. _, err := se.Execute([]interface{}{"main", map[interface{}]interface{}{
  237. "key": "123",
  238. "kind": "e",
  239. "end1cascading": true,
  240. "end1key": "a",
  241. "end1kind": "b",
  242. "end1role": "role1",
  243. "end2cascading": false,
  244. "end2key": "c",
  245. "end2kind": "d",
  246. "end2role": "role2",
  247. }, trans}, nil, mr)
  248. if err != nil {
  249. t.Error(err)
  250. return
  251. }
  252. if res := fmt.Sprint(trans.Counts()); res != "2 1 0 0" {
  253. t.Error("Unexpected result:", res)
  254. return
  255. }
  256. if _, err := tc.Execute([]interface{}{trans}, nil, mr); err != nil {
  257. t.Error(err)
  258. return
  259. }
  260. // Check that the nodes have been committed
  261. if res := fmt.Sprint(trans.Counts()); res != "0 0 0 0" {
  262. t.Error("Unexpected result:", res)
  263. return
  264. }
  265. if res := gm.EdgeCount("e"); res != 1 {
  266. t.Error("Unexpected result:", res)
  267. return
  268. }
  269. _, err = se.Execute([]interface{}{"main", map[interface{}]interface{}{
  270. "key": "123",
  271. "kind": "e",
  272. "end1cascading": true,
  273. "end1key": "a",
  274. "end1kind": "b",
  275. "end1role": "role1",
  276. "end2cascading": false,
  277. "end2key": "c1",
  278. "end2kind": "d",
  279. "end2role": "role2",
  280. }, trans}, nil, mr)
  281. if _, err := tc.Execute([]interface{}{trans}, nil, mr); err == nil || err.Error() !=
  282. "Invalid construct Cannot store node: GraphError: Invalid data (Can't find edge endpoint: c1 (d))" {
  283. t.Error(err)
  284. return
  285. }
  286. re := &RemoveEdgeFunc{}
  287. if _, err := re.Execute([]interface{}{"main", "123", "e", trans}, nil, mr); err != nil {
  288. t.Error(err)
  289. return
  290. }
  291. if res := fmt.Sprint(trans.Counts()); res != "0 0 0 1" {
  292. t.Error("Unexpected result:", res)
  293. return
  294. }
  295. if _, err := tc.Execute([]interface{}{trans}, nil, mr); err != nil {
  296. t.Error(err)
  297. return
  298. }
  299. if res := fmt.Sprint(trans.Counts()); res != "0 0 0 0" {
  300. t.Error("Unexpected result:", res)
  301. return
  302. }
  303. if res := gm.EdgeCount("e"); res != 0 {
  304. t.Error("Unexpected result:", res)
  305. return
  306. }
  307. }