em-pg-client-12 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,619 @@
1
+ NOTIFY_PAYLOAD = defined?(PG.library_version) && PG.library_version >= 90000
2
+ NOTIFY_PAYLOAD_QUERY = NOTIFY_PAYLOAD ? %q[NOTIFY "ruby-em-pg-client", 'foo'] : %q[NOTIFY "ruby-em-pg-client"]
3
+
4
+ module PGSpecMacros
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ def pg_exec_and_check(client, method, *args, &additional_checks)
10
+ client.__send__(method, *args) do |result|
11
+ result.should be_an_instance_of PG::Result
12
+ additional_checks.call(result) if additional_checks
13
+ EM.stop
14
+ end.should be_a_kind_of ::EM::Deferrable
15
+ end
16
+
17
+ def pg_exec_and_check_with_error(client, stop, err_class, err_message, method, *args, &additional_checks)
18
+ client.__send__(method, *args) do |exception|
19
+ exception.should be_an_instance_of err_class
20
+ exception.to_s.should include err_message if err_message
21
+ additional_checks.call(exception) if additional_checks
22
+ EM.next_tick { EM.stop } if stop
23
+ end.should be_a_kind_of ::EM::Deferrable
24
+ end
25
+
26
+ def ensure_em_stop
27
+ yield
28
+ ensure
29
+ EM.stop
30
+ end
31
+
32
+ module ClassMethods
33
+ def it_should_execute(text, method, *args)
34
+ it "should #{text}" do
35
+ pg_exec_and_check(@client, method, *args)
36
+ end
37
+ end
38
+
39
+ def it_should_execute_with_error(text, err_class, err_message, method, *args)
40
+ it "should #{text}" do
41
+ pg_exec_and_check_with_error(@client, true, err_class, err_message, method, *args)
42
+ end
43
+ end
44
+
45
+ def it_should_rollback
46
+ it_should_execute("rollback transaction", :query_defer, 'ROLLBACK')
47
+ end
48
+
49
+ def it_should_begin
50
+ it_should_execute("begin transaction", :query_defer, 'BEGIN TRANSACTION')
51
+ end
52
+ end
53
+ end
54
+
55
+ shared_context 'em-pg common before' do
56
+
57
+ around(:each) do |testcase|
58
+ EM.run do
59
+ EM.stop if testcase.call.is_a? Exception
60
+ end
61
+ end
62
+
63
+ before(:all) do
64
+ @cdates = []
65
+ @values = Array(('AA'..'ZZ').each_with_index)
66
+ ENV['PGCLIENTENCODING'] = nil
67
+ Encoding.default_internal = nil
68
+ @client = described_class.new
69
+ end
70
+
71
+ after(:all) do
72
+ @client.close
73
+ end
74
+
75
+ it "should be a client #{PG::VERSION}" do
76
+ ensure_em_stop do
77
+ @client.should be_an_instance_of described_class
78
+ end
79
+ end
80
+
81
+ it "should have disabled async_autoreconnect" do
82
+ ensure_em_stop do
83
+ @client.async_autoreconnect.should be_false
84
+ end
85
+ end
86
+
87
+ it "should enable async_autoreconnect" do
88
+ ensure_em_stop do
89
+ @client.async_autoreconnect = true
90
+ @client.async_autoreconnect.should be_true
91
+ end
92
+ end
93
+
94
+ it "should have same internal and external encoding" do
95
+ ensure_em_stop do
96
+ @client.external_encoding.should be @client.internal_encoding
97
+ end
98
+ end
99
+
100
+ it_should_begin
101
+
102
+ it_should_execute("drop table `foo` if exists",
103
+ :query_defer, 'DROP TABLE IF EXISTS foo')
104
+
105
+ it_should_execute("create simple table `foo`",
106
+ :query_defer, 'CREATE TABLE foo (id integer,cdate timestamp with time zone,data varchar)')
107
+
108
+ end
109
+
110
+ shared_context 'em-pg common after' do
111
+
112
+ if described_class.single_row_mode?
113
+
114
+ it "should get each result in single row mode" do
115
+ @client.single_row_mode?.should be_true
116
+ @client.get_result_defer do |result|
117
+ result.should be_nil
118
+ @client.send_query('SELECT data, id FROM foo order by id')
119
+ @client.set_single_row_mode
120
+ EM::Iterator.new(@values, 1).map(proc{ |(data, id), iter|
121
+ @client.get_result_defer do |result|
122
+ result.should be_an_instance_of PG::Result
123
+ result.check
124
+ result.result_status.should eq PG::PGRES_SINGLE_TUPLE
125
+ value = result.to_a
126
+ value.should eq [{'data' => data, 'id' => id.to_s}]
127
+ result.clear
128
+ iter.return value
129
+ end.should be_a_kind_of ::EM::Deferrable
130
+ }, proc{ |results|
131
+ results.length.should eq @values.length
132
+ @client.get_result_defer do |result|
133
+ result.should be_an_instance_of PG::Result
134
+ result.check
135
+ result.result_status.should eq PG::PGRES_TUPLES_OK
136
+ result.to_a.should eq []
137
+ result.clear
138
+ @client.get_result_defer do |result|
139
+ result.should be_nil
140
+ EM.stop
141
+ end.should be_a_kind_of ::EM::Deferrable
142
+ end.should be_a_kind_of ::EM::Deferrable
143
+ })
144
+ end.should be_a_kind_of ::EM::Deferrable
145
+ end
146
+
147
+ end
148
+
149
+ it_should_execute("create prepared statement",
150
+ :prepare_defer, 'get_foo', 'SELECT * FROM foo order by id')
151
+
152
+ it "should describe prepared statement" do
153
+ pg_exec_and_check(@client, :describe_prepared_defer, 'get_foo') do |result|
154
+ result.nfields.should eq 3
155
+ result.fname(0).should eq 'id'
156
+ result.values.should be_empty
157
+ end
158
+ end
159
+
160
+ it "should read foo table with prepared statement" do
161
+ pg_exec_and_check(@client, :exec_prepared_defer, 'get_foo') do |result|
162
+ result.each_with_index do |row, i|
163
+ row['id'].to_i.should == i
164
+ DateTime.parse(row['cdate']).should == @cdates[i]
165
+ row['data'].should == @values[i][0]
166
+ end
167
+ end
168
+ end
169
+
170
+ it_should_execute("declare cursor",
171
+ :query_defer, 'DECLARE foobar SCROLL CURSOR FOR SELECT * FROM foo')
172
+
173
+ it "should fetch two rows from table" do
174
+ pg_exec_and_check(@client, :query_defer, 'FETCH FORWARD 2 FROM foobar') do |result|
175
+ result.nfields.should eq 3
176
+ result.fname(0).should eq 'id'
177
+ result.values.length.should eq 2
178
+ end
179
+ end
180
+
181
+ it "should describe cursor with describe_portal" do
182
+ pg_exec_and_check(@client, :describe_portal_defer, 'foobar') do |result|
183
+ result.nfields.should eq 3
184
+ result.fname(0).should eq 'id'
185
+ end
186
+ end
187
+
188
+ it_should_execute("close cursor", :query_defer, 'CLOSE foobar')
189
+
190
+ it "should connect to database asynchronously" do
191
+ this = :first
192
+ Encoding.default_internal = Encoding::ISO_8859_1
193
+ described_class.connect_defer do |conn|
194
+ this = :second
195
+ Encoding.default_internal = nil
196
+ conn.should be_an_instance_of described_class
197
+ conn.external_encoding.should_not eq(conn.internal_encoding)
198
+ conn.internal_encoding.should be Encoding::ISO_8859_1
199
+ conn.get_client_encoding.should eq "LATIN1"
200
+ pg_exec_and_check(conn, :query_defer, 'SELECT pg_database_size(current_database());') do |result|
201
+ result[0]['pg_database_size'].to_i.should be > 0
202
+ end
203
+ end.should be_a_kind_of ::EM::Deferrable
204
+ this.should be :first
205
+ end
206
+
207
+ it "should connect without setting incompatible encoding" do
208
+ this = :first
209
+ Encoding.default_internal = Encoding::Emacs_Mule
210
+ described_class.connect_defer do |conn|
211
+ this = :second
212
+ Encoding.default_internal = nil
213
+ conn.should be_an_instance_of described_class
214
+ conn.external_encoding.should be conn.internal_encoding
215
+ EM.stop
216
+ end.should be_a_kind_of ::EM::Deferrable
217
+ this.should be :first
218
+ end
219
+
220
+ it_should_execute_with_error("raise syntax error in misspelled multiple statement",
221
+ PG::SyntaxError,
222
+ "syntax error",
223
+ :query_defer, 'SELECT * from pg_class; SRELECT CURRENT_TIMESTAMP; SELECT 42 number')
224
+
225
+ it_should_rollback
226
+
227
+ it "should return only last statement" do
228
+ pg_exec_and_check(@client, :query_defer,
229
+ 'SELECT * from pg_class; SELECT CURRENT_TIMESTAMP; SELECT 42 number') do |result|
230
+ result[0]['number'].should eq "42"
231
+ end
232
+ end
233
+
234
+ it "should timeout expire while executing query" do
235
+ @client.query_timeout.should eq 0
236
+ @client.query_timeout = 1.5
237
+ @client.query_timeout.should eq 1.5
238
+ start_time = Time.now
239
+ pg_exec_and_check_with_error(@client, false,
240
+ PG::ConnectionBad, "query timeout expired",
241
+ :query_defer, 'SELECT pg_sleep(2)') do
242
+ (Time.now - start_time).should be < 2
243
+ @client.async_command_aborted.should be_true
244
+ @client.status.should be PG::CONNECTION_BAD
245
+ @client.query_timeout = 0
246
+ @client.query_timeout.should eq 0
247
+ @client.async_autoreconnect = false
248
+ pg_exec_and_check_with_error(@client, true,
249
+ PG::ConnectionBad, "previous query expired",
250
+ :query_defer, 'SELECT 1') do
251
+ @client.async_autoreconnect = true
252
+ end
253
+ end
254
+ end
255
+
256
+ it "should timeout not expire while executing query with partial results" do
257
+ @client.query_timeout.should eq 0
258
+ @client.query_timeout = 1.1
259
+ @client.query_timeout.should eq 1.1
260
+ start_time = Time.now
261
+ pg_exec_and_check(@client, :query_defer,
262
+ 'SELECT * from pg_class;' +
263
+ 'SELECT pg_sleep(1);' +
264
+ 'SELECT * from pg_class;' +
265
+ 'SELECT pg_sleep(1);' +
266
+ 'SELECT 42 number') do |result|
267
+ (Time.now - start_time).should be > 2
268
+ result[0]['number'].should eq "42"
269
+ @client.query_timeout = 0
270
+ @client.query_timeout.should eq 0
271
+ @client.async_command_aborted.should be_false
272
+ @client.status.should be PG::CONNECTION_OK
273
+ end
274
+ end
275
+
276
+ it "should timeout expire while executing query with partial results" do
277
+ @client.query_timeout.should eq 0
278
+ @client.query_timeout = 1.1
279
+ @client.query_timeout.should eq 1.1
280
+ start_time = Time.now
281
+ pg_exec_and_check_with_error(@client, true,
282
+ PG::ConnectionBad, "query timeout expired",
283
+ :query_defer,
284
+ 'SELECT * from pg_class;' +
285
+ 'SELECT pg_sleep(1);' +
286
+ 'SELECT * from pg_class;' +
287
+ 'SELECT pg_sleep(2);' +
288
+ 'SELECT 42 number') do
289
+ (Time.now - start_time).should be > 2
290
+ @client.async_command_aborted.should be_true
291
+ @client.status.should be PG::CONNECTION_BAD
292
+ @client.query_timeout = 0
293
+ @client.query_timeout.should eq 0
294
+ end
295
+ end
296
+
297
+ it "should clear connection with blocking reset" do
298
+ ensure_em_stop do
299
+ @client.async_command_aborted.should be_true
300
+ @client.status.should be PG::CONNECTION_BAD
301
+ @client.reset
302
+ @client.async_command_aborted.should be_false
303
+ @client.status.should be PG::CONNECTION_OK
304
+ end
305
+ end
306
+
307
+ it "should not expire after executing erraneous query" do
308
+ @client.query_timeout.should eq 0
309
+ @client.query_timeout = 0.1
310
+ @client.query_timeout.should eq 0.1
311
+ start_time = Time.now
312
+ pg_exec_and_check_with_error(@client, false,
313
+ PG::SyntaxError, "syntax error",
314
+ :query_defer, 'SELLECT 1') do
315
+ @client.async_command_aborted.should be_false
316
+ ::EM.add_timer(0.11) do
317
+ @client.async_command_aborted.should be_false
318
+ @client.status.should be PG::CONNECTION_OK
319
+ @client.query_timeout = 0
320
+ @client.query_timeout.should eq 0
321
+ EM.stop
322
+ end
323
+ end
324
+ end
325
+
326
+ it "should get last result asynchronously" do
327
+ @client.get_last_result_defer do |result|
328
+ result.should be_nil
329
+ @client.send_query('SELECT 1; SELECT 2; SELECT 3')
330
+ @client.get_last_result_defer do |result|
331
+ result.should be_an_instance_of PG::Result
332
+ result.getvalue(0,0).should eq '3'
333
+ result.clear
334
+ @client.get_last_result_defer do |result|
335
+ result.should be_nil
336
+ EM.stop
337
+ end
338
+ end.should be_a_kind_of ::EM::Deferrable
339
+ end.should be_a_kind_of ::EM::Deferrable
340
+ end
341
+
342
+ it "should get each result asynchronously" do
343
+ @client.get_result_defer do |result|
344
+ result.should be_nil
345
+ @client.send_query('SELECT 4; SELECT 5; SELECT 6')
346
+ EM::Iterator.new(%w[4 5 6], 1).map(proc{ |value, iter|
347
+ @client.get_result_defer do |result|
348
+ result.should be_an_instance_of PG::Result
349
+ result.check
350
+ result.result_status.should eq PG::PGRES_TUPLES_OK
351
+ result.getvalue(0,0).should eq value
352
+ result.clear
353
+ iter.return value
354
+ end.should be_a_kind_of ::EM::Deferrable
355
+ }, proc{ |results|
356
+ results.should eq %w[4 5 6]
357
+ @client.get_result_defer do |result|
358
+ result.should be_nil
359
+ EM.stop
360
+ end.should be_a_kind_of ::EM::Deferrable
361
+ })
362
+ end.should be_a_kind_of ::EM::Deferrable
363
+ end
364
+
365
+ it "should raise connection reset on connection breakdown" do
366
+ client = described_class.new query_timeout: 0.1
367
+ client.send_query('SELECT pg_sleep(10)')
368
+ client.get_last_result_defer do |ex|
369
+ ex.should be_an_instance_of PG::ConnectionBad
370
+ ex.message.should match /connection reset/
371
+ EM.add_timer(0.2) do
372
+ client.async_command_aborted.should be_false
373
+ EM.stop
374
+ end
375
+ end
376
+ # simulate connection breakdown
377
+ client.finish
378
+ end
379
+
380
+ it "should return nil result after async reset began" do
381
+ checkpoint = 0
382
+ @client.send_query('SELECT 1')
383
+ @client.reset_defer do |conn|
384
+ conn.should be @client
385
+ EM.next_tick do
386
+ checkpoint.should eq 2
387
+ @client.send_query('SELECT 1')
388
+ @client.get_last_result_defer do |result|
389
+ result.should be_an_instance_of PG::Result
390
+ result.getvalue(0,0).should eq '1'
391
+ EM.stop
392
+ end
393
+ end
394
+ end
395
+ @client.get_result_defer do |result|
396
+ result.should be_nil
397
+ checkpoint += 1
398
+ end
399
+ @client.get_last_result_defer do |result|
400
+ result.should be_nil
401
+ checkpoint += 1
402
+ end
403
+ end
404
+
405
+ it "should receive notification while waiting for it" do
406
+ sender = described_class.new
407
+ sender_pid = nil
408
+ wait_over = false
409
+ @client.query_defer('LISTEN "ruby-em-pg-client"') do |result|
410
+ result.should be_an_instance_of PG::Result
411
+ @client.wait_for_notify_defer do |notification|
412
+ notification.should be_an_instance_of Hash
413
+ notification[:relname].should eq 'ruby-em-pg-client'
414
+ notification[:be_pid].should eq sender_pid
415
+ notification[:extra].should eq (NOTIFY_PAYLOAD ? 'foo' : '')
416
+ @client.query_defer('UNLISTEN *') do |result|
417
+ result.should be_an_instance_of PG::Result
418
+ EM.stop unless sender
419
+ wait_over = true
420
+ end
421
+ end.should be_a_kind_of ::EM::Deferrable
422
+ EM.next_tick do
423
+ sender.query_defer('SELECT pg_backend_pid()') do |result|
424
+ result.should be_an_instance_of PG::Result
425
+ sender_pid = result.getvalue(0,0).to_i
426
+ sender.query_defer(NOTIFY_PAYLOAD_QUERY) do |result|
427
+ result.should be_an_instance_of PG::Result
428
+ sender.finish
429
+ sender = nil
430
+ EM.stop if wait_over
431
+ end.should be_a_kind_of ::EM::Deferrable
432
+ end.should be_a_kind_of ::EM::Deferrable
433
+ end
434
+ end.should be_a_kind_of ::EM::Deferrable
435
+ end
436
+
437
+ it "should receive previously sent notification" do
438
+ @client.query_defer('LISTEN "ruby-em-pg-client"') do |result|
439
+ result.should be_an_instance_of PG::Result
440
+ @client.query_defer('SELECT pg_backend_pid()') do |result|
441
+ result.should be_an_instance_of PG::Result
442
+ sender_pid = result.getvalue(0,0).to_i
443
+ @client.query_defer(%q[NOTIFY "ruby-em-pg-client"]) do |result|
444
+ result.should be_an_instance_of PG::Result
445
+ @client.wait_for_notify_defer(1) do |notification|
446
+ notification.should be_an_instance_of Hash
447
+ notification[:relname].should eq 'ruby-em-pg-client'
448
+ notification[:be_pid].should eq sender_pid
449
+ notification[:extra].should eq ''
450
+ @client.query_defer('UNLISTEN *') do |result|
451
+ result.should be_an_instance_of PG::Result
452
+ EM.stop
453
+ end.should be_a_kind_of ::EM::Deferrable
454
+ end.should be_a_kind_of ::EM::Deferrable
455
+ end.should be_a_kind_of ::EM::Deferrable
456
+ end.should be_a_kind_of ::EM::Deferrable
457
+ end.should be_a_kind_of ::EM::Deferrable
458
+ end
459
+
460
+ it "should perform queries and receive own notification while waiting for it" do
461
+ sender_pid = nil
462
+ @client.query_defer('SELECT pg_backend_pid()') do |result|
463
+ sender_pid = result.getvalue(0,0).to_i
464
+ @client.query_defer('LISTEN "ruby-em-pg-client"') do |result|
465
+ result.should be_an_instance_of PG::Result
466
+ @client.query_defer(NOTIFY_PAYLOAD_QUERY) do |result|
467
+ result.should be_an_instance_of PG::Result
468
+ end.should be_a_kind_of ::EM::Deferrable
469
+ end.should be_a_kind_of ::EM::Deferrable
470
+ end.should be_a_kind_of ::EM::Deferrable
471
+ @client.wait_for_notify_defer do |notification|
472
+ notification.should be_an_instance_of Hash
473
+ notification[:relname].should eq 'ruby-em-pg-client'
474
+ notification[:be_pid].should eq sender_pid
475
+ notification[:extra].should eq (NOTIFY_PAYLOAD ? 'foo' : '')
476
+ @client.query_defer('UNLISTEN *') do |result|
477
+ result.should be_an_instance_of PG::Result
478
+ EM.stop
479
+ end.should be_a_kind_of ::EM::Deferrable
480
+ end.should be_a_kind_of ::EM::Deferrable
481
+ end
482
+
483
+ it "should reach timeout while waiting for notification" do
484
+ start_time = Time.now
485
+ async_flag = false
486
+ @client.wait_for_notify_defer(0.2) do |notification|
487
+ notification.should be_nil
488
+ (Time.now - start_time).should be >= 0.2
489
+ async_flag.should be_true
490
+ EM.stop
491
+ end.should be_a_kind_of ::EM::Deferrable
492
+ async_flag = true
493
+ end
494
+
495
+ it "should reach timeout while waiting for notification and executing query" do
496
+ start_time = Time.now
497
+ async_flag = false
498
+ @client.query_defer('SELECT pg_sleep(0.5)') do |result|
499
+ result.should be_an_instance_of PG::Result
500
+ (Time.now - start_time).should be >= 0.5
501
+ async_flag.should be_true
502
+ EM.stop
503
+ end
504
+ @client.wait_for_notify_defer(0.1) do |notification|
505
+ notification.should be_nil
506
+ (Time.now - start_time).should be_between(0.1, 0.5)
507
+ async_flag.should be_true
508
+ end.should be_a_kind_of ::EM::Deferrable
509
+ async_flag = true
510
+ end
511
+
512
+ it "should timeout expire while executing query and waiting for notification" do
513
+ @client.query_timeout.should eq 0
514
+ @client.query_timeout = 0.2
515
+ @client.query_timeout.should eq 0.2
516
+ visit_counter = 0
517
+ start_time = Time.now
518
+ pg_exec_and_check_with_error(@client, false,
519
+ PG::ConnectionBad, "query timeout expired (async)",
520
+ :wait_for_notify_defer) do
521
+ (Time.now - start_time).should be >= 0.2
522
+ (visit_counter+=1).should eq 2
523
+ @client.async_command_aborted.should be_true
524
+ @client.status.should be PG::CONNECTION_BAD
525
+ @client.query_timeout = 0
526
+ @client.query_timeout.should eq 0
527
+ @client.async_autoreconnect = false
528
+ pg_exec_and_check_with_error(@client, false,
529
+ PG::ConnectionBad, "previous query expired",
530
+ :wait_for_notify_defer) do
531
+ @client.reset_defer do |conn|
532
+ conn.should be @client
533
+ @client.async_autoreconnect = true
534
+ EM.stop
535
+ end
536
+ end
537
+ end
538
+ pg_exec_and_check_with_error(@client, false,
539
+ PG::ConnectionBad, "query timeout expired (async)",
540
+ :query_defer, 'SELECT pg_sleep(1)') do
541
+ (Time.now - start_time).should be_between(0.2, 1)
542
+ (visit_counter+=1).should eq 1
543
+ end
544
+ end
545
+
546
+ it "should fail wait_for_notify on connection reset" do
547
+ @client.status.should be PG::CONNECTION_OK
548
+ visit_counter = 0
549
+ pg_exec_and_check_with_error(@client, false,
550
+ PG::ConnectionBad, "connection reset",
551
+ :wait_for_notify_defer) do
552
+ pg_exec_and_check_with_error(@client, false,
553
+ PG::ConnectionBad, "connection reset",
554
+ :wait_for_notify_defer) do
555
+ (visit_counter+=1).should eq 2
556
+ end
557
+ @client.reset_defer do |conn|
558
+ conn.should be @client
559
+ (visit_counter+=1).should eq 3
560
+ EM.stop
561
+ end
562
+ end
563
+ @client.reset
564
+ (visit_counter+=1).should eq 1
565
+ end
566
+
567
+ it "should fail wait_for_notify and slow query on connection reset" do
568
+ @client.status.should be PG::CONNECTION_OK
569
+ visit_counter = 0
570
+ pg_exec_and_check_with_error(@client, false,
571
+ PG::ConnectionBad, "connection reset",
572
+ :query_defer, 'SELECT pg_sleep(10)') do
573
+ (visit_counter+=1).should eq 2
574
+ end
575
+ pg_exec_and_check_with_error(@client, false,
576
+ PG::ConnectionBad, "connection reset",
577
+ :wait_for_notify_defer) do
578
+ (visit_counter+=1).should eq 3
579
+ pg_exec_and_check_with_error(@client, false,
580
+ PG::ConnectionBad, "connection reset",
581
+ :wait_for_notify_defer) do
582
+ (visit_counter+=1).should eq 5
583
+ end
584
+ @client.reset_defer do |conn|
585
+ conn.should be @client
586
+ (visit_counter+=1).should eq 6
587
+ EM.stop
588
+ end
589
+ end
590
+ @client.reset
591
+ (visit_counter+=1).should eq 1
592
+ pg_exec_and_check_with_error(@client, false,
593
+ PG::ConnectionBad, "connection reset",
594
+ :query_defer, 'SELECT pg_sleep(10)') do
595
+ (visit_counter+=1).should eq 4
596
+ end
597
+ end
598
+
599
+ it "should fail wait_for_notify on another wait_for_notify" do
600
+ @client.status.should be PG::CONNECTION_OK
601
+ visit_counter = 0
602
+ @client.wait_for_notify_defer(0.5).errback do |ex|
603
+ ex.should be_nil
604
+ (visit_counter+=1).should eq 2
605
+ end.callback do
606
+ raise "This should never be called"
607
+ end.should be_a_kind_of ::EM::Deferrable
608
+ (visit_counter+=1).should eq 1
609
+ @client.wait_for_notify_defer(0.1).callback do |notification|
610
+ notification.should be_nil
611
+ (visit_counter+=1).should eq 4
612
+ EM.stop
613
+ end.errback do
614
+ raise "This should never be called"
615
+ end.should be_a_kind_of ::EM::Deferrable
616
+ (visit_counter+=1).should eq 3
617
+ end
618
+
619
+ end