pg 0.9.0-x86-mswin32 → 0.11.0pre229-x86-mswin32

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.
@@ -16,7 +16,7 @@ end
16
16
  SPEC_FILES = [] unless defined?( SPEC_FILES )
17
17
  TEST_FILES = [] unless defined?( TEST_FILES )
18
18
 
19
- COMMON_SPEC_OPTS = ['-Du'] unless defined?( COMMON_SPEC_OPTS )
19
+ COMMON_RSPEC_OPTS = [] unless defined?( COMMON_RSPEC_OPTS )
20
20
 
21
21
  COVERAGE_TARGETDIR = BASEDIR + 'coverage' unless defined?( COVERAGE_TARGETDIR )
22
22
  RCOV_EXCLUDES = 'spec,tests,/Library/Ruby,/var/lib,/usr/local/lib' unless
@@ -39,149 +39,114 @@ end
39
39
 
40
40
  ### RSpec specifications
41
41
  begin
42
- gem 'rspec', '>= 1.1.3'
42
+ gem 'rspec', '>= 2.0.0'
43
43
 
44
- require 'spec'
45
- require 'spec/rake/spectask'
44
+ require 'rspec'
45
+ require 'rspec/core/rake_task'
46
46
 
47
47
  ### Task: spec
48
48
  desc "Run specs"
49
49
  task :spec => 'spec:doc'
50
+ task :specs => :spec
50
51
 
51
52
  namespace :spec do
52
53
  desc "Run rspec every time there's a change to one of the files"
53
54
  task :autotest do
54
- require 'autotest/rspec'
55
-
56
- autotester = Autotest::Rspec.new
57
- autotester.run
55
+ require 'autotest'
56
+ Autotest.add_discovery { "rspec2" }
57
+ Autotest.run
58
58
  end
59
59
 
60
60
  desc "Generate regular color 'doc' spec output"
61
- Spec::Rake::SpecTask.new( :doc ) do |task|
62
- task.spec_files = SPEC_FILES
63
- task.spec_opts = COMMON_SPEC_OPTS + ['-f', 's', '-c']
61
+ RSpec::Core::RakeTask.new( :doc ) do |task|
62
+ task.rspec_opts = COMMON_RSPEC_OPTS + ['-f', 'd', '-c']
64
63
  end
65
64
 
66
65
  desc "Generate spec output with profiling"
67
- Spec::Rake::SpecTask.new( :profile ) do |task|
68
- task.spec_files = SPEC_FILES
69
- task.spec_opts = COMMON_SPEC_OPTS + ['-f', 'o']
66
+ RSpec::Core::RakeTask.new( :profile ) do |task|
67
+ task.rspec_opts = COMMON_RSPEC_OPTS + ['-f', 'p', '-p']
70
68
  end
71
69
 
72
70
  desc "Generate quiet non-colored plain-text output"
73
- Spec::Rake::SpecTask.new( :quiet ) do |task|
74
- task.spec_files = SPEC_FILES
75
- task.spec_opts = COMMON_SPEC_OPTS + ['-f', 'p']
71
+ RSpec::Core::RakeTask.new( :quiet ) do |task|
72
+ task.rspec_opts = COMMON_RSPEC_OPTS + ['-f', 'p']
76
73
  end
77
74
 
78
75
  desc "Generate HTML output"
79
- Spec::Rake::SpecTask.new( :html ) do |task|
80
- task.spec_files = SPEC_FILES
81
- task.spec_opts = COMMON_SPEC_OPTS + ['-f', 'h']
76
+ RSpec::Core::RakeTask.new( :html ) do |task|
77
+ task.rspec_opts = COMMON_RSPEC_OPTS + ['-f', 'h']
82
78
  end
83
79
 
