예제 #1
0
def test_simple_map(monkeypatch, executor):

    flow_run_id = str(uuid.uuid4())
    task_run_id_1 = str(uuid.uuid4())

    with prefect.Flow(name="test") as flow:
        t1 = plus_one.map([0, 1, 2])

    client = MockedCloudClient(
        flow_runs=[FlowRun(id=flow_run_id)],
        task_runs=[
            TaskRun(id=task_run_id_1, task_id=t1.id, flow_run_id=flow_run_id)
        ] + [
            TaskRun(id=t.id, task_id=t.id, flow_run_id=flow_run_id)
            for t in flow.tasks if t is not t1
        ],
        monkeypatch=monkeypatch,
    )

    with prefect.context(flow_run_id=flow_run_id):
        state = CloudFlowRunner(flow=flow).run(return_tasks=flow.tasks,
                                               executor=executor)

    assert state.is_successful()
    assert client.flow_runs[flow_run_id].state.is_successful()
    assert client.task_runs[task_run_id_1].state.is_mapped()
    # there should be a total of 4 task runs corresponding to the mapped task
    assert len([tr for tr in client.task_runs.values()
                if tr.task_id == t1.id]) == 4
예제 #2
0
def test_starting_at_arbitrary_loop_index_from_cloud_context(client):
    @prefect.task
    def looper(x):
        if prefect.context.get("task_loop_count", 1) < 20:
            raise LOOP(result=prefect.context.get("task_loop_result", 0) + x)
        return prefect.context.get("task_loop_result", 0) + x

    @prefect.task
    def downstream(l):
        return l ** 2

    with prefect.Flow(name="looping") as f:
        inter = looper(10)
        final = downstream(inter)

    client.get_flow_run_info = MagicMock(
        return_value=MagicMock(context={"task_loop_count": 20})
    )
    client.set_flow_run_state = MagicMock()

    flow_state = CloudFlowRunner(flow=f).run(return_tasks=[inter, final])

    assert flow_state.is_successful()
    assert flow_state.result[inter].result == 10
    assert flow_state.result[final].result == 100
예제 #3
0
def test_task_failure_with_upstream_secrets_doesnt_store_secret_value_and_recompute_if_necessary(
    client, ):
    @prefect.task(max_retries=2, retry_delay=timedelta(minutes=100))
    def is_p_three(p):
        if p == 3:
            raise ValueError("No thank you.")
        return p

    with prefect.Flow("test", result=PrefectResult()) as f:
        p = prefect.tasks.secrets.PrefectSecret("p")
        res = is_p_three(p)

    with prefect.context(secrets=dict(p=3)):
        state = CloudFlowRunner(flow=f).run(return_tasks=[res])

    assert state.is_running()
    assert isinstance(state.result[res], Retrying)

    assert state.result[res].cached_inputs["p"].location is None

    ## here we set the result of the secret to an empty result, ensuring
    ## it will get converted to a "true" result;
    ## we expect that the upstream value will actually get recomputed from context
    ## through the SecretResultHandler
    safe = SecretResult(p)
    state.result[p] = Success(result=safe)
    state.result[res].start_time = pendulum.now("utc")
    state.result[res].cached_inputs = dict(p=safe)

    with prefect.context(secrets=dict(p=4)):
        new_state = CloudFlowRunner(flow=f).run(return_tasks=[res],
                                                task_states=state.result)

    assert new_state.is_successful()
    assert new_state.result[res].result == 4
예제 #4
0
def test_simple_two_task_flow(monkeypatch, executor):
    flow_run_id = str(uuid.uuid4())
    task_run_id_1 = str(uuid.uuid4())
    task_run_id_2 = str(uuid.uuid4())

    with prefect.Flow(name="test") as flow:
        t1 = prefect.Task()
        t2 = prefect.Task()
        t2.set_upstream(t1)

    client = MockedCloudClient(
        flow_runs=[FlowRun(id=flow_run_id)],
        task_runs=[
            TaskRun(id=task_run_id_1, task_id=t1.id, flow_run_id=flow_run_id),
            TaskRun(id=task_run_id_2, task_id=t2.id, flow_run_id=flow_run_id),
        ],
        monkeypatch=monkeypatch,
    )

    with prefect.context(flow_run_id=flow_run_id):
        state = CloudFlowRunner(flow=flow).run(return_tasks=flow.tasks,
                                               executor=executor)

    assert state.is_successful()
    assert client.flow_runs[flow_run_id].state.is_successful()
    assert client.task_runs[task_run_id_1].state.is_successful()
    assert client.task_runs[task_run_id_1].version == 2
    assert client.task_runs[task_run_id_2].state.is_successful()
예제 #5
0
def test_scheduled_start_time_is_in_context(monkeypatch, executor):
    flow_run_id = str(uuid.uuid4())
    task_run_id_1 = str(uuid.uuid4())

    flow = prefect.Flow(name="test", tasks=[whats_the_time])

    client = MockedCloudClient(
        flow_runs=[FlowRun(id=flow_run_id)],
        task_runs=[
            TaskRun(
                id=task_run_id_1, task_slug=whats_the_time.slug, flow_run_id=flow_run_id
            )
        ],
        monkeypatch=monkeypatch,
    )

    with prefect.context(flow_run_id=flow_run_id):
        state = CloudFlowRunner(flow=flow).run(
            return_tasks=flow.tasks, executor=executor
        )

    assert state.is_successful()
    assert client.flow_runs[flow_run_id].state.is_successful()
    assert client.task_runs[task_run_id_1].state.is_successful()
    assert isinstance(state.result[whats_the_time].result, datetime.datetime)
