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.
Files changed (98) hide show
  1. data/CHANGELOG +47 -0
  2. data/README.rdoc +199 -0
  3. data/Rakefile +137 -0
  4. data/lib/deep_test.rb +78 -0
  5. data/lib/deep_test/agent.rb +108 -0
  6. data/lib/deep_test/central_command.rb +165 -0
  7. data/lib/deep_test/cpu_info.rb +22 -0
  8. data/lib/deep_test/database/mysql_setup_listener.rb +112 -0
  9. data/lib/deep_test/database/setup_listener.rb +116 -0
  10. data/lib/deep_test/deadlock_detector.rb +7 -0
  11. data/lib/deep_test/demon.rb +25 -0
  12. data/lib/deep_test/distributed/beachhead.rb +104 -0
  13. data/lib/deep_test/distributed/dispatch_controller.rb +60 -0
  14. data/lib/deep_test/distributed/establish_beachhead.rb +19 -0
  15. data/lib/deep_test/distributed/filename_resolver.rb +40 -0
  16. data/lib/deep_test/distributed/landing_fleet.rb +30 -0
  17. data/lib/deep_test/distributed/landing_ship.rb +60 -0
  18. data/lib/deep_test/distributed/remote_deployment.rb +56 -0
  19. data/lib/deep_test/distributed/rsync.rb +50 -0
  20. data/lib/deep_test/distributed/shell_environment.rb +50 -0
  21. data/lib/deep_test/distributed/ssh_client_connection_info.rb +14 -0
  22. data/lib/deep_test/extensions/object_extension.rb +40 -0
  23. data/lib/deep_test/failure_message.rb +19 -0
  24. data/lib/deep_test/lib_root.rb +4 -0
  25. data/lib/deep_test/listener_list.rb +17 -0
  26. data/lib/deep_test/local_deployment.rb +46 -0
  27. data/lib/deep_test/logger.rb +32 -0
  28. data/lib/deep_test/main.rb +41 -0
  29. data/lib/deep_test/marshallable_exception_wrapper.rb +44 -0
  30. data/lib/deep_test/metrics/data.rb +34 -0
  31. data/lib/deep_test/metrics/measurement.rb +39 -0
  32. data/lib/deep_test/null_listener.rb +62 -0
  33. data/lib/deep_test/options.rb +113 -0
  34. data/lib/deep_test/proxy_io.rb +77 -0
  35. data/lib/deep_test/rake_tasks.rb +13 -0
  36. data/lib/deep_test/result_reader.rb +40 -0
  37. data/lib/deep_test/rspec_detector.rb +21 -0
  38. data/lib/deep_test/spec.rb +17 -0
  39. data/lib/deep_test/spec/extensions/example_group_methods.rb +64 -0
  40. data/lib/deep_test/spec/extensions/example_methods.rb +52 -0
  41. data/lib/deep_test/spec/extensions/options.rb +43 -0
  42. data/lib/deep_test/spec/extensions/spec_task.rb +21 -0
  43. data/lib/deep_test/spec/runner.rb +72 -0
  44. data/lib/deep_test/spec/work_result.rb +35 -0
  45. data/lib/deep_test/spec/work_unit.rb +59 -0
  46. data/lib/deep_test/test.rb +10 -0
  47. data/lib/deep_test/test/extensions/error.rb +14 -0
  48. data/lib/deep_test/test/run_test_suite.rb +5 -0
  49. data/lib/deep_test/test/runner.rb +24 -0
  50. data/lib/deep_test/test/supervised_test_suite.rb +48 -0
  51. data/lib/deep_test/test/work_result.rb +35 -0
  52. data/lib/deep_test/test/work_unit.rb +40 -0
  53. data/lib/deep_test/test_task.rb +47 -0
  54. data/lib/deep_test/ui/console.rb +74 -0
  55. data/lib/deep_test/ui/null.rb +17 -0
  56. data/lib/deep_test/warlock.rb +146 -0
  57. data/lib/telegraph.rb +29 -0
  58. data/lib/telegraph/ack_sequence.rb +14 -0
  59. data/lib/telegraph/logging.rb +20 -0
  60. data/lib/telegraph/message.rb +39 -0
  61. data/lib/telegraph/operator.rb +47 -0
  62. data/lib/telegraph/switchboard.rb +57 -0
  63. data/lib/telegraph/wire.rb +73 -0
  64. data/test/deep_test/agent_test.rb +175 -0
  65. data/test/deep_test/central_command_test.rb +147 -0
  66. data/test/deep_test/cpu_info_test.rb +33 -0
  67. data/test/deep_test/database/mysql_setup_listener_test.rb +18 -0
  68. data/test/deep_test/demon_test.rb +23 -0
  69. data/test/deep_test/distributed/beachhead_test.rb +67 -0
  70. data/test/deep_test/distributed/dispatch_controller_test.rb +162 -0
  71. data/test/deep_test/distributed/filename_resolver_test.rb +56 -0
  72. data/test/deep_test/distributed/landing_fleet_test.rb +55 -0
  73. data/test/deep_test/distributed/landing_ship_test.rb +48 -0
  74. data/test/deep_test/distributed/remote_deployment_test.rb +134 -0
  75. data/test/deep_test/distributed/rsync_test.rb +47 -0
  76. data/test/deep_test/distributed/shell_environment_test.rb +108 -0
  77. data/test/deep_test/distributed/ssh_client_connection_info_test.rb +34 -0
  78. data/test/deep_test/extensions/object_extension_test.rb +37 -0
  79. data/test/deep_test/listener_list_test.rb +22 -0
  80. data/test/deep_test/local_deployment_test.rb +19 -0
  81. data/test/deep_test/logger_test.rb +38 -0
  82. data/test/deep_test/main_test.rb +12 -0
  83. data/test/deep_test/marshallable_exception_wrapper_test.rb +46 -0
  84. data/test/deep_test/metrics/data_test.rb +22 -0
  85. data/test/deep_test/metrics/measurement_test.rb +18 -0
  86. data/test/deep_test/proxy_io_test.rb +104 -0
  87. data/test/deep_test/result_reader_test.rb +128 -0
  88. data/test/deep_test/test/extensions/error_test.rb +42 -0
  89. data/test/deep_test/test/runner_test.rb +11 -0
  90. data/test/deep_test/test/supervised_test_suite_test.rb +107 -0
  91. data/test/deep_test/test/work_result_test.rb +85 -0
  92. data/test/deep_test/test/work_unit_test.rb +63 -0
  93. data/test/deep_test/test_task_test.rb +15 -0
  94. data/test/deep_test/ui/console_test.rb +13 -0
  95. data/test/deep_test/warlock_test.rb +40 -0
  96. data/test/test_helper.rb +30 -0
  97. data/test/test_task_test.rb +75 -0
  98. metadata +156 -0
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + "/../../lib_root"
2
+
3
+ module Spec
4
+ module Rake
5
+ class SpecTask
6
+ def deep_test(options)
7
+ deep_test_options = DeepTest::Options.new(options)
8
+ deep_test_path = File.expand_path(DeepTest::LIB_ROOT + "/deep_test")
9
+ @deep_test_spec_opts = [
10
+ "--require #{deep_test_path}",
11
+ "--runner 'DeepTest::Spec::Runner:#{deep_test_options.to_command_line}'"
12
+ ]
13
+ spec_opts.concat @deep_test_spec_opts
14
+ end
15
+
16
+ def spec_opts=(options)
17
+ @spec_opts = (@deep_test_spec_opts || []) + options
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,72 @@
1
+ module DeepTest
2
+ module Spec
3
+ class Runner < ::Spec::Runner::ExampleGroupRunner
4
+ def initialize(options, deep_test_options)
5
+ super(options)
6
+ if ::Spec::VERSION::MAJOR == 1 &&
7
+ ::Spec::VERSION::MINOR == 1 &&
8
+ ::Spec::VERSION::TINY >= 12
9
+ @runner_options = options # added to make work with 1.1.12
10
+ end
11
+ @deep_test_options = DeepTest::Options.from_command_line(deep_test_options)
12
+ end
13
+
14
+ def main
15
+ @main ||= Main.new @deep_test_options, @deep_test_options.new_deployment, self
16
+ end
17
+
18
+ def central_command
19
+ # Can't create central_command as default argument to initialize
20
+ # because Main hasn't been invoked at
21
+ # instantiation time
22
+ @central_command ||= main.central_command
23
+ end
24
+
25
+ def load_files(files)
26
+ main.load_files files
27
+ end
28
+
29
+ def run
30
+ main.run
31
+ end
32
+
33
+ def process_work_units(central_command)
34
+ prepare
35
+
36
+ examples = (example_groups.map do |g|
37
+ if ::Spec::VERSION::MAJOR == 1 &&
38
+ ::Spec::VERSION::MINOR == 1 &&
39
+ ::Spec::VERSION::TINY >= 12
40
+ g.send(:examples_to_run, @runner_options) # added @runner_options to make wiork with 1.1.12
41
+ else
42
+ g.send(:examples_to_run)
43
+ end
44
+ end).flatten
45
+ examples_by_location = {}
46
+ examples.each do |example|
47
+ raise "duplicate example: #{example.identifier}" if examples_by_location[example.identifier]
48
+ examples_by_location[example.identifier] = example
49
+ central_command.write_work Spec::WorkUnit.new(example.identifier)
50
+ end
51
+
52
+ success = true
53
+
54
+ missing_examples = ResultReader.new(central_command).read(examples_by_location) do |example, result|
55
+ @options.reporter.example_finished(example, result.error)
56
+ success &= result.success?
57
+ end
58
+
59
+ success &= missing_examples.empty?
60
+
61
+ if missing_examples.any?
62
+ @options.reporter.example_finished(examples_by_location[missing_examples.keys.first],
63
+ IncompleteTestRunError.new(missing_examples.size))
64
+ end
65
+
66
+ success
67
+ ensure
68
+ finish
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,35 @@
1
+ module DeepTest
2
+ module Spec
3
+ class WorkResult
4
+ include CentralCommand::Result
5
+
6
+ attr_reader :identifier, :output
7
+
8
+ def initialize(identifier, error, output)
9
+ @identifier, @output = identifier, output
10
+ @error = MarshallableExceptionWrapper.new error if error
11
+ end
12
+
13
+ def error
14
+ @error.resolve if @error
15
+ end
16
+
17
+ def ==(other)
18
+ identifier == other.identifier &&
19
+ @error == other.instance_variable_get(:@error)
20
+ end
21
+
22
+ def failed_due_to_deadlock?
23
+ DeadlockDetector.due_to_deadlock?(@error)
24
+ end
25
+
26
+ def success?
27
+ error.nil? || ::Spec::Example::ExamplePendingError === error
28
+ end
29
+
30
+ def deadlock_result
31
+ WorkResult.new(identifier, nil, '-deadlock-')
32
+ end
33
+ end
34
+ end
35
+ 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
@@ -0,0 +1,10 @@
1
+ require "test/unit/testresult"
2
+ require "test/unit/error"
3
+ require 'test/unit/failure'
4
+ require 'test/unit/autorunner'
5
+
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"
10
+ require File.dirname(__FILE__) + "/test/work_result"
@@ -0,0 +1,14 @@
1
+ module Test
2
+ module Unit
3
+ class Error
4
+ def resolve_marshallable_exception
5
+ @exception = @exception.resolve if @exception.kind_of?(DeepTest::MarshallableExceptionWrapper)
6
+ end
7
+
8
+ def make_exception_marshallable
9
+ return if @exception.kind_of?(DeepTest::MarshallableExceptionWrapper)
10
+ @exception = DeepTest::MarshallableExceptionWrapper.new(@exception)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + "/../../deep_test"
2
+ options = DeepTest::Options.from_command_line(ARGV[0])
3
+ main = DeepTest::Main.new options, options.new_deployment, DeepTest::Test::Runner.new(options)
4
+ main.load_files Dir.glob(options.pattern)
5
+ main.run
@@ -0,0 +1,24 @@
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 process_work_units(central_command)
16
+ suite = ::Test::Unit::AutoRunner::COLLECTORS[:objectspace].call NO_FILTERS
17
+ supervised_suite = DeepTest::Test::SupervisedTestSuite.new(suite, central_command)
18
+ require 'test/unit/ui/console/testrunner'
19
+ result = ::Test::Unit::UI::Console::TestRunner.run(supervised_suite, ::Test::Unit::UI::NORMAL)
20
+ result.passed?
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,48 @@
1
+ module DeepTest
2
+ module Test
3
+ class SupervisedTestSuite
4
+ def initialize(suite, central_command)
5
+ @suite = suite
6
+ @central_command = central_command
7
+ end
8
+
9
+ def run(result, &progress_block)
10
+ yield ::Test::Unit::TestSuite::STARTED, @suite.name
11
+ tests_by_name = {}
12
+ add_tests @suite, tests_by_name
13
+ read_results result, tests_by_name, &progress_block
14
+ yield ::Test::Unit::TestSuite::FINISHED, @suite.name
15
+ end
16
+
17
+ def size
18
+ @suite.size
19
+ end
20
+
21
+ def add_tests(test_suite, tests_by_name)
22
+ if test_suite.respond_to? :tests
23
+ test_suite.tests.each do |test|
24
+ add_tests(test, tests_by_name)
25
+ end
26
+ else
27
+ tests_by_name[test_suite.name] = test_suite
28
+ @central_command.write_work Test::WorkUnit.new(test_suite)
29
+ end
30
+ end
31
+
32
+ def read_results(result, tests_by_name)
33
+ DeepTest.logger.debug { "SupervisedTestSuite: going to read #{tests_by_name.size} results" }
34
+ missing_tests =
35
+ ResultReader.new(@central_command).read(tests_by_name) do |test, remote_result|
36
+ remote_result.add_to result
37
+ yield ::Test::Unit::TestCase::FINISHED, test.name if block_given?
38
+ end
39
+
40
+ if missing_tests.any?
41
+ result.add_error ::Test::Unit::Error.new("DeepTest Test Run", IncompleteTestRunError.new(missing_tests.size))
42
+ end
43
+ ensure
44
+ DeepTest.logger.debug { "SupervisedTestSuite: exiting with #{missing_tests.size} results left" }
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,35 @@
1
+ module DeepTest
2
+ module Test
3
+ class WorkResult < ::Test::Unit::TestResult
4
+ include CentralCommand::Result
5
+ attr_reader :identifier
6
+ attr_accessor :output
7
+
8
+ def initialize(identifier)
9
+ super()
10
+ @identifier = identifier
11
+ end
12
+
13
+ def add_to(result)
14
+ @failures.each {|e| result.add_failure(e)}
15
+
16
+ @errors.each do |e|
17
+ e.resolve_marshallable_exception
18
+ result.add_error(e)
19
+ end
20
+
21
+ assertion_count.times {result.add_assertion}
22
+ run_count.times {result.add_run}
23
+ end
24
+
25
+ def add_error(error)
26
+ error.make_exception_marshallable
27
+ super(error)
28
+ end
29
+
30
+ def failed_due_to_deadlock?
31
+ @errors.any? && DeepTest::DeadlockDetector.due_to_deadlock?(@errors.last)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
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 = WorkResult.new(@test_case.name)
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
+ def to_s
25
+ @test_case.to_s
26
+ end
27
+
28
+ protected
29
+
30
+ def run_without_deadlock_protection
31
+ result = WorkResult.new(@test_case.name)
32
+ output = capture_stdout do
33
+ @test_case.run(result) {|channel,event|}
34
+ end
35
+ result.output = output
36
+ result
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,47 @@
1
+ module DeepTest
2
+ class TestTask
3
+ attr_accessor :libs, :requires
4
+
5
+ def initialize(name = :deep_test)
6
+ @requires = []
7
+ @name = name
8
+ @libs = ["lib"]
9
+ @options = Options.new({})
10
+ self.pattern = "test/**/*_test.rb"
11
+ yield self if block_given?
12
+ define
13
+ end
14
+
15
+ def define
16
+ require 'rake'
17
+ desc "Run '#{@name}' suite using DeepTest"
18
+ task @name do
19
+ lib_options = @libs.any? ? "-I" + @libs.join(File::PATH_SEPARATOR) : ""
20
+ require_options = requires.map {|f| "-r#{f}"}.join(" ")
21
+ ruby "#{lib_options} #{require_options} #{runner} '#{@options.to_command_line}'"
22
+ end
23
+ end
24
+
25
+ Options::VALID_OPTIONS.each do |option|
26
+ eval <<-end_src
27
+ def #{option.name}
28
+ @options.#{option.name}
29
+ end
30
+
31
+ def #{option.name}=(value)
32
+ @options.#{option.name} = value
33
+ end
34
+ end_src
35
+ end
36
+
37
+ def pattern=(pattern)
38
+ @options.pattern = Dir.pwd + "/" + pattern
39
+ end
40
+
41
+ private
42
+
43
+ def runner
44
+ File.expand_path(File.dirname(__FILE__) + "/test/run_test_suite.rb")
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,74 @@
1
+ module DeepTest
2
+ module UI
3
+ class Console
4
+ def initialize(options)
5
+ end
6
+
7
+ METHOD_DESCRIPTIONS = {
8
+ :push_code => "Synchronizing working copies on distributed machines",
9
+ :establish_beachhead => "Spawning test environment processes",
10
+ :load_files => "Loading test files for agents",
11
+ :deploy_agents => "Deploying agents",
12
+ } unless defined?(METHOD_DESCRIPTIONS)
13
+
14
+ def distributed_failover_to_local(method, exception)
15
+ FailureMessage.show "Distributed DeepTest Failure", <<-end_msg
16
+ Failed during #{method}
17
+ #{exception.message}
18
+ Failing over to local run
19
+ end_msg
20
+ end
21
+
22
+ def dispatch_starting(method_name)
23
+ @spinner.stop if @spinner
24
+ @spinner = Spinner.new(label(method_name))
25
+ @spinner.start
26
+ end
27
+
28
+ def label(method_name)
29
+ METHOD_DESCRIPTIONS[method_name.to_sym] || method_name.to_s
30
+ end
31
+
32
+ def dispatch_finished(method_name)
33
+ @spinner.stop if @spinner
34
+ @spinner = nil
35
+ end
36
+
37
+ class Spinner
38
+ FRAMES = ['|', '/', '-', '\\'] unless defined?(FRAMES)
39
+ BACKSPACE = "\x08" unless defined?(BACKSPACE)
40
+ SECONDS_PER_FRAME = 0.5 / 4 unless defined?(SECONDS_PER_FRAME)
41
+
42
+ def initialize(label)
43
+ @label = label
44
+ end
45
+
46
+ def start
47
+ @start_time = Time.now
48
+ show "#{@label}: "
49
+ @thread = Thread.new do
50
+ index = 0
51
+ loop do
52
+ show FRAMES[index]
53
+ sleep SECONDS_PER_FRAME
54
+ show BACKSPACE
55
+ index = (index + 1) % FRAMES.length
56
+ end
57
+ end
58
+ end
59
+
60
+ def stop
61
+ @stop_time = Time.now
62
+ @thread.kill if @thread
63
+ show BACKSPACE
64
+ show("finished in %.2f seconds\n" % (@stop_time.to_f - @start_time.to_f))
65
+ end
66
+
67
+ def show(string)
68
+ $stdout.print string
69
+ $stdout.flush
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end