"""Tests for polling wrappers.""" from flexmock import flexmock from oto import response import pytest from availability import datastructures as ds from availability import exceptions from availability.constants import models from availability.constants import stores from availability.logic import polling from availability.logic.polling.stores import itunes from availability.logic.polling.stores import spotify PRODUCT_ID = 98143907070931 UPC = '819224018247' STORE_ID_NONEXISTENT = 0 STORE_RELEASE_ID = '123456' POLLING_MODULES = ( (stores.STORE_ID_ITUNES, itunes), (stores.STORE_ID_SPOTIFY, spotify), ) PRODUCT_IN_STORE_ID = 1 TASK_ID = 1 COUNTRIES = ['USA', 'UK'] @pytest.fixture def product_data(): """Return dict with data for polling.update_product_status.""" data = { 'store_id': 1, 'product_in_store_id': 1, 'orchard_product_id': 1, 'upc': '123456789012', 'task_id': 1, 'countries': ['USA', 'UK'] } return data @pytest.mark.parametrize('store_id, expected_module', POLLING_MODULES) def test_update_product_status_success(store_id, expected_module): """Test update_product_status wrapper calls proper implementation.""" (flexmock(expected_module) .should_receive('get_status_from_store') .with_args(product_id=PRODUCT_ID, upc=UPC, countries=COUNTRIES) .once() .and_return(ds.ReleaseStatus(store_release_id=STORE_RELEASE_ID))) (flexmock(polling.product_in_store) .should_receive('update_release_status') .and_return(True)) polling.update_product_status( store_id=store_id, orchard_product_id=PRODUCT_ID, upc=UPC, product_in_store_id=PRODUCT_IN_STORE_ID, task_id=TASK_ID, countries=COUNTRIES) def test_update_product_status_not_implemented(): """Test update_product_status wrapper fails on not implemented store.""" for store_id, module in POLLING_MODULES: (flexmock(module) .should_call('get_status_from_store') .never()) (flexmock(polling.logger) .should_call('error') .once()) (flexmock(polling.task_log) .should_call('create_task_log') .with_args(TASK_ID, models.TASK_LOG_TYPE_FAILED, str) .once()) with pytest.raises(exceptions.UpdateProductStatusError): polling.update_product_status( store_id=STORE_ID_NONEXISTENT, orchard_product_id=PRODUCT_ID, upc=UPC, product_in_store_id=PRODUCT_IN_STORE_ID, task_id=TASK_ID, countries=COUNTRIES) @pytest.mark.parametrize( 'exc_cls', [ exceptions.StoreRequestError, exceptions.StoreResponseParseError, ] ) def test_update_product_status_known_exception(test_database, exc_cls): """Test update_product_status implementation handles known exception.""" for store_id, polling_module in POLLING_MODULES: (flexmock(polling_module) .should_receive('get_status_from_store') .and_raise(exc_cls('Exception {} has happened'.format(exc_cls))) .once()) (flexmock(polling.logger) .should_call('error') .once()) (flexmock(polling.task_log) .should_call('create_task_log') .with_args(TASK_ID, models.TASK_LOG_TYPE_FAILED, str) .once()) with pytest.raises(exc_cls): polling.update_product_status( store_id=store_id, orchard_product_id=PRODUCT_ID, upc=UPC, product_in_store_id=PRODUCT_IN_STORE_ID, task_id=TASK_ID, countries=COUNTRIES) @pytest.mark.parametrize('exc_cls', [ValueError, OSError]) def test_update_product_status_unexpected_exception(exc_cls): """Test update_product_status raises unexpected exception.""" exc_args = ('foo bar',) for store_id, polling_module in POLLING_MODULES: (flexmock(polling_module) .should_receive('get_status_from_store') .and_raise(exc_cls(*exc_args)) .once()) with pytest.raises(exc_cls) as exc_info: polling.update_product_status( store_id=store_id, orchard_product_id=PRODUCT_ID, upc=UPC, product_in_store_id=PRODUCT_IN_STORE_ID, task_id=TASK_ID, countries=COUNTRIES) assert exc_info.value.args == exc_args def test_itunes_product_in_store_response_is_checked_for_errors( mocker, product_data): """Assert response from product_in_store.update is checked for errors.""" mocker.patch( 'availability.logic.polling.itunes.get_status_from_store', return_value=ds.ReleaseStatus()) mocker.patch( 'availability.logic.polling.product_in_store.update_release_status', return_value=response.create_fatal_response('something failed')) with pytest.raises(AssertionError): polling.update_product_status(**product_data) def test_release_status_is_updated(mocker, product_data): """Assert ProductInStore is updated with returned release status.""" release_data = { 'store_release_id': 'test_release_id', 'store_release_status': 'test_status', 'db_release_status': 'delivered', 'live_countries': ['UK', 'USA'] } release_status = ds.ReleaseStatus(**release_data) mocker.patch( 'availability.logic.polling.itunes.get_status_from_store', return_value=release_status) mock_store_product = mocker.patch( 'availability.logic.polling.product_in_store') polling.update_product_status(**product_data) mock_store_product.update_release_status.assert_called_with( product_data['product_in_store_id'], product_data['store_id'], release_status=release_status)