Exemple #1
0
    def test_find_step_by_name_not_first(self, mock_class):
        """ The _find_step_by_name method skips tasks that don't exist """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            "description": "Run two tasks",
            "steps": {
                1: {
                    "task": "pass_name"
                },
                2: {
                    "task": "name_response",
                    "options": {
                        "response": "^^pass_name.name"
                    },
                },
            },
        })

        flow = BaseFlow(self.project_config, flow_config, self.org_config)

        flow()

        task = flow._find_step_by_name("name_response")
        self.assertEquals(
            "cumulusci.core.tests.test_flows._TaskResponseName",
            task.task_config.class_path,
        )
Exemple #2
0
    def test_find_step_by_name_not_first(self, mock_class):
        """ The _find_step_by_name method skips tasks that don't exist """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            'description': 'Run two tasks',
            'steps': {
                1: {
                    'task': 'pass_name'
                },
                2: {
                    'task': 'name_response',
                    'options': {
                        'response': '^^pass_name.name'
                    }
                },
            }
        })

        flow = BaseFlow(
            self.project_config,
            flow_config,
            self.org_config,
        )

        flow()

        task = flow._find_step_by_name('name_response')
        self.assertEquals(
            'cumulusci.core.tests.test_flows._TaskResponseName',
            task.task_config.class_path,
        )
Exemple #3
0
    def test_render_task_config_empty_value(self, mock_class):
        """ The _render_task_config method skips option values of None """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            'description': 'Run a tasks',
            'steps': {
                1: {
                    'task': 'name_response',
                    'options': {
                        'response': None,
                    },
                },
            },
        })

        flow = BaseFlow(
            self.project_config,
            flow_config,
            self.org_config,
        )

        flow()

        task = flow._find_step_by_name('name_response')
        config = flow._render_task_config(task)
        self.assertEquals(['Options:'], config)
    def test_find_step_by_name_no_steps(self, mock_class):
        """ Running a flow with no steps throws an error """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({"description": "Run two tasks"})

        flow = BaseFlow(self.project_config, flow_config, self.org_config)
        self.assertIsNone(flow._find_step_by_name("task"))

        with self.assertRaises(FlowConfigError):
            flow()
Exemple #5
0
    def test_find_task_by_name_no_tasks(self, mock_class):
        """ The _find_task_by_name method skips tasks that don't exist """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            'description': 'Run two tasks',
        })

        flow = BaseFlow(
            self.project_config,
            flow_config,
            self.org_config,
        )

        self.assertEquals(None, flow._find_task_by_name('missing'))
Exemple #6
0
    def test_pass_around_values(self, mock_class):
        """ A flow's options reach into return values from other tasks. """

        mock_class.return_value = None
        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            'description': 'Run two tasks',
            'steps': {
                1: {
                    'task': 'pass_name'
                },
                2: {
                    'task': 'name_response',
                    'options': {
                        'response': '^^pass_name.name'
                    }
                },
            }
        })

        flow = BaseFlow(self.project_config, flow_config, self.org_config)

        # run the flow
        flow()
        # the flow results for the second task should be 'name'
        self.assertEquals('supername', flow.step_results[1])
Exemple #7
0
    def test_task_options(self, mock_class):
        """ A flow can accept task options and pass them to the task. """

        mock_class.return_value = None
        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            'description': 'Run two tasks',
            'steps': {
                1: {
                    'task': 'name_response',
                    'options': {
                        'response': 'foo'
                    }
                },
            }
        })

        flow = BaseFlow(
            self.project_config,
            flow_config,
            self.org_config,
            options={'name_response__response': 'bar'},
        )

        # run the flow
        flow()
        # the flow results for the first task should be 'bar'
        self.assertEquals('bar', flow.step_results[0])
Exemple #8
0
    def test_skip_task_value_none(self, mock_class):
        """ A flow skips any tasks whose name is None to allow override via yaml """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            'description': 'Run two tasks',
            'steps': {
                1: {
                    'task': 'pass_name'
                },
                2: {
                    'task': 'None'
                },
            }
        })

        flow = BaseFlow(
            self.project_config,
            flow_config,
            self.org_config,
            skip=['name_response'],
        )

        # run the flow
        flow()

        # the number of tasks in the flow should be 1 instead of 2
        self.assertEquals(1, len(flow.step_results))
