mock_redis 0.32.0 → 0.44.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +59 -0
- data/README.md +4 -4
- data/lib/mock_redis/database.rb +42 -13
- data/lib/mock_redis/geospatial_methods.rb +2 -2
- data/lib/mock_redis/hash_methods.rb +1 -1
- data/lib/mock_redis/list_methods.rb +37 -2
- data/lib/mock_redis/memory_method.rb +11 -0
- data/lib/mock_redis/multi_db_wrapper.rb +1 -1
- data/lib/mock_redis/pipelined_wrapper.rb +12 -14
- data/lib/mock_redis/set_methods.rb +18 -2
- data/lib/mock_redis/stream.rb +3 -3
- data/lib/mock_redis/string_methods.rb +33 -6
- data/lib/mock_redis/transaction_wrapper.rb +5 -7
- data/lib/mock_redis/utility_methods.rb +4 -2
- data/lib/mock_redis/version.rb +1 -1
- data/lib/mock_redis/zset.rb +4 -2
- data/lib/mock_redis/zset_methods.rb +13 -4
- data/lib/mock_redis.rb +5 -6
- metadata +20 -352
- data/.github/workflows/lint.yml +0 -31
- data/.github/workflows/tests.yml +0 -63
- data/.gitignore +0 -5
- data/.mailmap +0 -2
- data/.overcommit.yml +0 -21
- data/.rspec +0 -1
- data/.rubocop.yml +0 -148
- data/.rubocop_todo.yml +0 -35
- data/.simplecov +0 -4
- data/Gemfile +0 -13
- data/Rakefile +0 -2
- data/mock_redis.gemspec +0 -32
- data/spec/client_spec.rb +0 -29
- data/spec/cloning_spec.rb +0 -95
- data/spec/commands/append_spec.rb +0 -24
- data/spec/commands/auth_spec.rb +0 -7
- data/spec/commands/bgrewriteaof_spec.rb +0 -7
- data/spec/commands/bgsave_spec.rb +0 -7
- data/spec/commands/bitcount_spec.rb +0 -25
- data/spec/commands/bitfield_spec.rb +0 -169
- data/spec/commands/blpop_spec.rb +0 -53
- data/spec/commands/brpop_spec.rb +0 -59
- data/spec/commands/brpoplpush_spec.rb +0 -52
- data/spec/commands/connected_spec.rb +0 -7
- data/spec/commands/connection_spec.rb +0 -15
- data/spec/commands/dbsize_spec.rb +0 -18
- data/spec/commands/decr_spec.rb +0 -34
- data/spec/commands/decrby_spec.rb +0 -34
- data/spec/commands/del_spec.rb +0 -52
- data/spec/commands/disconnect_spec.rb +0 -7
- data/spec/commands/dump_spec.rb +0 -19
- data/spec/commands/echo_spec.rb +0 -11
- data/spec/commands/eval_spec.rb +0 -7
- data/spec/commands/evalsha_spec.rb +0 -10
- data/spec/commands/exists_spec.rb +0 -43
- data/spec/commands/expire_spec.rb +0 -111
- data/spec/commands/expireat_spec.rb +0 -47
- data/spec/commands/flushall_spec.rb +0 -38
- data/spec/commands/flushdb_spec.rb +0 -38
- data/spec/commands/future_spec.rb +0 -30
- data/spec/commands/geoadd_spec.rb +0 -58
- data/spec/commands/geodist_spec.rb +0 -118
- data/spec/commands/geohash_spec.rb +0 -52
- data/spec/commands/geopos_spec.rb +0 -55
- data/spec/commands/get_spec.rb +0 -31
- data/spec/commands/getbit_spec.rb +0 -34
- data/spec/commands/getrange_spec.rb +0 -22
- data/spec/commands/getset_spec.rb +0 -23
- data/spec/commands/hdel_spec.rb +0 -77
- data/spec/commands/hexists_spec.rb +0 -27
- data/spec/commands/hget_spec.rb +0 -28
- data/spec/commands/hgetall_spec.rb +0 -32
- data/spec/commands/hincrby_spec.rb +0 -58
- data/spec/commands/hincrbyfloat_spec.rb +0 -58
- data/spec/commands/hkeys_spec.rb +0 -19
- data/spec/commands/hlen_spec.rb +0 -19
- data/spec/commands/hmget_spec.rb +0 -46
- data/spec/commands/hmset_spec.rb +0 -69
- data/spec/commands/hscan_each_spec.rb +0 -48
- data/spec/commands/hscan_spec.rb +0 -27
- data/spec/commands/hset_spec.rb +0 -42
- data/spec/commands/hsetnx_spec.rb +0 -44
- data/spec/commands/hvals_spec.rb +0 -19
- data/spec/commands/incr_spec.rb +0 -34
- data/spec/commands/incrby_spec.rb +0 -44
- data/spec/commands/incrbyfloat_spec.rb +0 -44
- data/spec/commands/info_spec.rb +0 -62
- data/spec/commands/keys_spec.rb +0 -139
- data/spec/commands/lastsave_spec.rb +0 -8
- data/spec/commands/lindex_spec.rb +0 -49
- data/spec/commands/linsert_spec.rb +0 -68
- data/spec/commands/llen_spec.rb +0 -16
- data/spec/commands/lpop_spec.rb +0 -34
- data/spec/commands/lpush_spec.rb +0 -43
- data/spec/commands/lpushx_spec.rb +0 -46
- data/spec/commands/lrange_spec.rb +0 -51
- data/spec/commands/lrem_spec.rb +0 -80
- data/spec/commands/lset_spec.rb +0 -43
- data/spec/commands/ltrim_spec.rb +0 -45
- data/spec/commands/mapped_hmget_spec.rb +0 -29
- data/spec/commands/mapped_hmset_spec.rb +0 -47
- data/spec/commands/mapped_mget_spec.rb +0 -22
- data/spec/commands/mapped_mset_spec.rb +0 -19
- data/spec/commands/mapped_msetnx_spec.rb +0 -26
- data/spec/commands/mget_spec.rb +0 -65
- data/spec/commands/move_spec.rb +0 -147
- data/spec/commands/mset_spec.rb +0 -43
- data/spec/commands/msetnx_spec.rb +0 -40
- data/spec/commands/persist_spec.rb +0 -48
- data/spec/commands/pexpire_spec.rb +0 -86
- data/spec/commands/pexpireat_spec.rb +0 -48
- data/spec/commands/ping_spec.rb +0 -11
- data/spec/commands/pipelined_spec.rb +0 -114
- data/spec/commands/psetex_spec.rb +0 -44
- data/spec/commands/pttl_spec.rb +0 -41
- data/spec/commands/quit_spec.rb +0 -7
- data/spec/commands/randomkey_spec.rb +0 -20
- data/spec/commands/rename_spec.rb +0 -42
- data/spec/commands/renamenx_spec.rb +0 -41
- data/spec/commands/restore_spec.rb +0 -47
- data/spec/commands/rpop_spec.rb +0 -34
- data/spec/commands/rpoplpush_spec.rb +0 -50
- data/spec/commands/rpush_spec.rb +0 -43
- data/spec/commands/rpushx_spec.rb +0 -46
- data/spec/commands/sadd_spec.rb +0 -45
- data/spec/commands/save_spec.rb +0 -7
- data/spec/commands/scan_each_spec.rb +0 -39
- data/spec/commands/scan_spec.rb +0 -64
- data/spec/commands/scard_spec.rb +0 -18
- data/spec/commands/script_spec.rb +0 -9
- data/spec/commands/sdiff_spec.rb +0 -47
- data/spec/commands/sdiffstore_spec.rb +0 -58
- data/spec/commands/select_spec.rb +0 -61
- data/spec/commands/set_spec.rb +0 -119
- data/spec/commands/setbit_spec.rb +0 -55
- data/spec/commands/setex_spec.rb +0 -38
- data/spec/commands/setnx_spec.rb +0 -25
- data/spec/commands/setrange_spec.rb +0 -30
- data/spec/commands/sinter_spec.rb +0 -39
- data/spec/commands/sinterstore_spec.rb +0 -53
- data/spec/commands/sismember_spec.rb +0 -29
- data/spec/commands/smembers_spec.rb +0 -28
- data/spec/commands/smove_spec.rb +0 -41
- data/spec/commands/sort_list_spec.rb +0 -21
- data/spec/commands/sort_set_spec.rb +0 -21
- data/spec/commands/sort_zset_spec.rb +0 -21
- data/spec/commands/spop_spec.rb +0 -40
- data/spec/commands/srandmember_spec.rb +0 -49
- data/spec/commands/srem_spec.rb +0 -45
- data/spec/commands/sscan_each_spec.rb +0 -48
- data/spec/commands/sscan_spec.rb +0 -39
- data/spec/commands/strlen_spec.rb +0 -18
- data/spec/commands/sunion_spec.rb +0 -42
- data/spec/commands/sunionstore_spec.rb +0 -59
- data/spec/commands/ttl_spec.rb +0 -40
- data/spec/commands/type_spec.rb +0 -36
- data/spec/commands/unwatch_spec.rb +0 -7
- data/spec/commands/watch_spec.rb +0 -21
- data/spec/commands/xadd_spec.rb +0 -122
- data/spec/commands/xlen_spec.rb +0 -22
- data/spec/commands/xrange_spec.rb +0 -164
- data/spec/commands/xread_spec.rb +0 -66
- data/spec/commands/xrevrange_spec.rb +0 -130
- data/spec/commands/xtrim_spec.rb +0 -36
- data/spec/commands/zadd_spec.rb +0 -129
- data/spec/commands/zcard_spec.rb +0 -19
- data/spec/commands/zcount_spec.rb +0 -39
- data/spec/commands/zincrby_spec.rb +0 -31
- data/spec/commands/zinterstore_spec.rb +0 -130
- data/spec/commands/zpopmax_spec.rb +0 -60
- data/spec/commands/zpopmin_spec.rb +0 -60
- data/spec/commands/zrange_spec.rb +0 -80
- data/spec/commands/zrangebyscore_spec.rb +0 -83
- data/spec/commands/zrank_spec.rb +0 -29
- data/spec/commands/zrem_spec.rb +0 -43
- data/spec/commands/zremrangebyrank_spec.rb +0 -27
- data/spec/commands/zremrangebyscore_spec.rb +0 -35
- data/spec/commands/zrevrange_spec.rb +0 -56
- data/spec/commands/zrevrangebyscore_spec.rb +0 -58
- data/spec/commands/zrevrank_spec.rb +0 -29
- data/spec/commands/zscan_each_spec.rb +0 -48
- data/spec/commands/zscan_spec.rb +0 -26
- data/spec/commands/zscore_spec.rb +0 -22
- data/spec/commands/zunionstore_spec.rb +0 -137
- data/spec/mock_redis_spec.rb +0 -93
- data/spec/spec_helper.rb +0 -71
- data/spec/support/redis_multiplexer.rb +0 -123
- data/spec/support/shared_examples/does_not_cleanup_empty_strings.rb +0 -14
- data/spec/support/shared_examples/only_operates_on_hashes.rb +0 -15
- data/spec/support/shared_examples/only_operates_on_lists.rb +0 -15
- data/spec/support/shared_examples/only_operates_on_sets.rb +0 -15
- data/spec/support/shared_examples/only_operates_on_strings.rb +0 -13
- data/spec/support/shared_examples/only_operates_on_zsets.rb +0 -59
- data/spec/support/shared_examples/sorts_enumerables.rb +0 -56
- data/spec/transactions_spec.rb +0 -163
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e495091d84ea1fec4bf5206d2a02e32c446ef0bd89b0feaed38f31d95b142b2
|
4
|
+
data.tar.gz: 696f65058fe29cd5fa849363b6cfa60454a432c0d392f530ac1494cba31ff062
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78b558108b350dc35df4d1f202e96326096394f9e23d89398d07cdbb33c6b088e0089467b14624a9e2c73210406457e291ab0cb09495a8d12a854df5ab8da1c3
|
7
|
+
data.tar.gz: f7e6d3021a4f2f5dd78e53d126ecea26fa7d3f8903bbcf96b0cf2a03b74049acbb169a18ff571c2aab18a0678cf57b90908d06b8c0e10039e00fce5b6050ad26
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,64 @@
|
|
1
1
|
# MockRedis Changelog
|
2
2
|
|
3
|
+
### 0.44.0
|
4
|
+
|
5
|
+
* Add suppore for `memory usage` command
|
6
|
+
|
7
|
+
### 0.43.0
|
8
|
+
|
9
|
+
* Fix issue when using with `redis-store` gem
|
10
|
+
|
11
|
+
### 0.42.0
|
12
|
+
|
13
|
+
* Drop support for Ruby 2.x
|
14
|
+
* Add support for `srem?`
|
15
|
+
|
16
|
+
### 0.41.0
|
17
|
+
|
18
|
+
* Add support for `expire`-related command options `nx`/`xx`/`lt`/`gt`
|
19
|
+
|
20
|
+
### 0.40.0
|
21
|
+
|
22
|
+
* Add support for `call` method name to be case insensitive
|
23
|
+
* Add support for `zmscore`
|
24
|
+
|
25
|
+
### 0.39.0
|
26
|
+
|
27
|
+
* Add support for calling `call` in `pipelined` block
|
28
|
+
* Fix `sadd` to stringify array
|
29
|
+
|
30
|
+
### 0.38.0
|
31
|
+
|
32
|
+
* Fix detection of stream key types
|
33
|
+
* Add support for `EXAT` AND `PXAT` arguments to `SET` command
|
34
|
+
|
35
|
+
### 0.37.0
|
36
|
+
|
37
|
+
* Require Ruby 2.7 or newer, since Ruby 2.6 and older are EOL
|
38
|
+
* Remove unnecessary files from gem contents
|
39
|
+
* Add support for popping multiple items with `lpop`
|
40
|
+
* Add support for `scan` with type option
|
41
|
+
* Add support for `sadd?`
|
42
|
+
* Add support for scanning on keys containing hash tags (`{...}`)
|
43
|
+
|
44
|
+
### 0.36.0
|
45
|
+
|
46
|
+
* Add support for `smismember`
|
47
|
+
* Add support for `lmove` and `blmove`
|
48
|
+
* Fix `zrem` to support passing array of integers
|
49
|
+
|
50
|
+
### 0.35.0
|
51
|
+
|
52
|
+
* Add support for `getdel`
|
53
|
+
|
54
|
+
### 0.34.0
|
55
|
+
|
56
|
+
* Add support for `with`
|
57
|
+
|
58
|
+
### 0.33.0
|
59
|
+
|
60
|
+
* Add support for `GET` argument to `SET` command
|
61
|
+
|
3
62
|
### 0.32.0
|
4
63
|
|
5
64
|
* Add support for `psetex`
|
data/README.md
CHANGED
@@ -10,7 +10,7 @@ for use in tests.
|
|
10
10
|
|
11
11
|
## Requirements
|
12
12
|
|
13
|
-
Ruby
|
13
|
+
Ruby 3.0+
|
14
14
|
|
15
15
|
The current implementation is tested against Redis 6.2. Older versions may work, but can also return different results or not support some commands.
|
16
16
|
|
@@ -55,8 +55,8 @@ since it's an in-memory object confined to a single process. MockRedis
|
|
55
55
|
makes every attempt to be Redis-compatible, but there are some
|
56
56
|
necessary exceptions.
|
57
57
|
|
58
|
-
* Blocking list commands (`#blpop`, `#brpop`, and `#brpoplpush`)
|
59
|
-
as expected if there is data for them to retrieve. If you use one of
|
58
|
+
* Blocking list commands (`#blmove`, `#blpop`, `#brpop`, and `#brpoplpush`)
|
59
|
+
work as expected if there is data for them to retrieve. If you use one of
|
60
60
|
these commands with a nonzero timeout and there is no data for it to
|
61
61
|
retrieve, then the command returns immediately. However, if you ask
|
62
62
|
one of these commands for data with a 0 timeout (means "wait
|
@@ -105,7 +105,7 @@ We recommend running Redis within a Docker container to make development as simp
|
|
105
105
|
|
106
106
|
1. Start Redis.
|
107
107
|
```bash
|
108
|
-
docker run --rm -p 6379:6379 redis
|
108
|
+
docker run --rm -p 6379:6379 redis:6.2-alpine
|
109
109
|
```
|
110
110
|
2. Install dependencies.
|
111
111
|
```bash
|
data/lib/mock_redis/database.rb
CHANGED
@@ -12,6 +12,7 @@ require 'mock_redis/utility_methods'
|
|
12
12
|
require 'mock_redis/geospatial_methods'
|
13
13
|
require 'mock_redis/stream_methods'
|
14
14
|
require 'mock_redis/connection_method'
|
15
|
+
require 'mock_redis/memory_method'
|
15
16
|
|
16
17
|
class MockRedis
|
17
18
|
class Database
|
@@ -26,6 +27,7 @@ class MockRedis
|
|
26
27
|
include GeospatialMethods
|
27
28
|
include StreamMethods
|
28
29
|
include ConnectionMethod
|
30
|
+
include MemoryMethod
|
29
31
|
|
30
32
|
attr_reader :data, :expire_times
|
31
33
|
|
@@ -43,6 +45,13 @@ class MockRedis
|
|
43
45
|
|
44
46
|
# Redis commands go below this line and above 'private'
|
45
47
|
|
48
|
+
# FIXME: Current implementation of `call` does not work propetly with kwarg-options.
|
49
|
+
# i.e. `call("EXPIRE", "foo", 40, "NX")` (which redis-rb will simply transmit to redis-server)
|
50
|
+
# will be passed to `#expire` without keywords transformation.
|
51
|
+
def call(command, &_block)
|
52
|
+
public_send(command[0].downcase, *command[1..])
|
53
|
+
end
|
54
|
+
|
46
55
|
def auth(_)
|
47
56
|
'OK'
|
48
57
|
end
|
@@ -71,7 +80,7 @@ class MockRedis
|
|
71
80
|
|
72
81
|
def del(*keys)
|
73
82
|
keys = keys.flatten.map(&:to_s)
|
74
|
-
assert_has_args(keys, 'del')
|
83
|
+
# assert_has_args(keys, 'del') # no longer errors in redis > v4.5
|
75
84
|
|
76
85
|
keys.
|
77
86
|
find_all { |key| data[key] }.
|
@@ -85,32 +94,42 @@ class MockRedis
|
|
85
94
|
msg.to_s
|
86
95
|
end
|
87
96
|
|
88
|
-
def expire(key, seconds)
|
97
|
+
def expire(key, seconds, nx: nil, xx: nil, lt: nil, gt: nil) # rubocop:disable Metrics/ParameterLists
|
89
98
|
assert_valid_integer(seconds)
|
90
99
|
|
91
|
-
pexpire(key, seconds.to_i * 1000)
|
100
|
+
pexpire(key, seconds.to_i * 1000, nx: nx, xx: xx, lt: lt, gt: gt)
|
92
101
|
end
|
93
102
|
|
94
|
-
def pexpire(key, ms)
|
103
|
+
def pexpire(key, ms, nx: nil, xx: nil, lt: nil, gt: nil) # rubocop:disable Metrics/ParameterLists
|
95
104
|
assert_valid_integer(ms)
|
96
105
|
|
97
106
|
now, miliseconds = @base.now
|
98
107
|
now_ms = (now * 1000) + miliseconds
|
99
|
-
pexpireat(key, now_ms + ms.to_i)
|
108
|
+
pexpireat(key, now_ms + ms.to_i, nx: nx, xx: xx, lt: lt, gt: gt)
|
100
109
|
end
|
101
110
|
|
102
|
-
def expireat(key, timestamp)
|
111
|
+
def expireat(key, timestamp, nx: nil, xx: nil, lt: nil, gt: nil) # rubocop:disable Metrics/ParameterLists
|
103
112
|
assert_valid_integer(timestamp)
|
104
113
|
|
105
|
-
pexpireat(key, timestamp.to_i * 1000)
|
114
|
+
pexpireat(key, timestamp.to_i * 1000, nx: nx, xx: xx, lt: lt, gt: gt)
|
106
115
|
end
|
107
116
|
|
108
|
-
def pexpireat(key, timestamp_ms)
|
117
|
+
def pexpireat(key, timestamp_ms, nx: nil, xx: nil, lt: nil, gt: nil) # rubocop:disable Metrics/ParameterLists
|
109
118
|
assert_valid_integer(timestamp_ms)
|
110
119
|
|
111
|
-
if
|
112
|
-
|
113
|
-
|
120
|
+
if nx && gt || gt && lt || lt && nx || nx && xx
|
121
|
+
raise Redis::CommandError, <<~TXT.chomp
|
122
|
+
ERR NX and XX, GT or LT options at the same time are not compatible
|
123
|
+
TXT
|
124
|
+
end
|
125
|
+
|
126
|
+
return false unless exists?(key)
|
127
|
+
|
128
|
+
expiry = expiration(key)
|
129
|
+
new_expiry = @base.time_at(Rational(timestamp_ms.to_i, 1000))
|
130
|
+
|
131
|
+
if should_update_expiration?(expiry, new_expiry, nx: nx, xx: xx, lt: lt, gt: gt)
|
132
|
+
set_expiration(key, new_expiry)
|
114
133
|
true
|
115
134
|
else
|
116
135
|
false
|
@@ -267,6 +286,8 @@ class MockRedis
|
|
267
286
|
'set'
|
268
287
|
elsif zsety?(key)
|
269
288
|
'zset'
|
289
|
+
elsif streamy?(key)
|
290
|
+
'stream'
|
270
291
|
else
|
271
292
|
raise ArgumentError, "Not sure how #{data[key].inspect} got in here"
|
272
293
|
end
|
@@ -318,7 +339,7 @@ class MockRedis
|
|
318
339
|
end
|
319
340
|
|
320
341
|
def expiration(key)
|
321
|
-
expire_times.find { |(_, k)| k == key.to_s }
|
342
|
+
expire_times.find { |(_, k)| k == key.to_s }&.first
|
322
343
|
end
|
323
344
|
|
324
345
|
def has_expiration?(key)
|
@@ -333,10 +354,18 @@ class MockRedis
|
|
333
354
|
!!Float(str) rescue false
|
334
355
|
end
|
335
356
|
|
357
|
+
def should_update_expiration?(expiry, new_expiry, nx:, xx:, lt:, gt:) # rubocop:disable Metrics/ParameterLists
|
358
|
+
return false if nx && expiry || xx && !expiry
|
359
|
+
return false if lt && expiry && new_expiry > expiry
|
360
|
+
return false if gt && (!expiry || new_expiry < expiry)
|
361
|
+
|
362
|
+
true
|
363
|
+
end
|
364
|
+
|
336
365
|
def redis_pattern_to_ruby_regex(pattern)
|
337
366
|
Regexp.new(
|
338
367
|
"^#{pattern}$".
|
339
|
-
gsub(/([+|()])/, '\\\\\1').
|
368
|
+
gsub(/([+|(){}])/, '\\\\\1').
|
340
369
|
gsub(/(?<!\\)\?/, '\\1.').
|
341
370
|
gsub(/([^\\])\*/, '\\1.*')
|
342
371
|
)
|
@@ -6,6 +6,20 @@ class MockRedis
|
|
6
6
|
include Assertions
|
7
7
|
include UtilityMethods
|
8
8
|
|
9
|
+
def blmove(source, destination, wherefrom, whereto, options = {})
|
10
|
+
options = { :timeout => options } if options.is_a?(Integer)
|
11
|
+
timeout = options.is_a?(Hash) && options[:timeout] || 0
|
12
|
+
assert_valid_timeout(timeout)
|
13
|
+
|
14
|
+
if llen(source) > 0
|
15
|
+
lmove(source, destination, wherefrom, whereto)
|
16
|
+
elsif timeout > 0
|
17
|
+
nil
|
18
|
+
else
|
19
|
+
raise MockRedis::WouldBlock, "Can't block forever"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
9
23
|
def blpop(*args)
|
10
24
|
lists, timeout = extract_timeout(args)
|
11
25
|
nonempty_list = first_nonempty_list(lists)
|
@@ -78,8 +92,29 @@ class MockRedis
|
|
78
92
|
with_list_at(key, &:length)
|
79
93
|
end
|
80
94
|
|
81
|
-
def
|
82
|
-
|
95
|
+
def lmove(source, destination, wherefrom, whereto)
|
96
|
+
assert_listy(source)
|
97
|
+
assert_listy(destination)
|
98
|
+
|
99
|
+
wherefrom = wherefrom.to_s.downcase
|
100
|
+
whereto = whereto.to_s.downcase
|
101
|
+
|
102
|
+
unless %w[left right].include?(wherefrom) && %w[left right].include?(whereto)
|
103
|
+
raise Redis::CommandError, 'ERR syntax error'
|
104
|
+
end
|
105
|
+
|
106
|
+
value = wherefrom == 'left' ? lpop(source) : rpop(source)
|
107
|
+
(whereto == 'left' ? lpush(destination, value) : rpush(destination, value)) unless value.nil?
|
108
|
+
value
|
109
|
+
end
|
110
|
+
|
111
|
+
def lpop(key, count = nil)
|
112
|
+
return with_list_at(key, &:shift) if count.nil?
|
113
|
+
|
114
|
+
record_count = llen(key)
|
115
|
+
return nil if record_count.zero?
|
116
|
+
|
117
|
+
[record_count, count].min.times.map { with_list_at(key, &:shift) }
|
83
118
|
end
|
84
119
|
|
85
120
|
def lpush(key, values)
|
@@ -41,22 +41,20 @@ class MockRedis
|
|
41
41
|
end
|
42
42
|
|
43
43
|
responses = @pipelined_futures.flat_map do |future|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
future.store_result(result)
|
44
|
+
result = if future.block
|
45
|
+
send(*future.command, &future.block)
|
46
|
+
else
|
47
|
+
send(*future.command)
|
48
|
+
end
|
49
|
+
future.store_result(result)
|
51
50
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
57
|
-
rescue StandardError => e
|
58
|
-
e
|
51
|
+
if future.block
|
52
|
+
result
|
53
|
+
else
|
54
|
+
[result]
|
59
55
|
end
|
56
|
+
rescue StandardError => e
|
57
|
+
e
|
60
58
|
end
|
61
59
|
@pipelined_futures = []
|
62
60
|
responses
|
@@ -8,7 +8,7 @@ class MockRedis
|
|
8
8
|
|
9
9
|
def sadd(key, members)
|
10
10
|
members_class = members.class
|
11
|
-
members =
|
11
|
+
members = Array(members).map(&:to_s)
|
12
12
|
assert_has_args(members, 'sadd')
|
13
13
|
|
14
14
|
with_set_at(key) do |s|
|
@@ -27,6 +27,11 @@ class MockRedis
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
def sadd?(key, members)
|
31
|
+
res = sadd(key, members)
|
32
|
+
res.is_a?(Numeric) ? res > 0 : res
|
33
|
+
end
|
34
|
+
|
30
35
|
def scard(key)
|
31
36
|
with_set_at(key, &:length)
|
32
37
|
end
|
@@ -64,6 +69,12 @@ class MockRedis
|
|
64
69
|
with_set_at(key) { |s| s.include?(member.to_s) }
|
65
70
|
end
|
66
71
|
|
72
|
+
def smismember(key, *members)
|
73
|
+
with_set_at(key) do |set|
|
74
|
+
members.flatten.map { |m| set.include?(m.to_s) }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
67
78
|
def smembers(key)
|
68
79
|
with_set_at(key, &:to_a).map(&:dup).reverse
|
69
80
|
end
|
@@ -126,6 +137,11 @@ class MockRedis
|
|
126
137
|
end
|
127
138
|
end
|
128
139
|
|
140
|
+
def srem?(key, members)
|
141
|
+
res = srem(key, members)
|
142
|
+
res.is_a?(Numeric) ? res > 0 : res
|
143
|
+
end
|
144
|
+
|
129
145
|
def sscan(key, cursor, opts = {})
|
130
146
|
common_scan(smembers(key), cursor, opts)
|
131
147
|
end
|
@@ -165,7 +181,7 @@ class MockRedis
|
|
165
181
|
with_set_at(keys.first, &blk)
|
166
182
|
else
|
167
183
|
with_set_at(keys.first) do |set|
|
168
|
-
with_sets_at(*(keys[1
|
184
|
+
with_sets_at(*(keys[1..])) do |*sets|
|
169
185
|
yield(*([set] + sets))
|
170
186
|
end
|
171
187
|
end
|
data/lib/mock_redis/stream.rb
CHANGED
@@ -37,7 +37,7 @@ class MockRedis
|
|
37
37
|
@members = if count == 0
|
38
38
|
Set.new
|
39
39
|
else
|
40
|
-
@members.to_a[-count
|
40
|
+
@members.to_a[-count..].to_set
|
41
41
|
end
|
42
42
|
deleted
|
43
43
|
else
|
@@ -71,8 +71,8 @@ class MockRedis
|
|
71
71
|
items
|
72
72
|
end
|
73
73
|
|
74
|
-
def each
|
75
|
-
members.each
|
74
|
+
def each(&block)
|
75
|
+
members.each(&block)
|
76
76
|
end
|
77
77
|
|
78
78
|
private
|
@@ -38,7 +38,7 @@ class MockRedis
|
|
38
38
|
type, offset = args.shift(2)
|
39
39
|
|
40
40
|
is_signed = type.slice(0) == 'i'
|
41
|
-
type_size = type[1
|
41
|
+
type_size = type[1..].to_i
|
42
42
|
|
43
43
|
if (type_size > 64 && is_signed) || (type_size >= 64 && !is_signed)
|
44
44
|
raise Redis::CommandError,
|
@@ -47,7 +47,7 @@ class MockRedis
|
|
47
47
|
end
|
48
48
|
|
49
49
|
if offset.to_s[0] == '#'
|
50
|
-
offset = offset[1
|
50
|
+
offset = offset[1..].to_i * type_size
|
51
51
|
end
|
52
52
|
|
53
53
|
bits = []
|
@@ -107,6 +107,12 @@ class MockRedis
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
def getdel(key)
|
111
|
+
value = get(key)
|
112
|
+
del(key)
|
113
|
+
value
|
114
|
+
end
|
115
|
+
|
110
116
|
def getrange(key, start, stop)
|
111
117
|
assert_stringy(key)
|
112
118
|
(data[key] || '')[start..stop]
|
@@ -204,10 +210,13 @@ class MockRedis
|
|
204
210
|
msetnx(*hash.to_a.flatten)
|
205
211
|
end
|
206
212
|
|
207
|
-
#
|
213
|
+
# Parameter list required to ensure the ArgumentError is returned correctly
|
208
214
|
# rubocop:disable Metrics/ParameterLists
|
209
|
-
def set(key, value, ex: nil, px: nil,
|
215
|
+
def set(key, value, _hash = nil, ex: nil, px: nil, exat: nil, pxat: nil, nx: nil, xx: nil,
|
216
|
+
keepttl: nil, get: nil)
|
210
217
|
key = key.to_s
|
218
|
+
retval = self.get(key) if get
|
219
|
+
|
211
220
|
return_true = false
|
212
221
|
if nx
|
213
222
|
if exists?(key)
|
@@ -240,7 +249,25 @@ class MockRedis
|
|
240
249
|
pexpire(key, px)
|
241
250
|
end
|
242
251
|
|
243
|
-
|
252
|
+
if exat
|
253
|
+
if exat == 0
|
254
|
+
raise Redis::CommandError, 'ERR invalid expire time in set'
|
255
|
+
end
|
256
|
+
expireat(key, exat)
|
257
|
+
end
|
258
|
+
|
259
|
+
if pxat
|
260
|
+
if pxat == 0
|
261
|
+
raise Redis::CommandError, 'ERR invalid expire time in set'
|
262
|
+
end
|
263
|
+
pexpireat(key, pxat)
|
264
|
+
end
|
265
|
+
|
266
|
+
if get
|
267
|
+
retval
|
268
|
+
else
|
269
|
+
return_true ? true : 'OK'
|
270
|
+
end
|
244
271
|
end
|
245
272
|
# rubocop:enable Metrics/ParameterLists
|
246
273
|
|
@@ -353,7 +380,7 @@ class MockRedis
|
|
353
380
|
old_value = (data[key] || '')
|
354
381
|
|
355
382
|
prefix = zero_pad(old_value[0...offset], offset)
|
356
|
-
data[key] = prefix + value + (old_value[(offset + value.length)
|
383
|
+
data[key] = prefix + value + (old_value[(offset + value.length)..] || '')
|
357
384
|
data[key].length
|
358
385
|
end
|
359
386
|
|
@@ -57,13 +57,11 @@ class MockRedis
|
|
57
57
|
@multi_block_given = false
|
58
58
|
|
59
59
|
responses = @transaction_futures.map do |future|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
e
|
66
|
-
end
|
60
|
+
result = send(*future.command)
|
61
|
+
future.store_result(result)
|
62
|
+
future.value
|
63
|
+
rescue StandardError => e
|
64
|
+
e
|
67
65
|
end
|
68
66
|
|
69
67
|
@transaction_futures = []
|
@@ -28,6 +28,7 @@ class MockRedis
|
|
28
28
|
cursor = cursor.to_i
|
29
29
|
match = opts[:match] || '*'
|
30
30
|
key = opts[:key] || lambda { |x| x }
|
31
|
+
type_opt = opts[:type]
|
31
32
|
filtered_values = []
|
32
33
|
|
33
34
|
limit = cursor + count
|
@@ -35,7 +36,8 @@ class MockRedis
|
|
35
36
|
|
36
37
|
unless values[cursor...limit].nil?
|
37
38
|
filtered_values = values[cursor...limit].select do |val|
|
38
|
-
redis_pattern_to_ruby_regex(match).match(key.call(val))
|
39
|
+
redis_pattern_to_ruby_regex(match).match(key.call(val)) &&
|
40
|
+
(type_opt.nil? || type(val) == type_opt)
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
@@ -68,7 +70,7 @@ class MockRedis
|
|
68
70
|
end
|
69
71
|
|
70
72
|
def left_pad(str, size)
|
71
|
-
str =
|
73
|
+
str = "0#{str}" while str.length < size
|
72
74
|
|
73
75
|
str
|
74
76
|
end
|
data/lib/mock_redis/version.rb
CHANGED
data/lib/mock_redis/zset.rb
CHANGED
@@ -10,9 +10,11 @@ class MockRedis
|
|
10
10
|
|
11
11
|
def_delegators :members, :empty?, :include?, :size
|
12
12
|
|
13
|
-
def initialize
|
13
|
+
def initialize(enum = nil)
|
14
14
|
@members = Set.new
|
15
|
-
@
|
15
|
+
@members.merge(enum) if enum
|
16
|
+
|
17
|
+
@scores = {}
|
16
18
|
end
|
17
19
|
|
18
20
|
def initialize_copy(source)
|
@@ -26,7 +26,7 @@ class MockRedis
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def zadd_one_member(key, score, member, zadd_options = {})
|
29
|
-
assert_scorey(score) unless score.to_s =~ /(
|
29
|
+
assert_scorey(score) unless score.to_s =~ /(\+|-)inf/
|
30
30
|
|
31
31
|
with_zset_at(key) do |zset|
|
32
32
|
if zadd_options[:incr]
|
@@ -147,7 +147,7 @@ class MockRedis
|
|
147
147
|
else
|
148
148
|
retval = args.map { |member| !!zscore(key, member.to_s) }.count(true)
|
149
149
|
with_zset_at(key) do |z|
|
150
|
-
args.each { |member| z.delete?(member) }
|
150
|
+
args.each { |member| z.delete?(member.to_s) }
|
151
151
|
end
|
152
152
|
end
|
153
153
|
end
|
@@ -233,6 +233,15 @@ class MockRedis
|
|
233
233
|
end
|
234
234
|
end
|
235
235
|
|
236
|
+
def zmscore(key, *members)
|
237
|
+
with_zset_at(key) do |z|
|
238
|
+
members.map do |member|
|
239
|
+
score = z.score(member.to_s)
|
240
|
+
score&.to_f
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
236
245
|
def zunionstore(destination, keys, options = {})
|
237
246
|
assert_has_args(keys, 'zunionstore')
|
238
247
|
|
@@ -316,7 +325,7 @@ class MockRedis
|
|
316
325
|
with_zset_at(keys.first, coercible: coercible, &blk)
|
317
326
|
else
|
318
327
|
with_zset_at(keys.first, coercible: coercible) do |set|
|
319
|
-
with_zsets_at(*(keys[1
|
328
|
+
with_zsets_at(*(keys[1..]), coercible: coercible) do |*sets|
|
320
329
|
yield(*([set] + sets))
|
321
330
|
end
|
322
331
|
end
|
@@ -351,7 +360,7 @@ class MockRedis
|
|
351
360
|
end
|
352
361
|
|
353
362
|
def assert_scorey(value, message = 'ERR value is not a valid float')
|
354
|
-
return if value.to_s =~ /\(?(
|
363
|
+
return if value.to_s =~ /\(?(-|\+)inf/
|
355
364
|
|
356
365
|
value = $1 if value.to_s =~ /\((.*)/
|
357
366
|
unless looks_like_float?(value)
|
data/lib/mock_redis.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'set'
|
2
|
-
require 'ruby2_keywords'
|
3
2
|
|
4
3
|
require 'mock_redis/assertions'
|
5
4
|
require 'mock_redis/database'
|
@@ -50,10 +49,6 @@ class MockRedis
|
|
50
49
|
end
|
51
50
|
alias location id
|
52
51
|
|
53
|
-
def call(command, &_block)
|
54
|
-
send(*command)
|
55
|
-
end
|
56
|
-
|
57
52
|
def host
|
58
53
|
options[:host]
|
59
54
|
end
|
@@ -86,6 +81,10 @@ class MockRedis
|
|
86
81
|
self
|
87
82
|
end
|
88
83
|
|
84
|
+
def with
|
85
|
+
yield self
|
86
|
+
end
|
87
|
+
|
89
88
|
def respond_to?(method, include_private = false)
|
90
89
|
super || @db.respond_to?(method, include_private)
|
91
90
|
end
|
@@ -126,7 +125,7 @@ class MockRedis
|
|
126
125
|
defaults[:host] = uri.host
|
127
126
|
defaults[:port] = uri.port if uri.port
|
128
127
|
defaults[:password] = uri.password if uri.password
|
129
|
-
defaults[:db] = uri.path[1
|
128
|
+
defaults[:db] = uri.path[1..].to_i if uri.path
|
130
129
|
end
|
131
130
|
end
|
132
131
|
|