示例#1
0
 def setUp(self):
   super().setUp()
   self.mock_watchman = unittest.mock.create_autospec(Watchman, spec_set=True)
   self.service = FSEventService(self.mock_watchman, self.BUILD_ROOT)
   self.service.setup(None)
   self.service.register_all_files_handler(lambda x: True, name='test')
   self.service.register_all_files_handler(lambda x: False, name='test2')
示例#2
0
 def setUp(self):
   super(TestFSEventService, self).setUp()
   self.mock_watchman = mock.create_autospec(Watchman, spec_set=True)
   self.service = FSEventService(self.mock_watchman, self.BUILD_ROOT, self.WORKER_COUNT)
   self.service.setup(None, executor=TestExecutor())
   self.service.register_all_files_handler(lambda x: True, name='test')
   self.service.register_all_files_handler(lambda x: False, name='test2')
示例#3
0
        def _setup_services(build_root, bootstrap_options, legacy_graph_helper,
                            watchman):
            """Initialize pantsd services.

      :returns: A tuple of (`tuple` service_instances, `dict` port_map).
      """
            fs_event_service = FSEventService(
                watchman, build_root,
                bootstrap_options.pantsd_fs_event_workers)

            scheduler_service = SchedulerService(
                fs_event_service, legacy_graph_helper, build_root,
                bootstrap_options.pantsd_invalidation_globs)

            pailgun_service = PailgunService(
                bind_addr=(bootstrap_options.pantsd_pailgun_host,
                           bootstrap_options.pantsd_pailgun_port),
                exiter_class=DaemonExiter,
                runner_class=DaemonPantsRunner,
                target_roots_calculator=TargetRootsCalculator,
                scheduler_service=scheduler_service)

            store_gc_service = StoreGCService(legacy_graph_helper.scheduler)

            return (
                # Services.
                (fs_event_service, scheduler_service, pailgun_service,
                 store_gc_service),
                # Port map.
                dict(pailgun=pailgun_service.pailgun_port))
示例#4
0
    def _setup_services(self, watchman):
        """Initialize pantsd services.

    :returns: A tuple of (`tuple` service_instances, `dict` port_map).
    """
        # N.B. This inline import is currently necessary to avoid a circular reference in the import
        # of LocalPantsRunner for use by DaemonPantsRunner. This is because LocalPantsRunner must
        # ultimately import the pantsd services in order to itself launch pantsd.
        from pants.bin.daemon_pants_runner import DaemonExiter, DaemonPantsRunner

        pailgun_service = PailgunService(
            (self._pailgun_host, self._pailgun_port), DaemonExiter,
            DaemonPantsRunner)
        services = [pailgun_service]

        if self._fs_event_enabled and self._scheduler:
            fs_event_service = FSEventService(watchman, self._build_root,
                                              self._fs_event_workers)
            scheduler_service = SchedulerService(self._scheduler,
                                                 fs_event_service)
            services.extend((fs_event_service, scheduler_service))

        # Construct a mapping of named ports used by the daemon's services. In the default case these
        # will be randomly assigned by the underlying implementation so we can't reference via options.
        port_map = dict(pailgun=pailgun_service.pailgun_port)

        return tuple(services), port_map
示例#5
0
    def _setup_services(self, watchman):
        """Initialize pantsd services.

    :returns: A tuple of (`tuple` service_instances, `dict` port_map).
    """
        legacy_graph_helper = self._engine_initializer.setup_legacy_graph(
            self._pants_ignore_patterns,
            self._pants_workdir,
            native=self._native,
            build_ignore_patterns=self._build_ignore_patterns,
            exclude_target_regexps=self._exclude_target_regexp,
            subproject_roots=self._subproject_roots,
        )

        fs_event_service = FSEventService(watchman, self._build_root,
                                          self._fs_event_workers)
        scheduler_service = SchedulerService(fs_event_service,
                                             legacy_graph_helper)
        pailgun_service = PailgunService(bind_addr=(self._pailgun_host,
                                                    self._pailgun_port),
                                         exiter_class=DaemonExiter,
                                         runner_class=DaemonPantsRunner,
                                         target_roots_class=TargetRoots,
                                         scheduler_service=scheduler_service)

        return (
            # Use the schedulers reentrant lock as the daemon's global lock.
            legacy_graph_helper.scheduler.lock,
            # Services.
            (fs_event_service, scheduler_service, pailgun_service),
            # Port map.
            dict(pailgun=pailgun_service.pailgun_port))
 def setUp(self):
   super(TestFSEventService, self).setUp()
   self.mock_watchman = mock.create_autospec(Watchman, spec_set=True)
   self.service = FSEventService(self.mock_watchman, self.BUILD_ROOT, self.WORKER_COUNT)
   self.service.setup(None, None, executor=TestExecutor())
   self.service.register_all_files_handler(lambda x: True, name='test')
   self.service.register_all_files_handler(lambda x: False, name='test2')
