test-prof 0.11.3 → 1.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +122 -447
  3. data/LICENSE.txt +1 -1
  4. data/README.md +9 -13
  5. data/config/default.yml +0 -15
  6. data/config/rubocop-rspec.yml +6 -0
  7. data/lib/minitest/test_prof_plugin.rb +3 -0
  8. data/lib/test_prof/any_fixture.rb +116 -7
  9. data/lib/test_prof/any_fixture/dump.rb +207 -0
  10. data/lib/test_prof/any_fixture/dump/base_adapter.rb +43 -0
  11. data/lib/test_prof/any_fixture/dump/digest.rb +29 -0
  12. data/lib/test_prof/any_fixture/dump/postgresql.rb +91 -0
  13. data/lib/test_prof/any_fixture/dump/sqlite.rb +42 -0
  14. data/lib/test_prof/before_all.rb +9 -4
  15. data/lib/test_prof/before_all/adapters/active_record.rb +14 -5
  16. data/lib/test_prof/cops/rspec/aggregate_examples.rb +2 -2
  17. data/lib/test_prof/cops/rspec/aggregate_examples/its.rb +1 -1
  18. data/lib/test_prof/cops/rspec/aggregate_examples/line_range_helpers.rb +1 -1
  19. data/lib/test_prof/cops/rspec/aggregate_examples/matchers_with_side_effects.rb +1 -1
  20. data/lib/test_prof/cops/rspec/aggregate_examples/metadata_helpers.rb +1 -1
  21. data/lib/test_prof/cops/rspec/aggregate_examples/node_matchers.rb +1 -1
  22. data/lib/test_prof/event_prof/instrumentations/active_support.rb +22 -4
  23. data/lib/test_prof/recipes/minitest/before_all.rb +48 -23
  24. data/lib/test_prof/recipes/minitest/sample.rb +6 -10
  25. data/lib/test_prof/recipes/rspec/before_all.rb +10 -10
  26. data/lib/test_prof/recipes/rspec/let_it_be.rb +111 -13
  27. data/lib/test_prof/recipes/rspec/sample.rb +4 -2
  28. data/lib/test_prof/rubocop.rb +0 -1
  29. data/lib/test_prof/stack_prof.rb +3 -0
  30. data/lib/test_prof/version.rb +1 -1
  31. metadata +23 -21
  32. data/lib/test_prof/cops/rspec/aggregate_failures.rb +0 -26
  33. data/lib/test_prof/ext/active_record_3.rb +0 -27
  34. data/lib/test_prof/recipes/active_record_one_love.rb +0 -6
  35. data/lib/test_prof/recipes/active_record_shared_connection.rb +0 -77
@@ -35,18 +35,14 @@ module TestProf
35
35
  end
36
36
  end
37
37
  end
38
- end
39
38
 
40
- # Overrides Minitest.run
41
- def run(*)
42
- if ENV["SAMPLE"]
43
- MinitestSample.sample_examples(ENV["SAMPLE"].to_i)
44
- elsif ENV["SAMPLE_GROUPS"]
45
- MinitestSample.sample_groups(ENV["SAMPLE_GROUPS"].to_i)
39
+ def call
40
+ if ENV["SAMPLE"]
41
+ ::TestProf::MinitestSample.sample_examples(ENV["SAMPLE"].to_i)
42
+ elsif ENV["SAMPLE_GROUPS"]
43
+ ::TestProf::MinitestSample.sample_groups(ENV["SAMPLE_GROUPS"].to_i)
44
+ end
46
45
  end
47
- super
48
46
  end
49
47
  end
50
48
  end
51
-
52
- Minitest.singleton_class.prepend(TestProf::MinitestSample)
@@ -6,14 +6,22 @@ module TestProf
6
6
  module BeforeAll
7
7
  # Helper to wrap the whole example group into a transaction
8
8
  module RSpec
