em-pg-client-12 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.
@@ -0,0 +1,560 @@
1
+ $:.unshift "lib"
2
+ gem 'eventmachine', '~> 1.0.0'
3
+ gem 'pg', ENV['EM_PG_CLIENT_TEST_PG_VERSION']
4
+ require 'date'
5
+ require 'em-synchrony'
6
+ require 'pg/em'
7
+
8
+ $pgserver_cmd_stop = ENV['PG_CTL_STOP_CMD'] || %Q[sudo -i -u postgres pg_ctl -D "#{ENV['PGDATA']}" stop -s -m fast]
9
+ $pgserver_cmd_start = ENV['PG_CTL_START_CMD'] || %Q[sudo -i -u postgres pg_ctl -D "#{ENV['PGDATA']}" start -s -w]
10
+
11
+ DISCONNECTED_ERROR = ENV['PGHOST'].include?('/') ? PG::UnableToSend : PG::ConnectionBad
12
+
13
+ shared_context 'em-synchrony-pg common' do
14
+ around(:each) do |testcase|
15
+ EM.synchrony do
16
+ testcase.call
17
+ EM.stop
18
+ end
19
+ end
20
+
21
+ after(:all) do
22
+ @client.close
23
+ end
24
+ end
25
+
26
+ describe 'em-synchrony-pg default autoreconnect' do
27
+ include_context 'em-synchrony-pg common'
28
+
29
+ it "should not have modified argument Hash" do
30
+ @options.should eq(async_autoreconnect: true)
31
+ end
32
+
33
+ it "should get database size using query" do
34
+ @tested_proc.call
35
+ end
36
+
37
+ it "should get database size using query after server restart" do
38
+ system($pgserver_cmd_stop).should be_true
39
+ system($pgserver_cmd_start).should be_true
40
+ @tested_proc.call
41
+ end
42
+
43
+ it "should not get database size using query after server shutdown" do
44
+ system($pgserver_cmd_stop).should be_true
45
+ expect {
46
+ @tested_proc.call
47
+ }.to raise_error DISCONNECTED_ERROR
48
+ end
49
+
50
+ it "should get database size using query after server startup" do
51
+ system($pgserver_cmd_start).should be_true
52
+ @tested_proc.call
53
+ end
54
+
55
+ it "should raise an error when in transaction after server restart" do
56
+ expect do
57
+ @client.transaction do
58
+ system($pgserver_cmd_stop).should be_true
59
+ system($pgserver_cmd_start).should be_true
60
+ @tested_proc.call
61
+ end
62
+ end.to raise_error DISCONNECTED_ERROR
63
+ @tested_proc.call
64
+ end
65
+
66
+ it "should fail to get last result asynchronously after server restart" do
67
+ @client.send_query('SELECT pg_sleep(50); SELECT pg_database_size(current_database());')
68
+ system($pgserver_cmd_stop).should be_true
69
+ system($pgserver_cmd_start).should be_true
70
+ expect do
71
+ @client.get_last_result
72
+ end.to raise_error PG::ConnectionBad
73
+ @client.status.should be PG::CONNECTION_OK
74
+ @client.get_last_result.should be_nil
75
+ EM.stop
76
+ end
77
+
78
+ it "should fail to get each result asynchronously after server restart" do
79
+ @client.send_query('SELECT pg_sleep(50); SELECT pg_database_size(current_database());')
80
+ system($pgserver_cmd_stop).should be_true
81
+ system($pgserver_cmd_start).should be_true
82
+ result = @client.get_result
83
+ result.should be_an_instance_of PG::Result
84
+ expect do
85
+ result.check
86
+ end.to raise_error PG::Error
87
+ @client.status.should be PG::CONNECTION_OK
88
+ expect do
89
+ @client.get_result
90
+ end.to raise_error PG::ConnectionBad
91
+ @client.status.should be PG::CONNECTION_OK
92
+ @client.get_result.should be_nil
93
+ EM.stop
94
+ end
95
+
96
+ it "should fail wait_for_notify while server restarts" do
97
+ @client.status.should be PG::CONNECTION_OK
98
+ f = Fiber.current
99
+ notify_flag = false
100
+ Fiber.new do
101
+ expect {
102
+ @client.wait_for_notify do
103
+ raise "This block should not be called"
104
+ end
105
+ }.to raise_error(PG::ConnectionBad)
106
+ @client.status.should be PG::CONNECTION_OK
107
+ Fiber.new do
108
+ @client.wait_for_notify do |name,|
109
+ name.should eq 'em_synchrony_client_autoreconnect'
110
+ notify_flag = true
111
+ end.should eq 'em_synchrony_client_autoreconnect'
112
+ @client.query('UNLISTEN *').should be_an_instance_of PG::Result
113
+ f.resume
114
+ end.resume
115
+ @client.query('LISTEN em_synchrony_client_autoreconnect').should be_an_instance_of PG::Result
116
+ @client.query('NOTIFY em_synchrony_client_autoreconnect').should be_an_instance_of PG::Result
117
+ end.resume
118
+ system($pgserver_cmd_stop).should be_true
119
+ system($pgserver_cmd_start).should be_true
120
+ Fiber.yield
121
+ notify_flag.should be_true
122
+ end
123
+
124
+ it "should fail wait_for_notify and finish slow query while server restarts" do
125
+ @client.status.should be PG::CONNECTION_OK
126
+ f = Fiber.current
127
+ notify_flag = false
128
+ query_flag = false
129
+ start_time = Time.now
130
+ Fiber.new do
131
+ result = @client.query('SELECT pg_sleep(2); SELECT 42')
132
+ result.should be_an_instance_of PG::Result
133
+ result.getvalue(0,0).to_i.should eq 42
134
+ (Time.now - start_time).should be > 2
135
+ query_flag = true
136
+ end.resume
137
+ Fiber.new do
138
+ expect {
139
+ @client.wait_for_notify do
140
+ raise "This block should not be called"
141
+ end
142
+ }.to raise_error(PG::ConnectionBad)
143
+ query_flag.should be_true
144
+ @client.status.should be PG::CONNECTION_OK
145
+ Fiber.new do
146
+ @client.wait_for_notify do |name,|
147
+ name.should eq 'em_synchrony_client_autoreconnect'
148
+ notify_flag = true
149
+ end.should eq 'em_synchrony_client_autoreconnect'
150
+ @client.query('UNLISTEN *').should be_an_instance_of PG::Result
151
+ f.resume
152
+ end.resume
153
+ @client.query('LISTEN em_synchrony_client_autoreconnect').should be_an_instance_of PG::Result
154
+ @client.query('NOTIFY em_synchrony_client_autoreconnect').should be_an_instance_of PG::Result
155
+ end.resume
156
+ system($pgserver_cmd_stop).should be_true
157
+ system($pgserver_cmd_start).should be_true
158
+ Fiber.yield
159
+ notify_flag.should be_true
160
+ end
161
+
162
+ before(:all) do
163
+ @tested_proc = proc do
164
+ @client.query('SELECT pg_database_size(current_database());') do |result|
165
+ result.should be_an_instance_of PG::Result
166
+ result[0]['pg_database_size'].to_i.should be > 0
167
+ end
168
+ end
169
+ @options = {async_autoreconnect: true}
170
+ @client = PG::EM::Client.new(@options)
171
+ @client.set_notice_processor {|msg| puts "warning from pgsql: #{msg.to_s.chomp.inspect}"}
172
+ end
173
+ end
174
+
175
+ describe 'em-synchrony-pg autoreconnect with on_autoreconnect' do
176
+ include_context 'em-synchrony-pg common'
177
+
178
+ it "should not have modified argument Hash" do
179
+ @options.should eq(on_autoreconnect: @on_autoreconnect)
180
+ end
181
+
182
+ it "should get database size using prepared statement" do
183
+ @tested_proc.call
184
+ end
185
+
186
+ it "should get database size using prepared statement after server restart" do
187
+ system($pgserver_cmd_stop).should be_true
188
+ system($pgserver_cmd_start).should be_true
189
+ @tested_proc.call
190
+ end
191
+
192
+ it "should raise an error when in transaction after server restart" do
193
+ expect do
194
+ @client.transaction do
195
+ system($pgserver_cmd_stop).should be_true
196
+ system($pgserver_cmd_start).should be_true
197
+ @tested_proc.call
198
+ end
199
+ end.to raise_error DISCONNECTED_ERROR
200
+ @tested_proc.call
201
+ end
202
+
203
+ it "should fail to get last result asynchronously after server restart" do
204
+ @client.on_autoreconnect = proc {
205
+ EM::DefaultDeferrable.new.tap {|df| df.succeed }
206
+ }
207
+ @client.send_query('SELECT pg_sleep(50); SELECT pg_database_size(current_database());')
208
+ system($pgserver_cmd_stop).should be_true
209
+ system($pgserver_cmd_start).should be_true
210
+ expect do
211
+ @client.get_last_result
212
+ end.to raise_error PG::ConnectionBad
213
+ @client.status.should be PG::CONNECTION_OK
214
+ @client.get_last_result.should be_nil
215
+ EM.stop
216
+ end
217
+
218
+ it "should fail to get each result asynchronously after server restart" do
219
+ @client.on_autoreconnect = proc { true }
220
+ @client.send_query('SELECT pg_sleep(50); SELECT pg_database_size(current_database());')
221
+ system($pgserver_cmd_stop).should be_true
222
+ system($pgserver_cmd_start).should be_true
223
+ result = @client.get_result
224
+ result.should be_an_instance_of PG::Result
225
+ expect do
226
+ result.check
227
+ end.to raise_error PG::Error
228
+ @client.status.should be PG::CONNECTION_OK
229
+ expect do
230
+ @client.get_result
231
+ end.to raise_error PG::ConnectionBad
232
+ @client.status.should be PG::CONNECTION_OK
233
+ @client.get_result.should be_nil
234
+ EM.stop
235
+ end
236
+
237
+ it "should fail wait_for_notify while server restarts" do
238
+ @client.status.should be PG::CONNECTION_OK
239
+ @client.on_autoreconnect(&@on_autoreconnect)
240
+ f = Fiber.current
241
+ notify_flag = false
242
+ Fiber.new do
243
+ expect {
244
+ @client.wait_for_notify do
245
+ raise "This block should not be called"
246
+ end
247
+ }.to raise_error(PG::ConnectionBad)
248
+ @client.status.should be PG::CONNECTION_OK
249
+ Fiber.new do
250
+ @client.wait_for_notify do |name,|
251
+ name.should eq 'em_synchrony_client_autoreconnect'
252
+ notify_flag = true
253
+ end.should eq 'em_synchrony_client_autoreconnect'
254
+ @client.query('UNLISTEN *').should be_an_instance_of PG::Result
255
+ f.resume
256
+ end.resume
257
+ @client.query('LISTEN em_synchrony_client_autoreconnect').should be_an_instance_of PG::Result
258
+ @client.query('NOTIFY em_synchrony_client_autoreconnect').should be_an_instance_of PG::Result
259
+ end.resume
260
+ system($pgserver_cmd_stop).should be_true
261
+ system($pgserver_cmd_start).should be_true
262
+ Fiber.yield
263
+ notify_flag.should be_true
264
+ @tested_proc.call
265
+ end
266
+
267
+ it "should fail wait_for_notify and finish slow query while server restarts" do
268
+ @client.status.should be PG::CONNECTION_OK
269
+ @client.on_autoreconnect = @on_autoreconnect
270
+ f = Fiber.current
271
+ notify_flag = false
272
+ query_flag = false
273
+ start_time = Time.now
274
+ Fiber.new do
275
+ result = @client.query('SELECT pg_sleep(2); SELECT 42')
276
+ result.should be_an_instance_of PG::Result
277
+ result.getvalue(0,0).to_i.should eq 42
278
+ (Time.now - start_time).should be > 2
279
+ query_flag = true
280
+ end.resume
281
+ Fiber.new do
282
+ expect {
283
+ @client.wait_for_notify do
284
+ raise "This block should not be called"
285
+ end
286
+ }.to raise_error(PG::ConnectionBad)
287
+ query_flag.should be_true
288
+ @client.status.should be PG::CONNECTION_OK
289
+ Fiber.new do
290
+ @client.wait_for_notify do |name,|
291
+ name.should eq 'em_synchrony_client_autoreconnect'
292
+ notify_flag = true
293
+ end.should eq 'em_synchrony_client_autoreconnect'
294
+ @client.query('UNLISTEN *').should be_an_instance_of PG::Result
295
+ f.resume
296
+ end.resume
297
+ @client.query('LISTEN em_synchrony_client_autoreconnect').should be_an_instance_of PG::Result
298
+ @client.query('NOTIFY em_synchrony_client_autoreconnect').should be_an_instance_of PG::Result
299
+ end.resume
300
+ system($pgserver_cmd_stop).should be_true
301
+ system($pgserver_cmd_start).should be_true
302
+ Fiber.yield
303
+ notify_flag.should be_true
304
+ @tested_proc.call
305
+ end
306
+
307
+ it "should execute on_connect before on_autoreconnect after server restart" do
308
+ @client.on_connect.should be_nil
309
+ run_on_connect = false
310
+ @client.on_connect = proc do |client, is_async, is_reset|
311
+ client.should be_an_instance_of PG::EM::Client
312
+ is_async.should be_true
313
+ is_reset.should be_true
314
+ client.query('SELECT pg_database_size(current_database());') {
315
+ run_on_connect = true
316
+ }
317
+ end
318
+ @client.on_autoreconnect = proc do |client, ex|
319
+ run_on_connect.should be_true
320
+ @on_autoreconnect.call(client, ex)
321
+ end
322
+ system($pgserver_cmd_stop).should be_true
323
+ system($pgserver_cmd_start).should be_true
324
+ @tested_proc.call
325
+ EM.stop
326
+ end
327
+
328
+ it "should skip on_autoreconnect when on_connect failed after server restart" do
329
+ run_on_connect = false
330
+ run_on_autoreconnect = false
331
+ @client.on_connect = proc do |client, is_async, is_reset|
332
+ client.should be_an_instance_of PG::EM::Client
333
+ is_async.should be_true
334
+ is_reset.should be_true
335
+ begin
336
+ client.query('SELLECT 1;')
337
+ ensure
338
+ run_on_connect = true
339
+ end
340
+ end
341
+ @client.on_autoreconnect = proc do |client, ex|
342
+ run_on_autoreconnect = true
343
+ end
344
+ system($pgserver_cmd_stop).should be_true
345
+ system($pgserver_cmd_start).should be_true
346
+ expect do
347
+ @client.exec_prepared('get_db_size')
348
+ end.to raise_error PG::SyntaxError
349
+ @client.status.should be PG::CONNECTION_OK
350
+ run_on_connect.should be_true
351
+ run_on_autoreconnect.should be_false
352
+ EM.stop
353
+ end
354
+
355
+ before(:all) do
356
+ @tested_proc = proc do
357
+ @client.exec_prepared('get_db_size') do |result|
358
+ result.should be_an_instance_of PG::Result
359
+ result[0]['pg_database_size'].to_i.should be > 0
360
+ end
361
+ end
362
+ @on_autoreconnect = proc do |client, ex|
363
+ client.prepare('get_db_size', 'SELECT pg_database_size(current_database());')
364
+ end
365
+ @options = {on_autoreconnect: @on_autoreconnect}
366
+ @client = PG::EM::Client.new(@options)
367
+ @client.set_notice_processor {|msg| puts "warning from pgsql: #{msg.to_s.chomp.inspect}"}
368
+ @on_autoreconnect.call @client
369
+ end
370
+ end
371
+
372
+ describe 'em-synchrony-pg with autoreconnect disabled' do
373
+ include_context 'em-synchrony-pg common'
374
+
375
+ it "should get database size using query" do
376
+ @tested_proc.call
377
+ end
378
+
379
+ it "should not get database size using query after server restart" do
380
+ system($pgserver_cmd_stop).should be_true
381
+ system($pgserver_cmd_start).should be_true
382
+ expect {
383
+ @tested_proc.call
384
+ }.to raise_error DISCONNECTED_ERROR
385
+ end
386
+
387
+ it "should get database size using query after manual connection reset" do
388
+ @client.status.should be PG::CONNECTION_BAD
389
+ @client.reset
390
+ @client.status.should be PG::CONNECTION_OK
391
+ @tested_proc.call
392
+ end
393
+
394
+ it "should fail to get last result asynchronously after server restart" do
395
+ system($pgserver_cmd_stop).should be_true
396
+ system($pgserver_cmd_start).should be_true
397
+ begin
398
+ @client.send_query('SELECT pg_sleep(50); SELECT pg_database_size(current_database());')
399
+ rescue PG::UnableToSend
400
+ @client.status.should be PG::CONNECTION_BAD
401
+ @client.get_last_result.should be_nil
402
+ else
403
+ expect do
404
+ @client.get_last_result
405
+ end.to raise_error PG::ConnectionBad
406
+ end
407
+ @client.status.should be PG::CONNECTION_BAD
408
+ @client.get_last_result.should be_nil
409
+ @client.reset
410
+ @client.status.should be PG::CONNECTION_OK
411
+ @client.get_last_result.should be_nil
412
+ EM.stop
413
+ end
414
+
415
+ it "should fail to get each result asynchronously after server restart" do
416
+ system($pgserver_cmd_stop).should be_true
417
+ system($pgserver_cmd_start).should be_true
418
+ begin
419
+ @client.send_query('SELECT pg_sleep(50); SELECT pg_database_size(current_database());')
420
+ rescue PG::UnableToSend
421
+ @client.status.should be PG::CONNECTION_BAD
422
+ @client.get_result.should be_nil
423
+ else
424
+ result = @client.get_result
425
+ result.should be_an_instance_of PG::Result
426
+ expect do
427
+ result.check
428
+ end.to raise_error PG::Error
429
+ @client.status.should be PG::CONNECTION_OK
430
+ expect do
431
+ @client.get_result
432
+ end.to raise_error PG::ConnectionBad
433
+ end
434
+ @client.status.should be PG::CONNECTION_BAD
435
+ @client.get_result.should be_nil
436
+ @client.status.should be PG::CONNECTION_BAD
437
+ @client.reset
438
+ @client.status.should be PG::CONNECTION_OK
439
+ @client.get_result.should be_nil
440
+ EM.stop
441
+ end
442
+
443
+ it "should fail wait_for_notify while server restarts" do
444
+ @client.status.should be PG::CONNECTION_OK
445
+ f = Fiber.current
446
+ notify_flag = false
447
+ Fiber.new do
448
+ expect {
449
+ @client.wait_for_notify do
450
+ raise "This block should not be called"
451
+ end
452
+ }.to raise_error(PG::ConnectionBad)
453
+ @client.status.should be PG::CONNECTION_BAD
454
+ expect {
455
+ @client.wait_for_notify do
456
+ raise "This block should not be called"
457
+ end
458
+ }.to raise_error(PG::ConnectionBad)
459
+ @client.status.should be PG::CONNECTION_BAD
460
+ @client.reset
461
+ @client.status.should be PG::CONNECTION_OK
462
+ Fiber.new do
463
+ @client.wait_for_notify do |name,|
464
+ name.should eq 'em_synchrony_client_autoreconnect'
465
+ notify_flag = true
466
+ end.should eq 'em_synchrony_client_autoreconnect'
467
+ @client.query('UNLISTEN *').should be_an_instance_of PG::Result
468
+ f.resume
469
+ end.resume
470
+ @client.query('LISTEN em_synchrony_client_autoreconnect').should be_an_instance_of PG::Result
471
+ @client.query('NOTIFY em_synchrony_client_autoreconnect').should be_an_instance_of PG::Result
472
+ end.resume
473
+ system($pgserver_cmd_stop).should be_true
474
+ system($pgserver_cmd_start).should be_true
475
+ Fiber.yield
476
+ notify_flag.should be_true
477
+ end
478
+
479
+ it "should fail both wait_for_notify and slow query while server restarts" do
480
+ @client.status.should be PG::CONNECTION_OK
481
+ f = Fiber.current
482
+ notify_flag = false
483
+ query_flag = false
484
+ Fiber.new do
485
+ expect {
486
+ @client.query('SELECT pg_sleep(2); SELECT 42')
487
+ }.to raise_error(PG::ConnectionBad)
488
+ query_flag = true
489
+ end.resume
490
+ Fiber.new do
491
+ expect {
492
+ @client.wait_for_notify do
493
+ raise "This block should not be called"
494
+ end
495
+ }.to raise_error(PG::ConnectionBad)
496
+ query_flag.should be_true
497
+ @client.status.should be PG::CONNECTION_BAD
498
+ expect {
499
+ @client.wait_for_notify do
500
+ raise "This block should not be called"
501
+ end
502
+ }.to raise_error(PG::ConnectionBad)
503
+ @client.status.should be PG::CONNECTION_BAD
504
+ expect {
505
+ @client.query('SELECT 1')
506
+ }.to raise_error(PG::UnableToSend)
507
+ @client.reset
508
+ @client.status.should be PG::CONNECTION_OK
509
+ Fiber.new do
510
+ @client.wait_for_notify do |name,|
511
+ name.should eq 'em_synchrony_client_autoreconnect'
512
+ notify_flag = true
513
+ end.should eq 'em_synchrony_client_autoreconnect'
514
+ @client.query('UNLISTEN *').should be_an_instance_of PG::Result
515
+ f.resume
516
+ end.resume
517
+ @client.query('LISTEN em_synchrony_client_autoreconnect').should be_an_instance_of PG::Result
518
+ @client.query('NOTIFY em_synchrony_client_autoreconnect').should be_an_instance_of PG::Result
519
+ end.resume
520
+ system($pgserver_cmd_stop).should be_true
521
+ system($pgserver_cmd_start).should be_true
522
+ Fiber.yield
523
+ notify_flag.should be_true
524
+ end
525
+
526
+ it "should fail wait_for_notify when server was shutdown" do
527
+ @client.status.should be PG::CONNECTION_OK
528
+ @client.wait_for_notify(0.1) do
529
+ raise "This block should not be called"
530
+ end.should be_nil
531
+ system($pgserver_cmd_stop).should be_true
532
+ expect {
533
+ @client.wait_for_notify do
534
+ raise "This block should not be called"
535
+ end
536
+ }.to raise_error(PG::ConnectionBad)
537
+ @client.status.should be PG::CONNECTION_BAD
538
+ expect {
539
+ @client.wait_for_notify do
540
+ raise "This block should not be called"
541
+ end
542
+ }.to raise_error(PG::ConnectionBad)
543
+ @client.status.should be PG::CONNECTION_BAD
544
+ system($pgserver_cmd_start).should be_true
545
+ @client.status.should be PG::CONNECTION_BAD
546
+ @client.reset
547
+ @client.status.should be PG::CONNECTION_OK
548
+ end
549
+
550
+ before(:all) do
551
+ @tested_proc = proc do
552
+ @client.query('SELECT pg_database_size(current_database());') do |result|
553
+ result.should be_an_instance_of PG::Result
554
+ result[0]['pg_database_size'].to_i.should be > 0
555
+ end
556
+ end
557
+ @client = PG::EM::Client.new
558
+ @client.set_notice_processor {|msg| puts "warning from pgsql: #{msg.to_s.chomp.inspect}"}
559
+ end
560
+ end