def test_jobrequestapilist_filter_by_backend(api_rf):
    backend = BackendFactory()
    JobRequestFactory(backend=backend)
    JobRequestFactory()

    request = api_rf.get("/", HTTP_AUTHORIZATION=backend.auth_token)
    response = JobRequestAPIList.as_view()(request)

    assert response.status_code == 200, response.data
    assert len(response.data["results"]) == 1
def test_jobapiupdate_unknown_job_request(api_rf):
    backend = BackendFactory()
    JobRequestFactory()

    now = timezone.now()

    data = [{
        "identifier": "job1",
        "job_request_id": "test",
        "action": "test-action",
        "status": "running",
        "status_code": "",
        "status_message": "",
        "created_at": minutes_ago(now, 2),
        "started_at": minutes_ago(now, 1),
        "updated_at": now,
        "completed_at": None,
    }]

    request = api_rf.post("/",
                          HTTP_AUTHORIZATION=backend.auth_token,
                          data=data,
                          format="json")
    response = JobAPIUpdate.as_view()(request)

    assert response.status_code == 400, response.data
    assert "Unknown JobRequest IDs" in response.data[0]
def test_jobapiupdate_notifications_on_with_move_to_completed(api_rf, mocker):
    workspace = WorkspaceFactory()
    job_request = JobRequestFactory(workspace=workspace, will_notify=True)
    job = JobFactory(job_request=job_request, status="running")

    now = timezone.now()

    mocked_send = mocker.patch("jobserver.api.jobs.send_finished_notification",
                               autospec=True)

    data = [
        {
            "identifier": job.identifier,
            "job_request_id": job_request.identifier,
            "action": "test",
            "status": "succeeded",
            "status_code": "",
            "status_message": "",
            "created_at": minutes_ago(now, 2),
            "started_at": minutes_ago(now, 1),
            "updated_at": now,
            "completed_at": seconds_ago(now, 30),
        },
    ]
    request = api_rf.post(
        "/",
        HTTP_AUTHORIZATION=job_request.backend.auth_token,
        data=data,
        format="json",
    )

    response = JobAPIUpdate.as_view()(request)

    mocked_send.assert_called_once()
    assert response.status_code == 200
def test_workspacestatusesapi_success(api_rf):
    workspace = WorkspaceFactory()
    job_request = JobRequestFactory(workspace=workspace)
    JobFactory(job_request=job_request, action="run_all", status="failed")

    request = api_rf.get("/")
    response = WorkspaceStatusesAPI.as_view()(request, name=workspace.name)

    assert response.status_code == 200
    assert response.data["run_all"] == "failed"
def test_jobapiupdate_all_new(api_rf):
    backend = BackendFactory()
    job_request = JobRequestFactory()

    now = timezone.now()

    assert Job.objects.count() == 0

    data = [
        {
            "identifier": "job1",
            "job_request_id": job_request.identifier,
            "action": "test-action",
            "status": "running",
            "status_code": "",
            "status_message": "",
            "created_at": minutes_ago(now, 2),
            "started_at": minutes_ago(now, 1),
            "updated_at": now,
            "completed_at": None,
        },
        {
            "identifier": "job2",
            "action": "test-action",
            "job_request_id": job_request.identifier,
            "status": "pending",
            "status_code": "",
            "status_message": "",
            "created_at": minutes_ago(now, 2),
            "updated_at": now,
            "started_at": None,
            "completed_at": None,
        },
        {
            "identifier": "job3",
            "job_request_id": job_request.identifier,
            "action": "test-action",
            "status": "running",
            "status_code": "",
            "status_message": "",
            "created_at": minutes_ago(now, 2),
            "started_at": None,
            "updated_at": now,
            "completed_at": None,
        },
    ]

    request = api_rf.post("/",
                          HTTP_AUTHORIZATION=backend.auth_token,
                          data=data,
                          format="json")
    response = JobAPIUpdate.as_view()(request)

    assert response.status_code == 200, response.data
    assert Job.objects.count() == 3
def test_jobapiupdate_post_with_flags(api_rf):
    backend = BackendFactory()
    job_request = JobRequestFactory()

    now = timezone.now()

    data = [{
        "identifier": "job1",
        "job_request_id": job_request.identifier,
        "action": "test-action",
        "status": "running",
        "status_code": "",
        "status_message": "",
        "created_at": minutes_ago(now, 2),
        "started_at": minutes_ago(now, 1),
        "updated_at": now,
        "completed_at": None,
    }]

    flags = json.dumps(
        {
            "mode": {
                "v": "test",
                "ts": "1659092411.5025"
            },
            "paused": {
                "v": " ",
                "ts": "1657099752.16788"
            },
            "db-maintenance": {
                "v": "",
                "ts": "1657194377.72893"
            },
        },
        separators=(",", ":"),
    )

    request = api_rf.post(
        "/",
        data=data,
        format="json",
        HTTP_AUTHORIZATION=backend.auth_token,
        HTTP_FLAGS=flags,
    )
    response = JobAPIUpdate.as_view()(request)

    assert response.status_code == 200, response.data
    assert Job.objects.count() == 1

    backend.refresh_from_db()
    assert backend.jobrunner_state["mode"]["v"] == "test"
