Example #1
0
    def test_subscriber_is_reporter(self):
        self.bug = self.factory.makeBug(owner=self.subscriber)
        self.subscriptions = PersonSubscriptions(self.subscriber, self.bug)
        # Subscribed directly to the bug.
        with person_logged_in(self.subscriber):
            self.bug.subscribe(self.subscriber, self.subscriber)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.direct.personal[0],
            self.bug, self.subscriber, True, [])
Example #2
0
 def initialize(self):
     super(BugSubscriptionListView, self).initialize()
     subscriptions = list(
         get_structural_subscriptions_for_bug(self.context.bug, self.user))
     expose_structural_subscription_data_to_js(self.context, self.request,
                                               self.user, subscriptions)
     subscriptions_info = PersonSubscriptions(self.user, self.context.bug)
     subdata, references = subscriptions_info.getDataForClient()
     cache = IJSONRequestCache(self.request).objects
     cache.update(references)
     cache['bug_subscription_info'] = subdata
     cache['bug_is_private'] = self.context.bug.private
 def initialize(self):
     super(BugSubscriptionListView, self).initialize()
     subscriptions = list(get_structural_subscriptions_for_bug(
         self.context.bug, self.user))
     expose_structural_subscription_data_to_js(
         self.context, self.request, self.user, subscriptions)
     subscriptions_info = PersonSubscriptions(
             self.user, self.context.bug)
     subdata, references = subscriptions_info.getDataForClient()
     cache = IJSONRequestCache(self.request).objects
     cache.update(references)
     cache['bug_subscription_info'] = subdata
     cache['bug_is_private'] = self.context.bug.private
    def test_subscriber_is_reporter(self):
        self.bug = self.factory.makeBug(owner=self.subscriber)
        self.subscriptions = PersonSubscriptions(self.subscriber, self.bug)
        # Subscribed directly to the bug.
        with person_logged_in(self.subscriber):
            self.bug.subscribe(self.subscriber, self.subscriber)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.direct.personal[0],
            self.bug, self.subscriber, True, [])
Example #5
0
 def extractBugSubscriptionDetails(self, user, bug, cache):
     # We are using "direct" to represent both direct and personal
     # (not team).
     self.direct_notifications = False
     self.direct_all_notifications = False
     self.direct_metadata_notifications = False
     self.direct_lifecycle_notifications = False
     self.other_subscription_notifications = False
     self.only_other_subscription_notifications = False
     self.any_subscription_notifications = False
     self.muted = False
     if user is not None:
         has_structural_subscriptions = not (
             get_structural_subscriptions_for_bug(bug, user).is_empty())
         self.muted = bug.isMuted(user)
         psi = PersonSubscriptions(user, bug)
         if psi.direct.personal:
             self.direct_notifications = True
             direct = psi.direct.personal[0]
             cache['subscription'] = direct.subscription
             level = direct.subscription.bug_notification_level
             if level == BugNotificationLevel.COMMENTS:
                 self.direct_all_notifications = True
             elif level == BugNotificationLevel.METADATA:
                 self.direct_metadata_notifications = True
             else:
                 assert level == BugNotificationLevel.LIFECYCLE
                 self.direct_lifecycle_notifications = True
         self.other_subscription_notifications = bool(
             has_structural_subscriptions or
             psi.from_duplicate.count or
             psi.as_owner.count or
             psi.as_assignee.count or
             psi.direct.as_team_member or
             psi.direct.as_team_admin)
         cache['other_subscription_notifications'] = bool(
             self.other_subscription_notifications)
         self.only_other_subscription_notifications = (
             self.other_subscription_notifications and
             not self.direct_notifications)
         self.any_subscription_notifications = (
             self.other_subscription_notifications or
             self.direct_notifications)
     self.user_should_see_mute_link = (
         self.any_subscription_notifications or self.muted)
 def setUp(self):
     super(TestPersonSubscriptionInfo, self).setUp()
     self.subscriber = self.factory.makePerson()
     self.bug = self.factory.makeBug()
     self.subscriptions = PersonSubscriptions(self.subscriber, self.bug)
