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 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')
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))
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
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')
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), )
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
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()), )
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), )
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) )
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), )
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
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) )
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
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
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 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)
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
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')