Exemple #1
0
async def test_get_application_by_id(
    client,
    fill_application_data,
    inject_security_header,
):
    """
    Test GET /applications/<id>.

    This test proves that GET /applications/<id> returns the correct application, owned by
    the user making the request. We show this by asserting that the application data
    returned in the response is equal to the application data that exists in the database
    for the given application id.
    """
    inserted_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_identifier="app1"),
    )
    await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_identifier="app2"),
    )
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 2

    inject_security_header("*****@*****.**", Permissions.APPLICATIONS_VIEW)
    response = await client.get(f"/jobbergate/applications/{inserted_id}")
    assert response.status_code == status.HTTP_200_OK

    data = response.json()
    assert data["id"] == inserted_id
    assert data["application_identifier"] == "app1"
Exemple #2
0
async def test_delete_application__fk_error(
    client,
    application_data,
    inject_security_header,
):
    """
    Test DELETE /applications/<id> correctly returns a 409 when a foreign-key error occurs.

    Test that a helpful message when a delete is blocked by a foreign-key constraint.
    """
    inserted_id = await database.execute(
        query=applications_table.insert(),
        values=application_data,
    )
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 1

    inject_security_header("*****@*****.**", Permissions.APPLICATIONS_EDIT)
    with mock.patch(
            "jobbergate_api.storage.database.execute",
            side_effect=asyncpg.exceptions.ForeignKeyViolationError(f"""
            update or delete on table "applications" violates foreign key constraint
            "job_scripts_application_id_fkey" on table "job_scripts"
            DETAIL:  Key (id)=({inserted_id}) is still referenced from table "job_scripts".
            """),
    ):
        response = await client.delete(
            f"/jobbergate/applications/{inserted_id}")
    assert response.status_code == status.HTTP_409_CONFLICT
    error_data = json.loads(response.text)["detail"]
    assert error_data[
        "message"] == "Delete failed due to foreign-key constraint"
    assert error_data["table"] == "job_scripts"
    assert error_data["pk_id"] == f"{inserted_id}"
Exemple #3
0
async def test_package_response__without_pagination():
    """
    Test the package_response method without pagination.
    """
    await database.execute_many(
        query=applications_table.insert(),
        values=[
            dict(
                application_owner_email=f"owner{i}@org.com",
                application_name=f"app{i}",
                application_file="the\nfile",
                application_config="the configuration is here",
            ) for i in range(1, 6)
        ],
    )

    query = applications_table.select()
    pagination = Pagination()
    raw_response = await package_response(ApplicationResponse, query,
                                          pagination)
    response = Response[ApplicationResponse].parse_obj(
        json.loads(raw_response.body))

    results = response.results
    assert len(results) == 5
    for (i, result) in enumerate(results):
        assert isinstance(result, ApplicationResponse)
        assert result.application_name == f"app{i + 1}"

    assert response.pagination.total == 5
    assert response.pagination.start is None
    assert response.pagination.limit is None