Exemple #9
0
    def test_skip_kwarg(self, mock_class):
        """ A flow can receive during init a list of tasks to skip """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            'description': 'Run two tasks',
            'steps': {
                1: {
                    'task': 'pass_name'
                },
                2: {
                    'task': 'name_response',
                    'options': {
                        'response': '^^pass_name.name'
                    }
                },
            }
        })

        flow = BaseFlow(
            self.project_config,
            flow_config,
            self.org_config,
            skip=['name_response'],
        )

        # run the flow
        flow()

        # the number of tasks in the flow should be 1 instead of 2
        self.assertEquals(1, len(flow.step_results))
Exemple #10
0
    def test_skip_task_value_none(self, mock_class):
        """ A flow skips any tasks whose name is None to allow override via yaml """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            "description": "Run two tasks",
            "steps": {
                1: {
                    "task": "pass_name"
                },
                2: {
                    "task": "None"
                }
            },
        })

        flow = BaseFlow(self.project_config,
                        flow_config,
                        self.org_config,
                        skip=["name_response"])

        # run the flow
        flow()

        # the number of tasks in the flow should be 1 instead of 2
        self.assertEquals(1, len(flow.step_results))
Exemple #11
0
    def test_skip_kwarg(self, mock_class):
        """ A flow can receive during init a list of tasks to skip """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            "description": "Run two tasks",
            "steps": {
                1: {
                    "task": "pass_name"
                },
                2: {
                    "task": "name_response",
                    "options": {
                        "response": "^^pass_name.name"
                    },
                },
            },
        })

        flow = BaseFlow(self.project_config,
                        flow_config,
                        self.org_config,
                        skip=["name_response"])

        # run the flow
        flow()

        # the number of tasks in the flow should be 1 instead of 2
        self.assertEquals(1, len(flow.step_results))
Exemple #12
0
    def test_task_options(self, mock_class):
        """ A flow can accept task options and pass them to the task. """

        mock_class.return_value = None
        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            "description": "Run two tasks",
            "steps": {
                1: {
                    "task": "name_response",
                    "options": {
                        "response": "foo"
                    }
                }
            },
        })

        flow = BaseFlow(
            self.project_config,
            flow_config,
            self.org_config,
            options={"name_response__response": "bar"},
        )

        # run the flow
        flow()
        # the flow results for the first task should be 'bar'
        self.assertEquals("bar", flow.step_results[0])
Exemple #13
0
    def test_pass_around_values(self, mock_class):
        """ A flow's options reach into return values from other tasks. """

        mock_class.return_value = None
        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            "description": "Run two tasks",
            "steps": {
                1: {
                    "task": "pass_name"
                },
                2: {
                    "task": "name_response",
                    "options": {
                        "response": "^^pass_name.name"
                    },
                },
            },
        })

        flow = BaseFlow(self.project_config, flow_config, self.org_config)

        # run the flow
        flow()
        # the flow results for the second task should be 'name'
        self.assertEquals("supername", flow.step_results[1])
Exemple #14
0
    def test_init(self, mock_class):
        """ BaseFlow initializes and offers a logger """
        flow_config = FlowConfig({})
        mock_class.return_value = None
        flow = BaseFlow(self.project_config, flow_config, self.org_config)

        self.assertEquals(hasattr(flow, 'logger'), True)
 def test_call__not_prepped(self, mock_class):
     flow_config = FlowConfig({})
     flow = BaseFlow(self.project_config,
                     flow_config,
                     self.org_config,
                     prep=False)
     with self.assertRaises(FlowNotReadyError):
         flow()
Exemple #16
0
    def test_find_step_by_name_no_steps(self, mock_class):
        """ Running a flow with no steps throws an error """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({"description": "Run two tasks"})

        flow = BaseFlow(self.project_config, flow_config, self.org_config)
        flow()