class TestPersonSubscriptionInfo(TestCaseWithFactory):

    layer = DatabaseFunctionalLayer

    def setUp(self):
        super(TestPersonSubscriptionInfo, self).setUp()
        self.subscriber = self.factory.makePerson()
        self.bug = self.factory.makeBug()
        self.subscriptions = PersonSubscriptions(self.subscriber, self.bug)

    def makeDuplicates(self, count=1, subscriber=None):
        if subscriber is None:
            subscriber = self.subscriber
        if subscriber.is_team:
            subscribed_by = subscriber.teamowner
        else:
            subscribed_by = subscriber
        duplicates = [self.factory.makeBug() for i in range(count)]
        with person_logged_in(subscribed_by):
            for duplicate in duplicates:
                duplicate.markAsDuplicate(self.bug)
                duplicate.subscribe(subscriber, subscribed_by)
        return duplicates

    def assertCollectionsAreEmpty(self, except_=None):
        names = ('direct', 'from_duplicate', 'as_owner', 'as_assignee')
        assert except_ is None or except_ in names
        for name in names:
            collection = getattr(self.subscriptions, name)
            if name == except_:
                self.assertEqual(self.subscriptions.count, collection.count)
            else:
                self.assertEqual(collection.count, 0)

    def assertCollectionContents(
        self, collection,
        personal=0, as_team_member=0, as_team_admin=0):
        # Make sure that the collection has the values we expect.
        self.assertEqual(collection.count,
                         personal + as_team_member + as_team_admin)
        for name, expected in (('personal', personal),
                            ('as_team_member', as_team_member),
                            ('as_team_admin', as_team_admin)):
            actual = getattr(collection, name)
            self.assertEqual(expected, len(actual))
            if IVirtualSubscriptionInfoCollection.providedBy(collection):
                expected_interface = IVirtualSubscriptionInfo
            else:
                self.assertThat(collection,
                                Provides(IRealSubscriptionInfoCollection))
                expected_interface = IRealSubscriptionInfo
            for info in actual:
                self.assertThat(info, Provides(expected_interface))

    def assertVirtualSubscriptionInfoMatches(
        self, info, bug, principal, pillar, bugtasks):
        # Make sure that the virtual subscription info has expected values.
        self.assertEqual(info.bug, bug)
        self.assertEqual(info.principal, principal)
        self.assertEqual(info.pillar, pillar)
        self.assertContentEqual(info.tasks, bugtasks)

    def assertRealSubscriptionInfoMatches(self, info, bug, principal,
                                          principal_is_reporter,
                                          bug_supervisor_tasks):
        # Make sure that the real subscription info has expected values.
        self.assertEqual(info.bug, bug)
        self.assertEqual(info.principal, principal)
        self.assertEqual(info.principal_is_reporter, principal_is_reporter)
        self.assertContentEqual(
            info.bug_supervisor_tasks, bug_supervisor_tasks)

    def test_no_subscriptions(self):
        # Load a `PersonSubscriptionInfo`s for a subscriber and a bug.
        self.subscriptions.reload()
        self.assertCollectionsAreEmpty()
        self.failIf(self.subscriptions.muted)

    def test_no_subscriptions_getDataForClient(self):
        self.subscriptions.reload()
        subscriptions, references = self.subscriptions.getDataForClient()
        self.assertEqual(references, {})
        self.assertEqual(subscriptions['count'], 0)
        self.assertEqual(subscriptions['muted'], False)
        self.assertEqual(subscriptions['direct']['count'], 0)
        self.assertEqual(subscriptions['from_duplicate']['count'], 0)
        self.assertEqual(subscriptions['as_owner']['count'], 0)
        self.assertEqual(subscriptions['as_assignee']['count'], 0)
        self.assertEqual(subscriptions['bug_id'], self.bug.id)

    def test_assignee(self):
        with person_logged_in(self.subscriber):
            self.bug.default_bugtask.transitionToAssignee(self.subscriber)
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='as_assignee')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.as_assignee, personal=1)
        self.assertVirtualSubscriptionInfoMatches(
            self.subscriptions.as_assignee.personal[0],
            self.bug, self.subscriber,
            self.bug.default_bugtask.target, [self.bug.default_bugtask])

    def test_assignee_getDataForClient(self):
        with person_logged_in(self.subscriber):
            self.bug.default_bugtask.transitionToAssignee(self.subscriber)
        self.subscriptions.reload()

        subscriptions, references = self.subscriptions.getDataForClient()
        self.assertEqual(len(references), 3)
        self.assertEqual(subscriptions['count'], 1)
        self.assertEqual(subscriptions['muted'], False)
        self.assertEqual(subscriptions['direct']['count'], 0)
        self.assertEqual(subscriptions['from_duplicate']['count'], 0)
        self.assertEqual(subscriptions['as_owner']['count'], 0)
        self.assertEqual(subscriptions['as_assignee']['count'], 1)
        personal = subscriptions['as_assignee']['personal'][0]
        self.assertEqual(references[personal['bug']], self.bug)
        self.assertEqual(references[personal['principal']], self.subscriber)
        self.assertEqual(references[personal['pillar']],
                         self.bug.default_bugtask.target)

    def test_assignee_through_team(self):
        team = self.factory.makeTeam(members=[self.subscriber])
        with person_logged_in(self.subscriber):
            self.bug.bugtasks[0].transitionToAssignee(team)
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='as_assignee')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.as_assignee, as_team_member=1)
        self.assertVirtualSubscriptionInfoMatches(
            self.subscriptions.as_assignee.as_team_member[0],
            self.bug, team,
            self.bug.default_bugtask.target, [self.bug.default_bugtask])

    def test_assignee_through_team_getDataForClient(self):
        team = self.factory.makeTeam(members=[self.subscriber])
        with person_logged_in(self.subscriber):
            self.bug.bugtasks[0].transitionToAssignee(team)
        self.subscriptions.reload()

        subscriptions, references = self.subscriptions.getDataForClient()
        personal = subscriptions['as_assignee']['as_team_member'][0]
        self.assertEqual(references[personal['principal']], team)

    def test_assignee_through_team_as_admin(self):
        team = self.factory.makeTeam()
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
            self.bug.bugtasks[0].transitionToAssignee(team)
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='as_assignee')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.as_assignee, as_team_admin=1)
        self.assertVirtualSubscriptionInfoMatches(
            self.subscriptions.as_assignee.as_team_admin[0],
            self.bug, team,
            self.bug.default_bugtask.target, [self.bug.default_bugtask])

    def test_assignee_through_team_as_admin_getDataForClient(self):
        team = self.factory.makeTeam()
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
            self.bug.bugtasks[0].transitionToAssignee(team)
        self.subscriptions.reload()

        subscriptions, references = self.subscriptions.getDataForClient()
        personal = subscriptions['as_assignee']['as_team_admin'][0]
        self.assertEqual(references[personal['principal']], team)

    def test_direct(self):
        # Subscribed directly to the bug.
        with person_logged_in(self.subscriber):
            self.bug.subscribe(self.subscriber, self.subscriber)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='direct')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.direct, personal=1)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.direct.personal[0],
            self.bug, self.subscriber, False, [])

    def test_direct_getDataForClient(self):
        # Subscribed directly to the bug.
        with person_logged_in(self.subscriber):
            subscription = self.bug.subscribe(
                self.subscriber, self.subscriber)
        self.subscriptions.reload()

        subscriptions, references = self.subscriptions.getDataForClient()
        personal = subscriptions['direct']['personal'][0]
        self.assertEqual(references[personal['principal']], self.subscriber)
        self.assertEqual(references[personal['bug']], self.bug)
        self.assertEqual(references[personal['subscription']], subscription)
        self.assertEqual(personal['principal_is_reporter'], False)
        self.assertEqual(personal['bug_supervisor_pillars'], [])

    def test_direct_through_team(self):
        # Subscribed to the bug through membership in a team.
        team = self.factory.makeTeam(members=[self.subscriber])
        with person_logged_in(self.subscriber):
            self.bug.subscribe(team, self.subscriber)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='direct')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.direct, as_team_member=1)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.direct.as_team_member[0],
            self.bug, team, False, [])

    def test_direct_through_team_getDataForClient(self):
        # Subscribed to the bug through membership in a team.
        team = self.factory.makeTeam(members=[self.subscriber])
        with person_logged_in(self.subscriber):
            self.bug.subscribe(team, self.subscriber)
        self.subscriptions.reload()

        subscriptions, references = self.subscriptions.getDataForClient()
        personal = subscriptions['direct']['as_team_member'][0]
        self.assertEqual(references[personal['principal']], team)

    def test_direct_through_team_as_admin(self):
        # Subscribed to the bug through membership in a team
        # as an admin of that team.
        team = self.factory.makeTeam()
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
            self.bug.subscribe(team, team.teamowner)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='direct')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.direct, as_team_admin=1)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.direct.as_team_admin[0],
            self.bug, team, False, [])

    def test_direct_through_team_as_admin_getDataForClient(self):
        # Subscribed to the bug through membership in a team
        # as an admin of that team.
        team = self.factory.makeTeam()
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
            self.bug.subscribe(team, team.teamowner)
        self.subscriptions.reload()

        subscriptions, references = self.subscriptions.getDataForClient()
        personal = subscriptions['direct']['as_team_admin'][0]
        self.assertEqual(references[personal['principal']], team)

    def test_duplicate_direct(self):
        # Subscribed directly to the duplicate bug.
        [duplicate] = self.makeDuplicates(count=1)
        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='from_duplicate')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, personal=1)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.from_duplicate.personal[0],
            duplicate, self.subscriber, False, [])

    def test_duplicate_direct_reverse(self):
        # Subscribed directly to the primary bug, and a duplicate bug changes.
        primary = self.factory.makeBug()
        with person_logged_in(self.subscriber):
            self.bug.markAsDuplicate(primary)
            primary.subscribe(self.subscriber, self.subscriber)
        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        # This means no subscriptions on the duplicate bug.
        self.assertCollectionsAreEmpty()
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, personal=0)

    def test_duplicate_multiple(self):
        # Subscribed directly to more than one duplicate bug.
        duplicate1 = self.factory.makeBug()
        duplicate2 = self.factory.makeBug()
        with person_logged_in(self.subscriber):
            duplicate1.markAsDuplicate(self.bug)
            duplicate1.subscribe(self.subscriber, self.subscriber)
            duplicate2.markAsDuplicate(self.bug)
            duplicate2.subscribe(self.subscriber, self.subscriber)
        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='from_duplicate')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, personal=2)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.from_duplicate.personal[0],
            duplicate1, self.subscriber, False, [])
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.from_duplicate.personal[1],
            duplicate2, self.subscriber, False, [])

    def test_duplicate_through_team(self):
        # Subscribed to a duplicate bug through team membership.
        team = self.factory.makeTeam(members=[self.subscriber])
        duplicate = self.factory.makeBug()
        with person_logged_in(self.subscriber):
            duplicate.markAsDuplicate(self.bug)
            duplicate.subscribe(team, self.subscriber)
        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='from_duplicate')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, as_team_member=1)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.from_duplicate.as_team_member[0],
            duplicate, team, False, [])

    def test_duplicate_through_team_as_admin(self):
        # Subscribed to a duplicate bug through team membership
        # as an admin of that team.
        team = self.factory.makeTeam()
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
        duplicate = self.factory.makeBug()
        with person_logged_in(self.subscriber):
            duplicate.markAsDuplicate(self.bug)
            duplicate.subscribe(team, self.subscriber)
        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='from_duplicate')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, as_team_admin=1)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.from_duplicate.as_team_admin[0],
            duplicate, team, False, [])

    def test_subscriber_is_reporter(self):
        self.bug = self.factory.makeBug(owner=self.subscriber)
        self.subscriptions = PersonSubscriptions(self.subscriber, self.bug)
        # Subscribed directly to the bug.
        with person_logged_in(self.subscriber):
            self.bug.subscribe(self.subscriber, self.subscriber)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.direct.personal[0],
            self.bug, self.subscriber, True, [])

    def test_subscriber_is_bug_supervisor(self):
        target = self.bug.default_bugtask.target
        removeSecurityProxy(target).bug_supervisor = self.subscriber
        # Subscribed directly to the bug.
        with person_logged_in(self.subscriber):
            self.bug.subscribe(self.subscriber, self.subscriber)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.direct.personal[0],
            self.bug, self.subscriber, False,
             [{'task': self.bug.default_bugtask, 'pillar': target}])

    def test_owner(self):
        # Bug is targeted to a pillar with no supervisor set.
        target = self.bug.default_bugtask.target
        # Load a `PersonSubscriptionInfo`s for target.owner and a bug.
        self.subscriptions.loadSubscriptionsFor(target.owner, self.bug)

        self.assertCollectionsAreEmpty(except_='as_owner')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.as_owner, personal=1)
        self.assertVirtualSubscriptionInfoMatches(
            self.subscriptions.as_owner.personal[0],
            self.bug, target.owner,
            self.bug.default_bugtask.target, [self.bug.default_bugtask])

    def test_owner_as_bug_supervisor_is_empty(self):
        target = self.bug.default_bugtask.target
        removeSecurityProxy(target).bug_supervisor = target.owner
        # Subscribed directly to the bug.
        self.subscriptions.loadSubscriptionsFor(target.owner, self.bug)
        self.assertCollectionsAreEmpty()
        self.failIf(self.subscriptions.muted)

    def test_owner_through_team(self):
        # Bug is targeted to a pillar with no supervisor set.
        target = self.bug.default_bugtask.target
        team = self.factory.makeTeam(
            members=[self.subscriber],
            membership_policy=TeamMembershipPolicy.RESTRICTED)
        removeSecurityProxy(target).owner = team
        # Load a `PersonSubscriptionInfo`s for target.owner and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='as_owner')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.as_owner, as_team_member=1)
        self.assertVirtualSubscriptionInfoMatches(
            self.subscriptions.as_owner.as_team_member[0],
            self.bug, target.owner,
            self.bug.default_bugtask.target, [self.bug.default_bugtask])

    def test_owner_through_team_as_admin(self):
        # Bug is targeted to a pillar with no supervisor set.
        target = self.bug.default_bugtask.target
        team = self.factory.makeTeam(
            membership_policy=TeamMembershipPolicy.RESTRICTED)
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
        removeSecurityProxy(target).owner = team
        # Load a `PersonSubscriptionInfo`s for target.owner and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='as_owner')
        self.failIf(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.as_owner, as_team_admin=1)
        self.assertVirtualSubscriptionInfoMatches(
            self.subscriptions.as_owner.as_team_admin[0],
            self.bug, target.owner,
            self.bug.default_bugtask.target, [self.bug.default_bugtask])

    def test_is_muted(self):
        # Subscribed directly to the bug, muted.
        with person_logged_in(self.subscriber):
            self.bug.mute(self.subscriber, self.subscriber)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.failUnless(self.subscriptions.muted)

    def test_many_duplicate_team_admin_subscriptions_few_queries(self):
        # This is related to bug 811447. The user is subscribed to a
        # duplicate bug through team membership in which the user is an admin.
        team = self.factory.makeTeam()
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
        self.makeDuplicates(count=1, subscriber=team)
        with StormStatementRecorder() as recorder:
            self.subscriptions.reload()
        # This should produce a very small number of queries.
        self.assertThat(recorder, HasQueryCount(LessThan(6)))
        count_with_one_subscribed_duplicate = recorder.count
        # It should have the correct result.
        self.assertCollectionsAreEmpty(except_='from_duplicate')
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, as_team_admin=1)
        # If we increase the number of duplicates subscribed via the team that
        # the user administers...
        self.makeDuplicates(count=4, subscriber=team)
        with StormStatementRecorder() as recorder:
            self.subscriptions.reload()
        # ...then the query count should remain the same.
        count_with_five_subscribed_duplicates = recorder.count
        self.assertEqual(
            count_with_one_subscribed_duplicate,
            count_with_five_subscribed_duplicates)
        # We should still have the correct result.
        self.assertCollectionsAreEmpty(except_='from_duplicate')
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, as_team_admin=5)
Example #8
0
 def setUp(self):
     super(TestPersonSubscriptionInfo, self).setUp()
     self.subscriber = self.factory.makePerson()
     self.bug = self.factory.makeBug()
     self.subscriptions = PersonSubscriptions(self.subscriber, self.bug)
