예제 #1
0
def test_input_in_substate() -> None:
    @inputstep("Input Name", assignee=Assignee.SYSTEM)
    def input_action(state: State) -> FormGenerator:
        class SubForm(FormPage):
            a: int

        class TestForm(FormPage):
            sub: SubForm

        user_input = yield TestForm

        return user_input.dict()

    wf = workflow("Workflow with user interaction")(
        lambda: begin >> input_action >> purestep("process inputs")(Success))

    log: List[Tuple[str, Process]] = []
    pid = uuid4()
    p = ProcessStat(pid=pid,
                    workflow=wf,
                    state=Suspend({"sub": {
                        "a": 1,
                        "b": 2
                    }}),
                    log=wf.steps[1:],
                    current_user="******")
    result = runwf(p, logstep=store(log))

    assert_success(result)
    assert_state(result, {"sub": {"a": 1, "b": 2}})
예제 #2
0
def test_resume_suspended_workflow():
    wf = workflow("Workflow with user interaction")(
        lambda: begin >> step1 >> user_action >> step2)

    log = []

    p = ProcessStat(
        pid=1,
        workflow=wf,
        state=Suspend({
            "steps": [1],
            "name": "Jane Doe"
        }),
        log=wf.steps[1:],
        current_user="******",
    )
    result = runwf(p, logstep=store(log))

    assert_success(result)
    assert result == Success({"steps": [1, 2], "name": "Jane Doe"})
    assert [
        ("Input Name", Success({
            "steps": [1],
            "name": "Jane Doe"
        })),
        ("Step 2", Success({
            "steps": [1, 2],
            "name": "Jane Doe"
        })),
    ] == log
예제 #3
0
def start_process(
    workflow_key: str,
    user_inputs: Optional[List[State]] = None,
    user: str = SYSTEM_USER,
    broadcast_func: Optional[BroadcastFunc] = None,
) -> Tuple[UUID, Future]:
    """Start a process for workflow.

    Args:
        workflow_key: name of workflow
        user_inputs: List of form inputs from frontend
        user: User who starts this process
        broadcast_func: Optional function to broadcast process data

    Returns:
        process id

    """
    # ATTENTION!! When modifying this function make sure you make similar changes to `run_workflow` in the test code

    if user_inputs is None:
        user_inputs = [{}]

    pid = uuid4()
    workflow = get_workflow(workflow_key)

    if not workflow:
        raise_status(HTTPStatus.NOT_FOUND, "Workflow does not exist")

    initial_state = {
        "process_id": pid,
        "reporter": user,
        "workflow_name": workflow_key,
        "workflow_target": workflow.target,
    }

    try:
        state = post_process(workflow.initial_input_form, initial_state,
                             user_inputs)
    except FormValidationError:
        logger.exception("Validation errors", user_inputs=user_inputs)
        raise

    pstat = ProcessStat(pid,
                        workflow=workflow,
                        state=Success({
                            **state,
                            **initial_state
                        }),
                        log=workflow.steps,
                        current_user=user)

    _db_create_process(pstat)

    _safe_logstep_withfunc = partial(_safe_logstep,
                                     broadcast_func=broadcast_func)
    return _run_process_async(pstat.pid,
                              lambda: runwf(pstat, _safe_logstep_withfunc))
예제 #4
0
def test_recover():
    log = []

    p = ProcessStat(
        pid=1,
        workflow=sample_workflow,
        state=Success({"steps": [4]}),
        log=sample_workflow.steps[1:],
        current_user="******",
    )
    result = runwf(p, store(log))
    assert_success(result)
    assert_state(result, {"steps": [4, 2, 3]})
예제 #5
0
def load_process(process: ProcessTable) -> ProcessStat:
    workflow = get_workflow(process.workflow)

    if not workflow:
        workflow = removed_workflow

    log = _restore_log(process.steps)
    pstate, remaining = _recoverwf(workflow, log)

    return ProcessStat(pid=process.pid,
                       workflow=workflow,
                       state=pstate,
                       log=remaining,
                       current_user=SYSTEM_USER)
예제 #6
0
def test_abort_workflow():
    wf = workflow("Workflow with user interaction")(
        lambda: begin >> step1 >> user_action)

    log = []
    state = {"steps": [1]}
    pstat = ProcessStat(pid=1,
                        workflow=wf,
                        state=Success(state),
                        log=wf.steps[1:],
                        current_user="******")

    result = abort_wf(pstat, store(log))

    assert Abort({"steps": [1]}) == result
    assert log == [("User Aborted", Abort(state))]
예제 #7
0
def test_resume_waiting_workflow():
    hack = {"error": True}

    @retrystep("Waiting step")
    def soft_fail():
        if hack["error"]:
            raise ValueError("error")
        else:
            return {"some_key": True}

    wf = workflow("Workflow with soft fail")(
        lambda: begin >> step1 >> soft_fail >> step2)

    log = []

    state = Waiting({"steps": [1]})

    hack["error"] = False
    p = ProcessStat(pid=1,
                    workflow=wf,
                    state=state,
                    log=wf.steps[1:],
                    current_user="******")
    result = runwf(p, logstep=store(log))

    assert_success(result)
    assert [
        ("Waiting step", Success({
            "steps": [1],
            "some_key": True
        })),
        ("Step 2", Success({
            "steps": [1, 2],
            "some_key": True
        })),
    ] == log
예제 #8
0
def create_new_process_stat(workflow, initial_state):
    return ProcessStat(pid=str(uuid4()),
                       workflow=workflow,
                       state=Success(initial_state),
                       log=workflow.steps,
                       current_user=SYSTEM_USER)