mock_redis 0.19.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 +161 -0
- data/LICENSE.md +21 -0
- data/README.md +41 -17
- data/lib/mock_redis/connection_method.rb +13 -0
- data/lib/mock_redis/database.rb +116 -41
- data/lib/mock_redis/expire_wrapper.rb +1 -1
- data/lib/mock_redis/future.rb +1 -1
- data/lib/mock_redis/geospatial_methods.rb +13 -21
- data/lib/mock_redis/hash_methods.rb +34 -15
- data/lib/mock_redis/indifferent_hash.rb +0 -8
- data/lib/mock_redis/info_method.rb +2 -2
- data/lib/mock_redis/list_methods.rb +39 -4
- data/lib/mock_redis/memory_method.rb +11 -0
- data/lib/mock_redis/multi_db_wrapper.rb +4 -4
- data/lib/mock_redis/pipelined_wrapper.rb +32 -15
- data/lib/mock_redis/set_methods.rb +34 -6
- data/lib/mock_redis/stream/id.rb +58 -0
- data/lib/mock_redis/stream.rb +88 -0
- data/lib/mock_redis/stream_methods.rb +102 -0
- data/lib/mock_redis/string_methods.rb +81 -30
- data/lib/mock_redis/transaction_wrapper.rb +32 -21
- data/lib/mock_redis/utility_methods.rb +9 -4
- data/lib/mock_redis/version.rb +1 -1
- data/lib/mock_redis/zset.rb +5 -8
- data/lib/mock_redis/zset_methods.rb +64 -12
- data/lib/mock_redis.rb +38 -10
- metadata +40 -336
- data/.gitignore +0 -5
- data/.mailmap +0 -2
- data/.overcommit.yml +0 -21
- data/.rspec +0 -1
- data/.rubocop.yml +0 -121
- data/.rubocop_todo.yml +0 -35
- data/.simplecov +0 -4
- data/.travis.yml +0 -33
- data/Gemfile +0 -12
- data/LICENSE +0 -19
- data/Rakefile +0 -2
- data/mock_redis.gemspec +0 -30
- data/spec/client_spec.rb +0 -17
- 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 -59
- data/spec/commands/brpop_spec.rb +0 -58
- data/spec/commands/brpoplpush_spec.rb +0 -52
- data/spec/commands/connected_spec.rb +0 -7
- 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 -35
- data/spec/commands/disconnect_spec.rb +0 -7
- 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 -14
- 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 -20
- data/spec/commands/geoadd_spec.rb +0 -58
- data/spec/commands/geodist_spec.rb +0 -114
- data/spec/commands/geohash_spec.rb +0 -52
- data/spec/commands/geopos_spec.rb +0 -55
- data/spec/commands/get_spec.rb +0 -30
- 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/hash_operator_spec.rb +0 -21
- data/spec/commands/hdel_spec.rb +0 -54
- 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 -40
- data/spec/commands/hmset_spec.rb +0 -43
- data/spec/commands/hscan_each_spec.rb +0 -48
- data/spec/commands/hscan_spec.rb +0 -27
- data/spec/commands/hset_spec.rb +0 -38
- 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 -122
- 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 -34
- data/spec/commands/move_spec.rb +0 -147
- data/spec/commands/mset_spec.rb +0 -29
- 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 -7
- data/spec/commands/pipelined_spec.rb +0 -42
- 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/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 -55
- 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 -63
- data/spec/commands/setbit_spec.rb +0 -54
- data/spec/commands/setex_spec.rb +0 -22
- 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 -25
- data/spec/commands/srandmember_spec.rb +0 -49
- data/spec/commands/srem_spec.rb +0 -40
- 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 -16
- data/spec/commands/zadd_spec.rb +0 -123
- 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 -96
- 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 -104
- data/spec/mock_redis_spec.rb +0 -86
- data/spec/spec_helper.rb +0 -63
- data/spec/support/redis_multiplexer.rb +0 -106
- data/spec/support/shared_examples/only_operates_on_hashes.rb +0 -13
- data/spec/support/shared_examples/only_operates_on_lists.rb +0 -13
- data/spec/support/shared_examples/only_operates_on_sets.rb +0 -13
- data/spec/support/shared_examples/only_operates_on_strings.rb +0 -13
- data/spec/support/shared_examples/only_operates_on_zsets.rb +0 -57
- data/spec/support/shared_examples/sorts_enumerables.rb +0 -56
- data/spec/transactions_spec.rb +0 -159
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,166 @@
|
|
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
|
+
|
62
|
+
### 0.32.0
|
63
|
+
|
64
|
+
* Add support for `psetex`
|
65
|
+
|
66
|
+
### 0.31.0
|
67
|
+
|
68
|
+
* Allow `ping` to take argument
|
69
|
+
* Raise `CommandError` on `hmget` with empty list of fields
|
70
|
+
|
71
|
+
### 0.30.0
|
72
|
+
|
73
|
+
* Drop support for Ruby 2.4 and Ruby 2.5 since they are EOL
|
74
|
+
* Fix `expire` to to raise error on invalid integer
|
75
|
+
|
76
|
+
### 0.29.0
|
77
|
+
|
78
|
+
* Add support for `logger` option ([#211](https://github.com/sds/mock_redis/pull/211))
|
79
|
+
* Fix `zadd` to not perform conditional type conversion ([#214](https://github.com/sds/mock_redis/pull/214))
|
80
|
+
* Fix `hdel` to raise error when called with empty array ([#215](https://github.com/sds/mock_redis/pull/215))
|
81
|
+
|
82
|
+
### 0.28.0
|
83
|
+
|
84
|
+
* Fix `hmset` exception ([#206](https://github.com/sds/mock_redis/pull/206))
|
85
|
+
* Fix `hmset` to accept hashes in addition to key/value pairs ([#208](https://github.com/sds/mock_redis/pull/208))
|
86
|
+
* Fix stream ID regex to support `(` ([#209](https://github.com/sds/mock_redis/pull/209))
|
87
|
+
* Allow `mget` to accept a block ([#210](https://github.com/sds/mock_redis/pull/210))
|
88
|
+
|
89
|
+
### 0.27.3
|
90
|
+
|
91
|
+
* Ensure `ruby2_keywords` dependency is `require`d at runtime
|
92
|
+
|
93
|
+
### 0.27.2
|
94
|
+
|
95
|
+
* Switch `ruby2_keywords` gem from development dependency to runtime dependency
|
96
|
+
|
97
|
+
### 0.27.1
|
98
|
+
|
99
|
+
* Fix missing `ruby2_keywords` gem
|
100
|
+
* Allow passing string `offset` to `getbit` ([#203](https://github.com/sds/mock_redis/pull/203))
|
101
|
+
|
102
|
+
### 0.27.0
|
103
|
+
|
104
|
+
* Fix handling of keyword arguments on Ruby 3 ([#199](https://github.com/sds/mock_redis/pull/199))
|
105
|
+
* Allow passing string `offset` to `setbit` ([#200](https://github.com/sds/mock_redis/pull/200))
|
106
|
+
* Add `connection` method ([#201](https://github.com/sds/mock_redis/pull/201))
|
107
|
+
|
108
|
+
### 0.26.0
|
109
|
+
|
110
|
+
* Add block and count support to `xread` ([#194](https://github.com/sds/mock_redis/pull/194))
|
111
|
+
|
112
|
+
### 0.25.0
|
113
|
+
|
114
|
+
* Add support for `xread` command ([#190](https://github.com/sds/mock_redis/pull/190))
|
115
|
+
* Fix `mget` to raise error when passing empty array ([#191](https://github.com/sds/mock_redis/pull/191))
|
116
|
+
* Fix `xadd` when `maxlen` is zero ([#192](https://github.com/sds/mock_redis/pull/192))
|
117
|
+
|
118
|
+
### 0.24.0
|
119
|
+
|
120
|
+
* Fix handling of blocks within `multi` blocks ([#185](https://github.com/sds/mock_redis/pull/185))
|
121
|
+
* Fix handling of multiple consecutive `?` characters in key pattern matching ([#186](https://github.com/sds/mock_redis/pull/186))
|
122
|
+
* Change `exists` to return an integer and add `exists?` ([#188](https://github.com/sds/mock_redis/pull/188))
|
123
|
+
|
124
|
+
### 0.23.0
|
125
|
+
|
126
|
+
* Raise error when `setex` called with negative timeout ([#174](https://github.com/sds/mock_redis/pull/174))
|
127
|
+
* Add support for `dump`/`restore` between MockRedis instances ([#176](https://github.com/sds/mock_redis/pull/176))
|
128
|
+
* Fix warnings for ZSET methods on Ruby 2.7 ([#177](https://github.com/sds/mock_redis/pull/177))
|
129
|
+
* Add support for returning time in pipelines ([#179](https://github.com/sds/mock_redis/pull/179))
|
130
|
+
* Fix SET methods to correct set milliseconds with `px` ([#180](https://github.com/sds/mock_redis/pull/180))
|
131
|
+
* Add support for unsorted sets within `zinterstore`/`zunionstore`([#182](https://github.com/sds/mock_redis/pull/182))
|
132
|
+
|
133
|
+
### 0.22.0
|
134
|
+
|
135
|
+
* Gracefully handle cursors larger than the collection size in scan commands ([#171](https://github.com/sds/mock_redis/pull/171))
|
136
|
+
* Add `zpopmin` and `zpopmax` commands ([#172](https://github.com/sds/mock_redis/pull/172))
|
137
|
+
* Fix `hmset` to support array arguments ([#173](https://github.com/sds/mock_redis/pull/173))
|
138
|
+
* Fix `hmset` to always treat keys as strings ([#173](https://github.com/sds/mock_redis/pull/173))
|
139
|
+
* Remove unnecessary dependency on `rake` gem
|
140
|
+
|
141
|
+
### 0.21.0
|
142
|
+
|
143
|
+
* Fix behavior of `time` to return array of two integers ([#161](https://github.com/sds/mock_redis/pull/161))
|
144
|
+
* Add support for `close` and `disconnect!` ([#163](https://github.com/sds/mock_redis/pull/163))
|
145
|
+
* Fix `set` to properly handle (and ignore) other options ([#164](https://github.com/sds/mock_redis/pull/163))
|
146
|
+
* Fix `srem` to allow array of integers as argument ([#166](https://github.com/sds/mock_redis/pull/166))
|
147
|
+
* Fix `hdel` to allow array as argument ([#168](https://github.com/sds/mock_redis/pull/168))
|
148
|
+
|
149
|
+
### 0.20.0
|
150
|
+
|
151
|
+
* Add support for `count` parameter of `spop`
|
152
|
+
* Fix `mget` and `mset` to accept array as parameters
|
153
|
+
* Fix pipelined array replies
|
154
|
+
* Fix nested pipelining
|
155
|
+
* Allow nested multi
|
156
|
+
* Require Redis gem 4.0.1 or newer
|
157
|
+
* Add support for stream commands on Redis 5
|
158
|
+
* Keep empty strings on type mismatch
|
159
|
+
* Improve performance of `set_expiration`
|
160
|
+
* Fix `watch` to allow multiple keys
|
161
|
+
* Add `unlink` alias for `del`
|
162
|
+
* Drop support for Ruby 2.3 or older
|
163
|
+
|
3
164
|
### 0.19.0
|
4
165
|
|
5
166
|
* Require Ruby 2.2+
|
data/LICENSE.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MockRedis released under the MIT license.
|
2
|
+
|
3
|
+
> Copyright (c) Shane da Silva. http://shane.io
|
4
|
+
>
|
5
|
+
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
> of this software and associated documentation files (the "Software"), to deal
|
7
|
+
> in the Software without restriction, including without limitation the rights
|
8
|
+
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
> copies of the Software, and to permit persons to whom the Software is
|
10
|
+
> furnished to do so, subject to the following conditions:
|
11
|
+
>
|
12
|
+
> The above copyright notice and this permission notice shall be included in
|
13
|
+
> all copies or substantial portions of the Software.
|
14
|
+
>
|
15
|
+
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
> SOFTWARE.
|
data/README.md
CHANGED
@@ -1,18 +1,27 @@
|
|
1
1
|
# MockRedis
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/mock_redis.svg)](http://badge.fury.io/rb/mock_redis)
|
4
|
-
|
5
|
-
[![Coverage Status](https://coveralls.io/repos/
|
4
|
+
![Build Status](https://github.com/sds/mock_redis/actions/workflows/tests.yml/badge.svg)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/sds/mock_redis/badge.svg)](https://coveralls.io/r/sds/mock_redis)
|
6
6
|
|
7
7
|
MockRedis provides the same interface as `redis-rb`, but it stores its
|
8
8
|
data in memory instead of talking to a Redis server. It is intended
|
9
9
|
for use in tests.
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
## Requirements
|
12
|
+
|
13
|
+
Ruby 3.0+
|
14
|
+
|
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.
|
13
16
|
|
14
17
|
## Getting Started
|
15
18
|
|
19
|
+
Install the gem:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
gem install mock_redis
|
23
|
+
```
|
24
|
+
|
16
25
|
It's as easy as `require 'mock_redis'; mr = MockRedis.new`. Then you can
|
17
26
|
call the same methods on it as you can call on a real `Redis` object.
|
18
27
|
|
@@ -46,8 +55,8 @@ since it's an in-memory object confined to a single process. MockRedis
|
|
46
55
|
makes every attempt to be Redis-compatible, but there are some
|
47
56
|
necessary exceptions.
|
48
57
|
|
49
|
-
* Blocking list commands (`#blpop`, `#brpop`, and `#brpoplpush`)
|
50
|
-
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
|
51
60
|
these commands with a nonzero timeout and there is no data for it to
|
52
61
|
retrieve, then the command returns immediately. However, if you ask
|
53
62
|
one of these commands for data with a 0 timeout (means "wait
|
@@ -90,17 +99,32 @@ please submit a pull request with your (tested!) implementation.
|
|
90
99
|
* `#config(:get|:set|:resetstat)` isn't done. They can just return
|
91
100
|
canned values.
|
92
101
|
|
93
|
-
##
|
102
|
+
## Running tests
|
103
|
+
|
104
|
+
We recommend running Redis within a Docker container to make development as simple as possible, but as long as you have a Redis instance listening on `localhost:6379` you should be good to go.
|
105
|
+
|
106
|
+
1. Start Redis.
|
107
|
+
```bash
|
108
|
+
docker run --rm -p 6379:6379 redis:6.2-alpine
|
109
|
+
```
|
110
|
+
2. Install dependencies.
|
111
|
+
```bash
|
112
|
+
bundle install
|
113
|
+
```
|
114
|
+
3. Run tests.
|
115
|
+
```bash
|
116
|
+
bundle exec rspec
|
117
|
+
```
|
118
|
+
|
119
|
+
These tests were written with Redis running on `localhost` without any
|
120
|
+
passwords required. If you're using a different version of Redis, you
|
121
|
+
may see failures due to error message text being different and other
|
122
|
+
breaking changes over time.
|
123
|
+
|
124
|
+
## Changelog
|
94
125
|
|
95
|
-
|
96
|
-
older versions of Ruby, use `0.18.0` or older.
|
126
|
+
If you're interested in seeing the changes and bug fixes between each version of `mock_redis`, read the [MockRedis Changelog](CHANGELOG.md).
|
97
127
|
|
98
|
-
##
|
128
|
+
## License
|
99
129
|
|
100
|
-
|
101
|
-
tests. (Just kidding! There's no probably about it.) These tests were
|
102
|
-
written with Redis running on `localhost` without any passwords
|
103
|
-
required. If you're using a different version of Redis, you may see
|
104
|
-
failures due to error message text being different. If you're running
|
105
|
-
a really old version of Redis, you'll definitely see failures due to
|
106
|
-
stuff that doesn't work!
|
130
|
+
This project is released under the [MIT license](LICENSE.md).
|
data/lib/mock_redis/database.rb
CHANGED
@@ -10,6 +10,9 @@ require 'mock_redis/indifferent_hash'
|
|
10
10
|
require 'mock_redis/info_method'
|
11
11
|
require 'mock_redis/utility_methods'
|
12
12
|
require 'mock_redis/geospatial_methods'
|
13
|
+
require 'mock_redis/stream_methods'
|
14
|
+
require 'mock_redis/connection_method'
|
15
|
+
require 'mock_redis/memory_method'
|
13
16
|
|
14
17
|
class MockRedis
|
15
18
|
class Database
|
@@ -22,6 +25,9 @@ class MockRedis
|
|
22
25
|
include InfoMethod
|
23
26
|
include UtilityMethods
|
24
27
|
include GeospatialMethods
|
28
|
+
include StreamMethods
|
29
|
+
include ConnectionMethod
|
30
|
+
include MemoryMethod
|
25
31
|
|
26
32
|
attr_reader :data, :expire_times
|
27
33
|
|
@@ -33,12 +39,19 @@ class MockRedis
|
|
33
39
|
|
34
40
|
def initialize_copy(_source)
|
35
41
|
@data = @data.clone
|
36
|
-
@data.
|
42
|
+
@data.each_key { |k| @data[k] = @data[k].clone }
|
37
43
|
@expire_times = @expire_times.map(&:clone)
|
38
44
|
end
|
39
45
|
|
40
46
|
# Redis commands go below this line and above 'private'
|
41
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
|
+
|
42
55
|
def auth(_)
|
43
56
|
'OK'
|
44
57
|
end
|
@@ -54,6 +67,8 @@ class MockRedis
|
|
54
67
|
def disconnect
|
55
68
|
nil
|
56
69
|
end
|
70
|
+
alias close disconnect
|
71
|
+
alias disconnect! close
|
57
72
|
|
58
73
|
def connected?
|
59
74
|
true
|
@@ -65,7 +80,7 @@ class MockRedis
|
|
65
80
|
|
66
81
|
def del(*keys)
|
67
82
|
keys = keys.flatten.map(&:to_s)
|
68
|
-
assert_has_args(keys, 'del')
|
83
|
+
# assert_has_args(keys, 'del') # no longer errors in redis > v4.5
|
69
84
|
|
70
85
|
keys.
|
71
86
|
find_all { |key| data[key] }.
|
@@ -73,48 +88,81 @@ class MockRedis
|
|
73
88
|
each { |k| data.delete(k) }.
|
74
89
|
length
|
75
90
|
end
|
91
|
+
alias unlink del
|
76
92
|
|
77
93
|
def echo(msg)
|
78
94
|
msg.to_s
|
79
95
|
end
|
80
96
|
|
81
|
-
def expire(key, seconds)
|
82
|
-
|
97
|
+
def expire(key, seconds, nx: nil, xx: nil, lt: nil, gt: nil) # rubocop:disable Metrics/ParameterLists
|
98
|
+
assert_valid_integer(seconds)
|
99
|
+
|
100
|
+
pexpire(key, seconds.to_i * 1000, nx: nx, xx: xx, lt: lt, gt: gt)
|
83
101
|
end
|
84
102
|
|
85
|
-
def pexpire(key, ms)
|
86
|
-
|
87
|
-
|
103
|
+
def pexpire(key, ms, nx: nil, xx: nil, lt: nil, gt: nil) # rubocop:disable Metrics/ParameterLists
|
104
|
+
assert_valid_integer(ms)
|
105
|
+
|
106
|
+
now, miliseconds = @base.now
|
107
|
+
now_ms = (now * 1000) + miliseconds
|
108
|
+
pexpireat(key, now_ms + ms.to_i, nx: nx, xx: xx, lt: lt, gt: gt)
|
88
109
|
end
|
89
110
|
|
90
|
-
def expireat(key, timestamp)
|
91
|
-
|
92
|
-
raise Redis::CommandError, 'ERR value is not an integer or out of range'
|
93
|
-
end
|
111
|
+
def expireat(key, timestamp, nx: nil, xx: nil, lt: nil, gt: nil) # rubocop:disable Metrics/ParameterLists
|
112
|
+
assert_valid_integer(timestamp)
|
94
113
|
|
95
|
-
pexpireat(key, timestamp.to_i * 1000)
|
114
|
+
pexpireat(key, timestamp.to_i * 1000, nx: nx, xx: xx, lt: lt, gt: gt)
|
96
115
|
end
|
97
116
|
|
98
|
-
def pexpireat(key, timestamp_ms)
|
99
|
-
|
100
|
-
|
117
|
+
def pexpireat(key, timestamp_ms, nx: nil, xx: nil, lt: nil, gt: nil) # rubocop:disable Metrics/ParameterLists
|
118
|
+
assert_valid_integer(timestamp_ms)
|
119
|
+
|
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
|
101
124
|
end
|
102
125
|
|
103
|
-
|
104
|
-
|
105
|
-
|
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)
|
106
133
|
true
|
107
134
|
else
|
108
135
|
false
|
109
136
|
end
|
110
137
|
end
|
111
138
|
|
112
|
-
def exists(
|
113
|
-
data.key?(key)
|
139
|
+
def exists(*keys)
|
140
|
+
keys.count { |key| data.key?(key) }
|
141
|
+
end
|
142
|
+
|
143
|
+
def exists?(*keys)
|
144
|
+
keys.each { |key| return true if data.key?(key) }
|
145
|
+
false
|
114
146
|
end
|
115
147
|
|
116
148
|
def flushdb
|
117
|
-
data.
|
149
|
+
data.each_key { |k| del(k) }
|
150
|
+
'OK'
|
151
|
+
end
|
152
|
+
|
153
|
+
def dump(key)
|
154
|
+
value = data[key]
|
155
|
+
value ? Marshal.dump(value) : nil
|
156
|
+
end
|
157
|
+
|
158
|
+
def restore(key, ttl, value, replace: false)
|
159
|
+
if !replace && exists?(key)
|
160
|
+
raise Redis::CommandError, 'BUSYKEY Target key name already exists.'
|
161
|
+
end
|
162
|
+
data[key] = Marshal.load(value) # rubocop:disable Security/MarshalLoad
|
163
|
+
if ttl > 0
|
164
|
+
pexpire(key, ttl)
|
165
|
+
end
|
118
166
|
'OK'
|
119
167
|
end
|
120
168
|
|
@@ -137,11 +185,11 @@ class MockRedis
|
|
137
185
|
end
|
138
186
|
|
139
187
|
def lastsave
|
140
|
-
|
188
|
+
now.first
|
141
189
|
end
|
142
190
|
|
143
191
|
def persist(key)
|
144
|
-
if exists(key) && has_expiration?(key)
|
192
|
+
if exists?(key) && has_expiration?(key)
|
145
193
|
remove_expiration(key)
|
146
194
|
true
|
147
195
|
else
|
@@ -149,8 +197,8 @@ class MockRedis
|
|
149
197
|
end
|
150
198
|
end
|
151
199
|
|
152
|
-
def ping
|
153
|
-
|
200
|
+
def ping(response = 'PONG')
|
201
|
+
response
|
154
202
|
end
|
155
203
|
|
156
204
|
def quit
|
@@ -182,7 +230,7 @@ class MockRedis
|
|
182
230
|
raise Redis::CommandError, 'ERR no such key'
|
183
231
|
end
|
184
232
|
|
185
|
-
if exists(newkey)
|
233
|
+
if exists?(newkey)
|
186
234
|
false
|
187
235
|
else
|
188
236
|
rename(key, newkey)
|
@@ -195,27 +243,38 @@ class MockRedis
|
|
195
243
|
end
|
196
244
|
|
197
245
|
def ttl(key)
|
198
|
-
if !exists(key)
|
246
|
+
if !exists?(key)
|
199
247
|
-2
|
200
248
|
elsif has_expiration?(key)
|
201
|
-
|
249
|
+
now, = @base.now
|
250
|
+
expiration(key).to_i - now
|
202
251
|
else
|
203
252
|
-1
|
204
253
|
end
|
205
254
|
end
|
206
255
|
|
207
256
|
def pttl(key)
|
208
|
-
|
257
|
+
now, miliseconds = @base.now
|
258
|
+
now_ms = now * 1000 + miliseconds
|
259
|
+
|
260
|
+
if !exists?(key)
|
209
261
|
-2
|
210
262
|
elsif has_expiration?(key)
|
211
|
-
(expiration(key).to_r * 1000).to_i -
|
263
|
+
(expiration(key).to_r * 1000).to_i - now_ms
|
212
264
|
else
|
213
265
|
-1
|
214
266
|
end
|
215
267
|
end
|
216
268
|
|
269
|
+
def now
|
270
|
+
current_time = @base.options[:time_class].now
|
271
|
+
miliseconds = (current_time.to_r - current_time.to_i) * 1_000
|
272
|
+
[current_time.to_i, miliseconds.to_i]
|
273
|
+
end
|
274
|
+
alias time now
|
275
|
+
|
217
276
|
def type(key)
|
218
|
-
if !exists(key)
|
277
|
+
if !exists?(key)
|
219
278
|
'none'
|
220
279
|
elsif hashy?(key)
|
221
280
|
'hash'
|
@@ -227,6 +286,8 @@ class MockRedis
|
|
227
286
|
'set'
|
228
287
|
elsif zsety?(key)
|
229
288
|
'zset'
|
289
|
+
elsif streamy?(key)
|
290
|
+
'stream'
|
230
291
|
else
|
231
292
|
raise ArgumentError, "Not sure how #{data[key].inspect} got in here"
|
232
293
|
end
|
@@ -240,6 +301,13 @@ class MockRedis
|
|
240
301
|
|
241
302
|
private
|
242
303
|
|
304
|
+
def assert_valid_integer(integer)
|
305
|
+
unless looks_like_integer?(integer.to_s)
|
306
|
+
raise Redis::CommandError, 'ERR value is not an integer or out of range'
|
307
|
+
end
|
308
|
+
integer
|
309
|
+
end
|
310
|
+
|
243
311
|
def assert_valid_timeout(timeout)
|
244
312
|
if !looks_like_integer?(timeout.to_s)
|
245
313
|
raise Redis::CommandError, 'ERR timeout is not an integer or out of range'
|
@@ -271,7 +339,7 @@ class MockRedis
|
|
271
339
|
end
|
272
340
|
|
273
341
|
def expiration(key)
|
274
|
-
expire_times.find { |(_, k)| k == key.to_s }
|
342
|
+
expire_times.find { |(_, k)| k == key.to_s }&.first
|
275
343
|
end
|
276
344
|
|
277
345
|
def has_expiration?(key)
|
@@ -286,11 +354,19 @@ class MockRedis
|
|
286
354
|
!!Float(str) rescue false
|
287
355
|
end
|
288
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
|
+
|
289
365
|
def redis_pattern_to_ruby_regex(pattern)
|
290
366
|
Regexp.new(
|
291
367
|
"^#{pattern}$".
|
292
|
-
gsub(/([+|()])/, '\\\\\1').
|
293
|
-
gsub(/(
|
368
|
+
gsub(/([+|(){}])/, '\\\\\1').
|
369
|
+
gsub(/(?<!\\)\?/, '\\1.').
|
294
370
|
gsub(/([^\\])\*/, '\\1.*')
|
295
371
|
)
|
296
372
|
end
|
@@ -303,11 +379,9 @@ class MockRedis
|
|
303
379
|
|
304
380
|
def set_expiration(key, time)
|
305
381
|
remove_expiration(key)
|
306
|
-
|
307
|
-
|
308
|
-
expire_times.
|
309
|
-
a.first <=> b.first
|
310
|
-
end
|
382
|
+
found = expire_times.each_with_index.to_a.bsearch { |item, _| item.first >= time }
|
383
|
+
index = found ? found.last : -1
|
384
|
+
expire_times.insert(index, [time, key.to_s])
|
311
385
|
end
|
312
386
|
|
313
387
|
def zero_pad(string, desired_length)
|
@@ -320,10 +394,11 @@ class MockRedis
|
|
320
394
|
# This method isn't private, but it also isn't a Redis command, so
|
321
395
|
# it doesn't belong up above with all the Redis commands.
|
322
396
|
def expire_keys
|
323
|
-
|
397
|
+
now_sec, miliseconds = now
|
398
|
+
now_ms = now_sec * 1_000 + miliseconds
|
324
399
|
|
325
400
|
to_delete = expire_times.take_while do |(time, _key)|
|
326
|
-
(time.to_r * 1_000).to_i <=
|
401
|
+
(time.to_r * 1_000).to_i <= now_ms
|
327
402
|
end
|
328
403
|
|
329
404
|
to_delete.each do |(_time, key)|
|