#!/usr/bin/env ruby # # = Synopsis # # Run unit tests, usually with the goal of resolving some conflict # between tests. # # = Usage # # test [-d|--debug] [-f|--files] [-h|--help] [-n method] [-v|--verbose] [file] ... # # = Description # # This script is useful for running a specific subset of unit tests, especially # when attempting to find a conflict between tests. By default, it will take # the first argument you pass it and run that test or test directory with each # test directory in turn, looking for a failure. If any tests fail, then # the script will drill into that test directory, looking for the specific conflict. # # In this way, when you have deduced you have two conflicting unit tests (tests which # pass in isolation but fail when run together), you can tell this script where # the failure is and leave it alone to find the conflict. # # This script is different from the Rakefile because it will run all tests in # a single process, whereas if you ask the Rakefile to run multiple tests, it will # run them in separate processes thus making it impossible to find conflicts. # # = Examples # # Attempt to resolve a conflict between a single test suite that could be anywhere: # # ./test ral/providers/user.rb # # Determine whether two individual files conflict: # # ./test --files language/functions.rb ral/providers/provider.rb # # Run the same test, but only run a specific unit test: # # ./test -d -n test_search --files language/functions.rb ral/providers/provider.rb # # = Options # # debug:: # Enable full debugging. # # files:: # Specify exactly which files to test. # # help:: # Print this help message # # n:: # Specify a single unit test to run. You can still specify as many files # as you want. # # verbose:: # Print extra information. # # = Example # # puppet -l /tmp/script.log script.pp # # = Author # # Luke Kanies # # = Copyright # # Copyright (c) 2005-2011 Puppet Labs, LLC # Licensed under the Apache 2.0 License require 'find' require 'getoptlong' include Find result = GetoptLong.new( [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ], [ "-n", GetoptLong::REQUIRED_ARGUMENT ], [ "--files", "-f", GetoptLong::NO_ARGUMENT ], [ "--help", "-h", GetoptLong::NO_ARGUMENT ] ) usage = "USAGE: %s [--help] suite" % $0 $options = {} keep = [] result.each { |opt,arg| case opt when "--verbose" $options[:verbose] = true when "--files" $options[:files] = true when "--debug" $options[:debug] = true $options[:verbose] = true when "--help" puts usage exit else keep << opt keep << arg if arg end } def dirs Dir.glob("*").find_all { |d| FileTest.directory?(d) }.reject { |d| ["lib", "data"].include?(d) } end def rake(*args) print "trying %s..." % args.join(" ") output = %x{rake %s} % args.join(" ") if $?.exitstatus == 0 puts "succeeded" return true else puts "failed" return false end end def resolve(dir) dirs = dirs() # If the passed dir is a subdir or file, put the basedir last if dir.include?(File::SEPARATOR) basedir = dir.split(File::SEPARATOR)[0] if dirs.include?(basedir) dirs.delete(basedir) dirs << basedir end end failed = nil dirs.each do |d| next if d == dir unless run([d, dir]) failed = d break end end puts "%s failed" % failed files = ruby_files(failed) files.each do |file| unless run([file, dir]) puts file exit(0) end end exit(1) end def ruby_files(dir) files = [] # First collect the entire file list. begin find(dir) { |f| files << f if f =~ /\.rb$/ } rescue => detail puts "could not find on %s: %s" % [dir.inspect, detail] end files end def run(files, flags = nil) args = %w{ruby} args << "-Ilib:../lib" args << "lib/rake/puppet_test_loader.rb" if flags args += flags end args += ARGV print files.join(" ") + "... " $stdout.flush files.each do |file| case File.stat(file).ftype when "file"; args << file when "directory"; args += ruby_files(file) else $stderr.puts "Skipping %s; can't handle %s" % [file, File.stat(file).ftype] end end args = args.join(" ") if $options[:verbose] p args end output = %x{#{args} 2>&1} if $options[:debug] print output end if $?.exitstatus == 0 puts "succeeded" return true else puts "failed" puts output return false end end if $options[:files] run(ARGV, keep) else dir = ARGV.shift unless dir $stderr.puts usage exit(1) end resolve(dir) end # # #files = [] # #args.each do |test| # if FileTest.directory?(test) # files += ruby_files(test) # end #end ## Now load all of our files. #files.each do |file| # load file unless file =~ /^-/ #end # #runner = Test::Unit::AutoRunner.new(false) #runner.process_args #runner.run