Exemple #17
0
    def test_call_no_tasks(self, mock_class):
        """ A flow with no tasks will have no responses. """
        flow_config = FlowConfig({'description': 'Run no tasks', 'steps': {}})
        flow = BaseFlow(self.project_config, flow_config, self.org_config)
        flow()

        self.assertEqual([], flow.step_return_values)
        self.assertEqual([], flow.steps)
Exemple #18
0
def flow_run(config, flow_name, org, delete_org, debug, o, skip, no_prompt):
    # Check environment
    config.check_keychain()

    # Get necessary configs
    org, org_config = config.get_org(org)

    if delete_org and not org_config.scratch:
        raise click.UsageError(
            "--delete-org can only be used with a scratch org")

    flow_config = config.project_config.get_flow(flow_name)

    # Parse command line options and add to task config
    options = {}
    if o:
        for option in o:
            options[option[0]] = option[1]

    # Create the flow and handle initialization exceptions
    try:
        flow = BaseFlow(
            config.project_config,
            flow_config,
            org_config,
            options,
            skip,
            name=flow_name,
        )

        flow()
    except (TaskRequiresSalesforceOrg, TaskOptionsError) as e:
        exception = click.UsageError(e.message)
        handle_exception_debug(config, debug, throw_exception=exception)
    except (
            ApexTestException,
            BrowserTestFailure,
            MetadataComponentFailure,
            MetadataApiError,
            ScratchOrgException,
    ) as e:
        exception = click.ClickException("Failed: {}".format(
            e.__class__.__name__))
        handle_exception_debug(config, debug, throw_exception=exception)
    except Exception:
        handle_exception_debug(config, debug, no_prompt=no_prompt)

    # Delete the scratch org if --delete-org was set
    if delete_org:
        try:
            org_config.delete_org()
        except Exception as e:
            click.echo(
                "Scratch org deletion failed.  Ignoring the error below to complete the flow:"
            )
            click.echo(e.message)
Exemple #19
0
    def test_no_id_if_run_from_flow(self):
        """ A salesforce_task will not log the org id if run from a flow """

        task = _SfdcTask(self.project_config,
                         self.task_config,
                         self.org_config,
                         flow=BaseFlow(self.project_config, FlowConfig(),
                                       self.org_config))
        task()
        self.assertFalse(any(ORG_ID in s for s in self.task_log['info']))
 def test_rejects_flow_and_task_in_same_step(self, mock_class):
     flow_config = FlowConfig(
         {"steps": {
             1: {
                 "task": "pass_name",
                 "flow": "nested_flow"
             }
         }})
     with self.assertRaises(FlowConfigError):
         BaseFlow(self.project_config, flow_config, self.org_config)
    def test_no_id_if_run_from_flow(self, mock_class):
        """ A salesforce_task will not log the org id if run from a flow """

        mock_class.return_value = None
        task = _SfdcTask(
            self.project_config,
            self.task_config,
            self.org_config,
            flow=BaseFlow(self.project_config, FlowConfig(), self.org_config),
        )
        task()
        self.assertFalse(any(ORG_ID in s for s in self.task_log["info"]))
Exemple #22
0
    def test_task_raises_exception_fail(self, mock_class):
        """ A flow aborts when a task raises an exception """

        flow_config = FlowConfig({
            'description': 'Run a task',
            'steps': {
                1: {
                    'task': 'raise_exception'
                },
            }
        })
        flow = BaseFlow(self.project_config, flow_config, self.org_config)
        self.assertRaises(Exception, flow)
Exemple #23
0
    def test_task_raises_exception_fail(self, mock_class):
        """ A flow aborts when a task raises an exception """

        flow_config = FlowConfig({
            "description": "Run a task",
            "steps": {
                1: {
                    "task": "raise_exception"
                }
            }
        })
        flow = BaseFlow(self.project_config, flow_config, self.org_config)
        self.assertRaises(Exception, flow)
