xli-dtr 0.0.4
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/CHANGES +16 -0
- data/LICENSE.TXT +203 -0
- data/README +291 -0
- data/Rakefile +373 -0
- data/TODO +8 -0
- data/bin/dtr +124 -0
- data/dtr.gemspec +33 -0
- data/install.rb +88 -0
- data/lib/dtr/base.rb +172 -0
- data/lib/dtr/raketasks.rb +69 -0
- data/lib/dtr/runner.rb +270 -0
- data/lib/dtr/service_provider.rb +160 -0
- data/lib/dtr/test_unit.rb +289 -0
- data/lib/dtr/test_unit_injection.rb +19 -0
- data/lib/dtr.rb +111 -0
- metadata +78 -0
@@ -0,0 +1,289 @@
|
|
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/base'
|
16
|
+
require 'dtr/service_provider'
|
17
|
+
require 'test/unit/testcase'
|
18
|
+
require 'test/unit/util/observable'
|
19
|
+
require 'monitor'
|
20
|
+
require 'drb'
|
21
|
+
require 'timeout'
|
22
|
+
|
23
|
+
DTROPTIONS = {} unless defined?(DTROPTIONS)
|
24
|
+
DTROPTIONS[:log_file] = 'dtr_master_process.log' unless DTROPTIONS[:log_file]
|
25
|
+
|
26
|
+
module DTR
|
27
|
+
def reject
|
28
|
+
return unless Test::Unit::TestSuite.method_defined?(:dtr_injected?)
|
29
|
+
Test::Unit::TestCase.send(:include, Rejection)
|
30
|
+
Test::Unit::TestSuite.send(:include, Rejection)
|
31
|
+
end
|
32
|
+
|
33
|
+
def inject
|
34
|
+
return if Test::Unit::TestSuite.method_defined?(:dtr_injected?)
|
35
|
+
Test::Unit::TestCase.send(:include, TestCaseInjection)
|
36
|
+
Test::Unit::TestSuite.send(:include, TestSuiteInjection)
|
37
|
+
end
|
38
|
+
|
39
|
+
def service_provider
|
40
|
+
$dtr_service_provider ||= DTR::ServiceProvider.new
|
41
|
+
end
|
42
|
+
|
43
|
+
module_function :reject, :inject, :service_provider
|
44
|
+
|
45
|
+
class Counter
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
extend MonitorMixin
|
49
|
+
@start_count, @finish_count = 0, 0
|
50
|
+
@complete_cond = new_cond
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_start_count
|
54
|
+
synchronize do
|
55
|
+
@start_count += 1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_finish_count
|
60
|
+
synchronize do
|
61
|
+
@finish_count += 1
|
62
|
+
@complete_cond.signal
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_s
|
67
|
+
synchronize do
|
68
|
+
status
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def wait_until_complete
|
73
|
+
synchronize do
|
74
|
+
@complete_cond.wait_until {complete?}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
def complete?
|
80
|
+
DTR.info{ "Counter status: #{status}" }
|
81
|
+
@finish_count >= @start_count
|
82
|
+
end
|
83
|
+
|
84
|
+
def status
|
85
|
+
"finish_count => #{@finish_count}, start_count => #{@start_count}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class ThreadSafeTestResult
|
90
|
+
include Test::Unit::Util::Observable
|
91
|
+
include DRbUndumped
|
92
|
+
|
93
|
+
def initialize(rs)
|
94
|
+
extend MonitorMixin
|
95
|
+
@rs = rs
|
96
|
+
@channels = @rs.send(:channels).dup
|
97
|
+
@rs.send(:channels).clear
|
98
|
+
end
|
99
|
+
|
100
|
+
def add_run
|
101
|
+
synchronize do
|
102
|
+
@rs.add_run
|
103
|
+
end
|
104
|
+
notify_listeners(Test::Unit::TestResult::CHANGED, self)
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_failure(failure)
|
108
|
+
synchronize do
|
109
|
+
@rs.add_failure(failure)
|
110
|
+
end
|
111
|
+
notify_listeners(Test::Unit::TestResult::FAULT, failure)
|
112
|
+
notify_listeners(Test::Unit::TestResult::CHANGED, self)
|
113
|
+
end
|
114
|
+
|
115
|
+
def add_error(error)
|
116
|
+
synchronize do
|
117
|
+
@rs.add_error(error)
|
118
|
+
end
|
119
|
+
notify_listeners(Test::Unit::TestResult::FAULT, error)
|
120
|
+
notify_listeners(Test::Unit::TestResult::CHANGED, self)
|
121
|
+
end
|
122
|
+
|
123
|
+
def add_assertion
|
124
|
+
synchronize do
|
125
|
+
@rs.add_assertion
|
126
|
+
end
|
127
|
+
notify_listeners(Test::Unit::TestResult::CHANGED, self)
|
128
|
+
end
|
129
|
+
|
130
|
+
def to_s
|
131
|
+
synchronize do
|
132
|
+
@rs.to_s
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def passed?
|
137
|
+
synchronize do
|
138
|
+
@rs.passed?
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def failure_count
|
143
|
+
synchronize do
|
144
|
+
@rs.failure_count
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def error_count
|
149
|
+
synchronize do
|
150
|
+
@rs.error_count
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class DRbTestRunner
|
156
|
+
|
157
|
+
# because some test case will rewrite TestCase#run to ignore some tests, which
|
158
|
+
# makes TestResult#run_count different with TestSuite#size, so we need to count
|
159
|
+
# by ourselves.(for example: ActionController::IntegrationTest)
|
160
|
+
class << self
|
161
|
+
def counter
|
162
|
+
@counter ||= Counter.new
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
RUN_TEST_FINISHED = "::DRbTestRunner::RUN_TEST_FINISHED"
|
167
|
+
DEFAULT_RUN_TEST_TIMEOUT = 60 #seconds
|
168
|
+
|
169
|
+
def initialize(test, result, &progress_block)
|
170
|
+
@test = test
|
171
|
+
@result = result
|
172
|
+
@progress_block = progress_block
|
173
|
+
|
174
|
+
DRbTestRunner.counter.add_start_count
|
175
|
+
end
|
176
|
+
|
177
|
+
def run
|
178
|
+
if runner = lookup_runner
|
179
|
+
run_test_on(runner)
|
180
|
+
else
|
181
|
+
self.run
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def run_test_on(runner)
|
186
|
+
Thread.start do
|
187
|
+
begin
|
188
|
+
Timeout.timeout(ENV['RUN_TEST_TIMEOUT'] || DEFAULT_RUN_TEST_TIMEOUT) do
|
189
|
+
runner.run(@test, @result, &@progress_block)
|
190
|
+
end
|
191
|
+
@progress_block.call(RUN_TEST_FINISHED, @test.name)
|
192
|
+
rescue Timeout::Error => e
|
193
|
+
DTR.info {"Run test timeout(#{ENV['RUN_TEST_TIMEOUT'] || DEFAULT_RUN_TEST_TIMEOUT}), reboot runner"}
|
194
|
+
runner.reboot rescue nil
|
195
|
+
DTR.info {"rerun test: #{@test.name}"}
|
196
|
+
self.run
|
197
|
+
rescue DRb::DRbConnError => e
|
198
|
+
DTR.info {"DRb::DRbConnError(#{e.message}), rerun test: #{@test.name}"}
|
199
|
+
self.run
|
200
|
+
rescue Exception => e
|
201
|
+
DTR.info{ "#{test.name}, rescue an exception: #{e.message}, add error into result." }
|
202
|
+
@result.add_error(Test::Unit::Error.new(@test.name, e))
|
203
|
+
@result.add_run
|
204
|
+
@progress_block.call(Test::Unit::TestCase::FINISHED, @test.name)
|
205
|
+
@progress_block.call(RUN_TEST_FINISHED, @test.name)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def lookup_runner
|
211
|
+
runner = DTR.service_provider.lookup_runner
|
212
|
+
begin
|
213
|
+
DTR.debug {"#{runner.name}.env ==?: #{WorkingEnv.current[:identifier] == runner.identifier}"}
|
214
|
+
return runner if runner.identifier == WorkingEnv.current[:identifier]
|
215
|
+
runner.shutdown
|
216
|
+
rescue DRb::DRbConnError => e
|
217
|
+
DTR.debug {"DRb::DRbConnError(#{e.message})"}
|
218
|
+
end
|
219
|
+
nil
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
module TestCaseInjection
|
224
|
+
|
225
|
+
def self.included(base)
|
226
|
+
base.class_eval do
|
227
|
+
alias_method :__run__, :run
|
228
|
+
|
229
|
+
def run(result, &progress_block)
|
230
|
+
DTR.debug {"start of run TestCase(#{name})"}
|
231
|
+
DRbTestRunner.new(self, result, &progress_block).run
|
232
|
+
DTR.debug {"end of run TestCase(#{name})"}
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
module TestSuiteInjection
|
239
|
+
def self.included(base)
|
240
|
+
base.class_eval do
|
241
|
+
def dtr_injected?
|
242
|
+
true
|
243
|
+
end
|
244
|
+
|
245
|
+
alias_method :__run__, :run
|
246
|
+
|
247
|
+
def run(result, &progress_block)
|
248
|
+
DTR.info { "start of run suite(#{name}), size: #{size};"}
|
249
|
+
|
250
|
+
if result.kind_of?(ThreadSafeTestResult)
|
251
|
+
__run__(result, &progress_block)
|
252
|
+
else
|
253
|
+
if defined?(ActiveRecord::Base)
|
254
|
+
ActiveRecord::Base.clear_active_connections! rescue nil
|
255
|
+
end
|
256
|
+
|
257
|
+
DTR.service_provider.setup_working_env WorkingEnv.refresh
|
258
|
+
|
259
|
+
puts 'Refreshed dtr working environment, looking for runner service...' unless ENV['DTR_ENV'] == 'test'
|
260
|
+
DTR.info {"Master process started at #{Time.now}"}
|
261
|
+
result = ThreadSafeTestResult.new(result)
|
262
|
+
__run__(result) do |channel, value|
|
263
|
+
DTR.debug { "=> channel: #{channel}, value: #{value}" }
|
264
|
+
progress_block.call(channel, value)
|
265
|
+
if channel == DTR::DRbTestRunner::RUN_TEST_FINISHED
|
266
|
+
DRbTestRunner.counter.add_finish_count
|
267
|
+
end
|
268
|
+
end
|
269
|
+
DRbTestRunner.counter.wait_until_complete
|
270
|
+
DTR.debug { "==> teardown" }
|
271
|
+
DTR.service_provider.teardown_working_env
|
272
|
+
end
|
273
|
+
DTR.info { "end of run suite(#{name}), test result status: #{result}, counter status: #{DRbTestRunner.counter}"}
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
module Rejection
|
280
|
+
def self.included(base)
|
281
|
+
base.class_eval do
|
282
|
+
remove_method :dtr_injected? if base.method_defined?(:dtr_injected?)
|
283
|
+
remove_method :run
|
284
|
+
alias_method :run, :__run__
|
285
|
+
remove_method :__run__
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
@@ -0,0 +1,19 @@
|
|
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/service_provider'
|
16
|
+
require 'dtr/test_unit'
|
17
|
+
$argv_dup = ARGV.dup.delete_if{|f| f.include?('dtr/test_unit_injection')}
|
18
|
+
|
19
|
+
DTR.inject
|
data/lib/dtr.rb
ADDED
@@ -0,0 +1,111 @@
|
|
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
|
+
DTRVERSION="0.0.4"
|
16
|
+
DTROPTIONS = {} unless defined?(DTROPTIONS)
|
17
|
+
|
18
|
+
require 'fileutils'
|
19
|
+
|
20
|
+
module DTR
|
21
|
+
|
22
|
+
def start_server
|
23
|
+
require 'dtr/service_provider'
|
24
|
+
ServiceProvider.new.start
|
25
|
+
end
|
26
|
+
|
27
|
+
def start_runners
|
28
|
+
launch_runners(DTROPTIONS[:names], DTROPTIONS[:setup])
|
29
|
+
end
|
30
|
+
|
31
|
+
def launch_runners(names, setup=nil)
|
32
|
+
require 'dtr/runner'
|
33
|
+
names = names || "DTR(#{Time.now})"
|
34
|
+
DTR::RunnerAgent.start(names, setup)
|
35
|
+
end
|
36
|
+
|
37
|
+
def lib_path
|
38
|
+
File.expand_path(File.dirname(__FILE__))
|
39
|
+
end
|
40
|
+
|
41
|
+
def broadcast_list=(list)
|
42
|
+
require 'dtr/service_provider'
|
43
|
+
ServiceProvider.broadcast_list = list
|
44
|
+
end
|
45
|
+
|
46
|
+
def port=(port)
|
47
|
+
require 'dtr/service_provider'
|
48
|
+
ServiceProvider.port = port
|
49
|
+
end
|
50
|
+
|
51
|
+
def runners
|
52
|
+
require 'dtr/service_provider'
|
53
|
+
ServiceProvider.new.runners
|
54
|
+
end
|
55
|
+
|
56
|
+
def monitor
|
57
|
+
require 'dtr/service_provider'
|
58
|
+
DTROPTIONS[:log_file] = 'dtr_monitor.log'
|
59
|
+
ServiceProvider.new.monitor
|
60
|
+
end
|
61
|
+
|
62
|
+
def stop_runners_daemon_mode
|
63
|
+
with_daemon_gem do
|
64
|
+
Daemons.run_proc "dtr_runners", :ARGV => ['stop']
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def start_runners_daemon_mode
|
69
|
+
with_daemon_gem do
|
70
|
+
FileUtils.rm_rf('dtr_runners.output')
|
71
|
+
pwd = Dir.pwd
|
72
|
+
Daemons.run_proc "dtr_runners", :ARGV => ['start'], :backtrace => true do
|
73
|
+
Dir.chdir(pwd) do
|
74
|
+
start_runners
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def start_server_daemon_mode
|
81
|
+
with_daemon_gem do
|
82
|
+
Daemons.run_proc "dtr_server", :ARGV => ['start'] do
|
83
|
+
start_server
|
84
|
+
end
|
85
|
+
end
|
86
|
+
sleep(2)
|
87
|
+
end
|
88
|
+
|
89
|
+
def stop_server_daemon_mode
|
90
|
+
with_daemon_gem do
|
91
|
+
Daemons.run_proc "dtr_server", :ARGV => ['stop']
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def with_daemon_gem
|
96
|
+
require "rubygems"
|
97
|
+
begin
|
98
|
+
require "daemons"
|
99
|
+
rescue LoadError
|
100
|
+
raise "The daemons gem must be installed"
|
101
|
+
end
|
102
|
+
yield
|
103
|
+
end
|
104
|
+
|
105
|
+
def clean_server
|
106
|
+
require 'dtr/service_provider'
|
107
|
+
ServiceProvider.new.clear_workspace
|
108
|
+
end
|
109
|
+
|
110
|
+
module_function :start_server, :start_runners, :launch_runners, :lib_path, :broadcast_list=, :runners, :with_daemon_gem, :start_runners_daemon_mode, :stop_runners_daemon_mode, :start_server_daemon_mode, :stop_server_daemon_mode, :monitor, :port=, :clean_server
|
111
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xli-dtr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Li Xiao
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-08-13 00:00:00 -07:00
|
13
|
+
default_executable: dtr
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: daemons
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.0.7
|
23
|
+
version:
|
24
|
+
description:
|
25
|
+
email: iam@li-xiao.com
|
26
|
+
executables:
|
27
|
+
- dtr
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- lib/dtr/base.rb
|
34
|
+
- lib/dtr/raketasks.rb
|
35
|
+
- lib/dtr/runner.rb
|
36
|
+
- lib/dtr/service_provider.rb
|
37
|
+
- lib/dtr/test_unit.rb
|
38
|
+
- lib/dtr/test_unit_injection.rb
|
39
|
+
- lib/dtr.rb
|
40
|
+
- bin/dtr
|
41
|
+
- bin
|
42
|
+
- CHANGES
|
43
|
+
- doc
|
44
|
+
- dtr.gemspec
|
45
|
+
- install.rb
|
46
|
+
- lib
|
47
|
+
- LICENSE.TXT
|
48
|
+
- Rakefile
|
49
|
+
- README
|
50
|
+
- TODO
|
51
|
+
has_rdoc: false
|
52
|
+
homepage: http://github.com/xli/dtr/tree/master
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
version:
|
70
|
+
requirements: []
|
71
|
+
|
72
|
+
rubyforge_project: dtr
|
73
|
+
rubygems_version: 1.2.0
|
74
|
+
signing_key:
|
75
|
+
specification_version: 2
|
76
|
+
summary: DTR is a distributed test runner to run tests on distributed computers for decreasing build time.
|
77
|
+
test_files: []
|
78
|
+
|