fakeredis 0.5.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -0
  3. data/.travis.yml +14 -5
  4. data/LICENSE +1 -1
  5. data/README.md +42 -24
  6. data/fakeredis.gemspec +1 -1
  7. data/lib/fakeredis.rb +28 -0
  8. data/lib/fakeredis/bitop_command.rb +56 -0
  9. data/lib/fakeredis/command_executor.rb +6 -9
  10. data/lib/fakeredis/expiring_hash.rb +3 -5
  11. data/lib/fakeredis/geo_commands.rb +142 -0
  12. data/lib/fakeredis/geo_set.rb +84 -0
  13. data/lib/fakeredis/minitest.rb +24 -0
  14. data/lib/fakeredis/rspec.rb +1 -0
  15. data/lib/fakeredis/sort_method.rb +3 -3
  16. data/lib/fakeredis/sorted_set_store.rb +1 -1
  17. data/lib/fakeredis/transaction_commands.rb +2 -2
  18. data/lib/fakeredis/version.rb +1 -1
  19. data/lib/fakeredis/zset.rb +8 -2
  20. data/lib/redis/connection/memory.rb +650 -82
  21. data/spec/bitop_command_spec.rb +209 -0
  22. data/spec/command_executor_spec.rb +15 -0
  23. data/spec/compatibility_spec.rb +1 -1
  24. data/spec/connection_spec.rb +21 -21
  25. data/spec/fakeredis_spec.rb +73 -0
  26. data/spec/geo_set_spec.rb +164 -0
  27. data/spec/hashes_spec.rb +138 -57
  28. data/spec/hyper_log_logs_spec.rb +50 -0
  29. data/spec/keys_spec.rb +232 -90
  30. data/spec/lists_spec.rb +91 -35
  31. data/spec/memory_spec.rb +80 -7
  32. data/spec/server_spec.rb +38 -24
  33. data/spec/sets_spec.rb +112 -46
  34. data/spec/sort_method_spec.rb +6 -0
  35. data/spec/sorted_sets_spec.rb +482 -150
  36. data/spec/spec_helper.rb +9 -18
  37. data/spec/spec_helper_live_redis.rb +4 -4
  38. data/spec/strings_spec.rb +113 -79
  39. data/spec/subscription_spec.rb +107 -0
  40. data/spec/support/shared_examples/bitwise_operation.rb +59 -0
  41. data/spec/support/shared_examples/sortable.rb +20 -16
  42. data/spec/transactions_spec.rb +34 -13
  43. data/spec/upcase_method_name_spec.rb +2 -2
  44. metadata +23 -6
data/spec/lists_spec.rb CHANGED
@@ -10,41 +10,63 @@ module FakeRedis
10
10
  @client.lpush("key1", "val1")
11
11
  @client.lpush("key1", "val2")
12
12
 
13
- @client.lindex("key1", 0).should be == "val2"
14
- @client.lindex("key1", -1).should be == "val1"
15
- @client.lindex("key1", 3).should be == nil
13
+ expect(@client.lindex("key1", 0)).to eq("val2")
14
+ expect(@client.lindex("key1", -1)).to eq("val1")
15
+ expect(@client.lindex("key1", 3)).to eq(nil)
16
16
  end
17
17
 
18
18
  it "should insert an element before or after another element in a list" do
19
19
  @client.rpush("key1", "v1")
20
20
  @client.rpush("key1", "v3")
21
21
  @client.linsert("key1", :before, "v3", "v2")
22
+ @client.linsert("key1", :after, "v3", 100)
23
+ @client.linsert("key1", :before, 100, 99)
22
24
 
