mock_redis 0.5.4 → 0.31.0

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.
Files changed (201) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/lint.yml +31 -0
  3. data/.github/workflows/tests.yml +63 -0
  4. data/.gitignore +1 -1
  5. data/.overcommit.yml +21 -0
  6. data/.rspec +1 -1
  7. data/.rubocop.yml +148 -0
  8. data/.rubocop_todo.yml +35 -0
  9. data/.simplecov +4 -0
  10. data/CHANGELOG.md +278 -0
  11. data/Gemfile +9 -5
  12. data/LICENSE.md +21 -0
  13. data/README.md +52 -16
  14. data/Rakefile +0 -8
  15. data/lib/mock_redis/assertions.rb +0 -1
  16. data/lib/mock_redis/connection_method.rb +13 -0
  17. data/lib/mock_redis/database.rb +193 -257
  18. data/lib/mock_redis/expire_wrapper.rb +2 -2
  19. data/lib/mock_redis/future.rb +23 -0
  20. data/lib/mock_redis/geospatial_methods.rb +240 -0
  21. data/lib/mock_redis/hash_methods.rb +83 -24
  22. data/lib/mock_redis/indifferent_hash.rb +11 -0
  23. data/lib/mock_redis/info_method.rb +160 -0
  24. data/lib/mock_redis/list_methods.rb +34 -19
  25. data/lib/mock_redis/multi_db_wrapper.rb +8 -7
  26. data/lib/mock_redis/pipelined_wrapper.rb +42 -16
  27. data/lib/mock_redis/set_methods.rb +62 -19
  28. data/lib/mock_redis/sort_method.rb +81 -0
  29. data/lib/mock_redis/stream/id.rb +58 -0
  30. data/lib/mock_redis/stream.rb +88 -0
  31. data/lib/mock_redis/stream_methods.rb +102 -0
  32. data/lib/mock_redis/string_methods.rb +235 -42
  33. data/lib/mock_redis/transaction_wrapper.rb +62 -28
  34. data/lib/mock_redis/utility_methods.rb +62 -11
  35. data/lib/mock_redis/version.rb +4 -1
  36. data/lib/mock_redis/zset.rb +24 -29
  37. data/lib/mock_redis/zset_methods.rb +187 -59
  38. data/lib/mock_redis.rb +77 -27
  39. data/mock_redis.gemspec +23 -15
  40. data/spec/client_spec.rb +29 -0
  41. data/spec/cloning_spec.rb +17 -18
  42. data/spec/commands/append_spec.rb +4 -4
  43. data/spec/commands/auth_spec.rb +1 -1
  44. data/spec/commands/bgrewriteaof_spec.rb +2 -2
  45. data/spec/commands/bgsave_spec.rb +2 -2
  46. data/spec/commands/bitcount_spec.rb +25 -0
  47. data/spec/commands/bitfield_spec.rb +169 -0
  48. data/spec/commands/blpop_spec.rb +19 -21
  49. data/spec/commands/brpop_spec.rb +25 -20
  50. data/spec/commands/brpoplpush_spec.rb +16 -17
  51. data/spec/commands/connected_spec.rb +7 -0
  52. data/spec/commands/connection_spec.rb +15 -0
  53. data/spec/commands/dbsize_spec.rb +3 -3
  54. data/spec/commands/decr_spec.rb +8 -8
  55. data/spec/commands/decrby_spec.rb +8 -8
  56. data/spec/commands/del_spec.rb +35 -3
  57. data/spec/commands/disconnect_spec.rb +7 -0
  58. data/spec/commands/dump_spec.rb +19 -0
  59. data/spec/commands/echo_spec.rb +4 -4
  60. data/spec/commands/eval_spec.rb +7 -0
  61. data/spec/commands/evalsha_spec.rb +10 -0
  62. data/spec/commands/exists_spec.rb +36 -7
  63. data/spec/commands/expire_spec.rb +48 -20
  64. data/spec/commands/expireat_spec.rb +12 -13
  65. data/spec/commands/flushall_spec.rb +5 -5
  66. data/spec/commands/flushdb_spec.rb +5 -5
  67. data/spec/commands/future_spec.rb +30 -0
  68. data/spec/commands/geoadd_spec.rb +58 -0
  69. data/spec/commands/geodist_spec.rb +118 -0
  70. data/spec/commands/geohash_spec.rb +52 -0
  71. data/spec/commands/geopos_spec.rb +55 -0
  72. data/spec/commands/get_spec.rb +14 -6
  73. data/spec/commands/getbit_spec.rb +7 -7
  74. data/spec/commands/getrange_spec.rb +9 -9
  75. data/spec/commands/getset_spec.rb +7 -7
  76. data/spec/commands/hdel_spec.rb +41 -11
  77. data/spec/commands/hexists_spec.rb +11 -11
  78. data/spec/commands/hget_spec.rb +7 -7
  79. data/spec/commands/hgetall_spec.rb +15 -5
  80. data/spec/commands/hincrby_spec.rb +16 -16
  81. data/spec/commands/hincrbyfloat_spec.rb +58 -0
  82. data/spec/commands/hkeys_spec.rb +5 -5
  83. data/spec/commands/hlen_spec.rb +5 -5
  84. data/spec/commands/hmget_spec.rb +19 -9
  85. data/spec/commands/hmset_spec.rb +38 -12
  86. data/spec/commands/hscan_each_spec.rb +48 -0
  87. data/spec/commands/hscan_spec.rb +27 -0
  88. data/spec/commands/hset_spec.rb +26 -12
  89. data/spec/commands/hsetnx_spec.rb +16 -16
  90. data/spec/commands/hvals_spec.rb +5 -5
  91. data/spec/commands/incr_spec.rb +8 -8
  92. data/spec/commands/incrby_spec.rb +13 -13
  93. data/spec/commands/incrbyfloat_spec.rb +13 -13
  94. data/spec/commands/info_spec.rb +54 -5
  95. data/spec/commands/keys_spec.rb +83 -31
  96. data/spec/commands/lastsave_spec.rb +2 -2
  97. data/spec/commands/lindex_spec.rb +20 -10
  98. data/spec/commands/linsert_spec.rb +14 -14
  99. data/spec/commands/llen_spec.rb +4 -4
  100. data/spec/commands/lpop_spec.rb +6 -6
  101. data/spec/commands/lpush_spec.rb +21 -15
  102. data/spec/commands/lpushx_spec.rb +24 -11
  103. data/spec/commands/lrange_spec.rb +24 -8
  104. data/spec/commands/lrem_spec.rb +16 -16
  105. data/spec/commands/lset_spec.rb +17 -12
  106. data/spec/commands/ltrim_spec.rb +17 -7
  107. data/spec/commands/mapped_hmget_spec.rb +13 -9
  108. data/spec/commands/mapped_hmset_spec.rb +12 -12
  109. data/spec/commands/mapped_mget_spec.rb +22 -0
  110. data/spec/commands/mapped_mset_spec.rb +19 -0
  111. data/spec/commands/mapped_msetnx_spec.rb +26 -0
  112. data/spec/commands/mget_spec.rb +48 -17
  113. data/spec/commands/move_spec.rb +37 -37
  114. data/spec/commands/mset_spec.rb +20 -6
  115. data/spec/commands/msetnx_spec.rb +14 -14
  116. data/spec/commands/persist_spec.rb +15 -16
  117. data/spec/commands/pexpire_spec.rb +86 -0
  118. data/spec/commands/pexpireat_spec.rb +48 -0
  119. data/spec/commands/ping_spec.rb +6 -2
  120. data/spec/commands/pipelined_spec.rb +98 -7
  121. data/spec/commands/pttl_spec.rb +41 -0
  122. data/spec/commands/randomkey_spec.rb +3 -3
  123. data/spec/commands/rename_spec.rb +16 -12
  124. data/spec/commands/renamenx_spec.rb +13 -15
  125. data/spec/commands/restore_spec.rb +47 -0
  126. data/spec/commands/rpop_spec.rb +6 -6
  127. data/spec/commands/rpoplpush_spec.rb +13 -8
  128. data/spec/commands/rpush_spec.rb +21 -15
  129. data/spec/commands/rpushx_spec.rb +24 -11
  130. data/spec/commands/sadd_spec.rb +14 -10
  131. data/spec/commands/scan_each_spec.rb +39 -0
  132. data/spec/commands/scan_spec.rb +64 -0
  133. data/spec/commands/scard_spec.rb +3 -3
  134. data/spec/commands/script_spec.rb +9 -0
  135. data/spec/commands/sdiff_spec.rb +13 -13
  136. data/spec/commands/sdiffstore_spec.rb +13 -13
  137. data/spec/commands/select_spec.rb +13 -5
  138. data/spec/commands/set_spec.rb +112 -0
  139. data/spec/commands/setbit_spec.rb +25 -16
  140. data/spec/commands/setex_spec.rb +20 -4
  141. data/spec/commands/setnx_spec.rb +6 -6
  142. data/spec/commands/setrange_spec.rb +12 -12
  143. data/spec/commands/sinter_spec.rb +11 -13
  144. data/spec/commands/sinterstore_spec.rb +12 -12
  145. data/spec/commands/sismember_spec.rb +10 -10
  146. data/spec/commands/smembers_spec.rb +15 -5
  147. data/spec/commands/smove_spec.rb +13 -13
  148. data/spec/commands/sort_list_spec.rb +21 -0
  149. data/spec/commands/sort_set_spec.rb +21 -0
  150. data/spec/commands/sort_zset_spec.rb +21 -0
  151. data/spec/commands/spop_spec.rb +19 -4
  152. data/spec/commands/srandmember_spec.rb +28 -4
  153. data/spec/commands/srem_spec.rb +17 -12
  154. data/spec/commands/sscan_each_spec.rb +48 -0
  155. data/spec/commands/sscan_spec.rb +39 -0
  156. data/spec/commands/strlen_spec.rb +4 -5
  157. data/spec/commands/sunion_spec.rb +13 -11
  158. data/spec/commands/sunionstore_spec.rb +12 -12
  159. data/spec/commands/ttl_spec.rb +11 -6
  160. data/spec/commands/type_spec.rb +1 -1
  161. data/spec/commands/watch_spec.rb +9 -4
  162. data/spec/commands/xadd_spec.rb +122 -0
  163. data/spec/commands/xlen_spec.rb +22 -0
  164. data/spec/commands/xrange_spec.rb +164 -0
  165. data/spec/commands/xread_spec.rb +66 -0
  166. data/spec/commands/xrevrange_spec.rb +130 -0
  167. data/spec/commands/xtrim_spec.rb +36 -0
  168. data/spec/commands/zadd_spec.rb +100 -11
  169. data/spec/commands/zcard_spec.rb +4 -4
  170. data/spec/commands/zcount_spec.rb +18 -10
  171. data/spec/commands/zincrby_spec.rb +6 -6
  172. data/spec/commands/zinterstore_spec.rb +54 -20
  173. data/spec/commands/zpopmax_spec.rb +60 -0
  174. data/spec/commands/zpopmin_spec.rb +60 -0
  175. data/spec/commands/zrange_spec.rb +54 -13
  176. data/spec/commands/zrangebyscore_spec.rb +42 -27
  177. data/spec/commands/zrank_spec.rb +4 -4
  178. data/spec/commands/zrem_spec.rb +18 -12
  179. data/spec/commands/zremrangebyrank_spec.rb +5 -5
  180. data/spec/commands/zremrangebyscore_spec.rb +12 -5
  181. data/spec/commands/zrevrange_spec.rb +35 -10
  182. data/spec/commands/zrevrangebyscore_spec.rb +26 -15
  183. data/spec/commands/zrevrank_spec.rb +4 -4
  184. data/spec/commands/zscan_each_spec.rb +48 -0
  185. data/spec/commands/zscan_spec.rb +26 -0
  186. data/spec/commands/zscore_spec.rb +7 -7
  187. data/spec/commands/zunionstore_spec.rb +54 -21
  188. data/spec/mock_redis_spec.rb +61 -0
  189. data/spec/spec_helper.rb +35 -8
  190. data/spec/support/redis_multiplexer.rb +62 -37
  191. data/spec/support/shared_examples/does_not_cleanup_empty_strings.rb +14 -0
  192. data/spec/support/shared_examples/only_operates_on_hashes.rb +5 -3
  193. data/spec/support/shared_examples/only_operates_on_lists.rb +5 -3
  194. data/spec/support/shared_examples/only_operates_on_sets.rb +5 -3
  195. data/spec/support/shared_examples/only_operates_on_strings.rb +4 -4
  196. data/spec/support/shared_examples/only_operates_on_zsets.rb +18 -16
  197. data/spec/support/shared_examples/sorts_enumerables.rb +56 -0
  198. data/spec/transactions_spec.rb +79 -29
  199. metadata +162 -42
  200. data/LICENSE +0 -19
  201. data/spec/commands/hash_operator_spec.rb +0 -21
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#sort(key, options)' do
4
+ before do
5
+ @key = 'mock-redis-test:set_sort'
6
+
7
+ @redises.sadd(@key, '1')
8
+ @redises.sadd(@key, '2')
9
+
10
+ @redises.set('mock-redis-test:values_1', 'a')
11
+ @redises.set('mock-redis-test:values_2', 'b')
12
+
13
+ @redises.set('mock-redis-test:weight_1', '2')
14
+ @redises.set('mock-redis-test:weight_2', '1')
15
+
16
+ @redises.hset('mock-redis-test:hash_1', 'key', 'x')
17
+ @redises.hset('mock-redis-test:hash_2', 'key', 'y')
18
+ end
19
+
20
+ it_should_behave_like 'a sortable'
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#sort(key, options)' do
4
+ before do
5
+ @key = 'mock-redis-test:zset_sort'
6
+
7
+ @redises.zadd(@key, 100, '1')
8
+ @redises.zadd(@key, 99, '2')
9
+
10
+ @redises.set('mock-redis-test:values_1', 'a')
11
+ @redises.set('mock-redis-test:values_2', 'b')
12
+
13
+ @redises.set('mock-redis-test:weight_1', '2')
14
+ @redises.set('mock-redis-test:weight_2', '1')
15
+
16
+ @redises.hset('mock-redis-test:hash_1', 'key', 'x')
17
+ @redises.hset('mock-redis-test:hash_2', 'key', 'y')
18
+ end
19
+
20
+ it_should_behave_like 'a sortable'
21
+ end
@@ -7,19 +7,34 @@ describe '#spop(key)' do
7
7
  @redises.sadd(@key, 'value')
