test-prof 0.7.5 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|