def test_validation_no_signing_warning(self, _mock): """If we're not signing addon don't warn on signed addon submission.""" _mock.return_value = self.mock_sign_addon_warning tasks.validate(self.upload) validation = json.loads(self.get_upload().validation) assert validation['warnings'] == 0 assert len(validation['messages']) == 0
def test_no_upgrade_annotation_no_version(self): """Make sure there's no workaround the downgrade error.""" self.addon.update(guid='guid@xpi') file_ = amo.tests.AMOPaths().file_fixture_path( 'delicious_bookmarks-no-version.xpi') self.update_files(is_webextension=True) deleted_version = version_factory( addon=self.addon, file_kw={'is_webextension': False}) deleted_version.delete() upload = FileUpload.objects.create(path=file_, addon=self.addon) upload.addon.version = None upload.addon.save() upload.save(update_fields=('version',)) upload.refresh_from_db() tasks.validate(upload, listed=True) upload.refresh_from_db() expected = [u'testcases_installrdf', u'_test_rdf', u'missing_addon'] validation = upload.processed_validation assert validation['messages'][0]['id'] == expected assert validation['messages'][0]['type'] == 'error'
def test_validation_signing_warning(self, _mock): """If we sign addons, warn on signed addon submission.""" _mock.return_value = self.mock_sign_addon_warning tasks.validate(self.upload, listed=True) validation = json.loads(self.get_upload().validation) assert validation['warnings'] == 1 assert len(validation['messages']) == 1
def test_coauthor_api_key_in_submission_is_found(self): coauthor = user_factory() AddonUser.objects.create(addon=self.addon, user_id=coauthor.id) upload = FileUpload.objects.create(path=self.file, addon=self.addon, user=coauthor) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 1 messages = upload.processed_validation['messages'] assert len(messages) == 1 assert messages[0]['id'] == [ u'validation', u'messages', u'api_key_detected'] assert ('The developer API key of a coauthor was found in the ' 'submitted file.' in messages[0]['message']) assert not upload.valid # If the key has been revoked, there is no active key, # so `get_jwt_key` raises `DoesNotExist`. with pytest.raises(APIKey.DoesNotExist): APIKey.get_jwt_key(user_id=self.user.id) assert len(mail.outbox) == 1 assert ('Your AMO API credentials have been revoked' in mail.outbox[0].subject) assert ('never share your credentials' in mail.outbox[0].body) # We submit as the coauthor, the leaked key is the one from 'self.user' assert mail.outbox[0].to[0] == self.user.email
def test_only_consider_beta_for_downgrade_error_if_uploading_a_beta(self): """Make sure we don't raise the webextension downgrade error when uploading a public legacy version we have a beta webext.""" # Create a beta webext with a version number higher than the existing # legacy, but lower than the legacy we're about to upload... version_factory(addon=self.addon, version='1.0b1', file_kw={ 'is_webextension': True, 'status': amo.STATUS_BETA, }) file_ = amo.tests.AMOPaths().file_fixture_path( 'delicious_bookmarks-2.1.106-fx.xpi') upload = FileUpload.objects.create(path=file_, addon=self.addon) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.valid # Do consider previous betas when uploading a beta, though. file_ = amo.tests.AMOPaths().file_fixture_path( 'beta-extension.xpi') upload = FileUpload.objects.create(path=file_, addon=self.addon) tasks.validate(upload, listed=True) upload.refresh_from_db() assert not upload.valid expected = ['validation', 'messages', 'webext_downgrade'] assert upload.processed_validation['messages'][0]['id'] == expected assert upload.processed_validation['messages'][0]['type'] == 'error'
def test_annotate_passed_auto_validation_bogus_result(self, _mock): """Don't set passed_auto_validation, don't fail if results is bogus.""" _mock.return_value = '{"errors": 0}' tasks.validate(self.upload) assert (json.loads(self.get_upload().validation) == {"passed_auto_validation": True, "errors": 0, "signing_summary": {"high": 0, "medium": 0, "low": 0, "trivial": 0}})
def test_calls_run_linter(self, run_linter): run_linter.return_value = '{"errors": 0}' assert not self.valid_upload.valid tasks.validate(self.valid_upload) upload = self.get_upload(self.valid_upload) assert upload.valid, upload.validation
def test_submit_legacy_extension_targets_older_firefox_stricly(self): file_ = get_addon_file('valid_firefox_addon_strict_compatibility.xpi') upload = FileUpload.objects.create(path=file_) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_submit_non_extension(self): file_ = get_addon_file('searchgeek-20090701.xml') upload = FileUpload.objects.create(path=file_) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_submit_thunderbird_extension(self): file_ = get_addon_file('valid_firefox_and_thunderbird_addon.xpi') upload = FileUpload.objects.create(path=file_) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_validation_finishes_if_containing_binary_content(self): file_ = get_addon_file('webextension_containing_binary_files.xpi') upload = FileUpload.objects.create(path=file_, user=self.user) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_does_not_revoke_safe_webextension(self): file_ = get_addon_file('valid_webextension.xpi') upload = FileUpload.objects.create(path=file_, user=self.user) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_does_not_revoke_for_different_author(self): different_author = user_factory() upload = FileUpload.objects.create(path=self.file, user=different_author) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.valid
def test_annotate_failed_auto_validation(self, _mock): """Set passed_auto_validation on reception of the results.""" result = {'signing_summary': {'trivial': 0, 'low': 1, 'medium': 0, 'high': 0}, 'errors': 0} _mock.return_value = json.dumps(result) tasks.validate(self.upload) validation = json.loads(self.get_upload().validation) assert not validation['passed_auto_validation']
def test_does_not_revoke_safe_webextension(self): file_ = get_addon_file('valid_webextension.xpi') upload = self.get_upload( abspath=file_, with_validation=False, user=self.user) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_validation_finishes_if_containing_binary_content(self): file_ = get_addon_file('webextension_containing_binary_files.xpi') upload = self.get_upload( abspath=file_, with_validation=False, user=self.user) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_revoke_task_is_called(self): mock_str = 'olympia.devhub.tasks.revoke_api_key' wrapped = tasks.revoke_api_key with mock.patch(mock_str, wraps=wrapped) as mock_revoke: upload = FileUpload.objects.create(path=self.file, user=self.user) tasks.validate(upload, listed=True) upload.refresh_from_db() mock_revoke.apply_async.assert_called_with( kwargs={'key_id': self.key.id}, countdown=120) assert not upload.valid
def test_submit_legacy_extension_not_a_new_addon(self): file_ = get_addon_file('valid_firefox_addon.xpi') addon = addon_factory(version_kw={'version': '0.1'}) upload = FileUpload.objects.create(path=file_, addon=addon) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_does_not_revoke_for_different_author(self): different_author = user_factory() upload = self.get_upload(abspath=self.file, with_validation=False, user=different_author) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.valid
def test_submit_legacy_addon_restricted(self): file_ = get_addon_file('valid_firefox_addon.xpi') upload = FileUpload.objects.create(path=file_) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 1 expected = ['validation', 'messages', 'legacy_extensions_restricted'] assert upload.processed_validation['messages'][0]['id'] == expected assert not upload.valid
def test_run_once_file_upload(self, get_task_mock): """Tests that only a single validation task is run for a given file upload.""" get_task_mock.return_value.delay.return_value = mock.Mock(task_id='42') assert isinstance(tasks.validate(self.file_upload, listed=True), mock.Mock) assert get_task_mock.return_value.delay.call_count == 1 assert isinstance(tasks.validate(self.file_upload, listed=True), AsyncResult) assert get_task_mock.return_value.delay.call_count == 1
def test_validation_error(self, _mock): _mock.side_effect = Exception upload = self.get_upload( abspath=self.valid_path, with_validation=False) tasks.validate(upload, listed=True) upload.reload() validation = upload.processed_validation assert validation assert validation['errors'] == 1 assert validation['messages'][0]['id'] == ['validator', 'unexpected_exception'] assert not upload.valid
def test_submit_legacy_upgrade(self): # Works because it's not targeting >= 57. file_ = get_addon_file('valid_firefox_addon.xpi') addon = addon_factory(version_kw={'version': '0.1'}) upload = FileUpload.objects.create(path=file_, addon=addon) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_legacy_submissions_disabled(self): file_ = get_addon_file('valid_firefox_addon.xpi') upload = self.get_upload(abspath=file_, with_validation=False) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 1 expected = ['validation', 'messages', 'legacy_addons_unsupported'] assert upload.processed_validation['messages'][0]['id'] == expected assert upload.processed_validation['messages'][0]['description'] == [] assert not upload.valid
def test_legacy_updates_disabled(self): file_ = get_addon_file('valid_firefox_addon.xpi') addon = addon_factory(version_kw={'version': '0.1'}) upload = FileUpload.objects.create(path=file_, addon=addon) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 1 expected = ['validation', 'messages', 'legacy_addons_unsupported'] assert upload.processed_validation['messages'][0]['id'] == expected assert not upload.valid
def test_run_once_file_upload(self, chain): """Tests that only a single validation task is run for a given file upload.""" task = mock.Mock() chain.return_value = task task.delay.return_value = mock.Mock(task_id='42') assert isinstance(tasks.validate(self.file_upload), mock.Mock) assert task.delay.call_count == 1 assert isinstance(tasks.validate(self.file_upload), AsyncResult) assert task.delay.call_count == 1
def test_run_once_file_upload(self, get_task_mock): """Tests that only a single validation task is run for a given file upload.""" get_task_mock.return_value.delay.return_value = mock.Mock(task_id='42') assert isinstance( tasks.validate(self.file_upload, listed=True), mock.Mock) assert get_task_mock.return_value.delay.call_count == 1 assert isinstance( tasks.validate(self.file_upload, listed=True), AsyncResult) assert get_task_mock.return_value.delay.call_count == 1
def test_submit_legacy_dictionary_disabled(self): file_ = get_addon_file('dictionary_targeting_57.xpi') addon = addon_factory(version_kw={'version': '0.1'}, type=amo.ADDON_DICT) upload = FileUpload.objects.create(path=file_, addon=addon) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 1 expected = ['validation', 'messages', 'legacy_addons_unsupported'] assert upload.processed_validation['messages'][0]['id'] == expected assert not upload.valid
def test_validation_finishes_if_containing_invalid_filename(self): file_ = get_addon_file('invalid_webextension.xpi') upload = FileUpload.objects.create(path=file_, user=self.user) tasks.validate(upload, listed=True) upload.refresh_from_db() # https://github.com/mozilla/addons-server/issues/8208 # causes this to be 1 (and invalid) instead of 0 (and valid). # The invalid filename error is caught and raised outside of this # validation task. assert upload.processed_validation['errors'] == 1 assert not upload.valid
def test_webextension_no_webext_no_warning(self): file_ = amo.tests.AMOPaths().file_fixture_path( 'delicious_bookmarks-2.1.106-fx.xpi') upload = FileUpload.objects.create(path=file_, addon=self.addon) tasks.validate(upload, listed=True) upload.refresh_from_db() validation = upload.processed_validation assert 'is_upgrade_to_webextension' not in validation expected = ['validation', 'messages', 'webext_upgrade'] assert not any(msg['id'] == expected for msg in validation['messages'])
def test_submit_legacy_upgrade_targeting_star(self): # Should not error: extensions with a maxversion of '*' don't get the # error, the manifest parsing code will rewrite it as '56.*' instead. file_ = get_addon_file('valid_firefox_addon_targeting_star.xpi') addon = addon_factory(version_kw={'version': '0.1'}) upload = FileUpload.objects.create(path=file_, addon=addon) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_submit_webextension_upgrade_targeting_firefox_57(self): # Should not error: it's targeting 57 but it's a webextension. file_ = get_addon_file('valid_webextension_targeting_57.xpi') addon = addon_factory(version_kw={'version': '0.1'}, file_kw={'is_webextension': True}) upload = FileUpload.objects.create(path=file_, addon=addon) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_run_once_per_file(self, get_task_mock): """Tests that only a single validation task is run for a given file.""" get_task_mock.return_value.delay.return_value = mock.Mock(task_id='42') assert isinstance(tasks.validate(self.file), mock.Mock) assert get_task_mock.return_value.delay.call_count == 1 assert isinstance(tasks.validate(self.file), AsyncResult) assert get_task_mock.return_value.delay.call_count == 1 new_version = version_factory(addon=self.addon, version='0.0.2') assert isinstance(tasks.validate(new_version.current_file), mock.Mock) assert get_task_mock.return_value.delay.call_count == 2
def test_webextension_no_webext_no_warning(self): file_ = amo.tests.AMOPaths().file_fixture_path( 'delicious_bookmarks-2.1.106-fx.xpi') upload = self.get_upload( abspath=file_, with_validation=False, addon=self.addon, version='0.1') tasks.validate(upload, listed=True) upload.refresh_from_db() validation = upload.processed_validation expected = ['validation', 'messages', 'webext_upgrade'] assert not any(msg['id'] == expected for msg in validation['messages'])
def test_validation_finishes_if_containing_invalid_filename(self): file_ = get_addon_file('invalid_webextension.xpi') upload = FileUpload.objects.create(path=file_, user=self.user) tasks.validate(upload, listed=True) upload.refresh_from_db() # https://github.com/mozilla/addons-server/issues/8208 # causes this to be 2 (and invalid) instead of 0 (and valid). # The invalid filename error is caught and raised outside of this # validation task. assert upload.processed_validation['errors'] == 2 assert not upload.valid
def test_submit_legacy_extension_1st_version_in_that_channel_reverse(self): file_ = get_addon_file('valid_firefox_addon.xpi') addon = addon_factory( version_kw={'version': '0.1', 'channel': amo.RELEASE_CHANNEL_LISTED}) upload = FileUpload.objects.create(path=file_, addon=addon) tasks.validate(upload, listed=False) upload.refresh_from_db() assert upload.processed_validation['errors'] == 1 expected = ['validation', 'messages', 'legacy_addons_restricted'] assert upload.processed_validation['messages'][0]['id'] == expected assert not upload.valid
def process_webhook(upload_pk, callbacks): log.info('Processing webhook for: {}'.format(upload_pk)) upload = FileUpload.objects.get(pk=upload_pk) github = GithubCallback(callbacks) res = github.get() upload.name = '{}-github-webhook.xpi'.format(upload.pk) upload.path = rezip_file(res, upload.pk) upload.save() log.info('Validating: {}'.format(upload_pk)) validate(upload, listed=True, subtask=process_results.si(upload_pk, callbacks))
def test_submit_dictionary_upgrade_targeting_firefox_57(self): # Should not error: non-extensions types are not affected by the # restriction, even if they target 57. file_ = get_addon_file('dictionary_targeting_57.xpi') addon = addon_factory(version_kw={'version': '0.1'}, type=amo.ADDON_DICT) upload = FileUpload.objects.create(path=file_, addon=addon) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_submit_legacy_extension_waffle_is_off(self): switch = Switch.objects.get(name='restrict-new-legacy-submissions') switch.active = False switch.save() file_ = get_addon_file('valid_firefox_addon.xpi') upload = FileUpload.objects.create(path=file_) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 0 assert upload.processed_validation['messages'] == [] assert upload.valid
def test_annotate_passed_auto_validation_bogus_result(self, _mock): """Don't set passed_auto_validation, don't fail if results is bogus.""" _mock.return_value = '{"errors": 0}' tasks.validate(self.upload) assert (json.loads(self.get_upload().validation) == { "passed_auto_validation": True, "errors": 0, "signing_summary": { "high": 0, "medium": 0, "low": 0, "trivial": 0 } })
def test_validates_search_plugins_inline(self, run_linter): addon = addon_factory( file_kw={'filename': 'opensearch/sp_updateurl.xml'}) file_ = addon.current_version.current_file tasks.validate(file_, synchronous=True).get() assert not run_linter.called file_.refresh_from_db() validation = file_.validation.processed_validation assert validation['errors'] == 2 assert validation['messages'][0]['message'].startswith( 'OpenSearch: <updateURL> elements')
def test_webextension_cannot_be_downgraded(self): self.update_files(is_webextension=True) file_ = amo.tests.AMOPaths().file_fixture_path( 'delicious_bookmarks-2.1.106-fx.xpi') upload = self.get_upload( abspath=file_, with_validation=False, addon=self.addon) tasks.validate(upload, listed=True) upload.refresh_from_db() expected = ['validation', 'messages', 'legacy_addons_unsupported'] validation = upload.processed_validation assert validation['messages'][0]['id'] == expected assert validation['messages'][0]['type'] == 'error'
def test_validation_error_webextension(self, _mock): _mock.side_effect = Exception self.upload.update(path=get_addon_file('valid_webextension.xpi')) assert self.upload.validation is None tasks.validate(self.upload, listed=True) self.upload.reload() validation = self.upload.processed_validation assert validation assert validation['errors'] == 1 assert validation['messages'][0]['id'] == [ 'validator', 'unexpected_exception'] assert 'WebExtension' in validation['messages'][0]['message'] assert not self.upload.valid
def test_validation_error(self, _mock): _mock.side_effect = Exception self.upload.update(path=get_addon_file('desktop.xpi')) assert self.upload.validation is None tasks.validate(self.upload) self.upload.reload() validation = self.upload.processed_validation assert validation assert validation['errors'] == 1 assert validation['messages'][0]['id'] == ['validator', 'unexpected_exception'] assert not self.upload.valid
def test_webextension_cannot_be_downgraded(self): self.update_files(is_webextension=True) file_ = amo.tests.AMOPaths().file_fixture_path( 'delicious_bookmarks-2.1.106-fx.xpi') upload = FileUpload.objects.create(path=file_, addon=self.addon) tasks.validate(upload, listed=True) upload.refresh_from_db() expected = ['validation', 'messages', 'webext_downgrade'] validation = upload.processed_validation assert validation['messages'][0]['id'] == expected assert validation['messages'][0]['type'] == 'error'
def test_submit_legacy_upgrade_targeting_firefox_57(self): # Should error since it's a legacy extension targeting 57. file_ = get_addon_file('valid_firefox_addon_targeting_57.xpi') addon = addon_factory(version_kw={'version': '0.1'}) upload = FileUpload.objects.create(path=file_, addon=addon) tasks.validate(upload, listed=True) upload.refresh_from_db() assert upload.processed_validation['errors'] == 1 assert len(upload.processed_validation['messages']) == 1 assert upload.processed_validation['messages'][0]['type'] == 'error' assert upload.processed_validation['messages'][0]['id'] == [ 'validation', 'messages', 'legacy_addons_max_version'] assert not upload.valid