test-prof 1.3.0 → 1.4.4

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +78 -0
  3. data/README.md +2 -2
  4. data/lib/minitest/test_prof_plugin.rb +3 -0
  5. data/lib/test_prof/any_fixture/dsl.rb +19 -1
  6. data/lib/test_prof/any_fixture/dump.rb +1 -1
  7. data/lib/test_prof/any_fixture.rb +16 -2
  8. data/lib/test_prof/before_all/adapters/active_record.rb +82 -47
  9. data/lib/test_prof/before_all/isolator.rb +6 -15
  10. data/lib/test_prof/before_all.rb +31 -8
  11. data/lib/test_prof/cops/rspec/aggregate_examples/its.rb +2 -2
  12. data/lib/test_prof/cops/rspec/aggregate_examples/line_range_helpers.rb +1 -1
  13. data/lib/test_prof/cops/rspec/aggregate_examples/matchers_with_side_effects.rb +1 -1
  14. data/lib/test_prof/cops/rspec/aggregate_examples/metadata_helpers.rb +1 -1
  15. data/lib/test_prof/cops/rspec/aggregate_examples/node_matchers.rb +1 -1
  16. data/lib/test_prof/cops/rspec/aggregate_examples.rb +12 -18
  17. data/lib/test_prof/core.rb +28 -1
  18. data/lib/test_prof/event_prof/monitor.rb +3 -10
  19. data/lib/test_prof/ext/active_record_refind.rb +1 -1
  20. data/lib/test_prof/ext/string_truncate.rb +1 -1
  21. data/lib/test_prof/factory_bot.rb +2 -0
  22. data/lib/test_prof/factory_default/fabrication_patch.rb +60 -0
  23. data/lib/test_prof/factory_default/factory_bot_patch.rb +59 -9
  24. data/lib/test_prof/factory_default.rb +11 -39
  25. data/lib/test_prof/factory_doctor.rb +1 -2
  26. data/lib/test_prof/factory_prof/fabrication_patch.rb +7 -1
  27. data/lib/test_prof/factory_prof/factory_bot_patch.rb +15 -1
  28. data/lib/test_prof/factory_prof/factory_builders/fabrication.rb +2 -2
  29. data/lib/test_prof/factory_prof/factory_builders/factory_bot.rb +2 -2
  30. data/lib/test_prof/factory_prof/printers/json.rb +41 -0
  31. data/lib/test_prof/factory_prof/printers/nate_heckler.rb +1 -1
  32. data/lib/test_prof/factory_prof/printers/simple.rb +23 -4
  33. data/lib/test_prof/factory_prof.rb +57 -25
  34. data/lib/test_prof/memory_prof/printer.rb +2 -0
  35. data/lib/test_prof/memory_prof/rspec.rb +7 -4
  36. data/lib/test_prof/memory_prof/tracker/linked_list.rb +8 -6
  37. data/lib/test_prof/memory_prof/tracker.rb +14 -10
  38. data/lib/test_prof/recipes/minitest/before_all.rb +2 -2
  39. data/lib/test_prof/recipes/minitest/sample.rb +14 -5
  40. data/lib/test_prof/recipes/rspec/any_fixture.rb +8 -0
  41. data/lib/test_prof/recipes/rspec/let_it_be.rb +19 -0
  42. data/lib/test_prof/rspec_stamp/parser.rb +1 -1
  43. data/lib/test_prof/rspec_stamp.rb +7 -5
  44. data/lib/test_prof/ruby_prof/rspec_no_boot.rb +15 -0
  45. data/lib/test_prof/ruby_prof.rb +20 -7
  46. data/lib/test_prof/tag_prof/minitest.rb +74 -0
  47. data/lib/test_prof/tag_prof/result.rb +2 -2
  48. data/lib/test_prof/tps_prof/profiler.rb +55 -0
  49. data/lib/test_prof/tps_prof/reporter/text.rb +48 -0
  50. data/lib/test_prof/tps_prof/rspec.rb +63 -0
  51. data/lib/test_prof/tps_prof.rb +46 -0
  52. data/lib/test_prof/vernier.rb +3 -1
  53. data/lib/test_prof/version.rb +1 -1
  54. data/lib/test_prof.rb +1 -0
  55. metadata +15 -7
@@ -36,22 +36,26 @@ module TestProf
36
36
  @total_memory = node.total_memory
