jperkins-deep_test 1.2.2
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 +47 -0
- data/README.rdoc +228 -0
- data/Rakefile +247 -0
- data/bin/deep_test +15 -0
- data/lib/deep_test.rb +91 -0
- data/lib/deep_test/database/mysql_setup_listener.rb +112 -0
- data/lib/deep_test/database/postgresql_setup_listener.rb +116 -0
- data/lib/deep_test/database/setup_listener.rb +125 -0
- data/lib/deep_test/deadlock_detector.rb +7 -0
- data/lib/deep_test/distributed/dispatch_controller.rb +53 -0
- data/lib/deep_test/distributed/drb_client_connection_info.rb +15 -0
- data/lib/deep_test/distributed/filename_resolver.rb +40 -0
- data/lib/deep_test/distributed/master_test_server.rb +52 -0
- data/lib/deep_test/distributed/multi_test_server_proxy.rb +44 -0
- data/lib/deep_test/distributed/null_work_unit.rb +12 -0
- data/lib/deep_test/distributed/remote_worker_client.rb +54 -0
- data/lib/deep_test/distributed/remote_worker_server.rb +82 -0
- data/lib/deep_test/distributed/rsync.rb +37 -0
- data/lib/deep_test/distributed/show_status.rhtml +41 -0
- data/lib/deep_test/distributed/test_server.rb +78 -0
- data/lib/deep_test/distributed/test_server_status.rb +9 -0
- data/lib/deep_test/distributed/test_server_workers.rb +24 -0
- data/lib/deep_test/distributed/throughput_runner.rb +42 -0
- data/lib/deep_test/distributed/throughput_statistics.rb +26 -0
- data/lib/deep_test/distributed/throughput_worker_client.rb +19 -0
- data/lib/deep_test/extensions/drb_extension.rb +34 -0
- data/lib/deep_test/extensions/object_extension.rb +40 -0
- data/lib/deep_test/listener_list.rb +17 -0
- data/lib/deep_test/local_workers.rb +55 -0
- data/lib/deep_test/logger.rb +17 -0
- data/lib/deep_test/marshallable_exception_wrapper.rb +44 -0
- data/lib/deep_test/metrics/gatherer.rb +67 -0
- data/lib/deep_test/metrics/queue_lock_wait_time_measurement.rb +133 -0
- data/lib/deep_test/null_worker_listener.rb +62 -0
- data/lib/deep_test/option.rb +60 -0
- data/lib/deep_test/options.rb +110 -0
- data/lib/deep_test/process_orchestrator.rb +49 -0
- data/lib/deep_test/rake_tasks.rb +11 -0
- data/lib/deep_test/result_reader.rb +36 -0
- data/lib/deep_test/rspec_detector.rb +21 -0
- data/lib/deep_test/server.rb +75 -0
- data/lib/deep_test/spec.rb +13 -0
- data/lib/deep_test/spec/extensions/example_group_methods.rb +64 -0
- data/lib/deep_test/spec/extensions/example_methods.rb +46 -0
- data/lib/deep_test/spec/extensions/options.rb +43 -0
- data/lib/deep_test/spec/extensions/reporter.rb +29 -0
- data/lib/deep_test/spec/extensions/spec_task.rb +20 -0
- data/lib/deep_test/spec/runner.rb +57 -0
- data/lib/deep_test/spec/work_result.rb +33 -0
- data/lib/deep_test/spec/work_unit.rb +59 -0
- data/lib/deep_test/test.rb +10 -0
- data/lib/deep_test/test/extensions/error.rb +14 -0
- data/lib/deep_test/test/runner.rb +24 -0
- data/lib/deep_test/test/supervised_test_suite.rb +49 -0
- data/lib/deep_test/test/work_result.rb +34 -0
- data/lib/deep_test/test/work_unit.rb +40 -0
- data/lib/deep_test/test_task.rb +47 -0
- data/lib/deep_test/ui/console.rb +76 -0
- data/lib/deep_test/ui/null.rb +17 -0
- data/lib/deep_test/warlock.rb +134 -0
- data/lib/deep_test/worker.rb +57 -0
- data/script/internal/run_test_suite.rb +7 -0
- data/script/public/master_test_server.rb +24 -0
- data/script/public/test_server.rb +18 -0
- data/script/public/test_throughput.rb +29 -0
- data/spec/deep_test/option_spec.rb +33 -0
- data/spec/deep_test/options_spec.rb +183 -0
- data/spec/deep_test/spec/extensions/example_group_methods_spec.rb +48 -0
- data/spec/deep_test/spec/extensions/example_methods_spec.rb +61 -0
- data/spec/deep_test/spec/extensions/options_spec.rb +23 -0
- data/spec/deep_test/spec/extensions/reporter_spec.rb +28 -0
- data/spec/deep_test/spec/extensions/spec_task_spec.rb +36 -0
- data/spec/deep_test/spec/runner_spec.rb +106 -0
- data/spec/deep_test/spec/work_result_spec.rb +14 -0
- data/spec/deep_test/spec/work_unit_spec.rb +78 -0
- data/spec/spec_helper.rb +59 -0
- data/spec/thread_worker.rb +25 -0
- data/test/deep_test/database/mysql_setup_listener_test.rb +14 -0
- data/test/deep_test/distributed/dispatch_controller_test.rb +209 -0
- data/test/deep_test/distributed/drb_client_connection_info_test.rb +42 -0
- data/test/deep_test/distributed/filename_resolver_test.rb +52 -0
- data/test/deep_test/distributed/master_test_server_test.rb +32 -0
- data/test/deep_test/distributed/multi_test_server_proxy_test.rb +96 -0
- data/test/deep_test/distributed/remote_worker_client_test.rb +180 -0
- data/test/deep_test/distributed/remote_worker_server_test.rb +99 -0
- data/test/deep_test/distributed/rsync_test.rb +67 -0
- data/test/deep_test/distributed/test_server_test.rb +94 -0
- data/test/deep_test/distributed/test_server_workers_test.rb +26 -0
- data/test/deep_test/distributed/throughput_runner_test.rb +68 -0
- data/test/deep_test/distributed/throughput_worker_client_test.rb +28 -0
- data/test/deep_test/extensions/object_extension_test.rb +37 -0
- data/test/deep_test/listener_list_test.rb +20 -0
- data/test/deep_test/local_workers_test.rb +22 -0
- data/test/deep_test/logger_test.rb +11 -0
- data/test/deep_test/marshallable_exception_wrapper_test.rb +44 -0
- data/test/deep_test/metrics/gatherer_test.rb +66 -0
- data/test/deep_test/process_orchestrator_test.rb +11 -0
- data/test/deep_test/result_reader_test.rb +128 -0
- data/test/deep_test/server_test.rb +58 -0
- data/test/deep_test/test/extensions/error_test.rb +40 -0
- data/test/deep_test/test/runner_test.rb +7 -0
- data/test/deep_test/test/supervised_test_suite_test.rb +79 -0
- data/test/deep_test/test/work_result_test.rb +81 -0
- data/test/deep_test/test/work_unit_test.rb +61 -0
- data/test/deep_test/test_task_test.rb +43 -0
- data/test/deep_test/ui/console_test.rb +9 -0
- data/test/deep_test/warlock_test.rb +38 -0
- data/test/deep_test/worker_test.rb +94 -0
- data/test/failing.rake +11 -0
- data/test/failing.rb +7 -0
- data/test/fake_deadlock_error.rb +12 -0
- data/test/simple_test_blackboard.rb +45 -0
- data/test/simple_test_blackboard_test.rb +33 -0
- data/test/test_factory.rb +74 -0
- data/test/test_helper.rb +15 -0
- data/test/test_task_test.rb +72 -0
- metadata +214 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
class RSpecDetector
|
|
3
|
+
def self.if_rspec_available
|
|
4
|
+
if defined?(::Spec)
|
|
5
|
+
require 'spec/version'
|
|
6
|
+
if ::Spec::VERSION::MAJOR == 1 &&
|
|
7
|
+
::Spec::VERSION::MINOR == 1 &&
|
|
8
|
+
::Spec::VERSION::TINY == 8
|
|
9
|
+
yield
|
|
10
|
+
else
|
|
11
|
+
require 'spec/rake/spectask'
|
|
12
|
+
::Spec::Rake::SpecTask.class_eval do
|
|
13
|
+
def deep_test(options)
|
|
14
|
+
raise "* DeepTest RSpec support requires RSpec 1.1.8"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
class Server
|
|
3
|
+
def self.start(options)
|
|
4
|
+
server = new(options)
|
|
5
|
+
DRb.start_service("druby://0.0.0.0:#{options.server_port}", server)
|
|
6
|
+
DeepTest.logger.info "Started DeepTest service at #{DRb.uri}"
|
|
7
|
+
server
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.stop
|
|
11
|
+
DRb.stop_service
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.remote_reference(address, port)
|
|
15
|
+
DRb.start_service
|
|
16
|
+
blackboard = DRbObject.new_with_uri("druby://#{address}:#{port}")
|
|
17
|
+
DeepTest.logger.debug "Connecting to DeepTest server at #{blackboard.__drburi}"
|
|
18
|
+
blackboard
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def initialize(options)
|
|
22
|
+
@options = options
|
|
23
|
+
@work_queue = Queue.new
|
|
24
|
+
@result_queue = Queue.new
|
|
25
|
+
|
|
26
|
+
if Metrics::Gatherer.enabled?
|
|
27
|
+
require File.dirname(__FILE__) + "/metrics/queue_lock_wait_time_measurement"
|
|
28
|
+
@work_queue.extend Metrics::QueueLockWaitTimeMeasurement
|
|
29
|
+
@result_queue.extend Metrics::QueueLockWaitTimeMeasurement
|
|
30
|
+
Metrics::Gatherer.section("server queue lock wait times") do |s|
|
|
31
|
+
s.measurement("work queue total pop wait time", @work_queue.total_pop_time)
|
|
32
|
+
s.measurement("work queue total push wait time", @work_queue.total_push_time)
|
|
33
|
+
s.measurement("result queue total pop wait time", @result_queue.total_pop_time)
|
|
34
|
+
s.measurement("result queue total push wait time", @result_queue.total_push_time)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def done_with_work
|
|
40
|
+
@done_with_work = true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def take_result
|
|
44
|
+
Timeout.timeout(@options.timeout_in_seconds, ResultOverdueError) do
|
|
45
|
+
@result_queue.pop
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def take_work
|
|
50
|
+
raise NoWorkUnitsRemainingError if @done_with_work
|
|
51
|
+
|
|
52
|
+
@work_queue.pop(true)
|
|
53
|
+
rescue ThreadError => e
|
|
54
|
+
if e.message == "queue empty"
|
|
55
|
+
raise NoWorkUnitsAvailableError
|
|
56
|
+
else
|
|
57
|
+
raise
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def write_result(result)
|
|
62
|
+
@result_queue.push result
|
|
63
|
+
nil
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def write_work(work_unit)
|
|
67
|
+
@work_queue.push work_unit
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
class NoWorkUnitsAvailableError < StandardError; end
|
|
72
|
+
class NoWorkUnitsRemainingError < StandardError; end
|
|
73
|
+
class ResultOverdueError < StandardError; end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'spec/runner/example_group_runner'
|
|
3
|
+
require 'spec/example/example_group_methods'
|
|
4
|
+
require 'spec/rake/spectask'
|
|
5
|
+
|
|
6
|
+
require File.dirname(__FILE__) + "/spec/extensions/example_group_methods"
|
|
7
|
+
require File.dirname(__FILE__) + "/spec/extensions/example_methods"
|
|
8
|
+
require File.dirname(__FILE__) + "/spec/extensions/spec_task"
|
|
9
|
+
require File.dirname(__FILE__) + "/spec/extensions/options"
|
|
10
|
+
require File.dirname(__FILE__) + "/spec/extensions/reporter"
|
|
11
|
+
require File.dirname(__FILE__) + "/spec/runner"
|
|
12
|
+
require File.dirname(__FILE__) + "/spec/work_unit"
|
|
13
|
+
require File.dirname(__FILE__) + "/spec/work_result"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module Spec
|
|
2
|
+
module Example
|
|
3
|
+
module ExampleGroupMethods
|
|
4
|
+
class << self
|
|
5
|
+
def assign_instance_method_to_constant(proposed_constant)
|
|
6
|
+
method_sym = proposed_constant.to_s.downcase
|
|
7
|
+
|
|
8
|
+
unless const_defined?(proposed_constant)
|
|
9
|
+
const_set(proposed_constant, instance_method(method_sym))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private :assign_instance_method_to_constant
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
assign_instance_method_to_constant :PREPEND_BEFORE
|
|
17
|
+
assign_instance_method_to_constant :APPEND_BEFORE
|
|
18
|
+
assign_instance_method_to_constant :PREPEND_AFTER
|
|
19
|
+
assign_instance_method_to_constant :APPEND_AFTER
|
|
20
|
+
|
|
21
|
+
def prepend_before(*args, &block)
|
|
22
|
+
check_filter_args(args)
|
|
23
|
+
call_regular_instance_method :prepend_before, *args, &block
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def append_before(*args, &block)
|
|
27
|
+
check_filter_args(args)
|
|
28
|
+
call_regular_instance_method :append_before, *args, &block
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
alias_method :before, :append_before
|
|
32
|
+
|
|
33
|
+
def prepend_after(*args, &block)
|
|
34
|
+
check_filter_args(args)
|
|
35
|
+
call_regular_instance_method :prepend_after, *args, &block
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def append_after(*args, &block)
|
|
39
|
+
check_filter_args(args)
|
|
40
|
+
call_regular_instance_method :append_after, *args, &block
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
alias_method :after, :append_after
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
DeepTestAllBlockWarning =
|
|
48
|
+
"Warning: DeepTest will run before(:all) and after(:all) blocks for *every* test that is run. To remove this warning either convert all before/after blocks to each blocks or set $show_deep_test_all_block_warning to false" unless defined?(DeepTestAllBlockWarning)
|
|
49
|
+
|
|
50
|
+
$show_deep_test_all_block_warning = true
|
|
51
|
+
|
|
52
|
+
def check_filter_args(args)
|
|
53
|
+
if args.first == :all && $show_deep_test_all_block_warning
|
|
54
|
+
$show_deep_test_all_block_warning = false
|
|
55
|
+
$stderr.puts DeepTestAllBlockWarning
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def call_regular_instance_method(sym, *args, &block)
|
|
60
|
+
ExampleGroupMethods.const_get(sym.to_s.upcase).bind(self).call(*args, &block)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Spec
|
|
2
|
+
module Example
|
|
3
|
+
module ExampleMethods
|
|
4
|
+
def identifier
|
|
5
|
+
file, line = implementation_backtrace.first.split(/:/)
|
|
6
|
+
Identifier.new(file, line.to_i, self.class.description, description)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class Identifier
|
|
10
|
+
attr_reader :file, :line, :group_description, :description
|
|
11
|
+
def initialize(file, line, group_description, description)
|
|
12
|
+
@file, @line, @group_description, @description =
|
|
13
|
+
file, line, group_description, description
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def ==(other)
|
|
17
|
+
eql?(other)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def eql?(other)
|
|
21
|
+
File.basename(file) == File.basename(other.file) &&
|
|
22
|
+
line == other.line &&
|
|
23
|
+
group_description == other.group_description &&
|
|
24
|
+
description == other.description
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def hash
|
|
28
|
+
description.hash
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def locate(groups)
|
|
32
|
+
groups.each do |group|
|
|
33
|
+
group.examples.each do |example|
|
|
34
|
+
return example if example.identifier == self
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
raise "Unable to locate example #{self}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def to_s
|
|
41
|
+
"#{group_description} #{description}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Spec
|
|
2
|
+
module Runner
|
|
3
|
+
class Options
|
|
4
|
+
def run_one_example(identifier)
|
|
5
|
+
example = identifier.locate(example_groups)
|
|
6
|
+
SingleExampleRunner.new(self, example).run
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class SingleExampleRunner < ExampleGroupRunner
|
|
10
|
+
def initialize(options, example)
|
|
11
|
+
super(options)
|
|
12
|
+
@example = example
|
|
13
|
+
example_group.extend ExampleGroupHelper
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def example_group
|
|
17
|
+
@example.class
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def example_groups
|
|
21
|
+
[example_group]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def run
|
|
25
|
+
example_group.with_example_objects([@example]) do
|
|
26
|
+
super
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module ExampleGroupHelper
|
|
31
|
+
def with_example_objects(example_objects)
|
|
32
|
+
original_example_objects = @example_objects
|
|
33
|
+
@example_objects = example_objects
|
|
34
|
+
yield
|
|
35
|
+
ensure
|
|
36
|
+
@example_objects = original_example_objects
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'spec/runner/reporter'
|
|
2
|
+
module Spec
|
|
3
|
+
module Runner
|
|
4
|
+
class Reporter
|
|
5
|
+
def example_finished(example, error=nil)
|
|
6
|
+
@examples << example
|
|
7
|
+
|
|
8
|
+
if error.nil?
|
|
9
|
+
example_passed(example)
|
|
10
|
+
elsif Spec::Example::ExamplePendingError === error
|
|
11
|
+
example_pending(example, error.message)
|
|
12
|
+
else
|
|
13
|
+
example_failed(example, error)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def failure(example, error)
|
|
18
|
+
backtrace_tweaker.tweak_backtrace(error)
|
|
19
|
+
example_name = "#{example.class.description} #{example.description}"
|
|
20
|
+
failure = Failure.new(example, error)
|
|
21
|
+
@failures << failure
|
|
22
|
+
formatters.each do |f|
|
|
23
|
+
f.example_failed(example, @failures.length, failure)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
alias_method :example_failed, :failure
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
@deep_test_spec_opts = [
|
|
9
|
+
"--require #{deep_test_path}",
|
|
10
|
+
"--runner 'DeepTest::Spec::Runner:#{deep_test_options.to_command_line}'"
|
|
11
|
+
]
|
|
12
|
+
spec_opts.concat @deep_test_spec_opts
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def spec_opts=(options)
|
|
16
|
+
@spec_opts = (@deep_test_spec_opts || []) + options
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
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
|
+
DeepTest.init(@deep_test_options)
|
|
8
|
+
@blackboard = blackboard
|
|
9
|
+
@workers = @deep_test_options.new_workers
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def blackboard
|
|
13
|
+
# Can't create blackboard as default argument to initialize
|
|
14
|
+
# because ProcessOrchestrator hasn't been invoked at
|
|
15
|
+
# instantiation time
|
|
16
|
+
@blackboard ||= @deep_test_options.server
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def load_files(files)
|
|
20
|
+
@workers.load_files files
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def run
|
|
24
|
+
ProcessOrchestrator.run(@deep_test_options, @workers, self)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def process_work_units
|
|
28
|
+
prepare
|
|
29
|
+
|
|
30
|
+
examples = example_groups.map {|g| g.send(:examples_to_run)}.flatten
|
|
31
|
+
examples_by_location = {}
|
|
32
|
+
examples.each do |example|
|
|
33
|
+
raise "duplicate example: #{example.identifier}" if examples_by_location[example.identifier]
|
|
34
|
+
examples_by_location[example.identifier] = example
|
|
35
|
+
blackboard.write_work Spec::WorkUnit.new(example.identifier)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
success = true
|
|
39
|
+
|
|
40
|
+
missing_exmaples = ResultReader.new(blackboard).read(examples_by_location) do |example, result|
|
|
41
|
+
@options.reporter.example_finished(example, result.error)
|
|
42
|
+
success &= result.success?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
success &= missing_exmaples.empty?
|
|
46
|
+
|
|
47
|
+
missing_exmaples.each do |identifier, example|
|
|
48
|
+
@options.reporter.example_finished(example, WorkUnitNeverReceivedError.new)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
success
|
|
52
|
+
ensure
|
|
53
|
+
finish
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
module Spec
|
|
3
|
+
class WorkResult
|
|
4
|
+
attr_reader :identifier, :output
|
|
5
|
+
|
|
6
|
+
def initialize(identifier, error, output)
|
|
7
|
+
@identifier, @output = identifier, output
|
|
8
|
+
@error = MarshallableExceptionWrapper.new error if error
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def error
|
|
12
|
+
@error.resolve if @error
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ==(other)
|
|
16
|
+
identifier == other.identifier &&
|
|
17
|
+
@error == other.instance_variable_get(:@error)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def failed_due_to_deadlock?
|
|
21
|
+
DeadlockDetector.due_to_deadlock?(@error)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def success?
|
|
25
|
+
error.nil? || ::Spec::Example::ExamplePendingError === error
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def deadlock_result
|
|
29
|
+
WorkResult.new(identifier, nil, '-deadlock-')
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
module Spec
|
|
3
|
+
class WorkUnit
|
|
4
|
+
def initialize(identifier)
|
|
5
|
+
@identifier = identifier
|
|
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 = ::Spec::Runner.options
|
|
12
|
+
::Spec::Runner.use ::Spec::Runner.options.dup
|
|
13
|
+
::Spec::Runner.options.reporter = ResultReporter.new(@identifier)
|
|
14
|
+
result = run_without_deadlock_protection
|
|
15
|
+
result = run_without_deadlock_protection if result.failed_due_to_deadlock?
|
|
16
|
+
result = result.deadlock_result if result.failed_due_to_deadlock?
|
|
17
|
+
result
|
|
18
|
+
ensure
|
|
19
|
+
::Spec::Runner.use original_options
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_s
|
|
23
|
+
"#{@identifier.group_description}: #{@identifier.description}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected
|
|
27
|
+
|
|
28
|
+
def run_without_deadlock_protection
|
|
29
|
+
output = capture_stdout do
|
|
30
|
+
::Spec::Runner.options.run_one_example(@identifier)
|
|
31
|
+
end
|
|
32
|
+
::Spec::Runner.options.reporter.result(output)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class ResultReporter
|
|
36
|
+
attr_reader :result
|
|
37
|
+
|
|
38
|
+
def initialize(identifier)
|
|
39
|
+
@identifier = identifier
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def add_example_group(example_group); end
|
|
43
|
+
def dump; end
|
|
44
|
+
def end; end
|
|
45
|
+
def example_started(name); end
|
|
46
|
+
|
|
47
|
+
def example_finished(example, error)
|
|
48
|
+
@example, @error = example, error
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def result(output)
|
|
52
|
+
Spec::WorkResult.new(@identifier, @error, output)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def start(example); end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|