Exemple #4
0
async def test_delete_application_no_file_uploaded(
    client,
    application_data,
    inject_security_header,
):
    """
    Test DELETE /applications/<id> correctly deletes an application.

    This test proves that an application is successfully deleted via a DELETE request to the
    /applications/<id> endpoint. We show this by asserting that the application no longer exists in the
    database after the delete request is made and the correct status code is returned.
    """
    inserted_id = await database.execute(
        query=applications_table.insert(),
        values=application_data,
    )
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 1

    inject_security_header("*****@*****.**", Permissions.APPLICATIONS_EDIT)
    with mock.patch.object(s3man, "s3_client") as mock_s3:
        response = await client.delete(
            f"/jobbergate/applications/{inserted_id}")
        mock_s3.delete_object.assert_called_once()

    assert response.status_code == status.HTTP_204_NO_CONTENT
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 0
Exemple #5
0
async def test_delete_application_by_identifier(
    client,
    fill_application_data,
    inject_security_header,
):
    """
    Test DELETE /applications?identifier=<identifier> correctly deletes an application and it's file.

    This test proves that an application is successfully deleted via a DELETE request to the
    /applications?identifier=<identifier> endpoint. We show this by asserting that the application no longer
    exists in the database after the delete request is made, the correct status code is returned and the
    correct boto3 method was called.
    """
    await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(
            application_owner_email="*****@*****.**",
            application_identifier="test-identifier",
        ),
    )
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 1

    inject_security_header("*****@*****.**", Permissions.APPLICATIONS_EDIT)
    with mock.patch.object(s3man, "s3_client") as mock_s3:
        response = await client.delete(
            "/jobbergate/applications?identifier=test-identifier")
        mock_s3.delete_object.assert_called_once()

    assert response.status_code == status.HTTP_204_NO_CONTENT
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 0
Exemple #6
0
async def test_get_job_scripts__bad_permission(
    client,
    fill_application_data,
    fill_job_script_data,
    inject_security_header,
):
    """
    Test GET /job-scripts/ returns 403 since the user don't have the proper permission.

    This test proves that GET /job-scripts/ returns the 403 status code when the user making the request
    don't have the permission to list. We show this by asserting that the response status code is 403.
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**"),
    )
    await database.execute(
        query=job_scripts_table.insert(),
        values=fill_job_script_data(application_id=inserted_application_id),
    )

    count = await database.fetch_all("SELECT COUNT(*) FROM job_scripts")
    assert count[0][0] == 1

    inject_security_header("*****@*****.**", "INVALID_PERMISSION")
    response = await client.get("/jobbergate/job-scripts/")
    assert response.status_code == status.HTTP_403_FORBIDDEN
Exemple #7
0
async def test_delete_file(
    client,
    inject_security_header,
    fill_application_data,
):
    """
    Test that a file is uploaded.

    This test proves that an application's file is uploaded by making sure that the boto3 put_object method
    is called once and a 201 status code is returned.
    """
    inserted_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**",
                                     application_uploaded=True),
    )
    application: ApplicationResponse = await fetch_instance(
        inserted_id, applications_table, ApplicationResponse)
    assert application.application_uploaded

    inject_security_header("*****@*****.**", Permissions.APPLICATIONS_EDIT)
    with mock.patch.object(s3man, "s3_client") as mock_s3:
        response = await client.delete(
            f"/jobbergate/applications/{inserted_id}/upload")
    assert response.status_code == status.HTTP_204_NO_CONTENT
    mock_s3.delete_object.assert_called_once()

    application = await fetch_instance(inserted_id, applications_table,
                                       ApplicationResponse)
    assert not application.application_uploaded
async def applications_create(
    application: ApplicationCreateRequest,
    token_payload: TokenPayload = Depends(
        guard.lockdown(Permissions.APPLICATIONS_EDIT)),
):
    """
    Create new applications using an authenticated user token.
    """
    identity_claims = IdentityClaims.from_token_payload(token_payload)
    create_dict = dict(
        **application.dict(exclude_unset=True),
        application_owner_email=identity_claims.user_email,
    )

    try:
        insert_query = applications_table.insert().returning(
            applications_table)
        application_data = await database.fetch_one(query=insert_query,
                                                    values=create_dict)

    except INTEGRITY_CHECK_EXCEPTIONS as e:
        raise HTTPException(status_code=status.HTTP_409_CONFLICT,
                            detail=str(e))

    return application_data
Exemple #9
0
async def test_update_job_script_bad_permission(
    client,
    fill_application_data,
    fill_job_script_data,
    inject_security_header,
):
    """
    Test that it is not possible to update a job_script if the user don't have the proper permission.

    This test proves that it is not possible to update a job_script if the user don't have permission. We
    show this by asserting that the response status code of the request is 403, and that the data stored in
    the database for the job_script is not updated.
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**"),
    )
    await database.execute(
        query=job_scripts_table.insert(),
        values=fill_job_script_data(job_script_name="target-js",
                                    application_id=inserted_application_id),
    )

    inject_security_header("*****@*****.**", "INVALID_PERMISSION")
    response = await client.put("/jobbergate/job-scripts/1",
                                data={"job_script_name": "new name"})

    assert response.status_code == status.HTTP_403_FORBIDDEN

    query = job_scripts_table.select(
        job_scripts_table.c.job_script_name == "target-js")
    job_script_row = await database.fetch_one(query)

    assert job_script_row is not None
    assert job_script_row["job_script_name"] == "target-js"
