twirl 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +75 -0
- data/Rakefile +1 -0
- data/examples/server.rb +37 -0
- data/lib/twirl.rb +8 -0
- data/lib/twirl/cluster.rb +317 -0
- data/lib/twirl/instrumentation/log_subscriber.rb +35 -0
- data/lib/twirl/instrumentation/statsd.rb +6 -0
- data/lib/twirl/instrumentation/statsd_subscriber.rb +28 -0
- data/lib/twirl/instrumentation/subscriber.rb +60 -0
- data/lib/twirl/instrumenters/memory.rb +26 -0
- data/lib/twirl/instrumenters/noop.rb +9 -0
- data/lib/twirl/item.rb +49 -0
- data/lib/twirl/server.rb +253 -0
- data/lib/twirl/version.rb +3 -0
- data/script/bootstrap +21 -0
- data/script/kestrel +34 -0
- data/script/release +42 -0
- data/script/test +25 -0
- data/script/watch +29 -0
- data/test/cluster_test.rb +469 -0
- data/test/helper.rb +65 -0
- data/test/instrumentation/log_subscriber_test.rb +51 -0
- data/test/instrumentation/statsd_test.rb +173 -0
- data/test/instrumenters/memory_test.rb +22 -0
- data/test/instrumenters/noop_test.rb +16 -0
- data/test/integration/cluster_test.rb +199 -0
- data/test/item_test.rb +43 -0
- data/test/support/fake_udp_socket.rb +27 -0
- data/test/twirl_test.rb +11 -0
- data/twirl.gemspec +23 -0
- metadata +121 -0
data/test/helper.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require "minitest/autorun"
|
2
|
+
require_relative "support/fake_udp_socket"
|
3
|
+
require "twirl/instrumenters/noop"
|
4
|
+
|
5
|
+
module ClusterTestHelpers
|
6
|
+
def build(what, *args)
|
7
|
+
send "build_#{what}", *args
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def build_item(key, value, client, instrumenter = nil)
|
13
|
+
Twirl::Item.new(key, value, client, instrumenter)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Builds a cluster that will connect to what script/kestrel starts.
|
17
|
+
def build_cluster(options = {})
|
18
|
+
clients = [
|
19
|
+
KJess::Client.new(host: "localhost", port: 9444),
|
20
|
+
KJess::Client.new(host: "localhost", port: 9544),
|
21
|
+
]
|
22
|
+
queue_names = Array(options.delete(:queues))
|
23
|
+
Twirl::Cluster.new(clients, options).tap { |cluster|
|
24
|
+
queue_names.each { |queue_name|
|
25
|
+
cluster.each { |client|
|
26
|
+
client.flush queue_name
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_mock_cluster(options = {})
|
33
|
+
number_of_clients = options.delete(:number_of_clients) || 3
|
34
|
+
clients = number_of_clients.times.map { Minitest::Mock.new }
|
35
|
+
|
36
|
+
Twirl::Cluster.new clients, options
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module StatsdTestHelpers
|
41
|
+
def assert_timer(socket, metric)
|
42
|
+
regex = /#{Regexp.escape metric}\:\d+\|ms/
|
43
|
+
assert socket.buffer.detect { |op| op.first =~ regex },
|
44
|
+
"Timer #{metric} was not found in #{socket.buffer.inspect}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def assert_counter(socket, metric)
|
48
|
+
assert socket.buffer.detect { |op| op.first == "#{metric}:1|c" },
|
49
|
+
"Counter #{metric} was not found in #{socket.buffer.inspect}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def assert_no_timer(socket, metric)
|
53
|
+
regex = /#{Regexp.escape metric}\:\d+\|ms/
|
54
|
+
assert_nil socket.buffer.detect { |op| op.first =~ regex },
|
55
|
+
"Timer #{metric} was found in #{socket.buffer.inspect}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def assert_no_counter(socket, metric)
|
59
|
+
assert_nil socket.buffer.detect { |op| op.first == "#{metric}:1|c" },
|
60
|
+
"Counter #{metric} was found in #{socket.buffer.inspect}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
Minitest::Test.send :include, ClusterTestHelpers
|
65
|
+
Minitest::Test.send :include, StatsdTestHelpers
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "helper"
|
2
|
+
require "logger"
|
3
|
+
require "twirl/instrumentation/log_subscriber"
|
4
|
+
|
5
|
+
class LogSubscriberInstrumentationTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@cluster = build(:cluster, {
|
8
|
+
instrumenter: ActiveSupport::Notifications,
|
9
|
+
queues: %w(testing),
|
10
|
+
})
|
11
|
+
@io = StringIO.new
|
12
|
+
logger = Logger.new(@io)
|
13
|
+
logger.formatter = proc { |severity, datetime, progname, msg| "#{msg}\n" }
|
14
|
+
Twirl::Instrumentation::LogSubscriber.logger = logger
|
15
|
+
end
|
16
|
+
|
17
|
+
def log
|
18
|
+
@io.string
|
19
|
+
end
|
20
|
+
|
21
|
+
def teardown
|
22
|
+
Twirl::Instrumentation::LogSubscriber.logger = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_set
|
26
|
+
@cluster.set "testing", "data"
|
27
|
+
line = find_line("Twirl op(set)")
|
28
|
+
assert_match %r{queue_name=testing bytes=4}, line
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_get
|
32
|
+
@cluster.set "testing", "data"
|
33
|
+
@cluster.get "testing"
|
34
|
+
line = find_line("Twirl op(get)")
|
35
|
+
assert_match %r{queue_name=testing bytes=4}, line
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_reserve
|
39
|
+
@cluster.set "testing", "data"
|
40
|
+
@cluster.reserve "testing"
|
41
|
+
line = find_line("Twirl op(reserve)")
|
42
|
+
assert_match %r{queue_name=testing bytes=4}, line
|
43
|
+
end
|
44
|
+
|
45
|
+
def find_line(str)
|
46
|
+
regex = /#{Regexp.escape(str)}/
|
47
|
+
lines = log.split("\n")
|
48
|
+
lines.detect { |line| line =~ regex } ||
|
49
|
+
raise("Could not find line matching #{str.inspect} in #{lines.inspect}")
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require "helper"
|
2
|
+
require "twirl/instrumentation/statsd"
|
3
|
+
|
4
|
+
class StatsdInstrumentationTest < Minitest::Test
|
5
|
+
def setup
|
6
|
+
@statsd = Statsd.new
|
7
|
+
@socket = FakeUDPSocket.new
|
8
|
+
@cluster = build(:cluster, {
|
9
|
+
instrumenter: ActiveSupport::Notifications,
|
10
|
+
queues: %w(testing),
|
11
|
+
})
|
12
|
+
Thread.current[:statsd_socket] = @socket
|
13
|
+
Twirl::Instrumentation::StatsdSubscriber.client = @statsd
|
14
|
+
end
|
15
|
+
|
16
|
+
def teardown
|
17
|
+
Thread.current[:statsd_socket] = nil
|
18
|
+
Twirl::Instrumentation::StatsdSubscriber.client = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_set
|
22
|
+
@cluster.set "testing", "data"
|
23
|
+
assert_timer @socket, "twirl.op_set"
|
24
|
+
assert_timer @socket, "twirl.queue_testing_op_set"
|
25
|
+
assert_counter @socket, "twirl.bytes_op_set"
|
26
|
+
assert_counter @socket, "twirl.bytes_queue_testing_op_set"
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_get
|
30
|
+
@cluster.set "testing", "data"
|
31
|
+
@cluster.get "testing"
|
32
|
+
assert_timer @socket, "twirl.op_get"
|
33
|
+
assert_timer @socket, "twirl.queue_testing_op_get"
|
34
|
+
assert_counter @socket, "twirl.bytes_op_get"
|
35
|
+
assert_counter @socket, "twirl.bytes_queue_testing_op_get"
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_item_close
|
39
|
+
@cluster.set "testing", "data"
|
40
|
+
item = @cluster.reserve("testing")
|
41
|
+
item.close
|
42
|
+
assert_timer @socket, "twirl.op_item_close"
|
43
|
+
assert_timer @socket, "twirl.queue_testing_op_item_close"
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_item_abort
|
47
|
+
@cluster.set "testing", "data"
|
48
|
+
item = @cluster.reserve("testing")
|
49
|
+
item.abort
|
50
|
+
assert_timer @socket, "twirl.op_item_abort"
|
51
|
+
assert_timer @socket, "twirl.queue_testing_op_item_abort"
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_reserve
|
55
|
+
@cluster.set "testing", "data"
|
56
|
+
@cluster.reserve "testing"
|
57
|
+
assert_timer @socket, "twirl.op_reserve"
|
58
|
+
assert_timer @socket, "twirl.queue_testing_op_reserve"
|
59
|
+
assert_counter @socket, "twirl.bytes_op_reserve"
|
60
|
+
assert_counter @socket, "twirl.bytes_queue_testing_op_reserve"
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_peek
|
64
|
+
@cluster.set "testing", "data"
|
65
|
+
@cluster.peek "testing"
|
66
|
+
assert_timer @socket, "twirl.op_peek"
|
67
|
+
assert_timer @socket, "twirl.queue_testing_op_peek"
|
68
|
+
assert_counter @socket, "twirl.bytes_op_peek"
|
69
|
+
assert_counter @socket, "twirl.bytes_queue_testing_op_peek"
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_delete
|
73
|
+
@cluster.delete "testing"
|
74
|
+
assert_timer @socket, "twirl.op_delete"
|
75
|
+
assert_timer @socket, "twirl.queue_testing_op_delete"
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_flush
|
79
|
+
@cluster.flush "testing"
|
80
|
+
assert_timer @socket, "twirl.op_flush"
|
81
|
+
assert_timer @socket, "twirl.queue_testing_op_flush"
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_flush_all
|
85
|
+
@cluster.flush_all
|
86
|
+
assert_timer @socket, "twirl.op_flush_all"
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_version
|
90
|
+
@cluster.version
|
91
|
+
assert_timer @socket, "twirl.op_version"
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_ping
|
95
|
+
@cluster.ping
|
96
|
+
assert_timer @socket, "twirl.op_ping"
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_quit
|
100
|
+
@cluster.quit
|
101
|
+
assert_timer @socket, "twirl.op_quit"
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_stats
|
105
|
+
@cluster.stats
|
106
|
+
assert_timer @socket, "twirl.op_stats"
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_disconnect
|
110
|
+
@cluster.disconnect
|
111
|
+
assert_timer @socket, "twirl.op_disconnect"
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_rotate
|
115
|
+
cluster = build(:cluster, {
|
116
|
+
commands_per_client: 1,
|
117
|
+
instrumenter: ActiveSupport::Notifications,
|
118
|
+
})
|
119
|
+
|
120
|
+
# set data to avoid nil rotation
|
121
|
+
cluster[0].set "testing", "data"
|
122
|
+
cluster[1].set "testing", "data"
|
123
|
+
cluster.get("testing")
|
124
|
+
cluster.get("testing")
|
125
|
+
|
126
|
+
assert_counter @socket, "twirl.op_rotate"
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_get_nil_instruments_rotate
|
130
|
+
@cluster.get("testing")
|
131
|
+
@cluster.get("testing")
|
132
|
+
|
133
|
+
assert_counter @socket, "twirl.op_rotate"
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_get_retries_instrumented
|
137
|
+
@cluster.get("testing")
|
138
|
+
assert_no_timer @socket, "twirl.retries_op_get"
|
139
|
+
|
140
|
+
# force all clients to error
|
141
|
+
@cluster.each do |client|
|
142
|
+
def client.get(*args)
|
143
|
+
raise KJess::NetworkError
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
begin
|
148
|
+
@cluster.get("testing")
|
149
|
+
flunk "Should raise error and not get here."
|
150
|
+
rescue KJess::NetworkError
|
151
|
+
assert_counter @socket, "twirl.retries_op_get"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_set_retries_instrumented
|
156
|
+
@cluster.set("testing", "data")
|
157
|
+
assert_no_timer @socket, "twirl.retries_op_set"
|
158
|
+
|
159
|
+
# force all clients to error
|
160
|
+
@cluster.each do |client|
|
161
|
+
def client.set(*args)
|
162
|
+
raise KJess::NetworkError
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
begin
|
167
|
+
@cluster.set("testing", "data")
|
168
|
+
flunk "Should raise error and not get here."
|
169
|
+
rescue KJess::NetworkError
|
170
|
+
assert_counter @socket, "twirl.retries_op_set"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "helper"
|
2
|
+
require "twirl/instrumenters/memory"
|
3
|
+
|
4
|
+
class MemoryInstrumenterTest < Minitest::Test
|
5
|
+
def test_initialize
|
6
|
+
instrumentor = Twirl::Instrumenters::Memory.new
|
7
|
+
assert_equal [], instrumentor.events
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_instrument
|
11
|
+
instrumentor = Twirl::Instrumenters::Memory.new
|
12
|
+
name = 'user.signup'
|
13
|
+
payload = {:email => 'john@doe.com'}
|
14
|
+
block_result = :yielded
|
15
|
+
|
16
|
+
result = instrumentor.instrument(name, payload) { block_result }
|
17
|
+
assert_equal block_result, result
|
18
|
+
|
19
|
+
event = Twirl::Instrumenters::Memory::Event.new(name, payload, block_result)
|
20
|
+
assert_equal [event], instrumentor.events
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "helper"
|
2
|
+
require "twirl/instrumenters/noop"
|
3
|
+
|
4
|
+
class NoopInstrumenterTest < Minitest::Test
|
5
|
+
def test_instrument
|
6
|
+
yielded = false
|
7
|
+
Twirl::Instrumenters::Noop.instrument(:foo) { yielded = true }
|
8
|
+
assert yielded
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_instrument_with_payload
|
12
|
+
yielded = false
|
13
|
+
Twirl::Instrumenters::Noop.instrument(:foo, pay: :load) { yielded = true }
|
14
|
+
assert yielded
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require "helper"
|
2
|
+
require "twirl/cluster"
|
3
|
+
|
4
|
+
class ClusterIntegrationTest < Minitest::Test
|
5
|
+
def test_set
|
6
|
+
cluster = build(:cluster, queues: %w(testing))
|
7
|
+
client = cluster[0]
|
8
|
+
cluster.set("testing", "data")
|
9
|
+
assert_equal "data", client.get("testing")
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_set_rotates
|
13
|
+
cluster = build(:cluster, commands_per_client: 1, queues: %w(testing))
|
14
|
+
client1 = cluster[0]
|
15
|
+
client2 = cluster[1]
|
16
|
+
cluster.set("testing", "data1")
|
17
|
+
cluster.set("testing", "data2")
|
18
|
+
cluster.set("testing", "data3")
|
19
|
+
cluster.set("testing", "data4")
|
20
|
+
|
21
|
+
results = []
|
22
|
+
assert_equal "data1", client1.get("testing")
|
23
|
+
assert_equal "data2", client2.get("testing")
|
24
|
+
assert_equal "data3", client1.get("testing")
|
25
|
+
assert_equal "data4", client2.get("testing")
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_get
|
29
|
+
cluster = build(:cluster, queues: %w(testing))
|
30
|
+
client1 = cluster[0]
|
31
|
+
client2 = cluster[1]
|
32
|
+
|
33
|
+
client1.set("testing", "data1")
|
34
|
+
client1.set("testing", "data2")
|
35
|
+
client2.set("testing", "data3")
|
36
|
+
|
37
|
+
results = []
|
38
|
+
results << cluster.get("testing")
|
39
|
+
results << cluster.get("testing")
|
40
|
+
results << cluster.get("testing")
|
41
|
+
results << cluster.get("testing")
|
42
|
+
results << cluster.get("testing")
|
43
|
+
|
44
|
+
assert_equal ["data1", "data2", nil, "data3", nil], results.map { |result| result.value if result }
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_get_when_item_reserved_raises_error
|
48
|
+
cluster = build(:cluster, queues: %w(testing))
|
49
|
+
client1 = cluster[0]
|
50
|
+
|
51
|
+
client1.set("testing", "data1")
|
52
|
+
cluster.get("testing", open: true)
|
53
|
+
|
54
|
+
assert_raises KJess::ClientError do
|
55
|
+
cluster.get("testing")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_reserve_with_item_close_and_item_abort
|
60
|
+
cluster = build(:cluster, queues: %w(testing))
|
61
|
+
client1 = cluster[0]
|
62
|
+
client2 = cluster[1]
|
63
|
+
|
64
|
+
client1.set("testing", "data1")
|
65
|
+
client2.set("testing", "data2")
|
66
|
+
|
67
|
+
item = cluster.reserve("testing")
|
68
|
+
assert_equal "data1", item.value
|
69
|
+
|
70
|
+
item.abort
|
71
|
+
item = cluster.reserve("testing")
|
72
|
+
assert_equal "data1", item.value
|
73
|
+
|
74
|
+
item.close
|
75
|
+
cluster.reserve("testing") # => nil, then rotate
|
76
|
+
item = cluster.reserve("testing")
|
77
|
+
assert_equal "data2", item.value
|
78
|
+
|
79
|
+
cluster.rotate_for_next_op # force rotation to client1
|
80
|
+
assert_nil cluster.reserve("testing") # client1 returns nil
|
81
|
+
item.close # close item hopefully with client2
|
82
|
+
assert_nil client2.get("testing") # make sure that client2 queue is empty
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_peek
|
86
|
+
cluster = build(:cluster, queues: %w(testing))
|
87
|
+
client1 = cluster[0]
|
88
|
+
client2 = cluster[1]
|
89
|
+
|
90
|
+
client1.set("testing", "data")
|
91
|
+
|
92
|
+
item = Twirl::Item.new("testing", "data", client1)
|
93
|
+
assert_equal item, cluster.peek("testing")
|
94
|
+
assert_equal "data", client1.get("testing")
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_peek_with_no_items
|
98
|
+
cluster = build(:cluster, queues: %w(testing))
|
99
|
+
assert_nil cluster.peek("testing")
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_version
|
103
|
+
cluster = build(:cluster)
|
104
|
+
expected = {
|
105
|
+
"localhost:9444" => "2.4.1",
|
106
|
+
"localhost:9544" => "2.4.1",
|
107
|
+
}
|
108
|
+
|
109
|
+
assert_equal expected, cluster.version
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_flush
|
113
|
+
cluster = build(:cluster, queues: %w(testing))
|
114
|
+
cluster.each do |client|
|
115
|
+
client.set("testing", "data")
|
116
|
+
end
|
117
|
+
cluster.flush("testing")
|
118
|
+
|
119
|
+
cluster.each do |client|
|
120
|
+
assert_nil client.get("testing")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_flush
|
125
|
+
cluster = build(:cluster, queues: %w(testing))
|
126
|
+
cluster.each { |client| client.set("testing", "data") }
|
127
|
+
cluster.flush("testing")
|
128
|
+
|
129
|
+
cluster.each do |client|
|
130
|
+
assert_nil client.get("testing")
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_flush_all
|
135
|
+
cluster = build(:cluster, queues: %w(testing))
|
136
|
+
cluster.each { |client| client.set("testing", "data") }
|
137
|
+
cluster.flush_all
|
138
|
+
|
139
|
+
cluster.each do |client|
|
140
|
+
assert_nil client.get("testing")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_disconnect
|
145
|
+
cluster = build(:cluster)
|
146
|
+
cluster.each(&:ping)
|
147
|
+
expected = [true] * cluster.size
|
148
|
+
assert_equal expected, cluster.map(&:connected?)
|
149
|
+
cluster.disconnect
|
150
|
+
expected = [false] * cluster.size
|
151
|
+
assert_equal expected, cluster.map(&:connected?)
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_quit
|
155
|
+
cluster = build(:cluster)
|
156
|
+
cluster.each(&:ping)
|
157
|
+
expected = [true] * cluster.size
|
158
|
+
assert_equal expected, cluster.map(&:connected?)
|
159
|
+
cluster.quit
|
160
|
+
expected = [false] * cluster.size
|
161
|
+
assert_equal expected, cluster.map(&:connected?)
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_delete
|
165
|
+
cluster = build(:cluster)
|
166
|
+
cluster.each do |client|
|
167
|
+
client.delete("testing")
|
168
|
+
client.set("testing", "data")
|
169
|
+
assert_instance_of Hash, client.queue_stats("testing")
|
170
|
+
end
|
171
|
+
cluster.delete("testing")
|
172
|
+
cluster.each do |client|
|
173
|
+
assert_nil client.queue_stats("testing")
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_ping
|
178
|
+
cluster = build(:cluster)
|
179
|
+
expected = {
|
180
|
+
"localhost:9444" => true,
|
181
|
+
"localhost:9544" => true,
|
182
|
+
}
|
183
|
+
|
184
|
+
assert_equal expected, cluster.ping
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_stats
|
188
|
+
cluster = build(:cluster)
|
189
|
+
result = cluster.stats
|
190
|
+
assert_equal [
|
191
|
+
"localhost:9444",
|
192
|
+
"localhost:9544",
|
193
|
+
], result.keys.sort
|
194
|
+
|
195
|
+
result.values.each do |value|
|
196
|
+
assert_instance_of Hash, value
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|