8
8
  end
9
9
 
10
- it "returns a member of the set" do
10
+ it 'returns a member of the set' do
11
11
  @redises.spop(@key).should == 'value'
12
12
  end
13
13
 
14
- it "removes a member of the set" do
14
+ it 'removes a member of the set' do
15
15
  @redises.spop(@key)
16
16
  @redises.smembers(@key).should == []
17
17
  end
18
18
 
19
- it "returns nil if the set is empty" do
19
+ it 'returns nil if the set is empty' do
20
20
  @redises.spop(@key)
21
21
  @redises.spop(@key).should be_nil
22
22
  end
23
23
 
24
- it_should_behave_like "a set-only command"
24
+ it 'returns an array if count is not nil' do
25
+ @redises.sadd(@key, 'value2')
26
+ @redises.spop(@key, 2).should == %w[value value2]
27
+ end
28
+
29
+ it 'returns only whats in the set' do
30
+ @redises.spop(@key, 2).should == ['value']
31
+ @redises.smembers(@key).should == []
32
+ end
33
+
34
+ it 'returns an empty array if count is not nil and the set it empty' do
35
+ @redises.spop(@key)
36
+ @redises.spop(@key, 100).should == []
37
+ end
38
+
39
+ it_should_behave_like 'a set-only command'
25
40
  end