Exemple #10
0
async def test_get_application___bad_permission(
    client,
    fill_all_application_data,
    inject_security_header,
):
    """
    Test that it is not possible to list applications without proper permission.

    This test proves that the GET /applications returns 403 as status code in the response.
    We show this by making a request with an user without creating the permission, and then asserting the
    status code in the response.
    """
    await database.execute_many(
        query=applications_table.insert(),
        values=fill_all_application_data(
            dict(application_identifier="app1"),
            dict(application_identifier="app2"),
            dict(application_identifier="app3"),
        ),
    )
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 3

    inject_security_header("*****@*****.**", "INVALID_PERMISSION")
    response = await client.get("/jobbergate/applications/")
    assert response.status_code == status.HTTP_403_FORBIDDEN
Exemple #11
0
async def test_delete_job_script(
    client,
    fill_application_data,
    fill_job_script_data,
    inject_security_header,
):
    """
    Test delete job_script via DELETE.

    This test proves that a job_script is successfully deleted via a DELETE request to the /job-scripts/<id>
    endpoint. We show this by asserting that the job_script no longer exists in the database after the
    request is made and the correct status code is returned (204).
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(),
    )
    inserted_job_script_id = await database.execute(
        query=job_scripts_table.insert(),
        values=fill_job_script_data(application_id=inserted_application_id),
    )

    count = await database.fetch_all("SELECT COUNT(*) FROM job_scripts")
    assert count[0][0] == 1

    inject_security_header("*****@*****.**", Permissions.JOB_SCRIPTS_EDIT)
    response = await client.delete(
        f"/jobbergate/job-scripts/{inserted_job_script_id}")

    assert response.status_code == status.HTTP_204_NO_CONTENT

    count = await database.fetch_all("SELECT COUNT(*) FROM job_scripts")
    assert count[0][0] == 0
Exemple #12
0
async def test_delete_job_script_bad_permission(
    client,
    fill_application_data,
    fill_job_script_data,
    inject_security_header,
):
    """
    Test that it is not possible to delete a job_script when the user don't have the permission.

    This test proves that it is not possible to delete a job_script if the user don't have the permission.
    We show this by assert that a 403 response status code is returned and the job_script still exists in
    the database after the request.
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(),
    )
    inserted_job_script_id = await database.execute(
        query=job_scripts_table.insert(),
        values=fill_job_script_data(application_id=inserted_application_id),
    )

    count = await database.fetch_all("SELECT COUNT(*) FROM job_scripts")
    assert count[0][0] == 1

    inject_security_header("*****@*****.**", "INVALID_PERMISSION")
    response = await client.delete(
        f"/jobbergate/job-scripts/{inserted_job_script_id}")

    assert response.status_code == status.HTTP_403_FORBIDDEN

    count = await database.fetch_all("SELECT COUNT(*) FROM job_scripts")
    assert count[0][0] == 1
Exemple #13
0
async def test_get_job_script_by_id_bad_permission(
    client,
    fill_application_data,
    fill_job_script_data,
    inject_security_header,
):
    """
    Test the correct response code is returned when the user don't have the proper permission.

    This test proves that GET /job-script/<id> returns the correct response code when the
    user don't have the proper permission. We show this by asserting that the status code
    returned is what we would expect (403).
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**"),
    )
    inserted_job_script_id = await database.execute(
        query=job_scripts_table.insert(),
        values=fill_job_script_data(application_id=inserted_application_id),
    )
    inject_security_header("*****@*****.**", "INVALID_PERMISSION")
    response = await client.get(
        f"/jobbergate/job-scripts/{inserted_job_script_id}")
    assert response.status_code == status.HTTP_403_FORBIDDEN
Exemple #14
0
async def test_create_job_script_bad_permission(
    fill_application_data,
    fill_job_script_data,
    param_dict,
    client,
    inject_security_header,
):
    """
    Test that it is not possible to create job_script without proper permission.

    This test proves that is not possible to create a job_script without the proper permission.
    We show this by trying to create a job_script without a permission that allow "create" then assert
    that the job_script still does not exists in the database, and the correct status code (403) is returned.
    and that the boto3 method is never called.
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**"),
    )

    inject_security_header("*****@*****.**", "INVALID_PERMISSION")
    response = await client.post(
        "/jobbergate/job-scripts/",
        json=fill_job_script_data(
            application_id=inserted_application_id,
            param_dict=param_dict,
        ),
    )

    assert response.status_code == status.HTTP_403_FORBIDDEN

    count = await database.fetch_all("SELECT COUNT(*) FROM job_scripts")
    assert count[0][0] == 0
