blob: e18f696ef35c125a67e72965bc19a26620609545 [file] [log] [blame]
showarde39ebe92009-06-18 23:14:48 +00001#!/usr/bin/python
2
Prashanth B340fd1e2014-06-22 12:44:10 -07003import cPickle
showard42d44982009-10-12 20:34:03 +00004import os, unittest
showarde39ebe92009-06-18 23:14:48 +00005import common
Prashanth B340fd1e2014-06-22 12:44:10 -07006from autotest_lib.client.bin import local_host
showardac5b0002009-10-19 18:34:00 +00007from autotest_lib.client.common_lib import global_config
Prashanth B340fd1e2014-06-22 12:44:10 -07008from autotest_lib.client.common_lib import utils
showard42d44982009-10-12 20:34:03 +00009from autotest_lib.client.common_lib.test_utils import mock
Dan Shib9144a42014-12-01 16:09:32 -080010from autotest_lib.frontend import setup_django_lite_environment
showard2aafd902009-10-14 16:20:14 +000011from autotest_lib.scheduler import drone_manager, drone_utility, drones
Simran Basi882f15b2013-10-29 14:59:34 -070012from autotest_lib.scheduler import scheduler_config, site_drone_manager
Prashanth B340fd1e2014-06-22 12:44:10 -070013from autotest_lib.scheduler import thread_lib
14from autotest_lib.scheduler import pidfile_monitor
15from autotest_lib.server.hosts import ssh_host
16
showarde39ebe92009-06-18 23:14:48 +000017
18class MockDrone(drones._AbstractDrone):
showard9bb960b2009-11-19 01:02:11 +000019 def __init__(self, name, active_processes=0, max_processes=10,
Dan Shiec1d47d2015-02-13 11:38:13 -080020 allowed_users=None, support_ssp=False):
showarde39ebe92009-06-18 23:14:48 +000021 super(MockDrone, self).__init__()
22 self.name = name
jamesren76fcf192010-04-21 20:39:50 +000023 self.hostname = name
showarde39ebe92009-06-18 23:14:48 +000024 self.active_processes = active_processes
25 self.max_processes = max_processes
showard9bb960b2009-11-19 01:02:11 +000026 self.allowed_users = allowed_users
Dan Shiec1d47d2015-02-13 11:38:13 -080027 self._host = 'mock_drone'
28 self._support_ssp = support_ssp
showard42d44982009-10-12 20:34:03 +000029 # maps method names list of tuples containing method arguments
30 self._recorded_calls = {'queue_call': [],
31 'send_file_to': []}
32
33
34 def queue_call(self, method, *args, **kwargs):
35 self._recorded_calls['queue_call'].append((method, args, kwargs))
36
37
showard2aafd902009-10-14 16:20:14 +000038 def call(self, method, *args, **kwargs):
39 # don't bother differentiating between call() and queue_call()
40 return self.queue_call(method, *args, **kwargs)
41
42
showard42d44982009-10-12 20:34:03 +000043 def send_file_to(self, drone, source_path, destination_path,
44 can_fail=False):
45 self._recorded_calls['send_file_to'].append(
46 (drone, source_path, destination_path))
47
48
49 # method for use by tests
50 def _check_for_recorded_call(self, method_name, arguments):
51 recorded_arg_list = self._recorded_calls[method_name]
52 was_called = arguments in recorded_arg_list
53 if not was_called:
54 print 'Recorded args:', recorded_arg_list
55 print 'Expected:', arguments
56 return was_called
57
58
59 def was_call_queued(self, method, *args, **kwargs):
60 return self._check_for_recorded_call('queue_call',
61 (method, args, kwargs))
62
63
64 def was_file_sent(self, drone, source_path, destination_path):
65 return self._check_for_recorded_call('send_file_to',
66 (drone, source_path,
67 destination_path))
showarde39ebe92009-06-18 23:14:48 +000068
69
70class DroneManager(unittest.TestCase):
showard42d44982009-10-12 20:34:03 +000071 _DRONE_INSTALL_DIR = '/drone/install/dir'
showardc75fded2009-10-14 16:20:02 +000072 _DRONE_RESULTS_DIR = os.path.join(_DRONE_INSTALL_DIR, 'results')
showard42d44982009-10-12 20:34:03 +000073 _RESULTS_DIR = '/results/dir'
74 _SOURCE_PATH = 'source/path'
75 _DESTINATION_PATH = 'destination/path'
showard2aafd902009-10-14 16:20:14 +000076 _WORKING_DIRECTORY = 'working/directory'
showard9bb960b2009-11-19 01:02:11 +000077 _USERNAME = 'my_user'
showard42d44982009-10-12 20:34:03 +000078
showarde39ebe92009-06-18 23:14:48 +000079 def setUp(self):
showard42d44982009-10-12 20:34:03 +000080 self.god = mock.mock_god()
81 self.god.stub_with(drones, 'AUTOTEST_INSTALL_DIR',
82 self._DRONE_INSTALL_DIR)
showarde39ebe92009-06-18 23:14:48 +000083 self.manager = drone_manager.DroneManager()
showard42d44982009-10-12 20:34:03 +000084 self.god.stub_with(self.manager, '_results_dir', self._RESULTS_DIR)
85
showard2aafd902009-10-14 16:20:14 +000086 # we don't want this to ever actually get called
87 self.god.stub_function(drones, 'get_drone')
showardac5b0002009-10-19 18:34:00 +000088 # we don't want the DroneManager to go messing with global config
89 def do_nothing():
90 pass
91 self.god.stub_with(self.manager, 'refresh_drone_configs', do_nothing)
showard2aafd902009-10-14 16:20:14 +000092
showard42d44982009-10-12 20:34:03 +000093 # set up some dummy drones
showard202343e2009-10-14 16:20:24 +000094 self.mock_drone = MockDrone('mock_drone')
showard42d44982009-10-12 20:34:03 +000095 self.manager._drones[self.mock_drone.name] = self.mock_drone
96 self.results_drone = MockDrone('results_drone', 0, 10)
97 self.manager._results_drone = self.results_drone
98
99 self.mock_drone_process = drone_manager.Process(self.mock_drone.name, 0)
100
101
102 def tearDown(self):
103 self.god.unstub_all()
showarde39ebe92009-06-18 23:14:48 +0000104
105
106 def _test_choose_drone_for_execution_helper(self, processes_info_list,
Dan Shiec1d47d2015-02-13 11:38:13 -0800107 requested_processes,
108 require_ssp=False):
showarde39ebe92009-06-18 23:14:48 +0000109 for index, process_info in enumerate(processes_info_list):
Dan Shiec1d47d2015-02-13 11:38:13 -0800110 if len(process_info) == 2:
111 active_processes, max_processes = process_info
112 support_ssp = False
113 else:
114 active_processes, max_processes, support_ssp = process_info
115 self.manager._enqueue_drone(MockDrone(
116 index, active_processes, max_processes, allowed_users=None,
117 support_ssp=support_ssp))
showarde39ebe92009-06-18 23:14:48 +0000118
Dan Shiec1d47d2015-02-13 11:38:13 -0800119 return self.manager._choose_drone_for_execution(
120 requested_processes, self._USERNAME, None, require_ssp)
showarde39ebe92009-06-18 23:14:48 +0000121
122
123 def test_choose_drone_for_execution(self):
124 drone = self._test_choose_drone_for_execution_helper([(1, 2), (0, 2)],
125 1)
126 self.assertEquals(drone.name, 1)
127
128
129 def test_choose_drone_for_execution_some_full(self):
130 drone = self._test_choose_drone_for_execution_helper([(0, 1), (1, 3)],
131 2)
132 self.assertEquals(drone.name, 1)
133
134
135 def test_choose_drone_for_execution_all_full(self):
136 drone = self._test_choose_drone_for_execution_helper([(2, 1), (3, 2)],
137 1)
138 self.assertEquals(drone.name, 1)
139
140
jamesren37b50452010-03-25 20:38:56 +0000141 def test_choose_drone_for_execution_all_full_same_percentage_capacity(self):
142 drone = self._test_choose_drone_for_execution_helper([(5, 3), (10, 6)],
143 1)
144 self.assertEquals(drone.name, 1)
145
146
Dan Shiec1d47d2015-02-13 11:38:13 -0800147 def test_choose_drone_for_execution_no_ssp_support(self):
148 drone = self._test_choose_drone_for_execution_helper(
149 [(0, 1), (1, 3)], 1, True)
150 self.assertEquals(drone.name, 0)
151
152
153 def test_choose_drone_for_execution_with_ssp_support(self):
154 self.mock_drone._support_ssp = True
155 drone = self._test_choose_drone_for_execution_helper(
156 [(0, 1), (1, 3, True)], 1, True)
157 self.assertEquals(drone.name, 1)
158
159
showard9bb960b2009-11-19 01:02:11 +0000160 def test_user_restrictions(self):
161 # this drone is restricted to a different user
162 self.manager._enqueue_drone(MockDrone(1, max_processes=10,
163 allowed_users=['fakeuser']))
164 # this drone is allowed but has lower capacity
165 self.manager._enqueue_drone(MockDrone(2, max_processes=2,
166 allowed_users=[self._USERNAME]))
167
168 self.assertEquals(2,
jamesren76fcf192010-04-21 20:39:50 +0000169 self.manager.max_runnable_processes(self._USERNAME,
170 None))
showard9bb960b2009-11-19 01:02:11 +0000171 drone = self.manager._choose_drone_for_execution(
jamesren76fcf192010-04-21 20:39:50 +0000172 1, username=self._USERNAME, drone_hostnames_allowed=None)
showard9bb960b2009-11-19 01:02:11 +0000173 self.assertEquals(drone.name, 2)
174
175
jamesren37b50452010-03-25 20:38:56 +0000176 def test_user_restrictions_with_full_drone(self):
177 # this drone is restricted to a different user
178 self.manager._enqueue_drone(MockDrone(1, max_processes=10,
179 allowed_users=['fakeuser']))
180 # this drone is allowed but is full
181 self.manager._enqueue_drone(MockDrone(2, active_processes=3,
182 max_processes=2,
183 allowed_users=[self._USERNAME]))
184
185 self.assertEquals(0,
jamesren76fcf192010-04-21 20:39:50 +0000186 self.manager.max_runnable_processes(self._USERNAME,
187 None))
jamesren37b50452010-03-25 20:38:56 +0000188 drone = self.manager._choose_drone_for_execution(
jamesren76fcf192010-04-21 20:39:50 +0000189 1, username=self._USERNAME, drone_hostnames_allowed=None)
jamesren37b50452010-03-25 20:38:56 +0000190 self.assertEquals(drone.name, 2)
191
192
jamesren76fcf192010-04-21 20:39:50 +0000193 def _setup_test_drone_restrictions(self, active_processes=0):
194 self.manager._enqueue_drone(MockDrone(
195 1, active_processes=active_processes, max_processes=10))
196 self.manager._enqueue_drone(MockDrone(
197 2, active_processes=active_processes, max_processes=5))
198 self.manager._enqueue_drone(MockDrone(
199 3, active_processes=active_processes, max_processes=2))
200
201
202 def test_drone_restrictions_allow_any(self):
203 self._setup_test_drone_restrictions()
204 self.assertEquals(10,
205 self.manager.max_runnable_processes(self._USERNAME,
206 None))
207 drone = self.manager._choose_drone_for_execution(
208 1, username=self._USERNAME, drone_hostnames_allowed=None)
209 self.assertEqual(drone.name, 1)
210
211
212 def test_drone_restrictions_under_capacity(self):
213 self._setup_test_drone_restrictions()
214 drone_hostnames_allowed = (2, 3)
215 self.assertEquals(
216 5, self.manager.max_runnable_processes(self._USERNAME,
217 drone_hostnames_allowed))
218 drone = self.manager._choose_drone_for_execution(
219 1, username=self._USERNAME,
220 drone_hostnames_allowed=drone_hostnames_allowed)
221
222 self.assertEqual(drone.name, 2)
223
224
225 def test_drone_restrictions_over_capacity(self):
226 self._setup_test_drone_restrictions(active_processes=6)
227 drone_hostnames_allowed = (2, 3)
228 self.assertEquals(
229 0, self.manager.max_runnable_processes(self._USERNAME,
230 drone_hostnames_allowed))
231 drone = self.manager._choose_drone_for_execution(
232 7, username=self._USERNAME,
233 drone_hostnames_allowed=drone_hostnames_allowed)
234 self.assertEqual(drone.name, 2)
235
236
237 def test_drone_restrictions_allow_none(self):
238 self._setup_test_drone_restrictions()
239 drone_hostnames_allowed = ()
240 self.assertEquals(
241 0, self.manager.max_runnable_processes(self._USERNAME,
242 drone_hostnames_allowed))
243 drone = self.manager._choose_drone_for_execution(
244 1, username=self._USERNAME,
245 drone_hostnames_allowed=drone_hostnames_allowed)
246 self.assertEqual(drone, None)
247
248
showard2aafd902009-10-14 16:20:14 +0000249 def test_initialize(self):
showard2aafd902009-10-14 16:20:14 +0000250 results_hostname = 'results_repo'
showardac5b0002009-10-19 18:34:00 +0000251 results_install_dir = '/results/install'
252 global_config.global_config.override_config_value(
253 scheduler_config.CONFIG_SECTION,
254 'results_host_installation_directory', results_install_dir)
showard2aafd902009-10-14 16:20:14 +0000255
showard2aafd902009-10-14 16:20:14 +0000256 (drones.get_drone.expect_call(self.mock_drone.name)
257 .and_return(self.mock_drone))
showard202343e2009-10-14 16:20:24 +0000258
259 results_drone = MockDrone('results_drone')
260 self.god.stub_function(results_drone, 'set_autotest_install_dir')
261 drones.get_drone.expect_call(results_hostname).and_return(results_drone)
showardac5b0002009-10-19 18:34:00 +0000262 results_drone.set_autotest_install_dir.expect_call(results_install_dir)
showard2aafd902009-10-14 16:20:14 +0000263
264 self.manager.initialize(base_results_dir=self._RESULTS_DIR,
265 drone_hostnames=[self.mock_drone.name],
266 results_repository_hostname=results_hostname)
267
268 self.assert_(self.mock_drone.was_call_queued(
269 'initialize', self._DRONE_RESULTS_DIR + '/'))
showardac5b0002009-10-19 18:34:00 +0000270 self.god.check_playback()
showard2aafd902009-10-14 16:20:14 +0000271
272
showard42d44982009-10-12 20:34:03 +0000273 def test_execute_command(self):
274 self.manager._enqueue_drone(self.mock_drone)
275
showard42d44982009-10-12 20:34:03 +0000276 pidfile_name = 'my_pidfile'
277 log_file = 'log_file'
278
279 pidfile_id = self.manager.execute_command(
280 command=['test', drone_manager.WORKING_DIRECTORY],
showard2aafd902009-10-14 16:20:14 +0000281 working_directory=self._WORKING_DIRECTORY,
showard42d44982009-10-12 20:34:03 +0000282 pidfile_name=pidfile_name,
showard418785b2009-11-23 20:19:59 +0000283 num_processes=1,
showard42d44982009-10-12 20:34:03 +0000284 log_file=log_file)
285
showardc75fded2009-10-14 16:20:02 +0000286 full_working_directory = os.path.join(self._DRONE_RESULTS_DIR,
showard2aafd902009-10-14 16:20:14 +0000287 self._WORKING_DIRECTORY)
showard42d44982009-10-12 20:34:03 +0000288 self.assertEquals(pidfile_id.path,
289 os.path.join(full_working_directory, pidfile_name))
290 self.assert_(self.mock_drone.was_call_queued(
291 'execute_command', ['test', full_working_directory],
292 full_working_directory,
showardc75fded2009-10-14 16:20:02 +0000293 os.path.join(self._DRONE_RESULTS_DIR, log_file), pidfile_name))
showard42d44982009-10-12 20:34:03 +0000294
295
showard2aafd902009-10-14 16:20:14 +0000296 def test_attach_file_to_execution(self):
297 self.manager._enqueue_drone(self.mock_drone)
298
299 contents = 'my\ncontents'
300 attached_path = self.manager.attach_file_to_execution(
301 self._WORKING_DIRECTORY, contents)
302 self.manager.execute_command(command=['test'],
303 working_directory=self._WORKING_DIRECTORY,
showard418785b2009-11-23 20:19:59 +0000304 pidfile_name='mypidfile',
jamesren76fcf192010-04-21 20:39:50 +0000305 num_processes=1,
306 drone_hostnames_allowed=None)
showard2aafd902009-10-14 16:20:14 +0000307
308 self.assert_(self.mock_drone.was_call_queued(
309 'write_to_file',
310 os.path.join(self._DRONE_RESULTS_DIR, attached_path),
311 contents))
312
313
showard42d44982009-10-12 20:34:03 +0000314 def test_copy_results_on_drone(self):
315 self.manager.copy_results_on_drone(self.mock_drone_process,
316 self._SOURCE_PATH,
317 self._DESTINATION_PATH)
318 self.assert_(self.mock_drone.was_call_queued(
319 'copy_file_or_directory',
showardc75fded2009-10-14 16:20:02 +0000320 os.path.join(self._DRONE_RESULTS_DIR, self._SOURCE_PATH),
321 os.path.join(self._DRONE_RESULTS_DIR, self._DESTINATION_PATH)))
showard42d44982009-10-12 20:34:03 +0000322
323
324 def test_copy_to_results_repository(self):
Simran Basi882f15b2013-10-29 14:59:34 -0700325 site_drone_manager.ENABLE_ARCHIVING = True
showard42d44982009-10-12 20:34:03 +0000326 self.manager.copy_to_results_repository(self.mock_drone_process,
327 self._SOURCE_PATH)
328 self.assert_(self.mock_drone.was_file_sent(
329 self.results_drone,
showardc75fded2009-10-14 16:20:02 +0000330 os.path.join(self._DRONE_RESULTS_DIR, self._SOURCE_PATH),
showard42d44982009-10-12 20:34:03 +0000331 os.path.join(self._RESULTS_DIR, self._SOURCE_PATH)))
332
333
334 def test_write_lines_to_file(self):
335 file_path = 'file/path'
336 lines = ['line1', 'line2']
337 written_data = 'line1\nline2\n'
338
339 # write to results repository
340 self.manager.write_lines_to_file(file_path, lines)
341 self.assert_(self.results_drone.was_call_queued(
342 'write_to_file', os.path.join(self._RESULTS_DIR, file_path),
343 written_data))
344
345 # write to a drone
346 self.manager.write_lines_to_file(
347 file_path, lines, paired_with_process=self.mock_drone_process)
348 self.assert_(self.mock_drone.was_call_queued(
349 'write_to_file',
showardc75fded2009-10-14 16:20:02 +0000350 os.path.join(self._DRONE_RESULTS_DIR, file_path), written_data))
showard42d44982009-10-12 20:34:03 +0000351
352
showardd3496242009-12-10 21:41:43 +0000353 def test_pidfile_expiration(self):
354 self.god.stub_with(self.manager, '_get_max_pidfile_refreshes',
355 lambda: 0)
356 pidfile_id = self.manager.get_pidfile_id_from('tag', 'name')
357 self.manager.register_pidfile(pidfile_id)
358 self.manager._drop_old_pidfiles()
359 self.manager._drop_old_pidfiles()
360 self.assertFalse(self.manager._registered_pidfile_info)
361
362
Prashanth B340fd1e2014-06-22 12:44:10 -0700363class ThreadedDroneTest(unittest.TestCase):
364 _DRONE_INSTALL_DIR = '/drone/install/dir'
365 _RESULTS_DIR = '/results/dir'
366 _DRONE_CLASS = drones._RemoteDrone
367 _DRONE_HOST = ssh_host.SSHHost
368
369
Prashanth Bcf731e32014-08-10 18:03:57 -0700370 def create_drone(self, drone_hostname, mock_hostname,
371 timestamp_remote_calls=False):
Prashanth B340fd1e2014-06-22 12:44:10 -0700372 """Create and initialize a Remote Drone.
373
374 @return: A remote drone instance.
375 """
376 mock_host = self.god.create_mock_class(self._DRONE_HOST, mock_hostname)
377 self.god.stub_function(drones.drone_utility, 'create_host')
378 drones.drone_utility.create_host.expect_call(drone_hostname).and_return(
379 mock_host)
380 mock_host.is_up.expect_call().and_return(True)
Prashanth Bcf731e32014-08-10 18:03:57 -0700381 return self._DRONE_CLASS(drone_hostname,
382 timestamp_remote_calls=timestamp_remote_calls)
Prashanth B340fd1e2014-06-22 12:44:10 -0700383
384
385 def create_fake_pidfile_info(self, tag='tag', name='name'):
386 pidfile_id = self.manager.get_pidfile_id_from(tag, name)
387 self.manager.register_pidfile(pidfile_id)
388 return self.manager._registered_pidfile_info
389
390
391 def setUp(self):
392 self.god = mock.mock_god()
393 self.god.stub_with(drones, 'AUTOTEST_INSTALL_DIR',
394 self._DRONE_INSTALL_DIR)
395 self.manager = drone_manager.DroneManager()
396 self.god.stub_with(self.manager, '_results_dir', self._RESULTS_DIR)
397
398 # we don't want this to ever actually get called
399 self.god.stub_function(drones, 'get_drone')
400 # we don't want the DroneManager to go messing with global config
401 def do_nothing():
402 pass
403 self.god.stub_with(self.manager, 'refresh_drone_configs', do_nothing)
404
405 self.results_drone = MockDrone('results_drone', 0, 10)
406 self.manager._results_drone = self.results_drone
407 self.drone_utility_path = 'mock-drone-utility-path'
408 self.mock_return = {'results': ['mock results'],
409 'warnings': []}
410
411
412 def tearDown(self):
413 self.god.unstub_all()
414
415 def test_trigger_refresh(self):
416 """Test drone manager trigger refresh."""
417 self.god.stub_with(self._DRONE_CLASS, '_drone_utility_path',
418 self.drone_utility_path)
419 mock_drone = self.create_drone('fakedrone1', 'fakehost1')
420 self.manager._drones[mock_drone.hostname] = mock_drone
421
422 # Create some fake pidfiles and confirm that a refresh call is
423 # executed on each drone host, with the same pidfile paths. Then
424 # check that each drone gets a key in the returned results dictionary.
425 for i in range(0, 1):
426 pidfile_info = self.create_fake_pidfile_info(
427 'tag%s' % i, 'name%s' %i)
428 pidfile_paths = [pidfile.path for pidfile in pidfile_info.keys()]
429 refresh_call = drone_utility.call('refresh', pidfile_paths)
430 expected_results = {}
431 mock_result = utils.CmdResult(
432 stdout=cPickle.dumps(self.mock_return))
433 for drone in self.manager.get_drones():
434 drone._host.run.expect_call(
435 'python %s' % self.drone_utility_path,
436 stdin=cPickle.dumps([refresh_call]), stdout_tee=None,
437 connect_timeout=mock.is_instance_comparator(int)
438 ).and_return(mock_result)
439 expected_results[drone] = self.mock_return['results']
440 self.manager.trigger_refresh()
441 self.assertTrue(self.manager._refresh_task_queue.get_results() ==
442 expected_results)
443 self.god.check_playback()
444
445
446 def test_sync_refresh(self):
447 """Test drone manager sync refresh."""
448
449 mock_drone = self.create_drone('fakedrone1', 'fakehost1')
450 self.manager._drones[mock_drone.hostname] = mock_drone
451
452 # Insert some drone_utility results into the results queue, then
453 # check that get_results returns it in the right format, and that
454 # the rest of sync_refresh populates the right datastructures for
455 # correct handling of agents. Also confirm that this method of
456 # syncing is sufficient for the monitor to pick up the exit status
457 # of the process in the same way it would in handle_agents.
458 pidfile_path = 'results/hosts/host_id/job_id-name/.autoserv_execute'
459 pidfiles = {pidfile_path: '123\n12\n0\n'}
460 drone_utility_results = {
461 'pidfiles': pidfiles,
462 'autoserv_processes':{},
463 'all_processes':{},
464 'parse_processes':{},
465 'pidfiles_second_read':pidfiles,
466 }
467 # Our manager instance isn't the drone manager singletone that the
468 # pidfile_monitor will use by default, becuase setUp doesn't call
469 # drone_manager.instance().
Jakob Jülich36accc62014-07-23 10:26:55 -0700470 self.god.stub_with(drone_manager, '_the_instance', self.manager)
Prashanth B340fd1e2014-06-22 12:44:10 -0700471 monitor = pidfile_monitor.PidfileRunMonitor()
472 monitor.pidfile_id = drone_manager.PidfileId(pidfile_path)
473 self.manager.register_pidfile(monitor.pidfile_id)
474 self.assertTrue(monitor._state.exit_status == None)
475
476 self.manager._refresh_task_queue.results_queue.put(
477 thread_lib.ThreadedTaskQueue.result(
478 mock_drone, [drone_utility_results]))
479 self.manager.sync_refresh()
480 pidfiles = self.manager._pidfiles
481 pidfile_id = pidfiles.keys()[0]
482 pidfile_contents = pidfiles[pidfile_id]
483
484 self.assertTrue(
485 pidfile_id.path == pidfile_path and
486 pidfile_contents.process.pid == 123 and
487 pidfile_contents.process.hostname ==
488 mock_drone.hostname and
489 pidfile_contents.exit_status == 12 and
490 pidfile_contents.num_tests_failed == 0)
491 self.assertTrue(monitor.exit_code() == 12)
492 self.god.check_playback()
493
494
495class ThreadedLocalhostDroneTest(ThreadedDroneTest):
496 _DRONE_CLASS = drones._LocalDrone
497 _DRONE_HOST = local_host.LocalHost
498
499
Prashanth Bcf731e32014-08-10 18:03:57 -0700500 def create_drone(self, drone_hostname, mock_hostname,
501 timestamp_remote_calls=False):
Prashanth B340fd1e2014-06-22 12:44:10 -0700502 """Create and initialize a Remote Drone.
503
504 @return: A remote drone instance.
505 """
506 mock_host = self.god.create_mock_class(self._DRONE_HOST, mock_hostname)
507 self.god.stub_function(drones.drone_utility, 'create_host')
Prashanth Bcf731e32014-08-10 18:03:57 -0700508 local_drone = self._DRONE_CLASS(
509 timestamp_remote_calls=timestamp_remote_calls)
Prashanth B340fd1e2014-06-22 12:44:10 -0700510 self.god.stub_with(local_drone, '_host', mock_host)
511 return local_drone
512
513
showarde39ebe92009-06-18 23:14:48 +0000514if __name__ == '__main__':
515 unittest.main()