Skip to content

Commit

Permalink
Bug 1412836 - push_apk.py: expose --do-not-contact-google-play
Browse files Browse the repository at this point in the history
  • Loading branch information
JohanLorenzo committed Nov 28, 2017
1 parent 842084b commit 9b6e1e1
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 26 deletions.
49 changes: 44 additions & 5 deletions mozapkpublisher/common/googleplay.py
Expand Up @@ -16,8 +16,10 @@
import httplib2
import logging

from oauth2client.service_account import ServiceAccountCredentials
from apiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
# HACK: importing mock in production is useful for option `--do-not-contact-google-play`
from unittest.mock import MagicMock

from mozapkpublisher.common.exceptions import NoTransactionError, WrongArgumentGiven
from mozapkpublisher.common.store_l10n import STORE_PRODUCT_DETAILS_PER_PACKAGE_NAME
Expand All @@ -36,10 +38,14 @@ def add_general_google_play_arguments(parser):

parser.add_argument('--service-account', help='The service account email', required=True)
parser.add_argument('--credentials', dest='google_play_credentials_file', type=argparse.FileType(mode='rb'),
default='key.p12', help='The p12 authentication file', required=True)
help='The p12 authentication file', required=True)

parser.add_argument('--commit', action='store_true',
help='Commit changes onto Google Play. This action cannot be reverted.')
parser.add_argument('--do-not-contact-google-play', action='store_false', dest='contact_google_play',
help='''Prevent any request to reach Google Play. Use this option if you want to run the script
without any valid credentials nor valid APKs. In fact, Google Play may error out at the first invalid piece of data sent.
--service-account and --credentials must still be provided (you can just fill them with random string and file).''')


def is_package_name_nightly(package_name):
Expand All @@ -49,9 +55,15 @@ def is_package_name_nightly(package_name):


class EditService(object):
def __init__(self, service_account, credentials_file_path, package_name, commit=False):
general_service = _connect(service_account, credentials_file_path)
self._service = general_service.edits()
def __init__(self, service_account, credentials_file_path, package_name, commit=False, contact_google_play=True):
self._contact_google_play = contact_google_play
if self._contact_google_play:
general_service = _connect(service_account, credentials_file_path)
self._service = general_service.edits()
else:
self._service = _craft_google_play_service_mock()
logger.warn('`--do-not-contact-google-play` option was given. Not a single request to Google Play will be made!')

self._package_name = package_name
self._commit = commit
self.start_new_transaction()
Expand Down Expand Up @@ -132,6 +144,33 @@ def update_whats_new(self, language, apk_version_code, whats_new):
logger.debug(u'Apk listing response: {}'.format(response))


def _craft_google_play_service_mock():
edit_service_mock = MagicMock()

edit_service_mock.insert = lambda *args, **kwargs: _ExecuteDummy({'id': 'fake-transaction-id'})
edit_service_mock.commit = lambda *args, **kwargs: _ExecuteDummy(None)

apks_mock = MagicMock()
apks_mock.upload = lambda *args, **kwargs: _ExecuteDummy({'versionCode': 'fake-version-code'})
edit_service_mock.apks = lambda *args, **kwargs: apks_mock

update_mock = MagicMock()
update_mock.update = lambda *args, **kwargs: _ExecuteDummy('fake-update-response')
edit_service_mock.tracks = lambda *args, **kwargs: update_mock
edit_service_mock.listings = lambda *args, **kwargs: update_mock
edit_service_mock.apklistings = lambda *args, **kwargs: update_mock

return edit_service_mock


class _ExecuteDummy():
def __init__(self, return_value):
self._return_value = return_value

def execute(self):
return self._return_value


def _connect(service_account, credentials_file_path):
""" Connect to the google play interface
"""
Expand Down
7 changes: 5 additions & 2 deletions mozapkpublisher/push_apk.py
Expand Up @@ -67,7 +67,7 @@ def upload_apks(self, apks, l10n_strings=None):

edit_service = googleplay.EditService(
self.config.service_account, self.config.google_play_credentials_file.name, self.config.package_name,
self.config.commit
commit=self.config.commit, contact_google_play=self.config.contact_google_play
)