84
- end
85
- rescue LoadError => err
86
- task :no_rspec do
87
- $stderr.puts "Specification tasks not defined: %s" % [ err.message ]
88
- end
89
-
90
- task :spec => :no_rspec
91
- namespace :spec do
92
- task :autotest => :no_rspec
93
- task :doc => :no_rspec
94
- task :profile => :no_rspec
95
- task :quiet => :no_rspec
96
- task :html => :no_rspec
97
- end
98
- end
99
-
100
-
101
- ### Test::Unit tests
102
- begin
103
- require 'rake/testtask'
104
-
105
- Rake::TestTask.new( :unittests ) do |task|
106
- task.libs += [LIBDIR]
107
- task.test_files = TEST_FILES
108
- task.verbose = true
109
- end
110
80
 
111
- rescue LoadError => err
112
- task :no_test do
113
- $stderr.puts "Test tasks not defined: %s" % [ err.message ]
114
81
  end
115
82
 
116
- task :unittests => :no_rspec
117
- end
118
-
119
-
120
- ### RCov (via RSpec) tasks
121
- begin
122
- gem 'rcov'
123
- gem 'rspec', '>= 1.1.3'
124
-
125
- require 'spec'
126
- require 'rcov'
127
-
128
83
  ### Task: coverage (via RCov)
129
84
  desc "Build test coverage reports"
130
- unless SPEC_FILES.empty?
131
- Spec::Rake::SpecTask.new( :coverage ) do |task|
132
- task.spec_files = SPEC_FILES
133
- task.libs += [LIBDIR]
134
- task.spec_opts = ['-f', 'p', '-b']
135
- task.rcov_opts = RCOV_OPTS
136
- task.rcov = true
137
- end
85
+ RSpec::Core::RakeTask.new( :coverage ) do |task|
86
+ task.ruby_opts = [ "-I#{LIBDIR}" ]
87
+ task.rspec_opts = ['-f', 'p', '-b']
88
+ task.rcov_opts = RCOV_OPTS
89
+ task.rcov = true
138
90
  end
139
91
 
140
-
141
92
  ### Task: rcov
142
93
  task :rcov => :coverage
143
94
 
144
95
  ### Other coverage tasks
145
96
  namespace :coverage do
146
97
  desc "Generate a detailed text coverage report"
147
- Spec::Rake::SpecTask.new( :text ) do |task|
148
- task.spec_files = SPEC_FILES
98
+ RSpec::Core::RakeTask.new( :text ) do |task|
149
99
  task.rcov_opts = RCOV_OPTS + ['--text-report']
150
100
  task.rcov = true
151
101
  end
152
102
 
153
103
  desc "Show differences in coverage from last run"
154
- Spec::Rake::SpecTask.new( :diff ) do |task|
155
- task.spec_files = SPEC_FILES
156
- task.spec_opts = ['-f', 'p', '-b']
104
+ RSpec::Core::RakeTask.new( :diff ) do |task|
105
+ task.rspec_opts = ['-f', 'p', '-b']
157
106
  task.rcov_opts = RCOV_OPTS - ['--save'] + ['--text-coverage-diff']
158
107
  task.rcov = true
159
108
  end
160
109
 
161
110
  desc "Run RCov in 'spec-only' mode to check coverage from specs"
162
- Spec::Rake::SpecTask.new( :speconly ) do |task|
163
- task.spec_files = SPEC_FILES
111
+ RSpec::Core::RakeTask.new( :speconly ) do |task|
164
112
  task.rcov_opts = ['--exclude', RCOV_EXCLUDES, '--text-report', '--save']
165
113
  task.rcov = true
166
114
  end
167
115
  end
168
116
 
169
117
  CLOBBER.include( COVERAGE_TARGETDIR )
170
-
171
118
  rescue LoadError => err
172
- task :no_rcov do
173
- $stderr.puts "Coverage tasks not defined: RSpec+RCov tasklib not available: %s" %
174
- [ err.message ]
119
+ task :no_rspec do
120
+ $stderr.puts "Specification tasks not defined: %s" % [ err.message ]
175
121
  end
176
122
 
