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.
- data/CHANGELOG +6 -0
- data/README +39 -2
- data/Rakefile +17 -12
- data/lib/deep_test.rb +27 -18
- data/lib/deep_test/deadlock_detector.rb +7 -0
- data/lib/deep_test/logger.rb +9 -0
- data/lib/deep_test/null_worker_listener.rb +12 -0
- data/lib/deep_test/options.rb +72 -0
- data/lib/deep_test/process_orchestrator.rb +85 -0
- data/lib/deep_test/rake_tasks.rb +7 -0
- data/lib/deep_test/rinda_blackboard.rb +8 -7
- data/lib/deep_test/rspec_detector.rb +17 -0
- data/lib/deep_test/server.rb +3 -9
- data/lib/deep_test/spec.rb +9 -0
- data/lib/deep_test/spec/extensions/options.rb +11 -0
- data/lib/deep_test/spec/extensions/reporter.rb +17 -0
- data/lib/deep_test/spec/extensions/spec_task.rb +13 -0
- data/lib/deep_test/spec/runner.rb +48 -0
- data/lib/deep_test/spec/work_result.rb +26 -0
- data/lib/deep_test/spec/work_unit.rb +53 -0
- data/lib/deep_test/test.rb +9 -0
- data/lib/deep_test/{extensions → test/extensions}/error.rb +0 -0
- data/lib/deep_test/{extensions/testresult.rb → test/extensions/test_result.rb} +1 -1
- data/lib/deep_test/test/runner.rb +29 -0
- data/lib/deep_test/test/supervised_test_suite.rb +46 -0
- data/lib/deep_test/test/work_unit.rb +36 -0
- data/lib/deep_test/test_task.rb +36 -9
- data/lib/deep_test/tuple_space_factory.rb +3 -2
- data/lib/deep_test/warlock.rb +2 -2
- data/lib/deep_test/worker.rb +10 -20
- data/script/run_test_suite.rb +5 -34
- data/test/deep_test/rinda_blackboard_test.rb +5 -5
- data/test/{testresult_test.rb → deep_test/test/extensions/test_result_test.rb} +2 -2
- data/test/deep_test/test/runner_test.rb +7 -0
- data/test/deep_test/test/supervised_test_suite_test.rb +89 -0
- data/test/deep_test/test/work_unit_test.rb +50 -0
- data/test/deep_test/test_task_test.rb +23 -0
- data/test/deep_test/worker_test.rb +62 -0
- data/test/failing.rake +11 -0
- data/test/fake_deadlock_error.rb +12 -0
- data/test/logger_test.rb +11 -0
- data/test/simple_test_blackboard.rb +44 -0
- data/test/simple_test_blackboard_test.rb +5 -5
- data/test/test_factory.rb +74 -0
- data/test/test_helper.rb +5 -71
- metadata +32 -13
- data/lib/deep_test/loader.rb +0 -18
- data/lib/deep_test/simple_test_blackboard.rb +0 -24
- data/lib/deep_test/supervised_test_suite.rb +0 -19
- data/lib/deep_test/supervisor.rb +0 -27
- data/test/deep_test/loader_test.rb +0 -8
- data/test/supervised_test_suite_test.rb +0 -63
- data/test/supervisor_test.rb +0 -80
- data/test/worker_test.rb +0 -64
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
* 1.1.3 (March 10, 2008)
|
2
|
+
|
3
|
+
* Added Support for RSpec
|
4
|
+
* Added DeepTest::TestTask#timeout_in_seconds to configure Rinda IO timeouts
|
5
|
+
* Added worker_listener to configuration options
|
6
|
+
|
1
7
|
* 1.1.2 (February 9, 2008)
|
2
8
|
|
3
9
|
* Fix bug with run_test_suite script not exiting with correct exit code.
|
data/README
CHANGED
@@ -12,16 +12,53 @@ In your Rakefile:
|
|
12
12
|
# sample DeepTest task
|
13
13
|
|
14
14
|
DeepTest::TestTask.new "task_name" do |t|
|
15
|
-
t.number_of_workers = 2
|
15
|
+
t.number_of_workers = 2 # optional, defaults to 2
|
16
|
+
t.timeout_in_seconds = 30 # optional, defaults to 30
|
16
17
|
t.pattern = "test/**/*_test.rb"
|
17
18
|
end
|
18
19
|
|
20
|
+
# Sample SpecTask using DeepTest
|
21
|
+
|
22
|
+
Spec::Rake::SpecTask.new(:deep_spec) do |t|
|
23
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
24
|
+
t.deep_test :number_of_workers => 2, # optional, defaults to 2
|
25
|
+
:timeout_in_seconds => 30, # optional, defaults to 30
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
If you want to specify a listener to be notified of worker events:
|
30
|
+
|
31
|
+
In my_worker_listener.rb
|
32
|
+
class MyWorkerListener
|
33
|
+
def starting(worker)
|
34
|
+
end
|
35
|
+
|
36
|
+
def starting_work(worker, work_unit)
|
37
|
+
end
|
38
|
+
|
39
|
+
def finished_work(worker, work_unit, result)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
In your Rakefile
|
44
|
+
|
45
|
+
DeepTest::TestTask.new "task_name" do |t|
|
46
|
+
t.pattern = "test/**/*_test.rb"
|
47
|
+
t.worker_listener = "MyWorkerListener"
|
48
|
+
end
|
49
|
+
|
50
|
+
An instance of MyWorkerListener will be created for each worker that is
|
51
|
+
started, and will receive events from that worker. However, you must ensure
|
52
|
+
that the MyWorkerListener class is loaded at the time that the test files are
|
53
|
+
loaded, so it is available to be instantiated.
|
54
|
+
|
19
55
|
== Contributors
|
20
56
|
|
21
57
|
+* anonymous z
|
22
58
|
+* Alex Chaffee
|
23
59
|
+* Dan[http://www.dcmanges.com/blog] Manges[http://www.dcmanges.com/blog]
|
24
|
-
+* David Vollbracht
|
60
|
+
+* David Vollbracht[http://davidvollbracht.com/]
|
61
|
+
+* Scott Taylor
|
25
62
|
|
26
63
|
== License
|
27
64
|
Released under Ruby's[http://www.ruby-lang.org/en/LICENSE.txt] license[http://www.ruby-lang.org/en/LICENSE.txt]
|
data/Rakefile
CHANGED
@@ -6,32 +6,37 @@ require 'rake/contrib/sshpublisher'
|
|
6
6
|
$LOAD_PATH << File.dirname(__FILE__) + "/lib"
|
7
7
|
require "deep_test/rake_tasks"
|
8
8
|
|
9
|
-
task :default => %w[test failing_test deep_test]
|
9
|
+
task :default => %w[test spec failing_test deep_test deep_spec]
|
10
10
|
|
11
11
|
Rake::TestTask.new do |t|
|
12
12
|
t.pattern = "test/**/*_test.rb"
|
13
13
|
t.libs += ['test', 'lib']
|
14
14
|
end
|
15
15
|
|
16
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
17
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
18
|
+
end
|
19
|
+
|
16
20
|
DeepTest::TestTask.new :deep_test do |t|
|
17
21
|
t.number_of_workers = 2
|
18
22
|
t.pattern = "test/**/*_test.rb"
|
19
23
|
end
|
20
24
|
|
21
|
-
|
22
|
-
t.
|
23
|
-
t.
|
25
|
+
Spec::Rake::SpecTask.new(:deep_spec) do |t|
|
26
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
27
|
+
t.deep_test :number_of_workers => 2
|
24
28
|
end
|
25
29
|
|
26
|
-
# TODO: figure out a better way to test this that doesn't
|
27
|
-
# involve having a failing test in the output of 'rake test'
|
28
30
|
task :failing_test do
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
command = "rake --rakefile test/failing.rake 2>&1"
|
32
|
+
puts command
|
33
|
+
`#{command}`
|
34
|
+
if $?.success?
|
35
|
+
puts "F"
|
36
|
+
fail "****\ntest/failing.rake should have failed\n****"
|
37
|
+
else
|
38
|
+
puts "."
|
33
39
|
end
|
34
|
-
fail "exception should not be nil" if exception.nil?
|
35
40
|
end
|
36
41
|
|
37
42
|
desc "Generate documentation"
|
@@ -53,7 +58,7 @@ specification = Gem::Specification.new do |s|
|
|
53
58
|
s.platform = Gem::Platform::RUBY
|
54
59
|
s.name = "deep_test"
|
55
60
|
s.summary = "DeepTest runs tests in multiple processes."
|
56
|
-
s.version = "1.1.
|
61
|
+
s.version = "1.1.3"
|
57
62
|
s.author = "anonymous z, Dan Manges, David Vollbracht"
|
58
63
|
s.description = s.summary
|
59
64
|
s.email = "daniel.manges@gmail.com"
|
data/lib/deep_test.rb
CHANGED
@@ -1,23 +1,32 @@
|
|
1
1
|
module DeepTest
|
2
|
+
class << self
|
3
|
+
def logger
|
4
|
+
@logger ||= DeepTest::Logger.new($stdout)
|
5
|
+
end
|
6
|
+
end
|
2
7
|
end
|
3
|
-
require 'rinda/ring'
|
4
|
-
require 'rinda/tuplespace'
|
5
8
|
|
6
|
-
require "
|
7
|
-
require "
|
8
|
-
require
|
9
|
+
require "logger"
|
10
|
+
require "rinda/ring"
|
11
|
+
require "rinda/tuplespace"
|
9
12
|
|
10
|
-
require "deep_test/extensions/
|
11
|
-
|
12
|
-
require "deep_test/
|
13
|
+
require File.dirname(__FILE__) + "/deep_test/extensions/object_extension"
|
14
|
+
|
15
|
+
require File.dirname(__FILE__) + "/deep_test/deadlock_detector"
|
16
|
+
require File.dirname(__FILE__) + "/deep_test/tuple_space_factory"
|
17
|
+
require File.dirname(__FILE__) + "/deep_test/rinda_blackboard"
|
18
|
+
require File.dirname(__FILE__) + "/deep_test/logger"
|
19
|
+
require File.dirname(__FILE__) + "/deep_test/null_worker_listener"
|
20
|
+
require File.dirname(__FILE__) + "/deep_test/options"
|
21
|
+
require File.dirname(__FILE__) + "/deep_test/process_orchestrator"
|
22
|
+
require File.dirname(__FILE__) + "/deep_test/rspec_detector"
|
23
|
+
require File.dirname(__FILE__) + "/deep_test/server"
|
24
|
+
require File.dirname(__FILE__) + "/deep_test/test_task"
|
25
|
+
require File.dirname(__FILE__) + "/deep_test/worker"
|
26
|
+
require File.dirname(__FILE__) + "/deep_test/warlock"
|
27
|
+
|
28
|
+
DeepTest::RSpecDetector.if_rspec_available do
|
29
|
+
require File.dirname(__FILE__) + "/deep_test/spec"
|
30
|
+
end
|
31
|
+
require File.dirname(__FILE__) + "/deep_test/test"
|
13
32
|
|
14
|
-
require "deep_test/tuple_space_factory"
|
15
|
-
require "deep_test/rinda_blackboard"
|
16
|
-
require "deep_test/loader"
|
17
|
-
require "deep_test/server"
|
18
|
-
require "deep_test/simple_test_blackboard"
|
19
|
-
require "deep_test/supervised_test_suite"
|
20
|
-
require "deep_test/supervisor"
|
21
|
-
require "deep_test/test_task"
|
22
|
-
require "deep_test/worker"
|
23
|
-
require "deep_test/warlock"
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module DeepTest
|
2
|
+
class Options
|
3
|
+
class Option
|
4
|
+
attr_reader :name, :default
|
5
|
+
|
6
|
+
def initialize(name, conversion, default)
|
7
|
+
@name, @conversion, @default = name, conversion, default
|
8
|
+
end
|
9
|
+
|
10
|
+
def from_command_line(command_line)
|
11
|
+
command_line =~ /--#{name} (\S+)(\s|$)/
|
12
|
+
$1.send(@conversion) if $1
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_command_line(value)
|
16
|
+
"--#{name} #{value}" if value && value != default
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
unless defined?(VALID_OPTIONS)
|
21
|
+
VALID_OPTIONS = [
|
22
|
+
Option.new(:number_of_workers, :to_i, 2),
|
23
|
+
Option.new(:pattern, :to_s, nil),
|
24
|
+
Option.new(:timeout_in_seconds, :to_i, 30),
|
25
|
+
Option.new(:worker_listener, :to_s, "DeepTest::NullWorkerListener"),
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_accessor *VALID_OPTIONS.map {|o| o.name}
|
30
|
+
def worker_listener=(value)
|
31
|
+
@worker_listener = value.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.from_command_line(command_line)
|
35
|
+
hash = {}
|
36
|
+
VALID_OPTIONS.each do |option|
|
37
|
+
hash[option.name] = option.from_command_line(command_line)
|
38
|
+
end
|
39
|
+
new(hash)
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(hash)
|
43
|
+
check_option_keys(hash)
|
44
|
+
VALID_OPTIONS.each do |option|
|
45
|
+
send("#{option.name}=", hash[option.name] || option.default)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def new_worker_listener
|
50
|
+
eval(worker_listener).new
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_command_line
|
54
|
+
command_line = []
|
55
|
+
VALID_OPTIONS.each do |option|
|
56
|
+
value = send(option.name)
|
57
|
+
command_line << option.to_command_line(value)
|
58
|
+
end
|
59
|
+
command_line.compact.join(' ')
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
def check_option_keys(hash)
|
65
|
+
hash.keys.each do |key|
|
66
|
+
raise InvalidOptionError.new(key) unless VALID_OPTIONS.any? {|o| o.name == key.to_sym}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class InvalidOptionError < StandardError; end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module DeepTest
|
2
|
+
class ProcessOrchestrator
|
3
|
+
def self.run(options, runner)
|
4
|
+
new(options, runner).run
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(options, runner)
|
8
|
+
@options = options
|
9
|
+
@runner = runner
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
stop_zombie_warlocks
|
14
|
+
start_warlock_server
|
15
|
+
start_all_workers
|
16
|
+
start_loader
|
17
|
+
wait_for_loader_to_be_done
|
18
|
+
exit_process
|
19
|
+
ensure
|
20
|
+
stop_all_warlocks
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def exit_process
|
26
|
+
Kernel.exit($?.success? ? 0 : 1)
|
27
|
+
end
|
28
|
+
|
29
|
+
def start_all_workers
|
30
|
+
each_worker do |worker_num|
|
31
|
+
start_worker(worker_num) do
|
32
|
+
reseed_random_numbers
|
33
|
+
reconnect_to_database
|
34
|
+
worker = DeepTest::Worker.new(worker_num,
|
35
|
+
RindaBlackboard.new(@options),
|
36
|
+
@options.new_worker_listener)
|
37
|
+
worker.run
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def reconnect_to_database
|
43
|
+
ActiveRecord::Base.connection.reconnect! if defined?(ActiveRecord::Base)
|
44
|
+
end
|
45
|
+
|
46
|
+
def start_worker(worker_num, &blk)
|
47
|
+
@warlock.start("worker #{worker_num}", &blk)
|
48
|
+
end
|
49
|
+
|
50
|
+
def reseed_random_numbers
|
51
|
+
srand
|
52
|
+
end
|
53
|
+
|
54
|
+
def wait_for_loader_to_be_done
|
55
|
+
Process.wait(@loader_pid)
|
56
|
+
end
|
57
|
+
|
58
|
+
def start_warlock_server
|
59
|
+
@warlock.start("server") { DeepTest::Server.start }
|
60
|
+
sleep 0.5 # TODO: change from sleep to something better... Process.wait?
|
61
|
+
end
|
62
|
+
|
63
|
+
def stop_all_warlocks
|
64
|
+
@warlock.stop_all if @warlock
|
65
|
+
end
|
66
|
+
|
67
|
+
def each_worker
|
68
|
+
@options.number_of_workers.to_i.times { |worker_num| yield worker_num }
|
69
|
+
end
|
70
|
+
|
71
|
+
def stop_zombie_warlocks
|
72
|
+
@warlock = DeepTest::Warlock.new
|
73
|
+
Signal.trap("HUP") { warlock.stop_all; exit 0 }
|
74
|
+
end
|
75
|
+
|
76
|
+
def start_loader
|
77
|
+
@loader_pid = fork do
|
78
|
+
DeepTest.logger.debug "Loader Starting (#{$$})"
|
79
|
+
passed = @runner.process_work_units
|
80
|
+
exit(passed ? 0 : 1)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
data/lib/deep_test/rake_tasks.rb
CHANGED
@@ -1 +1,8 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/options"
|
1
2
|
require File.dirname(__FILE__) + "/test_task"
|
3
|
+
require File.dirname(__FILE__) + "/rspec_detector"
|
4
|
+
|
5
|
+
DeepTest::RSpecDetector.if_rspec_available do
|
6
|
+
require 'spec/rake/spectask'
|
7
|
+
require File.dirname(__FILE__) + "/spec/extensions/spec_task"
|
8
|
+
end
|
@@ -1,25 +1,26 @@
|
|
1
1
|
module DeepTest
|
2
2
|
class RindaBlackboard
|
3
|
-
def initialize(tuple_space = TupleSpaceFactory.tuple_space)
|
3
|
+
def initialize(options, tuple_space = TupleSpaceFactory.tuple_space)
|
4
|
+
@options = options
|
4
5
|
@tuple_space = tuple_space
|
5
6
|
end
|
6
7
|
|
7
8
|
def take_result
|
8
|
-
result = @tuple_space.take ["test_result", nil],
|
9
|
+
result = @tuple_space.take ["test_result", nil], @options.timeout_in_seconds
|
9
10
|
result[1]
|
10
11
|
end
|
11
12
|
|
12
|
-
def
|
13
|
-
tuple = @tuple_space.take ["
|
14
|
-
|
13
|
+
def take_work
|
14
|
+
tuple = @tuple_space.take ["deep_work", nil], @options.timeout_in_seconds
|
15
|
+
tuple[1]
|
15
16
|
end
|
16
17
|
|
17
18
|
def write_result(result)
|
18
19
|
@tuple_space.write ["test_result", result]
|
19
20
|
end
|
20
21
|
|
21
|
-
def
|
22
|
-
@tuple_space.write ["
|
22
|
+
def write_work(work_unit)
|
23
|
+
@tuple_space.write ["deep_work", work_unit]
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
data/lib/deep_test/server.rb
CHANGED
@@ -1,17 +1,11 @@
|
|
1
1
|
module DeepTest
|
2
2
|
class Server
|
3
|
-
PORT = 6969
|
3
|
+
PORT = 6969 unless defined?(PORT)
|
4
4
|
|
5
5
|
def self.start
|
6
|
-
require 'rinda/ring'
|
7
|
-
require 'rinda/tuplespace'
|
8
|
-
require 'test/unit'
|
9
|
-
require 'test/unit/testresult'
|
10
|
-
require 'deep_test'
|
11
6
|
DRb.start_service
|
12
|
-
|
13
|
-
|
14
|
-
puts "Started DeepTest service at #{DRb.uri}"
|
7
|
+
Rinda::RingServer.new(Rinda::TupleSpace.new, PORT)
|
8
|
+
DeepTest.logger.info "Started DeepTest service at #{DRb.uri}"
|
15
9
|
DRb.thread.join
|
16
10
|
end
|
17
11
|
end
|