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