dtr 0.0.4 → 1.0.0

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 (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,104 @@
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 'singleton'
16
+ require 'rinda/ring'
17
+ require 'rinda/tuplespace'
18
+
19
+ module DTR
20
+
21
+ def configuration
22
+ Configuration.instance
23
+ end
24
+
25
+ module_function :configuration
26
+
27
+ # DTR Configuration includes:
28
+ # For both master & agent process:
29
+ # * broadcast_list: broadcast ip list for looking for dtr services(agent and DTR master rinda server).
30
+ # * group: grouping agents for specific usage, master process should specify same group for catching agents to work
31
+ # For master process:
32
+ # * rinda_server_port: DTR would automatically detect unused port for master rinda server. The default port is 3344.
33
+ # * master_heartbeat_interval: master process heartbeat for keeping agents working. The default is 10 sec.
34
+ # For agent process:
35
+ # * agent_listen_port: agent listen master process command port, the default port is 7788.
36
+ # * follower_listen_heartbeat_timeout: agents would be going to sleep if listening master heartbeat timeout. The default is 15 sec.
37
+ #
38
+ # All configurations except rinda_server_port would be stored into pstore file .dtr_env_pstore in the DTR process launching directory.
39
+ #
40
+ class Configuration
41
+ include Singleton
42
+ include Service::Rinda
43
+
44
+ attr_accessor :broadcast_list, :rinda_server_port, :agent_listen_port, :master_heartbeat_interval, :follower_listen_heartbeat_timeout
45
+ attr_reader :group
46
+
47
+ def initialize
48
+ load
49
+ end
50
+
51
+ def load
52
+ store = EnvStore.new
53
+ # always have 'localhost' in broadcast_list, for our master process would start rinda server locally,
54
+ # and dtr should work well on local machine when the machine leaves dtr grid network environment.
55
+ @broadcast_list = ['localhost'].concat(store[:broadcast_list] || []).uniq
56
+ @rinda_server_port = 3344
57
+ @agent_listen_port = store[:agent_listen_port] || 7788
58
+ @master_heartbeat_interval = store[:master_heartbeat_interval] || 10
59
+ @follower_listen_heartbeat_timeout = store[:follower_listen_heartbeat_timeout] || 15
60
+ @group = store[:group]
61
+ end
62
+
63
+ def save
64
+ store = EnvStore.new
65
+ store[:broadcast_list] = @broadcast_list
66
+ store[:agent_listen_port] = @agent_listen_port
67
+ store[:master_heartbeat_interval] = @master_heartbeat_interval
68
+ store[:follower_listen_heartbeat_timeout] = @follower_listen_heartbeat_timeout
69
+ store[:group] = @group
70
+ end
71
+
72
+ def group=(group)
73
+ @group = group.blank? ? nil : group.gsub(' ', '_')
74
+ end
75
+
76
+ def with_rinda_server(&block)
77
+ DTR.do_println("Booting DTR service")
78
+ start_service
79
+ DTR.info {'-- Booting DTR Rinda server'}
80
+ loop do
81
+ begin
82
+ Rinda::RingServer.new Rinda::TupleSpace.new, @rinda_server_port
83
+ break
84
+ rescue Errno::EADDRINUSE
85
+ @rinda_server_port += 1
86
+ end
87
+ end
88
+ DTR.info {"-- DTR Rinda server started on port #{@rinda_server_port}"}
89
+ block.call
90
+ ensure
91
+ stop_service rescue nil
92
+ end
93
+
94
+ def lookup_ring_any
95
+ @ring ||= __lookup_ring_any__
96
+ end
97
+
98
+ private
99
+ def __lookup_ring_any__
100
+ DTR.info {"broadcast list: #{@broadcast_list.inspect} on port #{@rinda_server_port}"}
101
+ ::Rinda::TupleSpaceProxy.new(Rinda::RingFinger.new(@broadcast_list, @rinda_server_port).lookup_ring_any)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,28 @@
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 MessageDecorator
17
+ def decorate_message(msg, source=nil)
18
+ source ? "#{source} from #{Socket.gethostname}: #{msg}" : "From #{Socket.gethostname}: #{msg}"
19
+ end
20
+ end
21
+ class RemoteError < StandardError
22
+ include MessageDecorator
23
+ def initialize(e)
24
+ super(decorate_message(e.message, e.class.name))
25
+ set_backtrace(e.backtrace)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,129 @@
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
+ # from activesupport-2.1.1
16
+ class Object
17
+ def blank?
18
+ respond_to?(:empty?) ? empty? : !self
19
+ end
20
+ end
21
+
22
+ class NilClass
23
+ def blank?
24
+ true
25
+ end
26
+ end
27
+
28
+ class FalseClass
29
+ def blank?
30
+ true
31
+ end
32
+ end
33
+
34
+ class TrueClass
35
+ def blank?
36
+ false
37
+ end
38
+ end
39
+
40
+ class Array
41
+ alias_method :blank?, :empty?
42
+ end
43
+
44
+ class Hash
45
+ alias_method :blank?, :empty?
46
+ end
47
+
48
+ class String
49
+ def blank?
50
+ self !~ /\S/
51
+ end
52
+ end
53
+
54
+ class Numeric
55
+ def blank?
56
+ false
57
+ end
58
+ end
59
+
60
+ class Module
61
+ # Encapsulates the common pattern of:
62
+ #
63
+ # alias_method :foo_without_feature, :foo
64
+ # alias_method :foo, :foo_with_feature
65
+ #
66
+ # With this, you simply do:
67
+ #
68
+ # alias_method_chain :foo, :feature
69
+ #
70
+ # And both aliases are set up for you.
71
+ #
72
+ # Query and bang methods (foo?, foo!) keep the same punctuation:
73
+ #
74
+ # alias_method_chain :foo?, :feature
75
+ #
76
+ # is equivalent to
77
+ #
78
+ # alias_method :foo_without_feature?, :foo?
79
+ # alias_method :foo?, :foo_with_feature?
80
+ #
81
+ # so you can safely chain foo, foo?, and foo! with the same feature.
82
+ def alias_method_chain(target, feature)
83
+ # Strip out punctuation on predicates or bang methods since
84
+ # e.g. target?_without_feature is not a valid method name.
85
+ aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
86
+ yield(aliased_target, punctuation) if block_given?
87
+
88
+ with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}"
89
+
90
+ alias_method without_method, target
91
+ alias_method target, with_method
92
+
93
+ case
94
+ when public_method_defined?(without_method)
95
+ public target
96
+ when protected_method_defined?(without_method)
97
+ protected target
98
+ when private_method_defined?(without_method)
99
+ private target
100
+ end
101
+ end
102
+
103
+ # Allows you to make aliases for attributes, which includes
104
+ # getter, setter, and query methods.
105
+ #
106
+ # Example:
107
+ #
108
+ # class Content < ActiveRecord::Base
109
+ # # has a title attribute
110
+ # end
111
+ #
112
+ # class Email < Content
113
+ # alias_attribute :subject, :title
114
+ # end
115
+ #
116
+ # e = Email.find(1)
117
+ # e.title # => "Superstars"
118
+ # e.subject # => "Superstars"
119
+ # e.subject? # => true
120
+ # e.subject = "Megastars"
121
+ # e.title # => "Megastars"
122
+ def alias_attribute(new_name, old_name)
123
+ module_eval <<-STR, __FILE__, __LINE__+1
124
+ def #{new_name}; self.#{old_name}; end
125
+ def #{new_name}?; self.#{old_name}?; end
126
+ def #{new_name}=(v); self.#{old_name} = v; end
127
+ STR
128
+ end
129
+ end
@@ -0,0 +1,19 @@
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 'dtr/shared/service/rinda'
16
+ require 'dtr/shared/service/file'
17
+ require 'dtr/shared/service/runner'
18
+ require 'dtr/shared/service/working_env'
19
+ require 'dtr/shared/service/agent'
@@ -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 Service
17
+ module Agent
18
+ include Rinda
19
+ def new_agent_monitor
20
+ lookup_ring.notify(nil, [:agent, nil])
21
+ end
22
+
23
+ def provide_agent_info(setup_env_cmd, runners)
24
+ agent = %{
25
+ - agent(host at #{Socket.gethostname}):
26
+ default setup environment command: '#{setup_env_cmd}'
27
+ runners: #{runners.inspect}
28
+ }
29
+ lookup_ring.write [:agent, agent]
30
+ end
31
+
32
+ def all_agents_info
33
+ lookup_ring.read_all([:agent, nil]).collect{|t|t[1]}
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,28 @@
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 Service
17
+ module File
18
+ include Rinda
19
+ def lookup_file
20
+ lookup(:read, [:file, nil])[1]
21
+ end
22
+
23
+ def provide_file(file)
24
+ lookup_ring.write [:file, file]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -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
+ require 'drb'
16
+ require 'rinda/ring'
17
+
18
+ module DTR
19
+ module Service
20
+ module Rinda
21
+
22
+ def start_service
23
+ DTR.info {"-- Start drb service..."}
24
+ #todo need figure why agents couldn't be killed directly when start drb service by DRb.start_service
25
+ if ENV['DTR_ENV'] == 'test'
26
+ DRb.start_service("druby://#{Socket.gethostname}:0")
27
+ else
28
+ DRb.start_service
29
+ end
30
+ rescue
31
+ # for ruby 1.8.7 need specify uri
32
+ DRb.start_service("druby://#{Socket.gethostname}:0")
33
+ end
34
+
35
+ def stop_service
36
+ DRb.stop_service
37
+ end
38
+
39
+ def lookup(method, stuff, timeout=nil)
40
+ lookup_ring.send(method, stuff, timeout)
41
+ end
42
+
43
+ def lookup_ring
44
+ DTR.configuration.lookup_ring_any
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,34 @@
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 'rinda/ring'
16
+
17
+ module DTR
18
+ module Service
19
+ module Runner
20
+ include Rinda
21
+
22
+ def provide_runner(runner)
23
+ tuple = ['DTR::Runner'.to_sym, runner, "DTR remote runner #{Process.pid}-#{runner.name}"]
24
+ #expires after 1 sec for we don't need runner service anymore if there is no one is waiting for taking it
25
+ lookup_ring.write(tuple, 1)
26
+ end
27
+
28
+ def lookup_runner
29
+ lookup(:take, ['DTR::Runner'.to_sym, nil, nil])[1]
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,28 @@
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 Service
17
+ module WorkingEnv
18
+ include Rinda
19
+ def lookup_working_env
20
+ lookup(:read, [:working_env, nil])[1]
21
+ end
22
+
23
+ def provide_working_env(env)
24
+ lookup_ring.write [:working_env, env]
25
+ end
26
+ end
27
+ end
28
+ end