redis 3.3.5 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis/Gemfile +8 -1
  4. data/.travis.yml +34 -62
  5. data/CHANGELOG.md +45 -2
  6. data/Gemfile +5 -1
  7. data/README.md +32 -76
  8. data/benchmarking/logging.rb +1 -1
  9. data/bin/build +71 -0
  10. data/bors.toml +14 -0
  11. data/lib/redis/client.rb +38 -20
  12. data/lib/redis/cluster/command.rb +81 -0
  13. data/lib/redis/cluster/command_loader.rb +32 -0
  14. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  15. data/lib/redis/cluster/node.rb +104 -0
  16. data/lib/redis/cluster/node_key.rb +35 -0
  17. data/lib/redis/cluster/node_loader.rb +35 -0
  18. data/lib/redis/cluster/option.rb +76 -0
  19. data/lib/redis/cluster/slot.rb +69 -0
  20. data/lib/redis/cluster/slot_loader.rb +47 -0
  21. data/lib/redis/cluster.rb +285 -0
  22. data/lib/redis/connection/command_helper.rb +2 -8
  23. data/lib/redis/connection/hiredis.rb +2 -2
  24. data/lib/redis/connection/ruby.rb +13 -30
  25. data/lib/redis/connection/synchrony.rb +12 -4
  26. data/lib/redis/connection.rb +2 -2
  27. data/lib/redis/distributed.rb +29 -8
  28. data/lib/redis/errors.rb +46 -0
  29. data/lib/redis/hash_ring.rb +20 -64
  30. data/lib/redis/pipeline.rb +9 -7
  31. data/lib/redis/version.rb +1 -1
  32. data/lib/redis.rb +287 -52
  33. data/makefile +74 -0
  34. data/redis.gemspec +9 -10
  35. data/test/bitpos_test.rb +13 -19
  36. data/test/blocking_commands_test.rb +3 -5
  37. data/test/client_test.rb +18 -1
  38. data/test/cluster_abnormal_state_test.rb +38 -0
  39. data/test/cluster_blocking_commands_test.rb +15 -0
  40. data/test/cluster_client_internals_test.rb +77 -0
  41. data/test/cluster_client_key_hash_tags_test.rb +88 -0
  42. data/test/cluster_client_options_test.rb +147 -0
  43. data/test/cluster_client_pipelining_test.rb +59 -0
  44. data/test/cluster_client_replicas_test.rb +36 -0
  45. data/test/cluster_client_slots_test.rb +94 -0
  46. data/test/cluster_client_transactions_test.rb +71 -0
  47. data/test/cluster_commands_on_cluster_test.rb +165 -0
  48. data/test/cluster_commands_on_connection_test.rb +40 -0
  49. data/test/cluster_commands_on_geo_test.rb +74 -0
  50. data/test/cluster_commands_on_hashes_test.rb +11 -0
  51. data/test/cluster_commands_on_hyper_log_log_test.rb +17 -0
  52. data/test/cluster_commands_on_keys_test.rb +134 -0
  53. data/test/cluster_commands_on_lists_test.rb +15 -0
  54. data/test/cluster_commands_on_pub_sub_test.rb +101 -0
  55. data/test/cluster_commands_on_scripting_test.rb +56 -0
  56. data/test/cluster_commands_on_server_test.rb +221 -0
  57. data/test/cluster_commands_on_sets_test.rb +39 -0
  58. data/test/cluster_commands_on_sorted_sets_test.rb +35 -0
  59. data/test/cluster_commands_on_streams_test.rb +196 -0
  60. data/test/cluster_commands_on_strings_test.rb +15 -0
  61. data/test/cluster_commands_on_transactions_test.rb +41 -0
  62. data/test/cluster_commands_on_value_types_test.rb +14 -0
  63. data/test/command_map_test.rb +3 -5
  64. data/test/commands_on_geo_test.rb +116 -0
  65. data/test/commands_on_hashes_test.rb +2 -16
  66. data/test/commands_on_hyper_log_log_test.rb +3 -17
  67. data/test/commands_on_lists_test.rb +2 -15
  68. data/test/commands_on_sets_test.rb +2 -72
  69. data/test/commands_on_sorted_sets_test.rb +2 -132
  70. data/test/commands_on_strings_test.rb +2 -96
  71. data/test/commands_on_value_types_test.rb +80 -6
  72. data/test/connection_handling_test.rb +5 -7
  73. data/test/distributed_blocking_commands_test.rb +10 -4
  74. data/test/distributed_commands_on_hashes_test.rb +16 -5
  75. data/test/distributed_commands_on_hyper_log_log_test.rb +8 -15
  76. data/test/distributed_commands_on_lists_test.rb +4 -7
  77. data/test/distributed_commands_on_sets_test.rb +58 -36
  78. data/test/distributed_commands_on_sorted_sets_test.rb +51 -10
  79. data/test/distributed_commands_on_strings_test.rb +30 -10
  80. data/test/distributed_commands_on_value_types_test.rb +38 -4
  81. data/test/distributed_commands_requiring_clustering_test.rb +1 -3
  82. data/test/distributed_connection_handling_test.rb +1 -3
  83. data/test/distributed_internals_test.rb +8 -19
  84. data/test/distributed_key_tags_test.rb +4 -6
  85. data/test/distributed_persistence_control_commands_test.rb +1 -3
  86. data/test/distributed_publish_subscribe_test.rb +1 -3
  87. data/test/distributed_remote_server_control_commands_test.rb +1 -3
  88. data/test/distributed_scripting_test.rb +1 -3
  89. data/test/distributed_sorting_test.rb +1 -3
  90. data/test/distributed_test.rb +12 -14
  91. data/test/distributed_transactions_test.rb +1 -3
  92. data/test/encoding_test.rb +4 -8
  93. data/test/error_replies_test.rb +2 -4
  94. data/test/fork_safety_test.rb +1 -6
  95. data/test/helper.rb +179 -66
  96. data/test/helper_test.rb +1 -3
  97. data/test/internals_test.rb +47 -56
  98. data/test/lint/blocking_commands.rb +40 -16
  99. data/test/lint/hashes.rb +41 -0
  100. data/test/lint/hyper_log_log.rb +15 -1
  101. data/test/lint/lists.rb +16 -0
  102. data/test/lint/sets.rb +142 -0
  103. data/test/lint/sorted_sets.rb +183 -2
  104. data/test/lint/strings.rb +108 -20
  105. data/test/lint/value_types.rb +8 -0
  106. data/test/persistence_control_commands_test.rb +1 -3
  107. data/test/pipelining_commands_test.rb +12 -8
  108. data/test/publish_subscribe_test.rb +1 -3
  109. data/test/remote_server_control_commands_test.rb +60 -3
  110. data/test/scanning_test.rb +1 -7
  111. data/test/scripting_test.rb +1 -3
  112. data/test/sentinel_command_test.rb +1 -3
  113. data/test/sentinel_test.rb +1 -3
  114. data/test/sorting_test.rb +1 -3
  115. data/test/ssl_test.rb +45 -49
  116. data/test/support/cluster/orchestrator.rb +199 -0
  117. data/test/support/connection/hiredis.rb +1 -1
  118. data/test/support/connection/ruby.rb +1 -1
  119. data/test/support/connection/synchrony.rb +1 -1
  120. data/test/support/redis_mock.rb +1 -1
  121. data/test/synchrony_driver.rb +6 -9
  122. data/test/thread_safety_test.rb +1 -3
  123. data/test/transactions_test.rb +11 -3
  124. data/test/unknown_commands_test.rb +1 -3
  125. data/test/url_param_test.rb +44 -46
  126. metadata +109 -16
  127. data/Rakefile +0 -87