Exemple #24
0
    def test_render_task_config_empty_value(self, mock_class):
        """ The _render_task_config method skips option values of None """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            "description": "Run a tasks",
            "steps": {
                1: {
                    "task": "name_response",
                    "options": {
                        "response": None
                    }
                }
            },
        })

        flow = BaseFlow(self.project_config, flow_config, self.org_config)

        flow()

        task = flow._find_step_by_name("name_response")
        config = flow._render_task_config(task)
        self.assertEquals(["Options:"], config)
    def test_find_step_by_name__flow(self, mock_class):
        flow_config = FlowConfig({
            "description": "Run two tasks",
            "steps": {
                1: {
                    "flow": "nested_flow"
                },
                2: {
                    "task": "name_response",
                    "options": {
                        "response": "^^nested_flow.pass_name.name",
                        "from_flow": "^^nested_flow.name",
                    },
                },
            },
        })

        flow = BaseFlow(self.project_config, flow_config, self.org_config)

        flow()

        step = flow._find_step_by_name("nested_flow")
        self.assertIsInstance(step, BaseFlow)
 def test_check_infinite_flows(self, mock_class):
     self.project_config.config["flows"] = {
         "nested_flow": {
             "description": "A flow that runs inside another flow",
             "steps": {
                 1: {
                     "flow": "nested_flow"
                 }
             },
         }
     }
     flow_config = FlowConfig({"steps": {1: {"flow": "nested_flow"}}})
     with self.assertRaises(FlowInfiniteLoopError):
         BaseFlow(self.project_config, flow_config, self.org_config)
Exemple #27
0
def flow_run(config, flow_name, org, delete_org, debug, o, skip, no_prompt):

    # Get necessary configs
    org, org_config = config.get_org(org)

    if delete_org and not org_config.scratch:
        raise click.UsageError(
            "--delete-org can only be used with a scratch org")

    flow_config = config.project_config.get_flow(flow_name)

    # Parse command line options and add to task config
    options = {}
    if o:
        for option in o:
            options[option[0]] = option[1]

    # Create the flow and handle initialization exceptions
    try:
        flow = BaseFlow(
            config.project_config,
            flow_config,
            org_config,
            options,
            skip,
            name=flow_name,
        )

        flow()
    except CumulusCIUsageError as e:
        exception = click.UsageError(str(e))
        handle_exception_debug(config, debug, throw_exception=exception)
    except (CumulusCIFailure, ScratchOrgException) as e:
        exception = click.ClickException("Failed: {}".format(
            e.__class__.__name__))
        handle_exception_debug(config, debug, throw_exception=exception)
    except Exception:
        handle_exception_debug(config, debug, no_prompt=no_prompt)

    # Delete the scratch org if --delete-org was set
    if delete_org:
        try:
            org_config.delete_org()
        except Exception as e:
            click.echo(
                "Scratch org deletion failed.  Ignoring the error below to complete the flow:"
            )
            click.echo(str(e))

    config.alert("Flow Complete: {}".format(flow_name))
Exemple #28
0
    def test_call_task_not_found(self, mock_class):
        """ A flow with reference to a task that doesn't exist in the
        project will throw a TaskNotFoundError """

        flow_config = FlowConfig({
            'description': 'Run two tasks',
            'steps': {
                1: {
                    'task': 'pass_name'
                },
                2: {
                    'task': 'do_delightulthings'
                },
            }
        })
        flow = BaseFlow(self.project_config, flow_config, self.org_config)
Exemple #29
0
    def test_call_task_not_found(self, mock_class):
        """ A flow with reference to a task that doesn't exist in the
        project will throw a TaskNotFoundError """

        flow_config = FlowConfig({
            "description": "Run two tasks",
            "steps": {
                1: {
                    "task": "pass_name"
                },
                2: {
                    "task": "do_delightulthings"
                }
            },
        })
        flow = BaseFlow(self.project_config, flow_config, self.org_config)
 def test_nested_flow_options(self, mock_class):
     flow_config = FlowConfig({
         "description": "Run a flow with task options",
         "steps": {
             1: {
                 "flow": "nested_flow",
                 "options": {
                     "pass_name": {
                         "foo": "bar"
                     }
                 }
             }
         },
     })
     flow = BaseFlow(self.project_config, flow_config, self.org_config)
     flow()
     self.assertEqual("bar", flow.steps[0].options["pass_name__foo"])