slyphon-zookeeper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,92 @@
1
+ module ZookeeperExceptions
2
+ # exceptions/errors
3
+ ZOK = 0
4
+ ZSYSTEMERROR = -1
5
+ ZRUNTIMEINCONSISTENCY = -2
6
+ ZDATAINCONSISTENCY = -3
7
+ ZCONNECTIONLOSS = -4
8
+ ZMARSHALLINGERROR = -5
9
+ ZUNIMPLEMENTED = -6
10
+ ZOPERATIONTIMEOUT = -7
11
+ ZBADARGUMENTS = -8
12
+ ZINVALIDSTATE = -9
13
+
14
+ # api errors
15
+ ZAPIERROR = -100
16
+ ZNONODE = -101
17
+ ZNOAUTH = -102
18
+ ZBADVERSION = -103
19
+ ZNOCHILDRENFOREPHEMERALS = -108
20
+ ZNODEEXISTS = -110
21
+ ZNOTEMPTY = -111
22
+ ZSESSIONEXPIRED = -112
23
+ ZINVALIDCALLBACK = -113
24
+ ZINVALIDACL = -114
25
+ ZAUTHFAILED = -115
26
+ ZCLOSING = -116
27
+ ZNOTHING = -117
28
+ ZSESSIONMOVED = -118
29
+
30
+ class ZookeeperException < Exception
31
+ class EverythingOk < ZookeeperException; end
32
+ class SystemError < ZookeeperException; end
33
+ class RunTimeInconsistency < ZookeeperException; end
34
+ class DataInconsistency < ZookeeperException; end
35
+ class ConnectionLoss < ZookeeperException; end
36
+ class MarshallingError < ZookeeperException; end
37
+ class Unimplemented < ZookeeperException; end
38
+ class OperationTimeOut < ZookeeperException; end
39
+ class BadArguments < ZookeeperException; end
40
+ class InvalidState < ZookeeperException; end
41
+ class ApiError < ZookeeperException; end
42
+ class NoNode < ZookeeperException; end
43
+ class NoAuth < ZookeeperException; end
44
+ class BadVersion < ZookeeperException; end
45
+ class NoChildrenForEphemerals < ZookeeperException; end
46
+ class NodeExists < ZookeeperException; end
47
+ class NotEmpty < ZookeeperException; end
48
+ class SessionExpired < ZookeeperException; end
49
+ class InvalidCallback < ZookeeperException; end
50
+ class InvalidACL < ZookeeperException; end
51
+ class AuthFailed < ZookeeperException; end
52
+ class Closing < ZookeeperException; end
53
+ class Nothing < ZookeeperException; end
54
+ class SessionMoved < ZookeeperException; end
55
+ class ConnectionClosed < ZookeeperException; end # this is a Ruby client exception
56
+
57
+ def self.by_code(code)
58
+ case code
59
+ when ZOK then EverythingOk
60
+ when ZSYSTEMERROR then SystemError
61
+ when ZRUNTIMEINCONSISTENCY then RunTimeInconsistency
62
+ when ZDATAINCONSISTENCY then DataInconsistency
63
+ when ZCONNECTIONLOSS then ConnectionLoss
64
+ when ZMARSHALLINGERROR then MarshallingError
65
+ when ZUNIMPLEMENTED then Unimplemented
66
+ when ZOPERATIONTIMEOUT then OperationTimeOut
67
+ when ZBADARGUMENTS then BadArguments
68
+ when ZINVALIDSTATE then InvalidState
69
+ when ZAPIERROR then ApiError
70
+ when ZNONODE then NoNode
71
+ when ZNOAUTH then NoAuth
72
+ when ZBADVERSION then BadVersion
73
+ when ZNOCHILDRENFOREPHEMERALS then NoChildrenForEphemerals
74
+ when ZNODEEXISTS then NodeExists
75
+ when ZNOTEMPTY then NotEmpty
76
+ when ZSESSIONEXPIRED then SessionExpired
77
+ when ZINVALIDCALLBACK then InvalidCallback
78
+ when ZINVALIDACL then InvalidACL
79
+ when ZAUTHFAILED then AuthFailed
80
+ when ZCLOSING then Closing
81
+ when ZNOTHING then Nothing
82
+ when ZSESSIONMOVED then SessionMoved
83
+ else Exception.new("no exception defined for code #{code}")
84
+ end
85
+ end
86
+
87
+ def self.raise_on_error(code)
88
+ exc = self.by_code(code)
89
+ raise exc unless exc == EverythingOk
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,17 @@
1
+ module ZookeeperStat
2
+ class Stat
3
+ attr_reader :version, :exists, :czxid, :mzxid, :ctime, :mtime, :cversion, :aversion, :ephemeralOwner, :dataLength, :numChildren, :pzxid
4
+
5
+ alias :ephemeral_owner :ephemeralOwner
6
+ alias :num_children :numChildren
7
+ alias :data_length :dataLength
8
+
9
+ def initialize(val)
10
+ @exists = !!val
11
+ @czxid, @mzxid, @ctime, @mtime, @version, @cversion, @aversion,
12
+ @ephemeralOwner, @dataLength, @numChildren, @pzxid = val if val.is_a?(Array)
13
+ val.each { |k,v| instance_variable_set "@#{k}", v } if val.is_a?(Hash)
14
+ raise ArgumentError unless (val.is_a?(Hash) or val.is_a?(Array) or val == nil)
15
+ end
16
+ end
17
+ end
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,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "slyphon-zookeeper"
6
+ s.version = '0.1.0'
7
+
8
+ s.authors = ["Phillip Pearson", "Eric Maland", "Evan Weaver", "Brian Wickman", "Jonathan D. Simms"]
9
+ s.email = ["slyphon@gmail.com"]
10
+ s.summary = %q{twitter's zookeeper client}
11
+ s.description = s.summary
12
+
13
+ s.add_development_dependency "rspec", ">= 2.0.0"
14
+ s.add_development_dependency 'flexmock', '~> 0.8.11'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.require_paths = ["lib"]
18
+
19
+ if ENV['JAVA_GEM']
20
+ s.platform = 'java'
21
+ s.add_runtime_dependency('slyphon-log4j', '= 1.2.15')
22
+ s.add_runtime_dependency('slyphon-zookeeper_jar', '= 3.3.1')
23
+ s.require_paths += %w[java]
24
+ else
25
+ s.require_paths += %w[ext]
26
+ s.extensions = 'ext/extconf.rb'
27
+ end
28
+
29
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
31
+ end
@@ -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
+
@@ -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
+
@@ -0,0 +1,31 @@
1
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
2
+ $LOAD_PATH.unshift(File.expand_path('../../ext', __FILE__))
3
+ $LOAD_PATH.uniq!
4
+
5
+ require 'rubygems'
6
+
7
+ gem 'flexmock', '~> 0.8.11'
8
+
9
+ require 'flexmock'
10
+ require 'zookeeper'
11
+
12
+ Zookeeper.logger = Logger.new(File.expand_path('../../test.log', __FILE__)).tap do |log|
13
+ log.level = Logger::DEBUG
14
+ end
15
+
16
+
17
+ RSpec.configure do |config|
18
+ config.mock_with :flexmock
19
+ end
20
+
21
+
22
+ # method to wait until block passed returns true or timeout (default is 10 seconds) is reached
23
+ def wait_until(timeout=10, &block)
24
+ time_to_stop = Time.now + timeout
25
+ until yield do
26
+ break if Time.now > time_to_stop
27
+ sleep 0.3
28
+ end
29
+ end
30
+
31
+
@@ -0,0 +1,924 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ shared_examples_for "all success return values" do
4
+ it %[should have a return code of Zookeeper::ZOK] do
5
+ @rv[:rc].should == Zookeeper::ZOK
6
+ end
7
+
8
+ it %[should have a req_id integer] do
9
+ @rv[:req_id].should be_kind_of(Integer)
10
+ end
11
+ end
12
+
13
+ describe Zookeeper do
14
+ before do
15
+ @path = "/_zktest_"
16
+ @data = "underpants"
17
+
18
+ @zk = Zookeeper.new('localhost:2181')
19
+
20
+ # uncomment for driver debugging output
21
+ #@zk.set_debug_level(Zookeeper::ZOO_LOG_LEVEL_DEBUG) unless defined?(::JRUBY_VERSION)
22
+
23
+ @zk.create(:path => @path, :data => @data)
24
+ end
25
+
26
+ after do
27
+ @zk.delete(:path => @path)
28
+ @zk.close
29
+
30
+ wait_until do
31
+ begin
32
+ !@zk.connected?
33
+ rescue RuntimeError
34
+ true
35
+ end
36
+ end
37
+ end
38
+
39
+ # unfortunately, we can't test w/o exercising other parts of the driver, so
40
+ # if "set" is broken, this test will fail as well (but whaddyagonnado?)
41
+ describe :get do
42
+ describe :sync do
43
+ it_should_behave_like "all success return values"
44
+
45
+ before do
46
+ @rv = @zk.get(:path => @path)
47
+ end
48
+
49
+ it %[should return the data] do
50
+ @rv[:data].should == @data
51
+ end
52
+
53
+ it %[should return a stat] do
54
+ @rv[:stat].should_not be_nil
55
+ @rv[:stat].should be_kind_of(ZookeeperStat::Stat)
56
+ end
57
+ end
58
+
59
+ describe :sync_watch do
60
+ it_should_behave_like "all success return values"
61
+
62
+ before do
63
+ @event = nil
64
+ @watcher = Zookeeper::WatcherCallback.new
65
+
66
+ @rv = @zk.get(:path => @path, :watcher => @watcher, :watcher_context => @path)
67
+ end
68
+
69
+ it %[should return the data] do
70
+ @rv[:data].should == @data
71
+ end
72
+
73
+ it %[should set a watcher on the node] do
74
+ # test the watcher by changing node data
75
+ @zk.set(:path => @path, :data => 'blah')[:rc].should be_zero
76
+
77
+ wait_until(1.0) { @watcher.completed? }
78
+
79
+ @watcher.path.should == @path
80
+ @watcher.context.should == @path
81
+ @watcher.should be_completed
82
+ @watcher.type.should == Zookeeper::ZOO_CHANGED_EVENT
83
+ end
84
+ end
85
+
86
+ describe :async do
87
+ it_should_behave_like "all success return values"
88
+
89
+ before do
90
+ @cb = Zookeeper::DataCallback.new
91
+
92
+ @rv = @zk.get(:path => @path, :callback => @cb, :callback_context => @path)
93
+ wait_until(1.0) { @cb.completed? }
94
+ @cb.should be_completed
95
+ end
96
+
97
+ it %[should have a return code of ZOK] do
98
+ @cb.return_code.should == Zookeeper::ZOK
99
+ end
100
+
101
+ it %[should have the stat object in the callback] do
102
+ @cb.stat.should_not be_nil
103
+ @cb.stat.should be_kind_of(ZookeeperStat::Stat)
104
+ end
105
+
106
+ it %[should have the data] do
107
+ @cb.data.should == @data
108
+ end
109
+ end
110
+
111
+ describe :async_watch do
112
+ it_should_behave_like "all success return values"
113
+
114
+ before do
115
+ @cb = Zookeeper::DataCallback.new
116
+ @watcher = Zookeeper::WatcherCallback.new
117
+
118
+ @rv = @zk.get(:path => @path, :callback => @cb, :callback_context => @path, :watcher => @watcher, :watcher_context => @path)
119
+ wait_until(1.0) { @cb.completed? }
120
+ @cb.should be_completed
121
+ end
122
+
123
+ it %[should have the stat object in the callback] do
124
+ @cb.stat.should_not be_nil
125
+ @cb.stat.should be_kind_of(ZookeeperStat::Stat)
126
+ end
127
+
128
+ it %[should have the data] do
129
+ @cb.data.should == @data
130
+ end
131
+
132
+ it %[should have a return code of ZOK] do
133
+ @cb.return_code.should == Zookeeper::ZOK
134
+ end
135
+
136
+ it %[should set a watcher on the node] do
137
+ @zk.set(:path => @path, :data => 'blah')[:rc].should be_zero
138
+
139
+ wait_until(2) { @watcher.completed? }
140
+
141
+ @watcher.should be_completed
142
+
143
+ @watcher.path.should == @path
144
+ @watcher.context.should == @path
145
+ end
146
+ end
147
+
148
+ describe 'bad arguments' do
149
+ it %[should barf with a BadArguments error] do
150
+ lambda { @zk.get(:bad_arg => 'what!?') }.should raise_error(ZookeeperExceptions::ZookeeperException::BadArguments)
151
+ end
152
+ end
153
+ end # get
154
+
155
+ describe :set do
156
+ before do
157
+ @new_data = "Four score and \007 years ago"
158
+ @stat = @zk.stat(:path => @path)[:stat]
159
+ end
160
+
161
+ describe :sync do
162
+ describe 'without version' do
163
+ it_should_behave_like "all success return values"
164
+
165
+ before do
166
+ @rv = @zk.set(:path => @path, :data => @new_data)
167
+ end
168
+
169
+ it %[should return the new stat] do
170
+ @rv[:stat].should_not be_nil
171
+ @rv[:stat].should be_kind_of(ZookeeperStat::Stat)
172
+ @rv[:stat].version.should > @stat.version
173
+ end
174
+ end
175
+
176
+ describe 'with current version' do
177
+ it_should_behave_like "all success return values"
178
+
179
+ before do
180
+ @rv = @zk.set(:path => @path, :data => @new_data, :version => @stat.version)
181
+ end
182
+
183
+ it %[should return the new stat] do
184
+ @rv[:stat].should_not be_nil
185
+ @rv[:stat].should be_kind_of(ZookeeperStat::Stat)
186
+ @rv[:stat].version.should > @stat.version
187
+ end
188
+ end
189
+
190
+ describe 'with outdated version' do
191
+ before do
192
+ # need to do a couple of sets to ramp up the version
193
+ 3.times { |n| @stat = @zk.set(:path => @path, :data => "#{@new_data}#{n}")[:stat] }
194
+
195
+ @rv = @zk.set(:path => @path, :data => @new_data, :version => 0)
196
+ end
197
+
198
+ it %[should have a return code of ZBADVERSION] do
199
+ @rv[:rc].should == Zookeeper::ZBADVERSION
200
+ end
201
+
202
+ it %[should return a stat with !exists] do
203
+ @rv[:stat].exists.should be_false
204
+ end
205
+ end
206
+ end # sync
207
+
208
+ describe :async do
209
+ before do
210
+ @cb = Zookeeper::StatCallback.new
211
+ end
212
+
213
+ describe 'without version' do
214
+ it_should_behave_like "all success return values"
215
+
216
+ before do
217
+ @rv = @zk.set(:path => @path, :data => @new_data, :callback => @cb, :callback_context => @path)
218
+
219
+ wait_until(2) { @cb.completed? }
220
+ @cb.should be_completed
221
+ end
222
+
223
+ it %[should have the stat in the callback] do
224
+ @cb.stat.should_not be_nil
225
+ @cb.stat.version.should > @stat.version
226
+ end
227
+
228
+ it %[should have a return code of ZOK] do
229
+ @cb.return_code.should == Zookeeper::ZOK
230
+ end
231
+ end
232
+
233
+ describe 'with current version' do
234
+ it_should_behave_like "all success return values"
235
+
236
+ before do
237
+ @rv = @zk.set(:path => @path, :data => @new_data, :callback => @cb, :callback_context => @path, :version => @stat.version)
238
+
239
+ wait_until(2) { @cb.completed? }
240
+ @cb.should be_completed
241
+ end
242
+
243
+ it %[should have the stat in the callback] do
244
+ @cb.stat.should_not be_nil
245
+ @cb.stat.version.should > @stat.version
246
+ end
247
+
248
+ it %[should have a return code of ZOK] do
249
+ @cb.return_code.should == Zookeeper::ZOK
250
+ end
251
+ end
252
+
253
+ describe 'with outdated version' do
254
+ before do
255
+ # need to do a couple of sets to ramp up the version
256
+ 3.times { |n| @stat = @zk.set(:path => @path, :data => "#{@new_data}#{n}")[:stat] }
257
+
258
+ @rv = @zk.set(:path => @path, :data => @new_data, :callback => @cb, :callback_context => @path, :version => 0)
259
+
260
+ wait_until(2) { @cb.completed? }
261
+ @cb.should be_completed
262
+ end
263
+
264
+ it %[should have a return code of ZBADVERSION] do
265
+ @cb.return_code.should == Zookeeper::ZBADVERSION
266
+ end
267
+
268
+ it %[should return a stat with !exists] do
269
+ @cb.stat.exists.should be_false
270
+ end
271
+ end
272
+ end
273
+ end
274
+
275
+ describe :get_children do
276
+ before do
277
+ @children = %w[child0 child1 child2]
278
+
279
+ @children.each do |name|
280
+ @zk.create(:path => "#{@path}/#{name}", :data => name)
281
+ end
282
+ end
283
+
284
+ after do
285
+ @children.each do |name|
286
+ @zk.delete(:path => "#{@path}/#{name}")
287
+ end
288
+ end
289
+
290
+ describe :sync do
291
+ it_should_behave_like "all success return values"
292
+
293
+ before do
294
+ @rv = @zk.get_children(:path => @path)
295
+ end
296
+
297
+ it %[should have an array of names of the children] do
298
+ @rv[:children].should be_kind_of(Array)
299
+ @rv[:children].length.should == 3
300
+ @rv[:children].sort.should == @children.sort
301
+ end
302
+
303
+ # "Three shall be the number of the counting, and the number of the counting shall be 3"
304
+
305
+ it %[should have a stat object whose num_children is 3] do
306
+ @rv[:stat].should_not be_nil
307
+ @rv[:stat].should be_kind_of(ZookeeperStat::Stat)
308
+ @rv[:stat].num_children.should == 3
309
+ end
310
+ end
311
+
312
+ describe :sync_watch do
313
+ it_should_behave_like "all success return values"
314
+
315
+ before do
316
+ @addtl_child = 'child3'
317
+
318
+ @watcher = Zookeeper::WatcherCallback.new
319
+
320
+ @rv = @zk.get_children(:path => @path, :watcher => @watcher, :watcher_context => @path)
321
+ end
322
+
323
+ after do
324
+ @zk.delete(:path => "#{@path}/#{@addtl_child}")
325
+ end
326
+
327
+ it %[should have an array of names of the children] do
328
+ @rv[:children].should be_kind_of(Array)
329
+ @rv[:children].length.should == 3
330
+ @rv[:children].sort.should == @children.sort
331
+ end
332
+
333
+ it %[should have a stat object whose num_children is 3] do
334
+ @rv[:stat].should_not be_nil
335
+ @rv[:stat].should be_kind_of(ZookeeperStat::Stat)
336
+ @rv[:stat].num_children.should == 3
337
+ end
338
+
339
+ it %[should set a watcher for children on the node] do
340
+ @watcher.should_not be_completed
341
+
342
+ @zk.create(:path => "#{@path}/#{@addtl_child}", :data => '')[:rc].should == Zookeeper::ZOK
343
+
344
+ wait_until { @watcher.completed? }
345
+ @watcher.should be_completed
346
+
347
+ @watcher.path.should == @path
348
+ @watcher.context.should == @path
349
+ @watcher.type.should == Zookeeper::ZOO_CHILD_EVENT
350
+ end
351
+ end
352
+
353
+ describe :async do
354
+ it_should_behave_like "all success return values"
355
+
356
+ before do
357
+ @cb = ZookeeperCallbacks::StringsCallback.new
358
+ @rv = @zk.get_children(:path => @path, :callback => @cb, :callback_context => @path)
359
+
360
+ wait_until { @cb.completed? }
361
+ @cb.should be_completed
362
+ end
363
+
364
+ it %[should succeed] do
365
+ @cb.return_code.should == Zookeeper::ZOK
366
+ end
367
+
368
+ it %[should return an array of children] do
369
+ @cb.children.should be_kind_of(Array)
370
+ @cb.children.length.should == 3
371
+ @cb.children.sort.should == @children.sort
372
+ end
373
+
374
+ it %[should have a stat object whose num_children is 3] do
375
+ @cb.stat.should_not be_nil
376
+ @cb.stat.should be_kind_of(ZookeeperStat::Stat)
377
+ @cb.stat.num_children.should == 3
378
+ end
379
+ end
380
+
381
+ describe :async_watch do
382
+ it_should_behave_like "all success return values"
383
+
384
+ before do
385
+ @addtl_child = 'child3'
386
+
387
+ @watcher = Zookeeper::WatcherCallback.new
388
+ @cb = ZookeeperCallbacks::StringsCallback.new
389
+
390
+ @rv = @zk.get_children(:path => @path, :watcher => @watcher, :watcher_context => @path, :callback => @cb, :callback_context => @path)
391
+ wait_until { @cb.completed? }
392
+ @cb.should be_completed
393
+ end
394
+
395
+ after do
396
+ @zk.delete(:path => "#{@path}/#{@addtl_child}")
397
+ end
398
+
399
+ it %[should succeed] do
400
+ @cb.return_code.should == Zookeeper::ZOK
401
+ end
402
+
403
+ it %[should return an array of children] do
404
+ @cb.children.should be_kind_of(Array)
405
+ @cb.children.length.should == 3
406
+ @cb.children.sort.should == @children.sort
407
+ end
408
+
409
+ it %[should have a stat object whose num_children is 3] do
410
+ @cb.stat.should_not be_nil
411
+ @cb.stat.should be_kind_of(ZookeeperStat::Stat)
412
+ @cb.stat.num_children.should == 3
413
+ end
414
+
415
+ it %[should set a watcher for children on the node] do
416
+ @watcher.should_not be_completed
417
+
418
+ @zk.create(:path => "#{@path}/#{@addtl_child}", :data => '')[:rc].should == Zookeeper::ZOK
419
+
420
+ wait_until { @watcher.completed? }
421
+ @watcher.should be_completed
422
+
423
+ @watcher.path.should == @path
424
+ @watcher.context.should == @path
425
+ @watcher.type.should == Zookeeper::ZOO_CHILD_EVENT
426
+ end
427
+ end
428
+ end
429
+
430
+ # NOTE: the jruby version of stat on non-existent node will have a
431
+ # return_code of 0, but the C version will have a return_code of -101
432
+ describe :stat do
433
+ describe :sync do
434
+ it_should_behave_like "all success return values"
435
+
436
+ before do
437
+ @rv = @zk.stat(:path => @path)
438
+ end
439
+
440
+ it %[should have a stat object] do
441
+ @rv[:stat].should be_kind_of(Zookeeper::Stat)
442
+ end
443
+ end
444
+
445
+ describe :sync_watch do
446
+ it_should_behave_like "all success return values"
447
+
448
+ before do
449
+ @watcher = Zookeeper::WatcherCallback.new
450
+
451
+ @rv = @zk.stat(:path => @path, :watcher => @watcher, :watcher_context => @path)
452
+ end
453
+
454
+ it %[should have a stat object] do
455
+ @rv[:stat].should be_kind_of(Zookeeper::Stat)
456
+ end
457
+
458
+ it %[should set a watcher for data changes on the node] do
459
+ @watcher.should_not be_completed
460
+
461
+ @zk.set(:path => @path, :data => 'skunk')[:rc].should == Zookeeper::ZOK
462
+
463
+ wait_until { @watcher.completed? }
464
+ @watcher.should be_completed
465
+
466
+ @watcher.path.should == @path
467
+ @watcher.context.should == @path
468
+ @watcher.type.should == Zookeeper::ZOO_CHANGED_EVENT
469
+ end
470
+ end
471
+
472
+ describe :async do
473
+ it_should_behave_like "all success return values"
474
+
475
+ before do
476
+ @cb = ZookeeperCallbacks::StatCallback.new
477
+ @rv = @zk.stat(:path => @path, :callback => @cb, :callback_context => @path)
478
+
479
+ wait_until { @cb.completed? }
480
+ @cb.should be_completed
481
+ end
482
+
483
+ it %[should succeed] do
484
+ @cb.return_code.should == Zookeeper::ZOK
485
+ end
486
+
487
+ it %[should have a stat object] do
488
+ @cb.stat.should be_kind_of(Zookeeper::Stat)
489
+ end
490
+ end
491
+
492
+ describe :async_watch do
493
+ it_should_behave_like "all success return values"
494
+
495
+ before do
496
+ @addtl_child = 'child3'
497
+
498
+ @watcher = Zookeeper::WatcherCallback.new
499
+
500
+ @cb = ZookeeperCallbacks::StatCallback.new
501
+ @rv = @zk.stat(:path => @path, :callback => @cb, :callback_context => @path, :watcher => @watcher, :watcher_context => @path)
502
+
503
+ wait_until { @cb.completed? }
504
+ @cb.should be_completed
505
+ end
506
+
507
+ after do
508
+ @zk.delete(:path => "#{@path}/#{@addtl_child}")
509
+ end
510
+
511
+ it %[should succeed] do
512
+ @cb.return_code.should == Zookeeper::ZOK
513
+ end
514
+
515
+ it %[should have a stat object] do
516
+ @cb.stat.should be_kind_of(Zookeeper::Stat)
517
+ end
518
+
519
+ it %[should set a watcher for data changes on the node] do
520
+ @watcher.should_not be_completed
521
+
522
+ @zk.set(:path => @path, :data => 'skunk')[:rc].should == Zookeeper::ZOK
523
+
524
+ wait_until { @watcher.completed? }
525
+ @watcher.should be_completed
526
+
527
+ @watcher.path.should == @path
528
+ @watcher.context.should == @path
529
+ @watcher.type.should == Zookeeper::ZOO_CHANGED_EVENT
530
+ end
531
+ end
532
+ end # stat
533
+
534
+ describe :create do
535
+ before do
536
+ # remove the path set up by the global 'before' block
537
+ @zk.delete(:path => @path)
538
+ end
539
+
540
+ describe :sync do
541
+ describe :default_flags do
542
+ it_should_behave_like "all success return values"
543
+
544
+ before do
545
+ @rv = @zk.create(:path => @path)
546
+ end
547
+
548
+ it %[should return the path that was set] do
549
+ @rv[:path].should == @path
550
+ end
551
+
552
+ it %[should have created a permanent node] do
553
+ st = @zk.stat(:path => @path)
554
+ st[:rc].should == Zookeeper::ZOK
555
+
556
+ st[:stat].ephemeral_owner.should == 0
557
+ end
558
+ end
559
+
560
+ describe :ephemeral do
561
+ it_should_behave_like "all success return values"
562
+
563
+ before do
564
+ @rv = @zk.create(:path => @path, :ephemeral => true)
565
+ end
566
+
567
+ it %[should return the path that was set] do
568
+ @rv[:path].should == @path
569
+ end
570
+
571
+ it %[should have created a ephemeral node] do
572
+ st = @zk.stat(:path => @path)
573
+ st[:rc].should == Zookeeper::ZOK
574
+
575
+ st[:stat].ephemeral_owner.should_not be_zero
576
+ end
577
+ end
578
+
579
+ describe :sequence do
580
+ it_should_behave_like "all success return values"
581
+
582
+ before do
583
+ @orig_path = @path
584
+ @rv = @zk.create(:path => @path, :sequence => true)
585
+ @path = @rv[:path] # make sure this gets cleaned up
586
+ end
587
+
588
+ it %[should return the path that was set] do
589
+ @rv[:path].should_not == @orig_path
590
+ end
591
+
592
+ it %[should have created a permanent node] do
593
+ st = @zk.stat(:path => @path)
594
+ st[:rc].should == Zookeeper::ZOK
595
+
596
+ st[:stat].ephemeral_owner.should be_zero
597
+ end
598
+ end
599
+
600
+ describe :ephemeral_sequence do
601
+ it_should_behave_like "all success return values"
602
+
603
+ before do
604
+ @orig_path = @path
605
+ @rv = @zk.create(:path => @path, :sequence => true, :ephemeral => true)
606
+ @path = @rv[:path] # make sure this gets cleaned up
607
+ end
608
+
609
+ it %[should return the path that was set] do
610
+ @rv[:path].should_not == @orig_path
611
+ end
612
+
613
+ it %[should have created an ephemeral node] do
614
+ st = @zk.stat(:path => @path)
615
+ st[:rc].should == Zookeeper::ZOK
616
+
617
+ st[:stat].ephemeral_owner.should_not be_zero
618
+ end
619
+ end
620
+
621
+ describe :acl do
622
+ it %[should work] do
623
+ pending "need to write acl tests"
624
+ end
625
+ end
626
+ end
627
+
628
+ describe :async do
629
+ before do
630
+ @cb = ZookeeperCallbacks::StringCallback.new
631
+ end
632
+
633
+ describe :default_flags do
634
+ it_should_behave_like "all success return values"
635
+
636
+ before do
637
+ @rv = @zk.create(:path => @path, :callback => @cb, :callback_context => @path)
638
+ wait_until(2) { @cb.completed? }
639
+ @cb.should be_completed
640
+ end
641
+
642
+ it %[should have a path] do
643
+ @cb.path.should_not be_nil
644
+ end
645
+
646
+ it %[should return the path that was set] do
647
+ @cb.path.should == @path
648
+ end
649
+
650
+ it %[should have created a permanent node] do
651
+ st = @zk.stat(:path => @path)
652
+ st[:rc].should == Zookeeper::ZOK
653
+
654
+ st[:stat].ephemeral_owner.should == 0
655
+ end
656
+ end
657
+
658
+ describe :ephemeral do
659
+ it_should_behave_like "all success return values"
660
+
661
+ before do
662
+ @rv = @zk.create(:path => @path, :ephemeral => true, :callback => @cb, :callback_context => @path)
663
+ wait_until(2) { @cb.completed? }
664
+ @cb.should be_completed
665
+ end
666
+
667
+ it %[should have a path] do
668
+ @cb.path.should_not be_nil
669
+ end
670
+
671
+ it %[should return the path that was set] do
672
+ @cb.path.should == @path
673
+ end
674
+
675
+ it %[should have created a ephemeral node] do
676
+ st = @zk.stat(:path => @path)
677
+ st[:rc].should == Zookeeper::ZOK
678
+
679
+ st[:stat].ephemeral_owner.should_not be_zero
680
+ end
681
+ end
682
+
683
+ describe :sequence do
684
+ it_should_behave_like "all success return values"
685
+
686
+ before do
687
+ @orig_path = @path
688
+ @rv = @zk.create(:path => @path, :sequence => true, :callback => @cb, :callback_context => @path)
689
+
690
+ wait_until(2) { @cb.completed? }
691
+ @cb.should be_completed
692
+
693
+ @path = @cb.path
694
+ end
695
+
696
+ it %[should have a path] do
697
+ @cb.path.should_not be_nil
698
+ end
699
+
700
+ it %[should return the path that was set] do
701
+ @cb.path.should_not == @orig_path
702
+ end
703
+
704
+ it %[should have created a permanent node] do
705
+ st = @zk.stat(:path => @path)
706
+ st[:rc].should == Zookeeper::ZOK
707
+
708
+ st[:stat].ephemeral_owner.should be_zero
709
+ end
710
+ end
711
+
712
+ describe :ephemeral_sequence do
713
+ it_should_behave_like "all success return values"
714
+
715
+ before do
716
+ @orig_path = @path
717
+ @rv = @zk.create(:path => @path, :sequence => true, :ephemeral => true, :callback => @cb, :callback_context => @path)
718
+ @path = @rv[:path] # make sure this gets cleaned up
719
+
720
+ wait_until(2) { @cb.completed? }
721
+ @cb.should be_completed
722
+ @path = @cb.path
723
+ end
724
+
725
+ it %[should have a path] do
726
+ @cb.path.should_not be_nil
727
+ end
728
+
729
+ it %[should return the path that was set] do
730
+ @path.should_not == @orig_path
731
+ end
732
+
733
+ it %[should have created an ephemeral node] do
734
+ st = @zk.stat(:path => @path)
735
+ st[:rc].should == Zookeeper::ZOK
736
+
737
+ st[:stat].ephemeral_owner.should_not be_zero
738
+ end
739
+ end
740
+
741
+ describe :acl do
742
+ it %[should work] do
743
+ pending "need to write acl tests"
744
+ end
745
+ end
746
+ end
747
+ end
748
+
749
+ describe :delete do
750
+ describe :sync do
751
+ describe 'without version' do
752
+ it_should_behave_like "all success return values"
753
+
754
+ before do
755
+ @zk.create(:path => @path)
756
+ @rv = @zk.delete(:path => @path)
757
+ end
758
+
759
+ it %[should have deleted the node] do
760
+ @zk.stat(:path => @path)[:stat].exists.should be_false
761
+ end
762
+ end
763
+
764
+ describe 'with current version' do
765
+ it_should_behave_like "all success return values"
766
+
767
+ before do
768
+ @zk.create(:path => @path)
769
+
770
+ @stat = @zk.stat(:path => @path)[:stat]
771
+ @stat.exists.should be_true
772
+
773
+ @rv = @zk.delete(:path => @path, :version => @stat.version)
774
+ end
775
+
776
+ it %[should have deleted the node] do
777
+ @zk.stat(:path => @path)[:stat].exists.should be_false
778
+ end
779
+ end
780
+
781
+ describe 'with old version' do
782
+ before do
783
+ 3.times { |n| @stat = @zk.set(:path => @path, :data => n.to_s)[:stat] }
784
+
785
+ @rv = @zk.delete(:path => @path, :version => 0)
786
+ end
787
+
788
+ it %[should have a return code of ZBADVERSION] do
789
+ @rv[:rc].should == Zookeeper::ZBADVERSION
790
+ end
791
+ end
792
+ end # sync
793
+
794
+ describe :async do
795
+ before do
796
+ @cb = ZookeeperCallbacks::VoidCallback.new
797
+ end
798
+
799
+ describe 'without version' do
800
+ it_should_behave_like "all success return values"
801
+
802
+ before do
803
+ @rv = @zk.delete(:path => @path, :callback => @cb, :callback_context => @path)
804
+ wait_until { @cb.completed? }
805
+ @cb.should be_completed
806
+ end
807
+
808
+ it %[should have a success return_code] do
809
+ @cb.return_code.should == Zookeeper::ZOK
810
+ end
811
+
812
+ it %[should have deleted the node] do
813
+ @zk.stat(:path => @path)[:stat].exists.should be_false
814
+ end
815
+ end
816
+
817
+ describe 'with current version' do
818
+ it_should_behave_like "all success return values"
819
+
820
+ before do
821
+ @stat = @zk.stat(:path => @path)[:stat]
822
+ @rv = @zk.delete(:path => @path, :version => @stat.version, :callback => @cb, :callback_context => @path)
823
+ wait_until { @cb.completed? }
824
+ @cb.should be_completed
825
+ end
826
+
827
+ it %[should have a success return_code] do
828
+ @cb.return_code.should == Zookeeper::ZOK
829
+ end
830
+
831
+ it %[should have deleted the node] do
832
+ @zk.stat(:path => @path)[:stat].exists.should be_false
833
+ end
834
+ end
835
+
836
+ describe 'with old version' do
837
+ before do
838
+ 3.times { |n| @stat = @zk.set(:path => @path, :data => n.to_s)[:stat] }
839
+
840
+ @rv = @zk.delete(:path => @path, :version => 0, :callback => @cb, :callback_context => @path)
841
+ wait_until { @cb.completed? }
842
+ @cb.should be_completed
843
+ end
844
+
845
+ it %[should have a return code of ZBADVERSION] do
846
+ @cb.return_code.should == Zookeeper::ZBADVERSION
847
+ end
848
+ end
849
+ end
850
+ end # delete
851
+
852
+ describe :get_acl do
853
+ describe :sync do
854
+ it_should_behave_like "all success return values"
855
+
856
+ before do
857
+ @rv = @zk.get_acl(:path => @path)
858
+ end
859
+
860
+ it %[should return a stat for the path] do
861
+ @rv[:stat].should be_kind_of(ZookeeperStat::Stat)
862
+ end
863
+
864
+ it %[should return the acls] do
865
+ acls = @rv[:acl]
866
+ acls.should be_kind_of(Array)
867
+ h = acls.first
868
+
869
+ h.should be_kind_of(Hash)
870
+
871
+ h[:perms].should == Zookeeper::ZOO_PERM_ALL
872
+ h[:id][:scheme].should == 'world'
873
+ h[:id][:id].should == 'anyone'
874
+ end
875
+ end
876
+
877
+ describe :async do
878
+ it_should_behave_like "all success return values"
879
+
880
+ before do
881
+ @cb = Zookeeper::ACLCallback.new
882
+ @rv = @zk.get_acl(:path => @path, :callback => @cb, :callback_context => @path)
883
+
884
+ wait_until(2) { @cb.completed? }
885
+ @cb.should be_completed
886
+ end
887
+
888
+ it %[should return a stat for the path] do
889
+ @cb.stat.should be_kind_of(ZookeeperStat::Stat)
890
+ end
891
+
892
+ it %[should return the acls] do
893
+ acls = @cb.acl
894
+ acls.should be_kind_of(Array)
895
+
896
+ acl = acls.first
897
+ acl.should be_kind_of(ZookeeperACLs::ACL)
898
+
899
+ acl.perms.should == Zookeeper::ZOO_PERM_ALL
900
+
901
+ acl.id.scheme.should == 'world'
902
+ acl.id.id.should == 'anyone'
903
+ end
904
+ end
905
+ end
906
+
907
+ describe :set_acl do
908
+
909
+ before do
910
+ @perms = 5
911
+ @new_acl = [ZookeeperACLs::ACL.new(:perms => @perms, :id => ZookeeperACLs::ZOO_ANYONE_ID_UNSAFE)]
912
+ pending("No idea how to set ACLs")
913
+ end
914
+
915
+ describe :sync do
916
+ it_should_behave_like "all success return values"
917
+
918
+ before do
919
+ @rv = @zk.set_acl(:path => @path, :acl => @new_acl)
920
+ end
921
+
922
+ end
923
+ end
924
+ end