mock_redis 0.21.0 → 0.26.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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +26 -5
  3. data/.rubocop_todo.yml +1 -1
  4. data/.travis.yml +3 -3
  5. data/CHANGELOG.md +33 -0
  6. data/Gemfile +2 -2
  7. data/LICENSE.md +21 -0
  8. data/README.md +37 -13
  9. data/lib/mock_redis.rb +0 -7
  10. data/lib/mock_redis/database.rb +42 -14
  11. data/lib/mock_redis/future.rb +1 -1
  12. data/lib/mock_redis/geospatial_methods.rb +4 -4
  13. data/lib/mock_redis/hash_methods.rb +18 -6
  14. data/lib/mock_redis/info_method.rb +2 -2
  15. data/lib/mock_redis/multi_db_wrapper.rb +2 -2
  16. data/lib/mock_redis/stream.rb +25 -2
  17. data/lib/mock_redis/stream/id.rb +1 -1
  18. data/lib/mock_redis/stream_methods.rb +16 -1
  19. data/lib/mock_redis/string_methods.rb +17 -9
  20. data/lib/mock_redis/transaction_wrapper.rb +2 -2
  21. data/lib/mock_redis/utility_methods.rb +6 -3
  22. data/lib/mock_redis/version.rb +1 -1
  23. data/lib/mock_redis/zset_methods.rb +52 -9
  24. data/mock_redis.gemspec +1 -2
  25. data/spec/commands/blpop_spec.rb +0 -6
  26. data/spec/commands/brpop_spec.rb +6 -5
  27. data/spec/commands/del_spec.rb +15 -0
  28. data/spec/commands/dump_spec.rb +19 -0
  29. data/spec/commands/exists_spec.rb +34 -5
  30. data/spec/commands/future_spec.rb +11 -1
  31. data/spec/commands/geoadd_spec.rb +1 -1
  32. data/spec/commands/hmset_spec.rb +26 -0
  33. data/spec/commands/hset_spec.rb +6 -6
  34. data/spec/commands/keys_spec.rb +17 -0
  35. data/spec/commands/mget_spec.rb +6 -0
  36. data/spec/commands/move_spec.rb +5 -5
  37. data/spec/commands/pipelined_spec.rb +20 -0
  38. data/spec/commands/restore_spec.rb +47 -0
  39. data/spec/commands/scan_spec.rb +9 -0
  40. data/spec/commands/set_spec.rb +8 -4
  41. data/spec/commands/setbit_spec.rb +1 -0
  42. data/spec/commands/setex_spec.rb +16 -0
  43. data/spec/commands/srandmember_spec.rb +1 -1
  44. data/spec/commands/xadd_spec.rb +20 -0
  45. data/spec/commands/xrange_spec.rb +13 -0
  46. data/spec/commands/xread_spec.rb +66 -0
  47. data/spec/commands/xtrim_spec.rb +6 -0
  48. data/spec/commands/zinterstore_spec.rb +34 -0
  49. data/spec/commands/zpopmax_spec.rb +60 -0
  50. data/spec/commands/zpopmin_spec.rb +60 -0
  51. data/spec/commands/zrange_spec.rb +1 -1
  52. data/spec/commands/zrangebyscore_spec.rb +1 -1
  53. data/spec/commands/zrevrange_spec.rb +1 -1
  54. data/spec/commands/zrevrangebyscore_spec.rb +1 -1
  55. data/spec/commands/zunionstore_spec.rb +33 -0
  56. data/spec/spec_helper.rb +4 -2
  57. data/spec/support/redis_multiplexer.rb +1 -0
  58. data/spec/transactions_spec.rb +16 -0
  59. metadata +16 -26
  60. data/LICENSE +0 -19
