Skip to content

Commit

Permalink
Merge pull request #224 from Open-EO/issue215_part2-improve-reported-…
Browse files Browse the repository at this point in the history
…job-status-for-partial-results

Issue #215 Fix: report correct job status in _list_job_results when p…
  • Loading branch information
bossie authored Sep 29, 2023
2 parents 88d4eed + 28356ee commit 1de3faa
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 22 deletions.
19 changes: 17 additions & 2 deletions openeo_driver/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -948,8 +948,21 @@ def job_results_canonical_url() -> str:
if not partial:
raise JobNotFinishedException()
else:
if job_info.status == JOB_STATUS.RUNNING:
openeo_status = "running"
elif job_info.status == JOB_STATUS.ERROR:
openeo_status = "error"
elif job_info.status == JOB_STATUS.CANCELED:
openeo_status = "canceled"
elif job_info.status == JOB_STATUS.QUEUED:
openeo_status = "running"
elif job_info.status == JOB_STATUS.CREATED:
openeo_status = "running"
else:
raise AssertionError(f"unexpected job status: {job_info.status!r}")

result = {
"openeo:status": "running",
"openeo:status": openeo_status,
"type": "Collection",
"stac_version": "1.0.0",
"id": job_id,
Expand Down Expand Up @@ -1082,6 +1095,7 @@ def job_result_item_url(item_id) -> str:
"providers": providers or None,
"links": links,
"assets": assets,
"openeo:status": "finished",
}
)

Expand All @@ -1106,7 +1120,8 @@ def job_result_item_url(item_id) -> str:
"id": job_info.id,
"properties": _properties_from_job_info(job_info),
"assets": assets,
"links": links
"links": links,
"openeo:status": "finished",
}
if providers:
result["providers"] = providers
Expand Down
112 changes: 92 additions & 20 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1299,17 +1299,30 @@ def test_get_job_results_unfinished_with_partial_explicitly_false(self, api):
resp = api.get("/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results?partial=false", headers=self.AUTH_HEADER)
resp.assert_error(400, "JobNotFinished")

def test_get_job_results_unfinished_with_partial_true(self, api):
@pytest.mark.parametrize(
["job_status", "expected_openeo_status"],
[
("running", "running"),
("created", "running"),
("queued", "running"),
("error", "error"),
("canceled", "canceled"),
],
)
def test_get_job_results_unfinished_with_partial_true(self, api, job_status, expected_openeo_status):
job_id = "07024ee9-7847-4b8a-b260-6c879a2b3cdc"
with self._fresh_job_registry(next_job_id="job-345"):
dummy_backend.DummyBatchJobs._update_status(
job_id="07024ee9-7847-4b8a-b260-6c879a2b3cdc", user_id=TEST_USER, status=job_status
)
resp: ApiResponse = api.get(f"/jobs/{job_id}/results?partial=true", headers=self.AUTH_HEADER)
resp.assert_status_code(200)

job_result = resp.json
expected_canonical_url = f"http://oeo.net/openeo/{api.api_version}/jobs/{job_id}/results"
assert job_result == DictSubSet(
{
"openeo:status": "running",
"openeo:status": expected_openeo_status,
"type": "Collection",
"stac_version": "1.0.0",
"id": job_id,
Expand All @@ -1326,6 +1339,18 @@ def test_get_job_results_unfinished_with_partial_true(self, api):
}
)

def test_get_job_results_unfinished_with_partial_true_and_unsupported_jobstatus_raises_assertionerror(self, api):
"""Verify that we raise an error when the backend gives us a job status value that we don't support yet."""
job_id = "07024ee9-7847-4b8a-b260-6c879a2b3cdc"
with self._fresh_job_registry(next_job_id="job-345"):
dummy_backend.DummyBatchJobs._update_status(
job_id="07024ee9-7847-4b8a-b260-6c879a2b3cdc", user_id=TEST_USER, status="unsupported_status"
)
resp: ApiResponse = api.get(f"/jobs/{job_id}/results?partial=true", headers=self.AUTH_HEADER)

resp.assert_status_code(500)
assert resp.json["message"] == """Server error: AssertionError("unexpected job status: 'unsupported_status'")"""

def test_get_job_results_100(self, api100):
with self._fresh_job_registry(next_job_id="job-362"):
dummy_backend.DummyBatchJobs._update_status(
Expand Down Expand Up @@ -1388,6 +1413,7 @@ def test_get_job_results_100(self, api100):
],
"stac_version": "0.9.0",
"type": "Feature",
"openeo:status": "finished",
}

resp = api100.get('/jobs/53c71345-09b4-46b4-b6b0-03fd6fe1f199/results', headers=self.AUTH_HEADER)
Expand Down Expand Up @@ -1462,6 +1488,7 @@ def test_get_job_results_100(self, api100):
],
"stac_version": "0.9.0",
"type": "Feature",
"openeo:status": "finished",
}

