test-queue 0.2.9 → 0.2.10

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.
data/Gemfile CHANGED
@@ -1,2 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
+ gem 'minitest', '5.3.3'
data/Gemfile-minitest4 ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+ gem 'minitest', '4.7.3'
@@ -0,0 +1,38 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ test-queue (0.2.9)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ builder (3.2.2)
10
+ cucumber (1.3.15)
11
+ builder (>= 2.1.2)
12
+ diff-lcs (>= 1.1.3)
13
+ gherkin (~> 2.12)
14
+ multi_json (>= 1.7.5, < 2.0)
15
+ multi_test (>= 0.1.1)
16
+ diff-lcs (1.2.5)
17
+ gherkin (2.12.2)
18
+ multi_json (~> 1.3)
19
+ minitest (4.7.3)
20
+ multi_json (1.10.1)
21
+ multi_test (0.1.1)
22
+ rspec (2.99.0)
23
+ rspec-core (~> 2.99.0)
24
+ rspec-expectations (~> 2.99.0)
25
+ rspec-mocks (~> 2.99.0)
26
+ rspec-core (2.99.1)
27
+ rspec-expectations (2.99.1)
28
+ diff-lcs (>= 1.1.3, < 2.0)
29
+ rspec-mocks (2.99.1)
30
+
31
+ PLATFORMS
32
+ ruby
33
+
34
+ DEPENDENCIES
35
+ cucumber (~> 1.3.10)
36
+ minitest (= 4.7.3)
37
+ rspec (>= 2.13, < 4.0)
38
+ test-queue!
data/Gemfile.lock CHANGED
@@ -16,7 +16,7 @@ GEM
16
16
  diff-lcs (1.2.4)
17
17
  gherkin (2.12.2)
18
18
  multi_json (~> 1.3)
19
- minitest (4.7.3)
19
+ minitest (5.3.3)
20
20
  multi_json (1.8.4)
21
21
  multi_test (0.0.3)
22
22
  rspec (2.13.0)
@@ -33,6 +33,6 @@ PLATFORMS
33
33
 
34
34
  DEPENDENCIES
35
35
  cucumber (~> 1.3.10)
36
- minitest (~> 4.7.3)
37
- rspec (~> 2.13)
36
+ minitest (= 5.3.3)
37
+ rspec (>= 2.13, < 4.0)
38
38
  test-queue!
data/README.md CHANGED
@@ -32,6 +32,9 @@ the workload and relay results back to a central master.
32
32
  - `TEST_QUEUE_RELAY`: relay results back to a central master, specified as tcp `address:port`
33
33
  - `TEST_QUEUE_STATS`: `path` to cache build stats in-build CI runs (default: `.test_queue_stats`)
34
34
  - `TEST_QUEUE_FORCE`: comma separated list of suites to run
35
+ - `TEST_QUEUE_RELAY_TIMEOUT`: when using remote workers, the amount of time a worker will try to reconnect to start work
36
+ - `TEST_QUEUE_RELAY_TOKEN`: when using remote workers, this must be the same on both workers and the server for remote workers to run tests.
37
+ - `TEST_QUEUE_SLAVE_MESSAGE`: when using remote workers, set this on a slave worker and it will appear on the slave's connection message on the master.
35
38
 
36
39
  ### usage
37
40
 
@@ -75,6 +78,9 @@ class MyAppTestRunner < TestQueue::Runner::MiniTest
75
78
  concurrency.times do |i|
76
79
  # ...
77
80
  end
81
+
82
+ # If this is a remote slave, tell the master something about us
83
+ @slave_message = "Output for slave 123: http://myhost.com/build/123"
78
84
  end
79
85
 
80
86
  def around_filter(suite)
@@ -90,11 +96,13 @@ CustomMiniTestRunner.new.execute
90
96
  ### distributed mode
91
97
 
92
98
  To use distributed mode, the central master must listen on a tcp port. Additional masters can be booted
93
- in relay mode to connect to the central master.
99
+ in relay mode to connect to the central master. Workers must provide a TEST_QUEUE_RELAY_TOKEN to match
100
+ the master's.
94
101
 
