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
@@ -1,34 +1,5 @@
1
- number_of_workers, pattern = ARGV
2
- begin
3
- require "deep_test"
4
- warlock = DeepTest::Warlock.new
5
- Signal.trap("HUP") { warlock.stop_all; exit 0 }
6
-
7
- Dir.glob(pattern).each { |file| load file }
8
- Test::Unit.run = true
9
-
10
- # server
11
- warlock.start "server" do
12
- DeepTest::Server.start
13
- end
14
- sleep 0.25 # TODO: is this necessary?
15
-
16
- # workers
17
- number_of_workers.to_i.times do |i|
18
- warlock.start "worker #{i}" do
19
- srand # re-seed random numbers
20
- ActiveRecord::Base.connection.reconnect! if defined?(ActiveRecord::Base)
21
- DeepTest::Worker.new.run
22
- end
23
- end
24
-
25
- loader_pid = fork do
26
- puts "Loader (#{$$})"
27
- passed = DeepTest::Loader.run
28
- exit(passed ? 0 : 1)
29
- end
30
- Process.wait(loader_pid)
31
- exit($?.success? ? 0 : 1)
32
- ensure
33
- warlock.stop_all if warlock
34
- end
1
+ require File.dirname(__FILE__) + "/../lib/deep_test"
2
+ options = DeepTest::Options.from_command_line(ARGV[0])
3
+ runner = DeepTest::Test::Runner.new(options)
4
+ runner.load_files
5
+ DeepTest::ProcessOrchestrator.run(options, runner)
@@ -2,14 +2,14 @@ require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
3
  unit_tests do
4
4
  test "take result waits 30 seconds before timing out" do
5
- blackboard = DeepTest::RindaBlackboard.new(tuple_space = stub)
5
+ blackboard = DeepTest::RindaBlackboard.new(DeepTest::Options.new({}), tuple_space = stub)
6
6
  tuple_space.expects(:take).with(["test_result", nil], 30).returns([])
7
7
  blackboard.take_result
8
8
  end
9
9
 
10
10
  test "take test waits 30 seconds before timing out" do
11
- blackboard = DeepTest::RindaBlackboard.new(tuple_space = stub)
12
- tuple_space.expects(:take).with(["run_test", nil, nil], 30).returns([nil, "String", "foo"])
13
- blackboard.take_test
11
+ blackboard = DeepTest::RindaBlackboard.new(DeepTest::Options.new({}), tuple_space = stub)
12
+ tuple_space.expects(:take).with(["deep_work", nil], 30).returns([nil, "String"])
13
+ blackboard.take_work
14
14
  end
15
- end
15
+ end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + "/test_helper"
1
+ require File.dirname(__FILE__) + "/../../../test_helper"
2
2
 
3
3
  unit_tests do
4
4
  test "add_to adds correct run_count" do
@@ -62,7 +62,7 @@ unit_tests do
62
62
  test "failed due to deadlock" do
63
63
  result = Test::Unit::TestResult.new
64
64
  begin
65
- raise ActiveRecord::StatementInvalid.new("Deadlock found when trying to get lock")
65
+ raise FakeDeadlockError.new
66
66
  rescue => ex
67
67
  result.add_error Test::Unit::Error.new("test_", ex)
