Merge lp:~wallyworld/launchpad/sharing-view-scalability-956634 into lp:launchpad

Proposed by Ian Booth on 2012-03-16
Status: Merged
Approved by: Ian Booth on 2012-03-16
Approved revision: no longer in the source branch.
Merged at revision: 14962
Proposed branch: lp:~wallyworld/launchpad/sharing-view-scalability-956634
Merge into: lp:launchpad
Diff against target: 177 lines (+60/-12)
5 files modified
lib/lp/registry/javascript/sharing/pillarsharingview.js (+1/-2)
lib/lp/registry/javascript/sharing/shareetable.js (+1/-1)
lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js (+0/-2)
lib/lp/registry/services/sharingservice.py (+10/-4)
lib/lp/registry/services/tests/test_sharingservice.py (+48/-3)
To merge this branch: bzr merge lp:~wallyworld/launchpad/sharing-view-scalability-956634
Reviewer Review Type Date Requested Status
William Grant code 2012-03-16 Approve on 2012-03-16
Review via email: mp+97793@code.launchpad.net

Commit Message

Ensure the sharing service getPillarSharees uses a reasonable number of queries

Description of the Change

== Implementation ==

Don't use lazr.restful marshalling - do it ourselves.
Query count is now 2, regardless of how may sharees are returned.

Drive by - ensure team icon is rendered.

== Tests ==

Add query count test to test_sharingservice

== Lint ==

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/registry/javascript/sharing/pillarsharingview.js
  lib/lp/registry/javascript/sharing/shareetable.js
  lib/lp/registry/services/sharingservice.py
  lib/lp/registry/services/tests/test_sharingservice.py

