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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6cf66f80707806f1378f3164e1376e6ee8fe5c3472d0704ef865de4939852283
4
- data.tar.gz: 472ea3dde66363470b5e62995548760359f5ecd358b84099d12d9a622b36063d
3
+ metadata.gz: 19888b286ec85650d1d6c24c8d92ad1643e46cc506c2f9ce5e65c2f787f43949
4
+ data.tar.gz: ad6477b9980cd68782ceb2c2b138b9f01a3248f09ebf23e60acbe77e3124fc63
5
5
  SHA512:
6
- metadata.gz: 4c21d8cae35943af31f72617a20b11d653ade888ba264c510dbe1fc365052a3ed7c7e04a7516b967a4f47dcb2442754a0d4e60053c385ae859963b666d239f9e
7
- data.tar.gz: 7615a8bdb3d087c254333c265ffd759d13b51e76c6913d8e38a6856bdc036303f096ef2f2fb83c1b867024a87fe4989635105361103e85d7e1f4b14c0ae584bd
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
- Supported Ruby versions:
35
-
36
- - Ruby (MRI) >= 2.4.0 (**NOTE:** for Ruby 2.2 use TestProf < 0.7.0 or Ruby 2.3 use TestProf ~> 0.7.0)
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
- - JRuby >= 9.1.0.0 (**NOTE:** refinements-dependent features might require 9.2.7+)
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
- Supported RSpec version (for RSpec features only): >= 3.5.0 (for older RSpec versions use TestProf < 0.8.0).
45
+ ## Who uses TestProf
41
46
 
42
- <a href="https://evilmartians.com/">
43
- <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
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] = 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"]
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, # IO to write output messages.
134
- :color, # Whether to colorize output or not
135
- :output_dir, # Directory to store artifacts
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] =~ IGNORED_QUERIES_PATTERN
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, reload: false, refind: false)
68
- let_accessor = -> { instance_variable_get(:"#{PREFIX}#{identifier}") }
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.full_description.parameterize
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.full_description.parameterize
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf
4
- VERSION = "0.9.0"
4
+ VERSION = "0.10.0"
5
5
  end
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.9.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-05-14 00:00:00.000000000 Z
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.39
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.39
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.3
240
+ rubygems_version: 3.0.4
239
241
  signing_key:
240
242
  specification_version: 4
241
243
  summary: Ruby applications tests profiling tools