Example #9
0
class TestPersonSubscriptionInfo(TestCaseWithFactory):

    layer = DatabaseFunctionalLayer

    def setUp(self):
        super(TestPersonSubscriptionInfo, self).setUp()
        self.subscriber = self.factory.makePerson()
        self.bug = self.factory.makeBug()
        self.subscriptions = PersonSubscriptions(self.subscriber, self.bug)

    def makeDuplicates(self, count=1, subscriber=None):
        if subscriber is None:
            subscriber = self.subscriber
        if subscriber.is_team:
            subscribed_by = subscriber.teamowner
        else:
            subscribed_by = subscriber
        duplicates = [self.factory.makeBug() for i in range(count)]
        with person_logged_in(subscribed_by):
            for duplicate in duplicates:
                duplicate.markAsDuplicate(self.bug)
                duplicate.subscribe(subscriber, subscribed_by)
        return duplicates

    def assertCollectionsAreEmpty(self, except_=None):
        names = ('direct', 'from_duplicate', 'as_owner', 'as_assignee')
        assert except_ is None or except_ in names
        for name in names:
            collection = getattr(self.subscriptions, name)
            if name == except_:
                self.assertEqual(self.subscriptions.count, collection.count)
            else:
                self.assertEqual(collection.count, 0)

    def assertCollectionContents(
        self, collection,
        personal=0, as_team_member=0, as_team_admin=0):
        # Make sure that the collection has the values we expect.
        self.assertEqual(collection.count,
                         personal + as_team_member + as_team_admin)
        for name, expected in (('personal', personal),
                            ('as_team_member', as_team_member),
                            ('as_team_admin', as_team_admin)):
            actual = getattr(collection, name)
            self.assertEqual(expected, len(actual))
            if IVirtualSubscriptionInfoCollection.providedBy(collection):
                expected_interface = IVirtualSubscriptionInfo
            else:
                self.assertThat(collection,
                                Provides(IRealSubscriptionInfoCollection))
                expected_interface = IRealSubscriptionInfo
            for info in actual:
                self.assertThat(info, Provides(expected_interface))

    def assertVirtualSubscriptionInfoMatches(
        self, info, bug, principal, pillar, bugtasks):
        # Make sure that the virtual subscription info has expected values.
        self.assertEqual(info.bug, bug)
        self.assertEqual(info.principal, principal)
        self.assertEqual(info.pillar, pillar)
        self.assertContentEqual(info.tasks, bugtasks)

    def assertRealSubscriptionInfoMatches(self, info, bug, principal,
                                          principal_is_reporter,
                                          bug_supervisor_tasks):
        # Make sure that the real subscription info has expected values.
        self.assertEqual(info.bug, bug)
        self.assertEqual(info.principal, principal)
        self.assertEqual(info.principal_is_reporter, principal_is_reporter)
        self.assertContentEqual(
            info.bug_supervisor_tasks, bug_supervisor_tasks)

    def test_no_subscriptions(self):
        # Load a `PersonSubscriptionInfo`s for a subscriber and a bug.
        self.subscriptions.reload()
        self.assertCollectionsAreEmpty()
        self.assertFalse(self.subscriptions.muted)

    def test_no_subscriptions_getDataForClient(self):
        self.subscriptions.reload()
        subscriptions, references = self.subscriptions.getDataForClient()
        self.assertEqual(references, {})
        self.assertEqual(subscriptions['count'], 0)
        self.assertEqual(subscriptions['muted'], False)
        self.assertEqual(subscriptions['direct']['count'], 0)
        self.assertEqual(subscriptions['from_duplicate']['count'], 0)
        self.assertEqual(subscriptions['as_owner']['count'], 0)
        self.assertEqual(subscriptions['as_assignee']['count'], 0)
        self.assertEqual(subscriptions['bug_id'], self.bug.id)

    def test_assignee(self):
        with person_logged_in(self.subscriber):
            self.bug.default_bugtask.transitionToAssignee(self.subscriber)
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='as_assignee')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.as_assignee, personal=1)
        self.assertVirtualSubscriptionInfoMatches(
            self.subscriptions.as_assignee.personal[0],
            self.bug, self.subscriber,
            self.bug.default_bugtask.target, [self.bug.default_bugtask])

    def test_assignee_getDataForClient(self):
        with person_logged_in(self.subscriber):
            self.bug.default_bugtask.transitionToAssignee(self.subscriber)
        self.subscriptions.reload()

        subscriptions, references = self.subscriptions.getDataForClient()
        self.assertEqual(len(references), 3)
        self.assertEqual(subscriptions['count'], 1)
        self.assertEqual(subscriptions['muted'], False)
        self.assertEqual(subscriptions['direct']['count'], 0)
        self.assertEqual(subscriptions['from_duplicate']['count'], 0)
        self.assertEqual(subscriptions['as_owner']['count'], 0)
        self.assertEqual(subscriptions['as_assignee']['count'], 1)
        personal = subscriptions['as_assignee']['personal'][0]
        self.assertEqual(references[personal['bug']], self.bug)
        self.assertEqual(references[personal['principal']], self.subscriber)
        self.assertEqual(references[personal['pillar']],
                         self.bug.default_bugtask.target)

    def test_assignee_through_team(self):
        team = self.factory.makeTeam(members=[self.subscriber])
        with person_logged_in(self.subscriber):
            self.bug.bugtasks[0].transitionToAssignee(team)
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='as_assignee')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.as_assignee, as_team_member=1)
        self.assertVirtualSubscriptionInfoMatches(
            self.subscriptions.as_assignee.as_team_member[0],
            self.bug, team,
            self.bug.default_bugtask.target, [self.bug.default_bugtask])

    def test_assignee_through_team_getDataForClient(self):
        team = self.factory.makeTeam(members=[self.subscriber])
        with person_logged_in(self.subscriber):
            self.bug.bugtasks[0].transitionToAssignee(team)
        self.subscriptions.reload()

        subscriptions, references = self.subscriptions.getDataForClient()
        personal = subscriptions['as_assignee']['as_team_member'][0]
        self.assertEqual(references[personal['principal']], team)

    def test_assignee_through_team_as_admin(self):
        team = self.factory.makeTeam()
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
            self.bug.bugtasks[0].transitionToAssignee(team)
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='as_assignee')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.as_assignee, as_team_admin=1)
        self.assertVirtualSubscriptionInfoMatches(
            self.subscriptions.as_assignee.as_team_admin[0],
            self.bug, team,
            self.bug.default_bugtask.target, [self.bug.default_bugtask])

    def test_assignee_through_team_as_admin_getDataForClient(self):
        team = self.factory.makeTeam()
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
            self.bug.bugtasks[0].transitionToAssignee(team)
        self.subscriptions.reload()

        subscriptions, references = self.subscriptions.getDataForClient()
        personal = subscriptions['as_assignee']['as_team_admin'][0]
        self.assertEqual(references[personal['principal']], team)

    def test_direct(self):
        # Subscribed directly to the bug.
        with person_logged_in(self.subscriber):
            self.bug.subscribe(self.subscriber, self.subscriber)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='direct')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.direct, personal=1)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.direct.personal[0],
            self.bug, self.subscriber, False, [])

    def test_direct_getDataForClient(self):
        # Subscribed directly to the bug.
        with person_logged_in(self.subscriber):
            subscription = self.bug.subscribe(
                self.subscriber, self.subscriber)
        self.subscriptions.reload()

        subscriptions, references = self.subscriptions.getDataForClient()
        personal = subscriptions['direct']['personal'][0]
        self.assertEqual(references[personal['principal']], self.subscriber)
        self.assertEqual(references[personal['bug']], self.bug)
        self.assertEqual(references[personal['subscription']], subscription)
        self.assertEqual(personal['principal_is_reporter'], False)
        self.assertEqual(personal['bug_supervisor_pillars'], [])

    def test_direct_through_team(self):
        # Subscribed to the bug through membership in a team.
        team = self.factory.makeTeam(members=[self.subscriber])
        with person_logged_in(self.subscriber):
            self.bug.subscribe(team, self.subscriber)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='direct')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.direct, as_team_member=1)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.direct.as_team_member[0],
            self.bug, team, False, [])

    def test_direct_through_team_getDataForClient(self):
        # Subscribed to the bug through membership in a team.
        team = self.factory.makeTeam(members=[self.subscriber])
        with person_logged_in(self.subscriber):
            self.bug.subscribe(team, self.subscriber)
        self.subscriptions.reload()

        subscriptions, references = self.subscriptions.getDataForClient()
        personal = subscriptions['direct']['as_team_member'][0]
        self.assertEqual(references[personal['principal']], team)

    def test_direct_through_team_as_admin(self):
        # Subscribed to the bug through membership in a team
        # as an admin of that team.
        team = self.factory.makeTeam()
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
            self.bug.subscribe(team, team.teamowner)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='direct')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.direct, as_team_admin=1)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.direct.as_team_admin[0],
            self.bug, team, False, [])

    def test_direct_through_team_as_admin_getDataForClient(self):
        # Subscribed to the bug through membership in a team
        # as an admin of that team.
        team = self.factory.makeTeam()
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
            self.bug.subscribe(team, team.teamowner)
        self.subscriptions.reload()

        subscriptions, references = self.subscriptions.getDataForClient()
        personal = subscriptions['direct']['as_team_admin'][0]
        self.assertEqual(references[personal['principal']], team)

    def test_duplicate_direct(self):
        # Subscribed directly to the duplicate bug.
        [duplicate] = self.makeDuplicates(count=1)
        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='from_duplicate')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, personal=1)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.from_duplicate.personal[0],
            duplicate, self.subscriber, False, [])

    def test_duplicate_direct_reverse(self):
        # Subscribed directly to the primary bug, and a duplicate bug changes.
        primary = self.factory.makeBug()
        with person_logged_in(self.subscriber):
            self.bug.markAsDuplicate(primary)
            primary.subscribe(self.subscriber, self.subscriber)
        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        # This means no subscriptions on the duplicate bug.
        self.assertCollectionsAreEmpty()
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, personal=0)

    def test_duplicate_multiple(self):
        # Subscribed directly to more than one duplicate bug.
        duplicate1 = self.factory.makeBug()
        duplicate2 = self.factory.makeBug()
        with person_logged_in(self.subscriber):
            duplicate1.markAsDuplicate(self.bug)
            duplicate1.subscribe(self.subscriber, self.subscriber)
            duplicate2.markAsDuplicate(self.bug)
            duplicate2.subscribe(self.subscriber, self.subscriber)
        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='from_duplicate')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, personal=2)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.from_duplicate.personal[0],
            duplicate1, self.subscriber, False, [])
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.from_duplicate.personal[1],
            duplicate2, self.subscriber, False, [])

    def test_duplicate_through_team(self):
        # Subscribed to a duplicate bug through team membership.
        team = self.factory.makeTeam(members=[self.subscriber])
        duplicate = self.factory.makeBug()
        with person_logged_in(self.subscriber):
            duplicate.markAsDuplicate(self.bug)
            duplicate.subscribe(team, self.subscriber)
        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='from_duplicate')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, as_team_member=1)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.from_duplicate.as_team_member[0],
            duplicate, team, False, [])

    def test_duplicate_through_team_as_admin(self):
        # Subscribed to a duplicate bug through team membership
        # as an admin of that team.
        team = self.factory.makeTeam()
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
        duplicate = self.factory.makeBug()
        with person_logged_in(self.subscriber):
            duplicate.markAsDuplicate(self.bug)
            duplicate.subscribe(team, self.subscriber)
        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='from_duplicate')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, as_team_admin=1)
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.from_duplicate.as_team_admin[0],
            duplicate, team, False, [])

    def test_subscriber_is_reporter(self):
        self.bug = self.factory.makeBug(owner=self.subscriber)
        self.subscriptions = PersonSubscriptions(self.subscriber, self.bug)
        # Subscribed directly to the bug.
        with person_logged_in(self.subscriber):
            self.bug.subscribe(self.subscriber, self.subscriber)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.direct.personal[0],
            self.bug, self.subscriber, True, [])

    def test_subscriber_is_bug_supervisor(self):
        target = self.bug.default_bugtask.target
        removeSecurityProxy(target).bug_supervisor = self.subscriber
        # Subscribed directly to the bug.
        with person_logged_in(self.subscriber):
            self.bug.subscribe(self.subscriber, self.subscriber)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()
        self.assertRealSubscriptionInfoMatches(
            self.subscriptions.direct.personal[0],
            self.bug, self.subscriber, False,
             [{'task': self.bug.default_bugtask, 'pillar': target}])

    def test_owner(self):
        # Bug is targeted to a pillar with no supervisor set.
        target = self.bug.default_bugtask.target
        # Load a `PersonSubscriptionInfo`s for target.owner and a bug.
        self.subscriptions.loadSubscriptionsFor(target.owner, self.bug)

        self.assertCollectionsAreEmpty(except_='as_owner')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.as_owner, personal=1)
        self.assertVirtualSubscriptionInfoMatches(
            self.subscriptions.as_owner.personal[0],
            self.bug, target.owner,
            self.bug.default_bugtask.target, [self.bug.default_bugtask])

    def test_owner_as_bug_supervisor_is_empty(self):
        target = self.bug.default_bugtask.target
        removeSecurityProxy(target).bug_supervisor = target.owner
        # Subscribed directly to the bug.
        self.subscriptions.loadSubscriptionsFor(target.owner, self.bug)
        self.assertCollectionsAreEmpty()
        self.assertFalse(self.subscriptions.muted)

    def test_owner_through_team(self):
        # Bug is targeted to a pillar with no supervisor set.
        target = self.bug.default_bugtask.target
        team = self.factory.makeTeam(
            members=[self.subscriber],
            membership_policy=TeamMembershipPolicy.RESTRICTED)
        removeSecurityProxy(target).owner = team
        # Load a `PersonSubscriptionInfo`s for target.owner and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='as_owner')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.as_owner, as_team_member=1)
        self.assertVirtualSubscriptionInfoMatches(
            self.subscriptions.as_owner.as_team_member[0],
            self.bug, target.owner,
            self.bug.default_bugtask.target, [self.bug.default_bugtask])

    def test_owner_through_team_as_admin(self):
        # Bug is targeted to a pillar with no supervisor set.
        target = self.bug.default_bugtask.target
        team = self.factory.makeTeam(
            membership_policy=TeamMembershipPolicy.RESTRICTED)
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
        removeSecurityProxy(target).owner = team
        # Load a `PersonSubscriptionInfo`s for target.owner and a bug.
        self.subscriptions.reload()

        self.assertCollectionsAreEmpty(except_='as_owner')
        self.assertFalse(self.subscriptions.muted)
        self.assertCollectionContents(
            self.subscriptions.as_owner, as_team_admin=1)
        self.assertVirtualSubscriptionInfoMatches(
            self.subscriptions.as_owner.as_team_admin[0],
            self.bug, target.owner,
            self.bug.default_bugtask.target, [self.bug.default_bugtask])

    def test_is_muted(self):
        # Subscribed directly to the bug, muted.
        with person_logged_in(self.subscriber):
            self.bug.mute(self.subscriber, self.subscriber)

        # Load a `PersonSubscriptionInfo`s for subscriber and a bug.
        self.subscriptions.reload()

        self.assertTrue(self.subscriptions.muted)

    def test_many_duplicate_team_admin_subscriptions_few_queries(self):
        # This is related to bug 811447. The user is subscribed to a
        # duplicate bug through team membership in which the user is an admin.
        team = self.factory.makeTeam()
        with person_logged_in(team.teamowner):
            team.addMember(self.subscriber, team.teamowner,
                           status=TeamMembershipStatus.ADMIN)
        self.makeDuplicates(count=1, subscriber=team)
        with StormStatementRecorder() as recorder:
            self.subscriptions.reload()
        # This should produce a very small number of queries.
        self.assertThat(recorder, HasQueryCount(LessThan(6)))
        count_with_one_subscribed_duplicate = recorder.count
        # It should have the correct result.
        self.assertCollectionsAreEmpty(except_='from_duplicate')
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, as_team_admin=1)
        # If we increase the number of duplicates subscribed via the team that
        # the user administers...
        self.makeDuplicates(count=4, subscriber=team)
        with StormStatementRecorder() as recorder:
            self.subscriptions.reload()
        # ...then the query count should remain the same.
        count_with_five_subscribed_duplicates = recorder.count
        self.assertEqual(
            count_with_one_subscribed_duplicate,
            count_with_five_subscribed_duplicates)
        # We should still have the correct result.
        self.assertCollectionsAreEmpty(except_='from_duplicate')
        self.assertCollectionContents(
            self.subscriptions.from_duplicate, as_team_admin=5)