test-queue-split 0.3.0

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