Merge lp:~jtv/launchpad/son-of-bug-487447 into lp:launchpad

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Henning Eggers
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~jtv/launchpad/son-of-bug-487447
Merge into: lp:launchpad
Diff against target: 224 lines (+71/-4)
2 files modified
database/schema/security.cfg (+1/-0)
lib/lp/translations/tests/test_translationbranchapprover.py (+70/-4)
To merge this branch: bzr merge lp:~jtv/launchpad/son-of-bug-487447
Reviewer Review Type Date Requested Status
Henning Eggers (community) code Approve
Review via email: mp+16480@code.launchpad.net

Commit message

Fixed regressed permissions problem for branch approver.

To post a comment you must log in.
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

= Bug 487447 (regression) =

This bug, a missing database permission, just regressed. It's a bit hard to maintain complete test coverage because the same permissions are to an extent shared by two scripts, each with its own database user. The original fix unified those permissions; before that, they were duplicated. In this case, one of the two scripts had the needed privilege but the other one didn't.

Unfortunately I found no test that covered this from the right angle (database permissions for the branch approver), so I extended the existing unit test to switch database identities; and then I added a test for the part that breaks. It reproduces the bug as expected.

Some private methods in the test violate our naming standards (which mandate dromedaryCase instead of lower_case_with_underscores) but for the sake of brevity I decided not to touch them. If you so desire, dear reviewer, this can still be changed.

To Q/A, create a product with a template in one series; the template should have its base filename as its name and domain. Make some translations to ensure that it has POFiles. Then set up bzr imports for another release series, and commit a template with the same filename as the first one. Within an hour after pushing that branch, the template you pushed there should show up as Approved in the project's import queue.

Test:
{{{
./bin/test -vv -t translationbranchapprover
}}}

No lint.

Jeroen

Revision history for this message
Henning Eggers (henninge) wrote :