68
68
  end
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + "/../../test_helper"
2
+
3
+ unit_tests do
4
+ test "no filters constant has empty filters" do
5
+ assert_equal [], DeepTest::Test::Runner::NO_FILTERS.filters
6
+ end
7
+ end
@@ -0,0 +1,89 @@
1
+ require File.dirname(__FILE__) + "/../../test_helper"
2
+
3
+ unit_tests do
4
+ test "run yields name for start and finished of underlying suite" do
5
+ suite = Test::Unit::TestSuite.new("name")
6
+ supervised_suite = DeepTest::Test::SupervisedTestSuite.new(suite, DeepTest::SimpleTestBlackboard.new)
7
+
8
+ yielded = []
9
+ supervised_suite.run(stub_everything) do |channel,name|
10
+ yielded << [channel,name]
11
+ end
12
+
13
+ assert_equal [[Test::Unit::TestSuite::STARTED, "name"],
14
+ [Test::Unit::TestSuite::FINISHED, "name"]], yielded
15
+ end
16
+
17
+ test "run adds tests to blackboard and reads results" do
18
+ test_case_class = Class.new(Test::Unit::TestCase) do
19
+ test("1") {}
20
+ test("2") {assert_equal true, false}
21
+ end
22
+ blackboard = DeepTest::SimpleTestBlackboard.new
23
+ supervised_suite = DeepTest::Test::SupervisedTestSuite.new(test_case_class.suite, blackboard)
24
+ result = Test::Unit::TestResult.new
25
+
26
+ worker = ThreadWorker.new(blackboard, 2)
27
+ Timeout.timeout(5) do
28
+ supervised_suite.run(result) {}
29
+ end
30
+ worker.wait_until_done
31
+
32
+ assert_equal 2, result.run_count
33
+ assert_equal 1, result.failure_count
34
+ end
35
+
36
+ test "run yields test case finished events" do
37
+ test_case_class = Class.new(Test::Unit::TestCase) do
38
+ test("1") {}
39
+ end
40
+
41
+ blackboard = DeepTest::SimpleTestBlackboard.new
42
+ supervised_suite = DeepTest::Test::SupervisedTestSuite.new(test_case_class.suite, blackboard)
43
+
44
+ yielded = []
45
+
46
+ worker = ThreadWorker.new(blackboard, 1)
47
+ Timeout.timeout(5) do
48
+ supervised_suite.run(stub_everything) do |channel,name|
49
+ yielded << [channel, name]
50
+ end
51
+ end
52
+ worker.wait_until_done
53
+
54
+ assert_equal true, yielded.include?([::Test::Unit::TestCase::FINISHED, nil])
55
+ end
56
+
57
+ test "prints output if any" do
58
+ test_case_class = Class.new(Test::Unit::TestCase) do
59
+ test("1") {puts "hello"}
60
+ end
61
+
62
+ blackboard = DeepTest::SimpleTestBlackboard.new
63
+ supervised_suite = DeepTest::Test::SupervisedTestSuite.new(test_case_class.suite, blackboard)
64
+
65
+ worker = ThreadWorker.new(blackboard, 1)
66
+ class <<supervised_suite
67
+ def print(string)
68
+ output << string
69
+ end
70
+
71
+ def output
72
+ @output ||= ""
73
+ end
74
+ end
75
+ Timeout.timeout(5) do
76
+ supervised_suite.run(stub_everything) {}
77
+ end
78
+ worker.wait_until_done
79
+ assert_equal "hello\n", supervised_suite.output
80
+ end
81
+
82
+ test "has same size as underlying suite" do
83
+ suite = Test::Unit::TestSuite.new("name")
84
+ suite << "test"
85
+ supervised_suite = DeepTest::Test::SupervisedTestSuite.new(suite, DeepTest::SimpleTestBlackboard.new)
86
+
87
+ assert_equal suite.size, supervised_suite.size
88
+ end
89
+ end
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + "/../../test_helper"
2
+
3
+ unit_tests do
4
+ test "returns passed result for passing test" do
5
+ work_unit = DeepTest::Test::WorkUnit.new TestFactory.passing_test
6
+ assert_equal true, work_unit.run.passed?
7
+ end
8
+
9
+ test "returns failed result for failing test" do
10
+ work_unit = DeepTest::Test::WorkUnit.new TestFactory.failing_test
11
+ assert_equal false, work_unit.run.passed?
12
+ end
13
+
14
+ test "returns passed result correctly after being loaded from yaml" do
15
+ work_unit = DeepTest::Test::WorkUnit.new TestFactory.passing_test
16
+ work_unit_from_yaml = YAML.load(work_unit.to_yaml)
17
+ assert_equal true, work_unit_from_yaml.run.passed?
18
+ end
19
+
20
+ test "capturing stdout" do
21
+ work_unit = DeepTest::Test::WorkUnit.new TestFactory.passing_test_with_stdout
22
+ assert_equal "message printed to stdout", work_unit.run.output
23
+ end
24
+
25
+ test "retry on deadlock" do
26
+ work_unit = DeepTest::Test::WorkUnit.new TestFactory.deadlock_once_test
27
+ result = work_unit.run
28
+ assert_equal 0, result.error_count
29
+ assert_equal 0, result.failure_count
30
+ assert_equal 1, result.assertion_count
31
+ end
32
+
33
+ test "skip on deadlock twice" do
34
+ work_unit = DeepTest::Test::WorkUnit.new TestFactory.deadlock_always_test
35
+ result = work_unit.run
36
+ assert_equal 0, result.error_count
37
+ assert_equal 0, result.failure_count
38
+ assert_equal 0, result.assertion_count
39
+ end
40
+
41
+ test "equality is based on test_case" do
42
+ test_case_1 = TestFactory.passing_test
43
+ test_case_2 = TestFactory.failing_test
44
+ assert_equal DeepTest::Test::WorkUnit.new(test_case_1),
45
+ DeepTest::Test::WorkUnit.new(test_case_1)
46
+
47
+ assert_not_equal DeepTest::Test::WorkUnit.new(test_case_1),
48
+ DeepTest::Test::WorkUnit.new(test_case_2)
49
+ end
50
+ end
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ unit_tests do
4
+ test "should support setting timeout_in_seconds" do
5
+ t = DeepTest::TestTask.new :deep_test do |t|
6
+ t.stubs(:desc)
7
+ t.stubs(:task)
8
+ t.timeout_in_seconds = 20
9
+ end
10
+ assert_equal 20, t.instance_variable_get(:@options).timeout_in_seconds
11
+ assert_equal 20, t.timeout_in_seconds
12
+ end
13
+
14
+ test "should support worker_listener" do
15
+ t = DeepTest::TestTask.new :deep_test do |t|
16
+ t.stubs(:desc)
17
+ t.stubs(:task)
18
+ t.worker_listener = "A"
19
+ end
20
+ assert_equal "A", t.instance_variable_get(:@options).worker_listener
21
+ assert_equal "A", t.worker_listener
22
+ end
23
+ end
@@ -0,0 +1,62 @@
1
+ require File.dirname(__FILE__) + "/../test_helper"
2
+
3
+ unit_tests do
4
+ test "puts result on blackboard" do
5
+ blackboard = DeepTest::SimpleTestBlackboard.new
6
+ blackboard.write_work DeepTest::Test::WorkUnit.new(TestFactory.passing_test)
7
+
8
+ DeepTest::Worker.new(0, blackboard,stub_everything).run
9
+
10
+ assert_kind_of Test::Unit::TestResult, blackboard.take_result
11
+ end
12
+
13
+ test "puts passing and failing tests on blackboard for each test" do
14
+ blackboard = DeepTest::SimpleTestBlackboard.new
15
+ blackboard.write_work DeepTest::Test::WorkUnit.new(TestFactory.passing_test)
16
+ blackboard.write_work DeepTest::Test::WorkUnit.new(TestFactory.failing_test)
17
+
18
+ DeepTest::Worker.new(0, blackboard, stub_everything).run
19
+
20
+ result_1 = blackboard.take_result
21
+ result_2 = blackboard.take_result
22
+
23
+ assert_equal true, (result_1.passed? || result_2.passed?)
24
+ assert_equal false, (result_1.passed? && result_2.passed?)
25
+ end
26
+
27
+ test "notifies listener that it is starting" do
28
+ blackboard = DeepTest::SimpleTestBlackboard.new
29
+ listener = stub_everything
30
+ worker = DeepTest::Worker.new(0, blackboard, listener)
31
+ listener.expects(:starting).with(worker)
32
+ worker.run
33
+ end
34
+
35
+ test "notifies listener that it is about to do work" do
36
+ blackboard = DeepTest::SimpleTestBlackboard.new
37
+ work_unit = DeepTest::Test::WorkUnit.new(TestFactory.passing_test)
38
+ blackboard.write_work work_unit
39
+ listener = stub_everything
40
+ worker = DeepTest::Worker.new(0, blackboard, listener)
41
+ listener.expects(:starting_work).with(worker, work_unit)
42
+ worker.run
43
+ end
44
+
45
+ test "notifies listener that it has done work" do
46
+ blackboard = DeepTest::SimpleTestBlackboard.new
47
+ work_unit = mock(:run => :result)
48
+ blackboard.write_work work_unit
49
+ listener = stub_everything
50
+ worker = DeepTest::Worker.new(0, blackboard, listener)
51
+ listener.expects(:finished_work).with(worker, work_unit, :result)
52
+ worker.run
53
+ end
54
+
55
+ test "number is available to indentify worker" do
56
+ assert_equal 1, DeepTest::Worker.new(1, nil, nil).number
57
+ end
58
+
59
+ test "does not fork from rake" do
60
+ assert !defined?($rakefile)
61
+ end
62
+ end
@@ -0,0 +1,11 @@
1
+ require 'rake'
2
+ $LOAD_PATH << File.dirname(__FILE__) + "/../lib"
3
+ require "deep_test"
4
+ require "deep_test/rake_tasks"
5
+
6
+ task :default => %w[deep_test_failing]
7
+
8
+ DeepTest::TestTask.new :deep_test_failing do |t|
9
+ t.number_of_workers = 1
10
+ t.pattern = "test/failing.rb"
11
+ end
@@ -0,0 +1,12 @@
1
+ unless defined?(ActiveRecord::StatementInvalid)
2
+ module ActiveRecord
3
+ class StatementInvalid < StandardError
4
+ end
5
+ end
6
+ end
7
+
8
+ class FakeDeadlockError
9
+ def self.new
10
+ ActiveRecord::StatementInvalid.new("Deadlock found when trying to get lock")
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + "/test_helper"
2
+
3
+ unit_tests do
4
+ test "info log level by default" do
5
+ assert_equal Logger::INFO, DeepTest.logger.level
6
+ end
7
+
8
+ test "formatter uses msg only" do
9
+ assert_equal "my_msg\n", DeepTest.logger.formatter.call(nil, nil, nil, "my_msg")
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ module DeepTest
2
+ class SimpleTestBlackboard
3
+ attr_accessor :debug
4
+
5
+ def initialize
6
+ @work_units = []
7
+ @test_results = []
8
+ @semaphore = Mutex.new
9
+ end
10
+
11
+ def take_result
12
+ @semaphore.synchronize do
13
+ log_and_return "take_result", @test_results.shift
14
+ end
15
+ end
16
+
17
+ def take_work
18
+ @semaphore.synchronize do
19
+ log_and_return "take_work", @work_units.shift
20
+ end
21
+ end
22
+
23
+ def write_result(result)
24
+ @semaphore.synchronize do
25
+ log_and_return "write_result", result
26
+ @test_results.push result
27
+ end
28
+ end
29
+
30
+ def write_work(work_unit)
31
+ @semaphore.synchronize do
32
+ log_and_return "write_work", work_unit
33
+ @work_units.push work_unit
34
+ end
35
+ end
36
+
37
+ def log_and_return(message, object)
38
+ if debug && object
39
+ puts "* #{message} #{object.inspect}"
40
+ end
41
+ object
42
+ end
43
+ end
44
+ end
@@ -4,16 +4,16 @@ unit_tests do
4
4
  test "a test that is put on can be taken off later" do
