test-prof 0.1.0.beta1 → 0.1.0.pre5
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/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +69 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/README.md +2 -6
- data/Rakefile +8 -0
- data/bin/setup +8 -0
- data/circle.yml +11 -0
- data/guides/any_fixture.md +1 -1
- data/guides/stack_prof.md +1 -1
- data/lib/test_prof/factory_doctor.rb +9 -11
- data/lib/test_prof/ruby_prof.rb +5 -2
- data/lib/test_prof/stack_prof.rb +5 -2
- data/lib/test_prof/version.rb +1 -1
- data/lib/test_prof.rb +1 -19
- data/spec/integrations/any_fixture_spec.rb +11 -0
- data/spec/integrations/before_all_spec.rb +11 -0
- data/spec/integrations/event_prof_spec.rb +100 -0
- data/spec/integrations/factory_doctor_spec.rb +20 -0
- data/spec/integrations/fixtures/rspec/any_fixture_fixture.rb +37 -0
- data/spec/integrations/fixtures/rspec/before_all_fixture.rb +32 -0
- data/spec/integrations/fixtures/rspec/event_prof_factory_create_fixture.rb +23 -0
- data/spec/integrations/fixtures/rspec/event_prof_fixture.rb +51 -0
- data/spec/integrations/fixtures/rspec/event_prof_sidekiq_fixture.rb +53 -0
- data/spec/integrations/fixtures/rspec/factory_doctor_fixture.rb +33 -0
- data/spec/integrations/fixtures/rspec/rspec_stamp_fixture_tmpl.rb +33 -0
- data/spec/integrations/rspec_stamp_spec.rb +53 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/support/ar_models.rb +43 -0
- data/spec/support/instrumenter_stub.rb +19 -0
- data/spec/support/integration_helpers.rb +13 -0
- data/spec/support/transactional_context.rb +11 -0
- data/spec/test_prof/any_fixture_spec.rb +66 -0
- data/spec/test_prof/event_prof_spec.rb +138 -0
- data/spec/test_prof/ext/float_duration_spec.rb +12 -0
- data/spec/test_prof/factory_doctor_spec.rb +84 -0
- data/spec/test_prof/rspec_stamp/parser_spec.rb +58 -0
- data/spec/test_prof/rspec_stamp_spec.rb +281 -0
- data/spec/test_prof/ruby_prof_spec.rb +109 -0
- data/spec/test_prof/stack_prof_spec.rb +73 -0
- data/spec/test_prof_spec.rb +23 -0
- data/test-prof.gemspec +35 -0
- metadata +38 -21
- data/CHANGELOG.md +0 -7
- data/assets/flamegraph.demo.html +0 -173
- data/assets/flamegraph.template.html +0 -196
- data/assets/src/d3-tip.js +0 -352
- data/assets/src/d3-tip.min.js +0 -1
- data/assets/src/d3.flameGraph.css +0 -92
- data/assets/src/d3.flameGraph.js +0 -459
- data/assets/src/d3.flameGraph.min.css +0 -1
- data/assets/src/d3.flameGraph.min.js +0 -1
- data/assets/src/d3.v4.min.js +0 -8
- data/guides/factory_prof.md +0 -85
- data/guides/rubocop.md +0 -48
- data/lib/test_prof/cops/rspec/aggregate_failures.rb +0 -140
- data/lib/test_prof/factory_prof/factory_girl_patch.rb +0 -12
- data/lib/test_prof/factory_prof/printers/flamegraph.rb +0 -71
- data/lib/test_prof/factory_prof/printers/simple.rb +0 -28
- data/lib/test_prof/factory_prof.rb +0 -140
- data/lib/test_prof/rubocop.rb +0 -3
data/guides/factory_prof.md
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# FactoryProf
|
|
2
|
-
|
|
3
|
-
FactoryProf tracks your factories usage statistics, i.e. how often each factory has been used.
|
|
4
|
-
|
|
5
|
-
Example output:
|
|
6
|
-
|
|
7
|
-
```sh
|
|
8
|
-
[TEST PROF INFO] Factories usage
|
|
9
|
-
|
|
10
|
-
total top-level name
|
|
11
|
-
|
|
12
|
-
8 4 user
|
|
13
|
-
5 3 post
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
It shows both the total number of the factory runs and the number of _top-level_ runs, i.e. not during another factory invocation (e.g. when using associations.)
|
|
18
|
-
|
|
19
|
-
**NOTE**: FactoryProf only tracks the usage of `create` strategy.
|
|
20
|
-
|
|
21
|
-
## Instructions
|
|
22
|
-
|
|
23
|
-
FactoryProf can only be used with FactoryGirl.
|
|
24
|
-
|
|
25
|
-
To activate FactoryProf use `FPROF` environment variable:
|
|
26
|
-
|
|
27
|
-
```sh
|
|
28
|
-
# Simple profiler
|
|
29
|
-
FPROF=1 rspec
|
|
30
|
-
|
|
31
|
-
# or
|
|
32
|
-
FPROF=1 bundle exec rake test
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Factory Flamegraph
|
|
36
|
-
|
|
37
|
-
The most useful feature of FactoryProf is the _FactoryFlame_ report. That's the special interpetation of Brendan Gregg's [flame graphs](http://www.brendangregg.com/flamegraphs.html) which allows you to identify _factory cascades_.
|
|
38
|
-
|
|
39
|
-
To generate FactoryFlame report set `FPROF` environment variable to `flamegraph`:
|
|
40
|
-
|
|
41
|
-
```sh
|
|
42
|
-
FPROF=flamegraph rspec
|
|
43
|
-
|
|
44
|
-
# or
|
|
45
|
-
FPROF=flamegraph bundle exec rake test
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
That's how a report looks like:
|
|
49
|
-
|
|
50
|
-

|
|
51
|
-
|
|
52
|
-
How to read this?
|
|
53
|
-
|
|
54
|
-
Every column represents a _factory stack_ or _cascade_, that is a sequence of recursive `#create` method calls. Consider and example:
|
|
55
|
-
|
|
56
|
-
```ruby
|
|
57
|
-
factory :comment do
|
|
58
|
-
answer
|
|
59
|
-
author
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
factory :answer do
|
|
63
|
-
question
|
|
64
|
-
author
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
factory :question do
|
|
68
|
-
author
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
create(:comment) #=> creates 5 records
|
|
72
|
-
|
|
73
|
-
# And the corresponding stack is:
|
|
74
|
-
[:comment, :answer, :question, :author, :author, :author]
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
The wider column the more often this stack appears.
|
|
78
|
-
|
|
79
|
-
The `root` cell shows the total number of `create` calls.
|
|
80
|
-
|
|
81
|
-
## Acknowledgements
|
|
82
|
-
|
|
83
|
-
- Thanks to [Martin Spier](https://github.com/spiermar) for [d3-flame-graph](https://github.com/spiermar/d3-flame-graph)
|
|
84
|
-
|
|
85
|
-
- Thanks to [Sam Saffron](https://github.com/SamSaffron) for his [flame graphs implementation](https://github.com/SamSaffron/flamegraph).
|
data/guides/rubocop.md
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# Custom Rubocop Cops
|
|
2
|
-
|
|
3
|
-
TestProf comes with the [Rubocop](https://github.com/bbatsov/rubocop) cops that help you write more performant tests.
|
|
4
|
-
|
|
5
|
-
To enable them:
|
|
6
|
-
|
|
7
|
-
- Require `test_prof/rubocop` in your Rubocop configuration:
|
|
8
|
-
|
|
9
|
-
```yml
|
|
10
|
-
# .rubocop.yml
|
|
11
|
-
require:
|
|
12
|
-
- 'test_prof/rubocop'
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
- Enable cops:
|
|
16
|
-
|
|
17
|
-
```yml
|
|
18
|
-
RSpec/AggregateFailures:
|
|
19
|
-
Enabled: true
|
|
20
|
-
Include:
|
|
21
|
-
- 'spec/**/*.rb'
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Rspec/AggregateFailures
|
|
25
|
-
|
|
26
|
-
This cop encourages you to use one of the greatest features of the recent RSpec – aggregating failures within an example.
|
|
27
|
-
|
|
28
|
-
Instead of writing one example per assertion, you can group _independent_ assertions together, thus running all setup hooks only once. That can dramatically increase your performance (by reducing the total number of examples).
|
|
29
|
-
|
|
30
|
-
Consider an example:
|
|
31
|
-
|
|
32
|
-
```ruby
|
|
33
|
-
# bad
|
|
34
|
-
it { is_expected.to be_success }
|
|
35
|
-
it { is_expected.to have_header('X-TOTAL-PAGES', 10) }
|
|
36
|
-
it { is_expected.to have_header('X-NEXT-PAGE', 2) }
|
|
37
|
-
|
|
38
|
-
# good
|
|
39
|
-
it "returns the second page", :aggregate_failures do
|
|
40
|
-
is_expected.to be_success
|
|
41
|
-
is_expected.to have_header('X-TOTAL-PAGES', 10)
|
|
42
|
-
is_expected.to have_header('X-NEXT-PAGE', 2)
|
|
43
|
-
end
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
This cop supports auto-correct feature, so you can automatically refactor you legacy tests!
|
|
47
|
-
|
|
48
|
-
**NOTE**: auto-correction may break your tests (especially the ones using block-matchers, such as `change`).
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'rubocop'
|
|
4
|
-
|
|
5
|
-
module RuboCop
|
|
6
|
-
module Cop
|
|
7
|
-
module RSpec
|
|
8
|
-
# Rejects and auto-corrects the usage of one-liners examples in favour of
|
|
9
|
-
# :aggregate_failures feature.
|
|
10
|
-
#
|
|
11
|
-
# Example:
|
|
12
|
-
#
|
|
13
|
-
# # bad
|
|
14
|
-
# it { is_expected.to be_success }
|
|
15
|
-
# it { is_expected.to have_header('X-TOTAL-PAGES', 10) }
|
|
16
|
-
# it { is_expected.to have_header('X-NEXT-PAGE', 2) }
|
|
17
|
-
#
|
|
18
|
-
# # good
|
|
19
|
-
# it "returns the second page", :aggregate_failures do
|
|
20
|
-
# is_expected.to be_success
|
|
21
|
-
# is_expected.to have_header('X-TOTAL-PAGES', 10)
|
|
22
|
-
# is_expected.to have_header('X-NEXT-PAGE', 2)
|
|
23
|
-
# end
|
|
24
|
-
#
|
|
25
|
-
class AggregateFailures < RuboCop::Cop::Cop
|
|
26
|
-
# From https://github.com/backus/rubocop-rspec/blob/master/lib/rubocop/rspec/language.rb
|
|
27
|
-
GROUP_BLOCKS = %i[
|
|
28
|
-
describe context feature example_group
|
|
29
|
-
xdescribe xcontext xfeature
|
|
30
|
-
fdescribe fcontext ffeature
|
|
31
|
-
].freeze
|
|
32
|
-
|
|
33
|
-
EXAMPLE_BLOCKS = %i[
|
|
34
|
-
it specify example scenario its
|
|
35
|
-
fit fspecify fexample fscenario focus
|
|
36
|
-
xit xspecify xexample xscenario ski
|
|
37
|
-
pending
|
|
38
|
-
].freeze
|
|
39
|
-
|
|
40
|
-
def on_block(node)
|
|
41
|
-
method, _args, body = *node
|
|
42
|
-
return unless body&.begin_type?
|
|
43
|
-
|
|
44
|
-
_receiver, method_name, _object = *method
|
|
45
|
-
return unless GROUP_BLOCKS.include?(method_name)
|
|
46
|
-
|
|
47
|
-
return if check_node(body)
|
|
48
|
-
|
|
49
|
-
add_offense(
|
|
50
|
-
node,
|
|
51
|
-
:expression,
|
|
52
|
-
'Use :aggregate_failures instead of several one-liners.'
|
|
53
|
-
)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def autocorrect(node)
|
|
57
|
-
_method, _args, body = *node
|
|
58
|
-
iter = body.children.each
|
|
59
|
-
|
|
60
|
-
first_example = loop do
|
|
61
|
-
child = iter.next
|
|
62
|
-
break child if oneliner?(child)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
base_indent = " " * first_example.source_range.column
|
|
66
|
-
|
|
67
|
-
replacements = [
|
|
68
|
-
header_from(first_example),
|
|
69
|
-
body_from(first_example, base_indent)
|
|
70
|
-
]
|
|
71
|
-
|
|
72
|
-
last_example = nil
|
|
73
|
-
|
|
74
|
-
loop do
|
|
75
|
-
child = iter.next
|
|
76
|
-
break unless oneliner?(child)
|
|
77
|
-
last_example = child
|
|
78
|
-
replacements << body_from(child, base_indent)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
replacements << "#{base_indent}end"
|
|
82
|
-
|
|
83
|
-
range = first_example.source_range.begin.join(
|
|
84
|
-
last_example.source_range.end
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
replacement = replacements.join("\n")
|
|
88
|
-
|
|
89
|
-
lambda do |corrector|
|
|
90
|
-
corrector.replace(range, replacement)
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
private
|
|
95
|
-
|
|
96
|
-
def check_node(node)
|
|
97
|
-
offenders = 0
|
|
98
|
-
|
|
99
|
-
node.children.each do |child|
|
|
100
|
-
if oneliner?(child)
|
|
101
|
-
offenders += 1
|
|
102
|
-
elsif example_node?(child)
|
|
103
|
-
break if offenders > 1
|
|
104
|
-
offenders = 0
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
offenders < 2
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def oneliner?(node)
|
|
112
|
-
node&.block_type? &&
|
|
113
|
-
(node.source.lines.size == 1) &&
|
|
114
|
-
example_node?(node)
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def example_node?(node)
|
|
118
|
-
method, _args, _body = *node
|
|
119
|
-
_receiver, method_name, _object = *method
|
|
120
|
-
EXAMPLE_BLOCKS.include?(method_name)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def header_from(node)
|
|
124
|
-
method, _args, _body = *node
|
|
125
|
-
_receiver, method_name, _object = *method
|
|
126
|
-
%(#{method_name} "works", :aggregate_failures do)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def body_from(node, base_indent = '')
|
|
130
|
-
_method, _args, body = *node
|
|
131
|
-
"#{base_indent}#{indent}#{body.source}"
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def indent
|
|
135
|
-
@indent ||= " " * (config.for_cop('IndentationWidth')['Width'] || 2)
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "json"
|
|
4
|
-
|
|
5
|
-
module TestProf::FactoryProf
|
|
6
|
-
module Printers
|
|
7
|
-
module Flamegraph # :nodoc: all
|
|
8
|
-
class << self
|
|
9
|
-
include TestProf::Logging
|
|
10
|
-
|
|
11
|
-
def dump(result)
|
|
12
|
-
report_data = {
|
|
13
|
-
total_stacks: result.stacks.size,
|
|
14
|
-
total: result.total
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
report_data[:roots] = convert_stacks(result)
|
|
18
|
-
|
|
19
|
-
path = generate_html(report_data)
|
|
20
|
-
|
|
21
|
-
log :info, "FactoryFlame report generated: #{path}"
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def convert_stacks(result)
|
|
25
|
-
res = []
|
|
26
|
-
|
|
27
|
-
paths = {}
|
|
28
|
-
|
|
29
|
-
result.stacks.each do |stack|
|
|
30
|
-
parent = nil
|
|
31
|
-
path = ""
|
|
32
|
-
|
|
33
|
-
stack.each do |sample|
|
|
34
|
-
path = "#{path}/#{sample}"
|
|
35
|
-
|
|
36
|
-
if paths[path]
|
|
37
|
-
node = paths[path]
|
|
38
|
-
node[:value] += 1
|
|
39
|
-
else
|
|
40
|
-
node = { name: sample, value: 1, total: result.raw_stats.fetch(sample)[:total] }
|
|
41
|
-
paths[path] = node
|
|
42
|
-
|
|
43
|
-
if parent.nil?
|
|
44
|
-
res << node
|
|
45
|
-
else
|
|
46
|
-
parent[:children] ||= []
|
|
47
|
-
parent[:children] << node
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
parent = node
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
res
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
private
|
|
59
|
-
|
|
60
|
-
def generate_html(data)
|
|
61
|
-
template = File.read(TestProf.asset_path("flamegraph.template.html"))
|
|
62
|
-
template.sub! '/**REPORT-DATA**/', data.to_json
|
|
63
|
-
|
|
64
|
-
outpath = TestProf.artefact_path("factory-flame.html")
|
|
65
|
-
File.write(outpath, template)
|
|
66
|
-
outpath
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module TestProf::FactoryProf
|
|
4
|
-
module Printers
|
|
5
|
-
module Simple # :nodoc: all
|
|
6
|
-
class << self
|
|
7
|
-
include TestProf::Logging
|
|
8
|
-
|
|
9
|
-
def dump(result)
|
|
10
|
-
msgs = []
|
|
11
|
-
|
|
12
|
-
msgs <<
|
|
13
|
-
<<~MSG
|
|
14
|
-
Factories usage
|
|
15
|
-
|
|
16
|
-
total top-level name
|
|
17
|
-
MSG
|
|
18
|
-
|
|
19
|
-
result.stats.each do |stat|
|
|
20
|
-
msgs << format("%6d %11d %15s", stat[:total], stat[:top_level], stat[:name])
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
log :info, msgs.join("\n")
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "test_prof/factory_prof/factory_girl_patch"
|
|
4
|
-
require "test_prof/factory_prof/printers/simple"
|
|
5
|
-
require "test_prof/factory_prof/printers/flamegraph"
|
|
6
|
-
|
|
7
|
-
module TestProf
|
|
8
|
-
# FactoryProf collects "factory stacks" that can be used to build
|
|
9
|
-
# flamegraphs or detect most popular factories
|
|
10
|
-
module FactoryProf
|
|
11
|
-
# FactoryProf configuration
|
|
12
|
-
class Configuration
|
|
13
|
-
attr_accessor :mode
|
|
14
|
-
|
|
15
|
-
def initialize
|
|
16
|
-
@mode = ENV['FPROF'] == 'flamegraph' ? :flamegraph : :simple
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# Whether we want to generate flamegraphs
|
|
20
|
-
def flamegraph?
|
|
21
|
-
@mode == :flamegraph
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
class Result # :nodoc:
|
|
26
|
-
attr_reader :stacks, :raw_stats
|
|
27
|
-
|
|
28
|
-
def initialize(stacks, raw_stats)
|
|
29
|
-
@stacks = stacks
|
|
30
|
-
@raw_stats = raw_stats
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Returns sorted stats
|
|
34
|
-
def stats
|
|
35
|
-
return @stats if instance_variable_defined?(:@stats)
|
|
36
|
-
|
|
37
|
-
@stats = @raw_stats.values
|
|
38
|
-
.sort_by { |el| -el[:total] }
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def total
|
|
42
|
-
return @total if instance_variable_defined?(:@total)
|
|
43
|
-
@total = @raw_stats.values.sum { |v| v[:total] }
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
private
|
|
47
|
-
|
|
48
|
-
def sorted_stats(key)
|
|
49
|
-
@raw_stats.values
|
|
50
|
-
.map { |el| [el[:name], el[key]] }
|
|
51
|
-
.sort_by { |el| -el[1] }
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
class << self
|
|
56
|
-
include TestProf::Logging
|
|
57
|
-
|
|
58
|
-
def config
|
|
59
|
-
@config ||= Configuration.new
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def configure
|
|
63
|
-
yield config
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Patch factory lib, init vars
|
|
67
|
-
def init
|
|
68
|
-
@running = false
|
|
69
|
-
|
|
70
|
-
log :info, "FactoryProf enabled (#{config.mode} mode)"
|
|
71
|
-
|
|
72
|
-
# Monkey-patch FactoryGirl
|
|
73
|
-
::FactoryGirl::FactoryRunner.prepend(FactoryGirlPatch) if
|
|
74
|
-
defined?(::FactoryGirl)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# Inits FactoryProf and setups at exit hook,
|
|
78
|
-
# then runs
|
|
79
|
-
def run
|
|
80
|
-
init
|
|
81
|
-
|
|
82
|
-
printer = config.flamegraph? ? Printers::Flamegraph : Printers::Simple
|
|
83
|
-
|
|
84
|
-
at_exit { printer.dump(result) }
|
|
85
|
-
|
|
86
|
-
start
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def start
|
|
90
|
-
reset!
|
|
91
|
-
@running = true
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def stop
|
|
95
|
-
@running = false
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def result
|
|
99
|
-
Result.new(@stacks, @stats)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def track(strategy, factory)
|
|
103
|
-
return yield if !running? || (strategy != :create)
|
|
104
|
-
begin
|
|
105
|
-
@depth += 1
|
|
106
|
-
@current_stack << factory if config.flamegraph?
|
|
107
|
-
@stats[factory][:total] += 1
|
|
108
|
-
@stats[factory][:top_level] += 1 if @depth == 1
|
|
109
|
-
yield
|
|
110
|
-
ensure
|
|
111
|
-
@depth -= 1
|
|
112
|
-
flush_stack if @depth.zero?
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
private
|
|
117
|
-
|
|
118
|
-
def reset!
|
|
119
|
-
@stacks = [] if config.flamegraph?
|
|
120
|
-
@depth = 0
|
|
121
|
-
@stats = Hash.new { |h, k| h[k] = { name: k, total: 0, top_level: 0 } }
|
|
122
|
-
flush_stack
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def flush_stack
|
|
126
|
-
return unless config.flamegraph?
|
|
127
|
-
@stacks << @current_stack unless @current_stack.nil? || @current_stack.empty?
|
|
128
|
-
@current_stack = []
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def running?
|
|
132
|
-
@running == true
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
TestProf.activate('FPROF') do
|
|
139
|
-
TestProf::FactoryProf.run
|
|
140
|
-
end
|
data/lib/test_prof/rubocop.rb
DELETED