test-prof 0.9.0 → 0.10.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 +35 -0
- data/README.md +28 -11
- data/lib/minitest/test_prof_plugin.rb +5 -5
- data/lib/test_prof.rb +3 -3
- data/lib/test_prof/ext/string_parameterize.rb +15 -0
- data/lib/test_prof/factory_doctor.rb +1 -1
- data/lib/test_prof/recipes/active_record_shared_connection.rb +7 -0
- data/lib/test_prof/recipes/rspec/let_it_be.rb +61 -18
- data/lib/test_prof/ruby_prof/rspec.rb +9 -1
- data/lib/test_prof/stack_prof/rspec.rb +9 -1
- data/lib/test_prof/utils/rspec.rb +18 -0
- data/lib/test_prof/version.rb +1 -1
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 19888b286ec85650d1d6c24c8d92ad1643e46cc506c2f9ce5e65c2f787f43949
|
4
|
+
data.tar.gz: ad6477b9980cd68782ceb2c2b138b9f01a3248f09ebf23e60acbe77e3124fc63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3da02b7d11494242e30360c10c2f69123e2c43f1b3e3ebd6edea567f4f298bb572daa726d8520d524602cb5b5ce2a6b8d68d59ad21238d9d6c1060b4d2132bf4
|
7
|
+
data.tar.gz: 9b5831c47845a4c4337898b5e1a58f495e60bca3e1726813b30469162544b77f715f4f0a07d901026d991304d65077abe16ae3d61c990d8fe136937e3cd4ceb3
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,41 @@
|
|
2
2
|
|
3
3
|
## master (unreleased)
|
4
4
|
|
5
|
+
## 0.10.0 (2019-08-19)
|
6
|
+
|
7
|
+
- Use RSpec example ID instead of full description for RubyProf/Stackprof report names. ([@palkan][])
|
8
|
+
|
9
|
+
For more complex scenarios feel free to use your own report name generator:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
# for RubyProf
|
13
|
+
TestProf::RubyProf::Listener.report_name_generator = ->(example) { "..." }
|
14
|
+
# for Stackprof
|
15
|
+
TestProf::StackProf::Listener.report_name_generator = ->(example) { "..." }
|
16
|
+
```
|
17
|
+
|
18
|
+
- Support arrays in `let_it_be` with modifiers. ([@palkan][])
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
# Now you can use modifiers with arrays
|
22
|
+
let_it_be(:posts, reload: true) { create_pair(:post) }
|
23
|
+
```
|
24
|
+
|
25
|
+
- Refactor `let_it_be` modifiers and allow adding custom modifiers. ([@palkan][])
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
TestProf::LetItBe.config.register_modifier :reload do |record, val|
|
29
|
+
# ignore when `reload: false`
|
30
|
+
next record unless val
|
31
|
+
# ignore non-ActiveRecord objects
|
32
|
+
next record unless record.is_a?(::ActiveRecord::Base)
|
33
|
+
record.reload
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
- Print warning when `ActiveRecordSharedConnection` is used in the version of Rails
|
38
|
+
supporting `lock_threads` (5.1+). ([@palkan][])
|
39
|
+
|
5
40
|
## 0.9.0 (2019-05-14)
|
6
41
|
|
7
42
|
- Add threshold and custom event support to FactoryDoctor. ([@palkan][])
|
data/README.md
CHANGED
@@ -21,26 +21,35 @@ TestProf toolbox aims to help you identify bottlenecks in your test suite. It co
|
|
21
21
|
|
22
22
|
- ActiveSupport-backed profilers
|
23
23
|
|
24
|
+
- RSpec and minitest [helpers](https://test-prof.evilmartians.io/#/?id=recipes) to write faster tests
|
25
|
+
|
24
26
|
- RuboCop cops
|
25
27
|
|
26
28
|
- etc.
|
27
29
|
|
28
|
-
Of course, we have some [solutions](https://test-prof.evilmartians.io/#/?id=recipes) for common performance issues too, bundled into the gem.
|
29
|
-
|
30
|
-
[](http://bit.ly/test-prof-map)
|
31
|
-
|
32
30
|
📑 [Documentation](https://test-prof.evilmartians.io)
|
33
31
|
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
<p align="center">
|
33
|
+
<a href="http://bit.ly/test-prof-map">
|
34
|
+
<img src="./docs/assets/images/coggle.png" alt="TestProf map" width="738">
|
35
|
+
</a>
|
36
|
+
</p>
|
37
37
|
|
38
|
-
|
38
|
+
<p align="center">
|
39
|
+
<a href="https://evilmartians.com/?utm_source=test-prof">
|
40
|
+
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg"
|
41
|
+
alt="Sponsored by Evil Martians" width="236" height="54">
|
42
|
+
</a>
|
43
|
+
</p>
|
39
44
|
|
40
|
-
|
45
|
+
## Who uses TestProf
|
41
46
|
|
42
|
-
|
43
|
-
|
47
|
+
- [Discourse](https://github.com/discourse/discourse) reduced [~27% of their test suite time](https://twitter.com/samsaffron/status/1125602558024699904)
|
48
|
+
- [Gitlab](https://gitlab.com/gitlab-org/gitlab-ce) reduced [39% of their API tests time](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14370)
|
49
|
+
- [CodeTriage](https://github.com/codetriage/codetriage)
|
50
|
+
- [Dev.to](https://github.com/thepracticaldev/dev.to)
|
51
|
+
- [Open Project](https://github.com/opf/openproject)
|
52
|
+
- [...and others](https://github.com/palkan/test-prof/issues/73)
|
44
53
|
|
45
54
|
## Resources
|
46
55
|
|
@@ -70,6 +79,14 @@ end
|
|
70
79
|
|
71
80
|
And that's it)
|
72
81
|
|
82
|
+
Supported Ruby versions:
|
83
|
+
|
84
|
+
- Ruby (MRI) >= 2.4.0 (**NOTE:** for Ruby 2.2 use TestProf < 0.7.0 or Ruby 2.3 use TestProf ~> 0.7.0)
|
85
|
+
|
86
|
+
- JRuby >= 9.1.0.0 (**NOTE:** refinements-dependent features might require 9.2.7+)
|
87
|
+
|
88
|
+
Supported RSpec version (for RSpec features only): >= 3.5.0 (for older RSpec versions use TestProf < 0.8.0).
|
89
|
+
|
73
90
|
## Usage
|
74
91
|
|
75
92
|
Check out our [docs][].
|
@@ -7,11 +7,11 @@ module Minitest # :nodoc:
|
|
7
7
|
module TestProf # :nodoc:
|
8
8
|
def self.configure_options(options = {})
|
9
9
|
options.tap do |opts|
|
10
|
-
opts[:event]
|
11
|
-
opts[:rank_by]
|
12
|
-
opts[:top_count]
|
13
|
-
opts[:per_example]
|
14
|
-
opts[:fdoc]
|
10
|
+
opts[:event] = ENV["EVENT_PROF"] if ENV["EVENT_PROF"]
|
11
|
+
opts[:rank_by] = ENV["EVENT_PROF_RANK"].to_sym if ENV["EVENT_PROF_RANK"]
|
12
|
+
opts[:top_count] = ENV["EVENT_PROF_TOP"].to_i if ENV["EVENT_PROF_TOP"]
|
13
|
+
opts[:per_example] = true if ENV["EVENT_PROF_EXAMPLES"]
|
14
|
+
opts[:fdoc] = true if ENV["FDOC"]
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
data/lib/test_prof.rb
CHANGED
@@ -130,9 +130,9 @@ module TestProf
|
|
130
130
|
|
131
131
|
# TestProf configuration
|
132
132
|
class Configuration
|
133
|
-
attr_accessor :output,
|
134
|
-
:color,
|
135
|
-
:output_dir,
|
133
|
+
attr_accessor :output, # IO to write output messages.
|
134
|
+
:color, # Whether to colorize output or not
|
135
|
+
:output_dir, # Directory to store artifacts
|
136
136
|
:timestamps, # Whethere to use timestamped names for artifacts,
|
137
137
|
:report_suffix # Custom suffix for reports/artifacts
|
138
138
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TestProf
|
4
|
+
# Extend String with #parameterize method
|
5
|
+
module StringParameterize
|
6
|
+
refine String do
|
7
|
+
# Replaces special characters in a string with dashes.
|
8
|
+
def parameterize(separator: "-", preserve_case: false)
|
9
|
+
gsub(/[^a-z0-9\-_]+/i, separator).tap do |str|
|
10
|
+
str.downcase! unless preserve_case
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -146,7 +146,7 @@ module TestProf
|
|
146
146
|
def subscribe!
|
147
147
|
::ActiveSupport::Notifications.subscribe(config.event) do |_name, _start, _finish, _id, query|
|
148
148
|
next if ignore? || !running? || within_factory?
|
149
|
-
next if query[:sql]
|
149
|
+
next if IGNORED_QUERIES_PATTERN.match?(query[:sql])
|
150
150
|
@queries_count += 1
|
151
151
|
end
|
152
152
|
end
|
@@ -65,6 +65,13 @@ module TestProf
|
|
65
65
|
end
|
66
66
|
|
67
67
|
ActiveSupport.on_load(:active_record) do
|
68
|
+
if ::ActiveRecord::Base.connection.pool.respond_to?(:lock_thread=)
|
69
|
+
TestProf.log :warn, "You activated ActiveRecordSharedConnection patch for the Rails version,\n" \
|
70
|
+
"which has a built-in support for the same functionality.\n" \
|
71
|
+
"Consider removing it, 'cause this could result in unexpected behaviour.\n\n" \
|
72
|
+
"Read more in the docs: https://test-prof.evilmartians.io/#/active_record_shared_connection"
|
73
|
+
end
|
74
|
+
|
68
75
|
TestProf::ActiveRecordSharedConnection.enable!
|
69
76
|
ActiveRecord::Base.singleton_class.prepend TestProf::ActiveRecordSharedConnection::Ext
|
70
77
|
end
|
@@ -4,6 +4,15 @@ require "test_prof"
|
|
4
4
|
require_relative "./before_all"
|
5
5
|
|
6
6
|
module TestProf
|
7
|
+
# Add `#map` to Object as an alias for `then` to use in modifiers
|
8
|
+
using(Module.new do
|
9
|
+
refine Object do
|
10
|
+
def map
|
11
|
+
yield self
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end)
|
15
|
+
|
7
16
|
# Just like `let`, but persist the result for the whole group.
|
8
17
|
# NOTE: Experimental and magical, for more control use `before_all`.
|
9
18
|
module LetItBe
|
@@ -16,6 +25,12 @@ module TestProf
|
|
16
25
|
def alias_to(name, **default_args)
|
17
26
|
LetItBe.define_let_it_be_alias(name, **default_args)
|
18
27
|
end
|
28
|
+
|
29
|
+
def register_modifier(key, &block)
|
30
|
+
raise ArgumentError, "Modifier #{key} is already defined for let_it_be" if LetItBe.modifiers.key?(key)
|
31
|
+
|
32
|
+
LetItBe.modifiers[key] = block
|
33
|
+
end
|
19
34
|
end
|
20
35
|
|
21
36
|
class << self
|
@@ -27,6 +42,24 @@ module TestProf
|
|
27
42
|
yield config
|
28
43
|
end
|
29
44
|
|
45
|
+
def modifiers
|
46
|
+
@modifiers ||= {}
|
47
|
+
end
|
48
|
+
|
49
|
+
def wrap_with_modifiers(mods, &block)
|
50
|
+
validate_modifiers! mods
|
51
|
+
|
52
|
+
return block if mods.empty?
|
53
|
+
|
54
|
+
-> {
|
55
|
+
instance_eval(&block).map do |record|
|
56
|
+
mods.inject(record) do |rec, (k, v)|
|
57
|
+
LetItBe.modifiers.fetch(k).call(rec, v)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
30
63
|
def module_for(group)
|
31
64
|
modules[group] ||= begin
|
32
65
|
Module.new.tap { |mod| group.prepend(mod) }
|
@@ -38,6 +71,14 @@ module TestProf
|
|
38
71
|
def modules
|
39
72
|
@modules ||= {}
|
40
73
|
end
|
74
|
+
|
75
|
+
def validate_modifiers!(mods)
|
76
|
+
unknown = mods.keys - modifiers.keys
|
77
|
+
return if unknown.empty?
|
78
|
+
|
79
|
+
raise ArgumentError, "Unknown let_it_be modifiers were used: #{unknown.join(", ")}. " \
|
80
|
+
"Available modifiers are: #{modifiers.keys.join(", ")}"
|
81
|
+
end
|
41
82
|
end
|
42
83
|
# Use uniq prefix for instance variables to avoid collisions
|
43
84
|
# We want to use the power of Ruby's unicode support)
|
@@ -64,24 +105,9 @@ module TestProf
|
|
64
105
|
define_let_it_be_methods(identifier, **options)
|
65
106
|
end
|
66
107
|
|
67
|
-
def define_let_it_be_methods(identifier,
|
68
|
-
let_accessor =
|
69
|
-
|
70
|
-
if reload
|
71
|
-
let_accessor = lambda do
|
72
|
-
record = instance_variable_get(:"#{PREFIX}#{identifier}")
|
73
|
-
next unless record.is_a?(::ActiveRecord::Base)
|
74
|
-
record.reload
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
if refind
|
79
|
-
let_accessor = lambda do
|
80
|
-
record = instance_variable_get(:"#{PREFIX}#{identifier}")
|
81
|
-
next unless record.is_a?(::ActiveRecord::Base)
|
82
|
-
|
83
|
-
record.class.find(record.send(record.class.primary_key))
|
84
|
-
end
|
108
|
+
def define_let_it_be_methods(identifier, **modifiers)
|
109
|
+
let_accessor = LetItBe.wrap_with_modifiers(modifiers) do
|
110
|
+
instance_variable_get(:"#{PREFIX}#{identifier}")
|
85
111
|
end
|
86
112
|
|
87
113
|
LetItBe.module_for(self).module_eval do
|
@@ -101,4 +127,21 @@ module TestProf
|
|
101
127
|
end
|
102
128
|
end
|
103
129
|
|
130
|
+
require "test_prof/ext/active_record_refind"
|
131
|
+
using TestProf::Ext::ActiveRecordRefind
|
132
|
+
|
133
|
+
TestProf::LetItBe.configure do |config|
|
134
|
+
config.register_modifier :reload do |record, val|
|
135
|
+
next record unless val
|
136
|
+
next record unless record.is_a?(::ActiveRecord::Base)
|
137
|
+
record.reload
|
138
|
+
end
|
139
|
+
|
140
|
+
config.register_modifier :refind do |record, val|
|
141
|
+
next record unless val
|
142
|
+
next record unless record.is_a?(::ActiveRecord::Base)
|
143
|
+
record.refind
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
104
147
|
RSpec::Core::ExampleGroup.extend TestProf::LetItBe
|
@@ -1,9 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "test_prof/utils/rspec"
|
4
|
+
|
3
5
|
module TestProf
|
4
6
|
module RubyProf
|
5
7
|
# Reporter for RSpec to profile specific examples with RubyProf
|
6
8
|
class Listener # :nodoc:
|
9
|
+
class << self
|
10
|
+
attr_accessor :report_name_generator
|
11
|
+
end
|
12
|
+
|
13
|
+
self.report_name_generator = Utils::RSpec.method(:example_to_filename)
|
14
|
+
|
7
15
|
NOTIFICATIONS = %i[
|
8
16
|
example_started
|
9
17
|
example_finished
|
@@ -18,7 +26,7 @@ module TestProf
|
|
18
26
|
def example_finished(notification)
|
19
27
|
return unless profile?(notification.example)
|
20
28
|
notification.example.metadata[:rprof_report]&.dump(
|
21
|
-
notification.example
|
29
|
+
self.class.report_name_generator.call(notification.example)
|
22
30
|
)
|
23
31
|
end
|
24
32
|
|
@@ -1,9 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "test_prof/utils/rspec"
|
4
|
+
|
3
5
|
module TestProf
|
4
6
|
module StackProf
|
5
7
|
# Reporter for RSpec to profile specific examples with StackProf
|
6
8
|
class Listener # :nodoc:
|
9
|
+
class << self
|
10
|
+
attr_accessor :report_name_generator
|
11
|
+
end
|
12
|
+
|
13
|
+
self.report_name_generator = Utils::RSpec.method(:example_to_filename)
|
14
|
+
|
7
15
|
NOTIFICATIONS = %i[
|
8
16
|
example_started
|
9
17
|
example_finished
|
@@ -19,7 +27,7 @@ module TestProf
|
|
19
27
|
return unless notification.example.metadata[:sprof_report] == false
|
20
28
|
|
21
29
|
TestProf::StackProf.dump(
|
22
|
-
notification.example
|
30
|
+
self.class.report_name_generator.call(notification.example)
|
23
31
|
)
|
24
32
|
end
|
25
33
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
unless "".respond_to?(:parameterize)
|
4
|
+
require "test_prof/ext/string_parameterize"
|
5
|
+
using TestProf::StringParameterize
|
6
|
+
end
|
7
|
+
|
8
|
+
module TestProf
|
9
|
+
module Utils
|
10
|
+
module RSpec
|
11
|
+
class << self
|
12
|
+
def example_to_filename(example)
|
13
|
+
::RSpec::Core::Metadata.id_from(example.metadata).parameterize
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
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.
|
4
|
+
version: 0.10.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-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 0.0
|
103
|
+
version: 0.1.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.0
|
110
|
+
version: 0.1.0
|
111
111
|
description: "\n Ruby applications tests profiling tools.\n\n Contains tools
|
112
112
|
to analyze factories usage, integrate with Ruby profilers,\n profile your examples
|
113
113
|
using ActiveSupport notifications (if any) and\n statically analyze your code
|
@@ -158,6 +158,7 @@ files:
|
|
158
158
|
- lib/test_prof/ext/array_bsearch_index.rb
|
159
159
|
- lib/test_prof/ext/factory_bot_strategy.rb
|
160
160
|
- lib/test_prof/ext/float_duration.rb
|
161
|
+
- lib/test_prof/ext/string_parameterize.rb
|
161
162
|
- lib/test_prof/ext/string_truncate.rb
|
162
163
|
- lib/test_prof/factory_all_stub.rb
|
163
164
|
- lib/test_prof/factory_all_stub/factory_bot_patch.rb
|
@@ -209,6 +210,7 @@ files:
|
|
209
210
|
- lib/test_prof/tag_prof/rspec.rb
|
210
211
|
- lib/test_prof/utils.rb
|
211
212
|
- lib/test_prof/utils/html_builder.rb
|
213
|
+
- lib/test_prof/utils/rspec.rb
|
212
214
|
- lib/test_prof/utils/sized_ordered_set.rb
|
213
215
|
- lib/test_prof/version.rb
|
214
216
|
homepage: http://github.com/palkan/test-prof
|
@@ -235,7 +237,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
235
237
|
- !ruby/object:Gem::Version
|
236
238
|
version: '0'
|
237
239
|
requirements: []
|
238
|
-
rubygems_version: 3.0.
|
240
|
+
rubygems_version: 3.0.4
|
239
241
|
signing_key:
|
240
242
|
specification_version: 4
|
241
243
|
summary: Ruby applications tests profiling tools
|