Ejemplo n.º 1
0
class PantsDaemonTest(TestBase):
    def setUp(self):
        super().setUp()
        mock_options = unittest.mock.Mock()
        mock_options_values = unittest.mock.Mock()
        mock_options.for_global_scope.return_value = mock_options_values
        mock_options_values.pants_subprocessdir = "non_existent_dir"
        mock_server = unittest.mock.Mock()

        def create_services(bootstrap_options, legacy_graph_scheduler):
            return PantsServices()

        self.pantsd = PantsDaemon(
            native=Native(),
            work_dir="test_work_dir",
            log_level=logging.INFO,
            server=mock_server,
            core=PantsDaemonCore(create_services),
            metadata_base_dir="/tmp/pants_test_metadata_dir",
            bootstrap_options=mock_options,
        )

    @unittest.mock.patch("os.close", **PATCH_OPTS)
    def test_close_stdio(self, mock_close):
        with stdio_as(-1, -1, -1):
            handles = (sys.stdin, sys.stdout, sys.stderr)
            fds = [h.fileno() for h in handles]
            self.pantsd._close_stdio()
            mock_close.assert_has_calls(unittest.mock.call(x) for x in fds)
            for handle in handles:
                self.assertTrue(handle.closed, f"{handle} was not closed")
Ejemplo n.º 2
0
def test_close_stdio(mock_close):
    mock_options = unittest.mock.Mock()
    mock_options_values = unittest.mock.Mock()
    mock_options.for_global_scope.return_value = mock_options_values
    mock_options_values.pants_subprocessdir = "non_existent_dir"
    mock_server = unittest.mock.Mock()

    def create_services(bootstrap_options, legacy_graph_scheduler):
        return PantsServices()

    pantsd = PantsDaemon(
        native=Native(),
        work_dir="test_work_dir",
        log_level=logging.INFO,
        server=mock_server,
        core=PantsDaemonCore(create_services),
        metadata_base_dir="/tmp/pants_test_metadata_dir",
        bootstrap_options=mock_options,
    )

    with stdio_as(-1, -1, -1):
        handles = (sys.stdin, sys.stdout, sys.stderr)
        fds = [h.fileno() for h in handles]
        pantsd._close_stdio()
        mock_close.assert_has_calls(unittest.mock.call(x) for x in fds)
        for handle in handles:
            assert handle.closed is True
Ejemplo n.º 3
0
class PantsDaemonTest(BaseTest):
    def setUp(self):
        super(PantsDaemonTest, self).setUp()
        lock = threading.RLock()
        mock_options = mock.Mock()
        mock_options.pants_subprocessdir = 'non_existent_dir'
        self.pantsd = PantsDaemon(None, 'test_buildroot', 'test_work_dir',
                                  logging.INFO, lock, [], {},
                                  '/tmp/pants_test_metadata_dir', mock_options)
        self.mock_killswitch = mock.Mock()
        self.pantsd._kill_switch = self.mock_killswitch
        self.mock_service = mock.create_autospec(PantsService, spec_set=True)

    @mock.patch('os.close', **PATCH_OPTS)
    def test_close_fds(self, mock_close):
        mock_fd = mock.Mock()
        mock_fd.fileno.side_effect = [0, 1, 2]

        with stdio_as(mock_fd, mock_fd, mock_fd):
            self.pantsd._close_fds()

        self.assertEquals(mock_fd.close.call_count, 3)
        mock_close.assert_has_calls(mock.call(x) for x in [0, 1, 2])

    def test_shutdown(self):
        mock_thread = mock.Mock()
        mock_service_thread_map = {self.mock_service: mock_thread}

        self.pantsd.shutdown(mock_service_thread_map)

        self.mock_service.terminate.assert_called_once_with()
        self.assertTrue(self.pantsd.is_killed)
        mock_thread.join.assert_called_once_with()

    def test_run_services_no_services(self):
        self.pantsd._run_services([])

    @mock.patch('threading.Thread', **PATCH_OPTS)
    @mock.patch.object(PantsDaemon, 'shutdown', spec_set=True)
    def test_run_services_startupfailure(self, mock_shutdown, mock_thread):
        mock_thread.return_value.start.side_effect = RuntimeError('oops!')

        with self.assertRaises(PantsDaemon.StartupFailure):
            self.pantsd._run_services([self.mock_service])

        self.assertGreater(mock_shutdown.call_count, 0)

    @mock.patch('threading.Thread', **PATCH_OPTS)
    @mock.patch.object(PantsDaemon, 'shutdown', spec_set=True)
    def test_run_services_runtimefailure(self, mock_shutdown, mock_thread):
        self.mock_killswitch.is_set.side_effect = [False, False, True]
        mock_thread.return_value.is_alive.side_effect = [True, False]

        with self.assertRaises(PantsDaemon.RuntimeFailure):
            self.pantsd._run_services([self.mock_service])

        self.assertGreater(mock_shutdown.call_count, 0)
