Skip to content

Commit a8456c2

Browse files
authored
Fixes for redis.call("info") (#338)
Previously `call(:info)` would fail: ``` > MockRedis.new.call :info (foo):3 in '<main>': undefined method 'i' for an instance of MockRedis::Database (NoMethodError) public_send(command[0].downcase, *command[1..]) ``` I fixed that by flattening the arguments passed to `Database#call` ... but noticed that actually, `call(:info)` ought to return a raw string rather than a parsed hash. How about something like this?
1 parent fe36515 commit a8456c2

File tree

3 files changed

+80
-30
lines changed

3 files changed

+80
-30
lines changed

lib/mock_redis/database.rb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,18 @@ def initialize_copy(_source)
4949
# i.e. `call("EXPIRE", "foo", 40, "NX")` (which redis-rb will simply transmit to redis-server)
5050
# will be passed to `#expire` without keywords transformation.
5151
def call(*command, &_block)
52-
# allow for single array argument or multiple arguments
53-
command = command[0] if command.length == 1
52+
# flatten any nested arrays (eg from [:call, ["GET", "X"]] in pipelined commands)
53+
command = command.flatten
5454

55-
if command[0].downcase.to_s.include?('expire')
55+
cmd_name = command[0].downcase.to_s
56+
57+
if cmd_name.include?('expire')
5658
send_expires(command)
59+
elsif cmd_name == 'info'
60+
# call(:info) returns a string, not a parsed hash
61+
info_raw(*command[1..])
5762
else
58-
public_send(command[0].downcase, *command[1..])
63+
public_send(cmd_name, *command[1..])
5964
end
6065
end
6166

lib/mock_redis/info_method.rb

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -125,35 +125,65 @@ module InfoMethod
125125
}.freeze
126126
# rubocop:enable Layout/LineLength
127127

128-
DEFAULT_INFO = [
129-
SERVER_INFO,
130-
CLIENTS_INFO,
131-
MEMORY_INFO,
132-
PERSISTENCE_INFO,
133-
STATS_INFO,
134-
REPLICATION_INFO,
135-
CPU_INFO,
136-
KEYSPACE_INFO,
137-
].inject({}) { |memo, info| memo.merge(info) }
138-
139-
ALL_INFO = [
140-
DEFAULT_INFO,
141-
COMMAND_STATS_COMBINED_INFO,
142-
].inject({}) { |memo, info| memo.merge(info) }
128+
SECTIONS = {
129+
server: SERVER_INFO,
130+
clients: CLIENTS_INFO,
131+
memory: MEMORY_INFO,
132+
persistence: PERSISTENCE_INFO,
133+
stats: STATS_INFO,
134+
replication: REPLICATION_INFO,
135+
cpu: CPU_INFO,
136+
keyspace: KEYSPACE_INFO,
137+
commandstats: COMMAND_STATS_COMBINED_INFO,
138+
}.freeze
139+
SECTION_NAMES = {
140+
server: 'Server',
141+
clients: 'Clients',
142+
memory: 'Memory',
143+
persistence: 'Persistence',
144+
stats: 'Stats',
145+
replication: 'Replication',
146+
cpu: 'Cpu',
147+
keyspace: 'Keyspace',
148+
commandstats: 'Commandstats',
149+
}.freeze
150+
DEFAULT_SECTIONS = [
151+
:server, :clients, :memory, :persistence, :stats, :replication, :cpu, :keyspace
152+
].freeze
153+
ALL_SECTIONS = DEFAULT_SECTIONS + [:commandstats].freeze
143154

144155
def info(section = :default)
156+
if section.to_s.downcase == 'commandstats'
157+
# `redis.info(:commandstats)` gives a nested hash structure,
158+
# unlike when commandstats is printed as part of `redis.info(:all)`
159+
COMMAND_STATS_SOLO_INFO
160+
else
161+
sections = relevant_info_sections(section)
162+
sections.inject({}) { |memo, name| memo.merge(SECTIONS[name]) }
163+
end
164+
end
165+
166+
private
167+
168+
# Format info hash as raw string (used by call("info"))
169+
def info_raw(section = :default)
170+
sections = relevant_info_sections(section)
171+
sections.map do |name|
172+
header = "# #{SECTION_NAMES[name]}"
173+
lines = SECTIONS[name].map { |k, v| "#{k}:#{v}" }
174+
[header, *lines].join("\n")
175+
end.join("\n\n") << "\n"
176+
end
177+
178+
def relevant_info_sections(section)
179+
section = section.to_s.downcase.to_sym
145180
case section
146-
when :default; DEFAULT_INFO
147-
when :all; ALL_INFO
148-
when :server; SERVER_INFO
149-
when :clients; CLIENTS_INFO
150-
when :memory; MEMORY_INFO
151-
when :persistence; PERSISTENCE_INFO
152-
when :stats; STATS_INFO
153-
when :replication; REPLICATION_INFO
154-
when :cpu; CPU_INFO
155-
when :keyspace; KEYSPACE_INFO
156-
when :commandstats; COMMAND_STATS_SOLO_INFO
181+
when :default
182+
DEFAULT_SECTIONS
183+
when :all
184+
ALL_SECTIONS
185+
else
186+
[section]
157187
end
158188
end
159189
end

spec/commands/info_spec.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,19 @@
5959
it 'gets commandstats info' do
6060
expect(redis.info(:commandstats)['sunionstore']['usec']).to be_a(String)
6161
end
62+
63+
it 'returns raw string when called through call method' do
64+
result = redis.call('info')
65+
expect(result).to be_a(String)
66+
expect(result).to include('# Server')
67+
expect(result).to include('arch_bits:64')
68+
end
69+
70+
it 'returns raw string with section when called through call method' do
71+
result = redis.call('info', 'server')
72+
expect(result).to be_a(String)
73+
expect(result).to include('# Server')
74+
expect(result).to include('arch_bits:64')
75+
expect(result).not_to include('# Clients')
76+
end
6277
end

0 commit comments

Comments
 (0)