test-queue 0.2.9 → 0.2.10

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