test-prof-autopilot 0.0.7 → 0.1.0.pre.1

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: fa21fa398d9ae8f3a79906b3f33d0d75148e9c2ee7ebb5d9900f2302eaefeac1
4
- data.tar.gz: cc151f75133d9d71d370c31ba0e18c0466269bfa3241b2adb08005073a981699
3
+ metadata.gz: 55e6d41b4c30aa3390d97e550a425e92125e6ee74e4ffe6a3e2660be5f5e1795
4
+ data.tar.gz: 866cc0632a7304a5e675ae78541e77f304de4eeba781f8987a6f8d0563eba3db
5
5
  SHA512:
6
- metadata.gz: c4d70b1e42e3aabf5e1c7dc6f9c4403b863e5fc9b95af70cb291d48b1fc4760c91e697b96ff903099a364b3a667e53f151f7934d929e41718a153f88b0a5acc4
7
- data.tar.gz: b51e1abe16366626f57c347566d026e504313df6e3b4813b72b95eeaf8ccff9513f7e38729d3ab13fcc1b2afb6756152feb6c5a9b784fbc7433f607b2e7e1585
6
+ metadata.gz: 2ffc441d899c9fa8c2fcaec24930016ee0677705153dd4528aa19e9b48637563a06a0573e001c069d2f04ef5cf4964a49f6380afaefbb263c7b66b0ae8673b19
7
+ data.tar.gz: 389c5d56dbdc4553d21850f964d5880c0de8a2cde0c9938c65a390de84556b326d3abf8cdc71ad5626461e572e7021697f2272edeb8e34ac1a427f632fafa6f4
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2021 Vladimir Dementyev, Ruslan Shakirov
3
+ Copyright (c) 2021-2023 Vladimir Dementyev, Ruslan Shakirov
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,4 +1,7 @@
1
- # TestProf Autopilot (PoC)
1
+ [![Gem Version](https://badge.fury.io/rb/test-prof-autopilot.svg)](https://rubygems.org/gems/test-prof-autopilot)
2
+ [![Build](https://github.com/test-prof/test-prof-autopilot/workflows/Build/badge.svg)](https://github.com/test-prof/test-prof-autopilot/actions)
3
+
4
+ # TestProf Autopilot
2
5
 
3
6
  [TestProf][] has been used by many Ruby/Rails teams to optimize their test suites performance for a while.
4
7
 
@@ -6,23 +9,11 @@ Usually, it takes a decent amount of time to profile the test suite initially: w
6
9
 
7
10
  There are some common patterns in the way we use TestProf, for example: we run StackProf/RubyProf multiple times for different test samples, or we run EventProf for `factory.create` and then use FactoryProf for the slowest tests.
8
11
 
9
- It seems that there is a room for optimization here: we can automate this common tasks, make robots do all the repetition.
10
-
11
- This project (codename _TestProf Autopilot_) aims to solve this problem.
12
-
13
- ## Usage (proposal)
14
-
15
- Use a CLI to run a specific tests profiling plan:
16
-
17
- ```sh
18
- auto-test-prof -i plan.rb -с "bundle exec rspec"
19
- ```
20
-
21
- We specify the base command to run tests via the `-c` option.
12
+ It seems that there is a room for optimization here: we can automate this common tasks, make robots do all the repetition. And here comes **TestProf Autopilot**!
22
13
 
23
- Profiling plan is a Ruby file using a custom DSL to run profilers and access their reports:
14
+ ## Usage
24
15
 
25
- Here is an example #2:
16
+ First, write a test profiling plan in a Ruby file. For example, here is how you can perform StackProf profiling multiple times against different random subsets and aggregate the results:
26
17
 
27
18
  ```ruby
28
19
  # This plan runs multiple test samples and collects StackProf data.
@@ -36,41 +27,68 @@ aggregate(3) { run :stackprof, sample: 100 }
36
27
 
37
28
  # `report` returns the latest generated report (both `run` and `aggregate` set this value automatically)
38
29
  # `#methods` returns the list of collected reports sorted by their popularity
39
- # `info` prints the information (ideally, it should be human-readable)
40
- info report.methods.take(5)
30
+ puts report.methods.take(5)
41
31
  ```
42
32
 
43
- And example #2:
33
+ Now, you can use the `auto-test-prof` command to execute the plan:
44
34
 
45
- ```ruby
46
- # This plan first launch the test suite and collect the information about the time spent in factories.
47
- # Then it runs FactoryProf for the slowest tests and display the information.
35
+ ```sh
36
+ auto-test-prof -i plan.rb "bundle exec rspec"
37
+ ```
38
+
39
+ We specify the base command to run tests via the `-c` option. If you omit the command option, Autopilot would fall back to either `bundle exec rspec` or `bundle exec rake test` depending on the presense of the `spec/` and `test/` directories, respectively.
48
40
 
49
- run :event_prof, event: "factory.create"
50
- run :factory_prof, paths: report.paths
41
+ ### Merging results
51
42
 
52
- info report
43
+ Autopilot also allows you to merge reports created with it (using the `#save` method). That's useful when you profile tests on CI and want to see the aggregated results. For example, when using TagProf:
44
+
45
+ ```ruby
46
+ run :tag_prof, events: ["factory.create"]
47
+
48
+ save report, file_name: "tag_prof_#{ENV["CI_NODE_INDEX"]}"
53
49
  ```
54
50
 
55
- ### Notes on implementation
51
+ Then, assuming all reports were downloaded:
56
52
 
57
- We use `#run` method to launch tests with profiling. Each profiler has a uniq name (which is the first argument) and some options.
58
- Some options are common for all profilers (e.g., `sample:` and `paths:`).
53
+ ```sh
54
+ $ auto-test-prof --merge tag_prof --reports tag_prof_*.json
59
55
 
60
- ## Installation
56
+ Merging tag_prof reports at tag_prof_1.json, tag_prof_2.json, tag_prof_3.json
61
57
 
62
- Adding to a gem:
58
+ [TEST PROF] TagProf report for type
63
59
 
64
- ```ruby
65
- # my-cool-gem.gemspec
66
- Gem::Specification.new do |spec|
67
- # ...
68
- spec.add_dependency "test-prof-autopilot"
69
- # ...
70
- end
60
+ type time factory.create total %total %time avg
61
+
62
+ model 28:08.654 19:58.371 1730 56.44 46.23 00:00.976
63
+ service 20:56.071 16:14.435 808 29.18 28.35 00:01.554
64
+ api 04:48.179 03:54.178 214 7.32 4.78 00:01.346
65
+ ...
71
66
  ```
72
67
 
73
- Or adding to your project:
68
+ ### API
69
+
70
+ - `run(profiler_name, **options)`: launch the test command with the specified profiler activated; options depend on the profiler, but there are some commont: `sample: <number>` — enables sampling, `paths: <array of paths>` — adds the list of paths to the command.
71
+
72
+ - `info(report)`: shows the report in the console
73
+
74
+ - `save(report, path)`: store
75
+
76
+ - `aggregate(num_calls) { ... }`: aggregates reports obtained by calling the block `num_calls` times.
77
+
78
+ You can find more examples in the [examples/](examples/) folder.
79
+
80
+ ### Supported profilers
81
+
82
+ Currently, Autopilot supports the following Test Prof profilers:
83
+
84
+ - [EventProf](https://test-prof.evilmartians.io/profilers/event_prof) (as `:event_prof`)
85
+ - [TagProf](https://test-prof.evilmartians.io/profilers/tag_prof) (as `:tag_prof`)
86
+ - [StackProf](https://test-prof.evilmartians.io/profilers/stack_prof) (as `:stack_prof`)
87
+ - [FactoryProf](https://test-prof.evilmartians.io/profilers/factory_prof) (as `:factory_prof`)
88
+
89
+ ## Installation
90
+
91
+ Add the gem to your project:
74
92
 
75
93
  ```ruby
76
94
  # Gemfile
@@ -79,4 +97,8 @@ group :development, :test do
79
97
  end
80
98
  ```
81
99
 
100
+ Make sure `test-prof-autopilot` is required in your test environment.
101
+
102
+ That's it!
103
+
82
104
  [TestProf]: https://test-prof.evilmartians.io/
@@ -1,3 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "test_prof/autopilot/version"
4
+ require "test_prof/autopilot"
@@ -2,11 +2,14 @@
2
2
 
3
3
  require "optparse"
4
4
  require "test_prof/autopilot/runner"
5
+ require "test_prof/autopilot/logging"
5
6
  require "test_prof/autopilot/merger"
6
7
 
7
8
  module TestProf
8
9
  module Autopilot
9
10
  class CLI
11
+ include Logging
12
+
10
13
  attr_reader :command, :plan_path, :mode, :merge_type, :report_paths
11
14
 
12
15
  def run(args = ARGV)
@@ -15,6 +18,8 @@ module TestProf
15
18
  optparser.parse!(args)
16
19
 
17
20
  if mode == "runner"
21
+ infer_command! unless command
22
+
18
23
  raise "Test command must be specified. See -h for options" unless command
19
24
 
20
25
  raise "Plan path must be specified. See -h for options" unless plan_path
@@ -67,6 +72,18 @@ module TestProf
67
72
  end
68
73
  end
69
74
  end
75
+
76
+ def infer_command!
77
+ if Dir.exist?("spec")
78
+ @command = "bundle exec rspec"
79
+ elsif Dir.exist?("test")
80
+ @command = "bundle exec rake test"
81
+ end
82
+
83
+ if @command
84
+ Logging.log "No command specified, using: #{@command}"
85
+ end
86
+ end
70
87
  end
71
88
  end
72
89
  end
@@ -7,6 +7,8 @@ module TestProf
7
7
  # Module is used for commands execution in child process.
8
8
  module CommandExecutor
9
9
  def execute(env, command)
10
+ env.merge!("TEST_PROF_AUTOPILOT_ENABLED" => "true")
11
+
10
12
  Open3.popen2e(env, command) do |_stdin, stdout_and_stderr, _wait_thr|
11
13
  while (line = stdout_and_stderr.gets)
12
14
  Logging.log line
@@ -24,8 +24,8 @@ module TestProf
24
24
 
25
25
  def initialize
26
26
  @output = $stdout
27
- @tmp_dir = "tmp/test_prof_autopilot"
28
- @artifacts_dir = "test_prof_autopilot"
27
+ @tmp_dir = ENV.fetch("TEST_PROF_AUTOPILOT_TMP_DIR", "tmp/test_prof_autopilot")
28
+ @artifacts_dir = ENV.fetch("TEST_PROF_AUTOPILOT_DIR", "test_prof_autopilot")
29
29
  @merge_format = "info"
30
30
  end
31
31
  end
@@ -25,6 +25,10 @@ module TestProf
25
25
  def build_env
26
26
  super.tap do |env|
27
27
  env["EVENT_PROF"] = @options[:event]
28
+ env["EVENT_PROF_TOP"] = @options[:top_count].to_s if @options[:top_count]
29
+ env["EVENT_PROF_EXAMPLES"] = "1" if @options[:per_example]
30
+ env["EVENT_PROF_RANK"] = @options[:rank_by].to_s if @options[:rank_by]
31
+ env["EVENT_PROF_STAMP"] = @options[:stamp] if @options[:stamp]
28
32
  end
29
33
  end
30
34
  end
@@ -1,17 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestProf
4
- using(Module.new do
5
- refine FactoryProf::Result do
6
- def to_json
7
- {
8
- stacks: stacks,
9
- raw_stats: raw_stats
10
- }.to_json
11
- end
12
- end
13
- end)
14
-
15
4
  module Autopilot
16
5
  module FactoryProf
17
6
  # Class is used for writing :factory_prof report in different formats
@@ -13,10 +13,10 @@ module TestProf
13
13
 
14
14
  class << self
15
15
  def invoke(type, paths)
16
- Logging.log "Merging #{type} reports at #{paths.join(", ")}..."
17
-
18
16
  paths = paths.flat_map(&Dir.method(:glob))
19
17
 
18
+ Logging.log "Merging #{type} reports at #{paths.join(", ")}..."
19
+
20
20
  new(type, paths).print_report
21
21
  end
22
22
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module TestProf
4
4
  module Autopilot # :nodoc:
5
- VERSION = "0.0.7"
5
+ VERSION = "0.1.0.pre.1"
6
6
  end
7
7
  end
@@ -2,7 +2,12 @@
2
2
 
3
3
  require "test-prof"
4
4
  require "test_prof/autopilot/configuration"
5
- require "test_prof/autopilot/patches/event_prof_patch"
6
- require "test_prof/autopilot/patches/tag_prof_patch"
7
- require "test_prof/autopilot/patches/factory_prof_patch"
8
- require "test_prof/autopilot/patches/stack_prof_patch"
5
+
6
+ # We only load the patches when tests are executed by autopilot
7
+ # TODO: We should move the patches into TestProf itself as `--format=json`.
8
+ if ENV["TEST_PROF_AUTOPILOT_ENABLED"] == "true"
9
+ require "test_prof/autopilot/patches/event_prof_patch"
10
+ require "test_prof/autopilot/patches/tag_prof_patch"
11
+ require "test_prof/autopilot/patches/factory_prof_patch"
12
+ require "test_prof/autopilot/patches/stack_prof_patch"
13
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-prof-autopilot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.1.0.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruslan Shakirov
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-06-14 00:00:00.000000000 Z
12
+ date: 2023-11-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: test-prof
@@ -131,7 +131,13 @@ files:
131
131
  homepage: http://github.com/test-prof/test-prof-autopilot
132
132
  licenses:
133
133
  - MIT
134
- metadata: {}
134
+ metadata:
135
+ bug_tracker_uri: https://github.com/test-prof/test-prof-autopilot/issues
136
+ changelog_uri: https://github.com/test-prof/test-prof-autopilot/blob/master/CHANGELOG.md
137
+ documentation_uri: https://test-prof.evilmartians.io/
138
+ homepage_uri: https://test-prof.evilmartians.io/
139
+ source_code_uri: https://github.com/test-prof/test-prof-autopilot
140
+ funding_uri: https://github.com/sponsors/test-prof
135
141
  post_install_message:
136
142
  rdoc_options: []
137
143
  require_paths:
@@ -143,11 +149,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
143
149
  version: '2.7'
144
150
  required_rubygems_version: !ruby/object:Gem::Requirement
145
151
  requirements:
146
- - - ">="
152
+ - - ">"
147
153
  - !ruby/object:Gem::Version
148
- version: '0'
154
+ version: 1.3.1
149
155
  requirements: []
150
- rubygems_version: 3.3.7
156
+ rubygems_version: 3.4.20
151
157
  signing_key:
152
158
  specification_version: 4
153
159
  summary: Automatic TestProf runner