test-prof 0.8.0 → 0.9.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 +156 -107
- data/LICENSE.txt +1 -1
- data/README.md +4 -0
- data/lib/test_prof.rb +3 -9
- data/lib/test_prof/before_all.rb +73 -2
- data/lib/test_prof/before_all/adapters/active_record.rb +11 -12
- data/lib/test_prof/event_prof/custom_events/factory_create.rb +27 -45
- data/lib/test_prof/event_prof/custom_events/sidekiq_inline.rb +7 -37
- data/lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb +6 -24
- data/lib/test_prof/event_prof/monitor.rb +45 -8
- data/lib/test_prof/ext/factory_bot_strategy.rb +24 -0
- data/lib/test_prof/factory_doctor.rb +28 -6
- data/lib/test_prof/factory_doctor/fabrication_patch.rb +12 -0
- data/lib/test_prof/factory_doctor/factory_bot_patch.rb +5 -1
- data/lib/test_prof/factory_doctor/rspec.rb +8 -2
- data/lib/test_prof/factory_prof.rb +25 -11
- data/lib/test_prof/factory_prof/factory_builders/factory_bot.rb +2 -17
- data/lib/test_prof/factory_prof/printers/flamegraph.rb +6 -2
- data/lib/test_prof/factory_prof/printers/simple.rb +8 -6
- data/lib/test_prof/recipes/rspec/let_it_be.rb +25 -0
- data/lib/test_prof/version.rb +1 -1
- metadata +13 -20
@@ -1,11 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "test_prof/ext/factory_bot_strategy"
|
4
|
+
|
3
5
|
module TestProf
|
4
6
|
module FactoryDoctor
|
5
7
|
# Wrap #run method with FactoryDoctor tracking
|
6
8
|
module FactoryBotPatch
|
9
|
+
using TestProf::FactoryBotStrategy
|
10
|
+
|
7
11
|
def run(strategy = @strategy)
|
8
|
-
FactoryDoctor.within_factory(strategy) { super }
|
12
|
+
FactoryDoctor.within_factory(strategy.create? ? :create : :other) { super }
|
9
13
|
end
|
10
14
|
end
|
11
15
|
end
|
@@ -58,9 +58,15 @@ module TestProf
|
|
58
58
|
MSG
|
59
59
|
|
60
60
|
@example_groups.each do |group, examples|
|
61
|
-
|
61
|
+
group_time = examples.sum { |ex| ex.metadata[:time] }
|
62
|
+
group_count = examples.sum { |ex| ex.metadata[:factories] }
|
63
|
+
|
64
|
+
msgs << "#{group.description} (#{group.metadata[:location]}) " \
|
65
|
+
"(#{pluralize_records(group_count)} created, " \
|
66
|
+
"#{group_time.duration})\n"
|
67
|
+
|
62
68
|
examples.each do |ex|
|
63
|
-
msgs << " #{ex.description} (#{ex.metadata[:location]}) "\
|
69
|
+
msgs << " #{ex.description} (#{ex.metadata[:location]}) " \
|
64
70
|
"– #{pluralize_records(ex.metadata[:factories])} created, "\
|
65
71
|
"#{ex.metadata[:time].duration}\n"
|
66
72
|
end
|
@@ -36,15 +36,16 @@ module TestProf
|
|
36
36
|
|
37
37
|
# Returns sorted stats
|
38
38
|
def stats
|
39
|
-
|
39
|
+
@stats ||= @raw_stats.values
|
40
|
+
.sort_by { |el| -el[:total_count] }
|
41
|
+
end
|
40
42
|
|
41
|
-
|
42
|
-
|
43
|
+
def total_count
|
44
|
+
@total_count ||= @raw_stats.values.sum { |v| v[:total_count] }
|
43
45
|
end
|
44
46
|
|
45
|
-
def
|
46
|
-
|
47
|
-
@total = @raw_stats.values.sum { |v| v[:total] }
|
47
|
+
def total_time
|
48
|
+
@total_time ||= @raw_stats.values.sum { |v| v[:total_time] }
|
48
49
|
end
|
49
50
|
|
50
51
|
private
|
@@ -103,13 +104,18 @@ module TestProf
|
|
103
104
|
|
104
105
|
def track(factory)
|
105
106
|
return yield unless running?
|
107
|
+
@depth += 1
|
108
|
+
@current_stack << factory if config.flamegraph?
|
109
|
+
@stats[factory][:total_count] += 1
|
110
|
+
@stats[factory][:top_level_count] += 1 if @depth == 1
|
111
|
+
t1 = TestProf.now
|
106
112
|
begin
|
107
|
-
@depth += 1
|
108
|
-
@current_stack << factory if config.flamegraph?
|
109
|
-
@stats[factory][:total] += 1
|
110
|
-
@stats[factory][:top_level] += 1 if @depth == 1
|
111
113
|
yield
|
112
114
|
ensure
|
115
|
+
t2 = TestProf.now
|
116
|
+
elapsed = t2 - t1
|
117
|
+
@stats[factory][:total_time] += elapsed
|
118
|
+
@stats[factory][:top_level_time] += elapsed if @depth == 1
|
113
119
|
@depth -= 1
|
114
120
|
flush_stack if @depth.zero?
|
115
121
|
end
|
@@ -120,7 +126,15 @@ module TestProf
|
|
120
126
|
def reset!
|
121
127
|
@stacks = [] if config.flamegraph?
|
122
128
|
@depth = 0
|
123
|
-
@stats = Hash.new
|
129
|
+
@stats = Hash.new do |h, k|
|
130
|
+
h[k] = {
|
131
|
+
name: k,
|
132
|
+
total_count: 0,
|
133
|
+
top_level_count: 0,
|
134
|
+
total_time: 0.0,
|
135
|
+
top_level_time: 0.0
|
136
|
+
}
|
137
|
+
end
|
124
138
|
flush_stack
|
125
139
|
end
|
126
140
|
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "test_prof/factory_prof/factory_bot_patch"
|
4
4
|
require "test_prof/factory_bot"
|
5
|
+
require "test_prof/ext/factory_bot_strategy"
|
5
6
|
|
6
7
|
module TestProf
|
7
8
|
module FactoryProf
|
@@ -9,23 +10,7 @@ module TestProf
|
|
9
10
|
# implementation of #patch and #track methods
|
10
11
|
# to provide unified interface for all factory-building gems
|
11
12
|
class FactoryBot
|
12
|
-
|
13
|
-
# older versions and top-level invocations use Symbols
|
14
|
-
using(Module.new do
|
15
|
-
refine Symbol do
|
16
|
-
def create?
|
17
|
-
self == :create
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
if defined?(::FactoryBot::Strategy::Create)
|
22
|
-
refine Class do
|
23
|
-
def create?
|
24
|
-
self <= ::FactoryBot::Strategy::Create
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end)
|
13
|
+
using TestProf::FactoryBotStrategy
|
29
14
|
|
30
15
|
# Monkey-patch FactoryBot / FactoryGirl
|
31
16
|
def self.patch
|
@@ -15,7 +15,7 @@ module TestProf::FactoryProf
|
|
15
15
|
return log(:info, "No factories detected") if result.raw_stats == {}
|
16
16
|
report_data = {
|
17
17
|
total_stacks: result.stacks.size,
|
18
|
-
total: result.
|
18
|
+
total: result.total_count
|
19
19
|
}
|
20
20
|
|
21
21
|
report_data[:roots] = convert_stacks(result)
|
@@ -45,7 +45,11 @@ module TestProf::FactoryProf
|
|
45
45
|
node = paths[path]
|
46
46
|
node[:value] += 1
|
47
47
|
else
|
48
|
-
node = {
|
48
|
+
node = {
|
49
|
+
name: sample,
|
50
|
+
value: 1,
|
51
|
+
total: result.raw_stats.fetch(sample)[:total_count]
|
52
|
+
}
|
49
53
|
paths[path] = node
|
50
54
|
|
51
55
|
if parent.nil?
|
@@ -10,23 +10,25 @@ module TestProf::FactoryProf
|
|
10
10
|
return log(:info, "No factories detected") if result.raw_stats == {}
|
11
11
|
msgs = []
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
total_count = result.stats.sum { |stat| stat[:total_count] }
|
14
|
+
total_top_level_count = result.stats.sum { |stat| stat[:top_level_count] }
|
15
|
+
total_time = result.stats.sum { |stat| stat[:top_level_time] }
|
15
16
|
total_uniq_factories = result.stats.map { |stat| stat[:name] }.uniq.count
|
16
17
|
|
17
18
|
msgs <<
|
18
19
|
<<~MSG
|
19
20
|
Factories usage
|
20
21
|
|
21
|
-
Total: #{
|
22
|
-
Total top-level: #{
|
22
|
+
Total: #{total_count}
|
23
|
+
Total top-level: #{total_top_level_count}
|
24
|
+
Total time: #{format("%.4f", total_time)}s
|
23
25
|
Total uniq factories: #{total_uniq_factories}
|
24
26
|
|
25
|
-
|
27
|
+
total top-level total time top-level time name
|
26
28
|
MSG
|
27
29
|
|
28
30
|
result.stats.each do |stat|
|
29
|
-
msgs << format("%
|
31
|
+
msgs << format("%8d %11d %11.4fs %15.4fs %30s", stat[:total_count], stat[:top_level_count], stat[:total_time], stat[:top_level_time], stat[:name])
|
30
32
|
end
|
31
33
|
|
32
34
|
log :info, msgs.join("\n")
|
@@ -7,7 +7,26 @@ 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 Configuration
|
11
|
+
# Define an alias for `let_it_be` with the predefined options:
|
12
|
+
#
|
13
|
+
# TestProf::LetItBe.configure do |config|
|
14
|
+
# config.alias_to :let_it_be_reloaded, reload: true
|
15
|
+
# end
|
16
|
+
def alias_to(name, **default_args)
|
17
|
+
LetItBe.define_let_it_be_alias(name, **default_args)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
10
21
|
class << self
|
22
|
+
def config
|
23
|
+
@config ||= Configuration.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def configure
|
27
|
+
yield config
|
28
|
+
end
|
29
|
+
|
11
30
|
def module_for(group)
|
12
31
|
modules[group] ||= begin
|
13
32
|
Module.new.tap { |mod| group.prepend(mod) }
|
@@ -25,6 +44,12 @@ module TestProf
|
|
25
44
|
# And we love cats!)
|
26
45
|
PREFIX = RUBY_ENGINE == "jruby" ? "@__jruby_is_not_cat_friendly__" : "@😸"
|
27
46
|
|
47
|
+
def self.define_let_it_be_alias(name, **default_args)
|
48
|
+
define_method(name) do |identifier, **options, &blk|
|
49
|
+
let_it_be(identifier, default_args.merge(options), &blk)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
28
53
|
def let_it_be(identifier, **options, &block)
|
29
54
|
initializer = proc do
|
30
55
|
instance_variable_set(:"#{PREFIX}#{identifier}", instance_exec(&block))
|
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.9.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: 2019-
|
11
|
+
date: 2019-05-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,20 +80,6 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '5.9'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rubocop
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: 0.65.0
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: 0.65.0
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
84
|
name: rubocop-md
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,14 +100,14 @@ dependencies:
|
|
114
100
|
requirements:
|
115
101
|
- - "~>"
|
116
102
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0.0.
|
103
|
+
version: 0.0.39
|
118
104
|
type: :development
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
107
|
requirements:
|
122
108
|
- - "~>"
|
123
109
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.0.
|
110
|
+
version: 0.0.39
|
125
111
|
description: "\n Ruby applications tests profiling tools.\n\n Contains tools
|
126
112
|
to analyze factories usage, integrate with Ruby profilers,\n profile your examples
|
127
113
|
using ActiveSupport notifications (if any) and\n statically analyze your code
|
@@ -170,6 +156,7 @@ files:
|
|
170
156
|
- lib/test_prof/ext/active_record_3.rb
|
171
157
|
- lib/test_prof/ext/active_record_refind.rb
|
172
158
|
- lib/test_prof/ext/array_bsearch_index.rb
|
159
|
+
- lib/test_prof/ext/factory_bot_strategy.rb
|
173
160
|
- lib/test_prof/ext/float_duration.rb
|
174
161
|
- lib/test_prof/ext/string_truncate.rb
|
175
162
|
- lib/test_prof/factory_all_stub.rb
|
@@ -178,6 +165,7 @@ files:
|
|
178
165
|
- lib/test_prof/factory_default.rb
|
179
166
|
- lib/test_prof/factory_default/factory_bot_patch.rb
|
180
167
|
- lib/test_prof/factory_doctor.rb
|
168
|
+
- lib/test_prof/factory_doctor/fabrication_patch.rb
|
181
169
|
- lib/test_prof/factory_doctor/factory_bot_patch.rb
|
182
170
|
- lib/test_prof/factory_doctor/minitest.rb
|
183
171
|
- lib/test_prof/factory_doctor/rspec.rb
|
@@ -226,7 +214,12 @@ files:
|
|
226
214
|
homepage: http://github.com/palkan/test-prof
|
227
215
|
licenses:
|
228
216
|
- MIT
|
229
|
-
metadata:
|
217
|
+
metadata:
|
218
|
+
bug_tracker_uri: http://github.com/palkan/test-prof/issues
|
219
|
+
changelog_uri: https://github.com/palkan/test-prof/blob/master/CHANGELOG.md
|
220
|
+
documentation_uri: https://test-prof.evilmartians.io/
|
221
|
+
homepage_uri: https://test-prof.evilmartians.io/
|
222
|
+
source_code_uri: http://github.com/palkan/test-prof
|
230
223
|
post_install_message:
|
231
224
|
rdoc_options: []
|
232
225
|
require_paths:
|
@@ -242,7 +235,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
242
235
|
- !ruby/object:Gem::Version
|
243
236
|
version: '0'
|
244
237
|
requirements: []
|
245
|
-
rubygems_version: 3.0.
|
238
|
+
rubygems_version: 3.0.3
|
246
239
|
signing_key:
|
247
240
|
specification_version: 4
|
248
241
|
summary: Ruby applications tests profiling tools
|