jstorimer-deep-test 1.4.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. data/.gitignore +1 -0
  2. data/README.rdoc +41 -70
  3. data/Rakefile +47 -119
  4. data/TODO +2 -2
  5. data/VERSION +1 -1
  6. data/infrastructure/dynamic_teardown.rb +22 -0
  7. data/{test → infrastructure}/fake_deadlock_error.rb +0 -0
  8. data/infrastructure/load.rb +11 -0
  9. data/infrastructure/test_central_command.rb +15 -0
  10. data/infrastructure/test_exception.rb +7 -0
  11. data/{test → infrastructure}/test_factory.rb +0 -0
  12. data/infrastructure/test_logger.rb +11 -0
  13. data/infrastructure/test_operator.rb +15 -0
  14. data/infrastructure/test_result.rb +15 -0
  15. data/infrastructure/thread_agent.rb +21 -0
  16. data/infrastructure/timewarp/Rakefile +14 -0
  17. data/infrastructure/timewarp/lib/timewarp.rb +21 -0
  18. data/infrastructure/timewarp/test/timewarp_test.rb +45 -0
  19. data/lib/deep_test.rb +28 -40
  20. data/lib/deep_test/agent.rb +108 -0
  21. data/lib/deep_test/central_command.rb +165 -0
  22. data/lib/deep_test/cpu_info.rb +22 -0
  23. data/lib/deep_test/database/mysql_setup_listener.rb +11 -12
  24. data/lib/deep_test/database/setup_listener.rb +23 -23
  25. data/lib/deep_test/demon.rb +25 -0
  26. data/lib/deep_test/distributed/beachhead.rb +104 -0
  27. data/lib/deep_test/distributed/dispatch_controller.rb +17 -10
  28. data/lib/deep_test/distributed/establish_beachhead.rb +19 -0
  29. data/lib/deep_test/distributed/landing_fleet.rb +30 -0
  30. data/lib/deep_test/distributed/landing_ship.rb +60 -0
  31. data/lib/deep_test/distributed/remote_deployment.rb +56 -0
  32. data/lib/deep_test/distributed/rsync.rb +25 -12
  33. data/lib/deep_test/distributed/shell_environment.rb +50 -0
  34. data/lib/deep_test/distributed/ssh_client_connection_info.rb +14 -0
  35. data/lib/deep_test/failure_message.rb +19 -0
  36. data/lib/deep_test/lib_root.rb +4 -0
  37. data/lib/deep_test/listener_list.rb +1 -1
  38. data/lib/deep_test/local_deployment.rb +46 -0
  39. data/lib/deep_test/logger.rb +17 -2
  40. data/lib/deep_test/main.rb +41 -0
  41. data/lib/deep_test/marshallable_exception_wrapper.rb +4 -4
  42. data/lib/deep_test/metrics/data.rb +34 -0
  43. data/lib/deep_test/metrics/measurement.rb +39 -0
  44. data/lib/deep_test/{null_worker_listener.rb → null_listener.rb} +14 -14
  45. data/lib/deep_test/options.rb +41 -56
  46. data/lib/deep_test/proxy_io.rb +77 -0
  47. data/lib/deep_test/rake_tasks.rb +3 -1
  48. data/lib/deep_test/result_reader.rb +10 -6
  49. data/lib/deep_test/rspec_detector.rb +1 -1
  50. data/lib/deep_test/spec.rb +5 -1
  51. data/lib/deep_test/spec/extensions/example_methods.rb +7 -1
  52. data/lib/deep_test/spec/extensions/spec_task.rb +3 -2
  53. data/lib/deep_test/spec/runner.rb +32 -17
  54. data/lib/deep_test/spec/work_result.rb +2 -0
  55. data/lib/deep_test/test/run_test_suite.rb +5 -0
  56. data/lib/deep_test/test/runner.rb +2 -2
  57. data/lib/deep_test/test/supervised_test_suite.rb +9 -10
  58. data/lib/deep_test/test/work_result.rb +1 -0
  59. data/lib/deep_test/test_task.rb +1 -1
  60. data/lib/deep_test/ui/console.rb +9 -11
  61. data/lib/deep_test/warlock.rb +37 -25
  62. data/lib/telegraph.rb +29 -0
  63. data/lib/telegraph/ack_sequence.rb +14 -0
  64. data/lib/telegraph/logging.rb +20 -0
  65. data/lib/telegraph/message.rb +39 -0
  66. data/lib/telegraph/operator.rb +47 -0
  67. data/lib/telegraph/switchboard.rb +57 -0
  68. data/lib/telegraph/wire.rb +73 -0
  69. data/negative_acceptance_tests/dying_spec.rb +13 -0
  70. data/negative_acceptance_tests/dying_test.rb +13 -0
  71. data/negative_acceptance_tests/failing_spec.rb +9 -0
  72. data/{test/failing.rb → negative_acceptance_tests/failing_test.rb} +3 -1
  73. data/negative_acceptance_tests/kill_agent_one_on_start_work.rb +16 -0
  74. data/negative_acceptance_tests/passing_spec.rb +10 -0
  75. data/negative_acceptance_tests/passing_test.rb +12 -0
  76. data/negative_acceptance_tests/tasks.rake +87 -0
  77. data/negative_acceptance_tests/tests.rb +60 -0
  78. data/sample_rails_project/deep_test.rb +4 -0
  79. data/sample_rails_project/lib/{foreign_host_worker_simulation_listener.rb → foreign_host_agent_simulation_listener.rb} +6 -4
  80. data/sample_rails_project/lib/tasks/deep_test.rake +13 -4
  81. data/spec/deep_test/options_spec.rb +80 -59
  82. data/spec/deep_test/spec/extensions/example_methods_spec.rb +5 -4
  83. data/spec/deep_test/spec/extensions/spec_task_spec.rb +4 -6
  84. data/spec/deep_test/spec/runner_spec.rb +59 -32
  85. data/spec/spec_helper.rb +14 -6
  86. data/test/deep_test/agent_test.rb +175 -0
  87. data/test/deep_test/central_command_test.rb +147 -0
  88. data/test/deep_test/cpu_info_test.rb +33 -0
  89. data/test/deep_test/database/mysql_setup_listener_test.rb +13 -9
  90. data/test/deep_test/demon_test.rb +23 -0
  91. data/test/deep_test/distributed/beachhead_test.rb +67 -0
  92. data/test/deep_test/distributed/dispatch_controller_test.rb +130 -177
  93. data/test/deep_test/distributed/filename_resolver_test.rb +38 -34
  94. data/test/deep_test/distributed/landing_fleet_test.rb +55 -0
  95. data/test/deep_test/distributed/landing_ship_test.rb +48 -0
  96. data/test/deep_test/distributed/remote_deployment_test.rb +134 -0
  97. data/test/deep_test/distributed/rsync_test.rb +42 -62
  98. data/test/deep_test/distributed/shell_environment_fixtures/set_bar_to_foo +1 -0
  99. data/test/deep_test/distributed/shell_environment_fixtures/set_foo_to_bar +1 -0
  100. data/test/deep_test/distributed/shell_environment_fixtures/set_foo_to_baz +1 -0
  101. data/test/deep_test/distributed/shell_environment_test.rb +108 -0
  102. data/test/deep_test/distributed/ssh_client_connection_info_test.rb +34 -0
  103. data/test/deep_test/listener_list_test.rb +17 -15
  104. data/test/deep_test/local_deployment_test.rb +19 -0
  105. data/test/deep_test/logger_test.rb +34 -7
  106. data/test/deep_test/main_test.rb +12 -0
  107. data/test/deep_test/marshallable_exception_wrapper_test.rb +31 -29
  108. data/test/deep_test/metrics/data_test.rb +22 -0
  109. data/test/deep_test/metrics/measurement_test.rb +18 -0
  110. data/test/deep_test/proxy_io_test.rb +104 -0
  111. data/test/deep_test/result_reader_test.rb +95 -95
  112. data/test/deep_test/test/extensions/error_test.rb +38 -36
  113. data/test/deep_test/test/runner_test.rb +7 -3
  114. data/test/deep_test/test/supervised_test_suite_test.rb +89 -61
  115. data/test/deep_test/test/work_result_test.rb +80 -76
  116. data/test/deep_test/test/work_unit_test.rb +53 -51
  117. data/test/deep_test/test_task_test.rb +10 -38
  118. data/test/deep_test/ui/console_test.rb +8 -4
  119. data/test/deep_test/warlock_test.rb +33 -31
  120. data/test/test_helper.rb +20 -5
  121. data/test/test_task_test.rb +60 -57
  122. metadata +94 -84
  123. data/bin/deep_test +0 -15
  124. data/jstorimer-deep-test-0.1.0.gem +0 -0
  125. data/jstorimer-deep-test.gemspec +0 -1425
  126. data/lib/deep_test/distributed/drb_client_connection_info.rb +0 -15
  127. data/lib/deep_test/distributed/master_test_server.rb +0 -52
  128. data/lib/deep_test/distributed/multi_test_server_proxy.rb +0 -44
  129. data/lib/deep_test/distributed/null_work_unit.rb +0 -12
  130. data/lib/deep_test/distributed/remote_worker_client.rb +0 -54
  131. data/lib/deep_test/distributed/remote_worker_server.rb +0 -82
  132. data/lib/deep_test/distributed/show_status.rhtml +0 -41
  133. data/lib/deep_test/distributed/test_server.rb +0 -78
  134. data/lib/deep_test/distributed/test_server_status.rb +0 -9
  135. data/lib/deep_test/distributed/test_server_workers.rb +0 -24
  136. data/lib/deep_test/distributed/throughput_runner.rb +0 -42
  137. data/lib/deep_test/distributed/throughput_statistics.rb +0 -26
  138. data/lib/deep_test/distributed/throughput_worker_client.rb +0 -19
  139. data/lib/deep_test/extensions/drb_extension.rb +0 -34
  140. data/lib/deep_test/local_workers.rb +0 -55
  141. data/lib/deep_test/metrics/gatherer.rb +0 -67
  142. data/lib/deep_test/metrics/queue_lock_wait_time_measurement.rb +0 -133
  143. data/lib/deep_test/option.rb +0 -60
  144. data/lib/deep_test/process_orchestrator.rb +0 -49
  145. data/lib/deep_test/server.rb +0 -75
  146. data/lib/deep_test/spec/extensions/reporter.rb +0 -29
  147. data/lib/deep_test/worker.rb +0 -57
  148. data/script/internal/run_test_suite.rb +0 -7
  149. data/script/public/master_test_server.rb +0 -24
  150. data/script/public/test_server.rb +0 -18
  151. data/script/public/test_throughput.rb +0 -29
  152. data/spec/deep_test/option_spec.rb +0 -33
  153. data/spec/thread_worker.rb +0 -25
  154. data/test/deep_test/distributed/drb_client_connection_info_test.rb +0 -42
  155. data/test/deep_test/distributed/master_test_server_test.rb +0 -32
  156. data/test/deep_test/distributed/multi_test_server_proxy_test.rb +0 -96
  157. data/test/deep_test/distributed/remote_worker_client_test.rb +0 -180
  158. data/test/deep_test/distributed/remote_worker_server_test.rb +0 -99
  159. data/test/deep_test/distributed/test_server_test.rb +0 -94
  160. data/test/deep_test/distributed/test_server_workers_test.rb +0 -26
  161. data/test/deep_test/distributed/throughput_runner_test.rb +0 -68
  162. data/test/deep_test/distributed/throughput_worker_client_test.rb +0 -28
  163. data/test/deep_test/local_workers_test.rb +0 -22
  164. data/test/deep_test/metrics/gatherer_test.rb +0 -66
  165. data/test/deep_test/process_orchestrator_test.rb +0 -11
  166. data/test/deep_test/server_test.rb +0 -58
  167. data/test/deep_test/worker_test.rb +0 -94
  168. data/test/failing.rake +0 -11
  169. data/test/simple_test_blackboard.rb +0 -45
  170. data/test/simple_test_blackboard_test.rb +0 -33
