zk-eventmachine 0.1.13 → 0.2.0.beta.1

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.
@@ -1,31 +1,23 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  module ZK::ZKEventMachine
4
- shared_examples_for 'Client' do
4
+ describe 'Client' do
5
5
  include EventedSpec::SpecHelper
6
6
  default_timeout 2.0
7
7
 
8
- let(:base_path) { '/zk-em-testing' }
9
-
10
8
  before do
11
- @zk.rm_rf(base_path)
12
- @zk.mkdir_p(base_path)
9
+ @zk = ::ZK.new
10
+ @base_path = '/zk-em-testing'
11
+ @zk.rm_rf(@base_path)
12
+ @zk.mkdir_p(@base_path)
13
+ @zkem = ZK::ZKEventMachine::Client.new('localhost:2181')
13
14
  end
14
15
 
15
16
  after do
16
- @zk.rm_rf(base_path)
17
+ @zk.rm_rf(@base_path)
17
18
  @zk.close!
18
19
  end
19
20
 
20
- def event_mock(name=:event)
21
- flexmock(name).tap do |ev|
22
- ev.should_receive(:node_event?).and_return(false)
23
- ev.should_receive(:state_event?).and_return(true)
24
- ev.should_receive(:zk=).with_any_args
25
- yield ev if block_given?
26
- end
27
- end
28
-
29
21
  describe 'connect' do
30
22
  it %[should return a deferred that fires when connected and then close] do
31
23
  em do
@@ -53,10 +45,48 @@ module ZK::ZKEventMachine
53
45
  end
54
46
  end
55
47
 
48
+ describe 'on_connection_loss' do
49
+ before do
50
+ @path = [@base_path, 'foo'].join('/')
51
+ @data = 'this is data'
52
+ @zk.create(@path, @data)
53
+ end
54
+
55
+ it %[should be called back if the connection is lost] do
56
+ em do
57
+ @zkem.on_connection_lost do |exc|
58
+ logger.debug { "WIN!" }
59
+ exc.should be_kind_of(ZK::Exceptions::ConnectionLoss)
60
+ @zkem.close! { done }
61
+ end
62
+
63
+ @zkem.connect do
64
+ flexmock(@zkem.cnx) do |m|
65
+ m.should_receive(:get).with(Hash).and_return do |hash|
66
+ logger.debug { "client received :get wtih #{hash.inspect}" }
67
+ @user_cb = hash[:callback]
68
+
69
+ EM.next_tick do
70
+ logger.debug { "calling back user cb with connection loss" }
71
+ @user_cb.call(:rc => ZK::Exceptions::CONNECTIONLOSS)
72
+ end
73
+
74
+ { :rc => Zookeeper::ZOK }
75
+ end
76
+ end
77
+
78
+ @zkem.get(@path) do |exc,data|
79
+ exc.should be_kind_of(ZK::Exceptions::ConnectionLoss)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+
56
86
  describe 'get' do
57
87
  describe 'success' do
58
88
  before do
59
- @path = [base_path, 'foo'].join('/')
89
+ @path = [@base_path, 'foo'].join('/')
60
90
  @data = 'this is data'
61
91
  @zk.create(@path, @data)
62
92
  end
@@ -99,7 +129,7 @@ module ZK::ZKEventMachine
99
129
 
100
130
  describe 'failure' do
101
131
  before do
102
- @path = [base_path, 'foo'].join('/')
132
+ @path = [@base_path, 'foo'].join('/')
103
133
  @zk.delete(@path) rescue ZK::Exceptions::NoNode
104
134
  end
105
135
 
@@ -137,7 +167,7 @@ module ZK::ZKEventMachine
137
167
  describe 'create' do
138
168
  describe 'success' do
139
169
  before do
140
- @path = [base_path, 'foo'].join('/')
170
+ @path = [@base_path, 'foo'].join('/')
141
171
  @zk.delete(@path) rescue ZK::Exceptions::NoNode
142
172
 
143
173
  @data = 'this is data'
@@ -203,7 +233,7 @@ module ZK::ZKEventMachine
203
233
 
204
234
  describe 'failure' do
205
235
  before do
206
- @path = [base_path, 'foo'].join('/')
236
+ @path = [@base_path, 'foo'].join('/')
207
237
  @zk.create(@path, '')
