test-prof 0.1.0.beta4 → 0.1.0.pre2
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 -16
- data/Rakefile +8 -0
- data/bin/setup +8 -0
- data/circle.yml +11 -0
- data/guides/any_fixture.md +1 -1
- data/guides/ruby_prof.md +0 -2
- data/guides/stack_prof.md +1 -5
- data/lib/test_prof.rb +6 -31
- data/lib/test_prof/event_prof.rb +4 -2
- data/lib/test_prof/event_prof/custom_events.rb +3 -3
- data/lib/test_prof/event_prof/custom_events/factory_create.rb +9 -11
- data/lib/test_prof/event_prof/custom_events/sidekiq_inline.rb +9 -11
- data/lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb +11 -13
- data/lib/test_prof/event_prof/rspec.rb +1 -5
- data/lib/test_prof/factory_doctor.rb +9 -11
- data/lib/test_prof/factory_doctor/rspec.rb +3 -5
- data/lib/test_prof/ruby_prof.rb +12 -6
- data/lib/test_prof/stack_prof.rb +7 -14
- data/lib/test_prof/version.rb +1 -1
- 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 +54 -0
- data/spec/integrations/fixtures/rspec/factory_doctor_fixture.rb +33 -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/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 +34 -49
- 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_default.md +0 -109
- data/guides/factory_prof.md +0 -85
- data/guides/rspec_stamp.md +0 -53
- data/guides/rubocop.md +0 -48
- data/guides/tag_prof.md +0 -52
- data/guides/tests_sampling.md +0 -24
- data/lib/test_prof/cops/rspec/aggregate_failures.rb +0 -140
- data/lib/test_prof/factory_default.rb +0 -58
- data/lib/test_prof/factory_default/factory_girl_patch.rb +0 -22
- data/lib/test_prof/factory_prof.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/recipes/minitest/sample.rb +0 -29
- data/lib/test_prof/recipes/rspec/factory_default.rb +0 -9
- data/lib/test_prof/recipes/rspec/sample.rb +0 -13
- data/lib/test_prof/rspec_stamp.rb +0 -135
- data/lib/test_prof/rspec_stamp/parser.rb +0 -103
- data/lib/test_prof/rspec_stamp/rspec.rb +0 -95
- data/lib/test_prof/rubocop.rb +0 -3
- data/lib/test_prof/tag_prof.rb +0 -8
- data/lib/test_prof/tag_prof/rspec.rb +0 -84
@@ -83,11 +83,9 @@ TestProf.activate('FDOC') do
|
|
83
83
|
RSpec.configure do |config|
|
84
84
|
listener = TestProf::FactoryDoctor::RSpecListener.new
|
85
85
|
|
86
|
-
config.
|
87
|
-
|
88
|
-
|
89
|
-
)
|
90
|
-
end
|
86
|
+
config.reporter.register_listener(
|
87
|
+
listener, *TestProf::FactoryDoctor::RSpecListener::NOTIFICATIONS
|
88
|
+
)
|
91
89
|
|
92
90
|
config.after(:suite) { listener.print }
|
93
91
|
end
|
data/lib/test_prof/ruby_prof.rb
CHANGED
@@ -48,8 +48,8 @@ module TestProf
|
|
48
48
|
:include_threads, :eliminate_methods
|
49
49
|
|
50
50
|
def initialize
|
51
|
-
@printer =
|
52
|
-
@mode =
|
51
|
+
@printer = :call_stack
|
52
|
+
@mode = :wall
|
53
53
|
@min_percent = 1
|
54
54
|
@include_threads = false
|
55
55
|
@eliminate_methods = ELIMINATE_METHODS
|
@@ -65,10 +65,13 @@ module TestProf
|
|
65
65
|
end
|
66
66
|
|
67
67
|
# Returns an array of printer type (ID) and class.
|
68
|
+
# Takes ENV variable TEST_RUBY_PROF_PRINTER into account.
|
68
69
|
def resolve_printer
|
69
|
-
|
70
|
+
type = ENV['TEST_RUBY_PROF_PRINTER'] || printer
|
70
71
|
|
71
|
-
type
|
72
|
+
return ['custom', type] if type.is_a?(Module)
|
73
|
+
|
74
|
+
type = type.to_s
|
72
75
|
|
73
76
|
raise ArgumentError, "Unknown printer: #{type}" unless
|
74
77
|
PRINTERS.key?(type)
|
@@ -107,8 +110,11 @@ module TestProf
|
|
107
110
|
private
|
108
111
|
|
109
112
|
def build_path(name, printer)
|
110
|
-
TestProf.
|
111
|
-
|
113
|
+
TestProf.with_timestamps(
|
114
|
+
File.join(
|
115
|
+
TestProf.config.output_dir,
|
116
|
+
"ruby-prof-report-#{printer}-#{config.mode}-#{name}.html"
|
117
|
+
)
|
112
118
|
)
|
113
119
|
end
|
114
120
|
|
data/lib/test_prof/stack_prof.rb
CHANGED
@@ -25,8 +25,8 @@ module TestProf
|
|
25
25
|
attr_accessor :mode, :interval, :raw
|
26
26
|
|
27
27
|
def initialize
|
28
|
-
@mode =
|
29
|
-
@raw =
|
28
|
+
@mode = :wall
|
29
|
+
@raw = false
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -83,23 +83,16 @@ module TestProf
|
|
83
83
|
::StackProf.results(path)
|
84
84
|
|
85
85
|
log :info, "StackProf report generated: #{path}"
|
86
|
-
|
87
|
-
return unless config.raw
|
88
|
-
|
89
|
-
html_path = path.gsub(/\.dump$/, '.html')
|
90
|
-
|
91
|
-
log :info, <<~MSG
|
92
|
-
Run the following command to generate a flame graph report:
|
93
|
-
|
94
|
-
stackprof --flamegraph #{path} > #{html_path} && stackprof --flamegraph-viewer=#{html_path}
|
95
|
-
MSG
|
96
86
|
end
|
97
87
|
|
98
88
|
private
|
99
89
|
|
100
90
|
def build_path(name)
|
101
|
-
TestProf.
|
102
|
-
|
91
|
+
TestProf.with_timestamps(
|
92
|
+
File.join(
|
93
|
+
TestProf.config.output_dir,
|
94
|
+
"stack-prof-report-#{config.mode}-#{name}.dump"
|
95
|
+
)
|
103
96
|
)
|
104
97
|
end
|
105
98
|
|
data/lib/test_prof/version.rb
CHANGED
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe "EventProf" do
|
6
|
+
specify "RSpec integration", :aggregate_failures do
|
7
|
+
output = run_rspec('event_prof', env: { 'EVENT_PROF' => 'test.event' })
|
8
|
+
|
9
|
+
expect(output).to include("EventProf results for test.event")
|
10
|
+
expect(output).to match(/Total time: 25:56\.\d{3}/)
|
11
|
+
expect(output).to include("Total events: 8")
|
12
|
+
|
13
|
+
expect(output).to include("Top 5 slowest suites (by time):")
|
14
|
+
expect(output).to include("Top 5 slowest tests (by time):")
|
15
|
+
|
16
|
+
expect(output).to include(
|
17
|
+
"Another something (./event_prof_fixture.rb:42) – 16:40.000 (1 / 2)\n"\
|
18
|
+
"Something (./event_prof_fixture.rb:21) – 09:16.100 (7 / 3)"
|
19
|
+
)
|
20
|
+
|
21
|
+
expect(output).to include(
|
22
|
+
"do very long (./event_prof_fixture.rb:47) – 16:40.000 (1)\n"\
|
23
|
+
"invokes twice (./event_prof_fixture.rb:27) – 06:20.000 (2)\n"\
|
24
|
+
"invokes many times (./event_prof_fixture.rb:33) – 02:16.000 (4)\n"\
|
25
|
+
"invokes once (./event_prof_fixture.rb:22) – 00:40.100 (1)"
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
specify "RSpec integration with rank by count", :aggregate_failures do
|
30
|
+
output = run_rspec(
|
31
|
+
'event_prof',
|
32
|
+
env: { 'EVENT_PROF' => 'test.event', 'EVENT_PROF_RANK' => 'count' }
|
33
|
+
)
|
34
|
+
|
35
|
+
expect(output).to include("EventProf results for test.event")
|
36
|
+
expect(output).to match(/Total time: 25:56\.\d{3}/)
|
37
|
+
expect(output).to include("Total events: 8")
|
38
|
+
|
39
|
+
expect(output).to include("Top 5 slowest suites (by count):")
|
40
|
+
expect(output).to include("Top 5 slowest tests (by count):")
|
41
|
+
|
42
|
+
expect(output).to include(
|
43
|
+
"Something (./event_prof_fixture.rb:21) – 09:16.100 (7 / 3)\n"\
|
44
|
+
"Another something (./event_prof_fixture.rb:42) – 16:40.000 (1 / 2)"
|
45
|
+
)
|
46
|
+
|
47
|
+
expect(output).to include(
|
48
|
+
"invokes many times (./event_prof_fixture.rb:33) – 02:16.000 (4)\n"\
|
49
|
+
"invokes twice (./event_prof_fixture.rb:27) – 06:20.000 (2)\n"\
|
50
|
+
"invokes once (./event_prof_fixture.rb:22) – 00:40.100 (1)\n"\
|
51
|
+
"do very long (./event_prof_fixture.rb:47) – 16:40.000 (1)"
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
context "CustomEvents" do
|
56
|
+
it "works with factory.create" do
|
57
|
+
output = run_rspec(
|
58
|
+
'event_prof_factory_create',
|
59
|
+
env: { 'EVENT_PROF' => 'factory.create' }
|
60
|
+
)
|
61
|
+
|
62
|
+
expect(output).to include("EventProf results for factory.create")
|
63
|
+
expect(output).to match(/Total time: \d{2}:\d{2}\.\d{3}/)
|
64
|
+
expect(output).to include("Total events: 3")
|
65
|
+
|
66
|
+
expect(output).to match(%r{Post \(./event_prof_factory_create_fixture.rb:7\) – \d{2}:\d{2}.\d{3} \(2 / 1\)})
|
67
|
+
expect(output).to match(%r{User \(./event_prof_factory_create_fixture.rb:16\) – \d{2}:\d{2}.\d{3} \(1 / 1\)})
|
68
|
+
end
|
69
|
+
|
70
|
+
it "works with sidekiq.inline" do
|
71
|
+
output = run_rspec(
|
72
|
+
'event_prof_sidekiq',
|
73
|
+
env: { 'EVENT_PROF' => 'sidekiq.inline' }
|
74
|
+
)
|
75
|
+
|
76
|
+
expect(output).to include("EventProf results for sidekiq.inline")
|
77
|
+
expect(output).to match(/Total time: \d{2}:\d{2}\.\d{3}/)
|
78
|
+
expect(output).to include("Total events: 3")
|
79
|
+
|
80
|
+
expect(output).to match(%r{SingleJob \(./event_prof_sidekiq_fixture.rb:28\) – \d{2}:\d{2}.\d{3} \(2 / 2\)})
|
81
|
+
expect(output).to match(%r{BatchJob \(./event_prof_sidekiq_fixture.rb:40\) – \d{2}:\d{2}.\d{3} \(1 / 2\)})
|
82
|
+
end
|
83
|
+
|
84
|
+
it "works with sidekiq.jobs" do
|
85
|
+
output = run_rspec(
|
86
|
+
'event_prof_sidekiq',
|
87
|
+
env: { 'EVENT_PROF' => 'sidekiq.jobs' }
|
88
|
+
)
|
89
|
+
|
90
|
+
expect(output).to include("EventProf results for sidekiq.jobs")
|
91
|
+
expect(output).to match(/Total time: \d{2}:\d{2}\.\d{3}/)
|
92
|
+
expect(output).to include("Total events: 6")
|
93
|
+
|
94
|
+
expect(output).to include("Top 5 slowest suites (by count):")
|
95
|
+
|
96
|
+
expect(output).to match(%r{SingleJob \(./event_prof_sidekiq_fixture.rb:28\) – \d{2}:\d{2}.\d{3} \(2 / 2\)})
|
97
|
+
expect(output).to match(%r{BatchJob \(./event_prof_sidekiq_fixture.rb:40\) – \d{2}:\d{2}.\d{3} \(4 / 2\)})
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe "FactoryDoctor" do
|
6
|
+
specify "RSpec integration", :aggregate_failures do
|
7
|
+
output = run_rspec('factory_doctor', env: { 'FDOC' => '1' })
|
8
|
+
|
9
|
+
expect(output).to include("FactoryDoctor report")
|
10
|
+
expect(output).to include("Total (potentially) bad examples: 3")
|
11
|
+
expect(output).to match(/Total wasted time: \d{2}:\d{2}\.\d{3}/)
|
12
|
+
|
13
|
+
expect(output).to include("User (./factory_doctor_fixture.rb:7)")
|
14
|
+
expect(output).to include("generates random names (./factory_doctor_fixture.rb:10) – 2 records created")
|
15
|
+
expect(output).to include("validates name (./factory_doctor_fixture.rb:15) – 1 record created")
|
16
|
+
expect(output).to include("clones (./factory_doctor_fixture.rb:25) – 1 record created")
|
17
|
+
expect(output).not_to include("is ignored")
|
18
|
+
expect(output).not_to include("creates and reloads user")
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__)
|
4
|
+
require_relative "../../../support/ar_models"
|
5
|
+
require_relative "../../../support/transactional_context"
|
6
|
+
require "test_prof/recipes/rspec/any_fixture"
|
7
|
+
|
8
|
+
shared_context "user", user: true do
|
9
|
+
before(:all) do
|
10
|
+
@user = TestProf::AnyFixture.register(:user) do
|
11
|
+
FactoryGirl.create(:user)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:user) { User.find(@user.id) }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "User", :user do
|
19
|
+
it "creates user" do
|
20
|
+
user.name = ''
|
21
|
+
expect(user).not_to be_valid
|
22
|
+
end
|
23
|
+
|
24
|
+
context "with clean fixture", :transactional, :with_clean_fixture do
|
25
|
+
specify "no users" do
|
26
|
+
expect(User.count).to eq 0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "Post", :user do
|
32
|
+
let(:post) { FactoryGirl.create(:post, user: user) }
|
33
|
+
|
34
|
+
it "creates post with the same user" do
|
35
|
+
expect { post }.not_to change(User, :count)
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__)
|
4
|
+
require_relative "../../../support/ar_models"
|
5
|
+
require "test_prof/recipes/rspec/before_all"
|
6
|
+
|
7
|
+
describe "User" do
|
8
|
+
context "with before_all" do
|
9
|
+
before_all do
|
10
|
+
@user = FactoryGirl.create(:user)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:user) { User.find(@user.id) }
|
14
|
+
|
15
|
+
it "validates name" do
|
16
|
+
user.name = ''
|
17
|
+
expect(user).not_to be_valid
|
18
|
+
end
|
19
|
+
|
20
|
+
it "clones" do
|
21
|
+
cloned = user.clone
|
22
|
+
cloned.save!
|
23
|
+
expect(cloned.reload.name).to include("(cloned)")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "without before_all" do
|
28
|
+
specify "no users" do
|
29
|
+
expect(User.count).to eq 0
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__)
|
4
|
+
require_relative "../../../support/ar_models"
|
5
|
+
require "test-prof"
|
6
|
+
|
7
|
+
describe "Post" do
|
8
|
+
let(:user) { FactoryGirl.create(:user) }
|
9
|
+
|
10
|
+
it "generates random names" do
|
11
|
+
user2 = FactoryGirl.create(:post).user
|
12
|
+
expect(user.name).not_to eq user2.name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "User" do
|
17
|
+
let(:user) { FactoryGirl.create(:user) }
|
18
|
+
|
19
|
+
it "validates name" do
|
20
|
+
user.name = ''
|
21
|
+
expect(user).not_to be_valid
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__)
|
4
|
+
require "active_support"
|
5
|
+
require "test-prof"
|
6
|
+
|
7
|
+
TestProf::EventProf.configure do |config|
|
8
|
+
config.per_example = true
|
9
|
+
end
|
10
|
+
|
11
|
+
module Instrumenter
|
12
|
+
def self.notify(_event, time)
|
13
|
+
ActiveSupport::Notifications.publish(
|
14
|
+
'test.event',
|
15
|
+
0,
|
16
|
+
time
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "Something" do
|
22
|
+
it "invokes once" do
|
23
|
+
Instrumenter.notify 'test.event', 40.1
|
24
|
+
expect(true).to eq true
|
25
|
+
end
|
26
|
+
|
27
|
+
it "invokes twice" do
|
28
|
+
Instrumenter.notify 'test.event', 140
|
29
|
+
Instrumenter.notify 'test.event', 240
|
30
|
+
expect(true).to eq true
|
31
|
+
end
|
32
|
+
|
33
|
+
it "invokes many times" do
|
34
|
+
Instrumenter.notify 'test.event', 14
|
35
|
+
Instrumenter.notify 'test.event', 40
|
36
|
+
Instrumenter.notify 'test.event', 42
|
37
|
+
Instrumenter.notify 'test.event', 40
|
38
|
+
expect(true).to eq true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "Another something" do
|
43
|
+
it "do nothing" do
|
44
|
+
expect(true).to eq true
|
45
|
+
end
|
46
|
+
|
47
|
+
it "do very long" do
|
48
|
+
Instrumenter.notify 'test.event', 1000
|
49
|
+
expect(true).to eq true
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../../../lib", __FILE__)
|
4
|
+
require "active_support"
|
5
|
+
require "sidekiq/testing"
|
6
|
+
|
7
|
+
Sidekiq::Testing.inline!
|
8
|
+
|
9
|
+
class SingleJob
|
10
|
+
include Sidekiq::Worker
|
11
|
+
|
12
|
+
def perform(*args)
|
13
|
+
1 == 1
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
class BatchJob
|
19
|
+
include Sidekiq::Worker
|
20
|
+
|
21
|
+
def perform(count)
|
22
|
+
count.times { SingleJob.perform_async(true) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "test-prof"
|
27
|
+
|
28
|
+
describe "SingleJob" do
|
29
|
+
it "invokes once" do
|
30
|
+
SingleJob.perform_async(1)
|
31
|
+
expect(true).to eq true
|
32
|
+
end
|
33
|
+
|
34
|
+
it "invokes twice" do
|
35
|
+
SingleJob.perform_async(2)
|
36
|
+
expect(true).to eq true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "BatchJob" do
|
41
|
+
it "invokes nested" do
|
42
|
+
BatchJob.perform_async(3)
|
43
|
+
expect(true).to eq true
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when fake" do
|
47
|
+
it "is fake" do
|
48
|
+
Sidekiq::Testing.fake! do
|
49
|
+
BatchJob.perform_async(3)
|
50
|
+
end
|
51
|
+
expect(true).to eq true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|