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.
- checksums.yaml +7 -0
- data/.rspec +1 -0
- data/.travis.yml +32 -0
- data/.yardopts +1 -0
- data/BENCHMARKS.md +91 -0
- data/Gemfile +5 -0
- data/HISTORY.md +107 -0
- data/LICENSE +21 -0
- data/README.md +456 -0
- data/Rakefile +157 -0
- data/benchmarks/em_pg.rb +96 -0
- data/benchmarks/single_row_mode.rb +88 -0
- data/em-pg-client.gemspec +34 -0
- data/examples/single_row_mode.rb +57 -0
- data/lib/em-pg-client.rb +1 -0
- data/lib/em-synchrony/pg.rb +3 -0
- data/lib/pg/em-version.rb +5 -0
- data/lib/pg/em.rb +1129 -0
- data/lib/pg/em/client/connect_watcher.rb +89 -0
- data/lib/pg/em/client/watcher.rb +204 -0
- data/lib/pg/em/connection_pool.rb +480 -0
- data/lib/pg/em/featured_deferrable.rb +43 -0
- data/spec/connection_pool_helpers.rb +89 -0
- data/spec/em_client.rb +33 -0
- data/spec/em_client_autoreconnect.rb +672 -0
- data/spec/em_client_common.rb +619 -0
- data/spec/em_client_on_connect.rb +171 -0
- data/spec/em_connection_pool.rb +200 -0
- data/spec/em_synchrony_client.rb +787 -0
- data/spec/em_synchrony_client_autoreconnect.rb +560 -0
- data/spec/pg_em_client_connect_finish.rb +54 -0
- data/spec/pg_em_client_connect_timeout.rb +91 -0
- data/spec/pg_em_client_options.rb +133 -0
- data/spec/pg_em_connection_pool.rb +679 -0
- data/spec/pg_em_featured_deferrable.rb +125 -0
- data/spec/spec_helper.rb +9 -0
- metadata +187 -0
@@ -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
|
data/spec/em_client.rb
ADDED
@@ -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
|