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