diff --git a/hydra.gemspec b/hydra.gemspec index e248d4b..328e667 100644 --- a/hydra.gemspec +++ b/hydra.gemspec @@ -9,7 +9,7 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Nick Gauthier"] - s.date = %q{2010-02-16} + s.date = %q{2010-02-17} s.description = %q{Spread your tests over multiple machines to test your code faster.} s.email = %q{nick@smartlogicsolutions.com} s.extra_rdoc_files = [ @@ -27,6 +27,7 @@ Gem::Specification.new do |s| "VERSION", "caliper.yml", "hydra.gemspec", + "hydra_gray.png", "lib/hydra.rb", "lib/hydra/hash.rb", "lib/hydra/master.rb", diff --git a/lib/hydra/master.rb b/lib/hydra/master.rb index 732d9eb..054ba84 100644 --- a/lib/hydra/master.rb +++ b/lib/hydra/master.rb @@ -1,5 +1,6 @@ require 'hydra/hash' require 'open3' +require 'tmpdir' module Hydra #:nodoc: # Hydra class responsible for delegate work down to workers. # @@ -30,6 +31,8 @@ module Hydra #:nodoc: @workers = [] @listeners = [] @verbose = opts.fetch('verbose') { false } + @report = opts.fetch('report') { false } + init_report_file @sync = opts.fetch('sync') { nil } # default is one worker that is configured to use a pipe with one runner @@ -49,8 +52,11 @@ module Hydra #:nodoc: # Send a file down to a worker. def send_file(worker) f = @files.shift - trace "Sending #{f.inspect}" - worker[:io].write(RunFile.new(:file => f)) if f + if f + trace "Sending #{f.inspect}" + report_start_time(f) + worker[:io].write(RunFile.new(:file => f)) + end end # Process the results coming back from the worker. @@ -59,6 +65,7 @@ module Hydra #:nodoc: # only delete one @incomplete_files.delete_at(@incomplete_files.index(message.file)) trace "#{@incomplete_files.size} Files Remaining" + report_finish_time(message.file) if @incomplete_files.empty? shutdown_all_workers else @@ -66,6 +73,9 @@ module Hydra #:nodoc: end end + # A text report of the time it took to run each file + attr_reader :report_text + private def boot_workers(workers) @@ -171,6 +181,35 @@ module Hydra #:nodoc: end @listeners.each{|l| l.join} + + generate_report end + + def init_report_file + @report_file = File.join(Dir.tmpdir, 'hydra_report.txt') + FileUtils.rm_f(@report_file) + end + + def report_start_time(file) + File.open(@report_file, 'a'){|f| f.write "#{file}|start|#{Time.now.to_f}\n" } + end + + def report_finish_time(file) + File.open(@report_file, 'a'){|f| f.write "#{file}|finish|#{Time.now.to_f}\n" } + end + + def generate_report + report = {} + lines = nil + File.open(@report_file, 'r'){|f| lines = f.read.split("\n")} + lines.each{|l| l = l.split('|'); report[l[0]] ||= {}; report[l[0]][l[1]] = l[2]} + report.each{|file, times| report[file]['duration'] = times['finish'].to_f - times['start'].to_f} + report = report.sort{|a, b| b[1]['duration'] <=> a[1]['duration']} + output = [""] + report.each{|file, times| output << "%.2f\t#{file}" % times['duration']} + output << "Report available @ #{@report_file}" + @report_text = output.join("\n") + end + end end diff --git a/lib/hydra/tasks.rb b/lib/hydra/tasks.rb index 8daa2b0..509b068 100644 --- a/lib/hydra/tasks.rb +++ b/lib/hydra/tasks.rb @@ -18,6 +18,10 @@ module Hydra #:nodoc: # Path to the hydra config file. # If not set, it will check 'hydra.yml' and 'config/hydra.yml' attr_accessor :config + + # Set to true if you want hydra to generate a report. + # Defaults to fals + attr_accessor :report # # Search for the hydra config file def find_config_file @@ -45,6 +49,7 @@ module Hydra #:nodoc: # t.add_files 'test/functional/**/*_test.rb' # t.add_files 'test/integration/**/*_test.rb' # t.verbose = false # optionally set to true for lots of debug messages + # t.report = true # optionally set to true for a final report of test times # end class TestTask < Hydra::Task @@ -53,6 +58,7 @@ module Hydra #:nodoc: @name = name @files = [] @verbose = false + @report = false yield self if block_given? @@ -60,6 +66,7 @@ module Hydra #:nodoc: @opts = { :verbose => @verbose, + :report => @report, :files => @files } if @config @@ -77,7 +84,8 @@ module Hydra #:nodoc: desc "Hydra Tests" + (@name == :hydra ? "" : " for #{@name}") task @name do $stdout.write "Hydra Testing #{files.inspect}\n" - Hydra::Master.new(@opts) + h = Hydra::Master.new(@opts) + $stdout.write h.report_text if @report $stdout.write "\nHydra Completed\n" exit(0) #bypass test on_exit output end diff --git a/test/master_test.rb b/test/master_test.rb index 7671261..764ca42 100644 --- a/test/master_test.rb +++ b/test/master_test.rb @@ -20,6 +20,18 @@ class MasterTest < Test::Unit::TestCase assert_equal "HYDRA", File.read(target_file) end + should "generate a report" do + Hydra::Master.new( + :files => [test_file], + :report => true + ) + assert File.exists?(target_file) + assert_equal "HYDRA", File.read(target_file) + report_file = File.join(Dir.tmpdir, 'hydra_report.txt') + assert File.exists?(report_file) + assert_equal 2, File.read(report_file).split("\n").size + end + should "run a test 6 times on 1 worker with 2 runners" do Hydra::Master.new( :files => [test_file]*6, diff --git a/test/runner_test.rb b/test/runner_test.rb index c196060..fab6686 100644 --- a/test/runner_test.rb +++ b/test/runner_test.rb @@ -3,6 +3,7 @@ require File.join(File.dirname(__FILE__), 'test_helper') class RunnerTest < Test::Unit::TestCase context "with a file to test and a destination to verify" do setup do + sleep(0.2) FileUtils.rm_f(target_file) end