def test_get_permission(cidc_api, clean_db, monkeypatch):
    """Check that getting a single permission by ID works as expected."""
    mock_gcloud_client(monkeypatch)
    current_user_id, other_user_id = setup_permissions(cidc_api, monkeypatch)

    with cidc_api.app_context():
        current_user_perm = Permissions.find_for_user(current_user_id)[0]
        other_user_perm = Permissions.find_for_user(other_user_id)[0]

    client = cidc_api.test_client()

    # Check that getting a permission that doesn't exist yields 404
    res = client.get("permissions/123212321")
    assert res.status_code == 404

    # Check that a non-admin getting another user's permission yields 404
    res = client.get(f"permissions/{other_user_perm.id}")
    assert res.status_code == 404

    # Check that a non-admin can get their own permission
    res = client.get(f"permissions/{current_user_perm.id}")
    assert res.status_code == 200
    assert res.json == PermissionSchema().dump(current_user_perm)

    # Check that an admin can get another user's permission
    make_admin(current_user_id, cidc_api)
    res = client.get(f"permissions/{other_user_perm.id}")
    assert res.status_code == 200
    assert res.json == PermissionSchema().dump(other_user_perm)
def test_delete_permission(cidc_api, clean_db, monkeypatch):
    """Check that deleting a permission works as expected."""
    gcloud_client = mock_gcloud_client(monkeypatch)
    current_user_id, other_user_id = setup_permissions(cidc_api, monkeypatch)

    with cidc_api.app_context():
        perm = Permissions.find_for_user(current_user_id)[0]

    client = cidc_api.test_client()

    # Non-admins are not allowed to delete
    gcloud_client.reset_mock()
    res = client.delete(f"permissions/{perm.id}")
    assert res.status_code == 401
    assert "not authorized to access this endpoint" in res.json["_error"][
        "message"]
    gcloud_client.grant_download_access.assert_not_called()
    gcloud_client.revoke_download_access.assert_not_called()

    make_admin(current_user_id, cidc_api)

    # Requester must supply an If-Match header
    gcloud_client.reset_mock()
    res = client.delete(f"permissions/{perm.id}")
    assert res.status_code == 428
    gcloud_client.grant_download_access.assert_not_called()
    gcloud_client.revoke_download_access.assert_not_called()

    headers = {"If-Match": "foobar"}

    # Returns NotFound if no record exists
    gcloud_client.reset_mock()
    res = client.delete(f"permissions/1232123", headers=headers)
    assert res.status_code == 404
    gcloud_client.grant_download_access.assert_not_called()
    gcloud_client.revoke_download_access.assert_not_called()

    # A mismatched ETag leads to a PreconditionFailed error
    gcloud_client.reset_mock()
    res = client.delete(f"permissions/{perm.id}", headers=headers)
    assert res.status_code == 412
    gcloud_client.grant_download_access.assert_not_called()
    gcloud_client.revoke_download_access.assert_not_called()

    headers["If-Match"] = perm._etag

    # A well-formed delete request fails if IAM revoke fails
    gcloud_client.reset_mock()
    gcloud_client.revoke_download_access.side_effect = Exception("oops")
    res = client.delete(f"permissions/{perm.id}", headers=headers)
    assert "IAM revoke failed" in res.json["_error"]["message"]
    assert res.status_code == 500
    with cidc_api.app_context():
        assert Permissions.find_by_id(perm.id) is not None
    gcloud_client.revoke_download_access.side_effect = None

    # A matching ETag leads to a successful deletion
    gcloud_client.reset_mock()
    res = client.delete(f"permissions/{perm.id}", headers=headers)
    assert res.status_code == 204
    with cidc_api.app_context():
        assert Permissions.find_by_id(perm.id) is None
    gcloud_client.grant_download_access.assert_not_called()
    gcloud_client.revoke_download_access.assert_called_once()