test-prof 0.7.2 → 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/lib/minitest/event_prof_formatter.rb +24 -6
- data/lib/test_prof/any_fixture.rb +1 -1
- data/lib/test_prof/event_prof/profiler.rb +28 -4
- data/lib/test_prof/event_prof/rspec.rb +15 -3
- data/lib/test_prof/factory_doctor.rb +1 -1
- data/lib/test_prof/factory_prof/printers/simple.rb +8 -0
- data/lib/test_prof/recipes/minitest/sample.rb +31 -8
- data/lib/test_prof/recipes/rspec/sample.rb +33 -6
- data/lib/test_prof/rspec_stamp.rb +1 -1
- data/lib/test_prof/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b330384292e5a4bcb8429d4e2d1e215a320692e526b53cdddfb8714b43538b6
|
4
|
+
data.tar.gz: 0a22281b9a7acc4dde3552be07a143420bd63648a380f6b2e5cd446cdcc36b54
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4d008f6cfe0055fff132d6c31f440bbd9974e0294480498d76a57b1f39a49ea51a1145632d901de54bc3a18f6e4d6c317e565ddfca090ad4d905ec9ec7e7e5a
|
7
|
+
data.tar.gz: 001a18ff90644936cacff9e5a00858671e070ffe4b11a10921f4401ad29fb12b4de2d190fc92c7fbc3bb137e42a2eaa2a55945bf1b7c1fd88bcb87c2ded00f13
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,19 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 0.7.3 (2018-11-07)
|
6
|
+
|
7
|
+
- Add a header with the general information on factories usage [#99](https://github.com/palkan/test-prof/issues/99) ([@szemek][])
|
8
|
+
|
9
|
+
- Improve test sampling.([@mkldon][])
|
10
|
+
|
11
|
+
```bash
|
12
|
+
SAMPLE=10 rake test # runs 10 random test examples
|
13
|
+
SAMPLE_GROUPS=10 rake test # runs 10 random example groups
|
14
|
+
```
|
15
|
+
|
16
|
+
- Extend Event Prof formatter to include the absolute run time and the percentage of the event tim [#100](https://github.com/palkan/test-prof/issues/100) ([@dmagro][])
|
17
|
+
|
5
18
|
## 0.7.2 (2018-10-08)
|
6
19
|
|
7
20
|
- Add `RSpec/AggregateFailures` support for non-regular 'its' examples. ([@broels][])
|
@@ -368,3 +381,6 @@ Ensure output dir exists in `#artifact_path` method.
|
|
368
381
|
[@desoleary]: https://github.com/desoleary
|
369
382
|
[@rabotyaga]: https://github.com/rabotyaga
|
370
383
|
[@Vasfed]: https://github.com/Vasfed
|
384
|
+
[@szemek]: https://github.com/szemek
|
385
|
+
[@mkldon]: https://github.com/mkldon
|
386
|
+
[@dmagro]: https://github.com/dmagro
|
@@ -26,11 +26,13 @@ module Minitest
|
|
26
26
|
private
|
27
27
|
|
28
28
|
def total_results(profiler)
|
29
|
+
time_percentage = time_percentage(profiler.total_time, profiler.absolute_run_time)
|
30
|
+
|
29
31
|
@results <<
|
30
32
|
<<~MSG
|
31
33
|
EventProf results for #{profiler.event}
|
32
34
|
|
33
|
-
Total time: #{profiler.total_time.duration}
|
35
|
+
Total time: #{profiler.total_time.duration} of #{profiler.absolute_run_time.duration} (#{time_percentage}%)
|
34
36
|
Total events: #{profiler.total_count}
|
35
37
|
|
36
38
|
Top #{profiler.top_count} slowest suites (by #{profiler.rank_by}):
|
@@ -39,31 +41,47 @@ module Minitest
|
|
39
41
|
end
|
40
42
|
|
41
43
|
def by_groups(profiler)
|
42
|
-
profiler.results
|
44
|
+
result = profiler.results
|
45
|
+
groups = result[:groups]
|
46
|
+
|
47
|
+
groups.each do |group|
|
43
48
|
description = group[:id][:name]
|
44
49
|
location = group[:id][:location]
|
50
|
+
time = group[:time]
|
51
|
+
run_time = group[:run_time]
|
52
|
+
time_percentage = time_percentage(time, run_time)
|
45
53
|
|
46
54
|
@results <<
|
47
55
|
<<~GROUP
|
48
|
-
#{description.truncate} (#{location}) – #{
|
56
|
+
#{description.truncate} (#{location}) – #{time.duration} (#{group[:count]} / #{group[:examples]}) of #{run_time.duration} (#{time_percentage}%)
|
49
57
|
GROUP
|
50
58
|
end
|
51
59
|
end
|
52
60
|
|
53
61
|
def by_examples(profiler)
|
54
|
-
|
62
|
+
result = profiler.results
|
63
|
+
examples = result[:examples]
|
64
|
+
|
65
|
+
return unless examples
|
55
66
|
@results << "\nTop #{profiler.top_count} slowest tests (by #{profiler.rank_by}):\n\n"
|
56
67
|
|
57
|
-
|
68
|
+
examples.each do |example|
|
58
69
|
description = example[:id][:name]
|
59
70
|
location = example[:id][:location]
|
71
|
+
time = example[:time]
|
72
|
+
run_time = example[:run_time]
|
73
|
+
time_percentage = time_percentage(time, run_time)
|
60
74
|
|
61
75
|
@results <<
|
62
76
|
<<~GROUP
|
63
|
-
#{description.truncate} (#{location}) – #{
|
77
|
+
#{description.truncate} (#{location}) – #{time.duration} (#{example[:count]}) of #{run_time.duration} (#{time_percentage}%)
|
64
78
|
GROUP
|
65
79
|
end
|
66
80
|
end
|
81
|
+
|
82
|
+
def time_percentage(time, total_time)
|
83
|
+
(time / total_time * 100).round(2)
|
84
|
+
end
|
67
85
|
end
|
68
86
|
end
|
69
87
|
end
|
@@ -4,7 +4,7 @@ module TestProf
|
|
4
4
|
module EventProf
|
5
5
|
class Profiler # :nodoc:
|
6
6
|
attr_reader :event, :total_count, :total_time, :rank_by, :top_count, :per_example,
|
7
|
-
:time, :count, :example_time, :example_count
|
7
|
+
:time, :count, :example_time, :example_count, :absolute_run_time
|
8
8
|
|
9
9
|
alias per_example? per_example
|
10
10
|
|
@@ -26,6 +26,7 @@ module TestProf
|
|
26
26
|
|
27
27
|
@total_count = 0
|
28
28
|
@total_time = 0.0
|
29
|
+
@absolute_run_time = 0.0
|
29
30
|
end
|
30
31
|
|
31
32
|
def track(time)
|
@@ -48,7 +49,16 @@ module TestProf
|
|
48
49
|
end
|
49
50
|
|
50
51
|
def group_finished(id)
|
51
|
-
|
52
|
+
group_run_time = take_time(@group_ts)
|
53
|
+
@absolute_run_time += group_run_time
|
54
|
+
|
55
|
+
data = {
|
56
|
+
id: id,
|
57
|
+
time: @time,
|
58
|
+
run_time: group_run_time,
|
59
|
+
count: @count,
|
60
|
+
examples: @total_examples
|
61
|
+
}
|
52
62
|
|
53
63
|
@groups << data unless data[rank_by].zero?
|
54
64
|
|
@@ -65,19 +75,31 @@ module TestProf
|
|
65
75
|
@total_examples += 1
|
66
76
|
return unless per_example?
|
67
77
|
|
68
|
-
|
78
|
+
example_run_time = take_time(@example_ts)
|
79
|
+
data = {
|
80
|
+
id: id,
|
81
|
+
time: @example_time,
|
82
|
+
run_time: example_run_time,
|
83
|
+
count: @example_count
|
84
|
+
}
|
85
|
+
|
69
86
|
@examples << data unless data[rank_by].zero?
|
70
87
|
@current_example = nil
|
71
88
|
end
|
72
89
|
|
73
90
|
def results
|
74
|
-
{
|
91
|
+
results = {
|
75
92
|
groups: @groups.to_a
|
76
93
|
}.tap do |data|
|
77
94
|
next unless per_example?
|
78
95
|
|
79
96
|
data[:examples] = @examples.to_a
|
80
97
|
end
|
98
|
+
results
|
99
|
+
end
|
100
|
+
|
101
|
+
def take_time(start_ts)
|
102
|
+
TestProf.now - start_ts
|
81
103
|
end
|
82
104
|
|
83
105
|
private
|
@@ -86,11 +108,13 @@ module TestProf
|
|
86
108
|
@time = 0.0
|
87
109
|
@count = 0
|
88
110
|
@total_examples = 0
|
111
|
+
@group_ts = TestProf.now
|
89
112
|
end
|
90
113
|
|
91
114
|
def reset_example!
|
92
115
|
@example_count = 0
|
93
116
|
@example_time = 0.0
|
117
|
+
@example_ts = TestProf.now
|
94
118
|
end
|
95
119
|
end
|
96
120
|
|
@@ -54,6 +54,7 @@ module TestProf
|
|
54
54
|
|
55
55
|
def report(profiler)
|
56
56
|
result = profiler.results
|
57
|
+
time_percentage = time_percentage(profiler.total_time, profiler.absolute_run_time)
|
57
58
|
|
58
59
|
msgs = []
|
59
60
|
|
@@ -61,7 +62,7 @@ module TestProf
|
|
61
62
|
<<~MSG
|
62
63
|
EventProf results for #{profiler.event}
|
63
64
|
|
64
|
-
Total time: #{profiler.total_time.duration}
|
65
|
+
Total time: #{profiler.total_time.duration} of #{profiler.absolute_run_time.duration} (#{time_percentage}%)
|
65
66
|
Total events: #{profiler.total_count}
|
66
67
|
|
67
68
|
Top #{profiler.top_count} slowest suites (by #{profiler.rank_by}):
|
@@ -71,10 +72,13 @@ module TestProf
|
|
71
72
|
result[:groups].each do |group|
|
72
73
|
description = group[:id].top_level_description
|
73
74
|
location = group[:id].metadata[:location]
|
75
|
+
time = group[:time]
|
76
|
+
run_time = group[:run_time]
|
77
|
+
time_percentage = time_percentage(time, run_time)
|
74
78
|
|
75
79
|
msgs <<
|
76
80
|
<<~GROUP
|
77
|
-
#{description.truncate} (#{location}) – #{
|
81
|
+
#{description.truncate} (#{location}) – #{time.duration} (#{group[:count]} / #{group[:examples]}) of #{run_time.duration} (#{time_percentage}%)
|
78
82
|
GROUP
|
79
83
|
end
|
80
84
|
|
@@ -84,9 +88,13 @@ module TestProf
|
|
84
88
|
result[:examples].each do |example|
|
85
89
|
description = example[:id].description
|
86
90
|
location = example[:id].metadata[:location]
|
91
|
+
time = example[:time]
|
92
|
+
run_time = example[:run_time]
|
93
|
+
time_percentage = time_percentage(time, run_time)
|
94
|
+
|
87
95
|
msgs <<
|
88
96
|
<<~GROUP
|
89
|
-
#{description.truncate} (#{location}) – #{
|
97
|
+
#{description.truncate} (#{location}) – #{time.duration} (#{example[:count]}) of #{run_time.duration} (#{time_percentage}%)
|
90
98
|
GROUP
|
91
99
|
end
|
92
100
|
end
|
@@ -128,6 +136,10 @@ module TestProf
|
|
128
136
|
|
129
137
|
log :info, msgs.join
|
130
138
|
end
|
139
|
+
|
140
|
+
def time_percentage(time, total_time)
|
141
|
+
(time / total_time * 100).round(2)
|
142
|
+
end
|
131
143
|
end
|
132
144
|
end
|
133
145
|
end
|
@@ -10,10 +10,18 @@ module TestProf::FactoryProf
|
|
10
10
|
return log(:info, "No factories detected") if result.raw_stats == {}
|
11
11
|
msgs = []
|
12
12
|
|
13
|
+
total = result.stats.sum { |stat| stat[:total] }
|
14
|
+
total_top_level = result.stats.sum { |stat| stat[:top_level] }
|
15
|
+
total_uniq_factories = result.stats.map { |stat| stat[:name] }.uniq.count
|
16
|
+
|
13
17
|
msgs <<
|
14
18
|
<<~MSG
|
15
19
|
Factories usage
|
16
20
|
|
21
|
+
Total: #{total}
|
22
|
+
Total top-level: #{total_top_level}
|
23
|
+
Total uniq factories: #{total_uniq_factories}
|
24
|
+
|
17
25
|
total top-level name
|
18
26
|
MSG
|
19
27
|
|
@@ -10,16 +10,39 @@ module TestProf
|
|
10
10
|
Minitest::Spec
|
11
11
|
].freeze
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
sample_size = ENV['SAMPLE'].to_i
|
13
|
+
class << self
|
14
|
+
def suites
|
16
15
|
# Make sure that sample contains only _real_ suites
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
Minitest::Runnable.runnables
|
17
|
+
.reject { |suite| CORE_RUNNABLES.include?(suite) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def sample_groups(sample_size)
|
21
|
+
saved_suites = suites
|
21
22
|
Minitest::Runnable.reset
|
22
|
-
|
23
|
+
saved_suites.sample(sample_size).each { |r| Minitest::Runnable.runnables << r }
|
24
|
+
end
|
25
|
+
|
26
|
+
def sample_examples(sample_size)
|
27
|
+
all_examples = suites.flat_map do |runnable|
|
28
|
+
runnable.runnable_methods.map { |method| [runnable, method] }
|
29
|
+
end
|
30
|
+
sample = all_examples.sample(sample_size)
|
31
|
+
# Filter examples by overriding #runnable_methods for all suites
|
32
|
+
suites.each do |runnable|
|
33
|
+
runnable.define_singleton_method(:runnable_methods) do
|
34
|
+
super() & sample.select { |ex| ex.first.equal?(runnable) }.map(&:last)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Overrides Minitest.run
|
41
|
+
def run(*)
|
42
|
+
if ENV['SAMPLE']
|
43
|
+
MinitestSample.sample_examples(ENV['SAMPLE'].to_i)
|
44
|
+
elsif ENV['SAMPLE_GROUPS']
|
45
|
+
MinitestSample.sample_groups(ENV['SAMPLE_GROUPS'].to_i)
|
23
46
|
end
|
24
47
|
super
|
25
48
|
end
|
@@ -1,13 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module TestProf
|
4
|
-
#
|
5
|
-
module
|
6
|
-
def
|
7
|
-
@
|
8
|
-
super
|
4
|
+
# Instance variable writer for RSpec::Core::World
|
5
|
+
module RSpecWorldSamplePatch
|
6
|
+
def filtered_examples=(val)
|
7
|
+
@filtered_examples = val
|
9
8
|
end
|
10
9
|
end
|
11
10
|
end
|
12
11
|
|
13
|
-
|
12
|
+
if ENV["SAMPLE"]
|
13
|
+
RSpec::Core::World.include(TestProf::RSpecWorldSamplePatch)
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.before(:suite) do
|
17
|
+
filtered_examples = RSpec.world.filtered_examples.values.flatten
|
18
|
+
sample = filtered_examples.sample(ENV["SAMPLE"].to_i)
|
19
|
+
RSpec.world.filtered_examples = Hash.new do |hash, group|
|
20
|
+
hash[group] = group.examples & sample
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if ENV["SAMPLE_GROUPS"]
|
27
|
+
RSpec::Core::World.include(TestProf::RSpecWorldSamplePatch)
|
28
|
+
|
29
|
+
RSpec.configure do |config|
|
30
|
+
config.before(:suite) do
|
31
|
+
filtered_groups = RSpec.world.filtered_examples.reject do |_group, examples|
|
32
|
+
examples.empty?
|
33
|
+
end.keys
|
34
|
+
sample = filtered_groups.sample(ENV["SAMPLE_GROUPS"].to_i)
|
35
|
+
RSpec.world.filtered_examples = Hash.new do |hash, group|
|
36
|
+
hash[group] = sample.include?(group) ? group.examples : []
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -6,7 +6,7 @@ require "test_prof/rspec_stamp/parser"
|
|
6
6
|
module TestProf
|
7
7
|
# Mark RSpec examples with provided tags
|
8
8
|
module RSpecStamp
|
9
|
-
EXAMPLE_RXP = /(\s*)(\w+\s*(?:.*)\s*)(do|{)
|
9
|
+
EXAMPLE_RXP = /(\s*)(\w+\s*(?:.*)\s*)(do|{)/.freeze
|
10
10
|
|
11
11
|
# RSpecStamp configuration
|
12
12
|
class Configuration
|
data/lib/test_prof/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: test-prof
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladimir Dementyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0.
|
75
|
+
version: 0.60.0
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.
|
82
|
+
version: 0.60.0
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rubocop-md
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|