23
- @client.lrange("key1", 0, -1).should be == ["v1", "v2", "v3"]
25
+ expect(@client.lrange("key1", 0, -1)).to eq(["v1", "v2", "v3", "99", "100"])
26
+ end
27
+
28
+ it "inserts with case-insensitive position token" do
29
+ @client.rpush("key1", "v1")
30
+ @client.rpush("key1", "v4")
31
+
32
+ @client.linsert("key1", :BEFORE, "v4", "v2")
33
+ @client.linsert("key1", "Before", "v4", "v3")
34
+ @client.linsert("key1", :AFTER, "v4", "v5")
35
+ @client.linsert("key1", "After", "v5", "v6")
36
+
37
+ expect(@client.lrange("key1", 0, -1)).to eq(%w(v1 v2 v3 v4 v5 v6))
38
+ end
39
+
40
+ it "should not insert if after/before index not found" do
41
+ @client.rpush("key", "v1")
42
+ expect(@client.linsert("key", :before, "unknown", "v2")).to eq(-1)
43
+ expect(@client.linsert("key", :after, "unknown", "v3")).to eq(-1)
44
+
45
+ expect(@client.lrange("key", 0, -1)).to eq(["v1"])
24
46
  end
25
47
 
26
48
  it 'should allow multiple values to be added to a list in a single rpush' do
27
49
  @client.rpush('key1', [1, 2, 3])
28
- @client.lrange('key1', 0, -1).should be == ['1', '2', '3']
50
+ expect(@client.lrange('key1', 0, -1)).to eq(['1', '2', '3'])
29
51
  end
30
52
 
31
53
  it 'should allow multiple values to be added to a list in a single lpush' do
32
54
  @client.lpush('key1', [1, 2, 3])
33
- @client.lrange('key1', 0, -1).should be == ['3', '2', '1']
55
+ expect(@client.lrange('key1', 0, -1)).to eq(['3', '2', '1'])
34
56
  end
35
57
 
36
58
  it "should error if an invalid where argument is given" do
37
59
  @client.rpush("key1", "v1")
38
60
  @client.rpush("key1", "v3")
39
- lambda { @client.linsert("key1", :invalid, "v3", "v2") }.should raise_error(Redis::CommandError, "ERR syntax error")
61
+ expect { @client.linsert("key1", :invalid, "v3", "v2") }.to raise_error(Redis::CommandError, "ERR syntax error")
40
62
  end
41
63
 
42
64
  it "should get the length of a list" do
43
65
  @client.rpush("key1", "v1")
44
66
  @client.rpush("key1", "v2")
45
67
 
46
- @client.llen("key1").should be == 2
47
- @client.llen("key2").should be == 0
68
+ expect(@client.llen("key1")).to eq(2)
69
+ expect(@client.llen("key2")).to eq(0)
48
70
  end
49
71
 
50
72
  it "should remove and get the first element in a list" do
@@ -52,15 +74,15 @@ module FakeRedis
52
74
  @client.rpush("key1", "v2")
53
75
  @client.rpush("key1", "v3")
54
76
 
55
- @client.lpop("key1").should be == "v1"
56
- @client.lrange("key1", 0, -1).should be == ["v2", "v3"]
77
+ expect(@client.lpop("key1")).to eq("v1")
78
+ expect(@client.lrange("key1", 0, -1)).to eq(["v2", "v3"])
57
79
  end
58
80
 
59
81
  it "should prepend a value to a list" do
60
82
  @client.rpush("key1", "v1")
61
83
  @client.rpush("key1", "v2")
62
84
 
63
- @client.lrange("key1", 0, -1).should be == ["v1", "v2"]
85
+ expect(@client.lrange("key1", 0, -1)).to eq(["v1", "v2"])
64
86
  end
65
87
 
66
88
  it "should prepend a value to a list, only if the list exists" do
@@ -69,8 +91,8 @@ module FakeRedis
69
91
  @client.lpushx("key1", "v2")
70
92
  @client.lpushx("key2", "v3")
71
93
 
72
- @client.lrange("key1", 0, -1).should be == ["v2", "v1"]
73
- @client.llen("key2").should be == 0
94
+ expect(@client.lrange("key1", 0, -1)).to eq(["v2", "v1"])
95
+ expect(@client.llen("key2")).to eq(0)
74
96
  end
75
97
 
76
98
  it "should get a range of elements from a list" do
@@ -78,7 +100,8 @@ module FakeRedis
78
100
  @client.rpush("key1", "v2")
79
101
  @client.rpush("key1", "v3")
80
102
 