@@ -7,19 +7,43 @@ describe '#srandmember(key)' do
7
7
  @redises.sadd(@key, 'value')
8
8
  end
9
9
 
10
- it "returns a member of the set" do
10
+ it 'returns a member of the set' do
11
11
  @redises.srandmember(@key).should == 'value'
12
12
  end
13
13
 
14
- it "does not modify the set" do
14
+ it 'does not modify the set' do
15
15
  @redises.srandmember(@key)
16
16
  @redises.smembers(@key).should == ['value']
17
17
  end
18
18
 
19
- it "returns nil if the set is empty" do
19
+ it 'returns nil if the set is empty' do
20
20
  @redises.spop(@key)
21
21
  @redises.srandmember(@key).should be_nil
22
22
  end
23
23
 
24
- it_should_behave_like "a set-only command"
24
+ context 'when count argument is specified' do
25
+ before do
26
+ @redises.sadd(@key, 'value2')
27
+ @redises.sadd(@key, 'value3')
28
+ end
29
+
30
+ # NOTE: We disable result checking since MockRedis and Redis will likely
31
+ # return a different random set (since the selection is, well, random)
32
+ it 'returns the whole set if count is greater than the set size' do
33
+ @redises.send_without_checking(:srandmember, @key, 5).should =~ %w[value value2 value3]
34
+ end
35
+
36
+ it 'returns random members up to count from the set when count is smaller than the set size' do
37
+ @redises.send_without_checking(:srandmember, @key, 2).size.should == 2
38
+ end
39
+
40
+ it 'returns random members up to count from the set when count is negative even if count.abs is greater than the set size' do # rubocop:disable Layout/LineLength
41
+ @redises.send_without_checking(:srandmember, @key, -5).size.should == 5
42
+ end
43
+
44
+ it 'returns nil if the set is empty' do
45
+ @redises.srem(@key, %w[value value2 value3])
46
+ @redises.srandmember(@key, 2).should be_empty
47
+ end
48
+ end
25
49
  end
