rspec_log_formatter 0.0.1 → 0.1.0
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.
- checksums.yaml +8 -8
- data/lib/rspec_log_formatter/analysis/analyzer.rb +43 -8
- data/lib/rspec_log_formatter/analysis/pretty_printer.rb +9 -2
- data/lib/rspec_log_formatter/analyzer_formatter.rb +20 -0
- data/lib/rspec_log_formatter/formatter.rb +15 -18
- data/lib/rspec_log_formatter/version.rb +1 -1
- data/spec/lib/rspec_log_analyzer/analysis/analyzer_spec.rb +14 -0
- data/spec/lib/rspec_log_analyzer/analysis/pretty_printer_spec.rb +36 -1
- data/spec/lib/rspec_log_analyzer/analyzer_formatter_spec.rb +32 -0
- data/spec/lib/rspec_log_analyzer/formatter_spec.rb +49 -9
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NDA1NzQxMjZmZjU0ZWU3ZjkzZTRmMzIzNTYzM2Q1NTRiZTJiYTVkOA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NjhiY2JiNzgyMGEyZGFlOTIyZjk4NTZjZmU5NzFkODA3NjBlNGIwOQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NDE3M2RlZGExODYyNjc2ZGZmOGE4YjgxYzMxZDYzYTRlZWQwMGNjOGNiZGY5
|
10
|
+
MTlmOGIzYjE5ZDUyMWU0MjFjMjBhNjlkZjc0M2IzNzk3MWQ1MWVlYWQ0NTM0
|
11
|
+
ZmI3YzRlNjlhODcwZmZjYTQ2NGQxODU5ZTZhOWY2YWNiNjIwYjU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YTEwMTFlYzFjMTllODQ0NmQxZDU4Mjc1MDI4NzBhOTc2NGU4OWM1NDBhZmNk
|
14
|
+
YTNiYmY0MmYzZjdlMjMyYjc5YTgxNGE1YTk0YWZjOThiOTBmZDJlNmRkYjk1
|
15
|
+
ZTQ0NDEwNjNiZmU2OGRlZjY4MDNhMGYxMjAxNzU2ZmVhZjliNTY=
|
@@ -6,14 +6,7 @@ module RspecLogFormatter
|
|
6
6
|
def analyze(filepath, options = {})
|
7
7
|
window = options[:last_builds]
|
8
8
|
|
9
|
-
build_numbers =
|
10
|
-
results = File.open(filepath).each_line.map do |line|
|
11
|
-
result = Result.new(*CSV.parse_line(line, col_sep: "\t").first(7))
|
12
|
-
build_numbers << result.build_number
|
13
|
-
result
|
14
|
-
end
|
15
|
-
build_numbers.uniq!.sort!
|
16
|
-
|
9
|
+
build_numbers, results = result_numbers(filepath, options = {})
|
17
10
|
|
18
11
|
scores = []
|
19
12
|
results.group_by(&:description).each do |description, results|
|
@@ -33,6 +26,48 @@ module RspecLogFormatter
|
|
33
26
|
|
34
27
|
scores.sort.map(&:as_hash)
|
35
28
|
end
|
29
|
+
|
30
|
+
def truncate(filepath, opts = {})
|
31
|
+
builds = opts.fetch(:keep_builds)
|
32
|
+
build_numbers, results = result_numbers(filepath, options = {})
|
33
|
+
sio = StringIO.new
|
34
|
+
|
35
|
+
File.open(filepath, 'r').each_line do |line|
|
36
|
+
result = parse_line(line)
|
37
|
+
next unless build_numbers.last(builds).include? result.build_number
|
38
|
+
sio.puts line
|
39
|
+
end
|
40
|
+
|
41
|
+
sio.rewind
|
42
|
+
File.open(filepath, 'w') do |f|
|
43
|
+
f.write sio.read
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def parse_line(line)
|
50
|
+
Result.new(*CSV.parse_line(line, col_sep: "\t").first(7))
|
51
|
+
end
|
52
|
+
|
53
|
+
def each_result(filepath, &block)
|
54
|
+
File.open(filepath, 'r').each_line do |line|
|
55
|
+
result = parse_line(line)
|
56
|
+
block.call(result)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def result_numbers(filepath, options = {})
|
61
|
+
build_numbers = []
|
62
|
+
results = []
|
63
|
+
each_result(filepath) do |result|
|
64
|
+
build_numbers << result.build_number
|
65
|
+
results << result
|
66
|
+
end
|
67
|
+
[build_numbers.uniq.sort, results]
|
68
|
+
end
|
69
|
+
|
36
70
|
end
|
71
|
+
|
37
72
|
end
|
38
73
|
end
|
@@ -6,8 +6,15 @@ module RspecLogFormatter
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def to_s
|
9
|
-
results = @results.
|
10
|
-
|
9
|
+
results = @results.reject do |result|
|
10
|
+
result[:percent] == 0.0
|
11
|
+
end.first(10)
|
12
|
+
|
13
|
+
header = if results.empty?
|
14
|
+
"None of the specs were flaky"
|
15
|
+
else
|
16
|
+
"Top #{results.size} flakiest examples\n"
|
17
|
+
end
|
11
18
|
header + results.each_with_index.map do |result, i|
|
12
19
|
title = " #{i+1}) #{result[:description]} -- #{result[:percent]}%"
|
13
20
|
failure_messages = result[:failure_messages].map { |fm| " * #{fm}" }.join("\n")
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "csv"
|
2
|
+
require "rspec/core/formatters/base_formatter"
|
3
|
+
|
4
|
+
module RspecLogFormatter
|
5
|
+
class AnalyzerFormatter < RSpec::Core::Formatters::BaseFormatter
|
6
|
+
FILENAME = "rspec.history"
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def dump_summary(_,_,_,_)
|
14
|
+
output.puts RspecLogFormatter::Analysis::PrettyPrinter.new(
|
15
|
+
RspecLogFormatter::Analysis::Analyzer.new.analyze(FILENAME)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -5,23 +5,17 @@ module RspecLogFormatter
|
|
5
5
|
class Formatter < RSpec::Core::Formatters::BaseFormatter
|
6
6
|
FILENAME = "rspec.history"
|
7
7
|
|
8
|
-
class
|
9
|
-
def
|
10
|
-
|
8
|
+
class Maker
|
9
|
+
def new(_output)
|
10
|
+
RspecLogFormatter::Formatter.new(clock, opts)
|
11
11
|
end
|
12
|
-
def clock
|
13
|
-
@clock ||= Time
|
14
|
-
@clock
|
15
|
-
end
|
16
|
-
end
|
17
|
-
CONFIG = Config.new
|
18
|
-
|
19
|
-
def initialize(*args)
|
20
|
-
super
|
21
12
|
end
|
13
|
+
Factory = Maker.new
|
22
14
|
|
23
|
-
def
|
24
|
-
|
15
|
+
def initialize(clock=nil, opts={})
|
16
|
+
@clock = clock || Time
|
17
|
+
@build_number = opts[:build_number] || ENV["BUILD_NUMBER"]
|
18
|
+
@keep_builds = opts[:keep_builds]
|
25
19
|
end
|
26
20
|
|
27
21
|
def example_started(example)
|
@@ -36,11 +30,14 @@ module RspecLogFormatter
|
|
36
30
|
record("failed", example, clock.now, clock.now - @clock_start, example.exception)
|
37
31
|
end
|
38
32
|
|
33
|
+
def dump_summary(_,_,_,_)
|
34
|
+
return unless @keep_builds
|
35
|
+
RspecLogFormatter::Analysis::Analyzer.new.truncate(FILENAME, keep_builds: @keep_builds)
|
36
|
+
end
|
37
|
+
|
39
38
|
private
|
40
39
|
|
41
|
-
|
42
|
-
CONFIG.clock
|
43
|
-
end
|
40
|
+
attr_reader :clock
|
44
41
|
|
45
42
|
def record(outcome, example, time, duration, exception=nil)
|
46
43
|
if exception
|
@@ -53,7 +50,7 @@ module RspecLogFormatter
|
|
53
50
|
end
|
54
51
|
|
55
52
|
example_data = [
|
56
|
-
|
53
|
+
@build_number,
|
57
54
|
time,
|
58
55
|
outcome,
|
59
56
|
example.full_description.to_s.gsub(/\r|\n|\t/, " "),
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "spec_helper"
|
2
|
+
require 'tempfile'
|
2
3
|
|
3
4
|
describe RspecLogFormatter::Analysis::Analyzer do
|
4
5
|
it "sorts the parsed results by failure percentage" do
|
@@ -24,6 +25,19 @@ describe RspecLogFormatter::Analysis::Analyzer do
|
|
24
25
|
}
|
25
26
|
end
|
26
27
|
|
28
|
+
|
29
|
+
it "can truncate the log file" do
|
30
|
+
filepath = File.expand_path("../../../../fixtures/test_was_flaky_then_fixed.history", __FILE__)
|
31
|
+
temp = Tempfile.new('fixture')
|
32
|
+
FileUtils.copy(filepath, temp.path)
|
33
|
+
described_class.new.truncate(temp.path, keep_builds: 3)
|
34
|
+
File.open(temp.path, 'r').read.should == <<HEREDOC
|
35
|
+
5 2014-01-21 16:08:25 -0800 passed desc ./spec/m1k1_spec.rb
|
36
|
+
6 2014-01-21 16:08:25 -0800 passed desc ./spec/m1k1_spec.rb
|
37
|
+
7 2014-01-21 16:08:25 -0800 passed desc ./spec/m1k1_spec.rb
|
38
|
+
HEREDOC
|
39
|
+
end
|
40
|
+
|
27
41
|
it "can analyze only a window of builds" do
|
28
42
|
filepath = File.expand_path("../../../../fixtures/test_was_flaky_then_fixed.history", __FILE__)
|
29
43
|
subject.analyze(filepath, last_builds: 7).first.should == {
|
@@ -24,7 +24,7 @@ Top 2 flakiest examples
|
|
24
24
|
|
25
25
|
context "when there are more than 10 results" do
|
26
26
|
it "only prints the top 10" do
|
27
|
-
results = (1..
|
27
|
+
results = (1..11).map do |i|
|
28
28
|
{description: "hi#{i}", percent: 1, failure_messages: ["bye#{i}"]}
|
29
29
|
end
|
30
30
|
|
@@ -53,4 +53,39 @@ Top 10 flakiest examples
|
|
53
53
|
TEXT
|
54
54
|
end
|
55
55
|
end
|
56
|
+
|
57
|
+
it "only prints flaky specs" do
|
58
|
+
results = (1..7).map do |i|
|
59
|
+
{description: "hi#{i}", percent: 1, failure_messages: ["bye#{i}"]}
|
60
|
+
end + (8..10).map do |i|
|
61
|
+
{description: "hi#{i}", percent: 0.0, failure_messages: ["bye#{i}"]}
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
described_class.new(results).to_s.should == <<-TEXT.strip
|
66
|
+
Top 7 flakiest examples
|
67
|
+
1) hi1 -- 1%
|
68
|
+
* bye1
|
69
|
+
2) hi2 -- 1%
|
70
|
+
* bye2
|
71
|
+
3) hi3 -- 1%
|
72
|
+
* bye3
|
73
|
+
4) hi4 -- 1%
|
74
|
+
* bye4
|
75
|
+
5) hi5 -- 1%
|
76
|
+
* bye5
|
77
|
+
6) hi6 -- 1%
|
78
|
+
* bye6
|
79
|
+
7) hi7 -- 1%
|
80
|
+
* bye7
|
81
|
+
TEXT
|
82
|
+
end
|
83
|
+
|
84
|
+
it "only prints flaky specs" do
|
85
|
+
results = (1..11).map do |i|
|
86
|
+
{description: "hi#{i}", percent: 0, failure_messages: ["bye#{i}"]}
|
87
|
+
end
|
88
|
+
|
89
|
+
described_class.new(results).to_s.should == "None of the specs were flaky"
|
90
|
+
end
|
56
91
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RspecLogFormatter::Formatter do
|
4
|
+
|
5
|
+
|
6
|
+
it "works" do
|
7
|
+
filepath = File.expand_path("../../../fixtures/varying_flakiness.history", __FILE__)
|
8
|
+
FileUtils.cp(filepath, 'rspec.history')
|
9
|
+
out = StringIO.new
|
10
|
+
formatter = RspecLogFormatter::AnalyzerFormatter.new(out)
|
11
|
+
formatter.dump_summary(1,2,3,4)
|
12
|
+
out.rewind
|
13
|
+
out.read.should == <<HEREDOC
|
14
|
+
Top 3 flakiest examples
|
15
|
+
1) desc3 -- 75.0%
|
16
|
+
* ec10
|
17
|
+
msg10
|
18
|
+
* ec10
|
19
|
+
msg10
|
20
|
+
* ec10
|
21
|
+
msg10
|
22
|
+
2) desc2 -- 66.66666666666667%
|
23
|
+
* ec10
|
24
|
+
msg10
|
25
|
+
* ec10
|
26
|
+
msg10
|
27
|
+
3) desc1 -- 50.0%
|
28
|
+
* ec10
|
29
|
+
msg10
|
30
|
+
HEREDOC
|
31
|
+
end
|
32
|
+
end
|
@@ -10,25 +10,65 @@ describe RspecLogFormatter::Formatter do
|
|
10
10
|
}.merge(opts))
|
11
11
|
end
|
12
12
|
|
13
|
+
def formatter_for_build(build)
|
14
|
+
RspecLogFormatter::Formatter.new(double(now: Time.at(0)), keep_builds: 2, build_number: build)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "can truncate the log file" do
|
18
|
+
the_example = make_example
|
19
|
+
formatter = formatter_for_build(1)
|
20
|
+
formatter.example_started(the_example)
|
21
|
+
formatter.example_passed(the_example)
|
22
|
+
formatter.dump_summary(1,2,3,4)
|
23
|
+
|
24
|
+
formatter = formatter_for_build(2)
|
25
|
+
formatter.example_started(the_example)
|
26
|
+
formatter.example_passed(the_example)
|
27
|
+
formatter.dump_summary(1,2,3,4)
|
28
|
+
|
29
|
+
File.open(RspecLogFormatter::Formatter::FILENAME, 'r').read.should == <<HEREDOC
|
30
|
+
1 1969-12-31 16:00:00 -0800 passed description_1 path_1 0.0
|
31
|
+
2 1969-12-31 16:00:00 -0800 passed description_1 path_1 0.0
|
32
|
+
HEREDOC
|
33
|
+
|
34
|
+
formatter = formatter_for_build(3)
|
35
|
+
formatter.example_started(the_example)
|
36
|
+
formatter.example_passed(the_example)
|
37
|
+
formatter.dump_summary(1,2,3,4)
|
38
|
+
|
39
|
+
formatter = formatter_for_build(4)
|
40
|
+
formatter.example_started(the_example)
|
41
|
+
formatter.example_passed(the_example)
|
42
|
+
formatter.dump_summary(1,2,3,4)
|
43
|
+
|
44
|
+
File.open(RspecLogFormatter::Formatter::FILENAME, 'r').read.should == <<HEREDOC
|
45
|
+
3 1969-12-31 16:00:00 -0800 passed description_1 path_1 0.0
|
46
|
+
4 1969-12-31 16:00:00 -0800 passed description_1 path_1 0.0
|
47
|
+
HEREDOC
|
48
|
+
end
|
49
|
+
|
50
|
+
class FakeClock
|
51
|
+
def initialize(now)
|
52
|
+
self.now = now
|
53
|
+
end
|
54
|
+
attr_accessor :now
|
55
|
+
end
|
56
|
+
|
13
57
|
it "works" do
|
14
58
|
failed_example = make_example(exception: Exception.new("Error"))
|
15
59
|
passed_example = make_example(exception: nil)
|
16
60
|
time = Time.parse("2014-02-06 16:01:10")
|
17
|
-
clock =
|
18
|
-
RspecLogFormatter::Formatter
|
19
|
-
|
20
|
-
formatter = RspecLogFormatter::Formatter.new(StringIO.new)
|
61
|
+
clock = FakeClock.new(time)
|
62
|
+
formatter = RspecLogFormatter::Formatter.new(clock)
|
21
63
|
formatter.example_started(failed_example)
|
22
|
-
|
23
|
-
RspecLogFormatter::Formatter::CONFIG.clock = double(now: time + 5)
|
64
|
+
clock.now = time + 5
|
24
65
|
formatter.example_failed(failed_example)
|
25
66
|
|
26
67
|
formatter.example_started(passed_example)
|
27
|
-
|
28
|
-
RspecLogFormatter::Formatter::CONFIG.clock = double(now: time + 8)
|
68
|
+
clock.now = time + 8
|
29
69
|
formatter.example_passed(passed_example)
|
30
70
|
formatter.dump_summary(1,2,3,4)
|
31
|
-
File.open('rspec.history').readlines.should == [
|
71
|
+
File.open('rspec.history'). readlines.should == [
|
32
72
|
"\t2014-02-06 16:01:15 -0800\tfailed\tdescription_1\tpath_1\tError\tException\t5.0\n",
|
33
73
|
"\t2014-02-06 16:01:18 -0800\tpassed\tdescription_2\tpath_2\t\t\t3.0\n",
|
34
74
|
]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec_log_formatter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Serguei Filimonov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- lib/rspec_log_formatter/analysis/pretty_printer.rb
|
86
86
|
- lib/rspec_log_formatter/analysis/result.rb
|
87
87
|
- lib/rspec_log_formatter/analysis/score.rb
|
88
|
+
- lib/rspec_log_formatter/analyzer_formatter.rb
|
88
89
|
- lib/rspec_log_formatter/formatter.rb
|
89
90
|
- lib/rspec_log_formatter/version.rb
|
90
91
|
- rspec_log_formatter.gemspec
|
@@ -93,6 +94,7 @@ files:
|
|
93
94
|
- spec/fixtures/varying_flakiness.history
|
94
95
|
- spec/lib/rspec_log_analyzer/analysis/analyzer_spec.rb
|
95
96
|
- spec/lib/rspec_log_analyzer/analysis/pretty_printer_spec.rb
|
97
|
+
- spec/lib/rspec_log_analyzer/analyzer_formatter_spec.rb
|
96
98
|
- spec/lib/rspec_log_analyzer/formatter_spec.rb
|
97
99
|
- spec/spec_helper.rb
|
98
100
|
homepage: ''
|
@@ -125,5 +127,6 @@ test_files:
|
|
125
127
|
- spec/fixtures/varying_flakiness.history
|
126
128
|
- spec/lib/rspec_log_analyzer/analysis/analyzer_spec.rb
|
127
129
|
- spec/lib/rspec_log_analyzer/analysis/pretty_printer_spec.rb
|
130
|
+
- spec/lib/rspec_log_analyzer/analyzer_formatter_spec.rb
|
128
131
|
- spec/lib/rspec_log_analyzer/formatter_spec.rb
|
129
132
|
- spec/spec_helper.rb
|