177
- task :coverage => :no_rcov
178
- task :clobber_coverage
179
- task :rcov => :no_rcov
180
- namespace :coverage do
181
- task :text => :no_rcov
182
- task :diff => :no_rcov
123
+ task :spec => :no_rspec
124
+ namespace :spec do
125
+ task :autotest => :no_rspec
126
+ task :doc => :no_rspec
127
+ task :profile => :no_rspec
128
+ task :quiet => :no_rspec
129
+ task :html => :no_rspec
183
130
  end
184
- task :verify => :no_rcov
131
+ end
132
+
133
+
134
+ ### Test::Unit tests
135
+ begin
136
+ require 'rake/testtask'
137
+
138
+ Rake::TestTask.new( :unittests ) do |task|
139
+ task.libs += [LIBDIR]
140
+ task.test_files = TEST_FILES
141
+ task.verbose = true
142
+ end
143
+
144
+ rescue LoadError => err
145
+ task :no_test do
146
+ $stderr.puts "Test tasks not defined: %s" % [ err.message ]
147
+ end
148
+
149
+ task :unittests => :no_rspec
185
150
  end
186
151
 
187
152
 
@@ -1,9 +1,19 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'pathname'
4
+ require 'rspec'
5
+
6
+
7
+ RSpec.configure do |config|
8
+ ruby_version_vec = RUBY_VERSION.split('.').map {|c| c.to_i }.pack( "N*" )
9
+
10
+ config.mock_with :rspec
11
+ config.filter_run_excluding :ruby_19 => true if ruby_version_vec <= [1,9,1].pack( "N*" )
12
+ end
4
13
 
5
14
  module PgTestingHelpers
6
15
 
16
+
7
17
  # Set some ANSI escape code constants (Shamelessly stolen from Perl's
8
18
  # Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
