"""Test handle_artwork handler.""" from io import BytesIO from unittest.mock import MagicMock, patch from index import ( construct_error_correction_items, construct_s3_metadata, format_correction_detail_data, handler, load_artwork_image, process_artwork_size, rename_original_file, resize_image, upload_s3_file, ) from PIL import Image import pytest def test_construct_error_correction_items(product_object): """Test error correction creation.""" output = construct_error_correction_items(product_object.product_id) assert type(output) is list assert output[0]['field_name'] == 'coverart' assert output[0]['key_value'] assert output[0]['key_id'] == product_object.product_id assert output[0]['table_name'] == 'releases' def test_construct_s3_metadata(product_object): """Test s3 metadata formatting.""" output = construct_s3_metadata(product_object, product_object.artwork, '0') assert output['asset_type'] == 'TIF' assert output['product_id'] == str(product_object.product_id) assert output['upc'] == product_object.upc assert output['track_unique_id'] == '0' assert output['original_filename'] == product_object.artwork.filename assert output['is_correction'] == '0' def test_format_correction_detail_data(error_correction_object): """Test correction detail payload formatting.""" product_id = error_correction_object['release_id'] release_correction_id = error_correction_object['release_correction_id'] items = error_correction_object['items'] output = format_correction_detail_data( product_id, release_correction_id, items ) assert output['productId'] == product_id assert output['releaseCorrectionId'] == release_correction_id assert output['corrections'] == [{ 'fieldName': 'coverart', 'keyValue': '"true"', 'keyId': 2851194, 'tableName': 'releases' }] @patch('boto3.client') def test_load_artwork_image(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_artwork = MagicMock() mock_artwork.bucket = 'bucket' mock_artwork.key = 'key' output = load_artwork_image(mock_artwork) mock_boto3_client.assert_called_once_with('s3') mock_get_object.assert_called_once_with( Bucket='bucket', Key='key' ) assert output == b'ArtworkImageData' @patch('boto3.client') def test_upload_s3_file(mock_boto3_client): """Test uploading file to S3.""" mock_boto3_client_return = MagicMock() mock_boto3_client.return_value = mock_boto3_client_return mock_put_object = MagicMock() mock_boto3_client_return.put_object = mock_put_object upload_s3_file('bucket', 'key', 'data') mock_boto3_client.assert_called_once_with('s3') mock_put_object.assert_called_once_with( Bucket='bucket', Key='key', Body='data' ) @patch('index.upload_s3_file') def test_rename_original_file(mock_upload_s3_file): """Test renaming artwork image file.""" mock_artwork = MagicMock() mock_artwork.bucket = 'bucket' mock_artwork.key = 'artwork.jpg' rename_original_file(mock_artwork, b'data') mock_upload_s3_file.assert_called_once_with( 'bucket', 'artwork_original.jpg', b'data' ) @pytest.mark.parametrize('test_input,expected', [ (2000, 3000), (7000, 6000)]) def test_resize_image(test_input, expected): """Test resizing pillow image object.""" mock_image_object = MagicMock() mock_resized_image = MagicMock() mock_image_object.resize.return_value = mock_resized_image resize_image(mock_image_object, test_input) mock_image_object.resize.assert_called_once_with((expected, expected)) mock_resized_image.save.assert_called_once() def test_resize_image_file(): """Test the resizing of a pillow image object using an image file.""" input_filepath = 'tests/data/Image.jpg' with open(input_filepath, 'rb') as fd: image_data = fd.read() image_object = Image.open(BytesIO(image_data)) resized_image_data = resize_image(image_object, 12500) assert len(resized_image_data) == 2240792 def test_resize_image_file_truncated(): """Test the resizing of a pillow image object using a truncated image.""" input_filepath = 'tests/data/Truncated-Image.jpg' with open(input_filepath, 'rb') as fd: image_data = fd.read() image_object = Image.open(BytesIO(image_data)) resized_image_data = resize_image(image_object, 12500) assert len(resized_image_data) == 2149156 @patch('index.Image.open') @patch('index.resize_image') @patch('index.rename_original_file') @patch('index.upload_s3_file') @patch('index.load_artwork_image') def test_process_artwork_size_small_image( mock_load_artwork_image, mock_upload_s3_file, mock_rename_original_file, mock_resize_image, mock_image_open): """Test handling of an image that needs resizing.""" mock_load_artwork_image.return_value = None mock_image_open_return = MagicMock() mock_image_open_return.size = (256, 256) mock_image_open.return_value = mock_image_open_return mock_resize_image.return_value = 'data' mock_artwork = MagicMock() mock_artwork.bucket = 'bucket' mock_artwork.key = 'key' process_artwork_size(mock_artwork) mock_load_artwork_image.assert_called_once_with(mock_artwork) mock_image_open.assert_called_once() mock_rename_original_file.assert_called_once_with(mock_artwork, None) mock_resize_image.assert_called_once() mock_upload_s3_file.assert_called_once_with('bucket', 'key', 'data') @patch('index.Image.open') @patch('index.resize_image') @patch('index.rename_original_file') @patch('index.upload_s3_file') @patch('index.load_artwork_image') def test_process_artwork_size_large_image( mock_load_artwork_image, mock_upload_s3_file, mock_rename_original_file, mock_resize_image, mock_image_open): """Test handling of an image that does not need resizing.""" mock_load_artwork_image.return_value = None mock_image_open_return = MagicMock() mock_image_open_return.size = (3000, 3000) mock_image_open.return_value = mock_image_open_return mock_resize_image.return_value = 'data' mock_artwork = MagicMock() mock_artwork.bucket = 'bucket' mock_artwork.key = 'key' process_artwork_size(mock_artwork) mock_load_artwork_image.assert_called_once_with(mock_artwork) mock_image_open.assert_called_once() @patch('index.logger') @patch('index.create_asset_token') @patch('index.copy_asset') @patch('index.format_correction_detail_data') @patch('index.graphql_gateway.execute') @patch('index.graphql_gateway') @patch('index.load_ddex_json') @patch('index.process_artwork_size') def test_handler( mock_process_artwork_size, mock_load_ddex_json, mock_graphql_gateway, mock_graphql_execute, mock_format_correction_detail_data, mock_copy_asset, mock_create_asset_token, mock_logger, s3_object): """Test handler.""" filename = '1234-5678-9101' extention = '.tif' mock_create_asset_token.return_value = { 'filename': filename, 'bucket': 'bucket', 'credentials': { 'token': 'token' } } product_id = 2851194 release_correction_id = 287202 release_correction_detail_id = 4203813 items = [{ 'key_id': product_id, 'key_value': 'true', 'table_name': 'releases', 'field_name': 'coverart', }] mock_load_ddex_json.return_value = s3_object mock_format_correction_detail_data.return_value = { 'productId': product_id, 'releaseCorrectionId': release_correction_id, 'corrections': items, } mock_graphql_execute.return_value = { 'data': { 'createProductCorrectionDetail': [ { 'correctionDetailId': release_correction_detail_id, 'keyId': product_id, 'keyValue': True, 'tableName': 'releases', 'fieldName': 'coverart' } ] } } # TODO: We might want a state_machine object into this handler output_context = handler(s3_object, None) ows_assets_filename = ( output_context['product']['artwork']['ows_assets_filename'] ) mock_create_asset_token.assert_called_once_with( mock_graphql_gateway, 'image') mock_copy_asset.assert_called_once() assert ows_assets_filename == filename + extention