← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~stevenk/launchpad/product-merges-preload into lp:launchpad

 

Steve Kowalik has proposed merging lp:~stevenk/launchpad/product-merges-preload into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #1135518 in Launchpad itself: "IHasMergeProposals:+merges times out"
  https://bugs.launchpad.net/launchpad/+bug/1135518

For more details, see:
https://code.launchpad.net/~stevenk/launchpad/product-merges-preload/+merge/151410

Make use of the existing eager loading support for Product:+merges, by teaching HasMergeProposalsMixin.getMergeProposals about it.

Perform a massive clean-up in test_branchmergeproposallisting, and a small one in IHasBranches mostly to force this branch to be net-negative.
-- 
https://code.launchpad.net/~stevenk/launchpad/product-merges-preload/+merge/151410
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/product-merges-preload into lp:launchpad.
=== modified file 'lib/lp/code/browser/branchmergeproposallisting.py'
--- lib/lp/code/browser/branchmergeproposallisting.py	2012-01-01 02:58:52 +0000
+++ lib/lp/code/browser/branchmergeproposallisting.py	2013-03-04 04:42:21 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Base class view for branch merge proposal listings."""
@@ -142,8 +142,8 @@
     implements(IBranchMergeProposalListingBatchNavigator)
 
     def __init__(self, view):
-        TableBatchNavigator.__init__(
-            self, view.getVisibleProposalsForUser(), view.request,
+        super(BranchMergeProposalListingBatchNavigator, self).__init__(
+            view.getVisibleProposalsForUser(), view.request,
             columns_to_show=view.extra_columns,
             size=config.launchpad.branchlisting_batch_size)
         self.view = view
@@ -216,9 +216,7 @@
 
     @property
     def initial_values(self):
-        return {
-            'status': FilterableStatusValues.ALL,
-            }
+        return {'status': FilterableStatusValues.ALL}
 
     @cachedproperty
     def status_value(self):
@@ -248,8 +246,8 @@
 
     def getVisibleProposalsForUser(self):
         """Branch merge proposals that are visible by the logged in user."""
-        has_proposals = IHasMergeProposals(self.context)
-        return has_proposals.getMergeProposals(self.status_filter, self.user)
+        return IHasMergeProposals(self.context).getMergeProposals(
+            self.status_filter, self.user, eager_load=True)
 
     @cachedproperty
     def proposal_count(self):
@@ -286,8 +284,7 @@
         collection = collection.visibleByUser(self.user)
         proposals = collection.getMergeProposals(
             [BranchMergeProposalStatus.CODE_APPROVED,
-             BranchMergeProposalStatus.NEEDS_REVIEW, ],
-            eager_load=True)
+             BranchMergeProposalStatus.NEEDS_REVIEW], eager_load=True)
         return proposals
 
     def _getReviewGroup(self, proposal, votes, reviewer):
@@ -445,13 +442,9 @@
     def getProposals(self):
         """See `ActiveReviewsView`."""
         collection = self._getCollection().visibleByUser(self.user)
-        proposals = collection.getMergeProposalsForPerson(
-            self._getReviewer(),
-            [BranchMergeProposalStatus.CODE_APPROVED,
-             BranchMergeProposalStatus.NEEDS_REVIEW],
-            eager_load=True)
-
-        return proposals
+        return collection.getMergeProposalsForPerson(
+            self._getReviewer(), [BranchMergeProposalStatus.CODE_APPROVED,
+            BranchMergeProposalStatus.NEEDS_REVIEW], eager_load=True)
 
 
 class PersonProductActiveReviewsView(PersonActiveReviewsView):

=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposallisting.py'
--- lib/lp/code/browser/tests/test_branchmergeproposallisting.py	2012-09-28 02:41:52 +0000
+++ lib/lp/code/browser/tests/test_branchmergeproposallisting.py	2013-03-04 04:42:21 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2013 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Unit tests for BranchMergeProposal listing views."""
@@ -18,7 +18,6 @@
 from lp.code.browser.branchmergeproposallisting import (
     ActiveReviewsView,
     BranchMergeProposalListingItem,
-    BranchMergeProposalListingView,
     )
 from lp.code.enums import (
     BranchMergeProposalStatus,
@@ -26,7 +25,6 @@
     )
 from lp.registry.model.personproduct import PersonProduct
 from lp.services.database.sqlbase import flush_database_caches