示例#7
0
        def _setup_services(
            build_root,
            bootstrap_options,
            legacy_graph_scheduler,
            watchman,
            union_membership: UnionMembership,
        ):
            """Initialize pantsd services.

            :returns: A PantsServices instance.
            """
            should_shutdown_after_run = bootstrap_options.shutdown_pantsd_after_run
            fs_event_service = (FSEventService(
                watchman,
                build_root,
            ) if bootstrap_options.watchman_enable else None)

            pidfile_absolute = PantsDaemon.metadata_file_path(
                "pantsd", "pid", bootstrap_options.pants_subprocessdir)
            if pidfile_absolute.startswith(build_root):
                pidfile = os.path.relpath(pidfile_absolute, build_root)
            else:
                pidfile = None
                logging.getLogger(__name__).warning(
                    "Not watching pantsd pidfile because subprocessdir is outside of buildroot. Having "
                    "subprocessdir be a child of buildroot (as it is by default) may help avoid stray "
                    "pantsd processes.")

            # TODO make SchedulerService handle fs_event_service_being None
            scheduler_service = SchedulerService(
                fs_event_service=fs_event_service,
                legacy_graph_scheduler=legacy_graph_scheduler,
                build_root=build_root,
                invalidation_globs=OptionsInitializer.
                compute_pantsd_invalidation_globs(build_root,
                                                  bootstrap_options),
                pantsd_pidfile=pidfile,
                union_membership=union_membership,
            )

            pailgun_service = PailgunService(
                (bootstrap_options.pantsd_pailgun_host,
                 bootstrap_options.pantsd_pailgun_port),
                DaemonPantsRunner,
                scheduler_service,
                should_shutdown_after_run,
            )

            store_gc_service = StoreGCService(legacy_graph_scheduler.scheduler)

            return PantsServices(
                services=tuple(service for service in (
                    fs_event_service,
                    scheduler_service,
                    pailgun_service,
                    store_gc_service,
                ) if service is not None),
                port_map=dict(pailgun=pailgun_service.pailgun_port),
            )
示例#8
0
class TestFSEventService(TestBase):
    BUILD_ROOT = "/build_root"
    EMPTY_EVENT = (None, None)
    FAKE_EVENT = dict(subscription="test", files=["a/BUILD", "b/BUILD"])
    FAKE_EVENT_STREAM = [
        ("ignored", ev) for ev in [FAKE_EVENT, EMPTY_EVENT, EMPTY_EVENT, FAKE_EVENT, EMPTY_EVENT]
    ]
    WORKER_COUNT = 1

    def setUp(self):
        super().setUp()
        self.mock_watchman = unittest.mock.create_autospec(Watchman, spec_set=True)
        self.service = FSEventService(self.mock_watchman, self.scheduler.scheduler, self.BUILD_ROOT)
        self.service.setup(None)

    @contextmanager
    def mocked_run(self, asserts=True):
        self.service._handle_all_files_event = unittest.mock.Mock()
        yield self.service._handle_all_files_event
        if asserts:
            self.mock_watchman.watch_project.assert_called_once_with(self.BUILD_ROOT)

    def test_run_raise_on_failure_isalive(self):
        self.mock_watchman.is_alive.return_value = False
        with self.mocked_run(False), self.assertRaises(FSEventService.ServiceError):
            self.service.run()

    def test_run(self):
        with self.mocked_run() as mock_callback:
            self.mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
            self.service.run()
            mock_callback.assert_has_calls(
                [unittest.mock.call(self.FAKE_EVENT), unittest.mock.call(self.FAKE_EVENT)],
                any_order=True,
            )

    def test_run_breaks_on_kill_switch(self):
        with self.mocked_run() as mock_callback:
            self.service.terminate()
            self.mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
            self.service.run()
            assert not mock_callback.called
