"""Test handle_artwork handler.""" import json from unittest.mock import MagicMock from unittest.mock import patch from constants.artwork import MAX_ARTWORK_IMAGE_SIZE from constants.artwork import MIN_ARTWORK_IMAGE_SIZE from constants.artwork import NEW_ROOT_SUBFOLDER from constants.artwork import RESIZED_ARTWORK_QUALITY import pytest from src.index import handler from util.s3_image import get_image_from_s3 from util.s3_image import repair_image from util.s3_image import save_image_to_s3 @patch('util.s3_image.boto3.client') @patch('util.s3_image.get_current_logger') @patch('util.s3_image.BytesIO') @patch('util.s3_image.Image') def test_get_image_from_s3( mock_pil_image, mock_bytes, mock_logger, mock_boto3_client): """Test loading artwork image data.""" mock_boto3_client_return = MagicMock() mock_boto3_client.return_value = mock_boto3_client_return mock_get_object = MagicMock() mock_boto3_client_return.get_object = mock_get_object mock_get_object_body = MagicMock() mock_get_object_body.read.return_value = b'ArtworkImageData' mock_get_object.return_value = {'Body': mock_get_object_body} mock_image = mock_pil_image.open.return_value mock_key = 'key.jpg' mock_bucket = 'bucket' output = get_image_from_s3(mock_bucket, mock_key) mock_boto3_client.assert_called_once_with('s3') mock_get_object.assert_called_once_with( Bucket=mock_bucket, Key=mock_key ) assert output == mock_image @pytest.mark.parametrize('test_width,test_height,expected,test_mode', [ (2000, 2000, MIN_ARTWORK_IMAGE_SIZE, 'RGB'), (7000, 7000, MAX_ARTWORK_IMAGE_SIZE, 'RGB')]) @patch('util.s3_image.boto3.client') @patch('util.s3_image.get_current_logger') def test_repair_image_square(mock_logger, mock_boto3_client, test_width, test_height, expected, test_mode): """Test resizing pillow image object.""" mock_image_object = MagicMock() mock_resized_image = MagicMock( mode=test_mode, width=max(test_width, test_height)) mock_image_object.resize.return_value = mock_resized_image mock_image_object.width = test_width mock_image_object.height = test_height mock_image_object.mode = test_mode mock_image_name = 'file_name.jpg' repair_image(mock_image_name, mock_image_object) mock_image_object.resize.assert_called_with((expected, expected)) @patch('util.s3_image.boto3.client') @patch('util.s3_image.get_current_logger') def test_repair_image_non_square(mock_logger, mock_boto3_client): """Test resizing pillow image object.""" mock_image_object = MagicMock() # return_value = mock_resized_image test_width = 3500 test_height = 4200 test_mode = 'RGB' mock_resized_image = MagicMock( height=max(test_height, test_width), width=max(test_height, test_width), mode=test_mode ) mock_image_object.width = test_width mock_image_object.height = test_height mock_image_object.mode = 'RGB' mock_image_object.resize.return_value = mock_resized_image mock_image_name = 'file_name.jpg' repair_image(mock_image_name, mock_image_object) mock_image_object.resize.assert_called_with((test_height, test_height)) @patch('util.s3_image.boto3.client') @patch('util.s3_image.get_current_logger') def test_repair_image_mode(mock_logger, mock_boto3_client): """Test resizing pillow image object.""" mock_image_object = MagicMock(width=MIN_ARTWORK_IMAGE_SIZE, height=MIN_ARTWORK_IMAGE_SIZE) mock_convert_image = MagicMock(width=3000, height=3000) mock_image_object.convert.return_value = mock_convert_image mock_image_object.mode = 'CMYK' mock_image_name = 'file_name.jpg' repair_image(mock_image_name, mock_image_object) mock_image_object.convert.called_once_with('RGB') @patch('util.s3_image.boto3.client') @patch('util.s3_image.get_current_logger') @patch('util.s3_image.BytesIO') def test_save_image_to_s3(mock_bytes, mock_logger, mock_boto3_client): """Test renaming artwork image file.""" mock_boto3_client_return = MagicMock() mock_boto3_client.return_value = mock_boto3_client_return mock_boto3_client_return.put_object.return_value = { 'ResponseMetadata': { 'HTTPStatusCode': 200 } } mock_buffer = mock_bytes.return_value mock_artwork = MagicMock(name='img') mock_key = 'key.jpg' mock_bucket = 'bucket' mock_dpi = (72, 72) mock_format = 'JPEG' save_image_to_s3(mock_artwork, mock_bucket, mock_key) mock_artwork.save.assert_called_once_with( mock_buffer, dpi=mock_dpi, format=mock_format, quality=RESIZED_ARTWORK_QUALITY ) mock_boto3_client_return.put_object.assert_called_once_with( Body=mock_buffer, Key=mock_key, Bucket=mock_bucket, ContentType='image/jpeg' ) @patch('src.index.config.STAGING_S3_BUCKET', 'staging_bucket') @patch('src.index.config.get_current_logger') @patch('src.index.save_image_to_s3') @patch('src.index.repair_image') @patch('src.index.get_image_from_s3') def test_handler( mock_get_image_from_s3, mock_repair_image, mock_save_image_to_s3, mock_current_logger, context_json): """Test handler.""" mock_logger = MagicMock(name='info') mock_current_logger.return_value = mock_logger bucket = 'test_bucket' key = 'test_path/test_filename.jpg' filename = 'test_filename.jpg' dpi = (300, 300) correlation_id = 'test_correlation_id' mock_get_img = MagicMock(name='get_img') mock_get_image_from_s3.return_value = mock_get_img mock_repaired_img = MagicMock(name='repair_img') mock_repair_image.return_value = mock_repaired_img mock_save_image_to_s3.return_value = filename handler(json.loads(context_json), None) mock_get_image_from_s3.assert_called_once_with(bucket, key, correlation_id) mock_repair_image.assert_called_once_with( filename, mock_get_img, correlation_id) mock_save_image_to_s3.assert_called_once_with( img=mock_repaired_img, bucket='staging_bucket', key=NEW_ROOT_SUBFOLDER + '/' + bucket + '/' + key, dpi=dpi, correlation_id=correlation_id) @patch('src.index.config.STAGING_S3_BUCKET', 'staging_bucket') @patch('src.index.config.get_current_logger') @patch('src.index.save_image_to_s3') @patch('src.index.repair_image') @patch('src.index.get_image_from_s3') def test_handler_fails_get_image( mock_get_image_from_s3, mock_repair_image, mock_save_image_to_s3, mock_current_logger, context_json): """Test handler.""" mock_logger = MagicMock(name='info') mock_current_logger.return_value = mock_logger mock_get_image_from_s3.side_effect = Exception('Get Exception') mock_get_img = MagicMock(name='get_img') mock_get_image_from_s3.return_value = mock_get_img mock_repaired_img = MagicMock(name='repair_img') mock_repair_image.return_value = mock_repaired_img with pytest.raises(Exception): handler(json.loads(context_json), None) mock_logger.error.assert_called_once() @patch('src.index.config.STAGING_S3_BUCKET', 'staging_bucket') @patch('src.index.config.get_current_logger') @patch('src.index.save_image_to_s3') @patch('src.index.repair_image') @patch('src.index.get_image_from_s3') def test_handler_fails_repair_image( mock_get_image_from_s3, mock_repair_image, mock_save_image_to_s3, mock_current_logger, context_json): """Test handler.""" mock_logger = MagicMock(name='info') mock_current_logger.return_value = mock_logger mock_repair_image.side_effect = Exception('Repair Exception') mock_get_img = MagicMock(name='get_img') mock_get_image_from_s3.return_value = mock_get_img mock_repaired_img = MagicMock(name='repair_img') mock_repair_image.return_value = mock_repaired_img with pytest.raises(Exception): handler(json.loads(context_json), None) mock_logger.error.assert_called_once() @patch('src.index.config.STAGING_S3_BUCKET', 'staging_bucket') @patch('src.index.config.get_current_logger') @patch('src.index.save_image_to_s3') @patch('src.index.repair_image') @patch('src.index.get_image_from_s3') def test_handler_fails_save_image( mock_get_image_from_s3, mock_repair_image, mock_save_image_to_s3, mock_current_logger, context_json): """Test handler.""" mock_logger = MagicMock(name='info') mock_current_logger.return_value = mock_logger mock_save_image_to_s3.side_effect = Exception('Save Exception') mock_get_img = MagicMock(name='get_img') mock_get_image_from_s3.return_value = mock_get_img mock_repaired_img = MagicMock(name='repair_img') mock_repair_image.return_value = mock_repaired_img with pytest.raises(Exception): handler(json.loads(context_json), None) mock_logger.error.assert_called_once()