95
102
  ```
96
- $ TEST_QUEUE_SOCKET=0.0.0.0:12345 bundle exec minitest-queue ./test/sample_test.rb
97
- $ TEST_QUEUE_RELAY=0.0.0.0:12345 bundle exec minitest-queue ./test/sample_test.rb
103
+ $ TEST_QUEUE_RELAY_TOKEN=123 TEST_QUEUE_SOCKET=0.0.0.0:12345 bundle exec minitest-queue ./test/sample_test.rb
104
+ $ TEST_QUEUE_RELAY_TOKEN=123 TEST_QUEUE_RELAY=0.0.0.0:12345 bundle exec minitest-queue ./test/sample_test.rb
105
+ $ TEST_QUEUE_RELAY_TOKEN=123 ./test-multi.sh
98
106
  ```
99
107
 
100
108
  See the [Parameterized Trigger Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Parameterized+Trigger+Plugin)
@@ -16,7 +16,7 @@ module TestQueue
16
16
  end
17
17
 
18
18
  def each
19
- fail 'already used this iterator' if @done
19
+ fail "already used this iterator. previous caller: #@done" if @done
20
20
 
21
21
  while true
22
22
  client = connect_to_master('POP')
@@ -44,7 +44,7 @@ module TestQueue
44
44
  end
45
45
  rescue Errno::ENOENT, Errno::ECONNRESET, Errno::ECONNREFUSED
46
46
  ensure
47
- @done = true
47
+ @done = caller.first
48
48
  File.open("/tmp/test_queue_worker_#{$$}_stats", "wb") do |f|
49
49
  f.write Marshal.dump(@stats)
50
50
  end
@@ -1,10 +1,12 @@
1
1
  require 'socket'
2
2
  require 'fileutils'
3
+ require 'securerandom'
3
4
 
4
5
  module TestQueue
5
6
  class Worker
6
7
  attr_accessor :pid, :status, :output, :stats, :num, :host
7
8
  attr_accessor :start_time, :end_time
9
+ attr_accessor :summary, :failure_output
8
10
 
9
11
  def initialize(pid, num)
10
12
  @pid = pid
@@ -50,6 +52,12 @@ module TestQueue
50
52
  2
51
53
  end
52
54
 
55
+ @slave_connection_timeout =
56
+ (ENV['TEST_QUEUE_RELAY_TIMEOUT'] && ENV['TEST_QUEUE_RELAY_TIMEOUT'].to_i) ||
57
+ 30
58
+
59
+ @run_token = ENV['TEST_QUEUE_RELAY_TOKEN'] || SecureRandom.hex(8)
60
+
53
61
  @socket =
54
62
  socket ||
55
63
  ENV['TEST_QUEUE_SOCKET'] ||
@@ -59,6 +67,8 @@ module TestQueue
59
67
  relay ||
60
68
  ENV['TEST_QUEUE_RELAY']
61
69
 
70
+ @slave_message = ENV["TEST_QUEUE_SLAVE_MESSAGE"] if ENV.has_key?("TEST_QUEUE_SLAVE_MESSAGE")
71
+
62
72
  if @relay == @socket
63
73
  STDERR.puts "*** Detected TEST_QUEUE_RELAY == TEST_QUEUE_SOCKET. Disabling relay mode."
64
74
  @relay = nil
@@ -94,12 +104,12 @@ module TestQueue
94
104
 
95
105
  @failures = ''
96
106
  @completed.each do |worker|
97
- summary, failures = summarize_worker(worker)
98
- @failures << failures if failures
107
+ summarize_worker(worker)
108
+ @failures << worker.failure_output if worker.failure_output
99
109
 
