dtr 0.0.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/CHANGES +7 -0
  2. data/LICENSE.txt +203 -0
  3. data/README.rdoc +208 -0
  4. data/Rakefile +64 -205
  5. data/TODO +8 -2
  6. data/bin/dtr +27 -60
  7. data/dtr.gemspec +8 -11
  8. data/lib/dtr.rb +5 -94
  9. data/lib/dtr/agent.rb +38 -0
  10. data/lib/dtr/agent/brain.rb +57 -0
  11. data/lib/dtr/agent/herald.rb +60 -0
  12. data/lib/dtr/agent/runner.rb +87 -0
  13. data/lib/dtr/agent/sync_codebase.rb +44 -0
  14. data/lib/dtr/agent/sync_logger.rb +70 -0
  15. data/lib/dtr/agent/test_case.rb +53 -0
  16. data/lib/dtr/agent/test_unit.rb +40 -0
  17. data/lib/dtr/agent/worker.rb +89 -0
  18. data/lib/dtr/agent/working_env_ext.rb +47 -0
  19. data/lib/dtr/facade.rb +65 -0
  20. data/lib/dtr/master.rb +40 -0
  21. data/lib/dtr/monitor.rb +95 -0
  22. data/lib/dtr/raketasks.rb +155 -22
  23. data/lib/dtr/shared.rb +24 -0
  24. data/lib/dtr/shared/adapter.rb +115 -0
  25. data/lib/dtr/shared/configuration.rb +104 -0
  26. data/lib/dtr/shared/message_decorator.rb +28 -0
  27. data/lib/dtr/shared/ruby_ext.rb +129 -0
  28. data/lib/dtr/shared/service.rb +19 -0
  29. data/lib/dtr/shared/service/agent.rb +37 -0
  30. data/lib/dtr/shared/service/file.rb +28 -0
  31. data/lib/dtr/shared/service/rinda.rb +48 -0
  32. data/lib/dtr/shared/service/runner.rb +34 -0
  33. data/lib/dtr/shared/service/working_env.rb +28 -0
  34. data/lib/dtr/shared/sync_codebase.rb +18 -0
  35. data/lib/dtr/shared/sync_codebase/copiable_package.rb +40 -0
  36. data/lib/dtr/shared/sync_codebase/master_ext.rb +40 -0
  37. data/lib/dtr/shared/sync_codebase/package.rb +53 -0
  38. data/lib/dtr/shared/sync_codebase/sync_service.rb +36 -0
  39. data/lib/dtr/shared/sync_logger.rb +64 -0
  40. data/lib/dtr/shared/utils.rb +17 -0
  41. data/lib/dtr/shared/utils/cmd.rb +30 -0
  42. data/lib/dtr/shared/utils/env_store.rb +60 -0
  43. data/lib/dtr/shared/utils/logger.rb +87 -0
  44. data/lib/dtr/shared/working_env.rb +38 -0
  45. data/lib/dtr/test_unit.rb +9 -275
  46. data/lib/dtr/test_unit/drb_test_runner.rb +48 -0
  47. data/lib/dtr/test_unit/injection.rb +29 -0
  48. data/lib/dtr/test_unit/test_case_injection.rb +37 -0
  49. data/lib/dtr/test_unit/test_suite_injection.rb +24 -0
  50. data/lib/dtr/test_unit/testrunnermediator_injection.rb +72 -0
  51. data/lib/dtr/test_unit/thread_safe_test_result.rb +38 -0
  52. data/lib/dtr/test_unit/worker_club.rb +72 -0
  53. data/lib/dtr/test_unit_injection.rb +1 -2
  54. data/test/acceptance/agent_working_env_test.rb +86 -0
  55. data/test/acceptance/dtr_package_task_test.rb +36 -0
  56. data/test/acceptance/general_test.rb +331 -0
  57. data/test/acceptance/raketasks_test.rb +23 -0
  58. data/test/acceptance/sync_codebase_test.rb +66 -0
  59. data/test/acceptance/sync_logger_test.rb +32 -0
  60. data/test/agent_helper.rb +37 -0
  61. data/test/logger_stub.rb +34 -0
  62. data/test/test_helper.rb +71 -0
  63. data/test/unit/adapter_test.rb +149 -0
  64. data/test/unit/configuration_test.rb +44 -0
  65. data/test/unit/facade_test.rb +41 -0
  66. data/test/unit/logger_test.rb +72 -0
  67. data/test/unit/test_unit_test.rb +26 -0
  68. data/test/unit/working_env_test.rb +71 -0
  69. data/testdata/Rakefile +11 -0
  70. data/testdata/a_failed_test_case.rb +8 -0
  71. data/testdata/a_file_system_test_case.rb +8 -0
  72. data/testdata/a_test_case.rb +13 -0
  73. data/testdata/a_test_case2.rb +6 -0
  74. data/testdata/an_error_test_case.rb +9 -0
  75. data/testdata/another_project/Rakefile +6 -0
  76. data/testdata/another_project/passed_test_case.rb +7 -0
  77. data/testdata/hacked_run_method_test_case.rb +15 -0
  78. data/testdata/is_required_by_a_test.rb +9 -0
  79. data/testdata/lib/lib_test_case.rb +7 -0
  80. data/testdata/package_task_test_rakefile +8 -0
  81. data/testdata/raketasks/Rakefile +7 -0
  82. data/testdata/raketasks/success_test_case.rb +6 -0
  83. data/testdata/scenario_test_case.rb +34 -0
  84. data/testdata/setup_agent_env_test_case.rb +9 -0
  85. data/testdata/sleep_3_secs_test_case.rb +9 -0
  86. data/testdata/verify_dir_pwd/Rakefile +6 -0
  87. data/testdata/verify_dir_pwd/verify_dir_pwd_test_case.rb +10 -0
  88. metadata +101 -34
  89. data/README +0 -291
  90. data/install.rb +0 -88
  91. data/lib/dtr/base.rb +0 -172
  92. data/lib/dtr/runner.rb +0 -270
  93. data/lib/dtr/service_provider.rb +0 -160