示例#9
0
        def _setup_services(
            build_root,
            bootstrap_options,
            legacy_graph_scheduler,
            native,
            watchman,
            union_membership: UnionMembership,
        ):
            """Initialize pantsd services.

            :returns: A PantsServices instance.
            """
            native.override_thread_logging_destination_to_just_pantsd()
            fs_event_service = (
                FSEventService(
                    watchman, scheduler=legacy_graph_scheduler.scheduler, build_root=build_root
                )
                if bootstrap_options.watchman_enable
                else None
            )

            invalidation_globs = OptionsInitializer.compute_pantsd_invalidation_globs(
                build_root, bootstrap_options
            )

            scheduler_service = SchedulerService(
                fs_event_service=fs_event_service,
                legacy_graph_scheduler=legacy_graph_scheduler,
                build_root=build_root,
                invalidation_globs=invalidation_globs,
                union_membership=union_membership,
            )

            pailgun_service = PailgunService(
                bootstrap_options.pantsd_pailgun_port,
                DaemonPantsRunner(scheduler_service),
                scheduler_service,
            )

            store_gc_service = StoreGCService(legacy_graph_scheduler.scheduler)

            return PantsServices(
                services=tuple(
                    service
                    for service in (
                        fs_event_service,
                        scheduler_service,
                        pailgun_service,
                        store_gc_service,
                    )
                    if service is not None
                ),
                port_map=dict(pailgun=pailgun_service.pailgun_port()),
            )
示例#10
0
        def _setup_services(build_root, bootstrap_options,
                            legacy_graph_scheduler, watchman):
            """Initialize pantsd services.

      :returns: A PantsServices instance.
      """
            should_shutdown_after_run = bootstrap_options.shutdown_pantsd_after_run
            fs_event_service = FSEventService(
                watchman,
                build_root,
            )

            pidfile_absolute = PantsDaemon.metadata_file_path(
                'pantsd', 'pid', bootstrap_options.pants_subprocessdir)
            if pidfile_absolute.startswith(build_root):
                pidfile = os.path.relpath(pidfile_absolute, build_root)
            else:
                pidfile = None
                logging.getLogger(__name__).warning(
                    'Not watching pantsd pidfile because subprocessdir is outside of buildroot. Having '
                    'subprocessdir be a child of buildroot (as it is by default) may help avoid stray '
                    'pantsd processes.')

            scheduler_service = SchedulerService(
                fs_event_service,
                legacy_graph_scheduler,
                build_root,
                OptionsInitializer.compute_pantsd_invalidation_globs(
                    build_root, bootstrap_options),
                pidfile,
            )

            pailgun_service = PailgunService(
                (bootstrap_options.pantsd_pailgun_host,
                 bootstrap_options.pantsd_pailgun_port),
                DaemonPantsRunner,
                scheduler_service,
                should_shutdown_after_run,
            )

            store_gc_service = StoreGCService(legacy_graph_scheduler.scheduler)

            return PantsServices(
                services=(fs_event_service, scheduler_service, pailgun_service,
                          store_gc_service),
                port_map=dict(pailgun=pailgun_service.pailgun_port),
            )