@@ -1,14 +1,43 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe '#exists(key)' do
4
- before { @key = 'mock-redis-test:45794' }
3
+ describe '#exists(*keys)' do
4
+ before { @key1 = 'mock-redis-test:exists1' }
5
+ before { @key2 = 'mock-redis-test:exists2' }
6
+
7
+ it 'returns 0 for keys that do not exist' do
8
+ @redises.exists(@key1).should == 0
9
+ @redises.exists(@key1, @key2).should == 0
10
+ end
11
+
12
+ it 'returns 1 for keys that do exist' do
13
+ @redises.set(@key1, 1)
14
+ @redises.exists(@key1).should == 1
15
+ end
16
+
17
+ it 'returns the count of all keys that exist' do
18
+ @redises.set(@key1, 1)
19
+ @redises.set(@key2, 1)
20
+ @redises.exists(@key1, @key2).should == 2
21
+ @redises.exists(@key1, @key2, 'does-not-exist').should == 2
22
+ end
23
+ end
24
+
25
+ describe '#exists?(*keys)' do
26
+ before { @key1 = 'mock-redis-test:exists1' }
27
+ before { @key2 = 'mock-redis-test:exists2' }
5
28
 
6
29
  it 'returns false for keys that do not exist' do
7
- @redises.exists(@key).should == false
30
+ @redises.exists?(@key1).should == false
31
+ @redises.exists?(@key1, @key2).should == false
8
32
  end
9
33
 
10
34
  it 'returns true for keys that do exist' do
11
- @redises.set(@key, 1)
12
- @redises.exists(@key).should == true
35
+ @redises.set(@key1, 1)
36
+ @redises.exists?(@key1).should == true
37
+ end
38
+
39
+ it 'returns true if any keys exist' do
40
+ @redises.set(@key2, 1)
41
+ @redises.exists?(@key1, @key2).should == true
13
42
  end
14
43
  end
@@ -3,7 +3,12 @@ require 'spec_helper'
3
3
  describe MockRedis::Future do
4
4
  let(:command) { [:get, 'foo'] }
5
5
  let(:result) { 'bar' }
6
- before { @future = MockRedis::Future.new(command) }
6
+ let(:block) { ->(value) { value.upcase } }
7
+
8
+ before do
9
+ @future = MockRedis::Future.new(command)
10
+ @future2 = MockRedis::Future.new(command, block)
11
+ end
7
12
 
8
13
  it 'remembers the command' do
9
14
  @future.command.should eq(command)
@@ -17,4 +22,9 @@ describe MockRedis::Future do
17
22
  @future.store_result(result)
18
23
  @future.value.should eq(result)
19
24
  end
25
+
26
+ it 'executes the block on the value if block is passed in' do
27
+ @future2.store_result(result)
28
+ @future2.value.should eq('BAR')
29
+ end
20
30
  end
@@ -33,7 +33,7 @@ describe '#geoadd' do
33
33
  context 'when coordinates are not in allowed range' do
34
34
  let(:coords) { [181, 86] }
35
35
  let(:message) do
36
- formatted_coords = coords.map { |c| format('%.6f', c) }
36
+ formatted_coords = coords.map { |c| format('%<coords>.6f', coords: c) }
37
37
  "ERR invalid longitude,latitude pair #{formatted_coords.join(',')}"
38
38
  end
39
39
 
@@ -39,5 +39,31 @@ describe '#hmset(key, field, value [, field, value ...])' do
39
39
  end.should raise_error(Redis::CommandError)
40
40
  end
41
41
 
42
+ # The following tests address https://github.com/sds/mock_redis/issues/170
43
+ context 'keys are stored as strings' do
44
+ before do
45
+ @redises.hmset(1, :foo, :bar)
46
+ @redises.hmset(:a_sym, :boo, :bas)
47
+ end
48
+
49
+ it { expect(@redises.hgetall('1')).to eq @redises.hgetall(1) }
50
+ it { expect(@redises.hgetall('a_sym')).to eq @redises.hgetall(:a_sym) }
51
+ it { expect(@redises.del('1')).to eq 1 }
52
+ it { expect(@redises.del(1)).to eq 1 }
53
+ it { expect(@redises.del('a_sym')).to eq 1 }
54
+ it { expect(@redises.del(:a_sym)).to eq 1 }
55
+
56
+ after do
57
+ @redises.del(1)
58
+ @redises.del(:a_sym)
59
+ end
60
+ end
61
+
62
+ # The following tests address https://github.com/sds/mock_redis/issues/134
63
+ context 'hmset accepts an array as its only argument' do
64
+ it { expect(@redises.hmset([@key, :bar, :bas])).to eq 'OK' }
65
+ it { lambda { @redises.hmset([:foo, :bar]) }.should raise_error(Redis::CommandError) }
66
+ end
67
+
42
68
  it_should_behave_like 'a hash-only command'
