test-prof 1.4.0.rc.2 → 1.4.0.rc.3

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: 24fc1f10f015aca5ffcaa3fa9568bd397f31d4a23c043d2b2781a1ebb2158a9e
4
- data.tar.gz: fe79040f5a8455525e42d8b282cd6a48ff9d1be63ee9de2975c25f561419d7d9
3
+ metadata.gz: 55eaa3ce2f79b5cae7992ea0e45a499c28ae1d301b2f7c9e34796d587c0e6090
4
+ data.tar.gz: 2f5a07b3a9c78304c054e025d0e785a253d310c354005ca767a7ea0674033e0f
5
5
  SHA512:
6
- metadata.gz: 29e36545b692685977c96fd0f489a71189ee3472f2e1a09896c34635d43f01fe60de58a52a6bbec9f0352668057a4178d2f1f15aa454f94cafc4a87a933150ed
7
- data.tar.gz: a80468699056d18f936e53b7474f9082b39105d222b05e713e2bd2bf3d992568d0cc51a308ba679e123a1e3c8f222e2522b545a2db60fbc07869044c53b9449e
6
+ metadata.gz: f26d5cdd70cd05d93fc0cc596302a72089c1718fd5b58084b5a219333ac6b0ba034d09c7a0e57840fa790f4198c7b8ba24f8dfdaa0d0b85a5f7404246b922b07
7
+ data.tar.gz: 22e6d9304af0c182f4bd1bf7d4b34a9bc8d5435b505100bebe9519cdac2f3d29ba47db3fe7de48179cc88c191cac3da531de4d3b6f506c2275dc52f45b832444
data/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## master (unreleased)
4
4
 
5
+ - Add new TPS (tests per second) profiler. ([@palkan][])
6
+
5
7
  - FactoryDefault: add Fabrication support. ([@palkan][])
6
8
 
7
9
  - Drop support for **Ruby <2.7** and **Rails <6**.
@@ -1,15 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "test_prof/factory_bot"
4
+
3
5
  module TestProf
4
6
  module FactoryDefault # :nodoc: all
5
7
  module FactoryBotPatch
6
- module RunnerExt
7
- refine TestProf::FactoryBot::FactoryRunner do
8
- attr_reader :name, :traits, :overrides
8
+ if defined?(TestProf::FactoryBot::FactoryRunner)
9
+ module RunnerExt
10
+ refine TestProf::FactoryBot::FactoryRunner do
11
+ attr_reader :name, :traits, :overrides
12
+ end
9
13
  end
10
- end
11
14
 
12
- using RunnerExt
15
+ using RunnerExt
16
+ end
13
17
 
14
18
  module StrategyExt
15
19
  def association(runner)
@@ -53,7 +57,6 @@ module TestProf
53
57
  end
54
58
 
55
59
  def self.patch
56
- require "test_prof/factory_bot"
57
60
  return unless defined?(TestProf::FactoryBot)
58
61
 
