deep_test_pre 2.0
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 +199 -0
- data/Rakefile +137 -0
- data/lib/deep_test.rb +78 -0
- data/lib/deep_test/agent.rb +108 -0
- data/lib/deep_test/central_command.rb +165 -0
- data/lib/deep_test/cpu_info.rb +22 -0
- data/lib/deep_test/database/mysql_setup_listener.rb +112 -0
- data/lib/deep_test/database/setup_listener.rb +116 -0
- data/lib/deep_test/deadlock_detector.rb +7 -0
- data/lib/deep_test/demon.rb +25 -0
- data/lib/deep_test/distributed/beachhead.rb +104 -0
- data/lib/deep_test/distributed/dispatch_controller.rb +60 -0
- data/lib/deep_test/distributed/establish_beachhead.rb +19 -0
- data/lib/deep_test/distributed/filename_resolver.rb +40 -0
- data/lib/deep_test/distributed/landing_fleet.rb +30 -0
- data/lib/deep_test/distributed/landing_ship.rb +60 -0
- data/lib/deep_test/distributed/remote_deployment.rb +56 -0
- data/lib/deep_test/distributed/rsync.rb +50 -0
- data/lib/deep_test/distributed/shell_environment.rb +50 -0
- data/lib/deep_test/distributed/ssh_client_connection_info.rb +14 -0
- data/lib/deep_test/extensions/object_extension.rb +40 -0
- data/lib/deep_test/failure_message.rb +19 -0
- data/lib/deep_test/lib_root.rb +4 -0
- data/lib/deep_test/listener_list.rb +17 -0
- data/lib/deep_test/local_deployment.rb +46 -0
- data/lib/deep_test/logger.rb +32 -0
- data/lib/deep_test/main.rb +41 -0
- data/lib/deep_test/marshallable_exception_wrapper.rb +44 -0
- data/lib/deep_test/metrics/data.rb +34 -0
- data/lib/deep_test/metrics/measurement.rb +39 -0
- data/lib/deep_test/null_listener.rb +62 -0
- data/lib/deep_test/options.rb +113 -0
- data/lib/deep_test/proxy_io.rb +77 -0
- data/lib/deep_test/rake_tasks.rb +13 -0
- data/lib/deep_test/result_reader.rb +40 -0
- data/lib/deep_test/rspec_detector.rb +21 -0
- data/lib/deep_test/spec.rb +17 -0
- data/lib/deep_test/spec/extensions/example_group_methods.rb +64 -0
- data/lib/deep_test/spec/extensions/example_methods.rb +52 -0
- data/lib/deep_test/spec/extensions/options.rb +43 -0
- data/lib/deep_test/spec/extensions/spec_task.rb +21 -0
- data/lib/deep_test/spec/runner.rb +72 -0
- data/lib/deep_test/spec/work_result.rb +35 -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/run_test_suite.rb +5 -0
- data/lib/deep_test/test/runner.rb +24 -0
- data/lib/deep_test/test/supervised_test_suite.rb +48 -0
- data/lib/deep_test/test/work_result.rb +35 -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 +74 -0
- data/lib/deep_test/ui/null.rb +17 -0
- data/lib/deep_test/warlock.rb +146 -0
- data/lib/telegraph.rb +29 -0
- data/lib/telegraph/ack_sequence.rb +14 -0
- data/lib/telegraph/logging.rb +20 -0
- data/lib/telegraph/message.rb +39 -0
- data/lib/telegraph/operator.rb +47 -0
- data/lib/telegraph/switchboard.rb +57 -0
- data/lib/telegraph/wire.rb +73 -0
- data/test/deep_test/agent_test.rb +175 -0
- data/test/deep_test/central_command_test.rb +147 -0
- data/test/deep_test/cpu_info_test.rb +33 -0
- data/test/deep_test/database/mysql_setup_listener_test.rb +18 -0
- data/test/deep_test/demon_test.rb +23 -0
- data/test/deep_test/distributed/beachhead_test.rb +67 -0
- data/test/deep_test/distributed/dispatch_controller_test.rb +162 -0
- data/test/deep_test/distributed/filename_resolver_test.rb +56 -0
- data/test/deep_test/distributed/landing_fleet_test.rb +55 -0
- data/test/deep_test/distributed/landing_ship_test.rb +48 -0
- data/test/deep_test/distributed/remote_deployment_test.rb +134 -0
- data/test/deep_test/distributed/rsync_test.rb +47 -0
- data/test/deep_test/distributed/shell_environment_test.rb +108 -0
- data/test/deep_test/distributed/ssh_client_connection_info_test.rb +34 -0
- data/test/deep_test/extensions/object_extension_test.rb +37 -0
- data/test/deep_test/listener_list_test.rb +22 -0
- data/test/deep_test/local_deployment_test.rb +19 -0
- data/test/deep_test/logger_test.rb +38 -0
- data/test/deep_test/main_test.rb +12 -0
- data/test/deep_test/marshallable_exception_wrapper_test.rb +46 -0
- data/test/deep_test/metrics/data_test.rb +22 -0
- data/test/deep_test/metrics/measurement_test.rb +18 -0
- data/test/deep_test/proxy_io_test.rb +104 -0
- data/test/deep_test/result_reader_test.rb +128 -0
- data/test/deep_test/test/extensions/error_test.rb +42 -0
- data/test/deep_test/test/runner_test.rb +11 -0
- data/test/deep_test/test/supervised_test_suite_test.rb +107 -0
- data/test/deep_test/test/work_result_test.rb +85 -0
- data/test/deep_test/test/work_unit_test.rb +63 -0
- data/test/deep_test/test_task_test.rb +15 -0
- data/test/deep_test/ui/console_test.rb +13 -0
- data/test/deep_test/warlock_test.rb +40 -0
- data/test/test_helper.rb +30 -0
- data/test/test_task_test.rb +75 -0
- metadata +156 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
Option = Struct.new :name, :default unless defined?(Option)
|
|
3
|
+
|
|
4
|
+
class Options
|
|
5
|
+
unless defined?(VALID_OPTIONS)
|
|
6
|
+
VALID_OPTIONS = [
|
|
7
|
+
Option.new(:distributed_hosts, nil),
|
|
8
|
+
Option.new(:number_of_agents, nil),
|
|
9
|
+
Option.new(:metrics_file, nil),
|
|
10
|
+
Option.new(:pattern, nil),
|
|
11
|
+
Option.new(:server_port, nil),
|
|
12
|
+
Option.new(:sync_options, {}),
|
|
13
|
+
Option.new(:ui, "DeepTest::UI::Console"),
|
|
14
|
+
Option.new(:listener, "DeepTest::NullListener"),
|
|
15
|
+
]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
attr_accessor *VALID_OPTIONS.map {|o| o.name}
|
|
19
|
+
attr_accessor :ssh_client_connection_info, :environment_log_level
|
|
20
|
+
|
|
21
|
+
def number_of_agents
|
|
22
|
+
return CpuInfo.new.count unless @number_of_agents
|
|
23
|
+
@number_of_agents
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ui=(value)
|
|
27
|
+
@ui = value.to_s
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def listener=(value)
|
|
31
|
+
@listener = value.to_s
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.from_command_line(command_line)
|
|
35
|
+
return new({}) if command_line.nil? || command_line.empty?
|
|
36
|
+
Marshal.load Base64.decode64(command_line)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def initialize(hash)
|
|
40
|
+
@origin_hostname = Socket.gethostname
|
|
41
|
+
check_option_keys(hash)
|
|
42
|
+
VALID_OPTIONS.each do |option|
|
|
43
|
+
send("#{option.name}=", hash[option.name] || hash[option.name.to_s] || option.default)
|
|
44
|
+
end
|
|
45
|
+
self.environment_log_level = ENV['DEEP_TEST_LOG_LEVEL']
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def gathering_metrics?
|
|
49
|
+
!@metrics_file.nil?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def new_listener_list
|
|
53
|
+
listeners = listener.split(',').map do |listener|
|
|
54
|
+
eval(listener).new
|
|
55
|
+
end
|
|
56
|
+
ListenerList.new(listeners)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def origin_hostname
|
|
60
|
+
(Socket.gethostname == @origin_hostname) ? 'localhost' : @origin_hostname
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def connect_to_central_command
|
|
64
|
+
address = ssh_client_connection_info ? ssh_client_connection_info.address : "localhost"
|
|
65
|
+
Telegraph::Wire.connect(address, server_port) do |wire|
|
|
66
|
+
yield wire
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Don't store UI instances in the options instance, which will
|
|
71
|
+
# need to be dumped over Telegraph since UI instances may not be dumpable.
|
|
72
|
+
#
|
|
73
|
+
UI_INSTANCES = {} unless defined?(UI_INSTANCES)
|
|
74
|
+
def ui_instance
|
|
75
|
+
UI_INSTANCES[self] ||= eval(ui).new(self)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def to_command_line
|
|
79
|
+
Base64.encode64(Marshal.dump(self)).gsub("\n","")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def mirror_path
|
|
83
|
+
raise "No source directory specified in sync_options" unless sync_options[:source]
|
|
84
|
+
relative_mirror_path = @origin_hostname + sync_options[:source].gsub('/','_')
|
|
85
|
+
"#{sync_options[:remote_base_dir] || '/tmp'}/#{relative_mirror_path}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def new_deployment
|
|
89
|
+
if distributed_hosts.nil?
|
|
90
|
+
LocalDeployment.new self
|
|
91
|
+
else
|
|
92
|
+
Distributed::RemoteDeployment.new self, new_landing_fleet, LocalDeployment.new(self)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def new_landing_fleet
|
|
97
|
+
landing_ships = distributed_hosts.map do |host|
|
|
98
|
+
Distributed::LandingShip.new :address => host
|
|
99
|
+
end
|
|
100
|
+
Distributed::LandingFleet.new self, landing_ships
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
protected
|
|
104
|
+
|
|
105
|
+
def check_option_keys(hash)
|
|
106
|
+
hash.keys.each do |key|
|
|
107
|
+
raise InvalidOptionError.new("#{key} is not a valid option") unless VALID_OPTIONS.any? {|o| o.name == key.to_sym}
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
class InvalidOptionError < StandardError; end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
class ProxyIO < StringIO
|
|
3
|
+
def initialize(output_module, wire)
|
|
4
|
+
@output_module = output_module
|
|
5
|
+
@wire = wire
|
|
6
|
+
super("")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def write(*args)
|
|
10
|
+
super
|
|
11
|
+
@wire.send_message @output_module::Output.new(string)
|
|
12
|
+
self.string = ""
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def flush
|
|
16
|
+
@wire.send_message @output_module::Flush.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.replace_stdout_stderr!(wire)
|
|
20
|
+
old_stdout_const, old_stdout_global = STDOUT, $stdout
|
|
21
|
+
old_stderr_const, old_stderr_global = STDERR, $stderr
|
|
22
|
+
|
|
23
|
+
supress_warnings { Object.const_set :STDOUT, ProxyIO.new(Stdout, wire) }
|
|
24
|
+
$stdout = STDOUT
|
|
25
|
+
|
|
26
|
+
supress_warnings { Object.const_set :STDERR, ProxyIO.new(Stderr, wire) }
|
|
27
|
+
$stderr = STDERR
|
|
28
|
+
|
|
29
|
+
DeepTest.logger = nil
|
|
30
|
+
|
|
31
|
+
yield
|
|
32
|
+
ensure
|
|
33
|
+
$stdout = old_stdout_global
|
|
34
|
+
supress_warnings { Object.const_set :STDOUT, old_stdout_const }
|
|
35
|
+
|
|
36
|
+
$stderr = old_stderr_global
|
|
37
|
+
supress_warnings { Object.const_set :STDERR, old_stderr_const }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.supress_warnings
|
|
41
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
|
42
|
+
yield
|
|
43
|
+
ensure
|
|
44
|
+
$VERBOSE = old_verbose
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class AbstractOutput
|
|
48
|
+
include CentralCommand::Operation
|
|
49
|
+
attr_reader :s
|
|
50
|
+
def initialize(s); @s = s; end
|
|
51
|
+
def execute; stream.write s; end
|
|
52
|
+
def ==(other); self.class == other.class && s == other.s; end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
module Stdout
|
|
56
|
+
class Output < AbstractOutput
|
|
57
|
+
def stream; $stdout; end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class Flush
|
|
61
|
+
include CentralCommand::Operation
|
|
62
|
+
def execute; $stdout.flush; end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
module Stderr
|
|
67
|
+
class Output < AbstractOutput
|
|
68
|
+
def stream; $stderr; end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
class Flush
|
|
72
|
+
include CentralCommand::Operation
|
|
73
|
+
def execute; $stderr.flush; end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require "socket"
|
|
2
|
+
require "base64"
|
|
3
|
+
|
|
4
|
+
require File.dirname(__FILE__) + "/options"
|
|
5
|
+
require File.dirname(__FILE__) + "/cpu_info"
|
|
6
|
+
require File.dirname(__FILE__) + "/test_task"
|
|
7
|
+
require File.dirname(__FILE__) + "/rspec_detector"
|
|
8
|
+
|
|
9
|
+
DeepTest::RSpecDetector.if_rspec_available do
|
|
10
|
+
require 'spec/rake/spectask'
|
|
11
|
+
require File.dirname(__FILE__) + "/spec/extensions/spec_task"
|
|
12
|
+
end
|
|
13
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module DeepTest
|
|
2
|
+
class ResultReader
|
|
3
|
+
def initialize(central_command)
|
|
4
|
+
@central_command = central_command
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def read(original_work_units_by_id)
|
|
8
|
+
work_units_by_id = original_work_units_by_id.dup
|
|
9
|
+
errors = 0
|
|
10
|
+
|
|
11
|
+
begin
|
|
12
|
+
until errors == work_units_by_id.size
|
|
13
|
+
Thread.pass
|
|
14
|
+
result = @central_command.take_result
|
|
15
|
+
next if result.nil?
|
|
16
|
+
|
|
17
|
+
if Agent::Error === result
|
|
18
|
+
puts result
|
|
19
|
+
errors += 1
|
|
20
|
+
else
|
|
21
|
+
if result.respond_to?(:output) && (output = result.output)
|
|
22
|
+
print output
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
work_unit = work_units_by_id.delete(result.identifier)
|
|
26
|
+
yield [work_unit, result]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
rescue CentralCommand::NoAgentsRunningError
|
|
30
|
+
FailureMessage.show "DeepTest Agents Are Not Running", <<-end_msg
|
|
31
|
+
DeepTest's test running agents have not contacted the
|
|
32
|
+
server to indicate they are still running.
|
|
33
|
+
Shutting down the test run on the assumption that they have died.
|
|
34
|
+
end_msg
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
work_units_by_id
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -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,17 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'spec/runner/example_group_runner'
|
|
3
|
+
if ::Spec::VERSION::MAJOR == 1 &&
|
|
4
|
+
::Spec::VERSION::MINOR == 1 &&
|
|
5
|
+
::Spec::VERSION::TINY >= 12
|
|
6
|
+
require 'spec/example/before_and_after_hooks'
|
|
7
|
+
end
|
|
8
|
+
require 'spec/example/example_group_methods'
|
|
9
|
+
require 'spec/rake/spectask'
|
|
10
|
+
|
|
11
|
+
require File.dirname(__FILE__) + "/spec/extensions/example_group_methods"
|
|
12
|
+
require File.dirname(__FILE__) + "/spec/extensions/example_methods"
|
|
13
|
+
require File.dirname(__FILE__) + "/spec/extensions/spec_task"
|
|
14
|
+
require File.dirname(__FILE__) + "/spec/extensions/options"
|
|
15
|
+
require File.dirname(__FILE__) + "/spec/runner"
|
|
16
|
+
require File.dirname(__FILE__) + "/spec/work_unit"
|
|
17
|
+
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,52 @@
|
|
|
1
|
+
module Spec
|
|
2
|
+
module Example
|
|
3
|
+
module ExampleMethods
|
|
4
|
+
def identifier
|
|
5
|
+
if ::Spec::VERSION::MAJOR == 1 &&
|
|
6
|
+
::Spec::VERSION::MINOR == 1 &&
|
|
7
|
+
::Spec::VERSION::TINY >= 12
|
|
8
|
+
file, line = eval("caller", @_implementation).first.split(/:/)
|
|
9
|
+
else
|
|
10
|
+
file, line = implementation_backtrace.first.split(/:/)
|
|
11
|
+
end
|
|
12
|
+
Identifier.new(file, line.to_i, self.class.description, description)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class Identifier
|
|
16
|
+
attr_reader :file, :line, :group_description, :description
|
|
17
|
+
def initialize(file, line, group_description, description)
|
|
18
|
+
@file, @line, @group_description, @description =
|
|
19
|
+
file, line, group_description, description
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def ==(other)
|
|
23
|
+
eql?(other)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def eql?(other)
|
|
27
|
+
File.basename(file) == File.basename(other.file) &&
|
|
28
|
+
line == other.line &&
|
|
29
|
+
group_description == other.group_description &&
|
|
30
|
+
description == other.description
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def hash
|
|
34
|
+
description.hash
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def locate(groups)
|
|
38
|
+
groups.each do |group|
|
|
39
|
+
group.examples.each do |example|
|
|
40
|
+
return example if example.identifier == self
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
raise "Unable to locate example #{self}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def to_s
|
|
47
|
+
"#{group_description} #{description}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
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
|
+
|