zookeeper 0.4.4 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/CHANGELOG +95 -0
- data/Gemfile +17 -0
- data/Manifest +8 -2
- data/README.markdown +59 -0
- data/Rakefile +137 -7
- data/ext/.gitignore +6 -0
- data/ext/Rakefile +51 -0
- data/ext/c_zookeeper.rb +212 -0
- data/ext/dbg.h +53 -0
- data/ext/depend +5 -0
- data/ext/extconf.rb +44 -15
- data/ext/generate_gvl_code.rb +316 -0
- data/ext/zkc-3.3.5.tar.gz +0 -0
- data/ext/zkrb_wrapper.c +731 -0
- data/ext/zkrb_wrapper.h +330 -0
- data/ext/zkrb_wrapper_compat.c +15 -0
- data/ext/zkrb_wrapper_compat.h +11 -0
- data/ext/zookeeper_base.rb +211 -0
- data/ext/zookeeper_c.c +268 -97
- data/ext/zookeeper_lib.c +157 -92
- data/ext/zookeeper_lib.h +12 -6
- data/java/zookeeper_base.rb +477 -0
- data/lib/zookeeper/acls.rb +10 -1
- data/lib/zookeeper/callbacks.rb +5 -3
- data/lib/zookeeper/common/queue_with_pipe.rb +78 -0
- data/lib/zookeeper/common.rb +174 -0
- data/lib/zookeeper/constants.rb +31 -28
- data/lib/zookeeper/em_client.rb +55 -0
- data/lib/zookeeper/exceptions.rb +10 -2
- data/lib/zookeeper/stat.rb +11 -2
- data/lib/zookeeper/version.rb +6 -0
- data/lib/zookeeper.rb +155 -122
- data/notes.txt +14 -0
- data/spec/c_zookeeper_spec.rb +50 -0
- data/spec/chrooted_connection_spec.rb +81 -0
- data/spec/default_watcher_spec.rb +41 -0
- data/spec/em_spec.rb +51 -0
- data/spec/log4j.properties +17 -0
- data/spec/shared/all_success_return_values.rb +10 -0
- data/spec/shared/connection_examples.rb +1018 -0
- data/spec/spec_helper.rb +119 -0
- data/spec/support/progress_formatter.rb +15 -0
- data/spec/zookeeper_spec.rb +24 -0
- data/zookeeper.gemspec +37 -25
- metadata +78 -34
- data/README +0 -42
- data/ext/zkc-3.3.2.tar.gz +0 -0
data/lib/zookeeper.rb
CHANGED
@@ -1,59 +1,54 @@
|
|
1
1
|
# Ruby wrapper for the Zookeeper C API
|
2
2
|
|
3
|
-
require 'zookeeper_c'
|
4
3
|
require 'thread'
|
5
|
-
require '
|
4
|
+
require 'monitor'
|
5
|
+
require 'forwardable'
|
6
|
+
require 'logger'
|
7
|
+
|
8
|
+
require 'zookeeper/common'
|
6
9
|
require 'zookeeper/constants'
|
10
|
+
require 'zookeeper/callbacks'
|
7
11
|
require 'zookeeper/exceptions'
|
8
12
|
require 'zookeeper/stat'
|
9
13
|
require 'zookeeper/acls'
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
init(@host)
|
28
|
-
if timeout > 0
|
29
|
-
time_to_stop = Time.now + timeout
|
30
|
-
until state == Zookeeper::ZOO_CONNECTED_STATE
|
31
|
-
break if Time.now > time_to_stop
|
32
|
-
sleep 0.1
|
33
|
-
end
|
34
|
-
end
|
35
|
-
# flushes all outstanding watcher reqs.
|
36
|
-
@watcher_reqs = { ZKRB_GLOBAL_CB_REQ => { :watcher => get_default_global_watcher } }
|
37
|
-
setup_dispatch_thread!
|
38
|
-
state
|
15
|
+
|
16
|
+
if defined?(::JRUBY_VERSION)
|
17
|
+
$LOAD_PATH.unshift(File.expand_path('../java', File.dirname(__FILE__))).uniq!
|
18
|
+
else
|
19
|
+
$LOAD_PATH.unshift(File.expand_path('../ext', File.dirname(__FILE__))).uniq!
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'zookeeper_base'
|
23
|
+
|
24
|
+
class Zookeeper < ZookeeperBase
|
25
|
+
unless defined?(@@logger)
|
26
|
+
@@logger = Logger.new($stderr).tap { |l| l.level = Logger::ERROR }
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.logger
|
30
|
+
@@logger
|
39
31
|
end
|
40
32
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
33
|
+
def self.logger=(logger)
|
34
|
+
@@logger = logger
|
35
|
+
end
|
36
|
+
|
37
|
+
def reopen(timeout=10, watcher=nil)
|
38
|
+
warn "WARN: ZookeeperBase#reopen watcher argument is now ignored" if watcher
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(host, timeout=10, watcher=nil)
|
43
|
+
super
|
48
44
|
end
|
49
45
|
|
50
|
-
public
|
51
46
|
def get(options = {})
|
52
47
|
assert_open
|
53
48
|
assert_supported_keys(options, [:path, :watcher, :watcher_context, :callback, :callback_context])
|
54
49
|
assert_required_keys(options, [:path])
|
55
50
|
|
56
|
-
req_id = setup_call(options)
|
51
|
+
req_id = setup_call(:get, options)
|
57
52
|
rc, value, stat = super(req_id, options[:path], options[:callback], options[:watcher])
|
58
53
|
|
59
54
|
rv = { :req_id => req_id, :rc => rc }
|
@@ -64,9 +59,10 @@ public
|
|
64
59
|
assert_open
|
65
60
|
assert_supported_keys(options, [:path, :data, :version, :callback, :callback_context])
|
66
61
|
assert_required_keys(options, [:path])
|
62
|
+
assert_valid_data_size!(options[:data])
|
67
63
|
options[:version] ||= -1
|
68
64
|
|
69
|
-
req_id = setup_call(options)
|
65
|
+
req_id = setup_call(:set, options)
|
70
66
|
rc, stat = super(req_id, options[:path], options[:data], options[:callback], options[:version])
|
71
67
|
|
72
68
|
rv = { :req_id => req_id, :rc => rc }
|
@@ -78,7 +74,7 @@ public
|
|
78
74
|
assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
|
79
75
|
assert_required_keys(options, [:path])
|
80
76
|
|
81
|
-
req_id = setup_call(options)
|
77
|
+
req_id = setup_call(:get_children, options)
|
82
78
|
rc, children, stat = super(req_id, options[:path], options[:callback], options[:watcher])
|
83
79
|
|
84
80
|
rv = { :req_id => req_id, :rc => rc }
|
@@ -90,7 +86,7 @@ public
|
|
90
86
|
assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
|
91
87
|
assert_required_keys(options, [:path])
|
92
88
|
|
93
|
-
req_id = setup_call(options)
|
89
|
+
req_id = setup_call(:stat, options)
|
94
90
|
rc, stat = exists(req_id, options[:path], options[:callback], options[:watcher])
|
95
91
|
|
96
92
|
rv = { :req_id => req_id, :rc => rc }
|
@@ -101,6 +97,7 @@ public
|
|
101
97
|
assert_open
|
102
98
|
assert_supported_keys(options, [:path, :data, :acl, :ephemeral, :sequence, :callback, :callback_context])
|
103
99
|
assert_required_keys(options, [:path])
|
100
|
+
assert_valid_data_size!(options[:data])
|
104
101
|
|
105
102
|
flags = 0
|
106
103
|
flags |= ZOO_EPHEMERAL if options[:ephemeral]
|
@@ -108,7 +105,7 @@ public
|
|
108
105
|
|
109
106
|
options[:acl] ||= ZOO_OPEN_ACL_UNSAFE
|
110
107
|
|
111
|
-
req_id = setup_call(options)
|
108
|
+
req_id = setup_call(:create, options)
|
112
109
|
rc, newpath = super(req_id, options[:path], options[:data], options[:callback], options[:acl], flags)
|
113
110
|
|
114
111
|
rv = { :req_id => req_id, :rc => rc }
|
@@ -121,19 +118,37 @@ public
|
|
121
118
|
assert_required_keys(options, [:path])
|
122
119
|
options[:version] ||= -1
|
123
120
|
|
124
|
-
req_id = setup_call(options)
|
121
|
+
req_id = setup_call(:delete, options)
|
125
122
|
rc = super(req_id, options[:path], options[:version], options[:callback])
|
126
123
|
|
127
124
|
{ :req_id => req_id, :rc => rc }
|
128
125
|
end
|
129
126
|
|
127
|
+
# this method is *only* asynchronous
|
128
|
+
#
|
129
|
+
# @note There is a discrepancy between the zkc and java versions. zkc takes
|
130
|
+
# a string_callback_t, java takes a VoidCallback. You should most likely use
|
131
|
+
# the ZookeeperCallbacks::VoidCallback and not rely on the string value.
|
132
|
+
#
|
133
|
+
def sync(options = {})
|
134
|
+
assert_open
|
135
|
+
assert_supported_keys(options, [:path, :callback, :callback_context])
|
136
|
+
assert_required_keys(options, [:path, :callback])
|
137
|
+
|
138
|
+
req_id = setup_call(:sync, options)
|
139
|
+
|
140
|
+
rc = super(req_id, options[:path]) # we don't pass options[:callback] here as this method is *always* async
|
141
|
+
|
142
|
+
{ :req_id => req_id, :rc => rc }
|
143
|
+
end
|
144
|
+
|
130
145
|
def set_acl(options = {})
|
131
146
|
assert_open
|
132
147
|
assert_supported_keys(options, [:path, :acl, :version, :callback, :callback_context])
|
133
148
|
assert_required_keys(options, [:path, :acl])
|
134
149
|
options[:version] ||= -1
|
135
150
|
|
136
|
-
req_id = setup_call(options)
|
151
|
+
req_id = setup_call(:set_acl, options)
|
137
152
|
rc = super(req_id, options[:path], options[:acl], options[:callback], options[:version])
|
138
153
|
|
139
154
|
{ :req_id => req_id, :rc => rc }
|
@@ -144,121 +159,139 @@ public
|
|
144
159
|
assert_supported_keys(options, [:path, :callback, :callback_context])
|
145
160
|
assert_required_keys(options, [:path])
|
146
161
|
|
147
|
-
req_id = setup_call(options)
|
162
|
+
req_id = setup_call(:get_acl, options)
|
148
163
|
rc, acls, stat = super(req_id, options[:path], options[:callback])
|
149
164
|
|
150
165
|
rv = { :req_id => req_id, :rc => rc }
|
151
166
|
options[:callback] ? rv : rv.merge(:acl => acls, :stat => Stat.new(stat))
|
152
167
|
end
|
153
168
|
|
154
|
-
#
|
155
|
-
# signalling the waiting thread that there is a pending close. We then release
|
156
|
-
# the C-land Zk state.
|
169
|
+
# close this client and any underyling connections
|
157
170
|
def close
|
158
|
-
signal_pending_close
|
159
|
-
@dispatcher.join
|
160
171
|
super
|
161
172
|
end
|
162
173
|
|
163
|
-
|
164
|
-
|
165
|
-
@dispatcher = Thread.new {
|
166
|
-
while true do
|
167
|
-
hash = get_next_event
|
168
|
-
break if hash.nil? # Pending close => exit dispatcher thread
|
169
|
-
dispatch_event(hash)
|
170
|
-
end
|
171
|
-
}
|
174
|
+
def state
|
175
|
+
super
|
172
176
|
end
|
173
177
|
|
174
|
-
def
|
175
|
-
|
178
|
+
def connected?
|
179
|
+
super
|
180
|
+
end
|
176
181
|
|
177
|
-
|
178
|
-
|
182
|
+
def connecting?
|
183
|
+
super
|
184
|
+
end
|
179
185
|
|
180
|
-
|
181
|
-
|
182
|
-
|
186
|
+
def associating?
|
187
|
+
super
|
188
|
+
end
|
189
|
+
|
190
|
+
# There are some operations that are dangerous in the context of the event
|
191
|
+
# dispatch thread (because they would block further event delivery). This
|
192
|
+
# method allows clients to know if they're currently executing in the context of an
|
193
|
+
# event.
|
194
|
+
#
|
195
|
+
# @returns [true,false] true if the current thread is the event dispatch thread
|
196
|
+
def event_dispatch_thread?
|
197
|
+
super
|
198
|
+
end
|
183
199
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
200
|
+
# for expert use only. set the underlying debug level for the C layer, has no
|
201
|
+
# effect in java
|
202
|
+
#
|
203
|
+
# @private
|
204
|
+
def self.set_debug_level(val)
|
205
|
+
if defined?(::CZookeeper)
|
206
|
+
CZookeeper.set_debug_level(val.to_i)
|
189
207
|
end
|
190
208
|
end
|
191
209
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
setup_completion(req_id, opts) if opts[:callback]
|
198
|
-
setup_watcher(req_id, opts) if opts[:watcher]
|
199
|
-
}
|
200
|
-
req_id
|
210
|
+
# @private
|
211
|
+
def self.get_debug_level
|
212
|
+
if defined?(::CZookeeper)
|
213
|
+
CZookeeper.get_debug_level
|
214
|
+
end
|
201
215
|
end
|
202
216
|
|
203
|
-
|
204
|
-
@
|
205
|
-
|
217
|
+
class << self
|
218
|
+
# @private
|
219
|
+
alias :debug_level= :set_debug_level
|
220
|
+
|
221
|
+
# @private
|
222
|
+
alias :debug_level :get_debug_level
|
206
223
|
end
|
207
224
|
|
208
|
-
|
209
|
-
|
210
|
-
|
225
|
+
# DEPRECATED: use the class-level method instead
|
226
|
+
def set_debug_level(val)
|
227
|
+
super
|
211
228
|
end
|
212
229
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
}
|
230
|
+
# has the underlying connection been closed?
|
231
|
+
def closed?
|
232
|
+
super
|
217
233
|
end
|
218
234
|
|
219
|
-
|
220
|
-
|
235
|
+
# is the event delivery system running?
|
236
|
+
def running?
|
237
|
+
super
|
221
238
|
end
|
222
239
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
def unregister_watcher(req_id)
|
227
|
-
@req_mutex.synchronize {
|
228
|
-
@watcher_reqs.delete(req_id)
|
229
|
-
}
|
240
|
+
# return the session id of the current connection as an Fixnum
|
241
|
+
def session_id
|
242
|
+
super
|
230
243
|
end
|
231
244
|
|
232
|
-
|
233
|
-
|
245
|
+
# Return the passwd portion of this connection's credentials as a String
|
246
|
+
def session_passwd
|
247
|
+
super
|
248
|
+
end
|
249
|
+
|
250
|
+
protected
|
251
|
+
# used during shutdown, awaken the event delivery thread if it's blocked
|
252
|
+
# waiting for the next event
|
253
|
+
def wake_event_loop!
|
254
|
+
super
|
255
|
+
end
|
256
|
+
|
257
|
+
# starts the event delivery subsystem going. after calling this method, running? will be true
|
258
|
+
def setup_dispatch_thread!
|
259
|
+
super
|
260
|
+
end
|
261
|
+
|
262
|
+
# TODO: describe what this does
|
234
263
|
def get_default_global_watcher
|
235
|
-
|
236
|
-
# puts "Ruby ZK Global CB called type=#{event_by_value(args[:type])} state=#{state_by_value(args[:state])}"
|
237
|
-
true
|
238
|
-
}
|
264
|
+
super
|
239
265
|
end
|
240
266
|
|
241
|
-
|
242
|
-
|
243
|
-
if state == ZOO_EXPIRED_SESSION_STATE
|
244
|
-
raise ZookeeperException::SessionExpired
|
245
|
-
elsif state != Zookeeper::ZOO_CONNECTED_STATE
|
246
|
-
raise ZookeeperException::ConnectionClosed
|
247
|
-
end
|
267
|
+
def logger
|
268
|
+
Zookeeper.logger
|
248
269
|
end
|
249
270
|
|
250
|
-
def
|
251
|
-
|
252
|
-
|
253
|
-
|
271
|
+
def assert_valid_data_size!(data)
|
272
|
+
return if data.nil?
|
273
|
+
|
274
|
+
data = data.to_s
|
275
|
+
if data.length >= 1048576 # one megabyte
|
276
|
+
raise ZookeeperException::DataTooLargeException, "data must be smaller than 1 MiB, your data starts with: #{data[0..32].inspect}"
|
254
277
|
end
|
278
|
+
nil
|
255
279
|
end
|
256
280
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
281
|
+
private
|
282
|
+
# TODO: Sanitize user mistakes by unregistering watchers from ops that
|
283
|
+
# don't return ZOK (except wexists)? Make users clean up after themselves for now.
|
284
|
+
#
|
285
|
+
# XXX: is this dead code?
|
286
|
+
def unregister_watcher(req_id)
|
287
|
+
@mutex.synchronize {
|
288
|
+
@watcher_reqs.delete(req_id)
|
289
|
+
}
|
290
|
+
end
|
291
|
+
|
292
|
+
# must be supplied by parent class impl.
|
293
|
+
def assert_open
|
294
|
+
super
|
262
295
|
end
|
263
296
|
end
|
264
297
|
|
data/notes.txt
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Notes on this fork of http://github.com/twitter/zookeeper
|
2
|
+
|
3
|
+
The main purpose of this fork is to provide JRuby compatibility with the MRI driver of the original. We have been using an early fork with an incomplete binding to the C client, and had recently bumped up against a fairly serious bug with handling events. The twitter/zookeeper driver solved this problem but was lacking JRuby support (which is a core piece of our environment).
|
4
|
+
|
5
|
+
I've packaged the Java client (and its dependency on log4j) as gems that are installed separately from this codebase to cut down on the size of the zookeeper gem. If this poses a problem (for instance, if the original goal was to have an all-in-one install with no external dependencies), it would be trivial to package those jars along with this code.
|
6
|
+
|
7
|
+
In the course of writing the wrapper for JRuby, I've written nearly-complete specs for all of the public API methods: get, set, get_children, stat, create, delete, get_acl, and set_acl. The reason I say they're "nearly" complete is that I have no use for set_acl, and quite honestly, couldn't figure out how to make it work.
|
8
|
+
|
9
|
+
I'm planning on writing a companion gem, 'ZK', that would take some of the higher-level constructs that we'd written around the lower-level driver to implement features like locking and queues, and also to provide a more ruby-like interface.
|
10
|
+
|
11
|
+
I'd like to reorganize this codebase in a number of ways, most of all to move all of the various classes and modules under a common "Zookeeper" namespace, however I thought that would be a radical enough change where I'd want to discuss/coordinate with you on how exactly to do it.
|
12
|
+
|
13
|
+
|
14
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# tests the CZookeeper, obviously only available when running under MRI
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
if Module.const_defined?(:CZookeeper)
|
5
|
+
describe CZookeeper do
|
6
|
+
def pop_all_events
|
7
|
+
[].tap do |rv|
|
8
|
+
begin
|
9
|
+
rv << @event_queue.pop(non_blocking=true)
|
10
|
+
rescue ThreadError
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def wait_until_connected(timeout=2)
|
16
|
+
wait_until(timeout) { @czk.state == ZookeeperConstants::ZOO_CONNECTED_STATE }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe do
|
20
|
+
before do
|
21
|
+
@event_queue = ZookeeperCommon::QueueWithPipe.new
|
22
|
+
@czk = CZookeeper.new('localhost:2181', @event_queue)
|
23
|
+
end
|
24
|
+
|
25
|
+
after do
|
26
|
+
@czk.close rescue Exception
|
27
|
+
@event_queue.close rescue Exception
|
28
|
+
end
|
29
|
+
|
30
|
+
it %[should be in connected state within a reasonable amount of time] do
|
31
|
+
wait_until_connected.should be_true
|
32
|
+
end
|
33
|
+
|
34
|
+
describe :after_connected do
|
35
|
+
before do
|
36
|
+
wait_until_connected.should be_true
|
37
|
+
end
|
38
|
+
|
39
|
+
it %[should have a connection event after being connected] do
|
40
|
+
event = wait_until(2) { @event_queue.pop }
|
41
|
+
event.should be
|
42
|
+
event[:req_id].should == ZookeeperCommon::ZKRB_GLOBAL_CB_REQ
|
43
|
+
event[:type].should == ZookeeperConstants::ZOO_SESSION_EVENT
|
44
|
+
event[:state].should == ZookeeperConstants::ZOO_CONNECTED_STATE
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared/connection_examples'
|
3
|
+
|
4
|
+
describe 'Zookeeper chrooted' do
|
5
|
+
let(:path) { "/_zkchroottest_" }
|
6
|
+
let(:data) { "underpants" }
|
7
|
+
let(:chroot_path) { '/slyphon-zookeeper-chroot' }
|
8
|
+
|
9
|
+
let(:connection_string) { "localhost:2181#{chroot_path}" }
|
10
|
+
|
11
|
+
before do
|
12
|
+
@zk = Zookeeper.new(connection_string)
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
@zk and @zk.close
|
17
|
+
end
|
18
|
+
|
19
|
+
def zk
|
20
|
+
@zk
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'non-existent' do
|
24
|
+
describe 'with existing parent' do
|
25
|
+
let(:chroot_path) { '/one-level' }
|
26
|
+
|
27
|
+
describe 'create' do
|
28
|
+
before do
|
29
|
+
with_open_zk do |z|
|
30
|
+
rm_rf(z, chroot_path)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it %[should successfully create the path] do
|
35
|
+
rv = zk.create(:path => '/', :data => '')
|
36
|
+
rv[:rc].should be_zero
|
37
|
+
rv[:path].should == ''
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'with missing parent' do
|
43
|
+
let(:chroot_path) { '/deeply/nested/path' }
|
44
|
+
|
45
|
+
describe 'create' do
|
46
|
+
before do
|
47
|
+
with_open_zk do |z|
|
48
|
+
rm_rf(z, chroot_path)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it %[should return ZNONODE] do
|
53
|
+
rv = zk.create(:path => '/', :data => '')
|
54
|
+
rv[:rc].should_not be_zero
|
55
|
+
rv[:rc].should == ZookeeperExceptions::ZNONODE
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
describe do
|
63
|
+
before :all do
|
64
|
+
Zookeeper.logger.warn "running before :all"
|
65
|
+
|
66
|
+
with_open_zk do |z|
|
67
|
+
z.create(:path => chroot_path, :data => '')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
after :all do
|
72
|
+
with_open_zk do |z|
|
73
|
+
rm_rf(z, chroot_path)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it_should_behave_like "connection"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Zookeeper do
|
4
|
+
describe :initialize, 'with watcher block' do
|
5
|
+
before do
|
6
|
+
@events = []
|
7
|
+
@watch_block = lambda do |hash|
|
8
|
+
$stderr.puts "watch_block: #{hash.inspect}"
|
9
|
+
@events << hash
|
10
|
+
end
|
11
|
+
|
12
|
+
@zk = Zookeeper.new('localhost:2181', 10, @watch_block)
|
13
|
+
|
14
|
+
wait_until(2) { @zk.connected? }
|
15
|
+
@zk.should be_connected
|
16
|
+
$stderr.puts "connected!"
|
17
|
+
|
18
|
+
wait_until(2) { !@events.empty? }
|
19
|
+
$stderr.puts "got events!"
|
20
|
+
end
|
21
|
+
|
22
|
+
after do
|
23
|
+
@zk.close if @zk.connected?
|
24
|
+
end
|
25
|
+
|
26
|
+
it %[should receive initial connection state events] do
|
27
|
+
@events.should_not be_empty
|
28
|
+
@events.length.should == 1
|
29
|
+
@events.first[:state].should == Zookeeper::ZOO_CONNECTED_STATE
|
30
|
+
end
|
31
|
+
|
32
|
+
it %[should receive disconnection events] do
|
33
|
+
pending "the C driver doesn't appear to deliver disconnection events (?)"
|
34
|
+
@events.clear
|
35
|
+
@zk.close
|
36
|
+
wait_until(2) { !@events.empty? }
|
37
|
+
@events.should_not be_empty
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
data/spec/em_spec.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
require 'zookeeper/em_client'
|
3
|
+
|
4
|
+
gem 'evented-spec', '~> 0.9.0'
|
5
|
+
require 'evented-spec'
|
6
|
+
|
7
|
+
|
8
|
+
describe 'ZookeeperEM' do
|
9
|
+
describe 'Client' do
|
10
|
+
include EventedSpec::SpecHelper
|
11
|
+
default_timeout 3.0
|
12
|
+
|
13
|
+
def setup_zk
|
14
|
+
@zk = ZookeeperEM::Client.new('localhost:2181')
|
15
|
+
em do
|
16
|
+
@zk.on_attached do
|
17
|
+
yield
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def teardown_and_done
|
23
|
+
@zk.close do
|
24
|
+
logger.debug { "TEST: about to call done" }
|
25
|
+
EM.next_tick do
|
26
|
+
done
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'callbacks' do
|
32
|
+
it %[should be called on the reactor thread] do
|
33
|
+
cb = lambda do |h|
|
34
|
+
EM.reactor_thread?.should be_true
|
35
|
+
logger.debug { "called back on the reactor thread? #{EM.reactor_thread?}" }
|
36
|
+
teardown_and_done
|
37
|
+
end
|
38
|
+
|
39
|
+
setup_zk do
|
40
|
+
@zk.on_attached do |*|
|
41
|
+
logger.debug { "on_attached called" }
|
42
|
+
rv = @zk.get(:path => '/', :callback => cb)
|
43
|
+
logger.debug { "rv from @zk.get: #{rv.inspect}" }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
log4j.rootLogger = DEBUG,S
|
2
|
+
|
3
|
+
log4j.appender.S = org.apache.log4j.FileAppender
|
4
|
+
log4j.appender.S.File = /tmp/zk-test.log
|
5
|
+
|
6
|
+
log4j.appender.S.layout = org.apache.log4j.PatternLayout
|
7
|
+
log4j.appender.S.layout.ConversionPattern = %5p [%t] (%c:%F:%L) - %m%n
|
8
|
+
|
9
|
+
log4j.appender.C = org.apache.log4j.FileAppender
|
10
|
+
log4j.appender.C.File = /tmp/zk-test-client.log
|
11
|
+
|
12
|
+
log4j.appender.C.layout = org.apache.log4j.PatternLayout
|
13
|
+
log4j.appender.C.layout.ConversionPattern = %5p [%t] (%c:%F:%L) - %m%n
|
14
|
+
|
15
|
+
log4j.org.apache.zookeeper.ZooKeeper = DEBUG,C
|
16
|
+
log4j.org.apache.zookeeper.server = DEBUG,S
|
17
|
+
|