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,43 @@
1
+ module PG
2
+ module EM
3
+
4
+ # Deferrable with error protectors
5
+ #
6
+ # Author:: Rafal Michalski
7
+ class FeaturedDeferrable < ::EM::DefaultDeferrable
8
+
9
+ def initialize(&blk)
10
+ completion(&blk) if block_given?
11
+ end
12
+
13
+ def completion(&blk)
14
+ callback(&blk)
15
+ errback(&blk)
16
+ end
17
+
18
+ def protect(fail_value = nil)
19
+ yield
20
+ rescue Exception => e
21
+ ::EM.next_tick { fail e }
22
+ fail_value
23
+ end
24
+
25
+ def protect_and_succeed(fail_value = nil)
26
+ ret = yield
27
+ rescue Exception => e
28
+ ::EM.next_tick { fail e }
29
+ fail_value
30
+ else
31
+ ::EM.next_tick { succeed ret }
32
+ ret
33
+ end
34
+
35
+ # bind deferred status of this deferrable to other +df+
36
+ def bind_status(df)
37
+ df.callback { |*a| succeed(*a) }
38
+ df.errback { |*a| fail(*a) }
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,89 @@
1
+ module ConnectionPoolHelpers
2
+ def sleep_one_tick
3
+ f = Fiber.current
4
+ EM.next_tick { f.resume }
5
+ Fiber.yield
6
+ end
7
+
8
+ def create_connection
9
+ client.allocate.tap do |conn|
10
+ conn.stub(:query) do |query|
11
+ query.should start_with 'f'
12
+ checkpoint.check_defer
13
+ f = Fiber.current
14
+ conn.instance_eval { @fiber = f }
15
+ EM.next_tick {
16
+ conn.instance_variable_get(:@fiber).should be f
17
+ f.resume
18
+ }
19
+ Fiber.yield
20
+ if query == 'fee'
21
+ conn.should_receive(:status).once.and_return(PG::CONNECTION_BAD)
22
+ conn.should_receive(:finished?).once.and_return(false)
23
+ conn.should_receive(:finish).once
24
+ raise PG::ConnectionBad
25
+ else
26
+ :result
27
+ end
28
+ end
29
+ conn.stub(:query_defer) do |query|
30
+ query.should start_with 'b'
31
+ checkpoint.check_fiber
32
+ deferrable.new.tap do |df|
33
+ conn.instance_eval { @defer = df }
34
+ EM.next_tick {
35
+ conn.instance_variable_get(:@defer).should be df
36
+ if query == 'bzz'
37
+ conn.should_receive(:status).once.and_return(PG::CONNECTION_BAD)
38
+ conn.should_receive(:finished?).once.and_return(false)
39
+ conn.should_receive(:finish).once
40
+ df.fail pgerror
41
+ else
42
+ df.succeed :result
43
+ end
44
+ }
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def test_queries(pool, queries)
51
+ EM.synchrony do
52
+ EM.add_timer(2) { raise 'timeout' }
53
+ progress = Set.new
54
+ queries.each_with_index do |query, i|
55
+ case query
56
+ when 'foo'
57
+ Fiber.new do
58
+ pool.query(query).should be :result
59
+ progress.delete i
60
+ end.resume
61
+ when 'bar'
62
+ pool.query_defer(query).callback do |result|
63
+ result.should be :result
64
+ progress.delete i
65
+ end.should_not_receive(:fail)
66
+ when 'fee'
67
+ Fiber.new do
68
+ expect do
69
+ pool.query(query)
70
+ end.to raise_error(PG::ConnectionBad)
71
+ progress.delete i
72
+ end.resume
73
+ when 'bzz'
74
+ pool.query_defer(query).errback do |err|
75
+ err.should be pgerror
76
+ progress.delete i
77
+ end.should_not_receive(:succeed)
78
+ end
79
+ progress << i
80
+ end
81
+ progress.should eq Set.new(0...queries.length)
82
+ begin
83
+ yield progress
84
+ sleep_one_tick
85
+ end until progress.empty?
86
+ EM.stop
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,33 @@
1
+ $:.unshift "lib"
2
+ gem 'eventmachine', '~> 1.0.0'
3
+ gem 'pg', ENV['EM_PG_CLIENT_TEST_PG_VERSION']
4
+ require 'date'
5
+ require 'eventmachine'
6
+ require 'pg/em'
7
+ require 'em_client_common'
8
+ RSpec.configure do |config|
9
+ config.include(PGSpecMacros)
10
+ end
11
+
12
+ describe PG::EM::Client do
13
+
14
+ include_context 'em-pg common before'
15
+
16
+ it "should populate foo with some data " do
17
+ EM::Iterator.new(@values).map(proc{ |(data, id), iter|
18
+ @client.query_defer('INSERT INTO foo (id,cdate,data) VALUES($1,$2,$3) returning cdate',
19
+ [id, DateTime.now, data]) do |result|
20
+ result.should be_an_instance_of PG::Result
21
+ iter.return(DateTime.parse(result[0]['cdate']))
22
+ end.should be_a_kind_of ::EM::Deferrable
23
+ }, proc{ |results|
24
+ @cdates.replace results
25
+ results.length.should == @values.length
26
+ results.each {|r| r.should be_an_instance_of DateTime }
27
+ EM.stop
28
+ })
29
+ end
30
+
31
+ include_context 'em-pg common after'
32
+
33
+ end
@@ -0,0 +1,672 @@
1
+ $:.unshift "lib"
2
+ gem 'eventmachine', '~> 1.0.0'
3
+ gem 'pg', ENV['EM_PG_CLIENT_TEST_PG_VERSION']
4
+ require 'date'
5
+ require 'eventmachine'
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 'pg-em common' do
14
+ around(:each) do |testcase|
15
+ EM.run do
16
+ EM.stop if testcase.call.is_a? Exception
17
+ end
18
+ end
19
+
20
+ after(:all) do
21
+ @client.close
22
+ end
23
+ end
24
+
25
+ describe 'pg-em async connect fail' do
26
+ around(:each) do |testcase|
27
+ begin
28
+ system($pgserver_cmd_stop).should be_true
29
+ testcase.call
30
+ ensure
31
+ system($pgserver_cmd_start).should be_true
32
+ end
33
+ end
34
+
35
+ it "should not connect when server is down" do
36
+ error = nil
37
+ EM.run do
38
+ EM.add_timer(1) { EM.stop }
39
+ df = PG::EM::Client.async_connect
40
+ df.callback {|c| c.close }
41
+ df.errback do |err|
42
+ error = err
43
+ EM.stop
44
+ end
45
+ end
46
+ error.should be_an_instance_of PG::ConnectionBad
47
+ end
48
+ end
49
+
50
+ describe 'pg-em default autoreconnect' do
51
+ include_context 'pg-em common'
52
+
53
+ it "should not have modified argument Hash" do
54
+ begin
55
+ @options.should eq(async_autoreconnect: true)
56
+ ensure
57
+ EM.stop
58
+ end
59
+ end
60
+
61
+ it "should get database size using query" do
62
+ @tested_proc.call
63
+ end
64
+
65
+ it "should get database size using query after server restart" do
66
+ system($pgserver_cmd_stop).should be_true
67
+ system($pgserver_cmd_start).should be_true
68
+ @tested_proc.call
69
+ end
70
+
71
+ it "should not get database size using query after server shutdown" do
72
+ system($pgserver_cmd_stop).should be_true
73
+ @client.query_defer('SELECT pg_database_size(current_database());') do |ex|
74
+ ex.should be_an_instance_of DISCONNECTED_ERROR
75
+ EM.stop
76
+ end.should be_a_kind_of ::EM::Deferrable
77
+ end
78
+
79
+ it "should get database size using query after server startup" do
80
+ system($pgserver_cmd_start).should be_true
81
+ @tested_proc.call
82
+ end
83
+
84
+ it "should fail on invalid query after server restart" do
85
+ system($pgserver_cmd_stop).should be_true
86
+ system($pgserver_cmd_start).should be_true
87
+ @client.query_defer('SELLECT 1') do |ex|
88
+ ex.should be_an_instance_of PG::SyntaxError
89
+ EM.stop
90
+ end.should be_a_kind_of ::EM::Deferrable
91
+ end
92
+
93
+ it "should fail when in transaction after server restart" do
94
+ @client.query_defer('BEGIN') do |result|
95
+ result.should be_an_instance_of PG::Result
96
+ system($pgserver_cmd_stop).should be_true
97
+ system($pgserver_cmd_start).should be_true
98
+ @client.query_defer('SELECT pg_database_size(current_database());') do |ex|
99
+ ex.should be_an_instance_of DISCONNECTED_ERROR
100
+ @tested_proc.call
101
+ end.should be_a_kind_of ::EM::Deferrable
102
+ end
103
+ end
104
+
105
+ it "should fail to get last result asynchronously after server restart" do
106
+ @client.send_query('SELECT pg_sleep(50); SELECT pg_database_size(current_database());')
107
+ system($pgserver_cmd_stop).should be_true
108
+ system($pgserver_cmd_start).should be_true
109
+ @client.get_last_result_defer do |ex|
110
+ ex.should be_an_instance_of PG::ConnectionBad
111
+ @client.status.should be PG::CONNECTION_OK
112
+ @client.get_last_result_defer do |result|
113
+ result.should be_nil
114
+ EM.stop
115
+ end
116
+ end.should be_a_kind_of ::EM::Deferrable
117
+ end
118
+
119
+ it "should fail to get each result asynchronously after server restart" do
120
+ @client.send_query('SELECT pg_sleep(50); SELECT pg_database_size(current_database());')
121
+ system($pgserver_cmd_stop).should be_true
122
+ system($pgserver_cmd_start).should be_true
123
+ @client.get_result_defer do |result|
124
+ result.should be_an_instance_of PG::Result
125
+ expect do
126
+ result.check
127
+ end.to raise_error PG::Error
128
+ @client.status.should be PG::CONNECTION_OK
129
+ @client.get_result_defer do |ex|
130
+ ex.should be_an_instance_of PG::ConnectionBad
131
+ @client.status.should be PG::CONNECTION_OK
132
+ @client.get_result_defer do |result|
133
+ result.should be_nil
134
+ EM.stop
135
+ end.should be_a_kind_of ::EM::Deferrable
136
+ end.should be_a_kind_of ::EM::Deferrable
137
+ end
138
+ end
139
+
140
+ it "should fail wait_for_notify while server restarts" do
141
+ @client.status.should be PG::CONNECTION_OK
142
+ @client.wait_for_notify_defer do |ex|
143
+ ex.should be_an_instance_of PG::ConnectionBad
144
+ @client.status.should be PG::CONNECTION_OK
145
+ @client.wait_for_notify_defer do |notification|
146
+ notification.should be_an_instance_of Hash
147
+ notification[:relname].should eq 'em_client_autoreconnect'
148
+ @client.query_defer('UNLISTEN *') do |result|
149
+ result.should be_an_instance_of PG::Result
150
+ EM.stop
151
+ end.should be_a_kind_of ::EM::Deferrable
152
+ end.should be_a_kind_of ::EM::Deferrable
153
+ @client.query_defer('LISTEN em_client_autoreconnect') do |result|
154
+ result.should be_an_instance_of PG::Result
155
+ @client.query_defer('NOTIFY em_client_autoreconnect') do |result|
156
+ result.should be_an_instance_of PG::Result
157
+ end.should be_a_kind_of ::EM::Deferrable
158
+ end.should be_a_kind_of ::EM::Deferrable
159
+ end.should be_a_kind_of ::EM::Deferrable
160
+ system($pgserver_cmd_stop).should be_true
161
+ system($pgserver_cmd_start).should be_true
162
+ end
163
+
164
+ it "should fail wait_for_notify and finish slow query while server restarts" do
165
+ @client.status.should be PG::CONNECTION_OK
166
+ start_time = Time.now
167
+ query_flag = false
168
+ @client.query_defer('SELECT pg_sleep(2); SELECT 42') do |result|
169
+ result.should be_an_instance_of PG::Result
170
+ result.getvalue(0,0).to_i.should eq 42
171
+ (Time.now - start_time).should be > 2
172
+ query_flag = true
173
+ end.should be_a_kind_of ::EM::Deferrable
174
+ @client.wait_for_notify_defer do |ex|
175
+ query_flag.should be_true
176
+ ex.should be_an_instance_of PG::ConnectionBad
177
+ @client.status.should be PG::CONNECTION_OK
178
+ @client.wait_for_notify_defer do |notification|
179
+ notification.should be_an_instance_of Hash
180
+ notification[:relname].should eq 'em_client_autoreconnect'
181
+ @client.query_defer('UNLISTEN *') do |result|
182
+ result.should be_an_instance_of PG::Result
183
+ EM.stop
184
+ end.should be_a_kind_of ::EM::Deferrable
185
+ end.should be_a_kind_of ::EM::Deferrable
186
+ @client.query_defer('LISTEN em_client_autoreconnect') do |result|
187
+ result.should be_an_instance_of PG::Result
188
+ @client.query_defer('NOTIFY em_client_autoreconnect') do |result|
189
+ result.should be_an_instance_of PG::Result
190
+ end.should be_a_kind_of ::EM::Deferrable
191
+ end.should be_a_kind_of ::EM::Deferrable
192
+ end.should be_a_kind_of ::EM::Deferrable
193
+ system($pgserver_cmd_stop).should be_true
194
+ system($pgserver_cmd_start).should be_true
195
+ end
196
+
197
+ before(:all) do
198
+ @tested_proc = proc do
199
+ @client.query_defer('SELECT pg_database_size(current_database());') do |result|
200
+ result.should be_an_instance_of PG::Result
201
+ result[0]['pg_database_size'].to_i.should be > 0
202
+ EM.stop
203
+ end.should be_a_kind_of ::EM::Deferrable
204
+ end
205
+ @options = {async_autoreconnect: true}
206
+ @client = PG::EM::Client.new(@options)
207
+ @client.set_notice_processor {|msg| puts "warning from pgsql: #{msg.to_s.chomp.inspect}"}
208
+ end
209
+ end
210
+
211
+ describe 'pg-em autoreconnect with on_autoreconnect' do
212
+ include_context 'pg-em common'
213
+
214
+ it "should not have modified argument Hash" do
215
+ begin
216
+ @options.should eq(on_autoreconnect: @on_autoreconnect)
217
+ ensure
218
+ EM.stop
219
+ end
220
+ end
221
+
222
+ it "should get database size using prepared statement"do
223
+ @tested_proc.call
224
+ end
225
+
226
+ it "should get database size using prepared statement after server restart" do
227
+ system($pgserver_cmd_stop).should be_true
228
+ system($pgserver_cmd_start).should be_true
229
+ @tested_proc.call
230
+ end
231
+
232
+ it "should fail on invalid query after server restart" do
233
+ system($pgserver_cmd_stop).should be_true
234
+ system($pgserver_cmd_start).should be_true
235
+ @client.query_defer('SELLECT 1') do |ex|
236
+ ex.should be_an_instance_of PG::SyntaxError
237
+ EM.stop
238
+ end.should be_a_kind_of ::EM::Deferrable
239
+ end
240
+
241
+ it "should fail when in transaction after server restart" do
242
+ @client.query_defer('BEGIN') do |result|
243
+ result.should be_an_instance_of PG::Result
244
+ system($pgserver_cmd_stop).should be_true
245
+ system($pgserver_cmd_start).should be_true
246
+ @client.query_defer('SELECT pg_database_size(current_database());') do |ex|
247
+ ex.should be_an_instance_of DISCONNECTED_ERROR
248
+ @tested_proc.call
249
+ end.should be_a_kind_of ::EM::Deferrable
250
+ end
251
+ end
252
+
253
+ it "should fail on false from on_autoreconnect after server restart" do
254
+ @client.on_autoreconnect = proc { false }
255
+ system($pgserver_cmd_stop).should be_true
256
+ system($pgserver_cmd_start).should be_true
257
+ @client.query_defer('SELECT pg_database_size(current_database());') do |ex|
258
+ ex.should be_an_instance_of DISCONNECTED_ERROR
259
+ EM.stop
260
+ end.should be_a_kind_of ::EM::Deferrable
261
+ end
262
+
263
+ it "should complete on true from on_autoreconnect after server restart" do
264
+ @client.on_autoreconnect = proc { true }
265
+ system($pgserver_cmd_stop).should be_true
266
+ system($pgserver_cmd_start).should be_true
267
+ @client.query_defer('SELECT pg_database_size(current_database());') do |result|
268
+ result.should be_an_instance_of PG::Result
269
+ result[0]['pg_database_size'].to_i.should be > 0
270
+ EM.stop
271
+ end.should be_a_kind_of ::EM::Deferrable
272
+ end
273
+
274
+ it "should fail on query with true from on_autoreconnect after restart" do
275
+ @client.on_autoreconnect = proc { true }
276
+ system($pgserver_cmd_stop).should be_true
277
+ system($pgserver_cmd_start).should be_true
278
+ @client.query_defer('SELLECT 1') do |ex|
279
+ ex.should be_an_instance_of PG::SyntaxError
280
+ EM.stop
281
+ end.should be_a_kind_of ::EM::Deferrable
282
+ end
283
+
284
+ it "should fail on on_autoreconnect deferrable fail after server restart" do
285
+ @client.on_autoreconnect = proc do
286
+ ::EM::DefaultDeferrable.new.tap {|df| df.fail :boo }
287
+ end
288
+ system($pgserver_cmd_stop).should be_true
289
+ system($pgserver_cmd_start).should be_true
290
+ @client.query_defer('SELECT 1') do |ex|
291
+ ex.should be :boo
292
+ EM.stop
293
+ end.should be_a_kind_of ::EM::Deferrable
294
+ end
295
+
296
+ it "should fail on raised error in on_autoreconnect after server restart" do
297
+ @client.on_autoreconnect = proc do
298
+ raise TypeError
299
+ end
300
+ system($pgserver_cmd_stop).should be_true
301
+ system($pgserver_cmd_start).should be_true
302
+ @client.query_defer('SELECT 1') do |ex|
303
+ ex.should be_an_instance_of TypeError
304
+ EM.stop
305
+ end.should be_a_kind_of ::EM::Deferrable
306
+ end
307
+
308
+ it "should fail to get last result asynchronously after server restart" do
309
+ @client.on_autoreconnect = proc { true }
310
+ @client.send_query('SELECT pg_sleep(50); SELECT pg_database_size(current_database());')
311
+ system($pgserver_cmd_stop).should be_true
312
+ system($pgserver_cmd_start).should be_true
313
+ @client.get_last_result_defer do |ex|
314
+ ex.should be_an_instance_of PG::ConnectionBad
315
+ @client.status.should be PG::CONNECTION_OK
316
+ @client.get_last_result_defer do |result|
317
+ result.should be_nil
318
+ EM.stop
319
+ end
320
+ end.should be_a_kind_of ::EM::Deferrable
321
+ end
322
+
323
+ it "should fail to get each result asynchronously after server restart" do
324
+ @client.on_autoreconnect = proc {
325
+ ::EM::DefaultDeferrable.new.tap {|df| df.succeed }
326
+ }
327
+ @client.send_query('SELECT pg_sleep(50); SELECT pg_database_size(current_database());')
328
+ system($pgserver_cmd_stop).should be_true
329
+ system($pgserver_cmd_start).should be_true
330
+ @client.get_result_defer do |result|
331
+ result.should be_an_instance_of PG::Result
332
+ expect do
333
+ result.check
334
+ end.to raise_error PG::Error
335
+ @client.status.should be PG::CONNECTION_OK
336
+ @client.get_result_defer do |ex|
337
+ ex.should be_an_instance_of PG::ConnectionBad
338
+ @client.status.should be PG::CONNECTION_OK
339
+ @client.get_result_defer do |result|
340
+ result.should be_nil
341
+ EM.stop
342
+ end.should be_a_kind_of ::EM::Deferrable
343
+ end.should be_a_kind_of ::EM::Deferrable
344
+ end
345
+ end
346
+
347
+ it "should fail wait_for_notify while server restarts" do
348
+ @client.status.should be PG::CONNECTION_OK
349
+ @client.on_autoreconnect(&@on_autoreconnect)
350
+ @client.wait_for_notify_defer do |ex|
351
+ ex.should be_an_instance_of PG::ConnectionBad
352
+ @client.status.should be PG::CONNECTION_OK
353
+ @client.wait_for_notify_defer do |notification|
354
+ notification.should be_an_instance_of Hash
355
+ notification[:relname].should eq 'em_client_autoreconnect'
356
+ @client.query_defer('UNLISTEN *') do |result|
357
+ result.should be_an_instance_of PG::Result
358
+ @tested_proc.call
359
+ end.should be_a_kind_of ::EM::Deferrable
360
+ end.should be_a_kind_of ::EM::Deferrable
361
+ @client.query_defer('LISTEN em_client_autoreconnect') do |result|
362
+ result.should be_an_instance_of PG::Result
363
+ @client.query_defer('NOTIFY em_client_autoreconnect') do |result|
364
+ result.should be_an_instance_of PG::Result
365
+ end.should be_a_kind_of ::EM::Deferrable
366
+ end.should be_a_kind_of ::EM::Deferrable
367
+ end.should be_a_kind_of ::EM::Deferrable
368
+ system($pgserver_cmd_stop).should be_true
369
+ system($pgserver_cmd_start).should be_true
370
+ end
371
+
372
+ it "should fail wait_for_notify and finish slow query while server restarts" do
373
+ @client.status.should be PG::CONNECTION_OK
374
+ @client.on_autoreconnect = @on_autoreconnect
375
+ start_time = Time.now
376
+ query_flag = false
377
+ @client.query_defer('SELECT pg_sleep(2); SELECT 42') do |result|
378
+ result.should be_an_instance_of PG::Result
379
+ result.getvalue(0,0).to_i.should eq 42
380
+ (Time.now - start_time).should be > 2
381
+ query_flag = true
382
+ end.should be_a_kind_of ::EM::Deferrable
383
+ @client.wait_for_notify_defer do |ex|
384
+ query_flag.should be_true
385
+ ex.should be_an_instance_of PG::ConnectionBad
386
+ @client.status.should be PG::CONNECTION_OK
387
+ @client.wait_for_notify_defer do |notification|
388
+ notification.should be_an_instance_of Hash
389
+ notification[:relname].should eq 'em_client_autoreconnect'
390
+ @client.query_defer('UNLISTEN *') do |result|
391
+ result.should be_an_instance_of PG::Result
392
+ @tested_proc.call
393
+ end.should be_a_kind_of ::EM::Deferrable
394
+ end.should be_a_kind_of ::EM::Deferrable
395
+ @client.query_defer('LISTEN em_client_autoreconnect') do |result|
396
+ result.should be_an_instance_of PG::Result
397
+ @client.query_defer('NOTIFY em_client_autoreconnect') do |result|
398
+ result.should be_an_instance_of PG::Result
399
+ end.should be_a_kind_of ::EM::Deferrable
400
+ end.should be_a_kind_of ::EM::Deferrable
401
+ end.should be_a_kind_of ::EM::Deferrable
402
+ system($pgserver_cmd_stop).should be_true
403
+ system($pgserver_cmd_start).should be_true
404
+ end
405
+
406
+ it "should execute on_connect before on_autoreconnect after server restart" do
407
+ @client.on_connect.should be_nil
408
+ run_on_connect = false
409
+ @client.on_connect = proc do |client, is_async, is_reset|
410
+ client.should be_an_instance_of PG::EM::Client
411
+ is_async.should be_true
412
+ is_reset.should be_true
413
+ client.query_defer('SELECT pg_database_size(current_database());').callback {
414
+ run_on_connect = true
415
+ }
416
+ end
417
+ @client.on_autoreconnect = proc do |client, ex|
418
+ run_on_connect.should be_true
419
+ @on_autoreconnect.call(client, ex)
420
+ end
421
+ system($pgserver_cmd_stop).should be_true
422
+ system($pgserver_cmd_start).should be_true
423
+ @tested_proc.call
424
+ end
425
+
426
+ it "should skip on_autoreconnect when on_connect failed after server restart" do
427
+ run_on_connect = false
428
+ run_on_autoreconnect = false
429
+ @client.on_connect = proc do |client, is_async, is_reset|
430
+ client.should be_an_instance_of PG::EM::Client
431
+ is_async.should be_true
432
+ is_reset.should be_true
433
+ client.query_defer('SELLECT 1;').errback {
434
+ run_on_connect = true
435
+ }
436
+ end
437
+ @client.on_autoreconnect = proc do |client, ex|
438
+ run_on_autoreconnect = true
439
+ end
440
+ system($pgserver_cmd_stop).should be_true
441
+ system($pgserver_cmd_start).should be_true
442
+ @client.exec_prepared_defer('get_db_size') do |ex|
443
+ ex.should be_an_instance_of PG::SyntaxError
444
+ @client.status.should be PG::CONNECTION_OK
445
+ run_on_connect.should be_true
446
+ run_on_autoreconnect.should be_false
447
+ EM.stop
448
+ end.should be_a_kind_of ::EM::Deferrable
449
+ end
450
+
451
+ before(:all) do
452
+ @tested_proc = proc do
453
+ @client.exec_prepared_defer('get_db_size') do |result|
454
+ result.should be_an_instance_of PG::Result
455
+ result[0]['pg_database_size'].to_i.should be > 0
456
+ EM.stop
457
+ end.should be_a_kind_of ::EM::Deferrable
458
+ end
459
+ @on_autoreconnect = proc do |client, ex|
460
+ df = client.prepare_defer('get_db_size', 'SELECT pg_database_size(current_database());')
461
+ df.should be_a_kind_of ::EM::Deferrable
462
+ df
463
+ end
464
+ @options = {on_autoreconnect: @on_autoreconnect}
465
+ @client = PG::EM::Client.new(@options)
466
+ @client.set_notice_processor {|msg| puts "warning from pgsql: #{msg.to_s.chomp.inspect}"}
467
+ @client.prepare('get_db_size', 'SELECT pg_database_size(current_database());')
468
+ end
469
+ end
470
+
471
+ describe 'pg-em with autoreconnect disabled' do
472
+ include_context 'pg-em common'
473
+
474
+ it "should get database size using query" do
475
+ @tested_proc.call
476
+ end
477
+
478
+ it "should not get database size using query after server restart" do
479
+ system($pgserver_cmd_stop).should be_true
480
+ system($pgserver_cmd_start).should be_true
481
+ @client.query_defer('SELECT pg_database_size(current_database());') do |ex|
482
+ ex.should be_an_instance_of DISCONNECTED_ERROR
483
+ @client.status.should be PG::CONNECTION_BAD
484
+ EM.stop
485
+ end.should be_a_kind_of ::EM::Deferrable
486
+ end
487
+
488
+ it "should get database size using query after async manual connection reset" do
489
+ @client.status.should be PG::CONNECTION_BAD
490
+ @client.reset_defer do |conn|
491
+ conn.should be @client
492
+ @client.status.should be PG::CONNECTION_OK
493
+ @tested_proc.call
494
+ end.should be_a_kind_of ::EM::Deferrable
495
+ end
496
+
497
+ it "should fail to get last result asynchronously after server restart" do
498
+ @client.status.should be PG::CONNECTION_OK
499
+ check_get_last_result = proc do
500
+ @client.get_last_result_defer do |result|
501
+ result.should be_nil
502
+ @client.reset_defer do |conn|
503
+ conn.should be @client
504
+ @client.status.should be PG::CONNECTION_OK
505
+ EM.stop
506
+ end.should be_a_kind_of ::EM::Deferrable
507
+ end
508
+ end
509
+ system($pgserver_cmd_stop).should be_true
510
+ system($pgserver_cmd_start).should be_true
511
+ begin
512
+ @client.send_query('SELECT pg_sleep(50); SELECT pg_database_size(current_database());')
513
+ rescue PG::UnableToSend
514
+ @client.status.should be PG::CONNECTION_BAD
515
+ @client.get_last_result_defer do |ex|
516
+ ex.should be_nil
517
+ @client.status.should be PG::CONNECTION_BAD
518
+ check_get_last_result.call
519
+ end.should be_a_kind_of ::EM::Deferrable
520
+ else
521
+ @client.get_last_result_defer do |ex|
522
+ ex.should be_an_instance_of PG::ConnectionBad
523
+ @client.status.should be PG::CONNECTION_BAD
524
+ check_get_last_result.call
525
+ end.should be_a_kind_of ::EM::Deferrable
526
+ end
527
+ end
528
+
529
+ it "should fail to get each result asynchronously after server restart" do
530
+ @client.status.should be PG::CONNECTION_OK
531
+ check_get_result = proc do |expected_class|
532
+ @client.get_result_defer do |result|
533
+ result.should be_an_instance_of expected_class
534
+ @client.status.should be PG::CONNECTION_BAD
535
+ @client.reset_defer do |conn|
536
+ conn.should be @client
537
+ @client.status.should be PG::CONNECTION_OK
538
+ EM.stop
539
+ end.should be_a_kind_of ::EM::Deferrable
540
+ end.should be_a_kind_of ::EM::Deferrable
541
+ end
542
+ system($pgserver_cmd_stop).should be_true
543
+ system($pgserver_cmd_start).should be_true
544
+ begin
545
+ @client.send_query('SELECT pg_sleep(50); SELECT pg_database_size(current_database());')
546
+ rescue PG::UnableToSend
547
+ @client.get_result_defer do |result|
548
+ result.should be_nil
549
+ @client.status.should be PG::CONNECTION_BAD
550
+ check_get_result.call NilClass
551
+ end
552
+ else
553
+ @client.get_result_defer do |result|
554
+ result.should be_an_instance_of PG::Result
555
+ expect do
556
+ result.check
557
+ end.to raise_error PG::Error
558
+ @client.status.should be PG::CONNECTION_OK
559
+ check_get_result.call PG::ConnectionBad
560
+ end
561
+ end
562
+ end
563
+
564
+ it "should fail wait_for_notify while server restarts" do
565
+ @client.status.should be PG::CONNECTION_OK
566
+ @client.on_autoreconnect(&@on_autoreconnect)
567
+ @client.wait_for_notify_defer do |ex|
568
+ ex.should be_an_instance_of PG::ConnectionBad
569
+ @client.status.should be PG::CONNECTION_BAD
570
+ @client.wait_for_notify_defer do |ex|
571
+ ex.should be_an_instance_of PG::ConnectionBad
572
+ @client.status.should be PG::CONNECTION_BAD
573
+ @client.reset_defer do |conn|
574
+ conn.should be @client
575
+ @client.status.should be PG::CONNECTION_OK
576
+ @client.wait_for_notify_defer do |notification|
577
+ notification.should be_an_instance_of Hash
578
+ notification[:relname].should eq 'em_client_autoreconnect'
579
+ @client.query_defer('UNLISTEN *') do |result|
580
+ result.should be_an_instance_of PG::Result
581
+ EM.stop
582
+ end.should be_a_kind_of ::EM::Deferrable
583
+ end.should be_a_kind_of ::EM::Deferrable
584
+ @client.query_defer('LISTEN em_client_autoreconnect') do |result|
585
+ result.should be_an_instance_of PG::Result
586
+ @client.query_defer('NOTIFY em_client_autoreconnect') do |result|
587
+ result.should be_an_instance_of PG::Result
588
+ end.should be_a_kind_of ::EM::Deferrable
589
+ end.should be_a_kind_of ::EM::Deferrable
590
+ end.should be_a_kind_of ::EM::Deferrable
591
+ end.should be_a_kind_of ::EM::Deferrable
592
+ end.should be_a_kind_of ::EM::Deferrable
593
+ system($pgserver_cmd_stop).should be_true
594
+ system($pgserver_cmd_start).should be_true
595
+ end
596
+
597
+ it "should fail both wait_for_notify and slow query while server restarts" do
598
+ @client.status.should be PG::CONNECTION_OK
599
+ @client.on_autoreconnect = @on_autoreconnect
600
+ query_flag = false
601
+ @client.query_defer('SELECT pg_sleep(2); SELECT 42') do |ex|
602
+ ex.should be_an_instance_of PG::ConnectionBad
603
+ query_flag = true
604
+ end.should be_a_kind_of ::EM::Deferrable
605
+ @client.wait_for_notify_defer do |ex|
606
+ query_flag.should be_true
607
+ ex.should be_an_instance_of PG::ConnectionBad
608
+ @client.status.should be PG::CONNECTION_BAD
609
+ @client.wait_for_notify_defer do |ex|
610
+ ex.should be_an_instance_of PG::ConnectionBad
611
+ @client.status.should be PG::CONNECTION_BAD
612
+ @client.query_defer('SELECT 1') do |ex|
613
+ ex.should be_an_instance_of PG::UnableToSend
614
+ @client.reset_defer do |conn|
615
+ conn.should be @client
616
+ @client.status.should be PG::CONNECTION_OK
617
+ @client.wait_for_notify_defer do |notification|
618
+ notification.should be_an_instance_of Hash
619
+ notification[:relname].should eq 'em_client_autoreconnect'
620
+ @client.query_defer('UNLISTEN *') do |result|
621
+ result.should be_an_instance_of PG::Result
622
+ EM.stop
623
+ end.should be_a_kind_of ::EM::Deferrable
624
+ end.should be_a_kind_of ::EM::Deferrable
625
+ @client.query_defer('LISTEN em_client_autoreconnect') do |result|
626
+ result.should be_an_instance_of PG::Result
627
+ @client.query_defer('NOTIFY em_client_autoreconnect') do |result|
628
+ result.should be_an_instance_of PG::Result
629
+ end.should be_a_kind_of ::EM::Deferrable
630
+ end.should be_a_kind_of ::EM::Deferrable
631
+ end.should be_a_kind_of ::EM::Deferrable
632
+ end.should be_a_kind_of ::EM::Deferrable
633
+ end.should be_a_kind_of ::EM::Deferrable
634
+ end.should be_a_kind_of ::EM::Deferrable
635
+ system($pgserver_cmd_stop).should be_true
636
+ system($pgserver_cmd_start).should be_true
637
+ end
638
+
639
+ it "should fail wait_for_notify when server was shutdown" do
640
+ @client.status.should be PG::CONNECTION_OK
641
+ @client.wait_for_notify_defer(0.1) do |notification|
642
+ notification.should be_nil
643
+ system($pgserver_cmd_stop).should be_true
644
+ @client.wait_for_notify_defer do |ex|
645
+ ex.should be_an_instance_of PG::ConnectionBad
646
+ @client.status.should be PG::CONNECTION_BAD
647
+ @client.wait_for_notify_defer do |ex|
648
+ ex.should be_an_instance_of PG::ConnectionBad
649
+ system($pgserver_cmd_start).should be_true
650
+ @client.status.should be PG::CONNECTION_BAD
651
+ @client.reset_defer do |client|
652
+ client.should be @client
653
+ @client.status.should be PG::CONNECTION_OK
654
+ EM.stop
655
+ end.should be_a_kind_of ::EM::Deferrable
656
+ end.should be_a_kind_of ::EM::Deferrable
657
+ end.should be_a_kind_of ::EM::Deferrable
658
+ end.should be_a_kind_of ::EM::Deferrable
659
+ end
660
+
661
+ before(:all) do
662
+ @tested_proc = proc do
663
+ @client.query_defer('SELECT pg_database_size(current_database());') do |result|
664
+ result.should be_an_instance_of PG::Result
665
+ result[0]['pg_database_size'].to_i.should be > 0
666
+ EM.stop
667
+ end.should be_a_kind_of ::EM::Deferrable
668
+ end
669
+ @client = PG::EM::Client.new
670
+ @client.set_notice_processor {|msg| puts "warning from pgsql: #{msg.to_s.chomp.inspect}"}
671
+ end
672
+ end