diff --git a/florist/api/routes/server/job.py b/florist/api/routes/server/job.py index 258a127..ab336b8 100644 --- a/florist/api/routes/server/job.py +++ b/florist/api/routes/server/job.py @@ -3,6 +3,7 @@ from typing import List from fastapi import APIRouter, Body, Request, status +from fastapi.responses import JSONResponse from florist.api.db.entities import MAX_RECORDS_TO_FETCH, Job, JobStatus @@ -48,3 +49,26 @@ async def list_jobs_with_status(status: JobStatus, request: Request) -> List[Job of a Job instance with the specified status. """ return await Job.find_by_status(status, MAX_RECORDS_TO_FETCH, request.app.database) + + +@router.post(path="/change_status", response_description="Change job to the specified status") +async def change_job_status(job_id: str, status: JobStatus, request: Request) -> JSONResponse: + """ + Change job job_id to specified status. + + :param job_id: (str) The id of the job to change the status of. + :param status: (JobStatus) The status to change job_id to. + :param request: (fastapi.Request) the FastAPI request object. + + :return: (JSONResponse) If successful, returns 200. If not successful, returns response with status code 400 + and body: {"error": } + """ + job_in_db = await Job.find_by_id(job_id, request.app.database) + try: + assert job_in_db is not None, f"Job {job_id} not found" + await job_in_db.set_status(status, request.app.database) + return JSONResponse(content={"status": "success"}) + except AssertionError as assertion_e: + return JSONResponse(content={"error": str(assertion_e)}, status_code=400) + except Exception as general_e: + return JSONResponse(content={"error": str(general_e)}, status_code=500) diff --git a/florist/tests/unit/api/routes/server/test_job.py b/florist/tests/unit/api/routes/server/test_job.py new file mode 100644 index 0000000..3e448b5 --- /dev/null +++ b/florist/tests/unit/api/routes/server/test_job.py @@ -0,0 +1,71 @@ +import json + +from unittest.mock import patch, Mock, AsyncMock +from fastapi.responses import JSONResponse + +from florist.api.routes.server.job import change_job_status +from florist.api.db.entities import JobStatus + +@patch("florist.api.db.entities.Job.find_by_id") +async def test_change_job_status_success(mock_find_by_id: Mock) -> None: + mock_job = Mock() + mock_job.set_status = AsyncMock() + + mock_find_by_id.return_value = mock_job + + mock_request = Mock() + mock_request.app.database = Mock() + + test_id = "test_id" + test_status = JobStatus.NOT_STARTED + + response = await change_job_status(test_id, test_status, mock_request) + + mock_find_by_id.assert_called_once_with(test_id, mock_request.app.database) + mock_job.set_status.assert_called_once_with(test_status, mock_request.app.database) + + assert isinstance(response, JSONResponse) + assert response.status_code == 200 + assert json.loads(response.body.decode("utf-8")) == {"status": "success"} + +@patch("florist.api.db.entities.Job.find_by_id") +async def test_change_job_status_failure_in_find_by_id(mock_find_by_id: Mock) -> None: + mock_find_by_id.return_value = None + + mock_request = Mock() + mock_request.app.database = Mock() + + test_id = "test_id" + test_status = JobStatus.NOT_STARTED + + response = await change_job_status(test_id, test_status, mock_request) + + mock_find_by_id.assert_called_once_with(test_id, mock_request.app.database) + + assert isinstance(response, JSONResponse) + assert response.status_code == 400 + assert json.loads(response.body.decode("utf-8")) == {"error": "Job test_id not found"} + + +@patch("florist.api.db.entities.Job.find_by_id") +async def test_change_job_status_failure_in_set_status(mock_find_by_id: Mock) -> None: + mock_job = Mock() + mock_job.set_status = AsyncMock() + mock_job.set_status.side_effect = ValueError("Test Error") + + mock_find_by_id.return_value = mock_job + + mock_request = Mock() + mock_request.app.database = Mock() + + test_id = "test_id" + test_status = JobStatus.NOT_STARTED + + response = await change_job_status(test_id, test_status, mock_request) + + mock_find_by_id.assert_called_once_with(test_id, mock_request.app.database) + mock_job.set_status.assert_called_once_with(test_status, mock_request.app.database) + + assert isinstance(response, JSONResponse) + assert response.status_code == 500 + assert json.loads(response.body.decode("utf-8")) == {"error": "Test Error"}