"""Tests for iTunes status polling.""" import os import defusedxml.ElementTree from flexmock import flexmock import pytest from availability import config from availability import datastructures as ds from availability import exceptions from availability.connectors.stores import itunes as itunes_connector from availability.logic.polling.stores import itunes PRODUCT_ID = 98143907070931 # should match test xml data PRODUCT_ID_NO_MATCH = 98143907070900 # should not match test xml data ITUNES_INTERNAL_RELEASE_ID = '1000000001' # should match test xml data def test_get_status_from_store(): """Test iTunes status polling returns expected status.""" store_response = 'does not matter' (flexmock(itunes_connector) .should_receive('query_store') .with_args(PRODUCT_ID) .and_return(store_response)) for store_release_status in list(itunes.STATUS_MAPPING.keys()): status = ds.ReleaseStatus( store_release_id=ITUNES_INTERNAL_RELEASE_ID, store_release_status=store_release_status) (flexmock(itunes) .should_receive('release_status_from_xml') .with_args(xml_str=store_response, product_id=PRODUCT_ID) # Do not to pass the ReleaseStatus() instance itself to avoid inplace # modifications. .and_return(ds.ReleaseStatus(**status.as_dict())) .ordered() .once()) status.db_release_status = itunes.STATUS_MAPPING[ status.store_release_status] assert itunes.get_status_from_store(product_id=PRODUCT_ID) == status @pytest.mark.parametrize( 'xml_file, product_id, store_release_status, on_store_countries', [ ('itmstr_on_store_connect_status_partial.xml', PRODUCT_ID, itunes.ITUNES_CONNECT_STATUS_PARTIAL, ['GB', 'US'],), ('itmstr_on_store_ready_for_store_connect_status_partial.xml', PRODUCT_ID, itunes.ITUNES_CONNECT_STATUS_PARTIAL, ['GB', 'US']), ('itmstr_unpolished.xml', PRODUCT_ID, itunes.CONTENT_STATUS_UNPOLISHED, []), ('itmstr_polished.xml', PRODUCT_ID, itunes.CONTENT_STATUS_POLISHED, []), ('itmstr_imported_no_content_status_info.xml', PRODUCT_ID, itunes.UPLOAD_STATUS_IMPORTED, []), ('itmstr_partial_no_on_store.xml', PRODUCT_ID, itunes.ITUNES_CONNECT_STATUS_PARTIAL, []), ('itmstr_partial_no_store_status.xml', PRODUCT_ID, itunes.ITUNES_CONNECT_STATUS_PARTIAL, []), ('itmstr_ready_no_on_store.xml', PRODUCT_ID, itunes.ITUNES_CONNECT_STATUS_READY, []), ('itmstr_ready.xml', PRODUCT_ID, itunes.ITUNES_CONNECT_STATUS_READY, ['GB', 'US']), ('itmstr_upload_fail.xml', PRODUCT_ID, itunes.UPLOAD_STATUS_UPLOAD_FAILED, []), ('itmstr_live.xml', PRODUCT_ID, itunes.ITUNES_CONNECT_STATUS_LIVE, ['GB', 'US']), ('itmstr_no_apple_id.xml', PRODUCT_ID, None, None), ('itmstr_live.xml', PRODUCT_ID_NO_MATCH, None, None), ('itmstr_on_store_no_vendor_id.xml', PRODUCT_ID, None, None), ('itmstr_no_upload_status.xml', PRODUCT_ID, None, None), ('itmstr_unknown_structure.xml', PRODUCT_ID, None, None), ('itmstr_not_valid.xml', PRODUCT_ID, None, None), ('itmstr_empty.xml', PRODUCT_ID, None, None), ] ) def test_release_status_from_xml( xml_file, product_id, store_release_status, on_store_countries): """Test XML release status parsing. If expected_countries is None - checks for StoreResponseParseError. """ with open(os.path.join('tests', 'files', 'itunes', xml_file)) as file: xml_str = file.read() # if xml_file == 'itmstr_live.xml' and product_id == PRODUCT_ID: # import ipdb; ipdb.set_trace() if store_release_status is None: with pytest.raises(exceptions.StoreResponseParseError): itunes.release_status_from_xml( xml_str=xml_str, product_id=product_id) else: release_status = itunes.release_status_from_xml( xml_str=xml_str, product_id=product_id) assert release_status.store_release_status == store_release_status assert sorted(release_status.live_countries) == sorted( on_store_countries) if store_release_status == itunes.UPLOAD_STATUS_UPLOAD_FAILED: assert release_status.store_release_id is None return assert release_status.store_release_id == ITUNES_INTERNAL_RELEASE_ID @pytest.mark.parametrize( 'xml_templ, expect_success, ready_for_store, on_store', [ ('<{cont}><{store} {ready}="NZ,US"/>', True, ['NZ', 'US'], []), ('<{cont}><{store} {ready}="NZ,US" {on}="{na}"/>', True, ['NZ', 'US'], []), ('<{cont}><{store} {ready}="NZ,US" {on}=""/>', True, ['NZ', 'US'], []), ('<{cont}><{store} {on}="NZ,US"/>', True, [], ['NZ', 'US']), ('<{cont}><{store} {ready}="{na}" {on}="NZ,US"/>', True, [], ['NZ', 'US']), ('<{cont}><{store} {ready}="" {on}="NZ,US"/>', True, [], ['NZ', 'US']), ('<{cont}><{store} {ready}="AU" {on}="NZ,US"/>', True, ['AU'], ['NZ', 'US']), ('<{store} {ready}="AU" {on}="NZ,US"/>', True, [], []), ('<{cont}>', True, [], []), ('<{cont}><{store}/><{cont}><{store}/>', False, [], []), ] ) def test_get_countries(xml_templ, expect_success, ready_for_store, on_store): """Test helper that parses 'on store' and 'ready for store' countries.""" xml = xml_templ.format( cont=itunes.TAG_CONTENT_STATUS_INFO, store=itunes.TAG_STORE_STATUS, ready=itunes.ATTR_READY_FOR_STORE, on=itunes.ATTR_ON_STORE, na=itunes.VALUE_NA) root_tag = '{}'.format(xml) root = defusedxml.ElementTree.fromstring(root_tag, forbid_dtd=True) if expect_success: result = itunes._get_countries(root) assert sorted(ready_for_store) == sorted(result[0]) assert sorted(on_store) == sorted(result[1]) return with pytest.raises(exceptions.StoreResponseParseError): itunes._get_countries(root) @pytest.mark.parametrize( 'xml_templ, expected_status,', [ ('<{upload_tag} {upload_st}="{imported}"/>', itunes.UPLOAD_STATUS_IMPORTED), ('<{upload_tag} {upload_st}="{imported}"/><{content_tag} ' '{content_st}="UNKNOWN_STATUS">', itunes.UPLOAD_STATUS_IMPORTED), ('<{upload_tag} {upload_st}="{imported}"/>' '<{content_tag}>', itunes.UPLOAD_STATUS_IMPORTED), ('<{upload_tag} {upload_st}="{uploading}"/>', itunes.UPLOAD_STATUS_UPLOADING), ('<{upload_tag} {upload_st}="{imported}"/><{content_tag} ' '{content_st}="{unpolished}">', itunes.CONTENT_STATUS_UNPOLISHED), ('<{upload_tag} {upload_st}="{imported}"/><{content_tag} ' '{content_st}="{polished}">', itunes.CONTENT_STATUS_POLISHED), ('' '<{content_tag} {content_st}="{polished}">', None), ('<{upload_tag} {upload_st}="{imported}"/><{content_tag} ' '{content_st}="{polished}" {it_conn_st}="{partial}">', itunes.ITUNES_CONNECT_STATUS_PARTIAL), ] ) def test_get_explicit_status(xml_templ, expected_status): """Test helper that gets explicit release status.""" xml = xml_templ.format( upload_tag=itunes.TAG_UPLOAD_STATUS_INFO, content_tag=itunes.TAG_CONTENT_STATUS_INFO, upload_st=itunes.ATTR_STATUS, content_st=itunes.ATTR_CONTENT_STATUS, uploading=itunes.UPLOAD_STATUS_UPLOADING, imported=itunes.UPLOAD_STATUS_IMPORTED, unpolished=itunes.CONTENT_STATUS_UNPOLISHED, polished=itunes.CONTENT_STATUS_POLISHED, it_conn_st=itunes.ATTR_ITUNES_CONNECT_STATUS, partial=itunes.ITUNES_CONNECT_STATUS_PARTIAL, ) root_tag = '{}'.format(xml) root = defusedxml.ElementTree.fromstring(root_tag, forbid_dtd=True) if expected_status: assert itunes._get_explicit_status(root) == expected_status else: with pytest.raises(exceptions.StoreResponseParseError): itunes._get_explicit_status(root) @pytest.mark.parametrize( 'xml_templ, expect_success', [ ('<{name}/>', True), ('<{name}>', True), ('<{name}/><{name}/>', False), ('<{name}/>', False), ('<{name}>', False), ('', False), ] ) def test_xml_element_find_one(xml_templ, expect_success): """Test helper that searches for specific ElementTree.Element.""" name = 'any_element' root = defusedxml.ElementTree.fromstring( xml_templ.format(name=name), forbid_dtd=True) result = itunes._xml_element_find_one(root=root, name=name) if expect_success: element = defusedxml.ElementTree.fromstring( '<{name}/>'.format(name=name), forbid_dtd=True) assert result.tag == element.tag else: assert result is None @pytest.mark.parametrize('itunes_vendor_id', ['1', 1]) def test_get_itunes_command(itunes_vendor_id): """Assert iTMSTransporter command created correctly.""" command = itunes_connector._get_itunes_command(itunes_vendor_id) expected_command = [ config.ITUNES_CMD_BIN, '-u', config.ITUNES_USER, '-p', config.ITUNES_PASSWORD, '-m', 'status', '-outputFormat', 'xml', '-vendor_id', '1', '-Xmx1024m', '-Xms512m', ] assert command == expected_command