81
- @client.lrange("key1", 1, -1).should be == ["v2", "v3"]
103
+ expect(@client.lrange("key1", 1, -1)).to eq(["v2", "v3"])
104
+ expect(@client.lrange("key1", -999, -1)).to eq(["v1", "v2", "v3"])
82
105
  end
83
106
 
84
107
  it "should remove elements from a list" do
@@ -87,10 +110,17 @@ module FakeRedis
87
110
  @client.rpush("key1", "v2")
88
111
  @client.rpush("key1", "v2")
89
112
  @client.rpush("key1", "v1")
113
+ @client.rpush("key1", 42)
114
+
115
+ expect(@client.lrem("key1", 1, "v1")).to eq(1)
116
+ expect(@client.lrem("key1", -2, "v2")).to eq(2)
117
+ expect(@client.lrem("key1", 0, 42)).to eq(1)
118
+ expect(@client.llen("key1")).to eq(2)
119
+ end
90
120
 
91
- @client.lrem("key1", 1, "v1").should be == 1
92
- @client.lrem("key1", -2, "v2").should be == 2
93
- @client.llen("key1").should be == 2
121
+ it "should return 0 if key does not map to a list" do
122
+ expect(@client.exists("nonexistant")).to eq(false)
123
+ expect(@client.lrem("nonexistant", 0, "value")).to eq(0)
94
124
  end
95
125
 
96
126
  it "should remove list's key when list is empty" do
@@ -99,7 +129,7 @@ module FakeRedis
99
129
  @client.lrem("key1", 1, "v1")
100
130
  @client.lrem("key1", 1, "v2")
101
131
 
102
- @client.exists("key1").should be == false
132
+ expect(@client.exists("key1")).to eq(false)
103
133
  end
104
134
 
105
135
  it "should set the value of an element in a list by its index" do
@@ -109,9 +139,10 @@ module FakeRedis
109
139
 
110
140
  @client.lset("key1", 0, "four")
111
141
  @client.lset("key1", -2, "five")
112
- @client.lrange("key1", 0, -1).should be == ["four", "five", "three"]
142
+ @client.lset("key1", 2, 6)
113
143
 
114
- lambda { @client.lset("key1", 4, "six") }.should raise_error(Redis::CommandError, "ERR index out of range")
144
+ expect(@client.lrange("key1", 0, -1)).to eq(["four", "five", "6"])
145
+ expect { @client.lset("key1", 4, "seven") }.to raise_error(Redis::CommandError, "ERR index out of range")
115
146
  end
116
147
 
117
148
  it "should trim a list to the specified range" do
@@ -119,8 +150,8 @@ module FakeRedis
119
150
  @client.rpush("key1", "two")
120
151
  @client.rpush("key1", "three")
121
152
 
122
- @client.ltrim("key1", 1, -1).should be == "OK"
123
- @client.lrange("key1", 0, -1).should be == ["two", "three"]
153
+ expect(@client.ltrim("key1", 1, -1)).to eq("OK")
154
+ expect(@client.lrange("key1", 0, -1)).to eq(["two", "three"])
124
155
  end
125
156
 
126
157
 
@@ -131,7 +162,7 @@ module FakeRedis
131
162
  before { @client.ltrim("listOfOne", -5, -1) }
132
163
 
133
164
  it "returns the unmodified list" do
134
- @client.lrange("listOfOne", 0, -1).should be == ["one"]
165
+ expect(@client.lrange("listOfOne", 0, -1)).to eq(["one"])
135
166
  end
136
167
  end
137
168
  end
@@ -150,7 +181,7 @@ module FakeRedis
150
181
  before { @client.ltrim("maxTest", -5, -1) }
151
182
 
152
183
  it "should trim a list to the specified maximum size" do
153
- @client.lrange("maxTest", 0, -1).should be == ["two","three", "four", "five", "six"]
184
+ expect(@client.lrange("maxTest", 0, -1)).to eq(["two","three", "four", "five", "six"])
154
185
  end
155
186
  end
156
187
  end
@@ -161,26 +192,43 @@ module FakeRedis
161
192
  @client.rpush("key1", "two")
162
193
  @client.rpush("key1", "three")
163
194
 
