test-prof 1.0.7 → 1.0.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f55e42ee372a9ebe0f8981487931bf70ab3209e38163b32f84a7553bdfb4249
4
- data.tar.gz: 3ca0352ca4671c11d18937d3ee1de361322c827671d199d079b1460667c32a1c
3
+ metadata.gz: 9d847a0016b2749e8ba8a637d2db3d0044f7b77cfc5962596ff490aea0f5fc7d
4
+ data.tar.gz: 1f32af0e6e09b555bf258c5a52586a9d4a768578b0c816298343dfd5deb826da
5
5
  SHA512:
6
- metadata.gz: 00dcd7797667e28b54fe32e36392e44b80a1dd6fdcc04b8a0565084311c5420bbe017eecba2ae553b84b2cdd6bc92886f15a919da8e1ba7a293aa737bc2c81da
7
- data.tar.gz: eed04e297d23872fae979d7da614d4cf2730c4414b7eb26ad14095e619eeabd872619cd3e51293a4949fc04f214807cb10425da4a7ebe343df8a8f9af766f413
6
+ metadata.gz: 55db394aef01457404c8f5cd914cfa0eb359f3bea08874c6d4a6b75b1151af5b4153087815c90ed73ea5948c403941918b75af0b79558afe795db77c4d2b2568
7
+ data.tar.gz: d95cfbd7c513d086cd47b2ce0a804ec52fdf174854c0a07c239289c65d97d18833529321e0ffb4853aabc802f05a8a8eac4e3fcdc7011f0ffd1bf0c60d150b41
data/CHANGELOG.md CHANGED
@@ -1,6 +1,30 @@
1
1
  # Change log
2
2
 
3
- ## master (unrealeased)
3
+ ## master (unreleased)
4
+
5
+ ## 1.0.10 (2022-08-12)
6
+
7
+ - Allow overriding global logger. ([@palkan][])
8
+
9
+ ```ruby
10
+ require "test_prof/recipes/logging"
11
+
12
+ TestProf::Rails::LoggingHelpers.logger = CustomLogger.new
13
+ ```
14
+
15
+ ## 1.0.9 (2022-05-05)
16
+
17
+ - Add `AnyFixture.before_fixtures_reset` and `AnyFixture.after_fixtures_reset` callbacks. ([@ruslanshakirov][])
18
+
19
+ - Fixes ActiveRecord 6.1 issue with AnyFixture and Postgres config ([@markedmondson][])
20
+
21
+ ## 1.0.8 (2022-03-11)
22
+
23
+ - Restore the lock_thread value after rollback. ([@cou929][])
24
+
25
+ - Fixes the configuration of a printer for factory_prof runs
26
+
27
+ - Ensure that defaults are stored in a threadsafe manner
4
28
 
5
29
  ## 1.0.7 (2021-08-30)
6
30
 
@@ -267,3 +291,6 @@ See [changelog](https://github.com/test-prof/test-prof/blob/v0.8.0/CHANGELOG.md)
267
291
  [@stefkin]: https://github.com/stefkin
268
292
  [@jaimerson]: https://github.com/jaimerson
269
293
  [@alexvko]: https://github.com/alexvko
294
+ [@grillermo]: https://github.com/grillermo
295
+ [@cou929]: https://github.com/cou929
296
+ [@ruslanshakirov]: https://github.com/ruslanshakirov
@@ -2,7 +2,7 @@
2
2
 
3
3
  module TestProf
4
4
  module AnyFixture
5
- # Adds "global" `fixture` method (through refinement)
5
+ # Adds "global" `fixture`, `before_fixtures_reset` and `after_fixtures_reset` methods (through refinement)
6
6
  module DSL
7
7
  # Refine object, 'cause refining modules (Kernel) is vulnerable to prepend:
8
8
  # - https://bugs.ruby-lang.org/issues/13446
@@ -11,6 +11,14 @@ module TestProf
11
11
  def fixture(id, &block)
12
12
  ::TestProf::AnyFixture.register(:"#{id}", &block)
13
13
  end
14
+
15
+ def before_fixtures_reset(&block)
16
+ ::TestProf::AnyFixture.before_fixtures_reset(&block)
17
+ end
18
+
19
+ def after_fixtures_reset(&block)
20
+ ::TestProf::AnyFixture.after_fixtures_reset(&block)
21
+ end
14
22
  end
15
23
  end
16
24
  end
@@ -23,14 +23,14 @@ module TestProf
23
23
  end
24
24
 
25
25
  def compile_sql(sql, binds)
26
- sql.gsub(/\$\d+/) { binds.shift }
26
+ sql.gsub(/\$\d+/) { binds.shift.gsub("\n", "' || chr(10) || '") }
27
27
  end
28
28
 
29
29
  def import(path)
30
30
  # Test if psql is installed
31
31
  `psql --version`
32
32
 
33
- tasks = ActiveRecord::Tasks::PostgreSQLDatabaseTasks.new(conn.pool.spec.config.with_indifferent_access)
33
+ tasks = ActiveRecord::Tasks::PostgreSQLDatabaseTasks.new(config)
34
34
 
35
35
  while_disconnected do
36
36
  tasks.structure_load(path, "--output=/dev/null")
@@ -85,6 +85,15 @@ module TestProf
85
85
  def execute(query)
86
86
  super.values
87
87
  end
88
+
89
+ def config
90
+ conn_pool = conn.pool
91
+ if conn_pool.respond_to?(:spec) # Support for Rails < 6.1
92
+ conn_pool.spec.config
93
+ else
94
+ conn_pool.db_config
95
+ end
96
+ end
88
97
  end
89
98
  end
90
99
  end
@@ -18,7 +18,7 @@ module TestProf
18
18
  end
19
19
 
20
20
  def compile_sql(sql, binds)
21
- sql.gsub(/\?/) { binds.shift }
21
+ sql.gsub(/\?/) { binds.shift.gsub("\n", "' || char(10) || '") }
22
22
  end
23
23
 
24
24
  def import(path)
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "test_prof"
3
4
  require "test_prof/ext/float_duration"
4
5
  require "test_prof/any_fixture/dump"
5
6
 
@@ -118,6 +119,8 @@ module TestProf
118
119
  # returns the result of the block execution
119
120
  def register(id)
120
121
  cached(id) do
122
+ raise "No fixture named #{id} has been registered" unless block_given?
123
+
121
124
  ActiveSupport::Notifications.subscribed(method(:subscriber), "sql.active_record") do
122
125
  yield
123
126
  end
@@ -174,9 +177,22 @@ module TestProf
174
177
 
175
178
  # Reset all information and clean tables
176
179
  def reset
180
+ callbacks[:before_fixtures_reset].each(&:call)
181
+
177
182
  clean
178
183
  tables_cache.clear
179
184
  cache.clear
185
+
186
+ callbacks[:after_fixtures_reset].each(&:call)
187
+ callbacks.clear
188
+ end
189
+
190
+ def before_fixtures_reset(&block)
191
+ callbacks[:before_fixtures_reset] << block
192
+ end
193
+
194
+ def after_fixtures_reset(&block)
195
+ callbacks[:after_fixtures_reset] << block
180
196
  end
181
197
 
182
198
  def subscriber(_event, _start, _finish, _id, data)
@@ -253,6 +269,10 @@ module TestProf
253
269
  @tables_cache ||= {}
254
270
  end
255
271
 
272
+ def callbacks
273
+ @callbacks ||= Hash.new { |h, k| h[k] = [] }
274
+ end
275
+
256
276
  def disable_referential_integrity
257
277
  connection = ActiveRecord::Base.connection
258
278
  return yield unless connection.respond_to?(:disable_referential_integrity)
@@ -37,6 +37,9 @@ module TestProf
37
37
  end
38
38
  end
39
39
 
40
+ # avoid instance variable collisions with cats
41
+ PREFIX_RESTORE_LOCK_THREAD = "@😺"
42
+
40
43
  configure do |config|
41
44
  # Make sure ActiveRecord uses locked thread.
42
45
  # It only gets locked in `before` / `setup` hook,
@@ -44,8 +47,14 @@ module TestProf
44
47
  # might lead to leaking connections
45
48
  config.before(:begin) do
46
49
  next unless ::ActiveRecord::Base.connection.pool.respond_to?(:lock_thread=)
50
+ instance_variable_set("#{PREFIX_RESTORE_LOCK_THREAD}_orig_lock_thread", ::ActiveRecord::Base.connection.pool.instance_variable_get(:@lock_thread))
47
51
  ::ActiveRecord::Base.connection.pool.lock_thread = true
48
52
  end
53
+
54
+ config.after(:rollback) do
55
+ next unless ::ActiveRecord::Base.connection.pool.respond_to?(:lock_thread=)
56
+ ::ActiveRecord::Base.connection.pool.lock_thread = instance_variable_get("#{PREFIX_RESTORE_LOCK_THREAD}_orig_lock_thread")
57
+ end
49
58
  end
50
59
  end
51
60
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "test_prof"
4
+
3
5
  module TestProf
4
6
  # `before_all` helper configuration
5
7
  module BeforeAll
@@ -48,14 +48,15 @@ module RuboCop
48
48
 
49
49
  def transform_its(body, arguments)
50
50
  argument = arguments.first
51
- replacement = case argument.type
52
- when :array
53
- key = argument.values.first
54
- "expect(subject[#{key.source}])"
55
- else
56
- property = argument.value
57
- "expect(subject.#{property})"
58
- end
51
+ replacement =
52
+ case argument.type
53
+ when :array
54
+ key = argument.values.first
55
+ "expect(subject[#{key.source}])"
56
+ else
57
+ property = argument.value
58
+ "expect(subject.#{property})"
59
+ end
59
60
  body.source.gsub(/is_expected|are_expected/, replacement)
60
61
  end
61
62
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../language"
3
+ require "test_prof/cops/rspec/language"
4
4
 
5
5
  module RuboCop
6
6
  module Cop
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../language"
3
+ require "test_prof/cops/rspec/language"
4
4
 
5
5
  module RuboCop
6
6
  module Cop
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "aggregate_examples/line_range_helpers"
4
- require_relative "aggregate_examples/metadata_helpers"
5
- require_relative "aggregate_examples/node_matchers"
3
+ require "test_prof/cops/rspec/aggregate_examples/line_range_helpers"
4
+ require "test_prof/cops/rspec/aggregate_examples/metadata_helpers"
5
+ require "test_prof/cops/rspec/aggregate_examples/node_matchers"
6
6
 
7
- require_relative "aggregate_examples/its"
8
- require_relative "aggregate_examples/matchers_with_side_effects"
7
+ require "test_prof/cops/rspec/aggregate_examples/its"
8
+ require "test_prof/cops/rspec/aggregate_examples/matchers_with_side_effects"
9
9
 
10
10
  module RuboCop
11
11
  module Cop
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "test_prof"
3
4
  require "test_prof/factory_bot"
4
5
  require "test_prof/factory_all_stub/factory_bot_patch"
5
6
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "test_prof"
3
4
  require "test_prof/factory_bot"
4
5
  require "test_prof/factory_default/factory_bot_patch"
5
6
 
@@ -31,7 +32,6 @@ module TestProf
31
32
  TestProf::FactoryBot::Strategy::Build.prepend StrategyExt
32
33
  TestProf::FactoryBot::Strategy::Stub.prepend StrategyExt
33
34
 
34
- @store = {}
35
35
  # default is false to retain backward compatibility
36
36
  @preserve_traits = false
37
37
  end
@@ -57,12 +57,14 @@ module TestProf
57
57
  end
58
58
 
59
59
  def reset
60
- @store.clear
60
+ store.clear
61
61
  end
62
62
 
63
63
  private
64
64
 
65
- attr_reader :store
65
+ def store
66
+ Thread.current[:testprof_factory_store] ||= {}
67
+ end
66
68
  end
67
69
  end
68
70
  end
@@ -74,8 +74,8 @@ module Minitest
74
74
  @example_groups.each do |group, examples|
75
75
  msgs << "#{group[:description]} (#{group[:location]})\n"
76
76
  examples.each do |ex|
77
- msgs << " #{ex[:description]} (#{ex[:location]}) "\
78
- "– #{pluralize_records(ex[:factories])} created, "\
77
+ msgs << " #{ex[:description]} (#{ex[:location]}) " \
78
+ "– #{pluralize_records(ex[:factories])} created, " \
79
79
  "#{ex[:time].duration}\n"
80
80
  end
81
81
  msgs << "\n"
@@ -67,7 +67,7 @@ module TestProf
67
67
 
68
68
  examples.each do |ex|
69
69
  msgs << " #{ex.description} (#{ex.metadata[:location]}) " \
70
- "– #{pluralize_records(ex.metadata[:factories])} created, "\
70
+ "– #{pluralize_records(ex.metadata[:factories])} created, " \
71
71
  "#{ex.metadata[:time].duration}\n"
72
72
  end
73
73
  msgs << "\n"
@@ -100,15 +100,21 @@ module TestProf
100
100
  def run
101
101
  init
102
102
 
103
- printer = config.printer
104
-
105
103
  started_at = TestProf.now
106
104
 
107
- at_exit { printer.dump(result, start_time: started_at) }
105
+ at_exit do
106
+ print(started_at)
107
+ end
108
108
 
109
109
  start
110
110
  end
111
111
 
112
+ def print(started_at)
113
+ printer = config.printer
114
+
115
+ printer.dump(result, start_time: started_at)
116
+ end
117
+
112
118
  def start
113
119
  reset!
114
120
  @running = true
@@ -11,7 +11,7 @@ module TestProf
11
11
 
12
12
  class Formatter
13
13
  def call(severity, _time, progname, msg)
14
- colorize(severity.to_sym, "[#{progname} #{severity}] #{msg}\n")
14
+ colorize(severity.to_sym, "[#{progname} #{severity}] #{msg}") + "\n"
15
15
  end
16
16
 
17
17
  private
@@ -7,12 +7,38 @@ module TestProf
7
7
  # Add `with_logging` and `with_ar_logging helpers`
8
8
  module LoggingHelpers
9
9
  class << self
10
- attr_writer :logger
10
+ def logger=(logger)
11
+ @logger = logger
12
+
13
+ # swap global loggers
14
+ global_loggables.each do |loggable|
15
+ loggable.logger = logger
16
+ end
17
+ end
11
18
 
12
19
  def logger
13
20
  return @logger if instance_variable_defined?(:@logger)
14
21
 
15
- @logger = Logger.new($stdout)
22
+ @logger = if defined?(ActiveSupport::TaggedLogging)
23
+ ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new($stdout))
24
+ elsif defined?(ActiveSupport::Logger)
25
+ ActiveSupport::Logger.new($stdout)
26
+ else
27
+ Logger.new($stdout)
28
+ end
29
+ end
30
+
31
+ def global_loggables
32
+ return @global_loggables if instance_variable_defined?(:@global_loggables)
33
+
34
+ @global_loggables = []
35
+ end
36
+
37
+ def swap_logger!(loggables)
38
+ loggables.each do |loggable|
39
+ loggable.logger = logger
40
+ global_loggables << loggable
41
+ end
16
42
  end
17
43
 
18
44
  def ar_loggables
@@ -24,8 +50,6 @@ module TestProf
24
50
  ]
25
51
  end
26
52
 
27
- # rubocop:disable Metrics/CyclomaticComplexity
28
- # rubocop:disable Metrics/PerceivedComplexity
29
53
  def all_loggables
30
54
  return @all_loggables if instance_variable_defined?(:@all_loggables)
31
55
 
@@ -79,7 +103,9 @@ end
79
103
  if TestProf.rspec?
80
104
  RSpec.shared_context "logging:verbose" do
81
105
  around(:each) do |ex|
82
- with_logging(&ex)
106
+ next with_logging(&ex) if ex.metadata[:log] == true || ex.metadata[:log] == :all
107
+
108
+ ex.call
83
109
  end
84
110
  end
85
111
 
@@ -98,13 +124,10 @@ end
98
124
 
99
125
  TestProf.activate("LOG", "all") do
100
126
  TestProf.log :info, "Rails verbose logging enabled"
101
- ActiveSupport::LogSubscriber.logger =
102
- Rails.logger =
103
- ActiveRecord::Base.logger = TestProf::Rails::LoggingHelpers.logger
127
+ TestProf::Rails::LoggingHelpers.swap_logger!(TestProf::Rails::LoggingHelpers.all_loggables)
104
128
  end
105
129
 
106
130
  TestProf.activate("LOG", "ar") do
107
131
  TestProf.log :info, "Active Record verbose logging enabled"
108
- ActiveSupport::LogSubscriber.logger =
109
- ActiveRecord::Base.logger = TestProf::Rails::LoggingHelpers.logger
132
+ TestProf::Rails::LoggingHelpers.swap_logger!(TestProf::Rails::LoggingHelpers.ar_loggables)
110
133
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "test_prof"
4
- require_relative "./before_all"
4
+ require "test_prof/recipes/rspec/before_all"
5
5
 
6
6
  module TestProf
7
7
  # Just like `let`, but persist the result for the whole group.
@@ -75,7 +75,7 @@ module TestProf
75
75
  # Use uniq prefix for instance variables to avoid collisions
76
76
  # We want to use the power of Ruby's unicode support)
77
77
  # And we love cats!)
78
- PREFIX = RUBY_ENGINE == "jruby" ? "@__jruby_is_not_cat_friendly__" : "@😸"
78
+ PREFIX = "@😸"
79
79
 
80
80
  FROZEN_ERROR_HINT = "\nIf you are using `let_it_be`, you may want to pass `reload: true` or `refind: true` modifier to it."
81
81
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "./base"
3
+ require "test_prof/rspec_dissect/collectors/base"
4
4
 
5
5
  module TestProf
6
6
  module RSpecDissect
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "./base"
3
+ require "test_prof/rspec_dissect/collectors/base"
4
4
 
5
5
  module TestProf
6
6
  module RSpecDissect
@@ -28,8 +28,6 @@ module TestProf
28
28
  end
29
29
 
30
30
  class << self
31
- # rubocop: disable Metrics/CyclomaticComplexity
32
- # rubocop: disable Metrics/PerceivedComplexity
33
31
  def parse(code)
34
32
  sexp = Ripper.sexp(code)
35
33
  return unless sexp
@@ -116,8 +116,6 @@ module TestProf
116
116
 
117
117
  private
118
118
 
119
- # rubocop: disable Metrics/CyclomaticComplexity
120
- # rubocop: disable Metrics/PerceivedComplexity
121
119
  def stamp_example(example, tags)
122
120
  matches = example.match(EXAMPLE_RXP)
123
121
  return false unless matches
@@ -155,8 +153,8 @@ module TestProf
155
153
  end
156
154
  end
157
155
 
158
- replacement = "\\1#{parsed.fname}#{need_parens ? "(" : " "}"\
159
- "#{[desc, tags_str, htags_str].compact.join(", ")}"\
156
+ replacement = "\\1#{parsed.fname}#{need_parens ? "(" : " "}" \
157
+ "#{[desc, tags_str, htags_str].compact.join(", ")}" \
160
158
  "#{need_parens ? ") " : " "}\\3"
161
159
 
162
160
  if config.dry_run?
@@ -9,5 +9,5 @@ end
9
9
 
10
10
  require "rubocop"
11
11
 
12
- require_relative "cops/inject"
12
+ require "test_prof/cops/inject"
13
13
  require "test_prof/cops/rspec/aggregate_examples"
@@ -162,13 +162,13 @@ module TestProf
162
162
  log :info, <<~MSG
163
163
  Run the following command to generate a flame graph report:
164
164
 
165
- stackprof --flamegraph #{path} > #{html_path} && stackprof --flamegraph-viewer=#{html_path}
165
+ stackprof --d3-flamegraph #{path} > #{html_path} && stackprof --flamegraph-viewer=#{html_path}
166
166
  MSG
167
167
  end
168
168
 
169
169
  def dump_json_report(path)
170
170
  report = ::StackProf::Report.new(
171
- Marshal.load(IO.binread(path)) # rubocop:disable Security/MarshalLoad
171
+ Marshal.load(IO.binread(path))
172
172
  )
173
173
  json_path = path.gsub(/\.dump$/, ".json")
174
174
  File.write(json_path, JSON.generate(report.data))
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf
4
- VERSION = "1.0.7"
4
+ VERSION = "1.0.10"
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: 1.0.7
4
+ version: 1.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-30 00:00:00.000000000 Z
11
+ date: 2022-08-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -237,7 +237,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
237
237
  - !ruby/object:Gem::Version
238
238
  version: '0'
239
239
  requirements: []
240
- rubygems_version: 3.2.15
240
+ rubygems_version: 3.3.11
241
241
  signing_key:
242
242
  specification_version: 4
243
243
  summary: Ruby applications tests profiling tools