pg 0.9.0-x86-mingw32 → 0.11.0pre229-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
@@ -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