zk 1.0.0 → 1.1.0
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 +1 -0
- data/.travis.yml +6 -8
- data/Gemfile +4 -6
- data/README.markdown +39 -21
- data/Rakefile +4 -2
- data/lib/zk.rb +60 -5
- data/lib/zk/client/base.rb +31 -9
- data/lib/zk/client/threaded.rb +39 -20
- data/lib/zk/election.rb +42 -38
- data/lib/zk/event.rb +8 -0
- data/lib/zk/event_handler.rb +38 -7
- data/lib/zk/event_handler_subscription.rb +19 -55
- data/lib/zk/event_handler_subscription/actor.rb +38 -0
- data/lib/zk/event_handler_subscription/base.rb +76 -0
- data/lib/zk/threaded_callback.rb +56 -0
- data/lib/zk/threadpool.rb +1 -3
- data/lib/zk/version.rb +1 -1
- data/spec/event_catcher_spec.rb +29 -0
- data/spec/message_queue_spec.rb +2 -2
- data/spec/shared/client_contexts.rb +20 -10
- data/spec/shared/client_examples.rb +1 -1
- data/spec/spec_helper.rb +22 -7
- data/spec/support/00_test_port_attr.rb +20 -0
- data/spec/support/event_catcher.rb +73 -5
- data/spec/support/logging.rb +3 -1
- data/spec/support/pendings.rb +52 -0
- data/spec/support/wait_watchers.rb +10 -1
- data/spec/watch_spec.rb +143 -124
- data/spec/zk/client_spec.rb +15 -3
- data/spec/zk/election_spec.rb +12 -14
- data/spec/zk/locker_spec.rb +17 -12
- data/spec/zk/module_spec.rb +20 -12
- data/spec/zk/mongoid_spec.rb +3 -1
- data/spec/zk/pool_spec.rb +3 -3
- data/spec/zookeeper_spec.rb +2 -2
- metadata +13 -4
@@ -0,0 +1,56 @@
|
|
1
|
+
module ZK
|
2
|
+
# A class that encapsulates the queue + thread that calls a callback.
|
3
|
+
# Repsonds to `call` but places call on a queue to be delivered by a thread.
|
4
|
+
# You will not have a useful return value from `call` so this is only useful
|
5
|
+
# for background processing.
|
6
|
+
class ThreadedCallback
|
7
|
+
include ZK::Logging
|
8
|
+
|
9
|
+
attr_reader :callback
|
10
|
+
|
11
|
+
def initialize(callback=nil, &blk)
|
12
|
+
@callback = callback || blk
|
13
|
+
@mutex = Monitor.new
|
14
|
+
@queue = Queue.new
|
15
|
+
@running = true
|
16
|
+
setup_dispatch_thread
|
17
|
+
end
|
18
|
+
|
19
|
+
def running?
|
20
|
+
@mutex.synchronize { @running }
|
21
|
+
end
|
22
|
+
|
23
|
+
# how long to wait on thread shutdown before we return
|
24
|
+
def shutdown(timeout=2)
|
25
|
+
@mutex.synchronize do
|
26
|
+
@running = false
|
27
|
+
@queue.push(KILL_TOKEN)
|
28
|
+
return unless @thread
|
29
|
+
unless @thread.join(2)
|
30
|
+
logger.error { "#{self.class} timed out waiting for dispatch thread, callback: #{callback.inspect}" }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def call(*args)
|
36
|
+
@queue.push(args)
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
def setup_dispatch_thread
|
41
|
+
@thread ||= Thread.new do
|
42
|
+
while running?
|
43
|
+
args = @queue.pop
|
44
|
+
break if args == KILL_TOKEN
|
45
|
+
begin
|
46
|
+
callback.call(*args)
|
47
|
+
rescue Exception => e
|
48
|
+
logger.error { "error caught in handler for path: #{path.inspect}, interests: #{interests.inspect}" }
|
49
|
+
logger.error { e.to_std_format }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
data/lib/zk/threadpool.rb
CHANGED
@@ -20,7 +20,7 @@ module ZK
|
|
20
20
|
@threadpool = []
|
21
21
|
@threadqueue = ::Queue.new
|
22
22
|
|
23
|
-
@mutex =
|
23
|
+
@mutex = Monitor.new
|
24
24
|
|
25
25
|
@error_callbacks = []
|
26
26
|
|
@@ -86,9 +86,7 @@ module ZK
|
|
86
86
|
def shutdown(timeout=2)
|
87
87
|
@mutex.synchronize do
|
88
88
|
return unless @running
|
89
|
-
|
90
89
|
@running = false
|
91
|
-
|
92
90
|
@threadqueue.clear
|
93
91
|
@size.times { @threadqueue << KILL_TOKEN }
|
94
92
|
|
data/lib/zk/version.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
# quick tests for one of the support classes
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe EventCatcher do
|
5
|
+
subject { EventCatcher.new }
|
6
|
+
|
7
|
+
describe :wait_for do
|
8
|
+
it %[should wake when an event is delivered] do
|
9
|
+
th = Thread.new do
|
10
|
+
subject.synchronize do
|
11
|
+
logger.debug { "about to wait for created" }
|
12
|
+
subject.wait_for_created
|
13
|
+
logger.debug { "woke up, created must have been delivered" }
|
14
|
+
end
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
th.run
|
19
|
+
Thread.pass until th.status == 'sleep'
|
20
|
+
|
21
|
+
logger.debug { "th.status: #{th.status}" }
|
22
|
+
|
23
|
+
subject.add(:created, 'blah')
|
24
|
+
|
25
|
+
th.join(2).value.should be_true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
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:#{
|
7
|
-
@zk2 = ZK.new("localhost:#{
|
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)
|
@@ -1,20 +1,30 @@
|
|
1
|
+
shared_context 'connection opts' do
|
2
|
+
let(:connection_opts) { { :thread => :per_callback, :timeout => 5 } }
|
3
|
+
let(:connection_host) { "localhost:#{ZK.test_port}" }
|
4
|
+
let(:connection_args) { [connection_host, connection_opts] }
|
5
|
+
end
|
6
|
+
|
1
7
|
shared_context 'threaded client connection' do
|
8
|
+
include_context 'connection opts'
|
9
|
+
|
2
10
|
before do
|
3
|
-
@connection_string = "localhost:#{
|
11
|
+
@connection_string = "localhost:#{ZK.test_port}"
|
4
12
|
@base_path = '/zktests'
|
5
|
-
@zk = ZK::Client::Threaded.new(
|
6
|
-
@
|
13
|
+
@zk = ZK::Client::Threaded.new(*connection_args).tap { |z| wait_until { z.connected? } }
|
14
|
+
@threadpool_exception = nil
|
15
|
+
@zk.on_exception { |e| @threadpool_exception = e }
|
7
16
|
@zk.rm_rf(@base_path)
|
8
17
|
end
|
9
18
|
|
10
19
|
after do
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
20
|
+
# raise @threadpool_exception if @threadpool_exception
|
21
|
+
@zk.reopen if @zk.closed?
|
22
|
+
wait_until(5) { @zk.connected? }
|
23
|
+
|
24
|
+
@zk.rm_rf(@base_path)
|
25
|
+
@zk.close!
|
26
|
+
wait_until(5) { @zk.closed? }
|
18
27
|
end
|
19
28
|
end
|
20
29
|
|
30
|
+
|
@@ -175,7 +175,7 @@ shared_examples_for 'client' do
|
|
175
175
|
|
176
176
|
describe 'session_id and session_passwd' do
|
177
177
|
it %[should expose the underlying session_id] do
|
178
|
-
@zk.session_id.should be_kind_of(
|
178
|
+
@zk.session_id.should be_kind_of(Integer)
|
179
179
|
end
|
180
180
|
|
181
181
|
it %[should expose the underlying session_passwd] do
|
data/spec/spec_helper.rb
CHANGED
@@ -8,11 +8,9 @@ Bundler.require(:development, :test)
|
|
8
8
|
require 'zk'
|
9
9
|
require 'benchmark'
|
10
10
|
|
11
|
-
ZK_TEST_PORT = 2181 unless defined?(ZK_TEST_PORT)
|
12
|
-
|
13
11
|
# Requires supporting ruby files with custom matchers and macros, etc,
|
14
12
|
# in spec/support/ and its subdirectories.
|
15
|
-
Dir[File.expand_path("../{support,shared}/**/*.rb", __FILE__)].each {|f| require f}
|
13
|
+
Dir[File.expand_path("../{support,shared}/**/*.rb", __FILE__)].sort.each {|f| require f}
|
16
14
|
|
17
15
|
$stderr.sync = true
|
18
16
|
|
@@ -22,11 +20,28 @@ RSpec.configure do |config|
|
|
22
20
|
config.mock_with :flexmock
|
23
21
|
config.include(FlexMock::ArgumentTypes)
|
24
22
|
|
25
|
-
|
26
|
-
|
23
|
+
[WaitWatchers, SpecGlobalLogger, Pendings].each do |mod|
|
24
|
+
config.include(mod)
|
25
|
+
config.extend(mod)
|
26
|
+
end
|
27
|
+
|
28
|
+
if ZK.spawn_zookeeper?
|
29
|
+
require 'zk-server'
|
27
30
|
|
28
|
-
|
29
|
-
|
31
|
+
config.before(:suite) do
|
32
|
+
ZK.logger.debug { "Starting zookeeper service" }
|
33
|
+
ZK::Server.run do |c|
|
34
|
+
c.client_port = ZK.test_port
|
35
|
+
c.force_sync = false
|
36
|
+
c.snap_count = 1_000_000
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
config.after(:suite) do
|
41
|
+
ZK.logger.debug { "stopping zookeeper service" }
|
42
|
+
ZK::Server.shutdown
|
43
|
+
end
|
44
|
+
end
|
30
45
|
end
|
31
46
|
|
32
47
|
class ::Thread
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ZK
|
2
|
+
def self.spawn_zookeeper?
|
3
|
+
!!ENV['SPAWN_ZOOKEEPER']
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.travis?
|
7
|
+
!!ENV['TRAVIS']
|
8
|
+
end
|
9
|
+
|
10
|
+
@test_port ||= spawn_zookeeper? ? 21811 : 2181
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :test_port
|
14
|
+
end
|
15
|
+
|
16
|
+
# argh, blah, this affects ZK.new everywhere (which is kind of the point, but
|
17
|
+
# still gross)
|
18
|
+
self.default_port = self.test_port
|
19
|
+
end
|
20
|
+
|
@@ -1,11 +1,79 @@
|
|
1
|
-
class EventCatcher
|
1
|
+
class EventCatcher
|
2
|
+
extend Forwardable
|
3
|
+
include ZK::Logging
|
4
|
+
|
5
|
+
def_delegators :@mutex, :synchronize
|
6
|
+
|
7
|
+
MEMBERS = [:created, :changed, :deleted, :child, :all]
|
8
|
+
|
9
|
+
attr_reader :events
|
2
10
|
|
3
11
|
def initialize(*args)
|
4
|
-
|
12
|
+
@mutex = Monitor.new
|
13
|
+
@conds = {}
|
14
|
+
@events = {}
|
15
|
+
|
16
|
+
MEMBERS.each do |k|
|
17
|
+
@conds[k] = @mutex.new_cond
|
18
|
+
@events[k] = []
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def cond(name)
|
23
|
+
@conds.fetch(name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def clear_all
|
27
|
+
synchronize do
|
28
|
+
@events.values.each(&:clear)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def add(sym,obj)
|
33
|
+
synchronize do
|
34
|
+
logger.debug { "adding #{sym.inspect} #{obj.inspect}" }
|
35
|
+
events[sym] << obj
|
36
|
+
cond(sym).broadcast
|
5
37
|
|
6
|
-
|
7
|
-
|
38
|
+
events[:all] << obj
|
39
|
+
cond(:all).broadcast
|
8
40
|
end
|
9
41
|
end
|
10
|
-
end
|
11
42
|
|
43
|
+
def wait_for(ev_name, timeout=5)
|
44
|
+
cond(ev_name).wait(timeout)
|
45
|
+
end
|
46
|
+
|
47
|
+
def wait_while(ev_name)
|
48
|
+
cond(ev_name).wait_while { yield @events.fetch(ev_name) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def wait_until(ev_name)
|
52
|
+
cond(ev_name).wait_until { yield @events.fetch(ev_name) }
|
53
|
+
end
|
54
|
+
|
55
|
+
MEMBERS.each do |name|
|
56
|
+
class_eval <<-EOS, __FILE__, __LINE__+1
|
57
|
+
def #{name}
|
58
|
+
events[:#{name}]
|
59
|
+
end
|
60
|
+
|
61
|
+
def cond_#{name}
|
62
|
+
cond(:#{name})
|
63
|
+
end
|
64
|
+
|
65
|
+
# waits for an event group to not be empty (up to timeout sec)
|
66
|
+
def wait_for_#{name}(timeout=5)
|
67
|
+
cond(:#{name}).wait(timeout)
|
68
|
+
end
|
69
|
+
|
70
|
+
def wait_while_#{name}
|
71
|
+
cond(:#{name}).wait_while { yield __send__(:#{name}) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def wait_until_#{name}
|
75
|
+
cond(:#{name}).wait_until { yield __send__(:#{name}) }
|
76
|
+
end
|
77
|
+
EOS
|
78
|
+
end
|
79
|
+
end
|
data/spec/support/logging.rb
CHANGED
@@ -4,7 +4,9 @@ module ZK
|
|
4
4
|
# LOG_FILE = $stderr
|
5
5
|
end
|
6
6
|
|
7
|
-
ZK.logger = Logger.new(
|
7
|
+
# ZK.logger = ENV['TRAVIS'] ? Logger.new($stderr) : Logger.new(ZK::LOG_FILE)
|
8
|
+
|
9
|
+
ZK.logger = Logger.new(ZK::LOG_FILE).tap { |l| l.level = Logger::DEBUG }
|
8
10
|
|
9
11
|
# Zookeeper.logger = ZK.logger
|
10
12
|
# Zookeeper.set_debug_level(4)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Pendings
|
2
|
+
def pending_192(msg)
|
3
|
+
if ZK.mri_19x?
|
4
|
+
if block_given?
|
5
|
+
pending(msg) { yield }
|
6
|
+
else
|
7
|
+
pending(msg)
|
8
|
+
end
|
9
|
+
else
|
10
|
+
yield if block_given?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def pending_187(msg)
|
15
|
+
if ZK.mri_187?
|
16
|
+
if block_given?
|
17
|
+
pending(msg) { yield }
|
18
|
+
else
|
19
|
+
pending(msg)
|
20
|
+
end
|
21
|
+
else
|
22
|
+
yield if block_given?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def pending_jruby19(msg)
|
27
|
+
if ZK.ruby_19? and ZK.jruby?
|
28
|
+
if block_given?
|
29
|
+
pending(msg) { yield }
|
30
|
+
else
|
31
|
+
pending(msg)
|
32
|
+
end
|
33
|
+
else
|
34
|
+
yield if block_given?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def pending_in_travis(msg)
|
40
|
+
# defined in the somewhat ill-named 00_test_port_attr.rb
|
41
|
+
if ZK.travis?
|
42
|
+
if block_given?
|
43
|
+
pending("TRAVIS: #{msg}") { yield }
|
44
|
+
else
|
45
|
+
pending("TRAVIS: #{msg}")
|
46
|
+
end
|
47
|
+
else
|
48
|
+
yield if block_given?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -18,6 +18,11 @@ module WaitWatchers
|
|
18
18
|
# wait_until(2) { @a }.should == :fudge
|
19
19
|
#
|
20
20
|
def wait_until(timeout=2)
|
21
|
+
if ZK.travis? and timeout and timeout < 5
|
22
|
+
ZK.logger.debug { "TRAVIS: adjusting wait_until timeout from #{timeout} to 5 sec" }
|
23
|
+
timeout = 5
|
24
|
+
end
|
25
|
+
|
21
26
|
time_to_stop = Time.now + timeout
|
22
27
|
while true
|
23
28
|
rval = yield
|
@@ -29,6 +34,11 @@ module WaitWatchers
|
|
29
34
|
|
30
35
|
# inverse of wait_until
|
31
36
|
def wait_while(timeout=2)
|
37
|
+
if ZK.travis? and timeout and timeout < 5
|
38
|
+
ZK.logger.debug { "TRAVIS: adjusting wait_while timeout from #{timeout} to 5 sec" }
|
39
|
+
timeout = 5
|
40
|
+
end
|
41
|
+
|
32
42
|
time_to_stop = Time.now + timeout
|
33
43
|
while true
|
34
44
|
rval = yield
|
@@ -45,4 +55,3 @@ module WaitWatchers
|
|
45
55
|
end
|
46
56
|
end
|
47
57
|
|
48
|
-
|
data/spec/watch_spec.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe ZK do
|
4
|
+
include_context 'connection opts'
|
5
|
+
|
4
6
|
describe 'watchers' do
|
5
7
|
before do
|
6
8
|
mute_logger do
|
7
|
-
@
|
8
|
-
@zk = ZK.new(@cnx_str)
|
9
|
+
@zk = ZK.new(*connection_args)
|
9
10
|
|
10
11
|
@path = "/_testWatch"
|
11
12
|
wait_until { @zk.connected? }
|
@@ -20,7 +21,7 @@ describe ZK do
|
|
20
21
|
wait_until { !@zk.connected? }
|
21
22
|
end
|
22
23
|
|
23
|
-
ZK.open(
|
24
|
+
ZK.open(*connection_args) { |zk| zk.rm_rf(@path) }
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
@@ -42,78 +43,84 @@ describe ZK do
|
|
42
43
|
callback_called.should be_true
|
43
44
|
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
#
|
49
|
-
# again, we're testing a negative here, so consider this a regression check
|
50
|
-
#
|
51
|
-
def wait_for_events_to_not_be_delivered(events)
|
52
|
-
lambda { wait_until(0.2) { events.length >= 2 } }.should raise_error(WaitWatchers::TimeoutError)
|
53
|
-
end
|
54
|
-
|
55
|
-
it %[should only deliver an event once to each watcher registered for exists?] do
|
56
|
-
events = []
|
57
|
-
|
58
|
-
sub = @zk.register(@path) do |ev|
|
59
|
-
logger.debug "got event #{ev}"
|
60
|
-
events << ev
|
46
|
+
describe :regression do
|
47
|
+
before do
|
48
|
+
pending_in_travis("these tests take too long or time out")
|
61
49
|
end
|
62
50
|
|
63
|
-
|
64
|
-
|
51
|
+
# this is stupid, and a bad test, but we have to check that events
|
52
|
+
# don't get re-delivered to a single registered callback just because
|
53
|
+
# :watch => true was called twice
|
54
|
+
#
|
55
|
+
# again, we're testing a negative here, so consider this a regression check
|
56
|
+
#
|
57
|
+
def wait_for_events_to_not_be_delivered(events)
|
58
|
+
lambda { wait_until(0.2) { events.length >= 2 } }.should raise_error(WaitWatchers::TimeoutError)
|
65
59
|
end
|
66
60
|
|
67
|
-
|
68
|
-
|
69
|
-
wait_for_events_to_not_be_delivered(events)
|
61
|
+
it %[should only deliver an event once to each watcher registered for exists?] do
|
62
|
+
events = []
|
70
63
|
|
71
|
-
|
72
|
-
|
64
|
+
sub = @zk.register(@path) do |ev|
|
65
|
+
logger.debug "got event #{ev}"
|
66
|
+
events << ev
|
67
|
+
end
|
73
68
|
|
74
|
-
|
75
|
-
|
69
|
+
2.times do
|
70
|
+
@zk.exists?(@path, :watch => true).should_not be_true
|
71
|
+
end
|
76
72
|
|
77
|
-
|
73
|
+
@zk.create(@path, '', :mode => :ephemeral)
|
78
74
|
|
79
|
-
|
80
|
-
logger.debug "got event #{ev}"
|
81
|
-
events << ev
|
82
|
-
end
|
75
|
+
wait_for_events_to_not_be_delivered(events)
|
83
76
|
|
84
|
-
|
85
|
-
data, stat = @zk.get(@path, :watch => true)
|
86
|
-
data.should == 'one'
|
77
|
+
events.length.should == 1
|
87
78
|
end
|
88
79
|
|
89
|
-
|
80
|
+
it %[should only deliver an event once to each watcher registered for get] do
|
81
|
+
events = []
|
90
82
|
|
91
|
-
|
83
|
+
@zk.create(@path, 'one', :mode => :ephemeral)
|
92
84
|
|
93
|
-
|
94
|
-
|
85
|
+
sub = @zk.register(@path) do |ev|
|
86
|
+
logger.debug "got event #{ev}"
|
87
|
+
events << ev
|
88
|
+
end
|
95
89
|
|
90
|
+
2.times do
|
91
|
+
data, stat = @zk.get(@path, :watch => true)
|
92
|
+
data.should == 'one'
|
93
|
+
end
|
96
94
|
|
97
|
-
|
98
|
-
events = []
|
95
|
+
@zk.set(@path, 'two')
|
99
96
|
|
100
|
-
|
97
|
+
wait_for_events_to_not_be_delivered(events)
|
101
98
|
|
102
|
-
|
103
|
-
logger.debug "got event #{ev}"
|
104
|
-
events << ev
|
99
|
+
events.length.should == 1
|
105
100
|
end
|
106
101
|
|
107
|
-
2.times do
|
108
|
-
children = @zk.children(@path, :watch => true)
|
109
|
-
children.should be_empty
|
110
|
-
end
|
111
102
|
|
112
|
-
|
103
|
+
it %[should only deliver an event once to each watcher registered for children] do
|
104
|
+
events = []
|
105
|
+
|
106
|
+
@zk.create(@path, '')
|
113
107
|
|
114
|
-
|
108
|
+
sub = @zk.register(@path) do |ev|
|
109
|
+
logger.debug "got event #{ev}"
|
110
|
+
events << ev
|
111
|
+
end
|
112
|
+
|
113
|
+
2.times do
|
114
|
+
children = @zk.children(@path, :watch => true)
|
115
|
+
children.should be_empty
|
116
|
+
end
|
117
|
+
|
118
|
+
@zk.create("#{@path}/pfx", '', :mode => :ephemeral_sequential)
|
115
119
|
|
116
|
-
|
120
|
+
wait_for_events_to_not_be_delivered(events)
|
121
|
+
|
122
|
+
events.length.should == 1
|
123
|
+
end
|
117
124
|
end
|
118
125
|
|
119
126
|
it %[should restrict_new_watches_for? if a successul watch has been set] do
|
@@ -186,113 +193,120 @@ describe ZK do
|
|
186
193
|
before do
|
187
194
|
@events = EventCatcher.new
|
188
195
|
|
189
|
-
|
190
|
-
@events.created << event
|
191
|
-
end
|
196
|
+
[:created, :changed, :child, :deleted].each do |ev_name|
|
192
197
|
|
193
|
-
|
194
|
-
|
195
|
-
|
198
|
+
@zk.register(@path, :only => ev_name) do |event|
|
199
|
+
@events.add(ev_name, event)
|
200
|
+
end
|
196
201
|
|
197
|
-
@zk.register(@path, :child) do |event|
|
198
|
-
@events.child << event
|
199
|
-
end
|
200
|
-
|
201
|
-
@zk.register(@path, :deleted) do |event|
|
202
|
-
@events.deleted << event
|
203
|
-
end
|
204
|
-
|
205
|
-
# this will catch all events, that way we don't have to wait for an
|
206
|
-
# event to *not* be delivered to one of the other callbacks (which is
|
207
|
-
# kinda stupid)
|
208
|
-
@zk.register(@path) do |event|
|
209
|
-
@events.all << event
|
210
202
|
end
|
211
203
|
end
|
212
204
|
|
213
205
|
it %[should deliver only the created event to the created block] do
|
214
|
-
@
|
206
|
+
@events.synchronize do
|
207
|
+
@zk.stat(@path, :watch => true).should_not exist
|
215
208
|
|
216
|
-
|
217
|
-
wait_while { @events.created.empty? }.should be_false
|
218
|
-
@events.created.first.should be_node_created
|
209
|
+
@zk.create(@path)
|
219
210
|
|
220
|
-
|
211
|
+
@events.wait_for_created
|
221
212
|
|
222
|
-
|
213
|
+
@events.created.should_not be_empty
|
214
|
+
@events.created.first.should be_node_created
|
215
|
+
@events.all.should_not be_empty
|
216
|
+
|
217
|
+
@zk.stat(@path, :watch => true).should exist
|
218
|
+
|
219
|
+
@events.all.length.should == 1
|
220
|
+
|
221
|
+
@zk.delete(@path)
|
223
222
|
|
224
|
-
|
223
|
+
@events.wait_for_all
|
224
|
+
end
|
225
225
|
|
226
|
-
|
226
|
+
@events.all.length.should == 2
|
227
227
|
|
228
228
|
# :deleted event was delivered, make sure it didn't get delivered to the :created block
|
229
229
|
@events.created.length.should == 1
|
230
230
|
end
|
231
231
|
|
232
232
|
it %[should deliver only the changed event to the changed block] do
|
233
|
-
@
|
233
|
+
@events.synchronize do
|
234
|
+
@zk.create(@path)
|
234
235
|
|
235
|
-
|
236
|
+
@zk.stat(@path, :watch => true).should exist
|
236
237
|
|
237
|
-
|
238
|
+
@zk.set(@path, 'data')
|
238
239
|
|
239
|
-
|
240
|
+
@events.wait_for_changed
|
241
|
+
end
|
240
242
|
|
243
|
+
@events.changed.should_not be_empty
|
244
|
+
@events.changed.length.should == 1
|
241
245
|
@events.changed.first.should be_node_changed
|
242
246
|
|
243
|
-
@zk.stat(@path, :watch => true).should exist
|
244
|
-
|
245
247
|
@events.all.length.should == 1
|
246
248
|
|
247
|
-
@
|
249
|
+
@events.synchronize do
|
250
|
+
@zk.stat(@path, :watch => true).should exist
|
251
|
+
@zk.delete(@path)
|
252
|
+
@events.wait_for_all
|
253
|
+
end
|
248
254
|
|
249
|
-
|
255
|
+
@events.all.length.should == 2
|
250
256
|
|
251
257
|
# :deleted event was delivered, make sure it didn't get delivered to the :changed block
|
252
258
|
@events.changed.length.should == 1
|
253
259
|
end
|
254
260
|
|
255
261
|
it %[should deliver only the child event to the child block] do
|
256
|
-
|
262
|
+
child_path = nil
|
257
263
|
|
258
|
-
@
|
264
|
+
@events.synchronize do
|
265
|
+
@zk.create(@path)
|
266
|
+
@zk.children(@path, :watch => true).should be_empty
|
259
267
|
|
260
|
-
|
268
|
+
child_path = @zk.create("#{@path}/m", '', :sequence => true)
|
261
269
|
|
262
|
-
|
270
|
+
@events.wait_for_child
|
263
271
|
|
264
|
-
|
272
|
+
@events.child.length.should == 1
|
273
|
+
@events.child.first.should be_node_child
|
265
274
|
|
266
|
-
|
275
|
+
@zk.stat(@path, :watch => true).should exist
|
267
276
|
|
268
|
-
|
277
|
+
@events.all.length.should == 1
|
269
278
|
|
270
|
-
|
279
|
+
@zk.set(@path, '') # equivalent to a 'touch'
|
280
|
+
@events.wait_for_all
|
281
|
+
end
|
271
282
|
|
272
|
-
|
283
|
+
@events.all.length.should == 2
|
273
284
|
|
274
285
|
# :changed event was delivered, make sure it didn't get delivered to the :child block
|
275
286
|
@events.child.length.should == 1
|
276
287
|
end
|
277
288
|
|
278
289
|
it %[should deliver only the deleted event to the deleted block] do
|
279
|
-
@
|
280
|
-
|
281
|
-
|
290
|
+
@events.synchronize do
|
291
|
+
@zk.create(@path)
|
292
|
+
@zk.stat(@path, :watch => true).should exist
|
293
|
+
@zk.delete(@path)
|
282
294
|
|
283
|
-
|
295
|
+
@events.wait_for_deleted
|
296
|
+
@events.wait_while_all { |all| all.empty? }
|
284
297
|
|
285
|
-
|
298
|
+
@events.deleted.should_not be_empty
|
299
|
+
@events.deleted.first.should be_node_deleted
|
300
|
+
@events.all.length.should == 1
|
286
301
|
|
287
|
-
|
302
|
+
@zk.stat(@path, :watch => true).should_not exist
|
288
303
|
|
289
|
-
|
290
|
-
|
291
|
-
@events.all.length.should == 1
|
304
|
+
@zk.create(@path)
|
292
305
|
|
293
|
-
|
306
|
+
@events.wait_for_all
|
307
|
+
end
|
294
308
|
|
295
|
-
|
309
|
+
@events.all.length.should be > 1
|
296
310
|
|
297
311
|
# :deleted event was delivered, make sure it didn't get delivered to the :created block
|
298
312
|
@events.deleted.length.should == 1
|
@@ -301,35 +315,40 @@ describe ZK do
|
|
301
315
|
|
302
316
|
it %[should deliver interested events to a block registered for multiple deliveries] do
|
303
317
|
@events = []
|
318
|
+
@events.extend(MonitorMixin)
|
319
|
+
@cond = @events.new_cond
|
304
320
|
|
305
|
-
@zk.register(@path, [:created, :changed]) do |event|
|
306
|
-
@events
|
321
|
+
@zk.register(@path, :only => [:created, :changed]) do |event|
|
322
|
+
@events.synchronize do
|
323
|
+
@events << event
|
324
|
+
@cond.broadcast
|
325
|
+
end
|
307
326
|
end
|
308
327
|
|
309
|
-
@
|
310
|
-
|
311
|
-
@zk.create(@path)
|
312
|
-
|
313
|
-
wait_while { @events.empty? }
|
328
|
+
@events.synchronize do
|
329
|
+
@zk.stat(@path, :watch => true).should_not exist
|
314
330
|
|
315
|
-
|
331
|
+
@zk.create(@path)
|
316
332
|
|
317
|
-
|
333
|
+
@cond.wait(5)
|
318
334
|
|
319
|
-
|
335
|
+
@events.should_not be_empty
|
336
|
+
@events.length.should == 1
|
337
|
+
@events.first.should be_node_created
|
320
338
|
|
321
|
-
|
339
|
+
@zk.stat(@path, :watch => true).should exist
|
340
|
+
@zk.set(@path, 'blah')
|
322
341
|
|
323
|
-
|
342
|
+
@cond.wait(5)
|
343
|
+
end
|
324
344
|
|
325
345
|
@events.length.should == 2
|
326
|
-
|
327
346
|
@events.last.should be_node_changed
|
328
347
|
end
|
329
348
|
|
330
349
|
it %[should barf if an invalid event name is given] do
|
331
350
|
lambda do
|
332
|
-
@zk.register(@path, :tripping) { }
|
351
|
+
@zk.register(@path, :only => :tripping) { }
|
333
352
|
end.should raise_error(ArgumentError)
|
334
353
|
end
|
335
354
|
end # event interest
|
@@ -339,9 +358,9 @@ describe ZK do
|
|
339
358
|
describe 'live-fire test' do
|
340
359
|
before do
|
341
360
|
@event = nil
|
342
|
-
@cnx_str = "localhost:#{
|
361
|
+
@cnx_str = "localhost:#{ZK.test_port}"
|
343
362
|
|
344
|
-
@zk = ZK.new(
|
363
|
+
@zk = ZK.new(*connection_args) do |zk|
|
345
364
|
@cnx_reg = zk.on_connected { |event| @event = event }
|
346
365
|
end
|
347
366
|
end
|