def test_signing_error_roll_back(self, sign_file_mock): sign_file_mock.side_effect = [SigningError, None] call_command('auto_approve') # Make sure that the AutoApprovalSummary created for the first add-on # was rolled back because of the signing error, and that it didn't # affect the approval of the second one. assert sign_file_mock.call_count == 2 for file_ in self.files: file_.reload() for addon in self.addons: addon.reload() assert not AutoApprovalSummary.objects.filter( version=self.versions[0]).exists() assert self.addons[0].status == amo.STATUS_APPROVED # It already was. assert self.files[0].status == amo.STATUS_AWAITING_REVIEW assert not self.files[0].reviewed assert AutoApprovalSummary.objects.get(version=self.versions[1]) assert self.addons[1].status == amo.STATUS_APPROVED assert self.files[1].status == amo.STATUS_APPROVED assert self.files[1].reviewed assert len(mail.outbox) == 1 assert get_reviewing_cache(self.addons[0].pk) is None assert get_reviewing_cache(self.addons[1].pk) is None self._check_stats({'total': 2, 'error': 1, 'is_locked': 0, 'has_auto_approval_disabled': 0, 'auto_approved': 1, 'is_recommendable': 0, 'should_be_delayed': 0})
def test_signing_error_roll_back(self, sign_file_mock): sign_file_mock.side_effect = [SigningError, None] call_command('auto_approve') # Make sure that the AutoApprovalSummary created for the first add-on # was rolled back because of the signing error, and that it didn't # affect the approval of the second one. assert sign_file_mock.call_count == 2 for file_ in self.files: file_.reload() for addon in self.addons: addon.reload() assert not AutoApprovalSummary.objects.filter( version=self.versions[0]).exists() assert self.addons[0].status == amo.STATUS_APPROVED # It already was. assert self.files[0].status == amo.STATUS_AWAITING_REVIEW assert not self.files[0].reviewed assert AutoApprovalSummary.objects.get(version=self.versions[1]) assert self.addons[1].status == amo.STATUS_APPROVED assert self.files[1].status == amo.STATUS_APPROVED assert self.files[1].reviewed assert len(mail.outbox) == 1 assert get_reviewing_cache(self.addons[0].pk) is None assert get_reviewing_cache(self.addons[1].pk) is None self._check_stats({'total': 2, 'error': 1, 'is_locked': 0, 'has_auto_approval_disabled': 0, 'auto_approved': 1})
def test_no_validation_result(self, create_summary_for_version_mock): create_summary_for_version_mock.side_effect = ( AutoApprovalNoValidationResultError) call_command('auto_approve') assert get_reviewing_cache(self.addon.pk) is None assert create_summary_for_version_mock.call_count == 1 self._check_stats({'total': 1, 'error': 1})
def test_not_enough_files_error(self, create_summary_for_version_mock): create_summary_for_version_mock.side_effect = ( AutoApprovalNotEnoughFilesError) call_command('auto_approve') assert get_reviewing_cache(self.addon.pk) is None assert create_summary_for_version_mock.call_count == 1 self._check_stats({'total': 1, 'error': 1})
def test_signing_error(self, sign_file_mock): sign_file_mock.side_effect = SigningError call_command('auto_approve') assert sign_file_mock.call_count == 1 assert get_reviewing_cache(self.addon.pk) is None self._check_stats({'total': 1, 'error': 1, 'is_locked': 0, 'has_auto_approval_disabled': 0})
def process_addon(self, *, addon, now): latest_version = addon.find_latest_version( channel=amo.RELEASE_CHANNEL_LISTED) if (latest_version and latest_version.is_unreviewed and not latest_version.pending_rejection): # If latest version is unreviewed and not pending # rejection, we want to put the delayed rejection of all # versions of this addon on hold until a decision has been # made by reviewers on the latest one. log.info( 'Skipping rejections for add-on %s until version %s ' 'has been reviewed', addon.pk, latest_version.pk) return versions = self.fetch_version_candidates_for_addon(addon=addon, now=now) if not versions.exists(): log.info('Somehow no versions to auto-reject for add-on %s', addon.pk) return locked_by = get_reviewing_cache(addon.pk) if locked_by: # Don't auto-reject something that has been locked, even by the # task user - wait until it's free to avoid any conflicts. log.info( 'Skipping rejections for add-on %s until lock from user %s ' 'has expired', addon.pk, locked_by) return set_reviewing_cache(addon.pk, settings.TASK_USER_ID) try: self.reject_versions(addon=addon, versions=versions, latest_version=latest_version) finally: # Always clear our lock no matter what happens. clear_reviewing_cache(addon.pk)
def test_successful_verdict_dry_run( self, create_summary_for_version_mock, approve_mock): create_summary_for_version_mock.return_value = ( AutoApprovalSummary(verdict=amo.WOULD_HAVE_BEEN_AUTO_APPROVED), {}) call_command('auto_approve', '--dry-run') assert approve_mock.call_count == 0 assert create_summary_for_version_mock.call_args == ( (self.version, ), {'dry_run': True}) assert get_reviewing_cache(self.addon.pk) is None self._check_stats({'total': 1, 'auto_approved': 1})
def test_failed_verdict(self, create_summary_for_version_mock, approve_mock): fake_verdict_info = {'is_locked': True} create_summary_for_version_mock.return_value = (AutoApprovalSummary( verdict=amo.NOT_AUTO_APPROVED), fake_verdict_info) call_command('auto_approve') assert approve_mock.call_count == 0 assert create_summary_for_version_mock.call_args == ((self.version, ), { 'dry_run': False }) assert get_reviewing_cache(self.addon.pk) is None self._check_stats({ 'total': 1, 'is_locked': 1, })
def test_failed_verdict( self, create_summary_for_version_mock, approve_mock): fake_verdict_info = { 'is_locked': True } create_summary_for_version_mock.return_value = ( AutoApprovalSummary(verdict=amo.NOT_AUTO_APPROVED), fake_verdict_info) call_command('auto_approve') assert approve_mock.call_count == 0 assert create_summary_for_version_mock.call_args == ( (self.version, ), {'dry_run': False}) assert get_reviewing_cache(self.addon.pk) is None self._check_stats({ 'total': 1, 'is_locked': 1, })
def review_viewing(request): if 'addon_id' not in request.POST: return {} addon_id = request.POST['addon_id'] user_id = request.user.id current_name = '' is_user = 0 key = get_reviewing_cache_key(addon_id) user_key = '%s:review_viewing_user:%s' % (settings.CACHE_PREFIX, user_id) interval = amo.REVIEWER_VIEWING_INTERVAL # Check who is viewing. currently_viewing = get_reviewing_cache(addon_id) # If nobody is viewing or current user is, set current user as viewing if not currently_viewing or currently_viewing == user_id: # Get a list of all the reviews this user is locked on. review_locks = cache.get_many(cache.get(user_key, {})) can_lock_more_reviews = ( len(review_locks) < amo.REVIEWER_REVIEW_LOCK_LIMIT or acl.action_allowed(request, amo.permissions.REVIEWER_ADMIN_TOOLS_VIEW)) if can_lock_more_reviews or currently_viewing == user_id: set_reviewing_cache(addon_id, user_id) # Give it double expiry just to be safe. cache.set(user_key, set(review_locks) | {key}, interval * 4) currently_viewing = user_id current_name = request.user.name is_user = 1 else: currently_viewing = settings.TASK_USER_ID current_name = ugettext('Review lock limit reached') is_user = 2 else: current_name = UserProfile.objects.get(pk=currently_viewing).name return { 'current': currently_viewing, 'current_name': current_name, 'is_user': is_user, 'interval_seconds': interval }
def review_viewing(request): if 'addon_id' not in request.POST: return {} addon_id = request.POST['addon_id'] user_id = request.user.id current_name = '' is_user = 0 key = get_reviewing_cache_key(addon_id) user_key = '%s:review_viewing_user:%s' % (settings.CACHE_PREFIX, user_id) interval = amo.REVIEWER_VIEWING_INTERVAL # Check who is viewing. currently_viewing = get_reviewing_cache(addon_id) # If nobody is viewing or current user is, set current user as viewing if not currently_viewing or currently_viewing == user_id: # Get a list of all the reviews this user is locked on. review_locks = cache.get_many(cache.get(user_key, {})) can_lock_more_reviews = ( len(review_locks) < amo.REVIEWER_REVIEW_LOCK_LIMIT or acl.action_allowed(request, amo.permissions.REVIEWS_ADMIN)) if can_lock_more_reviews or currently_viewing == user_id: set_reviewing_cache(addon_id, user_id) # Give it double expiry just to be safe. cache.set(user_key, set(review_locks) | {key}, interval * 4) currently_viewing = user_id current_name = request.user.name is_user = 1 else: currently_viewing = settings.TASK_USER_ID current_name = ugettext('Review lock limit reached') is_user = 2 else: current_name = UserProfile.objects.get(pk=currently_viewing).name return {'current': currently_viewing, 'current_name': current_name, 'is_user': is_user, 'interval_seconds': interval}
def test_full(self, sign_file_mock): # Simple integration test with as few mocks as possible. assert not AutoApprovalSummary.objects.exists() assert not self.file.reviewed ActivityLog.objects.all().delete() self.author = user_factory() self.addon.addonuser_set.create(user=self.author) # Delete the add-on current version and approval info, leaving it # nominated. Set its nomination date in the past and it should be # picked up and auto-approved. AddonApprovalsCounter.objects.filter(addon=self.addon).get().delete() self.addon.current_version.delete() self.version.update(nomination=self.days_ago(2)) self.addon.update_status() call_command('auto_approve', '--dry-run') call_command('auto_approve') self.addon.reload() self.file.reload() assert AutoApprovalSummary.objects.count() == 1 assert AutoApprovalSummary.objects.get(version=self.version) assert get_reviewing_cache(self.addon.pk) is None assert self.addon.status == amo.STATUS_APPROVED assert self.file.status == amo.STATUS_APPROVED assert self.file.reviewed assert ActivityLog.objects.count() activity_log = ActivityLog.objects.latest('pk') assert activity_log.action == amo.LOG.APPROVE_VERSION.id assert sign_file_mock.call_count == 1 assert sign_file_mock.call_args[0][0] == self.file assert len(mail.outbox) == 1 msg = mail.outbox[0] assert msg.to == [self.author.email] assert msg.from_email == settings.ADDONS_EMAIL assert msg.subject == 'Mozilla Add-ons: %s %s Approved' % (str( self.addon.name), self.version.version)
def test_full(self, sign_file_mock): # Simple integration test with as few mocks as possible. assert not AutoApprovalSummary.objects.exists() assert not self.file.reviewed ActivityLog.objects.all().delete() self.author = user_factory() self.addon.addonuser_set.create(user=self.author) # Delete the add-on current version and approval info, leaving it # nominated. Because we're in post-review we should pick it up and # approve it anyway. AddonApprovalsCounter.objects.filter(addon=self.addon).get().delete() self.addon.current_version.delete() self.addon.update_status() call_command('auto_approve', '--dry-run') call_command('auto_approve') self.addon.reload() self.file.reload() assert AutoApprovalSummary.objects.count() == 1 assert AutoApprovalSummary.objects.get(version=self.version) assert get_reviewing_cache(self.addon.pk) is None assert self.addon.status == amo.STATUS_APPROVED assert self.file.status == amo.STATUS_APPROVED assert self.file.reviewed assert ActivityLog.objects.count() activity_log = ActivityLog.objects.latest('pk') assert activity_log.action == amo.LOG.APPROVE_VERSION.id assert sign_file_mock.call_count == 1 assert sign_file_mock.call_args[0][0] == self.file assert len(mail.outbox) == 1 msg = mail.outbox[0] assert msg.to == [self.author.email] assert msg.from_email == settings.ADDONS_EMAIL assert msg.subject == 'Mozilla Add-ons: %s %s Approved' % ( six.text_type(self.addon.name), self.version.version)