100
110
  puts " [%2d] %60s %4d suites in %.4fs (pid %d exit %d%s)" % [
101
111
  worker.num,
102
- summary,
112
+ worker.summary,
103
113
  worker.stats.size,
104
114
  worker.end_time - worker.start_time,
105
115
  worker.pid,
@@ -183,7 +193,15 @@ module TestQueue
183
193
  return unless relay?
184
194
 
185
195
  sock = connect_to_relay
186
- sock.puts("SLAVE #{@concurrency} #{Socket.gethostname}")
196
+ message = " #{@slave_message}" if @slave_message
197
+ message.gsub!(/(\r|\n)/, "") # Our "protocol" is newline-separated
198
+ sock.puts("SLAVE #{@concurrency} #{Socket.gethostname} #{@run_token}#{message}")
199
+ response = sock.gets.strip
200
+ unless response == "OK"
201
+ STDERR.puts "*** Got non-OK response from master: #{response}"
202
+ sock.close
203
+ exit! 1
204
+ end
187
205
  sock.close
188
206
  rescue Errno::ECONNREFUSED
189
207
  STDERR.puts "*** Unable to connect to relay #{@relay}. Aborting.."
@@ -209,7 +227,7 @@ module TestQueue
209
227
  after_fork_internal(num, iterator)
210
228
  ret = run_worker(iterator) || 0
211
229
  cleanup_worker
212
- exit! ret
230
+ Kernel.exit! ret
213
231
  end
214
232
 
215
233
  @workers[pid] = Worker.new(pid, num)
@@ -233,6 +251,9 @@ module TestQueue
233
251
  after_fork(num)
234
252
  end
235
253
 
254
+ # Run in the master before the fork. Used to create
255
+ # concurrency copies of any databases required by the
256
+ # test workers.
236
257
  def prepare(concurrency)
237
258
  end
238
259
 
@@ -240,9 +261,15 @@ module TestQueue
240
261
  yield
241
262
  end
242
263
 
264
+ # Prepare a worker for executing jobs after a fork.
243
265
  def after_fork(num)
244
266
  end
245
267
 
268
+ # Entry point for internal runner implementations. The iterator will yield
269
+ # jobs from the shared queue on the master.
270
+ #
271
+ # Returns nothing. exits 0 on success.
272
+ # exits N on error, where N is the number of failures.
246
273
  def run_worker(iterator)
247
274
  iterator.each do |item|
248
275
  puts " #{item.inspect}"
@@ -255,10 +282,8 @@ module TestQueue
255
282
  end
256
283
 
257
284
  def summarize_worker(worker)
258
- num_tests = ''
259
- failures = ''
260
-
261
- [ num_tests, failures ]
285
+ worker.summary = ''
286
+ worker.failure_output = ''
262
287
  end
263
288
 
264
289
  def reap_worker(blocking=true)
@@ -297,16 +322,28 @@ module TestQueue
297
322
  sock = @server.accept
298
323
  cmd = sock.gets.strip
299
324
  case cmd
300
- when 'POP'
325
+ when /^POP/
326
+ # If we have a slave from a different test run, don't respond, and it will consider the test run done.
301
327
  if obj = @queue.shift
302
328
  data = Marshal.dump(obj.to_s)
303
329
  sock.write(data)
304
330
  end
305
- when /^SLAVE (\d+) ([\w\.-]+)/
331
+ when /^SLAVE (\d+) ([\w\.-]+) (\w+)(?: (.+))?/
306
332
  num = $1.to_i
307
333
  slave = $2
308
- remote_workers += num
309
- STDERR.puts "*** #{num} workers connected from #{slave} after #{Time.now-@start_time}s"
334
+ run_token = $3
335
+ slave_message = $4
336
+ if run_token == @run_token
337
+ # If we have a slave from a different test run, don't respond, and it will consider the test run done.
338
+ sock.write("OK\n")
339
+ remote_workers += num
340
+ else
341
+ STDERR.puts "*** Worker from run #{run_token} connected to master for run #{@run_token}; ignoring."
342
+ sock.write("WRONG RUN\n")
343
+ end
344
+ message = "*** #{num} workers connected from #{slave} after #{Time.now-@start_time}s"
345
+ message << " " + slave_message if slave_message
346
+ STDERR.puts message
310
347
  when /^WORKER (\d+)/
311
348
  data = sock.read($1.to_i)
312
349
  worker = Marshal.load(data)
@@ -329,7 +366,19 @@ module TestQueue
329
366
  end
330
367
 
331
368
  def connect_to_relay
332
- TCPSocket.new(*@relay.split(':'))
369
+ sock = nil
370
+ start = Time.now
371
+ puts "Attempting to connect for #{@slave_connection_timeout}s..."
372
+ while sock.nil?
373
+ begin
374
+ sock = TCPSocket.new(*@relay.split(':'))
375
+ rescue Errno::ECONNREFUSED => e
376
+ raise e if Time.now - start > @slave_connection_timeout
377
+ puts "Master not yet available, sleeping..."
378
+ sleep 0.5
379
+ end
380
+ end
381
+ sock
333
382
  end
334
383
 
335
384
  def relay_to_master(worker)
@@ -38,10 +38,8 @@ module TestQueue
38
38
  end
39
39
 
40
40
  output = worker.output.gsub(/\e\[\d+./,'')
41
- summary = output.split("\n").grep(/^\d+ (scenarios?|steps?)/).first
42
- failures = output.scan(/^Failing Scenarios:\n(.*)\n\d+ scenarios?/m).join("\n")
43
-
44
- [ summary, failures ]
41
+ worker.summary = output.split("\n").grep(/^\d+ (scenarios?|steps?)/).first
42
+ worker.failure_output = output.scan(/^Failing Scenarios:\n(.*)\n\d+ scenarios?/m).join("\n")
45
43
  end
46
44
  end
47
45
  end
@@ -1,71 +1,24 @@
1
- require 'test_queue/runner'
2
- require 'minitest/unit'
3
- require 'stringio'
4
-
5
- class MiniTestQueueRunner < MiniTest::Unit
6
- def _run_suites(*)
7
- self.class.output = $stdout
8
- super
9
- end
10
-
11
- def _run_anything(*)
12
- ret = super
13
- output.puts
14
- ret
15
- end
16
-
17
- def _run_suite(suite, type)
18
- output.print ' '
19
- output.print suite
20
- output.print ': '
21
-
22
- start = Time.now
23
- ret = super
24
- diff = Time.now - start
25
-
26
- output.puts(" <%.3f>" % diff)
27
- ret
28
- end
29
-
30
- self.runner = self.new
31
- self.output = StringIO.new
32
- end
33
-
34
- class MiniTest::Unit::TestCase
35
- class << self
36
- attr_accessor :test_suites
37
-
38
- def original_test_suites
39
- @@test_suites.keys.reject{ |s| s.test_methods.empty? }
40
- end
41
- end
1
+ begin
2
+ require 'minitest'
3
+ require 'test_queue/runner/minitest5'
4
+ rescue LoadError => e
5
+ require 'minitest/unit'
6
+ require 'test_queue/runner/minitest4'
42
7
  end
43
8
 
44
9
  module TestQueue
45
10
  class Runner
46
11
  class MiniTest < Runner
47
- def initialize
48
- tests = ::MiniTest::Unit::TestCase.original_test_suites.sort_by{ |s| -(stats[s.to_s] || 0) }
49
- super(tests)
50
- end
51
-
52
- def run_worker(iterator)
53
- ::MiniTest::Unit::TestCase.test_suites = iterator
54
- ::MiniTest::Unit.new.run
55
- end
56
-
57
12
  def summarize_worker(worker)
58
13
  worker.stats.each do |s, val|
59
14
  stats[s.to_s] = val
60
15
  end
61
16
 
62
- num_tests = worker.lines.grep(/, \d+ errors?, /).first
17
+ worker.summary = worker.lines.grep(/, \d+ errors?, /).first
63
18
  failures = worker.lines.select{ |line|
64
19
  line if (line =~ /^Finished/) ... (line =~ /, \d+ errors?, /)
65
20
  }[1..-2]
66
- failures = failures.join("\n") if failures
67
-
68
- [ num_tests, failures ]
21
+ worker.failure_output = failures.join("\n") if failures
69
22
  end
70
23
  end
71
24
  end
@@ -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,71 @@
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
+ @@orig_runnables = @@runnables
15
+ @@runnables = runnables
16
+ end
17
+ def self.orig_runnables
18
+ @@orig_runnables
19
+ end
20
+ end
21
+
22
+ class ProgressReporter
23
+ # Override original method to make test-queue specific output
24
+ def record result
25
+ io.print ' '
26
+ io.print result.class
27
+ io.print ': '
28
+ io.print result.result_code
29
+ io.puts(" <%.3f>" % result.time)
30
+ end
31
+ end
32
+
33
+ begin
34
+ require 'minitest/minitest_reporter_plugin'
35
+
36
+ class << self
37
+ private
38
+ def total_count(options)
39
+ filter = options[:filter] || '/./'
40
+ filter = Regexp.new $1 if filter =~ /\/(.*)\//
41
+
42
+ Minitest::Test.orig_runnables.map(&:runnable_methods).flatten.find_all { |m|
43
+ filter === m || filter === "#{self}##{m}"
44
+ }.size
45
+ end
46
+ end
47
+ rescue LoadError
48
+ end
49
+ end
50
+
51
+ module TestQueue
52
+ class Runner
53
+ class MiniTest < Runner
54
+ def initialize
55
+ tests = ::MiniTest::Test.runnables.reject { |s|
56
+ s.runnable_methods.empty?
57
+ }.sort_by { |s|
58
+ -(stats[s.to_s] || 0)
59
+ }.partition { |s|
60
+ s.test_order == :parallel
61
+ }.reverse.flatten
62
+ super(tests)
63
+ end
64
+
65
+ def run_worker(iterator)
66
+ ::MiniTest::Test.runnables = iterator
67
+ ::MiniTest.run ? 0 : 1
68
+ end
69
+ end
70
+ end
71
+ end
@@ -23,9 +23,8 @@ module TestQueue
23
23
  errors = lines.select{ |line| line =~ /^ERROR/ }
24
24
  warnings = lines.select{ |line| line =~ /^WARNING/ }
25
25
 
26
- summary = "#{files.size} files, #{warnings.size} warnings, #{errors.size} errors"
27
-
28
- [summary, errors.join("\n")]
26
+ worker.summary = "#{files.size} files, #{warnings.size} warnings, #{errors.size} errors"
27
+ worker.failure_output = errors.join("\n")
29
28
  end
30
29
  end
31
30
  end
@@ -1,40 +1,13 @@
1
1
  require 'test_queue/runner'
2
2
  require 'rspec/core'
3
3
 
4
- module RSpec::Core
5
- class QueueRunner < CommandLine
6
- def initialize
7
- super(ARGV)
8
- @configuration.output_stream = $stdout
9
- @configuration.error_stream = $stderr
10
- end
11
-
12
- def example_groups
13
- @options.configure(@configuration)
14
- @configuration.load_spec_files
15
- @world.announce_filters
16
- @world.example_groups
17
- end
18
-
19
- def run_each(iterator)
20
- @configuration.reporter.report(0, @configuration.randomize? ? @configuration.seed : nil) do |reporter|
21
- begin
22
- @configuration.run_hook(:before, :suite)
23
- iterator.map {|g|
24
- print " #{g.description}: "
25
- start = Time.now
26
- ret = g.run(reporter)
27
- diff = Time.now-start
28
- puts(" <%.3f>" % diff)
29
-
30
- ret
31
- }.all? ? 0 : @configuration.failure_exit_code
32
- ensure
33
- @configuration.run_hook(:after, :suite)
34
- end
35
- end
36
- end
37
- end
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'
38
11
  end
39
12
 
40
13
  module TestQueue
@@ -46,7 +19,7 @@ module TestQueue
46
19
  end
47
20
 
48
21
  def run_worker(iterator)
49
- @rspec.run_each(iterator)
22
+ @rspec.run_each(iterator).to_i
50
23
  end
51
24
 
52
25
  def summarize_worker(worker)
@@ -54,10 +27,8 @@ module TestQueue
54
27
  stats[s] = val
55
28
  end
56
29
 
57
- summary = worker.lines.grep(/ examples?, /).first
58
- failures = worker.output[/^Failures:\n\n(.*)\n^Finished/m, 1]
59
-
60
- [ summary, failures ]
30
+ worker.summary = worker.lines.grep(/ examples?, /).first
31
+ worker.failure_output = worker.output[/^Failures:\n\n(.*)\n^Finished/m, 1]
61
32
  end
62
33
  end
63
34
  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,35 @@
1
+ module RSpec::Core
2
+ class QueueRunner < Runner
3
+ def initialize
4
+ options = ::RSpec::Core::ConfigurationOptions.new(ARGV)
5
+ super(options)
6
+ end
7
+
8
+ def example_groups
9
+ setup($stderr, $stdout)
10
+ @world.ordered_example_groups
11
+ end
12
+
13
+ def run_specs(iterator)
14
+ @configuration.reporter.report(@world.ordered_example_groups.count) do |reporter|
15
+ begin
16
+ hook_context = SuiteHookContext.new
17
+ @configuration.hooks.run(:before, :suite, hook_context)
18
+
19
+ iterator.map { |g|
20
+ print " #{g.description}: "
21
+ start = Time.now
22
+ ret = g.run(reporter)
23
+ diff = Time.now-start
24
+ puts(" <%.3f>" % diff)
25
+
26
+ ret
27
+ }.all? ? 0 : @configuration.failure_exit_code
28
+ ensure
29
+ @configuration.hooks.run(:after, :suite, hook_context)
30
+ end
31
+ end
32
+ end
33
+ alias_method :run_each, :run_specs
34
+ end
35
+ end
@@ -26,10 +26,8 @@ module TestQueue
26
26
  def summarize_worker(worker)
27
27
  stats.update(worker.stats)
28
28
 
29
- summary = worker.output.scan(/^\s*(\d+)/).join(', ')
30
- failures = ''
31
-
32
- [ summary, failures ]
29
+ worker.summary = worker.output.scan(/^\s*(\d+)/).join(', ')
30
+ worker.failure_output = ''
33
31
  end
34
32
  end
35
33
  end
data/test-multi.sh CHANGED
@@ -2,7 +2,7 @@
2
2
  set -x
3
3
 
4
4
  # export TEST_QUEUE_VERBOSE=1
5
- TEST_QUEUE_SOCKET=0.0.0.0:12345 bundle exec minitest-queue ./test/sample_test.rb &
5
+ TEST_QUEUE_SOCKET=0.0.0.0:12345 bundle exec minitest-queue ./test/sample_minitest5.rb &
6
6
  sleep 0.1
7
- TEST_QUEUE_RELAY=0.0.0.0:12345 bundle exec minitest-queue ./test/sample_test.rb
7
+ TEST_QUEUE_RELAY=0.0.0.0:12345 bundle exec minitest-queue ./test/sample_minitest5.rb
8
8
  wait
data/test-queue.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  spec = Gem::Specification.new do |s|
2
2
  s.name = 'test-queue'
3
- s.version = '0.2.9'
3
+ s.version = '0.2.10'
4
4
  s.summary = 'parallel test runner'
5
5
  s.description = 'minitest/rspec parallel test runner for CI environments'
6
6
 
@@ -16,8 +16,8 @@ spec = Gem::Specification.new do |s|
16
16
  s.executables << 'minitest-queue'
17
17
  s.executables << 'cucumber-queue'
18
18
 
19
- s.add_development_dependency 'rspec', '~> 2.13'
20
- s.add_development_dependency 'minitest', '~> 4.7.3'
19
+ s.add_development_dependency 'rspec', '>= 2.13', '< 4.0'
20
+ s.add_development_dependency 'minitest', '>= 4.7.3'
21
21
  s.add_development_dependency 'cucumber', '~> 1.3.10'
22
22
 
23
23
  s.files = `git ls-files`.split("\n")
data/test.sh CHANGED
@@ -3,9 +3,15 @@ set -x
3
3
 
4
4
  export TEST_QUEUE_WORKERS=2 TEST_QUEUE_VERBOSE=1
5
5
 
6
+ bundle install --gemfile=Gemfile-minitest4
7
+ bundle exec minitest-queue ./test/*_minitest4.rb
8
+ bundle exec minitest-queue ./test/*_minispec.rb
9
+
10
+ bundle install
11
+ bundle exec minitest-queue ./test/*_minitest4.rb
12
+ bundle exec minitest-queue ./test/*_minitest5.rb
6
13
  bundle exec minitest-queue ./test/*_minispec.rb
7
- bundle exec minitest-queue ./test/*_test.rb
8
14
  bundle exec rspec-queue test
9
15
  bundle exec cucumber-queue
10
16
 
11
- TEST_QUEUE_WORKERS=1 TEST_QUEUE_FORCE="MiniTestSleep21,MiniTestSleep8,MiniTestFailure" bundle exec minitest-queue ./test/*_test.rb
17
+ TEST_QUEUE_WORKERS=1 TEST_QUEUE_FORCE="MiniTestSleep21,MiniTestSleep8,MiniTestFailure" bundle exec minitest-queue ./test/*_minitest5.rb
File without changes
@@ -0,0 +1,23 @@
1
+ require 'minitest/autorun'
2
+
3
+ class MiniTestEqual < MiniTest::Test
4
+ def test_equal
5
+ assert_equal 1, 1
6
+ end
7
+ end
8
+
9
+ 30.times do |i|
10
+ Object.const_set("MiniTestSleep#{i}", Class.new(MiniTest::Test) do
11
+ define_method('test_sleep') do
12
+ start = Time.now
13
+ sleep(0.25)
14
+ assert_in_delta Time.now-start, 0.25, 0.02
15
+ end
16
+ end)
17
+ end
18
+
19
+ class MiniTestFailure < MiniTest::Test
20
+ def test_fail
21
+ assert_equal 0, 1
22
+ end
23
+ end
data/test/sample_spec.rb CHANGED
@@ -2,7 +2,7 @@ require 'rspec'
2
2
 
3
3
  describe 'RSpecEqual' do
4
4
  it 'checks equality' do
5
- 1.should equal(1)
5
+ expect(1).to eq 1
6
6
  end
7
7
  end
8
8
 
@@ -11,13 +11,13 @@ end
11
11
  it "sleeps" do
12
12
  start = Time.now
13
13
  sleep(0.25)
14
- (Time.now-start).should be_within(0.02).of(0.25)
14
+ expect(Time.now-start).to be_within(0.02).of(0.25)
15
15
  end
16
16
  end
17
17
  end
18
18
 
19
19
  describe 'RSpecFailure' do
20
20
  it 'fails' do
21
- :foo.should eq(:bar)
21
+ expect(:foo).to eq :bar
22
22
  end
23
23
  end
metadata CHANGED
@@ -1,46 +1,58 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.9
4
+ version: 0.2.10
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Aman Gupta
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-02-13 00:00:00.000000000 Z
12
+ date: 2014-12-20 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: rspec
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - ~>
19
+ - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
21
  version: '2.13'
22
+ - - <
23
+ - !ruby/object:Gem::Version
24
+ version: '4.0'
20
25
  type: :development
21
26
  prerelease: false
22
27
  version_requirements: !ruby/object:Gem::Requirement
28
+ none: false
23
29
  requirements:
24
- - - ~>
30
+ - - ! '>='
25
31
  - !ruby/object:Gem::Version
26
32
  version: '2.13'
33
+ - - <
34
+ - !ruby/object:Gem::Version
35
+ version: '4.0'
27
36
  - !ruby/object:Gem::Dependency
28
37
  name: minitest
29
38
  requirement: !ruby/object:Gem::Requirement
39
+ none: false
30
40
  requirements:
31
- - - ~>
41
+ - - ! '>='
32
42
  - !ruby/object:Gem::Version
33
43
  version: 4.7.3
34
44
  type: :development
35
45
  prerelease: false
36
46
  version_requirements: !ruby/object:Gem::Requirement
47
+ none: false
37
48
  requirements:
38
- - - ~>
49
+ - - ! '>='
39
50
  - !ruby/object:Gem::Version
40
51
  version: 4.7.3
41
52
  - !ruby/object:Gem::Dependency
42
53
  name: cucumber
43
54
  requirement: !ruby/object:Gem::Requirement
55
+ none: false
44
56
  requirements:
45
57
  - - ~>
46
58
  - !ruby/object:Gem::Version
@@ -48,6 +60,7 @@ dependencies:
48
60
  type: :development
49
61
  prerelease: false
50
62
  version_requirements: !ruby/object:Gem::Requirement
63
+ none: false
51
64
  requirements:
52
65
  - - ~>
53
66
  - !ruby/object:Gem::Version
@@ -62,6 +75,8 @@ extensions: []
62
75
  extra_rdoc_files: []
63
76
  files:
64
77
  - Gemfile
78
+ - Gemfile-minitest4
79
+ - Gemfile-minitest4.lock
65
80
  - Gemfile.lock
66
81
  - README.md
67
82
  - bin/cucumber-queue
@@ -77,38 +92,44 @@ files:
77
92
  - lib/test_queue/runner.rb
78
93
  - lib/test_queue/runner/cucumber.rb
79
94
  - lib/test_queue/runner/minitest.rb
95
+ - lib/test_queue/runner/minitest4.rb
96
+ - lib/test_queue/runner/minitest5.rb
80
97
  - lib/test_queue/runner/puppet_lint.rb
81
98
  - lib/test_queue/runner/rspec.rb
99
+ - lib/test_queue/runner/rspec2.rb
100
+ - lib/test_queue/runner/rspec3.rb
82
101
  - lib/test_queue/runner/sample.rb
83
102
  - test-multi.sh
84
103
  - test-queue.gemspec
85
104
  - test.sh
86
105
  - test/sample_minispec.rb
106
+ - test/sample_minitest4.rb
107
+ - test/sample_minitest5.rb
87
108
  - test/sample_spec.rb
88
- - test/sample_test.rb
89
109
  homepage: http://github.com/tmm1/test-queue
90
110
  licenses:
91
111
  - MIT
92
- metadata: {}
93
112
  post_install_message:
94
113
  rdoc_options: []
95
114
  require_paths:
96
115
  - lib
97
116
  required_ruby_version: !ruby/object:Gem::Requirement
117
+ none: false
98
118
  requirements:
99
119
  - - ! '>='
100
120
  - !ruby/object:Gem::Version
101
121
  version: '0'
102
122
  required_rubygems_version: !ruby/object:Gem::Requirement
123
+ none: false
103
124
  requirements:
104
125
  - - ! '>='
105
126
  - !ruby/object:Gem::Version
106
127
  version: '0'
107
128
  requirements: []
108
129
  rubyforge_project:
109
- rubygems_version: 2.1.11
130
+ rubygems_version: 1.8.23
110
131
  signing_key:
111
- specification_version: 4
132
+ specification_version: 3
112
133
  summary: parallel test runner
113
134
  test_files: []
114
135
  has_rdoc: false
checksums.yaml DELETED
@@ -1,15 +0,0 @@
1
- ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MjQ3ZGNkZDQ3OGNjMWU2YmIxZDU2NGZjOTZjYTk5ZTNhY2E4NzQxZQ==
5
- data.tar.gz: !binary |-
6
- MjJiZjRjM2M4Y2E0ODA5ZjQyYTJkMDkzOTM0MjA0Nzc2NjM1NDg3ZA==
7
- SHA512:
8
- metadata.gz: !binary |-
9
- MWYwODQ5NjBmMmEwMTNiYWFjZWQ1NGNmMTcyNjRiMWRhNDM4OWVkY2E3YTNi
10
- NDViMTBjZDNjMGU1ZDc1MTNmYjIzYTMzNDViMzMyYmEyMjY1Mjk2MjFhYmIz
11
- MTcxODg3NzA3MTI5MjkzMTc2MGRjMWNiNGIxOTNmYWFiMmI4MWE=
12
- data.tar.gz: !binary |-
13
- YzhhNTMxM2U3ZDNlNzg1YTcwY2Q4OTNiY2M1YTkwMmZlZTFhNjUzNTk5NzEw
14
- MTk1YTNlZjZjYTcwMzhkNTM4MTQ5Yjg1ZjFjZWU4Y2MyOGY4MWFjNGRhOGZl
15
- YTI2NWE5N2I2N2Y4MWVhMTEwZjA4ZWU0NjU0YWIwMGEzZjY1Njg=