jmeter-reports 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +2 -2
- data/Gemfile.lock +8 -1
- data/README.md +51 -0
- data/bin/jmeter-reports +31 -29
- data/jmeter-reports.gemspec +3 -3
- data/lib/jmeter/reports.rb +9 -4
- data/lib/jmeter/reports/summary.rb +62 -0
- data/lib/jmeter/reports/summary_item.rb +68 -0
- data/lib/jmeter/reports/summary_line.rb +33 -0
- data/lib/jmeter/reports/views/ascii_summary.rb +45 -0
- data/lib/jmeter/reports/views/ascii_summary_list.rb +30 -0
- data/test/fixtures/{summary_report.csv → summary_report1.csv} +0 -0
- data/test/fixtures/summary_report2.csv +17 -0
- data/test/helper.rb +7 -1
- data/test/test_ascii_summary.rb +16 -0
- data/test/test_ascii_summary_list.rb +16 -0
- data/test/test_jmeter_reports_version.rb +5 -7
- data/test/test_summary.rb +34 -0
- data/test/test_summary_line.rb +14 -0
- metadata +24 -17
- data/README.rdoc +0 -10
- data/lib/jmeter/reports/version.rb +0 -5
- data/lib/jmeter/summary_report/report.rb +0 -68
- data/lib/jmeter/summary_report/report_item.rb +0 -68
- data/lib/jmeter/summary_report/result_line.rb +0 -35
- data/test/test_report.rb +0 -37
- data/test/test_result_line.rb +0 -16
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -12,10 +12,17 @@ GEM
|
|
12
12
|
coderay (~> 1.0.5)
|
13
13
|
method_source (~> 0.8)
|
14
14
|
slop (~> 3.3.1)
|
15
|
-
|
15
|
+
pry (0.9.10-java)
|
16
|
+
coderay (~> 1.0.5)
|
17
|
+
method_source (~> 0.8)
|
18
|
+
slop (~> 3.3.1)
|
19
|
+
spoon (~> 0.0)
|
20
|
+
rake (10.0.3)
|
16
21
|
slop (3.3.3)
|
22
|
+
spoon (0.0.1)
|
17
23
|
|
18
24
|
PLATFORMS
|
25
|
+
java
|
19
26
|
ruby
|
20
27
|
|
21
28
|
DEPENDENCIES
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# JMeter Reports [](https://travis-ci.org/marcoshack/jmeter-reports)
|
2
|
+
|
3
|
+
Command-line tools for JMeter report processing. Right now it supports only CSV summary reports processing to show:
|
4
|
+
|
5
|
+
* Test execution time
|
6
|
+
* Total and transaction throughputs
|
7
|
+
* Transaction samples/errors
|
8
|
+
* Min / Avg / Max / Standard Deviation
|
9
|
+
* 90 and 95 response time percentiles
|
10
|
+
|
11
|
+
# Install
|
12
|
+
|
13
|
+
Requires Ruby >= 1.9
|
14
|
+
|
15
|
+
gem install jmeter-reports
|
16
|
+
|
17
|
+
# Usage
|
18
|
+
|
19
|
+
jmeter-reports <path_to_summary_report_file.csv>
|
20
|
+
|
21
|
+
will show you something like this:
|
22
|
+
|
23
|
+
Start: 2012-12-14 16:22:53 -0200
|
24
|
+
End: 2012-12-14 16:28:33 -0200
|
25
|
+
Duration: 340 secs
|
26
|
+
Total requests: 10520
|
27
|
+
Average throughput: 30 RPS
|
28
|
+
|
29
|
+
+--------------------------+------+--------+---------+-----+------+-------+--------+------------+
|
30
|
+
| label | reqs | errors | err_pct | min | avg | max | sd | avg_thrput |
|
31
|
+
+--------------------------+------+--------+---------+-----+------+-------+--------+------------+
|
32
|
+
| GET session/new | 2651 | 18 | 0.6 | 49 | 742 | 10062 | 1576ms | 7.797 RPS |
|
33
|
+
+--------------------------+------+--------+---------+-----+------+-------+--------+------------+
|
34
|
+
| POST session | 2629 | 562 | 21.3 | 272 | 3104 | 10093 | 3882ms | 7.732 RPS |
|
35
|
+
+--------------------------+------+--------+---------+-----+------+-------+--------+------------+
|
36
|
+
| GET session/:id | 2620 | 0 | 0.0 | 21 | 227 | 8099 | 682ms | 7.705 RPS |
|
37
|
+
+--------------------------+------+--------+---------+-----+------+-------+--------+------------+
|
38
|
+
| Login | 2620 | 570 | 21.7 | 377 | 4185 | 25724 | 4401ms | 7.705 RPS |
|
39
|
+
+--------------------------+------+--------+---------+-----+------+-------+--------+------------+
|
40
|
+
|
41
|
+
you can also pass a list of summary report files to get an overview of each one. Let say you've a bunch of summary files named _summary\_report\_N.csv_:
|
42
|
+
|
43
|
+
jmeter-reports summary_report_*
|
44
|
+
|
45
|
+
+----------------------+---------------------------+---------------------------+---------+------------+
|
46
|
+
| filename | start | end | samples | avg_thrput |
|
47
|
+
+----------------------+---------------------------+---------------------------+---------+------------+
|
48
|
+
| summary_report_1.csv | 2012-12-11 10:47:32 -0200 | 2012-12-11 10:47:34 -0200 | 9 | 3 RPS |
|
49
|
+
+----------------------+---------------------------+---------------------------+---------+------------+
|
50
|
+
| summary_report_2.csv | 2012-12-11 10:47:32 -0200 | 2012-12-11 10:47:35 -0200 | 16 | 4 RPS |
|
51
|
+
+----------------------+---------------------------+---------------------------+---------+------------+
|
data/bin/jmeter-reports
CHANGED
@@ -1,41 +1,43 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
require 'formatador'
|
4
|
+
require 'descriptive_statistics'
|
5
|
+
|
3
6
|
$:.push File.join(File.dirname(__FILE__), '..'), File.join(File.dirname(__FILE__), '..','lib')
|
7
|
+
require 'jmeter/reports'
|
4
8
|
|
5
|
-
|
6
|
-
|
7
|
-
Bundler.require(:default)
|
8
|
-
rescue LoadError
|
9
|
-
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
9
|
+
def version_message
|
10
|
+
"JMeter Reports version #{JmeterReports::VERSION}"
|
10
11
|
end
|
11
12
|
|
12
|
-
|
13
|
+
def usage_message
|
14
|
+
"""#{version_message}
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
Usage:
|
17
|
+
#{File.basename(__FILE__)} <report_file> | show the summary report for the given file
|
18
|
+
#{File.basename(__FILE__)} <report_file_list> | show a overview list of all report files
|
19
|
+
#{File.basename(__FILE__)} --version | show jmeter-reports version
|
20
|
+
#{File.basename(__FILE__)} --help | show this help page
|
21
|
+
"""
|
17
22
|
end
|
18
23
|
|
19
|
-
|
20
|
-
if
|
21
|
-
|
22
|
-
ARGV.each do |filename|
|
23
|
-
r = Jmeter::SummaryReport::Report.create(filename)
|
24
|
-
puts "#{filename},#{r.elapsed},#{r.total_requests},#{r.avg_throughput}"
|
25
|
-
end
|
24
|
+
def process_report(file_list)
|
25
|
+
if file_list.size > 1
|
26
|
+
JmeterReports::Views::AsciiSummaryList.new(file_list).render
|
26
27
|
else
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
JmeterReports::Views::AsciiSummary.new(JmeterReports::Summary.create(file_list.first)).render
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
if ARGV.empty? || ARGV[0] == '--help'
|
33
|
+
puts usage_message
|
34
|
+
elsif ARGV[0] == "--version"
|
35
|
+
puts version_message
|
36
|
+
else
|
37
|
+
begin
|
38
|
+
process_report(ARGV)
|
39
|
+
rescue Exception => e
|
40
|
+
puts e.message
|
41
|
+
exit 2
|
37
42
|
end
|
38
|
-
rescue Exception => e
|
39
|
-
puts e.message
|
40
|
-
exit 2
|
41
43
|
end
|
data/jmeter-reports.gemspec
CHANGED
@@ -5,7 +5,7 @@ require 'jmeter/reports'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
7
|
gem.name = "jmeter-reports"
|
8
|
-
gem.version =
|
8
|
+
gem.version = JmeterReports::VERSION
|
9
9
|
gem.authors = ["Marcos Hack"]
|
10
10
|
gem.email = ["marcos.hack@gmail.com"]
|
11
11
|
gem.description = %q{JMeter Reports}
|
@@ -19,10 +19,10 @@ Gem::Specification.new do |gem|
|
|
19
19
|
|
20
20
|
gem.required_ruby_version = '>= 1.9'
|
21
21
|
|
22
|
-
gem.add_runtime_dependency "bundler"
|
23
22
|
gem.add_runtime_dependency "descriptive_statistics"
|
24
23
|
gem.add_runtime_dependency "formatador"
|
25
|
-
|
24
|
+
|
25
|
+
gem.add_development_dependency "bundler"
|
26
26
|
gem.add_development_dependency "rake"
|
27
27
|
gem.add_development_dependency "minitest", "~> 3"
|
28
28
|
gem.add_development_dependency "minitest-colorize"
|
data/lib/jmeter/reports.rb
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
-
require 'jmeter/
|
2
|
-
require 'jmeter/
|
3
|
-
require 'jmeter/
|
4
|
-
require 'jmeter/reports/
|
1
|
+
require 'jmeter/reports/summary'
|
2
|
+
require 'jmeter/reports/summary_item'
|
3
|
+
require 'jmeter/reports/summary_line'
|
4
|
+
require 'jmeter/reports/views/ascii_summary'
|
5
|
+
require 'jmeter/reports/views/ascii_summary_list'
|
6
|
+
|
7
|
+
module JmeterReports
|
8
|
+
VERSION = "0.0.6"
|
9
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module JmeterReports
|
2
|
+
class Summary
|
3
|
+
CSV_HEADER = "timeStamp,elapsed,label,responseCode,responseMessage,threadName,"+
|
4
|
+
"dataType,success,bytes,grpThreads,allThreads,URL,Latency\n"
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@items = {}
|
8
|
+
@req_count = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.create(summary_report_file_path)
|
12
|
+
report = Summary.new
|
13
|
+
csv_report = File.open(summary_report_file_path,'r')
|
14
|
+
|
15
|
+
unless csv_report.readline == CSV_HEADER
|
16
|
+
raise Exception.new("Invalid CSV report: #{summary_report_file_path}")
|
17
|
+
end
|
18
|
+
|
19
|
+
csv_report.each_line do |line|
|
20
|
+
next if line.start_with?("timeStamp,") # ignore header
|
21
|
+
report.add(SummaryLine.parse(line))
|
22
|
+
end
|
23
|
+
return report
|
24
|
+
end
|
25
|
+
|
26
|
+
def add(line)
|
27
|
+
@items[line.label] = SummaryItem.new(line.label) if @items[line.label].nil?
|
28
|
+
@items[line.label].add(line)
|
29
|
+
@req_count += 1
|
30
|
+
@start_ms = line.timestamp if @start_ms.nil? || line.timestamp < @start_ms
|
31
|
+
@end_ms = line.timestamp if @end_ms.nil? || line.timestamp > @end_ms
|
32
|
+
end
|
33
|
+
|
34
|
+
def elapsed_in_ms
|
35
|
+
@end_ms - @start_ms
|
36
|
+
end
|
37
|
+
|
38
|
+
def elapsed
|
39
|
+
(self.elapsed_in_ms / 1000.0).ceil
|
40
|
+
end
|
41
|
+
|
42
|
+
def avg_throughput
|
43
|
+
@req_count / self.elapsed
|
44
|
+
end
|
45
|
+
|
46
|
+
def items
|
47
|
+
@items.values
|
48
|
+
end
|
49
|
+
|
50
|
+
def total_requests
|
51
|
+
@req_count
|
52
|
+
end
|
53
|
+
|
54
|
+
def start_date
|
55
|
+
Time.at(@start_ms / 1000.0)
|
56
|
+
end
|
57
|
+
|
58
|
+
def end_date
|
59
|
+
Time.at(@end_ms / 1000.0)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'descriptive_statistics'
|
2
|
+
|
3
|
+
module JmeterReports
|
4
|
+
class SummaryItem
|
5
|
+
def initialize(label)
|
6
|
+
@label = label
|
7
|
+
@items = []
|
8
|
+
@error_count = 0
|
9
|
+
@req_count = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(line)
|
13
|
+
@error_count += 1 if line.error?
|
14
|
+
@items << line.elapsed
|
15
|
+
@req_count += 1
|
16
|
+
@start_ms = line.timestamp if @start_ms.nil? || line.timestamp < @start_ms
|
17
|
+
@end_ms = line.timestamp if @end_ms.nil? || line.timestamp > @end_ms
|
18
|
+
end
|
19
|
+
|
20
|
+
def elapsed_in_ms
|
21
|
+
@end_ms - @start_ms
|
22
|
+
end
|
23
|
+
|
24
|
+
def elapsed
|
25
|
+
(self.elapsed_in_ms / 1000.0).ceil
|
26
|
+
end
|
27
|
+
|
28
|
+
def avg_throughput
|
29
|
+
@req_count > 1 ? @req_count / self.elapsed.to_f : 0.0
|
30
|
+
end
|
31
|
+
|
32
|
+
def size
|
33
|
+
@items.size
|
34
|
+
end
|
35
|
+
|
36
|
+
def errors
|
37
|
+
@error_count
|
38
|
+
end
|
39
|
+
|
40
|
+
def error_rate
|
41
|
+
@error_count / self.size.to_f
|
42
|
+
end
|
43
|
+
|
44
|
+
def percentil(percentil)
|
45
|
+
@items.sort[((percentil / 100.0) * @items.size).ceil]
|
46
|
+
end
|
47
|
+
|
48
|
+
def min
|
49
|
+
@items.min
|
50
|
+
end
|
51
|
+
|
52
|
+
def avg
|
53
|
+
@items.reduce { |n,s| s += n } / @items.size
|
54
|
+
end
|
55
|
+
|
56
|
+
def max
|
57
|
+
@items.max
|
58
|
+
end
|
59
|
+
|
60
|
+
def sd
|
61
|
+
@items.standard_deviation.to_i
|
62
|
+
end
|
63
|
+
|
64
|
+
def label
|
65
|
+
@label
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Representation of a summary report result line.
|
2
|
+
#
|
3
|
+
# Header:
|
4
|
+
# timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,
|
5
|
+
# success,bytes,grpThreads,allThreads,URL,Latency
|
6
|
+
#
|
7
|
+
# Line example:
|
8
|
+
# 1355164382383,97,Tela de Login,200,"Number of samples in transaction : 1,
|
9
|
+
# number of failing samples : 0",Thread Group 1-1,,true,5168,1,1,null,0
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'csv'
|
13
|
+
|
14
|
+
module JmeterReports
|
15
|
+
class SummaryLine
|
16
|
+
attr_accessor :timestamp, :elapsed, :label, :error, :latency
|
17
|
+
|
18
|
+
def self.parse(line)
|
19
|
+
t,e,l,rc,rm,_,_,s,_,_,_,_,lt = CSV.parse_line(line)
|
20
|
+
res = JmeterReports::SummaryLine.new
|
21
|
+
res.timestamp = t.to_i
|
22
|
+
res.elapsed = e.to_i
|
23
|
+
res.label = l
|
24
|
+
res.error = (s == "false" ? true : false)
|
25
|
+
res.latency = lt.to_i
|
26
|
+
return res
|
27
|
+
end
|
28
|
+
|
29
|
+
def error?
|
30
|
+
self.error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module JmeterReports
|
2
|
+
module Views
|
3
|
+
class AsciiSummary
|
4
|
+
HEADERS = [:label,:reqs,:errors,:err_pct,:min,:avg,:max,:sd,:avg_thrput,:pct_90,:pct_95]
|
5
|
+
|
6
|
+
def initialize(report)
|
7
|
+
@report = report
|
8
|
+
end
|
9
|
+
|
10
|
+
def report_data(color = true)
|
11
|
+
data = []
|
12
|
+
@report.items.each do |i|
|
13
|
+
data << {
|
14
|
+
:label => (color ? "[green]#{i.label}[/]" : i.label),
|
15
|
+
:reqs => i.size,
|
16
|
+
:errors => (i.errors > 0 && color ? "[red]#{i.errors}[/]" : i.errors),
|
17
|
+
:err_pct => (i.error_rate * 100).round(1),
|
18
|
+
:avg_thrput => "[yellow]#{i.avg_throughput.round(3)}[/]",
|
19
|
+
:min => i.min,
|
20
|
+
:avg => "[yellow]#{i.avg}[/]",
|
21
|
+
:max => i.max,
|
22
|
+
:sd => color ? "[yellow]#{i.sd}[/]" : i.sd,
|
23
|
+
:pct_90 => i.percentil(90),
|
24
|
+
:pct_95 => i.percentil(95)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
return data
|
28
|
+
end
|
29
|
+
|
30
|
+
def render
|
31
|
+
puts ""
|
32
|
+
puts " Start: #{@report.start_date}"
|
33
|
+
puts " End: #{@report.end_date}"
|
34
|
+
puts " Duration: #{@report.elapsed} secs"
|
35
|
+
puts " Total requests: #{@report.total_requests}"
|
36
|
+
puts "Overall throughput: #{@report.avg_throughput} RPS"
|
37
|
+
puts ""
|
38
|
+
Formatador.display_compact_table(report_data, HEADERS)
|
39
|
+
puts ""
|
40
|
+
puts " Time values in milliseconds and throughput in Requests Per Second."
|
41
|
+
puts ""
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module JmeterReports
|
2
|
+
module Views
|
3
|
+
class AsciiSummaryList
|
4
|
+
HEADERS = [:filename,:start,:end,:samples,:avg_thrput]
|
5
|
+
|
6
|
+
def initialize(files)
|
7
|
+
@files = files
|
8
|
+
end
|
9
|
+
|
10
|
+
def report_data(color = true)
|
11
|
+
data = []
|
12
|
+
@files.each do |filename|
|
13
|
+
r = JmeterReports::Summary.create(filename)
|
14
|
+
data << {
|
15
|
+
:filename => (color ? "[yellow]#{File.basename(filename)}[/]" : File.basename(filename)),
|
16
|
+
:start => r.start_date,
|
17
|
+
:end => r.end_date,
|
18
|
+
:samples => (color ? "[blue]#{r.total_requests}[/]" : r.total_requests),
|
19
|
+
:avg_thrput => "#{r.avg_throughput} RPS"
|
20
|
+
}
|
21
|
+
end
|
22
|
+
return data
|
23
|
+
end
|
24
|
+
|
25
|
+
def render
|
26
|
+
Formatador.display_compact_table(report_data, HEADERS)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
File without changes
|
@@ -0,0 +1,17 @@
|
|
1
|
+
timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,success,bytes,grpThreads,allThreads,URL,Latency
|
2
|
+
1355230052183,75,GET retrieve_gui,200,OK,Thread Group 1-1,text,true,5168,1,1,http://stage.id.abril.com.br/widgets/login/retrieve_gui?callback=AbrilIdJQuery2820887356_2820887356&application_login=PLAYBOY¤t_instance_id=aiwwidgets¤t_box_id=abril-id-load_test-login&confirmation_url=http://example.com/&_=3887356&provedores=facebook%2Ctwitter%2Cgoogle,74
|
3
|
+
1355230052256,72,GET retrieve_gui,200,OK,Thread Group 1-3,text,true,5168,3,3,http://stage.id.abril.com.br/widgets/login/retrieve_gui?callback=AbrilIdJQuery2464809911_2464809911&application_login=PLAYBOY¤t_instance_id=aiwwidgets¤t_box_id=abril-id-load_test-login&confirmation_url=http://example.com/&_=8771784&provedores=facebook%2Ctwitter%2Cgoogle,70
|
4
|
+
1355230052460,65,GET retrieve_gui,200,OK,Thread Group 1-5,text,true,5168,5,5,http://stage.id.abril.com.br/widgets/login/retrieve_gui?callback=AbrilIdJQuery2880723472_2880723472&application_login=PLAYBOY¤t_instance_id=aiwwidgets¤t_box_id=abril-id-load_test-login&confirmation_url=http://example.com/&_=9723472&provedores=facebook%2Ctwitter%2Cgoogle,64
|
5
|
+
1355230052560,65,GET retrieve_gui,200,OK,Thread Group 1-5,text,true,5168,5,5,http://stage.id.abril.com.br/widgets/login/retrieve_gui?callback=AbrilIdJQuery2880723472_2880723472&application_login=PLAYBOY¤t_instance_id=aiwwidgets¤t_box_id=abril-id-load_test-login&confirmation_url=http://example.com/&_=9723472&provedores=facebook%2Ctwitter%2Cgoogle,64
|
6
|
+
1355230053060,71,GET retrieve_gui,200,OK,Thread Group 1-6,text,true,5168,6,6,http://stage.id.abril.com.br/widgets/login/retrieve_gui?callback=AbrilIdJQuery2808390679_2808390679&application_login=PLAYBOY¤t_instance_id=aiwwidgets¤t_box_id=abril-id-load_test-login&confirmation_url=http://example.com/&_=9390679&provedores=facebook%2Ctwitter%2Cgoogle,69
|
7
|
+
1355230053262,66,GET retrieve_gui,200,OK,Thread Group 1-7,text,true,5168,7,7,http://stage.id.abril.com.br/widgets/login/retrieve_gui?callback=AbrilIdJQuery2692773635_2692773635&application_login=PLAYBOY¤t_instance_id=aiwwidgets¤t_box_id=abril-id-load_test-login&confirmation_url=http://example.com/&_=1773635&provedores=facebook%2Ctwitter%2Cgoogle,65
|
8
|
+
1355230053660,73,GET retrieve_gui,200,OK,Thread Group 1-8,text,true,5168,8,8,http://stage.id.abril.com.br/widgets/login/retrieve_gui?callback=AbrilIdJQuery2625634952_2625634952&application_login=PLAYBOY¤t_instance_id=aiwwidgets¤t_box_id=abril-id-load_test-login&confirmation_url=http://example.com/&_=6634952&provedores=facebook%2Ctwitter%2Cgoogle,71
|
9
|
+
1355230053760,73,GET retrieve_gui,200,OK,Thread Group 1-8,text,true,5168,8,8,http://stage.id.abril.com.br/widgets/login/retrieve_gui?callback=AbrilIdJQuery2625634952_2625634952&application_login=PLAYBOY¤t_instance_id=aiwwidgets¤t_box_id=abril-id-load_test-login&confirmation_url=http://example.com/&_=6634952&provedores=facebook%2Ctwitter%2Cgoogle,71
|
10
|
+
1355230054465,68,GET retrieve_gui,200,OK,Thread Group 1-9,text,true,5168,9,9,http://stage.id.abril.com.br/widgets/login/retrieve_gui?callback=AbrilIdJQuery1205134350_1205134350&application_login=PLAYBOY¤t_instance_id=aiwwidgets¤t_box_id=abril-id-load_test-login&confirmation_url=http://example.com/&_=8134350&provedores=facebook%2Ctwitter%2Cgoogle,67
|
11
|
+
1355230054867,434,POST execute,200,OK,Thread Group 1-5,text,true,1468,10,10,http://stage.id.abril.com.br/widgets/login/execute,434
|
12
|
+
1355230054967,434,POST execute,200,OK,Thread Group 1-5,text,true,1468,10,10,http://stage.id.abril.com.br/widgets/login/execute,434
|
13
|
+
1355230054987,434,POST execute,200,OK,Thread Group 1-5,text,true,1468,10,10,http://stage.id.abril.com.br/widgets/login/execute,434
|
14
|
+
1355230055102,22,GET retrieve_success_gui,200,OK,Thread Group 1-5,text,true,2084,10,10,http://stage.id.abril.com.br/widgets/login/retrieve_success_gui?callback=AbrilIdJQuery2880723472_2880723472&application_login=PLAYBOY¤t_instance_id=aiwwidgets¤t_box_id=abril-id-load_test-login&confirmation_url=http://example.com/&_=9723472,27
|
15
|
+
1355230055465,85,GET retrieve_gui,200,OK,Thread Group 1-9,text,true,5168,9,9,http://stage.id.abril.com.br/widgets/login/retrieve_gui?callback=AbrilIdJQuery1205134350_1205134350&application_login=PLAYBOY¤t_instance_id=aiwwidgets¤t_box_id=abril-id-load_test-login&confirmation_url=http://example.com/&_=8134350&provedores=facebook%2Ctwitter%2Cgoogle,67
|
16
|
+
1355230055867,628,POST execute,200,OK,Thread Group 1-5,text,true,1468,10,10,http://stage.id.abril.com.br/widgets/login/execute,434
|
17
|
+
1355230055902,98,GET retrieve_success_gui,200,OK,Thread Group 1-5,text,true,2084,10,10,http://stage.id.abril.com.br/widgets/login/retrieve_success_gui?callback=AbrilIdJQuery2880723472_2880723472&application_login=PLAYBOY¤t_instance_id=aiwwidgets¤t_box_id=abril-id-load_test-login&confirmation_url=http://example.com/&_=9723472,27
|
data/test/helper.rb
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
2
|
require 'minitest/colorize'
|
3
3
|
|
4
|
-
|
4
|
+
begin
|
5
|
+
require 'bundler/setup'
|
6
|
+
Bundler.require(:default, :development, :test)
|
7
|
+
rescue LoadError
|
8
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
9
|
+
end
|
10
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path('helper', File.dirname(__FILE__))
|
2
|
+
require 'jmeter/reports/views/ascii_summary'
|
3
|
+
|
4
|
+
module JmeterReports
|
5
|
+
module Views
|
6
|
+
class TestAsciiSummary < MiniTest::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@report = ::JmeterReports::Summary.create(File.expand_path('fixtures/summary_report1.csv', File.dirname(__FILE__)))
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_render
|
12
|
+
AsciiSummary.new(@report).render
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path('helper', File.dirname(__FILE__))
|
2
|
+
require 'jmeter/reports/views/ascii_summary_list'
|
3
|
+
|
4
|
+
module JmeterReports
|
5
|
+
module Views
|
6
|
+
class TestAsciiSummaryList < MiniTest::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@files = Dir.glob(File.expand_path('fixtures/*', File.dirname(__FILE__)))
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_render
|
12
|
+
AsciiSummaryList.new(@files).render
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,12 +1,10 @@
|
|
1
1
|
require File.expand_path('helper', File.dirname(__FILE__))
|
2
|
-
require 'jmeter/reports
|
2
|
+
require 'jmeter/reports'
|
3
3
|
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
assert Jmeter::Reports::VERSION != nil
|
9
|
-
end
|
4
|
+
module JmeterReports
|
5
|
+
class TestVersion < MiniTest::Unit::TestCase
|
6
|
+
def test_version
|
7
|
+
assert JmeterReports::VERSION != nil
|
10
8
|
end
|
11
9
|
end
|
12
10
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.expand_path('helper', File.dirname(__FILE__))
|
2
|
+
require 'jmeter/reports'
|
3
|
+
|
4
|
+
module JmeterReports
|
5
|
+
class TestSummary < MiniTest::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@report = Summary.create(File.expand_path('fixtures/summary_report1.csv', File.dirname(__FILE__)))
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_report_items
|
11
|
+
assert_equal 3, @report.items.size
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_avg_throughput
|
15
|
+
assert_equal 3, @report.avg_throughput
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_elapsed_in_ms
|
19
|
+
assert_equal 2719, @report.elapsed_in_ms
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_elapsed
|
23
|
+
assert_equal 3, @report.elapsed
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_start_date
|
27
|
+
assert_equal Time.new(2012,12,11,12,47,32,"+00:00").to_i, @report.start_date.utc.to_i, 'invalid start date'
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_end_date
|
31
|
+
assert_equal Time.new(2012,12,11,12,47,34,"+00:00").to_i, @report.end_date.utc.to_i, 'invalid end date'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.expand_path('helper', File.dirname(__FILE__))
|
2
|
+
require 'jmeter/reports/summary_line'
|
3
|
+
|
4
|
+
module JmeterReports
|
5
|
+
class TestSummaryLine < MiniTest::Unit::TestCase
|
6
|
+
def test_parse_simple_error_line
|
7
|
+
assert SummaryLine.parse('1355332336591,4850,POST execute,500,Internal Server Error,Thread Group 1-70,text,false,15535,75,75,http://stage.id.abril.com.br/widgets/login/execute,4847').error?
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_parse_transaction_error_line
|
11
|
+
assert SummaryLine.parse('1355163053904,5933,Login,,"Number of samples in transaction : 2, number of failing samples : 1",Thread Group 1-15,,false,2836,20,20,null,0').error?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jmeter-reports
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,10 +9,10 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: descriptive_statistics
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
@@ -28,7 +28,7 @@ dependencies:
|
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
31
|
+
name: formatador
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
47
|
+
name: bundler
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
51
51
|
- - ! '>='
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '0'
|
54
|
-
type: :
|
54
|
+
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
@@ -136,20 +136,24 @@ files:
|
|
136
136
|
- Gemfile
|
137
137
|
- Gemfile.lock
|
138
138
|
- LICENSE
|
139
|
-
- README.
|
139
|
+
- README.md
|
140
140
|
- Rakefile
|
141
141
|
- bin/jmeter-reports
|
142
142
|
- jmeter-reports.gemspec
|
143
143
|
- lib/jmeter/reports.rb
|
144
|
-
- lib/jmeter/reports/
|
145
|
-
- lib/jmeter/
|
146
|
-
- lib/jmeter/
|
147
|
-
- lib/jmeter/
|
148
|
-
-
|
144
|
+
- lib/jmeter/reports/summary.rb
|
145
|
+
- lib/jmeter/reports/summary_item.rb
|
146
|
+
- lib/jmeter/reports/summary_line.rb
|
147
|
+
- lib/jmeter/reports/views/ascii_summary.rb
|
148
|
+
- lib/jmeter/reports/views/ascii_summary_list.rb
|
149
|
+
- test/fixtures/summary_report1.csv
|
150
|
+
- test/fixtures/summary_report2.csv
|
149
151
|
- test/helper.rb
|
152
|
+
- test/test_ascii_summary.rb
|
153
|
+
- test/test_ascii_summary_list.rb
|
150
154
|
- test/test_jmeter_reports_version.rb
|
151
|
-
- test/
|
152
|
-
- test/
|
155
|
+
- test/test_summary.rb
|
156
|
+
- test/test_summary_line.rb
|
153
157
|
homepage: https://github.com/marcoshack/jmeter-reports
|
154
158
|
licenses: []
|
155
159
|
post_install_message:
|
@@ -175,9 +179,12 @@ signing_key:
|
|
175
179
|
specification_version: 3
|
176
180
|
summary: Basic tools for JMeter reports processing.
|
177
181
|
test_files:
|
178
|
-
- test/fixtures/
|
182
|
+
- test/fixtures/summary_report1.csv
|
183
|
+
- test/fixtures/summary_report2.csv
|
179
184
|
- test/helper.rb
|
185
|
+
- test/test_ascii_summary.rb
|
186
|
+
- test/test_ascii_summary_list.rb
|
180
187
|
- test/test_jmeter_reports_version.rb
|
181
|
-
- test/
|
182
|
-
- test/
|
188
|
+
- test/test_summary.rb
|
189
|
+
- test/test_summary_line.rb
|
183
190
|
has_rdoc:
|
data/README.rdoc
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
== JMeter Reports {<img src="https://travis-ci.org/marcoshack/jmeter-reports.png?branch=master" alt="Build Status" />}[https://travis-ci.org/marcoshack/jmeter-reports]
|
2
|
-
|
3
|
-
Basic tools for JMeter reports processing.
|
4
|
-
|
5
|
-
Right now it supports only CSV summary reports processing to show:
|
6
|
-
|
7
|
-
* Test execution time
|
8
|
-
* Average request throughput
|
9
|
-
* Number of requests/errors for each request and/or transaction
|
10
|
-
* 90 and 95 response time percentiles
|
@@ -1,68 +0,0 @@
|
|
1
|
-
module Jmeter
|
2
|
-
module SummaryReport
|
3
|
-
class Report
|
4
|
-
CSV_HEADER = "timeStamp,elapsed,label,responseCode,responseMessage,threadName,"+
|
5
|
-
"dataType,success,bytes,grpThreads,allThreads,URL,Latency\n"
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@items = {}
|
9
|
-
@req_count = 0
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.create(summary_report_file_path)
|
13
|
-
report = Report.new
|
14
|
-
csv_report = File.open(summary_report_file_path,'r')
|
15
|
-
|
16
|
-
unless csv_report.readline == CSV_HEADER
|
17
|
-
raise Exception.new("Invalid CSV report: #{summary_report_file_path}")
|
18
|
-
end
|
19
|
-
|
20
|
-
csv_report.each_line do |line|
|
21
|
-
next if line.start_with?("timeStamp,") # ignore header
|
22
|
-
report.add(ResultLine.parse(line))
|
23
|
-
end
|
24
|
-
return report
|
25
|
-
end
|
26
|
-
|
27
|
-
def add(line)
|
28
|
-
@items[line.label] = ReportItem.new(line.label) if @items[line.label].nil?
|
29
|
-
@items[line.label].add(line)
|
30
|
-
@req_count += 1
|
31
|
-
@start_ms = line.timestamp if @start_ms.nil? || line.timestamp < @start_ms
|
32
|
-
@end_ms = line.timestamp if @end_ms.nil? || line.timestamp > @end_ms
|
33
|
-
end
|
34
|
-
|
35
|
-
def elapsed_in_ms
|
36
|
-
@end_ms - @start_ms
|
37
|
-
end
|
38
|
-
|
39
|
-
def elapsed
|
40
|
-
(self.elapsed_in_ms / 1000.0).ceil
|
41
|
-
end
|
42
|
-
|
43
|
-
def avg_throughput
|
44
|
-
@req_count / self.elapsed
|
45
|
-
end
|
46
|
-
|
47
|
-
def items
|
48
|
-
@items.values
|
49
|
-
end
|
50
|
-
|
51
|
-
def total_requests
|
52
|
-
@req_count
|
53
|
-
end
|
54
|
-
|
55
|
-
def start_date
|
56
|
-
Time.at(@start_ms / 1000.0)
|
57
|
-
end
|
58
|
-
|
59
|
-
def end_date
|
60
|
-
Time.at(@end_ms / 1000.0)
|
61
|
-
end
|
62
|
-
|
63
|
-
def table_data
|
64
|
-
@items.values.collect { |i| i.table_data }
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require 'descriptive_statistics'
|
2
|
-
|
3
|
-
module Jmeter
|
4
|
-
module SummaryReport
|
5
|
-
class ReportItem
|
6
|
-
def initialize(label)
|
7
|
-
@label = label
|
8
|
-
@items = []
|
9
|
-
@error_count = 0
|
10
|
-
@req_count = 0
|
11
|
-
end
|
12
|
-
|
13
|
-
def add(line)
|
14
|
-
@error_count += 1 if line.error?
|
15
|
-
@items << line.elapsed
|
16
|
-
@req_count += 1
|
17
|
-
@start_ms = line.timestamp if @start_ms.nil? || line.timestamp < @start_ms
|
18
|
-
@end_ms = line.timestamp if @end_ms.nil? || line.timestamp > @end_ms
|
19
|
-
end
|
20
|
-
|
21
|
-
def elapsed_in_ms
|
22
|
-
@end_ms - @start_ms
|
23
|
-
end
|
24
|
-
|
25
|
-
def elapsed
|
26
|
-
(self.elapsed_in_ms / 1000.0).ceil
|
27
|
-
end
|
28
|
-
|
29
|
-
def avg_throughput
|
30
|
-
@req_count / self.elapsed.to_f
|
31
|
-
end
|
32
|
-
|
33
|
-
def size
|
34
|
-
@items.size
|
35
|
-
end
|
36
|
-
|
37
|
-
def errors
|
38
|
-
@error_count
|
39
|
-
end
|
40
|
-
|
41
|
-
def error_rate
|
42
|
-
@error_count / self.size.to_f
|
43
|
-
end
|
44
|
-
|
45
|
-
def table_data
|
46
|
-
sorted_items = @items.sort
|
47
|
-
{
|
48
|
-
:label => @label,
|
49
|
-
:reqs => self.size,
|
50
|
-
:errors => self.errors,
|
51
|
-
:err_pct => round(self.error_rate * 100, 1),
|
52
|
-
:avg_thrput => "#{round(self.avg_throughput, 3)} RPS",
|
53
|
-
:min => @items.min,
|
54
|
-
:avg => @items.reduce { |n,s| s += n } / @items.size,
|
55
|
-
:max => @items.max,
|
56
|
-
:sd => "#{@items.standard_deviation.to_i}ms",
|
57
|
-
:pct_90 => "#{sorted_items[(self.size * 0.90).round]}ms",
|
58
|
-
:pct_95 => "#{sorted_items[(self.size * 0.95).round]}ms"
|
59
|
-
}
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
def round(float_number, dec)
|
64
|
-
(float_number * 10**dec).to_i / (10**dec).to_f
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# Representation of a summary report result line.
|
2
|
-
#
|
3
|
-
# Header:
|
4
|
-
# timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,
|
5
|
-
# success,bytes,grpThreads,allThreads,URL,Latency
|
6
|
-
#
|
7
|
-
# Line example:
|
8
|
-
# 1355164382383,97,Tela de Login,200,"Number of samples in transaction : 1,
|
9
|
-
# number of failing samples : 0",Thread Group 1-1,,true,5168,1,1,null,0
|
10
|
-
#
|
11
|
-
|
12
|
-
require 'csv'
|
13
|
-
|
14
|
-
module Jmeter
|
15
|
-
module SummaryReport
|
16
|
-
class ResultLine
|
17
|
-
attr_accessor :timestamp, :elapsed, :label, :error, :latency
|
18
|
-
|
19
|
-
def self.parse(line)
|
20
|
-
t,e,l,rc,rm,_,_,s,_,_,_,_,lt = CSV.parse_line(line)
|
21
|
-
res = Jmeter::SummaryReport::ResultLine.new
|
22
|
-
res.timestamp = t.to_i
|
23
|
-
res.elapsed = e.to_i
|
24
|
-
res.label = l
|
25
|
-
res.error = (s == "false" ? true : false)
|
26
|
-
res.latency = lt.to_i
|
27
|
-
return res
|
28
|
-
end
|
29
|
-
|
30
|
-
def error?
|
31
|
-
self.error
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
data/test/test_report.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require File.expand_path('helper', File.dirname(__FILE__))
|
2
|
-
require 'jmeter/reports'
|
3
|
-
|
4
|
-
module Jmeter
|
5
|
-
module SummaryReport
|
6
|
-
class TestReport < MiniTest::Unit::TestCase
|
7
|
-
def setup
|
8
|
-
fixture = File.expand_path('fixtures/summary_report.csv', File.dirname(__FILE__))
|
9
|
-
@report = Report.create(fixture)
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_report_items
|
13
|
-
assert_equal 3, @report.items.size
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_avg_throughput
|
17
|
-
assert_equal 3, @report.avg_throughput
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_elapsed_in_ms
|
21
|
-
assert_equal 2719, @report.elapsed_in_ms
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_elapsed
|
25
|
-
assert_equal 3, @report.elapsed
|
26
|
-
end
|
27
|
-
|
28
|
-
def test_start_date
|
29
|
-
assert_equal Time.new(2012,12,11,12,47,32,"+00:00").to_i, @report.start_date.utc.to_i, 'invalid start date'
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_end_date
|
33
|
-
assert_equal Time.new(2012,12,11,12,47,34,"+00:00").to_i, @report.end_date.utc.to_i, 'invalid end date'
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
data/test/test_result_line.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
require File.expand_path('helper', File.dirname(__FILE__))
|
2
|
-
require 'jmeter/summary_report/result_line'
|
3
|
-
|
4
|
-
module Jmeter
|
5
|
-
module SummaryReport
|
6
|
-
class TestResultLine < MiniTest::Unit::TestCase
|
7
|
-
def test_parse_simple_error_line
|
8
|
-
assert ResultLine.parse('1355332336591,4850,POST execute,500,Internal Server Error,Thread Group 1-70,text,false,15535,75,75,http://stage.id.abril.com.br/widgets/login/execute,4847').error?
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_parse_transaction_error_line
|
12
|
-
assert ResultLine.parse('1355163053904,5933,Login,,"Number of samples in transaction : 2, number of failing samples : 1",Thread Group 1-15,,false,2836,20,20,null,0').error?
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|