split-test-rb 1.0.3 → 1.0.5
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/README.md +8 -11
- data/lib/split_test_rb/version.rb +1 -1
- data/lib/split_test_rb.rb +14 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f765610ad0a575e0bb582ea31ae9ed544382fed7d4ef63d2f9f396460a19c821
|
|
4
|
+
data.tar.gz: 65061f28e3bf6f0f9882b4d6f4e110c23eadd7146cb5bc0e3dfec608c2a49022
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '034288dce122aa532fb53ede46a67af4d05bad5d84163e54fee77e4eee067828f7aed2dd21fd88f870c99170ab19836895ebfc10669ae32a33fcdd4f0698a3f2'
|
|
7
|
+
data.tar.gz: 9808a967a1c9e7f96ff87fedbe9ddef03808a4455987ac0750709a840c8d42e6003dfad2cd5ab28fdf6318236b2c43dcbae2237feb2fc4ecb247ce3b6f20cb1c
|
data/README.md
CHANGED
|
@@ -87,12 +87,16 @@ The test directory and pattern options are useful for:
|
|
|
87
87
|
When you have test files that take significantly longer than others, you can use `--split-by-example-threshold` to automatically split them into individual RSpec examples. This enables finer-grained load balancing across CI nodes.
|
|
88
88
|
|
|
89
89
|
```bash
|
|
90
|
+
bundle exec rspec --dry-run --format json --out tmp/dry-run.json
|
|
90
91
|
split-test-rb --json-path tmp/test-results \
|
|
91
92
|
--node-index $CI_NODE_INDEX \
|
|
92
93
|
--node-total $CI_NODE_TOTAL \
|
|
93
|
-
--split-by-example-threshold 10.0
|
|
94
|
+
--split-by-example-threshold 10.0 \
|
|
95
|
+
--dry-run-json tmp/dry-run.json
|
|
94
96
|
```
|
|
95
97
|
|
|
98
|
+
`--dry-run-json` is recommended together with this option. Without it, examples missing from the cached JSON are not run (see [Keeping heavy files up to date with `--dry-run-json`](#keeping-heavy-files-up-to-date-with---dry-run-json)).
|
|
99
|
+
|
|
96
100
|
With this option:
|
|
97
101
|
- Files with execution time **below** the threshold are distributed as whole files (e.g., `spec/fast_spec.rb`)
|
|
98
102
|
- Files with execution time **at or above** the threshold are split into individual examples (e.g., `spec/slow_spec.rb[1:1]`, `spec/slow_spec.rb[1:2]`)
|
|
@@ -106,21 +110,14 @@ This is useful when:
|
|
|
106
110
|
|
|
107
111
|
#### Keeping heavy files up to date with `--dry-run-json`
|
|
108
112
|
|
|
109
|
-
|
|
113
|
+
Without `--dry-run-json`, heavy files are assigned only by the example IDs found in the cached JSON reports, and a warning is printed. Examples that are not in the cache are not assigned to any node:
|
|
110
114
|
|
|
111
115
|
- Examples newly added to a heavy file
|
|
112
116
|
- Examples whose IDs shifted because other examples were inserted or moved (RSpec example IDs are position based, e.g. `[1:2:1]`)
|
|
113
117
|
|
|
114
|
-
Pass the output of `rspec --dry-run --format json` to use the examples that currently exist
|
|
118
|
+
Pass the output of `rspec --dry-run --format json` to use the examples that currently exist (see the example above).
|
|
115
119
|
|
|
116
|
-
|
|
117
|
-
bundle exec rspec --dry-run --format json --out tmp/dry-run.json
|
|
118
|
-
split-test-rb --json-path tmp/test-results \
|
|
119
|
-
--node-index $CI_NODE_INDEX \
|
|
120
|
-
--node-total $CI_NODE_TOTAL \
|
|
121
|
-
--split-by-example-threshold 10.0 \
|
|
122
|
-
--dry-run-json tmp/dry-run.json
|
|
123
|
-
```
|
|
120
|
+
Every node must use a dry-run JSON with the same examples, or the nodes compute different splits and some tests are run on no node. Generating it once (e.g. in a setup job) and sharing it with all nodes as a CI artifact guarantees this, and boots the app only once instead of on every node.
|
|
124
121
|
|
|
125
122
|
With this option, for each heavy file:
|
|
126
123
|
- Examples in the dry-run JSON are assigned, using cached timings when available and the default timing (1.0s) otherwise
|
data/lib/split_test_rb.rb
CHANGED
|
@@ -121,8 +121,10 @@ module SplitTestRb
|
|
|
121
121
|
# Distributes test files across nodes based on execution times
|
|
122
122
|
# Uses greedy algorithm: assign each file to the node with lowest cumulative time
|
|
123
123
|
def self.balance(timings, total_nodes)
|
|
124
|
-
# Sort files by execution time (descending) for better balance
|
|
125
|
-
|
|
124
|
+
# Sort files by execution time (descending) for better balance.
|
|
125
|
+
# Ties are broken by file name so that every node computes the same split
|
|
126
|
+
# even when the input order differs (e.g. a dry-run JSON listed in random order)
|
|
127
|
+
sorted_files = timings.sort_by { |file, time| [-time, file] }
|
|
126
128
|
|
|
127
129
|
# Initialize nodes with empty arrays and zero cumulative time
|
|
128
130
|
nodes = Array.new(total_nodes) { { files: [], total_time: 0 } }
|
|
@@ -239,6 +241,7 @@ module SplitTestRb
|
|
|
239
241
|
threshold = options[:split_by_example_threshold]
|
|
240
242
|
timings = if threshold
|
|
241
243
|
current_example_ids = load_current_example_ids(options[:dry_run_json])
|
|
244
|
+
warn_cached_examples_only(file_timings, threshold) unless current_example_ids
|
|
242
245
|
apply_example_splitting(file_timings, json_files, threshold,
|
|
243
246
|
current_example_ids: current_example_ids, default_files: default_files)
|
|
244
247
|
else
|
|
@@ -254,6 +257,15 @@ module SplitTestRb
|
|
|
254
257
|
.split(file_timings, threshold)
|
|
255
258
|
end
|
|
256
259
|
|
|
260
|
+
# Warns that heavy files are assigned only by the cached example IDs when --dry-run-json is not given,
|
|
261
|
+
# because examples missing from the cache (new or shifted IDs) are then not run on any node
|
|
262
|
+
def self.warn_cached_examples_only(file_timings, threshold)
|
|
263
|
+
return unless file_timings.any? { |_file, time| time >= threshold }
|
|
264
|
+
|
|
265
|
+
warn 'Warning: --dry-run-json is not given, so examples of heavy files that are not in the cached JSON ' \
|
|
266
|
+
'will not be run. Pass the output of `rspec --dry-run --format json` with --dry-run-json'
|
|
267
|
+
end
|
|
268
|
+
|
|
257
269
|
# Loads example IDs from an RSpec dry-run JSON report, or returns nil when no path is given
|
|
258
270
|
def self.load_current_example_ids(dry_run_json)
|
|
259
271
|
return nil unless dry_run_json
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: split-test-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Naofumi Fujii
|
|
@@ -92,7 +92,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
92
92
|
requirements:
|
|
93
93
|
- - ">="
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: 3.
|
|
95
|
+
version: 3.3.0
|
|
96
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
97
|
requirements:
|
|
98
98
|
- - ">="
|