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.
Files changed (78) hide show
  1. data/README +6 -115
  2. data/Rakefile +22 -154
  3. data/TODO +16 -1
  4. data/bin/dtr +22 -61
  5. data/dtr.gemspec +7 -6
  6. data/lib/dtr/agent/brain.rb +66 -0
  7. data/lib/dtr/agent/herald.rb +50 -0
  8. data/lib/dtr/agent/runner.rb +100 -0
  9. data/lib/dtr/agent/sync_codebase.rb +44 -0
  10. data/lib/dtr/agent/sync_logger.rb +40 -0
  11. data/lib/dtr/agent/test_unit.rb +42 -0
  12. data/lib/dtr/agent/worker.rb +92 -0
  13. data/lib/dtr/agent/working_env_ext.rb +45 -0
  14. data/lib/dtr/agent.rb +37 -0
  15. data/lib/dtr/master.rb +40 -0
  16. data/lib/dtr/monitor.rb +37 -0
  17. data/lib/dtr/raketasks.rb +74 -13
  18. data/lib/dtr/shared/adapter.rb +112 -0
  19. data/lib/dtr/shared/configuration.rb +76 -0
  20. data/lib/dtr/shared/message_decorator.rb +28 -0
  21. data/lib/dtr/shared/ruby_ext.rb +153 -0
  22. data/lib/dtr/shared/service/agent.rb +33 -0
  23. data/lib/dtr/shared/service/file.rb +28 -0
  24. data/lib/dtr/shared/service/rinda.rb +40 -0
  25. data/lib/dtr/shared/service/runner.rb +33 -0
  26. data/lib/dtr/shared/service/working_env.rb +28 -0
  27. data/lib/dtr/shared/service.rb +19 -0
  28. data/lib/dtr/shared/sync_codebase/codebase.rb +32 -0
  29. data/lib/dtr/shared/sync_codebase/master_ext.rb +52 -0
  30. data/lib/dtr/shared/sync_codebase/package.rb +39 -0
  31. data/lib/dtr/shared/sync_codebase/sync_service.rb +41 -0
  32. data/lib/dtr/shared/sync_codebase.rb +18 -0
  33. data/lib/dtr/shared/sync_logger.rb +72 -0
  34. data/lib/dtr/shared/utils/cmd.rb +30 -0
  35. data/lib/dtr/shared/utils/env_store.rb +60 -0
  36. data/lib/dtr/shared/utils/logger.rb +71 -0
  37. data/lib/dtr/shared/utils.rb +17 -0
  38. data/lib/dtr/shared/working_env.rb +38 -0
  39. data/lib/dtr/shared.rb +24 -0
  40. data/lib/dtr/test_unit/drb_test_runner.rb +57 -0
  41. data/lib/dtr/test_unit/injection.rb +30 -0
  42. data/lib/dtr/test_unit/test_case_injection.rb +37 -0
  43. data/lib/dtr/test_unit/testrunnermediator_injection.rb +72 -0
  44. data/lib/dtr/test_unit/thread_safe_test_result.rb +40 -0
  45. data/lib/dtr/test_unit/worker_club.rb +72 -0
  46. data/lib/dtr/test_unit.rb +8 -275
  47. data/lib/dtr/test_unit_injection.rb +0 -1
  48. data/lib/dtr.rb +23 -81
  49. data/test/acceptance/agent_working_env_test.rb +92 -0
  50. data/test/acceptance/dtr_package_task_test.rb +26 -0
  51. data/test/acceptance/general_test.rb +275 -0
  52. data/test/acceptance/sync_codebase_test.rb +67 -0
  53. data/test/acceptance/sync_logger_test.rb +41 -0
  54. data/test/agent_helper.rb +39 -0
  55. data/test/logger_stub.rb +30 -0
  56. data/test/test_helper.rb +43 -0
  57. data/test/unit/adapter_test.rb +107 -0
  58. data/test/unit/test_unit_test.rb +47 -0
  59. data/test/unit/working_env_test.rb +71 -0
  60. data/testdata/Rakefile +15 -0
  61. data/testdata/a_failed_test_case.rb +8 -0
  62. data/testdata/a_file_system_test_case.rb +8 -0
  63. data/testdata/a_test_case.rb +13 -0
  64. data/testdata/a_test_case2.rb +6 -0
  65. data/testdata/an_error_test_case.rb +9 -0
  66. data/testdata/another_project/Rakefile +6 -0
  67. data/testdata/another_project/passed_test_case.rb +7 -0
  68. data/testdata/is_required_by_a_test.rb +9 -0
  69. data/testdata/lib/lib_test_case.rb +7 -0
  70. data/testdata/package_task_test_rakefile +8 -0
  71. data/testdata/scenario_test_case.rb +34 -0
  72. data/testdata/setup_agent_env_test_case.rb +9 -0
  73. data/testdata/should_not_sync_codebase_and_setup_working_dir_when_agent_is_in_same_dir_with_master_process/Rakefile +6 -0
  74. 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
  75. metadata +72 -18
  76. data/lib/dtr/base.rb +0 -172
  77. data/lib/dtr/runner.rb +0 -270
  78. 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