예제 #6
0
def test_deep_map(monkeypatch, executor):

    flow_run_id = str(uuid.uuid4())
    task_run_id_1 = str(uuid.uuid4())
    task_run_id_2 = str(uuid.uuid4())
    task_run_id_3 = str(uuid.uuid4())

    with prefect.Flow(name="test", result_handler=JSONResultHandler()) as flow:
        t1 = plus_one.map([0, 1, 2])
        t2 = plus_one.map(t1)
        t3 = plus_one.map(t2)

    client = MockedCloudClient(
        flow_runs=[FlowRun(id=flow_run_id)],
        task_runs=[
            TaskRun(
                id=task_run_id_1, task_slug=flow.slugs[t1], flow_run_id=flow_run_id
            ),
            TaskRun(
                id=task_run_id_2, task_slug=flow.slugs[t2], flow_run_id=flow_run_id
            ),
            TaskRun(
                id=task_run_id_3, task_slug=flow.slugs[t3], flow_run_id=flow_run_id
            ),
        ]
        + [
            TaskRun(
                id=str(uuid.uuid4()), task_slug=flow.slugs[t], flow_run_id=flow_run_id
            )
            for t in flow.tasks
            if t not in [t1, t2, t3]
        ],
        monkeypatch=monkeypatch,
    )

    with prefect.context(flow_run_id=flow_run_id):
        state = CloudFlowRunner(flow=flow).run(
            return_tasks=flow.tasks, executor=executor
        )

    assert state.is_successful()
    assert client.flow_runs[flow_run_id].state.is_successful()
    assert client.task_runs[task_run_id_1].state.is_mapped()
    assert client.task_runs[task_run_id_2].state.is_mapped()
    assert client.task_runs[task_run_id_3].state.is_mapped()

    # there should be a total of 4 task runs corresponding to each mapped task
    for t in [t1, t2, t3]:
        assert (
            len(
                [
                    tr
                    for tr in client.task_runs.values()
                    if tr.task_slug == flow.slugs[t]
                ]
            )
            == 4
        )
def test_flow_runner_puts_running_with_backend_in_context(client):
    @prefect.task()
    def whats_in_ctx():
        assert prefect.context.get("running_with_backend")

    flow = prefect.Flow(name="test", tasks=[whats_in_ctx])
    res = CloudFlowRunner(flow=flow).run()

    assert res.is_successful()
예제 #8
0
def test_can_queue_successfully_and_run(monkeypatch):
    @prefect.task
    def return_one():
        return 1

    with prefect.Flow("test-queues-work!") as flow:
        t1 = return_one()

    flow_run_id = str(uuid.uuid4())
    task_run_id_1 = str(uuid.uuid4())

    client = QueueingMockCloudClient(
        flow_runs=[FlowRun(id=flow_run_id)],
        task_runs=[
            TaskRun(
                id=task_run_id_1, task_slug=flow.slugs[t1], flow_run_id=flow_run_id
            ),
        ]
        + [
            TaskRun(
                id=str(uuid.uuid4()), task_slug=flow.slugs[t1], flow_run_id=flow_run_id
            )
            for t in flow.tasks
            if t
            not in [
                t1,
            ]
        ],
        monkeypatch=monkeypatch,
        num_times_in_queue=6,
    )

    with prefect.context(flow_run_id=flow_run_id):
        run_state = CloudFlowRunner(flow=flow).run(
            executor=LocalExecutor(), return_tasks=flow.tasks
        )

    assert run_state.is_successful()

    # Pending -> Running -> Queued (4x) -> Success
    # State transitions that result in `set_flow_run_state` calls are from
    # Pending -> Running and Running -> Success, all others
    # are from Running -> Queued or Queued -> Queued
    assert client.call_count["set_flow_run_state"] == 2 + (client.num_times_in_queue)
예제 #9
0
def test_flow_runner_retries_forever_on_queued_state(client, monkeypatch,
                                                     num_attempts):

    mock_sleep = MagicMock()
    monkeypatch.setattr("prefect.engine.cloud.flow_runner.time.sleep",
                        mock_sleep)

    run_states = [
        Queued(start_time=pendulum.now("UTC").add(seconds=i))
        for i in range(num_attempts - 1)
    ]
    run_states.append(Success())

    mock_run = MagicMock(side_effect=run_states)

    client.get_flow_run_info = MagicMock(
        side_effect=[MagicMock(version=i) for i in range(num_attempts)])

    # Mock out the actual flow execution
    monkeypatch.setattr("prefect.engine.cloud.flow_runner.FlowRunner.run",
                        mock_run)

    @prefect.task
    def return_one():
        return 1

    with prefect.Flow("test-cloud-flow-runner-with-queues") as flow:
        one = return_one()

    # Without these (actual, not mocked) sleep calls, when running full test suite this
    # test can fail for no reason.
    final_state = CloudFlowRunner(flow=flow).run()
    assert final_state.is_successful()

    assert mock_run.call_count == num_attempts
    # Not called on the initial run attempt
    assert client.get_flow_run_info.call_count == num_attempts - 1