@@ -8,33 +8,38 @@ describe '#srem(key, member)' do
8
8
  @redises.sadd(@key, 'ernie')
9
9
  end
10
10
 
11
- it "returns true if member is in the set" do
12
- @redises.srem(@key, 'bert').should be_true
11
+ it 'returns true if member is in the set' do
12
+ @redises.srem(@key, 'bert').should == true
13
13
  end
14
14
 
15
- it "returns false if member is not in the set" do
16
- @redises.srem(@key, 'cookiemonster').should be_false
15
+ it 'returns false if member is not in the set' do
16
+ @redises.srem(@key, 'cookiemonster').should == false
17
17
  end
18
18
 
19
- it "removes member from the set" do
19
+ it 'removes member from the set' do
20
20
  @redises.srem(@key, 'ernie')
21
21
  @redises.smembers(@key).should == ['bert']
22
22
  end
23
23
 
24
- it "stringifies member" do
24
+ it 'stringifies member' do
25
25
  @redises.sadd(@key, '1')
26
- @redises.srem(@key, 1).should be_true
26
+ @redises.srem(@key, 1).should == true
27
27
  end
28
28
 
29
- it "cleans up empty sets" do
30
- @redises.smembers(@key).each {|m| @redises.srem(@key, m)}
29
+ it 'cleans up empty sets' do
30
+ @redises.smembers(@key).each { |m| @redises.srem(@key, m) }
31
31
  @redises.get(@key).should be_nil
