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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c7d0976d2d56b7989f91253c752561a10d01ce12ba20b6a4fca377ea424c69a
4
- data.tar.gz: a41df011c54a846f949238cc89ab9a021f5d86281f1f18566bcb5963782397e9
3
+ metadata.gz: 6b330384292e5a4bcb8429d4e2d1e215a320692e526b53cdddfb8714b43538b6
4
+ data.tar.gz: 0a22281b9a7acc4dde3552be07a143420bd63648a380f6b2e5cd446cdcc36b54
5
5
  SHA512:
6
- metadata.gz: da313236dd4e1ab8078bac1267835b85303ba81129a5d469db198fd9fc65fae1f4decc0b0ad894878810bda3460feb4a84b76db637c4b1d1580457d48ea5e994
7
- data.tar.gz: ee2e2c89b3eef006a17362d18987bdc31f5269804814c890ccb2597517f0a67cee1ab1c80c6a05b6268c87930d6c56fc7f624d0427cf6764e2d11956efb16cce
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[:groups].each do |group|
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}) – #{group[:time].duration} (#{group[:count]} / #{group[:examples]})
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
- return unless profiler.results[:examples]
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
- profiler.results[:examples].each do |example|
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}) – #{example[:time].duration} (#{example[:count]})
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
@@ -5,7 +5,7 @@ require "test_prof/ext/float_duration"
5
5
  module TestProf
6
6
  # Make DB fixtures from blocks.
7
7
  module AnyFixture
8
- INSERT_RXP = /^INSERT INTO ([\S]+)/
8
+ INSERT_RXP = /^INSERT INTO ([\S]+)/.freeze
9
9
 
10
10
  using FloatDuration
11
11
 
@@ -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
- data = { id: id, time: @time, count: @count, examples: @total_examples }
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
- data = { id: id, time: @example_time, count: @example_count }
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}) – #{group[:time].duration} (#{group[:count]} / #{group[:examples]})
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}) – #{example[:time].duration} (#{example[:count]})
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
@@ -35,7 +35,7 @@ module TestProf
35
35
  \AROLLBACK|
36
36
  \ARELEASE|
37
37
  \ASAVEPOINT
38
- )}xi
38
+ )}xi.freeze
39
39
 
40
40
  class << self
41
41
  include TestProf::Logging
@@ -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
- def run(*)
14
- unless ENV['SAMPLE'].nil?
15
- sample_size = ENV['SAMPLE'].to_i
13
+ class << self
14
+ def suites
16
15
  # Make sure that sample contains only _real_ suites
17
- runnables = Minitest::Runnable.runnables
18
- .sample(sample_size + CORE_RUNNABLES.size)
19
- .reject { |suite| CORE_RUNNABLES.include?(suite) }
20
- .take(sample_size)
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
- runnables.each { |r| Minitest::Runnable.runnables << r }
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
- # Add ability to run only a specified number of example groups (randomly selected)
5
- module RSpecSample
6
- def ordered_example_groups
7
- @example_groups = @example_groups.sample(ENV['SAMPLE'].to_i) unless ENV['SAMPLE'].nil?
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
- RSpec::Core::World.prepend(TestProf::RSpecSample)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf
4
- VERSION = "0.7.2"
4
+ VERSION = "0.7.3"
5
5
  end
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.2
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-10-08 00:00:00.000000000 Z
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.59.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.59.0
82
+ version: 0.60.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rubocop-md
85
85
  requirement: !ruby/object:Gem::Requirement