def test_get_job_results_110(self, api110):
Expand Down Expand Up @@ -1535,6 +1562,7 @@ def test_get_job_results_110(self, api110):
],
"stac_version": "1.0.0",
"type": "Collection",
"openeo:status": "finished",
}

resp = api110.get("/jobs/53c71345-09b4-46b4-b6b0-03fd6fe1f199/results", headers=self.AUTH_HEADER)
Expand Down Expand Up @@ -1609,6 +1637,7 @@ def test_get_job_results_110(self, api110):
"title": "Your title here.",
"stac_version": "1.0.0",
"type": "Collection",
"openeo:status": "finished",
}

def test_get_job_results_public_href_asset_100(self, api, backend_implementation):
Expand Down Expand Up @@ -1699,6 +1728,7 @@ def test_get_job_results_signed_100(self, api100, flask_app, backend_config_over
],
"stac_version": "0.9.0",
"type": "Feature",
"openeo:status": "finished",
}

@pytest.mark.parametrize("backend_config_overrides", [{"url_signer": UrlSigner(secret="123&@#")}])
Expand All @@ -1712,18 +1742,29 @@ def test_get_job_results_signed_100_unfinished_and_partial_false(self, api100, f
)
resp.assert_error(400, "JobNotFinished")

@pytest.mark.parametrize("backend_config_overrides", [{"url_signer": UrlSigner(secret="123&@#")}])
def test_get_job_results_signed_100_unfinished_and_partial_true(self, api100, flask_app, backend_config_overrides):
@pytest.mark.parametrize(
["backend_config_overrides", "job_status", "expected_openeo_status"],
[
[{"url_signer": UrlSigner(secret="123&@#")}, "running", "running"],
[{"url_signer": UrlSigner(secret="123&@#")}, "error", "error"],
[{"url_signer": UrlSigner(secret="123&@#")}, "canceled", "canceled"],
[{"url_signer": UrlSigner(secret="123&@#")}, "queued", "running"],
[{"url_signer": UrlSigner(secret="123&@#")}, "created", "running"],
],
)
def test_get_job_results_signed_100_unfinished_and_partial_true(
self, api100, flask_app, backend_config_overrides, job_status, expected_openeo_status
):
job_id = "07024ee9-7847-4b8a-b260-6c879a2b3cdc"
with self._fresh_job_registry():
dummy_backend.DummyBatchJobs._update_status(job_id=job_id, user_id=TEST_USER, status="running")
dummy_backend.DummyBatchJobs._update_status(job_id=job_id, user_id=TEST_USER, status=job_status)
resp = api100.get(f"/jobs/{job_id}/results?partial=true", headers=self.AUTH_HEADER)