5
5
  blackboard = DeepTest::SimpleTestBlackboard.new
6
6
  test_case = TestFactory.passing_test
7
- blackboard.write_test test_case
8
- assert_equal test_case, blackboard.take_test
7
+ blackboard.write_work test_case
8
+ assert_equal test_case, blackboard.take_work
9
9
  end
10
10
 
11
11
  test "taking a test when all have been taken returns nil" do
12
12
  blackboard = DeepTest::SimpleTestBlackboard.new
13
13
  test_case = TestFactory.passing_test
14
- blackboard.write_test test_case
15
- blackboard.take_test
16
- assert_nil blackboard.take_test
14
+ blackboard.write_work test_case
15
+ blackboard.take_work
16
+ assert_nil blackboard.take_work
17
17
  end
18
18
 
19
19
  test "a result that is put on can be taken off later" do
@@ -0,0 +1,74 @@
1
+ module TestFactory
2
+ def self.failing_test
3
+ test_class do
4
+ def test_failing
5
+ assert_equal 1, 0
6
+ end
7
+ end.new(:test_failing)
8
+ end
9
+
10
+ def self.passed_result
11
+ result = Test::Unit::TestResult.new
12
+ result.add_run
13
+ result.add_assertion
14
+ result
15
+ end
16
+
17
+ def self.passing_test
18
+ test_class do
19
+ def test_passing
20
+ assert_equal 0, 0
21
+ end
22
+ end.new(:test_passing)
23
+ end
24
+
25
+ def self.passing_test_with_stdout
26
+ test_class do
27
+ def test_passing_with_stdout
28
+ print "message printed to stdout"
29
+ assert true
30
+ end
31
+ end.new :test_passing_with_stdout
32
+ end
33
+
34
+ def self.deadlock_once_test
35
+ test_class do
36
+ def test_deadlock_once
37
+ if @deadlocked
38
+ assert true
39
+ else
40
+ @deadlocked = true
41
+ raise FakeDeadlockError.new
42
+ end
43
+ end
44
+ end.new :test_deadlock_once
45
+ end
46
+
47
+ def self.deadlock_always_test
48
+ test_class do
49
+ def test_deadlock_always
50
+ raise FakeDeadlockError.new
51
+ end
52
+ end.new :test_deadlock_always
53
+ end
54
+
55
+ def self.suite
56
+ Test::Unit::TestSuite.new
57
+ end
58
+
59
+ def self.test_class(&block)
60
+ test_class = Class.new(Test::Unit::TestCase)
61
+
62
+ class_name = external_caller.upcase.gsub(/[^A-Z0-9]/,"_").sub(/^_*/,'')
63
+ const_set(class_name, test_class)
64
+
65
+ test_class.class_eval &block
66
+ test_class
67
+ end
68
+
69
+ def self.external_caller
70
+ caller.each do |trace_line|
71
+ return trace_line unless trace_line =~ /test_factory.rb/
72
+ end
73
+ end
74
+ end