deep_test 1.1.2 → 1.1.3
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/CHANGELOG +6 -0
- data/README +39 -2
- data/Rakefile +17 -12
- data/lib/deep_test.rb +27 -18
- data/lib/deep_test/deadlock_detector.rb +7 -0
- data/lib/deep_test/logger.rb +9 -0
- data/lib/deep_test/null_worker_listener.rb +12 -0
- data/lib/deep_test/options.rb +72 -0
- data/lib/deep_test/process_orchestrator.rb +85 -0
- data/lib/deep_test/rake_tasks.rb +7 -0
- data/lib/deep_test/rinda_blackboard.rb +8 -7
- data/lib/deep_test/rspec_detector.rb +17 -0
- data/lib/deep_test/server.rb +3 -9
- data/lib/deep_test/spec.rb +9 -0
- data/lib/deep_test/spec/extensions/options.rb +11 -0
- data/lib/deep_test/spec/extensions/reporter.rb +17 -0
- data/lib/deep_test/spec/extensions/spec_task.rb +13 -0
- data/lib/deep_test/spec/runner.rb +48 -0
- data/lib/deep_test/spec/work_result.rb +26 -0
- data/lib/deep_test/spec/work_unit.rb +53 -0
- data/lib/deep_test/test.rb +9 -0
- data/lib/deep_test/{extensions → test/extensions}/error.rb +0 -0
- data/lib/deep_test/{extensions/testresult.rb → test/extensions/test_result.rb} +1 -1
- data/lib/deep_test/test/runner.rb +29 -0
- data/lib/deep_test/test/supervised_test_suite.rb +46 -0
- data/lib/deep_test/test/work_unit.rb +36 -0
- data/lib/deep_test/test_task.rb +36 -9
- data/lib/deep_test/tuple_space_factory.rb +3 -2
- data/lib/deep_test/warlock.rb +2 -2
- data/lib/deep_test/worker.rb +10 -20
- data/script/run_test_suite.rb +5 -34
- data/test/deep_test/rinda_blackboard_test.rb +5 -5
- data/test/{testresult_test.rb → deep_test/test/extensions/test_result_test.rb} +2 -2
- data/test/deep_test/test/runner_test.rb +7 -0
- data/test/deep_test/test/supervised_test_suite_test.rb +89 -0
- data/test/deep_test/test/work_unit_test.rb +50 -0
- data/test/deep_test/test_task_test.rb +23 -0
- data/test/deep_test/worker_test.rb +62 -0
- data/test/failing.rake +11 -0
- data/test/fake_deadlock_error.rb +12 -0
- data/test/logger_test.rb +11 -0
- data/test/simple_test_blackboard.rb +44 -0
- data/test/simple_test_blackboard_test.rb +5 -5
- data/test/test_factory.rb +74 -0
- data/test/test_helper.rb +5 -71
- metadata +32 -13
- data/lib/deep_test/loader.rb +0 -18
- data/lib/deep_test/simple_test_blackboard.rb +0 -24
- data/lib/deep_test/supervised_test_suite.rb +0 -19
- data/lib/deep_test/supervisor.rb +0 -27
- data/test/deep_test/loader_test.rb +0 -8
- data/test/supervised_test_suite_test.rb +0 -63
- data/test/supervisor_test.rb +0 -80
- data/test/worker_test.rb +0 -64
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'spec/runner/example_group_runner'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
require File.dirname(__FILE__) + "/spec/extensions/spec_task"
|
5
|
+
require File.dirname(__FILE__) + "/spec/extensions/options"
|
6
|
+
require File.dirname(__FILE__) + "/spec/extensions/reporter"
|
7
|
+
require File.dirname(__FILE__) + "/spec/runner"
|
8
|
+
require File.dirname(__FILE__) + "/spec/work_unit"
|
9
|
+
require File.dirname(__FILE__) + "/spec/work_result"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec/runner/reporter'
|
2
|
+
module Spec
|
3
|
+
module Runner
|
4
|
+
class Reporter
|
5
|
+
def failure(example, error)
|
6
|
+
backtrace_tweaker.tweak_backtrace(error)
|
7
|
+
example_name = "#{example.class.description} #{example.description}"
|
8
|
+
failure = Failure.new(example_name, error)
|
9
|
+
@failures << failure
|
10
|
+
formatters.each do |f|
|
11
|
+
f.example_failed(example, @failures.length, failure)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
alias_method :example_failed, :failure
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Spec
|
2
|
+
module Rake
|
3
|
+
class SpecTask
|
4
|
+
def deep_test(options)
|
5
|
+
deep_test_options = DeepTest::Options.new(options)
|
6
|
+
deep_test_path = File.expand_path(File.dirname(__FILE__) +
|
7
|
+
"/../../../deep_test")
|
8
|
+
spec_opts << "--require #{deep_test_path}"
|
9
|
+
spec_opts << "--runner 'DeepTest::Spec::Runner:#{deep_test_options.to_command_line}'"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module DeepTest
|
2
|
+
module Spec
|
3
|
+
class Runner < ::Spec::Runner::ExampleGroupRunner
|
4
|
+
def initialize(options, deep_test_options, blackboard = nil)
|
5
|
+
super(options)
|
6
|
+
@deep_test_options = DeepTest::Options.from_command_line(deep_test_options)
|
7
|
+
@blackboard = blackboard
|
8
|
+
end
|
9
|
+
|
10
|
+
def blackboard
|
11
|
+
# Can't create blackboard as default argument to initialize
|
12
|
+
# because ProcessOrchestrator hasn't been invoked at
|
13
|
+
# instantiation time
|
14
|
+
@blackboard ||= RindaBlackboard.new(@deep_test_options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
ProcessOrchestrator.run(@deep_test_options, self)
|
19
|
+
end
|
20
|
+
|
21
|
+
def process_work_units
|
22
|
+
prepare
|
23
|
+
|
24
|
+
examples = example_groups.map {|g| g.send(:examples_to_run)}.flatten
|
25
|
+
examples_by_location = {}
|
26
|
+
examples.each do |example|
|
27
|
+
file, line, *rest = example.implementation_backtrace.first.split(/:/)
|
28
|
+
examples_by_location["#{file}:#{line}"] = example
|
29
|
+
blackboard.write_work Spec::WorkUnit.new(file, line.to_i)
|
30
|
+
end
|
31
|
+
|
32
|
+
success = true
|
33
|
+
until examples_by_location.empty?
|
34
|
+
result = blackboard.take_result
|
35
|
+
next unless result
|
36
|
+
print result.output if result.output
|
37
|
+
example = examples_by_location.delete("#{result.file}:#{result.line}")
|
38
|
+
@options.reporter.example_finished(example, result.error)
|
39
|
+
success &= result.error.nil?
|
40
|
+
end
|
41
|
+
|
42
|
+
success
|
43
|
+
ensure
|
44
|
+
finish
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module DeepTest
|
2
|
+
module Spec
|
3
|
+
class WorkResult
|
4
|
+
attr_reader :file, :line, :example_description, :error, :output
|
5
|
+
def initialize(file, line, example_description, error, output)
|
6
|
+
@file, @line, @example_description, @error, @output =
|
7
|
+
file, line, example_description, error, output
|
8
|
+
end
|
9
|
+
|
10
|
+
def ==(other)
|
11
|
+
file == other.file &&
|
12
|
+
line == other.line &&
|
13
|
+
example_description == other.example_description &&
|
14
|
+
error == other.error
|
15
|
+
end
|
16
|
+
|
17
|
+
def failed_due_to_deadlock?
|
18
|
+
DeadlockDetector.due_to_deadlock?(@error)
|
19
|
+
end
|
20
|
+
|
21
|
+
def deadlock_result
|
22
|
+
WorkResult.new(file, line, example_description, nil, '-deadlock-')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module DeepTest
|
2
|
+
module Spec
|
3
|
+
class WorkUnit
|
4
|
+
def initialize(file, line)
|
5
|
+
@file, @line = file, line
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
# Dup options here to avoid clobbering the reporter on someone
|
10
|
+
# elses options reference (Such as ExampleGroupRunner)
|
11
|
+
original_options, $rspec_options = $rspec_options, $rspec_options.dup
|
12
|
+
rspec_options.reporter = ResultReporter.new(@file, @line)
|
13
|
+
result = run_without_deadlock_protection
|
14
|
+
result = run_without_deadlock_protection if result.failed_due_to_deadlock?
|
15
|
+
result = result.deadlock_result if result.failed_due_to_deadlock?
|
16
|
+
result
|
17
|
+
ensure
|
18
|
+
$rspec_options = original_options
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def run_without_deadlock_protection
|
24
|
+
output = capture_stdout do
|
25
|
+
rspec_options.run_one_example(@file, @line)
|
26
|
+
end
|
27
|
+
rspec_options.reporter.result(output)
|
28
|
+
end
|
29
|
+
|
30
|
+
class ResultReporter
|
31
|
+
attr_reader :result
|
32
|
+
def initialize(file,line)
|
33
|
+
@file, @line = file, line
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_example_group(example_group); end
|
37
|
+
def dump; end
|
38
|
+
def end; end
|
39
|
+
def example_started(name); end
|
40
|
+
|
41
|
+
def example_finished(example, error)
|
42
|
+
@example, @error = example, error
|
43
|
+
end
|
44
|
+
|
45
|
+
def result(output)
|
46
|
+
Spec::WorkResult.new(@file, @line, @example.description, @error, output)
|
47
|
+
end
|
48
|
+
|
49
|
+
def start(example); end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require "test/unit/testresult"
|
2
|
+
require "test/unit/error"
|
3
|
+
require 'test/unit/failure'
|
4
|
+
|
5
|
+
require File.dirname(__FILE__) + "/test/extensions/test_result"
|
6
|
+
require File.dirname(__FILE__) + "/test/extensions/error"
|
7
|
+
require File.dirname(__FILE__) + "/test/runner"
|
8
|
+
require File.dirname(__FILE__) + "/test/supervised_test_suite"
|
9
|
+
require File.dirname(__FILE__) + "/test/work_unit"
|
File without changes
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module DeepTest
|
2
|
+
module Test
|
3
|
+
class Runner
|
4
|
+
unless defined?(NO_FILTERS)
|
5
|
+
NO_FILTERS = Object.new.instance_eval do
|
6
|
+
def filters; []; end;
|
7
|
+
self
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(options)
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_files
|
16
|
+
Dir.glob(@options.pattern).each { |file| load file }
|
17
|
+
::Test::Unit.run = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def process_work_units
|
21
|
+
suite = ::Test::Unit::AutoRunner::COLLECTORS[:objectspace].call NO_FILTERS
|
22
|
+
supervised_suite = DeepTest::Test::SupervisedTestSuite.new(suite, RindaBlackboard.new(@options))
|
23
|
+
require 'test/unit/ui/console/testrunner'
|
24
|
+
result = ::Test::Unit::UI::Console::TestRunner.run(supervised_suite, ::Test::Unit::UI::NORMAL)
|
25
|
+
result.passed?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module DeepTest
|
2
|
+
module Test
|
3
|
+
class SupervisedTestSuite
|
4
|
+
def initialize(suite, blackboard)
|
5
|
+
@suite = suite
|
6
|
+
@blackboard = blackboard
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(result, &progress_block)
|
10
|
+
yield ::Test::Unit::TestSuite::STARTED, @suite.name
|
11
|
+
count = add_tests @suite
|
12
|
+
read_results result, count, &progress_block
|
13
|
+
yield ::Test::Unit::TestSuite::FINISHED, @suite.name
|
14
|
+
end
|
15
|
+
|
16
|
+
def size
|
17
|
+
@suite.size
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_tests(test_suite)
|
21
|
+
count = 0
|
22
|
+
if test_suite.respond_to? :tests
|
23
|
+
test_suite.tests.each do |test|
|
24
|
+
count += add_tests(test)
|
25
|
+
end
|
26
|
+
else
|
27
|
+
count += 1
|
28
|
+
@blackboard.write_work Test::WorkUnit.new(test_suite)
|
29
|
+
end
|
30
|
+
count
|
31
|
+
end
|
32
|
+
|
33
|
+
def read_results(result, count)
|
34
|
+
while count > 0
|
35
|
+
remote_result = @blackboard.take_result
|
36
|
+
next unless remote_result
|
37
|
+
count -= 1
|
38
|
+
remote_result.add_to result
|
39
|
+
# TODO: is this the right place for this next line? -Dan
|
40
|
+
print remote_result.output if remote_result.output
|
41
|
+
yield ::Test::Unit::TestCase::FINISHED, nil if block_given?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module DeepTest
|
2
|
+
module Test
|
3
|
+
class WorkUnit
|
4
|
+
def initialize(test_case)
|
5
|
+
@test_case = test_case
|
6
|
+
end
|
7
|
+
|
8
|
+
def run
|
9
|
+
result = run_without_deadlock_protection
|
10
|
+
result = run_without_deadlock_protection if result.failed_due_to_deadlock?
|
11
|
+
if result.failed_due_to_deadlock?
|
12
|
+
result = ::Test::Unit::TestResult.new
|
13
|
+
result.add_run
|
14
|
+
result.output = "-deadlock-"
|
15
|
+
end
|
16
|
+
result
|
17
|
+
end
|
18
|
+
|
19
|
+
def ==(other)
|
20
|
+
return false unless other.class == self.class
|
21
|
+
@test_case == other.instance_variable_get(:@test_case)
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def run_without_deadlock_protection
|
27
|
+
result = ::Test::Unit::TestResult.new
|
28
|
+
output = capture_stdout do
|
29
|
+
@test_case.run(result) {|channel,event|}
|
30
|
+
end
|
31
|
+
result.output = output
|
32
|
+
result
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/deep_test/test_task.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
module DeepTest
|
2
2
|
class TestTask
|
3
|
-
DEFAULT_NUMBER_OF_WORKERS = 2
|
4
|
-
attr_writer :number_of_workers, :pattern
|
5
|
-
|
6
3
|
def initialize(name = :deep_test)
|
7
4
|
@name = name
|
5
|
+
@options = Options.new({})
|
6
|
+
self.pattern = "test/**/*_test.rb"
|
8
7
|
yield self if block_given?
|
9
8
|
define
|
10
9
|
end
|
@@ -12,18 +11,46 @@ module DeepTest
|
|
12
11
|
def define
|
13
12
|
desc "Run '#{@name}' suite using DeepTest"
|
14
13
|
task @name do
|
15
|
-
|
16
|
-
runner = File.expand_path(File.dirname(__FILE__) + "/../../script/run_test_suite.rb")
|
17
|
-
ruby "-I#{deep_test_lib} #{runner} '#{number_of_workers}' '#{pattern}'"
|
14
|
+
ruby "#{runner} '#{@options.to_command_line}'"
|
18
15
|
end
|
19
16
|
end
|
20
|
-
|
17
|
+
|
21
18
|
def number_of_workers
|
22
|
-
@number_of_workers
|
19
|
+
@options.number_of_workers
|
20
|
+
end
|
21
|
+
|
22
|
+
def number_of_workers=(num)
|
23
|
+
@options.number_of_workers = num
|
23
24
|
end
|
24
25
|
|
25
26
|
def pattern
|
26
|
-
|
27
|
+
@options.pattern
|
28
|
+
end
|
29
|
+
|
30
|
+
def pattern=(pattern)
|
31
|
+
@options.pattern = Dir.pwd + "/" + pattern
|
32
|
+
end
|
33
|
+
|
34
|
+
def timeout_in_seconds=(seconds)
|
35
|
+
@options.timeout_in_seconds = seconds
|
27
36
|
end
|
37
|
+
|
38
|
+
def timeout_in_seconds
|
39
|
+
@options.timeout_in_seconds
|
40
|
+
end
|
41
|
+
|
42
|
+
def worker_listener=(listener)
|
43
|
+
@options.worker_listener = listener
|
44
|
+
end
|
45
|
+
|
46
|
+
def worker_listener
|
47
|
+
@options.worker_listener
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def runner
|
53
|
+
File.expand_path(File.dirname(__FILE__) + "/../../script/run_test_suite.rb")
|
54
|
+
end
|
28
55
|
end
|
29
56
|
end
|
@@ -2,9 +2,10 @@ module DeepTest
|
|
2
2
|
class TupleSpaceFactory
|
3
3
|
def self.tuple_space
|
4
4
|
require "rinda/ring"
|
5
|
+
require "socket"
|
5
6
|
DRb.start_service
|
6
|
-
ts = Rinda::RingFinger.new([
|
7
|
-
|
7
|
+
ts = Rinda::RingFinger.new([Socket.gethostname],DeepTest::Server::PORT).lookup_ring_any
|
8
|
+
DeepTest.logger.debug "Connected to DeepTest server at #{ts.__drburi}"
|
8
9
|
Rinda::TupleSpaceProxy.new ts
|
9
10
|
end
|
10
11
|
end
|
data/lib/deep_test/warlock.rb
CHANGED
@@ -13,7 +13,7 @@ module DeepTest
|
|
13
13
|
end
|
14
14
|
raise "fatal: fork returned nil" if pid.nil?
|
15
15
|
@demons << [name, pid]
|
16
|
-
|
16
|
+
DeepTest.logger.debug "Started #{name} (#{pid})"
|
17
17
|
rescue => e
|
18
18
|
puts "exception starting #{name}: #{e}"
|
19
19
|
puts "\t" + e.backtrace.join("\n\t")
|
@@ -34,7 +34,7 @@ module DeepTest
|
|
34
34
|
rescue Errno::ECHILD => e
|
35
35
|
puts e
|
36
36
|
end
|
37
|
-
|
37
|
+
DeepTest.logger.debug "Stopped #{name} (#{pid})"
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
data/lib/deep_test/worker.rb
CHANGED
@@ -1,31 +1,21 @@
|
|
1
1
|
module DeepTest
|
2
2
|
class Worker
|
3
|
-
|
3
|
+
attr_reader :number
|
4
|
+
|
5
|
+
def initialize(number, blackboard, worker_listener)
|
6
|
+
@number = number
|
4
7
|
@blackboard = blackboard
|
8
|
+
@listener = worker_listener
|
5
9
|
end
|
6
10
|
|
7
11
|
def run
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
result.add_run
|
14
|
-
result.output = "-deadlock-"
|
15
|
-
end
|
12
|
+
@listener.starting(self)
|
13
|
+
while work_unit = @blackboard.take_work
|
14
|
+
@listener.starting_work(self, work_unit)
|
15
|
+
result = work_unit.run
|
16
|
+
@listener.finished_work(self, work_unit, result)
|
16
17
|
@blackboard.write_result result
|
17
18
|
end
|
18
19
|
end
|
19
|
-
|
20
|
-
protected
|
21
|
-
|
22
|
-
def run_test_case(test_case)
|
23
|
-
result = Test::Unit::TestResult.new
|
24
|
-
output = capture_stdout do
|
25
|
-
test_case.run(result) {|channel,event|}
|
26
|
-
end
|
27
|
-
result.output = output
|
28
|
-
result
|
29
|
-
end
|
30
20
|
end
|
31
21
|
end
|