9
- def before_all(&block)
9
+ def before_all(setup_fixtures: BeforeAll.config.setup_fixtures, &block)
10
10
  raise ArgumentError, "Block is required!" unless block_given?
11
11
 
12
- return within_before_all(&block) if within_before_all?
12
+ if within_before_all?
13
+ before(:all) do
14
+ @__inspect_output = "before_all hook"
15
+ instance_eval(&block)
16
+ end
17
+ return
18
+ end
13
19
 
14
20
  @__before_all_activated__ = true
15
21
 
16
22
  before(:all) do
23
+ @__inspect_output = "before_all hook"
24
+ BeforeAll.setup_fixtures(self) if setup_fixtures
17
25
  BeforeAll.begin_transaction do
18
26
  instance_eval(&block)
19
27
  end
@@ -24,14 +32,6 @@ module TestProf
24
32
  end
25
33
  end
26
34
 
27
- def within_before_all(&block)
28
- before(:all) do
29
- BeforeAll.within_transaction do
30
- instance_eval(&block)
31
- end
32
- end
33
- end
34
-
35
35
  def within_before_all?
36
36
  instance_variable_defined?(:@__before_all_activated__)
37
37
  end
@@ -22,6 +22,10 @@ module TestProf
22
22
 
23
23
  LetItBe.modifiers[key] = block
24
24
  end
25
+
26
+ def default_modifiers
27
+ @default_modifiers ||= {}
28
+ end
25
29
  end
26
30
 
27
31
  class << self
@@ -75,6 +79,8 @@ module TestProf
75
79
  # And we love cats!)
76
80
  PREFIX = RUBY_ENGINE == "jruby" ? "@__jruby_is_not_cat_friendly__" : "@😸"
77
81
 
82
+ FROZEN_ERROR_HINT = "\nIf you are using `let_it_be`, you may want to pass `reload: true` or `refind: true` modifier to it."
83
+
78
84
  def self.define_let_it_be_alias(name, **default_args)
79
85
  define_method(name) do |identifier, **options, &blk|
80
86
  let_it_be(identifier, **default_args.merge(options), &blk)
@@ -83,27 +89,28 @@ module TestProf
83
89
 
84
90
  def let_it_be(identifier, **options, &block)
85
91
  initializer = proc do
86
- instance_variable_set(:"#{PREFIX}#{identifier}", instance_exec(&block))
92
+ instance_variable_set(:"#{TestProf::LetItBe::PREFIX}#{identifier}", instance_exec(&block))
93
+ rescue FrozenError => e
94
+ e.message << TestProf::LetItBe::FROZEN_ERROR_HINT
95
+ raise
87
96
  end
88
97
 
89
- if within_before_all?
90
- within_before_all(&initializer)
91
- else
92
- before_all(&initializer)
93
- end
98
+ default_options = LetItBe.config.default_modifiers.dup
99
+ default_options.merge!(metadata[:let_it_be_modifiers]) if metadata[:let_it_be_modifiers]
94
100
 
95
- define_let_it_be_methods(identifier, **options)
96
- end
101
+ options = default_options.merge(options)
102
+
103
+ before_all(&initializer)
97
104
 
98
- def define_let_it_be_methods(identifier, **modifiers)
99
- let_accessor = LetItBe.wrap_with_modifiers(modifiers) do
105
+ let_accessor = LetItBe.wrap_with_modifiers(options) do
100
106
  instance_variable_get(:"#{PREFIX}#{identifier}")
101
107
  end
102
108
 
103
109
  LetItBe.module_for(self).module_eval do
104
110
  define_method(identifier) do
105
- # Trying to detect the context (couldn't find other way so far)
106
- if /\(:context\)/.match?(@__inspect_output)
111
+ # Trying to detect the context
112
+ # Based on https://github.com/rspec/rspec-rails/commit/7cb796db064f58da7790a92e73ab906ef50b1f34
113
+ if @__inspect_output.include?("before(:context)") || @__inspect_output.include?("before_all")
107
114
  instance_variable_get(:"#{PREFIX}#{identifier}")
