semaphore_test_boosters 1.7.3 → 1.8.0

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
  SHA1:
3
- metadata.gz: 55ecf357e070533847ba7fc22764a026d0ec2918
4
- data.tar.gz: 52e0d4afb19f129f079378600b871bb0c47e9d4f
3
+ metadata.gz: 9403e453151e8b33705cd21a2d2421efd6160e30
4
+ data.tar.gz: be15846080e83674e3cae45e34a8969646993228
5
5
  SHA512:
6
- metadata.gz: ecb7d0fb08e4a94de4bc17d9adefe2b2694185666b0c16fa0b4c0fcee4483c5f2de5b484646ea8f83448a5647b38b89e074648080fba0bec43e2160630541e31
7
- data.tar.gz: 866a3b4b308094b0f3ffb1d9593f6595ed74ba5683c191178f8738915f00fddccd21e41c30fcfa7f55955a35e0de38cead7218eb14420d5d886d9d1eb9bd3270
6
+ metadata.gz: c1383be5aba30566585ed5568ccda59ed28ad9097ee2f8f5999c614ae66133b7d145b3d69a61c1a6b10d06bfd68ec381e60caf93fa3acf93653b2d187accdab3
7
+ data.tar.gz: 80d349f51e9618bc7966fb4806b4346ef4465bd075a973e6e84bd759b07e404ac7929798eab8e8ced990f835628f588f0e3035ea86f9b1b1634dbe05653cf54f
data/README.md CHANGED
@@ -1,8 +1,23 @@
1
1
  # Test Boosters
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/semaphore_test_boosters.svg)](https://badge.fury.io/rb/semaphore_test_boosters)
4
+ [![Build Status](https://semaphoreci.com/api/v1/renderedtext/test-boosters/branches/master/badge.svg)](https://semaphoreci.com/renderedtext/test-boosters)
4
5
 
5
- Auto Parallelization — runs test files in multiple threads.
6
+ Auto Parallelization — runs test files in multiple jobs
7
+
8
+ - [Installation](#installation)
9
+
10
+ - RSpec Booster
11
+ - [Running RSpec jobs](#rspec-booster)
12
+ - [RSpec Split Configuration](#rspec-split-configuration)
13
+ - [Leftover RSpec specs](#leftover-rspec-specs)
14
+ - [Passing custom options to RSpec](#custom-rspec-options)
15
+
16
+ - Cucumber Booster
17
+ - [Running Cucumber jobs](#cucumber-booster)
18
+ - [Cucumber Split Configuration](#cucumber-split-configuration)
19
+ - [Leftover Cucumber specs](#leftover-rspec-specs)
20
+ - [Passing custom options to Cucumber](#custom-cucumber-options)
6
21
 
7
22
  ## Installation
8
23
 
@@ -10,25 +25,39 @@ Auto Parallelization — runs test files in multiple threads.
10
25
  gem install semaphore_test_boosters
11
26
  ````
12
27
 
13
- ## Usage
28
+ ## RSpec Booster
14
29
 
15
- ### RSpec Booster
30
+ The RSpec Booster splits your RSpec test suite to multiple jobs.
16
31
 
17
- The RSpec booster command allows you to run one out of several parallel RSpec
18
- threads.
32
+ For example, if you want to split your RSpec test suite into 21 jobs, and run
33
+ then executed the 3rd job, use the following command:
19
34
 
20
35
  ``` bash
21
- rspec_booster --thread 3
36
+ rspec_booster --thread 3/21
22
37
  ```
23
38
 
24
- #### RSpec Split Configuration
39
+ By default, RSpec Booster will distribute your spec files based on their size
40
+ into multiple jobs. This is OK for your first run, but the distribution is
41
+ usually suboptimal.
42
+
43
+ If you want to achieve better build times, and split your test files more
44
+ evenly, you need to provide a split configuration file for RSpec Booster.
45
+
46
+ On Semaphore, this file is generated before every build based on the duration's
47
+ of your previous builds.
48
+
49
+ ### RSpec Split Configuration
50
+
51
+ The `rspec_split_configuration.json` should be placed in your home directory and
52
+ should contain the list of files for each RSpec Booster job.
25
53
 
26
- The `rspec_split_configuration.json` located in your home directory is used to
27
- pass test files to the booster. On Semaphore, this file contains a list of
28
- specs files distributed across threads based on their estimated durations.
54
+ For example, if you have 3 RSpec Booster jobs, and you want to run:
29
55
 
30
- For example, if you have a `rspec_split_configuration.json` located in your home
31
- directory with the following content:
56
+ - `spec/a_spec.rb` and `spec/b_spec.rb` in the first job
57
+ - `spec/c_spec.rb` and `spec/d_spec.rb` in the second job
58
+ - `spec/e_spec.rb` in the third job
59
+
60
+ you should put the following in your split configuration file:
32
61
 
33
62
  ``` json
34
63
  [
@@ -38,19 +67,13 @@ directory with the following content:
38
67
  ]
39
68
  ```
40
69
 
41
- The `rspec_booster` command will deduce that you have 3 threads in total and
42
- that you want to run `spec/a_spec.rb` and `spec/b_spec.rb` on the first thread,
43
- `spec/c_spec.rb` and `spec/d_spec.rb` on the second thread, and `spec/e_spec.rb`
44
- on the third thread.
45
-
46
- #### Leftover files
70
+ ### Leftover RSpec specs
47
71
 
48
- The RSpec Split Configuration contains only those spec files that have an
49
- estimated duration recorded on Semaphore. New files, whose estimated duration
50
- is not yet stored on Semaphore will be distributed across threads in based on
51
- their file size in a round robin fashion.
72
+ Files that are part of your RSpec test suite, but are not in the split
73
+ configuration file, are called "leftover files". These files will be distributed
74
+ based on their file size in a round robin fashion across your jobs.
52
75
 
53
- For example, if you have the following split configuration:
76
+ For example, if you have the following in your split configuration:
54
77
 
55
78
  ``` json
56
79
  [
@@ -70,16 +93,16 @@ spec/d_spec.rb
70
93
  spec/e_spec.rb
71
94
  ```
72
95
 
73
- When you run the `rspec_booster --thread 1` command, the files from the
74
- configuration's first thread and some leftover files will be executed.
96
+ When you run the `rspec_booster --job 1/3` command, the files from the
97
+ configuration's first job and some leftover files will be executed.
75
98
 
76
99
  ``` bash
77
- rspec_booster --thread 1
100
+ rspec_booster --job 1/3
78
101
 
79
102
  # => runs: bundle exec rspec spec/a_spec.rb spec/d_spec.rb
80
103
  ```
81
104
 
82
- #### Custom RSpec options
105
+ ### Custom RSpec options
83
106
 
84
107
  By default, `rspec_booster` passes the following options to RSpec:
85
108
 
@@ -96,17 +119,97 @@ like this:
96
119
  ``` bash
97
120
  export TB_RSPEC_OPTIONS = '--fail-fast'
98
121
 
99
- rspec_booster --thread 2
122
+ rspec_booster --job 2/3
100
123
 
101
124
  # => runs: bundle exec rspec --fail-fast --format documentation --format json --out ~/rspec_report.json <file_list>
102
125
  ```
103
126
 
127
+ ## Cucumber Booster
128
+
129
+ The Cucumber Booster splits your Cucumber test suite to multiple jobs.
130
+
131
+ For example, if you want to split your Cucumber test suite into 21 jobs, and run
132
+ then executed the 3rd job, use the following command:
133
+
134
+ ``` bash
135
+ cucumber_booster --thread 3/21
136
+ ```
137
+
138
+ By default, Cucumber Booster will distribute your spec files based on their size
139
+ into multiple jobs. This is OK for your first run, but the distribution is
140
+ usually suboptimal.
141
+
142
+ If you want to achieve better build times, and split your test files more
143
+ evenly, you need to provide a split configuration file for Cucumber Booster.
144
+
145
+ On Semaphore, this file is generated before every build based on the duration's
146
+ of your previous builds.
147
+
148
+ ### Cucumber Split Configuration
149
+
150
+ The `cucumber_split_configuration.json` should be placed in your home directory
151
+ and should contain the list of files for each Cucumber Booster job.
152
+
153
+ For example, if you have 3 Cucumber Booster jobs, and you want to run:
154
+
155
+ - `features/a.feature` and `spec/b.feature` in the first job
156
+ - `features/c.feature` and `spec/d.feature` in the second job
157
+ - `features/e.feature` in the third job
158
+
159
+ you should put the following in your split configuration file:
160
+
161
+ ``` json
162
+ [
163
+ { "files": ["features/a.feature", "features/b.feature"] },
164
+ { "files": ["features/c.feature", "features/d.feature"] },
165
+ { "files": ["features/e.feature"] }
166
+ ]
167
+ ```
168
+
169
+ ### Leftover files
170
+
171
+ Files that are part of your Cucumber test suite, but are not in the split
172
+ configuration file, are called "leftover files". These files will be distributed
173
+ based on their file size in a round robin fashion across your jobs.
174
+
175
+ For example, if you have the following in your split configuration:
176
+
177
+ ``` json
178
+ [
179
+ { "files": ["features/a.feature"] }
180
+ { "files": ["features/b.feature"] }
181
+ { "files": ["features/c.feature"] }
182
+ ]
183
+ ```
184
+
185
+ and the following files in your spec directory:
186
+
187
+ ``` bash
188
+ features/a.feature
189
+ features/b.feature
190
+ features/c.feature
191
+ features/d.feature
192
+ features/e.feature
193
+ ```
194
+
195
+ When you run the `cucumber_booster --job 1/3` command, the files from the
196
+ configuration's first job and some leftover files will be executed.
197
+
198
+ ``` bash
199
+ cucumber_booster --job 1/3
200
+
201
+ # => runs: bundle exec cucumber features/a.feature features/d.feature
202
+ ```
203
+
204
+ ### Custom Cucumber options
205
+
206
+ Currently, you can't pass custom options to Cucumber.
207
+
104
208
  ## Contributing
105
209
 
106
210
  Bug reports and pull requests are welcome on GitHub at
107
211
  https://github.com/renderedtext/test-boosters.
108
212
 
109
-
110
213
  ## License
111
214
 
112
215
  The gem is available as open source under the terms of the
data/exe/cucumber_booster CHANGED
@@ -4,9 +4,9 @@ require "test_boosters"
4
4
 
5
5
  cli_options = TestBoosters::CliParser.parse
6
6
 
7
- thread_index = cli_options[:thread_index] - 1
8
- thread_count = cli_options[:thread_count]
7
+ job_index = cli_options[:job_index] - 1
8
+ job_count = cli_options[:job_count]
9
9
 
10
- cucumber_booster = TestBoosters::Cucumber::Booster.new(thread_index, thread_count)
10
+ cucumber_booster = TestBoosters::Cucumber::Booster.new(job_index, job_count)
11
11
 
12
12
  exit(cucumber_booster.run)
data/exe/rspec_booster CHANGED
@@ -4,9 +4,9 @@ require "test_boosters"
4
4
 
5
5
  cli_options = TestBoosters::CliParser.parse
6
6
 
7
- thread_index = cli_options[:thread_index] - 1
8
- thread_count = cli_options[:thread_count]
7
+ job_index = cli_options[:job_index] - 1
8
+ job_count = cli_options[:job_count]
9
9
 
10
- rspec_booster = TestBoosters::Rspec::Booster.new(thread_index, thread_count)
10
+ rspec_booster = TestBoosters::Rspec::Booster.new(job_index, job_count)
11
11
 
12
12
  exit(rspec_booster.run)
data/lib/test_boosters.rb CHANGED
@@ -15,8 +15,8 @@ module TestBoosters
15
15
  require "test_boosters/project_info"
16
16
 
17
17
  require "test_boosters/rspec/booster"
18
- require "test_boosters/rspec/thread"
18
+ require "test_boosters/rspec/job"
19
19
 
20
20
  require "test_boosters/cucumber/booster"
21
- require "test_boosters/cucumber/thread"
21
+ require "test_boosters/cucumber/job"
22
22
  end
@@ -4,15 +4,19 @@ module TestBoosters
4
4
 
5
5
  # :reek:TooManyStatements
6
6
  # :reek:NestedIterators
7
+ # :reek:DuplicateMethodCall
7
8
  def parse
8
9
  options = {}
9
10
 
10
11
  parser = OptionParser.new do |opts|
11
12
  opts.on("--thread INDEX") do |parameter|
12
- thread_index, thread_count, _rest = parameter.split("/")
13
+ puts "[DEPRECATION WARNING] The '--thread' parameter is deprecated. Please use '--job' instead."
13
14
 
14
- options[:thread_index] = thread_index.to_i
15
- options[:thread_count] = thread_count.to_i
15
+ options.merge!(parse_job_params(parameter))
16
+ end
17
+
18
+ opts.on("--job INDEX") do |parameter|
19
+ options.merge!(parse_job_params(parameter))
16
20
  end
17
21
  end
18
22
 
@@ -20,5 +24,13 @@ module TestBoosters
20
24
 
21
25
  options
22
26
  end
27
+
28
+ # parses input like '1/32' and ouputs { :job_index => 1, :job_count => 32 }
29
+ def parse_job_params(input_parameter)
30
+ job_index, job_count, _rest = input_parameter.split("/")
31
+
32
+ { :job_index => job_index.to_i, :job_count => job_count.to_i }
33
+ end
34
+
23
35
  end
24
36
  end
@@ -2,19 +2,19 @@ module TestBoosters
2
2
  module Cucumber
3
3
  class Booster
4
4
 
5
- attr_reader :thread_index
6
- attr_reader :thread_count
5
+ attr_reader :job_index
6
+ attr_reader :job_count
7
7
 
8
- def initialize(thread_index, thread_count)
9
- @thread_index = thread_index
10
- @thread_count = thread_count
8
+ def initialize(job_index, job_count)
9
+ @job_index = job_index
10
+ @job_count = job_count
11
11
  end
12
12
 
13
13
  def run
14
14
  TestBoosters::Shell.display_title("Cucumber Booster v#{TestBoosters::VERSION}")
15
15
  display_system_info
16
16
 
17
- threads[@thread_index].run
17
+ jobs[@job_index].run
18
18
  end
19
19
 
20
20
  def display_system_info
@@ -25,12 +25,12 @@ module TestBoosters
25
25
  puts
26
26
  end
27
27
 
28
- def threads
29
- @threads ||= Array.new(@thread_count) do |thread_index|
30
- known = all_specs & split_configuration.files_for_thread(thread_index)
31
- leftover = leftover_specs.select(:index => thread_index, :total => thread_count)
28
+ def jobs
29
+ @jobs ||= Array.new(job_count) do |job_index|
30
+ known = all_specs & split_configuration.files_for_job(job_index)
31
+ leftover = leftover_specs.select(:index => job_index, :total => job_count)
32
32
 
33
- TestBoosters::Cucumber::Thread.new(known, leftover)
33
+ TestBoosters::Cucumber::Job.new(known, leftover)
34
34
  end
35
35
  end
36
36
 
@@ -1,6 +1,6 @@
1
1
  module TestBoosters
2
2
  module Cucumber
3
- class Thread
3
+ class Job
4
4
 
5
5
  attr_reader :files_from_split_configuration
6
6
  attr_reader :leftover_files
@@ -13,14 +13,14 @@ module TestBoosters
13
13
  # :reek:TooManyStatements { max_statements: 10 }
14
14
  def run
15
15
  if all_files.empty?
16
- puts("No files to run in this thread!")
16
+ puts("No files to run in this job!")
17
17
 
18
18
  return 0
19
19
  end
20
20
 
21
21
  run_cucumber_config
22
22
 
23
- display_thread_info
23
+ display_job_info
24
24
 
25
25
  exit_status = run_cucumber
26
26
 
@@ -29,13 +29,13 @@ module TestBoosters
29
29
  exit_status
30
30
  end
31
31
 
32
- def display_thread_info
32
+ def display_job_info
33
33
  TestBoosters::Shell.display_files(
34
- "Known specs for this thread",
34
+ "Known specs for this job",
35
35
  files_from_split_configuration)
36
36
 
37
37
  TestBoosters::Shell.display_files(
38
- "Leftover specs for this thread",
38
+ "Leftover specs for this job",
39
39
  leftover_files)
40
40
  end
41
41
 
@@ -16,16 +16,16 @@ module TestBoosters
16
16
 
17
17
  private
18
18
 
19
- def file_distribution(thread_count)
19
+ def file_distribution(job_count)
20
20
  # create N empty boxes
21
- threads = Array.new(thread_count) { [] }
21
+ jobs = Array.new(job_count) { [] }
22
22
 
23
23
  # distribute files in Round Robin fashion
24
24
  sorted_files_by_file_size.each.with_index do |file, index|
25
- threads[index % thread_count] << file
25
+ jobs[index % job_count] << file
26
26
  end
27
27
 
28
- threads
28
+ jobs
29
29
  end
30
30
 
31
31
  def sorted_files_by_file_size
@@ -2,19 +2,19 @@ module TestBoosters
2
2
  module Rspec
3
3
  class Booster
4
4
 
5
- attr_reader :thread_index
6
- attr_reader :thread_count
5
+ attr_reader :job_index
6
+ attr_reader :job_count
7
7
 
8
- def initialize(thread_index, thread_count)
9
- @thread_index = thread_index
10
- @thread_count = thread_count
8
+ def initialize(job_index, job_count)
9
+ @job_index = job_index
10
+ @job_count = job_count
11
11
  end
12
12
 
13
13
  def run
14
14
  TestBoosters::Shell.display_title("RSpec Booster v#{TestBoosters::VERSION}")
15
15
  display_system_info
16
16
 
17
- threads[@thread_index].run
17
+ jobs[@job_index].run
18
18
  end
19
19
 
20
20
  def display_system_info
@@ -25,12 +25,12 @@ module TestBoosters
25
25
  puts
26
26
  end
27
27
 
28
- def threads
29
- @threads ||= Array.new(@thread_count) do |thread_index|
30
- known = all_specs & split_configuration.files_for_thread(thread_index)
31
- leftover = leftover_specs.select(:index => thread_index, :total => thread_count)
28
+ def jobs
29
+ @jobs ||= Array.new(job_count) do |job_index|
30
+ known = all_specs & split_configuration.files_for_job(job_index)
31
+ leftover = leftover_specs.select(:index => job_index, :total => job_count)
32
32
 
33
- TestBoosters::Rspec::Thread.new(known, leftover)
33
+ TestBoosters::Rspec::Job.new(known, leftover)
34
34
  end
35
35
  end
36
36
 
@@ -1,6 +1,6 @@
1
1
  module TestBoosters
2
2
  module Rspec
3
- class Thread
3
+ class Job
4
4
 
5
5
  attr_reader :files_from_split_configuration
6
6
  attr_reader :leftover_files
@@ -13,12 +13,12 @@ module TestBoosters
13
13
  # :reek:TooManyStatements { max_statements: 10 }
14
14
  def run
15
15
  if all_files.empty?
16
- puts("No files to run in this thread!")
16
+ puts("No files to run in this job!")
17
17
 
18
18
  return 0
19
19
  end
20
20
 
21
- display_thread_info
21
+ display_job_info
22
22
 
23
23
  exit_status = run_rspec
24
24
 
@@ -27,14 +27,9 @@ module TestBoosters
27
27
  exit_status
28
28
  end
29
29
 
30
- def display_thread_info
31
- TestBoosters::Shell.display_files(
32
- "Known specs for this thread",
33
- files_from_split_configuration)
34
-
35
- TestBoosters::Shell.display_files(
36
- "Leftover specs for this thread",
37
- leftover_files)
30
+ def display_job_info
31
+ TestBoosters::Shell.display_files("Known specs for this job", files_from_split_configuration)
32
+ TestBoosters::Shell.display_files("Leftover specs for this job", leftover_files)
38
33
 
39
34
  puts "RSpec options: #{rspec_options}"
40
35
  end
@@ -1,7 +1,7 @@
1
1
  module TestBoosters
2
2
  class SplitConfiguration
3
3
 
4
- Thread = Struct.new(:files, :thread_index)
4
+ Job = Struct.new(:files)
5
5
 
6
6
  def initialize(path)
7
7
  @path = path
@@ -13,23 +13,23 @@ module TestBoosters
13
13
  end
14
14
 
15
15
  def valid?
16
- threads # try to load data into memory
16
+ jobs # try to load data into memory
17
17
 
18
18
  @valid
19
19
  end
20
20
 
21
21
  def all_files
22
- @all_files ||= threads.map(&:files).flatten.sort
22
+ @all_files ||= jobs.map(&:files).flatten.sort
23
23
  end
24
24
 
25
- def files_for_thread(thread_index)
26
- thread = threads[thread_index]
25
+ def files_for_job(job_index)
26
+ job = jobs[job_index]
27
27
 
28
- thread ? thread.files : []
28
+ job ? job.files : []
29
29
  end
30
30
 
31
- def threads
32
- @threads ||= present? ? load_data : []
31
+ def jobs
32
+ @jobs ||= present? ? load_data : []
33
33
  end
34
34
 
35
35
  private
@@ -38,8 +38,10 @@ module TestBoosters
38
38
  def load_data
39
39
  @valid = false
40
40
 
41
- content = JSON.parse(File.read(@path)).map.with_index do |raw_thread, index|
42
- TestBoosters::SplitConfiguration::Thread.new(raw_thread.fetch("files").sort, index)
41
+ content = JSON.parse(File.read(@path)).map do |raw_job|
42
+ files = raw_job.fetch("files").sort
43
+
44
+ TestBoosters::SplitConfiguration::Job.new(files)
43
45
  end
44
46
 
45
47
  @valid = true
@@ -1,3 +1,3 @@
1
1
  module TestBoosters
2
- VERSION = "1.7.3".freeze
2
+ VERSION = "1.8.0".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: semaphore_test_boosters
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.3
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Developers at Rendered Text
@@ -160,13 +160,13 @@ files:
160
160
  - lib/test_boosters.rb
161
161
  - lib/test_boosters/cli_parser.rb
162
162
  - lib/test_boosters/cucumber/booster.rb
163
- - lib/test_boosters/cucumber/thread.rb
163
+ - lib/test_boosters/cucumber/job.rb
164
164
  - lib/test_boosters/insights_uploader.rb
165
165
  - lib/test_boosters/leftover_files.rb
166
166
  - lib/test_boosters/logger.rb
167
167
  - lib/test_boosters/project_info.rb
168
168
  - lib/test_boosters/rspec/booster.rb
169
- - lib/test_boosters/rspec/thread.rb
169
+ - lib/test_boosters/rspec/job.rb
170
170
  - lib/test_boosters/shell.rb
171
171
  - lib/test_boosters/split_configuration.rb
172
172
  - lib/test_boosters/version.rb