semaphore_test_boosters 1.7.3 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
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