"""Functional tests for consumer processing iTunes product.""" import datetime from oto import status as oto_status import pytest from availability.connectors import sql from availability.constants import models from availability.logic import product_submission from availability.logic.queue import consumer from availability.models import product_in_store as ps_model from availability.models import store as store_model from availability.models import task as task_model @pytest.fixture def itunes_store(test_database): """Create iTunes store entry in DB.""" with sql.session_scope() as session: store = store_model.Store( store_id=1, name='test', polling_delay_days=1, poll_days_after_sales=1) session.add(store) @pytest.fixture def itunes_product(test_database, products_data): """Create iTunes product and task for test.""" itunes_product = products_data[0] creation_response = product_submission.submit_to_poll([itunes_product]) assert creation_response.status == oto_status.NO_CONTENT return itunes_product def test_consumer_handles_subprocess_related_error( itunes_store, mocker, itunes_product): """Assert any error caused by subprocess is handled.""" mocker.patch( 'availability.connectors.stores.itunes.subprocess.check_output', side_effect=Exception) message = { 'upc': itunes_product['upc'], 'task_id': 1, 'product_in_store_id': 1, 'orchard_product_id': itunes_product['orchard_product_id'], 'store_id': itunes_product['store_id'] } consumer.process_single_message(message) with sql.session_scope() as session: tasks = session.query(task_model.Task).all() assert len(tasks) == 1 assert tasks[0].status == models.TASK_STATUS_FAILED def test_consumer_can_process_correct_response( mocker, itunes_store): """Assert consumer can process golive release.""" itunes_product = { 'product_id': 98143907070931, 'orchard_product_id': 98143907070931, 'upc': '191018802882', 'itunes_vendor_id': '98143907070931', 'provider': 'orchard', 'store_id': 1, 'status': 'delivered', 'store_internal_status': 'test', 'store_internal_id': 'test', 'received_for_polling_date': '2017-01-01T19:52:22Z', 'delivery_date': '2017-01-01T19:52:22Z', 'sales_start_date': '2017-01-01T19:52:22Z', 'countries': ['USA', 'UK'], 'go_live_date': '2017-01-01T19:52:22Z' } creation_response = product_submission.submit_to_poll([itunes_product]) assert creation_response.status == oto_status.NO_CONTENT # Mock just enough to return expected iTunes response. with open('tests/files/itunes/itmstr_live.xml', 'rb') as response_xml: itunes_response = response_xml.read() mock_process = mocker.Mock() mock_process.communicate.return_value = (itunes_response, b'stderr') mock_process.returncode = 0 mocker.patch( 'availability.connectors.stores.itunes.subprocess.Popen', return_value=mock_process) message = { 'upc': itunes_product['upc'], 'task_id': 1, 'product_in_store_id': 1, 'orchard_product_id': itunes_product['orchard_product_id'], 'store_id': itunes_product['store_id'], 'countries': ['USA', 'UK'] } # import ipdb; ipdb.set_trace() consumer.process_single_message(message) with sql.session_scope() as session: updated_product = session.query(ps_model.ProductInStore).first() assert updated_product.status == models.RELEASE_STATUS_LIVE assert updated_product.go_live_date def test_consumer_correctly_process_product_with_exceeded_ttl( mocker, test_database): """Assert status for product with exceeded ttl will be set correctly.""" poll_days_after_sales = 5 exceeded_ttl_date = datetime.datetime.utcnow() - datetime.timedelta( poll_days_after_sales + 1) store = store_model.Store( store_id=1, name='iTunes', poll_days_after_sales=poll_days_after_sales) with sql.session_scope() as session: session.add(store) itunes_product = { 'product_id': 98143907070931, 'orchard_product_id': 98143907070931, 'upc': '98143907070931', 'itunes_vendor_id': '98143907070931', 'provider': 'orchard', 'store_id': 1, 'status': 'delivered', 'store_internal_status': 'test', 'store_internal_id': 'test', 'received_for_polling_date': '2017-01-01T19:52:22Z', 'delivery_date': '2017-01-01T19:52:22Z', 'sales_start_date': exceeded_ttl_date.strftime( models.ISO8601_DATE_FORMAT), 'countries': ['USA', 'UK'], } message = { 'upc': itunes_product['upc'], 'task_id': 1, 'product_in_store_id': 1, 'orchard_product_id': itunes_product['orchard_product_id'], 'store_id': itunes_product['store_id'], 'countries': ['USA', 'UK'] } creation_response = product_submission.submit_to_poll([itunes_product]) assert creation_response.status == oto_status.NO_CONTENT with sql.session_scope() as session: product = session.query(ps_model.ProductInStore).first() product.force_polling = False # Mock just enough to return expected iTunes response. with open( 'tests/files/itunes/itmstr_unpolished.xml', 'rb') as response_xml: itunes_response = response_xml.read() mock_process = mocker.Mock() mock_process.communicate.return_value = (itunes_response, b'stderr') mock_process.returncode = 0 mocker.patch( 'availability.connectors.stores.itunes.subprocess.Popen', return_value=mock_process) consumer.process_single_message(message) with sql.session_scope() as session: product = session.query(ps_model.ProductInStore).first() assert product.status == models.RELEASE_STATUS_INGESTION_FAILED def test_consumer_correctly_process_product_with_exceeded_ttl_and_force_poll( mocker, test_database): """Assert status for product with exceeded ttl will be set correctly.""" poll_days_after_sales = 5 exceeded_ttl_date = datetime.datetime.utcnow() - datetime.timedelta( days=poll_days_after_sales + 1) store = store_model.Store( store_id=1, name='iTunes', poll_days_after_sales=poll_days_after_sales) with sql.session_scope() as session: session.add(store) itunes_product = { 'product_id': 98143907070931, 'orchard_product_id': 98143907070931, 'upc': '98143907070931', 'itunes_vendor_id': '98143907070931', 'provider': 'orchard', 'store_id': 1, 'status': 'delivered', 'store_internal_status': 'test', 'store_internal_id': 'test', 'delivery_date': '2017-01-01T19:52:22Z', 'sales_start_date': '2017-01-01T19:52:22Z', 'countries': ['USA', 'UK'], 'force_polling': True } message = { 'upc': itunes_product['upc'], 'task_id': 1, 'product_in_store_id': 1, 'orchard_product_id': itunes_product['orchard_product_id'], 'store_id': itunes_product['store_id'], 'countries': ['USA', 'UK'] } creation_response = product_submission.submit_to_poll([itunes_product]) assert creation_response.status == oto_status.NO_CONTENT # Set the field we are not allowed to pass via API. with sql.session_scope() as session: session.query(ps_model.ProductInStore).filter_by( product_in_store_id=1).update( {'received_for_polling_date': exceeded_ttl_date}) # Mock just enough to return expected iTunes response. with open( 'tests/files/itunes/itmstr_unpolished.xml', 'rb') as response_xml: itunes_response = response_xml.read() mock_process = mocker.Mock() mock_process.communicate.return_value = (itunes_response, b'stderr') mock_process.returncode = 0 mocker.patch( 'availability.connectors.stores.itunes.subprocess.Popen', return_value=mock_process) consumer.process_single_message(message) with sql.session_scope() as session: product = session.query(ps_model.ProductInStore).first() assert product.status == models.RELEASE_STATUS_INGESTION_FAILED