"""Test review queue item utils.""" import json from contextlib import nullcontext as does_not_raise from datetime import datetime, timedelta, timezone import pytest from freezegun import freeze_time from sqlalchemy.exc import OperationalError from product_review.models import review_queue as review_queue_model from product_review.util import review_queue_item as review_queue_item_util some_exception = Exception("some exception") test_check_lock_current_user_id = "5df21529-2026-4ee9-b823-99b69ade48fd" test_check_lock_current_datetime = datetime( 2022, 10, 28, 15, 7, 52, 444714, tzinfo=timezone.utc ) @pytest.mark.parametrize( ( "test_description", "locked_by_user_id", "locked_until_datetime", "expected_raise", "expected_raise_message", ), [ ( "no locked_by_user_id", None, test_check_lock_current_datetime.replace(tzinfo=None), does_not_raise(), "None", ), ( "no locked_until_datetime", test_check_lock_current_user_id, None, does_not_raise(), "None", ), ( "no locked_by_user_id and no locked_until_datetime", None, None, does_not_raise(), "None", ), ( "current datetime > locked_until_datetime", test_check_lock_current_user_id, test_check_lock_current_datetime.replace(tzinfo=None) - timedelta(microseconds=1), does_not_raise(), "None", ), ( "current datetime == locked_until_datetime", test_check_lock_current_user_id, test_check_lock_current_datetime.replace(tzinfo=None), does_not_raise(), "None", ), ( "locked_by_user_id == requesting user", test_check_lock_current_user_id, test_check_lock_current_datetime.replace(tzinfo=None) + timedelta(microseconds=1), does_not_raise(), "None", ), ( "locked_by_user_id != requesting user", f"{test_check_lock_current_user_id}-nope", test_check_lock_current_datetime.replace(tzinfo=None) + timedelta(microseconds=1), pytest.raises(Exception), '{"status": 403, "code": "review_queue_item_locked", "message": "Review queue item is locked."}', # noqa: E501 ), ], ) @freeze_time(test_check_lock_current_datetime) def test_check_lock( app_context, test_description, locked_by_user_id, locked_until_datetime, expected_raise, expected_raise_message, ): """Test check_lock.""" app_context.g.request_context.identity_id = test_check_lock_current_user_id with expected_raise as er: review_queue_item_util.check_lock(locked_by_user_id, locked_until_datetime) assert str(getattr(er, "value", None)) == expected_raise_message def test_get_review_queue_item_for_update_error_not_found(mocker): """Test get_review_queue_item_for_update error not found.""" mocker.patch.object(review_queue_model, "get_item_for_update", return_value=None) mocker.patch.object(review_queue_item_util, "check_lock") with pytest.raises( Exception, match=json.dumps({"status": 404, "code": "not_found", "message": "Not Found"}), ): review_queue_item_util.get_review_queue_item_for_update( review_queue_id=123, ) review_queue_model.get_item_for_update.assert_called_once_with( 123, ) review_queue_item_util.check_lock.assert_not_called() def test_get_review_queue_item_for_update_error_approval_in_progress(mocker): """Test get_review_queue_item_for_update error approval in progress.""" class DummyOrig: args = (1205, "Lock wait timeout exceeded; try restarting transaction") op_err = OperationalError("select for update", {}, DummyOrig()) mocker.patch.object( review_queue_model, "get_item_for_update", side_effect=op_err, ) mocker.patch.object(review_queue_item_util, "check_lock") with pytest.raises( Exception, match=json.dumps( { "status": 409, "code": "review_queue_item_update_in_progress", "message": "Review queue item already has an update in progress.", } ), ): review_queue_item_util.get_review_queue_item_for_update( review_queue_id=123, ) review_queue_model.get_item_for_update.assert_called_once_with(123) review_queue_item_util.check_lock.assert_not_called() def test_get_review_queue_item_for_update_error_not_new(mocker): """Test get_review_queue_item_for_update error not new.""" mock_review_queue_item = review_queue_model.ReviewQueue( review_queue_id=123, status="complete", ) mocker.patch.object( review_queue_model, "get_item_for_update", return_value=mock_review_queue_item ) mocker.patch.object(review_queue_item_util, "check_lock") with pytest.raises( Exception, match=json.dumps( { "status": 400, "code": "review_queue_item_status_not_new", "message": "Review queue item status is not new.", } ), ): review_queue_item_util.get_review_queue_item_for_update( review_queue_id=123, ) review_queue_model.get_item_for_update.assert_called_once_with( 123, ) review_queue_item_util.check_lock.assert_not_called() def test_get_review_queue_item_for_update_success(mocker): """Test get_review_queue_item_for_update success.""" mock_review_queue_item = review_queue_model.ReviewQueue( review_queue_id=123, status="new", locked_by_user_id="some-user-id", locked_until_datetime="some-datetime", ) mocker.patch.object( review_queue_model, "get_item_for_update", return_value=mock_review_queue_item ) mocker.patch.object(review_queue_item_util, "check_lock") result = review_queue_item_util.get_review_queue_item_for_update( review_queue_id=123, ) review_queue_model.get_item_for_update.assert_called_once_with(123) review_queue_item_util.check_lock.assert_called_once_with( "some-user-id", "some-datetime" ) assert result == mock_review_queue_item