Exemple #15
0
async def test_get_job_scripts__with_all_param(
    client,
    fill_application_data,
    fill_all_job_script_data,
    inject_security_header,
):
    """
    Test that listing job_scripts, when all=True, contains job_scripts owned by other users.

    This test proves that the user making the request can see job_scripts owned by other users.
    We show this by creating three job_scripts, one that are owned by the user making the request, and two
    owned by another user. Assert that the response to GET /job-scripts/?all=True includes all three
    job_scripts.
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**"),
    )
    await database.execute_many(
        query=job_scripts_table.insert(),
        values=fill_all_job_script_data(
            {
                "job_script_name": "script1",
                "job_script_owner_email": "*****@*****.**",
                "application_id": inserted_application_id,
            },
            {
                "job_script_name": "script2",
                "job_script_owner_email": "*****@*****.**",
                "application_id": inserted_application_id,
            },
            {
                "job_script_name": "script3",
                "job_script_owner_email": "*****@*****.**",
                "application_id": inserted_application_id,
            },
        ),
    )

    count = await database.fetch_all("SELECT COUNT(*) FROM job_scripts")
    assert count[0][0] == 3

    inject_security_header("*****@*****.**", Permissions.JOB_SCRIPTS_VIEW)
    response = await client.get("/jobbergate/job-scripts/?all=True")
    assert response.status_code == status.HTTP_200_OK

    data = response.json()
    results = data.get("results")
    assert results
    assert [d["job_script_name"]
            for d in results] == ["script1", "script2", "script3"]

    pagination = data.get("pagination")
    assert pagination == dict(
        total=3,
        start=None,
        limit=None,
    )
Exemple #16
0
async def test_get_job_script__no_params(
    client,
    fill_application_data,
    fill_all_job_script_data,
    inject_security_header,
):
    """
    Test GET /job-scripts/ returns only job_scripts owned by the user making the request.

    This test proves that GET /job-scripts/ returns the correct job_scripts for the user making
    the request. We show this by asserting that the job_scripts returned in the response are
    only job_scripts owned by the user making the request.
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**"),
    )
    await database.execute_many(
        query=job_scripts_table.insert(),
        values=fill_all_job_script_data(
            dict(
                job_script_name="js1",
                job_script_owner_email="*****@*****.**",
                application_id=inserted_application_id,
            ),
            dict(
                job_script_name="js2",
                job_script_owner_email="*****@*****.**",
                application_id=inserted_application_id,
            ),
            dict(
                job_script_name="js3",
                job_script_owner_email="*****@*****.**",
                application_id=inserted_application_id,
            ),
        ),
    )

    count = await database.fetch_all("SELECT COUNT(*) FROM job_scripts")
    assert count[0][0] == 3

    inject_security_header("*****@*****.**", Permissions.JOB_SCRIPTS_VIEW)
    response = await client.get("/jobbergate/job-scripts/")
    assert response.status_code == status.HTTP_200_OK

    data = response.json()
    results = data.get("results")
    assert results
    assert [d["job_script_name"] for d in results] == ["js1", "js3"]

    pagination = data.get("pagination")
    assert pagination == dict(
        total=2,
        start=None,
        limit=None,
    )
Exemple #17
0
async def test_get_applications__with_sort_params(
    client,
    fill_all_application_data,
    inject_security_header,
):
    """
    Test that listing applications with sort params returns correctly ordered matches.

    This test proves that the user making the request will be shown applications sorted in the correct order
    according to the ``sort_field`` and ``sort_ascending`` parameters.
    We show this by creating applications and using various sort parameters to order them.

    Assert that the response to GET /applications?sort_field=<field>&sort_ascending=<bool> includes correctly
    sorted applications.
    """
    await database.execute_many(
        query=applications_table.insert(),
        values=fill_all_application_data(
            dict(application_name="A", application_identifier="Z"),
            dict(application_name="B", application_identifier="Y"),
            dict(application_name="C", application_identifier="X"),
        ),
    )
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 3

    inject_security_header("*****@*****.**", Permissions.APPLICATIONS_VIEW)

    response = await client.get(
        "/jobbergate/applications?all=true&sort_field=application_name")
    assert response.status_code == status.HTTP_200_OK
    data = response.json()
    results = data.get("results")
    assert [d["application_identifier"] for d in results] == ["Z", "Y", "X"]

    response = await client.get(
        "/jobbergate/applications?all=true&sort_field=application_name&sort_ascending=false"
    )
    assert response.status_code == status.HTTP_200_OK
    data = response.json()
    results = data.get("results")
    assert [d["application_identifier"] for d in results] == ["X", "Y", "Z"]

    response = await client.get(
        "/jobbergate/applications?all=true&sort_field=application_identifier")
    assert response.status_code == status.HTTP_200_OK
    data = response.json()
    results = data.get("results")
    assert [d["application_identifier"] for d in results] == ["X", "Y", "Z"]

    response = await client.get(
        "/jobbergate/applications?all=true&sort_field=application_config")
    assert response.status_code == status.HTTP_400_BAD_REQUEST
    assert "Invalid sorting column requested" in response.text