Thanks for the fix, Jeroen. I shan't be picky about the naming of private methods today.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'database/schema/security.cfg'
2--- database/schema/security.cfg 2009-12-14 15:30:33 +0000
3+++ database/schema/security.cfg 2009-12-22 10:26:15 +0000
4@@ -1388,6 +1388,7 @@
5 public.teamparticipation = SELECT
6 public.translationgroup = SELECT
7 public.translationimportqueueentry = SELECT, UPDATE
8+public.translationmessage = SELECT
9 public.translationrelicensingagreement = SELECT
10 public.translationtemplateitem = SELECT
11 public.translator = SELECT
12
13=== modified file 'lib/lp/translations/tests/test_translationbranchapprover.py'
14--- lib/lp/translations/tests/test_translationbranchapprover.py 2009-11-28 15:31:52 +0000
15+++ lib/lp/translations/tests/test_translationbranchapprover.py 2009-12-22 10:26:15 +0000
16@@ -5,7 +5,9 @@
17
18 __metaclass__ = type
19
20+import transaction
21 from unittest import TestLoader
22+
23 from zope.component import getUtility
24
25 from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
26@@ -17,6 +19,13 @@
27 from lp.translations.model.translationbranchapprover import (
28 TranslationBranchApprover)
29
30+
31+def become_the_approver(layer):
32+ """Switch to the branch-approver's database user identity."""
33+ transaction.commit()
34+ layer.switchDbUser('translationsbranchscanner')
35+
36+
37 class TestTranslationBranchApprover(TestCaseWithFactory):
38
39 layer = LaunchpadZopelessLayer
40@@ -32,10 +41,12 @@
41 self.factory.getUniqueString(), True, self.series.owner,
42 productseries=self.series)
43
44- def _create_template(self, path, domain):
45+ def _create_template(self, path, domain, productseries=None):
46 # Create a template in the database
47+ if productseries is None:
48+ productseries = self.series
49 return self.factory.makePOTemplate(
50- productseries=self.series,
51+ productseries=productseries,
52 name=domain.replace('_', '-'),
53 translation_domain=domain,
54 path=path)
55@@ -53,6 +64,8 @@
56 entry = self._upload_file(template_path)
57 self.assertEqual(RosettaImportStatus.NEEDS_REVIEW, entry.status)
58 approver = self._create_approver(template_path)
59+
60+ become_the_approver(self.layer)
61 approver.approve(entry)
62 self.assertEqual(RosettaImportStatus.APPROVED, entry.status)
63
64@@ -62,6 +75,8 @@
65 template_path = u'messages.pot'
66 entry = self._upload_file(template_path)
67 approver = self._create_approver(template_path)
68+
69+ become_the_approver(self.layer)
70 approver.approve(entry)
71 self.assertEqual(RosettaImportStatus.NEEDS_REVIEW, entry.status)
72
73@@ -70,6 +85,8 @@
74 path = u'eo.po'
75 entry = self._upload_file(path)
76 approver = self._create_approver(path)
77+
78+ become_the_approver(self.layer)
79 approver.approve(entry)
80 self.assertEqual(RosettaImportStatus.NEEDS_REVIEW, entry.status)
81
82@@ -80,6 +97,8 @@
83 template_path = translation_domain + u'.pot'
84 entry = self._upload_file(template_path)
85 approver = self._create_approver(template_path)
86+
87+ become_the_approver(self.layer)
88 approver.approve(entry)
89 self.assertEqual(
90 translation_domain, entry.potemplate.translation_domain)
91@@ -90,6 +109,8 @@
92 template_path = translation_domain + '/en-US.xpi'
93 entry = self._upload_file(template_path)
94 approver = self._create_approver(template_path)
95+
96+ become_the_approver(self.layer)
97 approver.approve(entry)
98 self.assertEqual(
99 translation_domain, entry.potemplate.translation_domain)
100@@ -100,6 +121,8 @@
101 template_path = translation_domain + u'.pot'
102 entry = self._upload_file(template_path)
103 approver = self._create_approver(template_path)
104+
105+ become_the_approver(self.layer)
106 approver.approve(entry)
107 self.assertTrue(valid_name(entry.potemplate.name))
108 self.assertEqual(u'invalid-name-withillegalcharacters',
109@@ -112,6 +135,8 @@
110 self._create_template(template_path, translation_domain)
111 entry = self._upload_file(template_path)
112 approver = self._create_approver(template_path)
113+
114+ become_the_approver(self.layer)
115 approver.approve(entry)
116 self.assertEqual(RosettaImportStatus.APPROVED, entry.status)
117
118@@ -123,6 +148,8 @@
119 potemplate = self._create_template(template_path, translation_domain)
120 entry = self._upload_file(template_path)
121 approver = self._create_approver(template_path)
122+
123+ become_the_approver(self.layer)
124 approver.approve(entry)
125 self.assertEqual(potemplate, entry.potemplate)
126
127@@ -135,6 +162,8 @@
128 template_path = self.factory.getUniqueString() + u'.pot'
129 entry = self._upload_file(template_path)
130 approver = self._create_approver(template_path)
131+
132+ become_the_approver(self.layer)
133 approver.approve(entry)
134 self.assertEqual(RosettaImportStatus.APPROVED, entry.status)
135 self.assertEqual(potemplate, entry.potemplate)
136@@ -148,6 +177,8 @@
137 potemplate = self._create_template(generic_path, translation_domain)
138 entry = self._upload_file(generic_path)
139 approver = self._create_approver(generic_path)
140+
141+ become_the_approver(self.layer)
142 approver.approve(entry)
143 self.assertEqual(RosettaImportStatus.APPROVED, entry.status)
144
145@@ -159,6 +190,8 @@
146 potemplate = self._create_template(generic_path, translation_domain)
147 entry = self._upload_file(generic_path)
148 approver = self._create_approver(generic_path)
149+
150+ become_the_approver(self.layer)
151 approver.approve(entry)
152 self.assertEqual(
153 translation_domain, entry.potemplate.translation_domain)
154@@ -173,6 +206,8 @@
155 new_path = u"%s/%s.pot" % (new_domain, new_domain)
156 entry = self._upload_file(new_path)
157 approver = self._create_approver((existing_path, new_path))
158+
159+ become_the_approver(self.layer)
160 approver.approve(entry)
161 self.assertEqual(RosettaImportStatus.APPROVED, entry.status)
162 self.assertEqual(new_domain, entry.potemplate.translation_domain)
163@@ -185,6 +220,8 @@
164 entry1 = self._upload_file(pot_path1)
165 entry2 = self._upload_file(pot_path2)
166 approver = self._create_approver((pot_path1, pot_path2))
167+
168+ become_the_approver(self.layer)
169 approver.approve(entry1)
170 self.assertEqual(RosettaImportStatus.APPROVED, entry1.status)
171 approver.approve(entry2)
172@@ -198,6 +235,8 @@
173 entry1 = self._upload_file(pot_path1)
174 entry2 = self._upload_file(pot_path2)
175 approver = self._create_approver((pot_path1, pot_path2))
176+
177+ become_the_approver(self.layer)
178 approver.approve(entry1)
179 self.assertEqual(RosettaImportStatus.NEEDS_REVIEW, entry1.status)
180 approver.approve(entry2)
181@@ -205,7 +244,7 @@
182
183 def test_approve_only_if_needs_review(self):
184 # If an entry is not in NEEDS_REVIEW state, it must not be approved.
185- pot_path = self.factory.getUniqueString()+".pot"
186+ pot_path = self.factory.getUniqueString() + ".pot"
187 entry = self._upload_file(pot_path)
188 entry.potemplate = self.factory.makePOTemplate()
189 not_approve_status = (
190@@ -221,6 +260,33 @@
191 approver.approve(entry)
192 self.assertEqual(status, entry.status)
193
194+ def test_approveNewSharingTemplate(self):
195+ # When the approver creates a new template, the new template
196+ # gets copies of any existing POFiles for templates that it will
197+ # share translations with.
198+ domain = self.factory.getUniqueString()
199+ pot_path = domain + ".pot"
200+ trunk = self.series.product.getSeries('trunk')
201+ trunk_template = self._create_template(
202+ pot_path, domain=domain, productseries=trunk)
203+ dutch_pofile = self.factory.makePOFile(
204+ 'nl', potemplate=trunk_template)
205+ entry = self._upload_file(pot_path)
206+ approver = self._create_approver(pot_path)
207+
208+ become_the_approver(self.layer)
209+ approver.approve(entry)
210+
211+ # This really did create a new template.
212+ self.assertNotEqual(None, entry.potemplate)
213+ self.assertNotEqual(trunk_template, entry.potemplate)
214+ self.assertEqual(trunk_template.name, entry.potemplate.name)
215+
216+ # The new template also has a Dutch translation of its own.
217+ new_dutch_pofile = entry.potemplate.getPOFileByLang('nl')
218+ self.assertNotEqual(None, new_dutch_pofile)
219+ self.assertNotEqual(dutch_pofile, new_dutch_pofile)
220+
221+
222 def test_suite():
223 return TestLoader().loadTestsFromName(__name__)
224-