zk 0.9.1 → 1.0.0.rc.1
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.
- data/.gitignore +2 -2
- data/Gemfile +3 -4
- data/README.markdown +14 -5
- data/RELEASES.markdown +69 -1
- data/Rakefile +50 -18
- data/docs/examples/block_until_node_deleted_ex.rb +63 -0
- data/docs/examples/events_01.rb +36 -0
- data/docs/examples/events_02.rb +41 -0
- data/lib/{z_k → zk}/client/base.rb +87 -30
- data/lib/{z_k → zk}/client/conveniences.rb +0 -1
- data/lib/{z_k → zk}/client/state_mixin.rb +0 -0
- data/lib/zk/client/threaded.rb +196 -0
- data/lib/{z_k → zk}/client/unixisms.rb +0 -0
- data/lib/zk/client.rb +59 -0
- data/lib/zk/core_ext.rb +75 -0
- data/lib/{z_k → zk}/election.rb +0 -0
- data/lib/zk/event.rb +168 -0
- data/lib/{z_k → zk}/event_handler.rb +53 -28
- data/lib/zk/event_handler_subscription.rb +68 -0
- data/lib/{z_k → zk}/exceptions.rb +38 -23
- data/lib/zk/extensions.rb +79 -0
- data/lib/{z_k → zk}/find.rb +0 -0
- data/lib/{z_k → zk}/locker.rb +0 -0
- data/lib/{z_k → zk}/logging.rb +0 -0
- data/lib/{z_k → zk}/message_queue.rb +8 -4
- data/lib/{z_k → zk}/mongoid.rb +0 -0
- data/lib/{z_k → zk}/pool.rb +0 -0
- data/lib/zk/stat.rb +115 -0
- data/lib/{z_k → zk}/threadpool.rb +52 -4
- data/lib/zk/version.rb +3 -0
- data/lib/zk.rb +238 -1
- data/spec/message_queue_spec.rb +2 -2
- data/spec/shared/client_contexts.rb +8 -20
- data/spec/shared/client_examples.rb +136 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/support/event_catcher.rb +11 -0
- data/spec/support/exist_matcher.rb +6 -0
- data/spec/support/logging.rb +2 -1
- data/spec/watch_spec.rb +194 -10
- data/spec/{z_k → zk}/client/locking_and_session_death_spec.rb +0 -32
- data/spec/zk/client_spec.rb +23 -0
- data/spec/{z_k → zk}/election_spec.rb +0 -0
- data/spec/{z_k → zk}/extensions_spec.rb +0 -0
- data/spec/{z_k → zk}/locker_spec.rb +0 -40
- data/spec/zk/module_spec.rb +185 -0
- data/spec/{z_k → zk}/mongoid_spec.rb +0 -2
- data/spec/{z_k → zk}/pool_spec.rb +0 -2
- data/spec/{z_k → zk}/threadpool_spec.rb +32 -4
- data/spec/zookeeper_spec.rb +1 -6
- data/zk.gemspec +2 -2
- metadata +64 -56
- data/lib/z_k/client/continuation_proxy.rb +0 -109
- data/lib/z_k/client/drop_box.rb +0 -98
- data/lib/z_k/client/multiplexed.rb +0 -28
- data/lib/z_k/client/threaded.rb +0 -76
- data/lib/z_k/client.rb +0 -35
- data/lib/z_k/event_handler_subscription.rb +0 -36
- data/lib/z_k/extensions.rb +0 -155
- data/lib/z_k/version.rb +0 -3
- data/lib/z_k.rb +0 -97
- data/spec/z_k/client/drop_box_spec.rb +0 -90
- data/spec/z_k/client/multiplexed_spec.rb +0 -20
- data/spec/z_k/client_spec.rb +0 -7
data/lib/zk.rb
CHANGED
@@ -1,2 +1,239 @@
|
|
1
|
-
require
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'zookeeper'
|
5
|
+
require 'forwardable'
|
6
|
+
require 'thread'
|
7
|
+
require 'monitor'
|
8
|
+
require 'set'
|
9
|
+
require 'time'
|
10
|
+
require 'date'
|
11
|
+
|
12
|
+
require 'zk/core_ext'
|
13
|
+
require 'zk/logging'
|
14
|
+
require 'zk/exceptions'
|
15
|
+
require 'zk/extensions'
|
16
|
+
require 'zk/event'
|
17
|
+
require 'zk/stat'
|
18
|
+
require 'zk/threadpool'
|
19
|
+
require 'zk/event_handler_subscription'
|
20
|
+
require 'zk/event_handler'
|
21
|
+
require 'zk/message_queue'
|
22
|
+
require 'zk/locker'
|
23
|
+
require 'zk/election'
|
24
|
+
require 'zk/mongoid'
|
25
|
+
require 'zk/client'
|
26
|
+
require 'zk/pool'
|
27
|
+
require 'zk/find'
|
28
|
+
|
29
|
+
module ZK
|
30
|
+
silence_warnings do
|
31
|
+
# @private
|
32
|
+
ZK_ROOT = File.expand_path('../..', __FILE__).freeze
|
33
|
+
|
34
|
+
# @private
|
35
|
+
DEFAULT_SERVER = 'localhost:2181'.freeze
|
36
|
+
end
|
37
|
+
|
38
|
+
unless defined?(KILL_TOKEN)
|
39
|
+
# @private
|
40
|
+
KILL_TOKEN = Object.new
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
unless @logger
|
45
|
+
@logger = Logger.new($stderr).tap { |n| n.level = Logger::ERROR }
|
46
|
+
end
|
47
|
+
|
48
|
+
# The logger used by the ZK library. uses a Logger stderr with Logger::ERROR
|
49
|
+
# level. The only thing that should ever be logged are exceptions that are
|
50
|
+
# swallowed by background threads.
|
51
|
+
#
|
52
|
+
# You can change this logger by setting ZK#logger= to an object that
|
53
|
+
# implements the stdllb Logger API.
|
54
|
+
#
|
55
|
+
def self.logger
|
56
|
+
@logger
|
57
|
+
end
|
58
|
+
|
59
|
+
# Assign the Logger instance to be used by ZK
|
60
|
+
def self.logger=(logger)
|
61
|
+
@logger = logger
|
62
|
+
end
|
63
|
+
|
64
|
+
# Create a new ZK::Client instance. If no arguments are given, the default
|
65
|
+
# config of `localhost:2181` will be used. Otherwise all args will be passed
|
66
|
+
# to ZK::Client#new
|
67
|
+
#
|
68
|
+
# if a block is given, it will be yielded the client *before* the connection
|
69
|
+
# is established, this is useful for registering connected-state handlers.
|
70
|
+
#
|
71
|
+
# Since 1.0, if you pass a chrooted host string, i.e. `localhost:2181/foo/bar/baz` this
|
72
|
+
# method will create two connections. The first will be short lived, and will create the
|
73
|
+
# chroot path, the second will be the chrooted one and returned to the user. This is
|
74
|
+
# meant as a convenience to users who want to use chrooted connections.
|
75
|
+
#
|
76
|
+
# @note As it says in the ZooKeeper [documentation](http://zookeeper.apache.org/doc/r3.4.3/zookeeperProgrammers.html#ch_gotchas),
|
77
|
+
# if you are running a cluster: "The list of ZooKeeper servers used by the
|
78
|
+
# client must match the list of ZooKeeper servers that each ZooKeeper
|
79
|
+
# server has. Things can work, although not optimally, if the client list
|
80
|
+
# is a subset of the real list of ZooKeeper servers, but not if the client
|
81
|
+
# lists ZooKeeper servers not in the ZooKeeper cluster."
|
82
|
+
#
|
83
|
+
# @example Connection using defaults
|
84
|
+
#
|
85
|
+
# zk = ZK.new # will connect to 'localhost:2181'
|
86
|
+
#
|
87
|
+
# @example Connection to a single server
|
88
|
+
#
|
89
|
+
# zk = ZK.new('localhost:2181')
|
90
|
+
#
|
91
|
+
# @example Connection to a single server with a chroot (automatically created)
|
92
|
+
#
|
93
|
+
# zk = ZK.new('localhost:2181/look/around/you')
|
94
|
+
#
|
95
|
+
# @example Connection to multiple servers (a cluster)
|
96
|
+
#
|
97
|
+
# zk = ZK.new('server1:2181,server2:2181,server3:2181')
|
98
|
+
#
|
99
|
+
# @example Connection to multiple servers with a chroot (chroot will automatically be creatd)
|
100
|
+
#
|
101
|
+
# zk = ZK.new('server1:2181,server2:2181,server3:2181/look/around/you')
|
102
|
+
#
|
103
|
+
# @example Connection to a single server, assert that chroot path exists, but do not create it
|
104
|
+
#
|
105
|
+
# zk = ZK.new('localhost:2181/look/around/you', :chroot => :check)
|
106
|
+
#
|
107
|
+
# @example Connection to a single server, use a chrooted connection, do not check for validity, do not create
|
108
|
+
#
|
109
|
+
# zk = ZK.new('localhost:2181/look/around/you', :chroot => :do_nothing)
|
110
|
+
#
|
111
|
+
# @example Connection to a single server, chroot path specified as an option
|
112
|
+
#
|
113
|
+
# zk = ZK.new('localhost:2181', :chroot => '/look/around/you')
|
114
|
+
#
|
115
|
+
# @overload new(connection_str, opts={}, &block)
|
116
|
+
# @param [String] connection_str A zookeeper host connection string, which
|
117
|
+
# is a comma-separated list of zookeeper servers and an optional chroot
|
118
|
+
# path.
|
119
|
+
#
|
120
|
+
# @option opts [:create,:check,:do_nothing,String] :chroot (:create) if a chrooted
|
121
|
+
# `connection_str`, `:chroot` can have the following values:
|
122
|
+
#
|
123
|
+
# * `:create` (the default), then we will use a secondary (short-lived)
|
124
|
+
# un-chrooted connection to ensure that the path exists before returning
|
125
|
+
# the chrooted connection.
|
126
|
+
#
|
127
|
+
# * `:check`, we will not attempt to create the connection, but rather
|
128
|
+
# will raise a {Exceptions::ChrootPathDoesNotExistError
|
129
|
+
# ChrootPathDoesNotExistError} if the path doesn't exist.
|
130
|
+
#
|
131
|
+
# * `:do_nothing`, we do not create the path and furthermore we do not
|
132
|
+
# perform the check (the `<= 0.9` behavior).
|
133
|
+
#
|
134
|
+
# * if a `String` is given, it is used as the chroot path, and we will follow
|
135
|
+
# the same rules as if `:create` was given if `connection_str` also
|
136
|
+
# contains a chroot path, we raise an `ArgumentError`
|
137
|
+
#
|
138
|
+
# * if you don't like this for some reason, you can always use
|
139
|
+
# {ZK::Client::Threaded#initialize Threaded.new} directly. You probably
|
140
|
+
# also hate happiness and laughter.
|
141
|
+
#
|
142
|
+
# @raise [ChrootPathDoesNotExistError] if a chroot path is specified,
|
143
|
+
# `:chroot` is `:check`, and the path does not exist.
|
144
|
+
#
|
145
|
+
# @raise [ArgumentError] if both a chrooted `connection_str` is given *and* a
|
146
|
+
# `String` value for the `:chroot` option is given
|
147
|
+
#
|
148
|
+
def self.new(*args, &block)
|
149
|
+
opts = args.extract_options!
|
150
|
+
|
151
|
+
chroot_opt = opts.fetch(:chroot, :create)
|
152
|
+
|
153
|
+
args = [DEFAULT_SERVER] if args.empty? # the ZK.new() case
|
154
|
+
|
155
|
+
if args.first.kind_of?(String)
|
156
|
+
if new_cnx_str = do_chroot_setup(args.first, chroot_opt)
|
157
|
+
args[0] = new_cnx_str
|
158
|
+
end
|
159
|
+
else
|
160
|
+
raise ArgumentError, "cannot create a connection given args array: #{args}"
|
161
|
+
end
|
162
|
+
|
163
|
+
opts.delete(:chroot_opt)
|
164
|
+
|
165
|
+
args << opts
|
166
|
+
|
167
|
+
Client.new(*args, &block)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Like new, yields a connection to the given block and closes it when the
|
171
|
+
# block returns
|
172
|
+
def self.open(*args)
|
173
|
+
cnx = new(*args)
|
174
|
+
yield cnx
|
175
|
+
ensure
|
176
|
+
cnx.close! if cnx
|
177
|
+
end
|
178
|
+
|
179
|
+
# creates a new ZK::Pool::Bounded with the default options.
|
180
|
+
def self.new_pool(host, opts={})
|
181
|
+
ZK::Pool::Bounded.new(host, opts)
|
182
|
+
end
|
183
|
+
|
184
|
+
# @private
|
185
|
+
def self.join(*paths)
|
186
|
+
File.join(*paths)
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
# @return [String] a possibly modified connection string (with chroot info
|
191
|
+
# added)
|
192
|
+
#
|
193
|
+
def self.do_chroot_setup(cnx_str, chroot_opt=:create)
|
194
|
+
# "it should set up the chroot for us," they says.
|
195
|
+
# "it's confusing if it doesn't do that for us," they says.
|
196
|
+
# sheesh, look at this...
|
197
|
+
|
198
|
+
host, chroot_path = Client.split_chroot(cnx_str)
|
199
|
+
|
200
|
+
case chroot_opt
|
201
|
+
when :do_nothing
|
202
|
+
return
|
203
|
+
when String
|
204
|
+
if chroot_path
|
205
|
+
raise ArgumentError, "You cannot give a connection_str with a chroot path (#{cnx_str}) *and* specify a :chroot => #{chroot_opt} too!"
|
206
|
+
else
|
207
|
+
# ok, cnx_str didn't have a chroot path on it, but the user
|
208
|
+
# specified :chroot => '/path'. we'll use that, then
|
209
|
+
chroot_path = chroot_opt.dup
|
210
|
+
chroot_opt = :create
|
211
|
+
|
212
|
+
# oh, and return the correct string later
|
213
|
+
cnx_str = "#{host}#{chroot_path}"
|
214
|
+
end
|
215
|
+
when :create, :check
|
216
|
+
# no-op, valid options for later
|
217
|
+
else
|
218
|
+
raise ArgumentError, ":chroot must be one of :create, :check, :do_nothing, or a String, not: #{chroot_opt.inspect}"
|
219
|
+
end
|
220
|
+
|
221
|
+
return cnx_str unless chroot_path # if by this point, we don't have a chroot_path, then there isn't one to be had
|
222
|
+
|
223
|
+
# make sure the given path is kosher
|
224
|
+
Client.assert_valid_chroot_str!(chroot_path)
|
225
|
+
|
226
|
+
open(host) do |zk| # do path stuff with the virgin connection
|
227
|
+
unless zk.exists?(chroot_path) # someting must be done
|
228
|
+
if chroot_opt == :create # here, let me...
|
229
|
+
zk.mkdir_p(chroot_path) # ...get that for you
|
230
|
+
else # careful with that axe
|
231
|
+
raise Exceptions::ChrootPathDoesNotExistError.new(host, chroot_path) # ...eugene
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
cnx_str # the possibly-modified connection string (with chroot info)
|
237
|
+
end
|
238
|
+
end
|
2
239
|
|
data/spec/message_queue_spec.rb
CHANGED
@@ -3,8 +3,8 @@ require File.join(File.dirname(__FILE__), %w[spec_helper])
|
|
3
3
|
describe ZK::MessageQueue do
|
4
4
|
|
5
5
|
before(:each) do
|
6
|
-
@zk = ZK.new("localhost:#{ZK_TEST_PORT}"
|
7
|
-
@zk2 = ZK.new("localhost:#{ZK_TEST_PORT}"
|
6
|
+
@zk = ZK.new("localhost:#{ZK_TEST_PORT}")
|
7
|
+
@zk2 = ZK.new("localhost:#{ZK_TEST_PORT}")
|
8
8
|
wait_until{ @zk.connected? && @zk2.connected? }
|
9
9
|
@queue_name = "_specQueue"
|
10
10
|
@consume_queue = @zk.queue(@queue_name)
|
@@ -3,30 +3,18 @@ shared_context 'threaded client connection' do
|
|
3
3
|
@connection_string = "localhost:#{ZK_TEST_PORT}"
|
4
4
|
@base_path = '/zktests'
|
5
5
|
@zk = ZK::Client::Threaded.new(@connection_string).tap { |z| wait_until { z.connected? } }
|
6
|
+
@zk.on_exception { |e| raise e }
|
6
7
|
@zk.rm_rf(@base_path)
|
7
8
|
end
|
8
9
|
|
9
10
|
after do
|
10
|
-
@zk.
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
shared_context 'multiplexed client connection' do
|
18
|
-
before do
|
19
|
-
@connection_string = "localhost:#{ZK_TEST_PORT}"
|
20
|
-
@base_path = '/zktests'
|
21
|
-
@zk = ZK::Client::Multiplexed.new(@connection_string).tap { |z| wait_until { z.connected? } }
|
22
|
-
@zk.rm_rf(@base_path)
|
23
|
-
end
|
24
|
-
|
25
|
-
after do
|
26
|
-
@zk.rm_rf(@base_path)
|
27
|
-
@zk.close!
|
28
|
-
|
29
|
-
wait_until(2) { @zk.closed? }
|
11
|
+
if @zk.closed?
|
12
|
+
ZK.open(@connection_string) { |z| z.rm_rf(@base_path) }
|
13
|
+
else
|
14
|
+
@zk.rm_rf(@base_path)
|
15
|
+
@zk.close!
|
16
|
+
wait_until(2) { @zk.closed? }
|
17
|
+
end
|
30
18
|
end
|
31
19
|
end
|
32
20
|
|
@@ -3,6 +3,7 @@ shared_examples_for 'client' do
|
|
3
3
|
before(:each) do
|
4
4
|
@path_ary = %w[test mkdir_p path creation]
|
5
5
|
@bogus_path = File.join('/', *@path_ary)
|
6
|
+
@zk.rm_rf('/test')
|
6
7
|
end
|
7
8
|
|
8
9
|
it %[should create all intermediate paths for the path givem] do
|
@@ -14,6 +15,95 @@ shared_examples_for 'client' do
|
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
18
|
+
# nail down all possible cases
|
19
|
+
describe :create do
|
20
|
+
describe 'only path given' do
|
21
|
+
it %[should create a node with blank data] do
|
22
|
+
@zk.create(@base_path)
|
23
|
+
@zk.get(@base_path).first.should == ''
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'path and data given' do
|
28
|
+
it %[should create a node with the path and data] do
|
29
|
+
@zk.create(@base_path, 'blah')
|
30
|
+
@zk.get(@base_path).first.should == 'blah'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'path and sequential' do
|
35
|
+
it %[should create a sequential node with blank data] do
|
36
|
+
@zk.create(@base_path)
|
37
|
+
path = @zk.create("#{@base_path}/v", :sequential => true)
|
38
|
+
path.start_with?(@base_path).should be_true
|
39
|
+
|
40
|
+
File.basename(path).should match(/v\d+/)
|
41
|
+
|
42
|
+
@zk.get(path).first.should == ''
|
43
|
+
end
|
44
|
+
|
45
|
+
it %[should create a sequential node with given data] do
|
46
|
+
@zk.create(@base_path)
|
47
|
+
path = @zk.create("#{@base_path}/v", 'thedata', :sequential => true)
|
48
|
+
path.start_with?(@base_path).should be_true
|
49
|
+
|
50
|
+
File.basename(path).should match(/v\d+/)
|
51
|
+
|
52
|
+
data, st = @zk.get(path)
|
53
|
+
data.should == 'thedata'
|
54
|
+
st.should_not be_ephemeral
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'path and ephemeral' do
|
59
|
+
it %[should create an ephemeral node with blank data] do
|
60
|
+
@zk.create(@base_path, :ephemeral => true)
|
61
|
+
@zk.get(@base_path).last.should be_ephemeral
|
62
|
+
end
|
63
|
+
|
64
|
+
it %[should create an ephemeral node with given data] do
|
65
|
+
@zk.create(@base_path, 'thedata', :ephemeral => true)
|
66
|
+
data, stat = @zk.get(@base_path)
|
67
|
+
data.should == 'thedata'
|
68
|
+
stat.should be_ephemeral
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'path and sequential and ephemeral' do
|
73
|
+
it %[should create a sequential ephemeral node with blank data] do
|
74
|
+
@zk.create(@base_path)
|
75
|
+
path = @zk.create("#{@base_path}/v", :sequential => true, :ephemeral => true)
|
76
|
+
path.start_with?(@base_path).should be_true
|
77
|
+
|
78
|
+
File.basename(path).should match(/v\d+/)
|
79
|
+
|
80
|
+
data, st = @zk.get(path)
|
81
|
+
data.should == ''
|
82
|
+
st.should be_ephemeral
|
83
|
+
end
|
84
|
+
|
85
|
+
it %[should create a sequential ephemeral node with given data] do
|
86
|
+
@zk.create(@base_path)
|
87
|
+
path = @zk.create("#{@base_path}/v", 'thedata', :sequential => true, :ephemeral => true)
|
88
|
+
path.start_with?(@base_path).should be_true
|
89
|
+
|
90
|
+
File.basename(path).should match(/v\d+/)
|
91
|
+
|
92
|
+
data, st = @zk.get(path)
|
93
|
+
data.should == 'thedata'
|
94
|
+
st.should be_ephemeral
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
it %[should barf if someone hands 3 params] do
|
99
|
+
lambda { @zk.create(@base_path, 'data', :sequence) }.should raise_error(ArgumentError)
|
100
|
+
end
|
101
|
+
|
102
|
+
it %[should barf if both :sequence and :sequential are given] do
|
103
|
+
lambda { @zk.create(@base_path, 'data', :sequence => true, :sequential => true) }.should raise_error(ArgumentError)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
17
107
|
describe :stat do
|
18
108
|
describe 'for a missing node' do
|
19
109
|
before do
|
@@ -60,7 +150,7 @@ shared_examples_for 'client' do
|
|
60
150
|
|
61
151
|
describe 'node exists initially' do
|
62
152
|
before do
|
63
|
-
@zk.create(@path,
|
153
|
+
@zk.create(@path, :mode => :ephemeral)
|
64
154
|
@zk.exists?(@path).should be_true
|
65
155
|
end
|
66
156
|
|
@@ -113,7 +203,7 @@ shared_examples_for 'client' do
|
|
113
203
|
end
|
114
204
|
|
115
205
|
@zk.exists?(@path, :watch => true).should be_false
|
116
|
-
@zk.create(@path
|
206
|
+
@zk.create(@path)
|
117
207
|
|
118
208
|
logger.debug { "waiting for event delivery" }
|
119
209
|
|
@@ -151,6 +241,50 @@ shared_examples_for 'client' do
|
|
151
241
|
ensure_event_delivery!
|
152
242
|
end
|
153
243
|
end
|
244
|
+
|
245
|
+
end # reopen
|
246
|
+
|
247
|
+
describe 'reconnection' do
|
248
|
+
it %[should if it receives a client_invalid? event] do
|
249
|
+
flexmock(@zk) do |m|
|
250
|
+
m.should_receive(:reopen).with(0).once
|
251
|
+
end
|
252
|
+
|
253
|
+
bogus_event = flexmock(:expired_session_event, :session_event? => true, :client_invalid? => true, :state_name => 'ZOO_EXPIRED_SESSION_STATE')
|
254
|
+
|
255
|
+
@zk.raw_event_handler(bogus_event)
|
256
|
+
end
|
257
|
+
end # reconnection
|
258
|
+
|
259
|
+
describe :on_exception do
|
260
|
+
it %[should register a callback that will be called if an exception is raised on the threadpool] do
|
261
|
+
@ary = []
|
262
|
+
|
263
|
+
@zk.on_exception { |exc| @ary << exc }
|
264
|
+
|
265
|
+
@zk.defer { raise "ZOMG!" }
|
266
|
+
|
267
|
+
wait_while(2) { @ary.empty? }
|
268
|
+
|
269
|
+
@ary.length.should == 1
|
270
|
+
|
271
|
+
e = @ary.shift
|
272
|
+
|
273
|
+
e.should be_kind_of(RuntimeError)
|
274
|
+
e.message.should == 'ZOMG!'
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
describe :on_threadpool? do
|
279
|
+
it %[should be true if we're on the threadpool] do
|
280
|
+
@ary = []
|
281
|
+
|
282
|
+
@zk.defer { @ary << @zk.on_threadpool? }
|
283
|
+
|
284
|
+
wait_while(2) { @ary.empty? }
|
285
|
+
@ary.length.should == 1
|
286
|
+
@ary.first.should be_true
|
287
|
+
end
|
154
288
|
end
|
155
289
|
end
|
156
290
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bundler/setup'
|
3
3
|
|
4
|
-
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
4
|
+
# $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
5
|
+
|
6
|
+
Bundler.require(:development, :test)
|
5
7
|
|
6
8
|
require 'zk'
|
7
9
|
require 'benchmark'
|
8
10
|
|
9
|
-
ZK_TEST_PORT = 2181
|
11
|
+
ZK_TEST_PORT = 2181 unless defined?(ZK_TEST_PORT)
|
10
12
|
|
11
13
|
# Requires supporting ruby files with custom matchers and macros, etc,
|
12
14
|
# in spec/support/ and its subdirectories.
|
data/spec/support/logging.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module ZK
|
2
|
-
|
2
|
+
# LOG_FILE = File.open(File.join(ZK::ZK_ROOT, 'test.log'), 'a').tap { |f| f.sync = true }
|
3
|
+
LOG_FILE = File.join(ZK::ZK_ROOT, 'test.log')
|
3
4
|
# LOG_FILE = $stderr
|
4
5
|
end
|
5
6
|
|