diff --git a/utilities/load-testing/testResultMunger/_mergeTestResults.rb b/utilities/load-testing/testResultMunger/_mergeTestResults.rb new file mode 100644 index 00000000..516cd836 --- /dev/null +++ b/utilities/load-testing/testResultMunger/_mergeTestResults.rb @@ -0,0 +1,31 @@ +#! /usr/bin/ruby + +require "#{File.dirname(__FILE__)}/subscripts/loadParms" +require "#{File.dirname(__FILE__)}/subscripts/test_result_merger" + +properties = {} + +source_dir = "/home/jeb228/LoadTesting/tests/results/#{@version_name}" +properties["source_directory"] = source_dir +properties["target_directory"] = "/var/www/html/loadTesting/" +properties["version_name"] = ""#{@version_name}" + +suggestions = [] +if File.directory?(source_dir) + Dir.chdir(source_dir) do |dir| + if File.file?("fileOrderSuggestions.txt") + File.open("fileOrderSuggestions.txt") do |f| + f.each_line() do |line| + suggestions.push(line.strip()) + end + end + end + end +end +properties["file_order_suggestions"] = suggestions + +trm = TestResultMerger.new(properties) +trm.merge + +puts "TestResultMerger was successful." + diff --git a/utilities/load-testing/testResultMunger/test_result_file.rb b/utilities/load-testing/testResultMunger/test_result_file.rb new file mode 100644 index 00000000..1963eab8 --- /dev/null +++ b/utilities/load-testing/testResultMunger/test_result_file.rb @@ -0,0 +1,101 @@ +#! /usr/bin/ruby + +=begin +-------------------------------------------------------------------------------- + +Parse a file of JMeter test results (*./jtl), summarize the times for each test, +and make the summaries easily available. + +-------------------------------------------------------------------------------- +=end + +require "rexml/document" + +include REXML + +# ------------------------------------------------------------------------------------ +# TestResultSummary class +# ------------------------------------------------------------------------------------ + +class TestResultSummary + attr_reader :label + attr_reader :how_many + attr_reader :failures + attr_reader :min_time + attr_reader :max_time + attr_reader :avg_time + def addResult(result_element) + @how_many += 1 + @failures += 1 unless result_element.attributes["s"] == "true" + + time = result_element.attributes["t"].to_i + @total_time += time + @min_time = [@min_time, time].min + @max_time = [@max_time, time].max + + @avg_time = @total_time / how_many + end + + def initialize(result_element) + @label = result_element.attributes["lb"] + @how_many = 0 + @failures = 0 + @min_time = 100000000 + @max_time = 0 + @total_time = 0 + + addResult(result_element) + end +end + +# ------------------------------------------------------------------------------------ +# TestResultFile class +# ------------------------------------------------------------------------------------ + +class TestResultFile + attr_reader :filename + attr_reader :timestamp + attr_reader :summaries + attr_reader :version + def parse_result_file() + @summaries = {} + @version = "_" + + file = File.new( @file_path ) + doc = Document.new file + XPath.each(doc, "/testResults/httpSample") do | result | + test_label = result.attributes["lb"] + if @summaries[test_label] == nil + @summaries[test_label] = TestResultSummary.new(result) + else + @summaries[test_label].addResult(result) + end + end + + XPath.each(doc, "version") do | version | + @version = version.attributes["name"] + end + end + + def initialize(filename, source_directory) + raise("filename must not be nil") if filename == nil + raise("source_directory must not be nil") if source_directory == nil + + @filename = filename + @source_directory = source_directory + + if !File.directory?(@source_directory) + raise "Directory does not exist: '#{@source_directory}'." + end + + @file_path = File.expand_path(filename + ".jtl", @source_directory) + + if !File.file?(@file_path) + raise "File doesn't exist: '#{@file_path}'." + end + + @timestamp = File.mtime(@file_path) + + parse_result_file() + end +end diff --git a/utilities/load-testing/testResultMunger/test_result_marshaller.rb b/utilities/load-testing/testResultMunger/test_result_marshaller.rb new file mode 100644 index 00000000..9ec304ce --- /dev/null +++ b/utilities/load-testing/testResultMunger/test_result_marshaller.rb @@ -0,0 +1,160 @@ +#! /usr/bin/ruby + +=begin +-------------------------------------------------------------------------------- + +Parse a file of JMeter test results (*./jtl), summarize the times for each test, +and make the summaries easily available. + +-------------------------------------------------------------------------------- +=end + +# ------------------------------------------------------------------------------------ +# TestResultMarshaller class +# ------------------------------------------------------------------------------------ + +class TestResultMarshaller + def marshall() + File.open(@output_filename, 'w') do | out | + write_html_header(out) + write_table_header(out) + write_table_lines(out) + write_table_footer(out) + write_html_footer(out) + end + end + + def write_html_header(out) + out.puts <<"EOF" + + + + Performance tests for #{@site_name} + + +EOF + end + + def write_table_header(out) + top_cells = [' '] + @test_results.each do | test | + top_cells.push("#{test.version}
#{test.filename}
#{test.timestamp.strftime('%Y-%m-%d %H:%M:%S')}") + end + + bottom_cells = ['Test Name'] + @test_results.each do | test | + bottom_cells.push('Iterations') + bottom_cells.push('time
(min/max)') + bottom_cells.push("compare") + end + + out.puts <<"EOF" + + + #{top_cells.join("\n ")} + + + #{bottom_cells.join("\n ")} + +EOF + end + + def write_table_lines(out) + all_test_names().each do | test_name | + out.puts <<"EOF" + + + #{format_test_results(test_name)} + +EOF + end + end + + def all_test_names + names = [] + @test_results.each do | test | + names.concat(test.summaries.keys) + end + names.uniq.sort + end + + def format_test_results(test_name) + results = [] + @test_results.each do | test | + results.push(format_test_result(test_name, test)) + end + results.join("\n ") + end + + def format_test_result(test_name, test) + s = test.summaries[test_name] + if s + <<"EOF" + + + +EOF + else + <<"EOF" + + + +EOF + end + end + + def format_millis(millis) + "%.3f" % [millis.to_f / 1000] + end + + def performance_ratio(test_name, time) + return " " if @test_results.empty? + return " " unless @test_results[0].summaries.key?(test_name) + + s = @test_results[0].summaries[test_name] + reference = s.avg_time + return " " if reference == 0 + + return "#{"%.0f" % [time * 100 / reference]}%" + end + + def write_table_footer(out) + out.puts "
#{test_name}
#{s.how_many} + + + + + + + + +
#{format_millis(s.avg_time)}#{format_millis(s.min_time)}
#{format_millis(s.max_time)}
+
#{performance_ratio(test_name, s.avg_time)}  + + + + + + + + +
  
 
+
 
