test-prof 0.1.0.pre5 → 0.1.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 +7 -0
- data/README.md +16 -4
- data/assets/flamegraph.demo.html +173 -0
- data/assets/flamegraph.template.html +196 -0
- data/assets/src/d3-tip.js +352 -0
- data/assets/src/d3-tip.min.js +1 -0
- data/assets/src/d3.flameGraph.css +92 -0
- data/assets/src/d3.flameGraph.js +459 -0
- data/assets/src/d3.flameGraph.min.css +1 -0
- data/assets/src/d3.flameGraph.min.js +1 -0
- data/assets/src/d3.v4.min.js +8 -0
- data/guides/any_fixture.md +1 -1
- data/guides/event_prof.md +30 -0
- data/guides/factory_default.md +109 -0
- data/guides/factory_prof.md +85 -0
- data/guides/rubocop.md +48 -0
- data/guides/ruby_prof.md +2 -0
- data/guides/stack_prof.md +5 -1
- data/guides/tag_prof.md +52 -0
- data/guides/tests_sampling.md +24 -0
- data/lib/test_prof.rb +31 -7
- data/lib/test_prof/cops/rspec/aggregate_failures.rb +140 -0
- data/lib/test_prof/event_prof/custom_events.rb +3 -3
- data/lib/test_prof/event_prof/custom_events/factory_create.rb +10 -8
- data/lib/test_prof/event_prof/custom_events/sidekiq_inline.rb +10 -8
- data/lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb +12 -10
- data/lib/test_prof/event_prof/rspec.rb +5 -1
- data/lib/test_prof/factory_default.rb +58 -0
- data/lib/test_prof/factory_default/factory_girl_patch.rb +22 -0
- data/lib/test_prof/factory_doctor.rb +11 -9
- data/lib/test_prof/factory_doctor/rspec.rb +5 -3
- data/lib/test_prof/factory_prof.rb +140 -0
- data/lib/test_prof/factory_prof/factory_girl_patch.rb +12 -0
- data/lib/test_prof/factory_prof/printers/flamegraph.rb +71 -0
- data/lib/test_prof/factory_prof/printers/simple.rb +28 -0
- data/lib/test_prof/recipes/minitest/sample.rb +29 -0
- data/lib/test_prof/recipes/rspec/factory_default.rb +9 -0
- data/lib/test_prof/recipes/rspec/sample.rb +13 -0
- data/lib/test_prof/rspec_stamp/rspec.rb +5 -1
- data/lib/test_prof/rubocop.rb +3 -0
- data/lib/test_prof/ruby_prof.rb +6 -12
- data/lib/test_prof/stack_prof.rb +14 -7
- data/lib/test_prof/tag_prof.rb +8 -0
- data/lib/test_prof/tag_prof/rspec.rb +84 -0
- data/lib/test_prof/version.rb +1 -1
- metadata +48 -41
- data/.gitignore +0 -10
- data/.rspec +0 -2
- data/.rubocop.yml +0 -69
- data/.travis.yml +0 -5
- data/Gemfile +0 -4
- data/Rakefile +0 -8
- data/bin/setup +0 -8
- data/circle.yml +0 -11
- data/spec/integrations/any_fixture_spec.rb +0 -11
- data/spec/integrations/before_all_spec.rb +0 -11
- data/spec/integrations/event_prof_spec.rb +0 -100
- data/spec/integrations/factory_doctor_spec.rb +0 -20
- data/spec/integrations/fixtures/rspec/any_fixture_fixture.rb +0 -37
- data/spec/integrations/fixtures/rspec/before_all_fixture.rb +0 -32
- data/spec/integrations/fixtures/rspec/event_prof_factory_create_fixture.rb +0 -23
- data/spec/integrations/fixtures/rspec/event_prof_fixture.rb +0 -51
- data/spec/integrations/fixtures/rspec/event_prof_sidekiq_fixture.rb +0 -53
- data/spec/integrations/fixtures/rspec/factory_doctor_fixture.rb +0 -33
- data/spec/integrations/fixtures/rspec/rspec_stamp_fixture_tmpl.rb +0 -33
- data/spec/integrations/rspec_stamp_spec.rb +0 -53
- data/spec/spec_helper.rb +0 -38
- data/spec/support/ar_models.rb +0 -43
- data/spec/support/instrumenter_stub.rb +0 -19
- data/spec/support/integration_helpers.rb +0 -13
- data/spec/support/transactional_context.rb +0 -11
- data/spec/test_prof/any_fixture_spec.rb +0 -66
- data/spec/test_prof/event_prof_spec.rb +0 -138
- data/spec/test_prof/ext/float_duration_spec.rb +0 -12
- data/spec/test_prof/factory_doctor_spec.rb +0 -84
- data/spec/test_prof/rspec_stamp/parser_spec.rb +0 -58
- data/spec/test_prof/rspec_stamp_spec.rb +0 -281
- data/spec/test_prof/ruby_prof_spec.rb +0 -109
- data/spec/test_prof/stack_prof_spec.rb +0 -73
- data/spec/test_prof_spec.rb +0 -23
- data/test-prof.gemspec +0 -35
@@ -0,0 +1,140 @@
|
|
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,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "test_prof/event_prof/custom_events/factory_create"
|
4
|
-
require "test_prof/event_prof/custom_events/sidekiq_inline"
|
5
|
-
require "test_prof/event_prof/custom_events/sidekiq_jobs"
|
3
|
+
require "test_prof/event_prof/custom_events/factory_create"
|
4
|
+
require "test_prof/event_prof/custom_events/sidekiq_inline"
|
5
|
+
require "test_prof/event_prof/custom_events/sidekiq_jobs"
|
@@ -39,13 +39,15 @@ module TestProf::EventProf::CustomEvents
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
TestProf.activate('EVENT_PROF', 'factory.create') do
|
43
|
+
if TestProf.require(
|
44
|
+
'factory_girl',
|
45
|
+
<<~MSG
|
46
|
+
Failed to load FactoryGirl.
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
)
|
50
|
-
|
48
|
+
Make sure that "factory_girl" gem is in your Gemfile.
|
49
|
+
MSG
|
50
|
+
)
|
51
|
+
TestProf::EventProf::CustomEvents::FactoryCreate.setup!
|
52
|
+
end
|
51
53
|
end
|
@@ -36,13 +36,15 @@ module TestProf::EventProf::CustomEvents
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
TestProf.activate('EVENT_PROF', 'sidekiq.inline') do
|
40
|
+
if TestProf.require(
|
41
|
+
'sidekiq/testing',
|
42
|
+
<<~MSG
|
43
|
+
Failed to load Sidekiq.
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
)
|
47
|
-
|
45
|
+
Make sure that "sidekiq" gem is in your Gemfile.
|
46
|
+
MSG
|
47
|
+
)
|
48
|
+
TestProf::EventProf::CustomEvents::SidekiqInline.setup!
|
49
|
+
end
|
48
50
|
end
|
@@ -23,16 +23,18 @@ module TestProf::EventProf::CustomEvents
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
TestProf.activate('EVENT_PROF', 'sidekiq.jobs') do
|
27
|
+
if TestProf.require(
|
28
|
+
'sidekiq/testing',
|
29
|
+
<<~MSG
|
30
|
+
Failed to load Sidekiq.
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
)
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
Make sure that "sidekiq" gem is in your Gemfile.
|
33
|
+
MSG
|
34
|
+
)
|
35
|
+
TestProf::EventProf::CustomEvents::SidekiqJobs.setup!
|
36
|
+
TestProf::EventProf.configure do |config|
|
37
|
+
config.rank_by = :count
|
38
|
+
end
|
37
39
|
end
|
38
40
|
end
|
@@ -87,7 +87,11 @@ TestProf.activate('EVENT_PROF') do
|
|
87
87
|
RSpec.configure do |config|
|
88
88
|
listener = TestProf::EventProf::RSpecListener.new
|
89
89
|
|
90
|
-
config.
|
90
|
+
config.before(:suite) do
|
91
|
+
config.reporter.register_listener(
|
92
|
+
listener, *TestProf::EventProf::RSpecListener::NOTIFICATIONS
|
93
|
+
)
|
94
|
+
end
|
91
95
|
|
92
96
|
config.after(:suite) { listener.print }
|
93
97
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_prof/factory_default/factory_girl_patch"
|
4
|
+
|
5
|
+
module TestProf
|
6
|
+
# FactoryDefault allows use to re-use associated objects
|
7
|
+
# in factories implicilty
|
8
|
+
module FactoryDefault
|
9
|
+
module DefaultSyntax # :nodoc:
|
10
|
+
def create_default(name, *args, &block)
|
11
|
+
set_factory_default(
|
12
|
+
name,
|
13
|
+
FactoryGirl.create(name, *args, &block)
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_factory_default(name, obj)
|
18
|
+
FactoryDefault.register(name, obj)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def init
|
24
|
+
FactoryGirl::Syntax::Methods.include DefaultSyntax
|
25
|
+
FactoryGirl.extend DefaultSyntax
|
26
|
+
FactoryGirl::Strategy::Create.prepend StrategyExt
|
27
|
+
FactoryGirl::Strategy::Build.prepend StrategyExt
|
28
|
+
FactoryGirl::Strategy::Stub.prepend StrategyExt
|
29
|
+
|
30
|
+
@store = {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def register(name, obj)
|
34
|
+
store[name] = obj
|
35
|
+
end
|
36
|
+
|
37
|
+
def get(name)
|
38
|
+
store[name]
|
39
|
+
end
|
40
|
+
|
41
|
+
def exists?(name)
|
42
|
+
store.key?(name)
|
43
|
+
end
|
44
|
+
|
45
|
+
def remove(name)
|
46
|
+
store.delete(name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def reset
|
50
|
+
@store.clear
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
attr_reader :store
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TestProf
|
4
|
+
module FactoryDefault # :nodoc: all
|
5
|
+
module RunnerExt
|
6
|
+
refine FactoryGirl::FactoryRunner do
|
7
|
+
def name
|
8
|
+
@name
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
using RunnerExt
|
14
|
+
|
15
|
+
module StrategyExt
|
16
|
+
def association(runner)
|
17
|
+
return super unless FactoryDefault.exists?(runner.name)
|
18
|
+
FactoryDefault.get(runner.name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -3,8 +3,8 @@
|
|
3
3
|
require "test_prof/factory_doctor/factory_girl_patch"
|
4
4
|
|
5
5
|
module TestProf
|
6
|
-
# FactoryDoctor is a tool that helps you identify
|
7
|
-
#
|
6
|
+
# FactoryDoctor is a tool that helps you identify
|
7
|
+
# tests that perform unnecessary database queries.
|
8
8
|
module FactoryDoctor
|
9
9
|
class Result # :nodoc:
|
10
10
|
attr_reader :count, :time, :queries_count
|
@@ -81,14 +81,16 @@ module TestProf
|
|
81
81
|
def within_factory(strategy)
|
82
82
|
return yield if ignore? || !running? || (strategy != :create)
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
84
|
+
begin
|
85
|
+
ts = Time.now if @depth.zero?
|
86
|
+
@depth += 1
|
87
|
+
@count += 1
|
88
|
+
yield
|
89
|
+
ensure
|
90
|
+
@depth -= 1
|
90
91
|
|
91
|
-
|
92
|
+
@time += (Time.now - ts) if @depth.zero?
|
93
|
+
end
|
92
94
|
end
|
93
95
|
|
94
96
|
private
|
@@ -83,9 +83,11 @@ TestProf.activate('FDOC') do
|
|
83
83
|
RSpec.configure do |config|
|
84
84
|
listener = TestProf::FactoryDoctor::RSpecListener.new
|
85
85
|
|
86
|
-
config.
|
87
|
-
|
88
|
-
|
86
|
+
config.before(:suite) do
|
87
|
+
config.reporter.register_listener(
|
88
|
+
listener, *TestProf::FactoryDoctor::RSpecListener::NOTIFICATIONS
|
89
|
+
)
|
90
|
+
end
|
89
91
|
|
90
92
|
config.after(:suite) { listener.print }
|
91
93
|
end
|
@@ -0,0 +1,140 @@
|
|
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
|