示例#11
0
    def _setup_services(build_root, bootstrap_options, legacy_graph_scheduler, watchman):
      """Initialize pantsd services.

      :returns: A tuple of (`tuple` service_instances, `dict` port_map).
      """
      fs_event_service = FSEventService(
        watchman,
        build_root,
        bootstrap_options.pantsd_fs_event_workers
      )

      pidfile_absolute = PantsDaemon.metadata_file_path('pantsd', 'pid', bootstrap_options.pants_subprocessdir)
      if pidfile_absolute.startswith(build_root):
        pidfile = os.path.relpath(pidfile_absolute, build_root)
      else:
        pidfile = None
        logging.getLogger(__name__).warning(
          'Not watching pantsd pidfile because subprocessdir is outside of buildroot. Having '
          'subprocessdir be a child of buildroot (as it is by default) may help avoid stray '
          'pantsd processes.'
        )

      scheduler_service = SchedulerService(
        fs_event_service,
        legacy_graph_scheduler,
        build_root,
        bootstrap_options.pantsd_invalidation_globs,
        pidfile,
      )

      pailgun_service = PailgunService(
        bind_addr=(bootstrap_options.pantsd_pailgun_host, bootstrap_options.pantsd_pailgun_port),
        exiter_class=DaemonExiter,
        runner_class=DaemonPantsRunner,
        target_roots_calculator=TargetRootsCalculator,
        scheduler_service=scheduler_service
      )

      store_gc_service = StoreGCService(legacy_graph_scheduler.scheduler)

      return (
        # Services.
        (fs_event_service, scheduler_service, pailgun_service, store_gc_service),
        # Port map.
        dict(pailgun=pailgun_service.pailgun_port)
      )
示例#12
0
    def _setup_services(
        bootstrap_options: OptionValueContainer,
        legacy_graph_scheduler: LegacyGraphScheduler,
    ):
        """Initialize pantsd services.

        :returns: A PantsServices instance.
        """
        build_root = get_buildroot()

        # TODO: https://github.com/pantsbuild/pants/issues/3479
        watchman_launcher = WatchmanLauncher.create(bootstrap_options)
        watchman_launcher.maybe_launch()
        watchman = watchman_launcher.watchman
        fs_event_service = (FSEventService(
            watchman,
            scheduler=legacy_graph_scheduler.scheduler,
            build_root=build_root)
                            if bootstrap_options.watchman_enable else None)

        invalidation_globs = OptionsInitializer.compute_pantsd_invalidation_globs(
            build_root,
            bootstrap_options,
            PantsDaemon.metadata_file_path(
                "pantsd", "pid", bootstrap_options.pants_subprocessdir),
        )

        scheduler_service = SchedulerService(
            fs_event_service=fs_event_service,
            legacy_graph_scheduler=legacy_graph_scheduler,
            build_root=build_root,
            invalidation_globs=invalidation_globs,
            max_memory_usage_pid=os.getpid(),
            max_memory_usage_in_bytes=bootstrap_options.
            pantsd_max_memory_usage,
        )

        store_gc_service = StoreGCService(legacy_graph_scheduler.scheduler)

        return PantsServices(services=tuple(service for service in (
            fs_event_service,
            scheduler_service,
            store_gc_service,
        ) if service is not None), )
示例#13
0
    def _setup_services(self, watchman):
        """Initialize pantsd services.

    :returns: A tuple of (`tuple` service_instances, `dict` port_map).
    """
        # N.B. This inline import is currently necessary to avoid a circular reference in the import
        # of LocalPantsRunner for use by DaemonPantsRunner. This is because LocalPantsRunner must
        # ultimately import the pantsd services in order to itself launch pantsd.
        from pants.bin.daemon_pants_runner import DaemonExiter, DaemonPantsRunner

        services = []
        scheduler_service = None
        if self._fs_event_enabled:
            fs_event_service = FSEventService(watchman, self._build_root,
                                              self._fs_event_workers)

            legacy_graph_helper = self._engine_initializer.setup_legacy_graph(
                self._pants_ignore_patterns,
                self._pants_workdir,
                build_ignore_patterns=self._build_ignore_patterns,
                exclude_target_regexps=self._exclude_target_regexp,
                subproject_roots=self._subproject_roots,
            )
            scheduler_service = SchedulerService(fs_event_service,
                                                 legacy_graph_helper)
            services.extend((fs_event_service, scheduler_service))

        pailgun_service = PailgunService(bind_addr=(self._pailgun_host,
                                                    self._pailgun_port),
                                         exiter_class=DaemonExiter,
                                         runner_class=DaemonPantsRunner,
                                         target_roots_class=TargetRoots,
                                         scheduler_service=scheduler_service)
        services.append(pailgun_service)

        # Construct a mapping of named ports used by the daemon's services. In the default case these
        # will be randomly assigned by the underlying implementation so we can't reference via options.
        port_map = dict(pailgun=pailgun_service.pailgun_port)

        return tuple(services), port_map
