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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +26 -5
  3. data/.rubocop_todo.yml +1 -1
  4. data/.travis.yml +1 -0
  5. data/CHANGELOG.md +31 -0
  6. data/Gemfile +4 -2
  7. data/lib/mock_redis.rb +1 -8
  8. data/lib/mock_redis/connection_method.rb +13 -0
  9. data/lib/mock_redis/database.rb +44 -14
  10. data/lib/mock_redis/expire_wrapper.rb +1 -1
  11. data/lib/mock_redis/future.rb +1 -1
  12. data/lib/mock_redis/geospatial_methods.rb +5 -5
  13. data/lib/mock_redis/hash_methods.rb +9 -4
  14. data/lib/mock_redis/info_method.rb +2 -2
  15. data/lib/mock_redis/multi_db_wrapper.rb +3 -3
  16. data/lib/mock_redis/pipelined_wrapper.rb +1 -1
  17. data/lib/mock_redis/stream.rb +22 -2
  18. data/lib/mock_redis/stream/id.rb +1 -1
  19. data/lib/mock_redis/stream_methods.rb +16 -1
  20. data/lib/mock_redis/string_methods.rb +27 -20
  21. data/lib/mock_redis/transaction_wrapper.rb +3 -3
  22. data/lib/mock_redis/utility_methods.rb +1 -1
  23. data/lib/mock_redis/version.rb +1 -1
  24. data/lib/mock_redis/zset_methods.rb +34 -9
  25. data/mock_redis.gemspec +1 -1
  26. data/spec/commands/blpop_spec.rb +0 -6
  27. data/spec/commands/brpop_spec.rb +6 -5
  28. data/spec/commands/connection_spec.rb +15 -0
  29. data/spec/commands/del_spec.rb +17 -0
  30. data/spec/commands/dump_spec.rb +19 -0
  31. data/spec/commands/exists_spec.rb +34 -5
  32. data/spec/commands/future_spec.rb +11 -1
  33. data/spec/commands/geoadd_spec.rb +1 -1
  34. data/spec/commands/hset_spec.rb +6 -6
  35. data/spec/commands/keys_spec.rb +17 -0
  36. data/spec/commands/mget_spec.rb +6 -0
  37. data/spec/commands/move_spec.rb +5 -5
  38. data/spec/commands/pipelined_spec.rb +20 -0
  39. data/spec/commands/restore_spec.rb +47 -0
  40. data/spec/commands/set_spec.rb +59 -9
  41. data/spec/commands/setbit_spec.rb +1 -0
  42. data/spec/commands/setex_spec.rb +16 -0
  43. data/spec/commands/srandmember_spec.rb +1 -1
  44. data/spec/commands/xadd_spec.rb +23 -3
  45. data/spec/commands/xlen_spec.rb +3 -1
  46. data/spec/commands/xrange_spec.rb +13 -0
  47. data/spec/commands/xread_spec.rb +66 -0
  48. data/spec/commands/xtrim_spec.rb +6 -0
  49. data/spec/commands/zinterstore_spec.rb +34 -0
  50. data/spec/commands/zrange_spec.rb +1 -1
  51. data/spec/commands/zrangebyscore_spec.rb +1 -1
  52. data/spec/commands/zrevrange_spec.rb +1 -1
  53. data/spec/commands/zrevrangebyscore_spec.rb +1 -1
  54. data/spec/commands/zunionstore_spec.rb +33 -0
  55. data/spec/spec_helper.rb +2 -1
  56. data/spec/support/redis_multiplexer.rb +2 -1
  57. data/spec/transactions_spec.rb +16 -0
  58. metadata +14 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d9dd8cc0a4f19edccfb6c7b3f1a82724f0da757ad7139f4a576eed1d0b815b8d
4
- data.tar.gz: 980f4326447c75afb034b6292baab71bb723ca05689b04aa7ed4933bd8bbf356
3
+ metadata.gz: b491b0b8e260ee631a3633b35154946ef5822a3310d6bc51ce977febe8559b8a
4
+ data.tar.gz: 795a9ec1aa340ee6b0733b3a539a0ff355dc5e71287f59ca03f2ae64ef9e770e
5
5
  SHA512:
6
- metadata.gz: 53a8419ef9f62a4d276993714241f22f9da4087df9ce69158821ea42c735e4fc022f4ab9431bbef268eb562130cc139308fd46ad9eeef8941ef95d9b56afc083
7
- data.tar.gz: 266de40ac11c22fa449d709380cec9461a93cd18c6950d31aee538b295c613ab2a0ee2fb828420ff02ea2e2351e92e2d565a9bad630abfd21abf8b8eab7c144d
6
+ metadata.gz: ea3fd9aabe7c3afac9c358dbe97a2ffb78277a1d0dab830d6b9983404a1a9f3b2b47f97022441b62884ce01fb6557b1b5a8ca334378bc18ba6c0863b577a947a
7
+ data.tar.gz: 4a487e49858bed2684e8695affe470801de0a6247c1a7281c1f1f3a6913f59ebe38fffee8fa0a41142d20d65cb8339cbb4dd4c2d03ddc2ed5d538760f59fc959
@@ -3,10 +3,10 @@ inherit_from: .rubocop_todo.yml
3
3
  AllCops:
4
4
  TargetRubyVersion: 2.4
5
5
 
6
- Layout/AlignArguments:
6
+ Layout/ArgumentAlignment:
7
7
  Enabled: false
8
8
 
9
- Layout/AlignParameters:
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
@@ -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/UncommunicativeMethodParamName:
12
+ Naming/MethodParameterName:
13
13
  Exclude:
14
14
  - 'lib/mock_redis/database.rb'
15
15
  - 'lib/mock_redis/expire_wrapper.rb'
@@ -20,6 +20,7 @@ rvm:
20
20
  - 2.4
21
21
  - 2.5
22
22
  - 2.6
23
+ - 2.7
23
24
 
24
25
  before_script:
25
26
  - git config --local user.email "travis@travis.ci"
@@ -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.48.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.68.1'
10
+ gem 'rubocop', '0.82.0'
11
+
12
+ gem 'ruby2_keywords'
11
13
 
12
14
  gem 'coveralls', require: false
@@ -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
 
@@ -0,0 +1,13 @@
1
+ class MockRedis
2
+ module ConnectionMethod
3
+ def connection
4
+ {
5
+ :host => @base.host,
6
+ :port => @base.port,
7
+ :db => @base.db,
8
+ :id => @base.id,
9
+ :location => "#{@base.host}:#{@base.port}"
10
+ }
11
+ end
12
+ end
13
+ end
@@ -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.keys.each { |k| @data[k] = @data[k].clone }
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(key)
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.keys.each { |k| del(k) }
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
- @base.now.first
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(/([^\\])\?/, '\\1.').
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
- now, miliseconds = @base.now
332
- now_ms = now * 1_000 + miliseconds
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
@@ -12,7 +12,7 @@ class MockRedis
12
12
  @db = db
13
13
  end
14
14
 
15
- def method_missing(method, *args, &block)
15
+ ruby2_keywords def method_missing(method, *args, &block)
16
16
  @db.expire_keys
17
17
  @db.send(method, *args, &block)
18
18
  end
@@ -17,7 +17,7 @@ class MockRedis
17
17
 
18
18
  def store_result(result)
19
19
  @result_set = true
20
- @result = result
20
+ @result = @block ? @block.call(result) : result
21
21
  end
22
22
  end
23
23
  end
@@ -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('%.4f', distance)
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('%.6f', lng)
99
- lat = format('%.6f', lat)
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('%.17f', coord)
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, field, value)
132
- field_exists = hexists(key, field)
133
- with_hash_at(key) { |h| h[field.to_s] = value.to_s }
134
- !field_exists
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 Metrics/LineLength
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 Metrics/LineLength
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.keys.each do |k|
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)