Ejemplo n.º 4
0
 def setUp(self):
     super(PantsDaemonTest, self).setUp()
     mock_options = mock.Mock()
     mock_options.pants_subprocessdir = 'non_existent_dir'
     self.pantsd = PantsDaemon(None, 'test_buildroot', 'test_work_dir',
                               logging.INFO, PantsServices(),
                               '/tmp/pants_test_metadata_dir', mock_options)
     self.mock_killswitch = mock.Mock()
     self.pantsd._kill_switch = self.mock_killswitch
     self.mock_service = mock.create_autospec(PantsService, spec_set=True)
Ejemplo n.º 5
0
    def setUp(self):
        super(PantsDaemonTest, self).setUp()
        self.pantsd = PantsDaemon('test_buildroot',
                                  'test_work_dir',
                                  logging.INFO,
                                  log_dir='/non_existent')
        self.pantsd.set_services([])
        self.pantsd.set_socket_map({})

        self.mock_killswitch = mock.Mock()
        self.pantsd._kill_switch = self.mock_killswitch

        self.mock_service = mock.create_autospec(PantsService, spec_set=True)
Ejemplo n.º 6
0
 def pantsd(self):
   if not self._pantsd:
     self._pantsd = PantsDaemon(self._build_root,
                                self._pants_workdir,
                                self._log_level,
                                self._log_dir)
   return self._pantsd
Ejemplo n.º 7
0
 def pantsd(self):
     return PantsDaemon(self._build_root,
                        self._pants_workdir,
                        self._log_level,
                        self._native,
                        self._log_dir,
                        reset_func=clean_global_runtime_state)
Ejemplo n.º 8
0
  def setUp(self):
    super(PantsDaemonTest, self).setUp()
    lock = threading.RLock()
    self.pantsd = PantsDaemon('test_buildroot',
                              'test_work_dir',
                              logging.INFO,
                              None,
                              log_dir='/non_existent',
                              metadata_base_dir=self.subprocess_dir)
    self.pantsd.set_services([])
    self.pantsd.set_socket_map({})
    self.pantsd.set_lock(lock)

    self.mock_killswitch = mock.Mock()
    self.pantsd._kill_switch = self.mock_killswitch

    self.mock_service = mock.create_autospec(PantsService, spec_set=True)
Ejemplo n.º 9
0
 def setUp(self):
     super().setUp()
     mock_options = unittest.mock.Mock()
     mock_options.pants_subprocessdir = "non_existent_dir"
     self.pantsd = PantsDaemon(
         None,
         "test_buildroot",
         "test_work_dir",
         logging.INFO,
         PantsServices(),
         "/tmp/pants_test_metadata_dir",
         mock_options,
     )
     self.mock_killswitch = unittest.mock.Mock()
     self.pantsd._kill_switch = self.mock_killswitch
     self.mock_service = unittest.mock.create_autospec(PantsService,
                                                       spec_set=True)
Ejemplo n.º 10
0
    def setUp(self):
        super(PantsDaemonTest, self).setUp()
        self.pantsd = PantsDaemon("test_buildroot", "test_work_dir", logging.INFO, log_dir="/non_existent")
        self.pantsd.set_services([])
        self.pantsd.set_socket_map({})

        self.mock_killswitch = mock.Mock()
        self.pantsd._kill_switch = self.mock_killswitch

        self.mock_service = mock.create_autospec(PantsService, spec_set=True)
Ejemplo n.º 11
0
    def setUp(self):
        super().setUp()
        mock_options = unittest.mock.Mock()
        mock_options_values = unittest.mock.Mock()
        mock_options.for_global_scope.return_value = mock_options_values
        mock_options_values.pants_subprocessdir = "non_existent_dir"
        mock_server = unittest.mock.Mock()

        def create_services(bootstrap_options, legacy_graph_scheduler):
            return PantsServices()

        self.pantsd = PantsDaemon(
            native=Native(),
            work_dir="test_work_dir",
            log_level=logging.INFO,
            server=mock_server,
            core=PantsDaemonCore(create_services),
            metadata_base_dir="/tmp/pants_test_metadata_dir",
            bootstrap_options=mock_options,
        )