43
69
  end
@@ -5,18 +5,18 @@ describe '#hset(key, field)' do
5
5
  @key = 'mock-redis-test:hset'
6
6
  end
7
7
 
8
- it 'returns true if the key does not exist' do
9
- @redises.hset(@key, 'k1', 'v1').should == true
8
+ it 'returns 1 if the key does not exist' do
9
+ @redises.hset(@key, 'k1', 'v1').should == 1
10
10
  end
11
11
 
12
- it 'returns true if the key exists but the field does not' do
12
+ it 'returns 1 if the key exists but the field does not' do
13
13
  @redises.hset(@key, 'k1', 'v1')
14
- @redises.hset(@key, 'k2', 'v2').should == true
14
+ @redises.hset(@key, 'k2', 'v2').should == 1
15
15
  end
16
16
 
17
- it 'returns false if the field already exists' do
17
+ it 'returns 0 if the field already exists' do
18
18
  @redises.hset(@key, 'k1', 'v1')
19
- @redises.hset(@key, 'k1', 'v1').should == false
19
+ @redises.hset(@key, 'k1', 'v1').should == 0
20
20
  end
21
21
 
22
22
  it 'creates a hash there is no such field' do
@@ -29,6 +29,7 @@ describe '#keys()' do
29
29
 
30
30
  @redises.set('mock-redis-test:special-key?', 'true')
31
31
  @redises.set('mock-redis-test:special-key*', 'true')
32
+ @redises.set('mock-redis-test:special-key-!?*', 'true')
32
33
  end
33
34
 
34
35
  describe 'the ? character' do
@@ -53,6 +54,22 @@ describe '#keys()' do
53
54
  'mock-redis-test:special-key?',
54
55
  ]
55
56
  end
57
+
58
+ context 'multiple ? characters' do
59
+ it "properly handles multiple consequtive '?' characters" do
60
+ @redises.keys('mock-redis-test:special-key-???').sort.should == [
61
+ 'mock-redis-test:special-key-!?*',
62
+ ]
63
+ end
64
+
65
+ context '\\? as a literal ' do
66
+ it 'handles multiple ? as both literal and special character' do
67
+ @redises.keys('mock-redis-test:special-key-?\??').sort.should == [
68
+ 'mock-redis-test:special-key-!?*',
69
+ ]
70
+ end
71
+ end
72
+ end
56
73
  end
57
74
 
58
75
  describe 'the * character' do
@@ -49,5 +49,11 @@ describe '#mget(key [, key, ...])' do
49
49
  @redises.mget
50
50
  end.should raise_error(Redis::CommandError)
51
51
  end
52
+
53
+ it 'raises an error if you pass it empty array' do
54
+ lambda do
55
+ @redises.mget([])
56
+ end.should raise_error(Redis::CommandError)
57
+ end
52
58
  end
53
59
  end
@@ -64,7 +64,7 @@ describe '#move(key, db)' do
64
64
  end
65
65
 
66
66
  it 'removes key from srcdb' do
67
- @redises.exists(@key).should == false
67
+ @redises.exists?(@key).should == false
68
68
  end
69
69
 
70
70
  it 'copies key to destdb' do
@@ -81,7 +81,7 @@ describe '#move(key, db)' do
81
81
  end
82
82
 
83
83
  it 'removes key from srcdb' do
84
- @redises.exists(@key).should == false
84
+ @redises.exists?(@key).should == false
85
85
  end
86
86
 
87
87
  it 'copies key to destdb' do
@@ -99,7 +99,7 @@ describe '#move(key, db)' do
99
99
  end
100
100
 
101
101
  it 'removes key from srcdb' do
102
- @redises.exists(@key).should == false
102
+ @redises.exists?(@key).should == false
103
103
  end
104
104
 
105
105
  it 'copies key to destdb' do
@@ -117,7 +117,7 @@ describe '#move(key, db)' do
117
117
  end
118
118
 
119
119
  it 'removes key from srcdb' do