32
32
  end
33
33
 
34
- it "supports a variable number of arguments" do
35
- @redises.srem(@key, ['bert', 'ernie']).should == 2
34
+ it 'supports a variable number of arguments' do
35
+ @redises.srem(@key, %w[bert ernie]).should == 2
36
36
  @redises.get(@key).should be_nil
37
37
  end
38
38
 
39
- it_should_behave_like "a set-only command"
39
+ it 'allow passing an array of integers as argument' do
40
+ @redises.sadd(@key, %w[1 2])
41
+ @redises.srem(@key, [1, 2]).should == 2
42
+ end
43
+
44
+ it_should_behave_like 'a set-only command'
40
45
  end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#sscan_each' do
4
+ subject { MockRedis::Database.new(self) }
5
+
6
+ let(:key) { 'mock-redis-test:sscan_each' }
7
+
8
+ before do
9
+ allow(subject).to receive(:smembers).and_return(collection)
10
+ end
11
+
12
+ context 'when no keys are found' do
13
+ let(:collection) { [] }
14
+
15
+ it 'does not iterate over any elements' do
16
+ results = subject.sscan_each(key).map do |k|
17
+ k
18
+ end
19
+ expect(results).to match_array(collection)
20
+ end
21
+ end
22
+
23
+ context 'when keys are found' do
24
+ context 'when no match filter is supplied' do
25
+ let(:collection) { Array.new(20) { |i| "k#{i}" } }
26
+
27
+ it 'iterates over each item in the collection' do
28
+ results = subject.sscan_each(key).map do |k|
29
+ k
30
+ end
31
+ expect(results).to match_array(collection)
32
+ end
33
+ end
34
+
35
+ context 'when giving a custom match filter' do
36
+ let(:match) { 'k1*' }
37
+ let(:collection) { Array.new(12) { |i| "k#{i}" } }
38
+ let(:expected) { %w[k1 k10 k11] }
39
+
40
+ it 'iterates over each item in the filtered collection' do
41
+ results = subject.sscan_each(key, match: match).map do |k|
42
+ k
43
+ end
44
+ expect(results).to match_array(expected)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#sscan' do
4
+ let(:count) { 10 }
5
+ let(:match) { '*' }
6
+ let(:key) { 'mock-redis-test:sscan' }
7
+
8
+ before do
9
+ # The return order of the members is non-deterministic, so we sort them to compare
10
+ expect_any_instance_of(Redis).to receive(:sscan).and_wrap_original do |m, *args|
11
+ result = m.call(*args)
12
+ [result[0], result[1].sort]
13
+ end
14
+ expect_any_instance_of(MockRedis).to receive(:sscan).and_wrap_original do |m, *args|
15
+ result = m.call(*args)
16
+ [result[0], result[1].sort]
17
+ end
18
+ end
19
+
20
+ context 'when the set does not exist' do
21
+ it 'returns a 0 cursor and an empty collection' do
22
+ expect(@redises.sscan(key, 0, count: count, match: match)).to eq(['0', []])
23
+ end
24
+ end
25
+
26
+ context 'when the set exists' do
27
+ before do
28
+ @redises.sadd(key, 'Hello')
29
+ @redises.sadd(key, 'World')
30
+ @redises.sadd(key, 'Test')
31
+ end
32
+
33
+ let(:expected) { ['0', %w[Hello Test World]] }
34
+
35
+ it 'returns a 0 cursor and the collection' do
36
+ expect(@redises.sscan(key, 0, count: count)).to eq(expected)
37
+ end
38
+ end
39
+ end
@@ -1,19 +1,18 @@
1
- # -*- coding: utf-8 -*-
2
1
  require 'spec_helper'
3
2
 
4
- describe "#strlen(key)" do
3
+ describe '#strlen(key)' do
5
4
  before do
6
5
  @key = 'mock-redis-test:73288'
7
- @redises.set(@key, "5 ∈ (0..10)")
6
+ @redises.set(@key, '5 ∈ (0..10)')
8
7
  end
9
8
 
10
9
  it "returns the string's length in bytes" do
11
10
  @redises.strlen(@key).should == 13
12
11
  end
13
12
 
14
- it "returns 0 for a nonexistent value" do
13
+ it 'returns 0 for a nonexistent value' do
15
14
  @redises.strlen('mock-redis-test:does-not-exist').should == 0
16
15
  end
17
16
 
18
- it_should_behave_like "a string-only command"
17
+ it_should_behave_like 'a string-only command'
19
18
  end
@@ -5,36 +5,38 @@ describe '#sunion(key [, key, ...])' do
5
5
  @evens = 'mock-redis-test:sunion:evens'
6
6
  @primes = 'mock-redis-test:sunion:primes'
