graphdb_linux_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. package graphdb
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "os"
  6. "path"
  7. "runtime"
  8. "strconv"
  9. "testing"
  10. _ "github.com/mattn/go-sqlite3"
  11. )
  12. func newTestDb(t *testing.T) (*Database, string) {
  13. p := path.Join(os.TempDir(), "sqlite.db")
  14. conn, err := sql.Open("sqlite3", p)
  15. db, err := NewDatabase(conn)
  16. if err != nil {
  17. t.Fatal(err)
  18. }
  19. return db, p
  20. }
  21. func destroyTestDb(dbPath string) {
  22. os.Remove(dbPath)
  23. }
  24. func TestNewDatabase(t *testing.T) {
  25. db, dbpath := newTestDb(t)
  26. if db == nil {
  27. t.Fatal("Database should not be nil")
  28. }
  29. db.Close()
  30. defer destroyTestDb(dbpath)
  31. }
  32. func TestCreateRootEntity(t *testing.T) {
  33. db, dbpath := newTestDb(t)
  34. defer destroyTestDb(dbpath)
  35. root := db.RootEntity()
  36. if root == nil {
  37. t.Fatal("Root entity should not be nil")
  38. }
  39. }
  40. func TestGetRootEntity(t *testing.T) {
  41. db, dbpath := newTestDb(t)
  42. defer destroyTestDb(dbpath)
  43. e := db.Get("/")
  44. if e == nil {
  45. t.Fatal("Entity should not be nil")
  46. }
  47. if e.ID() != "0" {
  48. t.Fatalf("Entity id should be 0, got %s", e.ID())
  49. }
  50. }
  51. func TestSetEntityWithDifferentName(t *testing.T) {
  52. db, dbpath := newTestDb(t)
  53. defer destroyTestDb(dbpath)
  54. db.Set("/test", "1")
  55. if _, err := db.Set("/other", "1"); err != nil {
  56. t.Fatal(err)
  57. }
  58. }
  59. func TestSetDuplicateEntity(t *testing.T) {
  60. db, dbpath := newTestDb(t)
  61. defer destroyTestDb(dbpath)
  62. if _, err := db.Set("/foo", "42"); err != nil {
  63. t.Fatal(err)
  64. }
  65. if _, err := db.Set("/foo", "43"); err == nil {
  66. t.Fatalf("Creating an entry with a duplicate path did not cause an error")
  67. }
  68. }
  69. func TestCreateChild(t *testing.T) {
  70. db, dbpath := newTestDb(t)
  71. defer destroyTestDb(dbpath)
  72. child, err := db.Set("/db", "1")
  73. if err != nil {
  74. t.Fatal(err)
  75. }
  76. if child == nil {
  77. t.Fatal("Child should not be nil")
  78. }
  79. if child.ID() != "1" {
  80. t.Fail()
  81. }
  82. }
  83. func TestParents(t *testing.T) {
  84. db, dbpath := newTestDb(t)
  85. defer destroyTestDb(dbpath)
  86. for i := 1; i < 6; i++ {
  87. a := strconv.Itoa(i)
  88. if _, err := db.Set("/"+a, a); err != nil {
  89. t.Fatal(err)
  90. }
  91. }
  92. for i := 6; i < 11; i++ {
  93. a := strconv.Itoa(i)
  94. p := strconv.Itoa(i - 5)
  95. key := fmt.Sprintf("/%s/%s", p, a)
  96. if _, err := db.Set(key, a); err != nil {
  97. t.Fatal(err)
  98. }
  99. parents, err := db.Parents(key)
  100. if err != nil {
  101. t.Fatal(err)
  102. }
  103. if len(parents) != 1 {
  104. t.Fatalf("Expected 1 entry for %s got %d", key, len(parents))
  105. }
  106. if parents[0] != p {
  107. t.Fatalf("ID %s received, %s expected", parents[0], p)
  108. }
  109. }
  110. }
  111. func TestChildren(t *testing.T) {
  112. // TODO Windows: Port this test
  113. if runtime.GOOS == "windows" {
  114. t.Skip("Needs porting to Windows")
  115. }
  116. db, dbpath := newTestDb(t)
  117. defer destroyTestDb(dbpath)
  118. str := "/"
  119. for i := 1; i < 6; i++ {
  120. a := strconv.Itoa(i)
  121. if _, err := db.Set(str+a, a); err != nil {
  122. t.Fatal(err)
  123. }
  124. str = str + a + "/"
  125. }
  126. str = "/"
  127. for i := 10; i < 30; i++ { // 20 entities
  128. a := strconv.Itoa(i)
  129. if _, err := db.Set(str+a, a); err != nil {
  130. t.Fatal(err)
  131. }
  132. str = str + a + "/"
  133. }
  134. entries, err := db.Children("/", 5)
  135. if err != nil {
  136. t.Fatal(err)
  137. }
  138. if len(entries) != 11 {
  139. t.Fatalf("Expect 11 entries for / got %d", len(entries))
  140. }
  141. entries, err = db.Children("/", 20)
  142. if err != nil {
  143. t.Fatal(err)
  144. }
  145. if len(entries) != 25 {
  146. t.Fatalf("Expect 25 entries for / got %d", len(entries))
  147. }
  148. }
  149. func TestListAllRootChildren(t *testing.T) {
  150. // TODO Windows: Port this test
  151. if runtime.GOOS == "windows" {
  152. t.Skip("Needs porting to Windows")
  153. }
  154. db, dbpath := newTestDb(t)
  155. defer destroyTestDb(dbpath)
  156. for i := 1; i < 6; i++ {
  157. a := strconv.Itoa(i)
  158. if _, err := db.Set("/"+a, a); err != nil {
  159. t.Fatal(err)
  160. }
  161. }
  162. entries := db.List("/", -1)
  163. if len(entries) != 5 {
  164. t.Fatalf("Expect 5 entries for / got %d", len(entries))
  165. }
  166. }
  167. func TestListAllSubChildren(t *testing.T) {
  168. // TODO Windows: Port this test
  169. if runtime.GOOS == "windows" {
  170. t.Skip("Needs porting to Windows")
  171. }
  172. db, dbpath := newTestDb(t)
  173. defer destroyTestDb(dbpath)
  174. _, err := db.Set("/webapp", "1")
  175. if err != nil {
  176. t.Fatal(err)
  177. }
  178. child2, err := db.Set("/db", "2")
  179. if err != nil {
  180. t.Fatal(err)
  181. }
  182. child4, err := db.Set("/logs", "4")
  183. if err != nil {
  184. t.Fatal(err)
  185. }
  186. if _, err := db.Set("/db/logs", child4.ID()); err != nil {
  187. t.Fatal(err)
  188. }
  189. child3, err := db.Set("/sentry", "3")
  190. if err != nil {
  191. t.Fatal(err)
  192. }
  193. if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
  194. t.Fatal(err)
  195. }
  196. if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
  197. t.Fatal(err)
  198. }
  199. entries := db.List("/webapp", 1)
  200. if len(entries) != 3 {
  201. t.Fatalf("Expect 3 entries for / got %d", len(entries))
  202. }
  203. entries = db.List("/webapp", 0)
  204. if len(entries) != 2 {
  205. t.Fatalf("Expect 2 entries for / got %d", len(entries))
  206. }
  207. }
  208. func TestAddSelfAsChild(t *testing.T) {
  209. // TODO Windows: Port this test
  210. if runtime.GOOS == "windows" {
  211. t.Skip("Needs porting to Windows")
  212. }
  213. db, dbpath := newTestDb(t)
  214. defer destroyTestDb(dbpath)
  215. child, err := db.Set("/test", "1")
  216. if err != nil {
  217. t.Fatal(err)
  218. }
  219. if _, err := db.Set("/test/other", child.ID()); err == nil {
  220. t.Fatal("Error should not be nil")
  221. }
  222. }
  223. func TestAddChildToNonExistentRoot(t *testing.T) {
  224. db, dbpath := newTestDb(t)
  225. defer destroyTestDb(dbpath)
  226. if _, err := db.Set("/myapp", "1"); err != nil {
  227. t.Fatal(err)
  228. }
  229. if _, err := db.Set("/myapp/proxy/db", "2"); err == nil {
  230. t.Fatal("Error should not be nil")
  231. }
  232. }
  233. func TestWalkAll(t *testing.T) {
  234. // TODO Windows: Port this test
  235. if runtime.GOOS == "windows" {
  236. t.Skip("Needs porting to Windows")
  237. }
  238. db, dbpath := newTestDb(t)
  239. defer destroyTestDb(dbpath)
  240. _, err := db.Set("/webapp", "1")
  241. if err != nil {
  242. t.Fatal(err)
  243. }
  244. child2, err := db.Set("/db", "2")
  245. if err != nil {
  246. t.Fatal(err)
  247. }
  248. child4, err := db.Set("/db/logs", "4")
  249. if err != nil {
  250. t.Fatal(err)
  251. }
  252. if _, err := db.Set("/webapp/logs", child4.ID()); err != nil {
  253. t.Fatal(err)
  254. }
  255. child3, err := db.Set("/sentry", "3")
  256. if err != nil {
  257. t.Fatal(err)
  258. }
  259. if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
  260. t.Fatal(err)
  261. }
  262. if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
  263. t.Fatal(err)
  264. }
  265. child5, err := db.Set("/gograph", "5")
  266. if err != nil {
  267. t.Fatal(err)
  268. }
  269. if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
  270. t.Fatal(err)
  271. }
  272. if err := db.Walk("/", func(p string, e *Entity) error {
  273. t.Logf("Path: %s Entity: %s", p, e.ID())
  274. return nil
  275. }, -1); err != nil {
  276. t.Fatal(err)
  277. }
  278. }
  279. func TestGetEntityByPath(t *testing.T) {
  280. // TODO Windows: Port this test
  281. if runtime.GOOS == "windows" {
  282. t.Skip("Needs porting to Windows")
  283. }
  284. db, dbpath := newTestDb(t)
  285. defer destroyTestDb(dbpath)
  286. _, err := db.Set("/webapp", "1")
  287. if err != nil {
  288. t.Fatal(err)
  289. }
  290. child2, err := db.Set("/db", "2")
  291. if err != nil {
  292. t.Fatal(err)
  293. }
  294. child4, err := db.Set("/logs", "4")
  295. if err != nil {
  296. t.Fatal(err)
  297. }
  298. if _, err := db.Set("/db/logs", child4.ID()); err != nil {
  299. t.Fatal(err)
  300. }
  301. child3, err := db.Set("/sentry", "3")
  302. if err != nil {
  303. t.Fatal(err)
  304. }
  305. if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
  306. t.Fatal(err)
  307. }
  308. if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
  309. t.Fatal(err)
  310. }
  311. child5, err := db.Set("/gograph", "5")
  312. if err != nil {
  313. t.Fatal(err)
  314. }
  315. if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
  316. t.Fatal(err)
  317. }
  318. entity := db.Get("/webapp/db/logs")
  319. if entity == nil {
  320. t.Fatal("Entity should not be nil")
  321. }
  322. if entity.ID() != "4" {
  323. t.Fatalf("Expected to get entity with id 4, got %s", entity.ID())
  324. }
  325. }
  326. func TestEnitiesPaths(t *testing.T) {
  327. // TODO Windows: Port this test
  328. if runtime.GOOS == "windows" {
  329. t.Skip("Needs porting to Windows")
  330. }
  331. db, dbpath := newTestDb(t)
  332. defer destroyTestDb(dbpath)
  333. _, err := db.Set("/webapp", "1")
  334. if err != nil {
  335. t.Fatal(err)
  336. }
  337. child2, err := db.Set("/db", "2")
  338. if err != nil {
  339. t.Fatal(err)
  340. }
  341. child4, err := db.Set("/logs", "4")
  342. if err != nil {
  343. t.Fatal(err)
  344. }
  345. if _, err := db.Set("/db/logs", child4.ID()); err != nil {
  346. t.Fatal(err)
  347. }
  348. child3, err := db.Set("/sentry", "3")
  349. if err != nil {
  350. t.Fatal(err)
  351. }
  352. if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
  353. t.Fatal(err)
  354. }
  355. if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
  356. t.Fatal(err)
  357. }
  358. child5, err := db.Set("/gograph", "5")
  359. if err != nil {
  360. t.Fatal(err)
  361. }
  362. if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
  363. t.Fatal(err)
  364. }
  365. out := db.List("/", -1)
  366. for _, p := range out.Paths() {
  367. t.Log(p)
  368. }
  369. }
  370. func TestDeleteRootEntity(t *testing.T) {
  371. db, dbpath := newTestDb(t)
  372. defer destroyTestDb(dbpath)
  373. if err := db.Delete("/"); err == nil {
  374. t.Fatal("Error should not be nil")
  375. }
  376. }
  377. func TestDeleteEntity(t *testing.T) {
  378. // TODO Windows: Port this test
  379. if runtime.GOOS == "windows" {
  380. t.Skip("Needs porting to Windows")
  381. }
  382. db, dbpath := newTestDb(t)
  383. defer destroyTestDb(dbpath)
  384. _, err := db.Set("/webapp", "1")
  385. if err != nil {
  386. t.Fatal(err)
  387. }
  388. child2, err := db.Set("/db", "2")
  389. if err != nil {
  390. t.Fatal(err)
  391. }
  392. child4, err := db.Set("/logs", "4")
  393. if err != nil {
  394. t.Fatal(err)
  395. }
  396. if _, err := db.Set("/db/logs", child4.ID()); err != nil {
  397. t.Fatal(err)
  398. }
  399. child3, err := db.Set("/sentry", "3")
  400. if err != nil {
  401. t.Fatal(err)
  402. }
  403. if _, err := db.Set("/webapp/sentry", child3.ID()); err != nil {
  404. t.Fatal(err)
  405. }
  406. if _, err := db.Set("/webapp/db", child2.ID()); err != nil {
  407. t.Fatal(err)
  408. }
  409. child5, err := db.Set("/gograph", "5")
  410. if err != nil {
  411. t.Fatal(err)
  412. }
  413. if _, err := db.Set("/webapp/same-ref-diff-name", child5.ID()); err != nil {
  414. t.Fatal(err)
  415. }
  416. if err := db.Delete("/webapp/sentry"); err != nil {
  417. t.Fatal(err)
  418. }
  419. entity := db.Get("/webapp/sentry")
  420. if entity != nil {
  421. t.Fatal("Entity /webapp/sentry should be nil")
  422. }
  423. }
  424. func TestCountRefs(t *testing.T) {
  425. // TODO Windows: Port this test
  426. if runtime.GOOS == "windows" {
  427. t.Skip("Needs porting to Windows")
  428. }
  429. db, dbpath := newTestDb(t)
  430. defer destroyTestDb(dbpath)
  431. db.Set("/webapp", "1")
  432. if db.Refs("1") != 1 {
  433. t.Fatal("Expect reference count to be 1")
  434. }
  435. db.Set("/db", "2")
  436. db.Set("/webapp/db", "2")
  437. if db.Refs("2") != 2 {
  438. t.Fatal("Expect reference count to be 2")
  439. }
  440. }
  441. func TestPurgeId(t *testing.T) {
  442. // TODO Windows: Port this test
  443. if runtime.GOOS == "windows" {
  444. t.Skip("Needs porting to Windows")
  445. }
  446. db, dbpath := newTestDb(t)
  447. defer destroyTestDb(dbpath)
  448. db.Set("/webapp", "1")
  449. if c := db.Refs("1"); c != 1 {
  450. t.Fatalf("Expect reference count to be 1, got %d", c)
  451. }
  452. db.Set("/db", "2")
  453. db.Set("/webapp/db", "2")
  454. count, err := db.Purge("2")
  455. if err != nil {
  456. t.Fatal(err)
  457. }
  458. if count != 2 {
  459. t.Fatalf("Expected 2 references to be removed, got %d", count)
  460. }
  461. }
  462. // Regression test https://github.com/docker/docker/issues/12334
  463. func TestPurgeIdRefPaths(t *testing.T) {
  464. // TODO Windows: Port this test
  465. if runtime.GOOS == "windows" {
  466. t.Skip("Needs porting to Windows")
  467. }
  468. db, dbpath := newTestDb(t)
  469. defer destroyTestDb(dbpath)
  470. db.Set("/webapp", "1")
  471. db.Set("/db", "2")
  472. db.Set("/db/webapp", "1")
  473. if c := db.Refs("1"); c != 2 {
  474. t.Fatalf("Expected 2 reference for webapp, got %d", c)
  475. }
  476. if c := db.Refs("2"); c != 1 {
  477. t.Fatalf("Expected 1 reference for db, got %d", c)
  478. }
  479. if rp := db.RefPaths("2"); len(rp) != 1 {
  480. t.Fatalf("Expected 1 reference path for db, got %d", len(rp))
  481. }
  482. count, err := db.Purge("2")
  483. if err != nil {
  484. t.Fatal(err)
  485. }
  486. if count != 2 {
  487. t.Fatalf("Expected 2 rows to be removed, got %d", count)
  488. }
  489. if c := db.Refs("2"); c != 0 {
  490. t.Fatalf("Expected 0 reference for db, got %d", c)
  491. }
  492. if c := db.Refs("1"); c != 1 {
  493. t.Fatalf("Expected 1 reference for webapp, got %d", c)
  494. }
  495. }
  496. func TestRename(t *testing.T) {
  497. // TODO Windows: Port this test
  498. if runtime.GOOS == "windows" {
  499. t.Skip("Needs porting to Windows")
  500. }
  501. db, dbpath := newTestDb(t)
  502. defer destroyTestDb(dbpath)
  503. db.Set("/webapp", "1")
  504. if db.Refs("1") != 1 {
  505. t.Fatal("Expect reference count to be 1")
  506. }
  507. db.Set("/db", "2")
  508. db.Set("/webapp/db", "2")
  509. if db.Get("/webapp/db") == nil {
  510. t.Fatal("Cannot find entity at path /webapp/db")
  511. }
  512. if err := db.Rename("/webapp/db", "/webapp/newdb"); err != nil {
  513. t.Fatal(err)
  514. }
  515. if db.Get("/webapp/db") != nil {
  516. t.Fatal("Entity should not exist at /webapp/db")
  517. }
  518. if db.Get("/webapp/newdb") == nil {
  519. t.Fatal("Cannot find entity at path /webapp/newdb")
  520. }
  521. }
  522. func TestCreateMultipleNames(t *testing.T) {
  523. // TODO Windows: Port this test
  524. if runtime.GOOS == "windows" {
  525. t.Skip("Needs porting to Windows")
  526. }
  527. db, dbpath := newTestDb(t)
  528. defer destroyTestDb(dbpath)
  529. db.Set("/db", "1")
  530. if _, err := db.Set("/myapp", "1"); err != nil {
  531. t.Fatal(err)
  532. }
  533. db.Walk("/", func(p string, e *Entity) error {
  534. t.Logf("%s\n", p)
  535. return nil
  536. }, -1)
  537. }
  538. func TestRefPaths(t *testing.T) {
  539. db, dbpath := newTestDb(t)
  540. defer destroyTestDb(dbpath)
  541. db.Set("/webapp", "1")
  542. db.Set("/db", "2")
  543. db.Set("/webapp/db", "2")
  544. refs := db.RefPaths("2")
  545. if len(refs) != 2 {
  546. t.Fatalf("Expected reference count to be 2, got %d", len(refs))
  547. }
  548. }
  549. func TestExistsTrue(t *testing.T) {
  550. db, dbpath := newTestDb(t)
  551. defer destroyTestDb(dbpath)
  552. db.Set("/testing", "1")
  553. if !db.Exists("/testing") {
  554. t.Fatalf("/tesing should exist")
  555. }
  556. }
  557. func TestExistsFalse(t *testing.T) {
  558. // TODO Windows: Port this test
  559. if runtime.GOOS == "windows" {
  560. t.Skip("Needs porting to Windows")
  561. }
  562. db, dbpath := newTestDb(t)
  563. defer destroyTestDb(dbpath)
  564. db.Set("/toerhe", "1")
  565. if db.Exists("/testing") {
  566. t.Fatalf("/tesing should not exist")
  567. }
  568. }
  569. func TestGetNameWithTrailingSlash(t *testing.T) {
  570. db, dbpath := newTestDb(t)
  571. defer destroyTestDb(dbpath)
  572. db.Set("/todo", "1")
  573. e := db.Get("/todo/")
  574. if e == nil {
  575. t.Fatalf("Entity should not be nil")
  576. }
  577. }
  578. func TestConcurrentWrites(t *testing.T) {
  579. // TODO Windows: Port this test
  580. if runtime.GOOS == "windows" {
  581. t.Skip("Needs porting to Windows")
  582. }
  583. db, dbpath := newTestDb(t)
  584. defer destroyTestDb(dbpath)
  585. errs := make(chan error, 2)
  586. save := func(name string, id string) {
  587. if _, err := db.Set(fmt.Sprintf("/%s", name), id); err != nil {
  588. errs <- err
  589. }
  590. errs <- nil
  591. }
  592. purge := func(id string) {
  593. if _, err := db.Purge(id); err != nil {
  594. errs <- err
  595. }
  596. errs <- nil
  597. }
  598. save("/1", "1")
  599. go purge("1")
  600. go save("/2", "2")
  601. any := false
  602. for i := 0; i < 2; i++ {
  603. if err := <-errs; err != nil {
  604. any = true
  605. t.Log(err)
  606. }
  607. }
  608. if any {
  609. t.Fail()
  610. }
  611. }