@@ -0,0 +1,165 @@
1
+ require 'set'
2
+
3
+ module DeepTest
4
+ class CentralCommand
5
+ attr_reader :operator
6
+ attr_reader :switchboard
7
+ attr_reader :data
8
+
9
+ def initialize(options)
10
+ @options = options
11
+ @work_queue = Queue.new
12
+ @results_mutex = Mutex.new
13
+ @results_condvar = ConditionVariable.new
14
+ @results = []
15
+ @data = Metrics::Data.new
16
+ end
17
+
18
+ def done_with_work
19
+ @done_with_work = true
20
+ end
21
+
22
+ def take_result
23
+ @results_mutex.synchronize do
24
+ loop do
25
+ if @results.any?
26
+ return @results.shift
27
+ else
28
+ @results_condvar.wait @results_mutex
29
+ raise NoAgentsRunningError unless @results.any? || @switchboard.any_live_wires?
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def take_work
36
+ @work_queue.pop(true)
37
+ rescue ThreadError => e
38
+ if e.message == "queue empty"
39
+ raise NoWorkUnitsRemainingError if @done_with_work
40
+ raise NoWorkUnitsAvailableError
41
+ else
42
+ raise
43
+ end
44
+ end
45
+
46
+ def write_result(result)
47
+ @results_mutex.synchronize do
48
+ @results << result
49
+ @results_condvar.signal
50
+ end
51
+ end
52
+
53
+ def write_work(work_unit)
54
+ @work_queue.push work_unit
55
+ end
56
+
57
+ def stdout
58
+ $stdout
59
+ end
60
+
61
+ def stderr
62
+ $stderr
63
+ end
64
+
65
+ def self.start(options)
66
+ central_command = new(options)
67
+ central_command.start
68
+ central_command
69
+ end
70
+
71
+ def start
72
+ @switchboard = Telegraph::Switchboard.new
73
+ @operator = Telegraph::Operator.listen("0.0.0.0", 0, @switchboard)
74
+ @options.server_port = @operator.port
75
+ @process_messages_thread = Thread.new { process_messages }
76
+
77
+ DeepTest.logger.info { "Started DeepTest service on port #{@operator.port}" }
78
+ end
79
+
80
+ unless defined?(NeedWork)
81
+ NeedWork = "NeedWork"
82
+ NoMoreWork = "NoMoreWork"
83
+ module Result; end
84
+ module Operation; end
85
+ end
86
+
87
+ def process_messages
88
+ loop do
89
+ begin
90
+ return if @stop_process_messages
91
+ wires_waiting_for_work.each { |w| send_work w }
92
+
93
+ @results_mutex.synchronize do
94
+ # make take_result wake up and check if any agents are running
95
+ @results_condvar.signal
96
+ end
97
+
98
+ message, wire = switchboard.next_message(:timeout => 0.5)
99
+
100
+ case message.body
101
+ when NeedWork
102
+ send_work wire
103
+ when Result
104
+ write_result message.body
105
+ send_work wire
106
+ when Operation
107
+ message.body.execute
108
+ when Metrics::Measurement
109
+ data.add message.body
110
+ else
111
+ raise UnexpectedMessageError, message.inspect
112
+ end
113
+
114
+ rescue Telegraph::NoMessageAvailable
115
+ retry
116
+ rescue Exception => e
117
+ raise unless @stop_process_messages
118
+ end
119
+ end
120
+ end
121
+
122
+ def wires_waiting_for_work
123
+ @wires_waiting_for_work ||= Set.new
124
+ end
125
+
126
+ def send_work(wire)
127
+ begin
128
+ wire.send_message take_work, :need_ack => true
129
+ wires_waiting_for_work.delete wire
130
+
131
+ rescue NoWorkUnitsAvailableError
132
+ put_abandonded_work_back_on_the_queue
133
+ wires_waiting_for_work.add wire
134
+
135
+ rescue NoWorkUnitsRemainingError
136
+ wire.send_message NoMoreWork
137
+ wires_waiting_for_work.delete wire
138
+
139
+ end
140
+ end
141
+
142
+ def put_abandonded_work_back_on_the_queue
143
+ closed_wires = switchboard.using_wires { |wires| wires.select {|w| w.closed? }}
144
+ closed_wires.each do |wire|
145
+ wire.unacked_messages.each do |m|
146
+ write_work m.body
147
+ switchboard.drop_wire wire
148
+ end
149
+ end
150
+ end
151
+
152
+ def stop
153
+ @stop_process_messages = true
154
+ operator.shutdown
155
+ @process_messages_thread.join
156
+ data.save @options.metrics_file if @options.gathering_metrics?
157
+ end
158
+
159
+ class NoWorkUnitsAvailableError < StandardError; end
160
+ class NoWorkUnitsRemainingError < StandardError; end
161
+ class NoAgentsRunningError < StandardError; end
162
+ class CheckIfAgentsAreStillRunning < StandardError; end
163
+ class UnexpectedMessageError < StandardError; end
164
+ end
165
+ end
@@ -0,0 +1,22 @@
1
+ module DeepTest
2
+ class CpuInfo
3
+ attr_accessor :platform
4
+
5
+ def initialize(platform = RUBY_PLATFORM)
6
+ @platform = platform
7
+ end
8
+
9
+ def count
10
+ case platform
11
+ when /darwin/
12
+ output = `sysctl -n hw.ncpu`
13
+ output.strip.to_i
14
+ when /linux/
15
+ File.readlines("/proc/cpuinfo").inject(0) do |count, line|
16
+ next count + 1 if line =~ /processor\s*:\s*\d+/
17
+ count
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -26,26 +26,25 @@ module DeepTest
26
26
  #
