def test_http_lifecycle_wrapper_without_lifecycle(): mti_without_lifecycle = MesosTaskInstance() mti_without_http_lifecycle = MesosTaskInstance(lifecycle=LifecycleConfig()) runner_mock = mock.create_autospec(ThermosTaskRunner) assert HttpLifecycleManager.wrap(runner_mock, mti_without_lifecycle, {}) is runner_mock assert HttpLifecycleManager.wrap(runner_mock, mti_without_http_lifecycle, {}) is runner_mock
def make_mocks(mesos_task_instance, portmap): # wrap it once health is available and validate the constructor is called as expected runner_mock = mock.create_autospec(ThermosTaskRunner) with mock.patch.object(HttpLifecycleManager, '__init__', return_value=None) as wrapper_init: runner_wrapper = HttpLifecycleManager.wrap(runner_mock, mesos_task_instance, portmap) yield runner_mock, runner_wrapper, wrapper_init
def test_integration_http_teardown_escalate(self, SignalerClass): """Ensure that the http teardown process fully escalates when quit/abort both fail to kill.""" signaler = SignalerClass.return_value signaler.side_effect = lambda path, use_post_method: (True, None) clock = Mock(wraps=time) class KillCalledTaskRunner(ThermosTaskRunner): def __init__(self, *args, **kwargs): self._killed_called = False ThermosTaskRunner.__init__(self, *args, **kwargs) def kill_called(self): return self._killed_called def kill(self): self._killed_called = True @property def status(self): return None with self.yield_sleepy( KillCalledTaskRunner, portmap={'health': 3141}, clock=clock, sleep=0, exit_code=0) as task_runner: graceful_shutdown_wait = Amount(1, Time.SECONDS) shutdown_wait = Amount(5, Time.SECONDS) http_task_runner = HttpLifecycleManager( task_runner, 3141, [('/quitquitquit', graceful_shutdown_wait), ('/abortabortabort', shutdown_wait)], clock=clock) http_task_runner.start() task_runner.forked.wait() http_task_runner.stop() http_teardown_poll_wait_call = call(HttpLifecycleManager.WAIT_POLL_INTERVAL.as_(Time.SECONDS)) assert clock.sleep.mock_calls.count(http_teardown_poll_wait_call) == 6 assert signaler.mock_calls == [ call('/quitquitquit', use_post_method=True), call('/abortabortabort', use_post_method=True)] assert task_runner.kill_called() == True
def test_integration_http_teardown_killed(self, SignalerClass): """Ensure that the http teardown procedure closes correctly when abort kills the process.""" signaler = SignalerClass.return_value signaler.side_effect = lambda path, use_post_method: (path == '/abortabortabort', None) clock = Mock(wraps=time) class TerminalStateStatusRunner(ThermosTaskRunner): """ Status is called each poll in the teardown procedure. We return kill after the 3rd poll to mimic a task that exits early. We want to ensure the shutdown procedure doesn't wait the full time if it doesn't need to. """ TIMES_CALLED = 0 @property def status(self): if (self.TIMES_CALLED >= 3): return StatusResult('Test task mock status', mesos_pb2.TASK_KILLED) self.TIMES_CALLED += 1 with self.yield_sleepy( TerminalStateStatusRunner, portmap={'health': 3141}, clock=clock, sleep=0, exit_code=0) as task_runner: graceful_shutdown_wait = Amount(1, Time.SECONDS) shutdown_wait = Amount(5, Time.SECONDS) http_task_runner = HttpLifecycleManager( task_runner, 3141, [('/quitquitquit', graceful_shutdown_wait), ('/abortabortabort', shutdown_wait)], clock=clock) http_task_runner.start() task_runner.forked.wait() http_task_runner.stop() http_teardown_poll_wait_call = call(HttpLifecycleManager.WAIT_POLL_INTERVAL.as_(Time.SECONDS)) assert clock.sleep.mock_calls.count(http_teardown_poll_wait_call) == 3 # Killed before 5 assert signaler.mock_calls == [ call('/quitquitquit', use_post_method=True), call('/abortabortabort', use_post_method=True)]
def test_http_lifecycle_wraps_start_and_stop(): mti = MesosTaskInstance(lifecycle=LifecycleConfig(http=HttpLifecycleConfig())) runner_mock = mock.create_autospec(ThermosTaskRunner) with mock.patch.object(HttpLifecycleManager, '_terminate_http', return_value=None) as http_mock: runner_wrapper = HttpLifecycleManager.wrap(runner_mock, mti, {'health': 31337}) # ensure that start and stop are properly wrapped runner_wrapper.start(23.3) assert runner_mock.start.mock_calls == [mock.call(timeout=23.3)] # ensure that http teardown called when stopped runner_wrapper.stop(32.2) assert http_mock.mock_calls == [mock.call()] assert runner_mock.stop.mock_calls == [mock.call(timeout=32.2)]
def test_integration_http_teardown_killed(self, SignalerClass): """Ensure that the http teardown procedure closes correctly when abort kills the process.""" signaler = SignalerClass.return_value signaler.side_effect = lambda path, use_post_method: ( path == '/abortabortabort', None) clock = Mock(wraps=time) class TerminalStateStatusRunner(ThermosTaskRunner): """ Status is called each poll in the teardown procedure. We return kill after the 3rd poll to mimic a task that exits early. We want to ensure the shutdown procedure doesn't wait the full time if it doesn't need to. """ TIMES_CALLED = 0 @property def status(self): if (self.TIMES_CALLED >= 3): return StatusResult('Test task mock status', mesos_pb2.TASK_KILLED) self.TIMES_CALLED += 1 with self.yield_sleepy(TerminalStateStatusRunner, portmap={'health': 3141}, clock=clock, sleep=0, exit_code=0) as task_runner: graceful_shutdown_wait = Amount(1, Time.SECONDS) shutdown_wait = Amount(5, Time.SECONDS) http_task_runner = HttpLifecycleManager( task_runner, 3141, [('/quitquitquit', graceful_shutdown_wait), ('/abortabortabort', shutdown_wait)], clock=clock) http_task_runner.start() task_runner.forked.wait() http_task_runner.stop() http_teardown_poll_wait_call = call( HttpLifecycleManager.WAIT_POLL_INTERVAL.as_(Time.SECONDS)) assert clock.sleep.mock_calls.count( http_teardown_poll_wait_call) == 3 # Killed before 5 assert signaler.mock_calls == [ call('/quitquitquit', use_post_method=True), call('/abortabortabort', use_post_method=True) ]
def test_integration_http_teardown_escalate(self, SignalerClass): """Ensure that the http teardown process fully escalates when quit/abort both fail to kill.""" signaler = SignalerClass.return_value signaler.side_effect = lambda path, use_post_method: (True, None) clock = Mock(wraps=time) class KillCalledTaskRunner(ThermosTaskRunner): def __init__(self, *args, **kwargs): self._killed_called = False ThermosTaskRunner.__init__(self, *args, **kwargs) def kill_called(self): return self._killed_called def kill(self): self._killed_called = True @property def status(self): return None with self.yield_sleepy(KillCalledTaskRunner, portmap={'health': 3141}, clock=clock, sleep=0, exit_code=0) as task_runner: graceful_shutdown_wait = Amount(1, Time.SECONDS) shutdown_wait = Amount(5, Time.SECONDS) http_task_runner = HttpLifecycleManager( task_runner, 3141, [('/quitquitquit', graceful_shutdown_wait), ('/abortabortabort', shutdown_wait)], clock=clock) http_task_runner.start() task_runner.forked.wait() http_task_runner.stop() http_teardown_poll_wait_call = call( HttpLifecycleManager.WAIT_POLL_INTERVAL.as_(Time.SECONDS)) assert clock.sleep.mock_calls.count( http_teardown_poll_wait_call) == 6 assert signaler.mock_calls == [ call('/quitquitquit', use_post_method=True), call('/abortabortabort', use_post_method=True) ] assert task_runner.kill_called() is True