kuende-fakeredis 0.6.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 +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +19 -0
  4. data/Gemfile +13 -0
  5. data/Guardfile +8 -0
  6. data/LICENSE +21 -0
  7. data/README.md +102 -0
  8. data/Rakefile +27 -0
  9. data/fakeredis.gemspec +24 -0
  10. data/gemfiles/redisrb-master.gemfile +14 -0
  11. data/lib/fake_redis.rb +1 -0
  12. data/lib/fakeredis.rb +6 -0
  13. data/lib/fakeredis/bitop_command.rb +56 -0
  14. data/lib/fakeredis/command_executor.rb +25 -0
  15. data/lib/fakeredis/expiring_hash.rb +70 -0
  16. data/lib/fakeredis/minitest.rb +24 -0
  17. data/lib/fakeredis/rspec.rb +24 -0
  18. data/lib/fakeredis/sort_method.rb +117 -0
  19. data/lib/fakeredis/sorted_set_argument_handler.rb +74 -0
  20. data/lib/fakeredis/sorted_set_store.rb +80 -0
  21. data/lib/fakeredis/transaction_commands.rb +83 -0
  22. data/lib/fakeredis/version.rb +3 -0
  23. data/lib/fakeredis/zset.rb +39 -0
  24. data/lib/redis/connection/memory.rb +1375 -0
  25. data/spec/bitop_command_spec.rb +209 -0
  26. data/spec/compatibility_spec.rb +9 -0
  27. data/spec/connection_spec.rb +85 -0
  28. data/spec/hashes_spec.rb +261 -0
  29. data/spec/keys_spec.rb +488 -0
  30. data/spec/lists_spec.rb +229 -0
  31. data/spec/memory_spec.rb +28 -0
  32. data/spec/server_spec.rb +100 -0
  33. data/spec/sets_spec.rb +280 -0
  34. data/spec/sort_method_spec.rb +74 -0
  35. data/spec/sorted_sets_spec.rb +578 -0
  36. data/spec/spec_helper.rb +29 -0
  37. data/spec/spec_helper_live_redis.rb +14 -0
  38. data/spec/strings_spec.rb +289 -0
  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 +69 -0
  42. data/spec/transactions_spec.rb +92 -0
  43. data/spec/upcase_method_name_spec.rb +18 -0
  44. metadata +148 -0
