def test_flow_run_org_delete_error(self, echo): org_config = mock.Mock(scratch=True, config={}) org_config.delete_org.side_effect = Exception config = CliRuntime( config={ "flows": {"test": {"steps": {1: {"task": "test_task"}}}}, "tasks": { "test_task": { "class_path": "cumulusci.cli.tests.test_cci.DummyTask", "description": "Test Task", } }, }, load_keychain=False, ) config.get_org = mock.Mock(return_value=("test", org_config)) DummyTask._run_task = mock.Mock() run_click_command( cci.flow_run, config=config, flow_name="test", org="test", delete_org=True, debug=False, o=None, skip=(), no_prompt=True, ) echo.assert_any_call( "Scratch org deletion failed. Ignoring the error below to complete the flow:" )
def test_get_org_missing(self): config = CliRuntime() config.keychain = mock.Mock() config.keychain.get_org.return_value = None with self.assertRaises(click.UsageError): org_name, org_config_result = config.get_org("test", fail_if_missing=True)
def test_alert_linux(self, echo_mock, shell_mock): config = CliRuntime() config.alert("hello") echo_mock.assert_called_once() shell_mock.assert_called_once() self.assertIn("notify-send", shell_mock.call_args[0][0])
def test_flow_run_expected_failure(self): org_config = mock.Mock(config={}) config = CliRuntime( config={ "flows": {"test": {"steps": {1: {"task": "test_task"}}}}, "tasks": { "test_task": { "class_path": "cumulusci.cli.tests.test_cci.DummyTask", "description": "Test Task", } }, }, load_keychain=False, ) config.get_org = mock.Mock(return_value=("test", org_config)) DummyTask._run_task = mock.Mock(side_effect=ScratchOrgException("msg")) with self.assertRaises(click.ClickException) as e: run_click_command( cci.flow_run, config=config, flow_name="test", org="test", delete_org=False, debug=False, o=None, skip=(), no_prompt=True, ) assert "msg" in str(e)
def test_flow_run_usage_error(self): org_config = mock.Mock(config={}) config = CliRuntime( config={ "flows": {"test": {"steps": {1: {"task": "test_task"}}}}, "tasks": { "test_task": { "class_path": "cumulusci.cli.tests.test_cci.DummyTask", "description": "Test Task", } }, }, load_keychain=False, ) config.get_org = mock.Mock(return_value=("test", org_config)) DummyTask._run_task = mock.Mock(side_effect=TaskOptionsError) with self.assertRaises(click.UsageError): run_click_command( cci.flow_run, config=config, flow_name="test", org="test", delete_org=False, debug=False, o=None, skip=(), no_prompt=True, )
def test_flow_run_unexpected_exception(self, handle_sentry_event): org_config = mock.Mock(config={}) config = CliRuntime( config={ "flows": {"test": {"steps": {1: {"task": "test_task"}}}}, "tasks": { "test_task": { "class_path": "cumulusci.cli.tests.test_cci.DummyTask", "description": "Test Task", } }, }, load_keychain=False, ) config.get_org = mock.Mock(return_value=("test", org_config)) DummyTask._run_task = mock.Mock(side_effect=Exception) with self.assertRaises(Exception): run_click_command( cci.flow_run, config=config, flow_name="test", org="test", delete_org=False, debug=False, o=None, skip=(), no_prompt=True, ) handle_sentry_event.assert_called_once()
def test_check_org_overwrite_non_scratch_exists(self): config = CliRuntime() config.keychain.get_org = mock.Mock( return_value=OrgConfig({"scratch": False}, "test")) with self.assertRaises(click.ClickException): config.check_org_overwrite("test")
def test_flow_run(self): org_config = mock.Mock(scratch=True, config={}) config = CliRuntime( config={ "flows": {"test": {"steps": {1: {"task": "test_task"}}}}, "tasks": { "test_task": { "class_path": "cumulusci.cli.tests.test_cci.DummyTask", "description": "Test Task", } }, }, load_keychain=False, ) config.get_org = mock.Mock(return_value=("test", org_config)) config.get_flow = mock.Mock() run_click_command( cci.flow_run, config=config, flow_name="test", org="test", delete_org=True, debug=False, o=[("test_task__color", "blue")], skip=(), no_prompt=True, ) config.get_flow.assert_called_once_with( "test", options={"test_task": {"color": "blue"}} ) org_config.delete_org.assert_called_once()
def test_alert__disabled(self, echo_mock, shell_mock): config = CliRuntime() config.project_config.dev_config__no_alert = True config.alert("hello") echo_mock.assert_not_called() shell_mock.assert_not_called()
def test_alert_osx(self, echo_mock, shell_mock): config = CliRuntime() config.alert("hello") echo_mock.assert_called_once() shell_mock.assert_called_once() self.assertIn("osascript", shell_mock.call_args[0][0])
def test_get_org(self): config = CliRuntime() config.keychain = mock.Mock() config.keychain.get_org.return_value = org_config = OrgConfig({}, "test") org_name, org_config_result = config.get_org("test") self.assertEqual("test", org_name) self.assertIs(org_config, org_config_result)
def test_check_org_expired(self, confirm): config = CliRuntime() config.keychain = mock.Mock() org_config = OrgConfig( { "scratch": True, "date_created": date.today() - timedelta(days=2), "expired": True, }, "test", ) confirm.return_value = True config.check_org_expired("test", org_config) config.keychain.create_scratch_org.assert_called_once()
def test_check_org_expired_decline(self, confirm): config = CliRuntime() config.keychain = mock.Mock() org_config = OrgConfig( { "scratch": True, "date_created": date.today() - timedelta(days=2), "expired": True, }, "test", ) confirm.return_value = False with self.assertRaises(click.ClickException): config.check_org_expired("test", org_config)
def test_get_keychain_key__warns_if_generated_key_cannot_be_stored( self, keyring): del os.environ["CUMULUSCI_KEY"] keyring.get_password.side_effect = Exception with self.assertRaises(click.UsageError): CliRuntime()
def test_get_keychain_key__generates_key(self, keyring): del os.environ["CUMULUSCI_KEY"] keyring.get_password.return_value = None config = CliRuntime() self.assertNotEqual(self.key, config.keychain.key) self.assertEqual(16, len(config.keychain.key))
def test_get_keychain_key__migrates_from_env_to_keyring(self, keyring): keyring.get_password.return_value = None config = CliRuntime() self.assertEqual(self.key, config.keychain.key) keyring.set_password.assert_called_once_with("cumulusci", "CUMULUSCI_KEY", self.key)
def project_config(self): if self._project_config is None: if CURRENT_TASK.stack and isinstance(CURRENT_TASK.stack[0], Robot): # If CumulusCI is running a task, use that task's config return CURRENT_TASK.stack[0].project_config else: logger.console("Initializing CumulusCI config\n") self._project_config = CliRuntime().project_config return self._project_config
def test_init(self): config = CliRuntime() for key in {"cumulusci", "tasks", "flows", "services", "orgs", "project"}: self.assertIn(key, config.global_config.config) self.assertEqual("CumulusCI", config.project_config.project__name) for key in {"services", "orgs", "app"}: self.assertIn(key, config.keychain.config) self.assertIn(config.project_config.repo_root, sys.path)
def load_config(load_project_config=True, load_keychain=True, allow_global_keychain=False): try: config = TEST_CONFIG or CliRuntime( load_project_config=load_project_config, load_keychain=load_keychain, allow_global_keychain=allow_global_keychain, ) config.check_cumulusci_version() except click.UsageError as e: click.echo(str(e)) sys.exit(1) return config
def test_project_init_tasks(self, click): """Verify that the generated cumulusci.yml file is readable and has the proper robot task""" with temporary_dir(): os.mkdir(".git") click.prompt.side_effect = ( "testproj", # project_name "testpkg", # package_name "testns", # package_namespace "43.0", # api_version "mdapi", # source_format "3", # extend other URL "https://github.com/SalesforceFoundation/Cumulus", # github_url "default", # git_default_branch "work/", # git_prefix_feature "uat/", # git_prefix_beta "rel/", # git_prefix_release "%_TEST%", # test_name_match ) click.confirm.side_effect = (True, True ) # is managed? # extending? run_click_command(cci.project_init) # verify we can load the generated yml cli_runtime = CliRuntime(load_keychain=False) # ...and verify it has the expected tasks config = cli_runtime.project_config.config_project expected_tasks = { "robot": { "options": { "suites": u"robot/testproj/tests", "options": { "outputdir": "robot/testproj/results" }, } }, "robot_testdoc": { "options": { "path": "robot/testproj/tests", "output": "robot/testproj/doc/testproj_tests.html", } }, } self.assertDictEqual(config["tasks"], expected_tasks)
def test_alert__os_error(self, echo_mock, shell_mock): shell_mock.side_effect = OSError config = CliRuntime() config.alert("hello") echo_mock.assert_called_once() shell_mock.assert_called_once()
def test_check_org_overwrite_not_found(self): config = CliRuntime() config.keychain.get_org = mock.Mock(side_effect=OrgNotFound) self.assertTrue(config.check_org_overwrite("test"))
def test_check_cumulusci_version(self): config = CliRuntime() config.project_config.minimum_cumulusci_version = "999" with self.assertRaises(click.UsageError): config.check_cumulusci_version()
def test_load_project_config_no_file(self, load_proj_cfg_mock): load_proj_cfg_mock.side_effect = ProjectConfigNotFound with self.assertRaises(click.UsageError): CliRuntime()
def test_load_project_config_error(self, load_proj_cfg_mock): load_proj_cfg_mock.side_effect = ConfigError with self.assertRaises(click.UsageError): CliRuntime()
def test_get_keychain_key__env_takes_precedence(self, keyring): keyring.get_password.return_value = "overridden" config = CliRuntime() self.assertEqual(self.key, config.keychain.key)
def get_github_user(): keychain_class = CliRuntime().get_keychain_class() keychain = keychain_class(CliRuntime().project_config, CliRuntime().get_keychain_key()) github_config = keychain.get_service("github") return github_config.username, github_config.password
def test_load_project_not_in_project(self, load_proj_cfg_mock): load_proj_cfg_mock.side_effect = NotInProject with self.assertRaises(click.UsageError): CliRuntime()