" + end + + def write_html_footer(out) + out.puts <<"EOF" + + +EOF + end + + def initialize(target_directory, site_name, test_results) + @target_directory = target_directory + @site_name = site_name + @test_results = test_results + + filename = "#{site_name}-merged_#{Time.now.strftime('%Y-%m-%d_%H-%M-%S')}" + @output_filename = File.expand_path(filename, @target_directory) + end +end diff --git a/utilities/load-testing/testResultMunger/test_result_merger.rb b/utilities/load-testing/testResultMunger/test_result_merger.rb new file mode 100644 index 00000000..e406d8d8 --- /dev/null +++ b/utilities/load-testing/testResultMunger/test_result_merger.rb @@ -0,0 +1,95 @@ +#! /usr/bin/ruby + +=begin +-------------------------------------------------------------------------------- + +Look through a directory of test results files (*.jtl), and produce an HTML file +that summarizes, merges, and compares the information. + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +=end +$: << File.dirname(File.expand_path(__FILE__)) +require 'test_result_file' +require 'test_result_marshaller' + +# ------------------------------------------------------------------------------------ +# TestResultMerger class +# ------------------------------------------------------------------------------------ + +class TestResultMerger + # + # Do we have any chance of succeeding with these properties? + # + def sanity_checks_on_properties() + raise("Properties must contain a value for 'source_directory'") if @source_directory == nil + raise("Properties must contain a value for 'target_directory'") if @target_directory == nil + raise("Properties must contain a value for 'site_name'") if @site_name == nil + + if !File.directory?(@source_directory) + raise "Not a directory: '#{@source_directory}'." + end + if !File.directory?(@target_directory) + raise "Not a directory: '#{@target_directory}'." + end + end + + def parse_files() + test_result_files = build_file_list() + + @test_results = [] + test_result_files.each() do | test_result_file | + puts "Parsing #{test_result_file}" + @test_results.push(TestResultFile.new(test_result_file, @source_directory)) + end + end + + def build_file_list + existing_files = [] + Dir.foreach(@source_directory) do | filename | + next unless File.extname(filename) == ".jtl" + existing_files.push(File.basename(filename, ".jtl")) + end + puts "BOGUS existing files = [#{existing_files.join(', ')}]" + + file_list = [] + @file_order_suggestions.each() do | suggestion| + if existing_files.include?(suggestion) + file_list.push(suggestion) + existing_files.delete(suggestion) + end + end + file_list.concat(existing_files) + puts "BOGUS file list = [#{file_list.join(', ')}]" + + return file_list + end + + def marshall() + marshaller = TestResultMarshaller.new(@target_directory, @site_name, @test_results) + marshaller.marshall() + end + + def initialize(properties) + @source_directory = properties['source_directory'] + @target_directory = properties['target_directory'] + @site_name = properties['site_name'] + @file_order_suggestions = properties['file_order_suggestions'] + + puts "source_directory = #{@source_directory}" + puts "target_directory = #{@target_directory}" + puts "site_name = #{@site_name}" + if (@file_order_suggestions == nil) + puts "file_order_suggestions = nil" + else + puts "file_order_suggestions = [#{@file_order_suggestions.join(', ')}]" + end + + sanity_checks_on_properties + end + + def merge() + parse_files() + marshall() + end +end