fakeredis 0.5.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +3 -0
- data/.travis.yml +14 -5
- data/LICENSE +1 -1
- data/README.md +42 -24
- data/fakeredis.gemspec +1 -1
- data/lib/fakeredis.rb +28 -0
- data/lib/fakeredis/bitop_command.rb +56 -0
- data/lib/fakeredis/command_executor.rb +6 -9
- data/lib/fakeredis/expiring_hash.rb +3 -5
- data/lib/fakeredis/geo_commands.rb +142 -0
- data/lib/fakeredis/geo_set.rb +84 -0
- data/lib/fakeredis/minitest.rb +24 -0
- data/lib/fakeredis/rspec.rb +1 -0
- data/lib/fakeredis/sort_method.rb +3 -3
- data/lib/fakeredis/sorted_set_store.rb +1 -1
- data/lib/fakeredis/transaction_commands.rb +2 -2
- data/lib/fakeredis/version.rb +1 -1
- data/lib/fakeredis/zset.rb +8 -2
- data/lib/redis/connection/memory.rb +650 -82
- data/spec/bitop_command_spec.rb +209 -0
- data/spec/command_executor_spec.rb +15 -0
- data/spec/compatibility_spec.rb +1 -1
- data/spec/connection_spec.rb +21 -21
- data/spec/fakeredis_spec.rb +73 -0
- data/spec/geo_set_spec.rb +164 -0
- data/spec/hashes_spec.rb +138 -57
- data/spec/hyper_log_logs_spec.rb +50 -0
- data/spec/keys_spec.rb +232 -90
- data/spec/lists_spec.rb +91 -35
- data/spec/memory_spec.rb +80 -7
- data/spec/server_spec.rb +38 -24
- data/spec/sets_spec.rb +112 -46
- data/spec/sort_method_spec.rb +6 -0
- data/spec/sorted_sets_spec.rb +482 -150
- data/spec/spec_helper.rb +9 -18
- data/spec/spec_helper_live_redis.rb +4 -4
- data/spec/strings_spec.rb +113 -79
- data/spec/subscription_spec.rb +107 -0
- data/spec/support/shared_examples/bitwise_operation.rb +59 -0
- data/spec/support/shared_examples/sortable.rb +20 -16
- data/spec/transactions_spec.rb +34 -13
- data/spec/upcase_method_name_spec.rb +2 -2
- metadata +23 -6
data/spec/hashes_spec.rb
CHANGED
@@ -9,168 +9,194 @@ module FakeRedis
|
|
9
9
|
it "should delete a hash field" do
|
10
10
|
@client.hset("key1", "k1", "val1")
|
11
11
|
@client.hset("key1", "k2", "val2")
|
12
|
-
@client.hdel("key1", "k1").
|
12
|
+
expect(@client.hdel("key1", "k1")).to be(1)
|
13
13
|
|
14
|
-
@client.hget("key1", "k1").
|
15
|
-
@client.hget("key1", "k2").
|
14
|
+
expect(@client.hget("key1", "k1")).to be_nil
|
15
|
+
expect(@client.hget("key1", "k2")).to eq("val2")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should delete array of fields" do
|
19
|
+
@client.hset("key1", "k1", "val1")
|
20
|
+
@client.hset("key1", "k2", "val2")
|
21
|
+
@client.hset("key1", "k3", "val3")
|
22
|
+
expect(@client.hdel("key1", ["k1", "k2"])).to be(2)
|
23
|
+
|
24
|
+
expect(@client.hget("key1", "k1")).to be_nil
|
25
|
+
expect(@client.hget("key1", "k2")).to be_nil
|
26
|
+
expect(@client.hget("key1", "k3")).to eq("val3")
|
16
27
|
end
|
17
28
|
|
18
29
|
it "should remove a hash with no keys left" do
|
19
30
|
@client.hset("key1", "k1", "val1")
|
20
31
|
@client.hset("key1", "k2", "val2")
|
21
|
-
@client.hdel("key1", "k1").
|
22
|
-
@client.hdel("key1", "k2").
|
32
|
+
expect(@client.hdel("key1", "k1")).to be(1)
|
33
|
+
expect(@client.hdel("key1", "k2")).to be(1)
|
23
34
|
|
24
|
-
@client.exists("key1").
|
35
|
+
expect(@client.exists("key1")).to eq(false)
|
25
36
|
end
|
26
37
|
|
27
38
|
it "should convert key to a string for hset" do
|
28
39
|
m = double("key")
|
29
|
-
m.
|
40
|
+
allow(m).to receive(:to_s).and_return("foo")
|
30
41
|
|
31
42
|
@client.hset("key1", m, "bar")
|
32
|
-
@client.hget("key1", "foo").
|
43
|
+
expect(@client.hget("key1", "foo")).to eq("bar")
|
33
44
|
end
|
34
45
|
|
35
46
|
it "should convert key to a string for hget" do
|
36
47
|
m = double("key")
|
37
|
-
m.
|
48
|
+
allow(m).to receive(:to_s).and_return("foo")
|
38
49
|
|
39
50
|
@client.hset("key1", "foo", "bar")
|
40
|
-
@client.hget("key1", m).
|
51
|
+
expect(@client.hget("key1", m)).to eq("bar")
|
41
52
|
end
|
42
53
|
|
43
54
|
it "should determine if a hash field exists" do
|
44
55
|
@client.hset("key1", "index", "value")
|
45
56
|
|
46
|
-
@client.hexists("key1", "index").
|
47
|
-
@client.hexists("key2", "i2").
|
57
|
+
expect(@client.hexists("key1", "index")).to be true
|
58
|
+
expect(@client.hexists("key2", "i2")).to be false
|
48
59
|
end
|
49
60
|
|
50
61
|
it "should get the value of a hash field" do
|
51
62
|
@client.hset("key1", "index", "value")
|
52
63
|
|
53
|
-
@client.hget("key1", "index").
|
64
|
+
expect(@client.hget("key1", "index")).to eq("value")
|
54
65
|
end
|
55
66
|
|
56
67
|
it "should get all the fields and values in a hash" do
|
57
68
|
@client.hset("key1", "i1", "val1")
|
58
69
|
@client.hset("key1", "i2", "val2")
|
59
70
|
|
60
|
-
@client.hgetall("key1").
|
71
|
+
expect(@client.hgetall("key1")).to eq({"i1" => "val1", "i2" => "val2"})
|
61
72
|
end
|
62
73
|
|
63
74
|
it "should increment the integer value of a hash field by the given number" do
|
64
75
|
@client.hset("key1", "cont1", "5")
|
65
|
-
@client.hincrby("key1", "cont1", "5").
|
66
|
-
@client.hget("key1", "cont1").
|
76
|
+
expect(@client.hincrby("key1", "cont1", "5")).to eq(10)
|
77
|
+
expect(@client.hget("key1", "cont1")).to eq("10")
|
67
78
|
end
|
68
79
|
|
69
80
|
it "should increment non existing hash keys" do
|
70
|
-
@client.hget("key1", "cont2").
|
71
|
-
@client.hincrby("key1", "cont2", "5").
|
81
|
+
expect(@client.hget("key1", "cont2")).to be_nil
|
82
|
+
expect(@client.hincrby("key1", "cont2", "5")).to eq(5)
|
72
83
|
end
|
73
84
|
|
74
85
|
it "should increment the float value of a hash field by the given float" do
|
75
86
|
@client.hset("key1", "cont1", 5.0)
|
76
|
-
@client.hincrbyfloat("key1", "cont1", 4.1).
|
77
|
-
@client.hget("key1", "cont1").
|
87
|
+
expect(@client.hincrbyfloat("key1", "cont1", 4.1)).to eq(9.1)
|
88
|
+
expect(@client.hget("key1", "cont1")).to eq("9.1")
|
78
89
|
end
|
79
90
|
|
80
91
|
it "should increment non existing hash keys" do
|
81
|
-
@client.hget("key1", "cont2").
|
82
|
-
@client.hincrbyfloat("key1", "cont2", 5.5).
|
92
|
+
expect(@client.hget("key1", "cont2")).to be_nil
|
93
|
+
expect(@client.hincrbyfloat("key1", "cont2", 5.5)).to eq(5.5)
|
83
94
|
end
|
84
95
|
|
85
96
|
it "should get all the fields in a hash" do
|
86
97
|
@client.hset("key1", "i1", "val1")
|
87
98
|
@client.hset("key1", "i2", "val2")
|
88
99
|
|
89
|
-
@client.hkeys("key1").
|
90
|
-
@client.hkeys("key2").
|
100
|
+
expect(@client.hkeys("key1")).to match_array(["i1", "i2"])
|
101
|
+
expect(@client.hkeys("key2")).to eq([])
|
91
102
|
end
|
92
103
|
|
93
104
|
it "should get the number of fields in a hash" do
|
94
105
|
@client.hset("key1", "i1", "val1")
|
95
106
|
@client.hset("key1", "i2", "val2")
|
96
107
|
|
97
|
-
@client.hlen("key1").
|
108
|
+
expect(@client.hlen("key1")).to eq(2)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should get the string length of the value associated with field in a hash" do
|
112
|
+
@client.hset("key1", "i1", "val1")
|
113
|
+
expect(@client.hstrlen("key1", "i1")).to eq(4)
|
114
|
+
expect(@client.hstrlen("key1", "nonexistent")).to eq(0)
|
115
|
+
expect(@client.hstrlen("nonexistent", "field")).to eq(0)
|
98
116
|
end
|
99
117
|
|
100
118
|
it "should get the values of all the given hash fields" do
|
101
119
|
@client.hset("key1", "i1", "val1")
|
102
120
|
@client.hset("key1", "i2", "val2")
|
103
121
|
|
104
|
-
@client.hmget("key1", "i1", "i2", "i3").
|
105
|
-
@client.hmget("key1", ["i1", "i2", "i3"]).
|
122
|
+
expect(@client.hmget("key1", "i1", "i2", "i3")).to match_array(["val1", "val2", nil])
|
123
|
+
expect(@client.hmget("key1", ["i1", "i2", "i3"])).to match_array(["val1", "val2", nil])
|
106
124
|
|
107
|
-
@client.hmget("key2", "i1", "i2").
|
125
|
+
expect(@client.hmget("key2", "i1", "i2")).to eq([nil, nil])
|
108
126
|
end
|
109
127
|
|
110
128
|
it "should throw an argument error when you don't ask for any keys" do
|
111
|
-
|
129
|
+
expect { @client.hmget("key1") }.to raise_error(Redis::CommandError)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should throw an argument error when the list of keys you ask for is empty" do
|
133
|
+
expect { @client.hmget("key1", []) }.to raise_error(Redis::CommandError)
|
112
134
|
end
|
113
135
|
|
114
136
|
it "should reject an empty list of values" do
|
115
|
-
|
116
|
-
@client.exists("key").
|
137
|
+
expect { @client.hmset("key") }.to raise_error(Redis::CommandError)
|
138
|
+
expect(@client.exists("key")).to be false
|
117
139
|
end
|
118
140
|
|
119
141
|
it "rejects an insert with a key but no value" do
|
120
|
-
|
121
|
-
|
122
|
-
@client.exists("key").
|
142
|
+
expect { @client.hmset("key", 'foo') }.to raise_error(Redis::CommandError)
|
143
|
+
expect { @client.hmset("key", 'foo', 3, 'bar') }.to raise_error(Redis::CommandError)
|
144
|
+
expect(@client.exists("key")).to be false
|
123
145
|
end
|
124
146
|
|
125
147
|
it "should reject the wrong number of arguments" do
|
126
|
-
|
148
|
+
expect { @client.hmset("hash", "foo1", "bar1", "foo2", "bar2", "foo3") }.to raise_error(Redis::CommandError, "ERR wrong number of arguments for HMSET")
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should return OK on success" do
|
152
|
+
expect(@client.hmset("key", "k1", "value1")).to eq("OK")
|
127
153
|
end
|
128
154
|
|
129
155
|
it "should set multiple hash fields to multiple values" do
|
130
156
|
@client.hmset("key", "k1", "value1", "k2", "value2")
|
131
157
|
|
132
|
-
@client.hget("key", "k1").
|
133
|
-
@client.hget("key", "k2").
|
158
|
+
expect(@client.hget("key", "k1")).to eq("value1")
|
159
|
+
expect(@client.hget("key", "k2")).to eq("value2")
|
134
160
|
end
|
135
161
|
|
136
162
|
it "should set multiple hash fields from a ruby hash to multiple values" do
|
137
163
|
@client.mapped_hmset("foo", :k1 => "value1", :k2 => "value2")
|
138
164
|
|
139
|
-
@client.hget("foo", "k1").
|
140
|
-
@client.hget("foo", "k2").
|
165
|
+
expect(@client.hget("foo", "k1")).to eq("value1")
|
166
|
+
expect(@client.hget("foo", "k2")).to eq("value2")
|
141
167
|
end
|
142
168
|
|
143
169
|
it "should set the string value of a hash field" do
|
144
|
-
@client.hset("key1", "k1", "val1").
|
145
|
-
@client.hset("key1", "k1", "val1").
|
170
|
+
expect(@client.hset("key1", "k1", "val1")).to eq(true)
|
171
|
+
expect(@client.hset("key1", "k1", "val1")).to eq(false)
|
146
172
|
|
147
|
-
@client.hget("key1", "k1").
|
173
|
+
expect(@client.hget("key1", "k1")).to eq("val1")
|
148
174
|
end
|
149
175
|
|
150
176
|
it "should set the value of a hash field, only if the field does not exist" do
|
151
177
|
@client.hset("key1", "k1", "val1")
|
152
|
-
@client.hsetnx("key1", "k1", "value").
|
153
|
-
@client.hsetnx("key1", "k2", "val2").
|
154
|
-
@client.hsetnx("key1", :k1, "value").
|
155
|
-
@client.hsetnx("key1", :k3, "val3").
|
156
|
-
|
157
|
-
@client.hget("key1", "k1").
|
158
|
-
@client.hget("key1", "k2").
|
159
|
-
@client.hget("key1", "k3").
|
178
|
+
expect(@client.hsetnx("key1", "k1", "value")).to eq(false)
|
179
|
+
expect(@client.hsetnx("key1", "k2", "val2")).to eq(true)
|
180
|
+
expect(@client.hsetnx("key1", :k1, "value")).to eq(false)
|
181
|
+
expect(@client.hsetnx("key1", :k3, "val3")).to eq(true)
|
182
|
+
|
183
|
+
expect(@client.hget("key1", "k1")).to eq("val1")
|
184
|
+
expect(@client.hget("key1", "k2")).to eq("val2")
|
185
|
+
expect(@client.hget("key1", "k3")).to eq("val3")
|
160
186
|
end
|
161
187
|
|
162
188
|
it "should get all the values in a hash" do
|
163
189
|
@client.hset("key1", "k1", "val1")
|
164
190
|
@client.hset("key1", "k2", "val2")
|
165
191
|
|
166
|
-
@client.hvals("key1").
|
192
|
+
expect(@client.hvals("key1")).to match_array(["val1", "val2"])
|
167
193
|
end
|
168
194
|
|
169
195
|
it "should accept a list of array pairs as arguments and not throw an invalid argument number error" do
|
170
196
|
@client.hmset("key1", [:k1, "val1"], [:k2, "val2"], [:k3, "val3"])
|
171
|
-
@client.hget("key1", :k1).
|
172
|
-
@client.hget("key1", :k2).
|
173
|
-
@client.hget("key1", :k3).
|
197
|
+
expect(@client.hget("key1", :k1)).to eq("val1")
|
198
|
+
expect(@client.hget("key1", :k2)).to eq("val2")
|
199
|
+
expect(@client.hget("key1", :k3)).to eq("val3")
|
174
200
|
end
|
175
201
|
|
176
202
|
it "should reject a list of arrays that contain an invalid number of arguments" do
|
@@ -179,17 +205,72 @@ module FakeRedis
|
|
179
205
|
|
180
206
|
it "should convert a integer field name to string for hdel" do
|
181
207
|
@client.hset("key1", "1", 1)
|
182
|
-
@client.hdel("key1", 1).
|
208
|
+
expect(@client.hdel("key1", 1)).to be(1)
|
183
209
|
end
|
184
210
|
|
185
211
|
it "should convert a integer field name to string for hexists" do
|
186
212
|
@client.hset("key1", "1", 1)
|
187
|
-
@client.hexists("key1", 1).
|
213
|
+
expect(@client.hexists("key1", 1)).to be true
|
188
214
|
end
|
189
215
|
|
190
216
|
it "should convert a integer field name to string for hincrby" do
|
191
217
|
@client.hset("key1", 1, 0)
|
192
|
-
@client.hincrby("key1", 1, 1).
|
218
|
+
expect(@client.hincrby("key1", 1, 1)).to be(1)
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "#hscan" do
|
222
|
+
it 'with no arguments and few items, returns all items' do
|
223
|
+
@client.hmset('hash', 'name', 'Jack', 'age', '33')
|
224
|
+
result = @client.hscan('hash', 0)
|
225
|
+
|
226
|
+
expect(result[0]).to eq('0')
|
227
|
+
expect(result[1]).to eq([['name', 'Jack'], ['age', '33']])
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'with a count should return that number of members or more' do
|
231
|
+
@client.hmset('hash',
|
232
|
+
'a', '1', 'b', '2', 'c', '3', 'd', '4', 'e', '5', 'f', '6', 'g', '7'
|
233
|
+
)
|
234
|
+
result = @client.hscan('hash', 0, count: 3)
|
235
|
+
expect(result[0]).to eq('3')
|
236
|
+
expect(result[1]).to eq([
|
237
|
+
['a', '1'],
|
238
|
+
['b', '2'],
|
239
|
+
['c', '3'],
|
240
|
+
])
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'returns items starting at the provided cursor' do
|
244
|
+
@client.hmset('hash',
|
245
|
+
'a', '1', 'b', '2', 'c', '3', 'd', '4', 'e', '5', 'f', '6', 'g', '7'
|
246
|
+
)
|
247
|
+
result = @client.hscan('hash', 2, count: 3)
|
248
|
+
expect(result[0]).to eq('5')
|
249
|
+
expect(result[1]).to eq([
|
250
|
+
['c', '3'],
|
251
|
+
['d', '4'],
|
252
|
+
['e', '5']
|
253
|
+
])
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'with match, returns items matching the given pattern' do
|
257
|
+
@client.hmset('hash',
|
258
|
+
'aa', '1', 'b', '2', 'cc', '3', 'd', '4', 'ee', '5', 'f', '6', 'gg', '7'
|
259
|
+
)
|
260
|
+
result = @client.hscan('hash', 2, count: 3, match: '??')
|
261
|
+
expect(result[0]).to eq('5')
|
262
|
+
expect(result[1]).to eq([
|
263
|
+
['cc', '3'],
|
264
|
+
['ee', '5']
|
265
|
+
])
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'returns an empty result if the key is not found' do
|
269
|
+
result = @client.hscan('hash', 0)
|
270
|
+
|
271
|
+
expect(result[0]).to eq('0')
|
272
|
+
expect(result[1]).to eq([])
|
273
|
+
end
|
193
274
|
end
|
194
275
|
end
|
195
276
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module FakeRedis
|
4
|
+
describe "HyperLogLogsMethods" do
|
5
|
+
let(:redis) { Redis.new }
|
6
|
+
|
7
|
+
it "should add item to hyperloglog" do
|
8
|
+
expect(redis.pfadd("hll", "val")).to eq(true)
|
9
|
+
expect(redis.pfcount("hll")).to eq(1)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should not add duplicated item to hyperloglog" do
|
13
|
+
redis.pfadd("hll", "val")
|
14
|
+
expect(redis.pfadd("hll", "val")).to eq(false)
|
15
|
+
expect(redis.pfcount("hll")).to eq(1)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should not add multiple items to hyperloglog" do
|
19
|
+
expect(redis.pfadd("hll", ["val1", "val2"])).to eq(true)
|
20
|
+
expect(redis.pfcount("hll")).to eq(2)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return zero as cardinality for nonexistent key" do
|
24
|
+
expect(redis.pfcount("nonexistent")).to eq(0)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return cardinality of union of hyperloglogs" do
|
28
|
+
redis.pfadd("hll1", ["val1", "val2"])
|
29
|
+
redis.pfadd("hll2", ["val2", "val3"])
|
30
|
+
expect(redis.pfcount("hll1", "hll2")).to eq(3)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should error if an empty list of keys is given" do
|
34
|
+
expect { redis.pfcount([]) }.to raise_error(Redis::CommandError, "ERR wrong number of arguments for 'pfcount' command")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should merge hyperloglogs" do
|
38
|
+
redis.pfadd("hll1", ["val1", "val2"])
|
39
|
+
redis.pfadd("hll2", ["val2", "val3"])
|
40
|
+
expect(redis.pfmerge("hll3", "hll1", "hll2")).to eq(true)
|
41
|
+
expect(redis.pfcount("hll3")).to eq(3)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should merge nonexistent hyperloglogs with others" do
|
45
|
+
redis.pfadd("hll1", "val")
|
46
|
+
expect(redis.pfmerge("hll3", "hll1", "nonexistent")).to eq(true)
|
47
|
+
expect(redis.pfcount("hll3")).to eq(1)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/spec/keys_spec.rb
CHANGED
@@ -7,56 +7,89 @@ module FakeRedis
|
|
7
7
|
@client = Redis.new
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
[:del, :unlink].each do |command|
|
11
|
+
it "should #{command} a key" do
|
12
|
+
@client.set("key1", "1")
|
13
|
+
@client.set("key2", "2")
|
14
|
+
@client.public_send(command, "key1", "key2")
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
expect(@client.get("key1")).to eq(nil)
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
it "should #{command} multiple keys" do
|
20
|
+
@client.set("key1", "1")
|
21
|
+
@client.set("key2", "2")
|
22
|
+
@client.public_send(command, ["key1", "key2"])
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
expect(@client.get("key1")).to eq(nil)
|
25
|
+
expect(@client.get("key2")).to eq(nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should return the number of '#{command}'ed keys" do
|
29
|
+
@client.set("key1", "1")
|
30
|
+
expect(@client.public_send(command, ["key1", "key2"])).to eq(1)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should error '#{command}'ing no keys" do
|
34
|
+
expect { @client.public_send(command) }.to raise_error(Redis::CommandError, "ERR wrong number of arguments for '#{command}' command")
|
35
|
+
expect { @client.public_send(command, []) }.to raise_error(Redis::CommandError, "ERR wrong number of arguments for '#{command}' command")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should return true when setnx keys that don't exist" do
|
40
|
+
expect(@client.setnx("key1", "1")).to eq(true)
|
25
41
|
end
|
26
42
|
|
27
|
-
it "should
|
28
|
-
|
29
|
-
|
43
|
+
it "should return false when setnx keys exist" do
|
44
|
+
@client.set("key1", "1")
|
45
|
+
expect(@client.setnx("key1", "1")).to eq(false)
|
30
46
|
end
|
31
47
|
|
32
48
|
it "should return true when setting expires on keys that exist" do
|
33
49
|
@client.set("key1", "1")
|
34
|
-
@client.expire("key1", 1).
|
50
|
+
expect(@client.expire("key1", 1)).to eq(true)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return true when setting pexpires on keys that exist" do
|
54
|
+
@client.set("key1", "1")
|
55
|
+
expect(@client.pexpire("key1", 1)).to eq(true)
|
35
56
|
end
|
36
57
|
|
37
58
|
it "should return false when attempting to set expires on a key that does not exist" do
|
38
|
-
@client.expire("key1", 1).
|
59
|
+
expect(@client.expire("key1", 1)).to eq(false)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should return false when attempting to set pexpires on a key that does not exist" do
|
63
|
+
expect(@client.pexpire("key1", 1)).to eq(false)
|
39
64
|
end
|
40
65
|
|
41
66
|
it "should determine if a key exists" do
|
42
67
|
@client.set("key1", "1")
|
43
68
|
|
44
|
-
@client.exists("key1").
|
45
|
-
@client.exists("key2").
|
69
|
+
expect(@client.exists("key1")).to eq(true)
|
70
|
+
expect(@client.exists("key2")).to eq(false)
|
46
71
|
end
|
47
72
|
|
48
73
|
it "should set a key's time to live in seconds" do
|
49
74
|
@client.set("key1", "1")
|
50
75
|
@client.expire("key1", 1)
|
51
76
|
|
52
|
-
@client.ttl("key1").
|
77
|
+
expect(@client.ttl("key1")).to eq(1)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should set a key's time to live in miliseconds" do
|
81
|
+
allow(Time).to receive(:now).and_return(1000)
|
82
|
+
@client.set("key1", "1")
|
83
|
+
@client.pexpire("key1", 2200)
|
84
|
+
expect(@client.pttl("key1")).to be_within(0.1).of(2200)
|
85
|
+
allow(Time).to receive(:now).and_call_original
|
53
86
|
end
|
54
87
|
|
55
88
|
it "should set the expiration for a key as a UNIX timestamp" do
|
56
89
|
@client.set("key1", "1")
|
57
90
|
@client.expireat("key1", Time.now.to_i + 2)
|
58
91
|
|
59
|
-
@client.ttl("key1").
|
92
|
+
expect(@client.ttl("key1")).to eq(2)
|
60
93
|
end
|
61
94
|
|
62
95
|
it "should not have an expiration after re-set" do
|
@@ -64,21 +97,21 @@ module FakeRedis
|
|
64
97
|
@client.expireat("key1", Time.now.to_i + 2)
|
65
98
|
@client.set("key1", "1")
|
66
99
|
|
67
|
-
@client.ttl("key1").
|
100
|
+
expect(@client.ttl("key1")).to eq(-1)
|
68
101
|
end
|
69
102
|
|
70
103
|
it "should not have a ttl if expired (and thus key does not exist)" do
|
71
104
|
@client.set("key1", "1")
|
72
105
|
@client.expireat("key1", Time.now.to_i)
|
73
106
|
|
74
|
-
@client.ttl("key1").
|
107
|
+
expect(@client.ttl("key1")).to eq(-2)
|
75
108
|
end
|
76
109
|
|
77
110
|
it "should not find a key if expired" do
|
78
111
|
@client.set("key1", "1")
|
79
112
|
@client.expireat("key1", Time.now.to_i)
|
80
113
|
|
81
|
-
@client.get("key1").
|
114
|
+
expect(@client.get("key1")).to be_nil
|
82
115
|
end
|
83
116
|
|
84
117
|
it "should not find multiple keys if expired" do
|
@@ -86,7 +119,7 @@ module FakeRedis
|
|
86
119
|
@client.set("key2", "2")
|
87
120
|
@client.expireat("key1", Time.now.to_i)
|
88
121
|
|
89
|
-
@client.mget("key1", "key2").
|
122
|
+
expect(@client.mget("key1", "key2")).to eq([nil, "2"])
|
90
123
|
end
|
91
124
|
|
92
125
|
it "should only find keys that aren't expired" do
|
@@ -94,14 +127,21 @@ module FakeRedis
|
|
94
127
|
@client.set("key2", "2")
|
95
128
|
@client.expireat("key1", Time.now.to_i)
|
96
129
|
|
97
|
-
@client.keys.
|
130
|
+
expect(@client.keys).to eq(["key2"])
|
98
131
|
end
|
99
132
|
|
100
133
|
it "should not exist if expired" do
|
101
134
|
@client.set("key1", "1")
|
102
135
|
@client.expireat("key1", Time.now.to_i)
|
103
136
|
|
104
|
-
@client.exists("key1").
|
137
|
+
expect(@client.exists("key1")).to be false
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should get integer and string keys" do
|
141
|
+
@client.set("key1", "1")
|
142
|
+
@client.set(2, "2")
|
143
|
+
|
144
|
+
expect(@client.mget("key1", 2)).to eq(["1", "2"])
|
105
145
|
end
|
106
146
|
|
107
147
|
it "should find all keys matching the given pattern" do
|
@@ -113,32 +153,32 @@ module FakeRedis
|
|
113
153
|
|
114
154
|
@client.mset("database", 1, "above", 2, "suitability", 3, "able", 4)
|
115
155
|
|
116
|
-
@client.keys("key:*").
|
117
|
-
@client.keys("ab*").
|
156
|
+
expect(@client.keys("key:*")).to match_array(["key:a", "key:b", "key:c"])
|
157
|
+
expect(@client.keys("ab*")).to match_array(["above", "able"])
|
118
158
|
end
|
119
159
|
|
120
160
|
it "should remove the expiration from a key" do
|
121
161
|
@client.set("key1", "1")
|
122
162
|
@client.expireat("key1", Time.now.to_i + 1)
|
123
|
-
@client.persist("key1").
|
124
|
-
@client.persist("key1").
|
163
|
+
expect(@client.persist("key1")).to eq(true)
|
164
|
+
expect(@client.persist("key1")).to eq(false)
|
125
165
|
|
126
|
-
@client.ttl("key1").
|
166
|
+
expect(@client.ttl("key1")).to eq(-1)
|
127
167
|
end
|
128
168
|
|
129
169
|
it "should return a random key from the keyspace" do
|
130
170
|
@client.set("key1", "1")
|
131
171
|
@client.set("key2", "2")
|
132
172
|
|
133
|
-
["key1", "key2"].include?(@client.randomkey).
|
173
|
+
expect(["key1", "key2"].include?(@client.randomkey)).to eq(true)
|
134
174
|
end
|
135
175
|
|
136
176
|
it "should rename a key" do
|
137
177
|
@client.set("key1", "2")
|
138
178
|
@client.rename("key1", "key2")
|
139
179
|
|
140
|
-
@client.get("key1").
|
141
|
-
@client.get("key2").
|
180
|
+
expect(@client.get("key1")).to eq(nil)
|
181
|
+
expect(@client.get("key2")).to eq("2")
|
142
182
|
end
|
143
183
|
|
144
184
|
it "should rename a key, only if new key does not exist" do
|
@@ -148,100 +188,100 @@ module FakeRedis
|
|
148
188
|
@client.renamenx("key1", "key2")
|
149
189
|
@client.renamenx("key3", "key4")
|
150
190
|
|
151
|
-
@client.get("key1").
|
152
|
-
@client.get("key2").
|
153
|
-
@client.get("key3").
|
154
|
-
@client.get("key4").
|
191
|
+
expect(@client.get("key1")).to eq("1")
|
192
|
+
expect(@client.get("key2")).to eq("2")
|
193
|
+
expect(@client.get("key3")).to eq(nil)
|
194
|
+
expect(@client.get("key4")).to eq("3")
|
155
195
|
end
|
156
196
|
|
157
197
|
it "should determine the type stored at key" do
|
158
198
|
# Non-existing key
|
159
|
-
@client.type("key0").
|
199
|
+
expect(@client.type("key0")).to eq("none")
|
160
200
|
|
161
201
|
# String
|
162
202
|
@client.set("key1", "1")
|
163
|
-
@client.type("key1").
|
203
|
+
expect(@client.type("key1")).to eq("string")
|
164
204
|
|
165
205
|
# List
|
166
206
|
@client.lpush("key2", "1")
|
167
|
-
@client.type("key2").
|
207
|
+
expect(@client.type("key2")).to eq("list")
|
168
208
|
|
169
209
|
# Set
|
170
210
|
@client.sadd("key3", "1")
|
171
|
-
@client.type("key3").
|
211
|
+
expect(@client.type("key3")).to eq("set")
|
172
212
|
|
173
213
|
# Sorted Set
|
174
214
|
@client.zadd("key4", 1.0, "1")
|
175
|
-
@client.type("key4").
|
215
|
+
expect(@client.type("key4")).to eq("zset")
|
176
216
|
|
177
217
|
# Hash
|
178
218
|
@client.hset("key5", "a", "1")
|
179
|
-
@client.type("key5").
|
219
|
+
expect(@client.type("key5")).to eq("hash")
|
180
220
|
end
|
181
221
|
|
182
222
|
it "should convert the value into a string before storing" do
|
183
223
|
@client.set("key1", 1)
|
184
|
-
@client.get("key1").
|
224
|
+
expect(@client.get("key1")).to eq("1")
|
185
225
|
|
186
226
|
@client.setex("key2", 30, 1)
|
187
|
-
@client.get("key2").
|
227
|
+
expect(@client.get("key2")).to eq("1")
|
188
228
|
|
189
229
|
@client.getset("key3", 1)
|
190
|
-
@client.get("key3").
|
230
|
+
expect(@client.get("key3")).to eq("1")
|
191
231
|
end
|
192
232
|
|
193
233
|
it "should return 'OK' for the setex command" do
|
194
|
-
@client.setex("key4", 30, 1).
|
234
|
+
expect(@client.setex("key4", 30, 1)).to eq("OK")
|
195
235
|
end
|
196
236
|
|
197
237
|
it "should convert the key into a string before storing" do
|
198
238
|
@client.set(123, "foo")
|
199
|
-
@client.keys.
|
200
|
-
@client.get("123").
|
239
|
+
expect(@client.keys).to include("123")
|
240
|
+
expect(@client.get("123")).to eq("foo")
|
201
241
|
|
202
242
|
@client.setex(456, 30, "foo")
|
203
|
-
@client.keys.
|
204
|
-
@client.get("456").
|
243
|
+
expect(@client.keys).to include("456")
|
244
|
+
expect(@client.get("456")).to eq("foo")
|
205
245
|
|
206
246
|
@client.getset(789, "foo")
|
207
|
-
@client.keys.
|
208
|
-
@client.get("789").
|
247
|
+
expect(@client.keys).to include("789")
|
248
|
+
expect(@client.get("789")).to eq("foo")
|
209
249
|
end
|
210
250
|
|
211
251
|
it "should only operate against keys containing string values" do
|
212
252
|
@client.sadd("key1", "one")
|
213
|
-
|
214
|
-
|
253
|
+
expect { @client.get("key1") }.to raise_error(Redis::CommandError, "WRONGTYPE Operation against a key holding the wrong kind of value")
|
254
|
+
expect { @client.getset("key1", 1) }.to raise_error(Redis::CommandError, "WRONGTYPE Operation against a key holding the wrong kind of value")
|
215
255
|
|
216
256
|
@client.hset("key2", "one", "two")
|
217
|
-
|
218
|
-
|
257
|
+
expect { @client.get("key2") }.to raise_error(Redis::CommandError, "WRONGTYPE Operation against a key holding the wrong kind of value")
|
258
|
+
expect { @client.getset("key2", 1) }.to raise_error(Redis::CommandError, "WRONGTYPE Operation against a key holding the wrong kind of value")
|
219
259
|
end
|
220
260
|
|
221
261
|
it "should move a key from one database to another successfully" do
|
222
262
|
@client.select(0)
|
223
263
|
@client.set("key1", "1")
|
224
264
|
|
225
|
-
@client.move("key1", 1).
|
265
|
+
expect(@client.move("key1", 1)).to eq(true)
|
226
266
|
|
227
267
|
@client.select(0)
|
228
|
-
@client.get("key1").
|
268
|
+
expect(@client.get("key1")).to be_nil
|
229
269
|
|
230
270
|
@client.select(1)
|
231
|
-
@client.get("key1").
|
271
|
+
expect(@client.get("key1")).to eq("1")
|
232
272
|
end
|
233
273
|
|
234
274
|
it "should fail to move a key that does not exist in the source database" do
|
235
275
|
@client.select(0)
|
236
|
-
@client.get("key1").
|
276
|
+
expect(@client.get("key1")).to be_nil
|
237
277
|
|
238
|
-
@client.move("key1", 1).
|
278
|
+
expect(@client.move("key1", 1)).to eq(false)
|
239
279
|
|
240
280
|
@client.select(0)
|
241
|
-
@client.get("key1").
|
281
|
+
expect(@client.get("key1")).to be_nil
|
242
282
|
|
243
283
|
@client.select(1)
|
244
|
-
@client.get("key1").
|
284
|
+
expect(@client.get("key1")).to be_nil
|
245
285
|
end
|
246
286
|
|
247
287
|
it "should fail to move a key that exists in the destination database" do
|
@@ -252,23 +292,23 @@ module FakeRedis
|
|
252
292
|
@client.set("key1", "2")
|
253
293
|
|
254
294
|
@client.select(0)
|
255
|
-
@client.move("key1", 1).
|
295
|
+
expect(@client.move("key1", 1)).to eq(false)
|
256
296
|
|
257
297
|
@client.select(0)
|
258
|
-
@client.get("key1").
|
298
|
+
expect(@client.get("key1")).to eq("1")
|
259
299
|
|
260
300
|
@client.select(1)
|
261
|
-
@client.get("key1").
|
301
|
+
expect(@client.get("key1")).to eq("2")
|
262
302
|
end
|
263
303
|
|
264
304
|
it "should fail to move a key to the same database" do
|
265
305
|
@client.select(0)
|
266
306
|
@client.set("key1", "1")
|
267
307
|
|
268
|
-
|
308
|
+
expect { @client.move("key1", 0) }.to raise_error(Redis::CommandError, "ERR source and destination objects are the same")
|
269
309
|
|
270
310
|
@client.select(0)
|
271
|
-
@client.get("key1").
|
311
|
+
expect(@client.get("key1")).to eq("1")
|
272
312
|
end
|
273
313
|
|
274
314
|
it "should scan all keys in the database" do
|
@@ -284,8 +324,8 @@ module FakeRedis
|
|
284
324
|
break if cursor == "0"
|
285
325
|
}
|
286
326
|
|
287
|
-
all_keys.uniq.size.
|
288
|
-
all_keys[0].
|
327
|
+
expect(all_keys.uniq.size).to eq(100)
|
328
|
+
expect(all_keys[0]).to match(/key\d+/)
|
289
329
|
end
|
290
330
|
|
291
331
|
it "should match keys to a pattern when scanning" do
|
@@ -304,7 +344,7 @@ module FakeRedis
|
|
304
344
|
break if cursor == "0"
|
305
345
|
}
|
306
346
|
|
307
|
-
all_keys.uniq.size.
|
347
|
+
expect(all_keys.uniq.size).to eq(50)
|
308
348
|
end
|
309
349
|
|
310
350
|
it "should specify doing more work when scanning" do
|
@@ -314,23 +354,23 @@ module FakeRedis
|
|
314
354
|
|
315
355
|
cursor, all_keys = @client.scan(cursor, :count => 100)
|
316
356
|
|
317
|
-
cursor.
|
318
|
-
all_keys.uniq.size.
|
357
|
+
expect(cursor).to eq("0")
|
358
|
+
expect(all_keys.uniq.size).to eq(100)
|
319
359
|
end
|
320
360
|
|
321
361
|
context "with extended options" do
|
322
362
|
it "uses ex option to set the expire time, in seconds" do
|
323
363
|
ttl = 7
|
324
364
|
|
325
|
-
@client.set("key1", "1", { :ex => ttl }).
|
326
|
-
@client.ttl("key1").
|
365
|
+
expect(@client.set("key1", "1", { :ex => ttl })).to eq("OK")
|
366
|
+
expect(@client.ttl("key1")).to eq(ttl)
|
327
367
|
end
|
328
368
|
|
329
369
|
it "uses px option to set the expire time, in miliseconds" do
|
330
370
|
ttl = 7000
|
331
371
|
|
332
|
-
@client.set("key1", "1", { :px => ttl }).
|
333
|
-
@client.ttl("key1").
|
372
|
+
expect(@client.set("key1", "1", { :px => ttl })).to eq("OK")
|
373
|
+
expect(@client.ttl("key1")).to eq(ttl / 1000)
|
334
374
|
end
|
335
375
|
|
336
376
|
# Note that the redis-rb implementation will always give PX last.
|
@@ -340,30 +380,132 @@ module FakeRedis
|
|
340
380
|
ttl_ex = 10
|
341
381
|
|
342
382
|
@client.set("key1", "1", { :px => ttl_px, :ex => ttl_ex })
|
343
|
-
@client.ttl("key1").
|
383
|
+
expect(@client.ttl("key1")).to eq(ttl_px / 1000)
|
344
384
|
|
345
385
|
@client.set("key1", "1", { :ex => ttl_ex, :px => ttl_px })
|
346
|
-
@client.ttl("key1").
|
386
|
+
expect(@client.ttl("key1")).to eq(ttl_px / 1000)
|
347
387
|
end
|
348
388
|
|
349
389
|
it "uses nx option to only set the key if it does not already exist" do
|
350
|
-
@client.set("key1", "1", { :nx => true }).
|
351
|
-
@client.set("key1", "2", { :nx => true }).
|
390
|
+
expect(@client.set("key1", "1", { :nx => true })).to eq(true)
|
391
|
+
expect(@client.set("key1", "2", { :nx => true })).to eq(false)
|
352
392
|
|
353
|
-
@client.get("key1").
|
393
|
+
expect(@client.get("key1")).to eq("1")
|
354
394
|
end
|
355
395
|
|
356
396
|
it "uses xx option to only set the key if it already exists" do
|
357
|
-
@client.set("key2", "1", { :xx => true }).
|
397
|
+
expect(@client.set("key2", "1", { :xx => true })).to eq(false)
|
358
398
|
@client.set("key2", "2")
|
359
|
-
@client.set("key2", "1", { :xx => true }).
|
399
|
+
expect(@client.set("key2", "1", { :xx => true })).to eq(true)
|
360
400
|
|
361
|
-
@client.get("key2").
|
401
|
+
expect(@client.get("key2")).to eq("1")
|
362
402
|
end
|
363
403
|
|
364
404
|
it "does not set the key if both xx and nx option are specified" do
|
365
|
-
@client.set("key2", "1", { :nx => true, :xx => true }).
|
366
|
-
@client.get("key2").
|
405
|
+
expect(@client.set("key2", "1", { :nx => true, :xx => true })).to eq(false)
|
406
|
+
expect(@client.get("key2")).to be_nil
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
describe "#dump" do
|
411
|
+
it "returns nil for unknown key" do
|
412
|
+
expect(@client.exists("key1")).to be false
|
413
|
+
expect(@client.dump("key1")).to be nil
|
414
|
+
end
|
415
|
+
|
416
|
+
it "dumps a single known key successfully" do
|
417
|
+
@client.set("key1", "zomgwtf")
|
418
|
+
|
419
|
+
value = @client.dump("key1")
|
420
|
+
expect(value).not_to eq nil
|
421
|
+
expect(value).to be_a_kind_of(String)
|
422
|
+
end
|
423
|
+
|
424
|
+
it "errors with more than one argument" do
|
425
|
+
expect { @client.dump("key1", "key2") }.to raise_error(ArgumentError)
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
describe "#restore" do
|
430
|
+
it "errors with a missing payload" do
|
431
|
+
expect do
|
432
|
+
@client.restore("key1", 0, nil)
|
433
|
+
end.to raise_error(Redis::CommandError, "ERR DUMP payload version or checksum are wrong")
|
434
|
+
end
|
435
|
+
|
436
|
+
it "errors with an invalid payload" do
|
437
|
+
expect do
|
438
|
+
@client.restore("key1", 0, "zomgwtf not valid")
|
439
|
+
end.to raise_error(Redis::CommandError, "ERR DUMP payload version or checksum are wrong")
|
440
|
+
end
|
441
|
+
|
442
|
+
describe "with a dumped value" do
|
443
|
+
before do
|
444
|
+
@client.set("key1", "original value")
|
445
|
+
@dumped_value = @client.dump("key1")
|
446
|
+
|
447
|
+
@client.del("key1")
|
448
|
+
expect(@client.exists("key1")).to be false
|
449
|
+
end
|
450
|
+
|
451
|
+
it "restores to a new key successfully" do
|
452
|
+
response = @client.restore("key1", 0, @dumped_value)
|
453
|
+
expect(response).to eq "OK"
|
454
|
+
end
|
455
|
+
|
456
|
+
it "errors trying to restore to an existing key" do
|
457
|
+
@client.set("key1", "something else")
|
458
|
+
|
459
|
+
expect do
|
460
|
+
@client.restore("key1", 0, @dumped_value)
|
461
|
+
end.to raise_error(Redis::CommandError, "ERR Target key name is busy.")
|
462
|
+
end
|
463
|
+
|
464
|
+
it "restores successfully with a given expire time" do
|
465
|
+
@client.restore("key2", 2000, @dumped_value)
|
466
|
+
|
467
|
+
expect(@client.ttl("key2")).to eq 2
|
468
|
+
end
|
469
|
+
|
470
|
+
it "restores a list successfully" do
|
471
|
+
@client.lpush("key1", "val1")
|
472
|
+
@client.lpush("key1", "val2")
|
473
|
+
|
474
|
+
expect(@client.type("key1")).to eq "list"
|
475
|
+
|
476
|
+
dumped_value = @client.dump("key1")
|
477
|
+
|
478
|
+
response = @client.restore("key2", 0, dumped_value)
|
479
|
+
expect(response).to eq "OK"
|
480
|
+
|
481
|
+
expect(@client.type("key2")).to eq "list"
|
482
|
+
end
|
483
|
+
|
484
|
+
it "restores a set successfully" do
|
485
|
+
@client.sadd("key1", "val1")
|
486
|
+
@client.sadd("key1", "val2")
|
487
|
+
|
488
|
+
expect(@client.type("key1")).to eq "set"
|
489
|
+
|
490
|
+
dumped_value = @client.dump("key1")
|
491
|
+
|
492
|
+
response = @client.restore("key2", 0, dumped_value)
|
493
|
+
expect(response).to eq "OK"
|
494
|
+
|
495
|
+
expect(@client.type("key2")).to eq "set"
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
describe "#psetex" do
|
501
|
+
it "should set a key's time to live in milliseconds" do
|
502
|
+
allow(Time).to receive(:now).and_return(1000)
|
503
|
+
@client.psetex("key", 2200, "value")
|
504
|
+
expect(@client.pttl("key")).to be_within(0.1).of(2200)
|
505
|
+
end
|
506
|
+
|
507
|
+
it "should return 'OK'" do
|
508
|
+
expect(@client.psetex("key", 1000, "value")).to eq("OK")
|
367
509
|
end
|
368
510
|
end
|
369
511
|
end
|