"""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"/>{cont}>',
True, ['NZ', 'US'], []),
('<{cont}><{store} {ready}="NZ,US" {on}="{na}"/>{cont}>',
True, ['NZ', 'US'], []),
('<{cont}><{store} {ready}="NZ,US" {on}=""/>{cont}>',
True, ['NZ', 'US'], []),
('<{cont}><{store} {on}="NZ,US"/>{cont}>',
True, [], ['NZ', 'US']),
('<{cont}><{store} {ready}="{na}" {on}="NZ,US"/>{cont}>',
True, [], ['NZ', 'US']),
('<{cont}><{store} {ready}="" {on}="NZ,US"/>{cont}>',
True, [], ['NZ', 'US']),
('<{cont}><{store} {ready}="AU" {on}="NZ,US"/>{cont}>',
True, ['AU'], ['NZ', 'US']),
('<{store} {ready}="AU" {on}="NZ,US"/>',
True, [], []),
('<{cont}>{cont}>',
True, [], []),
('<{cont}><{store}/>{cont}><{cont}><{store}/>{cont}>',
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">{content_tag}>',
itunes.UPLOAD_STATUS_IMPORTED),
('<{upload_tag} {upload_st}="{imported}"/>'
'<{content_tag}>{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}">{content_tag}>',
itunes.CONTENT_STATUS_UNPOLISHED),
('<{upload_tag} {upload_st}="{imported}"/><{content_tag} '
'{content_st}="{polished}">{content_tag}>',
itunes.CONTENT_STATUS_POLISHED),
(''
'<{content_tag} {content_st}="{polished}">{content_tag}>',
None),
('<{upload_tag} {upload_st}="{imported}"/><{content_tag} '
'{content_st}="{polished}" {it_conn_st}="{partial}">{content_tag}>',
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}>{name}>', True),
('<{name}/><{name}/>', False),
('<{name}/>', False),
('<{name}>{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