120
- @redises.exists(@key).should == false
120
+ @redises.exists?(@key).should == false
121
121
  end
122
122
 
123
123
  it 'copies key to destdb' do
@@ -135,7 +135,7 @@ describe '#move(key, db)' do
135
135
  end
136
136
 
137
137
  it 'removes key from srcdb' do
138
- @redises.exists(@key).should == false
138
+ @redises.exists?(@key).should == false
139
139
  end
140
140
 
141
141
  it 'copies key to destdb' do
@@ -66,6 +66,26 @@ describe '#pipelined' do
66
66
  end
67
67
  end
68
68
 
69
+ context 'with redis time return value' do
70
+ let(:time_stub) { double 'Time', :now => Time.new(2019, 1, 2, 3, 4, 6, '+00:00') }
71
+ let(:options) { { :time_class => time_stub } }
72
+
73
+ subject { MockRedis.new(options) }
74
+
75
+ it 'returns the time value' do
76
+ subject.set('foo', 'bar')
77
+
78
+ results = subject.pipelined do
79
+ subject.get('foo')
80
+ subject.host # defined on MockRedis, so not captured
81
+ subject.time
82
+ subject.echo('baz')
83
+ end
84
+
85
+ expect(results).to eq(['bar', [1_546_398_246, 0], 'baz'])
86
+ end
87
+ end
88
+
69
89
  context 'with nested pipelines' do
70
90
  let(:key1) { 'hello' }
71
91
  let(:key2) { 'world' }
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#restore(key, ttl, value)' do
4
+ before do
5
+ @key = 'mock-redis-test:45794'
6
+ @src = MockRedis.new
7
+ @src.set(@key, '123')
8
+ @dumped_value = @src.dump(@key)
9
+ @dst = MockRedis.new
10
+ @now = Time.now.round
11
+ Time.stub(:now).and_return(@now)
12
+ end
13
+
14
+ it 'allows dump/restoring values between two redis instances' do
15
+ expect(@dst.restore(@key, 0, @dumped_value)).to eq('OK')
16
+ expect(@dst.get(@key)).to eq('123')
17
+ expect(@dst.pttl(@key)).to eq(-1)
18
+ end
19
+
20
+ context 'when the key being restored to already exists' do
21
+ before do
22
+ @dst.set(@key, '456')
23
+ end
24
+
25
+ it 'raises an error by default' do
26
+ expect { @dst.restore(@key, 0, @dumped_value) }.to raise_error(Redis::CommandError)
27
+ expect(@dst.get(@key)).to eq('456')
28
+ end
29
+
30
+ it 'allows replacing the key if replace==true' do
31
+ expect(@dst.restore(@key, 0, @dumped_value, replace: true)).to eq('OK')
32
+ expect(@dst.get(@key)).to eq('123')
33
+ end
34
+ end
35
+
36
+ it 'sets ttl in ms' do
37
+ @dst.restore(@key, 500, @dumped_value)
38
+ expect(@dst.pttl(@key)).to eq(500)
39
+ end
40
+
41
+ it 'can dump/restore more complex data types' do
42
+ key = 'a_hash'
43
+ @src.mapped_hmset(key, foo: 'bar')
44
+ @dst.restore(key, 0, @src.dump(key))
45
+ expect(@dst.hgetall(key)).to eq('foo' => 'bar')
46
+ end
47
+ end
@@ -42,6 +42,15 @@ describe '#scan' do
42
42
  end
43
43
  end
44
44
 
45
+ context 'when cursor is greater than collection size' do
46
+ let(:collection) { Array.new(count) { |i| "mock:key#{i}" } }
47
+ let(:expected) { ['0', []] }
48
+
49
+ it 'returns a 0 cursor and empty collection' do
50
+ expect(subject.scan(20, count: count, match: match)).to eq(expected)
51
+ end
52
+ end
53
+
45
54
  context 'when giving a custom match filter' do
46
55
  let(:match) { 'mock:key*' }
47
56
  let(:collection) { %w[mock:key mock:key2 mock:otherkey] }
@@ -33,10 +33,12 @@ describe '#set(key, value)' do
33
33
  @redises.set(key, 1, xx: true).should == true
34
34
  end
35
35
 