示例#14
0
  def _setup_services(self, watchman):
    """Initialize pantsd services.

    :returns: A tuple of (`tuple` service_instances, `dict` port_map).
    """
    # N.B. This inline import is currently necessary to avoid a circular reference in the import
    # of LocalPantsRunner for use by DaemonPantsRunner. This is because LocalPantsRunner must
    # ultimately import the pantsd services in order to itself launch pantsd.
    from pants.bin.daemon_pants_runner import DaemonExiter, DaemonPantsRunner

    legacy_graph_helper = self._engine_initializer.setup_legacy_graph(
      self._pants_ignore_patterns,
      self._pants_workdir,
      native=self._native,
      build_ignore_patterns=self._build_ignore_patterns,
      exclude_target_regexps=self._exclude_target_regexp,
      subproject_roots=self._subproject_roots,
    )

    fs_event_service = FSEventService(watchman, self._build_root, self._fs_event_workers)
    scheduler_service = SchedulerService(fs_event_service, legacy_graph_helper)
    pailgun_service = PailgunService(
      bind_addr=(self._pailgun_host, self._pailgun_port),
      exiter_class=DaemonExiter,
      runner_class=DaemonPantsRunner,
      target_roots_class=TargetRoots,
      scheduler_service=scheduler_service
    )

    return (
      # Use the schedulers reentrant lock as the daemon's global lock.
      legacy_graph_helper.scheduler.lock,
      # Services.
      (fs_event_service, scheduler_service, pailgun_service),
      # Port map.
      dict(pailgun=pailgun_service.pailgun_port)
    )
示例#15
0
class TestFSEventService(TestBase):
    BUILD_ROOT = '/build_root'
    EMPTY_EVENT = (None, None)
    FAKE_EVENT = ('test',
                  dict(subscription='test', files=['a/BUILD', 'b/BUILD']))
    FAKE_EVENT_STREAM = [
        FAKE_EVENT, EMPTY_EVENT, EMPTY_EVENT, FAKE_EVENT, EMPTY_EVENT
    ]
    WORKER_COUNT = 1

    def setUp(self):
        super().setUp()
        self.mock_watchman = unittest.mock.create_autospec(Watchman,
                                                           spec_set=True)
        self.service = FSEventService(self.mock_watchman, self.BUILD_ROOT)
        self.service.setup(None)
        self.service.register_all_files_handler(lambda x: True, name='test')
        self.service.register_all_files_handler(lambda x: False, name='test2')

    def test_registration(self):
        # N.B. This test implicitly tests register_handler; no need to duplicate work.
        self.assertTrue('test' in self.service._handlers)
        self.assertTrue('test2' in self.service._handlers)
        self.assertIsInstance(self.service._handlers['test'],
                              Watchman.EventHandler)
        self.assertIsInstance(self.service._handlers['test2'],
                              Watchman.EventHandler)

    def test_register_handler_duplicate(self):
        with self.assertRaises(AssertionError):
            self.service.register_handler('test', 'test', lambda x: True)

        with self.assertRaises(AssertionError):
            self.service.register_handler('test', dict(test=1), lambda x: True)

    def test_fire_callback(self):
        self.assertTrue(self.service.fire_callback('test', {}))
        self.assertFalse(self.service.fire_callback('test2', {}))

    @contextmanager
    def mocked_run(self, asserts=True):
        self.service.fire_callback = unittest.mock.Mock()
        yield self.service.fire_callback
        if asserts:
            self.mock_watchman.watch_project.assert_called_once_with(
                self.BUILD_ROOT)

    def test_run_raise_on_failure_isalive(self):
        self.mock_watchman.is_alive.return_value = False
        with self.mocked_run(False), self.assertRaises(
                FSEventService.ServiceError):
            self.service.run()

    def test_run(self):
        with self.mocked_run() as mock_callback:
            self.mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
            self.service.run()
            mock_callback.assert_has_calls([
                unittest.mock.call(*self.FAKE_EVENT),
                unittest.mock.call(*self.FAKE_EVENT)
            ],
                                           any_order=True)

    def test_run_failed_callback(self):
        with self.mocked_run() as mock_callback:
            self.mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
            mock_callback.side_effect = [False, True]
            self.service.run()
            mock_callback.assert_has_calls([
                unittest.mock.call(*self.FAKE_EVENT),
                unittest.mock.call(*self.FAKE_EVENT)
            ],
                                           any_order=True)

    def test_run_breaks_on_kill_switch(self):
        with self.mocked_run() as mock_callback:
            self.service.terminate()
            self.mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
            self.service.run()
            assert not mock_callback.called
