test-prof 0.7.2 → 0.7.3
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 +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
|