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,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