示例#16
0
class TestFSEventService(BaseTest):
  PATCH_OPTS = dict(autospec=True, spec_set=True)
  BUILD_ROOT = '/build_root'
  EMPTY_EVENT = (None, None)
  FAKE_EVENT = ('test', dict(subscription='test', files=['a/BUILD', 'b/BUILD']))
  FAKE_EVENT_STREAM = [FAKE_EVENT, EMPTY_EVENT, EMPTY_EVENT, FAKE_EVENT, EMPTY_EVENT]

  def setUp(self):
    BaseTest.setUp(self)
    self.service = FSEventService(self.BUILD_ROOT, TestExecutor())
    self.service.register_simple_handler('test', lambda x: True)
    self.service.register_simple_handler('test2', lambda x: False)

  def test_register_simple_handler(self):
    # N.B. This test implicitly tests register_handler; no need to duplicate work.
    self.assertTrue('test' in self.service._handlers)
    self.assertTrue('test2' in self.service._handlers)
    self.assertIsInstance(self.service._handlers['test'], Watchman.EventHandler)
    self.assertIsInstance(self.service._handlers['test2'], Watchman.EventHandler)

  def test_register_simple_handler_duplicate(self):
    with self.assertRaises(AssertionError):
      self.service.register_simple_handler('test', lambda x: True)

  def test_register_handler_duplicate(self):
    with self.assertRaises(AssertionError):
      self.service.register_handler('test', 'test', lambda x: True)

    with self.assertRaises(AssertionError):
      self.service.register_handler('test', dict(test=1), lambda x: True)

  def test_fire_callback(self):
    self.assertTrue(self.service.fire_callback('test', {}))
    self.assertFalse(self.service.fire_callback('test2', {}))

  @contextmanager
  def mocked_run(self, asserts=True):
    with mock.patch('pants.pantsd.service.fs_event_service.WatchmanLauncher',
                    **self.PATCH_OPTS) as mock_watchman_launcher, \
         mock.patch('pants.pantsd.service.fs_event_service.Watchman',
                    **self.PATCH_OPTS) as mock_watchman:
      mock_watchman_launcher.global_instance.return_value = mock_watchman_launcher
      mock_watchman_launcher.maybe_launch.return_value = mock_watchman
      self.service.fire_callback = mock.Mock()
      yield mock_watchman, mock_watchman_launcher, self.service.fire_callback
      if asserts:
        mock_watchman.watch_project.assert_called_once_with(self.BUILD_ROOT)

  def test_run_raise_on_failure_isalive(self):
    with self.mocked_run(False) as (mock_watchman, mock_watchman_launcher, mock_callback):
      with self.assertRaises(self.service.ServiceError):
        mock_watchman.is_alive.return_value = False
        self.service.run()

  def test_run_raise_on_failure_launch(self):
    with self.mocked_run(False) as (mock_watchman, mock_watchman_launcher, mock_callback):
      with self.assertRaises(self.service.ServiceError):
        mock_watchman_launcher.maybe_launch.return_value = False
        self.service.run()

  def test_run(self):
    with self.mocked_run() as (mock_watchman, mock_watchman_launcher, mock_callback):
      mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
      self.service.run()
      mock_callback.assert_has_calls([mock.call(*self.FAKE_EVENT), mock.call(*self.FAKE_EVENT)],
                                     any_order=True)

  def test_run_failed_callback(self):
    with self.mocked_run() as (mock_watchman, mock_watchman_launcher, mock_callback):
      mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
      mock_callback.side_effect = [False, True]
      self.service.run()
      mock_callback.assert_has_calls([mock.call(*self.FAKE_EVENT), mock.call(*self.FAKE_EVENT)],
                                     any_order=True)

  def test_run_breaks_on_kill_switch(self):
    with self.mocked_run() as (mock_watchman, mock_watchman_launcher, mock_callback):
      self.service.terminate()
      mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
      self.service.run()
      assert not mock_callback.called