108
115
  else
109
116
  # Fallback to let definition
@@ -114,16 +121,78 @@ module TestProf
114
121
 
115
122
  let(identifier, &let_accessor)
116
123
  end
124
+
125
+ module Freezer
126
+ # Stoplist to prevent freezing objects and theirs associations that are defined
127
+ # with `let_it_be`'s `freeze: false` options during deep freezing.
128
+ #
129
+ # To only keep track of objects that are available in current example group,
130
+ # `begin` adds a new layer, and `rollback` removes a layer of unrelated objects
131
+ # along with rolling back the transaction where they were created.
132
+ #
133
+ # Stoplist holds records declared with `freeze: false` (so we do not freeze them even if they're used as
134
+ # associated records for frozen objects)
135
+ module Stoplist
136
+ class << self
137
+ def stop?(record)
138
+ @stoplist.any? { |layer| layer.include?(record) }
139
+ end
140
+
141
+ def stop!(record)
142
+ @stoplist.last.push(record)
143
+ end
144
+
145
+ def begin
146
+ @stoplist.push([])
147
+ end
148
+
149
+ def rollback
150
+ @stoplist.pop
151
+ end
152
+ end
153
+
154
+ # Stack of example group-related variable definitions
155
+ @stoplist = []
156
+ end
157
+
158
+ class << self
159
+ # Rerucsively freezes the object to detect modifications
160
+ def deep_freeze(record)
161
+ return if record.frozen?
162
+ return if Stoplist.stop?(record)
163
+
164
+ record.freeze
165
+
166
+ # Support `let_it_be` with `create_list`
167
+ return record.each { |rec| deep_freeze(rec) } if record.respond_to?(:each)
168
+
169
+ # Freeze associations as well.
170
+ return unless defined?(::ActiveRecord::Base)
171
+ return unless record.is_a?(::ActiveRecord::Base)
172
+
173
+ record.class.reflections.keys.each do |reflection|
174
+ # But only if they are already loaded. If not yet loaded, they weren't
175
+ # created by factories, and it's ok to mutate them.
176
+
177
+ next unless record.association(reflection.to_sym).loaded?
178
+
179
+ target = record.association(reflection.to_sym).target
180
+ deep_freeze(target) if target.is_a?(::ActiveRecord::Base) || target.respond_to?(:each)
181
+ end
182
+ end
183
+ end
184
+ end
117
185
  end
118
186
  end
119
187
 
120
- if defined?(::ActiveRecord)
188
+ if defined?(::ActiveRecord::Base)
121
189
  require "test_prof/ext/active_record_refind"
122
190
  using TestProf::Ext::ActiveRecordRefind
123
191
 
124
192
  TestProf::LetItBe.configure do |config|
125
193
  config.register_modifier :reload do |record, val|
126
194
  next record unless val
195
+
127
196
  next record.reload if record.is_a?(::ActiveRecord::Base)
128
197
 
129
198
  if record.respond_to?(:map)
@@ -136,6 +205,7 @@ if defined?(::ActiveRecord)
136
205
 
137
206
  config.register_modifier :refind do |record, val|
138
207
  next record unless val
208
+
139
209
  next record.refind if record.is_a?(::ActiveRecord::Base)
140
210
 
141
211
  if record.respond_to?(:map)
@@ -145,7 +215,35 @@ if defined?(::ActiveRecord)
145
215
  end
146
216
  record
147
217
  end
218
+
219
+ config.register_modifier :freeze do |record, val|
220
+ if val == false
221
+ TestProf::LetItBe::Freezer::Stoplist.stop!(record)
222
+ next record
223
+ end
224
+
225
+ TestProf::LetItBe::Freezer.deep_freeze(record)
226
+ record
227
+ end
148
228
  end
