ryansch-mock_redis 0.2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +20 -0
- data/Gemfile +9 -0
- data/LICENSE +19 -0
- data/README.md +94 -0
- data/Rakefile +10 -0
- data/lib/mock_redis.rb +32 -0
- data/lib/mock_redis/assertions.rb +13 -0
- data/lib/mock_redis/database.rb +432 -0
- data/lib/mock_redis/exceptions.rb +3 -0
- data/lib/mock_redis/expire_wrapper.rb +25 -0
- data/lib/mock_redis/hash_methods.rb +102 -0
- data/lib/mock_redis/list_methods.rb +187 -0
- data/lib/mock_redis/multi_db_wrapper.rb +86 -0
- data/lib/mock_redis/set_methods.rb +125 -0
- data/lib/mock_redis/string_methods.rb +195 -0
- data/lib/mock_redis/transaction_wrapper.rb +80 -0
- data/lib/mock_redis/undef_redis_methods.rb +11 -0
- data/lib/mock_redis/utility_methods.rb +22 -0
- data/lib/mock_redis/version.rb +3 -0
- data/lib/mock_redis/zset.rb +110 -0
- data/lib/mock_redis/zset_methods.rb +209 -0
- data/mock_redis.gemspec +24 -0
- data/spec/cloning_spec.rb +96 -0
- data/spec/commands/append_spec.rb +24 -0
- data/spec/commands/auth_spec.rb +7 -0
- data/spec/commands/bgrewriteaof_spec.rb +7 -0
- data/spec/commands/bgsave_spec.rb +7 -0
- data/spec/commands/blpop_spec.rb +55 -0
- data/spec/commands/brpop_spec.rb +54 -0
- data/spec/commands/brpoplpush_spec.rb +53 -0
- data/spec/commands/dbsize_spec.rb +18 -0
- data/spec/commands/decr_spec.rb +34 -0
- data/spec/commands/decrby_spec.rb +34 -0
- data/spec/commands/del_spec.rb +20 -0
- data/spec/commands/echo_spec.rb +11 -0
- data/spec/commands/exists_spec.rb +14 -0
- data/spec/commands/expire_spec.rb +83 -0
- data/spec/commands/expireat_spec.rb +48 -0
- data/spec/commands/flushall_spec.rb +38 -0
- data/spec/commands/flushdb_spec.rb +38 -0
- data/spec/commands/get_spec.rb +23 -0
- data/spec/commands/getbit_spec.rb +34 -0
- data/spec/commands/getrange_spec.rb +22 -0
- data/spec/commands/getset_spec.rb +23 -0
- data/spec/commands/hdel_spec.rb +35 -0
- data/spec/commands/hexists_spec.rb +22 -0
- data/spec/commands/hget_spec.rb +23 -0
- data/spec/commands/hgetall_spec.rb +22 -0
- data/spec/commands/hincrby_spec.rb +52 -0
- data/spec/commands/hkeys_spec.rb +19 -0
- data/spec/commands/hlen_spec.rb +19 -0
- data/spec/commands/hmget_spec.rb +30 -0
- data/spec/commands/hmset_spec.rb +43 -0
- data/spec/commands/hset_spec.rb +23 -0
- data/spec/commands/hsetnx_spec.rb +39 -0
- data/spec/commands/hvals_spec.rb +19 -0
- data/spec/commands/incr_spec.rb +34 -0
- data/spec/commands/incrby_spec.rb +44 -0
- data/spec/commands/info_spec.rb +13 -0
- data/spec/commands/keys_spec.rb +87 -0
- data/spec/commands/lastsave_spec.rb +8 -0
- data/spec/commands/lindex_spec.rb +39 -0
- data/spec/commands/linsert_spec.rb +68 -0
- data/spec/commands/llen_spec.rb +16 -0
- data/spec/commands/lpop_spec.rb +34 -0
- data/spec/commands/lpush_spec.rb +30 -0
- data/spec/commands/lpushx_spec.rb +33 -0
- data/spec/commands/lrange_spec.rb +35 -0
- data/spec/commands/lrem_spec.rb +79 -0
- data/spec/commands/lset_spec.rb +38 -0
- data/spec/commands/ltrim_spec.rb +35 -0
- data/spec/commands/mget_spec.rb +34 -0
- data/spec/commands/move_spec.rb +147 -0
- data/spec/commands/mset_spec.rb +29 -0
- data/spec/commands/msetnx_spec.rb +40 -0
- data/spec/commands/persist_spec.rb +49 -0
- data/spec/commands/ping_spec.rb +7 -0
- data/spec/commands/quit_spec.rb +7 -0
- data/spec/commands/randomkey_spec.rb +20 -0
- data/spec/commands/rename_spec.rb +31 -0
- data/spec/commands/renamenx_spec.rb +36 -0
- data/spec/commands/rpop_spec.rb +34 -0
- data/spec/commands/rpoplpush_spec.rb +45 -0
- data/spec/commands/rpush_spec.rb +30 -0
- data/spec/commands/rpushx_spec.rb +33 -0
- data/spec/commands/sadd_spec.rb +22 -0
- data/spec/commands/save_spec.rb +7 -0
- data/spec/commands/scard_spec.rb +18 -0
- data/spec/commands/sdiff_spec.rb +47 -0
- data/spec/commands/sdiffstore_spec.rb +58 -0
- data/spec/commands/select_spec.rb +53 -0
- data/spec/commands/set_spec.rb +7 -0
- data/spec/commands/setbit_spec.rb +46 -0
- data/spec/commands/setex_spec.rb +22 -0
- data/spec/commands/setnx_spec.rb +25 -0
- data/spec/commands/setrange_spec.rb +30 -0
- data/spec/commands/sinter_spec.rb +41 -0
- data/spec/commands/sinterstore_spec.rb +53 -0
- data/spec/commands/sismember_spec.rb +29 -0
- data/spec/commands/smembers_spec.rb +18 -0
- data/spec/commands/smove_spec.rb +41 -0
- data/spec/commands/spop_spec.rb +25 -0
- data/spec/commands/srandmember_spec.rb +25 -0
- data/spec/commands/srem_spec.rb +35 -0
- data/spec/commands/strlen_spec.rb +19 -0
- data/spec/commands/sunion_spec.rb +40 -0
- data/spec/commands/sunionstore_spec.rb +53 -0
- data/spec/commands/ttl_spec.rb +36 -0
- data/spec/commands/type_spec.rb +36 -0
- data/spec/commands/unwatch_spec.rb +7 -0
- data/spec/commands/watch_spec.rb +7 -0
- data/spec/commands/zadd_spec.rb +29 -0
- data/spec/commands/zcard_spec.rb +19 -0
- data/spec/commands/zcount_spec.rb +23 -0
- data/spec/commands/zincrby_spec.rb +24 -0
- data/spec/commands/zinterstore_spec.rb +96 -0
- data/spec/commands/zrange_spec.rb +31 -0
- data/spec/commands/zrangebyscore_spec.rb +68 -0
- data/spec/commands/zrank_spec.rb +23 -0
- data/spec/commands/zrem_spec.rb +25 -0
- data/spec/commands/zremrangebyrank_spec.rb +22 -0
- data/spec/commands/zremrangebyscore_spec.rb +28 -0
- data/spec/commands/zrevrange_spec.rb +31 -0
- data/spec/commands/zrevrangebyscore_spec.rb +47 -0
- data/spec/commands/zrevrank_spec.rb +23 -0
- data/spec/commands/zscore_spec.rb +16 -0
- data/spec/commands/zunionstore_spec.rb +104 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/support/redis_multiplexer.rb +91 -0
- data/spec/support/shared_examples/only_operates_on_hashes.rb +13 -0
- data/spec/support/shared_examples/only_operates_on_lists.rb +13 -0
- data/spec/support/shared_examples/only_operates_on_sets.rb +13 -0
- data/spec/support/shared_examples/only_operates_on_strings.rb +13 -0
- data/spec/support/shared_examples/only_operates_on_zsets.rb +57 -0
- data/spec/transactions_spec.rb +96 -0
- metadata +361 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "#zrevrank(key, member)" do
|
4
|
+
before do
|
5
|
+
@key = 'mock-redis-test:zrevrank'
|
6
|
+
|
7
|
+
@redises.zadd(@key, 1, 'one')
|
8
|
+
@redises.zadd(@key, 2, 'two')
|
9
|
+
@redises.zadd(@key, 3, 'three')
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns nil if member wasn't present in the set" do
|
13
|
+
@redises.zrevrank(@key, 'foo').should be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "returns the index of the member in the set (ordered by -score)" do
|
17
|
+
@redises.zrevrank(@key, 'one').should == 2
|
18
|
+
@redises.zrevrank(@key, 'two').should == 1
|
19
|
+
@redises.zrevrank(@key, 'three').should == 0
|
20
|
+
end
|
21
|
+
|
22
|
+
it_should_behave_like "a zset-only command"
|
23
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "#zscore(key, member)" do
|
4
|
+
before { @key = 'mock-redis-test:zscore' }
|
5
|
+
|
6
|
+
it "returns the score as a string" do
|
7
|
+
@redises.zadd(@key, 0.25, 'foo').should be_true
|
8
|
+
@redises.zscore(@key, 'foo').should == "0.25"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns nil if member is not present in the set" do
|
12
|
+
@redises.zscore(@key, 'foo').should be_nil
|
13
|
+
end
|
14
|
+
|
15
|
+
it_should_behave_like "a zset-only command"
|
16
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "#zunionstore(destination, keys, [:weights => [w,w,], [:aggregate => :sum|:min|:max])" do
|
4
|
+
before do
|
5
|
+
@set1 = 'mock-redis-test:zunionstore1'
|
6
|
+
@set2 = 'mock-redis-test:zunionstore2'
|
7
|
+
@set3 = 'mock-redis-test:zunionstore3'
|
8
|
+
@dest = 'mock-redis-test:zunionstoredest'
|
9
|
+
|
10
|
+
@redises.zadd(@set1, 1, 'one')
|
11
|
+
|
12
|
+
@redises.zadd(@set2, 1, 'one')
|
13
|
+
@redises.zadd(@set2, 2, 'two')
|
14
|
+
|
15
|
+
@redises.zadd(@set3, 1, 'one')
|
16
|
+
@redises.zadd(@set3, 2, 'two')
|
17
|
+
@redises.zadd(@set3, 3, 'three')
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns the number of elements in the new set" do
|
21
|
+
@redises.zunionstore(@dest, [@set1, @set2, @set3]).should == 3
|
22
|
+
end
|
23
|
+
|
24
|
+
it "sums the members' scores by default" do
|
25
|
+
@redises.zunionstore(@dest, [@set1, @set2, @set3])
|
26
|
+
@redises.zrange(@dest, 0, -1, :with_scores => true).should ==
|
27
|
+
%w[one 3 three 3 two 4]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "removes existing elements in destination" do
|
31
|
+
@redises.zadd(@dest, 10, 'ten')
|
32
|
+
|
33
|
+
@redises.zunionstore(@dest, [@set1])
|
34
|
+
@redises.zrange(@dest, 0, -1, :with_scores => true).should ==
|
35
|
+
%w[one 1]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "raises an error if keys is empty" do
|
39
|
+
lambda do
|
40
|
+
@redises.zunionstore(@dest, [])
|
41
|
+
end.should raise_error(RuntimeError)
|
42
|
+
end
|
43
|
+
|
44
|
+
context "the :weights argument" do
|
45
|
+
it "multiplies the scores by the weights while aggregating" do
|
46
|
+
@redises.zunionstore(@dest, [@set1, @set2, @set3], :weights => [2, 3, 5])
|
47
|
+
@redises.zrange(@dest, 0, -1, :with_scores => true).should ==
|
48
|
+
%w[one 10 three 15 two 16]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "raises an error if the number of weights != the number of keys" do
|
52
|
+
lambda do
|
53
|
+
@redises.zunionstore(@dest, [@set1, @set2, @set3], :weights => [1,2])
|
54
|
+
end.should raise_error(RuntimeError)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "the :aggregate argument" do
|
59
|
+
before do
|
60
|
+
@smalls = 'mock-redis-test:zunionstore:smalls'
|
61
|
+
@bigs = 'mock-redis-test:zunionstore:bigs'
|
62
|
+
|
63
|
+
@redises.zadd(@smalls, 1, 'bert')
|
64
|
+
@redises.zadd(@smalls, 2, 'ernie')
|
65
|
+
@redises.zadd(@bigs, 100, 'bert')
|
66
|
+
@redises.zadd(@bigs, 200, 'ernie')
|
67
|
+
end
|
68
|
+
|
69
|
+
it "aggregates scores with min when :aggregate => :min is specified" do
|
70
|
+
@redises.zunionstore(@dest, [@bigs, @smalls], :aggregate => :min)
|
71
|
+
@redises.zrange(@dest, 0, -1, :with_scores => true).should ==
|
72
|
+
%w[bert 1 ernie 2]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "aggregates scores with max when :aggregate => :max is specified" do
|
76
|
+
@redises.zunionstore(@dest, [@bigs, @smalls], :aggregate => :max)
|
77
|
+
@redises.zrange(@dest, 0, -1, :with_scores => true).should ==
|
78
|
+
%w[bert 100 ernie 200]
|
79
|
+
end
|
80
|
+
|
81
|
+
it "ignores scores for missing members" do
|
82
|
+
@redises.zadd(@smalls, 3, 'grover')
|
83
|
+
@redises.zunionstore(@dest, [@bigs, @smalls], :aggregate => :min)
|
84
|
+
@redises.zscore(@dest, 'grover').should == '3'
|
85
|
+
|
86
|
+
@redises.zunionstore(@dest, [@bigs, @smalls], :aggregate => :max)
|
87
|
+
@redises.zscore(@dest, 'grover').should == '3'
|
88
|
+
end
|
89
|
+
|
90
|
+
it "allows 'min', 'MIN', etc. as aliases for :min" do
|
91
|
+
@redises.zunionstore(@dest, [@bigs, @smalls], :aggregate => 'min')
|
92
|
+
@redises.zscore(@dest, 'bert').should == '1'
|
93
|
+
|
94
|
+
@redises.zunionstore(@dest, [@bigs, @smalls], :aggregate => 'MIN')
|
95
|
+
@redises.zscore(@dest, 'bert').should == '1'
|
96
|
+
end
|
97
|
+
|
98
|
+
it "raises an error for unknown aggregation function" do
|
99
|
+
lambda do
|
100
|
+
@redises.zunionstore(@dest, [@bigs, @smalls], :aggregate => :mix)
|
101
|
+
end.should raise_error(RuntimeError)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'redis'
|
3
|
+
$LOAD_PATH.unshift(File.expand_path(File.join(__FILE__, "..", "..", "lib")))
|
4
|
+
require 'mock_redis'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..')))
|
7
|
+
Dir["spec/support/**/*.rb"].each {|x| require x}
|
8
|
+
|
9
|
+
module TypeCheckingHelper
|
10
|
+
def method_from_description
|
11
|
+
# extracting this from the RSpec description string may or may not
|
12
|
+
# be a good idea. On the one hand, it enforces the convention of
|
13
|
+
# putting the method name in the right place; on the other hand,
|
14
|
+
# it's pretty magic-looking.
|
15
|
+
self.example.full_description.match(/#(\w+)/).captures.first
|
16
|
+
end
|
17
|
+
|
18
|
+
def args_for_method(method)
|
19
|
+
method_arity = @redises.real.method(method).arity
|
20
|
+
if method_arity < 0 # -1 comes from def foo(*args)
|
21
|
+
[1, 2] # probably good enough
|
22
|
+
else
|
23
|
+
1.upto(method_arity - 1).to_a
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec.configure do |config|
|
29
|
+
config.include(TypeCheckingHelper)
|
30
|
+
|
31
|
+
config.before(:all) do
|
32
|
+
@redises = RedisMultiplexer.new
|
33
|
+
end
|
34
|
+
|
35
|
+
config.before(:each) do
|
36
|
+
# databases mentioned in our tests
|
37
|
+
[1, 0].each do |db|
|
38
|
+
@redises.send_without_checking(:select, db)
|
39
|
+
@redises.send_without_checking(:keys, "mock-redis-test:*").each do |key|
|
40
|
+
@redises.send_without_checking(:del, key)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
class BlankSlate
|
2
|
+
instance_methods.each {|m| undef_method(m) unless m =~ /^__/ || ['inspect', 'object_id'].include?(m.to_s)}
|
3
|
+
end
|
4
|
+
|
5
|
+
class RedisMultiplexer < BlankSlate
|
6
|
+
MismatchedResponse = Class.new(StandardError)
|
7
|
+
|
8
|
+
def initialize(*a)
|
9
|
+
@mock_redis = MockRedis.new(*a)
|
10
|
+
@real_redis = Redis.new(*a)
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(method, *args, &blk)
|
14
|
+
mock_retval, mock_error = catch_errors { @mock_redis.send(method, *args, &blk) }
|
15
|
+
real_retval, real_error = catch_errors { @real_redis.send(method, *args, &blk) }
|
16
|
+
|
17
|
+
mock_retval = handle_special_cases(method, mock_retval)
|
18
|
+
real_retval = handle_special_cases(method, real_retval)
|
19
|
+
|
20
|
+
if (!equalish?(mock_retval, real_retval) && !mock_error && !real_error)
|
21
|
+
# no exceptions, just different behavior
|
22
|
+
raise MismatchedResponse,
|
23
|
+
"Mock failure: responses not equal.\n" +
|
24
|
+
"Redis.#{method}(#{args.inspect}) returned #{real_retval.inspect}\n" +
|
25
|
+
"MockRedis.#{method}(#{args.inspect}) returned #{mock_retval.inspect}\n"
|
26
|
+
elsif (!mock_error && real_error)
|
27
|
+
raise MismatchedResponse,
|
28
|
+
"Mock failure: didn't raise an error when it should have.\n" +
|
29
|
+
"Redis.#{method}(#{args.inspect}) raised #{real_error.inspect}\n" +
|
30
|
+
"MockRedis.#{method}(#{args.inspect}) raised nothing " +
|
31
|
+
"and returned #{mock_retval.inspect}"
|
32
|
+
elsif (!real_error && mock_error)
|
33
|
+
raise MismatchedResponse,
|
34
|
+
"Mock failure: raised an error when it shouldn't have.\n" +
|
35
|
+
"Redis.#{method}(#{args.inspect}) returned #{real_retval.inspect}\n" +
|
36
|
+
"MockRedis.#{method}(#{args.inspect}) raised #{mock_error.inspect}"
|
37
|
+
elsif (mock_error && real_error && !equalish?(mock_error, real_error))
|
38
|
+
raise MismatchedResponse,
|
39
|
+
"Mock failure: raised the wrong error.\n" +
|
40
|
+
"Redis.#{method}(#{args.inspect}) raised #{real_error.inspect}\n" +
|
41
|
+
"MockRedis.#{method}(#{args.inspect}) raised #{mock_error.inspect}"
|
42
|
+
end
|
43
|
+
|
44
|
+
raise mock_error if mock_error
|
45
|
+
mock_retval
|
46
|
+
end
|
47
|
+
|
48
|
+
def equalish?(a, b)
|
49
|
+
if a == b
|
50
|
+
true
|
51
|
+
elsif a.is_a?(Array) && b.is_a?(Array)
|
52
|
+
a.zip(b).all? {|(x,y)| equalish?(x,y)}
|
53
|
+
elsif a.is_a?(Exception) && b.is_a?(Exception)
|
54
|
+
a.class == b.class && a.message == b.message
|
55
|
+
else
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def mock() @mock_redis end
|
61
|
+
def real() @real_redis end
|
62
|
+
|
63
|
+
# Some commands require special handling due to nondeterminism in
|
64
|
+
# the returned values.
|
65
|
+
def handle_special_cases(method, value)
|
66
|
+
case method.to_s
|
67
|
+
when 'keys', 'hkeys', 'sdiff', 'sinter', 'smembers', 'sunion'
|
68
|
+
# The order is irrelevant, but [a,b] != [b,a] in Ruby, so we
|
69
|
+
# sort the returned values so we can ignore the order.
|
70
|
+
value.sort if value
|
71
|
+
else
|
72
|
+
value
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Used in cleanup before() blocks.
|
77
|
+
def send_without_checking(method, *args)
|
78
|
+
@mock_redis.send(method, *args)
|
79
|
+
@real_redis.send(method, *args)
|
80
|
+
end
|
81
|
+
|
82
|
+
def catch_errors
|
83
|
+
begin
|
84
|
+
retval = yield
|
85
|
+
[retval, nil]
|
86
|
+
rescue StandardError => e
|
87
|
+
[nil, e]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
shared_examples_for "a hash-only command" do
|
2
|
+
it "raises an error for non-hash values" do
|
3
|
+
key = 'mock-redis-test:hash-only'
|
4
|
+
|
5
|
+
method = method_from_description
|
6
|
+
args = args_for_method(method).unshift(key)
|
7
|
+
|
8
|
+
@redises.set(key, 1)
|
9
|
+
lambda do
|
10
|
+
@redises.send(method, *args)
|
11
|
+
end.should raise_error(RuntimeError)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
shared_examples_for "a list-only command" do
|
2
|
+
it "raises an error for non-list values" do
|
3
|
+
key = 'mock-redis-test:list-only'
|
4
|
+
|
5
|
+
method = method_from_description
|
6
|
+
args = args_for_method(method).unshift(key)
|
7
|
+
|
8
|
+
@redises.set(key, 1)
|
9
|
+
lambda do
|
10
|
+
@redises.send(method, *args)
|
11
|
+
end.should raise_error(RuntimeError)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
shared_examples_for "a set-only command" do
|
2
|
+
it "raises an error for non-set values" do
|
3
|
+
key = 'mock-redis-test:set-only'
|
4
|
+
|
5
|
+
method = method_from_description
|
6
|
+
args = args_for_method(method).unshift(key)
|
7
|
+
|
8
|
+
@redises.set(key, 1)
|
9
|
+
lambda do
|
10
|
+
@redises.send(method, *args)
|
11
|
+
end.should raise_error(RuntimeError)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
shared_examples_for "a string-only command" do
|
2
|
+
it "raises an error for non-string values" do
|
3
|
+
key = "mock-redis-test:string-only-command"
|
4
|
+
|
5
|
+
method = method_from_description
|
6
|
+
args = args_for_method(method).unshift(key)
|
7
|
+
|
8
|
+
@redises.lpush(key, 1)
|
9
|
+
lambda do
|
10
|
+
@redises.send(method, *args)
|
11
|
+
end.should raise_error(RuntimeError)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
shared_examples_for "a zset-only command" do
|
2
|
+
it "raises an error for non-zset values" do
|
3
|
+
key = 'mock-redis-test:zset-only'
|
4
|
+
|
5
|
+
method = method_from_description
|
6
|
+
args = args_for_method(method).unshift(key)
|
7
|
+
|
8
|
+
@redises.set(key, 1)
|
9
|
+
lambda do
|
10
|
+
@redises.send(method, *args)
|
11
|
+
end.should raise_error(RuntimeError)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
shared_examples_for "arg 1 is a score" do
|
16
|
+
before { @_arg_index = 1 }
|
17
|
+
it_should_behave_like "arg N is a score"
|
18
|
+
end
|
19
|
+
|
20
|
+
shared_examples_for "arg 2 is a score" do
|
21
|
+
before { @_arg_index = 2 }
|
22
|
+
it_should_behave_like "arg N is a score"
|
23
|
+
end
|
24
|
+
|
25
|
+
shared_examples_for "arg N is a score" do
|
26
|
+
before do
|
27
|
+
key = 'mock-redis-test:zset-only'
|
28
|
+
|
29
|
+
@method = method_from_description
|
30
|
+
@args = args_for_method(@method).unshift(key)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "is okay with positive ints" do
|
34
|
+
@args[@_arg_index] = 1
|
35
|
+
lambda { @redises.send(@method, *@args) }.should_not raise_error
|
36
|
+
end
|
37
|
+
|
38
|
+
it "is okay with negative ints" do
|
39
|
+
@args[@_arg_index] = -1
|
40
|
+
lambda { @redises.send(@method, *@args) }.should_not raise_error
|
41
|
+
end
|
42
|
+
|
43
|
+
it "is okay with positive floats" do
|
44
|
+
@args[@_arg_index] = 1.5
|
45
|
+
lambda { @redises.send(@method, *@args) }.should_not raise_error
|
46
|
+
end
|
47
|
+
|
48
|
+
it "is okay with negative floats" do
|
49
|
+
@args[@_arg_index] = 1.5
|
50
|
+
lambda { @redises.send(@method, *@args) }.should_not raise_error
|
51
|
+
end
|
52
|
+
|
53
|
+
it "rejects non-numbers" do
|
54
|
+
@args[@_arg_index] = 'foo'
|
55
|
+
lambda { @redises.send(@method, *@args) }.should raise_error(RuntimeError)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'transactions (multi/exec/discard)' do
|
4
|
+
before(:each) do
|
5
|
+
@redises.discard rescue nil
|
6
|
+
end
|
7
|
+
|
8
|
+
context "#multi" do
|
9
|
+
it "responds with 'OK'" do
|
10
|
+
@redises.multi.should == 'OK'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "forbids nesting" do
|
14
|
+
@redises.multi
|
15
|
+
lambda do
|
16
|
+
@redises.multi
|
17
|
+
end.should raise_error(RuntimeError)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "#blocks" do
|
22
|
+
it "implicitly runs exec when finished" do
|
23
|
+
@redises.set("counter", 5)
|
24
|
+
@redises.multi do |r|
|
25
|
+
r.set("test", 1)
|
26
|
+
r.incr("counter")
|
27
|
+
end
|
28
|
+
@redises.get("counter").should == "6"
|
29
|
+
@redises.get("test").should == "1"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "forbids nesting via blocks" do
|
33
|
+
# Have to use only the mock here. redis-rb has a bug in it where
|
34
|
+
# nested #multi calls raise NoMethodError because it gets a nil
|
35
|
+
# where it's not expecting one.
|
36
|
+
@redises.mock.multi do |r|
|
37
|
+
lambda do
|
38
|
+
r.multi {}
|
39
|
+
end.should raise_error(RuntimeError)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "#discard" do
|
45
|
+
it "responds with 'OK' after #multi" do
|
46
|
+
@redises.multi
|
47
|
+
@redises.discard.should == 'OK'
|
48
|
+
end
|
49
|
+
|
50
|
+
it "can't be run outside of #multi/#exec" do
|
51
|
+
lambda do
|
52
|
+
@redises.discard
|
53
|
+
end.should raise_error(RuntimeError)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "#exec" do
|
58
|
+
it "raises an error outside of #multi" do
|
59
|
+
lambda do
|
60
|
+
@redises.exec.should raise_error
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "saving up commands for later" do
|
66
|
+
before(:each) do
|
67
|
+
@redises.multi
|
68
|
+
@string = 'mock-redis-test:string'
|
69
|
+
@list = 'mock-redis-test:list'
|
70
|
+
end
|
71
|
+
|
72
|
+
it "makes commands respond with 'QUEUED'" do
|
73
|
+
@redises.set(@string, 'string').should == 'QUEUED'
|
74
|
+
@redises.lpush(@list, 'list').should == 'QUEUED'
|
75
|
+
end
|
76
|
+
|
77
|
+
it "gives you the commands' responses when you call #exec" do
|
78
|
+
@redises.set(@string, 'string')
|
79
|
+
@redises.lpush(@list, 'list')
|
80
|
+
@redises.lpush(@list, 'list')
|
81
|
+
|
82
|
+
@redises.exec.should == ['OK', 1, 2]
|
83
|
+
end
|
84
|
+
|
85
|
+
it "does not raise exceptions, but rather puts them in #exec's response" do
|
86
|
+
@redises.set(@string, 'string')
|
87
|
+
@redises.lpush(@string, 'oops!')
|
88
|
+
@redises.lpush(@list, 'list')
|
89
|
+
|
90
|
+
responses = @redises.exec
|
91
|
+
responses[0].should == 'OK'
|
92
|
+
responses[1].should be_a(RuntimeError)
|
93
|
+
responses[2].should == 1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|