@@ -0,0 +1,38 @@
1
+ # Copyright (c) 2007-2008 Li Xiao <iam@li-xiao.com>
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 ? $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
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2007-2008 Li Xiao
1
+ # Copyright (c) 2007-2008 Li Xiao <iam@li-xiao.com>
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -12,278 +12,12 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
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'
15
+ require 'dtr/master'
22
16
 
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
17
+ require 'dtr/test_unit/worker_club'
18
+ require 'dtr/test_unit/thread_safe_test_result'
19
+ require 'dtr/test_unit/drb_test_runner'
20
+ require 'dtr/test_unit/test_case_injection'
21
+ require 'dtr/test_unit/test_suite_injection'
22
+ require 'dtr/test_unit/testrunnermediator_injection'
23
+ require 'dtr/test_unit/injection'
@@ -0,0 +1,48 @@
1
+ # Copyright (c) 2007-2008 Li Xiao <iam@li-xiao.com>
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
+ class DRbTestRunner
18
+ include Service::Runner
19
+
20
+ def initialize(test, result, &progress_block)
21
+ @test = test
22
+ @result = result
23
+ @progress_block = progress_block
24
+ end
25
+
26
+ def run
27
+ if runner = lookup_runner
28
+ WorkerClub.instance.start_thread(self, runner)
29
+ else
30
+ self.run
31
+ end
32
+ end
33
+
34
+ def run_test_on(runner)
35
+ runner.run(@test, @result, &@progress_block)
36
+ rescue DRb::DRbConnError => e
37
+ DTR.info {"#{cause.class.name}(#{cause.message}), rerun test: #{@test.name}"}
38
+ DTR.debug { cause.backtrace.join("\n") }
39
+ self.run
40
+ rescue Exception => e
41
+ DTR.info{ "#{@test.name}, rescue an exception: #{e.message}, add error into result." }
42
+ @result.add_error(Test::Unit::Error.new(@test.name, e))
43
+ @result.add_run
44
+ @progress_block.call(Test::Unit::TestCase::FINISHED, @test.name)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,29 @@
1
+ # Copyright (c) 2007-2008 Li Xiao <iam@li-xiao.com>
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/ui/testrunnermediator'
16
+
17
+ module DTR
18
+ def reject
19
+ return unless Test::Unit::UI::TestRunnerMediator.respond_to?(:reject_dtr)
20
+ Test::Unit::UI::TestRunnerMediator.reject_dtr
21
+ end
22
+
23
+ def inject
24
+ return if Test::Unit::UI::TestRunnerMediator.respond_to?(:reject_dtr)
25
+ Test::Unit::UI::TestRunnerMediator.send(:include, TestUnit::TestRunnerMediatorInjection)
26
+ end
27
+
28
+ module_function :reject, :inject
29
+ end
@@ -0,0 +1,37 @@
1
+ # Copyright (c) 2007-2008 Li Xiao <iam@li-xiao.com>
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
+ class Proxy
19
+ def initialize(test)
20
+ @test = test
21
+ end
22
+
23
+ def run(result, &progress_block)
24
+ DRbTestRunner.new(@test, result, &progress_block).run
25
+ end
26
+
27
+ def size
28
+ @test.size
29
+ end
30
+ end
31
+
32
+ def proxy
33
+ Proxy.new(self)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,24 @@
1
+ # Copyright (c) 2007-2008 Li Xiao <iam@li-xiao.com>
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 TestSuiteInjection
18
+ def proxy
19
+ @tests.collect! {|t| t.proxy}
20
+ self
21
+ end
22
+ end
23
+ end
24
+ end