test-prof 1.2.2 → 1.3.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 +4 -4
- data/CHANGELOG.md +15 -2
- data/README.md +1 -1
- data/lib/minitest/test_prof_plugin.rb +10 -0
- data/lib/test_prof/any_fixture/dump/sqlite.rb +1 -1
- data/lib/test_prof/any_fixture.rb +1 -1
- data/lib/test_prof/before_all/adapters/active_record.rb +3 -1
- data/lib/test_prof/before_all.rb +1 -1
- data/lib/test_prof/core.rb +167 -0
- data/lib/test_prof/factory_all_stub.rb +1 -1
- data/lib/test_prof/factory_default.rb +1 -1
- data/lib/test_prof/memory_prof/minitest.rb +56 -0
- data/lib/test_prof/memory_prof/printer/number_to_human.rb +44 -0
- data/lib/test_prof/memory_prof/printer.rb +93 -0
- data/lib/test_prof/memory_prof/rspec.rb +76 -0
- data/lib/test_prof/memory_prof/tracker/linked_list.rb +119 -0
- data/lib/test_prof/memory_prof/tracker/rss_tool.rb +87 -0
- data/lib/test_prof/memory_prof/tracker.rb +84 -0
- data/lib/test_prof/memory_prof.rb +78 -0
- data/lib/test_prof/recipes/logging.rb +1 -1
- data/lib/test_prof/recipes/minitest/sample.rb +2 -2
- data/lib/test_prof/recipes/rspec/let_it_be.rb +1 -1
- data/lib/test_prof/ruby_prof.rb +19 -3
- data/lib/test_prof/stack_prof/rspec.rb +2 -1
- data/lib/test_prof/stack_prof.rb +3 -3
- data/lib/test_prof/utils/sized_ordered_set.rb +4 -0
- data/lib/test_prof/vernier/rspec.rb +59 -0
- data/lib/test_prof/vernier.rb +152 -0
- data/lib/test_prof/version.rb +1 -1
- data/lib/test_prof.rb +3 -165
- metadata +14 -3
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TestProf
|
4
|
+
module MemoryProf
|
5
|
+
class Tracker
|
6
|
+
# LinkedList is a linked list that track memory usage for individual examples/groups.
|
7
|
+
# A list node (`LinkedListNode`) represents an example/group and its memory usage info:
|
8
|
+
#
|
9
|
+
# * memory_at_start - the amount of memory at the start of an example/group
|
10
|
+
# * memory_at_finish - the amount of memory at the end of an example/group
|
11
|
+
# * nested_memory - the amount of memory allocated by examples/groups defined inside a group
|
12
|
+
# * previous - a link to the previous node
|
13
|
+
#
|
14
|
+
# Each node has a link to its previous node, and the head node points to the current example/group.
|
15
|
+
# If we picture a linked list as a tree with root being the top level group and leaves being
|
16
|
+
# current examples/groups, then the head node will always point to a leaf in that tree.
|
17
|
+
#
|
18
|
+
# For example, if we have the following spec:
|
19
|
+
#
|
20
|
+
# describe Question do
|
21
|
+
# decribe "#publish" do
|
22
|
+
# context "when not published" do
|
23
|
+
# it "makes the question visible" do
|
24
|
+
# ...
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# At the moment when rspec is executing the example, the list has the following structure
|
31
|
+
# (^ denotes the head node):
|
32
|
+
#
|
33
|
+
# ^"makes the question visible" -> "when not published" -> "#publish" -> Question
|
34
|
+
#
|
35
|
+
# LinkedList supports two method for working with it:
|
36
|
+
#
|
37
|
+
# * add_node – adds a node to the beginig of the list. At this point an example or group
|
38
|
+
# has started and we track how much memory has already been used.
|
39
|
+
# * remove_node – removes and returns the head node from the list. It means that the node
|
40
|
+
# example/group has finished and it is time to calculate its memory usage.
|
41
|
+
#
|
42
|
+
# When we remove a node we add its total_memory to the previous node.nested_memory, thus
|
43
|
+
# gradually tracking the amount of memory used by nested examples inside a group.
|
44
|
+
#
|
45
|
+
# In the example above, after we remove the node "makes the question visible", we add its total
|
46
|
+
# memory usage to nested_memory of the "when not published" node. If the "when not published"
|
47
|
+
# group contains other examples or sub-groups, their total_memory will also be added to
|
48
|
+
# "when not published" nested_memory. So when the group finishes we will have the total amount
|
49
|
+
# of memory used by its nested examples/groups, and thus we will be able to calculate the memory
|
50
|
+
# used by hooks and other code inside a group by subtracting nested_memory from total_memory.
|
51
|
+
class LinkedList
|
52
|
+
attr_reader :head
|
53
|
+
|
54
|
+
def initialize(memory_at_start)
|
55
|
+
add_node(:total, memory_at_start)
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_node(item, memory_at_start)
|
59
|
+
@head = LinkedListNode.new(
|
60
|
+
item: item,
|
61
|
+
previous: head,
|
62
|
+
memory_at_start: memory_at_start
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def remove_node(item, memory_at_finish)
|
67
|
+
return if head.item != item
|
68
|
+
head.finish(memory_at_finish)
|
69
|
+
|
70
|
+
current = head
|
71
|
+
@head = head.previous
|
72
|
+
|
73
|
+
current
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class LinkedListNode
|
78
|
+
attr_reader :item, :previous, :memory_at_start, :memory_at_finish, :nested_memory
|
79
|
+
|
80
|
+
def initialize(item:, memory_at_start:, previous:)
|
81
|
+
@item = item
|
82
|
+
@previous = previous
|
83
|
+
|
84
|
+
@memory_at_start = memory_at_start || 0
|
85
|
+
@memory_at_finish = nil
|
86
|
+
@nested_memory = 0
|
87
|
+
end
|
88
|
+
|
89
|
+
def total_memory
|
90
|
+
return 0 if memory_at_finish.nil?
|
91
|
+
# It seems that on Windows Minitest may release a lot of memory to
|
92
|
+
# the OS when it finishes and executes #report, leading to memory_at_finish
|
93
|
+
# being less than memory_at_start. In this case we return nested_memory
|
94
|
+
# which does not account for the memory used in `after` hooks, but it
|
95
|
+
# is better than nothing.
|
96
|
+
return nested_memory if memory_at_start > memory_at_finish
|
97
|
+
|
98
|
+
memory_at_finish - memory_at_start
|
99
|
+
end
|
100
|
+
|
101
|
+
def hooks_memory
|
102
|
+
total_memory - nested_memory
|
103
|
+
end
|
104
|
+
|
105
|
+
def finish(memory_at_finish)
|
106
|
+
@memory_at_finish = memory_at_finish
|
107
|
+
|
108
|
+
previous&.add_nested(self)
|
109
|
+
end
|
110
|
+
|
111
|
+
protected
|
112
|
+
|
113
|
+
def add_nested(node)
|
114
|
+
@nested_memory += node.total_memory
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rbconfig"
|
4
|
+
|
5
|
+
module TestProf
|
6
|
+
module MemoryProf
|
7
|
+
class Tracker
|
8
|
+
module RssTool
|
9
|
+
class ProcFS
|
10
|
+
def initialize
|
11
|
+
@statm = File.open("/proc/#{$$}/statm", "r")
|
12
|
+
@page_size = get_page_size
|
13
|
+
end
|
14
|
+
|
15
|
+
def track
|
16
|
+
@statm.seek(0)
|
17
|
+
@statm.gets.split(/\s/)[1].to_i * @page_size
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def get_page_size
|
23
|
+
[
|
24
|
+
-> {
|
25
|
+
require "etc"
|
26
|
+
Etc.sysconf(Etc::SC_PAGE_SIZE)
|
27
|
+
},
|
28
|
+
-> { `getconf PAGE_SIZE`.to_i },
|
29
|
+
-> { 0x1000 }
|
30
|
+
].each do |strategy|
|
31
|
+
page_size = begin
|
32
|
+
strategy.call
|
33
|
+
rescue
|
34
|
+
next
|
35
|
+
end
|
36
|
+
return page_size
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class PS
|
42
|
+
def track
|
43
|
+
`ps -o rss -p #{$$}`.strip.split.last.to_i * 1024
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class GetProcess
|
48
|
+
def track
|
49
|
+
command.strip.split.last.to_i
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def command
|
55
|
+
`powershell -Command "Get-Process -Id #{$$} | select WS"`
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
TOOLS = {
|
60
|
+
linux: ProcFS,
|
61
|
+
macosx: PS,
|
62
|
+
unix: PS,
|
63
|
+
windows: GetProcess
|
64
|
+
}.freeze
|
65
|
+
|
66
|
+
class << self
|
67
|
+
def tool
|
68
|
+
TOOLS[os_type]&.new
|
69
|
+
end
|
70
|
+
|
71
|
+
def os_type
|
72
|
+
case RbConfig::CONFIG["host_os"]
|
73
|
+
when /linux/
|
74
|
+
:linux
|
75
|
+
when /darwin|mac os/
|
76
|
+
:macosx
|
77
|
+
when /solaris|bsd/
|
78
|
+
:unix
|
79
|
+
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
80
|
+
:windows
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_prof/memory_prof/tracker/linked_list"
|
4
|
+
require "test_prof/memory_prof/tracker/rss_tool"
|
5
|
+
|
6
|
+
module TestProf
|
7
|
+
module MemoryProf
|
8
|
+
# Tracker is responsible for tracking memory usage and determining
|
9
|
+
# the top n examples and groups. There are two types of trackers:
|
10
|
+
# AllocTracker and RssTracker.
|
11
|
+
#
|
12
|
+
# A tracker consists of four main parts:
|
13
|
+
# * list - a linked list that is being used to track memmory for individual groups/examples.
|
14
|
+
# list is an instance of LinkedList (for more info see tracker/linked_list.rb)
|
15
|
+
# * examples – the top n examples, an instance of Utils::SizedOrderedSet.
|
16
|
+
# * groups – the top n groups, an instance of Utils::SizedOrderedSet.
|
17
|
+
# * track - a method that fetches the amount of memory in use at a certain point.
|
18
|
+
class Tracker
|
19
|
+
attr_reader :top_count, :examples, :groups, :total_memory, :list
|
20
|
+
|
21
|
+
def initialize(top_count)
|
22
|
+
raise "Your Ruby Engine or OS is not supported" unless supported?
|
23
|
+
|
24
|
+
@top_count = top_count
|
25
|
+
|
26
|
+
@examples = Utils::SizedOrderedSet.new(top_count, sort_by: :memory)
|
27
|
+
@groups = Utils::SizedOrderedSet.new(top_count, sort_by: :memory)
|
28
|
+
end
|
29
|
+
|
30
|
+
def start
|
31
|
+
@list = LinkedList.new(track)
|
32
|
+
end
|
33
|
+
|
34
|
+
def finish
|
35
|
+
node = list.remove_node(:total, track)
|
36
|
+
@total_memory = node.total_memory
|
37
|
+
end
|
38
|
+
|
39
|
+
def example_started(example)
|
40
|
+
list.add_node(example, track)
|
41
|
+
end
|
42
|
+
|
43
|
+
def example_finished(example)
|
44
|
+
node = list.remove_node(example, track)
|
45
|
+
examples << {**example, memory: node.total_memory}
|
46
|
+
end
|
47
|
+
|
48
|
+
def group_started(group)
|
49
|
+
list.add_node(group, track)
|
50
|
+
end
|
51
|
+
|
52
|
+
def group_finished(group)
|
53
|
+
node = list.remove_node(group, track)
|
54
|
+
groups << {**group, memory: node.hooks_memory}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class AllocTracker < Tracker
|
59
|
+
def track
|
60
|
+
GC.stat[:total_allocated_objects]
|
61
|
+
end
|
62
|
+
|
63
|
+
def supported?
|
64
|
+
RUBY_ENGINE != "jruby"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class RssTracker < Tracker
|
69
|
+
def initialize(top_count)
|
70
|
+
@rss_tool = RssTool.tool
|
71
|
+
|
72
|
+
super
|
73
|
+
end
|
74
|
+
|
75
|
+
def track
|
76
|
+
@rss_tool.track
|
77
|
+
end
|
78
|
+
|
79
|
+
def supported?
|
80
|
+
!!@rss_tool
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_prof/memory_prof/tracker"
|
4
|
+
require "test_prof/memory_prof/printer"
|
5
|
+
|
6
|
+
module TestProf
|
7
|
+
# MemoryProf can help in detecting test examples causing memory spikes.
|
8
|
+
# It supports two metrics: RSS and allocations.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# TEST_MEM_PROF='rss' rspec ...
|
13
|
+
# TEST_MEM_PROF='alloc' rspec ...
|
14
|
+
#
|
15
|
+
# By default MemoryProf shows the top 5 examples and groups (for RSpec) but you can
|
16
|
+
# set how many items to display with `TEST_MEM_PROF_COUNT`:
|
17
|
+
#
|
18
|
+
# TEST_MEM_PROF='rss' TEST_MEM_PROF_COUNT=10 rspec ...
|
19
|
+
#
|
20
|
+
# The examples block shows the amount of memory used by each example, and the groups
|
21
|
+
# block displays the memory allocated by other code defined in the groups. For example,
|
22
|
+
# RSpec groups may include heavy `before(:all)` (or `before_all`) setup blocks, so it is
|
23
|
+
# helpful to see which groups use the most amount of memory outside of their examples.
|
24
|
+
|
25
|
+
module MemoryProf
|
26
|
+
# MemoryProf configuration
|
27
|
+
class Configuration
|
28
|
+
attr_reader :mode, :top_count
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
self.mode = ENV["TEST_MEM_PROF"]
|
32
|
+
self.top_count = ENV["TEST_MEM_PROF_COUNT"]
|
33
|
+
end
|
34
|
+
|
35
|
+
def mode=(value)
|
36
|
+
@mode = (value == "alloc") ? :alloc : :rss
|
37
|
+
end
|
38
|
+
|
39
|
+
def top_count=(value)
|
40
|
+
@top_count = value.to_i
|
41
|
+
@top_count = 5 unless @top_count.positive?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class << self
|
46
|
+
TRACKERS = {
|
47
|
+
alloc: AllocTracker,
|
48
|
+
rss: RssTracker
|
49
|
+
}.freeze
|
50
|
+
|
51
|
+
PRINTERS = {
|
52
|
+
alloc: AllocPrinter,
|
53
|
+
rss: RssPrinter
|
54
|
+
}.freeze
|
55
|
+
|
56
|
+
def config
|
57
|
+
@config ||= Configuration.new
|
58
|
+
end
|
59
|
+
|
60
|
+
def configure
|
61
|
+
yield config
|
62
|
+
end
|
63
|
+
|
64
|
+
def tracker
|
65
|
+
tracker = TRACKERS[config.mode]
|
66
|
+
tracker.new(config.top_count)
|
67
|
+
end
|
68
|
+
|
69
|
+
def printer(tracker)
|
70
|
+
printer = PRINTERS[config.mode]
|
71
|
+
printer.new(tracker)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
require "test_prof/memory_prof/rspec" if TestProf.rspec?
|
78
|
+
require "test_prof/memory_prof/minitest" if TestProf.minitest?
|
@@ -6,9 +6,9 @@ module TestProf
|
|
6
6
|
# Do not add these classes to resulted sample
|
7
7
|
CORE_RUNNABLES = [
|
8
8
|
Minitest::Test,
|
9
|
-
Minitest::Unit::TestCase,
|
9
|
+
defined?(Minitest::Unit::TestCase) ? Minitest::Unit::TestCase : nil,
|
10
10
|
Minitest::Spec
|
11
|
-
].freeze
|
11
|
+
].compact.freeze
|
12
12
|
|
13
13
|
class << self
|
14
14
|
def suites
|
data/lib/test_prof/ruby_prof.rb
CHANGED
@@ -53,7 +53,7 @@ module TestProf
|
|
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
|
-
@mode = ENV.fetch("TEST_RUBY_PROF_MODE", :wall).
|
56
|
+
@mode = ENV.fetch("TEST_RUBY_PROF_MODE", :wall).to_s
|
57
57
|
@min_percent = 1
|
58
58
|
@include_threads = false
|
59
59
|
@exclude_common_methods = true
|
@@ -84,6 +84,22 @@ module TestProf
|
|
84
84
|
|
85
85
|
[type, ::RubyProf.const_get(PRINTERS[type])]
|
86
86
|
end
|
87
|
+
|
88
|
+
# Based on deprecated https://github.com/ruby-prof/ruby-prof/blob/fd3a5236a459586c5ca7ce4de506c1835129516a/lib/ruby-prof.rb#L36
|
89
|
+
def ruby_prof_mode
|
90
|
+
case mode
|
91
|
+
when "wall", "wall_time"
|
92
|
+
::RubyProf::WALL_TIME
|
93
|
+
when "allocations"
|
94
|
+
::RubyProf::ALLOCATIONS
|
95
|
+
when "memory"
|
96
|
+
::RubyProf::MEMORY
|
97
|
+
when "process", "process_time"
|
98
|
+
::RubyProf::PROCESS_TIME
|
99
|
+
else
|
100
|
+
::RubyProf::WALL_TIME
|
101
|
+
end
|
102
|
+
end
|
87
103
|
end
|
88
104
|
|
89
105
|
# Wrapper over RubyProf profiler and printer
|
@@ -166,7 +182,7 @@ module TestProf
|
|
166
182
|
log :warn, <<~MSG
|
167
183
|
RubyProf is activated globally, you cannot generate per-example report.
|
168
184
|
|
169
|
-
Make sure you haven'
|
185
|
+
Make sure you haven't set the TEST_RUBY_PROF environmental variable.
|
170
186
|
MSG
|
171
187
|
return
|
172
188
|
end
|
@@ -177,6 +193,7 @@ module TestProf
|
|
177
193
|
|
178
194
|
options[:include_threads] = [Thread.current] unless
|
179
195
|
config.include_threads?
|
196
|
+
options[:measure_mode] = config.ruby_prof_mode
|
180
197
|
|
181
198
|
profiler = ::RubyProf::Profile.new(options)
|
182
199
|
profiler.exclude_common_methods! if config.exclude_common_methods?
|
@@ -206,7 +223,6 @@ module TestProf
|
|
206
223
|
|
207
224
|
def init_ruby_prof
|
208
225
|
return @initialized if instance_variable_defined?(:@initialized)
|
209
|
-
ENV["RUBY_PROF_MEASURE_MODE"] = config.mode.to_s
|
210
226
|
@initialized = TestProf.require(
|
211
227
|
"ruby-prof",
|
212
228
|
<<~MSG
|
@@ -19,12 +19,13 @@ module TestProf
|
|
19
19
|
|
20
20
|
def example_started(notification)
|
21
21
|
return unless profile?(notification.example)
|
22
|
+
|
22
23
|
notification.example.metadata[:sprof_report] = TestProf::StackProf.profile
|
23
24
|
end
|
24
25
|
|
25
26
|
def example_finished(notification)
|
26
27
|
return unless profile?(notification.example)
|
27
|
-
return
|
28
|
+
return if notification.example.metadata[:sprof_report] == false
|
28
29
|
|
29
30
|
TestProf::StackProf.dump(
|
30
31
|
self.class.report_name_generator.call(notification.example)
|
data/lib/test_prof/stack_prof.rb
CHANGED
@@ -33,7 +33,7 @@ module TestProf
|
|
33
33
|
if FORMATS.include?(ENV["TEST_STACK_PROF_FORMAT"])
|
34
34
|
ENV["TEST_STACK_PROF_FORMAT"]
|
35
35
|
else
|
36
|
-
"
|
36
|
+
"json"
|
37
37
|
end
|
38
38
|
|
39
39
|
sample_interval = ENV["TEST_STACK_PROF_INTERVAL"].to_i
|
@@ -81,9 +81,9 @@ module TestProf
|
|
81
81
|
def profile(name = nil)
|
82
82
|
if locked?
|
83
83
|
log :warn, <<~MSG
|
84
|
-
StackProf
|
84
|
+
StackProf has been already activated.
|
85
85
|
|
86
|
-
Make sure you
|
86
|
+
Make sure you have not set the TEST_STACK_PROF environmental variable.
|
87
87
|
MSG
|
88
88
|
return false
|
89
89
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_prof/utils/rspec"
|
4
|
+
|
5
|
+
module TestProf
|
6
|
+
module Vernier
|
7
|
+
# Reporter for RSpec to profile specific examples with Vernier
|
8
|
+
class Listener # :nodoc:
|
9
|
+
class << self
|
10
|
+
attr_accessor :report_name_generator
|
11
|
+
end
|
12
|
+
|
13
|
+
self.report_name_generator = Utils::RSpec.method(:example_to_filename)
|
14
|
+
|
15
|
+
NOTIFICATIONS = %i[
|
16
|
+
example_started
|
17
|
+
example_finished
|
18
|
+
].freeze
|
19
|
+
|
20
|
+
def example_started(notification)
|
21
|
+
return unless profile?(notification.example)
|
22
|
+
notification.example.metadata[:vernier_collector] = TestProf::Vernier.profile
|
23
|
+
end
|
24
|
+
|
25
|
+
def example_finished(notification)
|
26
|
+
return unless profile?(notification.example)
|
27
|
+
return unless notification.example.metadata[:vernier_collector]
|
28
|
+
|
29
|
+
TestProf::Vernier.dump(
|
30
|
+
notification.example.metadata[:vernier_collector],
|
31
|
+
self.class.report_name_generator.call(notification.example)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def profile?(example)
|
38
|
+
example.metadata.key?(:vernier)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
RSpec.configure do |config|
|
45
|
+
config.before(:suite) do
|
46
|
+
listener = TestProf::Vernier::Listener.new
|
47
|
+
|
48
|
+
config.reporter.register_listener(
|
49
|
+
listener, *TestProf::Vernier::Listener::NOTIFICATIONS
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Handle boot profiling
|
55
|
+
RSpec.configure do |config|
|
56
|
+
config.append_before(:suite) do
|
57
|
+
TestProf::Vernier.dump(TestProf::Vernier.default_collector, "boot") if TestProf::Vernier.config.boot?
|
58
|
+
end
|
59
|
+
end
|