redis 3.3.5 → 4.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.travis/Gemfile +8 -1
- data/.travis.yml +34 -62
- data/CHANGELOG.md +45 -2
- data/Gemfile +5 -1
- data/README.md +32 -76
- data/benchmarking/logging.rb +1 -1
- data/bin/build +71 -0
- data/bors.toml +14 -0
- data/lib/redis/client.rb +38 -20
- 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/cluster.rb +285 -0
- data/lib/redis/connection/command_helper.rb +2 -8
- data/lib/redis/connection/hiredis.rb +2 -2
- data/lib/redis/connection/ruby.rb +13 -30
- data/lib/redis/connection/synchrony.rb +12 -4
- data/lib/redis/connection.rb +2 -2
- data/lib/redis/distributed.rb +29 -8
- data/lib/redis/errors.rb +46 -0
- data/lib/redis/hash_ring.rb +20 -64
- data/lib/redis/pipeline.rb +9 -7
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +287 -52
- data/makefile +74 -0
- data/redis.gemspec +9 -10
- data/test/bitpos_test.rb +13 -19
- data/test/blocking_commands_test.rb +3 -5
- data/test/client_test.rb +18 -1
- 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/command_map_test.rb +3 -5
- data/test/commands_on_geo_test.rb +116 -0
- data/test/commands_on_hashes_test.rb +2 -16
- data/test/commands_on_hyper_log_log_test.rb +3 -17
- data/test/commands_on_lists_test.rb +2 -15
- data/test/commands_on_sets_test.rb +2 -72
- data/test/commands_on_sorted_sets_test.rb +2 -132
- data/test/commands_on_strings_test.rb +2 -96
- data/test/commands_on_value_types_test.rb +80 -6
- data/test/connection_handling_test.rb +5 -7
- data/test/distributed_blocking_commands_test.rb +10 -4
- data/test/distributed_commands_on_hashes_test.rb +16 -5
- data/test/distributed_commands_on_hyper_log_log_test.rb +8 -15
- data/test/distributed_commands_on_lists_test.rb +4 -7
- data/test/distributed_commands_on_sets_test.rb +58 -36
- data/test/distributed_commands_on_sorted_sets_test.rb +51 -10
- data/test/distributed_commands_on_strings_test.rb +30 -10
- data/test/distributed_commands_on_value_types_test.rb +38 -4
- data/test/distributed_commands_requiring_clustering_test.rb +1 -3
- data/test/distributed_connection_handling_test.rb +1 -3
- data/test/distributed_internals_test.rb +8 -19
- data/test/distributed_key_tags_test.rb +4 -6
- data/test/distributed_persistence_control_commands_test.rb +1 -3
- data/test/distributed_publish_subscribe_test.rb +1 -3
- data/test/distributed_remote_server_control_commands_test.rb +1 -3
- data/test/distributed_scripting_test.rb +1 -3
- data/test/distributed_sorting_test.rb +1 -3
- data/test/distributed_test.rb +12 -14
- data/test/distributed_transactions_test.rb +1 -3
- data/test/encoding_test.rb +4 -8
- data/test/error_replies_test.rb +2 -4
- data/test/fork_safety_test.rb +1 -6
- data/test/helper.rb +179 -66
- data/test/helper_test.rb +1 -3
- data/test/internals_test.rb +47 -56
- 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 +108 -20
- data/test/lint/value_types.rb +8 -0
- data/test/persistence_control_commands_test.rb +1 -3
- data/test/pipelining_commands_test.rb +12 -8
- data/test/publish_subscribe_test.rb +1 -3
- data/test/remote_server_control_commands_test.rb +60 -3
- data/test/scanning_test.rb +1 -7
- data/test/scripting_test.rb +1 -3
- data/test/sentinel_command_test.rb +1 -3
- data/test/sentinel_test.rb +1 -3
- data/test/sorting_test.rb +1 -3
- data/test/ssl_test.rb +45 -49
- data/test/support/cluster/orchestrator.rb +199 -0
- data/test/support/connection/hiredis.rb +1 -1
- data/test/support/connection/ruby.rb +1 -1
- data/test/support/connection/synchrony.rb +1 -1
- data/test/support/redis_mock.rb +1 -1
- data/test/synchrony_driver.rb +6 -9
- data/test/thread_safety_test.rb +1 -3
- data/test/transactions_test.rb +11 -3
- data/test/unknown_commands_test.rb +1 -3
- data/test/url_param_test.rb +44 -46
- metadata +109 -16
- data/Rakefile +0 -87
data/test/bitpos_test.rb
CHANGED
@@ -1,10 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require File.expand_path("helper", File.dirname(__FILE__))
|
4
|
-
|
5
|
-
unless defined?(Enumerator)
|
6
|
-
Enumerator = Enumerable::Enumerator
|
7
|
-
end
|
1
|
+
require_relative "helper"
|
8
2
|
|
9
3
|
class TestBitpos < Test::Unit::TestCase
|
10
4
|
|
@@ -13,48 +7,48 @@ class TestBitpos < Test::Unit::TestCase
|
|
13
7
|
def test_bitpos_empty_zero
|
14
8
|
target_version "2.9.11" do
|
15
9
|
r.del "foo"
|
16
|
-
assert_equal
|
10
|
+
assert_equal(0, r.bitpos("foo", 0))
|
17
11
|
end
|
18
12
|
end
|
19
13
|
|
20
14
|
def test_bitpos_empty_one
|
21
15
|
target_version "2.9.11" do
|
22
16
|
r.del "foo"
|
23
|
-
assert_equal
|
17
|
+
assert_equal(-1, r.bitpos("foo", 1))
|
24
18
|
end
|
25
19
|
end
|
26
20
|
|
27
21
|
def test_bitpos_zero
|
28
22
|
target_version "2.9.11" do
|
29
23
|
r.set "foo", "\xff\xf0\x00"
|
30
|
-
assert_equal
|
24
|
+
assert_equal(12, r.bitpos("foo", 0))
|
31
25
|
end
|
32
26
|
end
|
33
27
|
|
34
28
|
def test_bitpos_one
|
35
29
|
target_version "2.9.11" do
|
36
30
|
r.set "foo", "\x00\x0f\x00"
|
37
|
-
assert_equal
|
31
|
+
assert_equal(12, r.bitpos("foo", 1))
|
38
32
|
end
|
39
33
|
end
|
40
34
|
|
41
35
|
def test_bitpos_zero_end_is_given
|
42
36
|
target_version "2.9.11" do
|
43
37
|
r.set "foo", "\xff\xff\xff"
|
44
|
-
assert_equal
|
45
|
-
assert_equal
|
46
|
-
assert_equal
|
38
|
+
assert_equal(24, r.bitpos("foo", 0))
|
39
|
+
assert_equal(24, r.bitpos("foo", 0, 0))
|
40
|
+
assert_equal(-1, r.bitpos("foo", 0, 0, -1))
|
47
41
|
end
|
48
42
|
end
|
49
43
|
|
50
44
|
def test_bitpos_one_intervals
|
51
45
|
target_version "2.9.11" do
|
52
46
|
r.set "foo", "\x00\xff\x00"
|
53
|
-
assert_equal
|
54
|
-
assert_equal
|
55
|
-
assert_equal
|
56
|
-
assert_equal
|
57
|
-
assert_equal
|
47
|
+
assert_equal(8, r.bitpos("foo", 1, 0, -1))
|
48
|
+
assert_equal(8, r.bitpos("foo", 1, 1, -1))
|
49
|
+
assert_equal(-1, r.bitpos("foo", 1, 2, -1))
|
50
|
+
assert_equal(-1, r.bitpos("foo", 1, 2, 200))
|
51
|
+
assert_equal(8, r.bitpos("foo", 1, 1, 1))
|
58
52
|
end
|
59
53
|
end
|
60
54
|
|
@@ -1,7 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require File.expand_path("helper", File.dirname(__FILE__))
|
4
|
-
require "lint/blocking_commands"
|
1
|
+
require_relative "helper"
|
2
|
+
require_relative "lint/blocking_commands"
|
5
3
|
|
6
4
|
class TestBlockingCommands < Test::Unit::TestCase
|
7
5
|
|
@@ -17,7 +15,7 @@ class TestBlockingCommands < Test::Unit::TestCase
|
|
17
15
|
yield(r)
|
18
16
|
t2 = Time.now
|
19
17
|
|
20
|
-
assert timeout == r.
|
18
|
+
assert timeout == r._client.timeout
|
21
19
|
assert delay <= (t2 - t1)
|
22
20
|
end
|
23
21
|
end
|
data/test/client_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative "helper"
|
2
2
|
|
3
3
|
class TestClient < Test::Unit::TestCase
|
4
4
|
|
@@ -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
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
# ruby -w -Itest test/cluster_client_options_test.rb
|
6
|
+
class TestClusterClientOptions < Test::Unit::TestCase
|
7
|
+
include Helper::Cluster
|
8
|
+
|
9
|
+
def test_option_class
|
10
|
+
option = Redis::Cluster::Option.new(cluster: %w[rediss://127.0.0.1:7000], replica: true)
|
11
|
+
assert_equal({ '127.0.0.1:7000' => { url: 'rediss://127.0.0.1:7000' } }, option.per_node_key)
|
12
|
+
assert_equal true, option.secure?
|
13
|
+
assert_equal true, option.use_replica?
|
14
|
+
|
15
|
+
option = Redis::Cluster::Option.new(cluster: %w[redis://127.0.0.1:7000], replica: false)
|
16
|
+
assert_equal({ '127.0.0.1:7000' => { url: 'redis://127.0.0.1:7000' } }, option.per_node_key)
|
17
|
+
assert_equal false, option.secure?
|
18
|
+
assert_equal false, option.use_replica?
|
19
|
+
|
20
|
+
option = Redis::Cluster::Option.new(cluster: %w[redis://127.0.0.1:7000])
|
21
|
+
assert_equal({ '127.0.0.1:7000' => { url: 'redis://127.0.0.1:7000' } }, option.per_node_key)
|
22
|
+
assert_equal false, option.secure?
|
23
|
+
assert_equal false, option.use_replica?
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_client_accepts_valid_node_configs
|
27
|
+
nodes = ['redis://127.0.0.1:7000',
|
28
|
+
'redis://127.0.0.1:7001',
|
29
|
+
{ host: '127.0.0.1', port: '7002' },
|
30
|
+
{ 'host' => '127.0.0.1', port: 7003 },
|
31
|
+
'redis://127.0.0.1:7004',
|
32
|
+
'redis://127.0.0.1:7005']
|
33
|
+
|
34
|
+
assert_nothing_raised do
|
35
|
+
build_another_client(cluster: nodes)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_client_accepts_valid_options
|
40
|
+
assert_nothing_raised do
|
41
|
+
build_another_client(timeout: 1.0)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_client_ignores_invalid_options
|
46
|
+
assert_nothing_raised do
|
47
|
+
build_another_client(invalid_option: true)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_client_works_even_if_so_many_unavailable_nodes_specified
|
52
|
+
nodes = (6001..7005).map { |port| "redis://127.0.0.1:#{port}" }
|
53
|
+
redis = build_another_client(cluster: nodes)
|
54
|
+
|
55
|
+
assert_equal 'PONG', redis.ping
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_client_does_not_accept_db_specified_url
|
59
|
+
assert_raise(Redis::CannotConnectError, 'Could not connect to any nodes') do
|
60
|
+
build_another_client(cluster: ['redis://127.0.0.1:7000/1/namespace'])
|
61
|
+
end
|
62
|
+
|
63
|
+
assert_raise(Redis::CannotConnectError, 'Could not connect to any nodes') do
|
64
|
+
build_another_client(cluster: [{ host: '127.0.0.1', port: '7000' }], db: 1)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_client_does_not_accept_unconnectable_node_url_only
|
69
|
+
nodes = ['redis://127.0.0.1:7006']
|
70
|
+
|
71
|
+
assert_raise(Redis::CannotConnectError, 'Could not connect to any nodes') do
|
72
|
+
build_another_client(cluster: nodes)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_client_accepts_unconnectable_node_url_included
|
77
|
+
nodes = ['redis://127.0.0.1:7000', 'redis://127.0.0.1:7006']
|
78
|
+
|
79
|
+
assert_nothing_raised(Redis::CannotConnectError, 'Could not connect to any nodes') do
|
80
|
+
build_another_client(cluster: nodes)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_client_does_not_accept_http_scheme_url
|
85
|
+
nodes = ['http://127.0.0.1:80']
|
86
|
+
|
87
|
+
assert_raise(Redis::InvalidClientOptionError, "invalid uri scheme 'http'") do
|
88
|
+
build_another_client(cluster: nodes)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_client_does_not_accept_blank_included_config
|
93
|
+
nodes = ['']
|
94
|
+
|
95
|
+
assert_raise(Redis::InvalidClientOptionError, "invalid uri scheme ''") do
|
96
|
+
build_another_client(cluster: nodes)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_client_does_not_accept_bool_included_config
|
101
|
+
nodes = [true]
|
102
|
+
|
103
|
+
assert_raise(Redis::InvalidClientOptionError, "invalid uri scheme ''") do
|
104
|
+
build_another_client(cluster: nodes)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_client_does_not_accept_nil_included_config
|
109
|
+
nodes = [nil]
|
110
|
+
|
111
|
+
assert_raise(Redis::InvalidClientOptionError, "invalid uri scheme ''") do
|
112
|
+
build_another_client(cluster: nodes)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_client_does_not_accept_array_included_config
|
117
|
+
nodes = [[]]
|
118
|
+
|
119
|
+
assert_raise(Redis::InvalidClientOptionError, "invalid uri scheme ''") do
|
120
|
+
build_another_client(cluster: nodes)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_client_does_not_accept_empty_hash_included_config
|
125
|
+
nodes = [{}]
|
126
|
+
|
127
|
+
assert_raise(Redis::InvalidClientOptionError, 'Redis option of `cluster` must includes `:host` and `:port` keys') do
|
128
|
+
build_another_client(cluster: nodes)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_client_does_not_accept_object_included_config
|
133
|
+
nodes = [Object.new]
|
134
|
+
|
135
|
+
assert_raise(Redis::InvalidClientOptionError, 'Redis Cluster node config must includes String or Hash') do
|
136
|
+
build_another_client(cluster: nodes)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_client_does_not_accept_not_array_config
|
141
|
+
nodes = :not_array
|
142
|
+
|
143
|
+
assert_raise(Redis::InvalidClientOptionError, 'Redis Cluster node config must be Array') do
|
144
|
+
build_another_client(cluster: nodes)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
# ruby -w -Itest test/cluster_client_pipelining_test.rb
|
6
|
+
class TestClusterClientPipelining < Test::Unit::TestCase
|
7
|
+
include Helper::Cluster
|
8
|
+
|
9
|
+
def test_pipelining_with_a_hash_tag
|
10
|
+
p1 = p2 = p3 = p4 = p5 = p6 = nil
|
11
|
+
|
12
|
+
redis.pipelined do |r|
|
13
|
+
r.set('{Presidents.of.USA}:1', 'George Washington')
|
14
|
+
r.set('{Presidents.of.USA}:2', 'John Adams')
|
15
|
+
r.set('{Presidents.of.USA}:3', 'Thomas Jefferson')
|
16
|
+
r.set('{Presidents.of.USA}:4', 'James Madison')
|
17
|
+
r.set('{Presidents.of.USA}:5', 'James Monroe')
|
18
|
+
r.set('{Presidents.of.USA}:6', 'John Quincy Adams')
|
19
|
+
|
20
|
+
p1 = r.get('{Presidents.of.USA}:1')
|
21
|
+
p2 = r.get('{Presidents.of.USA}:2')
|
22
|
+
p3 = r.get('{Presidents.of.USA}:3')
|
23
|
+
p4 = r.get('{Presidents.of.USA}:4')
|
24
|
+
p5 = r.get('{Presidents.of.USA}:5')
|
25
|
+
p6 = r.get('{Presidents.of.USA}:6')
|
26
|
+
end
|
27
|
+
|
28
|
+
[p1, p2, p3, p4, p5, p6].each do |actual|
|
29
|
+
assert_true actual.is_a?(Redis::Future)
|
30
|
+
end
|
31
|
+
|
32
|
+
assert_equal('George Washington', p1.value)
|
33
|
+
assert_equal('John Adams', p2.value)
|
34
|
+
assert_equal('Thomas Jefferson', p3.value)
|
35
|
+
assert_equal('James Madison', p4.value)
|
36
|
+
assert_equal('James Monroe', p5.value)
|
37
|
+
assert_equal('John Quincy Adams', p6.value)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_pipelining_without_hash_tags
|
41
|
+
assert_raise(Redis::Cluster::CrossSlotPipeliningError) do
|
42
|
+
redis.pipelined do
|
43
|
+
redis.set(:a, 1)
|
44
|
+
redis.set(:b, 2)
|
45
|
+
redis.set(:c, 3)
|
46
|
+
redis.set(:d, 4)
|
47
|
+
redis.set(:e, 5)
|
48
|
+
redis.set(:f, 6)
|
49
|
+
|
50
|
+
redis.get(:a)
|
51
|
+
redis.get(:b)
|
52
|
+
redis.get(:c)
|
53
|
+
redis.get(:d)
|
54
|
+
redis.get(:e)
|
55
|
+
redis.get(:f)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
# ruby -w -Itest test/cluster_client_replicas_test.rb
|
6
|
+
class TestClusterClientReplicas < Test::Unit::TestCase
|
7
|
+
include Helper::Cluster
|
8
|
+
|
9
|
+
def test_client_can_command_with_replica
|
10
|
+
r = build_another_client(replica: true)
|
11
|
+
|
12
|
+
100.times do |i|
|
13
|
+
assert_equal 'OK', r.set("key#{i}", i)
|
14
|
+
end
|
15
|
+
|
16
|
+
100.times do |i|
|
17
|
+
assert_equal i.to_s, r.get("key#{i}")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_client_can_flush_with_replica
|
22
|
+
r = build_another_client(replica: true)
|
23
|
+
|
24
|
+
assert_equal 'OK', r.flushall
|
25
|
+
assert_equal 'OK', r.flushdb
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_some_reference_commands_are_sent_to_slaves_if_needed
|
29
|
+
r = build_another_client(replica: true)
|
30
|
+
|
31
|
+
5.times { |i| r.set("key#{i}", i) }
|
32
|
+
|
33
|
+
assert_equal %w[key0 key1 key2 key3 key4], r.keys
|
34
|
+
assert_equal 5, r.dbsize
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helper'
|
4
|
+
|
5
|
+
# ruby -w -Itest test/cluster_client_slots_test.rb
|
6
|
+
class TestClusterClientSlots < Test::Unit::TestCase
|
7
|
+
include Helper::Cluster
|
8
|
+
|
9
|
+
def test_slot_class
|
10
|
+
slot = Redis::Cluster::Slot.new('127.0.0.1:7000' => 1..10)
|
11
|
+
|
12
|
+
assert_equal false, slot.exists?(0)
|
13
|
+
assert_equal true, slot.exists?(1)
|
14
|
+
assert_equal true, slot.exists?(10)
|
15
|
+
assert_equal false, slot.exists?(11)
|
16
|
+
|
17
|
+
assert_equal nil, slot.find_node_key_of_master(0)
|
18
|
+
assert_equal nil, slot.find_node_key_of_slave(0)
|
19
|
+
assert_equal '127.0.0.1:7000', slot.find_node_key_of_master(1)
|
20
|
+
assert_equal '127.0.0.1:7000', slot.find_node_key_of_slave(1)
|
21
|
+
assert_equal '127.0.0.1:7000', slot.find_node_key_of_master(10)
|
22
|
+
assert_equal '127.0.0.1:7000', slot.find_node_key_of_slave(10)
|
23
|
+
assert_equal nil, slot.find_node_key_of_master(11)
|
24
|
+
assert_equal nil, slot.find_node_key_of_slave(11)
|
25
|
+
|
26
|
+
assert_equal nil, slot.put(1, '127.0.0.1:7001')
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_slot_class_with_node_flags_and_replicas
|
30
|
+
slot = Redis::Cluster::Slot.new({ '127.0.0.1:7000' => 1..10, '127.0.0.1:7001' => 1..10 },
|
31
|
+
{ '127.0.0.1:7000' => 'master', '127.0.0.1:7001' => 'slave' },
|
32
|
+
true)
|
33
|
+
|
34
|
+
assert_equal false, slot.exists?(0)
|
35
|
+
assert_equal true, slot.exists?(1)
|
36
|
+
assert_equal true, slot.exists?(10)
|
37
|
+
assert_equal false, slot.exists?(11)
|
38
|
+
|
39
|
+
assert_equal nil, slot.find_node_key_of_master(0)
|
40
|
+
assert_equal nil, slot.find_node_key_of_slave(0)
|
41
|
+
assert_equal '127.0.0.1:7000', slot.find_node_key_of_master(1)
|
42
|
+
assert_equal '127.0.0.1:7001', slot.find_node_key_of_slave(1)
|
43
|
+
assert_equal '127.0.0.1:7000', slot.find_node_key_of_master(10)
|
44
|
+
assert_equal '127.0.0.1:7001', slot.find_node_key_of_slave(10)
|
45
|
+
assert_equal nil, slot.find_node_key_of_master(11)
|
46
|
+
assert_equal nil, slot.find_node_key_of_slave(11)
|
47
|
+
|
48
|
+
assert_equal nil, slot.put(1, '127.0.0.1:7002')
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_slot_class_with_node_flags_and_without_replicas
|
52
|
+
slot = Redis::Cluster::Slot.new({ '127.0.0.1:7000' => 1..10, '127.0.0.1:7001' => 1..10 },
|
53
|
+
{ '127.0.0.1:7000' => 'master', '127.0.0.1:7001' => 'slave' },
|
54
|
+
false)
|
55
|
+
|
56
|
+
assert_equal false, slot.exists?(0)
|
57
|
+
assert_equal true, slot.exists?(1)
|
58
|
+
assert_equal true, slot.exists?(10)
|
59
|
+
assert_equal false, slot.exists?(11)
|
60
|
+
|
61
|
+
assert_equal nil, slot.find_node_key_of_master(0)
|
62
|
+
assert_equal nil, slot.find_node_key_of_slave(0)
|
63
|
+
assert_equal '127.0.0.1:7000', slot.find_node_key_of_master(1)
|
64
|
+
assert_equal '127.0.0.1:7000', slot.find_node_key_of_slave(1)
|
65
|
+
assert_equal '127.0.0.1:7000', slot.find_node_key_of_master(10)
|
66
|
+
assert_equal '127.0.0.1:7000', slot.find_node_key_of_slave(10)
|
67
|
+
assert_equal nil, slot.find_node_key_of_master(11)
|
68
|
+
assert_equal nil, slot.find_node_key_of_slave(11)
|
69
|
+
|
70
|
+
assert_equal nil, slot.put(1, '127.0.0.1:7002')
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_slot_class_with_empty_slots
|
74
|
+
slot = Redis::Cluster::Slot.new({})
|
75
|
+
|
76
|
+
assert_equal false, slot.exists?(0)
|
77
|
+
assert_equal false, slot.exists?(1)
|
78
|
+
|
79
|
+
assert_equal nil, slot.find_node_key_of_master(0)
|
80
|
+
assert_equal nil, slot.find_node_key_of_slave(0)
|
81
|
+
assert_equal nil, slot.find_node_key_of_master(1)
|
82
|
+
assert_equal nil, slot.find_node_key_of_slave(1)
|
83
|
+
|
84
|
+
assert_equal nil, slot.put(1, '127.0.0.1:7001')
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_redirection_when_slot_is_resharding
|
88
|
+
100.times { |i| redis.set("{key}#{i}", i) }
|
89
|
+
|
90
|
+
redis_cluster_resharding(12539, src: '127.0.0.1:7002', dest: '127.0.0.1:7000') do
|
91
|
+
100.times { |i| assert_equal i.to_s, redis.get("{key}#{i}") }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|