test-prof 0.7.5 → 0.8.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 -2
- data/README.md +5 -3
- data/lib/minitest/base_reporter.rb +18 -12
- data/lib/minitest/test_prof_plugin.rb +8 -8
- data/lib/test_prof.rb +3 -3
- data/lib/test_prof/any_fixture.rb +3 -3
- data/lib/test_prof/before_all.rb +9 -0
- data/lib/test_prof/before_all/adapters/active_record.rb +12 -0
- data/lib/test_prof/before_all/isolator.rb +18 -0
- data/lib/test_prof/cops/rspec/aggregate_failures.rb +6 -6
- data/lib/test_prof/event_prof.rb +6 -6
- data/lib/test_prof/event_prof/custom_events/factory_create.rb +1 -1
- data/lib/test_prof/event_prof/custom_events/sidekiq_inline.rb +2 -2
- data/lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb +2 -2
- data/lib/test_prof/event_prof/instrumentations/active_support.rb +1 -1
- data/lib/test_prof/event_prof/minitest.rb +4 -4
- data/lib/test_prof/event_prof/rspec.rb +4 -11
- data/lib/test_prof/factory_bot.rb +1 -1
- data/lib/test_prof/factory_default.rb +1 -1
- data/lib/test_prof/factory_doctor.rb +2 -2
- data/lib/test_prof/factory_doctor/minitest.rb +4 -4
- data/lib/test_prof/factory_doctor/rspec.rb +7 -10
- data/lib/test_prof/factory_prof.rb +6 -6
- data/lib/test_prof/factory_prof/factory_builders/fabrication.rb +1 -1
- data/lib/test_prof/factory_prof/printers/flamegraph.rb +1 -1
- data/lib/test_prof/recipes/logging.rb +86 -21
- data/lib/test_prof/recipes/minitest/before_all.rb +3 -2
- data/lib/test_prof/recipes/minitest/sample.rb +5 -5
- data/lib/test_prof/recipes/rspec/any_fixture.rb +3 -1
- data/lib/test_prof/recipes/rspec/before_all.rb +12 -3
- data/lib/test_prof/recipes/rspec/factory_all_stub.rb +5 -1
- data/lib/test_prof/recipes/rspec/let_it_be.rb +3 -13
- data/lib/test_prof/rspec_dissect.rb +13 -19
- data/lib/test_prof/rspec_dissect/rspec.rb +2 -6
- data/lib/test_prof/rspec_stamp.rb +14 -14
- data/lib/test_prof/rspec_stamp/parser.rb +1 -1
- data/lib/test_prof/rspec_stamp/rspec.rb +1 -1
- data/lib/test_prof/ruby_prof.rb +32 -24
- data/lib/test_prof/ruby_prof/rspec.rb +2 -6
- data/lib/test_prof/stack_prof.rb +23 -15
- data/lib/test_prof/stack_prof/rspec.rb +5 -6
- data/lib/test_prof/tag_prof/printers/simple.rb +4 -4
- data/lib/test_prof/tag_prof/result.rb +3 -3
- data/lib/test_prof/tag_prof/rspec.rb +9 -14
- data/lib/test_prof/utils/html_builder.rb +1 -1
- data/lib/test_prof/utils/sized_ordered_set.rb +1 -1
- data/lib/test_prof/version.rb +1 -1
- metadata +37 -9
@@ -14,15 +14,13 @@ module TestProf
|
|
14
14
|
example_group_started
|
15
15
|
example_group_finished
|
16
16
|
example_started
|
17
|
-
|
18
|
-
example_passed
|
19
|
-
example_pending
|
17
|
+
example_finished
|
20
18
|
].freeze
|
21
19
|
|
22
20
|
def initialize
|
23
21
|
@profiler = EventProf.build
|
24
22
|
|
25
|
-
log :info, "EventProf enabled (#{@profiler.events.join(
|
23
|
+
log :info, "EventProf enabled (#{@profiler.events.join(", ")})"
|
26
24
|
end
|
27
25
|
|
28
26
|
def example_group_started(notification)
|
@@ -43,11 +41,6 @@ module TestProf
|
|
43
41
|
@profiler.example_finished notification.example
|
44
42
|
end
|
45
43
|
|
46
|
-
# NOTE: RSpec < 3.4.0 doesn't have example_finished event
|
47
|
-
alias example_passed example_finished
|
48
|
-
alias example_failed example_finished
|
49
|
-
alias example_pending example_finished
|
50
|
-
|
51
44
|
def print
|
52
45
|
@profiler.each(&method(:report))
|
53
46
|
end
|
@@ -145,8 +138,8 @@ module TestProf
|
|
145
138
|
end
|
146
139
|
|
147
140
|
# Register EventProf listener
|
148
|
-
TestProf.activate(
|
149
|
-
TestProf::EventProf::CustomEvents.activate_all(ENV[
|
141
|
+
TestProf.activate("EVENT_PROF") do
|
142
|
+
TestProf::EventProf::CustomEvents.activate_all(ENV["EVENT_PROF"])
|
150
143
|
|
151
144
|
RSpec.configure do |config|
|
152
145
|
listener = nil
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module TestProf # :nodoc: all
|
4
|
-
FACTORY_GIRL_NAMES = {
|
4
|
+
FACTORY_GIRL_NAMES = {"factory_bot" => "::FactoryBot", "factory_girl" => "::FactoryGirl"}.freeze
|
5
5
|
|
6
6
|
FACTORY_GIRL_NAMES.find do |name, cname|
|
7
7
|
TestProf.require(name) do
|
@@ -45,7 +45,7 @@ module TestProf
|
|
45
45
|
attr_reader :count, :time, :queries_count
|
46
46
|
|
47
47
|
# Patch factory lib, init counters
|
48
|
-
def init(event =
|
48
|
+
def init(event = "sql.active_record")
|
49
49
|
@event = event
|
50
50
|
reset!
|
51
51
|
|
@@ -57,7 +57,7 @@ module TestProf
|
|
57
57
|
|
58
58
|
subscribe!
|
59
59
|
|
60
|
-
@stamp = ENV[
|
60
|
+
@stamp = ENV["FDOC_STAMP"]
|
61
61
|
|
62
62
|
RSpecStamp.config.tags = @stamp if stamp?
|
63
63
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "minitest/base_reporter"
|
4
|
+
require "test_prof/ext/float_duration"
|
5
5
|
|
6
6
|
module Minitest
|
7
7
|
module TestProf # :nodoc:
|
@@ -47,7 +47,7 @@ module Minitest
|
|
47
47
|
}
|
48
48
|
|
49
49
|
@example_groups[group] << {
|
50
|
-
description: example.name.gsub(/^test_(?:\d+_)?/,
|
50
|
+
description: example.name.gsub(/^test_(?:\d+_)?/, ""),
|
51
51
|
location: location_with_line_number(example),
|
52
52
|
factories: result.count,
|
53
53
|
time: result.time
|
@@ -87,7 +87,7 @@ module Minitest
|
|
87
87
|
private
|
88
88
|
|
89
89
|
def pluralize_records(count)
|
90
|
-
count == 1 ?
|
90
|
+
count == 1 ? "1 record" : "#{count} records"
|
91
91
|
end
|
92
92
|
end
|
93
93
|
end
|
@@ -12,9 +12,7 @@ module TestProf
|
|
12
12
|
|
13
13
|
NOTIFICATIONS = %i[
|
14
14
|
example_started
|
15
|
-
|
16
|
-
example_failed
|
17
|
-
example_pending
|
15
|
+
example_finished
|
18
16
|
].freeze
|
19
17
|
|
20
18
|
def initialize
|
@@ -45,11 +43,6 @@ module TestProf
|
|
45
43
|
@time += result.time
|
46
44
|
end
|
47
45
|
|
48
|
-
# NOTE: RSpec < 3.4.0 doesn't have example_finished event
|
49
|
-
alias example_passed example_finished
|
50
|
-
alias example_failed example_finished
|
51
|
-
alias example_pending example_finished
|
52
|
-
|
53
46
|
def print
|
54
47
|
return log(:info, SUCCESS_MESSAGE) if @example_groups.empty?
|
55
48
|
|
@@ -122,7 +115,7 @@ module TestProf
|
|
122
115
|
end
|
123
116
|
|
124
117
|
# Register FactoryDoctor listener
|
125
|
-
TestProf.activate(
|
118
|
+
TestProf.activate("FDOC") do
|
126
119
|
TestProf::FactoryDoctor.init
|
127
120
|
|
128
121
|
RSpec.configure do |config|
|
@@ -138,7 +131,11 @@ TestProf.activate('FDOC') do
|
|
138
131
|
config.after(:suite) { listener&.print }
|
139
132
|
end
|
140
133
|
|
141
|
-
RSpec.shared_context "factory_doctor:ignore"
|
134
|
+
RSpec.shared_context "factory_doctor:ignore" do
|
142
135
|
around(:each) { |ex| TestProf::FactoryDoctor.ignore(&ex) }
|
143
136
|
end
|
137
|
+
|
138
|
+
RSpec.configure do |config|
|
139
|
+
config.include_context "factory_doctor:ignore", fd_ignore: true
|
140
|
+
end
|
144
141
|
end
|
@@ -17,7 +17,7 @@ module TestProf
|
|
17
17
|
attr_accessor :mode
|
18
18
|
|
19
19
|
def initialize
|
20
|
-
@mode = ENV[
|
20
|
+
@mode = ENV["FPROF"] == "flamegraph" ? :flamegraph : :simple
|
21
21
|
end
|
22
22
|
|
23
23
|
# Whether we want to generate flamegraphs
|
@@ -39,7 +39,7 @@ module TestProf
|
|
39
39
|
return @stats if instance_variable_defined?(:@stats)
|
40
40
|
|
41
41
|
@stats = @raw_stats.values
|
42
|
-
|
42
|
+
.sort_by { |el| -el[:total] }
|
43
43
|
end
|
44
44
|
|
45
45
|
def total
|
@@ -51,8 +51,8 @@ module TestProf
|
|
51
51
|
|
52
52
|
def sorted_stats(key)
|
53
53
|
@raw_stats.values
|
54
|
-
|
55
|
-
|
54
|
+
.map { |el| [el[:name], el[key]] }
|
55
|
+
.sort_by { |el| -el[1] }
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -120,7 +120,7 @@ module TestProf
|
|
120
120
|
def reset!
|
121
121
|
@stacks = [] if config.flamegraph?
|
122
122
|
@depth = 0
|
123
|
-
@stats = Hash.new { |h, k| h[k] = {
|
123
|
+
@stats = Hash.new { |h, k| h[k] = {name: k, total: 0, top_level: 0} }
|
124
124
|
flush_stack
|
125
125
|
end
|
126
126
|
|
@@ -137,6 +137,6 @@ module TestProf
|
|
137
137
|
end
|
138
138
|
end
|
139
139
|
|
140
|
-
TestProf.activate(
|
140
|
+
TestProf.activate("FPROF") do
|
141
141
|
TestProf::FactoryProf.run
|
142
142
|
end
|
@@ -45,7 +45,7 @@ module TestProf::FactoryProf
|
|
45
45
|
node = paths[path]
|
46
46
|
node[:value] += 1
|
47
47
|
else
|
48
|
-
node = {
|
48
|
+
node = {name: sample, value: 1, total: result.raw_stats.fetch(sample)[:total]}
|
49
49
|
paths[path] = node
|
50
50
|
|
51
51
|
if parent.nil?
|
@@ -2,44 +2,109 @@
|
|
2
2
|
|
3
3
|
require "test_prof"
|
4
4
|
|
5
|
+
module TestProf
|
6
|
+
module Rails
|
7
|
+
# Add `with_logging` and `with_ar_logging helpers`
|
8
|
+
module LoggingHelpers
|
9
|
+
class << self
|
10
|
+
attr_writer :logger
|
11
|
+
|
12
|
+
def logger
|
13
|
+
return @logger if instance_variable_defined?(:@logger)
|
14
|
+
|
15
|
+
@logger = Logger.new(STDOUT)
|
16
|
+
end
|
17
|
+
|
18
|
+
def ar_loggables
|
19
|
+
return @ar_loggables if instance_variable_defined?(:@ar_loggables)
|
20
|
+
|
21
|
+
@ar_loggables = [
|
22
|
+
::ActiveRecord::Base,
|
23
|
+
::ActiveSupport::LogSubscriber
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
28
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
29
|
+
def all_loggables
|
30
|
+
return @all_loggables if instance_variable_defined?(:@all_loggables)
|
31
|
+
|
32
|
+
@all_loggables = [
|
33
|
+
::ActiveSupport::LogSubscriber,
|
34
|
+
::Rails,
|
35
|
+
defined?(::ActiveRecord::Base) && ::ActiveRecord::Base,
|
36
|
+
defined?(::ActiveJob::Base) && ::ActiveJob::Base,
|
37
|
+
defined?(::ActionView::Base) && ::ActionView::Base,
|
38
|
+
defined?(::ActionMailer::Base) && ::ActionMailer::Base,
|
39
|
+
defined?(::ActionCable::Server::Base.config) && ::ActionCable::Server::Base.config,
|
40
|
+
defined?(::ActiveStorage) && ::ActiveStorage
|
41
|
+
].compact
|
42
|
+
end
|
43
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
44
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
45
|
+
|
46
|
+
def swap_logger(loggables)
|
47
|
+
loggables.map do |loggable|
|
48
|
+
was_logger = loggable.logger
|
49
|
+
loggable.logger = logger
|
50
|
+
was_logger
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def restore_logger(was_loggers, loggables)
|
55
|
+
loggables.each_with_index do |loggable, i|
|
56
|
+
loggable.logger = was_loggers[i]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Enable verbose Rails logging within a block
|
62
|
+
def with_logging
|
63
|
+
*loggers = LoggingHelpers.swap_logger(LoggingHelpers.all_loggables)
|
64
|
+
yield
|
65
|
+
ensure
|
66
|
+
LoggingHelpers.restore_logger(loggers, LoggingHelpers.all_loggables)
|
67
|
+
end
|
68
|
+
|
69
|
+
def with_ar_logging
|
70
|
+
*loggers = LoggingHelpers.swap_logger(LoggingHelpers.ar_loggables)
|
71
|
+
yield
|
72
|
+
ensure
|
73
|
+
LoggingHelpers.restore_logger(loggers, LoggingHelpers.ar_loggables)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
5
79
|
if TestProf.rspec?
|
6
|
-
RSpec.shared_context "logging:verbose"
|
80
|
+
RSpec.shared_context "logging:verbose" do
|
7
81
|
around(:each) do |ex|
|
8
|
-
|
9
|
-
Rails.logger,
|
10
|
-
ActiveRecord::Base.logger
|
11
|
-
ActiveSupport::LogSubscriber.logger =
|
12
|
-
Rails.logger =
|
13
|
-
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
14
|
-
ex.run
|
15
|
-
ActiveSupport::LogSubscriber.logger,
|
16
|
-
Rails.logger,
|
17
|
-
ActiveRecord::Base.logger = *loggers
|
82
|
+
with_logging(&ex)
|
18
83
|
end
|
19
84
|
end
|
20
85
|
|
21
|
-
RSpec.shared_context "logging:active_record"
|
86
|
+
RSpec.shared_context "logging:active_record" do
|
22
87
|
around(:each) do |ex|
|
23
|
-
|
24
|
-
ActiveSupport::LogSubscriber.logger
|
25
|
-
ActiveSupport::LogSubscriber.logger =
|
26
|
-
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
27
|
-
ex.run
|
28
|
-
ActiveSupport::LogSubscriber.logger,
|
29
|
-
ActiveRecord::Base.logger = *loggers
|
88
|
+
with_ar_logging(&ex)
|
30
89
|
end
|
31
90
|
end
|
91
|
+
|
92
|
+
RSpec.configure do |config|
|
93
|
+
config.include TestProf::Rails::LoggingHelpers
|
94
|
+
config.include_context "logging:active_record", log: :ar
|
95
|
+
config.include_context "logging:verbose", log: true
|
96
|
+
end
|
32
97
|
end
|
33
98
|
|
34
99
|
TestProf.activate("LOG", "all") do
|
35
100
|
TestProf.log :info, "Rails verbose logging enabled"
|
36
101
|
ActiveSupport::LogSubscriber.logger =
|
37
102
|
Rails.logger =
|
38
|
-
ActiveRecord::Base.logger =
|
103
|
+
ActiveRecord::Base.logger = TestProf::Rails::LoggingHelpers.logger
|
39
104
|
end
|
40
105
|
|
41
106
|
TestProf.activate("LOG", "ar") do
|
42
107
|
TestProf.log :info, "Active Record verbose logging enabled"
|
43
108
|
ActiveSupport::LogSubscriber.logger =
|
44
|
-
ActiveRecord::Base.logger =
|
109
|
+
ActiveRecord::Base.logger = TestProf::Rails::LoggingHelpers.logger
|
45
110
|
end
|
@@ -14,7 +14,7 @@ module TestProf
|
|
14
14
|
def suites
|
15
15
|
# Make sure that sample contains only _real_ suites
|
16
16
|
Minitest::Runnable.runnables
|
17
|
-
|
17
|
+
.reject { |suite| CORE_RUNNABLES.include?(suite) }
|
18
18
|
end
|
19
19
|
|
20
20
|
def sample_groups(sample_size)
|
@@ -39,10 +39,10 @@ module TestProf
|
|
39
39
|
|
40
40
|
# Overrides Minitest.run
|
41
41
|
def run(*)
|
42
|
-
if ENV[
|
43
|
-
MinitestSample.sample_examples(ENV[
|
44
|
-
elsif ENV[
|
45
|
-
MinitestSample.sample_groups(ENV[
|
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)
|
46
46
|
end
|
47
47
|
super
|
48
48
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "test_prof/any_fixture"
|
4
4
|
require "test_prof/recipes/rspec/before_all"
|
5
5
|
|
6
|
-
RSpec.shared_context "any_fixture:clean"
|
6
|
+
RSpec.shared_context "any_fixture:clean" do
|
7
7
|
extend TestProf::BeforeAll::RSpec
|
8
8
|
|
9
9
|
before_all do
|
@@ -12,6 +12,8 @@ RSpec.shared_context "any_fixture:clean", with_clean_fixture: true do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
RSpec.configure do |config|
|
15
|
+
config.include_context "any_fixture:clean", with_clean_fixture: true
|
16
|
+
|
15
17
|
config.after(:suite) do
|
16
18
|
TestProf::AnyFixture.report_stats if TestProf::AnyFixture.reporting_enabled?
|
17
19
|
TestProf::AnyFixture.reset
|
@@ -9,13 +9,14 @@ module TestProf
|
|
9
9
|
def before_all(&block)
|
10
10
|
raise ArgumentError, "Block is required!" unless block_given?
|
11
11
|
|
12
|
-
return
|
12
|
+
return within_before_all(&block) if within_before_all?
|
13
13
|
|
14
14
|
@__before_all_activated__ = true
|
15
15
|
|
16
16
|
before(:all) do
|
17
|
-
BeforeAll.begin_transaction
|
18
|
-
|
17
|
+
BeforeAll.begin_transaction do
|
18
|
+
instance_eval(&block)
|
19
|
+
end
|
19
20
|
end
|
20
21
|
|
21
22
|
after(:all) do
|
@@ -23,6 +24,14 @@ module TestProf
|
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
27
|
+
def within_before_all(&block)
|
28
|
+
before(:all) do
|
29
|
+
BeforeAll.within_transaction do
|
30
|
+
instance_eval(&block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
26
35
|
def within_before_all?
|
27
36
|
instance_variable_defined?(:@__before_all_activated__)
|
28
37
|
end
|
@@ -4,7 +4,11 @@ require "test_prof/factory_all_stub"
|
|
4
4
|
|
5
5
|
TestProf::FactoryAllStub.init
|
6
6
|
|
7
|
-
RSpec.shared_context "factory:stub"
|
7
|
+
RSpec.shared_context "factory:stub" do
|
8
8
|
prepend_before(:all) { TestProf::FactoryAllStub.enable! }
|
9
9
|
append_after(:all) { TestProf::FactoryAllStub.disable! }
|
10
10
|
end
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.include_context "factory:stub", factory: :stub
|
14
|
+
end
|