164
- @client.rpop("key1").should be == "three"
165
- @client.lrange("key1", 0, -1).should be == ["one", "two"]
195
+ expect(@client.rpop("key1")).to eq("three")
196
+ expect(@client.lrange("key1", 0, -1)).to eq(["one", "two"])
166
197
  end
167
198
 
168
- it "should remove the last element in a list, append it to another list and return it" do
199
+ it "rpoplpush should remove the last element in a list, append it to another list and return it" do
169
200
  @client.rpush("key1", "one")
170
201
  @client.rpush("key1", "two")
171
202
  @client.rpush("key1", "three")
172
203
 
173
- @client.rpoplpush("key1", "key2").should be == "three"
204
+ expect(@client.rpoplpush("key1", "key2")).to eq("three")
174
205
 
175
- @client.lrange("key1", 0, -1).should be == ["one", "two"]
176
- @client.lrange("key2", 0, -1).should be == ["three"]
206
+ expect(@client.lrange("key1", 0, -1)).to eq(["one", "two"])
207
+ expect(@client.lrange("key2", 0, -1)).to eq(["three"])
208
+ end
209
+
210
+ it "brpoplpush should remove the last element in a list, append it to another list and return it" do
211
+ @client.rpush("key1", "one")
212
+ @client.rpush("key1", "two")
213
+ @client.rpush("key1", "three")
214
+
215
+ expect(@client.brpoplpush("key1", "key2")).to eq("three")
216
+
217
+ expect(@client.lrange("key1", 0, -1)).to eq(["one", "two"])
218
+ expect(@client.lrange("key2", 0, -1)).to eq(["three"])
177
219
  end
178
220
 
179
221
  context 'when the source list is empty' do
180
222
  it 'rpoplpush does not add anything to the destination list' do
181
223
  @client.rpoplpush("source", "destination")
182
224
 
183
- @client.lrange("destination", 0, -1).should be == []
225
+ expect(@client.lrange("destination", 0, -1)).to eq([])
226
+ end
227
+
228
+ it 'brpoplpush does not add anything to the destination list' do
229
+ expect(@client.brpoplpush("source", "destination")).to be_nil
230
+
231
+ expect(@client.lrange("destination", 0, -1)).to eq([])
184
232
  end
185
233
  end
186
234
 
@@ -188,7 +236,7 @@ module FakeRedis
188
236
  @client.rpush("key1", "one")
189
237
  @client.rpush("key1", "two")
190
238
 
191
- @client.lrange("key1", 0, -1).should be == ["one", "two"]
239
+ expect(@client.lrange("key1", 0, -1)).to eq(["one", "two"])
192
240
  end
193
241
 
194
242
  it "should append a value to a list, only if the list exists" do
@@ -196,8 +244,16 @@ module FakeRedis
196
244
  @client.rpushx("key1", "two")
197
245
  @client.rpushx("key2", "two")
198
246
 
199
- @client.lrange("key1", 0, -1).should be == ["one", "two"]
200
- @client.lrange("key2", 0, -1).should be == []
247
+ expect(@client.lrange("key1", 0, -1)).to eq(["one", "two"])
248
+ expect(@client.lrange("key2", 0, -1)).to eq([])
249
+ end
250
+
251
+ it 'should not allow pushing empty list of objects' do
252
+ expect { @client.lpush("key1", []) }.to raise_error(Redis::CommandError, /lpush[^x]/)
253
+ expect { @client.lpush("key1", 1); @client.lpushx("key1", []) }.to raise_error(Redis::CommandError, /lpushx/)
254
+
255
+ expect { @client.rpush("key1", []) }.to raise_error(Redis::CommandError, /rpush[^x]/)
256
+ expect { @client.rpush("key1", 1); @client.rpushx("key1", []) }.to raise_error(Redis::CommandError, /rpushx/)
201
257
  end
202
258
  end
203
259
  end
data/spec/memory_spec.rb CHANGED
@@ -1,28 +1,101 @@
1
1
  require 'spec_helper'
2
2
 