149
229
  end
150
230
 
151
231
  RSpec::Core::ExampleGroup.extend TestProf::LetItBe
232
+
233
+ TestProf::BeforeAll.configure do |config|
234
+ config.before(:begin) do
235
+ TestProf::LetItBe::Freezer::Stoplist.begin
236
+ end
237
+
238
+ config.after(:rollback) do
239
+ TestProf::LetItBe::Freezer::Stoplist.rollback
240
+ end
241
+ end
242
+
243
+ RSpec.configure do |config|
244
+ config.after(:example) do |example|
245
+ if example.exception&.is_a?(FrozenError)
246
+ example.exception.message << TestProf::LetItBe::FROZEN_ERROR_HINT
247
+ end
248
+ end
249
+ end
@@ -15,7 +15,8 @@ if ENV["SAMPLE"]
15
15
  RSpec.configure do |config|
16
16
  config.before(:suite) do
17
17
  filtered_examples = RSpec.world.filtered_examples.values.flatten
18
- sample = filtered_examples.sample(ENV["SAMPLE"].to_i)
18
+ random = Random.new(RSpec.configuration.seed)
19
+ sample = filtered_examples.sample(ENV["SAMPLE"].to_i, random: random)
19
20
  RSpec.world.filtered_examples = Hash.new do |hash, group|
20
21
  hash[group] = group.examples & sample
21
22
  end
@@ -31,7 +32,8 @@ if ENV["SAMPLE_GROUPS"]
31
32
  filtered_groups = RSpec.world.filtered_examples.reject do |_group, examples|
32
33
  examples.empty?
33
34
  end.keys
34
- sample = filtered_groups.sample(ENV["SAMPLE_GROUPS"].to_i)
35
+ random = Random.new(RSpec.configuration.seed)
36
+ sample = filtered_groups.sample(ENV["SAMPLE_GROUPS"].to_i, random: random)
35
37
  RSpec.world.filtered_examples = Hash.new do |hash, group|
36
38
  hash[group] = sample.include?(group) ? group.examples : []
37
39
  end
@@ -11,4 +11,3 @@ require "rubocop"
11
11
 
12
12
  require_relative "cops/inject"
13
13
  require "test_prof/cops/rspec/aggregate_examples"
14
- require "test_prof/cops/rspec/aggregate_failures"
@@ -36,6 +36,9 @@ module TestProf
36
36
  else
37
37
  "html"
38
38
  end
39
+
40
+ sample_interval = ENV["TEST_STACK_PROF_INTERVAL"].to_i
41
+ @interval = sample_interval > 0 ? sample_interval : nil
39
42
  end
40
43
 
41
44
  def raw?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf
4
- VERSION = "0.11.3"
4
+ VERSION = "1.0.0.rc2"
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.11.3
4
+ version: 1.0.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-11 00:00:00.000000000 Z
11
+ date: 2021-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '12.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '12.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -56,42 +56,42 @@ dependencies:
56
56
  name: isolator
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0.6'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.6'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: minitest
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '5.9'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '5.9'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rubocop
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: 0.77.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.77.0
97
97
  description: "\n Ruby applications tests profiling tools.\n\n Contains tools
@@ -119,6 +119,7 @@ files:
119
119
  - assets/tagprof.demo.html
120
120
  - assets/tagprof.template.html
121
121
  - config/default.yml
122
+ - config/rubocop-rspec.yml
122
123
  - lib/minitest/base_reporter.rb
123
124
  - lib/minitest/event_prof_formatter.rb
124
125
  - lib/minitest/test_prof_plugin.rb
@@ -126,6 +127,11 @@ files:
126
127
  - lib/test_prof.rb
127
128
  - lib/test_prof/any_fixture.rb
128
129
  - lib/test_prof/any_fixture/dsl.rb