-from lp.services.webapp.servers import LaunchpadTestRequest
 from lp.testing import (
     ANONYMOUS,
     BrowserTestCase,
@@ -65,17 +63,13 @@
         if comment is _default:
             comment = self.factory.getUniqueString()
         proposal.createComment(
-            owner=reviewer,
-            subject=self.factory.getUniqueString('subject'),
-            content=comment,
-            vote=vote)
+            owner=reviewer, subject=self.factory.getUniqueString('subject'),
+            content=comment, vote=vote)
 
     def _get_vote_summary(self, proposal):
         """Return the vote summary string for the proposal."""
-        view_context = proposal.source_branch.owner
-        view = BranchMergeProposalListingView(
-            view_context, LaunchpadTestRequest())
-        view.initialize()
+        view = create_initialized_view(
+            proposal.source_branch.owner, '+merges', rootsite='code')
         batch_navigator = view.proposals
         # There will only be one item in the list of proposals.
         [listing_item] = batch_navigator.proposals
@@ -105,8 +99,7 @@
         summary, comment_count = self._get_vote_summary(proposal)
         self.assertEqual(
             [{'name': 'APPROVE', 'title':'Approve', 'count':1,
-              'reviewers': ''}],
-            summary)
+              'reviewers': ''}], summary)
         self.assertEqual(0, comment_count)
 
     def test_vote_with_comment(self):
@@ -116,8 +109,7 @@
         summary, comment_count = self._get_vote_summary(proposal)
         self.assertEqual(
             [{'name': 'APPROVE', 'title':'Approve', 'count':1,
-              'reviewers': ''}],
-            summary)
+              'reviewers': ''}], summary)
         self.assertEqual(1, comment_count)
 
     def test_disapproval(self):
@@ -127,8 +119,7 @@
         summary, comment_count = self._get_vote_summary(proposal)
         self.assertEqual(
             [{'name': 'DISAPPROVE', 'title':'Disapprove', 'count':1,
-              'reviewers': ''}],
-            summary)
+              'reviewers': ''}], summary)
         self.assertEqual(1, comment_count)
 
     def test_abstain(self):
@@ -139,8 +130,7 @@
         summary, comment_count = self._get_vote_summary(proposal)
         self.assertEqual(
             [{'name': 'ABSTAIN', 'title':'Abstain', 'count':1,
-              'reviewers': ''}],
-            summary)
+              'reviewers': ''}], summary)
         self.assertEqual(1, comment_count)
 
     def test_vote_ranking(self):
@@ -153,8 +143,7 @@
             [{'name': 'APPROVE', 'title':'Approve', 'count':1,
               'reviewers': ''},
              {'name': 'DISAPPROVE', 'title':'Disapprove', 'count':1,
-              'reviewers': ''}],
-            summary)
+              'reviewers': ''}], summary)
         self.assertEqual(2, comment_count)
         self._createComment(proposal, vote=CodeReviewVote.ABSTAIN)
         summary, comment_count = self._get_vote_summary(proposal)
@@ -164,8 +153,7 @@
              {'name': 'ABSTAIN', 'title':'Abstain', 'count':1,
               'reviewers': ''},
              {'name': 'DISAPPROVE', 'title':'Disapprove', 'count':1,
-              'reviewers': ''}],
-            summary)
+              'reviewers': ''}], summary)
         self.assertEqual(3, comment_count)
 
     def test_multiple_votes_for_type(self):