class TestFSEventService(TestBase):
  BUILD_ROOT = '/build_root'
  EMPTY_EVENT = (None, None)
  FAKE_EVENT = ('test', dict(subscription='test', files=['a/BUILD', 'b/BUILD']))
  FAKE_EVENT_STREAM = [FAKE_EVENT, EMPTY_EVENT, EMPTY_EVENT, FAKE_EVENT, EMPTY_EVENT]
  WORKER_COUNT = 1

  def setUp(self):
    super(TestFSEventService, self).setUp()
    self.mock_watchman = mock.create_autospec(Watchman, spec_set=True)
    self.service = FSEventService(self.mock_watchman, self.BUILD_ROOT, self.WORKER_COUNT)
    self.service.setup(None, None, executor=TestExecutor())
    self.service.register_all_files_handler(lambda x: True, name='test')
    self.service.register_all_files_handler(lambda x: False, name='test2')

  def test_registration(self):
    # N.B. This test implicitly tests register_handler; no need to duplicate work.
    self.assertTrue('test' in self.service._handlers)
    self.assertTrue('test2' in self.service._handlers)
    self.assertIsInstance(self.service._handlers['test'], Watchman.EventHandler)
    self.assertIsInstance(self.service._handlers['test2'], Watchman.EventHandler)

  def test_register_handler_duplicate(self):
    with self.assertRaises(AssertionError):
      self.service.register_handler('test', 'test', lambda x: True)

    with self.assertRaises(AssertionError):
      self.service.register_handler('test', dict(test=1), lambda x: True)

  def test_fire_callback(self):
    self.assertTrue(self.service.fire_callback('test', {}))
    self.assertFalse(self.service.fire_callback('test2', {}))

  @contextmanager
  def mocked_run(self, asserts=True):
    self.service.fire_callback = mock.Mock()
    yield self.service.fire_callback
    if asserts:
      self.mock_watchman.watch_project.assert_called_once_with(self.BUILD_ROOT)

  def test_run_raise_on_failure_isalive(self):
    self.mock_watchman.is_alive.return_value = False
    with self.mocked_run(False), self.assertRaises(self.service.ServiceError):
      self.service.run()

  def test_run(self):
    with self.mocked_run() as mock_callback:
      self.mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
      self.service.run()
      mock_callback.assert_has_calls([mock.call(*self.FAKE_EVENT), mock.call(*self.FAKE_EVENT)],
                                     any_order=True)

  def test_run_failed_callback(self):
    with self.mocked_run() as mock_callback:
      self.mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
      mock_callback.side_effect = [False, True]
      self.service.run()
      mock_callback.assert_has_calls([mock.call(*self.FAKE_EVENT), mock.call(*self.FAKE_EVENT)],
                                     any_order=True)

  def test_run_breaks_on_kill_switch(self):
    with self.mocked_run() as mock_callback:
      self.service.terminate()
      self.mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
      self.service.run()
      assert not mock_callback.called
示例#18
0
 def setUp(self):
   BaseTest.setUp(self)
   self.service = FSEventService(self.BUILD_ROOT, TestExecutor())
   self.service.register_simple_handler('test', lambda x: True)
   self.service.register_simple_handler('test2', lambda x: False)
示例#19
0
 def setUp(self):
     super().setUp()
     self.mock_watchman = unittest.mock.create_autospec(Watchman, spec_set=True)
     self.service = FSEventService(self.mock_watchman, self.scheduler.scheduler, self.BUILD_ROOT)
     self.service.setup(None)
