deep_test_pre 2.0

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