130
+ - lib/test_prof/any_fixture/dump.rb
131
+ - lib/test_prof/any_fixture/dump/base_adapter.rb
132
+ - lib/test_prof/any_fixture/dump/digest.rb
133
+ - lib/test_prof/any_fixture/dump/postgresql.rb
134
+ - lib/test_prof/any_fixture/dump/sqlite.rb
129
135
  - lib/test_prof/before_all.rb
130
136
  - lib/test_prof/before_all/adapters/active_record.rb
131
137
  - lib/test_prof/before_all/isolator.rb
@@ -136,7 +142,6 @@ files:
136
142
  - lib/test_prof/cops/rspec/aggregate_examples/matchers_with_side_effects.rb
137
143
  - lib/test_prof/cops/rspec/aggregate_examples/metadata_helpers.rb
138
144
  - lib/test_prof/cops/rspec/aggregate_examples/node_matchers.rb
139
- - lib/test_prof/cops/rspec/aggregate_failures.rb
140
145
  - lib/test_prof/cops/rspec/language.rb
141
146
  - lib/test_prof/event_prof.rb
142
147
  - lib/test_prof/event_prof/custom_events.rb
@@ -148,7 +153,6 @@ files:
148
153
  - lib/test_prof/event_prof/monitor.rb
149
154
  - lib/test_prof/event_prof/profiler.rb
150
155
  - lib/test_prof/event_prof/rspec.rb
151
- - lib/test_prof/ext/active_record_3.rb
152
156
  - lib/test_prof/ext/active_record_refind.rb
153
157
  - lib/test_prof/ext/array_bsearch_index.rb
154
158
  - lib/test_prof/ext/factory_bot_strategy.rb
@@ -173,8 +177,6 @@ files:
173
177
  - lib/test_prof/factory_prof/printers/flamegraph.rb
174
178
  - lib/test_prof/factory_prof/printers/simple.rb
175
179
  - lib/test_prof/logging.rb
176
- - lib/test_prof/recipes/active_record_one_love.rb
177
- - lib/test_prof/recipes/active_record_shared_connection.rb
178
180
  - lib/test_prof/recipes/logging.rb
179
181
  - lib/test_prof/recipes/minitest/before_all.rb
180
182
  - lib/test_prof/recipes/minitest/sample.rb
@@ -208,15 +210,15 @@ files:
208
210
  - lib/test_prof/utils/rspec.rb
209
211
  - lib/test_prof/utils/sized_ordered_set.rb
210
212
  - lib/test_prof/version.rb
211
- homepage: http://github.com/palkan/test-prof
213
+ homepage: http://github.com/test-prof/test-prof
212
214
  licenses:
213
215
  - MIT
214
216
  metadata:
215
- bug_tracker_uri: http://github.com/palkan/test-prof/issues
216
- changelog_uri: https://github.com/palkan/test-prof/blob/master/CHANGELOG.md
217
+ bug_tracker_uri: http://github.com/test-prof/test-prof/issues
218
+ changelog_uri: https://github.com/test-prof/test-prof/blob/master/CHANGELOG.md
217
219
  documentation_uri: https://test-prof.evilmartians.io/
218
220
  homepage_uri: https://test-prof.evilmartians.io/
219
- source_code_uri: http://github.com/palkan/test-prof
221
+ source_code_uri: http://github.com/test-prof/test-prof
220
222
  post_install_message:
221
223
  rdoc_options: []
222
224
  require_paths:
@@ -225,12 +227,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
225
227
  requirements:
226
228
  - - ">="
227
229
  - !ruby/object:Gem::Version
228
- version: 2.4.0
230
+ version: 2.5.0
229
231
  required_rubygems_version: !ruby/object:Gem::Requirement
230
232
  requirements:
231
- - - ">="
233
+ - - ">"
232
234
  - !ruby/object:Gem::Version
233
- version: '0'
235
+ version: 1.3.1
234
236
  requirements: []
235
237
  rubygems_version: 3.0.6
236
238
  signing_key: