Preparation for parallel cmdtest:
- 'runner' parameter to methods instead of constructors - unique work-directory for each test method - detect class/method name clashes early - moved tmp-dir knowledge to "testcase.rb"
This commit is contained in:
parent
27f1f3f80f
commit
892dc530c5
123
bin/cmdtest.rb
123
bin/cmdtest.rb
@ -49,41 +49,51 @@ module Cmdtest
|
||||
|
||||
class TestMethod
|
||||
|
||||
def initialize(test_method, test_class, runner)
|
||||
@test_method, @test_class, @runner = test_method, test_class, runner
|
||||
def initialize(test_method, test_class)
|
||||
@test_method, @test_class = test_method, test_class
|
||||
end
|
||||
|
||||
def to_s
|
||||
class_name = @test_class.testcase_class.name.sub(/^.*::/, "")
|
||||
"<<TestMethod: #{class_name}.#{@test_method}>>"
|
||||
end
|
||||
|
||||
def as_filename
|
||||
klass_name = @test_class.as_filename
|
||||
"#{klass_name}.#{@test_method}"
|
||||
end
|
||||
|
||||
def method_id
|
||||
[@test_class.file, @test_class.testcase_class, @test_method]
|
||||
end
|
||||
|
||||
def skip?
|
||||
patterns = @runner.opts.patterns
|
||||
def skip?(runner)
|
||||
patterns = runner.opts.patterns
|
||||
selected = (patterns.size == 0 ||
|
||||
patterns.any? {|pattern| pattern =~ @test_method } )
|
||||
|
||||
!selected || @runner.method_filter.skip?(*method_id)
|
||||
!selected || runner.method_filter.skip?(*method_id)
|
||||
end
|
||||
|
||||
def run
|
||||
@runner.notify("testmethod", @test_method) do
|
||||
obj = @test_class.testcase_class.new(self, @runner)
|
||||
def run(runner)
|
||||
runner.notify("testmethod", @test_method) do
|
||||
obj = @test_class.testcase_class.new(self, runner)
|
||||
obj._work_dir.chdir do
|
||||
obj.setup
|
||||
begin
|
||||
obj.send(@test_method)
|
||||
@runner.assert_success
|
||||
runner.assert_success
|
||||
rescue Cmdtest::AssertFailed => e
|
||||
@runner.assert_failure(e.message)
|
||||
@runner.method_filter.error(*method_id)
|
||||
runner.assert_failure(e.message)
|
||||
runner.method_filter.error(*method_id)
|
||||
rescue => e
|
||||
io = StringIO.new
|
||||
io.puts "CAUGHT EXCEPTION:"
|
||||
io.puts " " + e.message + " (#{e.class})"
|
||||
io.puts "BACKTRACE:"
|
||||
io.puts e.backtrace.map {|line| " " + line }
|
||||
@runner.assert_error(io.string)
|
||||
@runner.method_filter.error(*method_id)
|
||||
runner.assert_error(io.string)
|
||||
runner.method_filter.error(*method_id)
|
||||
end
|
||||
obj.teardown
|
||||
end
|
||||
@ -98,22 +108,26 @@ module Cmdtest
|
||||
|
||||
attr_reader :testcase_class, :file
|
||||
|
||||
def initialize(testcase_class, file, runner)
|
||||
@testcase_class, @file, @runner = testcase_class, file, runner
|
||||
def initialize(testcase_class, file)
|
||||
@testcase_class, @file = testcase_class, file
|
||||
end
|
||||
|
||||
def run
|
||||
@runner.notify("testclass", @testcase_class) do
|
||||
get_test_methods.each do |method|
|
||||
test_method = TestMethod.new(method, self, @runner)
|
||||
test_method.run unless test_method.skip?
|
||||
def as_filename
|
||||
@testcase_class.name.sub(/^.*::/, "")
|
||||
end
|
||||
|
||||
def run(runner)
|
||||
runner.notify("testclass", @testcase_class) do
|
||||
get_test_methods(runner).each do |method|
|
||||
test_method = TestMethod.new(method, self)
|
||||
test_method.run(runner) unless test_method.skip?(runner)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_test_methods
|
||||
def get_test_methods(runner)
|
||||
@testcase_class.public_instance_methods(false).sort.select do |method|
|
||||
in_list = @runner.opts.tests.empty? || @runner.opts.tests.include?(method)
|
||||
in_list = runner.opts.tests.empty? || runner.opts.tests.include?(method)
|
||||
method =~ /^test_/ && in_list
|
||||
end
|
||||
end
|
||||
@ -126,20 +140,22 @@ module Cmdtest
|
||||
|
||||
attr_reader :path
|
||||
|
||||
attr_reader :test_classes
|
||||
|
||||
def initialize(path)
|
||||
@path = path
|
||||
@test_classes = Cmdtest::Testcase.new_subclasses do
|
||||
Kernel.load(@path, true)
|
||||
end.map do |testcase_class|
|
||||
TestClass.new(testcase_class, self)
|
||||
end
|
||||
end
|
||||
|
||||
def run(runner)
|
||||
@runner = runner
|
||||
@runner.notify("testfile", @path) do
|
||||
testcase_classes = Cmdtest::Testcase.new_subclasses do
|
||||
Kernel.load(@path, true)
|
||||
end
|
||||
for testcase_class in testcase_classes
|
||||
test_class = TestClass.new(testcase_class, self, @runner)
|
||||
if ! test_class.get_test_methods.empty?
|
||||
test_class.run
|
||||
runner.notify("testfile", @path) do
|
||||
for test_class in @test_classes
|
||||
if ! test_class.get_test_methods(runner).empty?
|
||||
test_class.run(runner)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -198,11 +214,30 @@ module Cmdtest
|
||||
# find local files "required" by testcase files
|
||||
$LOAD_PATH.unshift(@project_dir.test_files_dir)
|
||||
|
||||
# force loading of all test files
|
||||
test_files = @project_dir.test_filenames.map {|x| TestFile.new(x) }
|
||||
|
||||
# make sure class names are unique
|
||||
used_test_class_filenames = {}
|
||||
for test_file in test_files
|
||||
for test_class in test_file.test_classes
|
||||
filename = test_class.as_filename
|
||||
prev_test_file = used_test_class_filenames[filename]
|
||||
if prev_test_file
|
||||
puts "ERROR: same class name used twice: #{filename}"
|
||||
puts "ERROR: prev file: #{prev_test_file.path}"
|
||||
puts "ERROR: curr file: #{test_file.path}"
|
||||
exit(1)
|
||||
end
|
||||
used_test_class_filenames[filename] = test_file
|
||||
end
|
||||
end
|
||||
|
||||
@n_assert_failures = 0
|
||||
@n_assert_errors = 0
|
||||
@n_assert_successes = 0
|
||||
notify("testsuite") do
|
||||
for test_file in @project_dir.test_files
|
||||
for test_file in test_files
|
||||
test_file.run(self)
|
||||
end
|
||||
end
|
||||
@ -234,20 +269,20 @@ module Cmdtest
|
||||
|
||||
def initialize(argv)
|
||||
@argv = argv
|
||||
@test_files = nil
|
||||
@test_filenames = nil
|
||||
end
|
||||
|
||||
def test_files
|
||||
@test_files ||= _fs_test_files
|
||||
def test_filenames
|
||||
@test_filenames ||= _fs_test_filenames
|
||||
end
|
||||
|
||||
def test_files_dir
|
||||
File.dirname(test_files[0].path)
|
||||
File.dirname(test_filenames[0])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _fs_test_files
|
||||
def _fs_test_filenames
|
||||
if ! @argv.empty?
|
||||
files = _expand_files_or_dirs(@argv)
|
||||
if files.empty?
|
||||
@ -258,28 +293,24 @@ module Cmdtest
|
||||
end
|
||||
|
||||
try = Dir.glob("t/CMDTEST_*.rb")
|
||||
return _test_files(try) if ! try.empty?
|
||||
return try if ! try.empty?
|
||||
|
||||
try = Dir.glob("test/CMDTEST_*.rb")
|
||||
return _test_files(try) if ! try.empty?
|
||||
return try if ! try.empty?
|
||||
|
||||
try = Dir.glob("CMDTEST_*.rb")
|
||||
return _test_files(try) if ! try.empty?
|
||||
return try if ! try.empty?
|
||||
|
||||
puts "ERROR: no CMDTEST_*.rb files found"
|
||||
exit 1
|
||||
end
|
||||
|
||||
def _test_files(files)
|
||||
files.map {|file| TestFile.new(file) }
|
||||
end
|
||||
|
||||
def _expand_files_or_dirs(argv)
|
||||
files = []
|
||||
for arg in @argv
|
||||
if File.file?(arg)
|
||||
if File.basename(arg) =~ /^.*\.rb$/
|
||||
files << TestFile.new(arg)
|
||||
files << arg
|
||||
else
|
||||
puts "ERROR: illegal file: #{arg}"
|
||||
exit(1)
|
||||
@ -289,7 +320,7 @@ module Cmdtest
|
||||
path = File.join(arg,entry)
|
||||
next unless File.file?(path)
|
||||
next unless entry =~ /^CMDTEST_.*\.rb$/
|
||||
files << TestFile.new(path)
|
||||
files << path
|
||||
end
|
||||
else
|
||||
puts "ERROR: unknown file: #{arg}"
|
||||
|
@ -60,18 +60,34 @@ module Cmdtest
|
||||
|
||||
#------------------------------
|
||||
|
||||
ORIG_CWD = Dir.pwd
|
||||
|
||||
attr_reader :_work_dir
|
||||
|
||||
def initialize(test_method, runner)
|
||||
@_test_method = test_method
|
||||
@_runner = runner
|
||||
@_work_dir = Workdir.new(runner)
|
||||
@_work_dir = Workdir.new(self, runner)
|
||||
@_in_cmd = false
|
||||
@_comment_str = nil
|
||||
@_env_path = @_runner.orig_env_path
|
||||
@_t1 = @_t2 = 0
|
||||
end
|
||||
|
||||
#------------------------------
|
||||
|
||||
def tmp_cmdtest_dir
|
||||
File.join(ORIG_CWD, "tmp-cmdtest-%d" % [$cmdtest_level])
|
||||
end
|
||||
|
||||
def tmp_dir
|
||||
File.join(tmp_cmdtest_dir, @_test_method.as_filename)
|
||||
end
|
||||
|
||||
def tmp_work_dir
|
||||
File.join(tmp_dir, "work")
|
||||
end
|
||||
|
||||
#------------------------------
|
||||
# Import file into the "workdir" from the outside world.
|
||||
# The source is found relative to the current directory when "cmdtest"
|
||||
@ -79,7 +95,7 @@ module Cmdtest
|
||||
# the current directory at the time of the call.
|
||||
|
||||
def import_file(src, tgt)
|
||||
src_path = File.expand_path(src, Workdir::ORIG_CWD)
|
||||
src_path = File.expand_path(src, ORIG_CWD)
|
||||
tgt_path = tgt # rely on CWD
|
||||
FileUtils.mkdir_p(File.dirname(tgt_path))
|
||||
FileUtils.cp(src_path, tgt_path)
|
||||
@ -93,7 +109,7 @@ module Cmdtest
|
||||
# time of the call.
|
||||
|
||||
def create_file(filename, lines)
|
||||
#Util.wait_for_new_second
|
||||
#_wait_for_new_second
|
||||
FileUtils.mkdir_p( File.dirname(filename) )
|
||||
File.open(filename, "w") do |f|
|
||||
case lines
|
||||
@ -111,7 +127,7 @@ module Cmdtest
|
||||
# time of the call.
|
||||
|
||||
def touch_file(filename)
|
||||
#Util.wait_for_new_second
|
||||
#_wait_for_new_second
|
||||
FileUtils.touch(filename)
|
||||
end
|
||||
|
||||
@ -571,11 +587,17 @@ module Cmdtest
|
||||
|
||||
#------------------------------
|
||||
|
||||
def _wait_for_new_second
|
||||
Util.wait_for_new_second(tmp_dir, tmp_work_dir)
|
||||
end
|
||||
|
||||
#------------------------------
|
||||
|
||||
def cmd(cmdline)
|
||||
if Array === cmdline
|
||||
cmdline = _args_to_quoted_string(cmdline)
|
||||
end
|
||||
Util.wait_for_new_second
|
||||
_wait_for_new_second
|
||||
_update_hardlinks
|
||||
@_cmdline = cmdline
|
||||
@_cmd_done = false
|
||||
|
@ -30,22 +30,22 @@ module Cmdtest
|
||||
@@opts = opts
|
||||
end
|
||||
|
||||
def self._timestamp_file
|
||||
File.join(Workdir.tmp_cmdtest_dir, "TIMESTAMP")
|
||||
def self._timestamp_file(tmp_dir)
|
||||
File.join(tmp_dir, "TIMESTAMP")
|
||||
end
|
||||
|
||||
def self.wait_for_new_second
|
||||
def self.wait_for_new_second(tmp_dir, tmp_work_dir)
|
||||
return if ! TRUST_MTIME || @@opts.fast
|
||||
loop do
|
||||
File.open(_timestamp_file, "w") {|f| f.puts Time.now }
|
||||
break if File.mtime(_timestamp_file) != _newest_file_time
|
||||
File.open(_timestamp_file(tmp_dir), "w") {|f| f.puts Time.now }
|
||||
break if File.mtime(_timestamp_file(tmp_dir)) != _newest_file_time(tmp_work_dir)
|
||||
sleep 0.2
|
||||
end
|
||||
end
|
||||
|
||||
def self._newest_file_time
|
||||
def self._newest_file_time(tmp_work_dir)
|
||||
tnew = Time.at(0)
|
||||
Find.find(Workdir.tmp_work_dir) do |path|
|
||||
Find.find(tmp_work_dir) do |path|
|
||||
next if ! File.file?(path)
|
||||
t = File.mtime(path)
|
||||
tnew = t > tnew ? t : tnew
|
||||
|
@ -27,20 +27,11 @@ require "fileutils"
|
||||
module Cmdtest
|
||||
class Workdir
|
||||
|
||||
ORIG_CWD = Dir.pwd
|
||||
|
||||
def self.tmp_cmdtest_dir
|
||||
File.join(ORIG_CWD, "tmp-cmdtest-%d" % [$cmdtest_level])
|
||||
end
|
||||
|
||||
def self.tmp_work_dir
|
||||
File.join(tmp_cmdtest_dir, "workdir")
|
||||
end
|
||||
|
||||
def initialize(runner)
|
||||
def initialize(testcase, runner)
|
||||
@testcase = testcase
|
||||
@runner = runner
|
||||
@dir = Workdir.tmp_work_dir
|
||||
hardlinkdir = File.join(Workdir.tmp_cmdtest_dir, "hardlinks")
|
||||
@dir = @testcase.tmp_work_dir
|
||||
hardlinkdir = File.join(testcase.tmp_dir, "hardlinks")
|
||||
FileUtils.rm_rf(@dir)
|
||||
FileUtils.rm_rf(hardlinkdir)
|
||||
FileUtils.mkdir_p(@dir)
|
||||
@ -78,16 +69,16 @@ module Cmdtest
|
||||
end
|
||||
|
||||
def _tmp_command_sh
|
||||
File.join(Workdir.tmp_cmdtest_dir,
|
||||
File.join(@testcase.tmp_dir,
|
||||
_windows ? "tmp-command.bat" : "tmp-command.sh")
|
||||
end
|
||||
|
||||
def _tmp_stdout_log
|
||||
File.join(Workdir.tmp_cmdtest_dir, "tmp-stdout.log")
|
||||
File.join(@testcase.tmp_dir, "tmp-stdout.log")
|
||||
end
|
||||
|
||||
def _tmp_stderr_log
|
||||
File.join(Workdir.tmp_cmdtest_dir, "tmp-stderr.log")
|
||||
File.join(@testcase.tmp_dir, "tmp-stderr.log")
|
||||
end
|
||||
|
||||
def _set_env_path_str(env_path)
|
||||
|
Loading…
x
Reference in New Issue
Block a user