test-queue-split 0.3.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 +7 -0
- data/Gemfile +3 -0
- data/Gemfile-minitest4 +3 -0
- data/Gemfile-minitest4.lock +38 -0
- data/Gemfile-rspec3-0 +3 -0
- data/Gemfile-rspec3-0.lock +40 -0
- data/Gemfile-rspec3-1 +3 -0
- data/Gemfile-rspec3-1.lock +40 -0
- data/Gemfile-rspec3-2 +3 -0
- data/Gemfile-rspec3-2.lock +41 -0
- data/Gemfile-testunit +3 -0
- data/Gemfile-testunit.lock +44 -0
- data/Gemfile.lock +54 -0
- data/README.md +114 -0
- data/Thorfile +9 -0
- data/bin/cucumber-queue +4 -0
- data/bin/minitest-queue +5 -0
- data/bin/rspec-queue +4 -0
- data/bin/testunit-queue +5 -0
- data/features/bad.feature +5 -0
- data/features/sample.feature +25 -0
- data/features/sample2.feature +29 -0
- data/features/step_definitions/common.rb +15 -0
- data/lib/test-queue.rb +1 -0
- data/lib/test_queue/iterator.rb +72 -0
- data/lib/test_queue/runner/cucumber.rb +46 -0
- data/lib/test_queue/runner/minitest.rb +25 -0
- data/lib/test_queue/runner/minitest4.rb +65 -0
- data/lib/test_queue/runner/minitest5.rb +62 -0
- data/lib/test_queue/runner/puppet_lint.rb +31 -0
- data/lib/test_queue/runner/rspec.rb +35 -0
- data/lib/test_queue/runner/rspec2.rb +35 -0
- data/lib/test_queue/runner/rspec3.rb +45 -0
- data/lib/test_queue/runner/sample.rb +76 -0
- data/lib/test_queue/runner/testunit.rb +56 -0
- data/lib/test_queue/runner.rb +395 -0
- data/lib/test_queue/version.rb +4 -0
- data/lib/test_queue.rb +8 -0
- data/test/sample_minispec.rb +31 -0
- data/test/sample_minitest4.rb +23 -0
- data/test/sample_minitest5.rb +23 -0
- data/test/sample_spec.rb +23 -0
- data/test/sample_testunit.rb +23 -0
- data/test-multi.sh +8 -0
- data/test-queue-split.gemspec +28 -0
- data/test.sh +23 -0
- metadata +141 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'test_queue/runner'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
class MiniTestQueueRunner < MiniTest::Unit
|
5
|
+
def _run_suites(suites, type)
|
6
|
+
self.class.output = $stdout
|
7
|
+
|
8
|
+
if defined?(ParallelEach)
|
9
|
+
# Ignore its _run_suites implementation since we don't handle it gracefully.
|
10
|
+
# If we don't do this #partition is called on the iterator and all suites
|
11
|
+
# distributed immediately, instead of picked up as workers are available.
|
12
|
+
suites.map { |suite| _run_suite suite, type }
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def _run_anything(*)
|
19
|
+
ret = super
|
20
|
+
output.puts
|
21
|
+
ret
|
22
|
+
end
|
23
|
+
|
24
|
+
def _run_suite(suite, type)
|
25
|
+
output.print ' '
|
26
|
+
output.print suite
|
27
|
+
output.print ': '
|
28
|
+
|
29
|
+
start = Time.now
|
30
|
+
ret = super
|
31
|
+
diff = Time.now - start
|
32
|
+
|
33
|
+
output.puts(" <%.3f>" % diff)
|
34
|
+
ret
|
35
|
+
end
|
36
|
+
|
37
|
+
self.runner = self.new
|
38
|
+
self.output = StringIO.new
|
39
|
+
end
|
40
|
+
|
41
|
+
class MiniTest::Unit::TestCase
|
42
|
+
class << self
|
43
|
+
attr_accessor :test_suites
|
44
|
+
|
45
|
+
def original_test_suites
|
46
|
+
@@test_suites.keys.reject{ |s| s.test_methods.empty? }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
module TestQueue
|
52
|
+
class Runner
|
53
|
+
class MiniTest < Runner
|
54
|
+
def initialize
|
55
|
+
tests = ::MiniTest::Unit::TestCase.original_test_suites.sort_by{ |s| -(stats[s.to_s] || 0) }
|
56
|
+
super(tests)
|
57
|
+
end
|
58
|
+
|
59
|
+
def run_worker(iterator)
|
60
|
+
::MiniTest::Unit::TestCase.test_suites = iterator
|
61
|
+
::MiniTest::Unit.new.run
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'test_queue/runner'
|
2
|
+
|
3
|
+
module MiniTest
|
4
|
+
def self.__run reporter, options
|
5
|
+
suites = Runnable.runnables
|
6
|
+
|
7
|
+
# Run the serial tests first after they complete, run the parallels tests
|
8
|
+
# We already sort suites based on its test_order at TestQueue::Runner::Minitest#initialize.
|
9
|
+
suites.map { |suite| suite.run reporter, options }
|
10
|
+
end
|
11
|
+
|
12
|
+
class Test
|
13
|
+
def self.runnables= runnables
|
14
|
+
@@runnables = runnables
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class ProgressReporter
|
19
|
+
# Override original method to make test-queue specific output
|
20
|
+
def record result
|
21
|
+
io.print ' '
|
22
|
+
io.print result.class
|
23
|
+
io.print ': '
|
24
|
+
io.print result.result_code
|
25
|
+
io.puts(" <%.3f>" % result.time)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'minitest/minitest_reporter_plugin'
|
31
|
+
|
32
|
+
class << self
|
33
|
+
private
|
34
|
+
def total_count(options)
|
35
|
+
0
|
36
|
+
end
|
37
|
+
end
|
38
|
+
rescue LoadError
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module TestQueue
|
43
|
+
class Runner
|
44
|
+
class MiniTest < Runner
|
45
|
+
def initialize
|
46
|
+
tests = ::MiniTest::Test.runnables.reject { |s|
|
47
|
+
s.runnable_methods.empty?
|
48
|
+
}.sort_by { |s|
|
49
|
+
-(stats[s.to_s] || 0)
|
50
|
+
}.partition { |s|
|
51
|
+
s.test_order == :parallel
|
52
|
+
}.reverse.flatten
|
53
|
+
super(tests)
|
54
|
+
end
|
55
|
+
|
56
|
+
def run_worker(iterator)
|
57
|
+
::MiniTest::Test.runnables = iterator
|
58
|
+
::MiniTest.run ? 0 : 1
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test_queue'
|
2
|
+
require 'puppet-lint'
|
3
|
+
|
4
|
+
module TestQueue
|
5
|
+
class Runner
|
6
|
+
class PuppetLint < Runner
|
7
|
+
def run_worker(iterator)
|
8
|
+
errors = 0
|
9
|
+
linter = PuppetLint.new
|
10
|
+
iterator.each do |file|
|
11
|
+
puts "Evaluating #{file}"
|
12
|
+
linter.file = file
|
13
|
+
linter.run
|
14
|
+
errors += 1 if linter.errors?
|
15
|
+
end
|
16
|
+
errors
|
17
|
+
end
|
18
|
+
|
19
|
+
def summarize_worker(worker)
|
20
|
+
lines = worker.lines
|
21
|
+
|
22
|
+
files = lines.select{ |line| line =~ /^Evaluating/ }
|
23
|
+
errors = lines.select{ |line| line =~ /^ERROR/ }
|
24
|
+
warnings = lines.select{ |line| line =~ /^WARNING/ }
|
25
|
+
|
26
|
+
worker.summary = "#{files.size} files, #{warnings.size} warnings, #{errors.size} errors"
|
27
|
+
worker.failure_output = errors.join("\n")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test_queue/runner'
|
2
|
+
require 'rspec/core'
|
3
|
+
|
4
|
+
case ::RSpec::Core::Version::STRING.to_i
|
5
|
+
when 2
|
6
|
+
require_relative 'rspec2'
|
7
|
+
when 3
|
8
|
+
require_relative 'rspec3'
|
9
|
+
else
|
10
|
+
fail 'requires rspec version 2 or 3'
|
11
|
+
end
|
12
|
+
|
13
|
+
module TestQueue
|
14
|
+
class Runner
|
15
|
+
class RSpec < Runner
|
16
|
+
def initialize
|
17
|
+
@rspec = ::RSpec::Core::QueueRunner.new
|
18
|
+
super(@rspec.example_groups.sort_by{ |s| -(stats[s.to_s] || 0) })
|
19
|
+
end
|
20
|
+
|
21
|
+
def run_worker(iterator)
|
22
|
+
@rspec.run_each(iterator).to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
def summarize_worker(worker)
|
26
|
+
worker.stats.each do |s, val|
|
27
|
+
stats[s] = val
|
28
|
+
end
|
29
|
+
|
30
|
+
worker.summary = worker.lines.grep(/ examples?, /).first
|
31
|
+
worker.failure_output = worker.output[/^Failures:\n\n(.*)\n^Finished/m, 1]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module RSpec::Core
|
2
|
+
class QueueRunner < CommandLine
|
3
|
+
def initialize
|
4
|
+
super(ARGV)
|
5
|
+
@configuration.output_stream = $stdout
|
6
|
+
@configuration.error_stream = $stderr
|
7
|
+
end
|
8
|
+
|
9
|
+
def example_groups
|
10
|
+
@options.configure(@configuration)
|
11
|
+
@configuration.load_spec_files
|
12
|
+
@world.announce_filters
|
13
|
+
@world.example_groups
|
14
|
+
end
|
15
|
+
|
16
|
+
def run_each(iterator)
|
17
|
+
@configuration.reporter.report(0, @configuration.randomize? ? @configuration.seed : nil) do |reporter|
|
18
|
+
begin
|
19
|
+
@configuration.run_hook(:before, :suite)
|
20
|
+
iterator.map {|g|
|
21
|
+
print " #{g.description}: "
|
22
|
+
start = Time.now
|
23
|
+
ret = g.run(reporter)
|
24
|
+
diff = Time.now-start
|
25
|
+
puts(" <%.3f>" % diff)
|
26
|
+
|
27
|
+
ret
|
28
|
+
}.all? ? 0 : @configuration.failure_exit_code
|
29
|
+
ensure
|
30
|
+
@configuration.run_hook(:after, :suite)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module RSpec::Core
|
2
|
+
# RSpec 3.2 introduced:
|
3
|
+
unless Configuration.method_defined?(:with_suite_hooks)
|
4
|
+
class Configuration
|
5
|
+
def with_suite_hooks
|
6
|
+
begin
|
7
|
+
hook_context = SuiteHookContext.new
|
8
|
+
hooks.run(:before, :suite, hook_context)
|
9
|
+
yield
|
10
|
+
ensure
|
11
|
+
hooks.run(:after, :suite, hook_context)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class QueueRunner < Runner
|
18
|
+
def initialize
|
19
|
+
options = ConfigurationOptions.new(ARGV)
|
20
|
+
super(options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def example_groups
|
24
|
+
setup($stderr, $stdout)
|
25
|
+
@world.ordered_example_groups
|
26
|
+
end
|
27
|
+
|
28
|
+
def run_specs(iterator)
|
29
|
+
@configuration.reporter.report(@world.ordered_example_groups.count) do |reporter|
|
30
|
+
@configuration.with_suite_hooks do
|
31
|
+
iterator.map { |g|
|
32
|
+
print " #{g.description}: "
|
33
|
+
start = Time.now
|
34
|
+
ret = g.run(reporter)
|
35
|
+
diff = Time.now-start
|
36
|
+
puts(" <%.3f>" % diff)
|
37
|
+
|
38
|
+
ret
|
39
|
+
}.all? ? 0 : @configuration.failure_exit_code
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
alias_method :run_each, :run_specs
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'test_queue'
|
2
|
+
require 'test_queue/runner'
|
3
|
+
|
4
|
+
module TestQueue
|
5
|
+
class Runner
|
6
|
+
class Sample < Runner
|
7
|
+
def spawn_workers
|
8
|
+
puts "Spawning #@concurrency workers"
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def after_fork(num)
|
13
|
+
puts " -- worker #{num} booted as pid #{$$}"
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def run_worker(iterator)
|
18
|
+
sum = 0
|
19
|
+
iterator.each do |item|
|
20
|
+
puts " #{item.inspect}"
|
21
|
+
sum += item
|
22
|
+
end
|
23
|
+
sum
|
24
|
+
end
|
25
|
+
|
26
|
+
def summarize_worker(worker)
|
27
|
+
stats.update(worker.stats)
|
28
|
+
|
29
|
+
worker.summary = worker.output.scan(/^\s*(\d+)/).join(', ')
|
30
|
+
worker.failure_output = ''
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
if __FILE__ == $0
|
37
|
+
TestQueue::Runner::Sample.new(Array(1..10)).execute
|
38
|
+
end
|
39
|
+
|
40
|
+
__END__
|
41
|
+
|
42
|
+
Spawning 4 workers
|
43
|
+
-- worker 0 booted as pid 40406
|
44
|
+
-- worker 1 booted as pid 40407
|
45
|
+
-- worker 2 booted as pid 40408
|
46
|
+
-- worker 3 booted as pid 40409
|
47
|
+
|
48
|
+
==> Starting ruby test-queue worker [1] (40407)
|
49
|
+
|
50
|
+
2
|
51
|
+
5
|
52
|
+
8
|
53
|
+
|
54
|
+
==> Starting ruby test-queue worker [3] (40409)
|
55
|
+
|
56
|
+
|
57
|
+
==> Starting ruby test-queue worker [2] (40408)
|
58
|
+
|
59
|
+
3
|
60
|
+
6
|
61
|
+
9
|
62
|
+
|
63
|
+
==> Starting ruby test-queue worker [0] (40406)
|
64
|
+
|
65
|
+
1
|
66
|
+
4
|
67
|
+
7
|
68
|
+
10
|
69
|
+
|
70
|
+
==> Summary
|
71
|
+
|
72
|
+
[1] 2, 5, 8 in 0.0024s (pid 40407 exit 15)
|
73
|
+
[3] in 0.0036s (pid 40409 exit 0)
|
74
|
+
[2] 3, 6, 9 in 0.0038s (pid 40408 exit 18)
|
75
|
+
[0] 1, 4, 7, 10 in 0.0044s (pid 40406 exit 22)
|
76
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'test_queue/runner'
|
2
|
+
|
3
|
+
gem 'test-unit'
|
4
|
+
require 'test/unit'
|
5
|
+
require 'test/unit/collector/descendant'
|
6
|
+
require 'test/unit/testresult'
|
7
|
+
require 'test/unit/testsuite'
|
8
|
+
require 'test/unit/ui/console/testrunner'
|
9
|
+
|
10
|
+
class Test::Unit::TestSuite
|
11
|
+
attr_accessor :iterator
|
12
|
+
|
13
|
+
def run(result, &progress_block)
|
14
|
+
@start_time = Time.now
|
15
|
+
yield(STARTED, name)
|
16
|
+
yield(STARTED_OBJECT, self)
|
17
|
+
run_startup(result)
|
18
|
+
(@iterator || @tests).each do |test|
|
19
|
+
@n_tests += test.size
|
20
|
+
run_test(test, result, &progress_block)
|
21
|
+
@passed = false unless test.passed?
|
22
|
+
end
|
23
|
+
run_shutdown(result)
|
24
|
+
ensure
|
25
|
+
@elapsed_time = Time.now - @start_time
|
26
|
+
yield(FINISHED, name)
|
27
|
+
yield(FINISHED_OBJECT, self)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module TestQueue
|
32
|
+
class Runner
|
33
|
+
class TestUnit < Runner
|
34
|
+
def initialize
|
35
|
+
@suite = Test::Unit::Collector::Descendant.new.collect
|
36
|
+
tests = @suite.tests.sort_by{ |s| -(stats[s.to_s] || 0) }
|
37
|
+
super(tests)
|
38
|
+
end
|
39
|
+
|
40
|
+
def run_worker(iterator)
|
41
|
+
@suite.iterator = iterator
|
42
|
+
res = Test::Unit::UI::Console::TestRunner.new(@suite).start
|
43
|
+
res.run_count - res.pass_count
|
44
|
+
end
|
45
|
+
|
46
|
+
def summarize_worker(worker)
|
47
|
+
worker.stats.each do |s, val|
|
48
|
+
stats[s.to_s] = val
|
49
|
+
end
|
50
|
+
|
51
|
+
worker.summary = worker.output.split("\n").grep(/^\d+ tests?/).first
|
52
|
+
worker.failure_output = worker.output.scan(/^Failure:\n(.*)\n=======================*/m).join("\n")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|