test-prof 0.1.0.beta2 → 0.1.0.beta3
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/README.md +2 -0
- data/guides/ruby_prof.md +2 -0
- data/guides/stack_prof.md +4 -0
- data/guides/tag_prof.md +52 -0
- data/lib/test_prof.rb +12 -6
- 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_doctor/rspec.rb +5 -3
- data/lib/test_prof/rspec_stamp/rspec.rb +5 -1
- data/lib/test_prof/ruby_prof.rb +4 -7
- data/lib/test_prof/stack_prof.rb +3 -3
- 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 +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58805aeec9869d4d5b15a7a936ff1f0f10c6b7cb
|
4
|
+
data.tar.gz: 6e89ccd56db3e421d5660573ea4cfea9dceb8010
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1985d22be179fffe92e3a1f87bf76eb5b08a4667195badd55c3caa9e4705462358708e6c9362a14cfbaf0928e0ed23baa65e3358a42b773426c567007915d83
|
7
|
+
data.tar.gz: 96fd3e35e266b7e5cdb2558bab332a63b0d7ccc0233866444d108a7b7549e9ffbe528d2b51b44ab558ebb80947d49c061cf69c92bec9161117c4b337d7c61c0e
|
data/README.md
CHANGED
@@ -53,6 +53,8 @@ Checkout our guides for each specific tool:
|
|
53
53
|
|
54
54
|
- [Instrumentation Profiler](https://github.com/palkan/test-prof/tree/master/guides/event_prof.md) (e.g. ActiveSupport notifications)
|
55
55
|
|
56
|
+
- [Tag Profiler](https://github.com/palkan/test-prof/tree/master/guides/tag_prof.md)
|
57
|
+
|
56
58
|
- [Factory Doctor](https://github.com/palkan/test-prof/tree/master/guides/factory_doctor.md)
|
57
59
|
|
58
60
|
- [Factory Profiler](https://github.com/palkan/test-prof/tree/master/guides/factory_prof.md)
|
data/guides/ruby_prof.md
CHANGED
@@ -58,4 +58,6 @@ end
|
|
58
58
|
|
59
59
|
By default, we use `CallStackPrinter`.
|
60
60
|
|
61
|
+
Also, you can specify RubyProf mode (`wall`, `cpu`, etc) through `TEST_RUBY_PROF_MODE` env variable.
|
62
|
+
|
61
63
|
See [ruby_prof.rb](https://github.com/palkan/test-prof/tree/master/lib/test_prof/ruby_prof.rb) for all available configuration options and their usage.
|
data/guides/stack_prof.md
CHANGED
@@ -40,4 +40,8 @@ end
|
|
40
40
|
|
41
41
|
### Configuration
|
42
42
|
|
43
|
+
You can change StackProf mode (which is `wall` by default) through `TEST_STACK_PROF_MODE` env variable.
|
44
|
+
|
45
|
+
If you want to generate flame graphs you should collect _raw_ data. Turn _raw_ collection on by passing `TEST_STACK_PROF_RAW=1`.
|
46
|
+
|
43
47
|
See [stack_prof.rb](https://github.com/palkan/test-prof/tree/master/lib/test_prof/stack_prof.rb) for all available configuration options and their usage.
|
data/guides/tag_prof.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# TagProf
|
2
|
+
|
3
|
+
TagProf is a simple profiler which collects examples statistics grouped by a provided tag value.
|
4
|
+
|
5
|
+
That's pretty useful in conjunction with `rspec-rails` built-in feature – `infer_spec_types_from_location!` – which automatically adds `type` to examples metadata.
|
6
|
+
|
7
|
+
Example output:
|
8
|
+
|
9
|
+
```sh
|
10
|
+
[TEST PROF INFO] TagProf report for type
|
11
|
+
|
12
|
+
type time total %total %time avg
|
13
|
+
|
14
|
+
request 00:04.808 42 33.87 54.70 00:00.114
|
15
|
+
controller 00:02.855 42 33.87 32.48 00:00.067
|
16
|
+
model 00:01.127 40 32.26 12.82 00:00.028
|
17
|
+
```
|
18
|
+
|
19
|
+
|
20
|
+
It shows both the total number of examples in each group and the total time spent (as long as percentages and average values).
|
21
|
+
|
22
|
+
|
23
|
+
## Instructions
|
24
|
+
|
25
|
+
TagProf can only be used with RSpec.
|
26
|
+
|
27
|
+
To activate TagProf use `TAG_PROF` environment variable:
|
28
|
+
|
29
|
+
```sh
|
30
|
+
# Group by type
|
31
|
+
TAG_PROF=type rspec
|
32
|
+
```
|
33
|
+
|
34
|
+
## Pro-Tip: More Types
|
35
|
+
|
36
|
+
By default, RSpec only infers types for default Rails app entities (such as controllers, models, mailers, etc.).
|
37
|
+
Modern Rails applications typically contain other abstractions too (e.g. services, forms, presenters, etc.), but RSpec is not aware of them and doesn't add any metadata.
|
38
|
+
|
39
|
+
That's the quick workaround:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
RSpec.configure do |config|
|
43
|
+
|
44
|
+
...
|
45
|
+
config.define_derived_metadata(file_path: %r{/spec/}) do |metadata|
|
46
|
+
# do not overwrite type if it's already set
|
47
|
+
next if metadata.key?(:type)
|
48
|
+
match = metadata[:location].match(%r{/spec/([^/]+)/})
|
49
|
+
metadata[:type] = match[1].singularize.to_sym
|
50
|
+
end
|
51
|
+
end
|
52
|
+
```
|
data/lib/test_prof.rb
CHANGED
@@ -42,13 +42,14 @@ module TestProf
|
|
42
42
|
false
|
43
43
|
end
|
44
44
|
|
45
|
-
# Run block only if provided env var is present
|
45
|
+
# Run block only if provided env var is present and
|
46
|
+
# equal to the provided value (if any).
|
46
47
|
# Contains workaround for applications using Spring.
|
47
|
-
def activate(env_var)
|
48
|
-
if defined?(::Spring)
|
49
|
-
Spring.after_fork {
|
50
|
-
|
51
|
-
yield
|
48
|
+
def activate(env_var, val = nil)
|
49
|
+
if defined?(::Spring)
|
50
|
+
::Spring.after_fork { activate!(env_var, val) { yield } }
|
51
|
+
else
|
52
|
+
activate!(env_var, val) { yield }
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
@@ -69,6 +70,10 @@ module TestProf
|
|
69
70
|
|
70
71
|
private
|
71
72
|
|
73
|
+
def activate!(env_var, val)
|
74
|
+
yield if ENV[env_var] && (val.nil? || ENV[env_var] == val)
|
75
|
+
end
|
76
|
+
|
72
77
|
def with_timestamps(path)
|
73
78
|
return path unless config.timestamps?
|
74
79
|
timestamps = "-#{Time.now.to_i}"
|
@@ -106,3 +111,4 @@ require "test_prof/event_prof"
|
|
106
111
|
require "test_prof/factory_doctor"
|
107
112
|
require "test_prof/factory_prof"
|
108
113
|
require "test_prof/rspec_stamp"
|
114
|
+
require "test_prof/tag_prof"
|
@@ -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
|
@@ -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
|
@@ -84,7 +84,11 @@ TestProf.activate('RSTAMP') do
|
|
84
84
|
RSpec.configure do |config|
|
85
85
|
listener = TestProf::RSpecStamp::RSpecListener.new
|
86
86
|
|
87
|
-
config.
|
87
|
+
config.before(:suite) do
|
88
|
+
config.reporter.register_listener(
|
89
|
+
listener, *TestProf::RSpecStamp::RSpecListener::NOTIFICATIONS
|
90
|
+
)
|
91
|
+
end
|
88
92
|
|
89
93
|
config.after(:suite) { listener.stamp! }
|
90
94
|
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 = :call_stack
|
52
|
-
@mode = :wall
|
51
|
+
@printer = ENV.fetch('TEST_RUBY_PROF_PRINTER', :call_stack).to_sym
|
52
|
+
@mode = ENV.fetch('TEST_RUBY_PROF_MODE', :wall).to_sym
|
53
53
|
@min_percent = 1
|
54
54
|
@include_threads = false
|
55
55
|
@eliminate_methods = ELIMINATE_METHODS
|
@@ -65,13 +65,10 @@ 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.
|
69
68
|
def resolve_printer
|
70
|
-
|
69
|
+
return ['custom', printer] if printer.is_a?(Module)
|
71
70
|
|
72
|
-
|
73
|
-
|
74
|
-
type = type.to_s
|
71
|
+
type = printer.to_s
|
75
72
|
|
76
73
|
raise ArgumentError, "Unknown printer: #{type}" unless
|
77
74
|
PRINTERS.key?(type)
|
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 = :wall
|
29
|
-
@raw =
|
28
|
+
@mode = ENV.fetch('TEST_STACK_PROF_MODE', :wall).to_sym
|
29
|
+
@raw = ENV['TEST_STACK_PROF_RAW'] == '1'
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -89,7 +89,7 @@ module TestProf
|
|
89
89
|
|
90
90
|
def build_path(name)
|
91
91
|
TestProf.artefact_path(
|
92
|
-
"stack-prof-report-#{config.mode}-#{name}.dump"
|
92
|
+
"stack-prof-report-#{config.mode}#{config.raw ? '-raw' : ''}-#{name}.dump"
|
93
93
|
)
|
94
94
|
end
|
95
95
|
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_prof/ext/float_duration"
|
4
|
+
|
5
|
+
module TestProf
|
6
|
+
module TagProf
|
7
|
+
class RSpecListener # :nodoc:
|
8
|
+
include Logging
|
9
|
+
using FloatDuration
|
10
|
+
|
11
|
+
NOTIFICATIONS = %i[
|
12
|
+
example_started
|
13
|
+
example_finished
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@tag = ENV['TAG_PROF'].to_sym
|
18
|
+
@tags = Hash.new { |h, k| h[k] = { val: k, count: 0, time: 0.0 } }
|
19
|
+
|
20
|
+
log :info, "TagProf enabled (#{@tag})"
|
21
|
+
end
|
22
|
+
|
23
|
+
def example_started(_notification)
|
24
|
+
@ts = Time.now
|
25
|
+
end
|
26
|
+
|
27
|
+
def example_finished(notification)
|
28
|
+
return if notification.example.pending?
|
29
|
+
|
30
|
+
tag = notification.example.metadata.fetch(@tag, :__unknown__)
|
31
|
+
|
32
|
+
@tags[tag][:count] += 1
|
33
|
+
@tags[tag][:time] += (Time.now - @ts)
|
34
|
+
end
|
35
|
+
|
36
|
+
def print
|
37
|
+
msgs = []
|
38
|
+
|
39
|
+
msgs <<
|
40
|
+
<<~MSG
|
41
|
+
TagProf report for #{@tag}
|
42
|
+
MSG
|
43
|
+
|
44
|
+
msgs << format(
|
45
|
+
"%15s %12s %6s %6s %6s %12s",
|
46
|
+
@tag,
|
47
|
+
'time', 'total', '%total', '%time', 'avg'
|
48
|
+
)
|
49
|
+
|
50
|
+
msgs << ""
|
51
|
+
|
52
|
+
total = @tags.values.sum { |v| v[:count] }
|
53
|
+
total_time = @tags.values.sum { |v| v[:time] }
|
54
|
+
|
55
|
+
@tags.values.sort_by { |v| -v[:time] }.each do |tag|
|
56
|
+
msgs << format(
|
57
|
+
"%15s %12s %6d %6.2f %6.2f %12s",
|
58
|
+
tag[:val], tag[:time].duration, tag[:count],
|
59
|
+
100 * tag[:count].to_f / total,
|
60
|
+
100 * tag[:time] / total_time,
|
61
|
+
(tag[:time] / tag[:count]).duration
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
log :info, msgs.join("\n")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Register TagProf listener
|
72
|
+
TestProf.activate('TAG_PROF') do
|
73
|
+
RSpec.configure do |config|
|
74
|
+
listener = TestProf::TagProf::RSpecListener.new
|
75
|
+
|
76
|
+
config.before(:suite) do
|
77
|
+
config.reporter.register_listener(
|
78
|
+
listener, *TestProf::TagProf::RSpecListener::NOTIFICATIONS
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
config.after(:suite) { listener.print }
|
83
|
+
end
|
84
|
+
end
|
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.1.0.
|
4
|
+
version: 0.1.0.beta3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladimir Dementyev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-07-
|
11
|
+
date: 2017-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -167,6 +167,7 @@ files:
|
|
167
167
|
- guides/rubocop.md
|
168
168
|
- guides/ruby_prof.md
|
169
169
|
- guides/stack_prof.md
|
170
|
+
- guides/tag_prof.md
|
170
171
|
- lib/test-prof.rb
|
171
172
|
- lib/test_prof.rb
|
172
173
|
- lib/test_prof/any_fixture.rb
|
@@ -199,6 +200,8 @@ files:
|
|
199
200
|
- lib/test_prof/ruby_prof/rspec.rb
|
200
201
|
- lib/test_prof/stack_prof.rb
|
201
202
|
- lib/test_prof/stack_prof/rspec.rb
|
203
|
+
- lib/test_prof/tag_prof.rb
|
204
|
+
- lib/test_prof/tag_prof/rspec.rb
|
202
205
|
- lib/test_prof/version.rb
|
203
206
|
homepage: http://github.com/palkan/test-prof
|
204
207
|
licenses:
|