7
7
 
8
- [2, 4, 6, 8, 10].each {|i| @redises.sadd(@evens, i) }
9
- [2, 3, 5, 7].each {|i| @redises.sadd(@primes, i) }
8
+ [2, 4, 6, 8, 10].each { |i| @redises.sadd(@evens, i) }
9
+ [2, 3, 5, 7].each { |i| @redises.sadd(@primes, i) }
10
10
  end
11
11
 
12
- it "returns the elements in the resulting set" do
12
+ it 'returns the elements in the resulting set' do
13
13
  @redises.sunion(@evens, @primes).should == %w[2 4 6 8 10 3 5 7]
14
14
  end
15
15
 
16
- it "treats missing keys as empty sets" do
16
+ it 'treats missing keys as empty sets' do
17
17
  @redises.sunion(@primes, 'mock-redis-test:nonesuch').
18
18
  should == %w[2 3 5 7]
19
19
  end
20
20
 
21
- it "raises an error if given 0 sets" do
21
+ it 'allows Array as argument' do
22
+ @redises.sunion([@evens, @primes]).should == %w[2 4 6 8 10 3 5 7]
23
+ end
24
+
25
+ it 'raises an error if given 0 sets' do
22
26
  lambda do
23
27
  @redises.sunion
24
- end.should raise_error(RuntimeError)
28
+ end.should raise_error(Redis::CommandError)
25
29
  end
26
30
 
27
- it "raises an error if any argument is not a a set" do
31
+ it 'raises an error if any argument is not a a set' do
28
32
  @redises.set('mock-redis-test:notset', 1)
29
33
 
30
34
  lambda do
31
35
  @redises.sunion(@numbers, 'mock-redis-test:notset')
32
- end.should raise_error(RuntimeError)
36
+ end.should raise_error(Redis::CommandError)
33
37
 
34
38
  lambda do
35
39
  @redises.sunion('mock-redis-test:notset', @numbers)
36
- end.should raise_error(RuntimeError)
40
+ end.should raise_error(Redis::CommandError)
37
41
  end
38
42
  end
39
-
40
-
@@ -6,54 +6,54 @@ describe '#sunionstore(destination, key [, key, ...])' do
6
6
  @primes = 'mock-redis-test:sunionstore:primes'
7
7
  @destination = 'mock-redis-test:sunionstore:destination'
8
8
 
9
- [2, 4, 6, 8, 10].each {|i| @redises.sadd(@evens, i) }
10
- [2, 3, 5, 7].each {|i| @redises.sadd(@primes, i) }
9
+ [2, 4, 6, 8, 10].each { |i| @redises.sadd(@evens, i) }
10
+ [2, 3, 5, 7].each { |i| @redises.sadd(@primes, i) }
11
11
  end
12
12
 
13
- it "returns the number of elements in the resulting set" do
13
+ it 'returns the number of elements in the resulting set' do
14
14
  @redises.sunionstore(@destination, @primes, @evens).should == 8
15
15
  end
16
16
 
17
- it "stores the resulting set" do
17
+ it 'stores the resulting set' do
18
18
  @redises.sunionstore(@destination, @primes, @evens)
19
19
  @redises.smembers(@destination).should == %w[10 8 6 4 7 5 3 2]
20
20
  end
21
21
 
22
- it "does not store empty sets" do
22
+ it 'does not store empty sets' do
23
23
  @redises.sunionstore(@destination,
24
24
  'mock-redis-test:nonesuch',
25
25
  'mock-redis-test:nonesuch2').should == 0
26
26
  @redises.get(@destination).should be_nil
27
27
  end
28
28
 
29
- it "removes existing elements in destination" do
29
+ it 'removes existing elements in destination' do
30
30
  @redises.sadd(@destination, 42)
31
31
 
32
32
  @redises.sunionstore(@destination, @primes)
33
33
  @redises.smembers(@destination).should == %w[7 5 3 2]
34
34
  end
35
35
 
36
- it "correctly unions and stores when the destination is empty and is one of the arguments" do
36
+ it 'correctly unions and stores when the destination is empty and is one of the arguments' do
37
37
  @redises.sunionstore(@destination, @destination, @primes)
38
38
 
39
39
  @redises.smembers(@destination).should == %w[7 5 3 2]
40
40
  end
41
41
 
42
- it "raises an error if given 0 sets" do
42
+ it 'raises an error if given 0 sets' do
43
43
  lambda do
44
44
  @redises.sunionstore(@destination)
45
- end.should raise_error(RuntimeError)
45
+ end.should raise_error(Redis::CommandError)
46
46
  end
47
47
 
48
- it "raises an error if any argument is not a a set" do
48
+ it 'raises an error if any argument is not a a set' do
49
49
  @redises.set('mock-redis-test:notset', 1)
50
50
 
51
51
  lambda do