Exemple #18
0
async def test_get_applications__with_all_param(
    client,
    fill_all_application_data,
    inject_security_header,
):
    """
    Test that listing applications, when all=True, contains applications without identifiers.

    This test proves that the user making the request can see applications owned by other users.
    We show this by creating three applications, two that are owned by the user making the request, and one
    owned by another user. Assert that the response to GET /applications/?all=True includes all three
    applications.
    """
    await database.execute_many(
        query=applications_table.insert(),
        values=fill_all_application_data(
            dict(application_identifier="app1",
                 application_owner_email="*****@*****.**"),
            dict(application_owner_email="*****@*****.**"),
            dict(application_identifier="app3",
                 application_owner_email="*****@*****.**"),
        ),
    )
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 3

    inject_security_header("*****@*****.**", Permissions.APPLICATIONS_VIEW)

    response = await client.get("/jobbergate/applications")
    assert response.status_code == status.HTTP_200_OK

    data = response.json()
    results = data.get("results")
    assert [d["application_identifier"] for d in results] == ["app1", "app3"]

    pagination = data.get("pagination")
    assert pagination == dict(
        total=2,
        start=None,
        limit=None,
    )

    response = await client.get("/jobbergate/applications/?all=True")
    assert response.status_code == status.HTTP_200_OK

    data = response.json()
    results = data.get("results")
    pagination = data.get("pagination")
    assert pagination == dict(
        total=3,
        start=None,
        limit=None,
    )
Exemple #19
0
async def test_create_job_script(
    fill_application_data,
    job_script_data,
    fill_job_script_data,
    param_dict,
    client,
    inject_security_header,
    time_frame,
    s3_object,
):
    """
    Test POST /job_scripts/ correctly creates a job_script.

    This test proves that a job_script is successfully created via a POST request to the /job-scripts/
    endpoint. We show this by asserting that the job_script is created in the database after the post
    request is made, the correct status code (201) is returned.
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**"),
    )

    inject_security_header("*****@*****.**", Permissions.JOB_SCRIPTS_EDIT)
    with time_frame() as window:
        with mock.patch.object(s3man, "s3_client") as s3man_client_mock:
            s3man_client_mock.get_object.return_value = s3_object
            response = await client.post(
                "/jobbergate/job-scripts/",
                json=fill_job_script_data(
                    application_id=inserted_application_id,
                    param_dict=param_dict,
                ),
            )

    assert response.status_code == status.HTTP_201_CREATED
    s3man_client_mock.get_object.assert_called_once()

    id_rows = await database.fetch_all("SELECT id FROM job_scripts")
    assert len(id_rows) == 1

    job_script = JobScriptResponse(**response.json())

    assert job_script.id == id_rows[0][0]
    assert job_script.job_script_name == job_script_data["job_script_name"]
    assert job_script.job_script_owner_email == "*****@*****.**"
    assert job_script.job_script_description is None
    assert job_script.job_script_data_as_string
    assert job_script.job_script_data_as_string != job_script_data[
        "job_script_data_as_string"]
    assert job_script.application_id == inserted_application_id
    assert job_script.created_at in window
    assert job_script.updated_at in window
Exemple #20
0
async def test_update_job_script(
    client,
    fill_application_data,
    fill_job_script_data,
    inject_security_header,
    time_frame,
):
    """
    Test update job_script via PUT.

    This test proves that the job_script values are correctly updated following a PUT request to the
    /job-scripts/<id> endpoint. We show this by assert the response status code to 201, the response data
    corresponds to the updated data, and the data in the database is also updated.
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**"),
    )
    inserted_job_script_id = await database.execute(
        query=job_scripts_table.insert(),
        values=fill_job_script_data(application_id=inserted_application_id),
    )

    inject_security_header("*****@*****.**", Permissions.JOB_SCRIPTS_EDIT)
    with time_frame() as window:
        response = await client.put(
            f"/jobbergate/job-scripts/{inserted_job_script_id}",
            json={
                "job_script_name": "new name",
                "job_script_description": "new description",
                "job_script_data_as_string": "new value",
            },
        )

    assert response.status_code == status.HTTP_200_OK
    data = response.json()

    assert data["job_script_name"] == "new name"
    assert data["job_script_description"] == "new description"
    assert data["job_script_data_as_string"] == "new value"
    assert data["id"] == inserted_job_script_id

    query = job_scripts_table.select(
        job_scripts_table.c.id == inserted_job_script_id)
    job_script = JobScriptResponse.parse_obj(await database.fetch_one(query))

    assert job_script is not None
    assert job_script.job_script_name == "new name"
    assert job_script.job_script_description == "new description"
    assert job_script.job_script_data_as_string == "new value"
    assert job_script.updated_at in window
