mkvtoolnix/tests/run.rb

404 lines
10 KiB
Ruby
Raw Normal View History

#!/usr/bin/env ruby1.9
2010-06-18 07:10:05 +00:00
$message_mutex = Mutex.new
def show_message(message)
$message_mutex.lock
puts message
$message_mutex.unlock
end
def error_and_exit(text, exit_code = 2)
puts text
exit exit_code
end
class TestController
attr_accessor :test_failed, :test_new, :test_date_after, :teset_date_before, :update_failed, :num_failed
attr_reader :num_threads
def initialize
@results = Results.new
@test_failed = false
@test_new = false
@test_date_after = nil
@test_date_before = nil
@update_failed = false
@num_threads = self.get_num_processors
@tests = Array.new
@dir_entries = Dir.entries(".")
end
def get_num_processors
IO.readlines("/proc/cpuinfo").collect { |line| /^processor\s+:\s+(\d+)/.match(line) ? $1.to_i : 0 }.max + 1
end
def num_threads=(num)
error_and_exit "Invalid number of threads: must be > 0" if 0 >= num
@num_threads = num
end
def add_test_case(num)
@tests += @dir_entries.select { |entry| /^test-#{num}/.match(entry) }
end
def get_tests_to_run
test_all = !@test_failed && !@test_new
return (@tests.empty? ? @dir_entries : @tests).collect do |entry|
if (FileTest.file?(entry) && (entry =~ /^test-.*\.rb$/))
class_name = self.class.file_name_to_class_name entry
test_this = test_all
test_this ||= (@results.exist?(class_name) && ((@test_failed && (@results.status?(class_name) == "failed")) || (@test_new && (@results.status?(class_name) == "new"))) ||
(@test_date_after && (@results.date_added?(class_name) < @test_date_after)) ||
(@test_date_before && (@results.date_added?(class_name) > @test_date_before)))
test_this ||= !@results.exist?(class_name) && (@test_new || @test_failed)
test_this ? class_name : nil
else
nil
end
end.compact.sort
end
def self.file_name_to_class_name(file_name)
"T_" + file_name.gsub(/^test-/, "").gsub(/\.rb$/, "")
end
def self.class_name_to_file_name(class_name)
class_name.gsub(/^T_/, "test-") + ".rb"
end
def go
@num_failed = 0
@tests_to_run = self.get_tests_to_run
num_tests = @tests_to_run.size
@tests_mutex = Mutex.new
@results_mutex = Mutex.new
start = Time.now
self.run_threads
self.join_threads
duration = Time.now - start
2010-06-18 07:10:05 +00:00
show_message "#{@num_failed}/#{num_tests} failed (" + (num_tests > 0 ? (@num_failed * 100 / num_tests).to_s : "0") + "%). " + "Tests took #{duration}s."
end
def run_threads
@threads = Array.new
(1..@num_threads).each do |number|
@threads << Thread.new(number) do |thread_number|
Thread.current[:number] = thread_number
# puts "tnum is #{thread_number} and #{Thread.current.object_id}"
while true
@tests_mutex.lock
class_name = @tests_to_run.shift
@tests_mutex.unlock
break unless class_name
self.run_test class_name
end
end
end
end
def join_threads
@threads.each &:join
end
def run_test(class_name)
file_name = self.class.class_name_to_file_name class_name
if (!require("./#{file_name}"))
self.add_result class_name, "failed", " Failed to load '#{file_name}'."
return
end
begin
current_test = eval "#{class_name}.new"
rescue
self.add_result class_name, "failed", " Failed to create an instance of class '#{class_name}'."
return
end
if (current_test.description == "INSERT DESCRIPTION")
2010-06-18 07:10:05 +00:00
show_message "Skipping '#{class_name}': Not implemented yet"
return
end
2010-06-18 07:10:05 +00:00
show_message "Running '#{class_name}': #{current_test.description}"
result = current_test.run_test
if (result)
if (!@results.exist? class_name)
self.add_result class_name, "passed", " NEW test. Storing result '#{result}'.", result
elsif (@results.hash?(class_name) != result)
msg = " FAILED: checksum is different. Commands:\n" +
" " + current_test.commands.join("\n ") + "\n"
# msg += "ACTUAL: #{result}\n"
# msg += "CHECK: #{@results.hash?(class_name)}\n"
if (update_failed)
self.add_result class_name, "passed", msg + " UPDATING result\n", result
else
self.add_result class_name, "failed", msg
end
else
self.add_result class_name, "passed"
end
else
self.add_result class_name, "failed", " FAILED: no result from test"
end
end
def add_result(class_name, result, message = nil, new_checksum = nil)
@results_mutex.lock
show_message message if message
@num_failed += 1 if result == "failed"
if !@results.exist? class_name
@results.add class_name, new_checksum
else
@results.set class_name, result
@results.set_hash class_name, new_checksum if new_checksum
end
@results_mutex.unlock
end
end
class SubtestError < RuntimeError
end
class Test
2004-08-25 17:23:07 +00:00
attr_reader :commands
2004-09-29 09:35:27 +00:00
attr_reader :debug_commands
def initialize
@tmp_num = 0
@tmp_num_mutex = Mutex.new
@commands = Array.new
2004-09-29 09:35:27 +00:00
@debug_commands = Array.new
2004-08-25 17:23:07 +00:00
end
def description
return "dummy test class"
end
def run
return error("Trying to run the base class")
end
def unlink_tmp_files
2009-02-28 18:17:17 +00:00
return if (ENV["KEEP_TMPFILES"] == "1")
2010-06-19 10:38:55 +00:00
re = /^#{self.tmp_name_prefix}/
Dir.entries("/tmp").each do |entry|
file = "/tmp/#{entry}"
File.unlink(file) if re.match(file) and File.exists?(file)
end
end
def run_test
2010-06-19 10:38:55 +00:00
result = nil
begin
2010-06-19 10:38:55 +00:00
result = run
2004-08-28 14:14:38 +00:00
rescue RuntimeError => ex
2010-06-18 07:10:05 +00:00
show_message ex.to_s
end
2010-06-19 10:38:55 +00:00
unlink_tmp_files
result
end
def error(reason)
2010-06-18 07:10:05 +00:00
show_message " Failed. Reason: #{reason}"
raise "test failed"
end
def sys(command, *arg)
2004-08-25 17:23:07 +00:00
@commands.push(command)
2004-09-29 09:35:27 +00:00
@debug_commands.push(command)
2007-07-04 14:30:33 +00:00
command += " >/dev/null 2>/dev/null " unless (/>/.match(command))
2004-09-20 17:25:37 +00:00
if (!system(command))
if ((arg.size == 0) || ((arg[0] << 8) != $?))
error("system command failed: #{command} (" + ($? >> 8).to_s + ")")
end
end
end
def tmp_name_prefix
2010-06-19 10:38:55 +00:00
["/tmp/mkvtoolnix-auto-test", $$.to_s, Thread.current[:number]].join("-") + "-"
end
2004-08-19 19:37:07 +00:00
def tmp_name
@tmp_num_mutex.lock
2004-08-19 19:37:07 +00:00
@tmp_num ||= 0
@tmp_num += 1
result = self.tmp_name_prefix + @tmp_num.to_s
@tmp_num_mutex.unlock
result
2004-08-19 19:37:07 +00:00
end
def tmp
2004-08-19 19:37:07 +00:00
@tmp ||= tmp_name
end
def hash_file(name)
2004-09-29 09:35:27 +00:00
@debug_commands.push("md5sum #{name}")
2004-08-19 19:37:07 +00:00
return `md5sum #{name}`.chomp.gsub(/\s+.*/, "")
end
def hash_tmp(erase = true)
output = hash_file(@tmp)
if (erase)
2009-02-28 18:17:17 +00:00
File.unlink(@tmp) if (File.exists?(@tmp) && (ENV["KEEP_TMPFILES"] != "1"))
2004-09-29 09:35:27 +00:00
@debug_commands.push("rm #{@tmp}")
@tmp = nil
end
return output
end
2004-09-20 17:25:37 +00:00
def merge(*args)
command = "../src/mkvmerge --engage no_variable_data "
string_args = Array.new
retcode = 0
args.each do |a|
if (a.class == String)
string_args.push(a)
else
retcode = a
end
end
if ((string_args.size == 0) or (string_args.size > 2))
raise "Wrong use of the 'merge' function."
elsif (string_args.size == 1)
command += "-o " + tmp + " " + string_args[0]
else
command += "-o " + string_args[0] + " " + string_args[1]
end
sys(command, retcode)
end
def xtr_tracks_s(*args)
2004-09-25 20:14:35 +00:00
command = "../src/mkvextract tracks data/mkv/complex.mkv " +
"--no-variable-data "
2004-09-20 17:25:37 +00:00
command += args.join(" ")
command += ":#{tmp}"
sys(command, 0)
return hash_tmp
end
def xtr_tracks(*args)
command = "../src/mkvextract tracks "
2004-09-25 20:14:35 +00:00
command += args[0]
command += " --no-variable-data "
command += args[1..args.size - 1].join(" ")
2004-09-20 17:25:37 +00:00
sys(command, 0)
end
end
class Results
def initialize
load
end
def load
@results = Hash.new
return unless (FileTest.exist?("results.txt"))
IO.readlines("results.txt").each do |line|
parts = line.chomp.split(/:/)
2004-08-25 17:23:07 +00:00
parts[3] =~
/([0-9]{4})([0-9]{2})([0-9]{2})-([0-9]{2})([0-9]{2})([0-9]{2})/
@results[parts[0]] = {"hash" => parts[1], "status" => parts[2],
"date_added" => Time.local($1, $2, $3, $4, $5, $6) }
end
end
def save
f = File.new("results.txt", "w")
@results.keys.sort.each do |key|
f.puts [ key, @results[key]['hash'], @results[key]['status'], @results[key]['date_added'].strftime("%Y%m%d-%H%M%S") ].collect { |item| item.to_s }.join(":")
end
f.close
end
def exist?(name)
return @results.has_key?(name)
end
def hash?(name)
raise "No such result" unless (exist?(name))
return @results[name]['hash']
end
def status?(name)
raise "No such result" unless (exist?(name))
return @results[name]['status']
end
2004-08-25 17:23:07 +00:00
def date_added?(name)
raise "No such result" unless (exist?(name))
return @results[name]['date_added']
2010-05-22 14:24:25 +00:00
end
2004-08-25 17:23:07 +00:00
def add(name, hash)
raise "Test does already exist" if (exist?(name))
2004-08-25 17:23:07 +00:00
@results[name] = {"hash" => hash, "status" => "new",
"date_added" => Time.now }
save
end
def set(name, status)
return unless (exist?(name))
@results[name]["status"] = status
save
end
2004-08-30 21:27:45 +00:00
def set_hash(name, hash)
raise "Test does not exist" unless (exist?(name))
@results[name]["hash"] = hash
save
end
end
def main
2010-05-22 14:24:17 +00:00
ENV['LC_ALL'] = "en_US.UTF-8"
ENV['PATH'] = "../src:" + ENV['PATH']
2004-08-25 18:08:53 +00:00
controller = TestController.new
ARGV.each do |arg|
if ((arg == "-f") or (arg == "--failed"))
controller.test_failed = true
elsif ((arg == "-n") or (arg == "--new"))
controller.test_new = true
2004-08-30 21:27:45 +00:00
elsif ((arg == "-u") or (arg == "--update-failed"))
controller.update_failed = true
2004-08-25 17:23:07 +00:00
elsif (arg =~ /-d([0-9]{4})([0-9]{2})([0-9]{2})-([0-9]{2})([0-9]{2})/)
controller.test_date_after = Time.local($1, $2, $3, $4, $5, $6)
2004-08-25 17:23:07 +00:00
elsif (arg =~ /-D([0-9]{4})([0-9]{2})([0-9]{2})-([0-9]{2})([0-9]{2})/)
controller.test_date_before = Time.local($1, $2, $3, $4, $5, $6)
2004-08-25 21:18:55 +00:00
elsif (arg =~ /^[0-9]{3}$/)
controller.add_test_case arg
elsif arg =~ /-j(\d+)/
controller.num_threads = $1.to_i
else
error_and_exit "Unknown argument '#{arg}'."
end
end
controller.go
exit controller.num_failed > 0 ? 1 : 0
end
main