Ejemplo n.º 12
0
 def setUp(self):
   super(PantsDaemonTest, self).setUp()
   mock_options = mock.Mock()
   mock_options.pants_subprocessdir = 'non_existent_dir'
   self.pantsd = PantsDaemon(None,
                             'test_buildroot',
                             'test_work_dir',
                             logging.INFO,
                             PantsServices(),
                             '/tmp/pants_test_metadata_dir',
                             mock_options)
   self.mock_killswitch = mock.Mock()
   self.pantsd._kill_switch = self.mock_killswitch
   self.mock_service = mock.create_autospec(PantsService, spec_set=True)
Ejemplo n.º 13
0
  def setUp(self):
    super(PantsDaemonTest, self).setUp()
    self.pantsd = PantsDaemon('test_buildroot',
                              'test_work_dir',
                              logging.INFO,
                              log_dir='/non_existent',
                              metadata_base_dir=self.subprocess_dir)
    self.pantsd.set_services([])
    self.pantsd.set_socket_map({})

    self.mock_killswitch = mock.Mock()
    self.pantsd._kill_switch = self.mock_killswitch

    self.mock_service = mock.create_autospec(PantsService, spec_set=True)
Ejemplo n.º 14
0
class PantsDaemonTest(TestBase):
    def setUp(self):
        super(PantsDaemonTest, self).setUp()
        mock_options = mock.Mock()
        mock_options.pants_subprocessdir = 'non_existent_dir'
        self.pantsd = PantsDaemon(None, 'test_buildroot', 'test_work_dir',
                                  logging.INFO, PantsServices(),
                                  '/tmp/pants_test_metadata_dir', mock_options)
        self.mock_killswitch = mock.Mock()
        self.pantsd._kill_switch = self.mock_killswitch
        self.mock_service = mock.create_autospec(PantsService, spec_set=True)

    @mock.patch('os.close', **PATCH_OPTS)
    def test_close_stdio(self, mock_close):
        with stdio_as(-1, -1, -1):
            handles = (sys.stdin, sys.stdout, sys.stderr)
            fds = [h.fileno() for h in handles]
            self.pantsd._close_stdio()
            mock_close.assert_has_calls(mock.call(x) for x in fds)
            for handle in handles:
                self.assertTrue(handle.closed,
                                '{} was not closed'.format(handle))

    def test_shutdown(self):
        mock_thread = mock.Mock()
        mock_service_thread_map = {self.mock_service: mock_thread}

        self.pantsd.shutdown(mock_service_thread_map)

        self.mock_service.terminate.assert_called_once_with()
        self.assertTrue(self.pantsd.is_killed)
        mock_thread.join.assert_called_once_with(
            PantsDaemon.JOIN_TIMEOUT_SECONDS)

    def test_run_services_no_services(self):
        self.pantsd._run_services(PantsServices())

    @mock.patch('threading.Thread', **PATCH_OPTS)
    @mock.patch.object(PantsDaemon, 'shutdown', spec_set=True)
    def test_run_services_startupfailure(self, mock_shutdown, mock_thread):
        mock_thread.return_value.start.side_effect = RuntimeError('oops!')

        with self.assertRaises(PantsDaemon.StartupFailure):
            self.pantsd._run_services(
                PantsServices(services=(self.mock_service, )))

        self.assertGreater(mock_shutdown.call_count, 0)

    @mock.patch('threading.Thread', **PATCH_OPTS)
    @mock.patch.object(PantsDaemon, 'shutdown', spec_set=True)
    @mock.patch.object(PantsDaemon,
                       'options_fingerprint',
                       spec_set=True,
                       new_callable=mock.PropertyMock)
    def test_run_services_runtimefailure(self, mock_fp, mock_shutdown,
                                         mock_thread):
        self.mock_killswitch.is_set.side_effect = [False, False, True]
        mock_thread.return_value.is_alive.side_effect = [True, False]
        mock_fp.return_value = 'some_sha'

        with self.assertRaises(PantsDaemon.RuntimeFailure):
            self.pantsd._run_services(
                PantsServices(services=(self.mock_service, )))

        self.assertGreater(mock_shutdown.call_count, 0)
Ejemplo n.º 15
0
 def pantsd(self):
     return PantsDaemon(self._build_root, self._pants_workdir,
                        self._log_level, self._log_dir)
