|
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