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 +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +60 -38
- data/lib/test-prof-autopilot.rb +1 -0
- data/lib/test_prof/autopilot/cli.rb +17 -0
- data/lib/test_prof/autopilot/command_executor.rb +2 -0
- data/lib/test_prof/autopilot/configuration.rb +2 -2
- data/lib/test_prof/autopilot/event_prof/profiling_executor.rb +4 -0
- data/lib/test_prof/autopilot/factory_prof/writer.rb +0 -11
- data/lib/test_prof/autopilot/merger.rb +2 -2
- data/lib/test_prof/autopilot/version.rb +1 -1
- data/lib/test_prof/autopilot.rb +9 -4
- metadata +12 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55e6d41b4c30aa3390d97e550a425e92125e6ee74e4ffe6a3e2660be5f5e1795
|
4
|
+
data.tar.gz: 866cc0632a7304a5e675ae78541e77f304de4eeba781f8987a6f8d0563eba3db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
1
|
+
[](https://rubygems.org/gems/test-prof-autopilot)
|
2
|
+
[](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
|
-
|
14
|
+
## Usage
|
24
15
|
|
25
|
-
|
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
|
-
|
40
|
-
info report.methods.take(5)
|
30
|
+
puts report.methods.take(5)
|
41
31
|
```
|
42
32
|
|
43
|
-
|
33
|
+
Now, you can use the `auto-test-prof` command to execute the plan:
|
44
34
|
|
45
|
-
```
|
46
|
-
|
47
|
-
|
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
|
-
|
50
|
-
run :factory_prof, paths: report.paths
|
41
|
+
### Merging results
|
51
42
|
|
52
|
-
|
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
|
-
|
51
|
+
Then, assuming all reports were downloaded:
|
56
52
|
|
57
|
-
|
58
|
-
|
53
|
+
```sh
|
54
|
+
$ auto-test-prof --merge tag_prof --reports tag_prof_*.json
|
59
55
|
|
60
|
-
|
56
|
+
Merging tag_prof reports at tag_prof_1.json, tag_prof_2.json, tag_prof_3.json
|
61
57
|
|
62
|
-
|
58
|
+
[TEST PROF] TagProf report for type
|
63
59
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
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/
|
data/lib/test-prof-autopilot.rb
CHANGED
@@ -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
|
data/lib/test_prof/autopilot.rb
CHANGED
@@ -2,7 +2,12 @@
|
|
2
2
|
|
3
3
|
require "test-prof"
|
4
4
|
require "test_prof/autopilot/configuration"
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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.
|
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:
|
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:
|
154
|
+
version: 1.3.1
|
149
155
|
requirements: []
|
150
|
-
rubygems_version: 3.
|
156
|
+
rubygems_version: 3.4.20
|
151
157
|
signing_key:
|
152
158
|
specification_version: 4
|
153
159
|
summary: Automatic TestProf runner
|