deep_test 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/CHANGELOG +6 -0
  2. data/README +39 -2
  3. data/Rakefile +17 -12
  4. data/lib/deep_test.rb +27 -18
  5. data/lib/deep_test/deadlock_detector.rb +7 -0
  6. data/lib/deep_test/logger.rb +9 -0
  7. data/lib/deep_test/null_worker_listener.rb +12 -0
  8. data/lib/deep_test/options.rb +72 -0
  9. data/lib/deep_test/process_orchestrator.rb +85 -0
  10. data/lib/deep_test/rake_tasks.rb +7 -0
  11. data/lib/deep_test/rinda_blackboard.rb +8 -7
  12. data/lib/deep_test/rspec_detector.rb +17 -0
  13. data/lib/deep_test/server.rb +3 -9
  14. data/lib/deep_test/spec.rb +9 -0
  15. data/lib/deep_test/spec/extensions/options.rb +11 -0
  16. data/lib/deep_test/spec/extensions/reporter.rb +17 -0
  17. data/lib/deep_test/spec/extensions/spec_task.rb +13 -0
  18. data/lib/deep_test/spec/runner.rb +48 -0
  19. data/lib/deep_test/spec/work_result.rb +26 -0
  20. data/lib/deep_test/spec/work_unit.rb +53 -0
  21. data/lib/deep_test/test.rb +9 -0
  22. data/lib/deep_test/{extensions → test/extensions}/error.rb +0 -0
  23. data/lib/deep_test/{extensions/testresult.rb → test/extensions/test_result.rb} +1 -1
  24. data/lib/deep_test/test/runner.rb +29 -0
  25. data/lib/deep_test/test/supervised_test_suite.rb +46 -0
  26. data/lib/deep_test/test/work_unit.rb +36 -0
  27. data/lib/deep_test/test_task.rb +36 -9
  28. data/lib/deep_test/tuple_space_factory.rb +3 -2
  29. data/lib/deep_test/warlock.rb +2 -2
  30. data/lib/deep_test/worker.rb +10 -20
  31. data/script/run_test_suite.rb +5 -34
  32. data/test/deep_test/rinda_blackboard_test.rb +5 -5
  33. data/test/{testresult_test.rb → deep_test/test/extensions/test_result_test.rb} +2 -2
  34. data/test/deep_test/test/runner_test.rb +7 -0
  35. data/test/deep_test/test/supervised_test_suite_test.rb +89 -0
  36. data/test/deep_test/test/work_unit_test.rb +50 -0
  37. data/test/deep_test/test_task_test.rb +23 -0
  38. data/test/deep_test/worker_test.rb +62 -0
  39. data/test/failing.rake +11 -0
  40. data/test/fake_deadlock_error.rb +12 -0
  41. data/test/logger_test.rb +11 -0
  42. data/test/simple_test_blackboard.rb +44 -0
  43. data/test/simple_test_blackboard_test.rb +5 -5
  44. data/test/test_factory.rb +74 -0
  45. data/test/test_helper.rb +5 -71
  46. metadata +32 -13
  47. data/lib/deep_test/loader.rb +0 -18
  48. data/lib/deep_test/simple_test_blackboard.rb +0 -24
  49. data/lib/deep_test/supervised_test_suite.rb +0 -19
  50. data/lib/deep_test/supervisor.rb +0 -27
  51. data/test/deep_test/loader_test.rb +0 -8
  52. data/test/supervised_test_suite_test.rb +0 -63
  53. data/test/supervisor_test.rb +0 -80
  54. 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,11 @@
1
+ module Spec
2
+ module Runner
3
+ class Options
4
+ def run_one_example(file, line_number)
5
+ @examples = [SpecParser.new.spec_name_for(file, line_number)]
6
+ ExampleGroupRunner.new(self).run
7
+ end
8
+ end
9
+ end
10
+ end
11
+
@@ -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"
@@ -10,7 +10,7 @@ module Test
10
10
  end
11
11
 
12
12
  def failed_due_to_deadlock?
13
- @errors.any? && !@errors.last.message.to_s.match(/Deadlock found when trying to get lock/).nil?
13
+ @errors.any? && DeepTest::DeadlockDetector.due_to_deadlock?(@errors.last)
14
14
  end
15
15
  end
16
16
  end
@@ -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
@@ -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
- deep_test_lib = File.expand_path(File.dirname(__FILE__) + "/..")
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 ? @number_of_workers.to_i : DEFAULT_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
- Dir.pwd + "/" + (@pattern || "test/**/*_test.rb")
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(['localhost'],DeepTest::Server::PORT).lookup_ring_any
7
- puts "Connected to DeepTest server at #{ts.__drburi}"
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
@@ -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
- puts "Started #{name} (#{pid})"
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
- puts "Stopped #{name} (#{pid})"
37
+ DeepTest.logger.debug "Stopped #{name} (#{pid})"
38
38
  end
39
39
  end
40
40
 
@@ -1,31 +1,21 @@
1
1
  module DeepTest
2
2
  class Worker
3
- def initialize(blackboard = DeepTest::RindaBlackboard.new)
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
- while test_case = @blackboard.take_test
9
- result = run_test_case test_case
10
- result = run_test_case test_case 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
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