redis 4.0.1 → 4.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +17 -29
- data/.travis/Gemfile +5 -0
- data/CHANGELOG.md +29 -0
- data/Gemfile +5 -0
- data/README.md +1 -1
- data/bin/build +71 -0
- data/lib/redis.rb +198 -12
- data/lib/redis/client.rb +26 -12
- data/lib/redis/cluster.rb +285 -0
- data/lib/redis/cluster/command.rb +81 -0
- data/lib/redis/cluster/command_loader.rb +32 -0
- data/lib/redis/cluster/key_slot_converter.rb +72 -0
- data/lib/redis/cluster/node.rb +104 -0
- data/lib/redis/cluster/node_key.rb +35 -0
- data/lib/redis/cluster/node_loader.rb +35 -0
- data/lib/redis/cluster/option.rb +76 -0
- data/lib/redis/cluster/slot.rb +69 -0
- data/lib/redis/cluster/slot_loader.rb +47 -0
- data/lib/redis/connection/ruby.rb +5 -2
- data/lib/redis/distributed.rb +10 -2
- data/lib/redis/errors.rb +46 -0
- data/lib/redis/pipeline.rb +9 -1
- data/lib/redis/version.rb +1 -1
- data/makefile +54 -22
- data/redis.gemspec +2 -1
- data/test/client_test.rb +17 -0
- data/test/cluster_abnormal_state_test.rb +38 -0
- data/test/cluster_blocking_commands_test.rb +15 -0
- data/test/cluster_client_internals_test.rb +77 -0
- data/test/cluster_client_key_hash_tags_test.rb +88 -0
- data/test/cluster_client_options_test.rb +147 -0
- data/test/cluster_client_pipelining_test.rb +59 -0
- data/test/cluster_client_replicas_test.rb +36 -0
- data/test/cluster_client_slots_test.rb +94 -0
- data/test/cluster_client_transactions_test.rb +71 -0
- data/test/cluster_commands_on_cluster_test.rb +165 -0
- data/test/cluster_commands_on_connection_test.rb +40 -0
- data/test/cluster_commands_on_geo_test.rb +74 -0
- data/test/cluster_commands_on_hashes_test.rb +11 -0
- data/test/cluster_commands_on_hyper_log_log_test.rb +17 -0
- data/test/cluster_commands_on_keys_test.rb +134 -0
- data/test/cluster_commands_on_lists_test.rb +15 -0
- data/test/cluster_commands_on_pub_sub_test.rb +101 -0
- data/test/cluster_commands_on_scripting_test.rb +56 -0
- data/test/cluster_commands_on_server_test.rb +221 -0
- data/test/cluster_commands_on_sets_test.rb +39 -0
- data/test/cluster_commands_on_sorted_sets_test.rb +35 -0
- data/test/cluster_commands_on_streams_test.rb +196 -0
- data/test/cluster_commands_on_strings_test.rb +15 -0
- data/test/cluster_commands_on_transactions_test.rb +41 -0
- data/test/cluster_commands_on_value_types_test.rb +14 -0
- data/test/commands_on_geo_test.rb +116 -0
- data/test/commands_on_hashes_test.rb +2 -14
- data/test/commands_on_hyper_log_log_test.rb +2 -14
- data/test/commands_on_lists_test.rb +2 -13
- data/test/commands_on_sets_test.rb +2 -70
- data/test/commands_on_sorted_sets_test.rb +2 -145
- data/test/commands_on_strings_test.rb +2 -94
- data/test/commands_on_value_types_test.rb +36 -0
- data/test/distributed_blocking_commands_test.rb +8 -0
- data/test/distributed_commands_on_hashes_test.rb +16 -3
- data/test/distributed_commands_on_hyper_log_log_test.rb +8 -13
- data/test/distributed_commands_on_lists_test.rb +4 -5
- data/test/distributed_commands_on_sets_test.rb +45 -46
- data/test/distributed_commands_on_sorted_sets_test.rb +51 -8
- data/test/distributed_commands_on_strings_test.rb +10 -0
- data/test/distributed_commands_on_value_types_test.rb +36 -0
- data/test/helper.rb +176 -32
- data/test/internals_test.rb +20 -1
- data/test/lint/blocking_commands.rb +40 -16
- data/test/lint/hashes.rb +41 -0
- data/test/lint/hyper_log_log.rb +15 -1
- data/test/lint/lists.rb +16 -0
- data/test/lint/sets.rb +142 -0
- data/test/lint/sorted_sets.rb +183 -2
- data/test/lint/strings.rb +102 -0
- data/test/pipelining_commands_test.rb +8 -0
- data/test/support/cluster/orchestrator.rb +199 -0
- data/test/support/redis_mock.rb +1 -1
- data/test/transactions_test.rb +10 -0
- metadata +81 -2
@@ -267,7 +267,10 @@ class Redis
|
|
267
267
|
ssl_sock = new(tcp_sock, ctx)
|
268
268
|
ssl_sock.hostname = host
|
269
269
|
ssl_sock.connect
|
270
|
-
|
270
|
+
|
271
|
+
unless ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE
|
272
|
+
ssl_sock.post_connection_check(host)
|
273
|
+
end
|
271
274
|
|
272
275
|
ssl_sock
|
273
276
|
end
|
@@ -294,7 +297,7 @@ class Redis
|
|
294
297
|
end
|
295
298
|
|
296
299
|
instance = new(sock)
|
297
|
-
instance.timeout = config[:
|
300
|
+
instance.timeout = config[:read_timeout]
|
298
301
|
instance.write_timeout = config[:write_timeout]
|
299
302
|
instance.set_tcp_keepalive config[:tcp_keepalive]
|
300
303
|
instance
|
data/lib/redis/distributed.rb
CHANGED
@@ -161,6 +161,14 @@ class Redis
|
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|
164
|
+
# Unlink keys.
|
165
|
+
def unlink(*args)
|
166
|
+
keys_per_node = args.group_by { |key| node_for(key) }
|
167
|
+
keys_per_node.inject(0) do |sum, (node, keys)|
|
168
|
+
sum + node.unlink(*keys)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
164
172
|
# Determine if a key exists.
|
165
173
|
def exists(key)
|
166
174
|
node_for(key).exists(key)
|
@@ -692,8 +700,8 @@ class Redis
|
|
692
700
|
end
|
693
701
|
|
694
702
|
# Delete one or more hash fields.
|
695
|
-
def hdel(key,
|
696
|
-
node_for(key).hdel(key,
|
703
|
+
def hdel(key, *fields)
|
704
|
+
node_for(key).hdel(key, *fields)
|
697
705
|
end
|
698
706
|
|
699
707
|
# Determine if a hash field exists.
|
data/lib/redis/errors.rb
CHANGED
@@ -37,4 +37,50 @@ class Redis
|
|
37
37
|
# Raised when the connection was inherited by a child process.
|
38
38
|
class InheritedError < BaseConnectionError
|
39
39
|
end
|
40
|
+
|
41
|
+
# Raised when client options are invalid.
|
42
|
+
class InvalidClientOptionError < BaseError
|
43
|
+
end
|
44
|
+
|
45
|
+
class Cluster
|
46
|
+
# Raised when client connected to redis as cluster mode
|
47
|
+
# and some cluster subcommands were called.
|
48
|
+
class OrchestrationCommandNotSupported < BaseError
|
49
|
+
def initialize(command, subcommand = '')
|
50
|
+
str = [command, subcommand].map(&:to_s).reject(&:empty?).join(' ').upcase
|
51
|
+
msg = "#{str} command should be used with care "\
|
52
|
+
'only by applications orchestrating Redis Cluster, like redis-trib, '\
|
53
|
+
'and the command if used out of the right context can leave the cluster '\
|
54
|
+
'in a wrong state or cause data loss.'
|
55
|
+
super(msg)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Raised when error occurs on any node of cluster.
|
60
|
+
class CommandErrorCollection < BaseError
|
61
|
+
attr_reader :errors
|
62
|
+
|
63
|
+
# @param errors [Hash{String => Redis::CommandError}]
|
64
|
+
# @param error_message [String]
|
65
|
+
def initialize(errors, error_message = 'Command errors were replied on any node')
|
66
|
+
@errors = errors
|
67
|
+
super(error_message)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Raised when cluster client can't select node.
|
72
|
+
class AmbiguousNodeError < BaseError
|
73
|
+
def initialize(command)
|
74
|
+
super("Cluster client doesn't know which node the #{command} command should be sent to.")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Raised when commands in pipelining include cross slot keys.
|
79
|
+
class CrossSlotPipeliningError < BaseError
|
80
|
+
def initialize(keys)
|
81
|
+
super("Cluster client couldn't send pipelining to single node. "\
|
82
|
+
"The commands include cross slot keys. #{keys}")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
40
86
|
end
|
data/lib/redis/pipeline.rb
CHANGED
@@ -22,6 +22,10 @@ class Redis
|
|
22
22
|
@shutdown
|
23
23
|
end
|
24
24
|
|
25
|
+
def empty?
|
26
|
+
@futures.empty?
|
27
|
+
end
|
28
|
+
|
25
29
|
def call(command, &block)
|
26
30
|
# A pipeline that contains a shutdown should not raise ECONNRESET when
|
27
31
|
# the connection is gone.
|
@@ -86,7 +90,11 @@ class Redis
|
|
86
90
|
end
|
87
91
|
|
88
92
|
def commands
|
89
|
-
|
93
|
+
if empty?
|
94
|
+
[]
|
95
|
+
else
|
96
|
+
[[:multi]] + super + [[:exec]]
|
97
|
+
end
|
90
98
|
end
|
91
99
|
end
|
92
100
|
end
|
data/lib/redis/version.rb
CHANGED
data/makefile
CHANGED
@@ -1,33 +1,43 @@
|
|
1
|
-
TEST_FILES
|
2
|
-
REDIS_BRANCH
|
3
|
-
TMP
|
4
|
-
BUILD_DIR
|
5
|
-
TARBALL
|
6
|
-
BINARY
|
7
|
-
|
8
|
-
|
9
|
-
|
1
|
+
TEST_FILES := $(shell find ./test -name *_test.rb -type f)
|
2
|
+
REDIS_BRANCH ?= unstable
|
3
|
+
TMP := tmp
|
4
|
+
BUILD_DIR := ${TMP}/cache/redis-${REDIS_BRANCH}
|
5
|
+
TARBALL := ${TMP}/redis-${REDIS_BRANCH}.tar.gz
|
6
|
+
BINARY := ${BUILD_DIR}/src/redis-server
|
7
|
+
REDIS_CLIENT := ${BUILD_DIR}/src/redis-cli
|
8
|
+
REDIS_TRIB := ${BUILD_DIR}/src/redis-trib.rb
|
9
|
+
PID_PATH := ${BUILD_DIR}/redis.pid
|
10
|
+
SOCKET_PATH := ${BUILD_DIR}/redis.sock
|
11
|
+
PORT := 6381
|
12
|
+
CLUSTER_PORTS := 7000 7001 7002 7003 7004 7005
|
13
|
+
CLUSTER_PID_PATHS := $(addprefix ${TMP}/redis,$(addsuffix .pid,${CLUSTER_PORTS}))
|
14
|
+
CLUSTER_CONF_PATHS := $(addprefix ${TMP}/nodes,$(addsuffix .conf,${CLUSTER_PORTS}))
|
15
|
+
CLUSTER_ADDRS := $(addprefix 127.0.0.1:,${CLUSTER_PORTS})
|
10
16
|
|
11
|
-
|
17
|
+
define kill-redis
|
18
|
+
(ls $1 2> /dev/null && kill $$(cat $1) && rm -f $1) || true
|
19
|
+
endef
|
20
|
+
|
21
|
+
all:
|
12
22
|
make start
|
13
|
-
|
14
|
-
|
23
|
+
make start_cluster
|
24
|
+
make create_cluster
|
25
|
+
make test
|
15
26
|
make stop
|
27
|
+
make stop_cluster
|
16
28
|
|
17
29
|
${TMP}:
|
18
|
-
mkdir $@
|
30
|
+
mkdir -p $@
|
19
31
|
|
20
|
-
${
|
21
|
-
|
32
|
+
${BINARY}: ${TMP}
|
33
|
+
bin/build ${REDIS_BRANCH} $<
|
22
34
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
tar xf ${TARBALL} -C ${TMP}
|
27
|
-
cd ${BUILD_DIR} && make
|
35
|
+
test: ${TEST_FILES}
|
36
|
+
env SOCKET_PATH=${SOCKET_PATH} \
|
37
|
+
bundle exec ruby -v -e 'ARGV.each { |test_file| require test_file }' ${TEST_FILES}
|
28
38
|
|
29
39
|
stop:
|
30
|
-
(
|
40
|
+
$(call kill-redis,${PID_PATH})
|
31
41
|
|
32
42
|
start: ${BINARY}
|
33
43
|
${BINARY} \
|
@@ -36,7 +46,29 @@ start: ${BINARY}
|
|
36
46
|
--port ${PORT} \
|
37
47
|
--unixsocket ${SOCKET_PATH}
|
38
48
|
|
49
|
+
stop_cluster:
|
50
|
+
$(call kill-redis,${CLUSTER_PID_PATHS})
|
51
|
+
rm -f appendonly.aof || true
|
52
|
+
rm -f ${CLUSTER_CONF_PATHS} || true
|
53
|
+
|
54
|
+
start_cluster: ${BINARY}
|
55
|
+
for port in ${CLUSTER_PORTS}; do \
|
56
|
+
${BINARY} \
|
57
|
+
--daemonize yes \
|
58
|
+
--appendonly yes \
|
59
|
+
--cluster-enabled yes \
|
60
|
+
--cluster-config-file ${TMP}/nodes$$port.conf \
|
61
|
+
--cluster-node-timeout 5000 \
|
62
|
+
--pidfile ${TMP}/redis$$port.pid \
|
63
|
+
--port $$port \
|
64
|
+
--unixsocket ${TMP}/redis$$port.sock; \
|
65
|
+
done
|
66
|
+
|
67
|
+
create_cluster:
|
68
|
+
yes yes | ((bundle exec ruby ${REDIS_TRIB} create --replicas 1 ${CLUSTER_ADDRS}) || \
|
69
|
+
(${REDIS_CLIENT} --cluster create ${CLUSTER_ADDRS} --cluster-replicas 1))
|
70
|
+
|
39
71
|
clean:
|
40
72
|
(test -d ${BUILD_DIR} && cd ${BUILD_DIR}/src && make clean distclean) || true
|
41
73
|
|
42
|
-
.PHONY: test start
|
74
|
+
.PHONY: all test stop start stop_cluster start_cluster create_cluster clean
|
data/redis.gemspec
CHANGED
@@ -32,11 +32,12 @@ Gem::Specification.new do |s|
|
|
32
32
|
|
33
33
|
s.files = `git ls-files`.split("\n")
|
34
34
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
35
|
-
s.executables = `git ls-files --
|
35
|
+
s.executables = `git ls-files -- exe/*`.split("\n").map{ |f| File.basename(f) }
|
36
36
|
|
37
37
|
s.required_ruby_version = '>= 2.2.2'
|
38
38
|
|
39
39
|
s.add_development_dependency("test-unit", ">= 3.1.5")
|
40
|
+
s.add_development_dependency("mocha")
|
40
41
|
s.add_development_dependency("hiredis")
|
41
42
|
s.add_development_dependency("em-synchrony")
|
42
43
|
end
|
data/test/client_test.rb
CHANGED
@@ -56,4 +56,21 @@ class TestClient < Test::Unit::TestCase
|
|
56
56
|
|
57
57
|
assert_equal result, ["OK", 1]
|
58
58
|
end
|
59
|
+
|
60
|
+
def test_client_with_custom_connector
|
61
|
+
custom_connector = Class.new(Redis::Client::Connector) do
|
62
|
+
def resolve
|
63
|
+
@options[:host] = '127.0.0.5'
|
64
|
+
@options[:port] = '999'
|
65
|
+
@options
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
assert_raise_message(
|
70
|
+
'Error connecting to Redis on 127.0.0.5:999 (Errno::ECONNREFUSED)'
|
71
|
+
) do
|
72
|
+
new_redis = _new_client(connector: custom_connector)
|
73
|
+
new_redis.ping
|
74
|
+
end
|
75
|
+
end
|
59
76
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
# ruby -w -Itest test/cluster_abnormal_state_test.rb
|
6
|
+
class TestClusterAbnormalState < Test::Unit::TestCase
|
7
|
+
include Helper::Cluster
|
8
|
+
|
9
|
+
def test_the_state_of_cluster_down
|
10
|
+
redis_cluster_down do
|
11
|
+
assert_raise(Redis::CommandError, 'CLUSTERDOWN Hash slot not served') do
|
12
|
+
redis.set('key1', 1)
|
13
|
+
end
|
14
|
+
|
15
|
+
assert_equal 'fail', redis.cluster(:info).fetch('cluster_state')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_the_state_of_cluster_failover
|
20
|
+
redis_cluster_failover do
|
21
|
+
100.times do |i|
|
22
|
+
assert_equal 'OK', r.set("key#{i}", i)
|
23
|
+
end
|
24
|
+
|
25
|
+
100.times do |i|
|
26
|
+
assert_equal i.to_s, r.get("key#{i}")
|
27
|
+
end
|
28
|
+
|
29
|
+
assert_equal 'ok', redis.cluster(:info).fetch('cluster_state')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_raising_error_when_nodes_are_not_cluster_mode
|
34
|
+
assert_raise(Redis::CannotConnectError, 'Redis client could not connect to any cluster nodes') do
|
35
|
+
build_another_client(cluster: %W[redis://127.0.0.1:#{PORT}])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
require_relative 'lint/blocking_commands'
|
5
|
+
|
6
|
+
# ruby -w -Itest test/cluster_blocking_commands_test.rb
|
7
|
+
class TestClusterBlockingCommands < Test::Unit::TestCase
|
8
|
+
include Helper::Cluster
|
9
|
+
include Lint::BlockingCommands
|
10
|
+
|
11
|
+
def mock(options = {}, &blk)
|
12
|
+
commands = build_mock_commands(options)
|
13
|
+
redis_cluster_mock(commands, &blk)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
# ruby -w -Itest test/cluster_client_internals_test.rb
|
6
|
+
class TestClusterClientInternals < Test::Unit::TestCase
|
7
|
+
include Helper::Cluster
|
8
|
+
|
9
|
+
def test_handle_multiple_servers
|
10
|
+
100.times { |i| redis.set(i.to_s, "hogehoge#{i}") }
|
11
|
+
100.times { |i| assert_equal "hogehoge#{i}", redis.get(i.to_s) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_info_of_cluster_mode_is_enabled
|
15
|
+
assert_equal '1', redis.info['cluster_enabled']
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_unknown_commands_does_not_work_by_default
|
19
|
+
assert_raise(Redis::CommandError) do
|
20
|
+
redis.not_yet_implemented_command('boo', 'foo')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_with_reconnect
|
25
|
+
assert_equal('Hello World', redis.with_reconnect { 'Hello World' })
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_without_reconnect
|
29
|
+
assert_equal('Hello World', redis.without_reconnect { 'Hello World' })
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_connected?
|
33
|
+
assert_equal true, redis.connected?
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_close
|
37
|
+
assert_equal true, redis.close
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_disconnect!
|
41
|
+
assert_equal true, redis.disconnect!
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_asking
|
45
|
+
assert_equal 'OK', redis.asking
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_id
|
49
|
+
expected = 'redis://127.0.0.1:7000/0 '\
|
50
|
+
'redis://127.0.0.1:7001/0 '\
|
51
|
+
'redis://127.0.0.1:7002/0'
|
52
|
+
assert_equal expected, redis.id
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_inspect
|
56
|
+
expected = "#<Redis client v#{Redis::VERSION} for "\
|
57
|
+
'redis://127.0.0.1:7000/0 '\
|
58
|
+
'redis://127.0.0.1:7001/0 '\
|
59
|
+
'redis://127.0.0.1:7002/0>'
|
60
|
+
|
61
|
+
assert_equal expected, redis.inspect
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_dup
|
65
|
+
assert_instance_of Redis, redis.dup
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_connection
|
69
|
+
expected = [
|
70
|
+
{ host: '127.0.0.1', port: 7000, db: 0, id: 'redis://127.0.0.1:7000/0', location: '127.0.0.1:7000' },
|
71
|
+
{ host: '127.0.0.1', port: 7001, db: 0, id: 'redis://127.0.0.1:7001/0', location: '127.0.0.1:7001' },
|
72
|
+
{ host: '127.0.0.1', port: 7002, db: 0, id: 'redis://127.0.0.1:7002/0', location: '127.0.0.1:7002' }
|
73
|
+
]
|
74
|
+
|
75
|
+
assert_equal expected, redis.connection
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
# ruby -w -Itest test/cluster_client_key_hash_tags_test.rb
|
6
|
+
class TestClusterClientKeyHashTags < Test::Unit::TestCase
|
7
|
+
include Helper::Cluster
|
8
|
+
|
9
|
+
def build_described_class
|
10
|
+
option = Redis::Cluster::Option.new(cluster: ['redis://127.0.0.1:7000'])
|
11
|
+
node = Redis::Cluster::Node.new(option.per_node_key)
|
12
|
+
details = Redis::Cluster::CommandLoader.load(node)
|
13
|
+
Redis::Cluster::Command.new(details)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_key_extraction
|
17
|
+
described_class = build_described_class
|
18
|
+
|
19
|
+
assert_equal 'dogs:1', described_class.extract_first_key(%w[get dogs:1])
|
20
|
+
assert_equal 'user1000', described_class.extract_first_key(%w[get {user1000}.following])
|
21
|
+
assert_equal 'user1000', described_class.extract_first_key(%w[get {user1000}.followers])
|
22
|
+
assert_equal 'foo{}{bar}', described_class.extract_first_key(%w[get foo{}{bar}])
|
23
|
+
assert_equal '{bar', described_class.extract_first_key(%w[get foo{{bar}}zap])
|
24
|
+
assert_equal 'bar', described_class.extract_first_key(%w[get foo{bar}{zap}])
|
25
|
+
|
26
|
+
assert_equal '', described_class.extract_first_key([:get, ''])
|
27
|
+
assert_equal '', described_class.extract_first_key([:get, nil])
|
28
|
+
assert_equal '', described_class.extract_first_key([:get])
|
29
|
+
|
30
|
+
assert_equal '', described_class.extract_first_key([:set, '', 1])
|
31
|
+
assert_equal '', described_class.extract_first_key([:set, nil, 1])
|
32
|
+
assert_equal '', described_class.extract_first_key([:set])
|
33
|
+
|
34
|
+
# Keyless commands
|
35
|
+
assert_equal '', described_class.extract_first_key([:auth, 'password'])
|
36
|
+
assert_equal '', described_class.extract_first_key(%i[client kill])
|
37
|
+
assert_equal '', described_class.extract_first_key(%i[cluster addslots])
|
38
|
+
assert_equal '', described_class.extract_first_key(%i[command])
|
39
|
+
assert_equal '', described_class.extract_first_key(%i[command count])
|
40
|
+
assert_equal '', described_class.extract_first_key(%i[config get])
|
41
|
+
assert_equal '', described_class.extract_first_key(%i[debug segfault])
|
42
|
+
assert_equal '', described_class.extract_first_key([:echo, 'Hello World'])
|
43
|
+
assert_equal '', described_class.extract_first_key([:flushall, 'ASYNC'])
|
44
|
+
assert_equal '', described_class.extract_first_key([:flushdb, 'ASYNC'])
|
45
|
+
assert_equal '', described_class.extract_first_key([:info, 'cluster'])
|
46
|
+
assert_equal '', described_class.extract_first_key(%i[memory doctor])
|
47
|
+
assert_equal '', described_class.extract_first_key([:ping, 'Hi'])
|
48
|
+
assert_equal '', described_class.extract_first_key([:psubscribe, 'channel'])
|
49
|
+
assert_equal '', described_class.extract_first_key([:pubsub, 'channels', '*'])
|
50
|
+
assert_equal '', described_class.extract_first_key([:publish, 'channel', 'Hi'])
|
51
|
+
assert_equal '', described_class.extract_first_key([:punsubscribe, 'channel'])
|
52
|
+
assert_equal '', described_class.extract_first_key([:subscribe, 'channel'])
|
53
|
+
assert_equal '', described_class.extract_first_key([:unsubscribe, 'channel'])
|
54
|
+
assert_equal '', described_class.extract_first_key(%w[script exists sha1 sha1])
|
55
|
+
assert_equal '', described_class.extract_first_key([:select, 1])
|
56
|
+
assert_equal '', described_class.extract_first_key([:shutdown, 'SAVE'])
|
57
|
+
assert_equal '', described_class.extract_first_key([:slaveof, '127.0.0.1', 6379])
|
58
|
+
assert_equal '', described_class.extract_first_key([:slowlog, 'get', 2])
|
59
|
+
assert_equal '', described_class.extract_first_key([:swapdb, 0, 1])
|
60
|
+
assert_equal '', described_class.extract_first_key([:wait, 1, 0])
|
61
|
+
|
62
|
+
# 2nd argument is not a key
|
63
|
+
assert_equal 'key1', described_class.extract_first_key([:eval, 'script', 2, 'key1', 'key2', 'first', 'second'])
|
64
|
+
assert_equal '', described_class.extract_first_key([:eval, 'return 0', 0])
|
65
|
+
assert_equal 'key1', described_class.extract_first_key([:evalsha, 'sha1', 2, 'key1', 'key2', 'first', 'second'])
|
66
|
+
assert_equal '', described_class.extract_first_key([:evalsha, 'return 0', 0])
|
67
|
+
assert_equal 'key1', described_class.extract_first_key([:migrate, '127.0.0.1', 6379, 'key1', 0, 5000])
|
68
|
+
assert_equal 'key1', described_class.extract_first_key([:memory, :usage, 'key1'])
|
69
|
+
assert_equal 'key1', described_class.extract_first_key([:object, 'refcount', 'key1'])
|
70
|
+
assert_equal 'mystream', described_class.extract_first_key([:xread, 'COUNT', 2, 'STREAMS', 'mystream', 0])
|
71
|
+
assert_equal 'mystream', described_class.extract_first_key([:xreadgroup, 'GROUP', 'mygroup', 'Bob', 'COUNT', 2, 'STREAMS', 'mystream', '>'])
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_whether_the_command_effect_is_readonly_or_not
|
75
|
+
described_class = build_described_class
|
76
|
+
|
77
|
+
assert_equal true, described_class.should_send_to_master?([:set])
|
78
|
+
assert_equal false, described_class.should_send_to_slave?([:set])
|
79
|
+
|
80
|
+
assert_equal false, described_class.should_send_to_master?([:get])
|
81
|
+
assert_equal true, described_class.should_send_to_slave?([:get])
|
82
|
+
|
83
|
+
target_version('3.2.0') do
|
84
|
+
assert_equal false, described_class.should_send_to_master?([:info])
|
85
|
+
assert_equal false, described_class.should_send_to_slave?([:info])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|