Exemple #21
0
async def test_update_application(
    client,
    fill_application_data,
    inject_security_header,
    time_frame,
):
    """
    Test that an application is updated via PUT.

    This test proves that an application's values are correctly updated following a PUT request to the
    /application/<id> endpoint. We show this by asserting that the values provided to update the
    application are returned in the response made to the PUT /applciation/<id> endpoint.
    """
    await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(
            application_identifier="old_identifier",
            application_owner_email="*****@*****.**",
            application_description="old description",
        ),
    )
    rows = await database.fetch_all("select id from applications")
    assert len(rows) == 1
    id = rows[0][0]

    inject_security_header("*****@*****.**", Permissions.APPLICATIONS_EDIT)
    with time_frame() as window:
        response = await client.put(
            f"/jobbergate/applications/{id}",
            json=dict(
                application_name="new_name",
                application_identifier="new_identifier",
                application_description="new_description",
            ),
        )
    assert response.status_code == status.HTTP_200_OK

    data = response.json()
    assert data["application_name"] == "new_name"
    assert data["application_identifier"] == "new_identifier"
    assert data["application_description"] == "new_description"

    query = applications_table.select(applications_table.c.id == id)
    result = await database.fetch_one(query)

    assert result is not None
    assert result["application_name"] == "new_name"
    assert result["application_identifier"] == "new_identifier"
    assert result["application_owner_email"] == "*****@*****.**"
    assert result["application_description"] == "new_description"
    assert result["updated_at"] in window
Exemple #22
0
async def test_get_applications__no_params(
    client,
    fill_all_application_data,
    inject_security_header,
):
    """
    Test GET /applications returns only applications owned by the user making the request.

    This test proves that GET /applications returns the correct applications for the user making
    the request. We show this by asserting that the applications returned in the response are
    only applications owned by the user making the request.
    """
    await database.execute_many(
        applications_table.insert(),
        values=fill_all_application_data(
            dict(application_identifier="app1"),
            dict(application_identifier="app2"),
            dict(application_identifier="app3"),
        ),
    )
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 3

    inject_security_header("*****@*****.**", Permissions.APPLICATIONS_VIEW)
    response = await client.get("/jobbergate/applications/")
    assert response.status_code == status.HTTP_200_OK

    data = response.json()
    results = data.get("results")
    assert results
    assert sorted([d["application_identifier"] for d in results]) == [
        "app1",
        "app2",
        "app3",
    ]

    pagination = data.get("pagination")
    assert pagination == dict(
        total=3,
        start=None,
        limit=None,
    )
Exemple #23
0
async def test_update_application_bad_permission(
    client,
    fill_application_data,
    inject_security_header,
):
    """
    Test that it is not possible to update applications without proper permission.

    This test proves that an application's values are not updated following a PUT request to the
    /application/<id> endpoint by a user without permission. We show this by asserting that the status code
    403 is returned and that the application_data is still the same as before.
    """
    inserted_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(
            application_name="old-name",
            application_identifier="old_identifier",
            application_owner_email="*****@*****.**",
            application_description="old description",
        ),
    )
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 1

    inject_security_header("*****@*****.**", "INVALID_PERMISSION")
    response = await client.put(
        f"/jobbergate/applications/{inserted_id}",
        json=dict(
            application_name="new_name",
            application_identifier="new_identifier",
            application_description="new_description",
        ),
    )
    assert response.status_code == status.HTTP_403_FORBIDDEN

    query = applications_table.select(applications_table.c.id == inserted_id)
    result = await database.fetch_one(query)

    assert result is not None
    assert result["application_name"] == "old-name"
    assert result["application_identifier"] == "old_identifier"
    assert result["application_description"] == "old description"
