em-pg-client 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,130 +1,154 @@
1
- $:.unshift "lib"
2
- require 'date'
3
- require 'em-synchrony'
4
- require 'em-synchrony/pg'
5
-
6
- $pgserver_cmd_stop = %Q[sudo su - postgres -c 'pg_ctl stop -m fast']
7
- $pgserver_cmd_start = %Q[sudo su - postgres -c 'pg_ctl -l $PGDATA/postgres.log start -w']
8
-
9
- shared_context 'em-synchrony-pg common' do
10
- around(:each) do |testcase|
11
- EM.synchrony do
12
- testcase.call
13
- EM.stop
14
- end
15
- end
16
-
17
- after(:all) do
18
- @client.close
19
- end
20
- end
21
-
22
- describe 'em-synchrony-pg default autoreconnect' do
23
- include_context 'em-synchrony-pg common'
24
-
25
- it "should not have modified argument Hash" do
26
- @options.should eq(async_autoreconnect: true)
27
- end
28
-
29
- it "should get database size using query" do
30
- @tested_proc.call
31
- end
32
-
33
- it "should get database size using query after server restart" do
34
- system($pgserver_cmd_stop).should be_true
35
- system($pgserver_cmd_start).should be_true
36
- @tested_proc.call
37
- end
38
-
39
- it "should not get database size using query after server shutdown" do
40
- system($pgserver_cmd_stop).should be_true
41
- expect {
42
- @tested_proc.call
43
- }.to raise_error(PG::Error)
44
- end
45
-
46
- it "should get database size using query after server startup" do
47
- system($pgserver_cmd_start).should be_true
48
- @tested_proc.call
49
- end
50
-
51
- before(:all) do
52
- @tested_proc = proc do
53
- @client.query('SELECT pg_database_size(current_database());') do |result|
54
- result.should be_an_instance_of PG::Result
55
- result[0]['pg_database_size'].to_i.should be > 0
56
- end
57
- end
58
- @options = {async_autoreconnect: true}
59
- @client = PG::EM::Client.new(@options)
60
- @client.set_notice_processor {|msg| puts "warning from pgsql: #{msg.to_s.chomp.inspect}"}
61
- end
62
- end
63
-
64
- describe 'em-synchrony-pg autoreconnect with on_autoreconnect' do
65
- include_context 'em-synchrony-pg common'
66
-
67
- it "should not have modified argument Hash" do
68
- @options.should eq(on_autoreconnect: @on_autoreconnect)
69
- end
70
-
71
- it "should get database size using prepared statement" do
72
- @tested_proc.call
73
- end
74
-
75
- it "should get database size using prepared statement after server restart" do
76
- system($pgserver_cmd_stop).should be_true
77
- system($pgserver_cmd_start).should be_true
78
- @tested_proc.call
79
- end
80
-
81
- before(:all) do
82
- @tested_proc = proc do
83
- @client.exec_prepared('get_db_size') do |result|
84
- result.should be_an_instance_of PG::Result
85
- result[0]['pg_database_size'].to_i.should be > 0
86
- end
87
- end
88
- @on_autoreconnect = proc do |client, ex|
89
- client.prepare('get_db_size', 'SELECT pg_database_size(current_database());')
90
- end
91
- @options = {on_autoreconnect: @on_autoreconnect}
92
- @client = PG::EM::Client.new(@options)
93
- @client.set_notice_processor {|msg| puts "warning from pgsql: #{msg.to_s.chomp.inspect}"}
94
- @on_autoreconnect.call @client
95
- end
96
- end
97
-
98
- describe 'em-synchrony-pg with autoreconnect disabled' do
99
- include_context 'em-synchrony-pg common'
100
-
101
- it "should get database size using query" do
102
- @tested_proc.call
103
- end
104
-
105
- it "should not get database size using query after server restart" do
106
- system($pgserver_cmd_stop).should be_true
107
- system($pgserver_cmd_start).should be_true
108
- expect {
109
- @tested_proc.call
110
- }.to raise_error(PG::Error)
111
- end
112
-
113
- it "should get database size using query after manual connection reset" do
114
- @client.status.should be PG::CONNECTION_BAD
115
- @client.reset
116
- @client.status.should be PG::CONNECTION_OK
117
- @tested_proc.call
118
- end
119
-
120
- before(:all) do
121
- @tested_proc = proc do
122
- @client.query('SELECT pg_database_size(current_database());') do |result|
123
- result.should be_an_instance_of PG::Result
124
- result[0]['pg_database_size'].to_i.should be > 0
125
- end
126
- end
127
- @client = PG::EM::Client.new
128
- @client.set_notice_processor {|msg| puts "warning from pgsql: #{msg.to_s.chomp.inspect}"}
129
- end
130
- end
1
+ $:.unshift "lib"
2
+ gem 'eventmachine', '~> 1.0.0'
3
+ gem 'pg', ENV['EM_PG_CLIENT_TEST_PG_VERSION']
4
+ require 'date'
5
+ require 'em-synchrony'
6
+ require 'pg/em'
7
+
8
+ $pgserver_cmd_stop = %Q[sudo -i -u postgres pg_ctl -D "#{ENV['PGDATA']}" stop -s -m fast]
9
+ $pgserver_cmd_start = %Q[sudo -i -u postgres pg_ctl -D "#{ENV['PGDATA']}" start -s -w]
10
+
11
+ shared_context 'em-synchrony-pg common' do
12
+ around(:each) do |testcase|
13
+ EM.synchrony do
14
+ testcase.call
15
+ EM.stop
16
+ end
17
+ end
18
+
19
+ after(:all) do
20
+ @client.close
21
+ end
22
+ end
23
+
24
+ describe 'em-synchrony-pg default autoreconnect' do
25
+ include_context 'em-synchrony-pg common'
26
+
27
+ it "should not have modified argument Hash" do
28
+ @options.should eq(async_autoreconnect: true)
29
+ end
30
+
31
+ it "should get database size using query" do
32
+ @tested_proc.call
33
+ end
34
+
35
+ it "should get database size using query after server restart" do
36
+ system($pgserver_cmd_stop).should be_true
37
+ system($pgserver_cmd_start).should be_true
38
+ @tested_proc.call
39
+ end
40
+
41
+ it "should not get database size using query after server shutdown" do
42
+ system($pgserver_cmd_stop).should be_true
43
+ expect {
44
+ @tested_proc.call
45
+ }.to raise_error(@client.host.include?('/') ? PG::UnableToSend : PG::ConnectionBad)
46
+ end
47
+
48
+ it "should get database size using query after server startup" do
49
+ system($pgserver_cmd_start).should be_true
50
+ @tested_proc.call
51
+ end
52
+
53
+ it "should raise an error when in transaction after server restart" do
54
+ expect do
55
+ @client.transaction do
56
+ system($pgserver_cmd_stop).should be_true
57
+ system($pgserver_cmd_start).should be_true
58
+ @tested_proc.call
59
+ end
60
+ end.to raise_error(@client.host.include?('/') ? PG::UnableToSend : PG::ConnectionBad)
61
+ @tested_proc.call
62
+ end
63
+
64
+ before(:all) do
65
+ @tested_proc = proc do
66
+ @client.query('SELECT pg_database_size(current_database());') do |result|
67
+ result.should be_an_instance_of PG::Result
68
+ result[0]['pg_database_size'].to_i.should be > 0
69
+ end
70
+ end
71
+ @options = {async_autoreconnect: true}
72
+ @client = PG::EM::Client.new(@options)
73
+ @client.set_notice_processor {|msg| puts "warning from pgsql: #{msg.to_s.chomp.inspect}"}
74
+ end
75
+ end
76
+
77
+ describe 'em-synchrony-pg autoreconnect with on_autoreconnect' do
78
+ include_context 'em-synchrony-pg common'
79
+
80
+ it "should not have modified argument Hash" do
81
+ @options.should eq(on_autoreconnect: @on_autoreconnect)
82
+ end
83
+
84
+ it "should get database size using prepared statement" do
85
+ @tested_proc.call
86
+ end
87
+
88
+ it "should get database size using prepared statement after server restart" do
89
+ system($pgserver_cmd_stop).should be_true
90
+ system($pgserver_cmd_start).should be_true
91
+ @tested_proc.call
92
+ end
93
+
94
+ it "should raise an error when in transaction after server restart" do
95
+ expect do
96
+ @client.transaction do
97
+ system($pgserver_cmd_stop).should be_true
98
+ system($pgserver_cmd_start).should be_true
99
+ @tested_proc.call
100
+ end
101
+ end.to raise_error(@client.host.include?('/') ? PG::UnableToSend : PG::ConnectionBad)
102
+ @tested_proc.call
103
+ end
104
+
105
+ before(:all) do
106
+ @tested_proc = proc do
107
+ @client.exec_prepared('get_db_size') do |result|
108
+ result.should be_an_instance_of PG::Result
109
+ result[0]['pg_database_size'].to_i.should be > 0
110
+ end
111
+ end
112
+ @on_autoreconnect = proc do |client, ex|
113
+ client.prepare('get_db_size', 'SELECT pg_database_size(current_database());')
114
+ end
115
+ @options = {on_autoreconnect: @on_autoreconnect}
116
+ @client = PG::EM::Client.new(@options)
117
+ @client.set_notice_processor {|msg| puts "warning from pgsql: #{msg.to_s.chomp.inspect}"}
118
+ @on_autoreconnect.call @client
119
+ end
120
+ end
121
+
122
+ describe 'em-synchrony-pg with autoreconnect disabled' do
123
+ include_context 'em-synchrony-pg common'
124
+
125
+ it "should get database size using query" do
126
+ @tested_proc.call
127
+ end
128
+
129
+ it "should not get database size using query after server restart" do
130
+ system($pgserver_cmd_stop).should be_true
131
+ system($pgserver_cmd_start).should be_true
132
+ expect {
133
+ @tested_proc.call
134
+ }.to raise_error(@client.host.include?('/') ? PG::UnableToSend : PG::ConnectionBad)
135
+ end
136
+
137
+ it "should get database size using query after manual connection reset" do
138
+ @client.status.should be PG::CONNECTION_BAD
139
+ @client.reset
140
+ @client.status.should be PG::CONNECTION_OK
141
+ @tested_proc.call
142
+ end
143
+
144
+ before(:all) do
145
+ @tested_proc = proc do
146
+ @client.query('SELECT pg_database_size(current_database());') do |result|
147
+ result.should be_an_instance_of PG::Result
148
+ result[0]['pg_database_size'].to_i.should be > 0
149
+ end
150
+ end
151
+ @client = PG::EM::Client.new
152
+ @client.set_notice_processor {|msg| puts "warning from pgsql: #{msg.to_s.chomp.inspect}"}
153
+ end
154
+ end
@@ -0,0 +1,54 @@
1
+ $:.unshift "lib"
2
+ gem 'eventmachine', '~> 1.0.0'
3
+ gem 'pg', ENV['EM_PG_CLIENT_TEST_PG_VERSION']
4
+ require 'eventmachine'
5
+ require 'em-synchrony'
6
+ require 'pg/em'
7
+
8
+ shared_context 'test deferred' do
9
+ it "should not finish connection on deferred connection failure" do
10
+ EM.run do
11
+ subject.connect_defer(options) do |ex|
12
+ ex.should be_an_instance_of PG::ConnectionBad
13
+ ex.connection.should be_an_instance_of subject
14
+ ex.connection.finished?.should be_false
15
+ EM.stop
16
+ end.should be_a_kind_of ::EM::DefaultDeferrable
17
+ end
18
+ end
19
+ end
20
+
21
+ shared_context 'test blocking' do
22
+ it "should not finish connection on blocking connection failure" do
23
+ EM.synchrony do
24
+ expect do
25
+ subject.new(options)
26
+ end.to raise_error(PG::ConnectionBad)
27
+ begin
28
+ subject.new(options)
29
+ rescue => ex
30
+ ex.should be_an_instance_of PG::ConnectionBad
31
+ ex.connection.should be_an_instance_of subject
32
+ ex.connection.finished?.should be_false
33
+ end
34
+ EM.stop
35
+ end
36
+ end
37
+ end
38
+
39
+ describe 'connect failure and finished? status' do
40
+ subject { PG::EM::Client }
41
+ let(:bogus_port) { 1 }
42
+
43
+ describe 'with localhost' do
44
+ let(:options) { {host: 'localhost', port: bogus_port} }
45
+ include_context 'test deferred'
46
+ include_context 'test blocking'
47
+ end
48
+
49
+ describe 'with unix socket' do
50
+ let(:options) { {host: '/tmp', port: bogus_port} }
51
+ include_context 'test deferred'
52
+ include_context 'test blocking'
53
+ end unless RSpec.windows_os?
54
+ end
@@ -0,0 +1,91 @@
1
+ $:.unshift "lib"
2
+ gem 'eventmachine', '~> 1.0.0'
3
+ gem 'pg', ENV['EM_PG_CLIENT_TEST_PG_VERSION']
4
+ require 'eventmachine'
5
+ require 'em-synchrony'
6
+ require 'pg/em'
7
+
8
+ shared_context 'test async connect timeout' do
9
+ it "should timeout expire while connecting" do
10
+ this = :first
11
+ start = Time.now
12
+ subject.connect_defer(options) do |ex|
13
+ this = :second
14
+ ex.should be_an_instance_of PG::ConnectionBad
15
+ ex.message.should include 'timeout expired (async)'
16
+ (Time.now - start).should be > timeout
17
+ EM.stop
18
+ end.should be_a_kind_of ::EM::DefaultDeferrable
19
+ this.should be :first
20
+ end
21
+
22
+ around(:each) do |testcase|
23
+ EM.run(&testcase)
24
+ end
25
+ end
26
+
27
+ shared_context 'test synchrony connect timeout' do
28
+ it "should timeout expire while connecting" do
29
+ start = Time.now
30
+ this = nil
31
+ EM.next_tick { this = :that }
32
+ expect do
33
+ subject.new(options)
34
+ end.to raise_error(PG::ConnectionBad, 'timeout expired (async)')
35
+ this.should be :that
36
+ (Time.now - start).should be > timeout
37
+ end
38
+
39
+ around(:each) do |testcase|
40
+ EM.synchrony do
41
+ begin
42
+ testcase.call
43
+ ensure
44
+ EM.stop
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ describe 'connect timeout expire' do
51
+ subject { PG::EM::Client }
52
+ let(:black_hole) { '192.168.255.254' }
53
+ let(:timeout) { 1 }
54
+ let(:envvar) { 'PGCONNECT_TIMEOUT' }
55
+
56
+ describe 'asynchronously using connect_timeout option' do
57
+ let(:options) { {host: black_hole, connect_timeout: timeout} }
58
+
59
+ before(:each) { ENV[envvar] = nil }
60
+
61
+ include_context 'test async connect timeout'
62
+ end
63
+
64
+ describe 'asynchronously using PGCONNECT_TIMEOUT env var' do
65
+ let(:options) { {host: black_hole} }
66
+
67
+ before(:each) { ENV[envvar] = timeout.to_s }
68
+
69
+ include_context 'test async connect timeout'
70
+
71
+ after(:each) { ENV[envvar] = nil }
72
+ end
73
+
74
+ describe 'sync-to-fiber using connect_timeout option' do
75
+ let(:options) { {host: black_hole, connect_timeout: timeout} }
76
+
77
+ before(:each) { ENV[envvar] = nil }
78
+
79
+ include_context 'test synchrony connect timeout'
80
+ end
81
+
82
+ describe 'sync-to-fiber using PGCONNECT_TIMEOUT env var' do
83
+ let(:options) { {host: black_hole} }
84
+
85
+ before(:each) { ENV[envvar] = timeout.to_s }
86
+
87
+ include_context 'test synchrony connect timeout'
88
+
89
+ after(:each) { ENV[envvar] = nil }
90
+ end
91
+ end
@@ -0,0 +1,85 @@
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
+ describe 'em-pg-client options' do
9
+ subject { PG::EM::Client }
10
+
11
+ let(:callback) { proc {|c, e| false } }
12
+ let(:args) { [{async_autoreconnect: true, connect_timeout: 10, host: 'foo'}] }
13
+ let(:str_key_args) { [{'async_autoreconnect'=>true, 'connect_timeout'=>10, 'host'=>'foo'}] }
14
+ let(:pgconn_args) { [{connect_timeout: 10, host: 'foo'}] }
15
+ let(:str_key_pgconn_args) { [{'connect_timeout'=>10, 'host'=>'foo'}] }
16
+ let(:async_options) { {
17
+ :@async_autoreconnect => true,
18
+ :@connect_timeout => 10,
19
+ :@query_timeout=>0,
20
+ :@on_autoreconnect=>nil,
21
+ :@async_command_aborted=>false} }
22
+
23
+ it "should parse options and not modify original hash" do
24
+ orig_args = args.dup
25
+ orig_options = orig_args.first.dup
26
+ options = subject.parse_async_options orig_args
27
+ options.should eq async_options
28
+ orig_args.should eq pgconn_args
29
+ args.first.should eq orig_options
30
+ end
31
+
32
+ it "should parse options with keys as strings" do
33
+ orig_args = str_key_args.dup
34
+ orig_options = orig_args.first.dup
35
+ options = subject.parse_async_options orig_args
36
+ options.should eq async_options
37
+ orig_args.should eq str_key_pgconn_args
38
+ str_key_args.first.should eq orig_options
39
+ end
40
+
41
+ it "should set async_autoreconnect according to on_autoreconnect" do
42
+ options = subject.parse_async_options []
43
+ options.should be_an_instance_of Hash
44
+ options[:@on_autoreconnect].should be_nil
45
+ options[:@async_autoreconnect].should be_false
46
+
47
+ args = [on_autoreconnect: callback]
48
+ options = subject.parse_async_options args
49
+ args.should eq [{}]
50
+ options.should be_an_instance_of Hash
51
+ options[:@on_autoreconnect].should be callback
52
+ options[:@async_autoreconnect].should be_true
53
+
54
+ args = [async_autoreconnect: false,
55
+ on_autoreconnect: callback]
56
+ options = subject.parse_async_options args
57
+ args.should eq [{}]
58
+ options.should be_an_instance_of Hash
59
+ options[:@on_autoreconnect].should be callback
60
+ options[:@async_autoreconnect].should be_false
61
+
62
+ args = [on_autoreconnect: callback,
63
+ async_autoreconnect: false]
64
+ options = subject.parse_async_options args
65
+ args.should eq [{}]
66
+ options.should be_an_instance_of Hash
67
+ options[:@on_autoreconnect].should be callback
68
+ options[:@async_autoreconnect].should be_false
69
+ end
70
+
71
+ it "should set only callable on_autoreconnect" do
72
+ expect do
73
+ subject.parse_async_options [on_autoreconnect: true]
74
+ end.to raise_error(ArgumentError, /must respond to/)
75
+
76
+ expect do
77
+ subject.parse_async_options [on_autoreconnect: Object.new]
78
+ end.to raise_error(ArgumentError, /must respond to/)
79
+
80
+ options = subject.parse_async_options [on_autoreconnect: callback]
81
+ options.should be_an_instance_of Hash
82
+ options[:@on_autoreconnect].should be callback
83
+ end
84
+
85
+ end