@@ -0,0 +1,221 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+
5
+ # ruby -w -Itest test/cluster_commands_on_server_test.rb
6
+ # @see https://redis.io/commands#server
7
+ class TestClusterCommandsOnServer < Test::Unit::TestCase
8
+ include Helper::Cluster
9
+
10
+ def test_bgrewriteaof
11
+ assert_equal 'Background append only file rewriting started', redis.bgrewriteaof
12
+ end
13
+
14
+ def test_bgsave
15
+ redis_cluster_mock(bgsave: ->(*_) { '+OK' }) do |redis|
16
+ assert_equal 'OK', redis.bgsave
17
+ end
18
+
19
+ err_msg = 'ERR An AOF log rewriting in progress: '\
20
+ "can't BGSAVE right now. "\
21
+ 'Use BGSAVE SCHEDULE in order to schedule a BGSAVE whenever possible.'
22
+
23
+ redis_cluster_mock(bgsave: ->(*_) { "-Error #{err_msg}" }) do |redis|
24
+ assert_raise(Redis::Cluster::CommandErrorCollection, 'Command error replied on any node') do
25
+ redis.bgsave
26
+ end
27
+ end
28
+ end
29
+
30
+ def test_client_kill
31
+ redis_cluster_mock(client: ->(*_) { '-Error ERR No such client' }) do |redis|
32
+ assert_raise(Redis::CommandError, 'ERR No such client') do
33
+ redis.client(:kill, '127.0.0.1:6379')
34
+ end
35
+ end
36
+
37
+ redis_cluster_mock(client: ->(*_) { '+OK' }) do |redis|
38
+ assert_equal 'OK', redis.client(:kill, '127.0.0.1:6379')
39
+ end
40
+ end
41
+
42
+ def test_client_list
43
+ a_client_info = redis.client(:list).first
44
+ actual = a_client_info.keys.sort
45
+ expected = %w[addr age cmd db events fd flags id idle multi name obl oll omem psub qbuf qbuf-free sub]
46
+ assert_equal expected, actual
47
+ end
48
+
49
+ def test_client_getname
50
+ redis.client(:setname, 'my-client-01')
51
+ assert_equal 'my-client-01', redis.client(:getname)
52
+ end
53
+
54
+ def test_client_pause
55
+ assert_equal 'OK', redis.client(:pause, 0)
56
+ end
57
+
58
+ def test_client_reply
59
+ target_version('3.2.0') do
60
+ assert_equal 'OK', redis.client(:reply, 'ON')
61
+ end
62
+ end
63
+
64
+ def test_client_setname
65
+ assert_equal 'OK', redis.client(:setname, 'my-client-01')
66
+ end
67
+
68
+ def test_command
69
+ assert_instance_of Array, redis.command
70
+ end
71
+
72
+ def test_command_count
73
+ assert_true(redis.command(:count) > 0)
74
+ end
75
+
76
+ def test_command_getkeys
77
+ assert_equal %w[a c e], redis.command(:getkeys, :mset, 'a', 'b', 'c', 'd', 'e', 'f')
78
+ end
79
+
80
+ def test_command_info
81
+ expected = [
82
+ ['get', 2, %w[readonly fast], 1, 1, 1],
83
+ ['set', -3, %w[write denyoom], 1, 1, 1],
84
+ ['eval', -3, %w[noscript movablekeys], 0, 0, 0]
85
+ ]
86
+ assert_equal expected, redis.command(:info, :get, :set, :eval)
87
+ end
88
+
89
+ def test_config_get
90
+ expected_keys = if version < '3.2.0'
91
+ %w[hash-max-ziplist-entries list-max-ziplist-entries set-max-intset-entries zset-max-ziplist-entries]
92
+ else
93
+ %w[hash-max-ziplist-entries set-max-intset-entries zset-max-ziplist-entries]
94
+ end
95
+
96
+ assert_equal expected_keys, redis.config(:get, '*max-*-entries*').keys.sort
97
+ end
98
+
99
+ def test_config_rewrite
100
+ redis_cluster_mock(config: ->(*_) { '-Error ERR Rewriting config file: Permission denied' }) do |redis|
101
+ assert_raise(Redis::Cluster::CommandErrorCollection, 'Command error replied on any node') do
102
+ redis.config(:rewrite)
103
+ end
104
+ end
105
+
106
+ redis_cluster_mock(config: ->(*_) { '+OK' }) do |redis|
107
+ assert_equal 'OK', redis.config(:rewrite)
108
+ end
109
+ end
110
+
111
+ def test_config_set
112
+ assert_equal 'OK', redis.config(:set, 'hash-max-ziplist-entries', 512)
113
+ end
114
+
115
+ def test_config_resetstat
116
+ assert_equal 'OK', redis.config(:resetstat)
117
+ end
118
+
119
+ def test_config_db_size
120
+ 10.times { |i| redis.set("key#{i}", 1) }
121
+ assert_equal 10, redis.dbsize
122
+ end
123
+
124
+ def test_debug_object
125
+ # DEBUG OBJECT is a debugging command that should not be used by clients.
126
+ end
127
+
128
+ def test_debug_segfault
129
+ # DEBUG SEGFAULT performs an invalid memory access that crashes Redis.
130
+ # It is used to simulate bugs during the development.
131
+ end
132
+
133
+ def test_flushall
134
+ assert_equal 'OK', redis.flushall
135
+ end
136
+
137
+ def test_flushdb
138
+ assert_equal 'OK', redis.flushdb
139
+ end
140
+
141
+ def test_info
142
+ assert_equal({ 'cluster_enabled' => '1' }, redis.info(:cluster))
143
+ end
144
+
145
+ def test_lastsave
146
+ assert_instance_of Array, redis.lastsave
147
+ end
148
+
149
+ def test_memory_doctor
150
+ target_version('4.0.0') do
151
+ assert_instance_of String, redis.memory(:doctor)
152
+ end
153
+ end
154
+
155
+ def test_memory_help
156
+ target_version('4.0.0') do
157
+ assert_instance_of Array, redis.memory(:help)
158
+ end
159
+ end
160
+
161
+ def test_memory_malloc_stats
162
+ target_version('4.0.0') do
163
+ assert_instance_of String, redis.memory('malloc-stats')
164
+ end
165
+ end
166
+
167
+ def test_memory_purge
168
+ target_version('4.0.0') do
169
+ assert_equal 'OK', redis.memory(:purge)
170
+ end
171
+ end
172
+
173
+ def test_memory_stats
174
+ target_version('4.0.0') do
175
+ assert_instance_of Array, redis.memory(:stats)
176
+ end
177
+ end
178
+
179
+ def test_memory_usage
180
+ target_version('4.0.0') do
181
+ redis.set('key1', 'Hello World')
182
+ assert_equal 61, redis.memory(:usage, 'key1')
183
+ end
184
+ end
185
+
186
+ def test_monitor
187
+ # Add MONITOR command test
188
+ end
189
+
190
+ def test_role
191
+ assert_equal %w[master master master], redis.role.map(&:first)
192
+ end
193
+
194
+ def test_save
195
+ assert_equal 'OK', redis.save
196
+ end
197
+
198
+ def test_shutdown
199
+ assert_raise(Redis::Cluster::OrchestrationCommandNotSupported, 'SHUTDOWN command should be...') do
200
+ redis.shutdown
201
+ end
202
+ end
203
+
204
+ def test_slaveof
205
+ assert_raise(Redis::CommandError, 'ERR SLAVEOF not allowed in cluster mode.') do
206
+ redis.slaveof(:no, :one)
207
+ end
208
+ end
209
+
210
+ def test_slowlog
211
+ assert_instance_of Array, redis.slowlog(:get, 1)
212
+ end
213
+
214
+ def test_sync
215
+ # Internal command used for replication
216
+ end
217
+
218
+ def test_time
219
+ assert_instance_of Array, redis.time
220
+ end
221
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+ require_relative 'lint/sets'
5
+
6
+ # ruby -w -Itest test/cluster_commands_on_sets_test.rb
7
+ # @see https://redis.io/commands#set
8
+ class TestClusterCommandsOnSets < Test::Unit::TestCase
9
+ include Helper::Cluster
10
+ include Lint::Sets
11
+
12
+ def test_sdiff
13
+ assert_raise(Redis::CommandError) { super }
14
+ end
15
+
16
+ def test_sdiffstore
17
+ assert_raise(Redis::CommandError) { super }
18
+ end
19
+
20
+ def test_sinter
21
+ assert_raise(Redis::CommandError) { super }
22
+ end
23
+
24
+ def test_sinterstore
25
+ assert_raise(Redis::CommandError) { super }
26
+ end
27
+
28
+ def test_smove
29
+ assert_raise(Redis::CommandError) { super }
30
+ end
31
+
32
+ def test_sunion
33
+ assert_raise(Redis::CommandError) { super }
34
+ end
35
+
36
+ def test_sunionstore
37
+ assert_raise(Redis::CommandError) { super }
38
+ end
39
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+ require_relative 'lint/sorted_sets'
5
+
6
+ # ruby -w -Itest test/cluster_commands_on_sorted_sets_test.rb
7
+ # @see https://redis.io/commands#sorted_set
8
+ class TestClusterCommandsOnSortedSets < Test::Unit::TestCase
9
+ include Helper::Cluster
10
+ include Lint::SortedSets
11
+
12
+ def test_zinterstore
13
+ assert_raise(Redis::CommandError) { super }
14
+ end
15
+
16
+ def test_zinterstore_with_aggregate
17
+ assert_raise(Redis::CommandError) { super }
18
+ end
19
+
20
+ def test_zinterstore_with_weights
21
+ assert_raise(Redis::CommandError) { super }
22
+ end
23
+
24
+ def test_zunionstore
25
+ assert_raise(Redis::CommandError) { super }
26
+ end
27
+
28
+ def test_zunionstore_with_aggregate
29
+ assert_raise(Redis::CommandError) { super }
30
+ end
31
+
32
+ def test_zunionstore_with_weights
33
+ assert_raise(Redis::CommandError) { super }
34
+ end
35
+ end
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+
5
+ # ruby -w -Itest test/cluster_commands_on_streams_test.rb
6
+ # @see https://redis.io/commands#stream
7
+ class TestClusterCommandsOnStreams < Test::Unit::TestCase
8
+ include Helper::Cluster
9
+
10
+ MIN_REDIS_VERSION = '4.9.0'
11
+ ENTRY_ID_FORMAT = /\d+-\d+/
12
+
13
+ def setup
14
+ super
15
+ add_some_entries_to_streams_without_hashtag
16
+ add_some_entries_to_streams_with_hashtag
17
+ end
18
+
19
+ def add_some_entries_to_streams_without_hashtag
20
+ target_version(MIN_REDIS_VERSION) do
21
+ redis.xadd('stream1', '*', 'name', 'John', 'surname', 'Connor')
22
+ redis.xadd('stream1', '*', 'name', 'Sarah', 'surname', 'Connor')
23
+ redis.xadd('stream1', '*', 'name', 'Miles', 'surname', 'Dyson')
24
+ redis.xadd('stream1', '*', 'name', 'Peter', 'surname', 'Silberman')
25
+ end
26
+ end
27
+
28
+ def add_some_entries_to_streams_with_hashtag
29
+ target_version(MIN_REDIS_VERSION) do
30
+ redis.xadd('{stream}1', '*', 'name', 'John', 'surname', 'Connor')
31
+ redis.xadd('{stream}1', '*', 'name', 'Sarah', 'surname', 'Connor')
32
+ redis.xadd('{stream}1', '*', 'name', 'Miles', 'surname', 'Dyson')
33
+ redis.xadd('{stream}1', '*', 'name', 'Peter', 'surname', 'Silberman')
34
+ end
35
+ end
36
+
37
+ def assert_stream_entry(actual, expected_name, expected_surname)
38
+ actual_key = actual.keys.first
39
+ actual_values = actual[actual_key]
40
+
41
+ assert_match ENTRY_ID_FORMAT, actual_key
42
+ assert_equal expected_name, actual_values['name']
43
+ assert_equal expected_surname, actual_values['surname']
44
+ end
45
+
46
+ def assert_stream_pending(actual, expected_size_of_group, expected_consumer_name, expected_size_of_consumer)
47
+ assert_equal expected_size_of_group, actual[:size]
48
+ assert_match ENTRY_ID_FORMAT, actual[:min_entry_id]
49
+ assert_match ENTRY_ID_FORMAT, actual[:max_entry_id]
50
+ assert_equal({ expected_consumer_name => expected_size_of_consumer }, actual[:consumers])
51
+ end
52
+
53
+ # TODO: Remove this helper method when we implement streams interfaces
54
+ def hashify_stream_entries(reply)
55
+ reply.map do |entry_id, values|
56
+ [entry_id, Hash[values.each_slice(2).to_a]]
57
+ end.to_h
58
+ end
59
+
60
+ # TODO: Remove this helper method when we implement streams interfaces
61
+ def hashify_streams(reply)
62
+ reply.map do |stream_key, entries|
63
+ [stream_key, hashify_stream_entries(entries)]
64
+ end.to_h
65
+ end
66
+
67
+ # TODO: Remove this helper method when we implement streams interfaces
68
+ def hashify_stream_pendings(reply)
69
+ {
70
+ size: reply.first,
71
+ min_entry_id: reply[1],
72
+ max_entry_id: reply[2],
73
+ consumers: Hash[reply[3]]
74
+ }
75
+ end
76
+
77
+ def test_xadd
78
+ target_version(MIN_REDIS_VERSION) do
79
+ assert_match ENTRY_ID_FORMAT, redis.xadd('mystream', '*', 'type', 'T-800', 'model', '101')
80
+ assert_match ENTRY_ID_FORMAT, redis.xadd('my{stream}', '*', 'type', 'T-1000')
81
+ end
82
+ end
83
+
84
+ def test_xrange
85
+ target_version(MIN_REDIS_VERSION) do
86
+ actual = redis.xrange('stream1', '-', '+', 'COUNT', 1)
87
+ actual = hashify_stream_entries(actual) # TODO: Remove this step when we implement streams interfaces
88
+ assert_stream_entry(actual, 'John', 'Connor')
89
+
90
+ actual = redis.xrange('{stream}1', '-', '+', 'COUNT', 1)
91
+ actual = hashify_stream_entries(actual) # TODO: Remove this step when we implement streams interfaces
92
+ assert_stream_entry(actual, 'John', 'Connor')
93
+ end
94
+ end
95
+
96
+ def test_xrevrange
97
+ target_version(MIN_REDIS_VERSION) do
98
+ actual = redis.xrevrange('stream1', '+', '-', 'COUNT', 1)
99
+ actual = hashify_stream_entries(actual) # TODO: Remove this step when we implement streams interfaces
100
+ assert_stream_entry(actual, 'Peter', 'Silberman')
101
+
102
+ actual = redis.xrevrange('{stream}1', '+', '-', 'COUNT', 1)
103
+ actual = hashify_stream_entries(actual) # TODO: Remove this step when we implement streams interfaces
104
+ assert_stream_entry(actual, 'Peter', 'Silberman')
105
+ end
106
+ end
107
+
108
+ def test_xlen
109
+ target_version(MIN_REDIS_VERSION) do
110
+ assert_equal 4, redis.xlen('stream1')
111
+ assert_equal 4, redis.xlen('{stream}1')
112
+ end
113
+ end
114
+
115
+ def test_xread
116
+ target_version(MIN_REDIS_VERSION) do
117
+ # non blocking without hashtag
118
+ actual = redis.xread('COUNT', 1, 'STREAMS', 'stream1', 0)
119
+ actual = hashify_streams(actual) # TODO: Remove this step when we implement streams interfaces
120
+ assert_equal 'stream1', actual.keys.first
121
+ assert_stream_entry(actual['stream1'], 'John', 'Connor')
122
+
123
+ # blocking without hashtag
124
+ actual = redis.xread('COUNT', 1, 'BLOCK', 1, 'STREAMS', 'stream1', 0)
125
+ actual = hashify_streams(actual) # TODO: Remove this step when we implement streams interfaces
126
+ assert_equal 'stream1', actual.keys.first
127
+ assert_stream_entry(actual['stream1'], 'John', 'Connor')
128
+
129
+ # non blocking with hashtag
130
+ actual = redis.xread('COUNT', 1, 'STREAMS', '{stream}1', 0)
131
+ actual = hashify_streams(actual) # TODO: Remove this step when we implement streams interfaces
132
+ assert_equal '{stream}1', actual.keys.first
133
+ assert_stream_entry(actual['{stream}1'], 'John', 'Connor')
134
+
135
+ # blocking with hashtag
136
+ actual = redis.xread('COUNT', 1, 'BLOCK', 1, 'STREAMS', '{stream}1', 0)
137
+ actual = hashify_streams(actual) # TODO: Remove this step when we implement streams interfaces
138
+ assert_equal '{stream}1', actual.keys.first
139
+ assert_stream_entry(actual['{stream}1'], 'John', 'Connor')
140
+ end
141
+ end
142
+
143
+ def test_xreadgroup
144
+ target_version(MIN_REDIS_VERSION) do
145
+ # non blocking without hashtag
146
+ redis.xgroup('create', 'stream1', 'mygroup1', '$')
147
+ add_some_entries_to_streams_without_hashtag
148
+ actual = redis.xreadgroup('GROUP', 'mygroup1', 'T-1000', 'COUNT', 1, 'STREAMS', 'stream1', '>')
149
+ actual = hashify_streams(actual) # TODO: Remove this step when we implement streams interfaces
150
+ assert_equal 'stream1', actual.keys.first
151
+ assert_stream_entry(actual['stream1'], 'John', 'Connor')
152
+
153
+ # blocking without hashtag
154
+ redis.xgroup('create', 'stream1', 'mygroup2', '$')
155
+ add_some_entries_to_streams_without_hashtag
156
+ actual = redis.xreadgroup('GROUP', 'mygroup2', 'T-800', 'COUNT', 1, 'BLOCK', 1, 'STREAMS', 'stream1', '>')
157
+ actual = hashify_streams(actual) # TODO: Remove this step when we implement streams interfaces
158
+ assert_equal 'stream1', actual.keys.first
159
+ assert_stream_entry(actual['stream1'], 'John', 'Connor')
160
+
161
+ # non blocking with hashtag
162
+ redis.xgroup('create', '{stream}1', 'mygroup3', '$')
163
+ add_some_entries_to_streams_with_hashtag
164
+ actual = redis.xreadgroup('GROUP', 'mygroup3', 'T-1000', 'COUNT', 1, 'STREAMS', '{stream}1', '>')
165
+ actual = hashify_streams(actual) # TODO: Remove this step when we implement streams interfaces
166
+ assert_equal '{stream}1', actual.keys.first
167
+ assert_stream_entry(actual['{stream}1'], 'John', 'Connor')
168
+
169
+ # blocking with hashtag
170
+ redis.xgroup('create', '{stream}1', 'mygroup4', '$')
171
+ add_some_entries_to_streams_with_hashtag
172
+ actual = redis.xreadgroup('GROUP', 'mygroup4', 'T-800', 'COUNT', 1, 'BLOCK', 1, 'STREAMS', '{stream}1', '>')
173
+ actual = hashify_streams(actual) # TODO: Remove this step when we implement streams interfaces
174
+ assert_equal '{stream}1', actual.keys.first
175
+ assert_stream_entry(actual['{stream}1'], 'John', 'Connor')
176
+ end
177
+ end
178
+
179
+ def test_xpending
180
+ target_version(MIN_REDIS_VERSION) do
181
+ redis.xgroup('create', 'stream1', 'mygroup1', '$')
182
+ add_some_entries_to_streams_without_hashtag
183
+ redis.xreadgroup('GROUP', 'mygroup1', 'T-800', 'COUNT', 1, 'STREAMS', 'stream1', '>')
184
+ actual = redis.xpending('stream1', 'mygroup1')
185
+ actual = hashify_stream_pendings(actual) # TODO: Remove this step when we implement streams interfaces
186
+ assert_stream_pending(actual, 1, 'T-800', '1')
187
+
188
+ redis.xgroup('create', '{stream}1', 'mygroup2', '$')
189
+ add_some_entries_to_streams_with_hashtag
190
+ redis.xreadgroup('GROUP', 'mygroup2', 'T-800', 'COUNT', 1, 'STREAMS', '{stream}1', '>')
191
+ actual = redis.xpending('{stream}1', 'mygroup2')
192
+ actual = hashify_stream_pendings(actual) # TODO: Remove this step when we implement streams interfaces
193
+ assert_stream_pending(actual, 1, 'T-800', '1')
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+ require_relative 'lint/strings'
5
+
6
+ # ruby -w -Itest test/cluster_commands_on_strings_test.rb
7
+ # @see https://redis.io/commands#string
8
+ class TestClusterCommandsOnStrings < Test::Unit::TestCase
9
+ include Helper::Cluster
10
+ include Lint::Strings
11
+
12
+ def mock(*args, &block)
13
+ redis_cluster_mock(*args, &block)
14
+ end
15
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+
5
+ # ruby -w -Itest test/cluster_commands_on_transactions_test.rb
6
+ # @see https://redis.io/commands#transactions
7
+ class TestClusterCommandsOnTransactions < Test::Unit::TestCase
8
+ include Helper::Cluster
9
+
10
+ def test_discard
11
+ assert_raise(Redis::Cluster::AmbiguousNodeError) do
12
+ redis.discard
13
+ end
14
+ end
15
+
16
+ def test_exec
17
+ assert_raise(Redis::Cluster::AmbiguousNodeError) do
18
+ redis.exec
19
+ end
20
+ end
21
+
22
+ def test_multi
23
+ assert_raise(Redis::Cluster::AmbiguousNodeError) do
24
+ redis.multi
25
+ end
26
+ end
27
+
28
+ def test_unwatch
29
+ assert_raise(Redis::Cluster::AmbiguousNodeError) do
30
+ redis.unwatch
31
+ end
32
+ end
33
+
34
+ def test_watch
35
+ assert_raise(Redis::CommandError, "CROSSSLOT Keys in request don't hash to the same slot") do
36
+ redis.watch('key1', 'key2')
37
+ end
38
+
39
+ assert_equal 'OK', redis.watch('{key}1', '{key}2')
40
+ end
41
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+ require_relative 'lint/value_types'
5
+
6
+ # ruby -w -Itest test/cluster_commands_on_value_types_test.rb
7
+ class TestClusterCommandsOnValueTypes < Test::Unit::TestCase
8
+ include Helper::Cluster
9
+ include Lint::ValueTypes
10
+
11
+ def test_move
12
+ assert_raise(Redis::CommandError) { super }
13
+ end
14
+ end
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class TestCommandMap < Test::Unit::TestCase
6
4
 
@@ -11,7 +9,7 @@ class TestCommandMap < Test::Unit::TestCase
11
9
 
12
10
  assert_equal 2, r.incr("counter")
13
11
 
14
- r.client.command_map[:incr] = :decr
12
+ r._client.command_map[:incr] = :decr
15
13
 
16
14
  assert_equal 1, r.incr("counter")
17
15
  end
@@ -23,7 +21,7 @@ class TestCommandMap < Test::Unit::TestCase
23
21
  r.idontexist("key")
24
22
  end
25
23
 
26
- r.client.command_map[:idontexist] = :get
24
+ r._client.command_map[:idontexist] = :get
27
25
 
28
26
  assert_equal "value", r.idontexist("key")
29
27
  end