52
52
  @redises.sunionstore(@destination, @primes, 'mock-redis-test:notset')
53
- end.should raise_error(RuntimeError)
53
+ end.should raise_error(Redis::CommandError)
54
54
 
55
55
  lambda do
56
56
  @redises.sunionstore(@destination, 'mock-redis-test:notset', @primes)
57
- end.should raise_error(RuntimeError)
57
+ end.should raise_error(Redis::CommandError)
58
58
  end
59
59
  end
@@ -1,20 +1,25 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "#ttl(key)" do
3
+ describe '#ttl(key)' do
4
4
  before do
5
5
  @key = 'mock-redis-test:persist'
6
6
  @redises.set(@key, 'spork')
7
7
  end
8
8
 
9
- it "returns -1 for a key with no expiration" do
9
+ it 'returns -1 for a key with no expiration' do
10
10
  @redises.ttl(@key).should == -1
11
11
  end
12
12
 
13
- it "returns -1 for a key that does not exist" do
14
- @redises.ttl('mock-redis-test:nonesuch').should == -1
13
+ it 'returns -2 for a key that does not exist' do
14
+ @redises.ttl('mock-redis-test:nonesuch').should == -2
15
15
  end
16
16
 
17
- context "[mock only]" do
17
+ it 'stringifies key' do
18
+ @redises.expire(@key, 9)
19
+ @redises.ttl(@key.to_sym).should > 0
20
+ end
21
+
22
+ context '[mock only]' do
18
23
  # These are mock-only since we can't actually manipulate time in
19
24
  # the real Redis.
20
25
 
@@ -24,7 +29,7 @@ describe "#ttl(key)" do
24
29
 
25
30
  before do
26
31
  @now = Time.now
27
- Time.stub!(:now).and_return(@now)
32
+ Time.stub(:now).and_return(@now)
28
33
  end
29
34
 
30
35
  it "gives you the key's remaining lifespan in seconds" do
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "#type(key)" do
3
+ describe '#type(key)' do
4
4
  before do
5
5
  @key = 'mock-redis-test:type'
6
6
  end
@@ -1,12 +1,17 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe '#watch(key)' do
4
- it "responds with nil" do
5
- @redises.watch('mock-redis-test').should be_nil
3
+ describe '#watch(key [, key, ...)' do
4
+ before do
5
+ @key1 = 'mock-redis-test-watch1'
6
+ @key2 = 'mock-redis-test-watch2'
7
+ end
8
+
9
+ it "returns 'OK'" do
10
+ @redises.watch(@key1, @key2).should == 'OK'
6
11
  end
7
12
 
8
13
  it 'EXECs its MULTI on successes' do
9
- @redises.watch 'foo' do
14
+ @redises.watch @key1, @key2 do
10
15
  @redises.multi do |multi|
11
16
  multi.set 'bar', 'baz'
12
17
  end