Ejemplo n.º 16
0
class PantsDaemonTest(TestBase):
    def setUp(self):
        super().setUp()
        mock_options = unittest.mock.Mock()
        mock_options_values = unittest.mock.Mock()
        mock_options.for_global_scope.return_value = mock_options_values
        mock_options_values.pants_subprocessdir = "non_existent_dir"

        self.pantsd = PantsDaemon(
            None,
            "test_buildroot",
            "test_work_dir",
            logging.INFO,
            PantsServices(),
            "/tmp/pants_test_metadata_dir",
            mock_options,
        )
        self.mock_killswitch = unittest.mock.Mock()
        self.pantsd._kill_switch = self.mock_killswitch
        self.mock_service = unittest.mock.create_autospec(PantsService,
                                                          spec_set=True)

    @unittest.mock.patch("os.close", **PATCH_OPTS)
    def test_close_stdio(self, mock_close):
        with stdio_as(-1, -1, -1):
            handles = (sys.stdin, sys.stdout, sys.stderr)
            fds = [h.fileno() for h in handles]
            self.pantsd._close_stdio()
            mock_close.assert_has_calls(unittest.mock.call(x) for x in fds)
            for handle in handles:
                self.assertTrue(handle.closed, f"{handle} was not closed")

    def test_shutdown(self):
        mock_thread = unittest.mock.Mock()
        mock_service_thread_map = {self.mock_service: mock_thread}

        self.pantsd.shutdown(mock_service_thread_map)

        self.mock_service.terminate.assert_called_once_with()
        self.assertTrue(self.pantsd.is_killed)
        mock_thread.join.assert_called_once_with(
            PantsDaemon.JOIN_TIMEOUT_SECONDS)

    def test_run_services_no_services(self):
        self.pantsd._run_services(PantsServices())

    @unittest.mock.patch("threading.Thread", **PATCH_OPTS)
    @unittest.mock.patch.object(PantsDaemon, "shutdown", spec_set=True)
    def test_run_services_startupfailure(self, mock_shutdown, mock_thread):
        mock_thread.return_value.start.side_effect = RuntimeError("oops!")

        with self.assertRaises(PantsDaemon.StartupFailure):
            self.pantsd._run_services(
                PantsServices(services=(self.mock_service, )))

        self.assertGreater(mock_shutdown.call_count, 0)

    @unittest.mock.patch("threading.Thread", **PATCH_OPTS)
    @unittest.mock.patch.object(PantsDaemon, "shutdown", spec_set=True)
    @unittest.mock.patch.object(
        PantsDaemonProcessManager,
        "options_fingerprint",
        spec_set=True,
        new_callable=unittest.mock.PropertyMock,
    )
    def test_run_services_runtimefailure(self, mock_fp, mock_shutdown,
                                         mock_thread):
        self.mock_killswitch.is_set.side_effect = [False, False, True]
        mock_thread.return_value.is_alive.side_effect = [True, False]
        mock_fp.return_value = "some_sha"

        with self.assertRaises(PantsDaemon.RuntimeFailure):
            self.pantsd._run_services(
                PantsServices(services=(self.mock_service, )))

        self.assertGreater(mock_shutdown.call_count, 0)
Ejemplo n.º 17
0
class PantsDaemonTest(BaseTest):
  def setUp(self):
    super(PantsDaemonTest, self).setUp()
    self.pantsd = PantsDaemon('test_buildroot',
                              'test_work_dir',
                              logging.INFO,
                              None,
                              log_dir='/non_existent',
                              metadata_base_dir=self.subprocess_dir)
    self.pantsd.set_services([])
    self.pantsd.set_socket_map({})

    self.mock_killswitch = mock.Mock()
    self.pantsd._kill_switch = self.mock_killswitch

    self.mock_service = mock.create_autospec(PantsService, spec_set=True)

  @mock.patch('os.close', **PATCH_OPTS)
  def test_close_fds(self, mock_close):
    mock_fd = mock.Mock()
    mock_fd.fileno.side_effect = [0, 1, 2]

    with stdio_as(mock_fd, mock_fd, mock_fd):
      self.pantsd._close_fds()

    self.assertEquals(mock_fd.close.call_count, 3)
    mock_close.assert_has_calls(mock.call(x) for x in [0, 1, 2])

  def test_shutdown(self):
    mock_thread = mock.Mock()
    mock_service_thread_map = {self.mock_service: mock_thread}

    self.pantsd.shutdown(mock_service_thread_map)

    self.mock_service.terminate.assert_called_once_with()
    self.assertTrue(self.pantsd.is_killed)
    mock_thread.join.assert_called_once_with()

  def test_run_services_no_services(self):
    self.pantsd._run_services([])

  @mock.patch('threading.Thread', **PATCH_OPTS)
  @mock.patch.object(PantsDaemon, 'shutdown', spec_set=True)
  def test_run_services_startupfailure(self, mock_shutdown, mock_thread):
    mock_thread.return_value.start.side_effect = RuntimeError('oops!')

    with self.assertRaises(PantsDaemon.StartupFailure):
      self.pantsd._run_services([self.mock_service])

    self.assertGreater(mock_shutdown.call_count, 0)

  @mock.patch('threading.Thread', **PATCH_OPTS)
  @mock.patch.object(PantsDaemon, 'shutdown', spec_set=True)
  def test_run_services_runtimefailure(self, mock_shutdown, mock_thread):
    self.mock_killswitch.is_set.side_effect = [False, False, True]
    mock_thread.return_value.is_alive.side_effect = [True, False]

    with self.assertRaises(PantsDaemon.RuntimeFailure):
      self.pantsd._run_services([self.mock_service])

    self.assertGreater(mock_shutdown.call_count, 0)