9
19
  ANSI_ATTRIBUTES = {
@@ -104,6 +114,8 @@ module PgTestingHelpers
104
114
  end
105
115
 
106
116
 
117
+ NOFORK_PLATFORMS = %w{java}
118
+
107
119
  ### Run the specified command +cmd+ after redirecting stdout and stderr to the specified
108
120
  ### +logpath+, failing if the execution fails.
109
121
  def log_and_run( logpath, *cmd )
@@ -115,16 +127,24 @@ module PgTestingHelpers
115
127
  trace( cmd )
116
128
  end
117
129
 
118
- logfh = File.open( logpath, File::WRONLY|File::CREAT|File::APPEND )
119
- if pid = fork
120
- logfh.close
121
- Process.wait
130
+ # Eliminate the noise of creating/tearing down the database by
131
+ # redirecting STDERR/STDOUT to a logfile if the Ruby interpreter
132
+ # supports fork()
133
+ if NOFORK_PLATFORMS.include?( RUBY_PLATFORM )
134
+ system( *cmd )
122
135
  else
123
- $stdout.reopen( logfh )
124
- $stderr.reopen( $stdout )
125
- exec( *cmd )
126
- $stderr.puts "After the exec()?!??!"
127
- exit!
136
+ logfh = File.open( logpath, File::WRONLY|File::CREAT|File::APPEND )
137
+ if pid = fork
138
+ logfh.close
139
+ else
140
+ $stdout.reopen( logfh )
141
+ $stderr.reopen( $stdout )
142
+ exec( *cmd )
143
+ $stderr.puts "After the exec()?!??!"
144
+ exit!
145
+ end
146
+
147
+ Process.wait( pid )
128
148
  end
129
149
 
130
150
  raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
@@ -141,15 +161,18 @@ module PgTestingHelpers
141
161
  datadir = testdir + 'data'
142
162
  pidfile = datadir + 'postmaster.pid'
143
163
  if pidfile.exist? && pid = pidfile.read.chomp.to_i
164
+ $stderr.puts "pidfile (%p) exists: %d" % [ pidfile, pid ]
144
165
  begin
145
166
  Process.kill( 0, pid )
146
167
  rescue Errno::ESRCH
147
- trace "No postmaster running for %s" % [ datadir ]
168
+ $stderr.puts "No postmaster running for %s" % [ datadir ]
148
169
  # Process isn't alive, so don't try to stop it
149
170
  else
150
- trace "Stopping lingering database at PID %d"
171
+ $stderr.puts "Stopping lingering database at PID %d" % [ pid ]
151
172
  run 'pg_ctl', '-D', datadir.to_s, '-m', 'fast', 'stop'
152
173
  end
174
+ else
175
+ $stderr.puts "No pidfile (%p)" % [ pidfile ]
153
176
  end
154
177
  end
155
178
  end
@@ -176,20 +199,19 @@ module PgTestingHelpers
176
199
  begin
177
200
  unless (@test_pgdata+"postgresql.conf").exist?
178
201
  FileUtils.rm_rf( @test_pgdata, :verbose => $DEBUG )
179
- trace "Running initdb"
202
+ $stderr.puts "Running initdb"
180
203
  log_and_run @logfile, 'initdb', '--no-locale', '-D', @test_pgdata.to_s
181
204
  end
182
205
 
183
206
  trace "Starting postgres"
184
207
  log_and_run @logfile, 'pg_ctl', '-w', '-o', "-k #{@test_directory.to_s.inspect}",
185
208
  '-D', @test_pgdata.to_s, 'start'
209
+ sleep 2
210
+
211
+ $stderr.puts "Creating the test DB"
212
+ log_and_run @logfile, 'psql', '-e', '-c', 'DROP DATABASE IF EXISTS test', 'postgres'
213
+ log_and_run @logfile, 'createdb', '-e', 'test'
186
214
 
187
- if `psql -l` =~ /^\s*test\s/
188
- trace "Dropping the test DB"
189
- log_and_run @logfile, 'dropdb', 'test'
190
- end
191
- trace "Creating the test DB"
192
- log_and_run @logfile, 'createdb', 'test'
193
215
  rescue => err
194
216
  $stderr.puts "%p during test setup: %s" % [ err.class, err.message ]
195
217
  $stderr.puts "See #{@logfile} for details."
@@ -9,33 +9,21 @@ BEGIN {
9
9
  libdir = basedir + 'lib'
10
10
  archlib = libdir + Config::CONFIG['sitearch']
11
11
 
12
+ $LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
12
13
  $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
13
14
  $LOAD_PATH.unshift( archlib.to_s ) unless $LOAD_PATH.include?( archlib.to_s )
14
15
  }
15
16
 
16
- require 'pg'
17
-
18
- require 'rubygems'
19
- require 'spec'
17
+ require 'rspec'
20
18
  require 'spec/lib/helpers'
19
+ require 'pg'
21
20
 
22
- describe "multinationalization support" do
21
+ describe "multinationalization support", :ruby_19 => true do
23
22
  include PgTestingHelpers
24
23
 
25
- RUBY_VERSION_VEC = RUBY_VERSION.split('.').map {|c| c.to_i }.pack("N*")
26
- MIN_RUBY_VERSION_VEC = [1,9,1].pack('N*')
27
-
28
-
29
24
  before( :all ) do
30
- @conn = nil
31
- if RUBY_VERSION_VEC >= MIN_RUBY_VERSION_VEC
32
- @conn = setup_testing_db( "m17n" )
33
- @conn.exec( 'BEGIN' )
34
- end
35
- end
36
-
37
- before( :each ) do
38
- pending "depends on m17n support in Ruby >= 1.9.1" if @conn.nil?
25
+ @conn = setup_testing_db( "m17n" )
26
+ @conn.exec( 'BEGIN' )
39
27
  end
40
28
 
41
29
 
@@ -49,7 +37,7 @@ describe "multinationalization support" do
49
37
  res = conn.exec("VALUES ('#{PGconn.escape_bytea(in_bytes)}'::bytea)", [], 0)
50
38
  out_bytes = PGconn.unescape_bytea(res[0]['column1'])
51
39
  end
52
- out_bytes.should== in_bytes
40
+ out_bytes.should == in_bytes
53
41
  end
54
42
 
55
43
  describe "rubyforge #22925: m17n support" do
@@ -114,17 +102,41 @@ describe "multinationalization support" do
114
102
  res = conn.exec( stmt, [], 0 )
115
103
  out_string = res[0]['column1']
116
104
  end
117
- out_string.should == 'foo'.encode(Encoding::ASCII_8BIT)
105
+ out_string.should == 'foo'.encode( Encoding::ASCII_8BIT )
118
106
  out_string.encoding.should == Encoding::ASCII_8BIT
119
107
  end
120
108
  end
121
109
 
122
- it "should use client encoding for escaped string" do
123
- original = "string to escape".force_encoding("euc-jp")
124
- @conn.set_client_encoding("euc_jp")
125
- escaped = @conn.escape(original)
110
+ it "uses the client encoding for escaped string" do
111
+ original = "string to escape".force_encoding( "euc-jp" )
112
+ @conn.set_client_encoding( "euc_jp" )
113
+ escaped = @conn.escape( original )
126
114
  escaped.encoding.should == Encoding::EUC_JP
127
115
  end
116
+ end
117
+
118
+ describe "Ruby 1.9.x default_internal encoding" do
119
+
120
+ it "honors the Encoding.default_internal if it's set and the synchronous interface is used" do
121
+ @conn.transaction do |txn_conn|
122
+ txn_conn.internal_encoding = Encoding::ISO8859_1
123
+ txn_conn.exec( "CREATE TABLE defaultinternaltest ( foo text )" )
124
+ txn_conn.exec( "INSERT INTO defaultinternaltest VALUES ('Grün und Weiß')" )
125
+ end
126
+
127
+ begin
128
+ prev_encoding = Encoding.default_internal
129
+ Encoding.default_internal = Encoding::UTF_8
130
+
131
+ conn = PGconn.connect( @conninfo )
132
+ conn.internal_encoding.should == Encoding::UTF_8
133
+ res = conn.exec( "SELECT foo FROM defaultinternaltest" )
134
+ res[0]['foo'].encoding.should == Encoding::UTF_8
135
+ ensure
136
+ conn.finish if conn
137
+ Encoding.default_internal = prev_encoding
138
+ end
139
+ end
128
140
 
129
141
  end
130
142
 
@@ -9,15 +9,14 @@ BEGIN {
9
9
  libdir = basedir + 'lib'
10
10
  archlib = libdir + Config::CONFIG['sitearch']
11
11
 
12
+ $LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
12
13
  $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
13
14
  $LOAD_PATH.unshift( archlib.to_s ) unless $LOAD_PATH.include?( archlib.to_s )
14
15
  }
15
16
 
16
- require 'pg'
17
-
18
- require 'rubygems'
19
- require 'spec'
17
+ require 'rspec'
20
18
  require 'spec/lib/helpers'
19
+ require 'pg'
21
20
  require 'timeout'
22
21
 
23
22
  describe PGconn do
@@ -82,27 +81,69 @@ describe PGconn do
82
81
  res[0]['n'].should == '1'
83
82
  end
84
83
 
84
+
85
+ EXPECTED_TRACE_OUTPUT = %{
86
+ To backend> Msg Q
87
+ To backend> "SELECT 1 AS one"
88
+ To backend> Msg complete, length 21
89
+ From backend> T
90
+ From backend (#4)> 28
91
+ From backend (#2)> 1
92
+ From backend> "one"
93
+ From backend (#4)> 0
94
+ From backend (#2)> 0
95
+ From backend (#4)> 23
96
+ From backend (#2)> 4
97
+ From backend (#4)> -1
98
+ From backend (#2)> 0
99
+ From backend> D
100
+ From backend (#4)> 11
101
+ From backend (#2)> 1
102
+ From backend (#4)> 1
103
+ From backend (1)> 1
104
+ From backend> C
105
+ From backend (#4)> 13
106
+ From backend> "SELECT 1"
107
+ From backend> Z
108
+ From backend (#4)> 5
109
+ From backend> Z
110
+ From backend (#4)> 5
111
+ From backend> T
112
+ }.gsub( /^\t{2}/, '' ).lstrip
113
+
85
114
  unless RUBY_PLATFORM =~ /mswin|mingw/
86
115
  it "should trace and untrace client-server communication" do
87
116
  # be careful to explicitly close files so that the
88
117
  # directory can be removed and we don't have to wait for
89
118
  # the GC to run.
90
- expected_trace_file = File.join(Dir.getwd, "spec/data", "expected_trace.out")
91
- expected_trace_data = open(expected_trace_file, 'rb').read
92
- trace_file = open(File.join(@test_directory, "test_trace.out"), 'wb')
93
- @conn.trace(trace_file)
94
- trace_file.close
119
+ trace_file = @test_directory + "test_trace.out"
120
+ trace_io = trace_file.open( 'w', 0600 )
121
+ @conn.trace( trace_io )
122
+ trace_io.close
123
+
95
124
  res = @conn.exec("SELECT 1 AS one")
96
125
  @conn.untrace
126
+
97
127
  res = @conn.exec("SELECT 2 AS two")
98
- trace_file = open(File.join(@test_directory, "test_trace.out"), 'rb')
128
+
99
129
  trace_data = trace_file.read
100
- trace_file.close
101
- trace_data.should == expected_trace_data
130
+
131
+ expected_trace_output = EXPECTED_TRACE_OUTPUT.dup
132
+ # For PostgreSQL < 9.0, the output will be different:
133
+ # -From backend (#4)> 13
134
+ # -From backend> "SELECT 1"
135
+ # +From backend (#4)> 11
136
+ # +From backend> "SELECT"
137
+ if @conn.server_version < 90000
138
+ expected_trace_output.sub!( /From backend \(#4\)> 13/, 'From backend (#4)> 11' )
139
+ expected_trace_output.sub!( /From backend> "SELECT 1"/, 'From backend> "SELECT"' )
140
+ end
141
+
142
+ trace_data.should == expected_trace_output
102
143
  end
103
144
  end
104
145
 
105
- it "should cancel a query" do
146
+ it "allows a query to be cancelled" do
106
147
  error = false
107
148
  @conn.send_query("SELECT pg_sleep(1000)")
108
149
  @conn.cancel
@@ -113,6 +154,25 @@ describe PGconn do
113
154
  error.should == true
114
155
  end
115
156
 
157
+ it "automatically rolls back a transaction started with PGconn#transaction if an exception " +
158
+ "is raised" do
159
+ # abort the per-example transaction so we can test our own
160
+ @conn.exec( 'ROLLBACK' )
161
+
162
+ res = nil
163
+ @conn.exec( "CREATE TABLE pie ( flavor TEXT )" )
164
+
165
+ expect {
166
+ res = @conn.transaction do
167
+ @conn.exec( "INSERT INTO pie VALUES ('rhubarb'), ('cherry'), ('schizophrenia')" )
168
+ raise "Oh noes! All pie is gone!"
169
+ end
170
+ }.to raise_exception( RuntimeError, /all pie is gone/i )
171
+
172
+ res = @conn.exec( "SELECT * FROM pie" )
173
+ res.ntuples.should == 0
174
+ end
175
+
116
176
  it "should not read past the end of a large object" do
117
177
  @conn.transaction do
118
178
  oid = @conn.lo_create( 0 )
@@ -125,16 +185,19 @@ describe PGconn do
125
185
  end
126
186
 
127
187
 
128
- it "should wait for NOTIFY events via select()" do
188
+ it "can wait for NOTIFY events" do
129
189
  @conn.exec( 'ROLLBACK' )
130
190
  @conn.exec( 'LISTEN woo' )
131
191
 
132
192
  pid = fork do
133
- conn = PGconn.connect( @conninfo )
134
- sleep 1
135
- conn.exec( 'NOTIFY woo' )
136
- conn.finish
137
- exit!
193
+ begin
194
+ conn = PGconn.connect( @conninfo )
195
+ sleep 1
196
+ conn.exec( 'NOTIFY woo' )
197
+ ensure
198
+ conn.finish
199
+ exit!
200
+ end
138
201
  end
139
202
 
140
203
  @conn.wait_for_notify( 10 ).should == 'woo'
@@ -143,6 +206,199 @@ describe PGconn do
143
206
  Process.wait( pid )
144
207
  end
145
208
 
209
+ it "calls a block for NOTIFY events if one is given" do
210
+ @conn.exec( 'ROLLBACK' )
211
+ @conn.exec( 'LISTEN woo' )
212
+
213
+ pid = fork do
214
+ begin
215
+ conn = PGconn.connect( @conninfo )
216
+ sleep 1
217
+ conn.exec( 'NOTIFY woo' )
218
+ ensure
219
+ conn.finish
220
+ exit!
221
+ end
222
+ end
223
+
224
+ eventpid = event = nil
225
+ @conn.wait_for_notify( 10 ) {|*args| event, eventpid = args }
226
+ event.should == 'woo'
227
+ eventpid.should be_an( Integer )
228
+
229
+ @conn.exec( 'UNLISTEN woo' )
230
+
231
+ Process.wait( pid )
232
+ end
233
+
234
+ it "doesn't collapse sequential notifications" do
235
+ @conn.exec( 'ROLLBACK' )
236
+ @conn.exec( 'LISTEN woo' )
237
+ @conn.exec( 'LISTEN war' )
238
+ @conn.exec( 'LISTEN woz' )
239
+
240
+ pid = fork do
241
+ begin
242
+ conn = PGconn.connect( @conninfo )
243
+ conn.exec( 'NOTIFY woo' )
244
+ conn.exec( 'NOTIFY war' )
245
+ conn.exec( 'NOTIFY woz' )
246
+ ensure
247
+ conn.finish
248
+ exit!
249
+ end
250
+ end
251
+
252
+ Process.wait( pid )
253
+
254
+ channels = []
255
+ 3.times do
256
+ channels << @conn.wait_for_notify( 2 )
257
+ end
258
+
259
+ channels.should have( 3 ).members
260
+ channels.should include( 'woo', 'war', 'woz' )
261
+
262
+ @conn.exec( 'UNLISTEN woz' )
263
+ @conn.exec( 'UNLISTEN war' )
264
+ @conn.exec( 'UNLISTEN woo' )
265
+ end
266
+
267
+ it "returns notifications which are already in the queue before wait_for_notify is called " +
268
+ "without waiting for the socket to become readable" do
269
+ @conn.exec( 'ROLLBACK' )
270
+ @conn.exec( 'LISTEN woo' )
271
+
272
+ pid = fork do
273
+ begin
274
+ conn = PGconn.connect( @conninfo )
275
+ conn.exec( 'NOTIFY woo' )
276
+ ensure
277
+ conn.finish
278
+ exit!
279
+ end
280
+ end
281
+
282
+ # Wait for the forked child to send the notification
283
+ Process.wait( pid )
284
+
285
+ # Cause the notification to buffer, but not be read yet
286
+ @conn.exec( 'SELECT 1' )
287
+
288
+ @conn.wait_for_notify( 10 ).should == 'woo'
289
+ @conn.exec( 'UNLISTEN woo' )
290
+ end
291
+
292
+ context "under PostgreSQL 9" do
293
+
294
+ before( :each ) do
295
+ pending "only works under PostgreSQL 9" if @conn.server_version < 9_00_00
296
+ end
297
+
298
+ it "calls the block supplied to wait_for_notify with the notify payload if it accepts " +
299
+ "any number of arguments" do
300
+
301
+ @conn.exec( 'ROLLBACK' )
302
+ @conn.exec( 'LISTEN knees' )
303
+
304
+ pid = fork do
305
+ conn = PGconn.connect( @conninfo )
306
+ conn.exec( %Q{NOTIFY knees, 'skirt and boots'} )
307
+ conn.finish
308
+ exit!
309
+ end
310
+
311
+ Process.wait( pid )
312
+
313
+ event, pid, msg = nil
314
+ @conn.wait_for_notify( 10 ) do |*args|
315
+ event, pid, msg = *args
316
+ end
317
+ @conn.exec( 'UNLISTEN woo' )
318
+
319
+ event.should == 'knees'
320
+ pid.should be_a_kind_of( Integer )
321
+ msg.should == 'skirt and boots'
322
+ end
323
+
324
+ it "calls the block supplied to wait_for_notify with the notify payload if it accepts " +
325
+ "two arguments" do
326
+
327
+ @conn.exec( 'ROLLBACK' )
328
+ @conn.exec( 'LISTEN knees' )
329
+
330
+ pid = fork do
331
+ conn = PGconn.connect( @conninfo )
332
+ conn.exec( %Q{NOTIFY knees, 'skirt and boots'} )
333
+ conn.finish
334
+ exit!
335
+ end
336
+
337
+ Process.wait( pid )
338
+
339
+ event, pid, msg = nil
340
+ @conn.wait_for_notify( 10 ) do |arg1, arg2|
341
+ event, pid, msg = arg1, arg2
342
+ end
343
+ @conn.exec( 'UNLISTEN woo' )
344
+
345
+ event.should == 'knees'
346
+ pid.should be_a_kind_of( Integer )
347
+ msg.should be_nil()
348
+ end
349
+
350
+ it "calls the block supplied to wait_for_notify with the notify payload if it " +
351
+ "doesn't accept arguments" do
352
+
353
+ @conn.exec( 'ROLLBACK' )
354
+ @conn.exec( 'LISTEN knees' )
355
+
356
+ pid = fork do
357
+ conn = PGconn.connect( @conninfo )
358
+ conn.exec( %Q{NOTIFY knees, 'skirt and boots'} )
359
+ conn.finish
360
+ exit!
361
+ end
362
+
363
+ Process.wait( pid )
364
+
365
+ notification_received = false
366
+ @conn.wait_for_notify( 10 ) do
367
+ notification_received = true
368
+ end
369
+ @conn.exec( 'UNLISTEN woo' )
370
+
371
+ notification_received.should be_true()
372
+ end
373
+
374
+ it "calls the block supplied to wait_for_notify with the notify payload if it accepts " +
375
+ "three arguments" do
376
+
377
+ @conn.exec( 'ROLLBACK' )
378
+ @conn.exec( 'LISTEN knees' )
379
+
380
+ pid = fork do
381
+ conn = PGconn.connect( @conninfo )
382
+ conn.exec( %Q{NOTIFY knees, 'skirt and boots'} )
383
+ conn.finish
384
+ exit!
385
+ end
386
+
387
+ Process.wait( pid )
388
+
389
+ event, pid, msg = nil
390
+ @conn.wait_for_notify( 10 ) do |arg1, arg2, arg3|
391
+ event, pid, msg = arg1, arg2, arg3
392
+ end
393
+ @conn.exec( 'UNLISTEN woo' )
394
+
395
+ event.should == 'knees'
396
+ pid.should be_a_kind_of( Integer )
397
+ msg.should == 'skirt and boots'
398
+ end
399
+
400
+ end
401
+
146
402
  it "yields the result if block is given to exec" do
147
403
  rval = @conn.exec( "select 1234::int as a union select 5678::int as a" ) do |result|
148
404
  values = []
@@ -197,7 +453,7 @@ describe PGconn do
197
453
  @conn.block( 0.1 )
198
454
  finish = Time.now
199
455
 
200
- (finish - start).should be_close( 0.1, 0.05 )
456
+ (finish - start).should be_within( 0.05 ).of( 0.1 )
201
457
  end
202
458
 
203
459