|
5 | 5 | from fastapi import status |
6 | 6 | from httpx import AsyncClient, BasicAuth |
7 | 7 | from models_library.api_schemas_long_running_tasks.tasks import TaskGet, TaskStatus |
| 8 | +from models_library.api_schemas_rpc_async_jobs.exceptions import ( |
| 9 | + BaseAsyncjobRpcError, |
| 10 | + JobAbortedError, |
| 11 | + JobError, |
| 12 | + JobNotDoneError, |
| 13 | + JobSchedulerError, |
| 14 | +) |
8 | 15 | from pytest_mock import MockerFixture, MockType |
9 | 16 | from pytest_simcore.helpers.async_jobs_server import AsyncJobSideEffects |
10 | 17 | from simcore_service_api_server.models.schemas.tasks import ApiServerEnvelope |
|
13 | 20 |
|
14 | 21 |
|
15 | 22 | @pytest.fixture |
16 | | -async def async_jobs_rpc_side_effects() -> Any: |
17 | | - return AsyncJobSideEffects() |
| 23 | +async def async_jobs_rpc_side_effects( |
| 24 | + async_job_error: BaseAsyncjobRpcError | None, |
| 25 | +) -> Any: |
| 26 | + return AsyncJobSideEffects(exception=async_job_error) |
18 | 27 |
|
19 | 28 |
|
20 | 29 | @pytest.fixture |
@@ -51,48 +60,127 @@ def mocked_async_jobs_rpc_api( |
51 | 60 | return mocks |
52 | 61 |
|
53 | 62 |
|
| 63 | +@pytest.mark.parametrize( |
| 64 | + "async_job_error, expected_status_code", |
| 65 | + [ |
| 66 | + (None, status.HTTP_200_OK), |
| 67 | + ( |
| 68 | + JobSchedulerError( |
| 69 | + exc=Exception("A very rare exception raised by the scheduler") |
| 70 | + ), |
| 71 | + status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 72 | + ), |
| 73 | + ], |
| 74 | +) |
54 | 75 | async def test_get_async_jobs( |
55 | | - client: AsyncClient, mocked_async_jobs_rpc_api: dict[str, MockType], auth: BasicAuth |
| 76 | + client: AsyncClient, |
| 77 | + mocked_async_jobs_rpc_api: dict[str, MockType], |
| 78 | + auth: BasicAuth, |
| 79 | + expected_status_code: int, |
56 | 80 | ): |
57 | 81 |
|
58 | 82 | response = await client.get("/v0/tasks", auth=auth) |
59 | | - assert response.status_code == status.HTTP_200_OK |
60 | 83 | assert mocked_async_jobs_rpc_api["list_jobs"].called |
61 | | - result = ApiServerEnvelope[list[TaskGet]].model_validate_json(response.text) |
62 | | - assert len(result.data) > 0 |
63 | | - assert all(isinstance(task, TaskGet) for task in result.data) |
64 | | - task = result.data[0] |
65 | | - assert task.abort_href == f"/v0/tasks/{task.task_id}:cancel" |
66 | | - assert task.result_href == f"/v0/tasks/{task.task_id}/result" |
67 | | - assert task.status_href == f"/v0/tasks/{task.task_id}" |
68 | | - |
69 | | - |
| 84 | + assert response.status_code == expected_status_code |
| 85 | + |
| 86 | + if response.status_code == status.HTTP_200_OK: |
| 87 | + result = ApiServerEnvelope[list[TaskGet]].model_validate_json(response.text) |
| 88 | + assert len(result.data) > 0 |
| 89 | + assert all(isinstance(task, TaskGet) for task in result.data) |
| 90 | + task = result.data[0] |
| 91 | + assert task.abort_href == f"/v0/tasks/{task.task_id}:cancel" |
| 92 | + assert task.result_href == f"/v0/tasks/{task.task_id}/result" |
| 93 | + assert task.status_href == f"/v0/tasks/{task.task_id}" |
| 94 | + |
| 95 | + |
| 96 | +@pytest.mark.parametrize( |
| 97 | + "async_job_error, expected_status_code", |
| 98 | + [ |
| 99 | + (None, status.HTTP_200_OK), |
| 100 | + ( |
| 101 | + JobSchedulerError( |
| 102 | + exc=Exception("A very rare exception raised by the scheduler") |
| 103 | + ), |
| 104 | + status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 105 | + ), |
| 106 | + ], |
| 107 | +) |
70 | 108 | async def test_get_async_jobs_status( |
71 | | - client: AsyncClient, mocked_async_jobs_rpc_api: dict[str, MockType], auth: BasicAuth |
| 109 | + client: AsyncClient, |
| 110 | + mocked_async_jobs_rpc_api: dict[str, MockType], |
| 111 | + auth: BasicAuth, |
| 112 | + expected_status_code: int, |
72 | 113 | ): |
73 | 114 | task_id = f"{_faker.uuid4()}" |
74 | 115 | response = await client.get(f"/v0/tasks/{task_id}", auth=auth) |
75 | | - assert response.status_code == status.HTTP_200_OK |
76 | 116 | assert mocked_async_jobs_rpc_api["status"].called |
77 | 117 | assert f"{mocked_async_jobs_rpc_api['status'].call_args[1]['job_id']}" == task_id |
78 | | - TaskStatus.model_validate_json(response.text) |
79 | | - |
80 | | - |
| 118 | + assert response.status_code == expected_status_code |
| 119 | + if response.status_code == status.HTTP_200_OK: |
| 120 | + TaskStatus.model_validate_json(response.text) |
| 121 | + |
| 122 | + |
| 123 | +@pytest.mark.parametrize( |
| 124 | + "async_job_error, expected_status_code", |
| 125 | + [ |
| 126 | + (None, status.HTTP_204_NO_CONTENT), |
| 127 | + ( |
| 128 | + JobSchedulerError( |
| 129 | + exc=Exception("A very rare exception raised by the scheduler") |
| 130 | + ), |
| 131 | + status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 132 | + ), |
| 133 | + ], |
| 134 | +) |
81 | 135 | async def test_cancel_async_job( |
82 | | - client: AsyncClient, mocked_async_jobs_rpc_api: dict[str, MockType], auth: BasicAuth |
| 136 | + client: AsyncClient, |
| 137 | + mocked_async_jobs_rpc_api: dict[str, MockType], |
| 138 | + auth: BasicAuth, |
| 139 | + expected_status_code: int, |
83 | 140 | ): |
84 | 141 | task_id = f"{_faker.uuid4()}" |
85 | 142 | response = await client.post(f"/v0/tasks/{task_id}:cancel", auth=auth) |
86 | | - assert response.status_code == status.HTTP_204_NO_CONTENT |
87 | 143 | assert mocked_async_jobs_rpc_api["cancel"].called |
88 | 144 | assert f"{mocked_async_jobs_rpc_api['cancel'].call_args[1]['job_id']}" == task_id |
89 | | - |
90 | | - |
| 145 | + assert response.status_code == expected_status_code |
| 146 | + |
| 147 | + |
| 148 | +@pytest.mark.parametrize( |
| 149 | + "async_job_error, expected_status_code", |
| 150 | + [ |
| 151 | + (None, status.HTTP_200_OK), |
| 152 | + ( |
| 153 | + JobError( |
| 154 | + job_id=_faker.uuid4(), |
| 155 | + exc_type=Exception, |
| 156 | + exc_message="An exception from inside the async job", |
| 157 | + ), |
| 158 | + status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 159 | + ), |
| 160 | + ( |
| 161 | + JobNotDoneError(job_id=_faker.uuid4()), |
| 162 | + status.HTTP_404_NOT_FOUND, |
| 163 | + ), |
| 164 | + ( |
| 165 | + JobAbortedError(job_id=_faker.uuid4()), |
| 166 | + status.HTTP_409_CONFLICT, |
| 167 | + ), |
| 168 | + ( |
| 169 | + JobSchedulerError( |
| 170 | + exc=Exception("A very rare exception raised by the scheduler") |
| 171 | + ), |
| 172 | + status.HTTP_500_INTERNAL_SERVER_ERROR, |
| 173 | + ), |
| 174 | + ], |
| 175 | +) |
91 | 176 | async def test_get_async_job_result( |
92 | | - client: AsyncClient, mocked_async_jobs_rpc_api: dict[str, MockType], auth: BasicAuth |
| 177 | + client: AsyncClient, |
| 178 | + mocked_async_jobs_rpc_api: dict[str, MockType], |
| 179 | + auth: BasicAuth, |
| 180 | + expected_status_code: int, |
93 | 181 | ): |
94 | 182 | task_id = f"{_faker.uuid4()}" |
95 | 183 | response = await client.get(f"/v0/tasks/{task_id}/result", auth=auth) |
96 | | - assert response.status_code == status.HTTP_200_OK |
| 184 | + assert response.status_code == expected_status_code |
97 | 185 | assert mocked_async_jobs_rpc_api["result"].called |
98 | 186 | assert f"{mocked_async_jobs_rpc_api['result'].call_args[1]['job_id']}" == task_id |
0 commit comments