|
19 | 19 | @value.value.should == false |
20 | 20 | end |
21 | 21 |
|
| 22 | + it "should handle simple values" do |
| 23 | + @value.should == nil |
| 24 | + @value.value = 'Trevor Hoffman' |
| 25 | + @value.should == 'Trevor Hoffman' |
| 26 | + @value.get.should == 'Trevor Hoffman' |
| 27 | + @value.exists?.should == true |
| 28 | + @value.exists.should == 1 |
| 29 | + @value.del.should == 1 |
| 30 | + @value.should.be.nil |
| 31 | + @value.exists?.should == false |
| 32 | + @value.exists.should == 0 |
| 33 | + @value.value = 42 |
| 34 | + @value.value.should == '42' |
| 35 | + end |
| 36 | + |
22 | 37 | it "should compress non marshaled values" do |
23 | 38 | @value = Redis::Value.new('spec/value', compress: true) |
24 | 39 | @value.value = 'Trevor Hoffman' |
|
39 | 54 | @value.value.should == nil |
40 | 55 | @value.value = '' |
41 | 56 | @value.value.should == '' |
42 | | - end |
43 | | - |
44 | | - it "should handle simple values" do |
45 | | - @value.should == nil |
46 | | - @value.value = 'Trevor Hoffman' |
47 | | - @value.should == 'Trevor Hoffman' |
48 | | - @value.get.should == 'Trevor Hoffman' |
49 | | - @value.del.should == 1 |
50 | | - @value.should.be.nil |
51 | | - @value.value = 42 |
52 | | - @value.value.should == '42' |
| 57 | + @value.delete |
| 58 | + @value.value.should.be.nil |
53 | 59 | end |
54 | 60 |
|
55 | 61 | it "should handle complex marshaled values" do |
|
88 | 94 | marshalled_string = Marshal.dump({json: 'marshal'}) |
89 | 95 | @value = Redis::Value.new('spec/marshal', :default => marshalled_string, :marshal => true) |
90 | 96 | @value.value.should == marshalled_string |
91 | | - @value.clear |
| 97 | + @value.delete |
92 | 98 | end |
93 | 99 |
|
94 | 100 | it "should support renaming values" do |
|
499 | 505 | @counter.incrbyfloat 2.0e2 |
500 | 506 | @counter.to_f.should == 5214.31 |
501 | 507 | @counter.clear |
| 508 | + @counter.should.be.nil |
502 | 509 | end |
503 | 510 |
|
504 | 511 | it "should support an atomic block" do |
|
545 | 552 | @updated = @counter.decrement(1) { |updated| updated == 2 ? 'yep' : nil } |
546 | 553 | @updated.should == 'yep' |
547 | 554 | @counter.should == 2 |
| 555 | + |
| 556 | + @counter.value = nil |
| 557 | + @counter.should == 0 |
548 | 558 | end |
549 | 559 |
|
550 | 560 | it "should support #to_json" do |
|
644 | 654 | REDIS_HANDLE.get("test_lock").should.be.nil |
645 | 655 | end |
646 | 656 |
|
647 | | - it "should not let non-expired locks be gettable" do |
| 657 | + it "should not let blocks execute if they timeout" do |
648 | 658 | expiry = 15 |
649 | 659 | lock = Redis::Lock.new(:test_lock, :expiration => expiry, :timeout => 0.1) |
650 | 660 |
|
|
669 | 679 | REDIS_HANDLE.get("test_lock").should.not.be.nil |
670 | 680 | end |
671 | 681 |
|
| 682 | + it "should handle a timeout of 0" do |
| 683 | + expiry = 15 |
| 684 | + lock = Redis::Lock.new(:test_lock, :timeout => 0) |
| 685 | + |
| 686 | + # create a fake lock |
| 687 | + REDIS_HANDLE.set("test_lock", (Time.now + expiry).to_f) |
| 688 | + |
| 689 | + gotit = false |
| 690 | + error = nil |
| 691 | + begin |
| 692 | + lock.lock do |
| 693 | + gotit = true |
| 694 | + end |
| 695 | + rescue => error |
| 696 | + end |
| 697 | + |
| 698 | + error.should.be.kind_of(Redis::Lock::LockTimeout) |
| 699 | + |
| 700 | + # should not have the lock |
| 701 | + gotit.should.not.be.true |
| 702 | + |
| 703 | + # lock value should still be set |
| 704 | + REDIS_HANDLE.get("test_lock").should.not.be.nil |
| 705 | + end |
| 706 | + |
| 707 | + it "should properly keep the lock across threads" do |
| 708 | + lock = Redis::Lock.new(:test_lock0) |
| 709 | + |
| 710 | + t1 = Thread.new do |
| 711 | + lock.lock do |
| 712 | + lock.exists?.should.be.true |
| 713 | + REDIS_HANDLE.exists?("test_lock0").should.be.true |
| 714 | + sleep 0.3 # hand onto the lock |
| 715 | + end |
| 716 | + end |
| 717 | + |
| 718 | + t2 = Thread.new do |
| 719 | + # check for the lock from another thread |
| 720 | + lock.exists?.should.be.true |
| 721 | + REDIS_HANDLE.exists?("test_lock0").should.be.true |
| 722 | + end |
| 723 | + |
| 724 | + t1.join |
| 725 | + t2.join |
| 726 | + |
| 727 | + # lock value should not be set since the lock was held for more than the expiry |
| 728 | + lock.exists?.should.be.false |
| 729 | + REDIS_HANDLE.exists?("test_lock0").should.be.false |
| 730 | + end |
| 731 | + |
672 | 732 | it "Redis should remove the key if lock is held past expiration" do |
673 | | - lock = Redis::Lock.new(:test_lock, :expiration => 0.1) |
| 733 | + lock = Redis::Lock.new(:test_lock1, :expiration => 0.1) |
674 | 734 |
|
675 | 735 | lock.lock do |
676 | | - REDIS_HANDLE.exists("test_lock").should.be.true |
677 | | - sleep 0.3 |
678 | | - # technically undefined behavior because we don't have a BG thread |
679 | | - # running and deleting lock keys - that is only triggered on block exit |
680 | | - #REDIS_HANDLE.exists("test_lock").should.be.false |
| 736 | + lock.exists?.should.be.true |
| 737 | + REDIS_HANDLE.exists?("test_lock1").should.be.true |
| 738 | + sleep 0.3 # hang onto the lock > expiry |
681 | 739 | end |
682 | 740 |
|
683 | 741 | # lock value should not be set since the lock was held for more than the expiry |
684 | | - REDIS_HANDLE.exists("test_lock").should.be.false |
| 742 | + lock.exists?.should.be.false |
| 743 | + REDIS_HANDLE.exists?("test_lock1").should.be.false |
685 | 744 | end |
686 | 745 |
|
687 | 746 |
|
688 | 747 | it "should not manually delete a key with a 'lock' name if finished after expiration" do |
689 | 748 | lock = Redis::Lock.new(:test_lock2, :expiration => 0.1) |
690 | 749 |
|
691 | 750 | lock.lock do |
692 | | - REDIS_HANDLE.exists("test_lock2").should.be.true |
| 751 | + REDIS_HANDLE.exists?("test_lock2").should.be.true |
693 | 752 | sleep 0.3 # expired, key is deleted |
694 | | - REDIS_HANDLE.exists("test_lock2").should.be.false |
| 753 | + REDIS_HANDLE.exists?("test_lock2").should.be.false |
695 | 754 | REDIS_HANDLE.set("test_lock2", "foo") # this is no longer a lock key, name is a coincidence |
696 | 755 | end |
697 | 756 |
|
698 | 757 | REDIS_HANDLE.get("test_lock2").should == "foo" |
699 | 758 | end |
700 | 759 |
|
701 | 760 | it "should manually delete the key if finished before expiration" do |
702 | | - lock = Redis::Lock.new(:test_lock3, :expiration => 0.5) |
| 761 | + lock = Redis::Lock.new(:test_lock3, :expiration => 1.0) |
703 | 762 |
|
704 | 763 | lock.lock do |
705 | | - REDIS_HANDLE.exists("test_lock3").should.be.true |
| 764 | + REDIS_HANDLE.exists?("test_lock3").should.be.true |
706 | 765 | sleep 0.1 |
707 | | - REDIS_HANDLE.exists("test_lock3").should.be.true |
| 766 | + REDIS_HANDLE.exists?("test_lock3").should.be.true |
708 | 767 | end |
709 | 768 |
|
710 | | - # should delete the key because the lock block is done, regardless of time |
| 769 | + # should delete the key because the lock block is done, regardless of expiry |
711 | 770 | # for some strange reason, I have seen this test fail randomly, which is worrisome. |
712 | | - #REDIS_HANDLE.exists("test_lock3").should.be.false |
| 771 | + REDIS_HANDLE.exists?("test_lock3").should.be.false |
713 | 772 | end |
714 | 773 |
|
715 | 774 |
|
|
929 | 988 | hsh['foo'].should == 'bar' |
930 | 989 | end |
931 | 990 |
|
| 991 | + it "should return multiple items via bulk_values" do |
| 992 | + @hash['taco'] = 42 |
| 993 | + @hash['burrito'] = 99 |
| 994 | + res = @hash.bulk_values('taco', 'burrito') |
| 995 | + res.should == ['42', '99'] # hashes don't convert |
| 996 | + end |
| 997 | + |
932 | 998 | it "should increment field" do |
933 | 999 | @hash.incr('counter') |
934 | 1000 | @hash.incr('counter') |
|
1036 | 1102 |
|
1037 | 1103 | it "should handle sets of simple values" do |
1038 | 1104 | @set.should.be.empty |
1039 | | - @set << 'a' << 'a' << 'a' |
| 1105 | + @set << 'a' |
| 1106 | + @set.randmember.should == 'a' |
| 1107 | + @set << 'a' << 'a' |
1040 | 1108 | @set.should == ['a'] |
1041 | 1109 | @set.to_s.should == 'a' |
1042 | 1110 | @set.get.should == ['a'] |
|
1077 | 1145 | coll = @set.select{|st| st == 'c'} |
1078 | 1146 | coll.should == ['c'] |
1079 | 1147 | @set.sort.should == ['a','b','c'] |
| 1148 | + @set.randmember.should.not == 'd' |
1080 | 1149 | @set.delete_if{|m| m == 'c'} |
1081 | 1150 | @set.sort.should == ['a','b'] |
1082 | 1151 |
|
1083 | 1152 | @set << nil |
1084 | 1153 | @set.include?("").should.be.true |
| 1154 | + @set.sort.should == ['','a','b'] |
1085 | 1155 | end |
1086 | 1156 |
|
1087 | 1157 | it "should handle empty array adds" do |
|
1197 | 1267 | @set_1.value.should == ['a'] |
1198 | 1268 | end |
1199 | 1269 |
|
| 1270 | + it "should support moving between sets" do |
| 1271 | + @set_1 << 'X' << 'Y' << 'Z' |
| 1272 | + @set_1.move('X', @set_2) |
| 1273 | + @set_2.should == ['X'] |
| 1274 | + end |
| 1275 | + |
1200 | 1276 | it "should respond to #to_json" do |
1201 | 1277 | @set_1 << 'a' |
1202 | 1278 | JSON.parse(@set_1.to_json)['value'].should == ['a'] |
|
1296 | 1372 | @set.to_s.should == 'a, b' |
1297 | 1373 | @set.should == ['a','b'] |
1298 | 1374 | @set.members.should == ['a','b'] |
| 1375 | + @set.member?('a').should == true |
| 1376 | + @set.member?('b').should == true |
| 1377 | + @set.member?('c').should == false |
1299 | 1378 | @set['d'] = 0 |
1300 | 1379 |
|
1301 | 1380 | @set.rangebyscore(0, 4).should == ['d','a'] |
|
1345 | 1424 |
|
1346 | 1425 | @set.delete_if{|m| m == 'b'} |
1347 | 1426 | @set.size.should == 3 |
| 1427 | + |
| 1428 | + # this is destructive so must come last |
| 1429 | + res = @set.remrangebyrank(0, 2) |
| 1430 | + res.should == 3 |
1348 | 1431 | end |
1349 | 1432 |
|
1350 | 1433 | it "should handle inserting multiple values at once" do |
|
0 commit comments