示例#20
0
class TestFSEventService(BaseTest):
    PATCH_OPTS = dict(autospec=True, spec_set=True)
    BUILD_ROOT = '/build_root'
    EMPTY_EVENT = (None, None)
    FAKE_EVENT = ('test',
                  dict(subscription='test', files=['a/BUILD', 'b/BUILD']))
    FAKE_EVENT_STREAM = [
        FAKE_EVENT, EMPTY_EVENT, EMPTY_EVENT, FAKE_EVENT, EMPTY_EVENT
    ]

    def setUp(self):
        BaseTest.setUp(self)
        self.service = FSEventService(self.BUILD_ROOT, TestExecutor())
        self.service.register_simple_handler('test', lambda x: True)
        self.service.register_simple_handler('test2', lambda x: False)

    def test_register_simple_handler(self):
        # N.B. This test implicitly tests register_handler; no need to duplicate work.
        self.assertTrue('test' in self.service._handlers)
        self.assertTrue('test2' in self.service._handlers)
        self.assertIsInstance(self.service._handlers['test'],
                              Watchman.EventHandler)
        self.assertIsInstance(self.service._handlers['test2'],
                              Watchman.EventHandler)

    def test_register_simple_handler_duplicate(self):
        with self.assertRaises(AssertionError):
            self.service.register_simple_handler('test', lambda x: True)

    def test_register_handler_duplicate(self):
        with self.assertRaises(AssertionError):
            self.service.register_handler('test', 'test', lambda x: True)

        with self.assertRaises(AssertionError):
            self.service.register_handler('test', dict(test=1), lambda x: True)

    def test_fire_callback(self):
        self.assertTrue(self.service.fire_callback('test', {}))
        self.assertFalse(self.service.fire_callback('test2', {}))

    @contextmanager
    def mocked_run(self, asserts=True):
        with mock.patch('pants.pantsd.service.fs_event_service.WatchmanLauncher',
                        **self.PATCH_OPTS) as mock_watchman_launcher, \
             mock.patch('pants.pantsd.service.fs_event_service.Watchman',
                        **self.PATCH_OPTS) as mock_watchman:
            mock_watchman_launcher.global_instance.return_value = mock_watchman_launcher
            mock_watchman_launcher.maybe_launch.return_value = mock_watchman
            self.service.fire_callback = mock.Mock()
            yield mock_watchman, mock_watchman_launcher, self.service.fire_callback
            if asserts:
                mock_watchman.watch_project.assert_called_once_with(
                    self.BUILD_ROOT)

    def test_run_raise_on_failure_isalive(self):
        with self.mocked_run(False) as (mock_watchman, mock_watchman_launcher,
                                        mock_callback):
            with self.assertRaises(self.service.ServiceError):
                mock_watchman.is_alive.return_value = False
                self.service.run()

    def test_run_raise_on_failure_launch(self):
        with self.mocked_run(False) as (mock_watchman, mock_watchman_launcher,
                                        mock_callback):
            with self.assertRaises(self.service.ServiceError):
                mock_watchman_launcher.maybe_launch.return_value = False
                self.service.run()

    def test_run(self):
        with self.mocked_run() as (mock_watchman, mock_watchman_launcher,
                                   mock_callback):
            mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
            self.service.run()
            mock_callback.assert_has_calls(
                [mock.call(*self.FAKE_EVENT),
                 mock.call(*self.FAKE_EVENT)],
                any_order=True)

    def test_run_failed_callback(self):
        with self.mocked_run() as (mock_watchman, mock_watchman_launcher,
                                   mock_callback):
            mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
            mock_callback.side_effect = [False, True]
            self.service.run()
            mock_callback.assert_has_calls(
                [mock.call(*self.FAKE_EVENT),
                 mock.call(*self.FAKE_EVENT)],
                any_order=True)

    def test_run_breaks_on_kill_switch(self):
        with self.mocked_run() as (mock_watchman, mock_watchman_launcher,
                                   mock_callback):
            self.service.terminate()
            mock_watchman.subscribed.return_value = self.FAKE_EVENT_STREAM
            self.service.run()
            assert not mock_callback.called
示例#21
0
 def setUp(self):
     BaseTest.setUp(self)
     self.service = FSEventService(self.BUILD_ROOT, TestExecutor())
     self.service.register_simple_handler('test', lambda x: True)
     self.service.register_simple_handler('test2', lambda x: False)
示例#22
0
 def setUp(self):
   BaseTest.setUp(self)
   self.service = FSEventService(self.BUILD_ROOT, 1)
   self.service.setup(TestExecutor())
   self.service.register_all_files_handler(lambda x: True, name='test')
   self.service.register_all_files_handler(lambda x: False, name='test2')