class ReactorTest(unittest.TestCase): def setUp(self): self.old_reactor = Reactor.current_instance() self.plugin_loader_mock = Mock(PluginLoader) self.logger = Mock() self.execution_manager = Mock(ExecutionManager) self.reactor = Reactor(self.logger, self.execution_manager, self.plugin_loader_mock) def tearDown(self): Reactor._set_current_instance(self.old_reactor) def test_should_return_tasks_from_execution_manager_when_calling_get_tasks( self): self.execution_manager.tasks = ["spam"] self.assertEqual(["spam"], self.reactor.get_tasks()) def test_should_raise_exception_when_importing_plugin_and_plugin_not_found( self): self.plugin_loader_mock.load_plugin.side_effect = MissingPluginException( "not_found") self.assertRaises(MissingPluginException, self.reactor.import_plugin, PluginDef("not_found")) self.plugin_loader_mock.load_plugin.assert_called_with( ANY, PluginDef("not_found")) def test_should_collect_single_task(self): def task(): pass setattr(task, TASK_ATTRIBUTE, True) module = ModuleType("mock_module") module.task = task self.reactor.collect_project_annotations(module) self.assertEqual( len(self.execution_manager.register_task.call_args_list), 1) self.assertTrue( isinstance(self.execution_manager.register_task.call_args[0][0], Task) and len(self.execution_manager.register_task.call_args[0]) == 1) self.assertEqual( self.execution_manager.register_task.call_args[0][0].name, "task") def test_should_collect_single_task_with_overridden_name(self): def task(): pass setattr(task, TASK_ATTRIBUTE, True) setattr(task, NAME_ATTRIBUTE, "overridden_name") module = ModuleType("mock_module") module.task = task self.reactor.collect_project_annotations(module) self.assertEqual( len(self.execution_manager.register_task.call_args_list), 1) self.assertTrue( isinstance(self.execution_manager.register_task.call_args[0][0], Task) and len(self.execution_manager.register_task.call_args[0]) == 1) self.assertEqual( self.execution_manager.register_task.call_args[0][0].name, "overridden_name") def test_should_collect_multiple_tasks(self): def task(): pass setattr(task, TASK_ATTRIBUTE, True) def task2(): pass setattr(task2, TASK_ATTRIBUTE, True) module = ModuleType("mock_module") module.task = task module.task2 = task2 self.reactor.collect_project_annotations(module) self.assertEqual( len(self.execution_manager.register_task.call_args_list), 2) for call_args in self.execution_manager.register_task.call_args_list: self.assertTrue( isinstance(call_args[0][0], Task) and len(call_args[0]) == 1) def test_task_dependencies(self): import pybuilder.reactor with patch("pybuilder.reactor.Task"): @task def task1(): pass @task @depends(task1) def task2(): pass @task def task3(): pass @task @depends(optional(task3)) @dependents("task6") def task4(): pass @task @dependents("task6", optional(task3)) def task5(): pass @task @depends(task1, optional(task2)) def task6(): pass module = ModuleType("mock_module") module.task1 = task1 module.task2 = task2 module.task3 = task3 module.task4 = task4 module.task5 = task5 module.task6 = task6 self.reactor.collect_project_annotations(module) pybuilder.reactor.Task.assert_has_calls([ call("task1", task1, [], ''), call("task2", task2, [TaskDependency(task1)], ''), call("task3", task3, [TaskDependency(task5, True)], ''), call("task4", task4, [TaskDependency(task3, True)], ''), call("task5", task5, [], ''), call("task6", task6, [ TaskDependency(task1), TaskDependency(task2, True), TaskDependency(task4), TaskDependency(task5) ], '') ]) def test_task_dependencies_with_post_definition_injections(self): import pybuilder.reactor with patch("pybuilder.reactor.Task"): @task def task1(): pass @task @depends(task1) def task2(): pass @task @depends(task1) @dependents(task2) def task3(): pass module1 = ModuleType("mock_module_one") module1.task1 = task1 module1.task2 = task2 module2 = ModuleType("mock_module_two") module2.task3 = task3 self.reactor.collect_project_annotations(module1) pybuilder.reactor.Task.assert_has_calls([ call("task1", task1, [], ''), call("task2", task2, [TaskDependency(task1)], '') ]) self.reactor.collect_project_annotations(module2) pybuilder.reactor.Task.assert_has_calls( [call("task3", task3, [TaskDependency(task1)], '')]) self.execution_manager.register_late_task_dependencies.assert_has_calls( [call({}), call({"task2": [TaskDependency(task3)]})]) def test_task_dependencies_with_post_definition_injections_custom_names( self): import pybuilder.reactor with patch("pybuilder.reactor.Task"): @task def task1(): pass @task @depends(task1) def task2(): pass @task("task_3") @depends(task1) @dependents(task2) def task3(): pass module1 = ModuleType("mock_module_one") module1.task1 = task1 module1.task2 = task2 module2 = ModuleType("mock_module_two") module2.task3 = task3 self.reactor.collect_project_annotations(module1) pybuilder.reactor.Task.assert_has_calls([ call("task1", task1, [], ''), call("task2", task2, [TaskDependency(task1)], '') ]) self.reactor.collect_project_annotations(module2) pybuilder.reactor.Task.assert_has_calls( [call("task_3", task3, [TaskDependency(task1)], '')]) self.execution_manager.register_late_task_dependencies.assert_has_calls( [call({}), call({"task2": [TaskDependency("task_3")]})]) def test_should_collect_single_before_action(self): @before("spam") def action(): pass module = ModuleType("mock_module") module.task = action self.reactor.collect_project_annotations(module) self.assertEqual(self.execution_manager.register_action.call_count, 1) self.assertTrue( isinstance(self.execution_manager.register_action.call_args[0][0], Action) and len(self.execution_manager.register_action.call_args[0]) == 1) def test_should_collect_single_after_action(self): @after("spam") def action(): pass module = ModuleType("mock_module") module.task = action self.reactor.collect_project_annotations(module) self.assertEqual(self.execution_manager.register_action.call_count, 1) self.assertTrue( isinstance(self.execution_manager.register_action.call_args[0][0], Action) and len(self.execution_manager.register_action.call_args[0]) == 1) def test_should_collect_single_after_action_with_only_once_flag(self): @after("spam", only_once=True) def action(): pass module = ModuleType("mock_module") module.task = action def register_action(action): if not action.only_once: raise AssertionError("Action is not marked as only_once") self.execution_manager.register_action = register_action self.reactor.collect_project_annotations(module) def test_should_collect_single_after_action_with_teardown_flag(self): @after("spam", teardown=True) def action(): pass module = ModuleType("mock_module") module.task = action self.reactor.collect_project_annotations(module) def test_should_collect_single_initializer(self): def init(): pass setattr(init, INITIALIZER_ATTRIBUTE, True) module = ModuleType("mock_module") module.task = init self.reactor.collect_project_annotations(module) self.assertEqual( self.execution_manager.register_initializer.call_count, 1) self.assertTrue( isinstance( self.execution_manager.register_initializer.call_args[0][0], Initializer) and len(self.execution_manager.register_initializer.call_args[0]) == 1) def test_should_collect_single_initializer_with_environments(self): def init(): pass setattr(init, INITIALIZER_ATTRIBUTE, True) setattr(init, ENVIRONMENTS_ATTRIBUTE, ["any_environment"]) module = ModuleType("mock_module") module.task = init class ExecutionManagerMock(object): def register_initializer(self, initializer): self.initializer = initializer def register_late_task_dependencies(self, dependencies): pass execution_manager_mock = ExecutionManagerMock() self.reactor.execution_manager = execution_manager_mock self.reactor.collect_project_annotations(module) self.assertEqual(execution_manager_mock.initializer.environments, ["any_environment"]) @patch("pybuilder.reactor.os.path.exists", return_value=False) @patch("pybuilder.reactor.np", return_value="spam") def test_should_raise_when_verifying_project_directory_and_directory_does_not_exist( self, np, os_path_exists): self.assertRaises(PyBuilderException, self.reactor.verify_project_directory, "spam", "eggs") np.assert_called_with("spam") os_path_exists.assert_called_with("spam") @patch("pybuilder.reactor.os.path.isdir", return_value=False) @patch("pybuilder.reactor.os.path.exists", return_value=True) @patch("pybuilder.reactor.np", return_value="spam") def test_should_raise_when_verifying_project_directory_and_directory_is_not_a_directory( self, np, os_path_exists, os_path_isdir): self.assertRaises(PyBuilderException, self.reactor.verify_project_directory, "spam", "eggs") np.assert_called_with("spam") os_path_exists.assert_called_with("spam") os_path_isdir.assert_called_with("spam") @patch("pybuilder.reactor.jp", side_effect=lambda *x: "/".join(x)) @patch("pybuilder.reactor.os.path.isdir", return_value=True) @patch("pybuilder.reactor.os.path.exists", side_effect=lambda x: True if x == "spam" else False) @patch("pybuilder.reactor.np", return_value="spam") def test_should_raise_when_verifying_project_directory_and_build_descriptor_does_not_exist( self, np, os_path_exists, os_path_isdir, jp): self.assertRaises(PyBuilderException, self.reactor.verify_project_directory, "spam", "eggs") np.assert_called_with("spam") os_path_exists.assert_has_calls([call("spam"), call("spam/eggs")]) os_path_isdir.assert_called_with("spam") jp.assert_called_with("spam", "eggs") @patch("pybuilder.reactor.os.path.isfile", return_value=False) @patch("pybuilder.reactor.jp", side_effect=lambda *x: "/".join(x)) @patch("pybuilder.reactor.os.path.isdir", return_value=True) @patch("pybuilder.reactor.os.path.exists", return_value=True) @patch("pybuilder.reactor.np", return_value="spam") def test_should_raise_when_verifying_project_directory_and_build_descriptor_is_not_a_file( self, np, os_path_exists, os_path_isdir, jp, os_path_isfile): self.assertRaises(PyBuilderException, self.reactor.verify_project_directory, "spam", "eggs") np.assert_called_with("spam") os_path_exists.assert_has_calls([call("spam"), call("spam/eggs")]) os_path_isdir.assert_called_with("spam") jp.assert_called_with("spam", "eggs") os_path_isfile.assert_called_with("spam/eggs") @patch("pybuilder.reactor.os.path.isfile", return_value=True) @patch("pybuilder.reactor.jp", side_effect=lambda *x: "/".join(x)) @patch("pybuilder.reactor.os.path.isdir", return_value=True) @patch("pybuilder.reactor.os.path.exists", return_value=True) @patch("pybuilder.reactor.np", return_value="/spam") def test_should_return_directory_and_full_path_of_descriptor_when_verifying_project_directory( self, np, os_path_exists, os_path_isdir, jp, os_path_isfile): self.assertEqual(("/spam", "/spam/eggs"), self.reactor.verify_project_directory("spam", "eggs")) np.assert_called_with("spam") os_path_exists.assert_has_calls([call("/spam"), call("/spam/eggs")]) os_path_isdir.assert_called_with("/spam") jp.assert_called_with("/spam", "eggs") os_path_isfile.assert_called_with("/spam/eggs") @patch("pybuilder.reactor.imp.load_source", side_effect=ImportError("spam")) def test_should_raise_when_loading_project_module_and_import_raises_exception( self, imp_load_source): self.assertRaises(PyBuilderException, self.reactor.load_project_module, "spam") imp_load_source.assert_called_with("build", "spam") @patch("pybuilder.reactor.imp.load_source", return_value=Mock()) def test_should_return_module_when_loading_project_module_and_import_raises_exception( self, imp_load_source): self.assertTrue(imp_load_source.return_value is self.reactor.load_project_module("spam")) imp_load_source.assert_called_with("build", "spam") def test_ensure_project_attributes_are_set_when_instantiating_project( self): module = ModuleType("mock_module") module.version = "version" module.default_task = "default_task" module.summary = "summary" module.description = "description" module.author = "author" module.authors = "authors" module.maintainer = "maintainer" module.maintainers = "maintainers" module.license = "license" module.url = "url" module.urls = "urls" self.reactor.project = Mock() self.reactor.project_module = module self.reactor.apply_project_attributes() self.assertEqual("version", self.reactor.project.version) self.assertEqual("default_task", self.reactor.project.default_task) self.assertEqual("summary", self.reactor.project.summary) self.assertEqual("description", self.reactor.project.description) self.assertEqual("author", self.reactor.project.author) self.assertEqual("authors", self.reactor.project.authors) self.assertEqual("maintainer", self.reactor.project.maintainer) self.assertEqual("maintainers", self.reactor.project.maintainers) self.assertEqual("license", self.reactor.project.license) self.assertEqual("url", self.reactor.project.url) self.assertEqual("urls", self.reactor.project.urls) def test_ensure_project_name_is_set_from_attribute_when_instantiating_project( self): module = ModuleType("mock_module") module.name = "mock_module" self.reactor.project = Mock() self.reactor.project_module = module self.reactor.apply_project_attributes() self.assertEqual("mock_module", self.reactor.project.name) def test_should_import_plugin_only_once(self): plugin_module = ModuleType("mock_module") self.plugin_loader_mock.load_plugin.return_value = plugin_module self.reactor.require_plugin("spam") self.reactor.require_plugin("spam") self.reactor._load_deferred_plugins() self.assertEqual(["spam"], self.reactor.get_plugins()) self.plugin_loader_mock.load_plugin.assert_called_with( ANY, PluginDef("spam")) def test_ensure_project_properties_are_logged_when_calling_log_project_properties( self): project = Project("spam") project.set_property("spam", "spam") project.set_property("eggs", "eggs") self.reactor.project = project self.reactor.log_project_properties() call_args = self.logger.debug.call_args self.assertEqual(call_args[0][0], "Project properties: %s") self.assertTrue("basedir : %s" % project.basedir in call_args[0][1]) self.assertTrue("eggs : eggs" in call_args[0][1]) self.assertTrue("spam : spam" in call_args[0][1]) def test_should_raise_exception_when_project_is_not_valid(self): self.reactor.project = Mock(properties={}) self.reactor.project.validate.return_value = ["spam"] self.assertRaises(ProjectValidationFailedException, self.reactor.build) def test_prepare_tasks(self): self.reactor.project = Project("spam") self.reactor.project.default_task = ["a", "b"] self.assertEqual(self.reactor._prepare_tasks(["c"]), ["c"]) self.assertEqual(self.reactor._prepare_tasks(["+c"]), ["a", "b", "c"]) self.assertEqual(self.reactor._prepare_tasks(["+c", '^c']), ["a", "b"]) self.assertEqual(self.reactor._prepare_tasks(["^b"]), ["a"]) self.assertEqual(self.reactor._prepare_tasks(["^a"]), ["b"]) self.assertEqual(self.reactor._prepare_tasks(["^d"]), ["a", "b"]) self.assertEqual(self.reactor._prepare_tasks(["+c", "d"]), ["d", "c"]) self.assertEqual(self.reactor._prepare_tasks(["+c", "d", "^b"]), ["d", "c"]) self.assertEqual(self.reactor._prepare_tasks(["+c", "+", "^"]), ["+", "^", "c"]) self.assertEqual(self.reactor._prepare_tasks([]), ["a", "b"]) self.reactor.project.default_task = [] self.assertEqual(self.reactor._prepare_tasks(["c"]), ["c"]) self.assertEqual(self.reactor._prepare_tasks(["+c"]), ["c"]) self.assertEqual(self.reactor._prepare_tasks(["+c", "^d"]), ["c"]) self.assertEqual(self.reactor._prepare_tasks(["+c", "d", "^d"]), ["c"]) self.assertEqual(self.reactor._prepare_tasks(["^c", "c"]), []) self.assertEqual(self.reactor._prepare_tasks(["+c", "^c"]), []) self.assertEqual(self.reactor._prepare_tasks(["+c", "d"]), ["d", "c"]) self.assertEqual(self.reactor._prepare_tasks(["+c", "+"]), ["+", "c"]) self.assertRaises(PyBuilderException, self.reactor._prepare_tasks, [])