Esempio n. 1
0
def test_ignores_cancelled_jobs_when_calculating_dependencies(db):
    job_factory(
        id="1",
        action="other-action",
        state=State.SUCCEEDED,
        created_at=1000,
        outputs={"output-from-completed-run": "highly_sensitive_output"},
    )
    job_factory(
        id="2",
        action="other-action",
        state=State.SUCCEEDED,
        created_at=2000,
        cancelled=True,
        outputs={"output-from-cancelled-run": "highly_sensitive_output"},
    )

    api = RecordingExecutor(JobStatus(ExecutorState.UNKNOWN),
                            JobStatus(ExecutorState.PREPARING))
    run.handle_job(
        job_factory(id="3",
                    requires_outputs_from=["other-action"],
                    state=State.PENDING),
        api,
    )

    assert api.job.inputs == ["output-from-completed-run"]
Esempio n. 2
0
def test_handle_job_finalized_success_with_delete(db):
    api = StubExecutorAPI()

    # insert previous outputs
    job_factory(
        state=State.SUCCEEDED,
        outputs={"output/old.csv": "medium"},
    )

    job = api.add_test_job(ExecutorState.FINALIZED, State.RUNNING)
    api.set_job_result(job, outputs={"output/file.csv": "medium"})

    run.handle_job(job, api)

    # executor state
    assert job.id in api.tracker["cleanup"]
    # its been cleaned up and is now unknown
    assert api.get_status(job).state == ExecutorState.UNKNOWN

    # our state
    assert job.state == State.SUCCEEDED
    assert job.status_message == "Completed successfully"
    assert job.outputs == {"output/file.csv": "medium"}
    assert api.deleted["workspace"][Privacy.MEDIUM] == ["output/old.csv"]
    assert api.deleted["workspace"][Privacy.HIGH] == ["output/old.csv"]
Esempio n. 3
0
def test_handle_job_finalized_failed_exit_code(exit_code, run_command,
                                               extra_message, db,
                                               backend_db_config):
    api = StubExecutorAPI()
    job = api.add_test_job(
        ExecutorState.FINALIZED,
        State.RUNNING,
        run_command=run_command,
    )
    api.set_job_result(job,
                       outputs={"output/file.csv": "medium"},
                       exit_code=exit_code,
                       message=None)

    run.handle_job(job, api)

    # executor state
    assert job.id in api.tracker["cleanup"]
    # its been cleaned up and is now unknown
    assert api.get_status(job).state == ExecutorState.UNKNOWN

    # our state
    assert job.state == State.FAILED
    assert job.status_code == StatusCode.NONZERO_EXIT
    expected = f"Job exited with error code {exit_code}"
    if extra_message:
        expected += f": {extra_message}"
    assert job.status_message == expected
    assert job.outputs == {"output/file.csv": "medium"}
Esempio n. 4
0
def test_bad_transition(current, invalid, db):
    api = StubExecutorAPI()
    job = api.add_test_job(
        current,
        State.PENDING if current == ExecutorState.UNKNOWN else State.RUNNING,
    )
    # this will cause any call to prepare/execute/finalize to return that state
    api.set_job_transition(job, invalid)

    with pytest.raises(run.InvalidTransition):
        run.handle_job(job, api)
Esempio n. 5
0
def test_handle_job_waiting_on_workers(exec_state, job_state, tracker, db):
    api = StubExecutorAPI()
    job = api.add_test_job(exec_state, job_state)
    api.set_job_transition(job, exec_state)

    run.handle_job(job, api)

    assert job.id in api.tracker[tracker]
    assert api.get_status(job).state == exec_state

    assert job.state == job_state
    assert job.status_message == "Waiting on available resources"
    assert job.status_code == StatusCode.WAITING_ON_WORKERS
Esempio n. 6
0
def test_handle_job_executed_to_finalizing(db):
    api = StubExecutorAPI()
    job = api.add_test_job(ExecutorState.EXECUTED, State.RUNNING)

    run.handle_job(job, api)

    # executor state
    assert job.id in api.tracker["finalize"]
    assert api.get_status(job).state == ExecutorState.FINALIZING

    # our state
    assert job.state == State.RUNNING
    assert job.status_message == "Finalizing"
Esempio n. 7
0
def test_handle_job_prepared_to_executing(db):
    api = StubExecutorAPI()
    job = api.add_test_job(ExecutorState.PREPARED, State.RUNNING)

    run.handle_job(job, api)

    # executor state
    assert job.id in api.tracker["execute"]
    assert api.get_status(job).state == ExecutorState.EXECUTING

    # our state
    assert job.state == State.RUNNING
    assert job.status_message == "Executing"
Esempio n. 8
0
def test_handle_job_pending_to_preparing(db):
    api = StubExecutorAPI()
    job = api.add_test_job(ExecutorState.UNKNOWN, State.PENDING)

    run.handle_job(job, api)

    # executor state
    assert job.id in api.tracker["prepare"]
    assert api.get_status(job).state == ExecutorState.PREPARING

    # our state
    assert job.status_message == "Preparing"
    assert job.state == State.RUNNING
    assert job.started_at
Esempio n. 9
0
def test_handle_job_stable_states(state, message, db):
    api = StubExecutorAPI()
    job = api.add_test_job(state, State.RUNNING)

    run.handle_job(job, api)

    # executor state
    assert job.id not in api.tracker["prepare"]
    assert job.id not in api.tracker["execute"]
    assert job.id not in api.tracker["finalize"]
    assert api.get_status(job).state == state

    # our state
    assert job.state == State.RUNNING
    assert job.status_message == message