208
238
  end
209
239
 
@@ -237,10 +267,11 @@ module ZK::ZKEventMachine
237
267
  end # failure
238
268
  end # create
239
269
 
270
+
240
271
  describe 'set' do
241
272
  describe 'success' do
242
273
  before do
243
- @path = [base_path, 'foo'].join('/')
274
+ @path = [@base_path, 'foo'].join('/')
244
275
  @data = 'this is data'
245
276
  @new_data = 'this is better data'
246
277
  @zk.create(@path, @data)
@@ -290,7 +321,7 @@ module ZK::ZKEventMachine
290
321
 
291
322
  describe 'failure' do
292
323
  before do
293
- @path = [base_path, 'foo'].join('/')
324
+ @path = [@base_path, 'foo'].join('/')
294
325
  @zk.delete(@path) rescue ZK::Exceptions::NoNode
295
326
  end
296
327
 
@@ -326,7 +357,7 @@ module ZK::ZKEventMachine
326
357
 
327
358
  describe 'exists?' do
328
359
  before do
329
- @path = [base_path, 'foo'].join('/')
360
+ @path = [@base_path, 'foo'].join('/')
330
361
  @data = 'this is data'
331
362
  end
332
363
 
@@ -372,7 +403,7 @@ module ZK::ZKEventMachine
372
403
  describe 'stat' do
373
404
  describe 'success' do
374
405
  before do
375
- @path = [base_path, 'foo'].join('/')
406
+ @path = [@base_path, 'foo'].join('/')
376
407
  @data = 'this is data'
377
408
  @zk.create(@path, @data)
378
409
  @orig_stat = @zk.stat(@path)
@@ -414,7 +445,7 @@ module ZK::ZKEventMachine
414
445
 
415
446
  describe 'non-existent node' do
416
447
  before do
417
- @path = [base_path, 'foo'].join('/')
448
+ @path = [@base_path, 'foo'].join('/')
418
449
  @zk.delete(@path) rescue ZK::Exceptions::NoNode
419
450
  end
420
451
 
@@ -443,7 +474,7 @@ module ZK::ZKEventMachine
443
474
  describe 'delete' do
444
475
  describe 'success' do
445
476
  before do
446
- @path = [base_path, 'foo'].join('/')
477
+ @path = [@base_path, 'foo'].join('/')
447
478
  @data = 'this is data'
448
479
  @zk.create(@path, @data)
449
480
  end
@@ -481,7 +512,7 @@ module ZK::ZKEventMachine
481
512
 
482
513
  describe 'failure' do
483
514
  before do
484
- @path = [base_path, 'foo'].join('/')
515
+ @path = [@base_path, 'foo'].join('/')
485
516
  @zk.delete(@path) rescue ZK::Exceptions::NoNode
486
517
  end
487
518
 
@@ -518,7 +549,7 @@ module ZK::ZKEventMachine
518
549
  describe 'children' do
519
550
  describe 'success' do
520
551
  before do
521
- @path = [base_path, 'foo'].join('/')
552
+ @path = [@base_path, 'foo'].join('/')
522
553
  @child_1_path = [@path, 'child_1'].join('/')
523
554
  @child_2_path = [@path, 'child_2'].join('/')
524
555
 
@@ -572,7 +603,7 @@ module ZK::ZKEventMachine
572
603
 
573
604
  describe 'failure' do
574
605
  before do
575
- @path = [base_path, 'foo'].join('/')
606
+ @path = [@base_path, 'foo'].join('/')
576
607
  @zk.delete(@path) rescue ZK::Exceptions::NoNode
577
608
  end
578
609
 
@@ -609,7 +640,7 @@ module ZK::ZKEventMachine
609
640
  describe 'get_acl' do
610
641
  describe 'success' do
611
642
  before do
612
- @path = [base_path, 'foo'].join('/')
643
+ @path = [@base_path, 'foo'].join('/')
613
644
  @data = 'this is data'
614
645
  @zk.create(@path, @data)
615
646
  end
@@ -653,7 +684,7 @@ module ZK::ZKEventMachine
653
684
 
654
685
  describe 'failure' do
655
686
  before do