Ejemplo n.º 18
0
class PantsDaemonTest(BaseTest):
    def setUp(self):
        super(PantsDaemonTest, self).setUp()
        self.pantsd = PantsDaemon('test_buildroot',
                                  'test_work_dir',
                                  logging.INFO,
                                  log_dir='/non_existent')
        self.pantsd.set_services([])
        self.pantsd.set_socket_map({})

        self.mock_killswitch = mock.Mock()
        self.pantsd._kill_switch = self.mock_killswitch

        self.mock_service = mock.create_autospec(PantsService, spec_set=True)

    def test_close_fds(self):
        mock_stdout, mock_stderr, mock_stdin = mock.Mock(), mock.Mock(
        ), mock.Mock()

        with stdio_as(mock_stdout, mock_stderr, mock_stdin):
            self.pantsd._close_fds()

        mock_stdout.close.assert_called_once_with()
        mock_stderr.close.assert_called_once_with()
        mock_stdin.close.assert_called_once_with()

    def test_shutdown(self):
        mock_thread = mock.Mock()
        mock_service_thread_map = {self.mock_service: mock_thread}

        self.pantsd.shutdown(mock_service_thread_map)

        self.mock_service.terminate.assert_called_once_with()
        self.assertTrue(self.pantsd.is_killed)
        mock_thread.join.assert_called_once_with()

    def test_run_services_no_services(self):
        self.pantsd._run_services([])

    @mock.patch('threading.Thread', autospec=True, spec_set=True)
    @mock.patch.object(PantsDaemon, 'shutdown', spec_set=True)
    def test_run_services_startupfailure(self, mock_shutdown, mock_thread):
        mock_thread.return_value.start.side_effect = RuntimeError('oops!')

        with self.assertRaises(PantsDaemon.StartupFailure):
            self.pantsd._run_services([self.mock_service])

        self.assertGreater(mock_shutdown.call_count, 0)

    @mock.patch('threading.Thread', autospec=True, spec_set=True)
    @mock.patch.object(PantsDaemon, 'shutdown', spec_set=True)
    def test_run_services_runtimefailure(self, mock_shutdown, mock_thread):
        self.mock_killswitch.is_set.side_effect = [False, False, True]
        mock_thread.return_value.is_alive.side_effect = [True, False]

        with self.assertRaises(PantsDaemon.RuntimeFailure):
            self.pantsd._run_services([self.mock_service])

        self.assertGreater(mock_shutdown.call_count, 0)