To post a comment you must log in.
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/javascript/sharing/pillarsharingview.js'
2--- lib/lp/registry/javascript/sharing/pillarsharingview.js 2012-03-16 02:55:42 +0000
3+++ lib/lp/registry/javascript/sharing/pillarsharingview.js 2012-03-16 08:48:19 +0000
4@@ -324,8 +324,7 @@
5 if (!Y.Lang.isValue(sharee_entry)) {
6 self.remove_sharee_success(person_uri);
7 } else {
8- self.save_sharing_selection_success(
9- sharee_entry.getAttrs());
10+ self.save_sharing_selection_success(sharee_entry);
11 }
12 },
13 failure: error_handler.getFailureHandler()
14
15=== modified file 'lib/lp/registry/javascript/sharing/shareetable.js'
16--- lib/lp/registry/javascript/sharing/shareetable.js 2012-03-16 07:07:19 +0000
17+++ lib/lp/registry/javascript/sharing/shareetable.js 2012-03-16 08:48:19 +0000
18@@ -118,7 +118,7 @@
19 _sharee_row_template: function() {
20 return [
21 '<tr id="permission-{{name}}" data-name="{{name}}"><td>',
22- ' <a href="{{web_link}}" class="sprite person">',
23+ ' <a href="{{web_link}}" class="sprite {{meta}}">',
24 ' {{display_name}}',
25 ' <span class="formHelp">{{role}}</span></a>',
26 '</td>',
27
28=== modified file 'lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js'
29--- lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js 2012-03-16 01:42:53 +0000
30+++ lib/lp/registry/javascript/sharing/tests/test_pillarsharingview.js 2012-03-16 08:48:19 +0000
31@@ -302,7 +302,6 @@
32 expected_url, 'permissions', 'Policy 3,Nothing');
33 Y.Assert.areEqual(expected_url, mockio.last_request.config.data);
34 mockio.last_request.successJSON({
35- 'resource_type_link': 'entity',
36 'name': 'joe',
37 'self_link': '~joe'});
38 Y.Assert.isTrue(save_sharing_selection_success_called);
39@@ -349,7 +348,6 @@
40 expected_url, 'permissions', 'Policy 1,S2');
41 Y.Assert.areEqual(expected_url, mockio.last_request.config.data);
42 mockio.last_request.successJSON({
43- 'resource_type_link': 'entity',
44 'name': 'fred',
45 'self_link': '~fred'});
46 Y.Assert.isTrue(save_sharing_selection_success_called);
47
48=== modified file 'lib/lp/registry/services/sharingservice.py'
49--- lib/lp/registry/services/sharingservice.py 2012-03-16 08:11:47 +0000
50+++ lib/lp/registry/services/sharingservice.py 2012-03-16 08:48:19 +0000
51@@ -8,12 +8,13 @@
52 'SharingService',
53 ]
54
55-from lazr.restful import EntryResource
56+from lazr.restful.interfaces import IWebBrowserOriginatingRequest
57 from lazr.restful.utils import get_current_web_service_request
58
59 from zope.component import getUtility
60 from zope.interface import implements
61 from zope.security.interfaces import Unauthorized
62+from zope.traversing.browser.absoluteurl import absoluteURL
63
64 from lp.registry.enums import (
65 InformationType,
66@@ -98,9 +99,14 @@
67 request = get_current_web_service_request()
68 for (grantee, policy, sharing_permission) in grant_permissions:
69 if not grantee.id in person_by_id:
70- resource = EntryResource(grantee, request)
71- person_data = resource.toDataForJSON()
72- person_data['permissions'] = {}
73+ person_data = {
74+ 'name': grantee.name,
75+ 'meta': 'team' if grantee.is_team else 'person',
76+ 'display_name': grantee.displayname,
77+ 'self_link': absoluteURL(grantee, request),
78+ 'permissions': {}}
79+ browser_request = IWebBrowserOriginatingRequest(request)
80+ person_data['web_link'] = absoluteURL(grantee, browser_request)
81 person_by_id[grantee.id] = person_data
82 result.append(person_data)
83 person_data = person_by_id[grantee.id]
84
85=== modified file 'lib/lp/registry/services/tests/test_sharingservice.py'
86--- lib/lp/registry/services/tests/test_sharingservice.py 2012-03-16 06:47:43 +0000
87+++ lib/lp/registry/services/tests/test_sharingservice.py 2012-03-16 08:48:19 +0000
88@@ -4,11 +4,13 @@
89 __metaclass__ = type
90
91
92-from lazr.restful import EntryResource
93+from lazr.restful.interfaces import IWebBrowserOriginatingRequest
94 from lazr.restful.utils import get_current_web_service_request
95+from testtools.matchers import Equals
96 import transaction
97 from zope.component import getUtility
98 from zope.security.interfaces import Unauthorized
99+from zope.traversing.browser.absoluteurl import absoluteURL
100
101 from lp.app.interfaces.services import IService
102 from lp.registry.enums import (
103@@ -27,6 +29,7 @@
104 from lp.testing import (
105 login,
106 login_person,
107+ StormStatementRecorder,
108 TestCaseWithFactory,
109 WebServiceTestCase,
110 ws_object,
111@@ -35,6 +38,7 @@
112 AppServerLayer,
113 DatabaseFunctionalLayer,
114 )
115+from lp.testing.matchers import HasQueryCount
116 from lp.testing.pages import LaunchpadWebServiceCaller
117
118
119@@ -53,8 +57,14 @@
120 def _makeShareeData(self, sharee, policy_permissions):
121 # Unpack a sharee into its attributes and add in permissions.
122 request = get_current_web_service_request()
123- resource = EntryResource(sharee, request)
124- sharee_data = resource.toDataForJSON()
125+ sharee_data = {
126+ 'name': sharee.name,
127+ 'meta': 'team' if sharee.is_team else 'person',
128+ 'display_name': sharee.displayname,
129+ 'self_link': absoluteURL(sharee, request),
130+ 'permissions': {}}
131+ browser_request = IWebBrowserOriginatingRequest(request)
132+ sharee_data['web_link'] = absoluteURL(sharee, browser_request)
133 permissions = {}
134 for (policy, permission) in policy_permissions:
135 permissions[policy.name] = unicode(permission.name)
136@@ -139,6 +149,41 @@
137 login_person(driver)
138 self._test_getPillarSharees(distro)
139
140+ def test_getPillarShareesQueryCount(self):
141+ # getPillarSharees only should use 2 queries regardless of how many
142+ # sharees are returned.
143+ driver = self.factory.makePerson()
144+ product = self.factory.makeProduct(driver=driver)
145+ login_person(driver)
146+ access_policy = self.factory.makeAccessPolicy(
147+ pillar=product,
148+ type=InformationType.PROPRIETARY)
149+
150+ def makeGrants():
151+ grantee = self.factory.makePerson()
152+ # Make access policy grant so that 'All' is returned.
153+ self.factory.makeAccessPolicyGrant(access_policy, grantee)
154+ # Make access artifact grants so that 'Some' is returned.
155+ artifact_grant = self.factory.makeAccessArtifactGrant()
156+ self.factory.makeAccessPolicyArtifact(
157+ artifact=artifact_grant.abstract_artifact,
158+ policy=access_policy)
159+
160+ # Make some grants and check the count.
161+ for x in range(5):
162+ makeGrants()
163+ with StormStatementRecorder() as recorder:
164+ sharees = self.service.getPillarSharees(product)
165+ self.assertEqual(10, len(sharees))
166+ self.assertThat(recorder, HasQueryCount(Equals(2)))
167+ # Make some more grants and check again.
168+ for x in range(5):
169+ makeGrants()
170+ with StormStatementRecorder() as recorder:
171+ sharees = self.service.getPillarSharees(product)
172+ self.assertEqual(20, len(sharees))
173+ self.assertThat(recorder, HasQueryCount(Equals(2)))
174+
175 def test_getPillarSharees_filter_grantees(self):
176 # getPillarSharees only returns grantees in the specified list.
177 driver = self.factory.makePerson()