@@ -186,8 +174,7 @@
              {'name': 'ABSTAIN', 'title':'Abstain', 'count':1,
               'reviewers': ''},
              {'name': 'DISAPPROVE', 'title':'Disapprove', 'count':2,
-              'reviewers': ''}],
-            summary)
+              'reviewers': ''}], summary)
         self.assertEqual(4, comment_count)
 
 
@@ -206,6 +193,22 @@
         package = self.factory.makeDistributionSourcePackage()
         self.getViewBrowser(package, '+merges', rootsite='code')
 
+    def test_query_count(self):
+        product = self.factory.makeProduct()
+        target = self.factory.makeBranch(
+            product=product, information_type=InformationType.USERDATA)
+        for i in range(7):
+            source = self.factory.makeBranch(
+                product=product, information_type=InformationType.USERDATA)
+            self.factory.makeBranchMergeProposal(
+                source_branch=removeSecurityProxy(source),
+                target_branch=target)
+        flush_database_caches()
+        with StormStatementRecorder() as recorder:
+            self.getViewBrowser(
+                product, '+merges', rootsite='code', user=product.owner)
+        self.assertThat(recorder, HasQueryCount(Equals(40)))
+        
 
 class ActiveReviewGroupsTest(TestCaseWithFactory):
     """Tests for groupings used in for active reviews."""
@@ -222,8 +225,8 @@
         login(ANONYMOUS)
         # The actual context of the view doesn't matter here as all the
         # parameters are passed in.
-        view = ActiveReviewsView(
-            self.factory.makeProduct(), LaunchpadTestRequest())
+        view = create_initialized_view(
+            self.factory.makeProduct(), '+activereviews', rootsite='code')
         self.assertEqual(
             group, view._getReviewGroup(self.bmp, self.bmp.votes, reviewer))
 
@@ -405,8 +408,7 @@
             target_branch = self.factory.makePackageBranch(
                 owner=target_branch_owner)
         bmp = self.factory.makeBranchMergeProposal(
-            reviewer=reviewer,
-            target_branch=target_branch)
+            reviewer=reviewer, target_branch=target_branch)
         self.setupBMP(bmp)
         return bmp
 
@@ -430,8 +432,7 @@
         flush_database_caches()
         with StormStatementRecorder() as recorder:
             view = create_initialized_view(
-                user, name='+activereviews', rootsite='code',
-                principal=user)
+                user, name='+activereviews', rootsite='code', principal=user)
             view.render()
         return recorder, view
 

=== modified file 'lib/lp/code/model/hasbranches.py'
--- lib/lp/code/model/hasbranches.py	2011-03-03 01:13:47 +0000
+++ lib/lp/code/model/hasbranches.py	2013-03-04 04:42:21 +0000
@@ -41,7 +41,8 @@
 class HasMergeProposalsMixin:
     """A mixin implementation class for `IHasMergeProposals`."""
 
-    def getMergeProposals(self, status=None, visible_by_user=None):
+    def getMergeProposals(self, status=None, visible_by_user=None,
+                          eager_load=False):
         """See `IHasMergeProposals`."""
         if not status:
             status = (
@@ -50,7 +51,7 @@
                 BranchMergeProposalStatus.WORK_IN_PROGRESS)
 
         collection = IBranchCollection(self).visibleByUser(visible_by_user)
-        return collection.getMergeProposals(status)
+        return collection.getMergeProposals(status, eager_load=eager_load)
 
 
 class HasRequestedReviewsMixin:
@@ -63,9 +64,7 @@
 
         visible_branches = getUtility(IAllBranches).visibleByUser(
             visible_by_user)
-        proposals = visible_branches.getMergeProposalsForReviewer(
-            self, status)
-        return proposals
+        return visible_branches.getMergeProposalsForReviewer(self, status)
 
 
 class HasCodeImportsMixin: