test-prof 1.0.6 → 1.0.9

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: f26a5003d400d430571206914f2f15a94ef4cca220c5f359e315eda7adf7a6b9
4
- data.tar.gz: 74d5cfb5e92351e628134dcd51230c6c984bd4b03518b89b4f98d8d20621e46f
3
+ metadata.gz: 9680aa33c1d917182a0be6e8cfd0656149d510b634db637b8023feda29f10886
4
+ data.tar.gz: 721767f61684ed87eff0f2e4c62080b9bb2a9e24bf6f47db194fc687bedbbe9b
5
5
  SHA512:
6
- metadata.gz: ea8cd4e7907fceb36874a91240be7baa0bdfb3c43dbddda21dececde541dbe5b9d52738ef3412c9c906e208fe5d33d2b34ce4e13a9063d941f360f2ccb845a30
7
- data.tar.gz: b87bec660bcd642dced3582c147317bb575628ef264eb7a33e31b59a1f5f7b740423fbd0a08dddf6c28638ffe266b460b05524cbfabbf95a93105053876aaf05
6
+ metadata.gz: 5a1d037cdac034f7c58f7bd090de128a81d41c3927787c953cacd33e8ecec1dd11cbda282f64fd542c2679b5176aa7bce4fe2ecb49806abac895d2cf9f478c00
7
+ data.tar.gz: baf837db1165a0d5631f07c9f4a978234afcce65fd9be886ef80bcf0a020fd43926e57eb5f295f0daddb22027c821ee72960fb01cd2cd4c7db6d18100d404343
data/CHANGELOG.md CHANGED
@@ -1,6 +1,28 @@
1
1
  # Change log
2
2
 
3
- ## master (unrealeased)
3
+ ## master (unreleased)
4
+
5
+ ## 1.0.9 (2022-05-05)
6
+
7
+ - Add `AnyFixture.before_fixtures_reset` and `AnyFixture.after_fixtures_reset` callbacks. ([@ruslanshakirov][])
8
+
9
+ - Fixes ActiveRecord 6.1 issue with AnyFixture and Postgres config ([@markedmondson][])
10
+
11
+ ## 1.0.8 (2022-03-11)
12
+
13
+ - Restore the lock_thread value after rollback. ([@cou929][])
14
+
15
+ - Fixes the configuration of a printer for factory_prof runs
16
+
17
+ - Ensure that defaults are stored in a threadsafe manner
18
+
19
+ ## 1.0.7 (2021-08-30)
20
+
21
+ - Fix access to `let_it_be` variables in `after(:all)` hook. ([@cbarton][])
22
+
23
+ - Add support for using the before_all hook with Rails' parallelize feature (using processes). ([@peret][])
24
+
25
+ Make sure to include `TestProf::BeforeAll::Minitest` before you call `parallelize`.
4
26
 
5
27
  ## 1.0.6 (2021-06-23)
6
28
 
@@ -259,3 +281,6 @@ See [changelog](https://github.com/test-prof/test-prof/blob/v0.8.0/CHANGELOG.md)
259
281
  [@stefkin]: https://github.com/stefkin
260
282
  [@jaimerson]: https://github.com/jaimerson
261
283
  [@alexvko]: https://github.com/alexvko
284
+ [@grillermo]: https://github.com/grillermo
285
+ [@cou929]: https://github.com/cou929
286
+ [@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
@@ -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
@@ -24,8 +24,6 @@ module TestProf
24
24
  ]
25
25
  end
26
26
 
27
- # rubocop:disable Metrics/CyclomaticComplexity
28
- # rubocop:disable Metrics/PerceivedComplexity
29
27
  def all_loggables
30
28
  return @all_loggables if instance_variable_defined?(:@all_loggables)
31
29
 
@@ -2,6 +2,22 @@
2
2
 
3
3
  require "test_prof/before_all"
4
4
 
5
+ Minitest.singleton_class.prepend(Module.new do
6
+ attr_reader :previous_klass
7
+ @previous_klass = nil
8
+
9
+ def run_one_method(klass, method_name)
10
+ return super unless klass.respond_to?(:parallelized) && klass.parallelized
11
+
12
+ if @previous_klass && @previous_klass != klass
13
+ @previous_klass.before_all_executor&.deactivate!
14
+ end
15
+ @previous_klass = klass
16
+
17
+ super
18
+ end
19
+ end)
20
+
5
21
  module TestProf
6
22
  module BeforeAll
7
23
  # Add before_all hook to Minitest: wrap all examples into a transaction and
@@ -83,6 +99,38 @@ module TestProf
83
99
  class << self
84
100
  def included(base)
85
101
  base.extend ClassMethods
102
+
103
+ base.cattr_accessor :parallelized
104
+ if base.respond_to?(:parallelize_teardown)
105
+ base.parallelize_teardown do
106
+ last_klass = ::Minitest.previous_klass
107
+ if last_klass&.respond_to?(:parallelized) && last_klass&.parallelized
108
+ last_klass.before_all_executor&.deactivate!
109
+ end
110
+ end
111
+ end
112
+
113
+ if base.respond_to?(:parallelize)
114
+ base.singleton_class.prepend(Module.new do
115
+ def parallelize(workers: :number_of_processors, with: :processes)
116
+ # super.parallelize returns nil when no parallelization is set up
117
+ if super(workers: workers, with: with).nil?
118
+ return
119
+ end
120
+
121
+ case with
122
+ when :processes
123
+ self.parallelized = true
124
+ when :threads
125
+ warn "!!! before_all is not implemented for parallalization with threads and " \
126
+ "could work incorrectly"
127
+ else
128
+ warn "!!! tests are using an unknown parallelization strategy and before_all " \
129
+ "could work incorrectly"
130
+ end
131
+ end
132
+ end)
133
+ end
86
134
  end
87
135
  end
88
136
 
@@ -118,7 +166,7 @@ module TestProf
118
166
  def run(*)
119
167
  super
120
168
  ensure
121
- before_all_executor&.deactivate!
169
+ before_all_executor&.deactivate! unless parallelized
122
170
  end
123
171
  end)
124
172
  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
 
@@ -107,7 +107,7 @@ module TestProf
107
107
  define_method(identifier) do
108
108
  # Trying to detect the context
109
109
  # Based on https://github.com/rspec/rspec-rails/commit/7cb796db064f58da7790a92e73ab906ef50b1f34
110
- if @__inspect_output.include?("before(:context)") || @__inspect_output.include?("before_all")
110
+ if /(before|after)\(:context\)/.match?(@__inspect_output) || @__inspect_output.include?("before_all")
111
111
  instance_variable_get(:"#{PREFIX}#{identifier}")
112
112
  else
113
113
  # Fallback to let definition
@@ -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
@@ -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.6"
4
+ VERSION = "1.0.9"
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.6
4
+ version: 1.0.9
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-06-23 00:00:00.000000000 Z
11
+ date: 2022-05-06 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.7
241
241
  signing_key:
242
242
  specification_version: 4
243
243
  summary: Ruby applications tests profiling tools