59
62
  TestProf::FactoryBot::Syntax::Methods.include SyntaxExt
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_prof/utils/sized_ordered_set"
4
+
5
+ module TestProf
6
+ module TPSProf
7
+ class Profiler
8
+ attr_reader :top_count, :groups, :total_count, :total_time, :threshold
9
+
10
+ def initialize(top_count, threshold: 10)
11
+ @threshold = threshold
12
+ @top_count = top_count
13
+ @total_count = 0
14
+ @total_time = 0.0
15
+ @groups = Utils::SizedOrderedSet.new(top_count, sort_by: :tps)
16
+ end
17
+
18
+ def group_started(id)
19
+ @current_group = id
20
+ @examples_count = 0
21
+ @examples_time = 0.0
22
+ @group_started_at = TestProf.now
23
+ end
24
+
25
+ def group_finished(id)
26
+ return unless @examples_count >= threshold
27
+
28
+ # Context-time
29
+ group_time = (TestProf.now - @group_started_at) - @examples_time
30
+ run_time = @examples_time + group_time
31
+
32
+ groups << {
33
+ id: id,
34
+ run_time: run_time,
35
+ group_time: group_time,
36
+ count: @examples_count,
37
+ tps: -(@examples_count / run_time).round(2)
38
+ }
39
+ end
40
+
41
+ def example_started(id)
42
+ @example_started_at = TestProf.now
43
+ end
44
+
45
+ def example_finished(id)
46
+ @examples_count += 1
47
+ @total_count += 1
48
+
49
+ time = (TestProf.now - @example_started_at)
50
+ @examples_time += time
51
+ @total_time += time
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_prof/ext/float_duration"
4
+ require "test_prof/ext/string_truncate"
5
+
6
+ module TestProf
7
+ module TPSProf
8
+ module Reporter
9
+ class Text
10
+ include Logging
11
+ using FloatDuration
12
+ using StringTruncate
13
+
14
+ def print(profiler)
15
+ groups = profiler.groups
16
+
17
+ total_tps = (profiler.total_count / profiler.total_time).round(2)
18
+
19
+ msgs = []
20
+
21
+ msgs <<
22
+ <<~MSG
23
+ Total TPS (tests per second): #{total_tps}
24
+
25
+ Top #{profiler.top_count} slowest suites by TPS (tests per second) (min examples per group: #{profiler.threshold}):
26
+
27
+ MSG
28
+
29
+ groups.each do |group|
30
+ description = group[:id].top_level_description
31
+ location = group[:id].metadata[:location]
32
+ time = group[:run_time]
33
+ group_time = group[:group_time]
34
+ count = group[:count]
35
+ tps = -group[:tps]
36
+
37
+ msgs <<
38
+ <<~GROUP
39
+ #{description.truncate} (#{location}) – #{tps} TPS (#{time.duration} / #{count}), group time: #{group_time.duration}
40
+ GROUP
41
+ end
42
+
43
+ log :info, msgs.join
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TestProf
4
+ module TPSProf
5
+ class RSpecListener # :nodoc:
6
+ include Logging
7
+
8
+ NOTIFICATIONS = %i[
9
+ example_group_started
10
+ example_group_finished
11
+ example_started
12
+ example_finished
13
+ ].freeze
14
+
15
+ attr_reader :reporter, :profiler
16
+
17
+ def initialize
18
+ @profiler = Profiler.new(TPSProf.config.top_count, threshold: TPSProf.config.threshold)
19
+ @reporter = TPSProf.config.reporter
20
+
21
+ log :info, "TPSProf enabled (top-#{TPSProf.config.top_count})"
22
+ end
23
+
24
+ def example_group_started(notification)
25
+ return unless notification.group.top_level?
26
+ profiler.group_started notification.group
27
+ end
28
+
29
+ def example_group_finished(notification)
30
+ return unless notification.group.top_level?
31
+ profiler.group_finished notification.group
32
+ end
33
+
34
+ def example_started(notification)
35
+ profiler.example_started notification.example
36
+ end
37
+
38
+ def example_finished(notification)
39
+ profiler.example_finished notification.example
40
+ end
41
+
42
+ def print
43
+ reporter.print(profiler)
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ # Register TPSProf listener
50
+ TestProf.activate("TPS_PROF") do
51
+ RSpec.configure do |config|
52
+ listener = nil
53
+
54
+ config.before(:suite) do
55
+ listener = TestProf::TPSProf::RSpecListener.new
56
+ config.reporter.register_listener(
57
+ listener, *TestProf::TPSProf::RSpecListener::NOTIFICATIONS
58
+ )
59
+ end
60
+
61
+ config.after(:suite) { listener&.print }
62
+ end
63
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_prof/tps_prof/profiler"
4
+ require "test_prof/tps_prof/reporter/text"
5
+
6
+ module TestProf
7
+ # TPSProf shows top-N example group based on their tests-per-second value.
8
+ #
9
+ # Example:
10
+ #
11
+ # TPS_PROF=10 rspec ...
12
+ #
13
+ module TPSProf
14
+ class Configuration
15
+ attr_accessor :top_count, :threshold, :reporter
16
+
17
+ def initialize
18
+ @top_count = ENV["TPS_PROF"].to_i
19
+ @top_count = 10 if @top_count == 1
20
+ @threshold = ENV.fetch("TPS_PROF_MIN", 10).to_i
21
+ @reporter = resolve_reporter(ENV["TPS_PROF_FORMAT"])
22
+ end
23
+
24
+ private
25
+
26
+ def resolve_reporter(format)
27
+ # TODO: support other formats
28
+ TPSProf::Reporter::Text.new
29
+ end
30
+ end
31
+
32
+ class << self
33
+ def config
34
+ @config ||= Configuration.new
35
+ end
36
+
37
+ def configure
38
+ yield config
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ require "test_prof/tps_prof/rspec" if TestProf.rspec?
45
+ # TODO: Minitest support
46
+ # require "test_prof/tps_prof/minitest" if TestProf.minitest?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf
4
- VERSION = "1.4.0.rc.2"
4
+ VERSION = "1.4.0.rc.3"
5
5
  end
data/lib/test_prof.rb CHANGED
@@ -12,5 +12,6 @@ require "test_prof/factory_prof"
12
12
  require "test_prof/memory_prof"
13
13
  require "test_prof/rspec_stamp"
14
14
  require "test_prof/tag_prof"
15
+ require "test_prof/tps_prof"
15
16
  require "test_prof/rspec_dissect" if TestProf.rspec?
16
17
  require "test_prof/factory_all_stub"
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.4.0.rc.2
4
+ version: 1.4.0.rc.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Dementyev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-23 00:00:00.000000000 Z
11
+ date: 2024-07-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -219,6 +219,10 @@ files:
219
219
  - lib/test_prof/tag_prof/printers/simple.rb
220
220
  - lib/test_prof/tag_prof/result.rb
221
221
  - lib/test_prof/tag_prof/rspec.rb
222
+ - lib/test_prof/tps_prof.rb
223
+ - lib/test_prof/tps_prof/profiler.rb
224
+ - lib/test_prof/tps_prof/reporter/text.rb
225
+ - lib/test_prof/tps_prof/rspec.rb
222
226
  - lib/test_prof/utils.rb
223
227
  - lib/test_prof/utils/html_builder.rb
224
228
  - lib/test_prof/utils/rspec.rb