em-pg-client 0.2.1 → 0.3.0

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.
@@ -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