zk 0.9.1 → 1.0.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|