deep_test 1.1.2 → 1.1.3

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 (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