test-prof 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![](./docs/assets/images/coggle.png)](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
|