Exemple #24
0
async def test_get_application_by_id_bad_permission(
    client,
    application_data,
    inject_security_header,
):
    """
    Test that it is not possible to get application without proper permission.

    This test proves that GET /application/<id> returns the correct response code when the
    user don't have the proper permission. We show this by asserting that the status code
    returned is what we would expect (403).
    """
    inserted_id = await database.execute(
        query=applications_table.insert(),
        values=application_data,
    )

    inject_security_header("*****@*****.**", "INVALID_PERMISSION")
    response = await client.get(f"/jobbergate/applications/{inserted_id}")
    assert response.status_code == status.HTTP_403_FORBIDDEN
Exemple #25
0
async def test_upload_file__works_with_small_file(
    client,
    inject_security_header,
    fill_application_data,
    tweak_settings,
    make_dummy_file,
    make_files_param,
):
    """
    Test that a file is uploaded.

    This test proves that an application's file is uploaded by making sure that the
    boto3 put_object method is called once and a 201 status code is returned. It also
    checks to make sure that the application row in the database has
    `application_uploded` set.
    """
    inserted_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**"),
    )
    application = await fetch_instance(inserted_id, applications_table,
                                       ApplicationResponse)
    assert not application.application_uploaded

    dummy_file = make_dummy_file("dummy.py", size=10_000 -
                                 200)  # Need some buffer for file headers, etc
    inject_security_header("*****@*****.**", Permissions.APPLICATIONS_EDIT)
    with tweak_settings(MAX_UPLOAD_FILE_SIZE=10_000):
        with mock.patch.object(s3man, "s3_client") as mock_s3:
            with make_files_param(dummy_file) as files_param:
                response = await client.post(
                    f"/jobbergate/applications/{inserted_id}/upload",
                    files=files_param,
                )

    assert response.status_code == status.HTTP_201_CREATED
    mock_s3.put_object.assert_called_once()

    application = await fetch_instance(inserted_id, applications_table,
                                       ApplicationResponse)
    assert application.application_uploaded
Exemple #26
0
async def test_get_job_script_by_id(
    client,
    fill_application_data,
    job_script_data,
    fill_job_script_data,
    inject_security_header,
):
    """
    Test GET /job-scripts/<id>.

    This test proves that GET /job-scripts/<id> returns the correct job-script, owned by
    the user making the request. We show this by asserting that the job_script data
    returned in the response is equal to the job_script data that exists in the database
    for the given job_script id.
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**"),
    )
    inserted_job_script_id = await database.execute(
        query=job_scripts_table.insert(),
        values=fill_job_script_data(application_id=inserted_application_id),
    )

    count = await database.fetch_all("SELECT COUNT(*) FROM job_scripts")
    assert count[0][0] == 1

    inject_security_header("*****@*****.**", Permissions.JOB_SCRIPTS_VIEW)
    response = await client.get(
        f"/jobbergate/job-scripts/{inserted_job_script_id}")
    assert response.status_code == status.HTTP_200_OK

    data = response.json()
    assert data["id"] == inserted_job_script_id
    assert data["job_script_name"] == job_script_data["job_script_name"]
    assert data["job_script_data_as_string"] == job_script_data[
        "job_script_data_as_string"]
    assert data["job_script_owner_email"] == "*****@*****.**"
    assert data["application_id"] == inserted_application_id
Exemple #27
0
async def test_package_response__with_pagination(start, limit, total):
    """
    Test the package_response method with pagination.

    Parameters test pagination at upper bound and lower bound of total
    """
    await database.execute_many(
        query=applications_table.insert(),
        values=[
            dict(
                id=i,
                application_owner_email=f"owner{i}@org.com",
                application_name=f"app{i}",
                application_file="the\nfile",
                application_config="the configuration is here",
            ) for i in range(1, total + 1)
        ],
    )

    query = applications_table.select()
    pagination = Pagination(start=start, limit=limit)
    raw_response = await package_response(ApplicationResponse, query,
                                          pagination)
    response = Response[ApplicationResponse].parse_obj(
        json.loads(raw_response.body))

    results = response.results
    # Clamps the expected count at upper bound
    expected_count = max(0, min(total - start * limit, limit))
    assert len(results) == expected_count
    for (i, result) in enumerate(results):
        assert isinstance(result, ApplicationResponse)
        assert result.application_name == f"app{i + (start * limit) + 1}"

    assert response.pagination
    assert response.pagination.total == total
    assert response.pagination.start == start
    assert response.pagination.limit == limit
Exemple #28
0
async def test_create_job_script_file_not_found(
    fill_application_data,
    fill_job_script_data,
    param_dict,
    client,
    inject_security_header,
):
    """
    Test that is not possible to create a job_script if the application is in the database but not in S3.

    This test proves that is not possible to create a job_script with an existing application in the
    database but not in S3, this covers for when for some reason the application file in S3 is deleted but it
    remains in the database. We show this by trying to create a job_script with an existing application that
    is not in S3 (raises BotoCoreError), then assert that the job_script still does not exists in the
    database, the correct status code (404) is returned and that the boto3 method was called.
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**"),
    )

    inject_security_header("*****@*****.**", Permissions.JOB_SCRIPTS_EDIT)
    with mock.patch.object(s3man, "s3_client") as s3man_client_mock:
        s3man_client_mock.get_object.side_effect = BotoCoreError()
        response = await client.post(
            "/jobbergate/job-scripts/",
            json=fill_job_script_data(
                application_id=inserted_application_id,
                param_dict=param_dict,
            ),
        )

    assert response.status_code == status.HTTP_404_NOT_FOUND
    s3man_client_mock.get_object.assert_called_once()

    count = await database.fetch_all("SELECT COUNT(*) FROM job_scripts")
    assert count[0][0] == 0
