"""Lambda test module.""" import csv from io import StringIO from urllib.parse import unquote_plus from unittest.mock import MagicMock, patch import config import pytest from moto import mock_s3 import boto3 from owsrequest import request as requests from src import app as index class LambdaContext: """Request context for Lambda.""" aws_request_id = '1234-1234' @mock_s3 @patch('src.app.process_csv') def test_index_handler(mock_process_csv, sample_s3_file_created_event): """Test the index handler.""" test_file_contents = """artist_info_id,store_id,identifier\n1,100,abc123""" s3 = boto3.client('s3') s3.create_bucket(ACL='private', Bucket='dev-backfill-spotify-internal-id') s3.put_object( Bucket='dev-backfill-spotify-internal-id', Key='test_file.csv', Body=test_file_contents) index.handler(sample_s3_file_created_event, LambdaContext) mock_process_csv.assert_called_with( 'dev-backfill-spotify-internal-id', 'test_file.csv') @mock_s3 @patch('src.app.process_csv') def test_index_handler_filename_with_spaces( mock_process_csv, sample_s3_filename_with_spaces): """Test the index handler when the filename contains spaces.""" test_file_contents = """artist_info_id,store_id,identifier\n1,100,abc123""" s3 = boto3.client('s3') s3.create_bucket(ACL='private', Bucket='dev-backfill-spotify-internal-id') file_name = \ sample_s3_filename_with_spaces['Records'][0]['s3']['object']['key'] s3.put_object( Bucket='dev-backfill-spotify-internal-id', Key=file_name, Body=test_file_contents) index.handler(sample_s3_filename_with_spaces, LambdaContext) mock_process_csv.assert_called_with( 'dev-backfill-spotify-internal-id', unquote_plus(file_name)) @mock_s3 @patch('src.app.backfill_data_in_tables') def test_process_csv( mock_backfill_data_in_tables, sample_s3_file_created_event): """Test that CSVs are processed after being uploaded to S3.""" csv_data = """album_upc,album_live_from,album_ean,date_inserted,""" \ """countries, album_live_from,album_uri""" \ """\n1234567,'2019-10-10','1234567',""" \ """'2019-10-10','AE AB IN','2019-10-10','spotify:album:123gdhycjjs'""" data = [ { 'upc': '1234567', 'ean': "'1234567'", 'date_inserted': "'2019-10-10'", 'countries': "'AE,AB,IN'", 'live_from': "'2019-10-10'", 'album_uri': "'123gdhycjjs'" } ] s3 = boto3.client('s3') s3.create_bucket(ACL='private', Bucket='dev-backfill-spotify-internal-id') file_name = \ sample_s3_file_created_event['Records'][0]['s3']['object']['key'] bucket_name = \ sample_s3_file_created_event['Records'][0]['s3']['bucket']['name'] s3.put_object( Bucket='dev-backfill-spotify-internal-id', Key=file_name, Body=csv_data) index.process_csv(bucket_name, file_name) mock_backfill_data_in_tables.assert_called_with(data) @mock_s3 @patch('src.app.backfill_data_in_tables') @pytest.mark.parametrize( 'raw_value', [ '', ' ', 'None', 'none', 'null', 'NULL', '0000-00-00', '0000-00-00 00:00:00', ], ids=[ 'empty', 'whitespace', 'None', 'none', 'null', 'NULL', 'zero_date', 'zero_datetime', ], ) def test_process_csv_normalises_null_like_live_from_to_none( mock_backfill_data_in_tables, sample_s3_file_created_event, raw_value): """Assert null-like album_live_from values become Python None.""" buffer = StringIO() writer = csv.writer(buffer, quoting=csv.QUOTE_ALL) writer.writerow([ 'album_upc', 'album_live_from', 'album_ean', 'date_inserted', 'countries', 'album_uri', ]) writer.writerow([ '1234567', raw_value, '1234567', '2019-10-10', 'AE AB IN', 'spotify:album:123gdhycjjs', ]) s3 = boto3.client('s3') s3.create_bucket(ACL='private', Bucket='dev-backfill-spotify-internal-id') file_name = ( sample_s3_file_created_event['Records'][0]['s3']['object']['key'] ) bucket_name = ( sample_s3_file_created_event['Records'][0]['s3']['bucket']['name'] ) s3.put_object( Bucket='dev-backfill-spotify-internal-id', Key=file_name, Body=buffer.getvalue(), ) index.process_csv(bucket_name, file_name) mock_backfill_data_in_tables.assert_called_once_with([{ 'upc': '1234567', 'ean': '1234567', 'date_inserted': '2019-10-10', 'countries': 'AE,AB,IN', 'live_from': None, 'album_uri': '123gdhycjjs', }]) @patch('src.app.insert_record_in_product_and_product_in_store') def test_insert_record_in_product_and_product_in_store( mock_insert_record_in_product_and_product_in_store, sample_data_to_ingest): """Test that database records are inserted.""" mock_db_connection = MagicMock() mock_db_connection.executemany.return_value = 1 index.insert_record_in_product_and_product_in_store( sample_data_to_ingest, mock_db_connection) mock_insert_record_in_product_and_product_in_store.assert_called_with( sample_data_to_ingest, mock_db_connection) def test_get_product_data( mocker): """Test blocking a user.""" response = MagicMock() response.status_code = 200 response.json = lambda: {'release_id': '876956', 'upc': '12345678'} mocker.patch.object(requests, 'process', return_value=response) response = index.get_product_data({'upc': '12345678'}) assert response == {'release_id': '876956', 'upc': '12345678'} assert requests.process.call_args[0][0] == config.SCRIPT_NAME assert requests.process.call_args[0][1] == 'test' assert requests.process.call_args[0][2] == 'GET' assert requests.process.call_args[0][3] == config.SERVICE_NAME_OWS_PRODUCT assert requests.process.call_args[0][4] == '/product/upc/12345678' assert requests.process.call_args[1] == {'json': {'blocked': True}}