rest_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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 v1
  11. import (
  12. "bytes"
  13. "encoding/json"
  14. "flag"
  15. "fmt"
  16. "io/ioutil"
  17. "net/http"
  18. "os"
  19. "path/filepath"
  20. "strconv"
  21. "strings"
  22. "sync"
  23. "testing"
  24. "devt.de/krotik/common/errorutil"
  25. "devt.de/krotik/common/fileutil"
  26. "devt.de/krotik/common/httputil"
  27. "devt.de/krotik/eliasdb/api"
  28. "devt.de/krotik/eliasdb/config"
  29. "devt.de/krotik/eliasdb/ecal"
  30. "devt.de/krotik/eliasdb/eql"
  31. "devt.de/krotik/eliasdb/graph"
  32. "devt.de/krotik/eliasdb/graph/data"
  33. "devt.de/krotik/eliasdb/graph/graphstorage"
  34. )
  35. const TESTPORT = ":9090"
  36. var gmMSM *graphstorage.MemoryGraphStorage
  37. const testScriptDir = "testscripts"
  38. // Main function for all tests in this package
  39. func TestMain(m *testing.M) {
  40. flag.Parse()
  41. defer func() {
  42. if res, _ := fileutil.PathExists(testScriptDir); res {
  43. if err := os.RemoveAll(testScriptDir); err != nil {
  44. fmt.Print("Could not remove test directory:", err.Error())
  45. }
  46. }
  47. }()
  48. if res, _ := fileutil.PathExists(testScriptDir); res {
  49. if err := os.RemoveAll(testScriptDir); err != nil {
  50. fmt.Print("Could not remove test directory:", err.Error())
  51. }
  52. }
  53. ensurePath(testScriptDir)
  54. data := make(map[string]interface{})
  55. for k, v := range config.DefaultConfig {
  56. data[k] = v
  57. }
  58. config.Config = data
  59. config.Config[config.EnableECALScripts] = true
  60. config.Config[config.ECALScriptFolder] = testScriptDir
  61. config.Config[config.ECALLogFile] = filepath.Join(testScriptDir, "interpreter.log")
  62. gm, msm := filterGraph()
  63. api.GM = gm
  64. api.GS = msm
  65. gmMSM = msm
  66. resetSI()
  67. hs, wg := startServer()
  68. if hs == nil {
  69. return
  70. }
  71. // Register endpoints for version 1
  72. api.RegisterRestEndpoints(V1EndpointMap)
  73. api.RegisterRestEndpoints(V1PublicEndpointMap)
  74. // Run the tests
  75. m.Run()
  76. // Teardown
  77. stopServer(hs, wg)
  78. }
  79. func TestSwaggerDefs(t *testing.T) {
  80. // Test we can build swagger defs from the endpoint
  81. data := map[string]interface{}{
  82. "paths": map[string]interface{}{},
  83. "definitions": map[string]interface{}{},
  84. }
  85. for _, inst := range V1EndpointMap {
  86. inst().SwaggerDefs(data)
  87. }
  88. }
  89. /*
  90. Send a request to a HTTP test server
  91. */
  92. func sendTestRequest(url string, method string, content []byte) (string, http.Header, string) {
  93. var req *http.Request
  94. var err error
  95. if content != nil {
  96. req, err = http.NewRequest(method, url, bytes.NewBuffer(content))
  97. } else {
  98. req, err = http.NewRequest(method, url, nil)
  99. }
  100. if err != nil {
  101. panic(err)
  102. }
  103. req.Header.Set("Content-Type", "application/json")
  104. client := &http.Client{}
  105. resp, err := client.Do(req)
  106. if err != nil {
  107. panic(err)
  108. }
  109. defer resp.Body.Close()
  110. body, _ := ioutil.ReadAll(resp.Body)
  111. bodyStr := strings.Trim(string(body), " \n")
  112. // Try json decoding first
  113. out := bytes.Buffer{}
  114. err = json.Indent(&out, []byte(bodyStr), "", " ")
  115. if err == nil {
  116. return resp.Status, resp.Header, out.String()
  117. }
  118. // Just return the body
  119. return resp.Status, resp.Header, bodyStr
  120. }
  121. /*
  122. formatJSONString formats a given JSON string.
  123. */
  124. func formatJSONString(str string) string {
  125. out := bytes.Buffer{}
  126. errorutil.AssertOk(json.Indent(&out, []byte(str), "", " "))
  127. return out.String()
  128. }
  129. /*
  130. formatData returns a given datastructure as JSON string.
  131. */
  132. func formatData(data interface{}) string {
  133. actualResultBytes, _ := json.MarshalIndent(data, "", " ")
  134. return string(actualResultBytes)
  135. }
  136. /*
  137. Start a HTTP test server.
  138. */
  139. func startServer() (*httputil.HTTPServer, *sync.WaitGroup) {
  140. hs := &httputil.HTTPServer{}
  141. var wg sync.WaitGroup
  142. wg.Add(1)
  143. go hs.RunHTTPServer(TESTPORT, &wg)
  144. wg.Wait()
  145. // Server is started
  146. if hs.LastError != nil {
  147. panic(hs.LastError)
  148. }
  149. return hs, &wg
  150. }
  151. /*
  152. Stop a started HTTP test server.
  153. */
  154. func stopServer(hs *httputil.HTTPServer, wg *sync.WaitGroup) {
  155. if hs.Running == true {
  156. wg.Add(1)
  157. // Server is shut down
  158. hs.Shutdown()
  159. wg.Wait()
  160. } else {
  161. panic("Server was not running as expected")
  162. }
  163. }
  164. func songGraph() (*graph.Manager, *graphstorage.MemoryGraphStorage) {
  165. mgs := graphstorage.NewMemoryGraphStorage("mystorage")
  166. gm := graph.NewGraphManager(mgs)
  167. constructEdge := func(key string, node1 data.Node, node2 data.Node, number int) data.Edge {
  168. edge := data.NewGraphEdge()
  169. edge.SetAttr("key", key)
  170. edge.SetAttr("kind", "Wrote")
  171. edge.SetAttr(data.EdgeEnd1Key, node1.Key())
  172. edge.SetAttr(data.EdgeEnd1Kind, node1.Kind())
  173. edge.SetAttr(data.EdgeEnd1Role, "Author")
  174. edge.SetAttr(data.EdgeEnd1Cascading, true)
  175. edge.SetAttr(data.EdgeEnd2Key, node2.Key())
  176. edge.SetAttr(data.EdgeEnd2Kind, node2.Kind())
  177. edge.SetAttr(data.EdgeEnd2Role, "Song")
  178. edge.SetAttr(data.EdgeEnd2Cascading, false)
  179. edge.SetAttr("number", number)
  180. return edge
  181. }
  182. storeSong := func(node data.Node, name string, ranking int, number int) {
  183. node3 := data.NewGraphNode()
  184. node3.SetAttr("key", name)
  185. node3.SetAttr("kind", "Song")
  186. node3.SetAttr("name", name)
  187. node3.SetAttr("ranking", ranking)
  188. gm.StoreNode("main", node3)
  189. gm.StoreEdge("main", constructEdge(name, node, node3, number))
  190. }
  191. node0 := data.NewGraphNode()
  192. node0.SetAttr("key", "000")
  193. node0.SetAttr("kind", "Author")
  194. node0.SetAttr("name", "John")
  195. node0.SetAttr("desc", "One of the most popular acoustic artists of the decade and one of its best-selling artists.")
  196. gm.StoreNode("main", node0)
  197. gm.StoreNode("test", node0) // Same node but different partition
  198. gm.StoreNode("_test", node0) // Same node but different (hidden) partition
  199. storeSong(node0, "Aria1", 8, 1)
  200. storeSong(node0, "Aria2", 2, 2)
  201. storeSong(node0, "Aria3", 4, 3)
  202. storeSong(node0, "Aria4", 18, 4)
  203. node1 := data.NewGraphNode()
  204. node1.SetAttr("key", "123")
  205. node1.SetAttr("kind", "Author")
  206. node1.SetAttr("name", "Mike")
  207. gm.StoreNode("main", node1)
  208. storeSong(node1, "LoveSong3", 1, 3)
  209. storeSong(node1, "FightSong4", 3, 4)
  210. storeSong(node1, "DeadSong2", 6, 2)
  211. storeSong(node1, "StrangeSong1", 5, 1)
  212. node2 := data.NewGraphNode()
  213. node2.SetAttr("key", "456")
  214. node2.SetAttr("kind", "Author")
  215. node2.SetAttr("name", "Hans")
  216. gm.StoreNode("main", node2)
  217. storeSong(node2, "MyOnlySong3", 19, 3)
  218. // Create lots of spam nodes
  219. for i := 0; i < 21; i++ {
  220. nodespam := data.NewGraphNode()
  221. nodespam.SetAttr("key", "000"+strconv.Itoa(i))
  222. nodespam.SetAttr("kind", "Spam")
  223. nodespam.SetAttr("name", "Spam"+strconv.Itoa(i))
  224. gm.StoreNode("main", nodespam)
  225. }
  226. return gm, mgs.(*graphstorage.MemoryGraphStorage)
  227. }
  228. func songGraphGroups() (*graph.Manager, *graphstorage.MemoryGraphStorage) {
  229. gm, mgs := songGraph()
  230. node0 := data.NewGraphNode()
  231. node0.SetAttr("key", "Best")
  232. node0.SetAttr("kind", eql.GroupNodeKind)
  233. gm.StoreNode("main", node0)
  234. constructEdge := func(songkey string) data.Edge {
  235. edge := data.NewGraphEdge()
  236. edge.SetAttr("key", songkey)
  237. edge.SetAttr("kind", "Contains")
  238. edge.SetAttr(data.EdgeEnd1Key, node0.Key())
  239. edge.SetAttr(data.EdgeEnd1Kind, node0.Kind())
  240. edge.SetAttr(data.EdgeEnd1Role, "group")
  241. edge.SetAttr(data.EdgeEnd1Cascading, false)
  242. edge.SetAttr(data.EdgeEnd2Key, songkey)
  243. edge.SetAttr(data.EdgeEnd2Kind, "Song")
  244. edge.SetAttr(data.EdgeEnd2Role, "Song")
  245. edge.SetAttr(data.EdgeEnd2Cascading, false)
  246. return edge
  247. }
  248. gm.StoreEdge("main", constructEdge("LoveSong3"))
  249. gm.StoreEdge("main", constructEdge("Aria3"))
  250. gm.StoreEdge("main", constructEdge("MyOnlySong3"))
  251. gm.StoreEdge("main", constructEdge("StrangeSong1"))
  252. // Store additional groups
  253. node0 = data.NewGraphNode()
  254. node0.SetAttr("key", "foo")
  255. node0.SetAttr("kind", eql.GroupNodeKind)
  256. gm.StoreNode("main", node0)
  257. node0 = data.NewGraphNode()
  258. node0.SetAttr("key", "g1")
  259. node0.SetAttr("kind", eql.GroupNodeKind)
  260. gm.StoreNode("main", node0)
  261. node0 = data.NewGraphNode()
  262. node0.SetAttr("key", "g2")
  263. node0.SetAttr("kind", eql.GroupNodeKind)
  264. gm.StoreNode("main", node0)
  265. return gm, mgs
  266. }
  267. func filterGraph() (*graph.Manager, *graphstorage.MemoryGraphStorage) {
  268. gm, mgs := songGraphGroups()
  269. constructNode := func(key, val1, val2, val3 string) data.Node {
  270. node0 := data.NewGraphNode()
  271. node0.SetAttr("key", key)
  272. node0.SetAttr("kind", "filtertest")
  273. node0.SetAttr("val1", val1)
  274. node0.SetAttr("val2", val2)
  275. node0.SetAttr("val3", val3)
  276. return node0
  277. }
  278. gm.StoreNode("main", constructNode("1", "test", "Hans", "foo"))
  279. gm.StoreNode("main", constructNode("2", "test1", "Hans", "foo"))
  280. gm.StoreNode("main", constructNode("3", "test2", "Hans", "foo"))
  281. gm.StoreNode("main", constructNode("4", "test3", "Peter", "foo"))
  282. gm.StoreNode("main", constructNode("5", "test4", "Peter", "foo"))
  283. gm.StoreNode("main", constructNode("6", "test5", "Peter", "foo"))
  284. gm.StoreNode("main", constructNode("7", "test6", "Anna", "foo"))
  285. gm.StoreNode("main", constructNode("8", "test7", "Anna", "foo"))
  286. gm.StoreNode("main", constructNode("9", "test8", "Steve", "foo"))
  287. gm.StoreNode("main", constructNode("10", "test9", "Steve", "foo"))
  288. gm.StoreNode("main", constructNode("11", "test10", "Franz", "foo"))
  289. gm.StoreNode("main", constructNode("12", "test11", "Kevin", "foo"))
  290. gm.StoreNode("main", constructNode("13", "test12", "Kevin", "foo"))
  291. gm.StoreNode("main", constructNode("14", "test13", "Kevin", "foo"))
  292. gm.StoreNode("main", constructNode("15", "test14", "X1", "foo"))
  293. gm.StoreNode("main", constructNode("16", "test15", "X2", "foo"))
  294. gm.StoreNode("main", constructNode("17", "test16", "X3", "foo"))
  295. gm.StoreNode("main", constructNode("18", "test17", "X4", "foo"))
  296. gm.StoreNode("main", constructNode("19", "test18", "X5", "foo"))
  297. return gm, mgs
  298. }
  299. func ensurePath(path string) {
  300. if res, _ := fileutil.PathExists(path); !res {
  301. if err := os.Mkdir(path, 0770); err != nil {
  302. fmt.Print("Could not create directory:", err.Error())
  303. return
  304. }
  305. }
  306. }
  307. func resetSI() {
  308. api.SI = ecal.NewScriptingInterpreter(testScriptDir, api.GM)
  309. }
  310. func writeScript(content string) {
  311. filename := filepath.Join(testScriptDir, config.Str(config.ECALEntryScript))
  312. err := ioutil.WriteFile(
  313. filename,
  314. []byte(content), 0600)
  315. errorutil.AssertOk(err)
  316. os.Remove(config.Str(config.ECALLogFile))
  317. }
  318. func checkLog(expected string) error {
  319. var err error
  320. content, err := ioutil.ReadFile(config.Str(config.ECALLogFile))
  321. if err == nil {
  322. logtext := string(content)
  323. if logtext != expected {
  324. err = fmt.Errorf("Unexpected log text:\n%v", logtext)
  325. }
  326. }
  327. return err
  328. }