resp.assert_status_code(200)
expected_canonical_url = f"http://oeo.net/openeo/1.0.0/jobs/{job_id}/results/TXIuVGVzdA%3D%3D/05cb8b78f20c68a5aa9eb05249928d24?partial=true"
assert resp.json == DictSubSet(
{
"openeo:status": "running",
"openeo:status": expected_openeo_status,
"type": "Collection",
"stac_version": "1.0.0",
"id": job_id,
Expand Down Expand Up @@ -1811,6 +1852,7 @@ def test_get_job_results_signed_110(self, api110, flask_app, backend_config_over
],
"stac_version": "1.0.0",
"type": "Collection",
"openeo:status": "finished",
}

@pytest.mark.parametrize("backend_config_overrides", [{"url_signer": UrlSigner(secret="123&@#")}])
Expand All @@ -1824,12 +1866,23 @@ def test_get_job_results_signed_110_unfinished_and_partial_false(self, api110, f
)
resp.assert_error(400, "JobNotFinished")

@pytest.mark.parametrize("backend_config_overrides", [{"url_signer": UrlSigner(secret="123&@#")}])
def test_get_job_results_signed_110_unfinished_and_partial_true(self, api110, flask_app, backend_config_overrides):
@pytest.mark.parametrize(
["backend_config_overrides", "job_status", "expected_openeo_status"],
[
[{"url_signer": UrlSigner(secret="123&@#")}, "running", "running"],
[{"url_signer": UrlSigner(secret="123&@#")}, "error", "error"],
[{"url_signer": UrlSigner(secret="123&@#")}, "canceled", "canceled"],
[{"url_signer": UrlSigner(secret="123&@#")}, "queued", "running"],
[{"url_signer": UrlSigner(secret="123&@#")}, "created", "running"],
],
)
def test_get_job_results_signed_110_unfinished_and_partial_true(
self, api110, flask_app, backend_config_overrides, job_status, expected_openeo_status
):
job_id = "07024ee9-7847-4b8a-b260-6c879a2b3cdc"
with self._fresh_job_registry():
dummy_backend.DummyBatchJobs._update_status(
job_id="07024ee9-7847-4b8a-b260-6c879a2b3cdc", user_id=TEST_USER, status="running"
job_id="07024ee9-7847-4b8a-b260-6c879a2b3cdc", user_id=TEST_USER, status=job_status
)
resp: ApiResponse = api110.get(
"/jobs/07024ee9-7847-4b8a-b260-6c879a2b3cdc/results?partial=true", headers=self.AUTH_HEADER
Expand All @@ -1839,7 +1892,7 @@ def test_get_job_results_signed_110_unfinished_and_partial_true(self, api110, fl
expected_canonical_url = f"http://oeo.net/openeo/1.1.0/jobs/{job_id}/results/TXIuVGVzdA%3D%3D/05cb8b78f20c68a5aa9eb05249928d24?partial=true"
assert resp.json == DictSubSet(
{
"openeo:status": "running",
"openeo:status": expected_openeo_status,
"type": "Collection",
"stac_version": "1.0.0",
"id": job_id,
Expand Down Expand Up @@ -1920,6 +1973,7 @@ def test_get_job_results_signed_with_expiration_100(self, api100, flask_app, bac
],
"stac_version": "0.9.0",
"type": "Feature",
"openeo:status": "finished",
}

@mock.patch("time.time", mock.MagicMock(return_value=1234))
Expand All @@ -1937,20 +1991,29 @@ def test_get_job_results_signed_with_expiration_100_unfinished_and_partial_false
resp.assert_error(400, "JobNotFinished")

@mock.patch("time.time", mock.MagicMock(return_value=1234))
@pytest.mark.parametrize("backend_config_overrides", [{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}])
@pytest.mark.parametrize(
["backend_config_overrides", "job_status", "expected_openeo_status"],
[
[{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}, "running", "running"],
[{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}, "error", "error"],
[{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}, "canceled", "canceled"],
[{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}, "queued", "running"],
[{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}, "created", "running"],
],
)
def test_get_job_results_signed_with_expiration_100_unfinished_and_partial_true(
self, api100, flask_app, backend_config_overrides
self, api100, flask_app, backend_config_overrides, job_status, expected_openeo_status
):
job_id = "07024ee9-7847-4b8a-b260-6c879a2b3cdc"
with self._fresh_job_registry():
dummy_backend.DummyBatchJobs._update_status(job_id=job_id, user_id=TEST_USER, status="running")
dummy_backend.DummyBatchJobs._update_status(job_id=job_id, user_id=TEST_USER, status=job_status)
resp = api100.get(f"/jobs/{job_id}/results?partial=true", headers=self.AUTH_HEADER)
resp.assert_status_code(200)

expected_canonical_url = f"http://oeo.net/openeo/1.0.0/jobs/{job_id}/results/TXIuVGVzdA%3D%3D/9fea29cd94195399cc4d902388a3c32c?expires=2234&partial=true"
assert resp.json == DictSubSet(
{
"openeo:status": "running",
"openeo:status": expected_openeo_status,
"type": "Collection",
"stac_version": "1.0.0",
"id": job_id,
Expand Down Expand Up @@ -2042,7 +2105,8 @@ def test_get_job_results_signed_with_expiration_110(self, api110, flask_app, bac
'title': 'randomforest.model',
'type': 'application/octet-stream'
}
}
},
"openeo:status": "finished",
}

@mock.patch("time.time", mock.MagicMock(return_value=1234))
Expand All @@ -2057,21 +2121,29 @@ def test_get_job_results_signed_with_expiration_110_unfinished_and_partial_false
resp.assert_error(400, "JobNotFinished")

@mock.patch("time.time", mock.MagicMock(return_value=1234))
@pytest.mark.parametrize("backend_config_overrides", [{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}])
@pytest.mark.parametrize(
["backend_config_overrides", "job_status", "expected_openeo_status"],
[
[{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}, "running", "running"],
[{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}, "error", "error"],
[{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}, "canceled", "canceled"],
[{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}, "queued", "running"],
[{"url_signer": UrlSigner(secret="123&@#", expiration=1000)}, "created", "running"],
],
)
def test_get_job_results_signed_with_expiration_110_unfinished_and_partial_true(
self, api110, flask_app, backend_config_overrides
self, api110, flask_app, backend_config_overrides, job_status, expected_openeo_status
):
job_id = "07024ee9-7847-4b8a-b260-6c879a2b3cdc"
with self._fresh_job_registry(next_job_id="job-373"):
dummy_backend.DummyBatchJobs._update_status(job_id=job_id, user_id=TEST_USER, status="running")
dummy_backend.DummyBatchJobs._update_status(job_id=job_id, user_id=TEST_USER, status=job_status)
resp = api110.get(f"/jobs/{job_id}/results?partial=true", headers=self.AUTH_HEADER)
resp.assert_status_code(200)

job_result = resp.json
expected_canonical_url = f"http://oeo.net/openeo/1.1.0/jobs/{job_id}/results/TXIuVGVzdA%3D%3D/9fea29cd94195399cc4d902388a3c32c?expires=2234&partial=true"
assert resp.json == DictSubSet(
{
"openeo:status": "running",
"openeo:status": expected_openeo_status,
"type": "Collection",
"stac_version": "1.0.0",
"id": job_id,
Expand Down

0 comments on commit 1de3faa

Please sign in to comment.