new scripts for merging JMeter results.
This commit is contained in:
parent
989f52d75c
commit
5e40a08243
4 changed files with 387 additions and 0 deletions
31
utilities/load-testing/testResultMunger/_mergeTestResults.rb
Normal file
31
utilities/load-testing/testResultMunger/_mergeTestResults.rb
Normal file
|
@ -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."
|
||||
|
101
utilities/load-testing/testResultMunger/test_result_file.rb
Normal file
101
utilities/load-testing/testResultMunger/test_result_file.rb
Normal file
|
@ -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
|
|
@ -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"
|
||||
<html>
|
||||
<head>
|
||||
<link REL='STYLESHEET' TYPE='text/css' HREF='./mergedResults.css'>
|
||||
<title>Performance tests for #{@site_name}</title>
|
||||
</head>
|
||||
<body>
|
||||
EOF
|
||||
end
|
||||
|
||||
def write_table_header(out)
|
||||
top_cells = ['<th> </th>']
|
||||
@test_results.each do | test |
|
||||
top_cells.push("<th colspan='3'>#{test.version}<br/>#{test.filename}<br/>#{test.timestamp.strftime('%Y-%m-%d %H:%M:%S')}</th>")
|
||||
end
|
||||
|
||||
bottom_cells = ['<th>Test Name</th>']
|
||||
@test_results.each do | test |
|
||||
bottom_cells.push('<th>Iterations</th>')
|
||||
bottom_cells.push('<th>time<br/>(min/max)</th>')
|
||||
bottom_cells.push("<th>compare</th>")
|
||||
end
|
||||
|
||||
out.puts <<"EOF"
|
||||
<table class='testData' cellspacing='0'>
|
||||
<tr>
|
||||
#{top_cells.join("\n ")}
|
||||
</tr>
|
||||
<tr>
|
||||
#{bottom_cells.join("\n ")}
|
||||
</tr>
|
||||
EOF
|
||||
end
|
||||
|
||||
def write_table_lines(out)
|
||||
all_test_names().each do | test_name |
|
||||
out.puts <<"EOF"
|
||||
<tr>
|
||||
<td class='left'>#{test_name}</td>
|
||||
#{format_test_results(test_name)}
|
||||
</tr>
|
||||
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"
|
||||
<td class='open'>#{s.how_many}</td>
|
||||
<td>
|
||||
<table class='oneResult close' cellspacing='0'>
|
||||
<tr>
|
||||
<td rowspan='2'>#{format_millis(s.avg_time)}</td>
|
||||
<td class='minmax'>#{format_millis(s.min_time)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class='minmax'>#{format_millis(s.max_time)}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td>#{performance_ratio(test_name, s.avg_time)}</td>
|
||||
EOF
|
||||
else
|
||||
<<"EOF"
|
||||
<td class='open'> </td>
|
||||
<td>
|
||||
<table class='oneResult close' cellspacing='0'>
|
||||
<tr>
|
||||
<td rowspan='2'> </td>
|
||||
<td class='minmax'> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class='minmax'> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td> </td>
|
||||
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 "</table>"
|
||||
end
|
||||
|
||||
def write_html_footer(out)
|
||||
out.puts <<"EOF"
|
||||
</body>
|
||||
</html>
|
||||
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
|
|
@ -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
|
Loading…
Add table
Reference in a new issue