3
- module FakeRedis
3
+ RSpec.describe FakeRedis do
4
+ let(:redis) { Redis.new }
5
+
6
+ def populate_keys_in_redis(num)
7
+ num.times do |count|
8
+ redis.set("key#{count}", count)
9
+ end
10
+ end
11
+
12
+ describe '#write' do
13
+ it 'should not send unexpected arguments' do
14
+ expect { redis.write(['info', 'server']) }.not_to raise_error
15
+ end
16
+ end
17
+
18
+ describe '#scan' do
19
+ def result
20
+ returned_keys = []
21
+ cursor = 0
22
+
23
+ loop do
24
+ cursor, keys = redis.scan(cursor, match_arguments)
25
+ returned_keys += keys
26
+ break if cursor == '0'
27
+ end
28
+ returned_keys
29
+ end
30
+
31
+ before do
32
+ populate_keys_in_redis(11)
33
+ end
34
+
35
+ context('when deleting') do
36
+ it('preverves cursor') do
37
+ cursor, keys = redis.scan('0')
38
+ keys.each { |key| redis.del(key) }
39
+ _, keys = redis.scan(cursor)
40
+ expect(keys).to eq(%w(key10))
41
+ end
42
+ end
43
+
44
+ context 'with one namespace' do
45
+ let(:match_arguments) { {} }
46
+
47
+ it 'returns the expected array of keys' do
48
+ expect(result).to match_array(redis.keys)
49
+ end
50
+ end
51
+
52
+ context 'with multiple namespaces' do
53
+ let(:namespaced_key) { 'test' }
54
+ let(:match_arguments) { { match: namespaced_key } }
55
+
56
+ before { redis.set(namespaced_key, 12) }
57
+
58
+ it 'returns the expected array of keys' do
59
+ expect(result).to match_array([namespaced_key])
60
+ end
61
+ end
62
+ end
63
+
4
64
  describe 'time' do
5
65
  before(:each) do
6
- @client = Redis.new
7
- Time.stub_chain(:now, :to_f).and_return(1397845595.5139461)
66
+ allow(Time).to receive_message_chain(:now, :to_f).and_return(1397845595.5139461)
8
67
  end
9
68
 
10
69
  it 'is an array' do
11
- expect(@client.time).to be_an_instance_of(Array)
70
+ expect(redis.time).to be_an_instance_of(Array)
12
71
  end
13
72
 
14
73
  it 'has two elements' do
15
- expect(@client.time.count).to eql 2
74
+ expect(redis.time.count).to eql 2
16
75
  end
17
76
 
18
77
  if fakeredis?
19
78
  it 'has the current time in seconds' do
20
- expect(@client.time.first).to eql 1397845595
79
+ expect(redis.time.first).to eql 1397845595
21
80
  end
22
81
 
23
82
  it 'has the current leftover microseconds' do
24
- expect(@client.time.last).to eql 513946
83
+ expect(redis.time.last).to eql 513946
25
84
  end
26
85
  end
27
86
  end
87
+
88
+ describe '#client' do
89
+ it 'returns OK when command is :setname' do
90
+ expect(redis.client(:setname, 'my-client-01')).to eq 'OK'
91
+ end
92
+
93
+ it 'returns nil when command is :getname' do
94
+ expect(redis.client(:getname)).to eq nil
95
+ end
96
+
97
+ it 'raises error for other commands' do
98
+ expect { redis.write([:client, :wrong]) }.to raise_error(Redis::CommandError, "ERR unknown command 'wrong'")
99
+ end
100
+ end
28
101
  end
data/spec/server_spec.rb CHANGED
@@ -12,29 +12,29 @@ module FakeRedis
12
12
  @client.set("key2", "2")
13
13
  @client.set("key2", "two")
14
14
 
15
- @client.dbsize.should be == 2
15
+ expect(@client.dbsize).to eq(2)
16
16
  end
17
17
 
18
18
  it "should get information and statistics about the server" do
19
- @client.info.key?("redis_version").should be == true
19
+ expect(@client.info.key?("redis_version")).to eq(true)
20
20
  end
21
21
 
22
22
  it "should handle non-existent methods" do
23
- lambda { @client.idontexist }.should raise_error(Redis::CommandError, "ERR unknown command 'idontexist'")
23
+ expect { @client.idontexist }.to raise_error(Redis::CommandError, "ERR unknown command 'idontexist'")
24
24
  end
