Skip to content

Commit

Permalink
👽️ 🐛 fix stop job endpoint in API server (#5069)
Browse files Browse the repository at this point in the history
  • Loading branch information
bisgaard-itis authored Nov 22, 2023
1 parent 0177abf commit 5ad8c46
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 4 deletions.
2 changes: 1 addition & 1 deletion services/api-server/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Job"
"$ref": "#/components/schemas/JobStatus"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ async def start_job(

@router.post(
"/{solver_key:path}/releases/{version}/jobs/{job_id:uuid}:stop",
response_model=Job,
response_model=JobStatus,
)
async def stop_job(
solver_key: SolverKeyId,
Expand Down
118 changes: 118 additions & 0 deletions services/api-server/tests/mocks/stop_job.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
[
{
"name": "POST /v2/computations/4989fa99-b567-43bd-978a-68c2b95fdabc:stop",
"description": "<Request('POST', 'http://director-v2:8000/v2/computations/4989fa99-b567-43bd-978a-68c2b95fdabc:stop')>",
"method": "POST",
"host": "director-v2",
"path": {
"path": "/v2/computations/{project_id}:stop",
"path_parameters": [
{
"in": "path",
"name": "project_id",
"required": true,
"schema": {
"title": "Project Id",
"type": "str",
"pattern": null,
"format": "uuid",
"exclusiveMinimum": null,
"minimum": null,
"anyOf": null,
"allOf": null,
"oneOf": null
},
"response_value": "computations"
}
]
},
"query": null,
"request_payload": {
"user_id": 1
},
"response_body": {
"id": "4989fa99-b567-43bd-978a-68c2b95fdabc",
"state": "NOT_STARTED",
"result": null,
"pipeline_details": {
"adjacency_list": {
"0c8b627e-2d3e-5560-a4de-f6cbc8ebca2f": []
},
"progress": 0.0,
"node_states": {
"0c8b627e-2d3e-5560-a4de-f6cbc8ebca2f": {
"modified": true,
"dependencies": [],
"currentStatus": "NOT_STARTED",
"progress": null
}
}
},
"iteration": null,
"cluster_id": null,
"started": null,
"stopped": null,
"submitted": "2023-11-17T13:04:59.327557+00:00",
"url": "http://director-v2:8000/v2/computations/4989fa99-b567-43bd-978a-68c2b95fdabc:stop",
"stop_url": null
},
"status_code": 202
},
{
"name": "GET /v2/computations/4989fa99-b567-43bd-978a-68c2b95fdabc",
"description": "<Request('GET', 'http://director-v2:8000/v2/computations/4989fa99-b567-43bd-978a-68c2b95fdabc?user_id=1')>",
"method": "GET",
"host": "director-v2",
"path": {
"path": "/v2/computations/{project_id}",
"path_parameters": [
{
"in": "path",
"name": "project_id",
"required": true,
"schema": {
"title": "Project Id",
"type": "str",
"pattern": null,
"format": "uuid",
"exclusiveMinimum": null,
"minimum": null,
"anyOf": null,
"allOf": null,
"oneOf": null
},
"response_value": "computations"
}
]
},
"query": "user_id=1",
"request_payload": null,
"response_body": {
"id": "4989fa99-b567-43bd-978a-68c2b95fdabc",
"state": "NOT_STARTED",
"result": null,
"pipeline_details": {
"adjacency_list": {
"0c8b627e-2d3e-5560-a4de-f6cbc8ebca2f": []
},
"progress": 0.0,
"node_states": {
"0c8b627e-2d3e-5560-a4de-f6cbc8ebca2f": {
"modified": true,
"dependencies": [],
"currentStatus": "NOT_STARTED",
"progress": null
}
}
},
"iteration": null,
"cluster_id": null,
"started": null,
"stopped": null,
"submitted": "2023-11-17T13:04:59.327557+00:00",
"url": "http://director-v2:8000/v2/computations/4989fa99-b567-43bd-978a-68c2b95fdabc?user_id=1",
"stop_url": null
},
"status_code": 200
}
]
48 changes: 46 additions & 2 deletions services/api-server/tests/unit/test_api_solver_jobs.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
from pathlib import Path
from typing import Any, Callable
from typing import Any, Callable, Final
from uuid import UUID

import httpx
import pytest
import respx
from faker import Faker
from fastapi import status
from fastapi.encoders import jsonable_encoder
from httpx import AsyncClient
from models_library.api_schemas_webserver.resource_usage import PricingUnitGet
from pydantic import parse_obj_as
from simcore_service_api_server._meta import API_VTAG
from simcore_service_api_server.models.schemas.jobs import Job
from simcore_service_api_server.models.schemas.jobs import Job, JobStatus
from simcore_service_api_server.models.schemas.solvers import Solver
from simcore_service_api_server.services.director_v2 import ComputationTaskGet
from simcore_service_api_server.utils.http_calls_capture import HttpApiCallCaptureModel
from unit.conftest import SideEffectCallback

Expand Down Expand Up @@ -297,3 +299,45 @@ async def test_get_solver_job_pricing_unit_no_payment(

assert response.status_code == status.HTTP_200_OK
assert response.json()["job_id"] == _job_id


async def test_stop_job(
client: AsyncClient,
mocked_directorv2_service_api_base,
mocked_groups_extra_properties,
respx_mock_from_capture: Callable[
[list[respx.MockRouter], Path, list[SideEffectCallback]],
list[respx.MockRouter],
],
auth: httpx.BasicAuth,
project_tests_dir: Path,
):

_solver_key: Final[str] = "simcore/services/comp/isolve"
_version: Final[str] = "2.1.24"
_job_id: Final[str] = "1eefc09b-5d08-4022-bc18-33dedbbd7d0f"

def _stop_job_side_effect(
request: httpx.Request,
path_params: dict[str, Any],
capture: HttpApiCallCaptureModel,
) -> Any:
task = ComputationTaskGet.parse_obj(capture.response_body)
task.id = UUID(_job_id)

return jsonable_encoder(task)

respx_mock = respx_mock_from_capture(
[mocked_directorv2_service_api_base],
project_tests_dir / "mocks" / "stop_job.json",
[_stop_job_side_effect, get_inspect_job_side_effect(job_id=_job_id)],
)

response = await client.post(
f"{API_VTAG}/solvers/{_solver_key}/releases/{_version}/jobs/{_job_id}:stop",
auth=auth,
)

assert response.status_code == status.HTTP_200_OK
status_ = JobStatus.parse_obj(response.json())
assert status_.job_id == UUID(_job_id)

0 comments on commit 5ad8c46

Please sign in to comment.