test-prof 0.6.0 → 0.7.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 +20 -0
- data/README.md +1 -1
- data/lib/minitest/event_prof_formatter.rb +3 -5
- data/lib/test_prof/any_fixture.rb +2 -4
- data/lib/test_prof/before_all.rb +1 -1
- data/lib/test_prof/cops/rspec/aggregate_failures.rb +2 -2
- data/lib/test_prof/event_prof/custom_events/factory_create.rb +1 -4
- data/lib/test_prof/event_prof/custom_events/sidekiq_inline.rb +1 -5
- data/lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb +1 -5
- data/lib/test_prof/event_prof/monitor.rb +1 -5
- data/lib/test_prof/event_prof/rspec.rb +5 -7
- data/lib/test_prof/factory_doctor/minitest.rb +2 -4
- data/lib/test_prof/factory_doctor/rspec.rb +4 -6
- data/lib/test_prof/factory_prof/printers/flamegraph.rb +2 -2
- data/lib/test_prof/factory_prof/printers/simple.rb +1 -4
- data/lib/test_prof/recipes/active_record_one_love.rb +2 -0
- data/lib/test_prof/recipes/logging.rb +10 -4
- data/lib/test_prof/recipes/rspec/let_it_be.rb +2 -2
- data/lib/test_prof/rspec_dissect/collectors/base.rb +2 -4
- data/lib/test_prof/rspec_dissect/rspec.rb +3 -5
- data/lib/test_prof/rspec_stamp/parser.rb +2 -2
- data/lib/test_prof/rspec_stamp/rspec.rb +2 -5
- data/lib/test_prof/ruby_prof.rb +61 -28
- data/lib/test_prof/ruby_prof/rspec_exclusions.rb +93 -0
- data/lib/test_prof/stack_prof.rb +3 -6
- data/lib/test_prof/tag_prof/printers/html.rb +2 -2
- data/lib/test_prof/tag_prof/printers/simple.rb +1 -3
- data/lib/test_prof/tag_prof/rspec.rb +3 -3
- data/lib/test_prof/version.rb +1 -1
- metadata +6 -6
- data/lib/test_prof/ext/string_strip_heredoc.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8baffb743630e819928190645aa63d73436f2dc54fc2c56ab1ad5df8141ed3c
|
4
|
+
data.tar.gz: 7738b154073f150e23df40193f350e93e2fb047758023021acef237e08988da3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2f75e27df1795a31f3e39312bfa6268502881f1fd6cb28376603f0486048376d12d5e0266edb2eb7e76f6a54723ae03c43a6c35167242fe2c361b12535cda93
|
7
|
+
data.tar.gz: 56b472304e1291e9f392a2c62c36bc40fc2ad575c0b976d46a8f2fd881bfbf2db3f0948014dd29b99cf63eccded2a63b0ddd834676221f354e872622a80dc883
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,26 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 0.7.0 (2018-08-12)
|
6
|
+
|
7
|
+
- **Ruby 2.3+ is required**. ([@palkan][])
|
8
|
+
|
9
|
+
Ruby 2.2 EOL was on 2018-03-31.
|
10
|
+
|
11
|
+
- Upgrade RubyProf integration to `ruby-prof >= 0.17`. ([@palkan][])
|
12
|
+
|
13
|
+
Use `exclude_common_methods!` instead of the deprecated `eliminate_methods!`.
|
14
|
+
|
15
|
+
Add RSpec specific exclusions.
|
16
|
+
|
17
|
+
Add ability to specify custom exclusions through `config.custom_exclusions`, e.g.:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
TestProf::RubyProf.configure do |config|
|
21
|
+
config.custom_exclusions = { User => %i[save save!] }
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
5
25
|
## 0.6.0 (2018-06-29)
|
6
26
|
|
7
27
|
### Features
|
data/README.md
CHANGED
@@ -32,7 +32,7 @@ Of course, we have some [solutions](https://test-prof.evilmartians.io/#/?id=reci
|
|
32
32
|
|
33
33
|
Supported Ruby versions:
|
34
34
|
|
35
|
-
- Ruby (MRI) >= 2.
|
35
|
+
- Ruby (MRI) >= 2.3.0 (**NOTE:** for Ruby 2.2 use TestProf < 0.7.0)
|
36
36
|
|
37
37
|
- JRuby >= 9.1.0.0
|
38
38
|
|
@@ -2,14 +2,12 @@
|
|
2
2
|
|
3
3
|
require "test_prof/ext/float_duration"
|
4
4
|
require "test_prof/ext/string_truncate"
|
5
|
-
require "test_prof/ext/string_strip_heredoc"
|
6
5
|
|
7
6
|
module Minitest
|
8
7
|
module TestProf
|
9
8
|
class EventProfFormatter # :nodoc:
|
10
9
|
using ::TestProf::FloatDuration
|
11
10
|
using ::TestProf::StringTruncate
|
12
|
-
using ::TestProf::StringStripHeredoc
|
13
11
|
|
14
12
|
def initialize(profilers)
|
15
13
|
@profilers = profilers
|
@@ -29,7 +27,7 @@ module Minitest
|
|
29
27
|
|
30
28
|
def total_results(profiler)
|
31
29
|
@results <<
|
32
|
-
|
30
|
+
<<~MSG
|
33
31
|
EventProf results for #{profiler.event}
|
34
32
|
|
35
33
|
Total time: #{profiler.total_time.duration}
|
@@ -46,7 +44,7 @@ module Minitest
|
|
46
44
|
location = group[:id][:location]
|
47
45
|
|
48
46
|
@results <<
|
49
|
-
|
47
|
+
<<~GROUP
|
50
48
|
#{description.truncate} (#{location}) – #{group[:time].duration} (#{group[:count]} / #{group[:examples]})
|
51
49
|
GROUP
|
52
50
|
end
|
@@ -61,7 +59,7 @@ module Minitest
|
|
61
59
|
location = example[:id][:location]
|
62
60
|
|
63
61
|
@results <<
|
64
|
-
|
62
|
+
<<~GROUP
|
65
63
|
#{description.truncate} (#{location}) – #{example[:time].duration} (#{example[:count]})
|
66
64
|
GROUP
|
67
65
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "test_prof/ext/float_duration"
|
4
|
-
require "test_prof/ext/string_strip_heredoc"
|
5
4
|
|
6
5
|
module TestProf
|
7
6
|
# Make DB fixtures from blocks.
|
@@ -9,7 +8,6 @@ module TestProf
|
|
9
8
|
INSERT_RXP = /^INSERT INTO ([\S]+)/
|
10
9
|
|
11
10
|
using FloatDuration
|
12
|
-
using StringStripHeredoc
|
13
11
|
|
14
12
|
class Cache # :nodoc:
|
15
13
|
attr_reader :store, :stats
|
@@ -85,7 +83,7 @@ module TestProf
|
|
85
83
|
msgs = []
|
86
84
|
|
87
85
|
msgs <<
|
88
|
-
|
86
|
+
<<~MSG
|
89
87
|
AnyFixture usage stats:
|
90
88
|
MSG
|
91
89
|
|
@@ -119,7 +117,7 @@ module TestProf
|
|
119
117
|
end
|
120
118
|
|
121
119
|
msgs <<
|
122
|
-
|
120
|
+
<<~MSG
|
123
121
|
|
124
122
|
Total time spent: #{total_spent.duration}
|
125
123
|
Total time saved: #{total_saved.duration}
|
data/lib/test_prof/before_all.rb
CHANGED
@@ -5,7 +5,7 @@ module TestProf
|
|
5
5
|
module BeforeAll
|
6
6
|
class AdapterMissing < StandardError # :nodoc:
|
7
7
|
MSG = "Please, provide an adapter for `before_all` " \
|
8
|
-
"through `TestProf::BeforeAll.adapter = MyAdapter`"
|
8
|
+
"through `TestProf::BeforeAll.adapter = MyAdapter`"
|
9
9
|
|
10
10
|
def initialize
|
11
11
|
super(MSG)
|
@@ -50,7 +50,7 @@ module RuboCop
|
|
50
50
|
return unless self.class.supported?
|
51
51
|
|
52
52
|
method, _args, body = *node
|
53
|
-
return unless body
|
53
|
+
return unless body&.begin_type?
|
54
54
|
|
55
55
|
_receiver, method_name, _object = *method
|
56
56
|
return unless GROUP_BLOCKS.include?(method_name)
|
@@ -120,7 +120,7 @@ module RuboCop
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def oneliner?(node)
|
123
|
-
node
|
123
|
+
node&.block_type? &&
|
124
124
|
(node.source.lines.size == 1) &&
|
125
125
|
example_node?(node)
|
126
126
|
end
|
@@ -1,10 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "test_prof/ext/string_strip_heredoc"
|
4
3
|
require "test_prof/factory_bot"
|
5
4
|
|
6
|
-
using TestProf::StringStripHeredoc
|
7
|
-
|
8
5
|
module TestProf::EventProf::CustomEvents
|
9
6
|
module FactoryCreate # :nodoc: all
|
10
7
|
module RunnerPatch
|
@@ -49,7 +46,7 @@ TestProf::EventProf::CustomEvents.register("factory.create") do
|
|
49
46
|
TestProf::EventProf::CustomEvents::FactoryCreate.setup!
|
50
47
|
else
|
51
48
|
TestProf.log(:error,
|
52
|
-
|
49
|
+
<<~MSG
|
53
50
|
Failed to load factory_bot / factory_girl.
|
54
51
|
|
55
52
|
Make sure that any of them is in your Gemfile.
|
@@ -1,9 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "test_prof/ext/string_strip_heredoc"
|
4
|
-
|
5
|
-
using TestProf::StringStripHeredoc
|
6
|
-
|
7
3
|
module TestProf::EventProf::CustomEvents
|
8
4
|
module SidekiqInline # :nodoc: all
|
9
5
|
module ClientPatch
|
@@ -43,7 +39,7 @@ end
|
|
43
39
|
TestProf::EventProf::CustomEvents.register("sidekiq.inline") do
|
44
40
|
if TestProf.require(
|
45
41
|
'sidekiq/testing',
|
46
|
-
|
42
|
+
<<~MSG
|
47
43
|
Failed to load Sidekiq.
|
48
44
|
|
49
45
|
Make sure that "sidekiq" gem is in your Gemfile.
|
@@ -1,9 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "test_prof/ext/string_strip_heredoc"
|
4
|
-
|
5
|
-
using TestProf::StringStripHeredoc
|
6
|
-
|
7
3
|
module TestProf::EventProf::CustomEvents
|
8
4
|
module SidekiqJobs # :nodoc: all
|
9
5
|
module ClientPatch
|
@@ -30,7 +26,7 @@ end
|
|
30
26
|
TestProf::EventProf::CustomEvents.register("sidekiq.jobs") do
|
31
27
|
if TestProf.require(
|
32
28
|
'sidekiq/testing',
|
33
|
-
|
29
|
+
<<~MSG
|
34
30
|
Failed to load Sidekiq.
|
35
31
|
|
36
32
|
Make sure that "sidekiq" gem is in your Gemfile.
|
@@ -1,18 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "test_prof/ext/string_strip_heredoc"
|
4
|
-
|
5
3
|
module TestProf
|
6
4
|
module EventProf
|
7
5
|
# Wrap methods with instrumentation
|
8
6
|
module Monitor
|
9
|
-
using StringStripHeredoc
|
10
|
-
|
11
7
|
class << self
|
12
8
|
def call(mod, event, *mids)
|
13
9
|
patch = Module.new do
|
14
10
|
mids.each do |mid|
|
15
|
-
module_eval
|
11
|
+
module_eval <<~SRC, __FILE__, __LINE__ + 1
|
16
12
|
def #{mid}(*)
|
17
13
|
TestProf::EventProf.instrumenter.instrument(
|
18
14
|
'#{event}'
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require "test_prof/ext/float_duration"
|
4
4
|
require "test_prof/ext/string_truncate"
|
5
|
-
require "test_prof/ext/string_strip_heredoc"
|
6
5
|
|
7
6
|
module TestProf
|
8
7
|
module EventProf
|
@@ -10,7 +9,6 @@ module TestProf
|
|
10
9
|
include Logging
|
11
10
|
using FloatDuration
|
12
11
|
using StringTruncate
|
13
|
-
using StringStripHeredoc
|
14
12
|
|
15
13
|
NOTIFICATIONS = %i[
|
16
14
|
example_group_started
|
@@ -60,7 +58,7 @@ module TestProf
|
|
60
58
|
msgs = []
|
61
59
|
|
62
60
|
msgs <<
|
63
|
-
|
61
|
+
<<~MSG
|
64
62
|
EventProf results for #{profiler.event}
|
65
63
|
|
66
64
|
Total time: #{profiler.total_time.duration}
|
@@ -75,7 +73,7 @@ module TestProf
|
|
75
73
|
location = group[:id].metadata[:location]
|
76
74
|
|
77
75
|
msgs <<
|
78
|
-
|
76
|
+
<<~GROUP
|
79
77
|
#{description.truncate} (#{location}) – #{group[:time].duration} (#{group[:count]} / #{group[:examples]})
|
80
78
|
GROUP
|
81
79
|
end
|
@@ -87,7 +85,7 @@ module TestProf
|
|
87
85
|
description = example[:id].description
|
88
86
|
location = example[:id].metadata[:location]
|
89
87
|
msgs <<
|
90
|
-
|
88
|
+
<<~GROUP
|
91
89
|
#{description.truncate} (#{location}) – #{example[:time].duration} (#{example[:count]})
|
92
90
|
GROUP
|
93
91
|
end
|
@@ -118,7 +116,7 @@ module TestProf
|
|
118
116
|
msgs = []
|
119
117
|
|
120
118
|
msgs <<
|
121
|
-
|
119
|
+
<<~MSG
|
122
120
|
RSpec Stamp results
|
123
121
|
|
124
122
|
Total patches: #{stamper.total}
|
@@ -148,6 +146,6 @@ TestProf.activate('EVENT_PROF') do
|
|
148
146
|
)
|
149
147
|
end
|
150
148
|
|
151
|
-
config.after(:suite) { listener
|
149
|
+
config.after(:suite) { listener&.print }
|
152
150
|
end
|
153
151
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'minitest/base_reporter'
|
4
4
|
require 'test_prof/ext/float_duration'
|
5
|
-
require 'test_prof/ext/string_strip_heredoc'
|
6
5
|
|
7
6
|
module Minitest
|
8
7
|
module TestProf # :nodoc:
|
@@ -17,9 +16,8 @@ module Minitest
|
|
17
16
|
|
18
17
|
class FactoryDoctorReporter < BaseReporter # :nodoc:
|
19
18
|
using ::TestProf::FloatDuration
|
20
|
-
using ::TestProf::StringStripHeredoc
|
21
19
|
|
22
|
-
SUCCESS_MESSAGE = 'FactoryDoctor says: "Looks good to me!"'
|
20
|
+
SUCCESS_MESSAGE = 'FactoryDoctor says: "Looks good to me!"'
|
23
21
|
|
24
22
|
def initialize(io = $stdout, options = {})
|
25
23
|
super
|
@@ -65,7 +63,7 @@ module Minitest
|
|
65
63
|
msgs = []
|
66
64
|
|
67
65
|
msgs <<
|
68
|
-
|
66
|
+
<<~MSG
|
69
67
|
FactoryDoctor report
|
70
68
|
|
71
69
|
Total (potentially) bad examples: #{@count}
|
@@ -1,16 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "test_prof/ext/float_duration"
|
4
|
-
require "test_prof/ext/string_strip_heredoc"
|
5
4
|
|
6
5
|
module TestProf
|
7
6
|
module FactoryDoctor
|
8
7
|
class RSpecListener # :nodoc:
|
9
8
|
include Logging
|
10
9
|
using FloatDuration
|
11
|
-
using StringStripHeredoc
|
12
10
|
|
13
|
-
SUCCESS_MESSAGE = 'FactoryDoctor says: "Looks good to me!"'
|
11
|
+
SUCCESS_MESSAGE = 'FactoryDoctor says: "Looks good to me!"'
|
14
12
|
|
15
13
|
NOTIFICATIONS = %i[
|
16
14
|
example_started
|
@@ -58,7 +56,7 @@ module TestProf
|
|
58
56
|
msgs = []
|
59
57
|
|
60
58
|
msgs <<
|
61
|
-
|
59
|
+
<<~MSG
|
62
60
|
FactoryDoctor report
|
63
61
|
|
64
62
|
Total (potentially) bad examples: #{@count}
|
@@ -100,7 +98,7 @@ module TestProf
|
|
100
98
|
msgs = []
|
101
99
|
|
102
100
|
msgs <<
|
103
|
-
|
101
|
+
<<~MSG
|
104
102
|
RSpec Stamp results
|
105
103
|
|
106
104
|
Total patches: #{stamper.total}
|
@@ -137,7 +135,7 @@ TestProf.activate('FDOC') do
|
|
137
135
|
)
|
138
136
|
end
|
139
137
|
|
140
|
-
config.after(:suite) { listener
|
138
|
+
config.after(:suite) { listener&.print }
|
141
139
|
end
|
142
140
|
|
143
141
|
RSpec.shared_context "factory_doctor:ignore", fd_ignore: true do
|
@@ -5,8 +5,8 @@ require "test_prof/utils/html_builder"
|
|
5
5
|
module TestProf::FactoryProf
|
6
6
|
module Printers
|
7
7
|
module Flamegraph # :nodoc: all
|
8
|
-
TEMPLATE = "flamegraph.template.html"
|
9
|
-
OUTPUT_NAME = "factory-flame.html"
|
8
|
+
TEMPLATE = "flamegraph.template.html"
|
9
|
+
OUTPUT_NAME = "factory-flame.html"
|
10
10
|
|
11
11
|
class << self
|
12
12
|
include TestProf::Logging
|
@@ -1,20 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "test_prof/ext/string_strip_heredoc"
|
4
|
-
|
5
3
|
module TestProf::FactoryProf
|
6
4
|
module Printers
|
7
5
|
module Simple # :nodoc: all
|
8
6
|
class << self
|
9
7
|
include TestProf::Logging
|
10
|
-
using TestProf::StringStripHeredoc
|
11
8
|
|
12
9
|
def dump(result)
|
13
10
|
return log(:info, "No factories detected") if result.raw_stats == {}
|
14
11
|
msgs = []
|
15
12
|
|
16
13
|
msgs <<
|
17
|
-
|
14
|
+
<<~MSG
|
18
15
|
Factories usage
|
19
16
|
|
20
17
|
total top-level name
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
if defined?(RSpec)
|
2
4
|
RSpec.shared_context "logging:verbose", log: true do
|
3
5
|
around(:each) do |ex|
|
@@ -16,10 +18,13 @@ if defined?(RSpec)
|
|
16
18
|
|
17
19
|
RSpec.shared_context "logging:active_record", log: :ar do
|
18
20
|
around(:each) do |ex|
|
19
|
-
|
20
|
-
|
21
|
+
*loggers = ActiveRecord::Base.logger,
|
22
|
+
ActiveSupport::LogSubscriber.logger
|
23
|
+
ActiveSupport::LogSubscriber.logger =
|
24
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
21
25
|
ex.run
|
22
|
-
|
26
|
+
ActiveSupport::LogSubscriber.logger,
|
27
|
+
ActiveRecord::Base.logger = *loggers
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
@@ -33,5 +38,6 @@ end
|
|
33
38
|
|
34
39
|
TestProf.activate("LOG", "ar") do
|
35
40
|
TestProf.log :info, "Active Record verbose logging enabled"
|
36
|
-
|
41
|
+
ActiveSupport::LogSubscriber.logger =
|
42
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
37
43
|
end
|
@@ -9,7 +9,7 @@ module TestProf
|
|
9
9
|
module LetItBe
|
10
10
|
class << self
|
11
11
|
def module_for(group)
|
12
|
-
modules
|
12
|
+
modules[group] ||= begin
|
13
13
|
Module.new.tap { |mod| group.prepend(mod) }
|
14
14
|
end
|
15
15
|
end
|
@@ -28,7 +28,7 @@ module TestProf
|
|
28
28
|
# Use uniq prefix for instance variables to avoid collisions
|
29
29
|
# We want to use the power of Ruby's unicode support)
|
30
30
|
# And we love cats!)
|
31
|
-
PREFIX = RUBY_ENGINE == 'jruby' ? "@__jruby_is_not_cat_friendly__"
|
31
|
+
PREFIX = RUBY_ENGINE == 'jruby' ? "@__jruby_is_not_cat_friendly__" : "@😸"
|
32
32
|
|
33
33
|
def let_it_be(identifier, **options, &block)
|
34
34
|
unless LetItBe.supported?
|
@@ -3,12 +3,10 @@
|
|
3
3
|
require "test_prof/utils/sized_ordered_set"
|
4
4
|
require "test_prof/ext/float_duration"
|
5
5
|
require "test_prof/ext/string_truncate"
|
6
|
-
require "test_prof/ext/string_strip_heredoc"
|
7
6
|
|
8
7
|
module TestProf # :nodoc: all
|
9
8
|
using FloatDuration
|
10
9
|
using StringTruncate
|
11
|
-
using StringStripHeredoc
|
12
10
|
|
13
11
|
module RSpecDissect
|
14
12
|
module Collectors
|
@@ -44,7 +42,7 @@ module TestProf # :nodoc: all
|
|
44
42
|
end
|
45
43
|
|
46
44
|
def print_result_header
|
47
|
-
|
45
|
+
<<~MSG
|
48
46
|
|
49
47
|
Top #{top_count} slowest suites (by `#{print_name}` time):
|
50
48
|
|
@@ -52,7 +50,7 @@ module TestProf # :nodoc: all
|
|
52
50
|
end
|
53
51
|
|
54
52
|
def print_group_result(group)
|
55
|
-
|
53
|
+
<<~GROUP
|
56
54
|
#{group[:desc].truncate} (#{group[:loc]}) – #{group[name].duration} of #{group[:total].duration} (#{group[:count]})
|
57
55
|
GROUP
|
58
56
|
end
|
@@ -1,14 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "test_prof/ext/float_duration"
|
4
|
-
require "test_prof/ext/string_strip_heredoc"
|
5
4
|
|
6
5
|
module TestProf
|
7
6
|
module RSpecDissect
|
8
7
|
class Listener # :nodoc:
|
9
8
|
include Logging
|
10
9
|
using FloatDuration
|
11
|
-
using StringStripHeredoc
|
12
10
|
|
13
11
|
NOTIFICATIONS = %i[
|
14
12
|
example_group_finished
|
@@ -63,7 +61,7 @@ module TestProf
|
|
63
61
|
msgs = []
|
64
62
|
|
65
63
|
msgs <<
|
66
|
-
|
64
|
+
<<~MSG
|
67
65
|
RSpecDissect report
|
68
66
|
|
69
67
|
Total time: #{@total_examples_time.duration}
|
@@ -104,7 +102,7 @@ module TestProf
|
|
104
102
|
msgs = []
|
105
103
|
|
106
104
|
msgs <<
|
107
|
-
|
105
|
+
<<~MSG
|
108
106
|
RSpec Stamp results
|
109
107
|
|
110
108
|
Total patches: #{stamper.total}
|
@@ -141,6 +139,6 @@ TestProf.activate('RD_PROF') do
|
|
141
139
|
)
|
142
140
|
end
|
143
141
|
|
144
|
-
config.after(:suite) { listener
|
142
|
+
config.after(:suite) { listener&.print }
|
145
143
|
end
|
146
144
|
end
|
@@ -1,12 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "test_prof/ext/string_strip_heredoc"
|
4
|
-
|
5
3
|
module TestProf
|
6
4
|
module RSpecStamp
|
7
5
|
class RSpecListener # :nodoc:
|
8
6
|
include Logging
|
9
|
-
using StringStripHeredoc
|
10
7
|
|
11
8
|
NOTIFICATIONS = %i[
|
12
9
|
example_failed
|
@@ -39,7 +36,7 @@ module TestProf
|
|
39
36
|
msgs = []
|
40
37
|
|
41
38
|
msgs <<
|
42
|
-
|
39
|
+
<<~MSG
|
43
40
|
RSpec Stamp results
|
44
41
|
|
45
42
|
Total patches: #{stamper.total}
|
@@ -67,6 +64,6 @@ TestProf.activate('RSTAMP') do
|
|
67
64
|
)
|
68
65
|
end
|
69
66
|
|
70
|
-
config.after(:suite) { listener
|
67
|
+
config.after(:suite) { listener&.stamp! }
|
71
68
|
end
|
72
69
|
end
|
data/lib/test_prof/ruby_prof.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "test_prof/ext/string_strip_heredoc"
|
4
|
-
|
5
3
|
module TestProf
|
6
4
|
# RubyProf wrapper.
|
7
5
|
#
|
@@ -24,17 +22,6 @@ module TestProf
|
|
24
22
|
module RubyProf
|
25
23
|
# RubyProf configuration
|
26
24
|
class Configuration
|
27
|
-
# Default list of methods to exclude from profile.
|
28
|
-
# Contains a lot of RSpec stuff.
|
29
|
-
ELIMINATE_METHODS = [
|
30
|
-
/instance_exec/,
|
31
|
-
/ExampleGroup>?#run/,
|
32
|
-
/Procsy/,
|
33
|
-
/AroundHook#execute_with/,
|
34
|
-
/HookCollections/,
|
35
|
-
/Array#(map|each)/
|
36
|
-
].freeze
|
37
|
-
|
38
25
|
PRINTERS = {
|
39
26
|
'flat' => 'FlatPrinter',
|
40
27
|
'flat_wln' => 'FlatPrinterWithLineNumbers',
|
@@ -56,10 +43,12 @@ module TestProf
|
|
56
43
|
'call_stack' => 'html'
|
57
44
|
}.freeze
|
58
45
|
|
59
|
-
LOGFILE_PREFIX = "ruby-prof-report"
|
46
|
+
LOGFILE_PREFIX = "ruby-prof-report"
|
60
47
|
|
61
48
|
attr_accessor :printer, :mode, :min_percent,
|
62
|
-
:include_threads, :
|
49
|
+
:include_threads, :exclude_common_methods,
|
50
|
+
:test_prof_exclusions_enabled,
|
51
|
+
:custom_exclusions
|
63
52
|
|
64
53
|
def initialize
|
65
54
|
@printer = ENV['TEST_RUBY_PROF'].to_sym if PRINTERS.key?(ENV['TEST_RUBY_PROF'])
|
@@ -67,16 +56,21 @@ module TestProf
|
|
67
56
|
@mode = ENV.fetch('TEST_RUBY_PROF_MODE', :wall).to_sym
|
68
57
|
@min_percent = 1
|
69
58
|
@include_threads = false
|
70
|
-
@
|
59
|
+
@exclude_common_methods = true
|
60
|
+
@test_prof_exclusions_enabled = true
|
61
|
+
@custom_exclusions = {}
|
71
62
|
end
|
72
63
|
|
73
64
|
def include_threads?
|
74
65
|
include_threads == true
|
75
66
|
end
|
76
67
|
|
77
|
-
def
|
78
|
-
|
79
|
-
|
68
|
+
def exclude_common_methods?
|
69
|
+
exclude_common_methods == true
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_prof_exclusions_enabled?
|
73
|
+
@test_prof_exclusions_enabled == true
|
80
74
|
end
|
81
75
|
|
82
76
|
# Returns an array of printer type (ID) and class.
|
@@ -105,9 +99,6 @@ module TestProf
|
|
105
99
|
def dump(name)
|
106
100
|
result = @profiler.stop
|
107
101
|
|
108
|
-
result.eliminate_methods!(config.eliminate_methods) if
|
109
|
-
config.eliminate_methods?
|
110
|
-
|
111
102
|
printer_type, printer_class = config.resolve_printer
|
112
103
|
|
113
104
|
if %w[call_tree multi].include?(printer_type)
|
@@ -145,7 +136,6 @@ module TestProf
|
|
145
136
|
|
146
137
|
class << self
|
147
138
|
include Logging
|
148
|
-
using StringStripHeredoc
|
149
139
|
|
150
140
|
def config
|
151
141
|
@config ||= Configuration.new
|
@@ -183,6 +173,20 @@ module TestProf
|
|
183
173
|
config.include_threads?
|
184
174
|
|
185
175
|
profiler = ::RubyProf::Profile.new(options)
|
176
|
+
profiler.exclude_common_methods! if config.exclude_common_methods?
|
177
|
+
|
178
|
+
if config.test_prof_exclusions_enabled?
|
179
|
+
# custom test-prof exclusions
|
180
|
+
exclude_rspec_methods(profiler)
|
181
|
+
|
182
|
+
# custom global exclusions
|
183
|
+
exclude_common_methods(profiler)
|
184
|
+
end
|
185
|
+
|
186
|
+
config.custom_exclusions.each do |klass, mids|
|
187
|
+
profiler.exclude_methods! klass, *mids
|
188
|
+
end
|
189
|
+
|
186
190
|
profiler.start
|
187
191
|
|
188
192
|
Report.new(profiler)
|
@@ -199,7 +203,7 @@ module TestProf
|
|
199
203
|
ENV["RUBY_PROF_MEASURE_MODE"] = config.mode.to_s
|
200
204
|
@initialized = TestProf.require(
|
201
205
|
'ruby-prof',
|
202
|
-
|
206
|
+
<<~MSG
|
203
207
|
Please, install 'ruby-prof' first:
|
204
208
|
# Gemfile
|
205
209
|
gem 'ruby-prof', '>= 0.16.0', require: false
|
@@ -208,20 +212,49 @@ module TestProf
|
|
208
212
|
end
|
209
213
|
|
210
214
|
def check_ruby_prof_version
|
211
|
-
if Utils.verify_gem_version('ruby-prof', at_least: '0.
|
215
|
+
if Utils.verify_gem_version('ruby-prof', at_least: '0.17.0')
|
212
216
|
true
|
213
217
|
else
|
214
|
-
log :error,
|
215
|
-
Please, upgrade 'ruby-prof' to version >= 0.
|
218
|
+
log :error, <<~MGS
|
219
|
+
Please, upgrade 'ruby-prof' to version >= 0.17.0.
|
216
220
|
MGS
|
217
221
|
false
|
218
222
|
end
|
219
223
|
end
|
224
|
+
|
225
|
+
def exclude_rspec_methods(profiler)
|
226
|
+
return unless defined?(RSpec::Core)
|
227
|
+
|
228
|
+
RSpecExclusions.generate.each do |klass, mids|
|
229
|
+
profiler.exclude_methods!(klass, *mids)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def exclude_common_methods(profiler)
|
234
|
+
profiler.exclude_methods!(
|
235
|
+
TSort,
|
236
|
+
:tsort_each
|
237
|
+
)
|
238
|
+
|
239
|
+
profiler.exclude_methods!(
|
240
|
+
TSort.singleton_class,
|
241
|
+
:tsort_each, :each_strongly_connected_component,
|
242
|
+
:each_strongly_connected_component_from
|
243
|
+
)
|
244
|
+
|
245
|
+
profiler.exclude_methods!(
|
246
|
+
BasicObject,
|
247
|
+
:instance_exec
|
248
|
+
)
|
249
|
+
end
|
220
250
|
end
|
221
251
|
end
|
222
252
|
end
|
223
253
|
|
224
|
-
|
254
|
+
if defined?(RSpec::Core)
|
255
|
+
require "test_prof/ruby_prof/rspec"
|
256
|
+
require "test_prof/ruby_prof/rspec_exclusions"
|
257
|
+
end
|
225
258
|
|
226
259
|
# Hook to run RubyProf globally
|
227
260
|
TestProf.activate('TEST_RUBY_PROF') do
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TestProf
|
4
|
+
module RubyProf
|
5
|
+
# Generates the list of RSpec (framework internal) methods
|
6
|
+
# to exclude from profiling
|
7
|
+
module RSpecExclusions
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def generate
|
11
|
+
{
|
12
|
+
RSpec::Core::Runner => %i[
|
13
|
+
run
|
14
|
+
run_specs
|
15
|
+
],
|
16
|
+
|
17
|
+
RSpec::Core::ExampleGroup => %i[
|
18
|
+
run
|
19
|
+
run_examples
|
20
|
+
],
|
21
|
+
|
22
|
+
RSpec::Core::ExampleGroup.singleton_class => %i[
|
23
|
+
run
|
24
|
+
run_examples
|
25
|
+
],
|
26
|
+
|
27
|
+
RSpec::Core::Example => %i[
|
28
|
+
run
|
29
|
+
with_around_and_singleton_context_hooks
|
30
|
+
with_around_example_hooks
|
31
|
+
instance_exec
|
32
|
+
run_before_example
|
33
|
+
],
|
34
|
+
|
35
|
+
RSpec::Core::Example.singleton_class => %i[
|
36
|
+
run
|
37
|
+
with_around_and_singleton_context_hooks
|
38
|
+
with_around_example_hooks
|
39
|
+
],
|
40
|
+
|
41
|
+
RSpec::Core::Example::Procsy => [
|
42
|
+
:call
|
43
|
+
],
|
44
|
+
|
45
|
+
RSpec::Core::Hooks::HookCollections => %i[
|
46
|
+
run
|
47
|
+
run_around_example_hooks_for
|
48
|
+
run_example_hooks_for
|
49
|
+
run_owned_hooks_for
|
50
|
+
],
|
51
|
+
|
52
|
+
RSpec::Core::Hooks::BeforeHook => [
|
53
|
+
:run
|
54
|
+
],
|
55
|
+
|
56
|
+
RSpec::Core::Hooks::AroundHook => [
|
57
|
+
:execute_with
|
58
|
+
],
|
59
|
+
|
60
|
+
RSpec::Core::Configuration => [
|
61
|
+
:with_suite_hooks
|
62
|
+
],
|
63
|
+
|
64
|
+
RSpec::Core::Reporter => [
|
65
|
+
:report
|
66
|
+
]
|
67
|
+
}.tap do |data|
|
68
|
+
if defined?(RSpec::Support::ReentrantMutex)
|
69
|
+
data[RSpec::Support::ReentrantMutex] = [
|
70
|
+
:synchronize
|
71
|
+
]
|
72
|
+
end
|
73
|
+
|
74
|
+
if defined?(RSpec::Core::MemoizedHelpers::ThreadsafeMemoized)
|
75
|
+
data.merge!(
|
76
|
+
RSpec::Core::MemoizedHelpers::ThreadsafeMemoized => [
|
77
|
+
:fetch_or_store
|
78
|
+
],
|
79
|
+
|
80
|
+
RSpec::Core::MemoizedHelpers::NonThreadSafeMemoized => [
|
81
|
+
:fetch_or_store
|
82
|
+
],
|
83
|
+
|
84
|
+
RSpec::Core::MemoizedHelpers::ContextHookMemoized => [
|
85
|
+
:fetch_or_store
|
86
|
+
]
|
87
|
+
)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/lib/test_prof/stack_prof.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "test_prof/ext/string_strip_heredoc"
|
4
|
-
|
5
3
|
module TestProf
|
6
4
|
# StackProf wrapper.
|
7
5
|
#
|
@@ -47,7 +45,6 @@ module TestProf
|
|
47
45
|
|
48
46
|
class << self
|
49
47
|
include Logging
|
50
|
-
using StringStripHeredoc
|
51
48
|
|
52
49
|
def config
|
53
50
|
@config ||= Configuration.new
|
@@ -103,7 +100,7 @@ module TestProf
|
|
103
100
|
|
104
101
|
html_path = path.gsub(/\.dump$/, '.html')
|
105
102
|
|
106
|
-
log :info,
|
103
|
+
log :info, <<~MSG
|
107
104
|
Run the following command to generate a flame graph report:
|
108
105
|
|
109
106
|
stackprof --flamegraph #{path} > #{html_path} && stackprof --flamegraph-viewer=#{html_path}
|
@@ -126,7 +123,7 @@ module TestProf
|
|
126
123
|
return @initialized if instance_variable_defined?(:@initialized)
|
127
124
|
@initialized = TestProf.require(
|
128
125
|
'stackprof',
|
129
|
-
|
126
|
+
<<~MSG
|
130
127
|
Please, install 'stackprof' first:
|
131
128
|
# Gemfile
|
132
129
|
gem 'stackprof', '>= 0.2.9', require: false
|
@@ -138,7 +135,7 @@ module TestProf
|
|
138
135
|
if Utils.verify_gem_version('stackprof', at_least: '0.2.9')
|
139
136
|
true
|
140
137
|
else
|
141
|
-
log :error,
|
138
|
+
log :error, <<~MSG
|
142
139
|
Please, upgrade 'stackprof' to version >= 0.2.9.
|
143
140
|
MSG
|
144
141
|
false
|
@@ -3,8 +3,8 @@
|
|
3
3
|
module TestProf::TagProf
|
4
4
|
module Printers
|
5
5
|
module HTML # :nodoc: all
|
6
|
-
TEMPLATE = "tagprof.template.html"
|
7
|
-
OUTPUT_NAME = "tag-prof.html"
|
6
|
+
TEMPLATE = "tagprof.template.html"
|
7
|
+
OUTPUT_NAME = "tag-prof.html"
|
8
8
|
|
9
9
|
class << self
|
10
10
|
include TestProf::Logging
|
@@ -1,21 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "test_prof/ext/float_duration"
|
4
|
-
require "test_prof/ext/string_strip_heredoc"
|
5
4
|
|
6
5
|
module TestProf::TagProf
|
7
6
|
module Printers
|
8
7
|
module Simple # :nodoc: all
|
9
8
|
class << self
|
10
9
|
include TestProf::Logging
|
11
|
-
using TestProf::StringStripHeredoc
|
12
10
|
using TestProf::FloatDuration
|
13
11
|
|
14
12
|
def dump(result)
|
15
13
|
msgs = []
|
16
14
|
|
17
15
|
msgs <<
|
18
|
-
|
16
|
+
<<~MSG
|
19
17
|
TagProf report for #{result.tag}
|
20
18
|
MSG
|
21
19
|
|
@@ -33,7 +33,7 @@ module TestProf
|
|
33
33
|
def example_started(_notification)
|
34
34
|
@ts = TestProf.now
|
35
35
|
# enable event profiling
|
36
|
-
@events_profiler
|
36
|
+
@events_profiler&.group_started(true)
|
37
37
|
end
|
38
38
|
|
39
39
|
def example_finished(notification)
|
@@ -42,7 +42,7 @@ module TestProf
|
|
42
42
|
result.track(tag, time: TestProf.now - @ts, events: fetch_events_data)
|
43
43
|
|
44
44
|
# reset and disable event profilers
|
45
|
-
@events_profiler
|
45
|
+
@events_profiler&.group_started(nil)
|
46
46
|
end
|
47
47
|
|
48
48
|
# NOTE: RSpec < 3.4.0 doesn't have example_finished event
|
@@ -80,7 +80,7 @@ TestProf.activate('TAG_PROF') do
|
|
80
80
|
)
|
81
81
|
end
|
82
82
|
|
83
|
-
config.after(:suite) { listener
|
83
|
+
config.after(:suite) { listener&.report }
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
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.
|
4
|
+
version: 0.7.0
|
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-08-13 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.58.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.58.0
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rubocop-md
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,7 +142,6 @@ files:
|
|
142
142
|
- lib/test_prof/ext/active_record_refind.rb
|
143
143
|
- lib/test_prof/ext/array_bsearch_index.rb
|
144
144
|
- lib/test_prof/ext/float_duration.rb
|
145
|
-
- lib/test_prof/ext/string_strip_heredoc.rb
|
146
145
|
- lib/test_prof/ext/string_truncate.rb
|
147
146
|
- lib/test_prof/factory_all_stub.rb
|
148
147
|
- lib/test_prof/factory_all_stub/factory_bot_patch.rb
|
@@ -183,6 +182,7 @@ files:
|
|
183
182
|
- lib/test_prof/rubocop.rb
|
184
183
|
- lib/test_prof/ruby_prof.rb
|
185
184
|
- lib/test_prof/ruby_prof/rspec.rb
|
185
|
+
- lib/test_prof/ruby_prof/rspec_exclusions.rb
|
186
186
|
- lib/test_prof/stack_prof.rb
|
187
187
|
- lib/test_prof/stack_prof/rspec.rb
|
188
188
|
- lib/test_prof/tag_prof.rb
|
@@ -206,7 +206,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
206
206
|
requirements:
|
207
207
|
- - ">="
|
208
208
|
- !ruby/object:Gem::Version
|
209
|
-
version: 2.
|
209
|
+
version: 2.3.0
|
210
210
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
211
211
|
requirements:
|
212
212
|
- - ">="
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module TestProf
|
4
|
-
# Add #strip_heredoc method to use instead of
|
5
|
-
# squiggly docs (to support older Rubies)
|
6
|
-
module StringStripHeredoc
|
7
|
-
refine String do
|
8
|
-
def strip_heredoc
|
9
|
-
min = scan(/^[ \t]*(?=\S)/).min
|
10
|
-
indent = min ? min.size : 0
|
11
|
-
gsub(/^[ \t]{#{indent}}/, '')
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|