em-pg-client 0.3.3 → 0.3.4
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.
- data/HISTORY.md +5 -0
- data/README.md +52 -10
- data/lib/pg/em-version.rb +1 -1
- data/lib/pg/em.rb +151 -65
- data/lib/pg/em/client/watcher.rb +96 -20
- data/spec/em_client.rb +1 -1
- data/spec/em_client_autoreconnect.rb +253 -36
- data/spec/em_client_common.rb +230 -13
- data/spec/em_client_on_connect.rb +9 -9
- data/spec/em_connection_pool.rb +3 -1
- data/spec/em_synchrony_client.rb +191 -1
- data/spec/em_synchrony_client_autoreconnect.rb +249 -6
- data/spec/pg_em_client_connect_finish.rb +1 -1
- data/spec/pg_em_client_connect_timeout.rb +1 -1
- metadata +27 -13
- checksums.yaml +0 -7
data/spec/em_client_common.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
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
|
+
|
1
4
|
module PGSpecMacros
|
2
5
|
def self.included(base)
|
3
6
|
base.extend(ClassMethods)
|
@@ -8,7 +11,7 @@ module PGSpecMacros
|
|
8
11
|
result.should be_an_instance_of PG::Result
|
9
12
|
additional_checks.call(result) if additional_checks
|
10
13
|
EM.stop
|
11
|
-
end.should be_a_kind_of ::EM::
|
14
|
+
end.should be_a_kind_of ::EM::Deferrable
|
12
15
|
end
|
13
16
|
|
14
17
|
def pg_exec_and_check_with_error(client, stop, err_class, err_message, method, *args, &additional_checks)
|
@@ -17,7 +20,7 @@ module PGSpecMacros
|
|
17
20
|
exception.to_s.should include err_message if err_message
|
18
21
|
additional_checks.call(exception) if additional_checks
|
19
22
|
EM.next_tick { EM.stop } if stop
|
20
|
-
end.should be_a_kind_of ::EM::
|
23
|
+
end.should be_a_kind_of ::EM::Deferrable
|
21
24
|
end
|
22
25
|
|
23
26
|
def ensure_em_stop
|
@@ -123,7 +126,7 @@ shared_context 'em-pg common after' do
|
|
123
126
|
value.should eq [{'data' => data, 'id' => id.to_s}]
|
124
127
|
result.clear
|
125
128
|
iter.return value
|
126
|
-
end.should be_a_kind_of ::EM::
|
129
|
+
end.should be_a_kind_of ::EM::Deferrable
|
127
130
|
}, proc{ |results|
|
128
131
|
results.length.should eq @values.length
|
129
132
|
@client.get_result_defer do |result|
|
@@ -135,10 +138,10 @@ shared_context 'em-pg common after' do
|
|
135
138
|
@client.get_result_defer do |result|
|
136
139
|
result.should be_nil
|
137
140
|
EM.stop
|
138
|
-
end.should be_a_kind_of ::EM::
|
139
|
-
end.should be_a_kind_of ::EM::
|
141
|
+
end.should be_a_kind_of ::EM::Deferrable
|
142
|
+
end.should be_a_kind_of ::EM::Deferrable
|
140
143
|
})
|
141
|
-
end.should be_a_kind_of ::EM::
|
144
|
+
end.should be_a_kind_of ::EM::Deferrable
|
142
145
|
end
|
143
146
|
|
144
147
|
end
|
@@ -197,7 +200,7 @@ shared_context 'em-pg common after' do
|
|
197
200
|
pg_exec_and_check(conn, :query_defer, 'SELECT pg_database_size(current_database());') do |result|
|
198
201
|
result[0]['pg_database_size'].to_i.should be > 0
|
199
202
|
end
|
200
|
-
end.should be_a_kind_of ::EM::
|
203
|
+
end.should be_a_kind_of ::EM::Deferrable
|
201
204
|
this.should be :first
|
202
205
|
end
|
203
206
|
|
@@ -210,7 +213,7 @@ shared_context 'em-pg common after' do
|
|
210
213
|
conn.should be_an_instance_of described_class
|
211
214
|
conn.external_encoding.should be conn.internal_encoding
|
212
215
|
EM.stop
|
213
|
-
end.should be_a_kind_of ::EM::
|
216
|
+
end.should be_a_kind_of ::EM::Deferrable
|
214
217
|
this.should be :first
|
215
218
|
end
|
216
219
|
|
@@ -332,8 +335,8 @@ shared_context 'em-pg common after' do
|
|
332
335
|
result.should be_nil
|
333
336
|
EM.stop
|
334
337
|
end
|
335
|
-
end.should be_a_kind_of ::EM::
|
336
|
-
end.should be_a_kind_of ::EM::
|
338
|
+
end.should be_a_kind_of ::EM::Deferrable
|
339
|
+
end.should be_a_kind_of ::EM::Deferrable
|
337
340
|
end
|
338
341
|
|
339
342
|
it "should get each result asynchronously" do
|
@@ -348,15 +351,15 @@ shared_context 'em-pg common after' do
|
|
348
351
|
result.getvalue(0,0).should eq value
|
349
352
|
result.clear
|
350
353
|
iter.return value
|
351
|
-
end.should be_a_kind_of ::EM::
|
354
|
+
end.should be_a_kind_of ::EM::Deferrable
|
352
355
|
}, proc{ |results|
|
353
356
|
results.should eq %w[4 5 6]
|
354
357
|
@client.get_result_defer do |result|
|
355
358
|
result.should be_nil
|
356
359
|
EM.stop
|
357
|
-
end.should be_a_kind_of ::EM::
|
360
|
+
end.should be_a_kind_of ::EM::Deferrable
|
358
361
|
})
|
359
|
-
end.should be_a_kind_of ::EM::
|
362
|
+
end.should be_a_kind_of ::EM::Deferrable
|
360
363
|
end
|
361
364
|
|
362
365
|
it "should raise connection reset on connection breakdown" do
|
@@ -399,4 +402,218 @@ shared_context 'em-pg common after' do
|
|
399
402
|
end
|
400
403
|
end
|
401
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
|
+
|
402
619
|
end
|
@@ -52,11 +52,11 @@ shared_context 'test on_connect' do
|
|
52
52
|
client.exec_prepared_defer(query_name) do |result|
|
53
53
|
result.should be_an_instance_of PG::Result
|
54
54
|
result[0]['pg_database_size'].to_i.should be > 0
|
55
|
-
|
56
|
-
EM
|
57
|
-
end.should be_a_kind_of ::EM::
|
58
|
-
end.should be_a_kind_of ::EM::
|
59
|
-
end.should be_a_kind_of ::EM::
|
55
|
+
EM.stop
|
56
|
+
end.should be_a_kind_of ::EM::Deferrable
|
57
|
+
end.should be_a_kind_of ::EM::Deferrable
|
58
|
+
end.should be_a_kind_of ::EM::Deferrable
|
59
|
+
end.should be_a_kind_of ::EM::Deferrable
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -81,9 +81,9 @@ shared_context 'test on_connect error' do
|
|
81
81
|
client.reset_defer do |ex|
|
82
82
|
ex.should be_an_instance_of on_connect_exception
|
83
83
|
EM.stop
|
84
|
-
end.should be_a_kind_of ::EM::
|
85
|
-
end.should be_a_kind_of ::EM::
|
86
|
-
end.should be_a_kind_of ::EM::
|
84
|
+
end.should be_a_kind_of ::EM::Deferrable
|
85
|
+
end.should be_a_kind_of ::EM::Deferrable
|
86
|
+
end.should be_a_kind_of ::EM::Deferrable
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
@@ -162,7 +162,7 @@ describe 'on_connect option' do
|
|
162
162
|
|
163
163
|
describe 'with on_connect deferrable failure' do
|
164
164
|
let(:on_connect) { proc {|client|
|
165
|
-
EM::DefaultDeferrable.new.tap {|df| df.fail on_connect_exception.new }
|
165
|
+
::EM::DefaultDeferrable.new.tap {|df| df.fail on_connect_exception.new }
|
166
166
|
} }
|
167
167
|
|
168
168
|
include_context 'test on_connect error'
|
data/spec/em_connection_pool.rb
CHANGED
@@ -181,17 +181,19 @@ describe 'connection pool' do
|
|
181
181
|
end
|
182
182
|
|
183
183
|
it 'should lock transaction connection to fiber' do
|
184
|
+
over_count = 2
|
184
185
|
@pool.transaction do |pg|
|
185
186
|
@pool.hold {|c| c.should be pg }
|
186
187
|
Fiber.new do
|
187
188
|
@pool.size.should eq 1
|
188
189
|
@pool.hold {|c| c.should_not be pg }
|
189
190
|
@pool.size.should eq 2
|
190
|
-
EM.stop
|
191
|
+
EM.stop if (over_count-=1).zero?
|
191
192
|
end.resume
|
192
193
|
@pool.hold {|c| c.should be pg }
|
193
194
|
@pool.size.should eq 2
|
194
195
|
end
|
196
|
+
EM.stop if (over_count-=1).zero?
|
195
197
|
end
|
196
198
|
|
197
199
|
end
|
data/spec/em_synchrony_client.rb
CHANGED
@@ -5,6 +5,9 @@ require 'date'
|
|
5
5
|
require 'em-synchrony'
|
6
6
|
require 'pg/em'
|
7
7
|
|
8
|
+
NOTIFY_PAYLOAD = defined?(PG.library_version) && PG.library_version >= 90000
|
9
|
+
NOTIFY_PAYLOAD_QUERY = NOTIFY_PAYLOAD ? %q[NOTIFY "ruby-em-pg-client", 'foo'] : %q[NOTIFY "ruby-em-pg-client"]
|
10
|
+
|
8
11
|
describe PG::EM::Client do
|
9
12
|
|
10
13
|
it "should be client #{PG::VERSION}" do
|
@@ -135,7 +138,6 @@ describe PG::EM::Client do
|
|
135
138
|
result.to_a.should eq []
|
136
139
|
result.clear
|
137
140
|
@client.get_result.should be_nil
|
138
|
-
EM.stop
|
139
141
|
end
|
140
142
|
|
141
143
|
end
|
@@ -293,6 +295,8 @@ describe PG::EM::Client do
|
|
293
295
|
::EM::Synchrony.sleep 1.5
|
294
296
|
@client.async_command_aborted.should be_false
|
295
297
|
@client.status.should be PG::CONNECTION_OK
|
298
|
+
@client.query_timeout = 0
|
299
|
+
@client.query_timeout.should eq 0
|
296
300
|
end
|
297
301
|
|
298
302
|
it "should get last result asynchronously" do
|
@@ -336,6 +340,192 @@ describe PG::EM::Client do
|
|
336
340
|
asynchronous.should be true
|
337
341
|
end
|
338
342
|
|
343
|
+
it "should receive notification while waiting for it" do
|
344
|
+
sender = described_class.new
|
345
|
+
notify_flag = false
|
346
|
+
result = sender.query('SELECT pg_backend_pid()')
|
347
|
+
result.should be_an_instance_of PG::Result
|
348
|
+
sender_pid = result.getvalue(0,0).to_i
|
349
|
+
@client.query('LISTEN "ruby-em-pg-client"').should be_an_instance_of PG::Result
|
350
|
+
f = nil
|
351
|
+
EM::Synchrony.next_tick do
|
352
|
+
begin
|
353
|
+
sender.query(NOTIFY_PAYLOAD_QUERY).should be_an_instance_of PG::Result
|
354
|
+
sender.finish
|
355
|
+
ensure
|
356
|
+
sender = nil
|
357
|
+
f.resume if f
|
358
|
+
end
|
359
|
+
end
|
360
|
+
@client.wait_for_notify do |name, pid, payload|
|
361
|
+
name.should eq 'ruby-em-pg-client'
|
362
|
+
pid.should eq sender_pid
|
363
|
+
payload.should eq (NOTIFY_PAYLOAD ? 'foo' : '')
|
364
|
+
@client.query('UNLISTEN *').should be_an_instance_of PG::Result
|
365
|
+
notify_flag = true
|
366
|
+
end.should eq 'ruby-em-pg-client'
|
367
|
+
notify_flag.should be_true
|
368
|
+
f = Fiber.current
|
369
|
+
Fiber.yield if sender
|
370
|
+
end
|
371
|
+
|
372
|
+
it "should receive previously sent notification" do
|
373
|
+
notify_flag = false
|
374
|
+
@client.query('LISTEN "ruby-em-pg-client"').should be_an_instance_of PG::Result
|
375
|
+
result = @client.query('SELECT pg_backend_pid()')
|
376
|
+
result.should be_an_instance_of PG::Result
|
377
|
+
sender_pid = result.getvalue(0,0).to_i
|
378
|
+
@client.query(%q[NOTIFY "ruby-em-pg-client"]).should be_an_instance_of PG::Result
|
379
|
+
@client.wait_for_notify(1) do |name, pid, payload|
|
380
|
+
name.should eq 'ruby-em-pg-client'
|
381
|
+
pid.should eq sender_pid
|
382
|
+
payload.should eq ''
|
383
|
+
@client.query('UNLISTEN *').should be_an_instance_of PG::Result
|
384
|
+
notify_flag = true
|
385
|
+
end.should eq 'ruby-em-pg-client'
|
386
|
+
notify_flag.should be_true
|
387
|
+
end
|
388
|
+
|
389
|
+
it "should perform queries and receive own notification while waiting for it" do
|
390
|
+
f = nil
|
391
|
+
sender_pid = nil
|
392
|
+
notify_flag = false
|
393
|
+
Fiber.new do
|
394
|
+
begin
|
395
|
+
@client.wait_for_notify do |name, pid, payload|
|
396
|
+
name.should eq 'ruby-em-pg-client'
|
397
|
+
pid.should eq sender_pid
|
398
|
+
payload.should eq (NOTIFY_PAYLOAD ? 'foo' : '')
|
399
|
+
notify_flag = true
|
400
|
+
end.should eq 'ruby-em-pg-client'
|
401
|
+
notify_flag.should be_true
|
402
|
+
@client.query('UNLISTEN *').should be_an_instance_of PG::Result
|
403
|
+
ensure
|
404
|
+
sender_pid = nil
|
405
|
+
f.resume if f
|
406
|
+
end
|
407
|
+
end.resume
|
408
|
+
result = @client.query('SELECT pg_backend_pid()')
|
409
|
+
result.should be_an_instance_of PG::Result
|
410
|
+
sender_pid = result.getvalue(0,0).to_i
|
411
|
+
@client.query('LISTEN "ruby-em-pg-client"').should be_an_instance_of PG::Result
|
412
|
+
@client.query(NOTIFY_PAYLOAD_QUERY).should be_an_instance_of PG::Result
|
413
|
+
f = Fiber.current
|
414
|
+
Fiber.yield if sender_pid
|
415
|
+
end
|
416
|
+
|
417
|
+
it "should reach timeout while waiting for notification" do
|
418
|
+
start_time = Time.now
|
419
|
+
async_flag = false
|
420
|
+
EM.next_tick do
|
421
|
+
async_flag = true
|
422
|
+
end
|
423
|
+
@client.wait_for_notify(0.2) do
|
424
|
+
raise "This block should not be called"
|
425
|
+
end.should be_nil
|
426
|
+
(Time.now - start_time).should be >= 0.2
|
427
|
+
async_flag.should be_true
|
428
|
+
end
|
429
|
+
|
430
|
+
it "should reach timeout while waiting for notification and executing query" do
|
431
|
+
start_time = Time.now
|
432
|
+
async_flag = false
|
433
|
+
EM.next_tick do
|
434
|
+
async_flag = true
|
435
|
+
end
|
436
|
+
f = Fiber.current
|
437
|
+
Fiber.new do
|
438
|
+
begin
|
439
|
+
@client.query('SELECT pg_sleep(0.5)').should be_an_instance_of PG::Result
|
440
|
+
(Time.now - start_time).should be >= 0.5
|
441
|
+
async_flag.should be_true
|
442
|
+
ensure
|
443
|
+
f.resume
|
444
|
+
end
|
445
|
+
end.resume
|
446
|
+
@client.wait_for_notify(0.1) do
|
447
|
+
raise "This block should not be called"
|
448
|
+
end.should be_nil
|
449
|
+
delta = Time.now - start_time
|
450
|
+
delta.should be >= 0.1
|
451
|
+
delta.should be < 0.5
|
452
|
+
async_flag.should be_true
|
453
|
+
Fiber.yield
|
454
|
+
end
|
455
|
+
|
456
|
+
it "should timeout expire while executing query and waiting for notification" do
|
457
|
+
@client.query_timeout.should eq 0
|
458
|
+
@client.query_timeout = 0.2
|
459
|
+
@client.query_timeout.should eq 0.2
|
460
|
+
f = Fiber.current
|
461
|
+
visit_counter = 0
|
462
|
+
start_time = Time.now
|
463
|
+
Fiber.new do
|
464
|
+
expect {
|
465
|
+
@client.wait_for_notify do
|
466
|
+
raise "This block should not be called"
|
467
|
+
end
|
468
|
+
}.to raise_error(PG::ConnectionBad, /query timeout expired/)
|
469
|
+
(Time.now - start_time).should be >= 0.2
|
470
|
+
(visit_counter+=1).should eq 2
|
471
|
+
@client.query_timeout = 0
|
472
|
+
@client.query_timeout.should eq 0
|
473
|
+
@client.async_command_aborted.should be_true
|
474
|
+
@client.status.should be PG::CONNECTION_BAD
|
475
|
+
@client.async_autoreconnect = false
|
476
|
+
expect {
|
477
|
+
@client.wait_for_notify do
|
478
|
+
raise "This block should not be called"
|
479
|
+
end
|
480
|
+
}.to raise_error(PG::ConnectionBad, /previous query expired/)
|
481
|
+
@client.async_autoreconnect = true
|
482
|
+
f.resume
|
483
|
+
end.resume
|
484
|
+
expect {
|
485
|
+
@client.query('SELECT pg_sleep(1)')
|
486
|
+
}.to raise_error(PG::ConnectionBad, /query timeout expired/)
|
487
|
+
(Time.now - start_time).should be_between(0.2, 1)
|
488
|
+
(visit_counter+=1).should eq 1
|
489
|
+
Fiber.yield
|
490
|
+
@client.reset
|
491
|
+
end
|
492
|
+
|
493
|
+
it "should fail wait_for_notify on connection reset" do
|
494
|
+
@client.status.should be PG::CONNECTION_OK
|
495
|
+
visit_counter = 0
|
496
|
+
Fiber.new do
|
497
|
+
expect {
|
498
|
+
@client.wait_for_notify do
|
499
|
+
raise "This block should not be called"
|
500
|
+
end
|
501
|
+
}.to raise_error(PG::ConnectionBad, /connection reset/)
|
502
|
+
(visit_counter+=1).should eq 1
|
503
|
+
end.resume
|
504
|
+
@client.reset
|
505
|
+
(visit_counter+=1).should eq 2
|
506
|
+
end
|
507
|
+
|
508
|
+
it "should fail wait_for_notify and slow query on connection reset" do
|
509
|
+
@client.status.should be PG::CONNECTION_OK
|
510
|
+
visit_counter = 0
|
511
|
+
Fiber.new do
|
512
|
+
expect {
|
513
|
+
@client.query('SELECT pg_sleep(10)')
|
514
|
+
}.to raise_error(PG::ConnectionBad, /connection reset/)
|
515
|
+
(visit_counter+=1).should eq 1
|
516
|
+
end.resume
|
517
|
+
Fiber.new do
|
518
|
+
expect {
|
519
|
+
@client.wait_for_notify do
|
520
|
+
raise "This block should not be called"
|
521
|
+
end
|
522
|
+
}.to raise_error(PG::ConnectionBad, /connection reset/)
|
523
|
+
(visit_counter+=1).should eq 2
|
524
|
+
end.resume
|
525
|
+
@client.reset
|
526
|
+
(visit_counter+=1).should eq 3
|
527
|
+
end
|
528
|
+
|
339
529
|
describe 'PG::EM::Client#transaction' do
|
340
530
|
|
341
531
|
before(:all) do
|