pg-ct 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
data/rake/testing.rb ADDED
@@ -0,0 +1,151 @@
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_RSPEC_OPTS = [] unless defined?( COMMON_RSPEC_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', '>= 2.0.0'
43
+
44
+ require 'rspec'
45
+ require 'rspec/core/rake_task'
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'
55
+ Autotest.add_discovery { "rspec2" }
56
+ Autotest.run
57
+ end
58
+
59
+ desc "Generate regular color 'doc' spec output"
60
+ RSpec::Core::RakeTask.new( :doc ) do |task|
61
+ task.rspec_opts = COMMON_RSPEC_OPTS + ['-f', 'd', '-c']
62
+ end
63
+
64
+ desc "Generate spec output with profiling"
65
+ RSpec::Core::RakeTask.new( :profile ) do |task|
66
+ task.rspec_opts = COMMON_RSPEC_OPTS + ['-f', 'p', '-p']
67
+ end
68
+
69
+ desc "Generate quiet non-colored plain-text output"
70
+ RSpec::Core::RakeTask.new( :quiet ) do |task|
71
+ task.rspec_opts = COMMON_RSPEC_OPTS + ['-f', 'p']
72
+ end
73
+
74
+ desc "Generate HTML output"
75
+ RSpec::Core::RakeTask.new( :html ) do |task|
76
+ task.rspec_opts = COMMON_RSPEC_OPTS + ['-f', 'h']
77
+ end
78
+
79
+
80
+ end
81
+
82
+ ### Task: coverage (via RCov)
83
+ desc "Build test coverage reports"
84
+ RSpec::Core::RakeTask.new( :coverage ) do |task|
85
+ task.ruby_opts = [ "-I#{LIBDIR}" ]
86
+ task.rspec_opts = ['-f', 'p', '-b']
87
+ task.rcov_opts = RCOV_OPTS
88
+ task.rcov = true
89
+ end
90
+
91
+ ### Task: rcov
92
+ task :rcov => :coverage
93
+
94
+ ### Other coverage tasks
95
+ namespace :coverage do
96
+ desc "Generate a detailed text coverage report"
97
+ RSpec::Core::RakeTask.new( :text ) do |task|
98
+ task.rcov_opts = RCOV_OPTS + ['--text-report']
99
+ task.rcov = true
100
+ end
101
+
102
+ desc "Show differences in coverage from last run"
103
+ RSpec::Core::RakeTask.new( :diff ) do |task|
104
+ task.rspec_opts = ['-f', 'p', '-b']
105
+ task.rcov_opts = RCOV_OPTS - ['--save'] + ['--text-coverage-diff']
106
+ task.rcov = true
107
+ end
108
+
109
+ desc "Run RCov in 'spec-only' mode to check coverage from specs"
110
+ RSpec::Core::RakeTask.new( :speconly ) do |task|
111
+ task.rcov_opts = ['--exclude', RCOV_EXCLUDES, '--text-report', '--save']
112
+ task.rcov = true
113
+ end
114
+ end
115
+
116
+ CLOBBER.include( COVERAGE_TARGETDIR )
117
+ rescue LoadError => err
118
+ task :no_rspec do
119
+ $stderr.puts "Specification tasks not defined: %s" % [ err.message ]
120
+ end
121
+
122
+ task :spec => :no_rspec
123
+ namespace :spec do
124
+ task :autotest => :no_rspec
125
+ task :doc => :no_rspec
126
+ task :profile => :no_rspec
127
+ task :quiet => :no_rspec
128
+ task :html => :no_rspec
129
+ end
130
+ end
131
+
132
+
133
+ ### Test::Unit tests
134
+ begin
135
+ require 'rake/testtask'
136
+
137
+ Rake::TestTask.new( :unittests ) do |task|
138
+ task.libs += [LIBDIR]
139
+ task.test_files = TEST_FILES
140
+ task.verbose = true
141
+ end
142
+
143
+ rescue LoadError => err
144
+ task :no_test do
145
+ $stderr.puts "Test tasks not defined: %s" % [ err.message ]
146
+ end
147
+
148
+ task :unittests => :no_rspec
149
+ end
150
+
151
+
@@ -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,26 @@
1
+ To backend> Msg Q
2
+ To backend> "SELECT 1 AS one"
3
+ To backend> Msg complete, length 21
4
+ From backend> T
5
+ From backend (#4)> 28
6
+ From backend (#2)> 1
7
+ From backend> "one"
8
+ From backend (#4)> 0
9
+ From backend (#2)> 0
10
+ From backend (#4)> 23
11
+ From backend (#2)> 4
12
+ From backend (#4)> -1
13
+ From backend (#2)> 0
14
+ From backend> D
15
+ From backend (#4)> 11
16
+ From backend (#2)> 1
17
+ From backend (#4)> 1
18
+ From backend (1)> 1
19
+ From backend> C
20
+ From backend (#4)> 11
21
+ From backend> "SELECT"
22
+ From backend> Z
23
+ From backend (#4)> 5
24
+ From backend> Z
25
+ From backend (#4)> 5
26
+ From backend> T
Binary file
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env ruby
2
+
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
13
+
14
+ module PgTestingHelpers
15
+
16
+
17
+ # Set some ANSI escape code constants (Shamelessly stolen from Perl's
18
+ # Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
19
+ ANSI_ATTRIBUTES = {
20
+ 'clear' => 0,
21
+ 'reset' => 0,
22
+ 'bold' => 1,
23
+ 'dark' => 2,
24
+ 'underline' => 4,
25
+ 'underscore' => 4,
26
+ 'blink' => 5,
27
+ 'reverse' => 7,
28
+ 'concealed' => 8,
29
+
30
+ 'black' => 30, 'on_black' => 40,
31
+ 'red' => 31, 'on_red' => 41,
32
+ 'green' => 32, 'on_green' => 42,
33
+ 'yellow' => 33, 'on_yellow' => 43,
34
+ 'blue' => 34, 'on_blue' => 44,
35
+ 'magenta' => 35, 'on_magenta' => 45,
36
+ 'cyan' => 36, 'on_cyan' => 46,
37
+ 'white' => 37, 'on_white' => 47
38
+ }
39
+
40
+
41
+ ###############
42
+ module_function
43
+ ###############
44
+
45
+ ### Create a string that contains the ANSI codes specified and return it
46
+ def ansi_code( *attributes )
47
+ attributes.flatten!
48
+ attributes.collect! {|at| at.to_s }
49
+ # $stderr.puts "Returning ansicode for TERM = %p: %p" %
50
+ # [ ENV['TERM'], attributes ]
51
+ return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
52
+ attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
53
+
54
+ # $stderr.puts " attr is: %p" % [attributes]
55
+ if attributes.empty?
56
+ return ''
57
+ else
58
+ return "\e[%sm" % attributes
59
+ end
60
+ end
61
+
62
+
63
+ ### Colorize the given +string+ with the specified +attributes+ and return it, handling
64
+ ### line-endings, color reset, etc.
65
+ def colorize( *args )
66
+ string = ''
67
+
68
+ if block_given?
69
+ string = yield
70
+ else
71
+ string = args.shift
72
+ end
73
+
74
+ ending = string[/(\s)$/] || ''
75
+ string = string.rstrip
76
+
77
+ return ansi_code( args.flatten ) + string + ansi_code( 'reset' ) + ending
78
+ end
79
+
80
+
81
+ ### Output a message with highlighting.
82
+ def message( *msg )
83
+ $stderr.puts( colorize(:bold) { msg.flatten.join(' ') } )
84
+ end
85
+
86
+
87
+ ### Output a logging message if $VERBOSE is true
88
+ def trace( *msg )
89
+ return unless $VERBOSE
90
+ output = colorize( msg.flatten.join(' '), 'yellow' )
91
+ $stderr.puts( output )
92
+ end
93
+
94
+
95
+ ### Return the specified args as a string, quoting any that have a space.
96
+ def quotelist( *args )
97
+ return args.flatten.collect {|part| part.to_s =~ /\s/ ? part.to_s.inspect : part.to_s }
98
+ end
99
+
100
+
101
+ ### Run the specified command +cmd+ with system(), failing if the execution
102
+ ### fails.
103
+ def run( *cmd )
104
+ cmd.flatten!
105
+
106
+ if cmd.length > 1
107
+ trace( quotelist(*cmd) )
108
+ else
109
+ trace( cmd )
110
+ end
111
+
112
+ system( *cmd )
113
+ raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
114
+ end
115
+
116
+
117
+ NOFORK_PLATFORMS = %w{java}
118
+
119
+ ### Run the specified command +cmd+ after redirecting stdout and stderr to the specified
120
+ ### +logpath+, failing if the execution fails.
121
+ def log_and_run( logpath, *cmd )
122
+ cmd.flatten!
123
+
124
+ if cmd.length > 1
125
+ trace( quotelist(*cmd) )
126
+ else
127
+ trace( cmd )
128
+ end
129
+
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 )
135
+ else
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 )
148
+ end
149
+
150
+ raise "Command failed: [%s]" % [cmd.join(' ')] unless $?.success?
151
+ end
152
+
153
+
154
+ ### Check the current directory for directories that look like they're
155
+ ### testing directories from previous tests, and tell any postgres instances
156
+ ### running in them to shut down.
157
+ def stop_existing_postmasters
158
+ # tmp_test_0.22329534700318
159
+ pat = Pathname.getwd + 'tmp_test_*'
160
+ Pathname.glob( pat.to_s ).each do |testdir|
161
+ datadir = testdir + 'data'
162
+ pidfile = datadir + 'postmaster.pid'
163
+ if pidfile.exist? && pid = pidfile.read.chomp.to_i
164
+ begin
165
+ Process.kill( 0, pid )
166
+ rescue Errno::ESRCH
167
+ trace "No postmaster running for %s" % [ datadir ]
168
+ # Process isn't alive, so don't try to stop it
169
+ else
170
+ trace "Stopping lingering database at PID %d" % [ pid ]
171
+ run 'pg_ctl', '-D', datadir.to_s, '-m', 'fast', 'stop'
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+
178
+ ### Set up a PostgreSQL database instance for testing.
179
+ def setup_testing_db( description )
180
+ require 'pg'
181
+ stop_existing_postmasters()
182
+
183
+ puts "Setting up test database for #{description} tests"
184
+ @test_directory = Pathname.getwd + "tmp_test_specs"
185
+ @test_pgdata = @test_directory + 'data'
186
+ @test_pgdata.mkpath
187
+
188
+ @port = 54321
189
+ ENV['PGPORT'] = @port.to_s
190
+ ENV['PGHOST'] = 'localhost'
191
+ @conninfo = "host=localhost port=#{@port} dbname=test"
192
+
193
+ @logfile = @test_directory + 'setup.log'
194
+ trace "Command output logged to #{@logfile}"
195
+
196
+ begin
197
+ unless (@test_pgdata+"postgresql.conf").exist?
198
+ FileUtils.rm_rf( @test_pgdata, :verbose => $DEBUG )
199
+ trace "Running initdb"
200
+ log_and_run @logfile, 'initdb', '--no-locale', '-D', @test_pgdata.to_s
201
+ end
202
+
203
+ trace "Starting postgres"
204
+ log_and_run @logfile, 'pg_ctl', '-w', '-o', "-k #{@test_directory.to_s.inspect}",
205
+ '-D', @test_pgdata.to_s, 'start'
206
+
207
+ if `psql -l` =~ /^\s*test\s/
208
+ trace "Dropping the test DB"
209
+ log_and_run @logfile, 'dropdb', 'test'
210
+ end
211
+ trace "Creating the test DB"
212
+ log_and_run @logfile, 'createdb', 'test'
213
+ rescue => err
214
+ $stderr.puts "%p during test setup: %s" % [ err.class, err.message ]
215
+ $stderr.puts "See #{@logfile} for details."
216
+ $stderr.puts *err.backtrace if $DEBUG
217
+ fail
218
+ end
219
+
220
+ conn = PGconn.connect( @conninfo )
221
+ conn.set_notice_processor do |message|
222
+ $stderr.puts( message ) if $DEBUG
223
+ end
224
+
225
+ return conn
226
+ end
227
+
228
+
229
+ def teardown_testing_db( conn )
230
+ puts "Tearing down test database"
231
+ conn.finish if conn
232
+ log_and_run @logfile, 'pg_ctl', '-D', @test_pgdata.to_s, 'stop'
233
+ end
234
+ end
235
+
236
+