36
- it 'ignores other options' do
36
+ it 'raises on unknown options' do
37
37
  key = 'mock-redis-test'
38
38
  @redises.del(key)
39
- @redises.set(key, 1, logger: :something).should == 'OK'
39
+ expect do
40
+ @redises.set(key, 1, logger: :something)
41
+ end.to raise_error(ArgumentError, 'unknown keyword: logger')
40
42
  end
41
43
 
42
44
  context '[mock only]' do
@@ -59,9 +61,11 @@ describe '#set(key, value)' do
59
61
 
60
62
  it 'accepts PX milliseconds' do
61
63
  key = 'mock-redis-test'
62
- @mock.set(key, 1, px: 1000).should == 'OK'
64
+ @mock.set(key, 1, px: 500).should == 'OK'
63
65
  @mock.get(key).should_not be_nil
64
- Time.stub(:now).and_return(@now + 2)
66
+ Time.stub(:now).and_return(@now + 300 / 1000.to_f)
67
+ @mock.get(key).should_not be_nil
68
+ Time.stub(:now).and_return(@now + 600 / 1000.to_f)
65
69
  @mock.get(key).should be_nil
66
70
  end
67
71
  end
@@ -2,6 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe '#setbit(key, offset)' do
4
4
  before do
5
+ Encoding.default_external = 'UTF-8'
5
6
  @key = 'mock-redis-test:setbit'
6
7
  @redises.set(@key, 'h') # ASCII 0x68
7
8
  end
@@ -19,4 +19,20 @@ describe '#setex(key, seconds, value)' do
19
19
  @redises.real.ttl(@key).should > 0
20
20
  @redises.mock.ttl(@key).should > 0
21
21
  end
22
+
23
+ context 'when expiration time is zero' do
24
+ it 'raises Redis::CommandError' do
25
+ expect do
26
+ @redises.setex(@key, 0, 'value')
27
+ end.to raise_error(Redis::CommandError, 'ERR invalid expire time in setex')
28
+ end
29
+ end
30
+
31
+ context 'when expiration time is negative' do
32
+ it 'raises Redis::CommandError' do
33
+ expect do
34
+ @redises.setex(@key, -2, 'value')
35
+ end.to raise_error(Redis::CommandError, 'ERR invalid expire time in setex')
36
+ end
37
+ end
22
38
  end
@@ -37,7 +37,7 @@ describe '#srandmember(key)' do
37
37
  @redises.send_without_checking(:srandmember, @key, 2).size.should == 2
38
38
  end
39
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 Metrics/LineLength
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
41
  @redises.send_without_checking(:srandmember, @key, -5).size.should == 5
42
42
  end
43
43
 
@@ -54,6 +54,8 @@ describe '#xadd("mystream", { f1: "v1", f2: "v2" }, id: "0-0", maxlen: 1000, app
54
54
  Redis::CommandError,
55
55
  'ERR The ID specified in XADD is equal or smaller than the target ' \
56
56
  'stream top item'
57
+ # TOOD: Redis version 6.0.4, w redis 4.2.1 generates the following error message:
58
+ # 'ERR The ID specified in XADD must be greater than 0-0'
57
59
  )
58
60
  end
59
61
 
@@ -99,4 +101,22 @@ describe '#xadd("mystream", { f1: "v1", f2: "v2" }, id: "0-0", maxlen: 1000, app
99
101
  ]
100
102
  )
101
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
102
122
  end
@@ -54,6 +54,19 @@ describe '#xrange("mystream", first: "0-1", last: "0-3", count: 10)' do
54
54
  )
55
55
  end
56
56
 
57
+ it 'returns all entries with a lower limit of 0-0' do
58
+ expect(@redises.xrange(@key, '0-0', '+')).to eq(
59
+ [
60
+ ['1234567891234-0', { 'key1' => 'value1' }],
61
+ ['1234567891245-0', { 'key2' => 'value2' }],
62
+ ['1234567891245-1', { 'key3' => 'value3' }],
63
+ ['1234567891278-0', { 'key4' => 'value4' }],
64
+ ['1234567891278-1', { 'key5' => 'value5' }],
65
+ ['1234567891299-0', { 'key6' => 'value6' }]
66
+ ]
67
+ )
68
+ end
69
+
57
70
  it 'returns entries with an upper limit' do
