test-prof 0.7.5 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -2
  3. data/README.md +5 -3
  4. data/lib/minitest/base_reporter.rb +18 -12
  5. data/lib/minitest/test_prof_plugin.rb +8 -8
  6. data/lib/test_prof.rb +3 -3
  7. data/lib/test_prof/any_fixture.rb +3 -3
  8. data/lib/test_prof/before_all.rb +9 -0
  9. data/lib/test_prof/before_all/adapters/active_record.rb +12 -0
  10. data/lib/test_prof/before_all/isolator.rb +18 -0
  11. data/lib/test_prof/cops/rspec/aggregate_failures.rb +6 -6
  12. data/lib/test_prof/event_prof.rb +6 -6
  13. data/lib/test_prof/event_prof/custom_events/factory_create.rb +1 -1
  14. data/lib/test_prof/event_prof/custom_events/sidekiq_inline.rb +2 -2
  15. data/lib/test_prof/event_prof/custom_events/sidekiq_jobs.rb +2 -2
  16. data/lib/test_prof/event_prof/instrumentations/active_support.rb +1 -1
  17. data/lib/test_prof/event_prof/minitest.rb +4 -4
  18. data/lib/test_prof/event_prof/rspec.rb +4 -11
  19. data/lib/test_prof/factory_bot.rb +1 -1
  20. data/lib/test_prof/factory_default.rb +1 -1
  21. data/lib/test_prof/factory_doctor.rb +2 -2
  22. data/lib/test_prof/factory_doctor/minitest.rb +4 -4
  23. data/lib/test_prof/factory_doctor/rspec.rb +7 -10
  24. data/lib/test_prof/factory_prof.rb +6 -6
  25. data/lib/test_prof/factory_prof/factory_builders/fabrication.rb +1 -1
  26. data/lib/test_prof/factory_prof/printers/flamegraph.rb +1 -1
  27. data/lib/test_prof/recipes/logging.rb +86 -21
  28. data/lib/test_prof/recipes/minitest/before_all.rb +3 -2
  29. data/lib/test_prof/recipes/minitest/sample.rb +5 -5
  30. data/lib/test_prof/recipes/rspec/any_fixture.rb +3 -1
  31. data/lib/test_prof/recipes/rspec/before_all.rb +12 -3
  32. data/lib/test_prof/recipes/rspec/factory_all_stub.rb +5 -1
  33. data/lib/test_prof/recipes/rspec/let_it_be.rb +3 -13
  34. data/lib/test_prof/rspec_dissect.rb +13 -19
  35. data/lib/test_prof/rspec_dissect/rspec.rb +2 -6
  36. data/lib/test_prof/rspec_stamp.rb +14 -14
  37. data/lib/test_prof/rspec_stamp/parser.rb +1 -1
  38. data/lib/test_prof/rspec_stamp/rspec.rb +1 -1
  39. data/lib/test_prof/ruby_prof.rb +32 -24
  40. data/lib/test_prof/ruby_prof/rspec.rb +2 -6
  41. data/lib/test_prof/stack_prof.rb +23 -15
  42. data/lib/test_prof/stack_prof/rspec.rb +5 -6
  43. data/lib/test_prof/tag_prof/printers/simple.rb +4 -4
  44. data/lib/test_prof/tag_prof/result.rb +3 -3
  45. data/lib/test_prof/tag_prof/rspec.rb +9 -14
  46. data/lib/test_prof/utils/html_builder.rb +1 -1
  47. data/lib/test_prof/utils/sized_ordered_set.rb +1 -1
  48. data/lib/test_prof/version.rb +1 -1
  49. metadata +37 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d382abde5291f54f1168e9403e3151aaafbe6e6e7409de394169169a0eca19fe
4
- data.tar.gz: 68037c8c7d819c6e68d7e8d4a4291471101539a6239f452e630de5ea0a4648d6
3
+ metadata.gz: 65bd3447c63c3e7c037707ebd0f637831ccf0c98af1b0b3d9bf0a6fa72c56b11
4
+ data.tar.gz: d6af1b43e6924c67ef4c2297602ef641377584f3282eafc236e48eb951e04b68
5
5
  SHA512:
6
- metadata.gz: fe73709e9e6d6e609f4a0f705d2de0dbab37daecffeb1bac91a4b1a7585a9f81bc656489e9b84d43ad5a9dd04be93a5b9b1020eecd370cbbfee2d2c2fbc862ce
7
- data.tar.gz: 91ff9f2c02b86260c9d0d88b834775528007b05eefa3fb00ba28ce9464dbfc615ae7ddde33f2d7544bfc048602687da078b6d01bd38038609b1ca33bb83500fe
6
+ metadata.gz: 2eae07fcbce70eb7598b92fc578530ed5e20edfb3d7752c672740d44aa13f5d925005500aa26e83ce004c0b2ba128b0091362c39771b67e12d352360aacc2081
7
+ data.tar.gz: 213858acbdaa8d5e2e6e1fcdd99ca952a044949d23846f631a34513d379ce583013c13ed76c0303c8bd8fec777f44b99bf992e8937598d22bf4110cedb408eb6
@@ -2,6 +2,24 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.8.0 (2019-04-12) 🚀
6
+
7
+ - **Ruby 2.4+ is requiered** ([@palkan][])
8
+
9
+ - **RSpec 3.5+ is requiered for RSpec features** ([@palkan][])
10
+
11
+ - Make `before_all` compatible with [`isolator`](https://github.com/palkan/isolator). ([@palkan][])
12
+
13
+ - Add `with_logging` and `with_ar_logging` helpers to logging recipe. ([@palkan][])
14
+
15
+ - Make `before_all` for Active Record `lock_thread` aware. ([@palkan][])
16
+
17
+ `before_all` can went crazy if you open multiple connections within it
18
+ (since it tracks the number of open transactions).
19
+ Rails 5+ `lock_thread` feature only locks the connection thread in
20
+ `before`/`setup` hook thus making it possible to have multiple connections/transactions
21
+ in `before_all` (e.g. performing jobs with Active Job async adapter).
22
+
5
23
  ## 0.7.5 (2019-02-22)
6
24
 
7
25
  - Make `let_it_be` and `before_all` work with `include_context`. ([@palkan][])
@@ -58,7 +76,7 @@ Add ability to specify custom exclusions through `config.custom_exclusions`, e.g
58
76
 
59
77
  ```ruby
60
78
  TestProf::RubyProf.configure do |config|
61
- config.custom_exclusions = { User => %i[save save!] }
79
+ config.custom_exclusions = {User => %i[save save!]}
62
80
  end
63
81
  ```
64
82
 
@@ -161,7 +179,7 @@ LOG=all rspec
161
179
  Or per example (group):
162
180
 
163
181
  ```ruby
164
- it 'does smth weird', :log do
182
+ it "does smth weird", :log do
165
183
  # ...
166
184
  end
167
185
  ```
data/README.md CHANGED
@@ -33,9 +33,11 @@ Of course, we have some [solutions](https://test-prof.evilmartians.io/#/?id=reci
33
33
 
34
34
  Supported Ruby versions:
35
35
 
36
- - Ruby (MRI) >= 2.3.0 (**NOTE:** for Ruby 2.2 use TestProf < 0.7.0)
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)
37
37
 
38
- - JRuby >= 9.1.0.0
38
+ - JRuby >= 9.1.0.0 (**NOTE:** refinements-dependent features might require 9.2.7+)
39
+
40
+ Supported RSpec version (for RSpec features only): >= 3.5.0 (for older RSpec versions use TestProf < 0.8.0).
39
41
 
40
42
  <a href="https://evilmartians.com/">
41
43
  <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
@@ -62,7 +64,7 @@ Add `test-prof` gem to your application:
62
64
 
63
65
  ```ruby
64
66
  group :test do
65
- gem 'test-prof'
67
+ gem "test-prof"
66
68
  end
67
69
  ```
68
70
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'minitest'
4
- require 'test_prof/logging'
3
+ require "minitest"
4
+ require "test_prof/logging"
5
5
 
6
6
  module Minitest
7
7
  module TestProf
@@ -15,17 +15,23 @@ module Minitest
15
15
  inject_to_minitest_reporters if defined? Minitest::Reporters
16
16
  end
17
17
 
18
- def start; end
18
+ def start
19
+ end
19
20
 
20
- def prerecord(group, example); end
21
+ def prerecord(group, example)
22
+ end
21
23
 
22
- def before_test(test); end
24
+ def before_test(test)
25
+ end
23
26
 
24
- def record(*); end
27
+ def record(*)
28
+ end
25
29
 
26
- def after_test(test); end
30
+ def after_test(test)
31
+ end
27
32
 
28
- def report; end
33
+ def report
34
+ end
29
35
 
30
36
  private
31
37
 
@@ -33,22 +39,22 @@ module Minitest
33
39
  # Minitest::Result (>= 5.11) has `source_location` method
34
40
  return group.source_location if group.respond_to?(:source_location)
35
41
  if group.is_a? Class
36
- suite = group.public_instance_methods.select { |mtd| mtd.to_s.match /^test_/ }
42
+ suite = group.public_instance_methods.select { |mtd| mtd.to_s.match(/^test_/) }
37
43
  name = suite.find { |mtd| mtd.to_s == example }
38
44
  group.instance_method(name).source_location
39
45
  else
40
- suite = group.methods.select { |mtd| mtd.to_s.match /^test_/ }
46
+ suite = group.methods.select { |mtd| mtd.to_s.match(/^test_/) }
41
47
  name = suite.find { |mtd| mtd.to_s == group.name }
42
48
  group.method(name).source_location
43
49
  end
44
50
  end
45
51
 
46
52
  def location_with_line_number(group, example = nil)
47
- File.expand_path(location(group, example).join(':')).gsub(Dir.getwd, '.')
53
+ File.expand_path(location(group, example).join(":")).gsub(Dir.getwd, ".")
48
54
  end
49
55
 
50
56
  def location_without_line_number(group, example = nil)
51
- File.expand_path(location(group, example).first).gsub(Dir.getwd, '.')
57
+ File.expand_path(location(group, example).first).gsub(Dir.getwd, ".")
52
58
  end
53
59
 
54
60
  def inject_to_minitest_reporters
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'test_prof/event_prof/minitest'
4
- require 'test_prof/factory_doctor/minitest'
3
+ require "test_prof/event_prof/minitest"
4
+ require "test_prof/factory_doctor/minitest"
5
5
 
6
6
  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
@@ -29,7 +29,7 @@ module Minitest # :nodoc:
29
29
  opts.on "--event-prof-per-example", TrueClass, "Includes examples metrics to results" do |flag|
30
30
  options[:per_example] = flag
31
31
  end
32
- opts.on "--factory-doctor", TrueClass, 'Enable Factory Doctor for your examples' do |flag|
32
+ opts.on "--factory-doctor", TrueClass, "Enable Factory Doctor for your examples" do |flag|
33
33
  options[:fdoc] = flag
34
34
  end
35
35
  end
@@ -114,13 +114,13 @@ module TestProf
114
114
  def with_timestamps(path)
115
115
  return path unless config.timestamps?
116
116
  timestamps = "-#{now.to_i}"
117
- "#{path.sub(/\.\w+$/, '')}#{timestamps}#{::File.extname(path)}"
117
+ "#{path.sub(/\.\w+$/, "")}#{timestamps}#{::File.extname(path)}"
118
118
  end
119
119
 
120
120
  def with_report_suffix(path)
121
121
  return path if config.report_suffix.nil?
122
122
 
123
- "#{path.sub(/\.\w+$/, '')}-#{config.report_suffix}#{::File.extname(path)}"
123
+ "#{path.sub(/\.\w+$/, "")}-#{config.report_suffix}#{::File.extname(path)}"
124
124
  end
125
125
 
126
126
  def notify_spring_detected
@@ -147,7 +147,7 @@ module TestProf
147
147
  @color = true
148
148
  @output_dir = "tmp/test_prof"
149
149
  @timestamps = false
150
- @report_suffix = ENV['TEST_PROF_REPORT']
150
+ @report_suffix = ENV["TEST_PROF_REPORT"]
151
151
  end
152
152
 
153
153
  def color?
@@ -27,7 +27,7 @@ module TestProf
27
27
 
28
28
  ts = TestProf.now
29
29
  store[key] = yield
30
- stats[key] = { time: TestProf.now - ts, hit: 0 }
30
+ stats[key] = {time: TestProf.now - ts, hit: 0}
31
31
  store[key]
32
32
  end
33
33
 
@@ -91,7 +91,7 @@ module TestProf
91
91
 
92
92
  msgs << format(
93
93
  "%#{first_column}s %12s %9s %12s",
94
- 'key', 'build time', 'hit count', 'saved time'
94
+ "key", "build time", "hit count", "saved time"
95
95
  )
96
96
 
97
97
  msgs << ""
@@ -144,6 +144,6 @@ module TestProf
144
144
  end
145
145
  end
146
146
 
147
- self.reporting_enabled = ENV['ANYFIXTURE_REPORT'] == '1'
147
+ self.reporting_enabled = ENV["ANYFIXTURE_REPORT"] == "1"
148
148
  end
149
149
  end
@@ -18,6 +18,11 @@ module TestProf
18
18
  def begin_transaction
19
19
  raise AdapterMissing if adapter.nil?
20
20
  adapter.begin_transaction
21
+ yield
22
+ end
23
+
24
+ def within_transaction
25
+ yield
21
26
  end
22
27
 
23
28
  def rollback_transaction
@@ -33,3 +38,7 @@ if defined?(::ActiveRecord::Base)
33
38
 
34
39
  TestProf::BeforeAll.adapter = TestProf::BeforeAll::Adapters::ActiveRecord
35
40
  end
41
+
42
+ if defined?(::Isolator)
43
+ require "test_prof/before_all/isolator"
44
+ end
@@ -12,6 +12,7 @@ module TestProf
12
12
  module ActiveRecord
13
13
  class << self
14
14
  def begin_transaction
15
+ lock_thread!
15
16
  ::ActiveRecord::Base.connection.begin_transaction(joinable: false)
16
17
  end
17
18
 
@@ -23,6 +24,17 @@ module TestProf
23
24
  end
24
25
  ::ActiveRecord::Base.connection.rollback_transaction
25
26
  end
27
+
28
+ private
29
+
30
+ # Make sure ActiveRecord uses locked thread.
31
+ # It only gets locked in `before` / `setup` hook,
32
+ # thus using thread in `before_all` (e.g. ActiveJob async adapter)
33
+ # might lead to leaking connections
34
+ def lock_thread!
35
+ return unless ::ActiveRecord::Base.connection.pool.respond_to?(:lock_thread=)
36
+ ::ActiveRecord::Base.connection.pool.lock_thread = true
37
+ end
26
38
  end
27
39
  end
28
40
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TestProf
4
+ module BeforeAll
5
+ # Disable Isolator within before_all blocks
6
+ module Isolator
7
+ def begin_transaction(*)
8
+ ::Isolator.disable { super }
9
+ end
10
+
11
+ def within_transaction(*)
12
+ ::Isolator.disable { super }
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ TestProf::BeforeAll.singleton_class.prepend(TestProf::BeforeAll::Isolator)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rubocop'
4
- require 'test_prof/utils'
3
+ require "rubocop"
4
+ require "test_prof/utils"
5
5
 
6
6
  module RuboCop
7
7
  module Cop
@@ -38,7 +38,7 @@ module RuboCop
38
38
  class << self
39
39
  def supported?
40
40
  return @supported if instance_variable_defined?(:@supported)
41
- @supported = TestProf::Utils.verify_gem_version('rubocop', at_least: '0.51.0')
41
+ @supported = TestProf::Utils.verify_gem_version("rubocop", at_least: "0.51.0")
42
42
 
43
43
  unless @supported
44
44
  warn "RSpec/AggregateFailures cop requires RuboCop >= 0.51.0. Skipping"
@@ -62,7 +62,7 @@ module RuboCop
62
62
  add_offense(
63
63
  node,
64
64
  location: :expression,
65
- message: 'Use :aggregate_failures instead of several one-liners.'
65
+ message: "Use :aggregate_failures instead of several one-liners."
66
66
  )
67
67
  end
68
68
 
@@ -140,7 +140,7 @@ module RuboCop
140
140
  %(#{method_name} "works", :aggregate_failures do)
141
141
  end
142
142
 
143
- def body_from(node, base_indent = '')
143
+ def body_from(node, base_indent = "")
144
144
  method, _args, body = *node
145
145
  body_source = method.method_name == :its ? body_from_its(method, body) : body.source
146
146
  "#{base_indent}#{indent}#{body_source}"
@@ -162,7 +162,7 @@ module RuboCop
162
162
  end
163
163
 
164
164
  def indent
165
- @indent ||= " " * (config.for_cop('IndentationWidth')['Width'] || 2)
165
+ @indent ||= " " * (config.for_cop("IndentationWidth")["Width"] || 2)
166
166
  end
167
167
  end
168
168
  end
@@ -31,19 +31,19 @@ module TestProf
31
31
  class Configuration
32
32
  # Map of supported instrumenters
33
33
  INSTRUMENTERS = {
34
- active_support: 'ActiveSupport'
34
+ active_support: "ActiveSupport"
35
35
  }.freeze
36
36
 
37
37
  attr_accessor :instrumenter, :top_count, :per_example,
38
38
  :rank_by, :event
39
39
 
40
40
  def initialize
41
- @event = ENV['EVENT_PROF']
41
+ @event = ENV["EVENT_PROF"]
42
42
  @instrumenter = :active_support
43
- @top_count = (ENV['EVENT_PROF_TOP'] || 5).to_i
44
- @per_example = ENV['EVENT_PROF_EXAMPLES'] == '1'
45
- @rank_by = (ENV['EVENT_PROF_RANK'] || :time).to_sym
46
- @stamp = ENV['EVENT_PROF_STAMP']
43
+ @top_count = (ENV["EVENT_PROF_TOP"] || 5).to_i
44
+ @per_example = ENV["EVENT_PROF_EXAMPLES"] == "1"
45
+ @rank_by = (ENV["EVENT_PROF_RANK"] || :time).to_sym
46
+ @stamp = ENV["EVENT_PROF_STAMP"]
47
47
 
48
48
  RSpecStamp.config.tags = @stamp if stamp?
49
49
  end
@@ -26,7 +26,7 @@ module TestProf::EventProf::CustomEvents
26
26
  res =
27
27
  if @depth == 1
28
28
  ActiveSupport::Notifications.instrument(
29
- 'factory.create',
29
+ "factory.create",
30
30
  name: factory
31
31
  ) { yield }
32
32
  else
@@ -22,7 +22,7 @@ module TestProf::EventProf::CustomEvents
22
22
  res =
23
23
  if @depth == 1
24
24
  ActiveSupport::Notifications.instrument(
25
- 'sidekiq.inline'
25
+ "sidekiq.inline"
26
26
  ) { yield }
27
27
  else
28
28
  yield
@@ -38,7 +38,7 @@ end
38
38
 
39
39
  TestProf::EventProf::CustomEvents.register("sidekiq.inline") do
40
40
  if TestProf.require(
41
- 'sidekiq/testing',
41
+ "sidekiq/testing",
42
42
  <<~MSG
43
43
  Failed to load Sidekiq.
44
44
 
@@ -16,7 +16,7 @@ module TestProf::EventProf::CustomEvents
16
16
 
17
17
  def track
18
18
  ActiveSupport::Notifications.instrument(
19
- 'sidekiq.jobs'
19
+ "sidekiq.jobs"
20
20
  ) { yield }
21
21
  end
22
22
  end
@@ -25,7 +25,7 @@ end
25
25
 
26
26
  TestProf::EventProf::CustomEvents.register("sidekiq.jobs") do
27
27
  if TestProf.require(
28
- 'sidekiq/testing',
28
+ "sidekiq/testing",
29
29
  <<~MSG
30
30
  Failed to load Sidekiq.
31
31
 
@@ -6,7 +6,7 @@ module TestProf::EventProf
6
6
  module ActiveSupport
7
7
  class << self
8
8
  def subscribe(event)
9
- raise ArgumentError, 'Block is required!' unless block_given?
9
+ raise ArgumentError, "Block is required!" unless block_given?
10
10
 
11
11
  ::ActiveSupport::Notifications.subscribe(event) do |_event, start, finish, *_args|
12
12
  yield (finish - start)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'minitest/base_reporter'
4
- require 'minitest/event_prof_formatter'
3
+ require "minitest/base_reporter"
4
+ require "minitest/event_prof_formatter"
5
5
 
6
6
  module Minitest
7
7
  module TestProf
@@ -10,7 +10,7 @@ module Minitest
10
10
  super
11
11
  @profiler = configure_profiler(options)
12
12
 
13
- log :info, "EventProf enabled (#{@profiler.events.join(', ')})"
13
+ log :info, "EventProf enabled (#{@profiler.events.join(", ")})"
14
14
 
15
15
  @formatter = EventProfFormatter.new(@profiler)
16
16
  @current_group = nil
@@ -45,7 +45,7 @@ module Minitest
45
45
  end
46
46
 
47
47
  @current_example = {
48
- name: example.gsub(/^test_(?:\d+_)?/, ''),
48
+ name: example.gsub(/^test_(?:\d+_)?/, ""),
49
49
  location: location_with_line_number(group, example)
50
50
  }
51
51