if l10n_strings is not None:
Expand Down Expand Up @@ -136,7 +136,10 @@ def _check_apks_version_codes_are_correctly_ordered(apks):
# See https://bugzilla.mozilla.org/show_bug.cgi?id=1338477 for more context
x86_version_code = apks['x86']['version_code']
arm_version_code = apks['armv7_v15']['version_code']
if x86_version_code <= arm_version_code:
# Don't raise error if version code is the one provided by --do-not-contact-google-play
if 'fake-version-code' in (x86_version_code, arm_version_code):
logger.warn('Not comparing version codes as fake ones were used')
elif x86_version_code <= arm_version_code:
raise ArmVersionCodeTooHigh(arm_version_code, x86_version_code)


Expand Down
19 changes: 19 additions & 0 deletions mozapkpublisher/test/common/test_googleplay.py
Expand Up @@ -92,6 +92,25 @@ def test_edit_service_commits_only_when_option_is_provided(monkeypatch):
edit_service_mock.commit.assert_called_once_with(editId=current_edit_id, packageName='dummy_package_name')


def test_edit_service_is_allowed_to_not_make_a_single_call_to_google_play(monkeypatch):
edit_service_mock = set_up_edit_service_mock(monkeypatch)
edit_service = EditService('service_account', 'credentials_file_path', 'dummy_package_name', commit=True, contact_google_play=False)
upload_apk_result = edit_service.upload_apk(apk_path='/path/to/dummy.apk')
edit_service.update_listings(
language='some_language', title='some_title', full_description='some_description', short_description='some_desc'
)
edit_service.update_track(track='some_track', version_codes=['1', '2'])
edit_service.update_whats_new(language='some_language', apk_version_code='some_version_code', whats_new='some_text')
edit_service.commit_transaction()

assert upload_apk_result == {'versionCode': 'fake-version-code'} # Value set when contact_google_play is False
edit_service_mock.apks().upload.assert_not_called()
edit_service_mock.apklistings().update.assert_not_called()
edit_service_mock.tracks().update.assert_not_called()
edit_service_mock.apklistings().update.assert_not_called()
edit_service_mock.commit.assert_not_called()


def test_upload_apk_returns_files_metadata(monkeypatch):
edit_mock = set_up_edit_service_mock(monkeypatch)
edit_mock.apks().upload().execute.return_value = {
Expand Down
47 changes: 28 additions & 19 deletions mozapkpublisher/test/test_push_apk.py
Expand Up @@ -27,6 +27,8 @@
'apk_x86': apk_x86.name,
'apk_armv7_v15': apk_arm.name,
'update_gp_strings_from_l10n_store': True,
'commit': False,
'do_not_contact_google_play': False,
}


Expand All @@ -48,6 +50,13 @@ def _generate_version_code(apk_file_name):
return _edit_service_mock


def set_up_mocks(monkeypatch_, edit_service_mock_):
monkeypatch_.setattr(googleplay, 'EditService', lambda _, __, ___, commit, contact_google_play: edit_service_mock_)
monkeypatch_.setattr(apk, 'check_if_apk_is_multilocale', lambda _: None)
monkeypatch_.setattr(apk, 'check_if_apk_has_claimed_architecture', lambda _, __: None)
set_translations_per_google_play_locale_code(monkeypatch_)


def test_one_missing_file():
config = copy(VALID_CONFIG)

Expand Down Expand Up @@ -98,10 +107,7 @@ def test_valid_rollout_percentage(edit_service_mock, monkeypatch):
config = copy(VALID_CONFIG)
config['track'] = 'rollout'

monkeypatch.setattr(googleplay, 'EditService', lambda _, __, ___, ____: edit_service_mock)
monkeypatch.setattr(apk, 'check_if_apk_is_multilocale', lambda _: None)
monkeypatch.setattr(apk, 'check_if_apk_has_claimed_architecture', lambda _, __: None)
set_translations_per_google_play_locale_code(monkeypatch)
set_up_mocks(monkeypatch, edit_service_mock)
for i in range(0, 101):
valid_percentage = i
config['rollout_percentage'] = valid_percentage
Expand Down Expand Up @@ -133,10 +139,7 @@ def test_check_and_get_flatten_version_codes():