25
25
 
26
26
  describe "multiple databases" do
27
27
  it "should default to database 0" do
28
- @client.inspect.should =~ %r#/0>$#
28
+ expect(@client.inspect).to match(%r#/0>$#)
29
29
  end
30
30
 
31
31
  it "should select another database" do
32
32
  @client.select(1)
33
- @client.inspect.should =~ %r#/1>$#
33
+ expect(@client.inspect).to match(%r#/1>$#)
34
34
  end
35
35
 
36
36
  it "should store keys separately in each database" do
37
- @client.select(0).should be == "OK"
37
+ expect(@client.select(0)).to eq("OK")
38
38
  @client.set("key1", "1")
39
39
  @client.set("key2", "2")
40
40
 
@@ -44,56 +44,70 @@ module FakeRedis
44
44
  @client.set("key5", "5")
45
45
 
46
46
  @client.select(0)
47
- @client.dbsize.should be == 2
48
- @client.exists("key1").should be true
49
- @client.exists("key3").should be false
47
+ expect(@client.dbsize).to eq(2)
48
+ expect(@client.exists("key1")).to be true
49
+ expect(@client.exists("key3")).to be false
50
50
 
51
51
  @client.select(1)
52
- @client.dbsize.should be == 3
53
- @client.exists("key4").should be true
54
- @client.exists("key2").should be false
52
+ expect(@client.dbsize).to eq(3)
53
+ expect(@client.exists("key4")).to be true
54
+ expect(@client.exists("key2")).to be false
55
55
 
56
56
  @client.flushall
57
- @client.dbsize.should be == 0
57
+ expect(@client.dbsize).to eq(0)
58
58
 
59
59
  @client.select(0)
60
- @client.dbsize.should be == 0
60
+ expect(@client.dbsize).to eq(0)
61
61
  end
62
62
 
63
63
  it "should flush a database" do
64
64
  @client.select(0)
65
65
  @client.set("key1", "1")
66
66
  @client.set("key2", "2")
67
- @client.dbsize.should be == 2
67
+ expect(@client.dbsize).to eq(2)
68
68
 
69
69
  @client.select(1)
70
70
  @client.set("key3", "3")
71
71
  @client.set("key4", "4")
72
- @client.dbsize.should be == 2
72
+ expect(@client.dbsize).to eq(2)
73
73
 
74
- @client.flushdb.should be == "OK"
74
+ expect(@client.flushdb).to eq("OK")
75
75
 
76
- @client.dbsize.should be == 0
76
+ expect(@client.dbsize).to eq(0)
77
77
  @client.select(0)
78
- @client.dbsize.should be == 2
78
+ expect(@client.dbsize).to eq(2)
79
79
  end
80
80
 
81
81
  it "should flush all databases" do
82
82
  @client.select(0)
83
83
  @client.set("key3", "3")
84
84
  @client.set("key4", "4")
85
- @client.dbsize.should be == 2
85
+ expect(@client.dbsize).to eq(2)
86
86
 
87
87
  @client.select(1)
88
88
  @client.set("key3", "3")
89
89
  @client.set("key4", "4")
90
- @client.dbsize.should be == 2
90
+ expect(@client.dbsize).to eq(2)
91
91
 
92
- @client.flushall.should be == "OK"
92
+ expect(@client.flushall).to eq("OK")
93
93
 
94
- @client.dbsize.should be == 0
94
+ expect(@client.dbsize).to eq(0)
95
95
  @client.select(0)
96
- @client.dbsize.should be == 0
96
+ expect(@client.dbsize).to eq(0)
97
+ end
98
+ end
99
+ end
100
+
101
+ describe 'custom options' do
102
+ describe 'version' do
103
+ it 'reports default Redis version when not provided' do
104
+ client = Redis.new
105
+ expect(client.info['redis_version']).to eq Redis::Connection::DEFAULT_REDIS_VERSION
106
+ end
107
+
108
+ it 'creates with and reports properly' do
109
+ client = Redis.new(version: '3.3.0')
110
+ expect(client.info['redis_version']).to eq '3.3.0'
97
111
  end
98
112
  end
99
113
  end