Skip to content

Commit 0409456

Browse files
committed
Expanded test coverage in prep for redis-rb 4.3
1 parent e00b8fa commit 0409456

File tree

6 files changed

+179
-44
lines changed

6 files changed

+179
-44
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ spec/redis.pid
99
dump.rdb
1010
Gemfile.lock
1111
redis-objects-*.gem
12+
coverage/

lib/redis/hash_key.rb

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -123,24 +123,20 @@ def bulk_get(*fields)
123123
hsh
124124
end
125125

126-
# Get values in bulk, takes an array of keys as arguments.
126+
# Get values in bulk, takes an array of fields as arguments.
127127
# Values are returned in a collection in the same order than their keys in *keys Redis: HMGET
128-
def bulk_values(*keys)
129-
get_keys = *keys.flatten
130-
return [] if get_keys.empty?
131-
res = redis.hmget(key, get_keys)
132-
get_keys.inject([]){|collection, k| collection << unmarshal(res.shift, options[:marshal_keys][k])}
128+
def bulk_values(*fields)
129+
get_fields = *fields.flatten
130+
return [] if get_fields.empty?
131+
res = redis.hmget(key, get_fields)
132+
get_fields.collect{|k| unmarshal(res.shift, options[:marshal_keys][k])}
133133
end
134134

135135
# Increment value by integer at field. Redis: HINCRBY
136136
def incrby(field, by=1)
137137
allow_expiration do
138138
ret = redis.hincrby(key, field, by)
139-
unless ret.is_a? Array
140-
ret.to_i
141-
else
142-
nil
143-
end
139+
ret.to_i
144140
end
145141
end
146142
alias_method :incr, :incrby
@@ -155,11 +151,7 @@ def decrby(field, by=1)
155151
def incrbyfloat(field, by=1.0)
156152
allow_expiration do
157153
ret = redis.hincrbyfloat(key, field, by)
158-
unless ret.is_a? Array
159-
ret.to_f
160-
else
161-
nil
162-
end
154+
ret.to_f
163155
end
164156
end
165157

lib/redis/helpers/core_commands.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ class Redis
22
module Helpers
33
# These are core commands that all types share (rename, etc)
44
module CoreCommands
5+
def exists
6+
redis.exists key
7+
end
8+
59
def exists?
610
redis.exists? key
711
end

spec/redis_objects_instance_spec.rb

Lines changed: 111 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@
1919
@value.value.should == false
2020
end
2121

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+
2237
it "should compress non marshaled values" do
2338
@value = Redis::Value.new('spec/value', compress: true)
2439
@value.value = 'Trevor Hoffman'
@@ -39,17 +54,8 @@
3954
@value.value.should == nil
4055
@value.value = ''
4156
@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
5359
end
5460

5561
it "should handle complex marshaled values" do
@@ -88,7 +94,7 @@
8894
marshalled_string = Marshal.dump({json: 'marshal'})
8995
@value = Redis::Value.new('spec/marshal', :default => marshalled_string, :marshal => true)
9096
@value.value.should == marshalled_string
91-
@value.clear
97+
@value.delete
9298
end
9399

94100
it "should support renaming values" do
@@ -499,6 +505,7 @@
499505
@counter.incrbyfloat 2.0e2
500506
@counter.to_f.should == 5214.31
501507
@counter.clear
508+
@counter.should.be.nil
502509
end
503510

504511
it "should support an atomic block" do
@@ -545,6 +552,9 @@
545552
@updated = @counter.decrement(1) { |updated| updated == 2 ? 'yep' : nil }
546553
@updated.should == 'yep'
547554
@counter.should == 2
555+
556+
@counter.value = nil
557+
@counter.should == 0
548558
end
549559

550560
it "should support #to_json" do
@@ -644,7 +654,7 @@
644654
REDIS_HANDLE.get("test_lock").should.be.nil
645655
end
646656

647-
it "should not let non-expired locks be gettable" do
657+
it "should not let blocks execute if they timeout" do
648658
expiry = 15
649659
lock = Redis::Lock.new(:test_lock, :expiration => expiry, :timeout => 0.1)
650660

@@ -669,47 +679,96 @@
669679
REDIS_HANDLE.get("test_lock").should.not.be.nil
670680
end
671681

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+
672732
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)
674734

675735
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
681739
end
682740

683741
# 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
685744
end
686745

687746

688747
it "should not manually delete a key with a 'lock' name if finished after expiration" do
689748
lock = Redis::Lock.new(:test_lock2, :expiration => 0.1)
690749

691750
lock.lock do
692-
REDIS_HANDLE.exists("test_lock2").should.be.true
751+
REDIS_HANDLE.exists?("test_lock2").should.be.true
693752
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
695754
REDIS_HANDLE.set("test_lock2", "foo") # this is no longer a lock key, name is a coincidence
696755
end
697756

698757
REDIS_HANDLE.get("test_lock2").should == "foo"
699758
end
700759

701760
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)
703762

704763
lock.lock do
705-
REDIS_HANDLE.exists("test_lock3").should.be.true
764+
REDIS_HANDLE.exists?("test_lock3").should.be.true
706765
sleep 0.1
707-
REDIS_HANDLE.exists("test_lock3").should.be.true
766+
REDIS_HANDLE.exists?("test_lock3").should.be.true
708767
end
709768

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
711770
# 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
713772
end
714773

715774

@@ -929,6 +988,13 @@
929988
hsh['foo'].should == 'bar'
930989
end
931990

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+
932998
it "should increment field" do
933999
@hash.incr('counter')
9341000
@hash.incr('counter')
@@ -1036,7 +1102,9 @@
10361102

10371103
it "should handle sets of simple values" do
10381104
@set.should.be.empty
1039-
@set << 'a' << 'a' << 'a'
1105+
@set << 'a'
1106+
@set.randmember.should == 'a'
1107+
@set << 'a' << 'a'
10401108
@set.should == ['a']
10411109
@set.to_s.should == 'a'
10421110
@set.get.should == ['a']
@@ -1077,11 +1145,13 @@
10771145
coll = @set.select{|st| st == 'c'}
10781146
coll.should == ['c']
10791147
@set.sort.should == ['a','b','c']
1148+
@set.randmember.should.not == 'd'
10801149
@set.delete_if{|m| m == 'c'}
10811150
@set.sort.should == ['a','b']
10821151

10831152
@set << nil
10841153
@set.include?("").should.be.true
1154+
@set.sort.should == ['','a','b']
10851155
end
10861156

10871157
it "should handle empty array adds" do
@@ -1197,6 +1267,12 @@
11971267
@set_1.value.should == ['a']
11981268
end
11991269

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+
12001276
it "should respond to #to_json" do
12011277
@set_1 << 'a'
12021278
JSON.parse(@set_1.to_json)['value'].should == ['a']
@@ -1296,6 +1372,9 @@
12961372
@set.to_s.should == 'a, b'
12971373
@set.should == ['a','b']
12981374
@set.members.should == ['a','b']
1375+
@set.member?('a').should == true
1376+
@set.member?('b').should == true
1377+
@set.member?('c').should == false
12991378
@set['d'] = 0
13001379

13011380
@set.rangebyscore(0, 4).should == ['d','a']
@@ -1345,6 +1424,10 @@
13451424

13461425
@set.delete_if{|m| m == 'b'}
13471426
@set.size.should == 3
1427+
1428+
# this is destructive so must come last
1429+
res = @set.remrangebyrank(0, 2)
1430+
res.should == 3
13481431
end
13491432

13501433
it "should handle inserting multiple values at once" do

0 commit comments

Comments
 (0)