xli-dtr 0.0.4 → 0.0.5
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/README +6 -115
- data/Rakefile +22 -154
- data/TODO +16 -1
- data/bin/dtr +22 -61
- data/dtr.gemspec +7 -6
- data/lib/dtr/agent/brain.rb +66 -0
- data/lib/dtr/agent/herald.rb +50 -0
- data/lib/dtr/agent/runner.rb +100 -0
- data/lib/dtr/agent/sync_codebase.rb +44 -0
- data/lib/dtr/agent/sync_logger.rb +40 -0
- data/lib/dtr/agent/test_unit.rb +42 -0
- data/lib/dtr/agent/worker.rb +92 -0
- data/lib/dtr/agent/working_env_ext.rb +45 -0
- data/lib/dtr/agent.rb +37 -0
- data/lib/dtr/master.rb +40 -0
- data/lib/dtr/monitor.rb +37 -0
- data/lib/dtr/raketasks.rb +74 -13
- data/lib/dtr/shared/adapter.rb +112 -0
- data/lib/dtr/shared/configuration.rb +76 -0
- data/lib/dtr/shared/message_decorator.rb +28 -0
- data/lib/dtr/shared/ruby_ext.rb +153 -0
- data/lib/dtr/shared/service/agent.rb +33 -0
- data/lib/dtr/shared/service/file.rb +28 -0
- data/lib/dtr/shared/service/rinda.rb +40 -0
- data/lib/dtr/shared/service/runner.rb +33 -0
- data/lib/dtr/shared/service/working_env.rb +28 -0
- data/lib/dtr/shared/service.rb +19 -0
- data/lib/dtr/shared/sync_codebase/codebase.rb +32 -0
- data/lib/dtr/shared/sync_codebase/master_ext.rb +52 -0
- data/lib/dtr/shared/sync_codebase/package.rb +39 -0
- data/lib/dtr/shared/sync_codebase/sync_service.rb +41 -0
- data/lib/dtr/shared/sync_codebase.rb +18 -0
- data/lib/dtr/shared/sync_logger.rb +72 -0
- data/lib/dtr/shared/utils/cmd.rb +30 -0
- data/lib/dtr/shared/utils/env_store.rb +60 -0
- data/lib/dtr/shared/utils/logger.rb +71 -0
- data/lib/dtr/shared/utils.rb +17 -0
- data/lib/dtr/shared/working_env.rb +38 -0
- data/lib/dtr/shared.rb +24 -0
- data/lib/dtr/test_unit/drb_test_runner.rb +57 -0
- data/lib/dtr/test_unit/injection.rb +30 -0
- data/lib/dtr/test_unit/test_case_injection.rb +37 -0
- data/lib/dtr/test_unit/testrunnermediator_injection.rb +72 -0
- data/lib/dtr/test_unit/thread_safe_test_result.rb +40 -0
- data/lib/dtr/test_unit/worker_club.rb +72 -0
- data/lib/dtr/test_unit.rb +8 -275
- data/lib/dtr/test_unit_injection.rb +0 -1
- data/lib/dtr.rb +23 -81
- data/test/acceptance/agent_working_env_test.rb +92 -0
- data/test/acceptance/dtr_package_task_test.rb +26 -0
- data/test/acceptance/general_test.rb +275 -0
- data/test/acceptance/sync_codebase_test.rb +67 -0
- data/test/acceptance/sync_logger_test.rb +41 -0
- data/test/agent_helper.rb +39 -0
- data/test/logger_stub.rb +30 -0
- data/test/test_helper.rb +43 -0
- data/test/unit/adapter_test.rb +107 -0
- data/test/unit/test_unit_test.rb +47 -0
- data/test/unit/working_env_test.rb +71 -0
- data/testdata/Rakefile +15 -0
- data/testdata/a_failed_test_case.rb +8 -0
- data/testdata/a_file_system_test_case.rb +8 -0
- data/testdata/a_test_case.rb +13 -0
- data/testdata/a_test_case2.rb +6 -0
- data/testdata/an_error_test_case.rb +9 -0
- data/testdata/another_project/Rakefile +6 -0
- data/testdata/another_project/passed_test_case.rb +7 -0
- data/testdata/is_required_by_a_test.rb +9 -0
- data/testdata/lib/lib_test_case.rb +7 -0
- data/testdata/package_task_test_rakefile +8 -0
- data/testdata/scenario_test_case.rb +34 -0
- data/testdata/setup_agent_env_test_case.rb +9 -0
- data/testdata/should_not_sync_codebase_and_setup_working_dir_when_agent_is_in_same_dir_with_master_process/Rakefile +6 -0
- data/testdata/should_not_sync_codebase_and_setup_working_dir_when_agent_is_in_same_dir_with_master_process/verify_dir_pwd_test_case.rb +10 -0
- metadata +72 -18
- data/lib/dtr/base.rb +0 -172
- data/lib/dtr/runner.rb +0 -270
- data/lib/dtr/service_provider.rb +0 -160
@@ -0,0 +1,41 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module DTR
|
16
|
+
module SyncCodebase
|
17
|
+
module SyncService
|
18
|
+
include Package
|
19
|
+
include Service::File
|
20
|
+
def sync_codebase
|
21
|
+
DTR.info("start sync codebase, clean #{File.join(Dir.pwd, package_name)}")
|
22
|
+
FileUtils.rm_rf(File.join(Dir.pwd, package_name))
|
23
|
+
|
24
|
+
DTR.info("lookup codebase file")
|
25
|
+
codebase = lookup_file
|
26
|
+
DTR.info("receiving codebase: #{package_copy_file}")
|
27
|
+
File.open(package_copy_file, 'w') do |f|
|
28
|
+
codebase.write(f)
|
29
|
+
end
|
30
|
+
unless File.exists?(package_copy_file)
|
31
|
+
raise "#{package_copy_file} does not exist, sync codebase failed."
|
32
|
+
end
|
33
|
+
unless Cmd.execute("tar -xjf #{package_copy_file}")
|
34
|
+
raise "Extracting #{package_copy_file} by 'tar' failed."
|
35
|
+
end
|
36
|
+
DTR.info("sync codebase finished, clean #{package_copy_file}")
|
37
|
+
FileUtils.rm_f(package_copy_file)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'dtr/shared/sync_codebase/package'
|
16
|
+
require 'dtr/shared/sync_codebase/codebase'
|
17
|
+
require 'dtr/shared/sync_codebase/sync_service'
|
18
|
+
require 'dtr/shared/sync_codebase/master_ext'
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'delegate'
|
16
|
+
|
17
|
+
module DTR
|
18
|
+
module SyncLogger
|
19
|
+
class UndumpedLogger
|
20
|
+
include DRbUndumped
|
21
|
+
include MessageDecorator
|
22
|
+
|
23
|
+
def initialize(logger)
|
24
|
+
@logger = logger
|
25
|
+
end
|
26
|
+
|
27
|
+
def debug(message=nil, &block)
|
28
|
+
with_decorating_message(:debug, message, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def info(message=nil, &block)
|
32
|
+
with_decorating_message(:info, message, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def error(message=nil, &block)
|
36
|
+
with_decorating_message(:error, message, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def datetime_format=(format)
|
40
|
+
@logger.datetime_format = format
|
41
|
+
end
|
42
|
+
|
43
|
+
def level=(level)
|
44
|
+
@logger.level = level
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def with_decorating_message(level, msg, &block)
|
49
|
+
if block_given?
|
50
|
+
@logger.send(level) do
|
51
|
+
decorate_message(block.call)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
@logger.send(level, decorate_message(msg))
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module Provider
|
60
|
+
def self.included(base)
|
61
|
+
base.alias_method_chain :with_rinda_server, :providing_sync_logger
|
62
|
+
end
|
63
|
+
|
64
|
+
def with_rinda_server_with_providing_sync_logger(&block)
|
65
|
+
with_rinda_server_without_providing_sync_logger do
|
66
|
+
lookup_ring.write [:logger, UndumpedLogger.new(DTR.logger)]
|
67
|
+
block.call
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module DTR
|
16
|
+
class CmdInterrupt < StandardError; end
|
17
|
+
|
18
|
+
class Cmd
|
19
|
+
def self.execute(cmd)
|
20
|
+
return true if cmd.nil? || cmd.empty?
|
21
|
+
DTR.info "Executing: #{cmd.inspect}"
|
22
|
+
output = %x[#{cmd} 2>&1]
|
23
|
+
# don't put the following message into a block which maybe passed to remote process
|
24
|
+
# and no $? could be found
|
25
|
+
DTR.info "Execution is done, status: #{$?.exitstatus}"
|
26
|
+
DTR.error "#{cmd.inspect} output:\n#{output}" if $?.exitstatus != 0
|
27
|
+
$?.exitstatus == 0
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'pstore'
|
16
|
+
|
17
|
+
module DTR
|
18
|
+
class EnvStore
|
19
|
+
FILE_NAME = '.dtr_env_pstore' unless defined?(FILE_NAME)
|
20
|
+
|
21
|
+
def self.destroy
|
22
|
+
File.delete(FILE_NAME) if File.exist?(FILE_NAME)
|
23
|
+
end
|
24
|
+
|
25
|
+
def [](key)
|
26
|
+
return nil unless File.exist?(FILE_NAME)
|
27
|
+
|
28
|
+
repository = PStore.new(FILE_NAME)
|
29
|
+
repository.transaction(true) do
|
30
|
+
repository[key]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def []=(key, value)
|
35
|
+
repository = PStore.new(FILE_NAME)
|
36
|
+
repository.transaction do
|
37
|
+
repository[key] = value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def <<(key_value)
|
42
|
+
key, value = key_value
|
43
|
+
repository = PStore.new(FILE_NAME)
|
44
|
+
repository.transaction do
|
45
|
+
repository[key] = (repository[key] || []) << value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def shift(key)
|
50
|
+
repository = PStore.new(FILE_NAME)
|
51
|
+
repository.transaction do
|
52
|
+
if array = repository[key]
|
53
|
+
array.shift
|
54
|
+
repository[key] = array
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'logger'
|
16
|
+
|
17
|
+
module DTR
|
18
|
+
module LoggerExt
|
19
|
+
def logger(file=nil)
|
20
|
+
@logger ||= create_default_logger(file)
|
21
|
+
end
|
22
|
+
|
23
|
+
def logger=(logger)
|
24
|
+
@logger = logger
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_default_logger(file=nil)
|
28
|
+
dir = File.exist?('log') ? 'log' : '/tmp'
|
29
|
+
log_file = File.join(dir, file || "dtr.log")
|
30
|
+
do_print "dtr logfile at #{log_file}\n"
|
31
|
+
logger = Logger.new(log_file, 1, 5*1024*1024)
|
32
|
+
logger.datetime_format = "%m-%d %H:%M:%S"
|
33
|
+
logger.level = (ENV['DTR_LOG_LEVEL'] || Logger::INFO).to_i
|
34
|
+
logger
|
35
|
+
end
|
36
|
+
|
37
|
+
def do_print(str)
|
38
|
+
unless ENV['DTR_ENV'] == 'test'
|
39
|
+
print str
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def debug(message=nil, &block)
|
44
|
+
output(:debug, message, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def info(message=nil, &block)
|
48
|
+
output(:info, message, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
def error(message=nil, &block)
|
52
|
+
output(:error, message, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
def output(level, msg=nil, &block)
|
56
|
+
logger.send(level) do
|
57
|
+
message = block_given? ? block.call : msg.to_s
|
58
|
+
# puts "log: #{message}"
|
59
|
+
|
60
|
+
#output message when it's an error for agent error log should be displayed in console
|
61
|
+
if level == :error
|
62
|
+
$stderr.puts ''
|
63
|
+
$stderr.puts "#{Time.now}: #{message}"
|
64
|
+
end
|
65
|
+
message
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
extend LoggerExt
|
71
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'dtr/shared/utils/logger'
|
16
|
+
require 'dtr/shared/utils/env_store'
|
17
|
+
require 'dtr/shared/utils/cmd'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module DTR
|
16
|
+
class WorkingEnv
|
17
|
+
def initialize
|
18
|
+
files = (defined?($argv_dup) ? $argv_dup : []).dup
|
19
|
+
@env = {:libs => $LOAD_PATH.dup, :files => files, :created_at => Time.now.to_s, :dtr_master_env => ENV['DTR_MASTER_ENV'], :agent_env_setup_cmd => ENV['DTR_AGENT_ENV_SETUP_CMD'], :identifier => "#{Time.now.to_s}:#{rand}:#{object_id}", :host => Socket.gethostname, :pwd => Dir.pwd}
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](key)
|
23
|
+
@env[key]
|
24
|
+
end
|
25
|
+
|
26
|
+
def []=(key, value)
|
27
|
+
@env[key] = value
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
@env.inspect
|
32
|
+
end
|
33
|
+
|
34
|
+
def ==(obj)
|
35
|
+
obj && obj[:identifier] == self[:identifier]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/dtr/shared.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'fileutils'
|
16
|
+
require 'dtr/shared/ruby_ext'
|
17
|
+
require 'dtr/shared/utils'
|
18
|
+
require 'dtr/shared/message_decorator'
|
19
|
+
require 'dtr/shared/working_env'
|
20
|
+
require 'dtr/shared/service'
|
21
|
+
require 'dtr/shared/configuration'
|
22
|
+
require 'dtr/shared/sync_logger'
|
23
|
+
require 'dtr/shared/adapter'
|
24
|
+
require 'dtr/shared/sync_codebase'
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'timeout'
|
16
|
+
|
17
|
+
module DTR
|
18
|
+
module TestUnit
|
19
|
+
class DRbTestRunner
|
20
|
+
include Service::Runner
|
21
|
+
|
22
|
+
def initialize(test, result, &progress_block)
|
23
|
+
@test = test
|
24
|
+
@result = result
|
25
|
+
@progress_block = progress_block
|
26
|
+
end
|
27
|
+
|
28
|
+
def run
|
29
|
+
if runner = lookup_runner
|
30
|
+
WorkerClub.instance.start_thread(self, runner)
|
31
|
+
else
|
32
|
+
self.run
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def run_test_on(runner, timeout)
|
37
|
+
Timeout.timeout(timeout) do
|
38
|
+
runner.run(@test, @result, &@progress_block)
|
39
|
+
end
|
40
|
+
rescue Timeout::Error => e
|
41
|
+
DTR.info {"Run test timeout(#{timeout}), reboot runner"}
|
42
|
+
runner.reboot rescue nil
|
43
|
+
DTR.info {"rerun test: #{@test.name}"}
|
44
|
+
self.run
|
45
|
+
rescue DRb::DRbConnError => e
|
46
|
+
DTR.info {"DRb::DRbConnError(#{e.message}), rerun test: #{@test.name}"}
|
47
|
+
DTR.debug { e.backtrace.join("\n") }
|
48
|
+
self.run
|
49
|
+
rescue Exception => e
|
50
|
+
DTR.info{ "#{@test.name}, rescue an exception: #{e.message}, add error into result." }
|
51
|
+
@result.add_error(Test::Unit::Error.new(@test.name, e))
|
52
|
+
@result.add_run
|
53
|
+
@progress_block.call(Test::Unit::TestCase::FINISHED, @test.name)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'test/unit/testcase'
|
16
|
+
require 'test/unit/ui/testrunnermediator'
|
17
|
+
|
18
|
+
module DTR
|
19
|
+
def reject
|
20
|
+
return unless Test::Unit::UI::TestRunnerMediator.respond_to?(:reject_dtr)
|
21
|
+
Test::Unit::UI::TestRunnerMediator.reject_dtr
|
22
|
+
end
|
23
|
+
|
24
|
+
def inject
|
25
|
+
return if Test::Unit::UI::TestRunnerMediator.respond_to?(:reject_dtr)
|
26
|
+
Test::Unit::UI::TestRunnerMediator.send(:include, TestUnit::TestRunnerMediatorInjection)
|
27
|
+
end
|
28
|
+
|
29
|
+
module_function :reject, :inject
|
30
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module DTR
|
16
|
+
module TestUnit
|
17
|
+
module TestCaseInjection
|
18
|
+
|
19
|
+
def self.included(base)
|
20
|
+
base.alias_method_chain :run, :dtr_injection
|
21
|
+
#have to use class_eval for adding it back after removed reject_dtr method
|
22
|
+
base.class_eval do
|
23
|
+
def self.reject_dtr
|
24
|
+
remove_method :run
|
25
|
+
alias_method :run, :run_without_dtr_injection
|
26
|
+
remove_method :run_without_dtr_injection
|
27
|
+
(class << self; self; end;).send :remove_method, :reject_dtr
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def run_with_dtr_injection(result, &progress_block)
|
33
|
+
DRbTestRunner.new(self, result, &progress_block).run
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module DTR
|
16
|
+
module TestUnit
|
17
|
+
module TestRunnerMediatorInjection
|
18
|
+
|
19
|
+
class SuiteWrapper
|
20
|
+
def initialize(suite)
|
21
|
+
@suite = suite
|
22
|
+
end
|
23
|
+
def run(result, &block)
|
24
|
+
@suite.run(result, &block)
|
25
|
+
WorkerClub.instance.graceful_shutdown
|
26
|
+
end
|
27
|
+
def size
|
28
|
+
@suite.size
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.included(base)
|
33
|
+
base.send(:include, Master)
|
34
|
+
base.alias_method_chain :create_result, :thread_safe
|
35
|
+
base.alias_method_chain :run_suite, :dtr_injection
|
36
|
+
#have to use class_eval for adding it back after removed reject_dtr method
|
37
|
+
base.class_eval do
|
38
|
+
def self.reject_dtr
|
39
|
+
remove_method :run_suite
|
40
|
+
alias_method :run_suite, :run_suite_without_dtr_injection
|
41
|
+
remove_method :run_suite_without_dtr_injection
|
42
|
+
|
43
|
+
remove_method :create_result
|
44
|
+
alias_method :create_result, :create_result_without_thread_safe
|
45
|
+
remove_method :create_result_without_thread_safe
|
46
|
+
|
47
|
+
(class << self; self; end;).send :remove_method, :reject_dtr
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def create_result_with_thread_safe
|
53
|
+
ThreadSafeTestResult.new(create_result_without_thread_safe)
|
54
|
+
end
|
55
|
+
|
56
|
+
def run_suite_with_dtr_injection
|
57
|
+
DTR.logger('dtr_master_process.log')
|
58
|
+
@suite = SuiteWrapper.new(@suite)
|
59
|
+
with_dtr_master do
|
60
|
+
# inject testcase as late as possible, for in ruby world there is lots hacks added to TestCase#run method,
|
61
|
+
# DTR should be the last one to add dtr injection chain into run method
|
62
|
+
Test::Unit::TestCase.send(:include, TestUnit::TestCaseInjection)
|
63
|
+
begin
|
64
|
+
run_suite_without_dtr_injection
|
65
|
+
ensure
|
66
|
+
Test::Unit::TestCase.reject_dtr
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'drb'
|
16
|
+
|
17
|
+
module DTR
|
18
|
+
module TestUnit
|
19
|
+
class ThreadSafeTestResult
|
20
|
+
include DRbUndumped
|
21
|
+
|
22
|
+
def initialize(rs)
|
23
|
+
@mutex = Mutex.new
|
24
|
+
@rs = rs
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
@mutex.synchronize do
|
29
|
+
@rs.to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def method_missing(method, *args, &block)
|
34
|
+
@mutex.synchronize do
|
35
|
+
@rs.send(method, *args, &block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# Copyright (c) 2007-2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'singleton'
|
16
|
+
|
17
|
+
module DTR
|
18
|
+
module TestUnit
|
19
|
+
class WorkerClub
|
20
|
+
include Singleton
|
21
|
+
|
22
|
+
DEFAULT_RUN_TEST_TIMEOUT = 60 #seconds
|
23
|
+
|
24
|
+
def start_thread(drb_runner, remote_runner)
|
25
|
+
thread = Thread.new(drb_runner, remote_runner) do |local, remote|
|
26
|
+
local.run_test_on(remote, timeout)
|
27
|
+
end
|
28
|
+
thread[:started_on] = Time.now
|
29
|
+
workers.add(thread)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Performs a wait on all the currently running threads and kills any that take
|
33
|
+
# too long. It waits by ENV['RUN_TEST_TIMEOUT'] || 60 seconds
|
34
|
+
def graceful_shutdown
|
35
|
+
while reap_dead_workers("shutdown") > 0
|
36
|
+
DTR.info "Waiting for #{workers.list.length} threads to finish, could take #{timeout} seconds."
|
37
|
+
sleep timeout / 60
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def timeout
|
42
|
+
ENV['RUN_TEST_TIMEOUT'] || DEFAULT_RUN_TEST_TIMEOUT
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def workers
|
47
|
+
@workers ||= ThreadGroup.new
|
48
|
+
end
|
49
|
+
|
50
|
+
# Used internally to kill off any worker threads that have taken too long
|
51
|
+
# to complete processing. It returns the count of workers still active
|
52
|
+
# after the reap is done. It only runs if there are workers to reap.
|
53
|
+
def reap_dead_workers(reason='unknown')
|
54
|
+
if workers.list.length > 0
|
55
|
+
DTR.info "Reaping #{workers.list.length} threads because of '#{reason}'"
|
56
|
+
error_msg = "#{Time.now}: WorkerClub timed out this thread: #{reason}"
|
57
|
+
mark = Time.now
|
58
|
+
workers.list.each do |worker|
|
59
|
+
worker[:started_on] = Time.now if not worker[:started_on]
|
60
|
+
|
61
|
+
if mark - worker[:started_on] > timeout
|
62
|
+
DTR.info "Thread #{worker.inspect} is too old, killing."
|
63
|
+
worker.raise(TimeoutError.new(error_msg))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
return workers.list.length
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|