Ejemplo n.º 19
0
class PantsDaemonTest(BaseTest):
    def setUp(self):
        super(PantsDaemonTest, self).setUp()
        self.pantsd = PantsDaemon("test_buildroot", "test_work_dir", logging.INFO, log_dir="/non_existent")
        self.pantsd.set_services([])
        self.pantsd.set_socket_map({})

        self.mock_killswitch = mock.Mock()
        self.pantsd._kill_switch = self.mock_killswitch

        self.mock_service = mock.create_autospec(PantsService, spec_set=True)

    def test_close_fds(self):
        mock_stdout, mock_stderr, mock_stdin = mock.Mock(), mock.Mock(), mock.Mock()

        with stdio_as(mock_stdout, mock_stderr, mock_stdin):
            self.pantsd._close_fds()

        mock_stdout.close.assert_called_once_with()
        mock_stderr.close.assert_called_once_with()
        mock_stdin.close.assert_called_once_with()

    def test_shutdown(self):
        mock_thread = mock.Mock()
        mock_service_thread_map = {self.mock_service: mock_thread}

        self.pantsd.shutdown(mock_service_thread_map)

        self.mock_service.terminate.assert_called_once_with()
        self.assertTrue(self.pantsd.is_killed)
        mock_thread.join.assert_called_once_with()

    def test_run_services_no_services(self):
        self.pantsd._run_services([])

    @mock.patch("threading.Thread", autospec=True, spec_set=True)
    @mock.patch.object(PantsDaemon, "shutdown", spec_set=True)
    def test_run_services_startupfailure(self, mock_shutdown, mock_thread):
        mock_thread.return_value.start.side_effect = RuntimeError("oops!")

        with self.assertRaises(PantsDaemon.StartupFailure):
            self.pantsd._run_services([self.mock_service])

        self.assertGreater(mock_shutdown.call_count, 0)

    @mock.patch("threading.Thread", autospec=True, spec_set=True)
    @mock.patch.object(PantsDaemon, "shutdown", spec_set=True)
    def test_run_services_runtimefailure(self, mock_shutdown, mock_thread):
        self.mock_killswitch.is_set.side_effect = [False, False, True]
        mock_thread.return_value.is_alive.side_effect = [True, False]

        with self.assertRaises(PantsDaemon.RuntimeFailure):
            self.pantsd._run_services([self.mock_service])

        self.assertGreater(mock_shutdown.call_count, 0)
Ejemplo n.º 20
0
class PantsDaemonTest(TestBase):
  def setUp(self):
    super(PantsDaemonTest, self).setUp()
    mock_options = mock.Mock()
    mock_options.pants_subprocessdir = 'non_existent_dir'
    self.pantsd = PantsDaemon(None,
                              'test_buildroot',
                              'test_work_dir',
                              logging.INFO,
                              [],
                              {},
                              '/tmp/pants_test_metadata_dir',
                              mock_options)
    self.mock_killswitch = mock.Mock()
    self.pantsd._kill_switch = self.mock_killswitch
    self.mock_service = mock.create_autospec(PantsService, spec_set=True)

  @mock.patch('os.close', **PATCH_OPTS)
  def test_close_stdio(self, mock_close):
    with stdio_as(-1, -1, -1):
      handles = (sys.stdin, sys.stdout, sys.stderr)
      fds = [h.fileno() for h in handles]
      self.pantsd._close_stdio()
      mock_close.assert_has_calls(mock.call(x) for x in fds)
      for handle in handles:
        self.assertTrue(handle.closed, '{} was not closed'.format(handle))

  def test_shutdown(self):
    mock_thread = mock.Mock()
    mock_service_thread_map = {self.mock_service: mock_thread}

    self.pantsd.shutdown(mock_service_thread_map)

    self.mock_service.terminate.assert_called_once_with()
    self.assertTrue(self.pantsd.is_killed)
    mock_thread.join.assert_called_once_with(PantsDaemon.JOIN_TIMEOUT_SECONDS)

  def test_run_services_no_services(self):
    self.pantsd._run_services([])

  @mock.patch('threading.Thread', **PATCH_OPTS)
  @mock.patch.object(PantsDaemon, 'shutdown', spec_set=True)
  def test_run_services_startupfailure(self, mock_shutdown, mock_thread):
    mock_thread.return_value.start.side_effect = RuntimeError('oops!')

    with self.assertRaises(PantsDaemon.StartupFailure):
      self.pantsd._run_services([self.mock_service])

    self.assertGreater(mock_shutdown.call_count, 0)

  @mock.patch('threading.Thread', **PATCH_OPTS)
  @mock.patch.object(PantsDaemon, 'shutdown', spec_set=True)
  @mock.patch.object(PantsDaemon, 'options_fingerprint', spec_set=True,
                     new_callable=mock.PropertyMock)
  def test_run_services_runtimefailure(self, mock_fp, mock_shutdown, mock_thread):
    self.mock_killswitch.is_set.side_effect = [False, False, True]
    mock_thread.return_value.is_alive.side_effect = [True, False]
    mock_fp.return_value = 'some_sha'

    with self.assertRaises(PantsDaemon.RuntimeFailure):
      self.pantsd._run_services([self.mock_service])

    self.assertGreater(mock_shutdown.call_count, 0)