slyphon-zookeeper 0.3.0-java → 0.8.0-java
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/CHANGELOG +34 -0
- data/Rakefile +25 -5
- data/ext/c_zookeeper.rb +214 -0
- data/ext/dbg.h +18 -2
- data/ext/depend +1 -2
- data/ext/zookeeper_base.rb +73 -99
- data/ext/zookeeper_c.c +52 -41
- data/ext/zookeeper_lib.c +90 -78
- data/ext/zookeeper_lib.h +0 -1
- data/java/zookeeper_base.rb +72 -154
- data/lib/zookeeper/common/queue_with_pipe.rb +78 -0
- data/lib/zookeeper/common.rb +73 -9
- data/lib/zookeeper/constants.rb +28 -0
- data/lib/zookeeper/em_client.rb +13 -138
- data/lib/zookeeper/exceptions.rb +4 -1
- data/lib/zookeeper.rb +51 -15
- data/slyphon-zookeeper.gemspec +1 -1
- data/spec/c_zookeeper_spec.rb +50 -0
- data/spec/chrooted_connection_spec.rb +121 -0
- data/spec/em_spec.rb +0 -61
- data/spec/shared/all_success_return_values.rb +10 -0
- data/spec/shared/connection_examples.rb +1007 -0
- data/spec/spec_helper.rb +42 -19
- data/spec/zookeeper_spec.rb +8 -1033
- metadata +16 -6
data/lib/zookeeper/em_client.rb
CHANGED
@@ -13,6 +13,7 @@ module ZookeeperEM
|
|
13
13
|
@em_connection = nil
|
14
14
|
logger.debug { "ZookeeperEM::Client obj_id %x: init" % [object_id] }
|
15
15
|
super(*a, &b)
|
16
|
+
on_attached.succeed
|
16
17
|
end
|
17
18
|
|
18
19
|
# EM::DefaultDeferrable that will be called back when our em_connection has been detached
|
@@ -29,152 +30,26 @@ module ZookeeperEM
|
|
29
30
|
@on_attached
|
30
31
|
end
|
31
32
|
|
32
|
-
|
33
|
-
# has been shut down
|
34
|
-
#
|
35
|
-
# if a block is given, it will be registered as a callback when the
|
36
|
-
# connection has been closed
|
37
|
-
#
|
38
|
-
def close(&block)
|
39
|
-
on_close(&block)
|
40
|
-
|
41
|
-
logger.debug { "#{self.class.name}: close called, closed? #{closed?} running? #{running?}" }
|
42
|
-
|
43
|
-
if @_running
|
44
|
-
@start_stop_mutex.synchronize do
|
45
|
-
@_running = false
|
46
|
-
end
|
47
|
-
|
48
|
-
if @em_connection
|
49
|
-
EM.next_tick do
|
50
|
-
@em_connection.detach do
|
51
|
-
logger.debug { "#{self.class.name}: connection unbound, continuing with shutdown" }
|
52
|
-
finish_closing
|
53
|
-
end
|
54
|
-
end
|
55
|
-
else
|
56
|
-
logger.debug { "#{self.class.name}: em_connection was never set up, finish closing" }
|
57
|
-
finish_closing
|
58
|
-
end
|
59
|
-
else
|
60
|
-
logger.debug { "#{self.class.name}: we are not running, so returning on_close deferred" }
|
61
|
-
end
|
62
|
-
|
63
|
-
on_close
|
64
|
-
end
|
65
|
-
|
66
|
-
# make this public as the ZKConnection object needs to call it
|
67
|
-
public :dispatch_next_callback
|
68
|
-
|
69
|
-
protected
|
70
|
-
# instead of setting up a dispatch thread here, we instead attach
|
71
|
-
# the #selectable_io to the event loop
|
72
|
-
def setup_dispatch_thread!
|
33
|
+
def dispatch_next_callback(hash)
|
73
34
|
EM.schedule do
|
74
35
|
if running? and not closed?
|
75
|
-
|
76
|
-
|
77
|
-
@em_connection = EM.watch(selectable_io, ZKConnection, self) { |cnx| cnx.notify_readable = true }
|
78
|
-
rescue Exception => e
|
79
|
-
$stderr.puts "caught exception from EM.watch(): #{e.inspect}"
|
80
|
-
end
|
36
|
+
logger.debug { "#{self.class}##{__method__} dispatch_next_callback: #{hash.inspect}: reactor_thread? #{EM.reactor_thread?}, running? #{running?}, closed? #{closed?}" }
|
37
|
+
super(hash)
|
81
38
|
end
|
82
39
|
end
|
83
40
|
end
|
84
41
|
|
85
|
-
def
|
86
|
-
|
87
|
-
|
88
|
-
logger.debug { "closing handle" }
|
89
|
-
close_handle
|
90
|
-
end
|
91
|
-
|
92
|
-
unless selectable_io.closed?
|
93
|
-
logger.debug { "calling close on selectable_io: #{selectable_io.inspect}" }
|
94
|
-
selectable_io.close
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
42
|
+
def close(&block)
|
43
|
+
on_close(&block)
|
44
|
+
super()
|
98
45
|
on_close.succeed
|
99
46
|
end
|
100
|
-
end
|
101
|
-
|
102
|
-
# this class is handed to EventMachine.watch to handle event dispatching
|
103
|
-
# when the queue has a message waiting. There's a pipe shared between
|
104
|
-
# the event thread managed by the queue implementation in C. It's made
|
105
|
-
# available to the ruby-space through the Zookeeper#selectable_io method.
|
106
|
-
# When the pipe is readable, that means there's an event waiting. We call
|
107
|
-
# dispatch_next_event and read a single byte off the pipe.
|
108
|
-
#
|
109
|
-
class ZKConnection < EM::Connection
|
110
|
-
|
111
|
-
def initialize(zk_client)
|
112
|
-
@zk_client = zk_client
|
113
|
-
end
|
114
47
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
@on_unbind = EM::DefaultDeferrable.new.tap do |d|
|
120
|
-
d.callback do
|
121
|
-
logger.debug { "on_unbind deferred fired" }
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
# probably because of the way post_init works, unless we fire this
|
126
|
-
# callback in next_tick @em_connection in the client may not be set
|
127
|
-
# (which on_attached callbacks may be relying on)
|
128
|
-
EM.next_tick do
|
129
|
-
logger.debug { "firing on_attached callback" }
|
130
|
-
@zk_client.on_attached.succeed
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# EM::DefaultDeferrable that will be called back when our em_connection has been detached
|
135
|
-
# and we've completed the close operation
|
136
|
-
def on_unbind(&block)
|
137
|
-
@on_unbind.callback(&block) if block
|
138
|
-
@on_unbind
|
139
|
-
end
|
140
|
-
|
141
|
-
def attached?
|
142
|
-
@attached
|
143
|
-
end
|
144
|
-
|
145
|
-
def unbind
|
146
|
-
on_unbind.succeed
|
147
|
-
end
|
148
|
-
|
149
|
-
def detach(&blk)
|
150
|
-
on_unbind(&blk)
|
151
|
-
return unless @attached
|
152
|
-
@attached = false
|
153
|
-
rval = super()
|
154
|
-
logger.debug { "#{self.class.name}: detached, rval: #{rval.inspect}" }
|
48
|
+
# Because eventmachine is single-threaded, and events are dispatched on the
|
49
|
+
# reactor thread we just delegate this to EM.reactor_thread?
|
50
|
+
def event_dispatch_thread?
|
51
|
+
EM.reactor_thread?
|
155
52
|
end
|
156
|
-
|
157
|
-
|
158
|
-
def notify_readable
|
159
|
-
if @zk_client.running?
|
160
|
-
|
161
|
-
read_io_nb if @zk_client.dispatch_next_callback(false)
|
162
|
-
|
163
|
-
elsif attached?
|
164
|
-
logger.debug { "#{self.class.name}: @zk_client was not running? and attached? #{attached?}, detaching!" }
|
165
|
-
detach
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
private
|
170
|
-
def read_io_nb(size=1)
|
171
|
-
@io.read_nonblock(1)
|
172
|
-
rescue Errno::EWOULDBLOCK, Errno::EAGAIN, IOError
|
173
|
-
end
|
174
|
-
|
175
|
-
def logger
|
176
|
-
Zookeeper.logger
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
53
|
+
end # Client
|
54
|
+
end # ZookeeperEM
|
180
55
|
|
data/lib/zookeeper/exceptions.rb
CHANGED
@@ -27,7 +27,7 @@ module ZookeeperExceptions
|
|
27
27
|
ZNOTHING = -117
|
28
28
|
ZSESSIONMOVED = -118
|
29
29
|
|
30
|
-
class ZookeeperException <
|
30
|
+
class ZookeeperException < StandardError
|
31
31
|
class EverythingOk < ZookeeperException; end
|
32
32
|
class SystemError < ZookeeperException; end
|
33
33
|
class RunTimeInconsistency < ZookeeperException; end
|
@@ -58,6 +58,9 @@ module ZookeeperExceptions
|
|
58
58
|
class NotConnected < ZookeeperException; end
|
59
59
|
class ShuttingDownException < ZookeeperException; end
|
60
60
|
class DataTooLargeException < ZookeeperException; end
|
61
|
+
|
62
|
+
# yes, make an alias, this is the way zookeeper refers to it
|
63
|
+
ExpiredSession = SessionExpired
|
61
64
|
|
62
65
|
def self.by_code(code)
|
63
66
|
case code
|
data/lib/zookeeper.rb
CHANGED
@@ -14,7 +14,6 @@ if defined?(::JRUBY_VERSION)
|
|
14
14
|
$LOAD_PATH.unshift(File.expand_path('../java', File.dirname(__FILE__))).uniq!
|
15
15
|
else
|
16
16
|
$LOAD_PATH.unshift(File.expand_path('../ext', File.dirname(__FILE__))).uniq!
|
17
|
-
require 'zookeeper_c'
|
18
17
|
end
|
19
18
|
|
20
19
|
require 'zookeeper_base'
|
@@ -33,6 +32,7 @@ class Zookeeper < ZookeeperBase
|
|
33
32
|
end
|
34
33
|
|
35
34
|
def reopen(timeout=10, watcher=nil)
|
35
|
+
warn "WARN: ZookeeperBase#reopen watcher argument is now ignored" if watcher
|
36
36
|
super
|
37
37
|
end
|
38
38
|
|
@@ -121,6 +121,24 @@ class Zookeeper < ZookeeperBase
|
|
121
121
|
{ :req_id => req_id, :rc => rc }
|
122
122
|
end
|
123
123
|
|
124
|
+
# this method is *only* asynchronous
|
125
|
+
#
|
126
|
+
# @note There is a discrepancy between the zkc and java versions. zkc takes
|
127
|
+
# a string_callback_t, java takes a VoidCallback. You should most likely use
|
128
|
+
# the ZookeeperCallbacks::VoidCallback and not rely on the string value.
|
129
|
+
#
|
130
|
+
def sync(options = {})
|
131
|
+
assert_open
|
132
|
+
assert_supported_keys(options, [:path, :callback, :callback_context])
|
133
|
+
assert_required_keys(options, [:path, :callback])
|
134
|
+
|
135
|
+
req_id = setup_call(:sync, options)
|
136
|
+
|
137
|
+
rc = super(req_id, options[:path]) # we don't pass options[:callback] here as this method is *always* async
|
138
|
+
|
139
|
+
{ :req_id => req_id, :rc => rc }
|
140
|
+
end
|
141
|
+
|
124
142
|
def set_acl(options = {})
|
125
143
|
assert_open
|
126
144
|
assert_supported_keys(options, [:path, :acl, :version, :callback, :callback_context])
|
@@ -165,12 +183,40 @@ class Zookeeper < ZookeeperBase
|
|
165
183
|
def associating?
|
166
184
|
super
|
167
185
|
end
|
186
|
+
|
187
|
+
# There are some operations that are dangerous in the context of the event
|
188
|
+
# dispatch thread (because they would block further event delivery). This
|
189
|
+
# method allows clients to know if they're currently executing in the context of an
|
190
|
+
# event.
|
191
|
+
#
|
192
|
+
# @returns [true,false] true if the current thread is the event dispatch thread
|
193
|
+
def event_dispatch_thread?
|
194
|
+
super
|
195
|
+
end
|
168
196
|
|
169
197
|
# for expert use only. set the underlying debug level for the C layer, has no
|
170
198
|
# effect in java
|
171
199
|
#
|
200
|
+
# @private
|
172
201
|
def self.set_debug_level(val)
|
173
|
-
|
202
|
+
if defined?(::CZookeeper)
|
203
|
+
CZookeeper.set_debug_level(val.to_i)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# @private
|
208
|
+
def self.get_debug_level
|
209
|
+
if defined?(::CZookeeper)
|
210
|
+
CZookeeper.get_debug_level
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
class << self
|
215
|
+
# @private
|
216
|
+
alias :debug_level= :set_debug_level
|
217
|
+
|
218
|
+
# @private
|
219
|
+
alias :debug_level :get_debug_level
|
174
220
|
end
|
175
221
|
|
176
222
|
# DEPRECATED: use the class-level method instead
|
@@ -188,18 +234,6 @@ class Zookeeper < ZookeeperBase
|
|
188
234
|
super
|
189
235
|
end
|
190
236
|
|
191
|
-
# returns an IO object that will be readable when an event is ready for dispatching
|
192
|
-
# (for internal use only)
|
193
|
-
def selectable_io
|
194
|
-
super
|
195
|
-
end
|
196
|
-
|
197
|
-
# closes the underlying connection object
|
198
|
-
# (for internal use only)
|
199
|
-
def close_handle
|
200
|
-
super
|
201
|
-
end
|
202
|
-
|
203
237
|
# return the session id of the current connection as an Fixnum
|
204
238
|
def session_id
|
205
239
|
super
|
@@ -244,8 +278,10 @@ protected
|
|
244
278
|
private
|
245
279
|
# TODO: Sanitize user mistakes by unregistering watchers from ops that
|
246
280
|
# don't return ZOK (except wexists)? Make users clean up after themselves for now.
|
281
|
+
#
|
282
|
+
# XXX: is this dead code?
|
247
283
|
def unregister_watcher(req_id)
|
248
|
-
@
|
284
|
+
@mutex.synchronize {
|
249
285
|
@watcher_reqs.delete(req_id)
|
250
286
|
}
|
251
287
|
end
|
data/slyphon-zookeeper.gemspec
CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "slyphon-zookeeper"
|
6
|
-
s.version = '0.
|
6
|
+
s.version = '0.8.0'
|
7
7
|
|
8
8
|
s.authors = ["Phillip Pearson", "Eric Maland", "Evan Weaver", "Brian Wickman", "Neil Conway", "Jonathan D. Simms"]
|
9
9
|
s.email = ["slyphon@gmail.com"]
|
@@ -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,121 @@
|
|
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
|
+
|
20
|
+
def zk
|
21
|
+
@zk
|
22
|
+
end
|
23
|
+
|
24
|
+
def with_open_zk(host='localhost:2181')
|
25
|
+
z = Zookeeper.new(host)
|
26
|
+
yield z
|
27
|
+
ensure
|
28
|
+
z.close
|
29
|
+
|
30
|
+
wait_until do
|
31
|
+
begin
|
32
|
+
!z.connected?
|
33
|
+
rescue RuntimeError
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# this is not as safe as the one in ZK, just to be used to clean up
|
40
|
+
# when we're the only one adjusting a particular path
|
41
|
+
def rm_rf(z, path)
|
42
|
+
z.get_children(:path => path).tap do |h|
|
43
|
+
if h[:rc].zero?
|
44
|
+
h[:children].each do |child|
|
45
|
+
rm_rf(z, File.join(path, child))
|
46
|
+
end
|
47
|
+
elsif h[:rc] == ZookeeperExceptions::ZNONODE
|
48
|
+
# no-op
|
49
|
+
else
|
50
|
+
raise "Oh noes! unexpected return value! #{h.inspect}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
rv = z.delete(:path => path)
|
55
|
+
|
56
|
+
unless (rv[:rc].zero? or rv[:rc] == ZookeeperExceptions::ZNONODE)
|
57
|
+
raise "oh noes! failed to delete #{path}"
|
58
|
+
end
|
59
|
+
|
60
|
+
path
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'non-existent' do
|
64
|
+
describe 'with existing parent' do
|
65
|
+
let(:chroot_path) { '/one-level' }
|
66
|
+
|
67
|
+
describe 'create' do
|
68
|
+
before do
|
69
|
+
with_open_zk do |z|
|
70
|
+
rm_rf(z, chroot_path)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it %[should successfully create the path] do
|
75
|
+
rv = zk.create(:path => '/', :data => '')
|
76
|
+
rv[:rc].should be_zero
|
77
|
+
rv[:path].should == ''
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'with missing parent' do
|
83
|
+
let(:chroot_path) { '/deeply/nested/path' }
|
84
|
+
|
85
|
+
describe 'create' do
|
86
|
+
before do
|
87
|
+
with_open_zk do |z|
|
88
|
+
rm_rf(z, chroot_path)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it %[should return ZNONODE] do
|
93
|
+
rv = zk.create(:path => '/', :data => '')
|
94
|
+
rv[:rc].should_not be_zero
|
95
|
+
rv[:rc].should == ZookeeperExceptions::ZNONODE
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
describe do
|
103
|
+
before :all do
|
104
|
+
Zookeeper.logger.warn "running before :all"
|
105
|
+
|
106
|
+
with_open_zk do |z|
|
107
|
+
z.create(:path => chroot_path, :data => '')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
after :all do
|
112
|
+
with_open_zk do |z|
|
113
|
+
rm_rf(z, chroot_path)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
it_should_behave_like "connection"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
data/spec/em_spec.rb
CHANGED
@@ -28,66 +28,6 @@ describe 'ZookeeperEM' do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
describe 'selectable_io' do
|
32
|
-
it %[should return an IO object] do
|
33
|
-
setup_zk do
|
34
|
-
@zk.selectable_io.should be_instance_of(IO)
|
35
|
-
teardown_and_done
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
it %[should not be closed] do
|
40
|
-
setup_zk do
|
41
|
-
@zk.selectable_io.should_not be_closed
|
42
|
-
teardown_and_done
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
before do
|
47
|
-
@data_cb = ZookeeperCallbacks::DataCallback.new do
|
48
|
-
logger.debug { "cb called: #{@data_cb.inspect}" }
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
it %[should be read-ready if there's an event waiting] do
|
53
|
-
setup_zk do
|
54
|
-
@zk.get(:path => "/", :callback => @data_cb)
|
55
|
-
|
56
|
-
r, *_ = IO.select([@zk.selectable_io], [], [], 2)
|
57
|
-
|
58
|
-
r.should be_kind_of(Array)
|
59
|
-
|
60
|
-
teardown_and_done
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
describe 'em_connection' do
|
66
|
-
before do
|
67
|
-
@zk = ZookeeperEM::Client.new('localhost:2181')
|
68
|
-
end
|
69
|
-
|
70
|
-
it %[should be nil before the reactor is started] do
|
71
|
-
@zk.em_connection.should be_nil
|
72
|
-
|
73
|
-
em do
|
74
|
-
teardown_and_done
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
it %[should fire off the on_attached callbacks once the reactor is managing us] do
|
79
|
-
@zk.on_attached do |*|
|
80
|
-
@zk.em_connection.should_not be_nil
|
81
|
-
@zk.em_connection.should be_instance_of(ZookeeperEM::ZKConnection)
|
82
|
-
teardown_and_done
|
83
|
-
end
|
84
|
-
|
85
|
-
em do
|
86
|
-
EM.reactor_running?.should be_true
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
31
|
describe 'callbacks' do
|
92
32
|
it %[should be called on the reactor thread] do
|
93
33
|
cb = lambda do |h|
|
@@ -105,7 +45,6 @@ describe 'ZookeeperEM' do
|
|
105
45
|
end
|
106
46
|
end
|
107
47
|
end
|
108
|
-
|
109
48
|
end
|
110
49
|
end
|
111
50
|
|