656
- @path = [base_path, 'foo'].join('/')
687
+ @path = [@base_path, 'foo'].join('/')
657
688
  @zk.delete(@path) rescue ZK::Exceptions::NoNode
658
689
  end
659
690
 
@@ -698,157 +729,6 @@ module ZK::ZKEventMachine
698
729
  it %[should have NoNode as the first argument to the block]
699
730
  end # failure
700
731
  end # set_acl
701
-
702
- describe 'session_id and session_passwd' do
703
- it %[should return a Fixnum for session_id once connected] do
704
- em do
705
- @zkem.session_id.should be_nil
706
-
707
- @zkem.connect do
708
- @zkem.session_id.should be_kind_of(Fixnum)
709
- @zkem.close! { done }
710
- end
711
- end
712
- end
713
-
714
- it %[should return a String for session_passwd once connected] do
715
- em do
716
- @zkem.session_passwd.should be_nil
717
-
718
- @zkem.connect do
719
- @zkem.session_passwd.should be_kind_of(String)
720
- @zkem.close! { done }
721
- end
722
- end
723
- end
724
- end
725
-
726
- describe 'on_connection_lost' do
727
- before do
728
- @path = [base_path, 'foo'].join('/')
729
- @data = 'this is data'
730
- @zk.create(@path, @data)
731
- end
732
-
733
- it %[should be called back if the connection is lost] do
734
- em do
735
- @zkem.on_connection_lost do |exc|
736
- logger.debug { "WIN!" }
737
- exc.should be_kind_of(ZK::Exceptions::ConnectionLoss)
738
- @zkem.close! { done }
739
- end
740
-
741
- @zkem.connect do
742
- flexmock(@zkem.cnx) do |m|
743
- m.should_receive(:get).with(Hash).and_return do |hash|
744
- logger.debug { "client received :get wtih #{hash.inspect}" }
745
- @user_cb = hash[:callback]
746
-
747
- EM.next_tick do
748
- logger.debug { "calling back user cb with connection loss" }
749
- @user_cb.call(:rc => ZK::Exceptions::CONNECTIONLOSS)
750
- end
751
-
752
- { :rc => Zookeeper::ZOK }
753
- end
754
- end
755
-
756
- @zkem.get(@path) do |exc,data|
757
- exc.should be_kind_of(ZK::Exceptions::ConnectionLoss)
758
- end
759
- end
760
- end
761
- end
762
-
763
- it %[should be called if we get a session expired event] do
764
- @zkem.on_connection_lost do |exc|
765
- logger.debug { "WIN!" }
766
- exc.should be_kind_of(ZK::Exceptions::ConnectionLoss)
767
- @zkem.close! { done }
768
- end
769
-
770
- em do
771
- @zkem.connect do
772
- event = event_mock(:connection_loss_event).tap do |ev|
773
- ev.should_receive(:state).and_return(Zookeeper::ZOO_EXPIRED_SESSION_STATE)
774
- end
775
-
776
- EM.next_tick { @zkem.event_handler.process(event) }
777
- end
778
- end
779
- end
780
- end # on_connection_lost
781
-
782
- describe 'on_connected' do
783
- it %[should be called back when a ZOO_CONNECTED_STATE event is received] do
784
- em do
785
- @zkem.on_connected do |event|
786
- logger.debug { "WIN!" }
787
- @zkem.close! { done }
788
- end
789
-
790
- @zkem.connect do
791
- logger.debug { "we connected" }
792
- end
793
- end
794
- end
795
- end # on_connected
796
-
797
- describe 'on_connecting' do
798
- it %[should be called back when a ZOO_CONNECTING_STATE event is received] do
799
- @zkem.on_connecting do |event|
800
- logger.debug { "WIN!" }
801
- @zkem.close! { done }
802
- end
803
-
804
- em do
805
- @zkem.connect do
806
- event = event_mock(:connecting_event).tap do |ev|
807
- ev.should_receive(:state).and_return(Zookeeper::ZOO_CONNECTING_STATE)
808
- end
809
-
810
- EM.next_tick { @zkem.event_handler.process(event) }
811
- end
812
- end
813
- end
814
- end # on_connecting
815
732
  end # Client