@@ -0,0 +1,122 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#xadd("mystream", { f1: "v1", f2: "v2" }, id: "0-0", maxlen: 1000, approximate: true)' do
4
+ before :all do
5
+ sleep 1 - (Time.now.to_f % 1)
6
+ @key = 'mock-redis-test:xadd'
7
+ end
8
+
9
+ before :each do
10
+ # TODO: Redis appears to be returning a timestamp a few seconds in the future
11
+ # so we're ignoring the last 5 digits (time in milliseconds)
12
+ @redises._gsub(/\d{5}-\d/, '....-.')
13
+ end
14
+
15
+ it 'returns an id based on the timestamp' do
16
+ t = Time.now.to_i
17
+ id = @redises.xadd(@key, { key: 'value' })
18
+ expect(id).to match(/#{t}\d{3}-0/)
19
+ end
20
+
21
+ it 'adds data with symbols' do
22
+ @redises.xadd(@key, { symbol_key: :symbol_value })
23
+ expect(@redises.xrange(@key, '-', '+').last[1])
24
+ .to eq('symbol_key' => 'symbol_value')
25
+ end
26
+
27
+ it 'increments the sequence number with the same timestamp' do
28
+ Timecop.freeze do
29
+ @redises.xadd(@key, { key: 'value' })
30
+ expect(@redises.xadd(@key, { key: 'value' })).to match(/\d+-1/)
31
+ end
32
+ end
33
+
34
+ it 'sets the id if it is given' do
35
+ expect(@redises.xadd(@key, { key: 'value' }, id: '1234567891234-2'))
36
+ .to eq '1234567891234-2'
37
+ end
38
+
39
+ it 'accepts is as an integer' do
40
+ expect(@redises.xadd(@key, { key: 'value' }, id: 1_234_567_891_234))
41
+ .to eq '1234567891234-0'
42
+ end
43
+
44
+ it 'raises exception if id is less that stream top item' do
45
+ @redises.xadd(@key, { key: 'value' }, id: '1234567891234-0')
46
+ expect { @redises.xadd(@key, { key: 'value' }, id: '1234567891233-0') }
47
+ .to raise_error(
48
+ Redis::CommandError,
49
+ 'ERR The ID specified in XADD is equal or smaller than the target ' \
50
+ 'stream top item'
51
+ )
52
+ end
53
+
54
+ it 'raises exception if id of 0 is added to an empty stream' do
55
+ expect { @redises.xadd('mock-redis-test:unknown-stream', { key: 'value' }, id: '0') }
56
+ .to raise_error(
57
+ Redis::CommandError,
58
+ 'ERR The ID specified in XADD must be greater than 0-0'
59
+ )
60
+ end
61
+
62
+ it 'does not raise exception on empty stream with id of 0 and positive sequence number' do
63
+ expect { @redises.xadd('mock-redis-test:unknown-stream', { key: 'value' }, id: '0-1') }
64
+ .to_not raise_error
65
+ end
66
+
67
+ it 'caters for the current time being before the last time' do
68
+ t = (Time.now.to_f * 1000).to_i + 2000
69
+ @redises.xadd(@key, { key: 'value' }, id: "#{t}-0")
70
+ expect(@redises.xadd(@key, { key: 'value' })).to match(/#{t}-1/)
71
+ end
72
+
73
+ it 'appends a sequence number if it is missing' do
74
+ expect(@redises.xadd(@key, { key: 'value' }, id: '1234567891234'))
75
+ .to eq '1234567891234-0'
76
+ end
77
+
78
+ it 'raises an invalid stream id error' do
79
+ expect { @redises.xadd(@key, { key: 'value' }, id: 'X') }
80
+ .to raise_error(
81
+ Redis::CommandError,
82
+ 'ERR Invalid stream ID specified as stream command argument'
83
+ )
84
+ end
85
+
86
+ it 'caps the stream to 5 elements' do
87
+ @redises.xadd(@key, { key1: 'value1' }, id: '1234567891234-0')
88
+ @redises.xadd(@key, { key2: 'value2' }, id: '1234567891245-0')
89
+ @redises.xadd(@key, { key3: 'value3' }, id: '1234567891245-1')
90
+ @redises.xadd(@key, { key4: 'value4' }, id: '1234567891278-0')
91
+ @redises.xadd(@key, { key5: 'value5' }, id: '1234567891278-1')
92
+ @redises.xadd(@key, { key6: 'value6' }, id: '1234567891299-0')
93
+ @redises.xadd(@key, { key7: 'value7' }, id: '1234567891300-0', maxlen: 5)
94
+ expect(@redises.xrange(@key, '-', '+')).to eq(
95
+ [
96
+ ['1234567891245-1', { 'key3' => 'value3' }],
97
+ ['1234567891278-0', { 'key4' => 'value4' }],
98
+ ['1234567891278-1', { 'key5' => 'value5' }],
99
+ ['1234567891299-0', { 'key6' => 'value6' }],
100
+ ['1234567891300-0', { 'key7' => 'value7' }]
101
+ ]
102
+ )
103
+ end
104
+
105
+ it 'supports a maxlen greater than the current size' do
106
+ @redises.xadd(@key, { key1: 'value1' }, id: '1234567891234-0')
107
+ @redises.xadd(@key, { key2: 'value2' }, id: '1234567891245-0', maxlen: 1000)
108
+ expect(@redises.xrange(@key, '-', '+')).to eq(
109
+ [
110
+ ['1234567891234-0', { 'key1' => 'value1' }],
111
+ ['1234567891245-0', { 'key2' => 'value2' }],
112
+ ]
113
+ )
114
+ end
115
+
116
+ it 'creates an empty stream with maxlen of 0' do
117
+ @redises.xadd(@key, { key: 'value' }, maxlen: 0)
118
+ expect(@redises.xlen(@key)).to eq 0
119
+ expect(@redises.xrange(@key, '-', '+')).to eq([])
120
+ expect(@redises.exists?(@key)).to eq true
121
+ end
122
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#xlen(key)' do
4
+ before :all do
5
+ sleep 1 - (Time.now.to_f % 1)
6
+ @key = 'mock-redis-test:xlen'
7
+ end
8
+
9
+ before :each do
10
+ # TODO: Redis appears to be returning a timestamp a few seconds in the future
11
+ # so we're ignoring the last 5 digits (time in milliseconds)
12
+ @redises._gsub(/\d{5}-\d/, '...-.')
13
+ end
14
+
15
+ it 'returns the number of items in the stream' do
16
+ expect(@redises.xlen(@key)).to eq 0
17
+ @redises.xadd(@key, { key: 'value' })
18
+ expect(@redises.xlen(@key)).to eq 1
19
+ 3.times { @redises.xadd(@key, { key: 'value' }) }
20
+ expect(@redises.xlen(@key)).to eq 4
21
+ end
22
+ end