37
37
  end
38
38
 
39
- def example_started(example)
40
- list.add_node(example, track)
39
+ def example_started(id, example = id)
40
+ list.add_node(id, example, track)
41
41
  end
42
42
 
43
- def example_finished(example)
44
- node = list.remove_node(example, track)
45
- examples << {**example, memory: node.total_memory}
43
+ def example_finished(id)
44
+ node = list.remove_node(id, track)
45
+ return unless node
46
+
47
+ examples << {**node.item, memory: node.total_memory}
46
48
  end
47
49
 
48
- def group_started(group)
49
- list.add_node(group, track)
50
+ def group_started(id, group = id)
51
+ list.add_node(id, group, track)
50
52
  end
51
53
 
52
- def group_finished(group)
53
- node = list.remove_node(group, track)
54
- groups << {**group, memory: node.hooks_memory}
54
+ def group_finished(id)
55
+ node = list.remove_node(id, track)
56
+ return unless node
57
+
58
+ groups << {**node.item, memory: node.hooks_memory}
55
59
  end
56
60
  end
57
61
 
@@ -104,7 +104,7 @@ module TestProf
104
104
  if base.respond_to?(:parallelize_teardown)
105
105
  base.parallelize_teardown do
106
106
  last_klass = ::Minitest.previous_klass
107
- if last_klass&.respond_to?(:parallelized) && last_klass&.parallelized
107
+ if last_klass&.respond_to?(:parallelized) && last_klass.parallelized
108
108
  last_klass.before_all_executor&.deactivate!
109
109
  end
110
110
  end