816
-
817
- describe 'regular' do
818
-
819
- before do
820
- @zkem = ZK::ZKEventMachine::Client.new('localhost:2181')
821
- @zk = ZK.new.tap { |z| wait_until { z.connected? } }
822
- @zk.should be_connected
823
- end
824
-
825
- it_should_behave_like 'Client'
826
- end
827
-
828
- describe 'chrooted' do
829
- let(:chroot_path) { '/_zkem_chroot_' }
830
- let(:zk_connect_host) { "localhost:2181#{chroot_path}" }
831
-
832
- before :all do
833
- ZK.open('localhost:2181') do |z|
834
- z.rm_rf(chroot_path)
835
- z.mkdir_p(chroot_path)
836
- end
837
- end
838
-
839
- after :all do
840
- ZK.open('localhost:2181') do |z|
841
- z.rm_rf(chroot_path)
842
- end
843
- end
844
-
845
- before do
846
- @zkem = ZK::ZKEventMachine::Client.new(zk_connect_host)
847
- @zk = ZK.new(zk_connect_host).tap { |z| wait_until { z.connected? } }
848
- @zk.should be_connected
849
- end
850
-
851
- it_should_behave_like 'Client'
852
- end
853
733
  end # ZK::ZKEventMachine
854
734
 
@@ -0,0 +1,339 @@
1
+ require 'spec_helper'
2
+
3
+ module ZK
4
+ module ZKEventMachine
5
+ describe 'SynchronyClient' do
6
+ include EventedSpec::SpecHelper
7
+ default_timeout 2.0
8
+
9
+ def em_synchrony(&blk)
10
+ em do
11
+ EM.next_tick { Fiber.new { blk.call }.resume }
12
+ end
13
+ end
14
+
15
+ def with_zksync
16
+ em_synchrony do
17
+ begin
18
+ @zksync.connect
19
+ yield @zksync
20
+ ensure
21
+ @zksync.close!
22
+ done
23
+ end
24
+ end
25
+ end
26
+
27
+ before do
28
+ @zk = ::ZK.new
29
+ @base_path = '/zk-em-testing'
30
+ @zk.rm_rf(@base_path)
31
+ @zk.mkdir_p(@base_path)
32
+ @zksync = ZK::ZKEventMachine::SynchronyClient.new('localhost:2181')
33
+ end
34
+
35
+ after do
36
+ @zk.rm_rf(@base_path)
37
+ @zk.close!
38
+ end
39
+
40
+ describe 'connect' do
41
+ it %[should connect to zookeeper] do
42
+ logger.debug { "about to call connect" }
43
+ em_synchrony do
44
+ @zksync.connect
45
+
46
+ lambda { @zksync.get(@base_path) }.should_not raise_error
47
+
48
+ done { @zksync.close }
49
+ end
50
+ end
51
+ end
52
+
53
+ describe 'get' do
54
+ before do
55
+ @data = "this is data"
56
+ @zk.set(@base_path, @data)
57
+ end
58
+
59
+ it %[should get the data and stat of a node that exists] do
60
+ with_zksync do
61
+ data, stat = @zksync.get(@base_path)
62
+ data.should == @data
63
+ stat.should be_kind_of(ZookeeperStat::Stat)
64
+ end
65
+ end
66
+
67
+ it %[should raise an exception if the node does not exist] do
68
+ with_zksync do
69
+ lambda { @zksync.get('/thispathdoesnotexist') }.should raise_error(ZK::Exceptions::NoNode)
70
+ end
71
+ end
72
+ end
73
+
74
+ describe 'create' do
75
+ describe 'success' do
76
+ before do
77
+ @path = [@base_path, 'foo'].join('/')
78
+ @zk.delete(@path) rescue ZK::Exceptions::NoNode
79
+
80
+ @data = 'this is data'
81
+ end
82
+
83
+ it 'should create a non-sequence node' do
84
+ with_zksync do
85
+ @zksync.create(@path, @data).should == @path
86
+ end
87
+ end
88
+
89
+ it %[should create a sequence node] do
90
+ with_zksync do
91
+ @zksync.create(@path, @data, :sequence => true).should =~ /\A#{@path}\d+\Z/
92
+ end
93
+ end
94
+ end
95
+
96
+ describe 'failure' do
97
+ it %[should barf if the node exists] do
98
+ @path = [@base_path, 'foo'].join('/')
99
+ @zk.create(@path, '')
100
+
101
+ lambda { @zk.create(@path, '') }.should raise_error(ZK::Exceptions::NodeExists)
102
+ end
103
+ end
104
+ end
105
+
106
+ describe 'set' do
107
+ before do
108
+ @path = [@base_path, 'foo'].join('/')
109
+ @data = 'this is data'
110
+ @new_data = 'this is better data'
111
+ @zk.create(@path, @data)
112
+ @orig_stat = @zk.stat(@path)
113
+ end
114
+
115
+ it %[should set the data and return a stat] do
116
+ with_zksync do
117
+ stat = @zksync.set(@path, @new_data)
118
+ stat.should be_instance_of(ZookeeperStat::Stat)
119
+ stat.version.should > @orig_stat.version
120
+
121
+ @zksync.get(@path).first.should == @new_data
122
+ end
123
+ end
124
+
125
+ it %[should raise NoNode if the node doesn't exist] do
126
+ with_zksync do
127
+ lambda { @zksync.set('/thispathdoesnotexist', 'data') }.should raise_error(ZK::Exceptions::NoNode)
128
+ end
129
+ end
130
+
131
+ it %[should raise BadVersion if the version is wrong] do
132
+ with_zksync do
133
+ @zksync.set(@path, @new_data)
134
+ lambda { @zksync.set(@path, 'otherdata', :version => @orig_stat.version) }.should raise_error(ZK::Exceptions::BadVersion)
135
+ end
136
+ end
137
+ end
138
+
139
+ describe 'exists?' do
140
+ before do
141
+ @path = [@base_path, 'foo'].join('/')
142
+ @data = 'this is data'
143
+ end
144
+
145
+ it %[should return true if the node exists] do
146
+ @zk.create(@path, @data)
147
+
148
+ with_zksync do
149
+ @zksync.exists?(@path).should be_true
150
+ end
151
+ end
152
+
153
+ it %[should return false if the node doesn't exist] do
154
+ with_zksync do
155
+ @zksync.exists?(@path).should be_false
156
+ end
157
+ end
158
+ end
159
+
160
+ describe 'stat' do
161
+ describe 'success' do
162
+ before do
163
+ @path = [@base_path, 'foo'].join('/')
164
+ @data = 'this is data'
165
+ @zk.create(@path, @data)
166
+ @orig_stat = @zk.stat(@path)
167
+ end
168
+
169
+ it %[should get the stat] do
170
+ with_zksync do
171
+ stat = @zksync.stat(@path)
172
+
173
+ stat.should_not be_nil
174
+ stat.should == @orig_stat
175
+ stat.should be_instance_of(ZookeeperStat::Stat)
176
+ end
177
+ end
178
+ end
179
+
180
+ describe 'non-existent node' do
181
+ before do
182
+ @path = [@base_path, 'foo'].join('/')
183
+ @zk.delete(@path) rescue ZK::Exceptions::NoNode
184
+ end
185
+
186
+ it %[should not be an error] do
187
+ with_zksync do
188
+ stat = @zksync.stat(@path)
189
+ stat.should_not be_nil
190
+ stat.exists?.should be_false
191
+ stat.should be_instance_of(ZookeeperStat::Stat)
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ describe 'delete' do
198
+ it %[should delete the node] do
199
+ @path = [@base_path, 'foo'].join('/')
200
+ @data = 'this is data'
201
+ @zk.create(@path, @data)
202
+
203
+ with_zksync do
204
+ @zksync.delete(@path)
205
+ end
206
+
207
+ @zk.exists?(@path).should be_false
208
+ end
209
+
210
+ it %[should raise NoNode exception if the node does not exist] do
211
+ @path = [@base_path, 'foo'].join('/')
212
+ @zk.delete(@path) rescue ZK::Exceptions::NoNode
213
+
214
+ with_zksync do
215
+ lambda { @zksync.delete(@path) }.should raise_error(ZK::Exceptions::NoNode)
216
+ end
217
+ end
218
+ end
219
+
220
+ describe 'children' do
221
+ it %[should return the names of the children of the node] do
222
+ @path = [@base_path, 'foo'].join('/')
223
+ @child_1_path = [@path, 'child_1'].join('/')
224
+ @child_2_path = [@path, 'child_2'].join('/')
225
+
226
+ @data = 'this is data'
227
+ @zk.create(@path, @data)
228
+ @zk.create(@child_1_path, '')
229
+ @zk.create(@child_2_path, '')
230
+
231
+ with_zksync do
232
+ children, stat = @zksync.children(@path)
233
+ children.should be_kind_of(Array)
234
+ children.length.should == 2
235
+ children.should include('child_1')
236
+ children.should include('child_2')
237
+
238
+ stat.should be_instance_of(ZookeeperStat::Stat)
239
+ end
240
+ end
241
+
242
+ it %[should raise NoNode if the node doesn't exist] do
243
+ @path = [@base_path, 'foo'].join('/')
244
+ @zk.delete(@path) rescue ZK::Exceptions::NoNode
245
+
246
+ with_zksync do
247
+ lambda { @zksync.children(@path) }.should raise_error(ZK::Exceptions::NoNode)
248
+ end
249
+ end
250
+ end
251
+
252
+ describe 'mkdir_p' do
253
+ it %[should create the directory structure] do
254
+ paths = [ "#{@base_path}/bar/baz", "#{@base_path}/foo/bar/quux" ]
255
+
256
+ with_zksync do
257
+ @zksync.mkdir_p(paths)
258
+ end
259
+
260
+ @zk.exists?("#{@base_path}/bar").should be_true
261
+ @zk.exists?("#{@base_path}/bar/baz").should be_true
262
+ @zk.exists?("#{@base_path}/foo").should be_true
263
+ @zk.exists?("#{@base_path}/foo/bar").should be_true
264
+ @zk.exists?("#{@base_path}/foo/bar/quux").should be_true
265
+ end
266
+ end
267
+
268
+ describe 'rm_rf' do
269
+ it %[should remove all paths listed] do
270
+ @relpaths = ['disco/foo', 'prune/bar', 'fig/bar/one', 'apple/bar/two', 'orange/quux/c/d/e']
271
+
272
+ @roots = @relpaths.map { |p| File.join(@base_path, p.split('/').first) }.uniq
273
+ @paths = @relpaths.map { |n| File.join(@base_path, n) }
274
+
275
+ @paths.each { |n| @zk.mkdir_p(n) }
276
+
277
+ with_zksync do
278
+ @zksync.rm_rf(@roots)
279
+ end
280
+
281
+ @roots.each { |n| @zk.exists?(n).should be_false }
282
+
283
+ @zk.exists?(@base_path).should be_true
284
+ end
285
+ end
286
+
287
+ describe 'event delivery' do
288
+ default_timeout 0.5
289
+
290
+ before do
291
+ @path = [@base_path, 'foo'].join('/')
292
+ @data = 'this is data'
293
+ @zk.create(@path, @data)
294
+ @orig_stat = @zk.stat(@path)
295
+ end
296
+
297
+ it %[should receive an event when the node changes] do
298
+ em_synchrony do
299
+ @orig_fiber = Fiber.current
300
+
301
+ @zksync.connect
302
+ @zksync.should be_connected
303
+
304
+ @zksync.event_handler.register(@path) do |event|
305
+ Fiber.current.should_not == @orig_fiber
306
+
307
+ done { @zksync.close! }
308
+ end
309
+
310
+ @zksync.get(@path, :watch => true)
311
+
312
+ stat = @zksync.set(@path, 'new data')
313
+ logger.debug { "sksync set returned: #{stat}" }
314
+ end
315
+ end
316
+
317
+ it %[should be able to register for events on a node that doesn't exist yet] do
318
+ em_synchrony do
319
+ @new_path = "#{@path}/blah"
320
+
321
+ @zksync.connect
322
+ @zksync.should be_connected
323
+
324
+ @zksync.event_handler.register(@new_path) do |event|
325
+ logger.debug { "got event #{event}" }
326
+
327
+ done { @zksync.close! }
328
+ end
329
+
330
+ @zksync.stat(@new_path, :watch => true)
331
+
332
+ @zksync.create(@new_path, '')
333
+ end
334
+ end
335
+ end
336
+ end
337
+ end
338
+ end
339
+