58
71
  expect(@redises.xrange(@key, '-', '1234567891285-0')).to eq(
59
72
  [
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#xread(keys, ids)' do
4
+ before :all do
5
+ sleep 1 - (Time.now.to_f % 1)
6
+ @key = 'mock-redis-test:xread'
7
+ @key1 = 'mock-redis-test:xread1'
8
+ end
9
+
10
+ it 'reads a single entry' do
11
+ @redises.xadd(@key, { key: 'value' }, id: '1234567891234-0')
12
+ expect(@redises.xread(@key, '0-0'))
13
+ .to eq({ @key => [['1234567891234-0', { 'key' => 'value' }]] })
14
+ end
15
+
16
+ it 'reads multiple entries from the beginning of the stream' do
17
+ @redises.xadd(@key, { key0: 'value0' }, id: '1234567891234-0')
18
+ @redises.xadd(@key, { key1: 'value1' }, id: '1234567891234-1')
19
+ expect(@redises.xread(@key, '0-0'))
20
+ .to eq({ @key => [['1234567891234-0', { 'key0' => 'value0' }],
21
+ ['1234567891234-1', { 'key1' => 'value1' }]] })
22
+ end
23
+
24
+ it 'reads entries greater than the ID passed' do
25
+ @redises.xadd(@key, { key0: 'value0' }, id: '1234567891234-0')
26
+ @redises.xadd(@key, { key1: 'value1' }, id: '1234567891234-1')
27
+ expect(@redises.xread(@key, '1234567891234-0'))
28
+ .to eq({ @key => [['1234567891234-1', { 'key1' => 'value1' }]] })
29
+ end
30
+
31
+ it 'reads from multiple streams' do
32
+ @redises.xadd(@key, { key: 'value' }, id: '1234567891234-0')
33
+ @redises.xadd(@key1, { key1: 'value1' }, id: '1234567891234-0')
34
+ expect(@redises.xread([@key, @key1], %w[0-0 0-0]))
35
+ .to eq({ @key => [['1234567891234-0', { 'key' => 'value' }]],
36
+ @key1 => [['1234567891234-0', { 'key1' => 'value1' }]] })
37
+ end
38
+
39
+ it 'reads from multiple streams at the given IDs' do
40
+ @redises.xadd(@key, { key: 'value0' }, id: '1234567891234-0')
41
+ @redises.xadd(@key, { key: 'value1' }, id: '1234567891234-1')
42
+ @redises.xadd(@key, { key: 'value2' }, id: '1234567891234-2')
43
+ @redises.xadd(@key1, { key1: 'value0' }, id: '1234567891234-0')
44
+ @redises.xadd(@key1, { key1: 'value1' }, id: '1234567891234-1')
45
+ @redises.xadd(@key1, { key1: 'value2' }, id: '1234567891234-2')
46
+ # The first stream won't return anything since we specify the last ID
47
+ expect(@redises.xread([@key, @key1], %w[1234567891234-2 1234567891234-1]))
48
+ .to eq({ @key1 => [['1234567891234-2', { 'key1' => 'value2' }]] })
49
+ end
50
+
51
+ it 'supports the block parameter' do
52
+ @redises.xadd(@key, { key: 'value' }, id: '1234567891234-0')
53
+ expect(@redises.xread(@key, '0-0', block: 1000))
54
+ .to eq({ @key => [['1234567891234-0', { 'key' => 'value' }]] })
55
+ end
56
+
57
+ it 'limits results with count' do
58
+ @redises.xadd(@key, { key: 'value' }, id: '1234567891234-0')
59
+ @redises.xadd(@key, { key: 'value' }, id: '1234567891234-1')
60
+ @redises.xadd(@key, { key: 'value' }, id: '1234567891234-2')
61
+ expect(@redises.xread(@key, '0-0', count: 1))
62
+ .to eq({ @key => [['1234567891234-0', { 'key' => 'value' }]] })
63
+ expect(@redises.xread(@key, '1234567891234-0', count: 1))
64
+ .to eq({ @key => [['1234567891234-1', { 'key' => 'value' }]] })
65
+ end
66
+ end