mock_redis 0.22.0 → 0.27.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +26 -5
- data/.rubocop_todo.yml +1 -1
- data/.travis.yml +1 -0
- data/CHANGELOG.md +31 -0
- data/Gemfile +4 -2
- data/lib/mock_redis.rb +1 -8
- data/lib/mock_redis/connection_method.rb +13 -0
- data/lib/mock_redis/database.rb +44 -14
- data/lib/mock_redis/expire_wrapper.rb +1 -1
- data/lib/mock_redis/future.rb +1 -1
- data/lib/mock_redis/geospatial_methods.rb +5 -5
- data/lib/mock_redis/hash_methods.rb +9 -4
- data/lib/mock_redis/info_method.rb +2 -2
- data/lib/mock_redis/multi_db_wrapper.rb +3 -3
- data/lib/mock_redis/pipelined_wrapper.rb +1 -1
- data/lib/mock_redis/stream.rb +22 -2
- data/lib/mock_redis/stream/id.rb +1 -1
- data/lib/mock_redis/stream_methods.rb +16 -1
- data/lib/mock_redis/string_methods.rb +27 -20
- data/lib/mock_redis/transaction_wrapper.rb +3 -3
- data/lib/mock_redis/utility_methods.rb +1 -1
- data/lib/mock_redis/version.rb +1 -1
- data/lib/mock_redis/zset_methods.rb +34 -9
- data/mock_redis.gemspec +1 -1
- data/spec/commands/blpop_spec.rb +0 -6
- data/spec/commands/brpop_spec.rb +6 -5
- data/spec/commands/connection_spec.rb +15 -0
- data/spec/commands/del_spec.rb +17 -0
- data/spec/commands/dump_spec.rb +19 -0
- data/spec/commands/exists_spec.rb +34 -5
- data/spec/commands/future_spec.rb +11 -1
- data/spec/commands/geoadd_spec.rb +1 -1
- data/spec/commands/hset_spec.rb +6 -6
- data/spec/commands/keys_spec.rb +17 -0
- data/spec/commands/mget_spec.rb +6 -0
- data/spec/commands/move_spec.rb +5 -5
- data/spec/commands/pipelined_spec.rb +20 -0
- data/spec/commands/restore_spec.rb +47 -0
- data/spec/commands/set_spec.rb +59 -9
- data/spec/commands/setbit_spec.rb +1 -0
- data/spec/commands/setex_spec.rb +16 -0
- data/spec/commands/srandmember_spec.rb +1 -1
- data/spec/commands/xadd_spec.rb +23 -3
- data/spec/commands/xlen_spec.rb +3 -1
- data/spec/commands/xrange_spec.rb +13 -0
- data/spec/commands/xread_spec.rb +66 -0
- data/spec/commands/xtrim_spec.rb +6 -0
- data/spec/commands/zinterstore_spec.rb +34 -0
- data/spec/commands/zrange_spec.rb +1 -1
- data/spec/commands/zrangebyscore_spec.rb +1 -1
- data/spec/commands/zrevrange_spec.rb +1 -1
- data/spec/commands/zrevrangebyscore_spec.rb +1 -1
- data/spec/commands/zunionstore_spec.rb +33 -0
- data/spec/spec_helper.rb +2 -1
- data/spec/support/redis_multiplexer.rb +2 -1
- data/spec/transactions_spec.rb +16 -0
- metadata +14 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b491b0b8e260ee631a3633b35154946ef5822a3310d6bc51ce977febe8559b8a
|
4
|
+
data.tar.gz: 795a9ec1aa340ee6b0733b3a539a0ff355dc5e71287f59ca03f2ae64ef9e770e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea3fd9aabe7c3afac9c358dbe97a2ffb78277a1d0dab830d6b9983404a1a9f3b2b47f97022441b62884ce01fb6557b1b5a8ca334378bc18ba6c0863b577a947a
|
7
|
+
data.tar.gz: 4a487e49858bed2684e8695affe470801de0a6247c1a7281c1f1f3a6913f59ebe38fffee8fa0a41142d20d65cb8339cbb4dd4c2d03ddc2ed5d538760f59fc959
|
data/.rubocop.yml
CHANGED
@@ -3,10 +3,10 @@ inherit_from: .rubocop_todo.yml
|
|
3
3
|
AllCops:
|
4
4
|
TargetRubyVersion: 2.4
|
5
5
|
|
6
|
-
Layout/
|
6
|
+
Layout/ArgumentAlignment:
|
7
7
|
Enabled: false
|
8
8
|
|
9
|
-
Layout/
|
9
|
+
Layout/ParameterAlignment:
|
10
10
|
Enabled: false
|
11
11
|
|
12
12
|
Layout/DotPosition:
|
@@ -15,9 +15,21 @@ Layout/DotPosition:
|
|
15
15
|
Layout/EmptyLineAfterGuardClause:
|
16
16
|
Enabled: false
|
17
17
|
|
18
|
+
Layout/LineLength:
|
19
|
+
Max: 100
|
20
|
+
|
21
|
+
Layout/SpaceAroundMethodCallOperator:
|
22
|
+
Enabled: true
|
23
|
+
|
18
24
|
Lint/AssignmentInCondition:
|
19
25
|
Enabled: false
|
20
26
|
|
27
|
+
Lint/RaiseException:
|
28
|
+
Enabled: true
|
29
|
+
|
30
|
+
Lint/StructNewOverride:
|
31
|
+
Enabled: true
|
32
|
+
|
21
33
|
# We use this a lot in specs where it's perfectly valid
|
22
34
|
Lint/Void:
|
23
35
|
Exclude:
|
@@ -35,9 +47,6 @@ Metrics/CyclomaticComplexity:
|
|
35
47
|
Metrics/ClassLength:
|
36
48
|
Enabled: false
|
37
49
|
|
38
|
-
Metrics/LineLength:
|
39
|
-
Max: 100
|
40
|
-
|
41
50
|
Metrics/MethodLength:
|
42
51
|
Enabled: false
|
43
52
|
|
@@ -57,6 +66,18 @@ Style/Documentation:
|
|
57
66
|
Style/DoubleNegation:
|
58
67
|
Enabled: false
|
59
68
|
|
69
|
+
Style/ExponentialNotation:
|
70
|
+
Enabled: true
|
71
|
+
|
72
|
+
Style/HashEachMethods:
|
73
|
+
Enabled: true
|
74
|
+
|
75
|
+
Style/HashTransformKeys:
|
76
|
+
Enabled: true
|
77
|
+
|
78
|
+
Style/HashTransformValues:
|
79
|
+
Enabled: true
|
80
|
+
|
60
81
|
# We have too much code that relies on modifying strings
|
61
82
|
Style/FrozenStringLiteralComment:
|
62
83
|
Enabled: false
|
data/.rubocop_todo.yml
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
# Offense count: 17
|
10
10
|
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
11
11
|
# AllowedNames: io, id, to, by, on, in, at, ip
|
12
|
-
Naming/
|
12
|
+
Naming/MethodParameterName:
|
13
13
|
Exclude:
|
14
14
|
- 'lib/mock_redis/database.rb'
|
15
15
|
- 'lib/mock_redis/expire_wrapper.rb'
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,36 @@
|
|
1
1
|
# MockRedis Changelog
|
2
2
|
|
3
|
+
### 0.27.0
|
4
|
+
|
5
|
+
* Fix handling of keyword arguments on Ruby 3 ([#199](https://github.com/sds/mock_redis/pull/199))
|
6
|
+
* Allow passing string `offset` to `setbit` ([#200](https://github.com/sds/mock_redis/pull/200))
|
7
|
+
* Add `connection` method ([#201](https://github.com/sds/mock_redis/pull/201))
|
8
|
+
|
9
|
+
### 0.26.0
|
10
|
+
|
11
|
+
* Add block and count support to `xread` ([#194](https://github.com/sds/mock_redis/pull/194))
|
12
|
+
|
13
|
+
### 0.25.0
|
14
|
+
|
15
|
+
* Add support for `xread` command ([#190](https://github.com/sds/mock_redis/pull/190))
|
16
|
+
* Fix `mget` to raise error when passing empty array ([#191](https://github.com/sds/mock_redis/pull/191))
|
17
|
+
* Fix `xadd` when `maxlen` is zero ([#192](https://github.com/sds/mock_redis/pull/192))
|
18
|
+
|
19
|
+
### 0.24.0
|
20
|
+
|
21
|
+
* Fix handling of blocks within `multi` blocks ([#185](https://github.com/sds/mock_redis/pull/185))
|
22
|
+
* Fix handling of multiple consecutive `?` characters in key pattern matching ([#186](https://github.com/sds/mock_redis/pull/186))
|
23
|
+
* Change `exists` to return an integer and add `exists?` ([#188](https://github.com/sds/mock_redis/pull/188))
|
24
|
+
|
25
|
+
### 0.23.0
|
26
|
+
|
27
|
+
* Raise error when `setex` called with negative timeout ([#174](https://github.com/sds/mock_redis/pull/174))
|
28
|
+
* Add support for `dump`/`restore` between MockRedis instances ([#176](https://github.com/sds/mock_redis/pull/176))
|
29
|
+
* Fix warnings for ZSET methods on Ruby 2.7 ([#177](https://github.com/sds/mock_redis/pull/177))
|
30
|
+
* Add support for returning time in pipelines ([#179](https://github.com/sds/mock_redis/pull/179))
|
31
|
+
* Fix SET methods to correct set milliseconds with `px` ([#180](https://github.com/sds/mock_redis/pull/180))
|
32
|
+
* Add support for unsorted sets within `zinterstore`/`zunionstore`([#182](https://github.com/sds/mock_redis/pull/182))
|
33
|
+
|
3
34
|
### 0.22.0
|
4
35
|
|
5
36
|
* Gracefully handle cursors larger than the collection size in scan commands ([#171](https://github.com/sds/mock_redis/pull/171))
|
data/Gemfile
CHANGED
@@ -4,9 +4,11 @@ source 'http://rubygems.org'
|
|
4
4
|
gemspec
|
5
5
|
|
6
6
|
# Run all pre-commit hooks via Overcommit during CI runs
|
7
|
-
gem 'overcommit', '0.
|
7
|
+
gem 'overcommit', '0.53.0'
|
8
8
|
|
9
9
|
# Pin tool versions (which are executed by Overcommit) for Travis builds
|
10
|
-
gem 'rubocop', '0.
|
10
|
+
gem 'rubocop', '0.82.0'
|
11
|
+
|
12
|
+
gem 'ruby2_keywords'
|
11
13
|
|
12
14
|
gem 'coveralls', require: false
|
data/lib/mock_redis.rb
CHANGED
@@ -64,13 +64,6 @@ class MockRedis
|
|
64
64
|
options[:db]
|
65
65
|
end
|
66
66
|
|
67
|
-
def now
|
68
|
-
current_time = options[:time_class].now
|
69
|
-
miliseconds = (current_time.to_r - current_time.to_i) * 1_000
|
70
|
-
[current_time.to_i, miliseconds.to_i]
|
71
|
-
end
|
72
|
-
alias time now
|
73
|
-
|
74
67
|
def time_at(timestamp)
|
75
68
|
options[:time_class].at(timestamp)
|
76
69
|
end
|
@@ -91,7 +84,7 @@ class MockRedis
|
|
91
84
|
super || @db.respond_to?(method, include_private)
|
92
85
|
end
|
93
86
|
|
94
|
-
def method_missing(method, *args, &block)
|
87
|
+
ruby2_keywords def method_missing(method, *args, &block)
|
95
88
|
@db.send(method, *args, &block)
|
96
89
|
end
|
97
90
|
|
data/lib/mock_redis/database.rb
CHANGED
@@ -11,6 +11,7 @@ require 'mock_redis/info_method'
|
|
11
11
|
require 'mock_redis/utility_methods'
|
12
12
|
require 'mock_redis/geospatial_methods'
|
13
13
|
require 'mock_redis/stream_methods'
|
14
|
+
require 'mock_redis/connection_method'
|
14
15
|
|
15
16
|
class MockRedis
|
16
17
|
class Database
|
@@ -24,6 +25,7 @@ class MockRedis
|
|
24
25
|
include UtilityMethods
|
25
26
|
include GeospatialMethods
|
26
27
|
include StreamMethods
|
28
|
+
include ConnectionMethod
|
27
29
|
|
28
30
|
attr_reader :data, :expire_times
|
29
31
|
|
@@ -35,7 +37,7 @@ class MockRedis
|
|
35
37
|
|
36
38
|
def initialize_copy(_source)
|
37
39
|
@data = @data.clone
|
38
|
-
@data.
|
40
|
+
@data.each_key { |k| @data[k] = @data[k].clone }
|
39
41
|
@expire_times = @expire_times.map(&:clone)
|
40
42
|
end
|
41
43
|
|
@@ -106,7 +108,7 @@ class MockRedis
|
|
106
108
|
raise Redis::CommandError, 'ERR value is not an integer or out of range'
|
107
109
|
end
|
108
110
|
|
109
|
-
if exists(key)
|
111
|
+
if exists?(key)
|
110
112
|
timestamp = Rational(timestamp_ms.to_i, 1000)
|
111
113
|
set_expiration(key, @base.time_at(timestamp))
|
112
114
|
true
|
@@ -115,12 +117,33 @@ class MockRedis
|
|
115
117
|
end
|
116
118
|
end
|
117
119
|
|
118
|
-
def exists(
|
119
|
-
data.key?(key)
|
120
|
+
def exists(*keys)
|
121
|
+
keys.count { |key| data.key?(key) }
|
122
|
+
end
|
123
|
+
|
124
|
+
def exists?(*keys)
|
125
|
+
keys.each { |key| return true if data.key?(key) }
|
126
|
+
false
|
120
127
|
end
|
121
128
|
|
122
129
|
def flushdb
|
123
|
-
data.
|
130
|
+
data.each_key { |k| del(k) }
|
131
|
+
'OK'
|
132
|
+
end
|
133
|
+
|
134
|
+
def dump(key)
|
135
|
+
value = data[key]
|
136
|
+
value ? Marshal.dump(value) : nil
|
137
|
+
end
|
138
|
+
|
139
|
+
def restore(key, ttl, value, replace: false)
|
140
|
+
if !replace && exists?(key)
|
141
|
+
raise Redis::CommandError, 'BUSYKEY Target key name already exists.'
|
142
|
+
end
|
143
|
+
data[key] = Marshal.load(value) # rubocop:disable Security/MarshalLoad
|
144
|
+
if ttl > 0
|
145
|
+
pexpire(key, ttl)
|
146
|
+
end
|
124
147
|
'OK'
|
125
148
|
end
|
126
149
|
|
@@ -143,11 +166,11 @@ class MockRedis
|
|
143
166
|
end
|
144
167
|
|
145
168
|
def lastsave
|
146
|
-
|
169
|
+
now.first
|
147
170
|
end
|
148
171
|
|
149
172
|
def persist(key)
|
150
|
-
if exists(key) && has_expiration?(key)
|
173
|
+
if exists?(key) && has_expiration?(key)
|
151
174
|
remove_expiration(key)
|
152
175
|
true
|
153
176
|
else
|
@@ -188,7 +211,7 @@ class MockRedis
|
|
188
211
|
raise Redis::CommandError, 'ERR no such key'
|
189
212
|
end
|
190
213
|
|
191
|
-
if exists(newkey)
|
214
|
+
if exists?(newkey)
|
192
215
|
false
|
193
216
|
else
|
194
217
|
rename(key, newkey)
|
@@ -201,7 +224,7 @@ class MockRedis
|
|
201
224
|
end
|
202
225
|
|
203
226
|
def ttl(key)
|
204
|
-
if !exists(key)
|
227
|
+
if !exists?(key)
|
205
228
|
-2
|
206
229
|
elsif has_expiration?(key)
|
207
230
|
now, = @base.now
|
@@ -215,7 +238,7 @@ class MockRedis
|
|
215
238
|
now, miliseconds = @base.now
|
216
239
|
now_ms = now * 1000 + miliseconds
|
217
240
|
|
218
|
-
if !exists(key)
|
241
|
+
if !exists?(key)
|
219
242
|
-2
|
220
243
|
elsif has_expiration?(key)
|
221
244
|
(expiration(key).to_r * 1000).to_i - now_ms
|
@@ -224,8 +247,15 @@ class MockRedis
|
|
224
247
|
end
|
225
248
|
end
|
226
249
|
|
250
|
+
def now
|
251
|
+
current_time = @base.options[:time_class].now
|
252
|
+
miliseconds = (current_time.to_r - current_time.to_i) * 1_000
|
253
|
+
[current_time.to_i, miliseconds.to_i]
|
254
|
+
end
|
255
|
+
alias time now
|
256
|
+
|
227
257
|
def type(key)
|
228
|
-
if !exists(key)
|
258
|
+
if !exists?(key)
|
229
259
|
'none'
|
230
260
|
elsif hashy?(key)
|
231
261
|
'hash'
|
@@ -300,7 +330,7 @@ class MockRedis
|
|
300
330
|
Regexp.new(
|
301
331
|
"^#{pattern}$".
|
302
332
|
gsub(/([+|()])/, '\\\\\1').
|
303
|
-
gsub(/(
|
333
|
+
gsub(/(?<!\\)\?/, '\\1.').
|
304
334
|
gsub(/([^\\])\*/, '\\1.*')
|
305
335
|
)
|
306
336
|
end
|
@@ -328,8 +358,8 @@ class MockRedis
|
|
328
358
|
# This method isn't private, but it also isn't a Redis command, so
|
329
359
|
# it doesn't belong up above with all the Redis commands.
|
330
360
|
def expire_keys
|
331
|
-
|
332
|
-
now_ms =
|
361
|
+
now_sec, miliseconds = now
|
362
|
+
now_ms = now_sec * 1_000 + miliseconds
|
333
363
|
|
334
364
|
to_delete = expire_times.take_while do |(time, _key)|
|
335
365
|
(time.to_r * 1_000).to_i <= now_ms
|
data/lib/mock_redis/future.rb
CHANGED
@@ -12,7 +12,7 @@ class MockRedis
|
|
12
12
|
D_R = Math::PI / 180.0
|
13
13
|
EARTH_RADIUS_IN_METERS = 6_372_797.560856
|
14
14
|
|
15
|
-
def geoadd(key, *args)
|
15
|
+
ruby2_keywords def geoadd(key, *args)
|
16
16
|
points = parse_points(args)
|
17
17
|
|
18
18
|
scored_points = points.map do |point|
|
@@ -38,7 +38,7 @@ class MockRedis
|
|
38
38
|
lng2, lat2 = geohash_decode(hash2)
|
39
39
|
|
40
40
|
distance = geohash_distance(lng1, lat1, lng2, lat2) / to_meter
|
41
|
-
format('
|
41
|
+
format('%<distance>.4f', distance: distance)
|
42
42
|
end
|
43
43
|
|
44
44
|
def geohash(key, members)
|
@@ -95,8 +95,8 @@ class MockRedis
|
|
95
95
|
lat = Float(point[1])
|
96
96
|
|
97
97
|
unless LNG_RANGE.include?(lng) && LAT_RANGE.include?(lat)
|
98
|
-
lng = format('
|
99
|
-
lat = format('
|
98
|
+
lng = format('%<long>.6f', long: lng)
|
99
|
+
lat = format('%<lat>.6f', lat: lat)
|
100
100
|
raise Redis::CommandError,
|
101
101
|
"ERR invalid longitude,latitude pair #{lng},#{lat}"
|
102
102
|
end
|
@@ -201,7 +201,7 @@ class MockRedis
|
|
201
201
|
end
|
202
202
|
|
203
203
|
def format_decoded_coord(coord)
|
204
|
-
coord = format('
|
204
|
+
coord = format('%<coord>.17f', coord: coord)
|
205
205
|
l = 1
|
206
206
|
l += 1 while coord[-l] == '0'
|
207
207
|
coord = coord[0..-l]
|
@@ -128,10 +128,15 @@ class MockRedis
|
|
128
128
|
end
|
129
129
|
end
|
130
130
|
|
131
|
-
def hset(key,
|
132
|
-
|
133
|
-
with_hash_at(key)
|
134
|
-
|
131
|
+
def hset(key, *args)
|
132
|
+
added = 0
|
133
|
+
with_hash_at(key) do |hash|
|
134
|
+
args.each_slice(2) do |field, value|
|
135
|
+
added += 1 unless hash.key?(field.to_s)
|
136
|
+
hash[field.to_s] = value.to_s
|
137
|
+
end
|
138
|
+
end
|
139
|
+
added
|
135
140
|
end
|
136
141
|
|
137
142
|
def hsetnx(key, field, value)
|
@@ -83,7 +83,7 @@ class MockRedis
|
|
83
83
|
|
84
84
|
# The Ruby Redis client returns commandstats differently when it's called as
|
85
85
|
# "INFO commandstats".
|
86
|
-
# rubocop:disable
|
86
|
+
# rubocop:disable Layout/LineLength
|
87
87
|
COMMAND_STATS_SOLO_INFO = {
|
88
88
|
'auth' => { 'calls' => '572501', 'usec' => '2353163', 'usec_per_call' => '4.11' },
|
89
89
|
'client' => { 'calls' => '1', 'usec' => '80', 'usec_per_call' => '80.00' },
|
@@ -123,7 +123,7 @@ class MockRedis
|
|
123
123
|
'cmdstat_smembers' => 'calls=58,usec=231,usec_per_call=3.98',
|
124
124
|
'cmdstat_sunionstore' => 'calls=4185027,usec=11762454022,usec_per_call=2810.60',
|
125
125
|
}.freeze
|
126
|
-
# rubocop:enable
|
126
|
+
# rubocop:enable Layout/LineLength
|
127
127
|
|
128
128
|
DEFAULT_INFO = [
|
129
129
|
SERVER_INFO,
|
@@ -17,14 +17,14 @@ class MockRedis
|
|
17
17
|
super || current_db.respond_to?(method, include_private)
|
18
18
|
end
|
19
19
|
|
20
|
-
def method_missing(method, *args, &block)
|
20
|
+
ruby2_keywords def method_missing(method, *args, &block)
|
21
21
|
current_db.send(method, *args, &block)
|
22
22
|
end
|
23
23
|
|
24
24
|
def initialize_copy(source)
|
25
25
|
super
|
26
26
|
@databases = @databases.clone
|
27
|
-
@databases.
|
27
|
+
@databases.each_key do |k|
|
28
28
|
@databases[k] = @databases[k].clone
|
29
29
|
end
|
30
30
|
end
|
@@ -39,7 +39,7 @@ class MockRedis
|
|
39
39
|
src = current_db
|
40
40
|
dest = db(db_index)
|
41
41
|
|
42
|
-
if !src.exists(key) || dest.exists(key)
|
42
|
+
if !src.exists?(key) || dest.exists?(key)
|
43
43
|
false
|
44
44
|
else
|
45
45
|
case current_db.type(key)
|