Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reflect webapp pending status changes #82

Merged
merged 8 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions src/qibo_client/qibo_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ def convert_str_to_job_status(status: str):


class QiboJobStatus(Enum):
QUEUED = "to_do"
RUNNING = "in_progress"
DONE = "success"
QUEUEING = "queueing"
PENDING = "pending"
RUNNING = "running"
POSTPROCESSING = "postprocessing"
SUCCESS = "success"
ERROR = "error"


Expand Down Expand Up @@ -122,10 +124,10 @@ def running(self) -> bool:
self.refresh()
return self._status is QiboJobStatus.RUNNING

def done(self) -> bool:
def success(self) -> bool:
if self._status is None:
self.refresh()
return self._status is QiboJobStatus.DONE
return self._status is QiboJobStatus.SUCCESS

def result(
self, wait: int = 5, verbose: bool = False
Expand Down Expand Up @@ -187,7 +189,10 @@ def _wait_for_response_to_get_request(
if seconds_between_checks is None:
seconds_between_checks = constants.SECONDS_BETWEEN_CHECKS

is_job_finished = self.status() not in [QiboJobStatus.DONE, QiboJobStatus.ERROR]
is_job_finished = self.status() not in [
QiboJobStatus.SUCCESS,
QiboJobStatus.ERROR,
]
if not verbose and is_job_finished:
logger.info("Please wait until your job is completed...")

Expand All @@ -196,11 +201,16 @@ def _wait_for_response_to_get_request(
while True:
response = QiboApiRequest.get(url, timeout=constants.TIMEOUT)
job_status = convert_str_to_job_status(response.headers["Job-Status"])
if verbose and job_status == QiboJobStatus.QUEUED:
logger.info("Job QUEUING")

if verbose and job_status == QiboJobStatus.QUEUEING:
logger.info("Job QUEUEING")
if verbose and job_status == QiboJobStatus.PENDING:
logger.info("Job PENDING")
if verbose and job_status == QiboJobStatus.RUNNING:
logger.info("Job RUNNING")
if job_status in [QiboJobStatus.DONE, QiboJobStatus.ERROR]:
if verbose and job_status == QiboJobStatus.POSTPROCESSING:
logger.info("Job POSTPROCESSING")
if job_status in [QiboJobStatus.SUCCESS, QiboJobStatus.ERROR]:
if verbose:
logger.info("Job COMPLETED")
return response, job_status
Expand Down
37 changes: 18 additions & 19 deletions tests/test_config_logging.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
from unittest import TestCase
from unittest.mock import patch
import pytest

MOD = "qibo_client.config_logging"


def logging_wrap_function(logger_object):
logger_object.info("A debug log")
logger_object.debug("A debug log")
logger_object.info("An info log")
logger_object.error("An error log")


class TestLogger(TestCase):
@patch(f"{MOD}.os.environ", {"QIBO_CLIENT_LOGGER_LEVEL": "info"})
def test_logging_with_info_level(self, mock_os):
from qibo_client.config_logging import logger
@pytest.mark.parametrize(
"loglevel,expected_messages",
[
("DEBUG", ["A debug log", "An info log", "An error log"]),
("INFO", ["An info log", "An error log"]),
("ERROR", ["An error log"]),
],
)
def test_logger_levels(monkeypatch, caplog, loglevel, expected_messages):
monkeypatch.setenv("QIBO_CLIENT_LOGGER_LEVEL", loglevel)

with self.assertLogs() as captured:
logging_wrap_function(logger)
self.assertEqual(len(captured.records), 1)
self.assertEqual(captured.records[0].getMessage(), "An error log")
from qibo_client.config_logging import logger

@patch(f"{MOD}.os.environ", {"QIBO_CLIENT_LOGGER_LEVEL": "notset"})
def test_logging_with_info_level(self):
from qibo_client.config_logging import logger
caplog.set_level(loglevel, MOD)

with self.assertLogs() as captured:
logging_wrap_function(logger)
self.assertEqual(len(captured.records), 2)
self.assertEqual(captured.records[0].getMessage(), "A debug log")
self.assertEqual(captured.records[1].getMessage(), "An error log")
logging_wrap_function(logger)

assert caplog.messages == expected_messages
4 changes: 2 additions & 2 deletions tests/test_qibo_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ def test_get_job(self):
"description": None,
"status": FAKE_STATUS,
},
"status": "to_do",
"status": "queueing",
}
responses.add(responses.GET, endpoint, status=200, json=response_json)

Expand All @@ -332,5 +332,5 @@ def test_get_job(self):
nshots=FAKE_NSHOTS,
device=FAKE_DEVICE,
)
expected_result._status = QiboJobStatus.QUEUED
expected_result._status = QiboJobStatus.QUEUEING
assert vars(result) == vars(expected_result)
74 changes: 46 additions & 28 deletions tests/test_qibo_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
@pytest.mark.parametrize(
"status, expected_result",
[
("to_do", QiboJobStatus.QUEUED),
("in_progress", QiboJobStatus.RUNNING),
("success", QiboJobStatus.DONE),
("queueing", QiboJobStatus.QUEUEING),
("pending", QiboJobStatus.PENDING),
("running", QiboJobStatus.RUNNING),
("postprocessing", QiboJobStatus.POSTPROCESSING),
("success", QiboJobStatus.SUCCESS),
("error", QiboJobStatus.ERROR),
("done", None),
("invalid", None),
Expand Down Expand Up @@ -147,7 +149,7 @@ def test__save_and_unpack_stream_response_to_folder(monkeypatch, tmp_path: Path)
FAKE_HARDWARE_TYPE = "fakeHardwareType"
FAKE_DESCRIPTION = "fakeDescription"
FAKE_STATUS = "fakeStatus"
BASE_JOB_STATUS = QiboJobStatus.DONE
BASE_JOB_STATUS = QiboJobStatus.SUCCESS
BASE_JOB_STATUS_STR = "success"
FAKE_RESULT = "fakeResult"

Expand Down Expand Up @@ -208,9 +210,11 @@ def test_refresh_with_invalid_pid(self):
@pytest.mark.parametrize(
"status, expected_result",
[
("to_do", QiboJobStatus.QUEUED),
("in_progress", QiboJobStatus.RUNNING),
("success", QiboJobStatus.DONE),
("queueing", QiboJobStatus.QUEUEING),
("pending", QiboJobStatus.PENDING),
("running", QiboJobStatus.RUNNING),
("postprocessing", QiboJobStatus.POSTPROCESSING),
("success", QiboJobStatus.SUCCESS),
("error", QiboJobStatus.ERROR),
],
)
Expand All @@ -227,9 +231,11 @@ def test_status(self, status, expected_result):
@pytest.mark.parametrize(
"status, expected_result",
[
(QiboJobStatus.QUEUED, False),
(QiboJobStatus.QUEUEING, False),
(QiboJobStatus.PENDING, False),
(QiboJobStatus.RUNNING, True),
(QiboJobStatus.DONE, False),
(QiboJobStatus.POSTPROCESSING, False),
(QiboJobStatus.SUCCESS, False),
(QiboJobStatus.ERROR, False),
],
)
Expand All @@ -243,9 +249,11 @@ def test_running_with_cached_results(
@pytest.mark.parametrize(
"status, expected_result",
[
(QiboJobStatus.QUEUED, False),
(QiboJobStatus.QUEUEING, False),
(QiboJobStatus.PENDING, False),
(QiboJobStatus.RUNNING, True),
(QiboJobStatus.DONE, False),
(QiboJobStatus.POSTPROCESSING, False),
(QiboJobStatus.SUCCESS, False),
(QiboJobStatus.ERROR, False),
],
)
Expand All @@ -264,29 +272,33 @@ def change_obj_status_to():
@pytest.mark.parametrize(
"status, expected_result",
[
(QiboJobStatus.QUEUED, False),
(QiboJobStatus.QUEUEING, False),
(QiboJobStatus.PENDING, False),
(QiboJobStatus.RUNNING, False),
(QiboJobStatus.DONE, True),
(QiboJobStatus.POSTPROCESSING, False),
(QiboJobStatus.SUCCESS, True),
(QiboJobStatus.ERROR, False),
],
)
def test_done_with_cached_results(
def test_success_with_cached_results(
self, status: QiboJobStatus, expected_result: bool
):
self.obj._status = status
result = self.obj.done()
result = self.obj.success()
assert result == expected_result

@pytest.mark.parametrize(
"status, expected_result",
[
(QiboJobStatus.QUEUED, False),
(QiboJobStatus.QUEUEING, False),
(QiboJobStatus.PENDING, False),
(QiboJobStatus.RUNNING, False),
(QiboJobStatus.DONE, True),
(QiboJobStatus.POSTPROCESSING, False),
(QiboJobStatus.SUCCESS, True),
(QiboJobStatus.ERROR, False),
],
)
def test_done_without_cached_results(
def test_success_without_cached_results(
self, monkeypatch, status: QiboJobStatus, expected_result: bool
):
assert self.obj._status is None
Expand All @@ -295,7 +307,7 @@ def change_obj_status_to():
self.obj._status = status

monkeypatch.setattr(self.obj, "refresh", change_obj_status_to)
result = self.obj.done()
result = self.obj.success()
assert result == expected_result

@responses.activate
Expand All @@ -308,7 +320,7 @@ def test_result_handles_tarfile_readerror(self, monkeypatch, refresh_job):
responses.add(
responses.GET,
info_endpoint,
json={"status": "in_progress"},
json={"status": "running"},
status=200,
)

Expand All @@ -332,7 +344,7 @@ def test_result_with_job_status_error(self, monkeypatch, refresh_job):
responses.add(
responses.GET,
info_endpoint,
json={"status": "in_progress"},
json={"status": "running"},
status=200,
)

Expand All @@ -353,7 +365,7 @@ def test_result_with_job_status_success(self, monkeypatch, refresh_job):
responses.add(
responses.GET,
info_endpoint,
json={"status": "in_progress"},
json={"status": "running"},
status=200,
)

Expand All @@ -372,7 +384,7 @@ def test_result_with_job_status_success(self, monkeypatch, refresh_job):
@pytest.mark.parametrize(
"status, expected_job_status",
[
("success", QiboJobStatus.DONE),
("success", QiboJobStatus.SUCCESS),
("error", QiboJobStatus.ERROR),
],
)
Expand All @@ -387,13 +399,13 @@ def test_wait_for_response_to_get_request(
responses.add(
responses.GET,
info_endpoint,
json={"status": "in_progress"},
json={"status": "running"},
status=200,
)

failed_attempts = 3
endpoint = FAKE_URL + f"/job/result/{FAKE_PID}/"
failed_headers = {"Job-Status": "in_progress"}
failed_headers = {"Job-Status": "running"}
response_json = {"detail": "output"}
for _ in range(failed_attempts):
responses.add(
Expand Down Expand Up @@ -446,12 +458,12 @@ def test_wait_for_response_to_get_request_verbose(
responses.add(
responses.GET,
endpoint,
json={"status": "in_progress"},
json={"status": "running"},
status=200,
)

endpoint = FAKE_URL + f"/job/result/{FAKE_PID}/"
statuses_list = ["to_do", "in_progress", status]
statuses_list = ["queueing", "pending", "running", "postprocessing", status]
for s in statuses_list:
failed_headers = {"Job-Status": s}
responses.add(
Expand All @@ -462,5 +474,11 @@ def test_wait_for_response_to_get_request_verbose(
)
self.obj._wait_for_response_to_get_request(verbose=True)

expected_logs = ["Job QUEUING", "Job RUNNING", "Job COMPLETED"]
expected_logs = [
"Job QUEUEING",
"Job PENDING",
"Job RUNNING",
"Job POSTPROCESSING",
"Job COMPLETED",
]
assert caplog.messages == expected_logs