pg 0.8.0 → 0.9.0.pre156

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,187 @@
1
+ #
2
+ # Rake tasklib for testing tasks
3
+
4
+ #
5
+ # Authors:
6
+ # * Michael Granger <ged@FaerieMUD.org>
7
+ #
8
+
9
+ unless defined?( COVERAGE_MINIMUM )
10
+ if ENV['COVVERAGE_MINIMUM']
11
+ COVERAGE_MINIMUM = Float( ENV['COVERAGE_MINIMUM'] )
12
+ else
13
+ COVERAGE_MINIMUM = 85.0
14
+ end
15
+ end
16
+ SPEC_FILES = [] unless defined?( SPEC_FILES )
17
+ TEST_FILES = [] unless defined?( TEST_FILES )
18
+
19
+ COMMON_SPEC_OPTS = ['-Du'] unless defined?( COMMON_SPEC_OPTS )
20
+
21
+ COVERAGE_TARGETDIR = BASEDIR + 'coverage' unless defined?( COVERAGE_TARGETDIR )
22
+ RCOV_EXCLUDES = 'spec,tests,/Library/Ruby,/var/lib,/usr/local/lib' unless
23
+ defined?( RCOV_EXCLUDES )
24
+
25
+
26
+ desc "Run all defined tests"
27
+ task :test do
28
+ unless SPEC_FILES.empty?
29
+ log "Running specs"
30
+ Rake::Task['spec:quiet'].invoke
31
+ end
32
+
33
+ unless TEST_FILES.empty?
34
+ log "Running unit tests"
35
+ Rake::Task[:unittests].invoke
36
+ end
37
+ end
38
+
39
+
40
+ ### RSpec specifications
41
+ begin
42
+ gem 'rspec', '>= 1.1.3'
43
+
44
+ require 'spec'
45
+ require 'spec/rake/spectask'
46
+
47
+ ### Task: spec
48
+ desc "Run specs"
49
+ task :spec => 'spec:doc'
50
+
51
+ namespace :spec do
52
+ desc "Run rspec every time there's a change to one of the files"
53
+ task :autotest do
54
+ require 'autotest/rspec'
55
+
56
+ autotester = Autotest::Rspec.new
57
+ autotester.run
58
+ end
59
+
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']
64
+ end
65
+
66
+ 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']
70
+ end
71
+
72
+ 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']
76
+ end
77
+
78
+ 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']
82
+ end
83
+
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
+
111
+ rescue LoadError => err
112
+ task :no_test do
113
+ $stderr.puts "Test tasks not defined: %s" % [ err.message ]
114
+ end
115
+
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
+ ### Task: coverage (via RCov)
129
+ 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
138
+ end
139
+
140
+
141
+ ### Task: rcov
142
+ task :rcov => :coverage
143
+
144
+ ### Other coverage tasks
145
+ namespace :coverage do
146
+ desc "Generate a detailed text coverage report"
147
+ Spec::Rake::SpecTask.new( :text ) do |task|
148
+ task.spec_files = SPEC_FILES
149
+ task.rcov_opts = RCOV_OPTS + ['--text-report']
150
+ task.rcov = true
151
+ end
152
+
153
+ 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']
157
+ task.rcov_opts = RCOV_OPTS - ['--save'] + ['--text-coverage-diff']
158
+ task.rcov = true
159
+ end
160
+
161
+ 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
164
+ task.rcov_opts = ['--exclude', RCOV_EXCLUDES, '--text-report', '--save']
165
+ task.rcov = true
166
+ end
167
+ end
168
+
169
+ CLOBBER.include( COVERAGE_TARGETDIR )
170
+
171
+ rescue LoadError => err
172
+ task :no_rcov do
173
+ $stderr.puts "Coverage tasks not defined: RSpec+RCov tasklib not available: %s" %
174
+ [ err.message ]
175
+ end
176
+
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
183
+ end
184
+ task :verify => :no_rcov
185
+ end
186
+
187
+
@@ -0,0 +1,64 @@
1
+ #####################################################################
2
+ ### S U B V E R S I O N T A S K S A N D H E L P E R S
3
+ #####################################################################
4
+
5
+ require 'rake/tasklib'
6
+
7
+ #
8
+ # Work around the inexplicable behaviour of the original RDoc::VerifyTask, which
9
+ # errors if your coverage isn't *exactly* the threshold.
10
+ #
11
+
12
+ # A task that can verify that the RCov coverage doesn't
13
+ # drop below a certain threshold. It should be run after
14
+ # running Spec::Rake::SpecTask.
15
+ class VerifyTask < Rake::TaskLib
16
+
17
+ COVERAGE_PERCENTAGE_PATTERN =
18
+ %r{<tt class='coverage_code'>(\d+\.\d+)%</tt>}
19
+
20
+ # Name of the task. Defaults to :verify_rcov
21
+ attr_accessor :name
22
+
23
+ # Path to the index.html file generated by RCov, which
24
+ # is the file containing the total coverage.
25
+ # Defaults to 'coverage/index.html'
26
+ attr_accessor :index_html
27
+
28
+ # Whether or not to output details. Defaults to true.
29
+ attr_accessor :verbose
30
+
31
+ # The threshold value (in percent) for coverage. If the
32
+ # actual coverage is not equal to this value, the task will raise an
33
+ # exception.
34
+ attr_accessor :threshold
35
+
36
+ def initialize( name=:verify )
37
+ @name = name
38
+ @index_html = 'coverage/index.html'
39
+ @verbose = true
40
+ yield self if block_given?
41
+ raise "Threshold must be set" if @threshold.nil?
42
+ define
43
+ end
44
+
45
+ def define
46
+ desc "Verify that rcov coverage is at least #{threshold}%"
47
+
48
+ task @name do
49
+ total_coverage = nil
50
+ if match = File.read( index_html ).match( COVERAGE_PERCENTAGE_PATTERN )
51
+ total_coverage = Float( match[1] )
52
+ else
53
+ raise "Couldn't find the coverage percentage in #{index_html}"
54
+ end
55
+
56
+ puts "Coverage: #{total_coverage}% (threshold: #{threshold}%)" if verbose
57
+ if total_coverage < threshold
58
+ raise "Coverage must be at least #{threshold}% but was #{total_coverage}%"
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ # vim: set nosta noet ts=4 sw=4:
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pathname'
4
+
5
+ module PgTestingHelpers
6
+
7
+ # Set some ANSI escape code constants (Shamelessly stolen from Perl's
8
+ # Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
9
+ ANSI_ATTRIBUTES = {
10
+ 'clear' => 0,
11
+ 'reset' => 0,
12
+ 'bold' => 1,
13
+ 'dark' => 2,
14
+ 'underline' => 4,
15
+ 'underscore' => 4,
16
+ 'blink' => 5,
17
+ 'reverse' => 7,
18
+ 'concealed' => 8,
19
+
20
+ 'black' => 30, 'on_black' => 40,
21
+ 'red' => 31, 'on_red' => 41,
22
+ 'green' => 32, 'on_green' => 42,
23
+ 'yellow' => 33, 'on_yellow' => 43,
24
+ 'blue' => 34, 'on_blue' => 44,
25
+ 'magenta' => 35, 'on_magenta' => 45,
26
+ 'cyan' => 36, 'on_cyan' => 46,
27
+ 'white' => 37, 'on_white' => 47
28
+ }
29
+
30
+
31
+ ###############
32
+ module_function
33
+ ###############
34
+
35
+ ### Create a string that contains the ANSI codes specified and return it
36
+ def ansi_code( *attributes )
37
+ attributes.flatten!
38
+ attributes.collect! {|at| at.to_s }
39
+ # $stderr.puts "Returning ansicode for TERM = %p: %p" %
40
+ # [ ENV['TERM'], attributes ]
41
+ return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
42
+ attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
43
+
44
+ # $stderr.puts " attr is: %p" % [attributes]
45
+ if attributes.empty?
46
+ return ''
47
+ else
48
+ return "\e[%sm" % attributes
49
+ end
50
+ end
51
+
52
+
53
+ ### Colorize the given +string+ with the specified +attributes+ and return it, handling
54
+ ### line-endings, color reset, etc.
55
+ def colorize( *args )
56
+ string = ''
57
+
58
+ if block_given?
59
+ string = yield
60
+ else
61
+ string = args.shift
62
+ end
63
+
64
+ ending = string[/(\s)$/] || ''
65
+ string = string.rstrip
66
+
67
+ return ansi_code( args.flatten ) + string + ansi_code( 'reset' ) + ending
68
+ end
69
+
70
+
71
+ ### Output a message with highlighting.
72
+ def message( *msg )
73
+ $stderr.puts( colorize(:bold) { msg.flatten.join(' ') } )
74
+ end
75
+
76
+
77
+ ### Output a logging message if $VERBOSE is true
78
+ def trace( *msg )
79
+ return unless $VERBOSE
80
+ output = colorize( msg.flatten.join(' '), 'yellow' )
81
+ $stderr.puts( output )
82
+ end
83
+
84
+
85
+ ### Return the specified args as a string, quoting any that have a space.
86
+ def quotelist( *args )
87
+ return args.flatten.collect {|part| part.to_s =~ /\s/ ? part.to_s.inspect : part.to_s }
88
+ end
89
+
90
+
91
+ ### Run the specified command +cmd+ with system(), failing if the execution
92
+ ### fails.
93
+ def run( *cmd )
94
+ cmd.flatten!
95
+
96
+ if cmd.length > 1
97
+ trace( quotelist(*cmd) )
98
+ else
99
+ trace( cmd )
100
+ end
101
+
102
+ system( *cmd )
103
+ raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
104
+ end
105
+
106
+
107
+ ### Run the specified command +cmd+ after redirecting stdout and stderr to the specified
108
+ ### +logpath+, failing if the execution fails.
109
+ def log_and_run( logpath, *cmd )
110
+ cmd.flatten!
111
+
112
+ if cmd.length > 1
113
+ trace( quotelist(*cmd) )
114
+ else
115
+ trace( cmd )
116
+ end
117
+
118
+ logfh = File.open( logpath, File::WRONLY|File::CREAT|File::APPEND )
119
+ if pid = fork
120
+ logfh.close
121
+ Process.wait
122
+ else
123
+ $stdout.reopen( logfh )
124
+ $stderr.reopen( $stdout )
125
+ exec( *cmd )
126
+ $stderr.puts "After the exec()?!??!"
127
+ exit!
128
+ end
129
+
130
+ raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
131
+ end
132
+
133
+
134
+ ### Check the current directory for directories that look like they're
135
+ ### testing directories from previous tests, and tell any postgres instances
136
+ ### running in them to shut down.
137
+ def stop_existing_postmasters
138
+ # tmp_test_0.22329534700318
139
+ pat = Pathname.getwd + 'tmp_test_*'
140
+ Pathname.glob( pat.to_s ).each do |testdir|
141
+ datadir = testdir + 'data'
142
+ pidfile = datadir + 'postmaster.pid'
143
+ if pidfile.exist? && pid = pidfile.read.chomp.to_i
144
+ begin
145
+ Process.kill( 0, pid )
146
+ rescue Errno::ESRCH
147
+ trace "No postmaster running for %s" % [ datadir ]
148
+ # Process isn't alive, so don't try to stop it
149
+ else
150
+ trace "Stopping lingering database at PID %d"
151
+ run 'pg_ctl', '-D', datadir.to_s, '-m', 'fast', 'stop'
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+
158
+ ### Set up a PostgreSQL database instance for testing.
159
+ def setup_testing_db( description )
160
+ require 'pg'
161
+ stop_existing_postmasters()
162
+
163
+ puts "Setting up test database for #{description} tests"
164
+ @test_directory = Pathname.getwd + "tmp_test_specs"
165
+ @test_pgdata = @test_directory + 'data'
166
+ @test_pgdata.mkpath
167
+
168
+ @port = 54321
169
+ ENV['PGPORT'] = @port.to_s
170
+ ENV['PGHOST'] = 'localhost'
171
+ @conninfo = "host=localhost port=#{@port} dbname=test"
172
+
173
+ @logfile = @test_directory + 'setup.log'
174
+ trace "Command output logged to #{@logfile}"
175
+
176
+ begin
177
+ unless (@test_pgdata+"postgresql.conf").exist?
178
+ FileUtils.rm_rf( @test_pgdata, :verbose => $DEBUG )
179
+ trace "Running initdb"
180
+ log_and_run @logfile, 'initdb', '--no-locale', '-D', @test_pgdata.to_s
181
+ end
182
+
183
+ trace "Starting postgres"
184
+ log_and_run @logfile, 'pg_ctl', '-w', '-o', "-k #{@test_directory.to_s.inspect}",
185
+ '-D', @test_pgdata.to_s, 'start'
186
+
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
+ rescue => err
194
+ $stderr.puts "%p during test setup: %s" % [ err.class, err.message ]
195
+ $stderr.puts "See #{@logfile} for details."
196
+ $stderr.puts *err.backtrace if $DEBUG
197
+ fail
198
+ end
199
+
200
+ conn = PGconn.connect( @conninfo )
201
+ conn.set_notice_processor do |message|
202
+ $stderr.puts( message ) if $DEBUG
203
+ end
204
+
205
+ return conn
206
+ end
207
+
208
+
209
+ def teardown_testing_db( conn )
210
+ puts "Tearing down test database"
211
+ conn.finish if conn
212
+ log_and_run @logfile, 'pg_ctl', '-D', @test_pgdata.to_s, 'stop'
213
+ end
214
+ end
215
+
216
+