interpreter_test.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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 ecal
  11. import (
  12. "flag"
  13. "fmt"
  14. "io/ioutil"
  15. "os"
  16. "path/filepath"
  17. "testing"
  18. "devt.de/krotik/common/errorutil"
  19. "devt.de/krotik/common/fileutil"
  20. "devt.de/krotik/eliasdb/config"
  21. "devt.de/krotik/eliasdb/graph"
  22. "devt.de/krotik/eliasdb/graph/data"
  23. "devt.de/krotik/eliasdb/graph/graphstorage"
  24. )
  25. const testScriptDir = "testscripts"
  26. func TestMain(m *testing.M) {
  27. flag.Parse()
  28. defer func() {
  29. if res, _ := fileutil.PathExists(testScriptDir); res {
  30. if err := os.RemoveAll(testScriptDir); err != nil {
  31. fmt.Print("Could not remove test directory:", err.Error())
  32. }
  33. }
  34. }()
  35. if res, _ := fileutil.PathExists(testScriptDir); res {
  36. if err := os.RemoveAll(testScriptDir); err != nil {
  37. fmt.Print("Could not remove test directory:", err.Error())
  38. }
  39. }
  40. ensurePath(testScriptDir)
  41. data := make(map[string]interface{})
  42. for k, v := range config.DefaultConfig {
  43. data[k] = v
  44. }
  45. config.Config = data
  46. config.Config[config.EnableECALScripts] = true
  47. config.Config[config.ECALScriptFolder] = testScriptDir
  48. config.Config[config.ECALLogFile] = filepath.Join(testScriptDir, "interpreter.log")
  49. // Run the tests
  50. m.Run()
  51. }
  52. /*
  53. ensurePath ensures that a given relative path exists.
  54. */
  55. func ensurePath(path string) {
  56. if res, _ := fileutil.PathExists(path); !res {
  57. if err := os.Mkdir(path, 0770); err != nil {
  58. fmt.Print("Could not create directory:", err.Error())
  59. return
  60. }
  61. }
  62. }
  63. func writeScript(content string) {
  64. filename := filepath.Join(testScriptDir, config.Str(config.ECALEntryScript))
  65. err := ioutil.WriteFile(
  66. filename,
  67. []byte(content), 0600)
  68. errorutil.AssertOk(err)
  69. os.Remove(config.Str(config.ECALLogFile))
  70. }
  71. func checkLog(expected string) error {
  72. var err error
  73. content, err := ioutil.ReadFile(config.Str(config.ECALLogFile))
  74. errorutil.AssertOk(err)
  75. logtext := string(content)
  76. if logtext != expected {
  77. err = fmt.Errorf("Unexpected log text:\n%v", logtext)
  78. }
  79. return err
  80. }
  81. func TestDebugInterpreter(t *testing.T) {
  82. config.Config[config.EnableECALDebugServer] = true
  83. defer func() {
  84. config.Config[config.EnableECALDebugServer] = false
  85. errorutil.AssertOk(os.Remove(config.Str(config.ECALLogFile)))
  86. }()
  87. mgs := graphstorage.NewMemoryGraphStorage("mystorage")
  88. gm := graph.NewGraphManager(mgs)
  89. ds := NewScriptingInterpreter(testScriptDir, gm)
  90. filename := filepath.Join(testScriptDir, config.Str(config.ECALEntryScript))
  91. os.Remove(filename)
  92. if err := ds.Run(); err != nil {
  93. t.Error("Unexpected result:", err)
  94. return
  95. }
  96. }
  97. func TestInterpreter(t *testing.T) {
  98. mgs := graphstorage.NewMemoryGraphStorage("mystorage")
  99. gm := graph.NewGraphManager(mgs)
  100. ds := NewScriptingInterpreter(testScriptDir, gm)
  101. // Test normal log output
  102. writeScript(`
  103. log("test insert")
  104. `)
  105. if err := ds.Run(); err != nil {
  106. t.Error("Unexpected result:", err)
  107. return
  108. }
  109. if err := checkLog(`test insert
  110. `); err != nil {
  111. t.Error(err)
  112. }
  113. // Test stack trace
  114. writeScript(`
  115. raise("some error")
  116. `)
  117. if err := ds.Run(); err == nil || err.Error() != `ECAL error in eliasdb-runtime (testscripts/main.ecal): some error () (Line:2 Pos:1)
  118. raise("some error") (testscripts/main.ecal:2)` {
  119. t.Error("Unexpected result:", err)
  120. return
  121. }
  122. // Test db functions
  123. writeScript(`
  124. db.storeNode("main", {
  125. "key" : "foo",
  126. "kind" : "bar",
  127. "data" : 123,
  128. })
  129. db.storeNode("main", {
  130. "key" : "key2",
  131. "kind" : "kind2",
  132. "data" : 456,
  133. })
  134. db.storeEdge("main", {
  135. "key": "123",
  136. "kind": "myedges",
  137. "end1cascading": true,
  138. "end1key": "foo",
  139. "end1kind": "bar",
  140. "end1role": "role1",
  141. "end2cascading": false,
  142. "end2key": "key2",
  143. "end2kind": "kind2",
  144. "end2role": "role2",
  145. })
  146. [n, e] := db.traverse("main", "key2", "kind2", "role2:myedges:role1:bar")
  147. log("nodes: ", n, " edges: ", e)
  148. `)
  149. // The store statements should trigger the triggerCheck shortcut in the eventbridge
  150. // because no rules are defined to handle the events.
  151. if err := ds.Run(); err != nil {
  152. t.Error("Unexpected result:", err)
  153. return
  154. }
  155. if err := checkLog(`nodes: [
  156. {
  157. "data": 123,
  158. "key": "foo",
  159. "kind": "bar"
  160. }
  161. ] edges: [
  162. {
  163. "end1cascading": false,
  164. "end1key": "key2",
  165. "end1kind": "kind2",
  166. "end1role": "role2",
  167. "end2cascading": true,
  168. "end2key": "foo",
  169. "end2kind": "bar",
  170. "end2role": "role1",
  171. "key": "123",
  172. "kind": "myedges"
  173. }
  174. ]
  175. `); err != nil {
  176. t.Error(err)
  177. }
  178. }
  179. func TestEvents(t *testing.T) {
  180. mgs := graphstorage.NewMemoryGraphStorage("mystorage")
  181. gm := graph.NewGraphManager(mgs)
  182. ds := NewScriptingInterpreter(testScriptDir, gm)
  183. writeScript(`
  184. sink mysink
  185. kindmatch [ "db.*.*" ],
  186. {
  187. log("Got event: ", event)
  188. if event.state["node"] != NULL {
  189. if event.state.node.key == "foo2" {
  190. raise("Oh no")
  191. }
  192. if event.state.node.key == "foo3" {
  193. db.raiseGraphEventHandled()
  194. }
  195. } elif event.state["edge"] != NULL {
  196. if event.state.edge.key == "foo2" {
  197. raise("Oh no edge")
  198. }
  199. if event.state.edge.key == "foo3" and event.kind == "db.edge.created" {
  200. raise("Oh no edge2")
  201. }
  202. if event.state.edge.key == "foo3" and event.kind == "db.edge.updated" {
  203. raise("Oh no edge3")
  204. }
  205. } else {
  206. if event.state.key == "foo3" {
  207. db.raiseGraphEventHandled()
  208. }
  209. }
  210. }
  211. `)
  212. if err := ds.Run(); err != nil {
  213. t.Error("Unexpected result:", err)
  214. return
  215. }
  216. err := gm.StoreNode("main", data.NewGraphNodeFromMap(map[string]interface{}{
  217. "key": "foo",
  218. "kind": "bar",
  219. "data": 123,
  220. }))
  221. errorutil.AssertOk(err)
  222. if err := checkLog(`Got event: {
  223. "kind": "db.node.store",
  224. "name": "EliasDB: db.node.store",
  225. "state": {
  226. "node": {
  227. "data": 123,
  228. "key": "foo",
  229. "kind": "bar"
  230. },
  231. "part": "main",
  232. "trans": {}
  233. }
  234. }
  235. Got event: {
  236. "kind": "db.node.created",
  237. "name": "EliasDB: db.node.created",
  238. "state": {
  239. "node": {
  240. "data": 123,
  241. "key": "foo",
  242. "kind": "bar"
  243. },
  244. "part": "main",
  245. "trans": {}
  246. }
  247. }
  248. `); err != nil {
  249. t.Error(err)
  250. }
  251. // Test raising an error before node storage
  252. err = gm.StoreNode("main", data.NewGraphNodeFromMap(map[string]interface{}{
  253. "key": "foo2",
  254. "kind": "bar",
  255. "data": 123,
  256. }))
  257. if err == nil || err.Error() != `GraphError: Graph rule error (Taskerror:
  258. EliasDB: db.node.store -> mysink : ECAL error in eliasdb-runtime (testscripts/main.ecal): Oh no () (Line:8 Pos:7))` {
  259. t.Error("Unexpected result:", err)
  260. return
  261. }
  262. if res, err := gm.FetchNode("main", "foo2", "bar"); res != nil || err != nil {
  263. t.Error("Unexpected result:", res, err)
  264. return
  265. }
  266. err = gm.UpdateNode("main", data.NewGraphNodeFromMap(map[string]interface{}{
  267. "key": "foo",
  268. "kind": "bar",
  269. "data": 1234,
  270. }))
  271. if err != nil {
  272. t.Error("Unexpected result:", err)
  273. return
  274. }
  275. err = gm.StoreEdge("main", data.NewGraphEdgeFromNode(data.NewGraphNodeFromMap(map[string]interface{}{
  276. "key": "foo2",
  277. "kind": "e",
  278. "end1cascading": true,
  279. "end1key": "a",
  280. "end1kind": "b",
  281. "end1role": "role1",
  282. "end2cascading": false,
  283. "end2key": "c",
  284. "end2kind": "d",
  285. "end2role": "role2",
  286. })))
  287. if err == nil || err.Error() != `GraphError: Graph rule error (Taskerror:
  288. EliasDB: db.edge.store -> mysink : ECAL error in eliasdb-runtime (testscripts/main.ecal): Oh no edge () (Line:15 Pos:7))` {
  289. t.Error("Unexpected result:", err)
  290. return
  291. }
  292. err = gm.StoreEdge("main", data.NewGraphEdgeFromNode(data.NewGraphNodeFromMap(map[string]interface{}{
  293. "key": "foo3",
  294. "kind": "e",
  295. "end1cascading": true,
  296. "end1key": "foo",
  297. "end1kind": "bar",
  298. "end1role": "role1",
  299. "end2cascading": false,
  300. "end2key": "foo",
  301. "end2kind": "bar",
  302. "end2role": "role2",
  303. })))
  304. if err == nil || err.Error() != `GraphError: Graph rule error (Taskerror:
  305. EliasDB: db.edge.created -> mysink : ECAL error in eliasdb-runtime (testscripts/main.ecal): Oh no edge2 () (Line:18 Pos:7))` {
  306. t.Error("Unexpected result:", err)
  307. return
  308. }
  309. err = gm.StoreEdge("main", data.NewGraphEdgeFromNode(data.NewGraphNodeFromMap(map[string]interface{}{
  310. "key": "foo3",
  311. "kind": "e",
  312. "end1cascading": true,
  313. "end1key": "foo",
  314. "end1kind": "bar",
  315. "end1role": "role1",
  316. "end2cascading": false,
  317. "end2key": "foo",
  318. "end2kind": "bar",
  319. "end2role": "role2",
  320. })))
  321. if err == nil || err.Error() != `GraphError: Graph rule error (Taskerror:
  322. EliasDB: db.edge.updated -> mysink : ECAL error in eliasdb-runtime (testscripts/main.ecal): Oh no edge3 () (Line:21 Pos:7))` {
  323. t.Error("Unexpected result:", err)
  324. return
  325. }
  326. // Test preventing node storage without raising an error
  327. err = gm.StoreNode("main", data.NewGraphNodeFromMap(map[string]interface{}{
  328. "key": "foo3",
  329. "kind": "bar",
  330. "data": 123,
  331. }))
  332. if err != nil {
  333. t.Error("Unexpected result:", err)
  334. return
  335. }
  336. if res, err := gm.FetchNode("main", "foo2", "bar"); res != nil || err != nil {
  337. t.Error("Unexpected result:", res, err)
  338. return
  339. }
  340. err = gm.UpdateNode("main", data.NewGraphNodeFromMap(map[string]interface{}{
  341. "key": "foo3",
  342. "kind": "bar",
  343. "data": 123,
  344. }))
  345. if err != nil {
  346. t.Error("Unexpected result:", err)
  347. return
  348. }
  349. _, err = gm.RemoveNode("main", "foo3", "bar")
  350. if err != nil {
  351. t.Error("Unexpected result:", err)
  352. return
  353. }
  354. }