27
27
  def create_database
28
28
  admin_connection do |connection|
29
- connection.create_database worker_database
29
+ connection.create_database agent_database
30
30
  grant_privileges connection
31
31
  end
32
32
  end
33
33
 
34
34
  #
35
- # Grants 'all' privilege on worker database to username and password
36
- # specified by worker database config. If your application has
35
+ # Grants 'all' privilege on agent database to username and password
36
+ # specified by agent database config. If your application has
37
37
  # special database privilege needs beyond 'all', you should override
38
38
  # this method and grant them.
39
39
  #
40
40
  def grant_privileges(connection)
41
- puts "==== #{worker_database_config[:password].inspect}"
42
- identified_by = if worker_database_config[:password]
43
- %{identified by %s} % connection.quote(worker_database_config[:password])
41
+ identified_by = if agent_database_config[:password]
42
+ %{identified by %s} % connection.quote(agent_database_config[:password])
44
43
  else
45
44
  ""
46
45
  end
47
- sql = %{grant all on #{worker_database}.* to %s@'localhost' #{identified_by} ; } %
48
- connection.quote(worker_database_config[:username])
46
+ sql = %{grant all on #{agent_database}.* to %s@'localhost' #{identified_by} ; } %
47
+ connection.quote(agent_database_config[:username])
49
48
 
50
49
  connection.execute sql
51
50
  end
@@ -55,7 +54,7 @@ module DeepTest
55
54
  #
56
55
  def drop_database
57
56
  admin_connection do |connection|
58
- connection.drop_database worker_database
57
+ connection.drop_database agent_database
59
58
  end
60
59
  end
61
60
 
@@ -69,10 +68,10 @@ module DeepTest
69
68
  end
70
69
 
71
70
  #
72
- # Loads dumpfile into worker database using mysql command
71
+ # Loads dumpfile into agent database using mysql command
73
72
  #
74
73
  def load_schema
75
- config = command_line_config(worker_database_config)
74
+ config = command_line_config(agent_database_config)
76
75
  system "mysql #{config} < #{dump_file_name}"
77
76
  raise "Error Loading schema" unless $?.success?
78
77
  end
@@ -87,7 +86,7 @@ module DeepTest
87
86
  end
88
87
 
89
88
  def system(command) # :nodoc:
90
- DeepTest.logger.info command
89
+ DeepTest.logger.info { command }
91
90
  super command
92
91
  end
93
92
 
@@ -2,18 +2,18 @@ module DeepTest
2
2
  module Database
3
3
  #
4
4
  # Skeleton Listener to help with setting up a separate database
5
- # for each worker. Calls +dump_schema+, +load_schema+, +create_database+,
5
+ # for each agent. Calls +dump_schema+, +load_schema+, +create_database+,
6
6
  # and +drop_database+ hooks provided by subclasses that implement database
7
7
  # setup strategies for particular database flavors.
8
8
  #
9
- class SetupListener < NullWorkerListener
9
+ class SetupListener < NullListener
10
10
  DUMPED_SCHEMAS = [] unless defined?(DUMPED_SCHEMAS)
11
11
 
12
12
  def before_sync # :nodoc:
13
13
  dump_schema_once
14
14
  end
15
15
 
16
- def before_starting_workers # :nodoc:
16
+ def before_starting_agents # :nodoc:
17
17
  dump_schema_once
18
18
  end
19
19
 
@@ -23,11 +23,11 @@ module DeepTest
23
23
  DUMPED_SCHEMAS << schema_name
24
24
  end
25
25
 
26
- def starting(worker) # :nodoc:
27
- @worker = worker
26
+ def starting(agent) # :nodoc:
27
+ @agent = agent
28
28
 
29
29
  at_exit do
30
- DeepTest.logger.debug("dropping database #{worker_database}")
30
+ DeepTest.logger.debug { "dropping database #{agent_database}" }
31
31
  drop_database
32
32
  end
33
33
 
@@ -38,26 +38,26 @@ module DeepTest
38
38
  end
39
39
 
40
40
  #
41
- # Called on each worker after creating database and before loading
41
+ # Called on each agent after creating database and before loading
42
42
  # schema to initialize connections
43
43
  #
44
44
  def connect_to_database
45
- ActiveRecord::Base.establish_connection(worker_database_config)
45
+ ActiveRecord::Base.establish_connection(agent_database_config)
46
46
  end
47
47
 
48
48
  #
49
- # Called in each worker to create the database named by
50
- # +worker_database+.
49
+ # Called in each agent to create the database named by
50
+ # +agent_database+.
51
51
  #
52
52
  def create_database
53
53
  raise "Subclass must implement"
54
54
  end
55
55
 
56
56
  #
57
- # Called in each worker to drop the database created by
57
+ # Called in each agent to drop the database created by
58
58
  # +create_database+. This method is called twice, once before
59
59
  # +create_database+ to ensure that no database exists and once
60
- # at exit to clean as the worker process exits. This method
60
+ # at exit to clean as the agent process exits. This method
61
61
  # must not fail if the database does not exist when it is called.
62
62
  #
63
63
  def drop_database
@@ -65,12 +65,12 @@ module DeepTest
65
65
  end
66
66
 
67
67
  #
68
- # Called before any workers are spawned to dump the schema that
68
+ # Called before any agents are spawned to dump the schema that
69
69
  # will be used for testing. When running distributed, this method
70
70
  # is called on the local machine providing the tests to run.
71
71
  #
72
72
  # For distributed testing to work, the schema must be dumped in
73
- # location accessible by all worker machines. The easiest way to
73
+ # location accessible by all agent machines. The easiest way to
74
74
  # accomplish this is to dump it to a location within the working copy.
75
75
  #
76
76
  def dump_schema
@@ -79,21 +79,21 @@ module DeepTest
79
79
 
80
80
 
81
81
  #
82
- # Called once in each worker as it is starting to load the schema
82
+ # Called once in each agent as it is starting to load the schema
83
83
  # dumped from dump_schema. Subclasses should load the schema definition
84
- # into the +worker_database+
84
+ # into the +agent_database+
85
85
  #
86
86
  def load_schema
87
87
  raise "Subclass must implement"
88
88
  end
89
89
 
90
90
  #
91
- # ActiveRecord configuration for the worker database. By default,
91
+ # ActiveRecord configuration for the agent database. By default,
92
92
  # the same as +master_database_config+, except that points to
93
- # +worker_database+ instead of the database named in the master config.
93
+ # +agent_database+ instead of the database named in the master config.
94
94
  #
95
- def worker_database_config
96
- master_database_config.merge(:database => worker_database)
95
+ def agent_database_config
96
+ master_database_config.merge(:database => agent_database)
97
97
  end
98
98
 
99
99
  #
@@ -106,10 +106,10 @@ module DeepTest
106
106
  end
107
107
 
108
108
  #
109
- # Unique name for database on machine that worker is running on.
109
+ # Unique name for database on machine that agent is running on.
110
110
  #
111
- def worker_database
112
- "deep_test_worker_#{@worker.number}_pid_#{Process.pid}"
111
+ def agent_database
112
+ "deep_test_agent_#{@agent.number}_pid_#{Process.pid}"
113
113
  end
114
114
  end
115
115
  end
@@ -0,0 +1,25 @@
1
+ module DeepTest
2
+ module Demon
3
+ def forked(name, options, demon_args)
4
+ options.connect_to_central_command do |wire|
5
+ ProxyIO.replace_stdout_stderr!(wire) do
6
+ begin
7
+ catch(:exit_demon) do
8
+ Signal.trap("TERM") { throw :exit_demon }
9
+ execute *demon_args
10
+ end
11
+ rescue SystemExit => e
12
+ raise
13
+ rescue Exception => e
14
+ FailureMessage.show self.class.name, "Process #{Process.pid} exiting with excetion: #{e.class}: #{e.message}"
15
+ raise
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ def execute(*args)
22
+ raise "#{self.class} must implement the execute method to be a Demon"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,104 @@
1
+ module DeepTest
2
+ module Distributed
3
+ class Beachhead < LocalDeployment
4
+ include Demon
5
+
6
+ MERCY_KILLING_GRACE_PERIOD = 10 * 60 unless defined?(MERCY_KILLING_GRACE_PERIOD)
7
+
8
+ def initialize(base_path, options)
9
+ super options
10
+ @base_path = base_path
11
+ end
12
+
13
+ def launch_mercy_killer(grace_period)
14
+ Thread.new do
15
+ sleep grace_period
16
+ exit(0) unless agents_deployed?
17
+ end
18
+ end
19
+
20
+ def load_files(files)
21
+ spec_support_path = File.expand_path(File.dirname(__FILE__) + "/../spec")
22
+ Dir.chdir @base_path
23
+ resolver = FilenameResolver.new(@base_path)
24
+ files.each do |file|
25
+ load resolver.resolve(file)
26
+ end
27
+
28
+ # Load rspec support if rspec is available now that we've loaded the host project files
29
+ #
30
+ DeepTest::RSpecDetector.if_rspec_available do
31
+ require spec_support_path
32
+ end
33
+ end
34
+
35
+ def deploy_agents
36
+ @agents_deployed = true
37
+ super
38
+ warlock.exit_when_none_running
39
+ end
40
+
41
+ def agents_deployed?
42
+ @agents_deployed
43
+ end
44
+
45
+ def forked(*args)
46
+ $stdout.reopen("/dev/null")
47
+ $stderr.reopen("/dev/null")
48
+ super
49
+ end
50
+
51
+ def execute(innie, outie, grace_period)
52
+ innie.close
53
+
54
+ switchboard = Telegraph::Switchboard.new
55
+ operator = Telegraph::Operator.listen "0.0.0.0", 0, switchboard
56
+
57
+ DeepTest.logger.debug { "Beachhead started on port #{operator.port}" }
58
+
59
+ outie.write operator.port
60
+ outie.close
61
+
62
+ launch_mercy_killer grace_period
63
+
64
+ loop do
65
+ begin
66
+ switchboard.process_messages :timeout => 1 do |message, wire|
67
+ case message.body
68
+ when LoadFiles
69
+ load_files message.body.files
70
+ when DeployAgents
71
+ deploy_agents
72
+ wire.send_message Done
73
+ operator.shutdown
74
+ break
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ def daemonize(grace_period = MERCY_KILLING_GRACE_PERIOD)
82
+ innie, outie = IO.pipe
83
+
84
+ warlock.start "Beachhead", self, innie, outie, grace_period
85
+
86
+ outie.close
87
+ port = innie.gets
88
+ innie.close
89
+ port.to_i
90
+ end
91
+
92
+ unless defined? DeployAgents
93
+ DeployAgents = "DeployAgents"
94
+ Done = "Done"
95
+ class LoadFiles
96
+ attr_reader :files
97
+ def initialize(files)
98
+ @files = files
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end