class LoaderTest(unittest.TestCase): def setUp(self): self.build_configuration = BuildConfiguration() self.working_set = WorkingSet() for entry in working_set.entries: self.working_set.add_entry(entry) def tearDown(self): Goal.clear() @contextmanager def create_register(self, build_file_aliases=None, register_goals=None, global_subsystems=None, module_name='register'): package_name = b'__test_package_{0}'.format(uuid.uuid4().hex) self.assertFalse(package_name in sys.modules) package_module = types.ModuleType(package_name) sys.modules[package_name] = package_module try: register_module_fqn = b'{0}.{1}'.format(package_name, module_name) register_module = types.ModuleType(register_module_fqn) setattr(package_module, module_name, register_module) sys.modules[register_module_fqn] = register_module def register_entrypoint(function_name, function): if function: setattr(register_module, function_name, function) register_entrypoint('build_file_aliases', build_file_aliases) register_entrypoint('global_subsystems', global_subsystems) register_entrypoint('register_goals', register_goals) yield package_name finally: del sys.modules[package_name] def assert_empty_aliases(self): registered_aliases = self.build_configuration.registered_aliases() self.assertEqual(0, len(registered_aliases.targets)) self.assertEqual(0, len(registered_aliases.objects)) self.assertEqual(0, len(registered_aliases.context_aware_object_factories)) self.assertEqual(self.build_configuration.subsystem_types(), set()) def test_load_valid_empty(self): with self.create_register() as backend_package: load_backend(self.build_configuration, backend_package) self.assert_empty_aliases() def test_load_valid_partial_aliases(self): aliases = BuildFileAliases.create(targets={'bob': DummyTarget}, objects={'obj1': DummyObject1, 'obj2': DummyObject2}) with self.create_register(build_file_aliases=lambda: aliases) as backend_package: load_backend(self.build_configuration, backend_package) registered_aliases = self.build_configuration.registered_aliases() self.assertEqual(DummyTarget, registered_aliases.targets['bob']) self.assertEqual(DummyObject1, registered_aliases.objects['obj1']) self.assertEqual(DummyObject2, registered_aliases.objects['obj2']) self.assertEqual(self.build_configuration.subsystem_types(), set([DummySubsystem1, DummySubsystem2])) def test_load_valid_partial_goals(self): def register_goals(): Goal.by_name('jack').install(TaskRegistrar('jill', DummyTask)) with self.create_register(register_goals=register_goals) as backend_package: Goal.clear() self.assertEqual(0, len(Goal.all())) load_backend(self.build_configuration, backend_package) self.assert_empty_aliases() self.assertEqual(1, len(Goal.all())) task_names = Goal.by_name('jack').ordered_task_names() self.assertEqual(1, len(task_names)) task_name = task_names[0] self.assertEqual('jill', task_name) def test_load_invalid_entrypoint(self): def build_file_aliases(bad_arg): return BuildFileAliases.create() with self.create_register(build_file_aliases=build_file_aliases) as backend_package: with self.assertRaises(BuildConfigurationError): load_backend(self.build_configuration, backend_package) def test_load_invalid_module(self): with self.create_register(module_name='register2') as backend_package: with self.assertRaises(BuildConfigurationError): load_backend(self.build_configuration, backend_package) def test_load_missing_plugin(self): with self.assertRaises(PluginNotFound): self.load_plugins(['Foobar']) def get_mock_plugin(self, name, version, reg=None, alias=None, after=None): """Make a fake Distribution (optionally with entry points) Note the entry points do not actually point to code in the returned distribution -- the distribution does not even have a location and does not contain any code, just metadata. A module is synthesized on the fly and installed into sys.modules under a random name. If optional entry point callables are provided, those are added as methods to the module and their name (foo/bar/baz in fake module) is added as the requested entry point to the mocked metadata added to the returned dist. :param str name: project_name for distribution (see pkg_resources) :param str version: version for distribution (see pkg_resources) :param callable reg: Optional callable for goal registration entry point :param callable alias: Optional callable for build_file_aliases entry point :param callable after: Optional callable for load_after list entry point """ plugin_pkg = b'demoplugin{0}'.format(uuid.uuid4().hex) pkg = types.ModuleType(plugin_pkg) sys.modules[plugin_pkg] = pkg module_name = b'{0}.{1}'.format(plugin_pkg, 'demo') plugin = types.ModuleType(module_name) setattr(pkg, 'demo', plugin) sys.modules[module_name] = plugin metadata = {} entry_lines = [] if reg is not None: setattr(plugin, 'foo', reg) entry_lines.append('register_goals = {}:foo\n'.format(module_name)) if alias is not None: setattr(plugin, 'bar', alias) entry_lines.append('build_file_aliases = {}:bar\n'.format(module_name)) if after is not None: setattr(plugin, 'baz', after) entry_lines.append('load_after = {}:baz\n'.format(module_name)) if entry_lines: entry_data = '[pantsbuild.plugin]\n{}\n'.format('\n'.join(entry_lines)) metadata = {'entry_points.txt': entry_data} return Distribution(project_name=name, version=version, metadata=MockMetadata(metadata)) def load_plugins(self, plugins): load_plugins(self.build_configuration, plugins, load_from=self.working_set) def test_plugin_load_and_order(self): d1 = self.get_mock_plugin('demo1', '0.0.1', after=lambda: ['demo2']) d2 = self.get_mock_plugin('demo2', '0.0.3') self.working_set.add(d1) # Attempting to load 'demo1' then 'demo2' should fail as 'demo1' requires 'after'=['demo2']. with self.assertRaises(PluginLoadOrderError): self.load_plugins(['demo1', 'demo2']) # Attempting to load 'demo2' first should fail as it is not (yet) installed. with self.assertRaises(PluginNotFound): self.load_plugins(['demo2', 'demo1']) # Installing demo2 and then loading in correct order should work though. self.working_set.add(d2) self.load_plugins(['demo2>=0.0.2', 'demo1']) # But asking for a bad (not installed) version fails. with self.assertRaises(VersionConflict): self.load_plugins(['demo2>=0.0.5']) def test_plugin_installs_goal(self): def reg_goal(): Goal.by_name('plugindemo').install(TaskRegistrar('foo', DummyTask)) self.working_set.add(self.get_mock_plugin('regdemo', '0.0.1', reg=reg_goal)) # Start without the custom goal. self.assertEqual(0, len(Goal.by_name('plugindemo').ordered_task_names())) # Load plugin which registers custom goal. self.load_plugins(['regdemo']) # Now the custom goal exists. self.assertEqual(1, len(Goal.by_name('plugindemo').ordered_task_names())) self.assertEqual('foo', Goal.by_name('plugindemo').ordered_task_names()[0]) def test_plugin_installs_alias(self): def reg_alias(): return BuildFileAliases.create(targets={'pluginalias': DummyTarget}, objects={'FROMPLUGIN1': DummyObject1, 'FROMPLUGIN2': DummyObject2}) self.working_set.add(self.get_mock_plugin('aliasdemo', '0.0.1', alias=reg_alias)) # Start with no aliases. self.assert_empty_aliases() # Now load the plugin which defines aliases. self.load_plugins(['aliasdemo']) # Aliases now exist. registered_aliases = self.build_configuration.registered_aliases() self.assertEqual(DummyTarget, registered_aliases.targets['pluginalias']) self.assertEqual(DummyObject1, registered_aliases.objects['FROMPLUGIN1']) self.assertEqual(DummyObject2, registered_aliases.objects['FROMPLUGIN2']) self.assertEqual(self.build_configuration.subsystem_types(), {DummySubsystem1, DummySubsystem2}) def test_subsystems(self): def global_subsystems(): return {DummySubsystem1, DummySubsystem2} with self.create_register(global_subsystems=global_subsystems) as backend_package: load_backend(self.build_configuration, backend_package) self.assertEqual(self.build_configuration.subsystem_types(), {DummySubsystem1, DummySubsystem2})
class BuildConfigurationTest(unittest.TestCase): def setUp(self): self.build_configuration = BuildConfiguration() def _register_aliases(self, **kwargs): self.build_configuration.register_aliases(BuildFileAliases(**kwargs)) def test_register_bad(self): with self.assertRaises(TypeError): self.build_configuration.register_aliases(42) def test_register_target_alias(self): class Fred(Target): pass self._register_aliases(targets={'fred': Fred}) aliases = self.build_configuration.registered_aliases() self.assertEqual({}, aliases.target_macro_factories) self.assertEqual({}, aliases.objects) self.assertEqual({}, aliases.context_aware_object_factories) self.assertEqual(dict(fred=Fred), aliases.target_types) build_file = FilesystemBuildFile('/tmp', 'fred', must_exist=False) parse_state = self.build_configuration.initialize_parse_state(build_file) self.assertEqual(0, len(parse_state.registered_addressable_instances)) self.assertEqual(1, len(parse_state.parse_globals)) target_call_proxy = parse_state.parse_globals['fred'] target_call_proxy(name='jake') self.assertEqual(1, len(parse_state.registered_addressable_instances)) name, target_proxy = parse_state.registered_addressable_instances.pop() self.assertEqual('jake', target_proxy.addressed_name) self.assertEqual(Fred, target_proxy.addressed_type) def test_register_target_macro_facory(self): class Fred(Target): pass class FredMacro(TargetMacro): def __init__(self, parse_context): self._parse_context = parse_context def expand(self, *args, **kwargs): return self._parse_context.create_object(Fred, name='frog', dependencies=[kwargs['name']]) class FredFactory(TargetMacro.Factory): @property def target_types(self): return {Fred} def macro(self, parse_context): return FredMacro(parse_context) factory = FredFactory() self._register_aliases(targets={'fred': factory}) aliases = self.build_configuration.registered_aliases() self.assertEqual({}, aliases.target_types) self.assertEqual({}, aliases.objects) self.assertEqual({}, aliases.context_aware_object_factories) self.assertEqual(dict(fred=factory), aliases.target_macro_factories) build_file = FilesystemBuildFile('/tmp', 'fred', must_exist=False) parse_state = self.build_configuration.initialize_parse_state(build_file) self.assertEqual(0, len(parse_state.registered_addressable_instances)) self.assertEqual(1, len(parse_state.parse_globals)) target_call_proxy = parse_state.parse_globals['fred'] target_call_proxy(name='jake') self.assertEqual(1, len(parse_state.registered_addressable_instances)) name, target_proxy = parse_state.registered_addressable_instances.pop() self.assertEqual('frog', target_proxy.addressed_name) self.assertEqual(Fred, target_proxy.addressed_type) self.assertEqual(['jake'], target_proxy.dependency_specs) def test_register_exposed_object(self): self._register_aliases(objects={'jane': 42}) aliases = self.build_configuration.registered_aliases() self.assertEqual({}, aliases.target_types) self.assertEqual({}, aliases.target_macro_factories) self.assertEqual({}, aliases.context_aware_object_factories) self.assertEqual(dict(jane=42), aliases.objects) build_file = FilesystemBuildFile('/tmp', 'jane', must_exist=False) parse_state = self.build_configuration.initialize_parse_state(build_file) self.assertEqual(0, len(parse_state.registered_addressable_instances)) self.assertEqual(1, len(parse_state.parse_globals)) self.assertEqual(42, parse_state.parse_globals['jane']) def test_register_exposed_context_aware_function(self): self.do_test_exposed_context_aware_function(lambda context: lambda: context.rel_path) self.do_test_exposed_context_aware_function(lambda context=None: lambda: context.rel_path) def george_method(self, parse_context): return lambda: parse_context.rel_path def test_register_exposed_context_aware_method(self): self.do_test_exposed_context_aware_function(self.george_method) @classmethod def george_classmethod(cls, parse_context): return lambda: parse_context.rel_path def test_register_exposed_context_aware_classmethod(self): self.do_test_exposed_context_aware_function(self.george_classmethod) @staticmethod def george_staticmethod(parse_context): return lambda: parse_context.rel_path def test_register_exposed_context_aware_staticmethod(self): self.do_test_exposed_context_aware_function(self.george_staticmethod) def do_test_exposed_context_aware_function(self, func, *args, **kwargs): with self.do_test_exposed_context_aware_object(func) as context_aware_object: self.assertEqual('george', context_aware_object(*args, **kwargs)) def test_register_exposed_context_aware_class(self): class George(object): def __init__(self, parse_context): self._parse_context = parse_context def honorific(self): return len(self._parse_context.rel_path) with self.do_test_exposed_context_aware_object(George) as context_aware_object: self.assertEqual(6, context_aware_object.honorific()) @contextmanager def do_test_exposed_context_aware_object(self, context_aware_object_factory): self._register_aliases(context_aware_object_factories={'george': context_aware_object_factory}) aliases = self.build_configuration.registered_aliases() self.assertEqual({}, aliases.target_types) self.assertEqual({}, aliases.target_macro_factories) self.assertEqual({}, aliases.objects) self.assertEqual(dict(george=context_aware_object_factory), aliases.context_aware_object_factories) with temporary_dir() as root: build_file_path = os.path.join(root, 'george', 'BUILD') touch(build_file_path) build_file = FilesystemBuildFile(root, 'george') parse_state = self.build_configuration.initialize_parse_state(build_file) self.assertEqual(0, len(parse_state.registered_addressable_instances)) self.assertEqual(1, len(parse_state.parse_globals)) yield parse_state.parse_globals['george']
class BuildConfigurationTest(unittest.TestCase): def setUp(self): self.build_configuration = BuildConfiguration() def test_register_target_alias(self): class Fred(Target): pass self.build_configuration._register_target_alias('fred', Fred) aliases = self.build_configuration.registered_aliases() self.assertEqual({}, aliases.objects) self.assertEqual({}, aliases.context_aware_object_factories) self.assertEqual(dict(fred=Fred), aliases.targets) build_file = FilesystemBuildFile('/tmp', 'fred', must_exist=False) parse_state = self.build_configuration.initialize_parse_state(build_file) self.assertEqual(0, len(parse_state.registered_addressable_instances)) self.assertEqual(1, len(parse_state.parse_globals)) target_call_proxy = parse_state.parse_globals['fred'] target_call_proxy(name='jake') self.assertEqual(1, len(parse_state.registered_addressable_instances)) name, target_proxy = parse_state.registered_addressable_instances.pop() self.assertEqual('jake', target_proxy.addressed_name) self.assertEqual(Fred, target_proxy.addressed_type) def test_register_bad_target_alias(self): with self.assertRaises(TypeError): self.build_configuration._register_target_alias('fred', object()) target = Target('fred', Address.parse('a:b'), BuildGraph(address_mapper=None)) with self.assertRaises(TypeError): self.build_configuration._register_target_alias('fred', target) def test_register_exposed_object(self): self.build_configuration._register_exposed_object('jane', 42) aliases = self.build_configuration.registered_aliases() self.assertEqual({}, aliases.targets) self.assertEqual({}, aliases.context_aware_object_factories) self.assertEqual(dict(jane=42), aliases.objects) build_file = FilesystemBuildFile('/tmp', 'jane', must_exist=False) parse_state = self.build_configuration.initialize_parse_state(build_file) self.assertEqual(0, len(parse_state.registered_addressable_instances)) self.assertEqual(1, len(parse_state.parse_globals)) self.assertEqual(42, parse_state.parse_globals['jane']) def test_register_bad_exposed_object(self): with self.assertRaises(TypeError): self.build_configuration._register_exposed_object('jane', Target) def test_register_exposed_context_aware_function(self): self.do_test_exposed_context_aware_function(lambda context: lambda: context.rel_path) self.do_test_exposed_context_aware_function(lambda context=None: lambda: context.rel_path) def george_method(self, parse_context): return lambda: parse_context.rel_path def test_register_exposed_context_aware_method(self): self.do_test_exposed_context_aware_function(self.george_method) @classmethod def george_classmethod(cls, parse_context): return lambda: parse_context.rel_path def test_register_exposed_context_aware_classmethod(self): self.do_test_exposed_context_aware_function(self.george_classmethod) @staticmethod def george_staticmethod(parse_context): return lambda: parse_context.rel_path def test_register_exposed_context_aware_staticmethod(self): self.do_test_exposed_context_aware_function(self.george_staticmethod) def do_test_exposed_context_aware_function(self, func, *args, **kwargs): with self.do_test_exposed_context_aware_object(func) as context_aware_object: self.assertEqual('george', context_aware_object(*args, **kwargs)) def test_register_exposed_context_aware_class(self): class George(object): def __init__(self, parse_context): self._parse_context = parse_context def honorific(self): return len(self._parse_context.rel_path) with self.do_test_exposed_context_aware_object(George) as context_aware_object: self.assertEqual(6, context_aware_object.honorific()) @contextmanager def do_test_exposed_context_aware_object(self, context_aware_object_factory): self.build_configuration._register_exposed_context_aware_object_factory( 'george', context_aware_object_factory) aliases = self.build_configuration.registered_aliases() self.assertEqual({}, aliases.targets) self.assertEqual({}, aliases.objects) self.assertEqual(dict(george=context_aware_object_factory), aliases.context_aware_object_factories) with temporary_dir() as root: build_file_path = os.path.join(root, 'george', 'BUILD') touch(build_file_path) build_file = FilesystemBuildFile(root, 'george') parse_state = self.build_configuration.initialize_parse_state(build_file) self.assertEqual(0, len(parse_state.registered_addressable_instances)) self.assertEqual(1, len(parse_state.parse_globals)) yield parse_state.parse_globals['george'] def test_register_bad_exposed_context_aware_object(self): with self.assertRaises(TypeError): self.build_configuration._register_exposed_context_aware_object_factory('george', 1)
class LoaderTest(unittest.TestCase): def setUp(self): self.build_configuration = BuildConfiguration() self.working_set = WorkingSet() for entry in working_set.entries: self.working_set.add_entry(entry) def tearDown(self): Goal.clear() @contextmanager def create_register(self, build_file_aliases=None, register_goals=None, global_subsystems=None, module_name='register'): package_name = b'__test_package_{0}'.format(uuid.uuid4().hex) self.assertFalse(package_name in sys.modules) package_module = types.ModuleType(package_name) sys.modules[package_name] = package_module try: register_module_fqn = b'{0}.{1}'.format(package_name, module_name) register_module = types.ModuleType(register_module_fqn) setattr(package_module, module_name, register_module) sys.modules[register_module_fqn] = register_module def register_entrypoint(function_name, function): if function: setattr(register_module, function_name, function) register_entrypoint('build_file_aliases', build_file_aliases) register_entrypoint('global_subsystems', global_subsystems) register_entrypoint('register_goals', register_goals) yield package_name finally: del sys.modules[package_name] def assert_empty_aliases(self): registered_aliases = self.build_configuration.registered_aliases() self.assertEqual(0, len(registered_aliases.targets)) self.assertEqual(0, len(registered_aliases.objects)) self.assertEqual( 0, len(registered_aliases.context_aware_object_factories)) self.assertEqual(self.build_configuration.subsystems(), set()) def test_load_valid_empty(self): with self.create_register() as backend_package: load_backend(self.build_configuration, backend_package) self.assert_empty_aliases() def test_load_valid_partial_aliases(self): aliases = BuildFileAliases.create(targets={'bob': DummyTarget}, objects={ 'obj1': DummyObject1, 'obj2': DummyObject2 }) with self.create_register( build_file_aliases=lambda: aliases) as backend_package: load_backend(self.build_configuration, backend_package) registered_aliases = self.build_configuration.registered_aliases() self.assertEqual(DummyTarget, registered_aliases.targets['bob']) self.assertEqual(DummyObject1, registered_aliases.objects['obj1']) self.assertEqual(DummyObject2, registered_aliases.objects['obj2']) self.assertEqual(self.build_configuration.subsystems(), set([DummySubsystem1, DummySubsystem2])) def test_load_valid_partial_goals(self): def register_goals(): Goal.by_name('jack').install(TaskRegistrar('jill', DummyTask)) with self.create_register( register_goals=register_goals) as backend_package: Goal.clear() self.assertEqual(0, len(Goal.all())) load_backend(self.build_configuration, backend_package) self.assert_empty_aliases() self.assertEqual(1, len(Goal.all())) task_names = Goal.by_name('jack').ordered_task_names() self.assertEqual(1, len(task_names)) task_name = task_names[0] self.assertEqual('jill', task_name) def test_load_invalid_entrypoint(self): def build_file_aliases(bad_arg): return BuildFileAliases.create() with self.create_register( build_file_aliases=build_file_aliases) as backend_package: with self.assertRaises(BuildConfigurationError): load_backend(self.build_configuration, backend_package) def test_load_invalid_module(self): with self.create_register(module_name='register2') as backend_package: with self.assertRaises(BuildConfigurationError): load_backend(self.build_configuration, backend_package) def test_load_missing_plugin(self): with self.assertRaises(PluginNotFound): self.load_plugins(['Foobar']) def get_mock_plugin(self, name, version, reg=None, alias=None, after=None): """Make a fake Distribution (optionally with entry points) Note the entry points do not actually point to code in the returned distribution -- the distribution does not even have a location and does not contain any code, just metadata. A module is synthesized on the fly and installed into sys.modules under a random name. If optional entry point callables are provided, those are added as methods to the module and their name (foo/bar/baz in fake module) is added as the requested entry point to the mocked metadata added to the returned dist. :param str name: project_name for distribution (see pkg_resources) :param str version: version for distribution (see pkg_resources) :param callable reg: Optional callable for goal registration entry point :param callable alias: Optional callable for build_file_aliases entry point :param callable after: Optional callable for load_after list entry point """ plugin_pkg = b'demoplugin{0}'.format(uuid.uuid4().hex) pkg = types.ModuleType(plugin_pkg) sys.modules[plugin_pkg] = pkg module_name = b'{0}.{1}'.format(plugin_pkg, 'demo') plugin = types.ModuleType(module_name) setattr(pkg, 'demo', plugin) sys.modules[module_name] = plugin metadata = {} entry_lines = [] if reg is not None: setattr(plugin, 'foo', reg) entry_lines.append('register_goals = {}:foo\n'.format(module_name)) if alias is not None: setattr(plugin, 'bar', alias) entry_lines.append( 'build_file_aliases = {}:bar\n'.format(module_name)) if after is not None: setattr(plugin, 'baz', after) entry_lines.append('load_after = {}:baz\n'.format(module_name)) if entry_lines: entry_data = '[pantsbuild.plugin]\n{}\n'.format( '\n'.join(entry_lines)) metadata = {'entry_points.txt': entry_data} return Distribution(project_name=name, version=version, metadata=MockMetadata(metadata)) def load_plugins(self, plugins): load_plugins(self.build_configuration, plugins, load_from=self.working_set) def test_plugin_load_and_order(self): d1 = self.get_mock_plugin('demo1', '0.0.1', after=lambda: ['demo2']) d2 = self.get_mock_plugin('demo2', '0.0.3') self.working_set.add(d1) # Attempting to load 'demo1' then 'demo2' should fail as 'demo1' requires 'after'=['demo2']. with self.assertRaises(PluginLoadOrderError): self.load_plugins(['demo1', 'demo2']) # Attempting to load 'demo2' first should fail as it is not (yet) installed. with self.assertRaises(PluginNotFound): self.load_plugins(['demo2', 'demo1']) # Installing demo2 and then loading in correct order should work though. self.working_set.add(d2) self.load_plugins(['demo2>=0.0.2', 'demo1']) # But asking for a bad (not installed) version fails. with self.assertRaises(VersionConflict): self.load_plugins(['demo2>=0.0.5']) def test_plugin_installs_goal(self): def reg_goal(): Goal.by_name('plugindemo').install(TaskRegistrar('foo', DummyTask)) self.working_set.add( self.get_mock_plugin('regdemo', '0.0.1', reg=reg_goal)) # Start without the custom goal. self.assertEqual(0, len(Goal.by_name('plugindemo').ordered_task_names())) # Load plugin which registers custom goal. self.load_plugins(['regdemo']) # Now the custom goal exists. self.assertEqual(1, len(Goal.by_name('plugindemo').ordered_task_names())) self.assertEqual('foo', Goal.by_name('plugindemo').ordered_task_names()[0]) def test_plugin_installs_alias(self): def reg_alias(): return BuildFileAliases.create( targets={'pluginalias': DummyTarget}, objects={ 'FROMPLUGIN1': DummyObject1, 'FROMPLUGIN2': DummyObject2 }) self.working_set.add( self.get_mock_plugin('aliasdemo', '0.0.1', alias=reg_alias)) # Start with no aliases. self.assert_empty_aliases() # Now load the plugin which defines aliases. self.load_plugins(['aliasdemo']) # Aliases now exist. registered_aliases = self.build_configuration.registered_aliases() self.assertEqual(DummyTarget, registered_aliases.targets['pluginalias']) self.assertEqual(DummyObject1, registered_aliases.objects['FROMPLUGIN1']) self.assertEqual(DummyObject2, registered_aliases.objects['FROMPLUGIN2']) self.assertEqual(self.build_configuration.subsystems(), {DummySubsystem1, DummySubsystem2}) def test_subsystems(self): def global_subsystems(): return {DummySubsystem1, DummySubsystem2} with self.create_register( global_subsystems=global_subsystems) as backend_package: load_backend(self.build_configuration, backend_package) self.assertEqual(self.build_configuration.subsystems(), {DummySubsystem1, DummySubsystem2})
class LoaderTest(unittest.TestCase): def setUp(self): self.build_configuration = BuildConfiguration() def tearDown(self): Goal.clear() @contextmanager def create_register( self, build_file_aliases=None, register_commands=None, register_goals=None, module_name="register" ): package_name = b"__test_package_{0}".format(uuid.uuid4().hex) self.assertFalse(package_name in sys.modules) package_module = types.ModuleType(package_name) sys.modules[package_name] = package_module try: register_module_fqn = b"{0}.{1}".format(package_name, module_name) register_module = types.ModuleType(register_module_fqn) setattr(package_module, module_name, register_module) sys.modules[register_module_fqn] = register_module def register_entrypoint(function_name, function): if function: setattr(register_module, function_name, function) register_entrypoint("build_file_aliases", build_file_aliases) register_entrypoint("register_commands", register_commands) register_entrypoint("register_goals", register_goals) yield package_name finally: del sys.modules[package_name] def assert_empty_aliases(self): registered_aliases = self.build_configuration.registered_aliases() self.assertEqual(0, len(registered_aliases.targets)) self.assertEqual(0, len(registered_aliases.objects)) self.assertEqual(0, len(registered_aliases.context_aware_object_factories)) def test_load_valid_empty(self): with self.create_register() as backend_package: load_backend(self.build_configuration, backend_package) self.assert_empty_aliases() def test_load_valid_partial_aliases(self): aliases = BuildFileAliases.create(targets={"bob": Target}, objects={"MEANING_OF_LIFE": 42}) with self.create_register(build_file_aliases=lambda: aliases) as backend_package: load_backend(self.build_configuration, backend_package) registered_aliases = self.build_configuration.registered_aliases() self.assertEqual(Target, registered_aliases.targets["bob"]) self.assertEqual(42, registered_aliases.objects["MEANING_OF_LIFE"]) def test_load_valid_partial_goals(self): def register_goals(): Goal.by_name("jack").install(TaskRegistrar("jill", lambda: 42)) with self.create_register(register_goals=register_goals) as backend_package: Goal.clear() self.assertEqual(0, len(Goal.all())) load_backend(self.build_configuration, backend_package) self.assert_empty_aliases() self.assertEqual(1, len(Goal.all())) task_names = Goal.by_name("jack").ordered_task_names() self.assertEqual(1, len(task_names)) task_name = task_names[0] self.assertEqual("jill", task_name) def test_load_invalid_entrypoint(self): def build_file_aliases(bad_arg): return BuildFileAliases.create() with self.create_register(build_file_aliases=build_file_aliases) as backend_package: with self.assertRaises(BuildConfigurationError): load_backend(self.build_configuration, backend_package) def test_load_invalid_module(self): with self.create_register(module_name="register2") as backend_package: with self.assertRaises(BuildConfigurationError): load_backend(self.build_configuration, backend_package)
class BuildConfigurationTest(unittest.TestCase): def setUp(self): self.build_configuration = BuildConfiguration() def test_register_target_alias(self): class Fred(Target): pass self.build_configuration.register_target_alias('fred', Fred) aliases = self.build_configuration.registered_aliases() self.assertEqual({}, aliases.objects) self.assertEqual({}, aliases.context_aware_object_factories) self.assertEqual(dict(fred=Fred), aliases.targets) build_file = FilesystemBuildFile('/tmp', 'fred', must_exist=False) parse_state = self.build_configuration.initialize_parse_state( build_file) self.assertEqual(0, len(parse_state.registered_addressable_instances)) self.assertEqual(1, len(parse_state.parse_globals)) target_call_proxy = parse_state.parse_globals['fred'] target_call_proxy(name='jake') self.assertEqual(1, len(parse_state.registered_addressable_instances)) name, target_proxy = parse_state.registered_addressable_instances.pop() self.assertEqual('jake', target_proxy.name) self.assertEqual(Fred, target_proxy.target_type) def test_register_bad_target_alias(self): with self.assertRaises(TypeError): self.build_configuration.register_target_alias('fred', object()) target = Target('fred', SyntheticAddress.parse('a:b'), BuildGraph(address_mapper=None)) with self.assertRaises(TypeError): self.build_configuration.register_target_alias('fred', target) def test_register_exposed_object(self): self.build_configuration.register_exposed_object('jane', 42) aliases = self.build_configuration.registered_aliases() self.assertEqual({}, aliases.targets) self.assertEqual({}, aliases.context_aware_object_factories) self.assertEqual(dict(jane=42), aliases.objects) build_file = FilesystemBuildFile('/tmp', 'jane', must_exist=False) parse_state = self.build_configuration.initialize_parse_state( build_file) self.assertEqual(0, len(parse_state.registered_addressable_instances)) self.assertEqual(1, len(parse_state.parse_globals)) self.assertEqual(42, parse_state.parse_globals['jane']) def test_register_bad_exposed_object(self): with self.assertRaises(TypeError): self.build_configuration.register_exposed_object('jane', Target) def test_register_exposed_context_aware_function(self): self.do_test_exposed_context_aware_function( lambda context: lambda: context.rel_path) self.do_test_exposed_context_aware_function( lambda context=None: lambda: context.rel_path) def george_method(self, parse_context): return lambda: parse_context.rel_path def test_register_exposed_context_aware_method(self): self.do_test_exposed_context_aware_function(self.george_method) @classmethod def george_classmethod(cls, parse_context): return lambda: parse_context.rel_path def test_register_exposed_context_aware_classmethod(self): self.do_test_exposed_context_aware_function(self.george_classmethod) @staticmethod def george_staticmethod(parse_context): return lambda: parse_context.rel_path def test_register_exposed_context_aware_staticmethod(self): self.do_test_exposed_context_aware_function(self.george_staticmethod) def do_test_exposed_context_aware_function(self, func, *args, **kwargs): with self.do_test_exposed_context_aware_object( func) as context_aware_object: self.assertEqual('george', context_aware_object(*args, **kwargs)) def test_register_exposed_context_aware_class(self): class George(object): def __init__(self, parse_context): self._parse_context = parse_context def honorific(self): return len(self._parse_context.rel_path) with self.do_test_exposed_context_aware_object( George) as context_aware_object: self.assertEqual(6, context_aware_object.honorific()) @contextmanager def do_test_exposed_context_aware_object(self, context_aware_object_factory): self.build_configuration.register_exposed_context_aware_object_factory( 'george', context_aware_object_factory) aliases = self.build_configuration.registered_aliases() self.assertEqual({}, aliases.targets) self.assertEqual({}, aliases.objects) self.assertEqual(dict(george=context_aware_object_factory), aliases.context_aware_object_factories) with temporary_dir() as root: build_file_path = os.path.join(root, 'george', 'BUILD') touch(build_file_path) build_file = FilesystemBuildFile(root, 'george') parse_state = self.build_configuration.initialize_parse_state( build_file) self.assertEqual(0, len(parse_state.registered_addressable_instances)) self.assertEqual(1, len(parse_state.parse_globals)) yield parse_state.parse_globals['george'] def test_register_bad_exposed_context_aware_object(self): with self.assertRaises(TypeError): self.build_configuration.register_exposed_context_aware_object_factory( 'george', 1)
class LoaderTest(unittest2.TestCase): def setUp(self): self.build_configuration = BuildConfiguration() def tearDown(self): Phase.clear() @contextmanager def create_register(self, build_file_aliases=None, register_commands=None, register_goals=None, module_name='register'): package_name = b'__test_package_{0}'.format(uuid.uuid4().hex) self.assertFalse(package_name in sys.modules) package_module = types.ModuleType(package_name) sys.modules[package_name] = package_module try: register_module_fqn = b'{0}.{1}'.format(package_name, module_name) register_module = types.ModuleType(register_module_fqn) setattr(package_module, module_name, register_module) sys.modules[register_module_fqn] = register_module def register_entrypoint(function_name, function): if function: setattr(register_module, function_name, function) register_entrypoint('build_file_aliases', build_file_aliases) register_entrypoint('register_commands', register_commands) register_entrypoint('register_goals', register_goals) yield package_name finally: del sys.modules[package_name] def assert_empty_aliases(self): registered_aliases = self.build_configuration.registered_aliases() self.assertEqual(0, len(registered_aliases.targets)) self.assertEqual(0, len(registered_aliases.objects)) self.assertEqual(0, len(registered_aliases.context_aware_object_factories)) def test_load_valid_empty(self): with self.create_register() as backend_package: load_backend(self.build_configuration, backend_package) self.assert_empty_aliases() def test_load_valid_partial_aliases(self): aliases = BuildFileAliases.create(targets={'bob': Target}, objects={'MEANING_OF_LIFE': 42}) with self.create_register(build_file_aliases=lambda: aliases) as backend_package: load_backend(self.build_configuration, backend_package) registered_aliases = self.build_configuration.registered_aliases() self.assertEqual(Target, registered_aliases.targets['bob']) self.assertEqual(42, registered_aliases.objects['MEANING_OF_LIFE']) def test_load_valid_partial_goals(self): def register_goals(): Phase('jack').install(Goal('jill', lambda: 42)) with self.create_register(register_goals=register_goals) as backend_package: Phase.clear() self.assertEqual(0, len(Phase.all())) load_backend(self.build_configuration, backend_package) self.assert_empty_aliases() self.assertEqual(1, len(Phase.all())) goals = Phase('jack').goals() self.assertEqual(1, len(goals)) goal = goals[0] self.assertEqual('jill', goal.name) def test_load_invalid_entrypoint(self): def build_file_aliases(bad_arg): return BuildFileAliases.create() with self.create_register(build_file_aliases=build_file_aliases) as backend_package: with self.assertRaises(BuildConfigurationError): load_backend(self.build_configuration, backend_package) def test_load_invalid_module(self): with self.create_register(module_name='register2') as backend_package: with self.assertRaises(BuildConfigurationError): load_backend(self.build_configuration, backend_package)
class LoaderTest(unittest.TestCase): def setUp(self): self.build_configuration = BuildConfiguration() def tearDown(self): Goal.clear() @contextmanager def create_register(self, build_file_aliases=None, register_commands=None, register_goals=None, module_name='register'): package_name = b'__test_package_{0}'.format(uuid.uuid4().hex) self.assertFalse(package_name in sys.modules) package_module = types.ModuleType(package_name) sys.modules[package_name] = package_module try: register_module_fqn = b'{0}.{1}'.format(package_name, module_name) register_module = types.ModuleType(register_module_fqn) setattr(package_module, module_name, register_module) sys.modules[register_module_fqn] = register_module def register_entrypoint(function_name, function): if function: setattr(register_module, function_name, function) register_entrypoint('build_file_aliases', build_file_aliases) register_entrypoint('register_commands', register_commands) register_entrypoint('register_goals', register_goals) yield package_name finally: del sys.modules[package_name] def assert_empty_aliases(self): registered_aliases = self.build_configuration.registered_aliases() self.assertEqual(0, len(registered_aliases.targets)) self.assertEqual(0, len(registered_aliases.objects)) self.assertEqual(0, len(registered_aliases.context_aware_object_factories)) def test_load_valid_empty(self): with self.create_register() as backend_package: load_backend(self.build_configuration, backend_package) self.assert_empty_aliases() def test_load_valid_partial_aliases(self): aliases = BuildFileAliases.create(targets={'bob': Target}, objects={'MEANING_OF_LIFE': 42}) with self.create_register(build_file_aliases=lambda: aliases) as backend_package: load_backend(self.build_configuration, backend_package) registered_aliases = self.build_configuration.registered_aliases() self.assertEqual(Target, registered_aliases.targets['bob']) self.assertEqual(42, registered_aliases.objects['MEANING_OF_LIFE']) def test_load_valid_partial_goals(self): def register_goals(): Goal.by_name('jack').install(TaskRegistrar('jill', lambda: 42)) with self.create_register(register_goals=register_goals) as backend_package: Goal.clear() self.assertEqual(0, len(Goal.all())) load_backend(self.build_configuration, backend_package) self.assert_empty_aliases() self.assertEqual(1, len(Goal.all())) task_names = Goal.by_name('jack').ordered_task_names() self.assertEqual(1, len(task_names)) task_name = task_names[0] self.assertEqual('jill', task_name) def test_load_invalid_entrypoint(self): def build_file_aliases(bad_arg): return BuildFileAliases.create() with self.create_register(build_file_aliases=build_file_aliases) as backend_package: with self.assertRaises(BuildConfigurationError): load_backend(self.build_configuration, backend_package) def test_load_invalid_module(self): with self.create_register(module_name='register2') as backend_package: with self.assertRaises(BuildConfigurationError): load_backend(self.build_configuration, backend_package)