spec/zk/client_spec.rb in zk-1.3.1 vs spec/zk/client_spec.rb in zk-1.4.0

- old
+ new

@@ -58,62 +58,131 @@ @zk.close! if @zk ZK.open(*connection_args) { |z| z.rm_rf(@base_path) } end - it %[should deliver callbacks in the child] do - pending_in_travis "skip this test, flaky in travis" - pending_rbx('fails in rubinius') do + it %[should deliver callbacks in the child], :fork => true do +# pending_in_travis "skip this test, flaky in travis" + pending_rbx('fails in rubinius') - logger.debug { "Process.pid of parent: #{Process.pid}" } + logger.debug { "Process.pid of parent: #{Process.pid}" } - @zk = ZK.new do |z| - z.on_connected do - logger.debug { "on_connected fired, writing pid to path #{@pids_root}/#{$$}" } - begin - z.create("#{@pids_root}/#{Process.pid}", Process.pid.to_s) - rescue ZK::Exceptions::NodeExists + @zk = ZK.new do |z| + z.on_connected do + logger.debug { "on_connected fired, writing pid to path #{@pids_root}/#{$$}" } + begin + z.create("#{@pids_root}/#{Process.pid}", Process.pid.to_s) + rescue ZK::Exceptions::NodeExists + end + end + end + + @parent_pid = $$ + + @zk.create("#{@pids_root}/#{$$}", $$.to_s) + + event_catcher = EventCatcher.new + + @zk.register(@pids_root) do |event| + if event.node_child? + event_catcher << event + else + @zk.children(@pids_root, :watch => true) + end + end + + logger.debug { "parent watching for children on #{@pids_root}" } + @zk.children(@pids_root, :watch => true) # side-effect, register watch + + @pid = fork do + @zk.reopen + @zk.wait_until_connected + + child_pid_path = "#{@pids_root}/#{$$}" + + create_latch = Zookeeper::Latch.new + + create_sub = @zk.register(child_pid_path) do |event| + if event.node_created? + logger.debug { "got created event, releasing create_latch" } + create_latch.release + else + if @zk.exists?(child_pid_path, :watch => true) + logger.debug { "created behind our backs, releasing create_latch" } + create_latch.release end end end - @parent_pid = $$ + if @zk.exists?(child_pid_path, :watch => true) + logger.debug { "woot! #{child_pid_path} exists!" } + create_sub.unregister + else + logger.debug { "awaiting the create_latch to release" } + create_latch.await + end - @zk.create("#{@pids_root}/#{$$}", $$.to_s) + logger.debug { "now testing for delete event totally created in child" } - event_catcher = EventCatcher.new + delete_latch = Zookeeper::Latch.new - @zk.register(@pids_root, :only => :child) do |event| - event_catcher << event + delete_event = nil + + delete_sub = @zk.register(child_pid_path) do |event| + if event.node_deleted? + delete_event = event + logger.debug { "child got delete event on #{child_pid_path}" } + delete_latch.release + else + unless @zk.exists?(child_pid_path, :watch => true) + logger.debug { "child: someone deleted #{child_pid_path} behind our back" } + delete_latch.release + end + end end - @pid = fork do - @zk.reopen - @zk.wait_until_connected + @zk.exists?(child_pid_path, :watch => true) - wait_until(3) { @zk.exists?("#{@pids_root}/#{$$}") } + @zk.delete(child_pid_path) - logger.debug { "in child: child pid path exists?: %p" % [@zk.exists?("#{@pids_root}/#{$$}")] } + logger.debug { "awaiting deletion event notification" } + delete_latch.await unless delete_event + logger.debug { "deletion event: #{delete_event}" } + + if delete_event exit! 0 + else + exit! 1 end + end - _, stat = Process.wait2(@pid) + # replicates deletion watcher inside child + child_pid_path = "#{@pids_root}/#{@pid}" - stat.should_not be_signaled - stat.should be_exited - stat.should be_success + delete_latch = Latch.new - event_catcher.synchronize do - unless event_catcher.child.empty? - event_catcher.wait_for_child - event_catcher.child.should_not be_empty + delete_sub = @zk.register(child_pid_path) do |event| + if event.node_deleted? + logger.debug { "parent got delete event on #{child_pid_path}" } + delete_latch.release + else + unless @zk.exists?(child_pid_path, :watch => true) + logger.debug { "child: someone deleted #{child_pid_path} behind our back" } + delete_latch.release end end + end - @zk.should be_exists("#{@pids_root}/#{@pid}") + delete_latch.await if @zk.exists?(child_pid_path, :watch => true) - end + _, stat = Process.wait2(@pid) + + stat.should_not be_signaled + stat.should be_exited + stat.should be_success + + end # should deliver callbacks in the child end # forked end # # jruby guard end # ZK::Client::Threaded