Exemple #29
0
async def test_delete_application_bad_permission(
    client,
    application_data,
    inject_security_header,
):
    """
    Test that it is not possible to delete application without proper permission.

    This test proves that an application is not deleted via a DELETE request to the /applications/<id>
    endpoint. We show this by asserting that the application still exists in the database after the delete
    request is made and the correct status code is returned.
    """
    inserted_id = await database.execute(
        query=applications_table.insert(),
        values=application_data,
    )
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 1

    inject_security_header("*****@*****.**", "INVALID_PERMISSION")
    response = await client.delete(f"/jobbergate/applications/{inserted_id}")
    assert response.status_code == status.HTTP_403_FORBIDDEN
    count = await database.fetch_all("SELECT COUNT(*) FROM applications")
    assert count[0][0] == 1
Exemple #30
0
async def test_get_job_scripts__with_pagination(
    client,
    fill_application_data,
    fill_job_script_data,
    inject_security_header,
):
    """
    Test that listing job_scripts works with pagination.

    This test proves that the user making the request can see job_scripts paginated.
    We show this by creating three job_scripts and assert that the response is correctly paginated.
    """
    inserted_application_id = await database.execute(
        query=applications_table.insert(),
        values=fill_application_data(application_owner_email="*****@*****.**"),
    )
    await database.execute_many(
        query=job_scripts_table.insert(),
        values=[
            fill_job_script_data(
                job_script_name=f"script{i}",
                job_script_owner_email="*****@*****.**",
                application_id=inserted_application_id,
            ) for i in range(1, 6)
        ],
    )

    count = await database.fetch_all("SELECT COUNT(*) FROM job_scripts")
    assert count[0][0] == 5

    inject_security_header("*****@*****.**", Permissions.JOB_SCRIPTS_VIEW)
    response = await client.get("/jobbergate/job-scripts?start=0&limit=1")
    assert response.status_code == status.HTTP_200_OK

    data = response.json()
    results = data.get("results")
    assert results
    assert [d["job_script_name"] for d in results] == ["script1"]

    pagination = data.get("pagination")
    assert pagination == dict(total=5, start=0, limit=1)

    response = await client.get("/jobbergate/job-scripts?start=1&limit=2")
    assert response.status_code == status.HTTP_200_OK

    data = response.json()
    results = data.get("results")
    assert results
    assert [d["job_script_name"] for d in results] == ["script3", "script4"]

    pagination = data.get("pagination")
    assert pagination == dict(total=5, start=1, limit=2)

    response = await client.get("/jobbergate/job-scripts?start=2&limit=2")
    assert response.status_code == status.HTTP_200_OK

    data = response.json()
    results = data.get("results")
    assert results
    assert [d["job_script_name"] for d in results] == ["script5"]

    pagination = data.get("pagination")
    assert pagination == dict(total=5, start=2, limit=2)