@@ -114,7 +114,7 @@ module TestProf
114
114
  base.singleton_class.prepend(Module.new do
115
115
  def parallelize(workers: :number_of_processors, with: :processes)
116
116
  # super.parallelize returns nil when no parallelization is set up
117
- if super(workers: workers, with: with).nil?
117
+ if super.nil?
118
118
  return
119
119
  end
120
120
 
@@ -7,14 +7,16 @@ module TestProf
7
7
  CORE_RUNNABLES = [
8
8
  Minitest::Test,
9
9
  defined?(Minitest::Unit::TestCase) ? Minitest::Unit::TestCase : nil,
10
- Minitest::Spec
10
+ defined?(Minitest::Spec) ? Minitest::Spec : nil
11
11
  ].compact.freeze
12
12
 
13
13
  class << self
14
14
  def suites
15
15
  # Make sure that sample contains only _real_ suites
16
16
  Minitest::Runnable.runnables
17
- .reject { |suite| CORE_RUNNABLES.include?(suite) }
17
+ .select do |suite|
18
+ CORE_RUNNABLES.any? { |kl| suite < kl } && suite.runnable_methods.any?
19
+ end
18
20
  end
19
21
 
20
22
  def sample_groups(sample_size)
@@ -27,11 +29,18 @@ module TestProf
27
29
  all_examples = suites.flat_map do |runnable|
28
30
  runnable.runnable_methods.map { |method| [runnable, method] }
29
31
  end
30
- sample = all_examples.sample(sample_size)
32
+
33
+ sample = all_examples.sample(sample_size).group_by(&:first)
34
+ sample.transform_values! { |v| v.map(&:last) }
35
+
31
36
  # Filter examples by overriding #runnable_methods for all suites
32
37
  suites.each do |runnable|
33
- runnable.define_singleton_method(:runnable_methods) do
34
- super() & sample.select { |ex| ex.first.equal?(runnable) }.map(&:last)
38
+ if sample.key?(runnable)
39
+ runnable.define_singleton_method(:runnable_methods) do
40
+ super() & sample[runnable]
41
+ end
42
+ else
43
+ runnable.define_singleton_method(:runnable_methods) { [] }
35
44
  end
36
45
  end
37
46
  end
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "test_prof/any_fixture"
4
+ require "test_prof/any_fixture/dsl"
5
+ require "test_prof/ext/active_record_refind"
6
+
4
7
  require "test_prof/recipes/rspec/before_all"
5
8
 
6
9
  RSpec.shared_context "any_fixture:clean" do
@@ -8,6 +11,11 @@ RSpec.shared_context "any_fixture:clean" do
8
11
 
9
12
  before_all do
10
13
  TestProf::AnyFixture.clean
14
+ TestProf::AnyFixture.disable!
15
+ end
16
+
17
+ after(:all) do
18
+ TestProf::AnyFixture.enable!
11
19
  end
12
20
  end
13
21
 
@@ -7,6 +7,8 @@ module TestProf
7
7
  # Just like `let`, but persist the result for the whole group.
8
8
  # NOTE: Experimental and magical, for more control use `before_all`.
9
9
  module LetItBe
10
+ class DuplicationError < StandardError; end
11
+
10
12
  Modifier = Struct.new(:scope, :block) do
11
13
  def call(record, config)
12
14
  block.call(record, config)
@@ -14,6 +16,8 @@ module TestProf
14
16
  end
15
17
 
16
18
  class Configuration
19
+ attr_accessor :report_duplicates
20
+
17
21
  # Define an alias for `let_it_be` with the predefined options:
18
22
  #
19
23
  # TestProf::LetItBe.configure do |config|
@@ -117,6 +121,8 @@ module TestProf
117
121
  instance_variable_get(:"#{PREFIX}#{identifier}")
118
122
  end
119
123
 
124
+ report_duplicates(identifier) if LetItBe.config.report_duplicates
125
+
120
126
  LetItBe.module_for(self).module_eval do
121
127
  define_method(identifier) do
122
128
  # Trying to detect the context
@@ -135,6 +141,19 @@ module TestProf
135
141
  let(identifier, &let_accessor)
136
142
  end
137
143
 
144
+ private def report_duplicates(identifier)
145
+ if instance_methods.include?(identifier) && File.basename(__FILE__) == File.basename(instance_method(identifier).source_location[0])
146
+ error_msg = "let_it_be(:#{identifier}) was redefined in nested group"
147
+ report_level = LetItBe.config.report_duplicates.to_sym
148
+
149
+ if report_level == :warn
150
+ ::RSpec.warn_with(error_msg)
151
+ elsif report_level == :raise
152
+ raise DuplicationError, error_msg
153
+ end
154
+ end
155
+ end
156
+
138
157
  module Freezer
139
158
  # Stoplist to prevent freezing objects and theirs associations that are defined
140
159
  # with `let_it_be`'s `freeze: false` options during deep freezing.
@@ -143,7 +143,7 @@ module TestProf
143
143
  elsif expr.first == :@const
144
144
  expr[1]
145
145
  elsif expr.first == :const_path_ref
146
- expr[1..-1].map(&method(:parse_const)).join("::")
146
+ expr[1..].map(&method(:parse_const)).join("::")
147
147
  end
148
148
  end
149
149
  end
@@ -153,14 +153,16 @@ module TestProf
153
153
  end
154
154
  end
155
155
 
156
- replacement = "\\1#{parsed.fname}#{need_parens ? "(" : " "}" \
157
- "#{[desc, tags_str, htags_str].compact.join(", ")}" \
158
- "#{need_parens ? ") " : " "}\\3"
156
+ replacement = proc do
157
+ $1 + "#{parsed.fname}#{need_parens ? "(" : " "}" \
158
+ "#{[desc, tags_str, htags_str].compact.join(", ")}" \
159
+ "#{need_parens ? ") " : " "}" + $3
160
+ end
159
161
 
160
162
  if config.dry_run?
161
- log :info, "Patched: #{example.sub(EXAMPLE_RXP, replacement)}"
163
+ log :info, "Patched: #{example.sub(EXAMPLE_RXP, &replacement)}"
162
164
  else
163
- example.sub!(EXAMPLE_RXP, replacement)
165
+ example.sub!(EXAMPLE_RXP, &replacement)
164
166
  end
165
167
  true
166
168
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.configure do |config|
4
+ report = nil
5
+
6
+ config.append_before(:suite) do
7
+ report = TestProf::RubyProf.profile(locked: true)
8
+
9
+ TestProf.log :info, "RubyProf enabled for examples"
10
+ end
11
+
12
+ config.after(:suite) do
13
+ report&.dump("examples")
14
+ end
15
+ end
@@ -48,12 +48,13 @@ module TestProf
48
48
  attr_accessor :printer, :mode, :min_percent,
49
49
  :include_threads, :exclude_common_methods,
50
50
  :test_prof_exclusions_enabled,
51
- :custom_exclusions
51
+ :custom_exclusions, :skip_boot
52
52
 
53
53
  def initialize
54
54
  @printer = ENV["TEST_RUBY_PROF"].to_sym if PRINTERS.key?(ENV["TEST_RUBY_PROF"])
55
55
  @printer ||= ENV.fetch("TEST_RUBY_PROF_PRINTER", :flat).to_sym
56
56
  @mode = ENV.fetch("TEST_RUBY_PROF_MODE", :wall).to_s
57
+ @skip_boot = %w[0 false f].include?(ENV["TEST_RUBY_PROF_BOOT"])
57
58
  @min_percent = 1
58
59
  @include_threads = false
59
60
  @exclude_common_methods = true
@@ -65,6 +66,10 @@ module TestProf
65
66
  include_threads == true
66
67
  end
67
68
 
69
+ def skip_boot?
70
+ skip_boot == true
71
+ end
72
+
68
73
  def exclude_common_methods?
69
74
  exclude_common_methods == true
70
75
  end
@@ -166,23 +171,21 @@ module TestProf
166
171
  #
167
172
  # Use this method to profile the whole run.
168
173
  def run
169
- report = profile
174
+ report = profile(locked: true)
170
175
 
171
176
  return unless report
172
177
 
173
- @locked = true
174
-
175
178
  log :info, "RubyProf enabled globally"
176
179
 
177
180
  at_exit { report.dump("total") }
178
181
  end
179
182
 
180
- def profile
183
+ def profile(locked: false)
181
184
  if locked?
182
185
  log :warn, <<~MSG
183
186
  RubyProf is activated globally, you cannot generate per-example report.
184
187
 
185
- Make sure you haven't set the TEST_RUBY_PROF environmental variable.
188
+ Make sure you haven not set the TEST_RUBY_PROF environmental variable.
186
189
  MSG
187
190
  return
188
191
  end
@@ -212,6 +215,8 @@ module TestProf
212
215
 
213
216
  profiler.start
214
217
 
218
+ @locked = true if locked
219
+
215
220
  Report.new(profiler)
216
221
  end
217
222
 
@@ -282,5 +287,13 @@ end
282
287
 
283
288
  # Hook to run RubyProf globally
284
289
  TestProf.activate("TEST_RUBY_PROF") do
285
- TestProf::RubyProf.run
290
+ if TestProf::RubyProf.config.skip_boot?
291
+ if TestProf.rspec?
292
+ require "test_prof/ruby_prof/rspec_no_boot"
293
+ else
294
+ TestProf.log :warn, "RubyProf tests profiling w/o test suite boot is only supported in RSpec"
295
+ end
296
+ else
297
+ TestProf::RubyProf.run
298
+ end
286
299
  end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Minitest
4
+ module TestProf
5
+ class TagProfReporter < BaseReporter # :nodoc:
6
+ attr_reader :results
7
+
8
+ def initialize(io = $stdout, _options = {})
9
+ super
10
+ @results = ::TestProf::TagProf::Result.new("type")
11
+
12
+ if event_prof_activated?
13
+ require "test_prof/event_prof"
14
+ @current_group_id = nil
15
+ @events_profiler = configure_profiler
16
+ @results = ::TestProf::TagProf::Result.new("type", @events_profiler.events)
17
+ end
18
+ end
19
+
20
+ def prerecord(group, example)
21
+ return unless event_prof_activated?
22
+
23
+ # enable event profiling
24
+ @events_profiler.group_started(true)
25
+ end
26
+
27
+ def record(result)
28
+ results.track(main_folder_path(result), time: result.time, events: fetch_events_data)
29
+ @events_profiler.group_started(nil) if event_prof_activated? # reset and disable event profilers
30
+ end
31
+
32
+ def report
33
+ printer = (ENV["TAG_PROF_FORMAT"] == "html") ? ::TestProf::TagProf::Printers::HTML : ::TestProf::TagProf::Printers::Simple
34
+ printer.dump(results)
35
+ end
36
+
37
+ private
38
+
39
+ def main_folder_path(result)
40
+ return :__unknown__ if absolute_path_from(result).nil?
41
+
42
+ absolute_path_from(result)
43
+ end
44
+
45
+ def absolute_path_from(result)
46
+ absolute_path = File.expand_path(result.source_location.first)
47
+ absolute_path.slice(/(?<=(?:spec|test)\/)\w*/)
48
+ end
49
+
50
+ def configure_profiler
51
+ ::TestProf::EventProf::CustomEvents.activate_all(tag_prof_event)
52
+ ::TestProf::EventProf.build(tag_prof_event)
53
+ end
54
+
55
+ def event_prof_activated?
56
+ return false if tag_prof_event.nil?
57
+
58
+ !tag_prof_event.empty?
59
+ end
60
+
61
+ def tag_prof_event
62
+ ENV["TAG_PROF_EVENT"]
63
+ end
64
+
65
+ def fetch_events_data
66
+ return {} unless @events_profiler
67
+
68
+ @events_profiler.profilers.map do |profiler|
69
+ [profiler.event, profiler.time || 0.0]
70
+ end.to_h
71
+ end
72
+ end
73
+ end
74
+ end
@@ -21,8 +21,8 @@ module TestProf
21
21
  def track(tag, time:, events: {})
22
22
  data[tag][:count] += 1
23
23
  data[tag][:time] += time
24
- events.each do |k, v|
25
- data[tag][k] += v
24
+ events.each do |event, time|
25
+ data[tag][event] += time
26
26
  end
27
27
  end
28
28
 
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_prof/utils/sized_ordered_set"
4
+
5
+ module TestProf
6
+ module TPSProf
7
+ class Profiler
8
+ attr_reader :top_count, :groups, :total_count, :total_time, :threshold
9
+
10
+ def initialize(top_count, threshold: 10)
11
+ @threshold = threshold
12
+ @top_count = top_count
13
+ @total_count = 0
14
+ @total_time = 0.0
15
+ @groups = Utils::SizedOrderedSet.new(top_count, sort_by: :tps)
16
+ end
17
+
18
+ def group_started(id)
19
+ @current_group = id
20
+ @examples_count = 0
21
+ @examples_time = 0.0
22
+ @group_started_at = TestProf.now
23
+ end
24
+
25
+ def group_finished(id)
26
+ return unless @examples_count >= threshold
27
+
28
+ # Context-time
29
+ group_time = (TestProf.now - @group_started_at) - @examples_time
30
+ run_time = @examples_time + group_time
31
+
32
+ groups << {
33
+ id: id,
34
+ run_time: run_time,
35
+ group_time: group_time,
36
+ count: @examples_count,
37
+ tps: -(@examples_count / run_time).round(2)
38
+ }
39
+ end
40
+
41
+ def example_started(id)
42
+ @example_started_at = TestProf.now
43
+ end
44
+
45
+ def example_finished(id)
46
+ @examples_count += 1
47
+ @total_count += 1
48
+
49
+ time = (TestProf.now - @example_started_at)
50
+ @examples_time += time
51
+ @total_time += time
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_prof/ext/float_duration"
4
+ require "test_prof/ext/string_truncate"
5
+
6
+ module TestProf
7
+ module TPSProf
8
+ module Reporter
9
+ class Text
10
+ include Logging
11
+ using FloatDuration
12
+ using StringTruncate
13
+
14
+ def print(profiler)
15
+ groups = profiler.groups
16
+
17
+ total_tps = (profiler.total_count / profiler.total_time).round(2)
18
+
19
+ msgs = []
20
+
21
+ msgs <<
22
+ <<~MSG
23
+ Total TPS (tests per second): #{total_tps}
24
+
25
+ Top #{profiler.top_count} slowest suites by TPS (tests per second) (min examples per group: #{profiler.threshold}):
26
+
27
+ MSG
28
+
29
+ groups.each do |group|
30
+ description = group[:id].top_level_description
31
+ location = group[:id].metadata[:location]
32
+ time = group[:run_time]
33
+ group_time = group[:group_time]
34
+ count = group[:count]
35
+ tps = -group[:tps]
36
+
37
+ msgs <<
38
+ <<~GROUP
39
+ #{description.truncate} (#{location}) – #{tps} TPS (#{time.duration} / #{count}), group time: #{group_time.duration}
40
+ GROUP
41
+ end
42
+
43
+ log :info, msgs.join
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TestProf
4
+ module TPSProf
5
+ class RSpecListener # :nodoc:
6
+ include Logging
7
+
8
+ NOTIFICATIONS = %i[
9
+ example_group_started
10
+ example_group_finished
11
+ example_started
12
+ example_finished
13
+ ].freeze
14
+
15
+ attr_reader :reporter, :profiler
16
+
17
+ def initialize
18
+ @profiler = Profiler.new(TPSProf.config.top_count, threshold: TPSProf.config.threshold)
19
+ @reporter = TPSProf.config.reporter
20
+
21
+ log :info, "TPSProf enabled (top-#{TPSProf.config.top_count})"
22
+ end
23
+
24
+ def example_group_started(notification)
25
+ return unless notification.group.top_level?
26
+ profiler.group_started notification.group
27
+ end
28
+
29
+ def example_group_finished(notification)
30
+ return unless notification.group.top_level?
31
+ profiler.group_finished notification.group
32
+ end
33
+
34
+ def example_started(notification)
35
+ profiler.example_started notification.example
36
+ end
37
+
38
+ def example_finished(notification)
39
+ profiler.example_finished notification.example
40
+ end
41
+
42
+ def print
43
+ reporter.print(profiler)
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ # Register TPSProf listener
50
+ TestProf.activate("TPS_PROF") do
51
+ RSpec.configure do |config|
52
+ listener = nil
53
+
54
+ config.before(:suite) do
55
+ listener = TestProf::TPSProf::RSpecListener.new
56
+ config.reporter.register_listener(
57
+ listener, *TestProf::TPSProf::RSpecListener::NOTIFICATIONS
58
+ )
59
+ end
60
+
61
+ config.after(:suite) { listener&.print }
62
+ end
63
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_prof/tps_prof/profiler"
4
+ require "test_prof/tps_prof/reporter/text"
5
+
6
+ module TestProf
7
+ # TPSProf shows top-N example group based on their tests-per-second value.
8
+ #
9
+ # Example:
10
+ #
11
+ # TPS_PROF=10 rspec ...
12
+ #
13
+ module TPSProf
14
+ class Configuration
15
+ attr_accessor :top_count, :threshold, :reporter
16
+
17
+ def initialize
18
+ @top_count = ENV["TPS_PROF"].to_i
19
+ @top_count = 10 if @top_count == 1
20
+ @threshold = ENV.fetch("TPS_PROF_MIN", 10).to_i
21
+ @reporter = resolve_reporter(ENV["TPS_PROF_FORMAT"])
22
+ end
23
+
24
+ private
25
+
26
+ def resolve_reporter(format)
27
+ # TODO: support other formats
28
+ TPSProf::Reporter::Text.new
29
+ end
30
+ end
31
+
32
+ class << self
33
+ def config
34
+ @config ||= Configuration.new
35
+ end
36
+
37
+ def configure
38
+ yield config
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ require "test_prof/tps_prof/rspec" if TestProf.rspec?
45
+ # TODO: Minitest support
46
+ # require "test_prof/tps_prof/minitest" if TestProf.minitest?
@@ -19,7 +19,7 @@ module TestProf
19
19
  module Vernier
20
20
  # Vernier configuration
21
21
  class Configuration
22
- attr_accessor :mode, :target, :interval
22
+ attr_accessor :mode, :target, :interval, :hooks
23
23
 
24
24
  def initialize
25
25
  @mode = ENV.fetch("TEST_VERNIER_MODE", :wall).to_sym
@@ -27,6 +27,7 @@ module TestProf
27
27
 
28
28
  sample_interval = ENV["TEST_VERNIER_INTERVAL"].to_i
29
29
  @interval = (sample_interval > 0) ? sample_interval : nil
30
+ @hooks = ENV["TEST_VERNIER_HOOKS"]&.split(",")&.map { |hook| hook.strip.to_sym }
30
31
  end
31
32
 
32
33
  def boot?
@@ -82,6 +83,7 @@ module TestProf
82
83
  options = {}
83
84
 
84
85
  options[:interval] = config.interval if config.interval
86
+ options[:hooks] = config.hooks if config.hooks
85
87
 
86
88
  if block_given?
87
89
  options[:mode] = config.mode
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf
4
- VERSION = "1.3.0"
4
+ VERSION = "1.4.4"
5
5
  end
data/lib/test_prof.rb CHANGED
@@ -12,5 +12,6 @@ require "test_prof/factory_prof"
12
12
  require "test_prof/memory_prof"
13
13
  require "test_prof/rspec_stamp"
14
14
  require "test_prof/tag_prof"
15
+ require "test_prof/tps_prof"
15
16
  require "test_prof/rspec_dissect" if TestProf.rspec?
16
17
  require "test_prof/factory_all_stub"