github.com/statechannels/buntdb@v0.0.0-20230310210558-7916a96c8fff/buntdb_test.go (about) 1 package buntdb 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io/ioutil" 8 "math/rand" 9 "os" 10 "strconv" 11 "strings" 12 "sync" 13 "testing" 14 "time" 15 16 "github.com/tidwall/assert" 17 "github.com/tidwall/lotsa" 18 ) 19 20 func testOpen(t testing.TB) *DB { 21 if err := os.RemoveAll("data.db"); err != nil { 22 t.Fatal(err) 23 } 24 return testReOpen(t, nil) 25 } 26 func testReOpen(t testing.TB, db *DB) *DB { 27 return testReOpenDelay(t, db, 0) 28 } 29 30 func testReOpenDelay(t testing.TB, db *DB, dur time.Duration) *DB { 31 if db != nil { 32 if err := db.Close(); err != nil { 33 t.Fatal(err) 34 } 35 } 36 time.Sleep(dur) 37 db, err := Open("data.db") 38 if err != nil { 39 t.Fatal(err) 40 } 41 return db 42 } 43 44 func testClose(db *DB) { 45 _ = db.Close() 46 _ = os.RemoveAll("data.db") 47 } 48 49 func TestBackgroudOperations(t *testing.T) { 50 db := testOpen(t) 51 defer testClose(db) 52 for i := 0; i < 1000; i++ { 53 if err := db.Update(func(tx *Tx) error { 54 for j := 0; j < 200; j++ { 55 if _, _, err := tx.Set(fmt.Sprintf("hello%d", j), "planet", nil); err != nil { 56 return err 57 } 58 } 59 if _, _, err := tx.Set("hi", "world", &SetOptions{Expires: true, TTL: time.Second / 2}); err != nil { 60 return err 61 } 62 return nil 63 }); err != nil { 64 t.Fatal(err) 65 } 66 } 67 n := 0 68 err := db.View(func(tx *Tx) error { 69 var err error 70 n, err = tx.Len() 71 return err 72 }) 73 if err != nil { 74 t.Fatal(err) 75 } 76 if n != 201 { 77 t.Fatalf("expecting '%v', got '%v'", 201, n) 78 } 79 time.Sleep(time.Millisecond * 1500) 80 db = testReOpen(t, db) 81 defer testClose(db) 82 n = 0 83 err = db.View(func(tx *Tx) error { 84 var err error 85 n, err = tx.Len() 86 return err 87 }) 88 if err != nil { 89 t.Fatal(err) 90 } 91 if n != 200 { 92 t.Fatalf("expecting '%v', got '%v'", 200, n) 93 } 94 } 95 func TestSaveLoad(t *testing.T) { 96 db, _ := Open(":memory:") 97 defer db.Close() 98 if err := db.Update(func(tx *Tx) error { 99 for i := 0; i < 20; i++ { 100 _, _, err := tx.Set(fmt.Sprintf("key:%d", i), fmt.Sprintf("planet:%d", i), nil) 101 if err != nil { 102 return err 103 } 104 } 105 return nil 106 }); err != nil { 107 t.Fatal(err) 108 } 109 f, err := os.Create("temp.db") 110 if err != nil { 111 t.Fatal(err) 112 } 113 defer func() { 114 f.Close() 115 os.RemoveAll("temp.db") 116 }() 117 if err := db.Save(f); err != nil { 118 t.Fatal(err) 119 } 120 if err := f.Close(); err != nil { 121 t.Fatal(err) 122 } 123 db.Close() 124 db, _ = Open(":memory:") 125 defer db.Close() 126 f, err = os.Open("temp.db") 127 if err != nil { 128 t.Fatal(err) 129 } 130 defer f.Close() 131 if err := db.Load(f); err != nil { 132 t.Fatal(err) 133 } 134 if err := db.View(func(tx *Tx) error { 135 for i := 0; i < 20; i++ { 136 ex := fmt.Sprintf("planet:%d", i) 137 val, err := tx.Get(fmt.Sprintf("key:%d", i)) 138 if err != nil { 139 return err 140 } 141 if ex != val { 142 t.Fatalf("expected %s, got %s", ex, val) 143 } 144 } 145 return nil 146 }); err != nil { 147 t.Fatal(err) 148 } 149 } 150 151 func TestMutatingIterator(t *testing.T) { 152 db := testOpen(t) 153 defer testClose(db) 154 count := 1000 155 if err := db.CreateIndex("ages", "user:*:age", IndexInt); err != nil { 156 t.Fatal(err) 157 } 158 159 for i := 0; i < 10; i++ { 160 if err := db.Update(func(tx *Tx) error { 161 for j := 0; j < count; j++ { 162 key := fmt.Sprintf("user:%d:age", j) 163 val := fmt.Sprintf("%d", rand.Intn(100)) 164 if _, _, err := tx.Set(key, val, nil); err != nil { 165 return err 166 } 167 } 168 return nil 169 }); err != nil { 170 t.Fatal(err) 171 } 172 173 if err := db.Update(func(tx *Tx) error { 174 return tx.Ascend("ages", func(key, val string) bool { 175 _, err := tx.Delete(key) 176 if err != ErrTxIterating { 177 t.Fatal("should not be able to call Delete while iterating.") 178 } 179 _, _, err = tx.Set(key, "", nil) 180 if err != ErrTxIterating { 181 t.Fatal("should not be able to call Set while iterating.") 182 } 183 return true 184 }) 185 }); err != nil { 186 t.Fatal(err) 187 } 188 } 189 } 190 191 func TestCaseInsensitiveIndex(t *testing.T) { 192 db := testOpen(t) 193 defer testClose(db) 194 count := 1000 195 if err := db.Update(func(tx *Tx) error { 196 opts := &IndexOptions{ 197 CaseInsensitiveKeyMatching: true, 198 } 199 return tx.CreateIndexOptions("ages", "User:*:age", opts, IndexInt) 200 }); err != nil { 201 t.Fatal(err) 202 } 203 204 if err := db.Update(func(tx *Tx) error { 205 for j := 0; j < count; j++ { 206 key := fmt.Sprintf("user:%d:age", j) 207 val := fmt.Sprintf("%d", rand.Intn(100)) 208 if _, _, err := tx.Set(key, val, nil); err != nil { 209 return err 210 } 211 } 212 return nil 213 }); err != nil { 214 t.Fatal(err) 215 } 216 217 if err := db.View(func(tx *Tx) error { 218 var vals []string 219 err := tx.Ascend("ages", func(key, value string) bool { 220 vals = append(vals, value) 221 return true 222 }) 223 if err != nil { 224 return err 225 } 226 if len(vals) != count { 227 return fmt.Errorf("expected '%v', got '%v'", count, len(vals)) 228 } 229 return nil 230 }); err != nil { 231 t.Fatal(err) 232 } 233 234 } 235 236 func TestIndexTransaction(t *testing.T) { 237 db := testOpen(t) 238 defer testClose(db) 239 var errFine = errors.New("this is fine") 240 ascend := func(tx *Tx, index string) ([]string, error) { 241 var vals []string 242 if err := tx.Ascend(index, func(key, val string) bool { 243 vals = append(vals, key, val) 244 return true 245 }); err != nil { 246 return nil, err 247 } 248 return vals, nil 249 } 250 ascendEqual := func(tx *Tx, index string, vals []string) error { 251 vals2, err := ascend(tx, index) 252 if err != nil { 253 return err 254 } 255 if len(vals) != len(vals2) { 256 return errors.New("invalid size match") 257 } 258 for i := 0; i < len(vals); i++ { 259 if vals[i] != vals2[i] { 260 return errors.New("invalid order") 261 } 262 } 263 return nil 264 } 265 // test creating an index and adding items 266 if err := db.Update(func(tx *Tx) error { 267 tx.Set("1", "3", nil) 268 tx.Set("2", "2", nil) 269 tx.Set("3", "1", nil) 270 if err := tx.CreateIndex("idx1", "*", IndexInt); err != nil { 271 return err 272 } 273 if err := ascendEqual(tx, "idx1", []string{"3", "1", "2", "2", "1", "3"}); err != nil { 274 return err 275 } 276 return nil 277 }); err != nil { 278 t.Fatal(err) 279 } 280 281 // test to see if the items persisted from previous transaction 282 // test add item. 283 // test force rollback. 284 if err := db.Update(func(tx *Tx) error { 285 if err := ascendEqual(tx, "idx1", []string{"3", "1", "2", "2", "1", "3"}); err != nil { 286 return err 287 } 288 tx.Set("4", "0", nil) 289 if err := ascendEqual(tx, "idx1", []string{"4", "0", "3", "1", "2", "2", "1", "3"}); err != nil { 290 return err 291 } 292 return errFine 293 }); err != errFine { 294 t.Fatalf("expected '%v', got '%v'", errFine, err) 295 } 296 297 // test to see if the rollback happened 298 if err := db.View(func(tx *Tx) error { 299 if err := ascendEqual(tx, "idx1", []string{"3", "1", "2", "2", "1", "3"}); err != nil { 300 return err 301 } 302 return nil 303 }); err != nil { 304 t.Fatalf("expected '%v', got '%v'", nil, err) 305 } 306 307 // del item, drop index, rollback 308 if err := db.Update(func(tx *Tx) error { 309 if err := tx.DropIndex("idx1"); err != nil { 310 return err 311 } 312 return errFine 313 }); err != errFine { 314 t.Fatalf("expected '%v', got '%v'", errFine, err) 315 } 316 317 // test to see if the rollback happened 318 if err := db.View(func(tx *Tx) error { 319 if err := ascendEqual(tx, "idx1", []string{"3", "1", "2", "2", "1", "3"}); err != nil { 320 return err 321 } 322 return nil 323 }); err != nil { 324 t.Fatalf("expected '%v', got '%v'", nil, err) 325 } 326 327 various := func(reterr error) error { 328 // del item 3, add index 2, add item 4, test index 1 and 2. 329 // flushdb, test index 1 and 2. 330 // add item 1 and 2, add index 2 and 3, test index 2 and 3 331 return db.Update(func(tx *Tx) error { 332 tx.Delete("3") 333 tx.CreateIndex("idx2", "*", IndexInt) 334 tx.Set("4", "0", nil) 335 if err := ascendEqual(tx, "idx1", []string{"4", "0", "2", "2", "1", "3"}); err != nil { 336 return fmt.Errorf("err: %v", err) 337 } 338 if err := ascendEqual(tx, "idx2", []string{"4", "0", "2", "2", "1", "3"}); err != nil { 339 return fmt.Errorf("err: %v", err) 340 } 341 tx.DeleteAll() 342 if err := ascendEqual(tx, "idx1", []string{}); err != nil { 343 return fmt.Errorf("err: %v", err) 344 } 345 if err := ascendEqual(tx, "idx2", []string{}); err != nil { 346 return fmt.Errorf("err: %v", err) 347 } 348 tx.Set("1", "3", nil) 349 tx.Set("2", "2", nil) 350 tx.CreateIndex("idx1", "*", IndexInt) 351 tx.CreateIndex("idx2", "*", IndexInt) 352 if err := ascendEqual(tx, "idx1", []string{"2", "2", "1", "3"}); err != nil { 353 return fmt.Errorf("err: %v", err) 354 } 355 if err := ascendEqual(tx, "idx2", []string{"2", "2", "1", "3"}); err != nil { 356 return fmt.Errorf("err: %v", err) 357 } 358 return reterr 359 }) 360 } 361 // various rollback 362 if err := various(errFine); err != errFine { 363 t.Fatalf("expected '%v', got '%v'", errFine, err) 364 } 365 // test to see if the rollback happened 366 if err := db.View(func(tx *Tx) error { 367 if err := ascendEqual(tx, "idx1", []string{"3", "1", "2", "2", "1", "3"}); err != nil { 368 return fmt.Errorf("err: %v", err) 369 } 370 if err := ascendEqual(tx, "idx2", []string{"3", "1", "2", "2", "1", "3"}); err != ErrNotFound { 371 return fmt.Errorf("err: %v", err) 372 } 373 return nil 374 }); err != nil { 375 t.Fatalf("expected '%v', got '%v'", nil, err) 376 } 377 378 // various commit 379 if err := various(nil); err != nil { 380 t.Fatalf("expected '%v', got '%v'", nil, err) 381 } 382 383 // test to see if the commit happened 384 if err := db.View(func(tx *Tx) error { 385 if err := ascendEqual(tx, "idx1", []string{"2", "2", "1", "3"}); err != nil { 386 return fmt.Errorf("err: %v", err) 387 } 388 if err := ascendEqual(tx, "idx2", []string{"2", "2", "1", "3"}); err != nil { 389 return fmt.Errorf("err: %v", err) 390 } 391 return nil 392 }); err != nil { 393 t.Fatalf("expected '%v', got '%v'", nil, err) 394 } 395 } 396 397 func TestDeleteAll(t *testing.T) { 398 db := testOpen(t) 399 defer testClose(db) 400 401 db.Update(func(tx *Tx) error { 402 tx.Set("hello1", "planet1", nil) 403 tx.Set("hello2", "planet2", nil) 404 tx.Set("hello3", "planet3", nil) 405 return nil 406 }) 407 db.CreateIndex("all", "*", IndexString) 408 db.Update(func(tx *Tx) error { 409 tx.Set("hello1", "planet1.1", nil) 410 tx.DeleteAll() 411 tx.Set("bb", "11", nil) 412 tx.Set("aa", "**", nil) 413 tx.Delete("aa") 414 tx.Set("aa", "22", nil) 415 return nil 416 }) 417 var res string 418 var res2 string 419 db.View(func(tx *Tx) error { 420 tx.Ascend("", func(key, val string) bool { 421 res += key + ":" + val + "\n" 422 return true 423 }) 424 tx.Ascend("all", func(key, val string) bool { 425 res2 += key + ":" + val + "\n" 426 return true 427 }) 428 return nil 429 }) 430 if res != "aa:22\nbb:11\n" { 431 t.Fatal("fail") 432 } 433 if res2 != "bb:11\naa:22\n" { 434 t.Fatal("fail") 435 } 436 db = testReOpen(t, db) 437 defer testClose(db) 438 res = "" 439 res2 = "" 440 db.CreateIndex("all", "*", IndexString) 441 db.View(func(tx *Tx) error { 442 tx.Ascend("", func(key, val string) bool { 443 res += key + ":" + val + "\n" 444 return true 445 }) 446 tx.Ascend("all", func(key, val string) bool { 447 res2 += key + ":" + val + "\n" 448 return true 449 }) 450 return nil 451 }) 452 if res != "aa:22\nbb:11\n" { 453 t.Fatal("fail") 454 } 455 if res2 != "bb:11\naa:22\n" { 456 t.Fatal("fail") 457 } 458 db.Update(func(tx *Tx) error { 459 tx.Set("1", "1", nil) 460 tx.Set("2", "2", nil) 461 tx.Set("3", "3", nil) 462 tx.Set("4", "4", nil) 463 return nil 464 }) 465 err := db.Update(func(tx *Tx) error { 466 tx.Set("1", "a", nil) 467 tx.Set("5", "5", nil) 468 tx.Delete("2") 469 tx.Set("6", "6", nil) 470 tx.DeleteAll() 471 tx.Set("7", "7", nil) 472 tx.Set("8", "8", nil) 473 tx.Set("6", "c", nil) 474 return errors.New("please rollback") 475 }) 476 if err == nil || err.Error() != "please rollback" { 477 t.Fatal("expecteding 'please rollback' error") 478 } 479 480 res = "" 481 res2 = "" 482 db.View(func(tx *Tx) error { 483 tx.Ascend("", func(key, val string) bool { 484 res += key + ":" + val + "\n" 485 return true 486 }) 487 tx.Ascend("all", func(key, val string) bool { 488 res2 += key + ":" + val + "\n" 489 return true 490 }) 491 return nil 492 }) 493 if res != "1:1\n2:2\n3:3\n4:4\naa:22\nbb:11\n" { 494 t.Fatal("fail") 495 } 496 if res2 != "1:1\nbb:11\n2:2\naa:22\n3:3\n4:4\n" { 497 t.Fatal("fail") 498 } 499 } 500 501 func TestAscendEqual(t *testing.T) { 502 db := testOpen(t) 503 defer testClose(db) 504 if err := db.Update(func(tx *Tx) error { 505 for i := 0; i < 300; i++ { 506 _, _, err := tx.Set(fmt.Sprintf("key:%05dA", i), fmt.Sprintf("%d", i+1000), nil) 507 if err != nil { 508 return err 509 } 510 _, _, err = tx.Set(fmt.Sprintf("key:%05dB", i), fmt.Sprintf("%d", i+1000), nil) 511 if err != nil { 512 return err 513 } 514 } 515 return tx.CreateIndex("num", "*", IndexInt) 516 }); err != nil { 517 t.Fatal(err) 518 } 519 var res []string 520 if err := db.View(func(tx *Tx) error { 521 return tx.AscendEqual("", "key:00055A", func(key, value string) bool { 522 res = append(res, key) 523 return true 524 }) 525 }); err != nil { 526 t.Fatal(err) 527 } 528 if len(res) != 1 { 529 t.Fatalf("expected %v, got %v", 1, len(res)) 530 } 531 if res[0] != "key:00055A" { 532 t.Fatalf("expected %v, got %v", "key:00055A", res[0]) 533 } 534 res = nil 535 if err := db.View(func(tx *Tx) error { 536 return tx.AscendEqual("num", "1125", func(key, value string) bool { 537 res = append(res, key) 538 return true 539 }) 540 }); err != nil { 541 t.Fatal(err) 542 } 543 if len(res) != 2 { 544 t.Fatalf("expected %v, got %v", 2, len(res)) 545 } 546 if res[0] != "key:00125A" { 547 t.Fatalf("expected %v, got %v", "key:00125A", res[0]) 548 } 549 if res[1] != "key:00125B" { 550 t.Fatalf("expected %v, got %v", "key:00125B", res[1]) 551 } 552 } 553 func TestDescendEqual(t *testing.T) { 554 db := testOpen(t) 555 defer testClose(db) 556 if err := db.Update(func(tx *Tx) error { 557 for i := 0; i < 300; i++ { 558 _, _, err := tx.Set(fmt.Sprintf("key:%05dA", i), fmt.Sprintf("%d", i+1000), nil) 559 if err != nil { 560 return err 561 } 562 _, _, err = tx.Set(fmt.Sprintf("key:%05dB", i), fmt.Sprintf("%d", i+1000), nil) 563 if err != nil { 564 return err 565 } 566 } 567 return tx.CreateIndex("num", "*", IndexInt) 568 }); err != nil { 569 t.Fatal(err) 570 } 571 var res []string 572 if err := db.View(func(tx *Tx) error { 573 return tx.DescendEqual("", "key:00055A", func(key, value string) bool { 574 res = append(res, key) 575 return true 576 }) 577 }); err != nil { 578 t.Fatal(err) 579 } 580 if len(res) != 1 { 581 t.Fatalf("expected %v, got %v", 1, len(res)) 582 } 583 if res[0] != "key:00055A" { 584 t.Fatalf("expected %v, got %v", "key:00055A", res[0]) 585 } 586 res = nil 587 if err := db.View(func(tx *Tx) error { 588 return tx.DescendEqual("num", "1125", func(key, value string) bool { 589 res = append(res, key) 590 return true 591 }) 592 }); err != nil { 593 t.Fatal(err) 594 } 595 if len(res) != 2 { 596 t.Fatalf("expected %v, got %v", 2, len(res)) 597 } 598 if res[0] != "key:00125B" { 599 t.Fatalf("expected %v, got %v", "key:00125B", res[0]) 600 } 601 if res[1] != "key:00125A" { 602 t.Fatalf("expected %v, got %v", "key:00125A", res[1]) 603 } 604 } 605 func TestVariousTx(t *testing.T) { 606 db := testOpen(t) 607 defer testClose(db) 608 if err := db.Update(func(tx *Tx) error { 609 _, _, err := tx.Set("hello", "planet", nil) 610 return err 611 }); err != nil { 612 t.Fatal(err) 613 } 614 errBroken := errors.New("broken") 615 if err := db.Update(func(tx *Tx) error { 616 _, _, _ = tx.Set("hello", "world", nil) 617 return errBroken 618 }); err != errBroken { 619 t.Fatalf("did not correctly receive the user-defined transaction error.") 620 } 621 var val string 622 err := db.View(func(tx *Tx) error { 623 var err error 624 val, err = tx.Get("hello") 625 return err 626 }) 627 if err != nil { 628 t.Fatal(err) 629 } 630 if val == "world" { 631 t.Fatal("a rollbacked transaction got through") 632 } 633 if val != "planet" { 634 t.Fatalf("expecting '%v', got '%v'", "planet", val) 635 } 636 if err := db.Update(func(tx *Tx) error { 637 tx.db = nil 638 if _, _, err := tx.Set("hello", "planet", nil); err != ErrTxClosed { 639 t.Fatal("expecting a tx closed error") 640 } 641 if _, err := tx.Delete("hello"); err != ErrTxClosed { 642 t.Fatal("expecting a tx closed error") 643 } 644 if _, err := tx.Get("hello"); err != ErrTxClosed { 645 t.Fatal("expecting a tx closed error") 646 } 647 tx.db = db 648 tx.writable = false 649 if _, _, err := tx.Set("hello", "planet", nil); err != ErrTxNotWritable { 650 t.Fatal("expecting a tx not writable error") 651 } 652 if _, err := tx.Delete("hello"); err != ErrTxNotWritable { 653 t.Fatal("expecting a tx not writable error") 654 } 655 tx.writable = true 656 if _, err := tx.Get("something"); err != ErrNotFound { 657 t.Fatalf("expecting not found error") 658 } 659 if _, err := tx.Delete("something"); err != ErrNotFound { 660 t.Fatalf("expecting not found error") 661 } 662 if _, _, err := tx.Set("var", "val", &SetOptions{Expires: true, TTL: 0}); err != nil { 663 t.Fatal(err) 664 } 665 if _, err := tx.Get("var"); err != ErrNotFound { 666 t.Fatalf("expecting not found error") 667 } 668 if _, err := tx.Delete("var"); err != ErrNotFound { 669 tx.unlock() 670 t.Fatalf("expecting not found error") 671 } 672 return nil 673 }); err != nil { 674 t.Fatal(err) 675 } 676 677 // test non-managed transactions 678 tx, err := db.Begin(true) 679 if err != nil { 680 t.Fatal(err) 681 } 682 defer tx.Rollback() 683 _, _, err = tx.Set("howdy", "world", nil) 684 if err != nil { 685 t.Fatal(err) 686 } 687 if err := tx.Commit(); err != nil { 688 t.Fatal(err) 689 } 690 tx, err = db.Begin(false) 691 if err != nil { 692 t.Fatal(err) 693 } 694 defer tx.Rollback() 695 v, err := tx.Get("howdy") 696 if err != nil { 697 t.Fatal(err) 698 } 699 if v != "world" { 700 t.Fatalf("expecting '%v', got '%v'", "world", v) 701 } 702 if err := tx.Rollback(); err != nil { 703 t.Fatal(err) 704 } 705 tx, err = db.Begin(true) 706 if err != nil { 707 t.Fatal(err) 708 } 709 defer tx.Rollback() 710 v, err = tx.Get("howdy") 711 if err != nil { 712 t.Fatal(err) 713 } 714 if v != "world" { 715 t.Fatalf("expecting '%v', got '%v'", "world", v) 716 } 717 _, err = tx.Delete("howdy") 718 if err != nil { 719 t.Fatal(err) 720 } 721 if err := tx.Commit(); err != nil { 722 t.Fatal(err) 723 } 724 725 // test for invalid commits 726 if err := db.Update(func(tx *Tx) error { 727 // we are going to do some hackery 728 defer func() { 729 if v := recover(); v != nil { 730 if v.(string) != "managed tx commit not allowed" { 731 t.Fatal(v.(string)) 732 } 733 } 734 }() 735 return tx.Commit() 736 }); err != nil { 737 t.Fatal(err) 738 } 739 740 // test for invalid commits 741 if err := db.Update(func(tx *Tx) error { 742 // we are going to do some hackery 743 defer func() { 744 if v := recover(); v != nil { 745 if v.(string) != "managed tx rollback not allowed" { 746 t.Fatal(v.(string)) 747 } 748 } 749 }() 750 return tx.Rollback() 751 }); err != nil { 752 t.Fatal(err) 753 } 754 755 // test for closed transactions 756 if err := db.Update(func(tx *Tx) error { 757 tx.db = nil 758 return nil 759 }); err != ErrTxClosed { 760 t.Fatal("expecting tx closed error") 761 } 762 db.mu.Unlock() 763 764 // test for invalid writes 765 if err := db.Update(func(tx *Tx) error { 766 tx.writable = false 767 return nil 768 }); err != ErrTxNotWritable { 769 t.Fatal("expecting tx not writable error") 770 } 771 db.mu.Unlock() 772 // test for closed transactions 773 if err := db.View(func(tx *Tx) error { 774 tx.db = nil 775 return nil 776 }); err != ErrTxClosed { 777 t.Fatal("expecting tx closed error") 778 } 779 db.mu.RUnlock() 780 // flush to unwritable file 781 if err := db.Update(func(tx *Tx) error { 782 _, _, err := tx.Set("var1", "val1", nil) 783 if err != nil { 784 t.Fatal(err) 785 } 786 return tx.db.file.Close() 787 }); err == nil { 788 t.Fatal("should not be able to commit when the file is closed") 789 } 790 db.file, err = os.OpenFile("data.db", os.O_CREATE|os.O_RDWR, 0666) 791 if err != nil { 792 t.Fatal(err) 793 } 794 if _, err := db.file.Seek(0, 2); err != nil { 795 t.Fatal(err) 796 } 797 db.buf = nil 798 if err := db.CreateIndex("blank", "*", nil); err != nil { 799 t.Fatal(err) 800 } 801 if err := db.CreateIndex("real", "*", IndexInt); err != nil { 802 t.Fatal(err) 803 } 804 // test scanning 805 if err := db.Update(func(tx *Tx) error { 806 less, err := tx.GetLess("junk") 807 if err != ErrNotFound { 808 t.Fatalf("expecting a not found, got %v", err) 809 } 810 if less != nil { 811 t.Fatal("expecting nil, got a less function") 812 } 813 less, err = tx.GetLess("blank") 814 if err != ErrNotFound { 815 t.Fatalf("expecting a not found, got %v", err) 816 } 817 if less != nil { 818 t.Fatal("expecting nil, got a less function") 819 } 820 less, err = tx.GetLess("real") 821 if err != nil { 822 return err 823 } 824 if less == nil { 825 t.Fatal("expecting a less function, got nil") 826 } 827 _, _, err = tx.Set("nothing", "here", nil) 828 return err 829 }); err != nil { 830 t.Fatal(err) 831 } 832 if err := db.View(func(tx *Tx) error { 833 s := "" 834 err := tx.Ascend("", func(key, val string) bool { 835 s += key + ":" + val + "\n" 836 return true 837 }) 838 if err != nil { 839 return err 840 } 841 if s != "hello:planet\nnothing:here\n" { 842 t.Fatal("invalid scan") 843 } 844 tx.db = nil 845 err = tx.Ascend("", func(key, val string) bool { return true }) 846 if err != ErrTxClosed { 847 tx.unlock() 848 t.Fatal("expecting tx closed error") 849 } 850 tx.db = db 851 err = tx.Ascend("na", func(key, val string) bool { return true }) 852 if err != ErrNotFound { 853 t.Fatal("expecting not found error") 854 } 855 err = tx.Ascend("blank", func(key, val string) bool { return true }) 856 if err != nil { 857 t.Fatal(err) 858 } 859 s = "" 860 err = tx.AscendLessThan("", "liger", func(key, val string) bool { 861 s += key + ":" + val + "\n" 862 return true 863 }) 864 if err != nil { 865 return err 866 } 867 if s != "hello:planet\n" { 868 t.Fatal("invalid scan") 869 } 870 871 s = "" 872 err = tx.Descend("", func(key, val string) bool { 873 s += key + ":" + val + "\n" 874 return true 875 }) 876 if err != nil { 877 return err 878 } 879 if s != "nothing:here\nhello:planet\n" { 880 t.Fatal("invalid scan") 881 } 882 883 s = "" 884 err = tx.DescendLessOrEqual("", "liger", func(key, val string) bool { 885 s += key + ":" + val + "\n" 886 return true 887 }) 888 if err != nil { 889 return err 890 } 891 892 if s != "hello:planet\n" { 893 t.Fatal("invalid scan") 894 } 895 896 s = "" 897 err = tx.DescendGreaterThan("", "liger", func(key, val string) bool { 898 s += key + ":" + val + "\n" 899 return true 900 }) 901 if err != nil { 902 return err 903 } 904 905 if s != "nothing:here\n" { 906 t.Fatal("invalid scan") 907 } 908 s = "" 909 err = tx.DescendRange("", "liger", "apple", func(key, val string) bool { 910 s += key + ":" + val + "\n" 911 return true 912 }) 913 if err != nil { 914 return err 915 } 916 if s != "hello:planet\n" { 917 t.Fatal("invalid scan") 918 } 919 return nil 920 }); err != nil { 921 t.Fatal(err) 922 } 923 924 // test some spatial stuff 925 if err := db.CreateSpatialIndex("spat", "rect:*", IndexRect); err != nil { 926 t.Fatal(err) 927 } 928 if err := db.CreateSpatialIndex("junk", "rect:*", nil); err != nil { 929 t.Fatal(err) 930 } 931 err = db.Update(func(tx *Tx) error { 932 rect, err := tx.GetRect("spat") 933 if err != nil { 934 return err 935 } 936 if rect == nil { 937 t.Fatal("expecting a rect function, got nil") 938 } 939 rect, err = tx.GetRect("junk") 940 if err != ErrNotFound { 941 t.Fatalf("expecting a not found, got %v", err) 942 } 943 if rect != nil { 944 t.Fatal("expecting nil, got a rect function") 945 } 946 rect, err = tx.GetRect("na") 947 if err != ErrNotFound { 948 t.Fatalf("expecting a not found, got %v", err) 949 } 950 if rect != nil { 951 t.Fatal("expecting nil, got a rect function") 952 } 953 if _, _, err := tx.Set("rect:1", "[10 10],[20 20]", nil); err != nil { 954 return err 955 } 956 if _, _, err := tx.Set("rect:2", "[15 15],[25 25]", nil); err != nil { 957 return err 958 } 959 if _, _, err := tx.Set("shape:1", "[12 12],[25 25]", nil); err != nil { 960 return err 961 } 962 s := "" 963 err = tx.Intersects("spat", "[5 5],[13 13]", func(key, val string) bool { 964 s += key + ":" + val + "\n" 965 return true 966 }) 967 if err != nil { 968 return err 969 } 970 if s != "rect:1:[10 10],[20 20]\n" { 971 t.Fatal("invalid scan") 972 } 973 tx.db = nil 974 err = tx.Intersects("spat", "[5 5],[13 13]", func(key, val string) bool { 975 return true 976 }) 977 if err != ErrTxClosed { 978 t.Fatal("expecting tx closed error") 979 } 980 tx.db = db 981 err = tx.Intersects("", "[5 5],[13 13]", func(key, val string) bool { 982 return true 983 }) 984 if err != nil { 985 t.Fatal(err) 986 } 987 err = tx.Intersects("na", "[5 5],[13 13]", func(key, val string) bool { 988 return true 989 }) 990 if err != ErrNotFound { 991 t.Fatal("expecting not found error") 992 } 993 err = tx.Intersects("junk", "[5 5],[13 13]", func(key, val string) bool { 994 return true 995 }) 996 if err != nil { 997 t.Fatal(err) 998 } 999 n, err := tx.Len() 1000 if err != nil { 1001 t.Fatal(err) 1002 } 1003 if n != 5 { 1004 t.Fatalf("expecting %v, got %v", 5, n) 1005 } 1006 tx.db = nil 1007 _, err = tx.Len() 1008 if err != ErrTxClosed { 1009 t.Fatal("expecting tx closed error") 1010 } 1011 tx.db = db 1012 return nil 1013 }) 1014 if err != nil { 1015 t.Fatal(err) 1016 } 1017 // test after closing 1018 if err := db.Close(); err != nil { 1019 t.Fatal(err) 1020 } 1021 1022 if err := db.Update(func(tx *Tx) error { return nil }); err != ErrDatabaseClosed { 1023 t.Fatalf("should not be able to perform transactionso on a closed database.") 1024 } 1025 } 1026 1027 func TestNearby(t *testing.T) { 1028 rand.Seed(time.Now().UnixNano()) 1029 N := 100000 1030 db, _ := Open(":memory:") 1031 db.CreateSpatialIndex("points", "*", IndexRect) 1032 db.Update(func(tx *Tx) error { 1033 for i := 0; i < N; i++ { 1034 p := Point( 1035 rand.Float64()*100, 1036 rand.Float64()*100, 1037 rand.Float64()*100, 1038 rand.Float64()*100, 1039 ) 1040 tx.Set(fmt.Sprintf("p:%d", i), p, nil) 1041 } 1042 return nil 1043 }) 1044 var keys, values []string 1045 var dists []float64 1046 var pdist float64 1047 var i int 1048 db.View(func(tx *Tx) error { 1049 tx.Nearby("points", Point(0, 0, 0, 0), func(key, value string, dist float64) bool { 1050 if i != 0 && dist < pdist { 1051 t.Fatal("out of order") 1052 } 1053 keys = append(keys, key) 1054 values = append(values, value) 1055 dists = append(dists, dist) 1056 pdist = dist 1057 i++ 1058 return true 1059 }) 1060 return nil 1061 }) 1062 if len(keys) != N { 1063 t.Fatalf("expected '%v', got '%v'", N, len(keys)) 1064 } 1065 } 1066 1067 func Example_descKeys() { 1068 db, _ := Open(":memory:") 1069 db.CreateIndex("name", "*", IndexString) 1070 db.Update(func(tx *Tx) error { 1071 tx.Set("user:100:first", "Tom", nil) 1072 tx.Set("user:100:last", "Johnson", nil) 1073 tx.Set("user:101:first", "Janet", nil) 1074 tx.Set("user:101:last", "Prichard", nil) 1075 tx.Set("user:102:first", "Alan", nil) 1076 tx.Set("user:102:last", "Cooper", nil) 1077 return nil 1078 }) 1079 db.View(func(tx *Tx) error { 1080 tx.AscendKeys("user:101:*", 1081 func(key, value string) bool { 1082 fmt.Printf("%s: %s\n", key, value) 1083 return true 1084 }) 1085 tx.AscendKeys("user:10?:*", 1086 func(key, value string) bool { 1087 fmt.Printf("%s: %s\n", key, value) 1088 return true 1089 }) 1090 tx.AscendKeys("*2*", 1091 func(key, value string) bool { 1092 fmt.Printf("%s: %s\n", key, value) 1093 return true 1094 }) 1095 tx.DescendKeys("user:101:*", 1096 func(key, value string) bool { 1097 fmt.Printf("%s: %s\n", key, value) 1098 return true 1099 }) 1100 tx.DescendKeys("*", 1101 func(key, value string) bool { 1102 fmt.Printf("%s: %s\n", key, value) 1103 return true 1104 }) 1105 return nil 1106 }) 1107 1108 // Output: 1109 // user:101:first: Janet 1110 // user:101:last: Prichard 1111 // user:100:first: Tom 1112 // user:100:last: Johnson 1113 // user:101:first: Janet 1114 // user:101:last: Prichard 1115 // user:102:first: Alan 1116 // user:102:last: Cooper 1117 // user:102:first: Alan 1118 // user:102:last: Cooper 1119 // user:101:last: Prichard 1120 // user:101:first: Janet 1121 // user:102:last: Cooper 1122 // user:102:first: Alan 1123 // user:101:last: Prichard 1124 // user:101:first: Janet 1125 // user:100:last: Johnson 1126 // user:100:first: Tom 1127 } 1128 1129 func ExampleDesc() { 1130 db, _ := Open(":memory:") 1131 db.CreateIndex("last_name_age", "*", IndexJSON("name.last"), Desc(IndexJSON("age"))) 1132 db.Update(func(tx *Tx) error { 1133 tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38}`, nil) 1134 tx.Set("2", `{"name":{"first":"Janet","last":"Prichard"},"age":47}`, nil) 1135 tx.Set("3", `{"name":{"first":"Carol","last":"Anderson"},"age":52}`, nil) 1136 tx.Set("4", `{"name":{"first":"Alan","last":"Cooper"},"age":28}`, nil) 1137 tx.Set("5", `{"name":{"first":"Sam","last":"Anderson"},"age":51}`, nil) 1138 tx.Set("6", `{"name":{"first":"Melinda","last":"Prichard"},"age":44}`, nil) 1139 return nil 1140 }) 1141 db.View(func(tx *Tx) error { 1142 tx.Ascend("last_name_age", func(key, value string) bool { 1143 fmt.Printf("%s: %s\n", key, value) 1144 return true 1145 }) 1146 return nil 1147 }) 1148 1149 // Output: 1150 //3: {"name":{"first":"Carol","last":"Anderson"},"age":52} 1151 //5: {"name":{"first":"Sam","last":"Anderson"},"age":51} 1152 //4: {"name":{"first":"Alan","last":"Cooper"},"age":28} 1153 //1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1154 //2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1155 //6: {"name":{"first":"Melinda","last":"Prichard"},"age":44} 1156 } 1157 1158 func ExampleDB_CreateIndex_jSON() { 1159 db, _ := Open(":memory:") 1160 db.CreateIndex("last_name", "*", IndexJSON("name.last")) 1161 db.CreateIndex("age", "*", IndexJSON("age")) 1162 db.Update(func(tx *Tx) error { 1163 tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38}`, nil) 1164 tx.Set("2", `{"name":{"first":"Janet","last":"Prichard"},"age":47}`, nil) 1165 tx.Set("3", `{"name":{"first":"Carol","last":"Anderson"},"age":52}`, nil) 1166 tx.Set("4", `{"name":{"first":"Alan","last":"Cooper"},"age":28}`, nil) 1167 return nil 1168 }) 1169 db.View(func(tx *Tx) error { 1170 fmt.Println("Order by last name") 1171 tx.Ascend("last_name", func(key, value string) bool { 1172 fmt.Printf("%s: %s\n", key, value) 1173 return true 1174 }) 1175 fmt.Println("Order by age") 1176 tx.Ascend("age", func(key, value string) bool { 1177 fmt.Printf("%s: %s\n", key, value) 1178 return true 1179 }) 1180 fmt.Println("Order by age range 30-50") 1181 tx.AscendRange("age", `{"age":30}`, `{"age":50}`, func(key, value string) bool { 1182 fmt.Printf("%s: %s\n", key, value) 1183 return true 1184 }) 1185 return nil 1186 }) 1187 1188 // Output: 1189 // Order by last name 1190 // 3: {"name":{"first":"Carol","last":"Anderson"},"age":52} 1191 // 4: {"name":{"first":"Alan","last":"Cooper"},"age":28} 1192 // 1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1193 // 2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1194 // Order by age 1195 // 4: {"name":{"first":"Alan","last":"Cooper"},"age":28} 1196 // 1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1197 // 2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1198 // 3: {"name":{"first":"Carol","last":"Anderson"},"age":52} 1199 // Order by age range 30-50 1200 // 1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1201 // 2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1202 } 1203 1204 func ExampleDB_CreateIndex_strings() { 1205 db, _ := Open(":memory:") 1206 db.CreateIndex("name", "*", IndexString) 1207 db.Update(func(tx *Tx) error { 1208 tx.Set("1", "Tom", nil) 1209 tx.Set("2", "Janet", nil) 1210 tx.Set("3", "Carol", nil) 1211 tx.Set("4", "Alan", nil) 1212 tx.Set("5", "Sam", nil) 1213 tx.Set("6", "Melinda", nil) 1214 return nil 1215 }) 1216 db.View(func(tx *Tx) error { 1217 tx.Ascend("name", func(key, value string) bool { 1218 fmt.Printf("%s: %s\n", key, value) 1219 return true 1220 }) 1221 return nil 1222 }) 1223 1224 // Output: 1225 //4: Alan 1226 //3: Carol 1227 //2: Janet 1228 //6: Melinda 1229 //5: Sam 1230 //1: Tom 1231 } 1232 1233 func ExampleDB_CreateIndex_ints() { 1234 db, _ := Open(":memory:") 1235 db.CreateIndex("age", "*", IndexInt) 1236 db.Update(func(tx *Tx) error { 1237 tx.Set("1", "30", nil) 1238 tx.Set("2", "51", nil) 1239 tx.Set("3", "16", nil) 1240 tx.Set("4", "76", nil) 1241 tx.Set("5", "23", nil) 1242 tx.Set("6", "43", nil) 1243 return nil 1244 }) 1245 db.View(func(tx *Tx) error { 1246 tx.Ascend("age", func(key, value string) bool { 1247 fmt.Printf("%s: %s\n", key, value) 1248 return true 1249 }) 1250 return nil 1251 }) 1252 1253 // Output: 1254 //3: 16 1255 //5: 23 1256 //1: 30 1257 //6: 43 1258 //2: 51 1259 //4: 76 1260 } 1261 func ExampleDB_CreateIndex_multipleFields() { 1262 db, _ := Open(":memory:") 1263 db.CreateIndex("last_name_age", "*", IndexJSON("name.last"), IndexJSON("age")) 1264 db.Update(func(tx *Tx) error { 1265 tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38}`, nil) 1266 tx.Set("2", `{"name":{"first":"Janet","last":"Prichard"},"age":47}`, nil) 1267 tx.Set("3", `{"name":{"first":"Carol","last":"Anderson"},"age":52}`, nil) 1268 tx.Set("4", `{"name":{"first":"Alan","last":"Cooper"},"age":28}`, nil) 1269 tx.Set("5", `{"name":{"first":"Sam","last":"Anderson"},"age":51}`, nil) 1270 tx.Set("6", `{"name":{"first":"Melinda","last":"Prichard"},"age":44}`, nil) 1271 return nil 1272 }) 1273 db.View(func(tx *Tx) error { 1274 tx.Ascend("last_name_age", func(key, value string) bool { 1275 fmt.Printf("%s: %s\n", key, value) 1276 return true 1277 }) 1278 return nil 1279 }) 1280 1281 // Output: 1282 //5: {"name":{"first":"Sam","last":"Anderson"},"age":51} 1283 //3: {"name":{"first":"Carol","last":"Anderson"},"age":52} 1284 //4: {"name":{"first":"Alan","last":"Cooper"},"age":28} 1285 //1: {"name":{"first":"Tom","last":"Johnson"},"age":38} 1286 //6: {"name":{"first":"Melinda","last":"Prichard"},"age":44} 1287 //2: {"name":{"first":"Janet","last":"Prichard"},"age":47} 1288 } 1289 1290 func TestNoExpiringItem(t *testing.T) { 1291 item := &dbItem{key: "key", val: "val"} 1292 if !item.expiresAt().Equal(maxTime) { 1293 t.Fatal("item.expiresAt() != maxTime") 1294 } 1295 if min, max := item.Rect(nil); min != nil || max != nil { 1296 t.Fatal("item min,max should both be nil") 1297 } 1298 } 1299 func TestAutoShrink(t *testing.T) { 1300 db := testOpen(t) 1301 defer testClose(db) 1302 for i := 0; i < 1000; i++ { 1303 err := db.Update(func(tx *Tx) error { 1304 for i := 0; i < 20; i++ { 1305 if _, _, err := tx.Set(fmt.Sprintf("HELLO:%d", i), "WORLD", nil); err != nil { 1306 return err 1307 } 1308 } 1309 return nil 1310 }) 1311 if err != nil { 1312 t.Fatal(err) 1313 } 1314 } 1315 db = testReOpen(t, db) 1316 defer testClose(db) 1317 db.config.AutoShrinkMinSize = 64 * 1024 // 64K 1318 for i := 0; i < 2000; i++ { 1319 err := db.Update(func(tx *Tx) error { 1320 for i := 0; i < 20; i++ { 1321 if _, _, err := tx.Set(fmt.Sprintf("HELLO:%d", i), "WORLD", nil); err != nil { 1322 return err 1323 } 1324 } 1325 return nil 1326 }) 1327 if err != nil { 1328 t.Fatal(err) 1329 } 1330 } 1331 time.Sleep(time.Second * 3) 1332 db = testReOpen(t, db) 1333 defer testClose(db) 1334 err := db.View(func(tx *Tx) error { 1335 n, err := tx.Len() 1336 if err != nil { 1337 return err 1338 } 1339 if n != 20 { 1340 t.Fatalf("expecting 20, got %v", n) 1341 } 1342 return nil 1343 }) 1344 if err != nil { 1345 t.Fatal(err) 1346 } 1347 } 1348 1349 // test database format loading 1350 func TestDatabaseFormat(t *testing.T) { 1351 // should succeed 1352 func() { 1353 resp := strings.Join([]string{ 1354 "*3\r\n$3\r\nset\r\n$4\r\nvar1\r\n$4\r\n1234\r\n", 1355 "*3\r\n$3\r\nset\r\n$4\r\nvar2\r\n$4\r\n1234\r\n", 1356 "*2\r\n$3\r\ndel\r\n$4\r\nvar1\r\n", 1357 "*5\r\n$3\r\nset\r\n$3\r\nvar\r\n$3\r\nval\r\n$2\r\nex\r\n$2\r\n10\r\n", 1358 }, "") 1359 if err := os.RemoveAll("data.db"); err != nil { 1360 t.Fatal(err) 1361 } 1362 if err := ioutil.WriteFile("data.db", []byte(resp), 0666); err != nil { 1363 t.Fatal(err) 1364 } 1365 db := testOpen(t) 1366 defer testClose(db) 1367 }() 1368 testFormat := func(t *testing.T, expectValid bool, resp string, do func(db *DB) error) { 1369 t.Helper() 1370 os.RemoveAll("data.db") 1371 if err := ioutil.WriteFile("data.db", []byte(resp), 0666); err != nil { 1372 t.Fatal(err) 1373 } 1374 defer os.RemoveAll("data.db") 1375 1376 db, err := Open("data.db") 1377 if err == nil { 1378 if do != nil { 1379 if err := do(db); err != nil { 1380 t.Fatal(err) 1381 } 1382 } 1383 if err := db.Close(); err != nil { 1384 t.Fatal(err) 1385 } 1386 } 1387 if err == nil && !expectValid { 1388 t.Fatalf("expected invalid database") 1389 } else if err != nil && expectValid { 1390 t.Fatalf("expected valid database, got '%s'", err) 1391 } 1392 } 1393 1394 // basic valid commands 1395 testFormat(t, true, "*2\r\n$3\r\nDEL\r\n$5\r\nHELLO\r\n", nil) 1396 testFormat(t, true, "*3\r\n$3\r\nSET\r\n$5\r\nHELLO\r\n$5\r\nWORLD\r\n", nil) 1397 testFormat(t, true, "*1\r\n$7\r\nFLUSHDB\r\n", nil) 1398 1399 // commands with invalid names or arguments 1400 testFormat(t, false, "*3\r\n$3\r\nDEL\r\n$5\r\nHELLO\r\n$5\r\nWORLD\r\n", nil) 1401 testFormat(t, false, "*2\r\n$3\r\nSET\r\n$5\r\nHELLO\r\n", nil) 1402 testFormat(t, false, "*1\r\n$6\r\nSET123\r\n", nil) 1403 1404 // partial tail commands should be ignored but allowed 1405 pcmd := "*3\r\n$3\r\nSET\r\n$5\r\nHELLO\r\n$5\r\nWORLD\r\n" 1406 for i := 1; i < len(pcmd); i++ { 1407 cmd := "*3\r\n$3\r\nSET\r\n$5\r\nHELLO\r\n$5\r\nJELLO\r\n" 1408 testFormat(t, true, cmd+pcmd[:len(pcmd)-i], 1409 func(db *DB) error { 1410 return db.View(func(tx *Tx) error { 1411 val, err := tx.Get("HELLO") 1412 if err != nil { 1413 return err 1414 } 1415 if val != "JELLO" { 1416 return fmt.Errorf("expected '%s', got '%s'", "JELLO", val) 1417 } 1418 return nil 1419 }) 1420 }) 1421 } 1422 1423 // commands with invalid formatting 1424 testFormat(t, false, "^3\r\n$3\r\nSET\r\n$5\r\nHELLO\r\n$5\r\nWORLD\r\n", nil) 1425 testFormat(t, false, "*3\n$3\r\nSET\r\n$5\r\nHELLO\r\n$5\r\nWORLD\r\n", nil) 1426 testFormat(t, false, "*\n$3\r\nSET\r\n$5\r\nHELLO\r\n$5\r\nWORLD\r\n", nil) 1427 testFormat(t, false, "*3\r\n^3\r\nSET\r\n$5\r\nHELLO\r\n$5\r\nWORLD\r\n", nil) 1428 testFormat(t, false, "*3\r\n$\r\nSET\r\n$5\r\nHELLO\r\n$5\r\nWORLD\r\n", nil) 1429 testFormat(t, false, "*3\r\n$3\nSET\r\n$5\r\nHELLO\r\n$5\r\nWORLD\r\n", nil) 1430 testFormat(t, false, "*3\r\n$3SET\r\n$5\r\nHELLO\r\n$5\r\nWORLD\r\n", nil) 1431 testFormat(t, false, "*3\r\n$3\r\nSET\r\n$5\r\nHELLO\r\n$5\r\nWORLD\r\n123\n", nil) 1432 1433 // commands with nuls 1434 testFormat(t, true, "\u0000*3\r\n$3\r\nSET\r\n$5\r\nHELLO\r\n$5\r\nWORLD\r\n"+ 1435 "\u0000\u0000*3\r\n$3\r\nSET\r\n$5\r\nHELLO\r\n$5\r\nJELLO\r\n\u0000", func(db *DB) error { 1436 return db.View(func(tx *Tx) error { 1437 val, err := tx.Get("HELLO") 1438 if err != nil { 1439 return err 1440 } 1441 if val != "JELLO" { 1442 return fmt.Errorf("expected '%s', got '%s'", "JELLO", val) 1443 } 1444 return nil 1445 }) 1446 }) 1447 1448 } 1449 1450 func TestInsertsAndDeleted(t *testing.T) { 1451 db := testOpen(t) 1452 defer testClose(db) 1453 if err := db.CreateIndex("any", "*", IndexString); err != nil { 1454 t.Fatal(err) 1455 } 1456 if err := db.CreateSpatialIndex("rect", "*", IndexRect); err != nil { 1457 t.Fatal(err) 1458 } 1459 if err := db.Update(func(tx *Tx) error { 1460 if _, _, err := tx.Set("item1", "value1", &SetOptions{Expires: true, TTL: time.Second}); err != nil { 1461 return err 1462 } 1463 if _, _, err := tx.Set("item2", "value2", nil); err != nil { 1464 return err 1465 } 1466 if _, _, err := tx.Set("item3", "value3", &SetOptions{Expires: true, TTL: time.Second}); err != nil { 1467 return err 1468 } 1469 return nil 1470 }); err != nil { 1471 t.Fatal(err) 1472 } 1473 1474 // test replacing items in the database 1475 if err := db.Update(func(tx *Tx) error { 1476 if _, _, err := tx.Set("item1", "nvalue1", nil); err != nil { 1477 return err 1478 } 1479 if _, _, err := tx.Set("item2", "nvalue2", nil); err != nil { 1480 return err 1481 } 1482 if _, err := tx.Delete("item3"); err != nil { 1483 return err 1484 } 1485 return nil 1486 }); err != nil { 1487 t.Fatal(err) 1488 } 1489 } 1490 1491 func TestInsertDoesNotMisuseIndex(t *testing.T) { 1492 db := testOpen(t) 1493 defer testClose(db) 1494 fail := func(a, b string) bool { t.Fatal("Misused index"); return false } 1495 if err := db.CreateIndex("some", "a*", fail); err != nil { 1496 // Only one item is eligible for the index, so no comparison is necessary. 1497 t.Fatal(err) 1498 } 1499 if err := db.Update(func(tx *Tx) error { 1500 if _, _, err := tx.Set("a", "1", nil); err != nil { 1501 return err 1502 } 1503 if _, _, err := tx.Set("b", "1", nil); err != nil { 1504 return err 1505 } 1506 return nil 1507 }); err != nil { 1508 t.Fatal(err) 1509 } 1510 1511 if err := db.Update(func(tx *Tx) error { 1512 _, _, err := tx.Set("b", "2", nil) 1513 return err 1514 }); err != nil { 1515 t.Fatal(err) 1516 } 1517 } 1518 1519 func TestDeleteDoesNotMisuseIndex(t *testing.T) { 1520 db := testOpen(t) 1521 defer testClose(db) 1522 fail := func(a, b string) bool { t.Fatal("Misused index"); return false } 1523 if err := db.CreateIndex("some", "a*", fail); err != nil { 1524 // Only one item is eligible for the index, so no comparison is necessary. 1525 t.Fatal(err) 1526 } 1527 if err := db.Update(func(tx *Tx) error { 1528 if _, _, err := tx.Set("a", "1", nil); err != nil { 1529 return err 1530 } 1531 if _, _, err := tx.Set("b", "1", nil); err != nil { 1532 return err 1533 } 1534 return nil 1535 }); err != nil { 1536 t.Fatal(err) 1537 } 1538 1539 if err := db.Update(func(tx *Tx) error { 1540 _, err := tx.Delete("b") 1541 return err 1542 }); err != nil { 1543 t.Fatal(err) 1544 } 1545 } 1546 1547 // test index compare functions 1548 func TestIndexCompare(t *testing.T) { 1549 if !IndexFloat("1.5", "1.6") { 1550 t.Fatalf("expected true, got false") 1551 } 1552 if !IndexInt("-1", "2") { 1553 t.Fatalf("expected true, got false") 1554 } 1555 if !IndexUint("10", "25") { 1556 t.Fatalf("expected true, got false") 1557 } 1558 if !IndexBinary("Hello", "hello") { 1559 t.Fatalf("expected true, got false") 1560 } 1561 if IndexString("hello", "hello") { 1562 t.Fatalf("expected false, got true") 1563 } 1564 if IndexString("Hello", "hello") { 1565 t.Fatalf("expected false, got true") 1566 } 1567 if IndexString("hello", "Hello") { 1568 t.Fatalf("expected false, got true") 1569 } 1570 if !IndexString("gello", "Hello") { 1571 t.Fatalf("expected true, got false") 1572 } 1573 if IndexString("Hello", "gello") { 1574 t.Fatalf("expected false, got true") 1575 } 1576 if Rect(IndexRect("[1 2 3 4],[5 6 7 8]")) != "[1 2 3 4],[5 6 7 8]" { 1577 t.Fatalf("expected '%v', got '%v'", "[1 2 3 4],[5 6 7 8]", Rect(IndexRect("[1 2 3 4],[5 6 7 8]"))) 1578 } 1579 if Rect(IndexRect("[1 2 3 4]")) != "[1 2 3 4]" { 1580 t.Fatalf("expected '%v', got '%v'", "[1 2 3 4]", Rect(IndexRect("[1 2 3 4]"))) 1581 } 1582 if Rect(nil, nil) != "[]" { 1583 t.Fatalf("expected '%v', got '%v'", "", Rect(nil, nil)) 1584 } 1585 if Point(1, 2, 3) != "[1 2 3]" { 1586 t.Fatalf("expected '%v', got '%v'", "[1 2 3]", Point(1, 2, 3)) 1587 } 1588 } 1589 1590 // test opening a folder. 1591 func TestOpeningAFolder(t *testing.T) { 1592 if err := os.RemoveAll("dir.tmp"); err != nil { 1593 t.Fatal(err) 1594 } 1595 if err := os.Mkdir("dir.tmp", 0700); err != nil { 1596 t.Fatal(err) 1597 } 1598 defer func() { _ = os.RemoveAll("dir.tmp") }() 1599 db, err := Open("dir.tmp") 1600 if err == nil { 1601 if err := db.Close(); err != nil { 1602 t.Fatal(err) 1603 } 1604 t.Fatalf("opening a directory should not be allowed") 1605 } 1606 } 1607 1608 // test opening an invalid resp file. 1609 func TestOpeningInvalidDatabaseFile(t *testing.T) { 1610 if err := os.RemoveAll("data.db"); err != nil { 1611 t.Fatal(err) 1612 } 1613 if err := ioutil.WriteFile("data.db", []byte("invalid\r\nfile"), 0666); err != nil { 1614 t.Fatal(err) 1615 } 1616 defer func() { _ = os.RemoveAll("data.db") }() 1617 db, err := Open("data.db") 1618 if err == nil { 1619 if err := db.Close(); err != nil { 1620 t.Fatal(err) 1621 } 1622 t.Fatalf("invalid database should not be allowed") 1623 } 1624 } 1625 1626 // test closing a closed database. 1627 func TestOpeningClosedDatabase(t *testing.T) { 1628 if err := os.RemoveAll("data.db"); err != nil { 1629 t.Fatal(err) 1630 } 1631 db, err := Open("data.db") 1632 if err != nil { 1633 t.Fatal(err) 1634 } 1635 defer func() { _ = os.RemoveAll("data.db") }() 1636 if err := db.Close(); err != nil { 1637 t.Fatal(err) 1638 } 1639 if err := db.Close(); err != ErrDatabaseClosed { 1640 t.Fatal("should not be able to close a closed database") 1641 } 1642 db, err = Open(":memory:") 1643 if err != nil { 1644 t.Fatal(err) 1645 } 1646 if err := db.Close(); err != nil { 1647 t.Fatal(err) 1648 } 1649 if err := db.Close(); err != ErrDatabaseClosed { 1650 t.Fatal("should not be able to close a closed database") 1651 } 1652 } 1653 1654 // test shrinking a database. 1655 func TestShrink(t *testing.T) { 1656 db := testOpen(t) 1657 defer testClose(db) 1658 if err := db.Shrink(); err != nil { 1659 t.Fatal(err) 1660 } 1661 fi, err := os.Stat("data.db") 1662 if err != nil { 1663 t.Fatal(err) 1664 } 1665 if fi.Size() != 0 { 1666 t.Fatalf("expected %v, got %v", 0, fi.Size()) 1667 } 1668 // add 10 items 1669 err = db.Update(func(tx *Tx) error { 1670 for i := 0; i < 10; i++ { 1671 if _, _, err := tx.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i), nil); err != nil { 1672 return err 1673 } 1674 } 1675 return nil 1676 }) 1677 if err != nil { 1678 t.Fatal(err) 1679 } 1680 // add the same 10 items 1681 // this will create 10 duplicate log entries 1682 err = db.Update(func(tx *Tx) error { 1683 for i := 0; i < 10; i++ { 1684 if _, _, err := tx.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i), nil); err != nil { 1685 return err 1686 } 1687 } 1688 return nil 1689 }) 1690 if err != nil { 1691 t.Fatal(err) 1692 } 1693 fi, err = os.Stat("data.db") 1694 if err != nil { 1695 t.Fatal(err) 1696 } 1697 sz1 := fi.Size() 1698 if sz1 == 0 { 1699 t.Fatalf("expected > 0, got %v", sz1) 1700 } 1701 if err := db.Shrink(); err != nil { 1702 t.Fatal(err) 1703 } 1704 fi, err = os.Stat("data.db") 1705 if err != nil { 1706 t.Fatal(err) 1707 } 1708 sz2 := fi.Size() 1709 if sz2 >= sz1 { 1710 t.Fatalf("expected < %v, got %v", sz1, sz2) 1711 } 1712 if err := db.Close(); err != nil { 1713 t.Fatal(err) 1714 } 1715 if err := db.Shrink(); err != ErrDatabaseClosed { 1716 t.Fatal("shrink on a closed databse should not be allowed") 1717 } 1718 // Now we will open a db that does not persist 1719 db, err = Open(":memory:") 1720 if err != nil { 1721 t.Fatal(err) 1722 } 1723 defer func() { _ = db.Close() }() 1724 // add 10 items 1725 err = db.Update(func(tx *Tx) error { 1726 for i := 0; i < 10; i++ { 1727 if _, _, err := tx.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i), nil); err != nil { 1728 return err 1729 } 1730 } 1731 return nil 1732 }) 1733 if err != nil { 1734 t.Fatal(err) 1735 } 1736 // add the same 10 items 1737 // this will create 10 duplicate log entries 1738 err = db.Update(func(tx *Tx) error { 1739 for i := 0; i < 10; i++ { 1740 if _, _, err := tx.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i), nil); err != nil { 1741 return err 1742 } 1743 } 1744 return nil 1745 }) 1746 if err != nil { 1747 t.Fatal(err) 1748 } 1749 err = db.View(func(tx *Tx) error { 1750 n, err := tx.Len() 1751 if err != nil { 1752 t.Fatal(err) 1753 } 1754 if n != 10 { 1755 t.Fatalf("expecting %v, got %v", 10, n) 1756 } 1757 return nil 1758 }) 1759 if err != nil { 1760 t.Fatal(err) 1761 } 1762 // this should succeed even though it's basically a noop. 1763 if err := db.Shrink(); err != nil { 1764 t.Fatal(err) 1765 } 1766 } 1767 1768 func TestVariousIndexOperations(t *testing.T) { 1769 db := testOpen(t) 1770 defer testClose(db) 1771 // test creating an index with no index name. 1772 err := db.CreateIndex("", "", nil) 1773 if err == nil { 1774 t.Fatal("should not be able to create an index with no name") 1775 } 1776 // test creating an index with a name that has already been used. 1777 err = db.CreateIndex("hello", "", nil) 1778 if err != nil { 1779 t.Fatal(err) 1780 } 1781 err = db.CreateIndex("hello", "", nil) 1782 if err == nil { 1783 t.Fatal("should not be able to create a duplicate index") 1784 } 1785 err = db.Update(func(tx *Tx) error { 1786 1787 if _, _, err := tx.Set("user:1", "tom", nil); err != nil { 1788 return err 1789 } 1790 if _, _, err := tx.Set("user:2", "janet", nil); err != nil { 1791 return err 1792 } 1793 if _, _, err := tx.Set("alt:1", "from", nil); err != nil { 1794 return err 1795 } 1796 if _, _, err := tx.Set("alt:2", "there", nil); err != nil { 1797 return err 1798 } 1799 if _, _, err := tx.Set("rect:1", "[1 2],[3 4]", nil); err != nil { 1800 return err 1801 } 1802 if _, _, err := tx.Set("rect:2", "[5 6],[7 8]", nil); err != nil { 1803 return err 1804 } 1805 return nil 1806 }) 1807 if err != nil { 1808 t.Fatal(err) 1809 } 1810 // test creating an index after adding items. use pattern matching. have some items in the match and some not. 1811 if err := db.CreateIndex("string", "user:*", IndexString); err != nil { 1812 t.Fatal(err) 1813 } 1814 // test creating a spatial index after adding items. use pattern matching. have some items in the match and some not. 1815 if err := db.CreateSpatialIndex("rect", "rect:*", IndexRect); err != nil { 1816 t.Fatal(err) 1817 } 1818 // test dropping an index 1819 if err := db.DropIndex("hello"); err != nil { 1820 t.Fatal(err) 1821 } 1822 // test dropping an index with no name 1823 if err := db.DropIndex(""); err == nil { 1824 t.Fatal("should not be allowed to drop an index with no name") 1825 } 1826 // test dropping an index with no name 1827 if err := db.DropIndex("na"); err == nil { 1828 t.Fatal("should not be allowed to drop an index that does not exist") 1829 } 1830 // test retrieving index names 1831 names, err := db.Indexes() 1832 if err != nil { 1833 t.Fatal(err) 1834 } 1835 if strings.Join(names, ",") != "rect,string" { 1836 t.Fatalf("expecting '%v', got '%v'", "rect,string", strings.Join(names, ",")) 1837 } 1838 // test creating an index after closing database 1839 if err := db.Close(); err != nil { 1840 t.Fatal(err) 1841 } 1842 if err := db.CreateIndex("new-index", "", nil); err != ErrDatabaseClosed { 1843 t.Fatal("should not be able to create an index on a closed database") 1844 } 1845 // test getting index names after closing database 1846 if _, err := db.Indexes(); err != ErrDatabaseClosed { 1847 t.Fatal("should not be able to get index names on a closed database") 1848 } 1849 // test dropping an index after closing database 1850 if err := db.DropIndex("rect"); err != ErrDatabaseClosed { 1851 t.Fatal("should not be able to drop an index on a closed database") 1852 } 1853 } 1854 1855 func test(t *testing.T, a, b bool) { 1856 if a != b { 1857 t.Fatal("failed, bummer...") 1858 } 1859 } 1860 1861 func TestBasic(t *testing.T) { 1862 rand.Seed(time.Now().UnixNano()) 1863 db := testOpen(t) 1864 defer testClose(db) 1865 1866 // create a simple index 1867 if err := db.CreateIndex("users", "fun:user:*", IndexString); err != nil { 1868 t.Fatal(err) 1869 } 1870 1871 // create a spatial index 1872 if err := db.CreateSpatialIndex("rects", "rect:*", IndexRect); err != nil { 1873 t.Fatal(err) 1874 } 1875 if true { 1876 err := db.Update(func(tx *Tx) error { 1877 if _, _, err := tx.Set("fun:user:0", "tom", nil); err != nil { 1878 return err 1879 } 1880 if _, _, err := tx.Set("fun:user:1", "Randi", nil); err != nil { 1881 return err 1882 } 1883 if _, _, err := tx.Set("fun:user:2", "jane", nil); err != nil { 1884 return err 1885 } 1886 if _, _, err := tx.Set("fun:user:4", "Janet", nil); err != nil { 1887 return err 1888 } 1889 if _, _, err := tx.Set("fun:user:5", "Paula", nil); err != nil { 1890 return err 1891 } 1892 if _, _, err := tx.Set("fun:user:6", "peter", nil); err != nil { 1893 return err 1894 } 1895 if _, _, err := tx.Set("fun:user:7", "Terri", nil); err != nil { 1896 return err 1897 } 1898 return nil 1899 }) 1900 if err != nil { 1901 t.Fatal(err) 1902 } 1903 // add some random items 1904 start := time.Now() 1905 if err := db.Update(func(tx *Tx) error { 1906 for _, i := range rand.Perm(100) { 1907 if _, _, err := tx.Set(fmt.Sprintf("tag:%d", i+100), fmt.Sprintf("val:%d", rand.Int()%100+100), nil); err != nil { 1908 return err 1909 } 1910 } 1911 return nil 1912 }); err != nil { 1913 t.Fatal(err) 1914 } 1915 if false { 1916 println(time.Since(start).String(), db.keys.Len()) 1917 } 1918 // add some random rects 1919 if err := db.Update(func(tx *Tx) error { 1920 if _, _, err := tx.Set("rect:1", Rect([]float64{10, 10}, []float64{20, 20}), nil); err != nil { 1921 return err 1922 } 1923 if _, _, err := tx.Set("rect:2", Rect([]float64{15, 15}, []float64{24, 24}), nil); err != nil { 1924 return err 1925 } 1926 if _, _, err := tx.Set("rect:3", Rect([]float64{17, 17}, []float64{27, 27}), nil); err != nil { 1927 return err 1928 } 1929 return nil 1930 }); err != nil { 1931 t.Fatal(err) 1932 } 1933 } 1934 // verify the data has been created 1935 buf := &bytes.Buffer{} 1936 err := db.View(func(tx *Tx) error { 1937 err := tx.Ascend("users", func(key, val string) bool { 1938 fmt.Fprintf(buf, "%s %s\n", key, val) 1939 return true 1940 }) 1941 if err != nil { 1942 t.Fatal(err) 1943 } 1944 err = tx.AscendRange("", "tag:170", "tag:172", func(key, val string) bool { 1945 fmt.Fprintf(buf, "%s\n", key) 1946 return true 1947 }) 1948 if err != nil { 1949 t.Fatal(err) 1950 } 1951 err = tx.AscendGreaterOrEqual("", "tag:195", func(key, val string) bool { 1952 fmt.Fprintf(buf, "%s\n", key) 1953 return true 1954 }) 1955 if err != nil { 1956 t.Fatal(err) 1957 } 1958 err = tx.AscendGreaterOrEqual("", "rect:", func(key, val string) bool { 1959 if !strings.HasPrefix(key, "rect:") { 1960 return false 1961 } 1962 min, max := IndexRect(val) 1963 fmt.Fprintf(buf, "%s: %v,%v\n", key, min, max) 1964 return true 1965 }) 1966 if err != nil { 1967 t.Fatal(err) 1968 } 1969 expect := make([]string, 2) 1970 n := 0 1971 err = tx.Intersects("rects", "[0 0],[15 15]", func(key, val string) bool { 1972 if n == 2 { 1973 t.Fatalf("too many rects where received, expecting only two") 1974 } 1975 min, max := IndexRect(val) 1976 s := fmt.Sprintf("%s: %v,%v\n", key, min, max) 1977 if key == "rect:1" { 1978 expect[0] = s 1979 } else if key == "rect:2" { 1980 expect[1] = s 1981 } 1982 n++ 1983 return true 1984 }) 1985 if err != nil { 1986 t.Fatal(err) 1987 } 1988 for _, s := range expect { 1989 if _, err := buf.WriteString(s); err != nil { 1990 return err 1991 } 1992 } 1993 return nil 1994 }) 1995 if err != nil { 1996 t.Fatal(err) 1997 } 1998 res := ` 1999 fun:user:2 jane 2000 fun:user:4 Janet 2001 fun:user:5 Paula 2002 fun:user:6 peter 2003 fun:user:1 Randi 2004 fun:user:7 Terri 2005 fun:user:0 tom 2006 tag:170 2007 tag:171 2008 tag:195 2009 tag:196 2010 tag:197 2011 tag:198 2012 tag:199 2013 rect:1: [10 10],[20 20] 2014 rect:2: [15 15],[24 24] 2015 rect:3: [17 17],[27 27] 2016 rect:1: [10 10],[20 20] 2017 rect:2: [15 15],[24 24] 2018 ` 2019 res = strings.Replace(res, "\r", "", -1) 2020 if strings.TrimSpace(buf.String()) != strings.TrimSpace(res) { 2021 t.Fatalf("expected [%v], got [%v]", strings.TrimSpace(res), strings.TrimSpace(buf.String())) 2022 } 2023 } 2024 2025 func TestIndexAscend(t *testing.T) { 2026 rand.Seed(time.Now().UnixNano()) 2027 db := testOpen(t) 2028 defer testClose(db) 2029 2030 // create a simple index 2031 if err := db.CreateIndex("usr", "usr:*", IndexInt); err != nil { 2032 t.Fatal(err) 2033 } 2034 if err := db.Update(func(tx *Tx) error { 2035 for i := 10; i > 0; i-- { 2036 tx.Set(fmt.Sprintf("usr:%d", i), fmt.Sprintf("%d", 10-i), nil) 2037 } 2038 return nil 2039 }); err != nil { 2040 t.Fatal(err) 2041 } 2042 2043 buf := &bytes.Buffer{} 2044 err := db.View(func(tx *Tx) error { 2045 tx.Ascend("usr", func(key, value string) bool { 2046 fmt.Fprintf(buf, "%s %s\n", key, value) 2047 return true 2048 }) 2049 fmt.Fprintln(buf) 2050 2051 tx.AscendGreaterOrEqual("usr", "8", func(key, value string) bool { 2052 fmt.Fprintf(buf, "%s %s\n", key, value) 2053 return true 2054 }) 2055 fmt.Fprintln(buf) 2056 2057 tx.AscendLessThan("usr", "3", func(key, value string) bool { 2058 fmt.Fprintf(buf, "%s %s\n", key, value) 2059 return true 2060 }) 2061 fmt.Fprintln(buf) 2062 2063 tx.AscendRange("usr", "4", "8", func(key, value string) bool { 2064 fmt.Fprintf(buf, "%s %s\n", key, value) 2065 return true 2066 }) 2067 return nil 2068 }) 2069 2070 if err != nil { 2071 t.Fatal(err) 2072 } 2073 2074 res := ` 2075 usr:10 0 2076 usr:9 1 2077 usr:8 2 2078 usr:7 3 2079 usr:6 4 2080 usr:5 5 2081 usr:4 6 2082 usr:3 7 2083 usr:2 8 2084 usr:1 9 2085 2086 usr:2 8 2087 usr:1 9 2088 2089 usr:10 0 2090 usr:9 1 2091 usr:8 2 2092 2093 usr:6 4 2094 usr:5 5 2095 usr:4 6 2096 usr:3 7 2097 ` 2098 res = strings.Replace(res, "\r", "", -1) 2099 s1 := strings.TrimSpace(buf.String()) 2100 s2 := strings.TrimSpace(res) 2101 if s1 != s2 { 2102 t.Fatalf("expected [%v], got [%v]", s1, s2) 2103 } 2104 } 2105 2106 func testRectStringer(min, max []float64) error { 2107 nmin, nmax := IndexRect(Rect(min, max)) 2108 if len(nmin) != len(min) { 2109 return fmt.Errorf("rect=%v,%v, expect=%v,%v", nmin, nmax, min, max) 2110 } 2111 for i := 0; i < len(min); i++ { 2112 if min[i] != nmin[i] || max[i] != nmax[i] { 2113 return fmt.Errorf("rect=%v,%v, expect=%v,%v", nmin, nmax, min, max) 2114 } 2115 } 2116 return nil 2117 } 2118 func TestRectStrings(t *testing.T) { 2119 test(t, Rect(IndexRect(Point(1))) == "[1]", true) 2120 test(t, Rect(IndexRect(Point(1, 2, 3, 4))) == "[1 2 3 4]", true) 2121 test(t, Rect(IndexRect(Rect(IndexRect("[1 2],[1 2]")))) == "[1 2]", true) 2122 test(t, Rect(IndexRect(Rect(IndexRect("[1 2],[2 2]")))) == "[1 2],[2 2]", true) 2123 test(t, Rect(IndexRect(Rect(IndexRect("[1 2],[2 2],[3]")))) == "[1 2],[2 2]", true) 2124 test(t, Rect(IndexRect(Rect(IndexRect("[1 2]")))) == "[1 2]", true) 2125 test(t, Rect(IndexRect(Rect(IndexRect("[1.5 2 4.5 5.6]")))) == "[1.5 2 4.5 5.6]", true) 2126 test(t, Rect(IndexRect(Rect(IndexRect("[1.5 2 4.5 5.6 -1],[]")))) == "[1.5 2 4.5 5.6 -1]", true) 2127 test(t, Rect(IndexRect(Rect(IndexRect("[]")))) == "[]", true) 2128 test(t, Rect(IndexRect(Rect(IndexRect("")))) == "[]", true) 2129 if err := testRectStringer(nil, nil); err != nil { 2130 t.Fatal(err) 2131 } 2132 if err := testRectStringer([]float64{}, []float64{}); err != nil { 2133 t.Fatal(err) 2134 } 2135 if err := testRectStringer([]float64{1}, []float64{2}); err != nil { 2136 t.Fatal(err) 2137 } 2138 if err := testRectStringer([]float64{1, 2}, []float64{3, 4}); err != nil { 2139 t.Fatal(err) 2140 } 2141 if err := testRectStringer([]float64{1, 2, 3}, []float64{4, 5, 6}); err != nil { 2142 t.Fatal(err) 2143 } 2144 if err := testRectStringer([]float64{1, 2, 3, 4}, []float64{5, 6, 7, 8}); err != nil { 2145 t.Fatal(err) 2146 } 2147 if err := testRectStringer([]float64{1, 2, 3, 4, 5}, []float64{6, 7, 8, 9, 10}); err != nil { 2148 t.Fatal(err) 2149 } 2150 } 2151 2152 // TestTTLReOpen test setting a TTL and then immediately closing the database and 2153 // then waiting the TTL before reopening. The key should not be accessible. 2154 func TestTTLReOpen(t *testing.T) { 2155 ttl := time.Second * 3 2156 db := testOpen(t) 2157 defer testClose(db) 2158 err := db.Update(func(tx *Tx) error { 2159 if _, _, err := tx.Set("key1", "val1", &SetOptions{Expires: true, TTL: ttl}); err != nil { 2160 return err 2161 } 2162 return nil 2163 }) 2164 if err != nil { 2165 t.Fatal(err) 2166 } 2167 db = testReOpenDelay(t, db, ttl/4) 2168 err = db.View(func(tx *Tx) error { 2169 val, err := tx.Get("key1") 2170 if err != nil { 2171 return err 2172 } 2173 if val != "val1" { 2174 t.Fatalf("expecting '%v', got '%v'", "val1", val) 2175 } 2176 return nil 2177 }) 2178 if err != nil { 2179 t.Fatal(err) 2180 } 2181 db = testReOpenDelay(t, db, ttl-ttl/4) 2182 defer testClose(db) 2183 err = db.View(func(tx *Tx) error { 2184 val, err := tx.Get("key1") 2185 if err == nil || err != ErrNotFound || val != "" { 2186 t.Fatal("expecting not found") 2187 } 2188 2189 return nil 2190 }) 2191 if err != nil { 2192 t.Fatal(err) 2193 } 2194 } 2195 2196 func TestTTL(t *testing.T) { 2197 db := testOpen(t) 2198 defer testClose(db) 2199 err := db.Update(func(tx *Tx) error { 2200 if _, _, err := tx.Set("key1", "val1", &SetOptions{Expires: true, TTL: time.Second}); err != nil { 2201 return err 2202 } 2203 if _, _, err := tx.Set("key2", "val2", nil); err != nil { 2204 return err 2205 } 2206 return nil 2207 }) 2208 if err != nil { 2209 t.Fatal(err) 2210 } 2211 err = db.View(func(tx *Tx) error { 2212 dur1, err := tx.TTL("key1") 2213 if err != nil { 2214 t.Fatal(err) 2215 } 2216 if dur1 > time.Second || dur1 <= 0 { 2217 t.Fatalf("expecting between zero and one second, got '%v'", dur1) 2218 } 2219 dur1, err = tx.TTL("key2") 2220 if err != nil { 2221 t.Fatal(err) 2222 } 2223 if dur1 >= 0 { 2224 t.Fatalf("expecting a negative value, got '%v'", dur1) 2225 } 2226 return nil 2227 }) 2228 if err != nil { 2229 t.Fatal(err) 2230 } 2231 } 2232 2233 func TestConfig(t *testing.T) { 2234 db := testOpen(t) 2235 defer testClose(db) 2236 2237 err := db.SetConfig(Config{SyncPolicy: SyncPolicy(-1)}) 2238 if err == nil { 2239 t.Fatal("expecting a config syncpolicy error") 2240 } 2241 err = db.SetConfig(Config{SyncPolicy: SyncPolicy(3)}) 2242 if err == nil { 2243 t.Fatal("expecting a config syncpolicy error") 2244 } 2245 err = db.SetConfig(Config{SyncPolicy: Never}) 2246 if err != nil { 2247 t.Fatal(err) 2248 } 2249 err = db.SetConfig(Config{SyncPolicy: EverySecond}) 2250 if err != nil { 2251 t.Fatal(err) 2252 } 2253 err = db.SetConfig(Config{AutoShrinkMinSize: 100, AutoShrinkPercentage: 200, SyncPolicy: Always}) 2254 if err != nil { 2255 t.Fatal(err) 2256 } 2257 2258 var c Config 2259 if err := db.ReadConfig(&c); err != nil { 2260 t.Fatal(err) 2261 } 2262 if c.AutoShrinkMinSize != 100 || c.AutoShrinkPercentage != 200 && c.SyncPolicy != Always { 2263 t.Fatalf("expecting %v, %v, and %v, got %v, %v, and %v", 100, 200, Always, c.AutoShrinkMinSize, c.AutoShrinkPercentage, c.SyncPolicy) 2264 } 2265 } 2266 func testUint64Hex(n uint64) string { 2267 s := strconv.FormatUint(n, 16) 2268 s = "0000000000000000" + s 2269 return s[len(s)-16:] 2270 } 2271 func textHexUint64(s string) uint64 { 2272 n, _ := strconv.ParseUint(s, 16, 64) 2273 return n 2274 } 2275 func benchClose(t *testing.B, persist bool, db *DB) { 2276 if persist { 2277 if err := os.RemoveAll("data.db"); err != nil { 2278 t.Fatal(err) 2279 } 2280 } 2281 if err := db.Close(); err != nil { 2282 t.Fatal(err) 2283 } 2284 } 2285 2286 func benchOpenFillData(t *testing.B, N int, 2287 set, persist, random bool, 2288 geo bool, 2289 batch int) (db *DB, keys, vals []string) { 2290 /// 2291 t.StopTimer() 2292 rand.Seed(time.Now().UnixNano()) 2293 var err error 2294 if persist { 2295 if err := os.RemoveAll("data.db"); err != nil { 2296 t.Fatal(err) 2297 } 2298 db, err = Open("data.db") 2299 } else { 2300 db, err = Open(":memory:") 2301 } 2302 if err != nil { 2303 t.Fatal(err) 2304 } 2305 keys = make([]string, N) 2306 vals = make([]string, N) 2307 perm := rand.Perm(N) 2308 for i := 0; i < N; i++ { 2309 if random && set { 2310 keys[perm[i]] = testUint64Hex(uint64(i)) 2311 vals[perm[i]] = strconv.FormatInt(rand.Int63()%1000+1000, 10) 2312 } else { 2313 keys[i] = testUint64Hex(uint64(i)) 2314 vals[i] = strconv.FormatInt(rand.Int63()%1000+1000, 10) 2315 } 2316 } 2317 if set { 2318 t.StartTimer() 2319 } 2320 for i := 0; i < N; { 2321 err := db.Update(func(tx *Tx) error { 2322 var err error 2323 for j := 0; j < batch && i < N; j++ { 2324 _, _, err = tx.Set(keys[i], vals[i], nil) 2325 i++ 2326 } 2327 return err 2328 }) 2329 if err != nil { 2330 t.Fatal(err) 2331 } 2332 } 2333 if set { 2334 t.StopTimer() 2335 } 2336 var n uint64 2337 err = db.View(func(tx *Tx) error { 2338 err := tx.Ascend("", func(key, value string) bool { 2339 n2 := textHexUint64(key) 2340 if n2 != n { 2341 t.Fatalf("expecting '%v', got '%v'", n2, n) 2342 } 2343 n++ 2344 return true 2345 }) 2346 return err 2347 }) 2348 if err != nil { 2349 t.Fatal(err) 2350 } 2351 if n != uint64(N) { 2352 t.Fatalf("expecting '%v', got '%v'", N, n) 2353 } 2354 t.StartTimer() 2355 return db, keys, vals 2356 } 2357 2358 func benchSetGet(t *testing.B, set, persist, random bool, batch int) { 2359 N := t.N 2360 for N > 0 { 2361 n := 0 2362 if N >= 100000 { 2363 n = 100000 2364 } else { 2365 n = N 2366 } 2367 func() { 2368 db, keys, _ := benchOpenFillData(t, n, set, persist, random, false, batch) 2369 defer benchClose(t, persist, db) 2370 if !set { 2371 for i := 0; i < n; { 2372 err := db.View(func(tx *Tx) error { 2373 var err error 2374 for j := 0; j < batch && i < n; j++ { 2375 _, err = tx.Get(keys[i]) 2376 i++ 2377 } 2378 return err 2379 }) 2380 if err != nil { 2381 t.Fatal(err) 2382 } 2383 } 2384 } 2385 }() 2386 N -= n 2387 } 2388 } 2389 2390 // Set Persist 2391 func Benchmark_Set_Persist_Random_1(t *testing.B) { 2392 benchSetGet(t, true, true, true, 1) 2393 } 2394 func Benchmark_Set_Persist_Random_10(t *testing.B) { 2395 benchSetGet(t, true, true, true, 10) 2396 } 2397 func Benchmark_Set_Persist_Random_100(t *testing.B) { 2398 benchSetGet(t, true, true, true, 100) 2399 } 2400 func Benchmark_Set_Persist_Sequential_1(t *testing.B) { 2401 benchSetGet(t, true, true, false, 1) 2402 } 2403 func Benchmark_Set_Persist_Sequential_10(t *testing.B) { 2404 benchSetGet(t, true, true, false, 10) 2405 } 2406 func Benchmark_Set_Persist_Sequential_100(t *testing.B) { 2407 benchSetGet(t, true, true, false, 100) 2408 } 2409 2410 // Set NoPersist 2411 func Benchmark_Set_NoPersist_Random_1(t *testing.B) { 2412 benchSetGet(t, true, false, true, 1) 2413 } 2414 func Benchmark_Set_NoPersist_Random_10(t *testing.B) { 2415 benchSetGet(t, true, false, true, 10) 2416 } 2417 func Benchmark_Set_NoPersist_Random_100(t *testing.B) { 2418 benchSetGet(t, true, false, true, 100) 2419 } 2420 func Benchmark_Set_NoPersist_Sequential_1(t *testing.B) { 2421 benchSetGet(t, true, false, false, 1) 2422 } 2423 func Benchmark_Set_NoPersist_Sequential_10(t *testing.B) { 2424 benchSetGet(t, true, false, false, 10) 2425 } 2426 func Benchmark_Set_NoPersist_Sequential_100(t *testing.B) { 2427 benchSetGet(t, true, false, false, 100) 2428 } 2429 2430 // Get 2431 func Benchmark_Get_1(t *testing.B) { 2432 benchSetGet(t, false, false, false, 1) 2433 } 2434 func Benchmark_Get_10(t *testing.B) { 2435 benchSetGet(t, false, false, false, 10) 2436 } 2437 func Benchmark_Get_100(t *testing.B) { 2438 benchSetGet(t, false, false, false, 100) 2439 } 2440 2441 func benchScan(t *testing.B, asc bool, count int) { 2442 N := count 2443 db, _, _ := benchOpenFillData(t, N, false, false, false, false, 100) 2444 defer benchClose(t, false, db) 2445 for i := 0; i < t.N; i++ { 2446 count := 0 2447 err := db.View(func(tx *Tx) error { 2448 if asc { 2449 return tx.Ascend("", func(key, val string) bool { 2450 count++ 2451 return true 2452 }) 2453 } 2454 return tx.Descend("", func(key, val string) bool { 2455 count++ 2456 return true 2457 }) 2458 2459 }) 2460 if err != nil { 2461 t.Fatal(err) 2462 } 2463 if count != N { 2464 t.Fatalf("expecting '%v', got '%v'", N, count) 2465 } 2466 } 2467 } 2468 2469 func Benchmark_Ascend_1(t *testing.B) { 2470 benchScan(t, true, 1) 2471 } 2472 func Benchmark_Ascend_10(t *testing.B) { 2473 benchScan(t, true, 10) 2474 } 2475 func Benchmark_Ascend_100(t *testing.B) { 2476 benchScan(t, true, 100) 2477 } 2478 func Benchmark_Ascend_1000(t *testing.B) { 2479 benchScan(t, true, 1000) 2480 } 2481 func Benchmark_Ascend_10000(t *testing.B) { 2482 benchScan(t, true, 10000) 2483 } 2484 2485 func Benchmark_Descend_1(t *testing.B) { 2486 benchScan(t, false, 1) 2487 } 2488 func Benchmark_Descend_10(t *testing.B) { 2489 benchScan(t, false, 10) 2490 } 2491 func Benchmark_Descend_100(t *testing.B) { 2492 benchScan(t, false, 100) 2493 } 2494 func Benchmark_Descend_1000(t *testing.B) { 2495 benchScan(t, false, 1000) 2496 } 2497 func Benchmark_Descend_10000(t *testing.B) { 2498 benchScan(t, false, 10000) 2499 } 2500 2501 /* 2502 func Benchmark_Spatial_2D(t *testing.B) { 2503 N := 100000 2504 db, _, _ := benchOpenFillData(t, N, true, true, false, true, 100) 2505 defer benchClose(t, false, db) 2506 2507 } 2508 */ 2509 func TestCoverCloseAlreadyClosed(t *testing.T) { 2510 db := testOpen(t) 2511 defer testClose(db) 2512 _ = db.file.Close() 2513 if err := db.Close(); err == nil { 2514 t.Fatal("expecting an error") 2515 } 2516 } 2517 2518 func TestCoverConfigClosed(t *testing.T) { 2519 db := testOpen(t) 2520 defer testClose(db) 2521 _ = db.Close() 2522 var config Config 2523 if err := db.ReadConfig(&config); err != ErrDatabaseClosed { 2524 t.Fatal("expecting database closed error") 2525 } 2526 if err := db.SetConfig(config); err != ErrDatabaseClosed { 2527 t.Fatal("expecting database closed error") 2528 } 2529 } 2530 func TestCoverShrinkShrink(t *testing.T) { 2531 db := testOpen(t) 2532 defer testClose(db) 2533 if err := db.Update(func(tx *Tx) error { 2534 for i := 0; i < 10000; i++ { 2535 _, _, err := tx.Set(fmt.Sprintf("%d", i), fmt.Sprintf("%d", i), nil) 2536 if err != nil { 2537 return err 2538 } 2539 } 2540 return nil 2541 }); err != nil { 2542 t.Fatal(err) 2543 } 2544 if err := db.Update(func(tx *Tx) error { 2545 for i := 250; i < 250+100; i++ { 2546 _, err := tx.Delete(fmt.Sprintf("%d", i)) 2547 if err != nil { 2548 return err 2549 } 2550 } 2551 return nil 2552 }); err != nil { 2553 t.Fatal(err) 2554 } 2555 var err1, err2 error 2556 var wg sync.WaitGroup 2557 wg.Add(2) 2558 go func() { 2559 defer wg.Done() 2560 err1 = db.Shrink() 2561 }() 2562 go func() { 2563 defer wg.Done() 2564 err2 = db.Shrink() 2565 }() 2566 wg.Wait() 2567 //println(123) 2568 //fmt.Printf("%v\n%v\n", err1, err2) 2569 if err1 != ErrShrinkInProcess && err2 != ErrShrinkInProcess { 2570 t.Fatal("expecting a shrink in process error") 2571 } 2572 db = testReOpen(t, db) 2573 defer testClose(db) 2574 if err := db.View(func(tx *Tx) error { 2575 n, err := tx.Len() 2576 if err != nil { 2577 return err 2578 } 2579 if n != 9900 { 2580 t.Fatal("expecting 9900 items") 2581 } 2582 return nil 2583 }); err != nil { 2584 t.Fatal(err) 2585 } 2586 } 2587 2588 func TestPreviousItem(t *testing.T) { 2589 db := testOpen(t) 2590 defer testClose(db) 2591 err := db.Update(func(tx *Tx) error { 2592 _, _, err := tx.Set("hello", "world", nil) 2593 if err != nil { 2594 return err 2595 } 2596 prev, replaced, err := tx.Set("hello", "planet", nil) 2597 if err != nil { 2598 return err 2599 } 2600 if !replaced { 2601 t.Fatal("should be replaced") 2602 } 2603 if prev != "world" { 2604 t.Fatalf("expecting '%v', got '%v'", "world", prev) 2605 } 2606 return nil 2607 }) 2608 if err != nil { 2609 t.Fatal(err) 2610 } 2611 } 2612 2613 func TestJSONIndex(t *testing.T) { 2614 db := testOpen(t) 2615 defer testClose(db) 2616 2617 _ = db.CreateIndex("last_name", "*", IndexJSON("name.last")) 2618 _ = db.CreateIndex("last_name_cs", "*", IndexJSONCaseSensitive("name.last")) 2619 _ = db.CreateIndex("age", "*", IndexJSON("age")) 2620 _ = db.CreateIndex("student", "*", IndexJSON("student")) 2621 _ = db.Update(func(tx *Tx) error { 2622 _, _, _ = tx.Set("1", `{"name":{"first":"Tom","last":"Johnson"},"age":38,"student":false}`, nil) 2623 _, _, _ = tx.Set("2", `{"name":{"first":"Janet","last":"Prichard"},"age":47,"student":true}`, nil) 2624 _, _, _ = tx.Set("3", `{"name":{"first":"Carol","last":"Anderson"},"age":52,"student":true}`, nil) 2625 _, _, _ = tx.Set("4", `{"name":{"first":"Alan","last":"Cooper"},"age":28,"student":false}`, nil) 2626 _, _, _ = tx.Set("5", `{"name":{"first":"bill","last":"frank"},"age":21,"student":true}`, nil) 2627 _, _, _ = tx.Set("6", `{"name":{"first":"sally","last":"randall"},"age":68,"student":false}`, nil) 2628 return nil 2629 }) 2630 var keys []string 2631 _ = db.View(func(tx *Tx) error { 2632 _ = tx.Ascend("last_name_cs", func(key, value string) bool { 2633 //fmt.Printf("%s: %s\n", key, value) 2634 keys = append(keys, key) 2635 return true 2636 }) 2637 _ = tx.Ascend("last_name", func(key, value string) bool { 2638 //fmt.Printf("%s: %s\n", key, value) 2639 keys = append(keys, key) 2640 return true 2641 }) 2642 _ = tx.Ascend("age", func(key, value string) bool { 2643 //fmt.Printf("%s: %s\n", key, value) 2644 keys = append(keys, key) 2645 return true 2646 }) 2647 _ = tx.Ascend("student", func(key, value string) bool { 2648 //fmt.Printf("%s: %s\n", key, value) 2649 keys = append(keys, key) 2650 return true 2651 }) 2652 return nil 2653 }) 2654 expect := "3,4,1,2,5,6,3,4,5,1,2,6,5,4,1,2,3,6,1,4,6,2,3,5" 2655 if strings.Join(keys, ",") != expect { 2656 t.Fatalf("expected %v, got %v", expect, strings.Join(keys, ",")) 2657 } 2658 } 2659 2660 func TestOnExpiredSync(t *testing.T) { 2661 db := testOpen(t) 2662 defer testClose(db) 2663 2664 var config Config 2665 if err := db.ReadConfig(&config); err != nil { 2666 t.Fatal(err) 2667 } 2668 hits := make(chan int, 3) 2669 config.OnExpiredSync = func(key, value string, tx *Tx) error { 2670 n, err := strconv.Atoi(value) 2671 if err != nil { 2672 return err 2673 } 2674 defer func() { hits <- n }() 2675 if n >= 2 { 2676 _, err = tx.Delete(key) 2677 if err != ErrNotFound { 2678 return err 2679 } 2680 return nil 2681 } 2682 n++ 2683 _, _, err = tx.Set(key, strconv.Itoa(n), &SetOptions{Expires: true, TTL: time.Millisecond * 100}) 2684 return err 2685 } 2686 if err := db.SetConfig(config); err != nil { 2687 t.Fatal(err) 2688 } 2689 err := db.Update(func(tx *Tx) error { 2690 _, _, err := tx.Set("K", "0", &SetOptions{Expires: true, TTL: time.Millisecond * 100}) 2691 return err 2692 }) 2693 if err != nil { 2694 t.Fail() 2695 } 2696 2697 done := make(chan struct{}) 2698 go func() { 2699 ticks := time.NewTicker(time.Millisecond * 50) 2700 defer ticks.Stop() 2701 for { 2702 select { 2703 case <-done: 2704 return 2705 case <-ticks.C: 2706 err := db.View(func(tx *Tx) error { 2707 v, err := tx.Get("K", true) 2708 if err != nil { 2709 return err 2710 } 2711 n, err := strconv.Atoi(v) 2712 if err != nil { 2713 return err 2714 } 2715 if n < 0 || n > 2 { 2716 t.Fail() 2717 } 2718 return nil 2719 }) 2720 if err != nil { 2721 t.Fail() 2722 } 2723 } 2724 } 2725 }() 2726 2727 OUTER1: 2728 for { 2729 select { 2730 case <-time.After(time.Second * 2): 2731 t.Fail() 2732 case v := <-hits: 2733 if v >= 2 { 2734 break OUTER1 2735 } 2736 } 2737 } 2738 err = db.View(func(tx *Tx) error { 2739 defer close(done) 2740 v, err := tx.Get("K") 2741 if err != nil { 2742 t.Fail() 2743 return err 2744 } 2745 if v != "2" { 2746 t.Fail() 2747 } 2748 return nil 2749 }) 2750 if err != nil { 2751 t.Fail() 2752 } 2753 } 2754 2755 func TestTransactionLeak(t *testing.T) { 2756 // This tests an bug identified in Issue #69. When inside a Update 2757 // transaction, a Set after a Delete for a key that previously exists will 2758 // remove the key when the transaction was rolledback. 2759 buntDB, err := Open(":memory:") 2760 if err != nil { 2761 t.Fatal(err) 2762 } 2763 bd := buntDB 2764 err = bd.Update(func(tx *Tx) error { 2765 _, _, err := tx.Set("a", "a", nil) 2766 return err 2767 }) 2768 if err != nil { 2769 t.Fatal(err) 2770 } 2771 bd.View(func(tx *Tx) error { 2772 val, err := tx.Get("a") 2773 if err != nil { 2774 return err 2775 } 2776 if val != "a" { 2777 return errors.New("mismatch") 2778 } 2779 return nil 2780 }) 2781 if err != nil { 2782 t.Fatal(err) 2783 } 2784 bd.Update(func(tx *Tx) error { 2785 val, err := tx.Delete("a") 2786 if err != nil { 2787 return err 2788 } 2789 if val != "a" { 2790 return errors.New("mismatch") 2791 } 2792 val, err = tx.Get("a") 2793 if err != ErrNotFound { 2794 return fmt.Errorf("expected NotFound, got %v", err) 2795 } 2796 if val != "" { 2797 return errors.New("mismatch") 2798 } 2799 val, rep, err := tx.Set("a", "b", nil) 2800 if err != nil { 2801 return err 2802 } 2803 if rep { 2804 return errors.New("replaced") 2805 } 2806 if val != "" { 2807 return errors.New("mismatch") 2808 } 2809 val, err = tx.Get("a") 2810 if err != nil { 2811 return err 2812 } 2813 if val != "b" { 2814 return errors.New("mismatch") 2815 } 2816 return errors.New("rollback") 2817 }) 2818 if err != nil { 2819 t.Fatal(err) 2820 } 2821 bd.View(func(tx *Tx) error { 2822 val, err := tx.Get("a") 2823 if err != nil { 2824 return err 2825 } 2826 if val != "a" { 2827 return errors.New("mismatch") 2828 } 2829 return nil 2830 }) 2831 if err != nil { 2832 t.Fatal(err) 2833 } 2834 } 2835 2836 func TestReloadNotInvalid(t *testing.T) { 2837 rand.Seed(time.Now().UnixNano()) 2838 os.RemoveAll("data.db") 2839 defer os.RemoveAll("data.db") 2840 start := time.Now() 2841 ii := 0 2842 for time.Since(start) < time.Second*5 { 2843 func() { 2844 db, err := Open("data.db") 2845 if err != nil { 2846 t.Fatal(err) 2847 } 2848 defer func() { 2849 if err := db.Close(); err != nil { 2850 panic(err) 2851 } 2852 // truncate at a random point in the file 2853 f, err := os.OpenFile("data.db", os.O_RDWR, 0666) 2854 if err != nil { 2855 panic(err) 2856 } 2857 defer f.Close() 2858 sz, err := f.Seek(0, 2) 2859 if err != nil { 2860 panic(err) 2861 } 2862 n := sz/2 + int64(rand.Intn(int(sz/2))) 2863 err = f.Truncate(n) 2864 if err != nil { 2865 panic(err) 2866 } 2867 }() 2868 N := 500 2869 lotsa.Ops(N, 16, func(i, t int) { 2870 if i == N/2 && ii&7 == 0 { 2871 if err := db.Shrink(); err != nil { 2872 panic(err) 2873 } 2874 } 2875 err := db.Update(func(tx *Tx) error { 2876 _, _, err := tx.Set(fmt.Sprintf("key:%d", i), fmt.Sprintf("val:%d", i), &SetOptions{ 2877 Expires: true, 2878 TTL: 30, 2879 }) 2880 return err 2881 }) 2882 if err != nil { 2883 panic(err) 2884 } 2885 }) 2886 }() 2887 ii++ 2888 } 2889 } 2890 2891 func TestEstSize(t *testing.T) { 2892 t.Run("estIntSize", func(t *testing.T) { 2893 assert.Assert(estIntSize(0) == 1) 2894 assert.Assert(estIntSize(1) == 1) 2895 assert.Assert(estIntSize(9) == 1) 2896 assert.Assert(estIntSize(10) == 2) 2897 assert.Assert(estIntSize(11) == 2) 2898 assert.Assert(estIntSize(19) == 2) 2899 assert.Assert(estIntSize(20) == 2) 2900 assert.Assert(estIntSize(113) == 3) 2901 assert.Assert(estIntSize(3822) == 4) 2902 assert.Assert(estIntSize(-1) == 2) 2903 assert.Assert(estIntSize(-12) == 3) 2904 assert.Assert(estIntSize(-124) == 4) 2905 }) 2906 } 2907 2908 func TestWrappedError(t *testing.T) { 2909 defer func() { 2910 if err, ok := recover().(error); ok { 2911 if strings.HasPrefix(err.Error(), "buntdb: ") { 2912 err := errors.Unwrap(err) 2913 if err.Error() != "my fake error" { 2914 t.Fatal("!") 2915 } 2916 } 2917 } 2918 }() 2919 panicErr(errors.New("my fake error")) 2920 }