def test_upload_apk(edit_service_mock, monkeypatch):
monkeypatch.setattr(googleplay, 'EditService', lambda _, __, ___, ____: edit_service_mock)
monkeypatch.setattr(apk, 'check_if_apk_is_multilocale', lambda _: None)
monkeypatch.setattr(apk, 'check_if_apk_has_claimed_architecture', lambda _, __: None)
set_translations_per_google_play_locale_code(monkeypatch)
set_up_mocks(monkeypatch, edit_service_mock)

PushAPK(VALID_CONFIG).run()

Expand All @@ -148,10 +151,7 @@ def test_upload_apk(edit_service_mock, monkeypatch):


def test_upload_apk_with_locales_updated_from_l10n_store(edit_service_mock, monkeypatch):
monkeypatch.setattr(googleplay, 'EditService', lambda _, __, ___, ____: edit_service_mock)
monkeypatch.setattr(apk, 'check_if_apk_is_multilocale', lambda _: None)
monkeypatch.setattr(apk, 'check_if_apk_has_claimed_architecture', lambda _, __: None)
set_translations_per_google_play_locale_code(monkeypatch)
set_up_mocks(monkeypatch, edit_service_mock)
monkeypatch.setattr(store_l10n, '_translate_moz_locate_into_google_play_one', lambda locale: 'es-US' if locale == 'es-MX' else locale)

config = copy(VALID_CONFIG)
Expand All @@ -178,10 +178,7 @@ def test_upload_apk_with_locales_updated_from_l10n_store(edit_service_mock, monk


def test_upload_apk_without_locales_updated(edit_service_mock, monkeypatch):
monkeypatch.setattr(googleplay, 'EditService', lambda _, __, ___, ____: edit_service_mock)
monkeypatch.setattr(apk, 'check_if_apk_is_multilocale', lambda _: None)
monkeypatch.setattr(apk, 'check_if_apk_has_claimed_architecture', lambda _, __: None)
set_translations_per_google_play_locale_code(monkeypatch)
set_up_mocks(monkeypatch, edit_service_mock)

config = copy(VALID_CONFIG)
del config['update_gp_strings_from_l10n_store']
Expand All @@ -197,9 +194,7 @@ def test_upload_apk_without_locales_updated(edit_service_mock, monkeypatch):


def test_upload_apk_with_locales_updated_from_file(edit_service_mock, monkeypatch):
monkeypatch.setattr(googleplay, 'EditService', lambda _, __, ___, ____: edit_service_mock)
monkeypatch.setattr(apk, 'check_if_apk_is_multilocale', lambda _: None)
monkeypatch.setattr(apk, 'check_if_apk_has_claimed_architecture', lambda _, __: None)
set_up_mocks(monkeypatch, edit_service_mock)

config = copy(VALID_CONFIG)
del config['update_gp_strings_from_l10n_store']
Expand Down Expand Up @@ -233,6 +228,20 @@ def test_create_or_update_whats_new(edit_service_mock, monkeypatch):
assert edit_service_mock.update_whats_new.call_count == 3


def test_do_not_contact_google_play_flag_does_not_request_google_play(monkeypatch):
monkeypatch.setattr(apk, 'check_if_apk_is_multilocale', lambda _: None)
monkeypatch.setattr(apk, 'check_if_apk_has_claimed_architecture', lambda _, __: None)
set_translations_per_google_play_locale_code(monkeypatch)

config = copy(VALID_CONFIG)
config['do_not_contact_google_play'] = True

PushAPK(config).run()
# Checks are done by the fact that Google Play doesn't error out. In fact, we
# provide dummy data. If Google Play was reached, it would have failed at the
# authentication step


def test_main(monkeypatch):
incomplete_args = [
'--package-name', 'org.mozilla.fennec_aurora', '--track', 'alpha',
Expand Down

0 comments on commit 9b6e1e1

Please sign in to comment.