def test_jobrequestapilist_success(api_rf):
    workspace = WorkspaceFactory()

    # all completed
    job_request1 = JobRequestFactory(workspace=workspace)
    JobFactory.create_batch(2,
                            job_request=job_request1,
                            completed_at=timezone.now())

    # some completed
    job_request2 = JobRequestFactory(workspace=workspace)
    JobFactory(job_request=job_request2, completed_at=timezone.now())
    JobFactory(job_request=job_request2, completed_at=None)

    # none completed
    job_request3 = JobRequestFactory(workspace=workspace)
    JobFactory.create_batch(2, job_request=job_request3, completed_at=None)

    #  no jobs
    job_request4 = JobRequestFactory(workspace=workspace)

    assert JobRequest.objects.count() == 4

    request = api_rf.get("/")
    response = JobRequestAPIList.as_view()(request)

    assert response.status_code == 200
    assert response.data["count"] == 3
    assert len(response.data["results"]) == 3

    identifiers = {j["identifier"] for j in response.data["results"]}
    assert identifiers == {
        job_request2.identifier,
        job_request3.identifier,
        job_request4.identifier,
    }
def test_jobapiupdate_post_with_errors(api_rf, mocker, error_message):
    backend = BackendFactory()
    job_request = JobRequestFactory()
    mocked_sentry = mocker.patch("jobserver.api.jobs.sentry_sdk",
                                 autospec=True)

    now = timezone.now()

    data = [
        {
            "identifier": "job",
            "job_request_id": job_request.identifier,
            "action": "test-action",
            "status": "running",
            "status_code": "",
            "status_message": "Running",
            "created_at": now,
            "started_at": now,
            "updated_at": now,
            "completed_at": None,
        },
    ]
    request_1 = api_rf.post("/",
                            HTTP_AUTHORIZATION=backend.auth_token,
                            data=data,
                            format="json")
    JobAPIUpdate.as_view()(request_1)

    data[0]["status"] = "failed"
    data[0]["status_message"] = error_message
    request_2 = api_rf.post("/",
                            HTTP_AUTHORIZATION=backend.auth_token,
                            data=data,
                            format="json")
    response = JobAPIUpdate.as_view()(request_2)

    assert response.status_code == 200, response.data

    mocked_sentry.capture_message.assert_called_once()
def test_jobapiupdate_all_existing(api_rf, freezer):
    backend = BackendFactory()
    job_request = JobRequestFactory()

    now = timezone.now()

    # 3 pending jobs already exist
    job1, job2, job3, = JobFactory.create_batch(
        3,
        job_request=job_request,
        started_at=None,
        status="pending",
        completed_at=None,
    )
    job1.identifier = "job1"
    job1.save()

    job2.identifier = "job2"
    job2.save()

    job3.identifier = "job3"
    job3.save()

    assert Job.objects.count() == 3

    data = [
        {
            "identifier": "job1",
            "job_request_id": job_request.identifier,
            "action": "test-action1",
            "status": "succeeded",
            "status_code": "",
            "status_message": "",
            "created_at": minutes_ago(now, 2),
            "started_at": minutes_ago(now, 1),
            "updated_at": now,
            "completed_at": seconds_ago(now, 30),
        },
        {
            "identifier": "job2",
            "job_request_id": job_request.identifier,
            "action": "test-action2",
            "status": "running",
            "status_code": "",
            "status_message": "",
            "created_at": minutes_ago(now, 2),
            "started_at": minutes_ago(now, 1),
            "updated_at": now,
            "completed_at": None,
        },
        {
            "identifier": "job3",
            "job_request_id": job_request.identifier,
            "action": "test-action3",
            "status": "pending",
            "status_code": "",
            "status_message": "",
            "created_at": minutes_ago(now, 2),
            "started_at": None,
            "updated_at": now,
            "completed_at": None,
        },
    ]

    request = api_rf.post("/",
                          HTTP_AUTHORIZATION=backend.auth_token,
                          data=data,
                          format="json")
    response = JobAPIUpdate.as_view()(request)

    assert response.status_code == 200, response.data

    # we shouldn't have a different number of jobs
    jobs = Job.objects.all()
    assert len(jobs) == 3

    # check our jobs look as expected
    job1, job2, job3 = jobs

    # succeeded
    assert job1.identifier == "job1"
    assert job1.started_at == minutes_ago(now, 1)
    assert job1.updated_at == now
    assert job1.completed_at == seconds_ago(now, 30)

    # running
    assert job2.identifier == "job2"
    assert job2.started_at == minutes_ago(now, 1)
    assert job2.updated_at == now
    assert job2.completed_at is None

    # pending
    assert job3.identifier == "job3"
    assert job3.started_at is None
    assert job3.updated_at == now
    assert job3.completed_at is None