parallel_tests-fine_grain_test 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.hound.yml +8 -0
- data/.rubocop.default.yml +1114 -0
- data/.rubocop.disabled.yml +125 -0
- data/.rubocop.enabled.yml +1352 -0
- data/.rubocop.yml +66 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/Appraisals +14 -0
- data/Gemfile +8 -0
- data/README.md +51 -0
- data/Rakefile +10 -0
- data/bin/parallel_fine_grain_test +9 -0
- data/exe/parallel_tests-fine_grain_test +3 -0
- data/gemfiles/activesupport_3.gemfile +11 -0
- data/gemfiles/activesupport_3.gemfile.lock +44 -0
- data/gemfiles/activesupport_4.gemfile +10 -0
- data/gemfiles/activesupport_4.gemfile.lock +48 -0
- data/gemfiles/activesupport_5.gemfile +10 -0
- data/gemfiles/activesupport_5.gemfile.lock +47 -0
- data/lib/parallel_tests/fine_grain_test.rb +8 -0
- data/lib/parallel_tests/fine_grain_test/file_queue.rb +80 -0
- data/lib/parallel_tests/fine_grain_test/minitest.rb +4 -0
- data/lib/parallel_tests/fine_grain_test/minitest/extension.rb +27 -0
- data/lib/parallel_tests/fine_grain_test/minitest/suite.rb +35 -0
- data/lib/parallel_tests/fine_grain_test/railtie.rb +8 -0
- data/lib/parallel_tests/fine_grain_test/runner.rb +27 -0
- data/lib/parallel_tests/fine_grain_test/runtime_logger.rb +81 -0
- data/lib/parallel_tests/fine_grain_test/tasks.rb +21 -0
- data/lib/parallel_tests/fine_grain_test/test_case.rb +20 -0
- data/lib/parallel_tests/fine_grain_test/test_helper.rb +16 -0
- data/lib/parallel_tests/fine_grain_test/test_unit.rb +11 -0
- data/lib/parallel_tests/fine_grain_test/test_unit/collector.rb +54 -0
- data/lib/parallel_tests/fine_grain_test/test_unit/test_suite.rb +59 -0
- data/lib/parallel_tests/fine_grain_test/version.rb +5 -0
- data/parallel_tests-fine_grain_test.gemspec +23 -0
- metadata +122 -0
data/.rubocop.yml
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
inherit_from:
|
2
|
+
- .rubocop.enabled.yml
|
3
|
+
- .rubocop.disabled.yml
|
4
|
+
- .rubocop.default.yml
|
5
|
+
|
6
|
+
AllCops:
|
7
|
+
TargetRubyVersion: 2.2
|
8
|
+
|
9
|
+
# Set max line length to 100
|
10
|
+
Metrics/LineLength:
|
11
|
+
Max: 100
|
12
|
+
Enabled: true
|
13
|
+
|
14
|
+
# Set max method length to 100
|
15
|
+
Metrics/MethodLength:
|
16
|
+
Max: 100
|
17
|
+
|
18
|
+
# Renaming `has_something?` to `something?` obfuscates whether it is a 'is-a'
|
19
|
+
# or a 'has-a' relationship.
|
20
|
+
Style/PredicateName:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
# ClassLength, ugh
|
24
|
+
Metrics/ClassLength:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
# Because only Paulus cares about documentation
|
28
|
+
Style/Documentation:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
# This cop is too aggresive in claiming a guard clause should be used
|
32
|
+
Style/GuardClause:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
# rescue in modifier form is very idiomatic and useful in certain situations!
|
36
|
+
Style/RescueModifier:
|
37
|
+
Enabled: false
|
38
|
+
|
39
|
+
# Otherwise you get a warning if you do ['Paulus', 'Productive', 'Very']
|
40
|
+
Style/WordArray:
|
41
|
+
Enabled: false
|
42
|
+
|
43
|
+
# This cop does not fare well with our increased method length. See http://c2.com/cgi/wiki?AbcMetric
|
44
|
+
Metrics/AbcSize:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
Metrics/CyclomaticComplexity:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
Metrics/PerceivedComplexity:
|
51
|
+
Enabled: false
|
52
|
+
|
53
|
+
# Avoid chaining a method call on a do...end block.
|
54
|
+
Style/MethodCalledOnDoEndBlock:
|
55
|
+
Enabled: true
|
56
|
+
|
57
|
+
# Prefer keyword arguments over option hashes
|
58
|
+
Style/OptionHash:
|
59
|
+
Enabled: true
|
60
|
+
|
61
|
+
Style/TrailingCommaInLiteral:
|
62
|
+
# If `comma`, the cop requires a comma after the last item in an array or
|
63
|
+
# hash, but only when each item is on its own line.
|
64
|
+
# If `consistent_comma`, the cop requires a comma after the last item of all
|
65
|
+
# non-empty array and hash literals.
|
66
|
+
EnforcedStyleForMultiline: comma
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.2.4
|
data/.travis.yml
ADDED
data/Appraisals
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
appraise 'activesupport_3' do
|
2
|
+
gem 'test-unit', '2.5.5', require: false
|
3
|
+
gem 'activesupport', '3.2.22'
|
4
|
+
end
|
5
|
+
|
6
|
+
appraise 'activesupport_4' do
|
7
|
+
gem 'minitest', require: false
|
8
|
+
gem 'activesupport', '4.2.6'
|
9
|
+
end
|
10
|
+
|
11
|
+
appraise 'activesupport_5' do
|
12
|
+
gem 'minitest', require: false
|
13
|
+
gem 'activesupport', '5.0.0.rc1'
|
14
|
+
end
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# ParallelTests::FineGrainTest
|
2
|
+
|
3
|
+
Normally the `parallel_tests` divvies up the test files between parallel test processes at the
|
4
|
+
beginning. This causes uneven runtimes as some test processes end up with faster test files while others end up with slower test files. Utilizing past execution times when divving up the tests helps, however, due to differences in test agents and varied execution times (i'm looking at you selenium) it still results in uneven runtimes.
|
5
|
+
|
6
|
+
This gem extends the `parallel_tests` gem to enable parallel test processes to pull tests from a global queue until there are no more tests. This results in all parallel test processes being
|
7
|
+
utilized much more optimally which leads to faster tests.
|
8
|
+
|
9
|
+
Tested with,
|
10
|
+
test-unit / activesupport 3.x
|
11
|
+
minitest / activesupport 4.x
|
12
|
+
minitest / activesupport 5.x
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this lines to your application's Gemfile:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'parallel_tests'
|
20
|
+
gem 'parallel_tests-fine_grain_test'
|
21
|
+
```
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
$ bundle
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
$ gem install parallel_tests-fine_grain_test
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
The usage is much like `parallel:test` task.
|
34
|
+
|
35
|
+
Example,
|
36
|
+
```
|
37
|
+
%> rake parallel:fine_grain_test[^test/selenium]
|
38
|
+
```
|
39
|
+
|
40
|
+
The FINE_GRAIN_TEST_RUNTIME_LOGGER can be optionally set to the location of the file where the test times should be read from / written to. Although optional, it is highly recommended to set FINE_GRAIN_TEST_RUNTIME_LOGGER as it helps the tests complete faster.
|
41
|
+
|
42
|
+
## Development
|
43
|
+
|
44
|
+
After checking out the repo, run `bundle` to install dependencies. Then, run `rake test` to run the tests.
|
45
|
+
|
46
|
+
Note, this gem uses Minitest framework for its own tests but uses the Appraisal gem to test against potentially different version of test-unit and minitest. See the integration tests.
|
47
|
+
|
48
|
+
## Contributing
|
49
|
+
|
50
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/parallel_tests-fine_grain_test.
|
51
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# enable local usage from cloned repo
|
4
|
+
root = File.expand_path("../..", __FILE__)
|
5
|
+
$LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
|
6
|
+
|
7
|
+
require "parallel_tests"
|
8
|
+
|
9
|
+
ParallelTests::CLI.new.run(["--type", "fine_grain_test"] + ARGV)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "minitest", :require => false
|
6
|
+
gem "mocha", :require => false
|
7
|
+
gem "appraisal"
|
8
|
+
gem "test-unit", "2.5.5", :require => false
|
9
|
+
gem "activesupport", "3.2.22"
|
10
|
+
|
11
|
+
gemspec :path => "../"
|
@@ -0,0 +1,44 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../
|
3
|
+
specs:
|
4
|
+
parallel_tests-fine_grain_test (0.1.0)
|
5
|
+
parallel_tests (~> 2.4)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activesupport (3.2.22)
|
11
|
+
i18n (~> 0.6, >= 0.6.4)
|
12
|
+
multi_json (~> 1.0)
|
13
|
+
appraisal (2.1.0)
|
14
|
+
bundler
|
15
|
+
rake
|
16
|
+
thor (>= 0.14.0)
|
17
|
+
i18n (0.7.0)
|
18
|
+
metaclass (0.0.4)
|
19
|
+
minitest (5.9.0)
|
20
|
+
mocha (1.1.0)
|
21
|
+
metaclass (~> 0.0.1)
|
22
|
+
multi_json (1.12.0)
|
23
|
+
parallel (1.9.0)
|
24
|
+
parallel_tests (2.5.0)
|
25
|
+
parallel
|
26
|
+
rake (10.5.0)
|
27
|
+
test-unit (2.5.5)
|
28
|
+
thor (0.19.1)
|
29
|
+
|
30
|
+
PLATFORMS
|
31
|
+
ruby
|
32
|
+
|
33
|
+
DEPENDENCIES
|
34
|
+
activesupport (= 3.2.22)
|
35
|
+
appraisal
|
36
|
+
bundler (~> 1.11)
|
37
|
+
minitest
|
38
|
+
mocha
|
39
|
+
parallel_tests-fine_grain_test!
|
40
|
+
rake (~> 10.0)
|
41
|
+
test-unit (= 2.5.5)
|
42
|
+
|
43
|
+
BUNDLED WITH
|
44
|
+
1.12.3
|
@@ -0,0 +1,48 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../
|
3
|
+
specs:
|
4
|
+
parallel_tests-fine_grain_test (0.1.0)
|
5
|
+
parallel_tests (~> 2.4)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activesupport (4.2.6)
|
11
|
+
i18n (~> 0.7)
|
12
|
+
json (~> 1.7, >= 1.7.7)
|
13
|
+
minitest (~> 5.1)
|
14
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
15
|
+
tzinfo (~> 1.1)
|
16
|
+
appraisal (2.1.0)
|
17
|
+
bundler
|
18
|
+
rake
|
19
|
+
thor (>= 0.14.0)
|
20
|
+
i18n (0.7.0)
|
21
|
+
json (1.8.3)
|
22
|
+
metaclass (0.0.4)
|
23
|
+
minitest (5.9.0)
|
24
|
+
mocha (1.1.0)
|
25
|
+
metaclass (~> 0.0.1)
|
26
|
+
parallel (1.9.0)
|
27
|
+
parallel_tests (2.5.0)
|
28
|
+
parallel
|
29
|
+
rake (10.5.0)
|
30
|
+
thor (0.19.1)
|
31
|
+
thread_safe (0.3.5)
|
32
|
+
tzinfo (1.2.2)
|
33
|
+
thread_safe (~> 0.1)
|
34
|
+
|
35
|
+
PLATFORMS
|
36
|
+
ruby
|
37
|
+
|
38
|
+
DEPENDENCIES
|
39
|
+
activesupport (= 4.2.6)
|
40
|
+
appraisal
|
41
|
+
bundler (~> 1.11)
|
42
|
+
minitest
|
43
|
+
mocha
|
44
|
+
parallel_tests-fine_grain_test!
|
45
|
+
rake (~> 10.0)
|
46
|
+
|
47
|
+
BUNDLED WITH
|
48
|
+
1.12.3
|
@@ -0,0 +1,47 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../
|
3
|
+
specs:
|
4
|
+
parallel_tests-fine_grain_test (0.1.0)
|
5
|
+
parallel_tests (~> 2.4)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activesupport (5.0.0.rc1)
|
11
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
12
|
+
i18n (~> 0.7)
|
13
|
+
minitest (~> 5.1)
|
14
|
+
tzinfo (~> 1.1)
|
15
|
+
appraisal (2.1.0)
|
16
|
+
bundler
|
17
|
+
rake
|
18
|
+
thor (>= 0.14.0)
|
19
|
+
concurrent-ruby (1.0.2)
|
20
|
+
i18n (0.7.0)
|
21
|
+
metaclass (0.0.4)
|
22
|
+
minitest (5.9.0)
|
23
|
+
mocha (1.1.0)
|
24
|
+
metaclass (~> 0.0.1)
|
25
|
+
parallel (1.9.0)
|
26
|
+
parallel_tests (2.5.0)
|
27
|
+
parallel
|
28
|
+
rake (10.5.0)
|
29
|
+
thor (0.19.1)
|
30
|
+
thread_safe (0.3.5)
|
31
|
+
tzinfo (1.2.2)
|
32
|
+
thread_safe (~> 0.1)
|
33
|
+
|
34
|
+
PLATFORMS
|
35
|
+
ruby
|
36
|
+
|
37
|
+
DEPENDENCIES
|
38
|
+
activesupport (= 5.0.0.rc1)
|
39
|
+
appraisal
|
40
|
+
bundler (~> 1.11)
|
41
|
+
minitest
|
42
|
+
mocha
|
43
|
+
parallel_tests-fine_grain_test!
|
44
|
+
rake (~> 10.0)
|
45
|
+
|
46
|
+
BUNDLED WITH
|
47
|
+
1.12.3
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'parallel_tests/fine_grain_test/test_case'
|
2
|
+
|
3
|
+
module ParallelTests
|
4
|
+
module FineGrainTest
|
5
|
+
class FileQueue
|
6
|
+
FILE_NAME = '.test.queue'.freeze
|
7
|
+
MARKER = '--POPULATE--'.freeze
|
8
|
+
|
9
|
+
def initialize(file_name = FILE_NAME)
|
10
|
+
@file_name = file_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def reset
|
14
|
+
lock do |file|
|
15
|
+
rewrite(file, [ MARKER ])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def enq_all(test_cases)
|
20
|
+
lock do |file|
|
21
|
+
return if already_populated?(file)
|
22
|
+
|
23
|
+
test_cases = yield(test_cases) if block_given?
|
24
|
+
|
25
|
+
lines = test_cases.map { |test_case| TestCase.encode(test_case) }
|
26
|
+
rewrite(file, lines)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def deq
|
31
|
+
lock do |file|
|
32
|
+
lines = file.read.split(/\n/)
|
33
|
+
return nil if lines.empty? || lines[0].chomp == MARKER
|
34
|
+
rewrite(file, lines[1..-1])
|
35
|
+
|
36
|
+
return TestCase.decode(lines[0].chomp)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def size
|
41
|
+
lock do |file|
|
42
|
+
lines = file.read.split(/\n/)
|
43
|
+
if lines.empty? || lines[0].chomp == MARKER
|
44
|
+
return 0
|
45
|
+
else
|
46
|
+
return lines.size
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def rewrite(file, lines)
|
54
|
+
file.pos = 0
|
55
|
+
file.truncate(0)
|
56
|
+
lines.each do |line|
|
57
|
+
file.puts(line)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def already_populated?(file)
|
62
|
+
lines = file.read.split(/\n/)
|
63
|
+
return true if lines.empty?
|
64
|
+
|
65
|
+
lines[0].chomp != MARKER
|
66
|
+
end
|
67
|
+
|
68
|
+
def lock
|
69
|
+
File.open(@file_name, File::RDWR|File::CREAT) do |f|
|
70
|
+
begin
|
71
|
+
f.flock File::LOCK_EX
|
72
|
+
yield(f)
|
73
|
+
ensure
|
74
|
+
f.flock File::LOCK_UN
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|