zk-eventmachine 0.1.13 → 0.2.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+