mock_redis 0.5.4 → 0.31.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/lint.yml +31 -0
- data/.github/workflows/tests.yml +63 -0
- data/.gitignore +1 -1
- data/.overcommit.yml +21 -0
- data/.rspec +1 -1
- data/.rubocop.yml +148 -0
- data/.rubocop_todo.yml +35 -0
- data/.simplecov +4 -0
- data/CHANGELOG.md +278 -0
- data/Gemfile +9 -5
- data/LICENSE.md +21 -0
- data/README.md +52 -16
- data/Rakefile +0 -8
- data/lib/mock_redis/assertions.rb +0 -1
- data/lib/mock_redis/connection_method.rb +13 -0
- data/lib/mock_redis/database.rb +193 -257
- data/lib/mock_redis/expire_wrapper.rb +2 -2
- data/lib/mock_redis/future.rb +23 -0
- data/lib/mock_redis/geospatial_methods.rb +240 -0
- data/lib/mock_redis/hash_methods.rb +83 -24
- data/lib/mock_redis/indifferent_hash.rb +11 -0
- data/lib/mock_redis/info_method.rb +160 -0
- data/lib/mock_redis/list_methods.rb +34 -19
- data/lib/mock_redis/multi_db_wrapper.rb +8 -7
- data/lib/mock_redis/pipelined_wrapper.rb +42 -16
- data/lib/mock_redis/set_methods.rb +62 -19
- data/lib/mock_redis/sort_method.rb +81 -0
- 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 +235 -42
- data/lib/mock_redis/transaction_wrapper.rb +62 -28
- data/lib/mock_redis/utility_methods.rb +62 -11
- data/lib/mock_redis/version.rb +4 -1
- data/lib/mock_redis/zset.rb +24 -29
- data/lib/mock_redis/zset_methods.rb +187 -59
- data/lib/mock_redis.rb +77 -27
- data/mock_redis.gemspec +23 -15
- data/spec/client_spec.rb +29 -0
- data/spec/cloning_spec.rb +17 -18
- data/spec/commands/append_spec.rb +4 -4
- data/spec/commands/auth_spec.rb +1 -1
- data/spec/commands/bgrewriteaof_spec.rb +2 -2
- data/spec/commands/bgsave_spec.rb +2 -2
- data/spec/commands/bitcount_spec.rb +25 -0
- data/spec/commands/bitfield_spec.rb +169 -0
- data/spec/commands/blpop_spec.rb +19 -21
- data/spec/commands/brpop_spec.rb +25 -20
- data/spec/commands/brpoplpush_spec.rb +16 -17
- data/spec/commands/connected_spec.rb +7 -0
- data/spec/commands/connection_spec.rb +15 -0
- data/spec/commands/dbsize_spec.rb +3 -3
- data/spec/commands/decr_spec.rb +8 -8
- data/spec/commands/decrby_spec.rb +8 -8
- data/spec/commands/del_spec.rb +35 -3
- data/spec/commands/disconnect_spec.rb +7 -0
- data/spec/commands/dump_spec.rb +19 -0
- data/spec/commands/echo_spec.rb +4 -4
- data/spec/commands/eval_spec.rb +7 -0
- data/spec/commands/evalsha_spec.rb +10 -0
- data/spec/commands/exists_spec.rb +36 -7
- data/spec/commands/expire_spec.rb +48 -20
- data/spec/commands/expireat_spec.rb +12 -13
- data/spec/commands/flushall_spec.rb +5 -5
- data/spec/commands/flushdb_spec.rb +5 -5
- data/spec/commands/future_spec.rb +30 -0
- data/spec/commands/geoadd_spec.rb +58 -0
- data/spec/commands/geodist_spec.rb +118 -0
- data/spec/commands/geohash_spec.rb +52 -0
- data/spec/commands/geopos_spec.rb +55 -0
- data/spec/commands/get_spec.rb +14 -6
- data/spec/commands/getbit_spec.rb +7 -7
- data/spec/commands/getrange_spec.rb +9 -9
- data/spec/commands/getset_spec.rb +7 -7
- data/spec/commands/hdel_spec.rb +41 -11
- data/spec/commands/hexists_spec.rb +11 -11
- data/spec/commands/hget_spec.rb +7 -7
- data/spec/commands/hgetall_spec.rb +15 -5
- data/spec/commands/hincrby_spec.rb +16 -16
- data/spec/commands/hincrbyfloat_spec.rb +58 -0
- data/spec/commands/hkeys_spec.rb +5 -5
- data/spec/commands/hlen_spec.rb +5 -5
- data/spec/commands/hmget_spec.rb +19 -9
- data/spec/commands/hmset_spec.rb +38 -12
- data/spec/commands/hscan_each_spec.rb +48 -0
- data/spec/commands/hscan_spec.rb +27 -0
- data/spec/commands/hset_spec.rb +26 -12
- data/spec/commands/hsetnx_spec.rb +16 -16
- data/spec/commands/hvals_spec.rb +5 -5
- data/spec/commands/incr_spec.rb +8 -8
- data/spec/commands/incrby_spec.rb +13 -13
- data/spec/commands/incrbyfloat_spec.rb +13 -13
- data/spec/commands/info_spec.rb +54 -5
- data/spec/commands/keys_spec.rb +83 -31
- data/spec/commands/lastsave_spec.rb +2 -2
- data/spec/commands/lindex_spec.rb +20 -10
- data/spec/commands/linsert_spec.rb +14 -14
- data/spec/commands/llen_spec.rb +4 -4
- data/spec/commands/lpop_spec.rb +6 -6
- data/spec/commands/lpush_spec.rb +21 -15
- data/spec/commands/lpushx_spec.rb +24 -11
- data/spec/commands/lrange_spec.rb +24 -8
- data/spec/commands/lrem_spec.rb +16 -16
- data/spec/commands/lset_spec.rb +17 -12
- data/spec/commands/ltrim_spec.rb +17 -7
- data/spec/commands/mapped_hmget_spec.rb +13 -9
- data/spec/commands/mapped_hmset_spec.rb +12 -12
- data/spec/commands/mapped_mget_spec.rb +22 -0
- data/spec/commands/mapped_mset_spec.rb +19 -0
- data/spec/commands/mapped_msetnx_spec.rb +26 -0
- data/spec/commands/mget_spec.rb +48 -17
- data/spec/commands/move_spec.rb +37 -37
- data/spec/commands/mset_spec.rb +20 -6
- data/spec/commands/msetnx_spec.rb +14 -14
- data/spec/commands/persist_spec.rb +15 -16
- data/spec/commands/pexpire_spec.rb +86 -0
- data/spec/commands/pexpireat_spec.rb +48 -0
- data/spec/commands/ping_spec.rb +6 -2
- data/spec/commands/pipelined_spec.rb +98 -7
- data/spec/commands/pttl_spec.rb +41 -0
- data/spec/commands/randomkey_spec.rb +3 -3
- data/spec/commands/rename_spec.rb +16 -12
- data/spec/commands/renamenx_spec.rb +13 -15
- data/spec/commands/restore_spec.rb +47 -0
- data/spec/commands/rpop_spec.rb +6 -6
- data/spec/commands/rpoplpush_spec.rb +13 -8
- data/spec/commands/rpush_spec.rb +21 -15
- data/spec/commands/rpushx_spec.rb +24 -11
- data/spec/commands/sadd_spec.rb +14 -10
- data/spec/commands/scan_each_spec.rb +39 -0
- data/spec/commands/scan_spec.rb +64 -0
- data/spec/commands/scard_spec.rb +3 -3
- data/spec/commands/script_spec.rb +9 -0
- data/spec/commands/sdiff_spec.rb +13 -13
- data/spec/commands/sdiffstore_spec.rb +13 -13
- data/spec/commands/select_spec.rb +13 -5
- data/spec/commands/set_spec.rb +112 -0
- data/spec/commands/setbit_spec.rb +25 -16
- data/spec/commands/setex_spec.rb +20 -4
- data/spec/commands/setnx_spec.rb +6 -6
- data/spec/commands/setrange_spec.rb +12 -12
- data/spec/commands/sinter_spec.rb +11 -13
- data/spec/commands/sinterstore_spec.rb +12 -12
- data/spec/commands/sismember_spec.rb +10 -10
- data/spec/commands/smembers_spec.rb +15 -5
- data/spec/commands/smove_spec.rb +13 -13
- data/spec/commands/sort_list_spec.rb +21 -0
- data/spec/commands/sort_set_spec.rb +21 -0
- data/spec/commands/sort_zset_spec.rb +21 -0
- data/spec/commands/spop_spec.rb +19 -4
- data/spec/commands/srandmember_spec.rb +28 -4
- data/spec/commands/srem_spec.rb +17 -12
- data/spec/commands/sscan_each_spec.rb +48 -0
- data/spec/commands/sscan_spec.rb +39 -0
- data/spec/commands/strlen_spec.rb +4 -5
- data/spec/commands/sunion_spec.rb +13 -11
- data/spec/commands/sunionstore_spec.rb +12 -12
- data/spec/commands/ttl_spec.rb +11 -6
- data/spec/commands/type_spec.rb +1 -1
- data/spec/commands/watch_spec.rb +9 -4
- data/spec/commands/xadd_spec.rb +122 -0
- data/spec/commands/xlen_spec.rb +22 -0
- data/spec/commands/xrange_spec.rb +164 -0
- data/spec/commands/xread_spec.rb +66 -0
- data/spec/commands/xrevrange_spec.rb +130 -0
- data/spec/commands/xtrim_spec.rb +36 -0
- data/spec/commands/zadd_spec.rb +100 -11
- data/spec/commands/zcard_spec.rb +4 -4
- data/spec/commands/zcount_spec.rb +18 -10
- data/spec/commands/zincrby_spec.rb +6 -6
- data/spec/commands/zinterstore_spec.rb +54 -20
- data/spec/commands/zpopmax_spec.rb +60 -0
- data/spec/commands/zpopmin_spec.rb +60 -0
- data/spec/commands/zrange_spec.rb +54 -13
- data/spec/commands/zrangebyscore_spec.rb +42 -27
- data/spec/commands/zrank_spec.rb +4 -4
- data/spec/commands/zrem_spec.rb +18 -12
- data/spec/commands/zremrangebyrank_spec.rb +5 -5
- data/spec/commands/zremrangebyscore_spec.rb +12 -5
- data/spec/commands/zrevrange_spec.rb +35 -10
- data/spec/commands/zrevrangebyscore_spec.rb +26 -15
- data/spec/commands/zrevrank_spec.rb +4 -4
- data/spec/commands/zscan_each_spec.rb +48 -0
- data/spec/commands/zscan_spec.rb +26 -0
- data/spec/commands/zscore_spec.rb +7 -7
- data/spec/commands/zunionstore_spec.rb +54 -21
- data/spec/mock_redis_spec.rb +61 -0
- data/spec/spec_helper.rb +35 -8
- data/spec/support/redis_multiplexer.rb +62 -37
- data/spec/support/shared_examples/does_not_cleanup_empty_strings.rb +14 -0
- data/spec/support/shared_examples/only_operates_on_hashes.rb +5 -3
- data/spec/support/shared_examples/only_operates_on_lists.rb +5 -3
- data/spec/support/shared_examples/only_operates_on_sets.rb +5 -3
- data/spec/support/shared_examples/only_operates_on_strings.rb +4 -4
- data/spec/support/shared_examples/only_operates_on_zsets.rb +18 -16
- data/spec/support/shared_examples/sorts_enumerables.rb +56 -0
- data/spec/transactions_spec.rb +79 -29
- metadata +162 -42
- data/LICENSE +0 -19
- data/spec/commands/hash_operator_spec.rb +0 -21
data/lib/mock_redis/database.rb
CHANGED
@@ -5,6 +5,13 @@ require 'mock_redis/list_methods'
|
|
5
5
|
require 'mock_redis/set_methods'
|
6
6
|
require 'mock_redis/string_methods'
|
7
7
|
require 'mock_redis/zset_methods'
|
8
|
+
require 'mock_redis/sort_method'
|
9
|
+
require 'mock_redis/indifferent_hash'
|
10
|
+
require 'mock_redis/info_method'
|
11
|
+
require 'mock_redis/utility_methods'
|
12
|
+
require 'mock_redis/geospatial_methods'
|
13
|
+
require 'mock_redis/stream_methods'
|
14
|
+
require 'mock_redis/connection_method'
|
8
15
|
|
9
16
|
class MockRedis
|
10
17
|
class Database
|
@@ -13,277 +20,157 @@ class MockRedis
|
|
13
20
|
include SetMethods
|
14
21
|
include StringMethods
|
15
22
|
include ZsetMethods
|
23
|
+
include SortMethod
|
24
|
+
include InfoMethod
|
25
|
+
include UtilityMethods
|
26
|
+
include GeospatialMethods
|
27
|
+
include StreamMethods
|
28
|
+
include ConnectionMethod
|
16
29
|
|
17
30
|
attr_reader :data, :expire_times
|
18
31
|
|
19
|
-
def initialize(*
|
20
|
-
@
|
32
|
+
def initialize(base, *_args)
|
33
|
+
@base = base
|
34
|
+
@data = MockRedis::IndifferentHash.new
|
21
35
|
@expire_times = []
|
22
36
|
end
|
23
37
|
|
24
|
-
def initialize_copy(
|
38
|
+
def initialize_copy(_source)
|
25
39
|
@data = @data.clone
|
26
|
-
@data.
|
27
|
-
@expire_times = @expire_times.map
|
40
|
+
@data.each_key { |k| @data[k] = @data[k].clone }
|
41
|
+
@expire_times = @expire_times.map(&:clone)
|
28
42
|
end
|
29
43
|
|
30
44
|
# Redis commands go below this line and above 'private'
|
31
45
|
|
32
|
-
def auth(_)
|
46
|
+
def auth(_)
|
47
|
+
'OK'
|
48
|
+
end
|
49
|
+
|
50
|
+
def bgrewriteaof
|
51
|
+
'Background append only file rewriting started'
|
52
|
+
end
|
33
53
|
|
34
|
-
def
|
54
|
+
def bgsave
|
55
|
+
'Background saving started'
|
56
|
+
end
|
57
|
+
|
58
|
+
def disconnect
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
alias close disconnect
|
62
|
+
alias disconnect! close
|
35
63
|
|
36
|
-
def
|
64
|
+
def connected?
|
65
|
+
true
|
66
|
+
end
|
37
67
|
|
38
68
|
def dbsize
|
39
69
|
data.keys.length
|
40
70
|
end
|
41
71
|
|
42
72
|
def del(*keys)
|
73
|
+
keys = keys.flatten.map(&:to_s)
|
74
|
+
assert_has_args(keys, 'del')
|
75
|
+
|
43
76
|
keys.
|
44
|
-
find_all{|key| data[key]}.
|
45
|
-
each {|k| persist(k)}.
|
46
|
-
each {|k| data.delete(k)}.
|
77
|
+
find_all { |key| data[key] }.
|
78
|
+
each { |k| persist(k) }.
|
79
|
+
each { |k| data.delete(k) }.
|
47
80
|
length
|
48
81
|
end
|
82
|
+
alias unlink del
|
49
83
|
|
50
84
|
def echo(msg)
|
51
85
|
msg.to_s
|
52
86
|
end
|
53
87
|
|
54
88
|
def expire(key, seconds)
|
55
|
-
|
89
|
+
assert_valid_integer(seconds)
|
90
|
+
|
91
|
+
pexpire(key, seconds.to_i * 1000)
|
92
|
+
end
|
93
|
+
|
94
|
+
def pexpire(key, ms)
|
95
|
+
assert_valid_integer(ms)
|
96
|
+
|
97
|
+
now, miliseconds = @base.now
|
98
|
+
now_ms = (now * 1000) + miliseconds
|
99
|
+
pexpireat(key, now_ms + ms.to_i)
|
56
100
|
end
|
57
101
|
|
58
102
|
def expireat(key, timestamp)
|
59
|
-
|
60
|
-
raise Redis::CommandError, "ERR value is not an integer or out of range"
|
61
|
-
end
|
103
|
+
assert_valid_integer(timestamp)
|
62
104
|
|
63
|
-
|
64
|
-
|
105
|
+
pexpireat(key, timestamp.to_i * 1000)
|
106
|
+
end
|
107
|
+
|
108
|
+
def pexpireat(key, timestamp_ms)
|
109
|
+
assert_valid_integer(timestamp_ms)
|
110
|
+
|
111
|
+
if exists?(key)
|
112
|
+
timestamp = Rational(timestamp_ms.to_i, 1000)
|
113
|
+
set_expiration(key, @base.time_at(timestamp))
|
65
114
|
true
|
66
115
|
else
|
67
116
|
false
|
68
117
|
end
|
69
118
|
end
|
70
119
|
|
71
|
-
def exists(
|
72
|
-
data.
|
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
|
73
127
|
end
|
74
128
|
|
75
129
|
def flushdb
|
76
|
-
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
|
77
147
|
'OK'
|
78
148
|
end
|
79
149
|
|
80
|
-
def
|
81
|
-
astats = [
|
82
|
-
["2", "2699"],
|
83
|
-
["6", "1"],
|
84
|
-
["7", "1"],
|
85
|
-
["8", "17197"],
|
86
|
-
["9", "109875"],
|
87
|
-
["10", "94348"],
|
88
|
-
["11", "32580"],
|
89
|
-
["12", "52347"],
|
90
|
-
["13", "86475"],
|
91
|
-
["14", "58175"],
|
92
|
-
["15", "53408"],
|
93
|
-
["16", "876949"],
|
94
|
-
["17", "71157"],
|
95
|
-
["18", "5104"],
|
96
|
-
["19", "2705"],
|
97
|
-
["20", "2903"],
|
98
|
-
["21", "1024"],
|
99
|
-
["22", "2546"],
|
100
|
-
["23", "952"],
|
101
|
-
["24", "186080"],
|
102
|
-
["25", "611"],
|
103
|
-
["26", "40936"],
|
104
|
-
["27", "960"],
|
105
|
-
["28", "1323"],
|
106
|
-
["29", "14216"],
|
107
|
-
["30", "52412"],
|
108
|
-
["31", "21130"],
|
109
|
-
["32", "47959"],
|
110
|
-
["33", "6891"],
|
111
|
-
["34", "9712"],
|
112
|
-
["35", "3366"],
|
113
|
-
["36", "5737"],
|
114
|
-
["37", "11274"],
|
115
|
-
["38", "8057"],
|
116
|
-
["39", "2957"],
|
117
|
-
["40", "51200"],
|
118
|
-
["42", "8220"],
|
119
|
-
["43", "8278"],
|
120
|
-
["44", "6539"],
|
121
|
-
["45", "764"],
|
122
|
-
["47", "1018"],
|
123
|
-
["48", "19250"],
|
124
|
-
["49", "713"],
|
125
|
-
["51", "51"],
|
126
|
-
["53", "2"],
|
127
|
-
["55", "3922"],
|
128
|
-
["56", "153"],
|
129
|
-
["57", "614"],
|
130
|
-
["58", "1"],
|
131
|
-
["59", "1775"],
|
132
|
-
["61", "32865"],
|
133
|
-
["63", "2530"],
|
134
|
-
["64", "565"],
|
135
|
-
["65", "1322"],
|
136
|
-
["67", "1572"],
|
137
|
-
["69", "1421"],
|
138
|
-
["71", "1220"],
|
139
|
-
["72", "241"],
|
140
|
-
["73", "5432"],
|
141
|
-
["74", "1122"],
|
142
|
-
["75", "2555"],
|
143
|
-
["77", "1539"],
|
144
|
-
["78", "612"],
|
145
|
-
["79", "902"],
|
146
|
-
["81", "1678"],
|
147
|
-
["83", "51"],
|
148
|
-
["84", "612"],
|
149
|
-
["85", "706"],
|
150
|
-
["87", "410"],
|
151
|
-
["88", "5435"],
|
152
|
-
["89", "813"],
|
153
|
-
["90", "612"],
|
154
|
-
["93", "153"],
|
155
|
-
["94", "612"],
|
156
|
-
["96", "159"],
|
157
|
-
["97", "306"],
|
158
|
-
["99", "153"],
|
159
|
-
["101", "456"],
|
160
|
-
["103", "741"],
|
161
|
-
["105", "447"],
|
162
|
-
["107", "754"],
|
163
|
-
["109", "414"],
|
164
|
-
["111", "475"],
|
165
|
-
["113", "757"],
|
166
|
-
["115", "287"],
|
167
|
-
["117", "420"],
|
168
|
-
["118", "765"],
|
169
|
-
["119", "642"],
|
170
|
-
["120", "159"],
|
171
|
-
["121", "926"],
|
172
|
-
["122", "612"],
|
173
|
-
["123", "251"],
|
174
|
-
["125", "390"],
|
175
|
-
["127", "354"],
|
176
|
-
["128", "617"],
|
177
|
-
["129", "528"],
|
178
|
-
["131", "298"],
|
179
|
-
["132", "612"],
|
180
|
-
["133", "809"],
|
181
|
-
["135", "244"],
|
182
|
-
["136", "306"],
|
183
|
-
["137", "504"],
|
184
|
-
["139", "201"],
|
185
|
-
["141", "1124"],
|
186
|
-
["143", "139"],
|
187
|
-
["144", "159"],
|
188
|
-
["145", "1322"],
|
189
|
-
["147", "410"],
|
190
|
-
["149", "253"],
|
191
|
-
["151", "304"],
|
192
|
-
["153", "312"],
|
193
|
-
["155", "249"],
|
194
|
-
["157", "306"],
|
195
|
-
["159", "348"],
|
196
|
-
["161", "255"],
|
197
|
-
["163", "458"],
|
198
|
-
["165", "5"],
|
199
|
-
["167", "306"],
|
200
|
-
["168", "47"],
|
201
|
-
["169", "214"],
|
202
|
-
["171", "250"],
|
203
|
-
["173", "5"],
|
204
|
-
["177", "10"],
|
205
|
-
["179", "158"],
|
206
|
-
["181", "5"],
|
207
|
-
["183", "10"],
|
208
|
-
["185", "51"],
|
209
|
-
["187", "49"],
|
210
|
-
["191", "5"],
|
211
|
-
["192", "47"],
|
212
|
-
["193", "51"],
|
213
|
-
["197", "112"],
|
214
|
-
["199", "5"],
|
215
|
-
["201", "5"],
|
216
|
-
["203", "5"],
|
217
|
-
["209", "5"],
|
218
|
-
["213", "51"],
|
219
|
-
["217", "102"],
|
220
|
-
["225", "357"],
|
221
|
-
["229", "51"],
|
222
|
-
["233", "204"],
|
223
|
-
["237", "51"],
|
224
|
-
["239", "1"],
|
225
|
-
["247", "46"],
|
226
|
-
["255", "102"],
|
227
|
-
[">=256", "6201"],
|
228
|
-
]
|
229
|
-
|
230
|
-
{
|
231
|
-
"allocation_stats" => astats.map {|(a,b)| "#{a}=#{b}"}.join(','),
|
232
|
-
"aof_enabled" => "0",
|
233
|
-
"arch_bits" => "64",
|
234
|
-
"bgrewriteaof_in_progress" => "0",
|
235
|
-
"bgsave_in_progress" => "0",
|
236
|
-
"blocked_clients" => "0",
|
237
|
-
"changes_since_last_save" => "0",
|
238
|
-
"client_biggest_input_buf" => "0",
|
239
|
-
"client_longest_output_list" => "0",
|
240
|
-
"connected_clients" => "1",
|
241
|
-
"connected_slaves" => "0",
|
242
|
-
"db0" => "keys=8,expires=0",
|
243
|
-
"evicted_keys" => "0",
|
244
|
-
"expired_keys" => "0",
|
245
|
-
"hash_max_zipmap_entries" => "512",
|
246
|
-
"hash_max_zipmap_value" => "64",
|
247
|
-
"keyspace_hits" => "62645",
|
248
|
-
"keyspace_misses" => "29757",
|
249
|
-
"last_save_time" => "1310596333",
|
250
|
-
"loading" => "0",
|
251
|
-
"lru_clock" => "1036434",
|
252
|
-
"mem_fragmentation_ratio" => "2.04",
|
253
|
-
"multiplexing_api" => "kqueue",
|
254
|
-
"process_id" => "14508",
|
255
|
-
"pubsub_channels" => "0",
|
256
|
-
"pubsub_patterns" => "0",
|
257
|
-
"redis_git_dirty" => "0",
|
258
|
-
"redis_git_sha1" => "00000000",
|
259
|
-
"redis_version" => "2.2.11",
|
260
|
-
"role" => "master",
|
261
|
-
"total_commands_processed" => "196800",
|
262
|
-
"total_connections_received" => "4359",
|
263
|
-
"uptime_in_days" => "0",
|
264
|
-
"uptime_in_seconds" => "84215",
|
265
|
-
"use_tcmalloc" => "0",
|
266
|
-
"used_cpu_sys" => "5.54",
|
267
|
-
"used_cpu_sys_childrens" => "0.00",
|
268
|
-
"used_cpu_user" => "7.65",
|
269
|
-
"used_cpu_user_childrens" => "0.02",
|
270
|
-
"used_memory" => "931456",
|
271
|
-
"used_memory_human" => "909.62K",
|
272
|
-
"used_memory_rss" => "1904640",
|
273
|
-
"vm_enabled" => "0",
|
274
|
-
}
|
275
|
-
end
|
276
|
-
|
277
|
-
def keys(format)
|
150
|
+
def keys(format = '*')
|
278
151
|
data.keys.grep(redis_pattern_to_ruby_regex(format))
|
279
152
|
end
|
280
153
|
|
154
|
+
def scan(cursor, opts = {})
|
155
|
+
common_scan(data.keys, cursor, opts)
|
156
|
+
end
|
157
|
+
|
158
|
+
def scan_each(opts = {}, &block)
|
159
|
+
return to_enum(:scan_each, opts) unless block_given?
|
160
|
+
cursor = 0
|
161
|
+
loop do
|
162
|
+
cursor, keys = scan(cursor, opts)
|
163
|
+
keys.each(&block)
|
164
|
+
break if cursor == '0'
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
281
168
|
def lastsave
|
282
|
-
|
169
|
+
now.first
|
283
170
|
end
|
284
171
|
|
285
172
|
def persist(key)
|
286
|
-
if exists(key) && has_expiration?(key)
|
173
|
+
if exists?(key) && has_expiration?(key)
|
287
174
|
remove_expiration(key)
|
288
175
|
true
|
289
176
|
else
|
@@ -291,8 +178,8 @@ class MockRedis
|
|
291
178
|
end
|
292
179
|
end
|
293
180
|
|
294
|
-
def ping
|
295
|
-
|
181
|
+
def ping(response = 'PONG')
|
182
|
+
response
|
296
183
|
end
|
297
184
|
|
298
185
|
def quit
|
@@ -304,22 +191,27 @@ class MockRedis
|
|
304
191
|
end
|
305
192
|
|
306
193
|
def rename(key, newkey)
|
307
|
-
|
308
|
-
raise Redis::CommandError,
|
309
|
-
elsif key == newkey
|
310
|
-
raise Redis::CommandError, "ERR source and destination objects are the same"
|
194
|
+
unless data.include?(key)
|
195
|
+
raise Redis::CommandError, 'ERR no such key'
|
311
196
|
end
|
312
|
-
|
197
|
+
|
198
|
+
if key != newkey
|
199
|
+
data[newkey] = data.delete(key)
|
200
|
+
if has_expiration?(key)
|
201
|
+
set_expiration(newkey, expiration(key))
|
202
|
+
remove_expiration(key)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
313
206
|
'OK'
|
314
207
|
end
|
315
208
|
|
316
209
|
def renamenx(key, newkey)
|
317
|
-
|
318
|
-
raise Redis::CommandError,
|
319
|
-
elsif key == newkey
|
320
|
-
raise Redis::CommandError, "ERR source and destination objects are the same"
|
210
|
+
unless data.include?(key)
|
211
|
+
raise Redis::CommandError, 'ERR no such key'
|
321
212
|
end
|
322
|
-
|
213
|
+
|
214
|
+
if exists?(newkey)
|
323
215
|
false
|
324
216
|
else
|
325
217
|
rename(key, newkey)
|
@@ -332,15 +224,38 @@ class MockRedis
|
|
332
224
|
end
|
333
225
|
|
334
226
|
def ttl(key)
|
335
|
-
if
|
336
|
-
|
227
|
+
if !exists?(key)
|
228
|
+
-2
|
229
|
+
elsif has_expiration?(key)
|
230
|
+
now, = @base.now
|
231
|
+
expiration(key).to_i - now
|
337
232
|
else
|
338
233
|
-1
|
339
234
|
end
|
340
235
|
end
|
341
236
|
|
237
|
+
def pttl(key)
|
238
|
+
now, miliseconds = @base.now
|
239
|
+
now_ms = now * 1000 + miliseconds
|
240
|
+
|
241
|
+
if !exists?(key)
|
242
|
+
-2
|
243
|
+
elsif has_expiration?(key)
|
244
|
+
(expiration(key).to_r * 1000).to_i - now_ms
|
245
|
+
else
|
246
|
+
-1
|
247
|
+
end
|
248
|
+
end
|
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
|
+
|
342
257
|
def type(key)
|
343
|
-
if !exists(key)
|
258
|
+
if !exists?(key)
|
344
259
|
'none'
|
345
260
|
elsif hashy?(key)
|
346
261
|
'hash'
|
@@ -357,13 +272,26 @@ class MockRedis
|
|
357
272
|
end
|
358
273
|
end
|
359
274
|
|
275
|
+
def script(subcommand, *args); end
|
276
|
+
|
277
|
+
def evalsha(*args); end
|
278
|
+
|
279
|
+
def eval(*args); end
|
280
|
+
|
360
281
|
private
|
361
282
|
|
283
|
+
def assert_valid_integer(integer)
|
284
|
+
unless looks_like_integer?(integer.to_s)
|
285
|
+
raise Redis::CommandError, 'ERR value is not an integer or out of range'
|
286
|
+
end
|
287
|
+
integer
|
288
|
+
end
|
289
|
+
|
362
290
|
def assert_valid_timeout(timeout)
|
363
|
-
if !
|
364
|
-
raise Redis::CommandError,
|
291
|
+
if !looks_like_integer?(timeout.to_s)
|
292
|
+
raise Redis::CommandError, 'ERR timeout is not an integer or out of range'
|
365
293
|
elsif timeout < 0
|
366
|
-
raise Redis::CommandError,
|
294
|
+
raise Redis::CommandError, 'ERR timeout is negative'
|
367
295
|
end
|
368
296
|
timeout
|
369
297
|
end
|
@@ -377,16 +305,24 @@ class MockRedis
|
|
377
305
|
end
|
378
306
|
|
379
307
|
def extract_timeout(arglist)
|
380
|
-
|
381
|
-
|
308
|
+
options = arglist.last
|
309
|
+
if options.is_a?(Hash) && options[:timeout]
|
310
|
+
timeout = assert_valid_timeout(options[:timeout])
|
311
|
+
[arglist[0..-2], timeout]
|
312
|
+
elsif options.is_a?(Integer)
|
313
|
+
timeout = assert_valid_timeout(options)
|
314
|
+
[arglist[0..-2], timeout]
|
315
|
+
else
|
316
|
+
[arglist, 0]
|
317
|
+
end
|
382
318
|
end
|
383
319
|
|
384
320
|
def expiration(key)
|
385
|
-
expire_times.find {|(_,k)| k == key}.first
|
321
|
+
expire_times.find { |(_, k)| k == key.to_s }.first
|
386
322
|
end
|
387
323
|
|
388
324
|
def has_expiration?(key)
|
389
|
-
expire_times.any? {|(_,k)| k == key}
|
325
|
+
expire_times.any? { |(_, k)| k == key.to_s }
|
390
326
|
end
|
391
327
|
|
392
328
|
def looks_like_integer?(str)
|
@@ -400,23 +336,23 @@ class MockRedis
|
|
400
336
|
def redis_pattern_to_ruby_regex(pattern)
|
401
337
|
Regexp.new(
|
402
338
|
"^#{pattern}$".
|
403
|
-
gsub(/([
|
404
|
-
gsub(/(
|
339
|
+
gsub(/([+|()])/, '\\\\\1').
|
340
|
+
gsub(/(?<!\\)\?/, '\\1.').
|
341
|
+
gsub(/([^\\])\*/, '\\1.*')
|
342
|
+
)
|
405
343
|
end
|
406
344
|
|
407
345
|
def remove_expiration(key)
|
408
|
-
expire_times.delete_if do |(
|
409
|
-
key == k
|
346
|
+
expire_times.delete_if do |(_t, k)|
|
347
|
+
key.to_s == k
|
410
348
|
end
|
411
349
|
end
|
412
350
|
|
413
351
|
def set_expiration(key, time)
|
414
352
|
remove_expiration(key)
|
415
|
-
|
416
|
-
|
417
|
-
expire_times.
|
418
|
-
a.first <=> b.first
|
419
|
-
end
|
353
|
+
found = expire_times.each_with_index.to_a.bsearch { |item, _| item.first >= time }
|
354
|
+
index = found ? found.last : -1
|
355
|
+
expire_times.insert(index, [time, key.to_s])
|
420
356
|
end
|
421
357
|
|
422
358
|
def zero_pad(string, desired_length)
|
@@ -425,20 +361,20 @@ class MockRedis
|
|
425
361
|
end
|
426
362
|
|
427
363
|
public
|
364
|
+
|
428
365
|
# This method isn't private, but it also isn't a Redis command, so
|
429
366
|
# it doesn't belong up above with all the Redis commands.
|
430
367
|
def expire_keys
|
431
|
-
|
368
|
+
now_sec, miliseconds = now
|
369
|
+
now_ms = now_sec * 1_000 + miliseconds
|
432
370
|
|
433
|
-
to_delete = expire_times.take_while do |(time,
|
434
|
-
time <=
|
371
|
+
to_delete = expire_times.take_while do |(time, _key)|
|
372
|
+
(time.to_r * 1_000).to_i <= now_ms
|
435
373
|
end
|
436
374
|
|
437
|
-
to_delete.each do |(
|
375
|
+
to_delete.each do |(_time, key)|
|
438
376
|
del(key)
|
439
377
|
end
|
440
|
-
|
441
|
-
expire_times.slice!(0, to_delete.length)
|
442
378
|
end
|
443
379
|
end
|
444
380
|
end
|
@@ -4,7 +4,7 @@ class MockRedis
|
|
4
4
|
class ExpireWrapper
|
5
5
|
include UndefRedisMethods
|
6
6
|
|
7
|
-
def respond_to?(method, include_private=false)
|
7
|
+
def respond_to?(method, include_private = false)
|
8
8
|
super || @db.respond_to?(method)
|
9
9
|
end
|
10
10
|
|
@@ -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
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class MockRedis
|
2
|
+
class FutureNotReady < RuntimeError; end
|
3
|
+
|
4
|
+
class Future
|
5
|
+
attr_reader :command, :block
|
6
|
+
|
7
|
+
def initialize(command, block = nil)
|
8
|
+
@command = command
|
9
|
+
@block = block
|
10
|
+
@result_set = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def value
|
14
|
+
raise FutureNotReady unless @result_set
|
15
|
+
@result
|
16
|
+
end
|
17
|
+
|
18
|
+
def store_result(result)
|
19
|
+
@result_set = true
|
20
|
+
@result = @block ? @block.call(result) : result
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|