@@ -0,0 +1,488 @@
1
+ require 'spec_helper'
2
+
3
+ module FakeRedis
4
+ describe "KeysMethods" do
5
+
6
+ before(:each) do
7
+ @client = Redis.new
8
+ end
9
+
10
+ it "should delete a key" do
11
+ @client.set("key1", "1")
12
+ @client.set("key2", "2")
13
+ @client.del("key1", "key2")
14
+
15
+ expect(@client.get("key1")).to eq(nil)
16
+ end
17
+
18
+ it "should delete multiple keys" do
19
+ @client.set("key1", "1")
20
+ @client.set("key2", "2")
21
+ @client.del(["key1", "key2"])
22
+
23
+ expect(@client.get("key1")).to eq(nil)
24
+ expect(@client.get("key2")).to eq(nil)
25
+ end
26
+
27
+ it "should error deleting no keys" do
28
+ expect { @client.del }.to raise_error(Redis::CommandError, "ERR wrong number of arguments for 'del' command")
29
+ expect { @client.del [] }.to raise_error(Redis::CommandError, "ERR wrong number of arguments for 'del' command")
30
+ end
31
+
32
+ it "should return true when setnx keys that don't exist" do
33
+ expect(@client.setnx("key1", "1")).to eq(true)
34
+ end
35
+
36
+ it "should return false when setnx keys exist" do
37
+ @client.set("key1", "1")
38
+ expect(@client.setnx("key1", "1")).to eq(false)
39
+ end
40
+
41
+ it "should return true when setting expires on keys that exist" do
42
+ @client.set("key1", "1")
43
+ expect(@client.expire("key1", 1)).to eq(true)
44
+ end
45
+
46
+ it "should return true when setting pexpires on keys that exist" do
47
+ @client.set("key1", "1")
48
+ expect(@client.pexpire("key1", 1)).to eq(true)
49
+ end
50
+
51
+ it "should return false when attempting to set expires on a key that does not exist" do
52
+ expect(@client.expire("key1", 1)).to eq(false)
53
+ end
54
+
55
+ it "should return false when attempting to set pexpires on a key that does not exist" do
56
+ expect(@client.pexpire("key1", 1)).to eq(false)
57
+ end
58
+
59
+ it "should determine if a key exists" do
60
+ @client.set("key1", "1")
61
+
62
+ expect(@client.exists("key1")).to eq(true)
63
+ expect(@client.exists("key2")).to eq(false)
64
+ end
65
+
66
+ it "should set a key's time to live in seconds" do
67
+ @client.set("key1", "1")
68
+ @client.expire("key1", 1)
69
+
70
+ expect(@client.ttl("key1")).to eq(1)
71
+ end
72
+
73
+ it "should set a key's time to live in miliseconds" do
74
+ allow(Time).to receive(:now).and_return(1000)
75
+ @client.set("key1", "1")
76
+ @client.pexpire("key1", 2200)
77
+ expect(@client.pttl("key1")).to be_within(0.1).of(2200)
78
+ allow(Time).to receive(:now).and_call_original
79
+ end
80
+
81
+ it "should set the expiration for a key as a UNIX timestamp" do
82
+ @client.set("key1", "1")
83
+ @client.expireat("key1", Time.now.to_i + 2)
84
+
85
+ expect(@client.ttl("key1")).to eq(2)
86
+ end
87
+
88
+ it "should not have an expiration after re-set" do
89
+ @client.set("key1", "1")
90
+ @client.expireat("key1", Time.now.to_i + 2)
91
+ @client.set("key1", "1")
92
+
93
+ expect(@client.ttl("key1")).to eq(-1)
94
+ end
95
+
96
+ it "should not have a ttl if expired (and thus key does not exist)" do
97
+ @client.set("key1", "1")
98
+ @client.expireat("key1", Time.now.to_i)
99
+
100
+ expect(@client.ttl("key1")).to eq(-2)
101
+ end
102
+
103
+ it "should not find a key if expired" do
104
+ @client.set("key1", "1")
105
+ @client.expireat("key1", Time.now.to_i)
106
+
107
+ expect(@client.get("key1")).to be_nil
108
+ end
109
+
110
+ it "should not find multiple keys if expired" do
111
+ @client.set("key1", "1")
112
+ @client.set("key2", "2")
113
+ @client.expireat("key1", Time.now.to_i)
114
+
115
+ expect(@client.mget("key1", "key2")).to eq([nil, "2"])
116
+ end
117
+
118
+ it "should only find keys that aren't expired" do
119
+ @client.set("key1", "1")
120
+ @client.set("key2", "2")
121
+ @client.expireat("key1", Time.now.to_i)
122
+
123
+ expect(@client.keys).to eq(["key2"])
124
+ end
125
+
126
+ it "should not exist if expired" do
127
+ @client.set("key1", "1")
128
+ @client.expireat("key1", Time.now.to_i)
129
+
130
+ expect(@client.exists("key1")).to be false
131
+ end
132
+
133
+ it "should find all keys matching the given pattern" do
134
+ @client.set("key:a", "1")
135
+ @client.set("key:b", "2")
136
+ @client.set("key:c", "3")
137
+ @client.set("akeyd", "4")
138
+ @client.set("key1", "5")
139
+
140
+ @client.mset("database", 1, "above", 2, "suitability", 3, "able", 4)
141
+
142
+ expect(@client.keys("key:*")).to match_array(["key:a", "key:b", "key:c"])
143
+ expect(@client.keys("ab*")).to match_array(["above", "able"])
144
+ end
145
+
146
+ it "should remove the expiration from a key" do
147
+ @client.set("key1", "1")
148
+ @client.expireat("key1", Time.now.to_i + 1)
149
+ expect(@client.persist("key1")).to eq(true)
150
+ expect(@client.persist("key1")).to eq(false)
151
+
152
+ expect(@client.ttl("key1")).to eq(-1)
153
+ end
154
+
155
+ it "should return a random key from the keyspace" do
156
+ @client.set("key1", "1")
157
+ @client.set("key2", "2")
158
+
159
+ expect(["key1", "key2"].include?(@client.randomkey)).to eq(true)
160
+ end
161
+
162
+ it "should rename a key" do
163
+ @client.set("key1", "2")
164
+ @client.rename("key1", "key2")
165
+
166
+ expect(@client.get("key1")).to eq(nil)
167
+ expect(@client.get("key2")).to eq("2")
168
+ end
169
+
170
+ it "should rename a key, only if new key does not exist" do
171
+ @client.set("key1", "1")
172
+ @client.set("key2", "2")
173
+ @client.set("key3", "3")
174
+ @client.renamenx("key1", "key2")
175
+ @client.renamenx("key3", "key4")
176
+
177
+ expect(@client.get("key1")).to eq("1")
178
+ expect(@client.get("key2")).to eq("2")
179
+ expect(@client.get("key3")).to eq(nil)
180
+ expect(@client.get("key4")).to eq("3")
181
+ end
182
+
183
+ it "should determine the type stored at key" do
184
+ # Non-existing key
185
+ expect(@client.type("key0")).to eq("none")
186
+
187
+ # String
188
+ @client.set("key1", "1")
189
+ expect(@client.type("key1")).to eq("string")
190
+
191
+ # List
192
+ @client.lpush("key2", "1")
193
+ expect(@client.type("key2")).to eq("list")
194
+
195
+ # Set
196
+ @client.sadd("key3", "1")
197
+ expect(@client.type("key3")).to eq("set")
198
+
199
+ # Sorted Set
200
+ @client.zadd("key4", 1.0, "1")
201
+ expect(@client.type("key4")).to eq("zset")
202
+
203
+ # Hash
204
+ @client.hset("key5", "a", "1")
205
+ expect(@client.type("key5")).to eq("hash")
206
+ end
207
+
208
+ it "should convert the value into a string before storing" do
209
+ @client.set("key1", 1)
210
+ expect(@client.get("key1")).to eq("1")
211
+
212
+ @client.setex("key2", 30, 1)
213
+ expect(@client.get("key2")).to eq("1")
214
+
215
+ @client.getset("key3", 1)
216
+ expect(@client.get("key3")).to eq("1")
217
+ end
218
+
219
+ it "should return 'OK' for the setex command" do
220
+ expect(@client.setex("key4", 30, 1)).to eq("OK")
221
+ end
222
+
223
+ it "should convert the key into a string before storing" do
224
+ @client.set(123, "foo")
225
+ expect(@client.keys).to include("123")
226
+ expect(@client.get("123")).to eq("foo")
227
+
228
+ @client.setex(456, 30, "foo")
229
+ expect(@client.keys).to include("456")
230
+ expect(@client.get("456")).to eq("foo")
231
+
232
+ @client.getset(789, "foo")
233
+ expect(@client.keys).to include("789")
234
+ expect(@client.get("789")).to eq("foo")
235
+ end
236
+
237
+ it "should only operate against keys containing string values" do
238
+ @client.sadd("key1", "one")
239
+ expect { @client.get("key1") }.to raise_error(Redis::CommandError, "WRONGTYPE Operation against a key holding the wrong kind of value")
240
+ expect { @client.getset("key1", 1) }.to raise_error(Redis::CommandError, "WRONGTYPE Operation against a key holding the wrong kind of value")
241
+
242
+ @client.hset("key2", "one", "two")
243
+ expect { @client.get("key2") }.to raise_error(Redis::CommandError, "WRONGTYPE Operation against a key holding the wrong kind of value")
244
+ expect { @client.getset("key2", 1) }.to raise_error(Redis::CommandError, "WRONGTYPE Operation against a key holding the wrong kind of value")
245
+ end
246
+
247
+ it "should move a key from one database to another successfully" do
248
+ @client.select(0)
249
+ @client.set("key1", "1")
250
+
251
+ expect(@client.move("key1", 1)).to eq(true)
252
+
253
+ @client.select(0)
254
+ expect(@client.get("key1")).to be_nil
255
+
256
+ @client.select(1)
257
+ expect(@client.get("key1")).to eq("1")
258
+ end
259
+
260
+ it "should fail to move a key that does not exist in the source database" do
261
+ @client.select(0)
262
+ expect(@client.get("key1")).to be_nil
263
+
264
+ expect(@client.move("key1", 1)).to eq(false)
265
+
266
+ @client.select(0)
267
+ expect(@client.get("key1")).to be_nil
268
+
269
+ @client.select(1)
270
+ expect(@client.get("key1")).to be_nil
271
+ end
272
+
273
+ it "should fail to move a key that exists in the destination database" do
274
+ @client.select(0)
275
+ @client.set("key1", "1")
276
+
277
+ @client.select(1)
278
+ @client.set("key1", "2")
279
+
280
+ @client.select(0)
281
+ expect(@client.move("key1", 1)).to eq(false)
282
+
283
+ @client.select(0)
284
+ expect(@client.get("key1")).to eq("1")
285
+
286
+ @client.select(1)
287
+ expect(@client.get("key1")).to eq("2")
288
+ end
289
+
290
+ it "should fail to move a key to the same database" do
291
+ @client.select(0)
292
+ @client.set("key1", "1")
293
+
294
+ expect { @client.move("key1", 0) }.to raise_error(Redis::CommandError, "ERR source and destination objects are the same")
295
+
296
+ @client.select(0)
297
+ expect(@client.get("key1")).to eq("1")
298
+ end
299
+
300
+ it "should scan all keys in the database" do
301
+ 100.times do |x|
302
+ @client.set("key#{x}", "#{x}")
303
+ end
304
+
305
+ cursor = 0
306
+ all_keys = []
307
+ loop {
308
+ cursor, keys = @client.scan(cursor)
309
+ all_keys += keys
310
+ break if cursor == "0"
311
+ }
312
+
313
+ expect(all_keys.uniq.size).to eq(100)
314
+ expect(all_keys[0]).to match(/key\d+/)
315
+ end
316
+
317
+ it "should match keys to a pattern when scanning" do
318
+ 50.times do |x|
319
+ @client.set("key#{x}", "#{x}")
320
+ end
321
+
322
+ @client.set("miss_me", 1)
323
+ @client.set("pass_me", 2)
324
+
325
+ cursor = 0
326
+ all_keys = []
327
+ loop {
328
+ cursor, keys = @client.scan(cursor, :match => "key*")
329
+ all_keys += keys
330
+ break if cursor == "0"
331
+ }
332
+
333
+ expect(all_keys.uniq.size).to eq(50)
334
+ end
335
+
336
+ it "should specify doing more work when scanning" do
337
+ 100.times do |x|
338
+ @client.set("key#{x}", "#{x}")
339
+ end
340
+
341
+ cursor, all_keys = @client.scan(cursor, :count => 100)
342
+
343
+ expect(cursor).to eq("0")
344
+ expect(all_keys.uniq.size).to eq(100)
345
+ end
346
+
347
+ context "with extended options" do
348
+ it "uses ex option to set the expire time, in seconds" do
349
+ ttl = 7
350
+
351
+ expect(@client.set("key1", "1", { :ex => ttl })).to eq("OK")
352
+ expect(@client.ttl("key1")).to eq(ttl)
353
+ end
354
+
355
+ it "uses px option to set the expire time, in miliseconds" do
356
+ ttl = 7000
357
+
358
+ expect(@client.set("key1", "1", { :px => ttl })).to eq("OK")
359
+ expect(@client.ttl("key1")).to eq(ttl / 1000)
360
+ end
361
+
362
+ # Note that the redis-rb implementation will always give PX last.
363
+ # Redis seems to process each expiration option and the last one wins.
364
+ it "prefers the finer-grained PX expiration option over EX" do
365
+ ttl_px = 6000
366
+ ttl_ex = 10
367
+
368
+ @client.set("key1", "1", { :px => ttl_px, :ex => ttl_ex })
369
+ expect(@client.ttl("key1")).to eq(ttl_px / 1000)
370
+
371
+ @client.set("key1", "1", { :ex => ttl_ex, :px => ttl_px })
372
+ expect(@client.ttl("key1")).to eq(ttl_px / 1000)
373
+ end
374
+
375
+ it "uses nx option to only set the key if it does not already exist" do
376
+ expect(@client.set("key1", "1", { :nx => true })).to eq(true)
377
+ expect(@client.set("key1", "2", { :nx => true })).to eq(false)
378
+
379
+ expect(@client.get("key1")).to eq("1")
380
+ end
381
+
382
+ it "uses xx option to only set the key if it already exists" do
383
+ expect(@client.set("key2", "1", { :xx => true })).to eq(false)
384
+ @client.set("key2", "2")
385
+ expect(@client.set("key2", "1", { :xx => true })).to eq(true)
386
+
387
+ expect(@client.get("key2")).to eq("1")
388
+ end
389
+
390
+ it "does not set the key if both xx and nx option are specified" do
391
+ expect(@client.set("key2", "1", { :nx => true, :xx => true })).to eq(false)
392
+ expect(@client.get("key2")).to be_nil
393
+ end
394
+ end
395
+
396
+ describe "#dump" do
397
+ it "returns nil for unknown key" do
398
+ expect(@client.exists("key1")).to be false
399
+ expect(@client.dump("key1")).to be nil
400
+ end
401
+
402
+ it "dumps a single known key successfully" do
403
+ @client.set("key1", "zomgwtf")
404
+
405
+ value = @client.dump("key1")
406
+ expect(value).not_to eq nil
407
+ expect(value).to be_a_kind_of(String)
408
+ end
409
+
410
+ it "errors with more than one argument" do
411
+ expect { @client.dump("key1", "key2") }.to raise_error(ArgumentError)
412
+ end
413
+ end
414
+
415
+ describe "#restore" do
416
+ it "errors with a missing payload" do
417
+ expect do
418
+ @client.restore("key1", 0, nil)
419
+ end.to raise_error(Redis::CommandError, "ERR DUMP payload version or checksum are wrong")
420
+ end
421
+
422
+ it "errors with an invalid payload" do
423
+ expect do
424
+ @client.restore("key1", 0, "zomgwtf not valid")
425
+ end.to raise_error(Redis::CommandError, "ERR DUMP payload version or checksum are wrong")
426
+ end
427
+
428
+ describe "with a dumped value" do
429
+ before do
430
+ @client.set("key1", "original value")
431
+ @dumped_value = @client.dump("key1")
432
+
433
+ @client.del("key1")
434
+ expect(@client.exists("key1")).to be false
435
+ end
436
+
437
+ it "restores to a new key successfully" do
438
+ response = @client.restore("key1", 0, @dumped_value)
439
+ expect(response).to eq "OK"
440
+ end
441
+
442
+ it "errors trying to restore to an existing key" do
443
+ @client.set("key1", "something else")
444
+
445
+ expect do
446
+ @client.restore("key1", 0, @dumped_value)
447
+ end.to raise_error(Redis::CommandError, "ERR Target key name is busy.")
448
+ end
449
+
450
+ it "restores successfully with a given expire time" do
451
+ @client.restore("key2", 2000, @dumped_value)
452
+
453
+ expect(@client.ttl("key2")).to eq 2
454
+ end
455
+
456
+ it "restores a list successfully" do
457
+ @client.lpush("key1", "val1")
458
+ @client.lpush("key1", "val2")
459
+
460
+ expect(@client.type("key1")).to eq "list"
461
+
462
+ dumped_value = @client.dump("key1")
463
+
464
+ response = @client.restore("key2", 0, dumped_value)
465
+ expect(response).to eq "OK"
466
+
467
+ expect(@client.type("key2")).to eq "list"
468
+ end
469
+
470
+ it "restores a set successfully" do
471
+ @client.sadd("key1", "val1")
472
+ @client.sadd("key1", "val2")
473
+
474
+ expect(@client.type("key1")).to eq "set"
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 "set"
482
+ end
483
+ end
484
+ end
485
+
486
+ end
487
+ end
488
+