test-queue 0.6.0 → 0.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 +4 -4
- data/README.md +42 -42
- data/exe/cucumber-queue +2 -1
- data/exe/minitest-queue +3 -2
- data/exe/rspec-queue +2 -1
- data/exe/testunit-queue +2 -1
- data/lib/test-queue.rb +2 -0
- data/lib/test_queue/iterator.rb +23 -15
- data/lib/test_queue/runner/cucumber.rb +3 -0
- data/lib/test_queue/runner/{sample.rb → example.rb} +30 -9
- data/lib/test_queue/runner/minitest.rb +5 -3
- data/lib/test_queue/runner/minitest4.rb +12 -7
- data/lib/test_queue/runner/minitest5.rb +37 -22
- data/lib/test_queue/runner/puppet_lint.rb +6 -4
- data/lib/test_queue/runner/rspec.rb +15 -4
- data/lib/test_queue/runner/rspec2.rb +24 -24
- data/lib/test_queue/runner/rspec3.rb +11 -11
- data/lib/test_queue/runner/testunit.rb +6 -3
- data/lib/test_queue/runner.rb +93 -103
- data/lib/test_queue/stats.rb +17 -13
- data/lib/test_queue/test_framework.rb +2 -0
- data/lib/test_queue/version.rb +5 -0
- data/lib/test_queue.rb +1 -5
- metadata +7 -42
- data/.github/workflows/test.yml +0 -93
- data/.gitignore +0 -6
- data/Appraisals +0 -35
- data/Gemfile +0 -7
- data/Rakefile +0 -14
- data/gemfiles/cucumber1_3.gemfile +0 -9
- data/gemfiles/cucumber2_4.gemfile +0 -9
- data/gemfiles/minitest4.gemfile +0 -7
- data/gemfiles/minitest5.gemfile +0 -7
- data/gemfiles/rspec2.gemfile +0 -8
- data/gemfiles/rspec3.gemfile +0 -7
- data/gemfiles/testunit.gemfile +0 -7
- data/script/bootstrap +0 -13
- data/spec/stats_spec.rb +0 -79
- data/test/cucumber.bats +0 -57
- data/test/minitest4.bats +0 -34
- data/test/minitest5.bats +0 -194
- data/test/rspec2.bats +0 -46
- data/test/rspec3.bats +0 -56
- data/test/samples/features/bad.feature +0 -5
- data/test/samples/features/sample.feature +0 -25
- data/test/samples/features/sample2.feature +0 -29
- data/test/samples/features/step_definitions/common.rb +0 -19
- data/test/samples/sample_minispec.rb +0 -37
- data/test/samples/sample_minitest4.rb +0 -25
- data/test/samples/sample_minitest5.rb +0 -33
- data/test/samples/sample_rspec_helper.rb +0 -1
- data/test/samples/sample_shared_examples_for_spec.rb +0 -5
- data/test/samples/sample_spec.rb +0 -25
- data/test/samples/sample_split_spec.rb +0 -17
- data/test/samples/sample_testunit.rb +0 -25
- data/test/samples/sample_use_shared_example1_spec.rb +0 -8
- data/test/samples/sample_use_shared_example2_spec.rb +0 -8
- data/test/sleepy_runner.rb +0 -16
- data/test/testlib.bash +0 -89
- data/test/testunit.bats +0 -20
- data/test-queue.gemspec +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b99d05b99bd64f0b8efb578d5641077984fae57a6cef805f3ed92beb0fadb56b
|
4
|
+
data.tar.gz: dec70c7bef1dd759350333fa913ee780494dab07575342baa9e6545a9808c42a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ac80e29b3b5f7ac78db7f4167a8d75de63e3e5295f00139182257b99991003abd801f38c9c216310ab21566fba1ac216585c3621204d59df1a58f917e2cbf30
|
7
|
+
data.tar.gz: caf10f2498bd05f890dad0cc4feb45c5b0d2824d4ef3a3a00c9e1255fdbdf777437eee4ea9a4543752125c90f5cea7361778bec0b1eb64527ce895bdea93ec5b
|
data/README.md
CHANGED
@@ -10,46 +10,16 @@ Specifically optimized for CI environments: build statistics from each run
|
|
10
10
|
are stored locally and used to sort the queue at the beginning of the
|
11
11
|
next run.
|
12
12
|
|
13
|
-
## Design
|
14
|
-
|
15
|
-
test-queue uses a simple master + pre-fork worker model. The master
|
16
|
-
exposes a unix domain socket server which workers use to grab tests off
|
17
|
-
the queue.
|
18
|
-
|
19
|
-
```console
|
20
|
-
─┬─ 21232 minitest-queue master
|
21
|
-
├─── 21571 minitest-queue worker [3] - AuthenticationTest
|
22
|
-
├─── 21568 minitest-queue worker [2] - ApiTest
|
23
|
-
├─── 21565 minitest-queue worker [1] - UsersControllerTest
|
24
|
-
└─── 21562 minitest-queue worker [0] - UserTest
|
25
|
-
```
|
26
|
-
|
27
|
-
test-queue also has a distributed mode, where additional masters can share
|
28
|
-
the workload and relay results back to a central master.
|
29
|
-
|
30
|
-
## Environment variables
|
31
|
-
|
32
|
-
- `TEST_QUEUE_WORKERS`: number of workers to use per master (default: all available cores)
|
33
|
-
- `TEST_QUEUE_VERBOSE`: show results as they are available (default: `0`)
|
34
|
-
- `TEST_QUEUE_SOCKET`: unix socket `path` (or tcp `address:port` pair) used for communication (default: `/tmp/test_queue_XXXXX.sock`)
|
35
|
-
- `TEST_QUEUE_RELAY`: relay results back to a central master, specified as tcp `address:port`
|
36
|
-
- `TEST_QUEUE_STATS`: `path` to cache build stats in-build CI runs (default: `.test_queue_stats`)
|
37
|
-
- `TEST_QUEUE_FORCE`: comma separated list of suites to run
|
38
|
-
- `TEST_QUEUE_RELAY_TIMEOUT`: when using distributed builds, the amount of time a remote master will try to reconnect to start work
|
39
|
-
- `TEST_QUEUE_RELAY_TOKEN`: when using distributed builds, this must be the same on remote masters and the central master for remote masters to be able to connect.
|
40
|
-
- `TEST_QUEUE_REMOTE_MASTER_MESSAGE`: when using distributed builds, set this on a remote master and it will appear in that master's connection message on the central master.
|
41
|
-
- `TEST_QUEUE_SPLIT_GROUPS`: split tests up by example rather than example group. Faster for tests with short setup time such as selenium. RSpec only. Add the :no_split tag to ExampleGroups you don't want split.
|
42
|
-
|
43
13
|
## Usage
|
44
14
|
|
45
|
-
test-queue bundles `testunit-queue`, `minitest-queue
|
15
|
+
test-queue bundles `testunit-queue`, `minitest-queue`, and `rspec-queue` binaries which can be used directly:
|
46
16
|
|
47
17
|
```console
|
48
18
|
$ minitest-queue $(find test/ -name \*_test.rb)
|
49
19
|
$ rspec-queue --format progress spec
|
50
20
|
```
|
51
21
|
|
52
|
-
But the underlying `TestQueue::Runner::TestUnit`, `TestQueue::Runner::
|
22
|
+
But the underlying `TestQueue::Runner::TestUnit`, `TestQueue::Runner::Minitest`, and `TestQueue::Runner::RSpec` are
|
53
23
|
built to be subclassed by your application. I recommend checking a new
|
54
24
|
executable into your project using one of these superclasses.
|
55
25
|
|
@@ -66,19 +36,19 @@ runner to reset any global state.
|
|
66
36
|
``` ruby
|
67
37
|
#!/usr/bin/env ruby
|
68
38
|
|
69
|
-
class MyAppTestRunner < TestQueue::Runner::
|
39
|
+
class MyAppTestRunner < TestQueue::Runner::Minitest
|
70
40
|
def after_fork(num)
|
71
|
-
#
|
41
|
+
# Use separate mysql database (we assume it exists and has the right schema already)
|
72
42
|
ActiveRecord::Base.configurations.configs_for(env_name: 'test', name: 'primary').database << num.to_s
|
73
43
|
ActiveRecord::Base.establish_connection(:test)
|
74
44
|
|
75
|
-
#
|
45
|
+
# Use separate redis database
|
76
46
|
$redis.client.db = num
|
77
47
|
$redis.client.reconnect
|
78
48
|
end
|
79
49
|
|
80
50
|
def prepare(concurrency)
|
81
|
-
#
|
51
|
+
# Create mysql databases exists with correct schema
|
82
52
|
concurrency.times do |i|
|
83
53
|
# ...
|
84
54
|
end
|
@@ -97,22 +67,52 @@ end
|
|
97
67
|
MyAppTestRunner.new.execute
|
98
68
|
```
|
99
69
|
|
70
|
+
## Environment variables
|
71
|
+
|
72
|
+
- `TEST_QUEUE_WORKERS`: Number of workers to use per master (default: all available cores)
|
73
|
+
- `TEST_QUEUE_VERBOSE`: Show results as they are available (default: `0`)
|
74
|
+
- `TEST_QUEUE_SOCKET`: Unix socket `path` (or TCP `address:port` pair) used for communication (default: `/tmp/test_queue_XXXXX.sock`)
|
75
|
+
- `TEST_QUEUE_RELAY`: Relay results back to a central master, specified as TCP `address:port`
|
76
|
+
- `TEST_QUEUE_STATS`: `path` to cache build stats in-build CI runs (default: `.test_queue_stats`)
|
77
|
+
- `TEST_QUEUE_FORCE`: Comma separated list of suites to run
|
78
|
+
- `TEST_QUEUE_RELAY_TIMEOUT`: When using distributed builds, the amount of time a remote master will try to reconnect to start work
|
79
|
+
- `TEST_QUEUE_RELAY_TOKEN`: When using distributed builds, this must be the same on remote masters and the central master for remote masters to be able to connect.
|
80
|
+
- `TEST_QUEUE_REMOTE_MASTER_MESSAGE`: When using distributed builds, set this on a remote master and it will appear in that master's connection message on the central master.
|
81
|
+
- `TEST_QUEUE_SPLIT_GROUPS`: Split tests up by example rather than example group. Faster for tests with short setup time such as selenium. RSpec only. Add the `:no_split` tag to `ExampleGroups` you don't want split.
|
82
|
+
|
83
|
+
## Design
|
84
|
+
|
85
|
+
test-queue uses a simple master + pre-fork worker model. The master
|
86
|
+
exposes a Unix domain socket server which workers use to grab tests off
|
87
|
+
the queue.
|
88
|
+
|
89
|
+
```console
|
90
|
+
─┬─ 21232 minitest-queue master
|
91
|
+
├─── 21571 minitest-queue worker [3] - AuthenticationTest
|
92
|
+
├─── 21568 minitest-queue worker [2] - ApiTest
|
93
|
+
├─── 21565 minitest-queue worker [1] - UsersControllerTest
|
94
|
+
└─── 21562 minitest-queue worker [0] - UserTest
|
95
|
+
```
|
96
|
+
|
97
|
+
test-queue also has a distributed mode, where additional masters can share
|
98
|
+
the workload and relay results back to a central master.
|
99
|
+
|
100
100
|
## Distributed mode
|
101
101
|
|
102
|
-
To use distributed mode, the central master must listen on a
|
102
|
+
To use distributed mode, the central master must listen on a TCP port. Additional masters can be booted
|
103
103
|
in relay mode to connect to the central master. Remote masters must provide a `TEST_QUEUE_RELAY_TOKEN`
|
104
104
|
to match the central master's.
|
105
105
|
|
106
106
|
```console
|
107
|
-
$ TEST_QUEUE_RELAY_TOKEN=123 TEST_QUEUE_SOCKET=0.0.0.0:12345 bundle exec minitest-queue ./test/
|
108
|
-
$ TEST_QUEUE_RELAY_TOKEN=123 TEST_QUEUE_RELAY=0.0.0.0:12345 bundle exec minitest-queue ./test/
|
107
|
+
$ TEST_QUEUE_RELAY_TOKEN=123 TEST_QUEUE_SOCKET=0.0.0.0:12345 bundle exec minitest-queue ./test/example_test.rb
|
108
|
+
$ TEST_QUEUE_RELAY_TOKEN=123 TEST_QUEUE_RELAY=0.0.0.0:12345 bundle exec minitest-queue ./test/example_test.rb
|
109
109
|
$ TEST_QUEUE_RELAY_TOKEN=123 ./test-multi.sh
|
110
110
|
```
|
111
111
|
|
112
112
|
See the [Parameterized Trigger Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Parameterized+Trigger+Plugin)
|
113
|
-
for a simple way to do this with
|
113
|
+
for a simple way to do this with Jenkins.
|
114
114
|
|
115
115
|
## See also
|
116
116
|
|
117
|
-
|
118
|
-
|
117
|
+
- https://github.com/Shopify/rails_parallel
|
118
|
+
- https://github.com/grosser/parallel_tests
|
data/exe/cucumber-queue
CHANGED
data/exe/minitest-queue
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
|
-
$LOAD_PATH.unshift File.expand_path(
|
4
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __dir__)
|
4
5
|
|
5
6
|
require 'test_queue'
|
6
7
|
require 'test_queue/runner/minitest'
|
7
8
|
|
8
|
-
TestQueue::Runner::
|
9
|
+
TestQueue::Runner::Minitest.new.execute
|
data/exe/rspec-queue
CHANGED
data/exe/testunit-queue
CHANGED
data/lib/test-queue.rb
CHANGED
data/lib/test_queue/iterator.rb
CHANGED
@@ -1,14 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module TestQueue
|
2
4
|
class Iterator
|
5
|
+
include Enumerable
|
6
|
+
|
3
7
|
attr_reader :sock
|
4
8
|
|
5
|
-
def initialize(test_framework, sock, filter=nil, run_token:, early_failure_limit: nil)
|
9
|
+
def initialize(test_framework, sock, filter = nil, run_token:, early_failure_limit: nil)
|
6
10
|
@test_framework = test_framework
|
7
11
|
@done = false
|
8
12
|
@suite_stats = []
|
9
13
|
@sock = sock
|
10
14
|
@filter = filter
|
11
|
-
if @sock =~
|
15
|
+
if @sock =~ /\A(.+):(\d+)\z/
|
12
16
|
@tcp_address = $1
|
13
17
|
@tcp_port = $2.to_i
|
14
18
|
end
|
@@ -18,29 +22,34 @@ module TestQueue
|
|
18
22
|
end
|
19
23
|
|
20
24
|
def each
|
21
|
-
|
25
|
+
raise "already used this iterator. previous caller: #{@done}" if @done
|
22
26
|
|
23
27
|
procline = $0
|
24
28
|
|
25
|
-
|
29
|
+
loop do
|
26
30
|
# If we've hit too many failures in one worker, assume the entire
|
27
31
|
# test suite is broken, and notify master so the run
|
28
32
|
# can be immediately halted.
|
29
33
|
if @early_failure_limit && @failures >= @early_failure_limit
|
30
|
-
connect_to_master(
|
34
|
+
connect_to_master('KABOOM')
|
31
35
|
break
|
32
36
|
else
|
33
37
|
client = connect_to_master("POP #{Socket.gethostname} #{Process.pid}")
|
34
38
|
end
|
35
39
|
break if client.nil?
|
40
|
+
|
41
|
+
# rubocop:disable Lint/IncompatibleIoSelectWithFiberScheduler
|
42
|
+
# This false positive will be resolved by https://github.com/rubocop/rubocop/pull/11830.
|
36
43
|
_r, _w, e = IO.select([client], nil, [client], nil)
|
37
|
-
|
44
|
+
# rubocop:enable Lint/IncompatibleIoSelectWithFiberScheduler
|
45
|
+
break unless e.empty?
|
38
46
|
|
39
|
-
if data = client.read(65536)
|
47
|
+
if (data = client.read(65536))
|
40
48
|
client.close
|
41
49
|
item = Marshal.load(data)
|
42
50
|
break if item.nil? || item.empty?
|
43
|
-
|
51
|
+
|
52
|
+
if item == 'WAIT'
|
44
53
|
$0 = "#{procline} - Waiting for work"
|
45
54
|
sleep 0.1
|
46
55
|
next
|
@@ -54,7 +63,7 @@ module TestQueue
|
|
54
63
|
$0 = "#{procline} - #{suite.respond_to?(:description) ? suite.description : suite}"
|
55
64
|
start = Time.now
|
56
65
|
if @filter
|
57
|
-
@filter.call(suite){ yield suite }
|
66
|
+
@filter.call(suite) { yield suite }
|
58
67
|
else
|
59
68
|
yield suite
|
60
69
|
end
|
@@ -65,10 +74,11 @@ module TestQueue
|
|
65
74
|
end
|
66
75
|
end
|
67
76
|
rescue Errno::ENOENT, Errno::ECONNRESET, Errno::ECONNREFUSED
|
77
|
+
# noop
|
68
78
|
ensure
|
69
79
|
$0 = procline
|
70
|
-
@done = caller.first
|
71
|
-
File.open("/tmp/test_queue_worker_#{$$}_suites",
|
80
|
+
@done = caller(1..1).first
|
81
|
+
File.open("/tmp/test_queue_worker_#{$$}_suites", 'wb') do |f|
|
72
82
|
Marshal.dump(@suite_stats, f)
|
73
83
|
end
|
74
84
|
end
|
@@ -87,8 +97,6 @@ module TestQueue
|
|
87
97
|
nil
|
88
98
|
end
|
89
99
|
|
90
|
-
include Enumerable
|
91
|
-
|
92
100
|
def empty?
|
93
101
|
false
|
94
102
|
end
|
@@ -98,8 +106,8 @@ module TestQueue
|
|
98
106
|
suite = @loaded_suites[suite_name]
|
99
107
|
return suite if suite
|
100
108
|
|
101
|
-
@test_framework.suites_from_file(path).each do |name,
|
102
|
-
@loaded_suites[name] =
|
109
|
+
@test_framework.suites_from_file(path).each do |name, suite_from_file|
|
110
|
+
@loaded_suites[name] = suite_from_file
|
103
111
|
end
|
104
112
|
@loaded_suites[suite_name]
|
105
113
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cucumber'
|
2
4
|
require 'cucumber/rspec/disable_option_parser'
|
3
5
|
require 'cucumber/cli/main'
|
@@ -24,6 +26,7 @@ module Cucumber
|
|
24
26
|
module InjectableFeatures
|
25
27
|
def features
|
26
28
|
return @features if defined?(@features)
|
29
|
+
|
27
30
|
super
|
28
31
|
end
|
29
32
|
|
@@ -1,11 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../../test_queue'
|
2
4
|
require_relative '../runner'
|
3
5
|
|
4
6
|
module TestQueue
|
5
7
|
class Runner
|
6
|
-
class
|
8
|
+
class Example < Runner
|
9
|
+
def initialize(args)
|
10
|
+
super(TestFramework::Example.new(args))
|
11
|
+
end
|
12
|
+
|
7
13
|
def spawn_workers
|
8
|
-
puts "Spawning
|
14
|
+
puts "Spawning #{@concurrency} workers"
|
9
15
|
super
|
10
16
|
end
|
11
17
|
|
@@ -15,24 +21,40 @@ module TestQueue
|
|
15
21
|
end
|
16
22
|
|
17
23
|
def run_worker(iterator)
|
18
|
-
sum
|
19
|
-
iterator.each do |item|
|
24
|
+
iterator.inject(0) do |sum, item|
|
20
25
|
puts " #{item.inspect}"
|
21
|
-
sum
|
26
|
+
sum + item.to_i
|
22
27
|
end
|
23
|
-
sum
|
24
28
|
end
|
25
29
|
|
26
30
|
def summarize_worker(worker)
|
27
|
-
worker.summary
|
31
|
+
worker.summary = worker.output.scan(/^\s*(\d+)/).join(', ')
|
28
32
|
worker.failure_output = ''
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
36
|
+
|
37
|
+
class TestFramework
|
38
|
+
class Example < TestFramework
|
39
|
+
def initialize(args)
|
40
|
+
super()
|
41
|
+
|
42
|
+
@args = args.map(&:to_s)
|
43
|
+
end
|
44
|
+
|
45
|
+
def all_suite_files
|
46
|
+
@args
|
47
|
+
end
|
48
|
+
|
49
|
+
def suites_from_file(_path)
|
50
|
+
@args.map { |i| [i, i] }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
32
54
|
end
|
33
55
|
|
34
56
|
if __FILE__ == $0
|
35
|
-
TestQueue::Runner::
|
57
|
+
TestQueue::Runner::Example.new(Array(1..10)).execute
|
36
58
|
end
|
37
59
|
|
38
60
|
__END__
|
@@ -71,4 +93,3 @@ Spawning 4 workers
|
|
71
93
|
[3] in 0.0036s (pid 40409 exit 0)
|
72
94
|
[2] 3, 6, 9 in 0.0038s (pid 40408 exit 18)
|
73
95
|
[0] 1, 4, 7, 10 in 0.0044s (pid 40406 exit 22)
|
74
|
-
|
@@ -1,17 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
4
|
require 'minitest'
|
3
5
|
require_relative '../runner/minitest5'
|
4
|
-
rescue LoadError
|
6
|
+
rescue LoadError
|
5
7
|
require 'minitest/unit'
|
6
8
|
require_relative '../runner/minitest4'
|
7
9
|
end
|
8
10
|
|
9
11
|
module TestQueue
|
10
12
|
class Runner
|
11
|
-
class
|
13
|
+
class Minitest < Runner
|
12
14
|
def summarize_worker(worker)
|
13
15
|
worker.summary = worker.lines.grep(/, \d+ errors?, /).first
|
14
|
-
failures
|
16
|
+
failures = worker.lines.select { |line|
|
15
17
|
line if (line =~ /^Finished/) ... (line =~ /, \d+ errors?, /)
|
16
18
|
}[1..-2]
|
17
19
|
worker.failure_output = failures.join("\n") if failures
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../runner'
|
2
4
|
require 'set'
|
3
5
|
require 'stringio'
|
@@ -31,11 +33,11 @@ class MiniTestQueueRunner < MiniTest::Unit
|
|
31
33
|
ret = super
|
32
34
|
diff = Time.now - start
|
33
35
|
|
34
|
-
output.puts(
|
36
|
+
output.puts(' <%.3f>' % diff)
|
35
37
|
ret
|
36
38
|
end
|
37
39
|
|
38
|
-
self.runner =
|
40
|
+
self.runner = new
|
39
41
|
self.output = StringIO.new
|
40
42
|
end
|
41
43
|
|
@@ -44,7 +46,7 @@ class MiniTest::Unit::TestCase
|
|
44
46
|
attr_accessor :test_suites
|
45
47
|
|
46
48
|
def original_test_suites
|
47
|
-
@@test_suites.keys.reject{ |s| s.test_methods.empty? }
|
49
|
+
@@test_suites.keys.reject { |s| s.test_methods.empty? }
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
@@ -55,12 +57,13 @@ end
|
|
55
57
|
|
56
58
|
module TestQueue
|
57
59
|
class Runner
|
58
|
-
class
|
60
|
+
class Minitest < Runner
|
59
61
|
def initialize
|
60
62
|
if ::MiniTest::Unit::TestCase.original_test_suites.any?
|
61
|
-
|
63
|
+
raise 'Do not `require` test files. Pass them via ARGV instead and they will be required as needed.'
|
62
64
|
end
|
63
|
-
|
65
|
+
|
66
|
+
super(TestFramework::Minitest.new)
|
64
67
|
end
|
65
68
|
|
66
69
|
def run_worker(iterator)
|
@@ -68,10 +71,11 @@ module TestQueue
|
|
68
71
|
::MiniTest::Unit.new.run
|
69
72
|
end
|
70
73
|
end
|
74
|
+
MiniTest = Minitest # For compatibility with test-queue 0.7.0 and earlier.
|
71
75
|
end
|
72
76
|
|
73
77
|
class TestFramework
|
74
|
-
class
|
78
|
+
class Minitest < TestFramework
|
75
79
|
def all_suite_files
|
76
80
|
ARGV
|
77
81
|
end
|
@@ -84,5 +88,6 @@ module TestQueue
|
|
84
88
|
}
|
85
89
|
end
|
86
90
|
end
|
91
|
+
MiniTest = Minitest # For compatibility with test-queue 0.7.0 and earlier.
|
87
92
|
end
|
88
93
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../runner'
|
2
4
|
|
3
|
-
module
|
4
|
-
def self.__run
|
5
|
+
module Minitest
|
6
|
+
def self.__run(reporter, options)
|
5
7
|
suites = Runnable.runnables
|
6
8
|
suites.map { |suite| suite.run reporter, options }
|
7
9
|
end
|
@@ -13,7 +15,7 @@ module MiniTest
|
|
13
15
|
end
|
14
16
|
|
15
17
|
class Test
|
16
|
-
def self.runnables=
|
18
|
+
def self.runnables=(runnables)
|
17
19
|
@@runnables = runnables
|
18
20
|
end
|
19
21
|
|
@@ -25,17 +27,19 @@ module MiniTest
|
|
25
27
|
# code, there's no way to know which are parallel and which are serial.
|
26
28
|
# Synchronizing serial tests does add some overhead, but hopefully this is
|
27
29
|
# outweighed by the speed benefits of using test-queue.
|
28
|
-
def _synchronize
|
30
|
+
def _synchronize
|
31
|
+
Test.io_lock.synchronize { yield }
|
32
|
+
end
|
29
33
|
end
|
30
34
|
|
31
35
|
class ProgressReporter
|
32
36
|
# Override original method to make test-queue specific output
|
33
|
-
def record
|
37
|
+
def record(result)
|
34
38
|
io.print ' '
|
35
39
|
io.print result.class
|
36
40
|
io.print ': '
|
37
41
|
io.print result.result_code
|
38
|
-
io.puts(
|
42
|
+
io.puts(' <%.3f>' % result.time)
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
@@ -44,51 +48,62 @@ module MiniTest
|
|
44
48
|
|
45
49
|
class << self
|
46
50
|
private
|
47
|
-
|
51
|
+
|
52
|
+
def total_count(_options)
|
48
53
|
0
|
49
54
|
end
|
50
55
|
end
|
51
56
|
rescue LoadError
|
57
|
+
# noop
|
52
58
|
end
|
53
59
|
end
|
54
60
|
|
55
61
|
module TestQueue
|
56
62
|
class Runner
|
57
|
-
class
|
63
|
+
class Minitest < Runner
|
58
64
|
def initialize
|
59
|
-
options = Minitest.process_args ARGV
|
65
|
+
@options = ::Minitest.process_args ARGV
|
60
66
|
|
61
|
-
if Minitest.respond_to?(:seed)
|
62
|
-
Minitest.seed = options[:seed]
|
63
|
-
srand Minitest.seed
|
67
|
+
if ::Minitest.respond_to?(:seed)
|
68
|
+
::Minitest.seed = @options[:seed]
|
69
|
+
srand ::Minitest.seed
|
64
70
|
end
|
65
71
|
|
66
|
-
if ::
|
67
|
-
|
72
|
+
if ::Minitest::Test.runnables.any? { |r| r.runnable_methods.any? }
|
73
|
+
raise 'Do not `require` test files. Pass them via ARGV instead and they will be required as needed.'
|
68
74
|
end
|
69
|
-
|
75
|
+
|
76
|
+
super(TestFramework::Minitest.new)
|
77
|
+
end
|
78
|
+
|
79
|
+
def start_master
|
80
|
+
puts "Run options: #{@options[:args]}\n\n"
|
81
|
+
|
82
|
+
super
|
70
83
|
end
|
71
84
|
|
72
85
|
def run_worker(iterator)
|
73
|
-
::
|
74
|
-
::
|
86
|
+
::Minitest::Test.runnables = iterator
|
87
|
+
::Minitest.run ? 0 : 1
|
75
88
|
end
|
76
89
|
end
|
90
|
+
MiniTest = Minitest # For compatibility with test-queue 0.7.0 and earlier.
|
77
91
|
end
|
78
92
|
|
79
93
|
class TestFramework
|
80
|
-
class
|
94
|
+
class Minitest < TestFramework
|
81
95
|
def all_suite_files
|
82
96
|
ARGV
|
83
97
|
end
|
84
98
|
|
85
99
|
def suites_from_file(path)
|
86
|
-
::
|
100
|
+
::Minitest::Test.reset
|
87
101
|
require File.absolute_path(path)
|
88
|
-
::
|
89
|
-
|
90
|
-
|
102
|
+
::Minitest::Test.runnables
|
103
|
+
.reject { |s| s.runnable_methods.empty? }
|
104
|
+
.map { |s| [s.name, s] }
|
91
105
|
end
|
92
106
|
end
|
107
|
+
MiniTest = Minitest # For compatibility with test-queue 0.7.0 and earlier.
|
93
108
|
end
|
94
109
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../../test_queue'
|
2
4
|
require 'puppet-lint'
|
3
5
|
|
@@ -6,7 +8,7 @@ module TestQueue
|
|
6
8
|
class PuppetLint < Runner
|
7
9
|
def run_worker(iterator)
|
8
10
|
errors = 0
|
9
|
-
linter =
|
11
|
+
linter = PuppetLint.new
|
10
12
|
iterator.each do |file|
|
11
13
|
puts "Evaluating #{file}"
|
12
14
|
linter.file = file
|
@@ -19,9 +21,9 @@ module TestQueue
|
|
19
21
|
def summarize_worker(worker)
|
20
22
|
lines = worker.lines
|
21
23
|
|
22
|
-
files = lines.
|
23
|
-
errors = lines.
|
24
|
-
warnings = lines.
|
24
|
+
files = lines.grep(/^Evaluating/)
|
25
|
+
errors = lines.grep(/^ERROR/)
|
26
|
+
warnings = lines.grep(/^WARNING/)
|
25
27
|
|
26
28
|
worker.summary = "#{files.size} files, #{warnings.size} warnings, #{errors.size} errors"
|
27
29
|
worker.failure_output = errors.join("\n")
|
@@ -1,13 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../runner'
|
2
4
|
require 'rspec/core'
|
3
5
|
|
4
|
-
case
|
6
|
+
case RSpec::Core::Version::STRING.to_i
|
5
7
|
when 2
|
6
8
|
require_relative 'rspec2'
|
7
|
-
when 3
|
9
|
+
when 3, 4
|
8
10
|
require_relative 'rspec3'
|
9
11
|
else
|
10
|
-
|
12
|
+
raise 'requires rspec version 2, 3, or 4'
|
11
13
|
end
|
12
14
|
|
13
15
|
module TestQueue
|
@@ -23,7 +25,7 @@ module TestQueue
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def summarize_worker(worker)
|
26
|
-
worker.summary
|
28
|
+
worker.summary = worker.lines.grep(/ examples?, /).first
|
27
29
|
worker.failure_output = worker.output[/^Failures:\n\n(.*)\n^Finished/m, 1]
|
28
30
|
end
|
29
31
|
end
|
@@ -31,6 +33,14 @@ module TestQueue
|
|
31
33
|
|
32
34
|
class TestFramework
|
33
35
|
class RSpec < TestFramework
|
36
|
+
begin
|
37
|
+
require 'turnip/rspec'
|
38
|
+
|
39
|
+
include Turnip::RSpec::Loader
|
40
|
+
rescue LoadError
|
41
|
+
# noop
|
42
|
+
end
|
43
|
+
|
34
44
|
def all_suite_files
|
35
45
|
options = ::RSpec::Core::ConfigurationOptions.new(ARGV)
|
36
46
|
options.parse_options if options.respond_to?(:parse_options)
|
@@ -77,6 +87,7 @@ module TestQueue
|
|
77
87
|
|
78
88
|
def split_groups?
|
79
89
|
return @split_groups if defined?(@split_groups)
|
90
|
+
|
80
91
|
@split_groups = ENV['TEST_QUEUE_SPLIT_GROUPS'] && ENV['TEST_QUEUE_SPLIT_GROUPS'].strip.downcase == 'true'
|
81
92
|
end
|
82
93
|
end
|