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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile-minitest4 +3 -0
  4. data/Gemfile-minitest4.lock +38 -0
  5. data/Gemfile-rspec3-0 +3 -0
  6. data/Gemfile-rspec3-0.lock +40 -0
  7. data/Gemfile-rspec3-1 +3 -0
  8. data/Gemfile-rspec3-1.lock +40 -0
  9. data/Gemfile-rspec3-2 +3 -0
  10. data/Gemfile-rspec3-2.lock +41 -0
  11. data/Gemfile-testunit +3 -0
  12. data/Gemfile-testunit.lock +44 -0
  13. data/Gemfile.lock +54 -0
  14. data/README.md +114 -0
  15. data/Thorfile +9 -0
  16. data/bin/cucumber-queue +4 -0
  17. data/bin/minitest-queue +5 -0
  18. data/bin/rspec-queue +4 -0
  19. data/bin/testunit-queue +5 -0
  20. data/features/bad.feature +5 -0
  21. data/features/sample.feature +25 -0
  22. data/features/sample2.feature +29 -0
  23. data/features/step_definitions/common.rb +15 -0
  24. data/lib/test-queue.rb +1 -0
  25. data/lib/test_queue/iterator.rb +72 -0
  26. data/lib/test_queue/runner/cucumber.rb +46 -0
  27. data/lib/test_queue/runner/minitest.rb +25 -0
  28. data/lib/test_queue/runner/minitest4.rb +65 -0
  29. data/lib/test_queue/runner/minitest5.rb +62 -0
  30. data/lib/test_queue/runner/puppet_lint.rb +31 -0
  31. data/lib/test_queue/runner/rspec.rb +35 -0
  32. data/lib/test_queue/runner/rspec2.rb +35 -0
  33. data/lib/test_queue/runner/rspec3.rb +45 -0
  34. data/lib/test_queue/runner/sample.rb +76 -0
  35. data/lib/test_queue/runner/testunit.rb +56 -0
  36. data/lib/test_queue/runner.rb +395 -0
  37. data/lib/test_queue/version.rb +4 -0
  38. data/lib/test_queue.rb +8 -0
  39. data/test/sample_minispec.rb +31 -0
  40. data/test/sample_minitest4.rb +23 -0
  41. data/test/sample_minitest5.rb +23 -0
  42. data/test/sample_spec.rb +23 -0
  43. data/test/sample_testunit.rb +23 -0
  44. data/test-multi.sh +8 -0
  45. data/test-queue-split.gemspec +28 -0
  46. data/test.sh +23 -0
  47. 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