Esempio n. 10
0
def test_handle_running_pause_mode(db, backend_db_config):
    api = StubExecutorAPI()
    job = api.add_test_job(
        ExecutorState.EXECUTING,
        State.RUNNING,
        run_command="cohortextractor:latest generate_cohort",
    )

    run.handle_job(job, api, paused=True)

    # check we did nothing
    # executor state
    assert api.get_status(job).state == ExecutorState.EXECUTING
    # our state
    assert job.state == State.RUNNING
    assert "paused" not in job.status_message
Esempio n. 11
0
def test_handle_pending_pause_mode(db, backend_db_config):
    api = StubExecutorAPI()
    job = api.add_test_job(
        ExecutorState.UNKNOWN,
        State.PENDING,
        run_command="cohortextractor:latest generate_cohort",
    )

    run.handle_job(job, api, paused=True)

    # executor state
    assert api.get_status(job).state == ExecutorState.UNKNOWN
    # our state
    assert job.state == State.PENDING
    assert job.started_at is None
    assert "paused" in job.status_message
Esempio n. 12
0
def test_handle_pending_db_maintenance_mode(db, backend_db_config):
    api = StubExecutorAPI()
    job = api.add_test_job(
        ExecutorState.UNKNOWN,
        State.PENDING,
        run_command="cohortextractor:latest generate_cohort",
    )

    run.handle_job(job, api, mode="db-maintenance")

    # executor state
    assert api.get_status(job).state == ExecutorState.UNKNOWN
    # our state
    assert job.state == State.PENDING
    assert job.status_message == "Waiting for database to finish maintenance"
    assert job.started_at is None
Esempio n. 13
0
def test_handle_pending_job_cancelled(db):
    api = StubExecutorAPI()
    job = api.add_test_job(ExecutorState.UNKNOWN,
                           State.PENDING,
                           cancelled=True)

    run.handle_job(job, api)

    # executor state
    assert job.id in api.tracker["terminate"]
    assert job.id in api.tracker["cleanup"]
    assert api.get_status(job).state == ExecutorState.UNKNOWN

    # our state
    assert job.state == State.FAILED
    assert job.status_message == "Cancelled by user"
    assert job.status_code == StatusCode.CANCELLED_BY_USER
Esempio n. 14
0
def test_handle_job_initial_error(db):
    api = StubExecutorAPI()
    job = api.add_test_job(ExecutorState.ERROR,
                           State.RUNNING,
                           message="broken")

    run.handle_job(job, api)

    # executor state
    assert job.id in api.tracker["cleanup"]
    # its been cleaned up and is now unknown
    assert api.get_status(job).state == ExecutorState.UNKNOWN

    # our state
    assert job.state == State.FAILED
    assert job.status_message == "broken"
    assert job.status_code is None
Esempio n. 15
0
def test_handle_job_pending_to_error(db):
    api = StubExecutorAPI()

    job = api.add_test_job(ExecutorState.UNKNOWN, State.PENDING)
    api.set_job_transition(job, ExecutorState.ERROR, "it is b0rked")

    run.handle_job(job, api)

    # executor state
    assert job.id in api.tracker["prepare"]
    assert job.id in api.tracker["cleanup"]
    # its been cleaned up and is now unknown
    assert api.get_status(job).state == ExecutorState.UNKNOWN

    # our state
    assert job.state == State.FAILED
    assert job.status_message == "it is b0rked"
    assert job.status_code is None
Esempio n. 16
0
def test_handle_job_pending_dependency_failed(db):
    api = StubExecutorAPI()
    dependency = api.add_test_job(ExecutorState.UNKNOWN, State.FAILED)
    job = api.add_test_job(
        ExecutorState.UNKNOWN,
        State.PENDING,
        job_request_id=dependency.job_request_id,
        action="action2",
        wait_for_job_ids=[dependency.id],
    )

    run.handle_job(job, api)

    # executor state
    assert job.id not in api.tracker["prepare"]
    assert api.get_status(job).state == ExecutorState.UNKNOWN

    # our state
    assert job.state == State.FAILED
    assert job.status_message == "Not starting as dependency failed"
    assert job.status_code == StatusCode.DEPENDENCY_FAILED
Esempio n. 17
0
def test_handle_pending_job_waiting_on_dependency(db):
    api = StubExecutorAPI()
    dependency = api.add_test_job(ExecutorState.EXECUTING, State.RUNNING)

    job = api.add_test_job(
        ExecutorState.UNKNOWN,
        State.PENDING,
        job_request_id=dependency.job_request_id,
        action="action2",
        wait_for_job_ids=[dependency.id],
    )

    run.handle_job(job, api)

    # executor state
    assert job.id not in api.tracker["prepare"]
    assert api.get_status(job).state == ExecutorState.UNKNOWN

    # our state
    assert job.state == State.PENDING
    assert job.status_message == "Waiting on dependencies"
    assert job.status_code == StatusCode.WAITING_ON_DEPENDENCIES
Esempio n. 18
0
def test_handle_job_finalized_failed_unmatched_patterns(db):
    api = StubExecutorAPI()
    job = api.add_test_job(ExecutorState.FINALIZED, State.RUNNING)
    api.set_job_result(
        job,
        outputs={"output/file.csv": "medium"},
        unmatched_patterns=["badfile.csv"],
        unmatched_outputs=["otherbadfile.csv"],
    )

    run.handle_job(job, api)

    # executor state
    assert job.id in api.tracker["cleanup"]
    # its been cleaned up and is now unknown
    assert api.get_status(job).state == ExecutorState.UNKNOWN

    # our state
    assert job.state == State.FAILED
    assert job.status_message == "No outputs found matching patterns:\n - badfile.csv"
    assert job.outputs == {"output/file.csv": "medium"}
    assert job.unmatched_outputs == ["otherbadfile.csv"]