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