Merge lp:~stub/launchpad/pending-db-changes into lp:launchpad
- pending-db-changes
- Merge into devel
Proposed by
Stuart Bishop
Status: | Rejected | ||||
---|---|---|---|---|---|
Rejected by: | Stuart Bishop | ||||
Proposed branch: | lp:~stub/launchpad/pending-db-changes | ||||
Merge into: | lp:launchpad | ||||
Diff against target: |
1281 lines (+989/-8) (has conflicts) 16 files modified
database/schema/patch-2209-21-4.sql (+111/-0) lib/lp/app/browser/tales.py (+14/-5) lib/lp/app/templates/banner-macros.pt (+50/-0) lib/lp/archivepublisher/debian_installer.py (+27/-0) lib/lp/archivepublisher/tests/test_debian_installer.py (+150/-0) lib/lp/archivepublisher/tests/test_dist_upgrader.py (+89/-0) lib/lp/bugs/browser/bugtarget.py (+8/-0) lib/lp/bugs/browser/tests/test_bugtarget_filebug.py (+93/-0) lib/lp/bugs/javascript/filebug.js (+78/-0) lib/lp/bugs/javascript/tests/test_filebug.html (+106/-0) lib/lp/bugs/javascript/tests/test_filebug.js (+116/-0) lib/lp/code/model/tests/test_branch.py (+35/-0) lib/lp/code/model/tests/test_branchlookup.py (+6/-0) lib/lp/code/model/tests/test_branchvisibility.py (+9/-0) lib/lp/soyuz/tests/test_distroseriesqueue_debian_installer.py (+77/-0) lib/lp/testing/factory.py (+20/-3) Text conflict in lib/lp/app/browser/tales.py Text conflict in lib/lp/app/templates/banner-macros.pt Text conflict in lib/lp/archivepublisher/debian_installer.py Text conflict in lib/lp/archivepublisher/tests/test_debian_installer.py Text conflict in lib/lp/archivepublisher/tests/test_dist_upgrader.py Text conflict in lib/lp/bugs/browser/bugtarget.py Text conflict in lib/lp/bugs/browser/tests/test_bugtarget_filebug.py Text conflict in lib/lp/bugs/javascript/filebug.js Text conflict in lib/lp/bugs/javascript/tests/test_filebug.html Text conflict in lib/lp/bugs/javascript/tests/test_filebug.js Text conflict in lib/lp/code/model/tests/test_branch.py Text conflict in lib/lp/code/model/tests/test_branchlookup.py Text conflict in lib/lp/code/model/tests/test_branchvisibility.py Text conflict in lib/lp/soyuz/tests/test_distroseriesqueue_debian_installer.py Text conflict in lib/lp/testing/factory.py |
||||
To merge this branch: | bzr merge lp:~stub/launchpad/pending-db-changes | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Launchpad code reviewers | Pending | ||
Review via email: mp+108323@code.launchpad.net |
Commit message
Description of the change
= Summary =
Turns out pgstattuple doesn't support GIN indexes, so one of our monitoring scripts fails.
== Proposed fix ==
Skip GIN indexes. Leave a better fix (such as replacing pgstattuple output with guesses) is better left to lp:pgdbr work which will replace this stuff and make it non-LP specific.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'database/schema/patch-2209-21-4.sql' |
2 | --- database/schema/patch-2209-21-4.sql 1970-01-01 00:00:00 +0000 |
3 | +++ database/schema/patch-2209-21-4.sql 2012-06-01 11:55:34 +0000 |
4 | @@ -0,0 +1,111 @@ |
5 | +CREATE OR REPLACE FUNCTION update_database_disk_utilization() RETURNS void |
6 | + LANGUAGE sql SECURITY DEFINER |
7 | + SET search_path TO public |
8 | + AS $$ |
9 | + INSERT INTO DatabaseDiskUtilization |
10 | + SELECT |
11 | + CURRENT_TIMESTAMP AT TIME ZONE 'UTC', |
12 | + namespace, name, |
13 | + sub_namespace, sub_name, |
14 | + kind, |
15 | + (namespace || '.' || name || COALESCE( |
16 | + '/' || sub_namespace || '.' || sub_name, '')) AS sort, |
17 | + (stat).table_len, |
18 | + (stat).tuple_count, |
19 | + (stat).tuple_len, |
20 | + (stat).tuple_percent, |
21 | + (stat).dead_tuple_count, |
22 | + (stat).dead_tuple_len, |
23 | + (stat).dead_tuple_percent, |
24 | + (stat).free_space, |
25 | + (stat).free_percent |
26 | + FROM ( |
27 | + -- Tables |
28 | + SELECT |
29 | + pg_namespace.nspname AS namespace, |
30 | + pg_class.relname AS name, |
31 | + NULL AS sub_namespace, |
32 | + NULL AS sub_name, |
33 | + pg_class.relkind AS kind, |
34 | + pgstattuple(pg_class.oid) AS stat |
35 | + FROM pg_class, pg_namespace |
36 | + WHERE |
37 | + pg_class.relnamespace = pg_namespace.oid |
38 | + AND pg_class.relkind = 'r' |
39 | + AND pg_table_is_visible(pg_class.oid) |
40 | + |
41 | + UNION ALL |
42 | + |
43 | + -- Indexes |
44 | + SELECT |
45 | + pg_namespace_table.nspname AS namespace, |
46 | + pg_class_table.relname AS name, |
47 | + pg_namespace_index.nspname AS sub_namespace, |
48 | + pg_class_index.relname AS sub_name, |
49 | + pg_class_index.relkind AS kind, |
50 | + pgstattuple(pg_class_index.oid) AS stat |
51 | + FROM |
52 | + pg_namespace AS pg_namespace_table, |
53 | + pg_namespace AS pg_namespace_index, |
54 | + pg_class AS pg_class_table, |
55 | + pg_class AS pg_class_index, |
56 | + pg_index, |
57 | + pg_am |
58 | + WHERE |
59 | + pg_class_index.relkind = 'i' |
60 | + AND pg_am.amname <> 'gin' -- pgstattuple doesn't support GIN |
61 | + AND pg_table_is_visible(pg_class_table.oid) |
62 | + AND pg_class_index.relnamespace = pg_namespace_index.oid |
63 | + AND pg_class_table.relnamespace = pg_namespace_table.oid |
64 | + AND pg_class_index.relam = pg_am.oid |
65 | + AND pg_index.indexrelid = pg_class_index.oid |
66 | + AND pg_index.indrelid = pg_class_table.oid |
67 | + |
68 | + UNION ALL |
69 | + |
70 | + -- TOAST tables |
71 | + SELECT |
72 | + pg_namespace_table.nspname AS namespace, |
73 | + pg_class_table.relname AS name, |
74 | + pg_namespace_toast.nspname AS sub_namespace, |
75 | + pg_class_toast.relname AS sub_name, |
76 | + pg_class_toast.relkind AS kind, |
77 | + pgstattuple(pg_class_toast.oid) AS stat |
78 | + FROM |
79 | + pg_namespace AS pg_namespace_table, |
80 | + pg_namespace AS pg_namespace_toast, |
81 | + pg_class AS pg_class_table, |
82 | + pg_class AS pg_class_toast |
83 | + WHERE |
84 | + pg_class_toast.relnamespace = pg_namespace_toast.oid |
85 | + AND pg_table_is_visible(pg_class_table.oid) |
86 | + AND pg_class_table.relnamespace = pg_namespace_table.oid |
87 | + AND pg_class_toast.oid = pg_class_table.reltoastrelid |
88 | + |
89 | + UNION ALL |
90 | + |
91 | + -- TOAST indexes |
92 | + SELECT |
93 | + pg_namespace_table.nspname AS namespace, |
94 | + pg_class_table.relname AS name, |
95 | + pg_namespace_index.nspname AS sub_namespace, |
96 | + pg_class_index.relname AS sub_name, |
97 | + pg_class_index.relkind AS kind, |
98 | + pgstattuple(pg_class_index.oid) AS stat |
99 | + FROM |
100 | + pg_namespace AS pg_namespace_table, |
101 | + pg_namespace AS pg_namespace_index, |
102 | + pg_class AS pg_class_table, |
103 | + pg_class AS pg_class_index, |
104 | + pg_class AS pg_class_toast |
105 | + WHERE |
106 | + pg_class_table.relnamespace = pg_namespace_table.oid |
107 | + AND pg_table_is_visible(pg_class_table.oid) |
108 | + AND pg_class_index.relnamespace = pg_namespace_index.oid |
109 | + AND pg_class_table.reltoastrelid = pg_class_toast.oid |
110 | + AND pg_class_index.oid = pg_class_toast.reltoastidxid |
111 | + ) AS whatever; |
112 | +$$; |
113 | + |
114 | +INSERT INTO LaunchpadDatabaseRevision VALUES (2209, 21, 4); |
115 | + |
116 | |
117 | === modified file 'lib/lp/app/browser/tales.py' |
118 | --- lib/lp/app/browser/tales.py 2012-05-31 02:20:41 +0000 |
119 | +++ lib/lp/app/browser/tales.py 2012-06-01 11:55:34 +0000 |
120 | @@ -666,11 +666,20 @@ |
121 | css_classes.add('private') |
122 | css_classes.add('global-notification-visible') |
123 | else: |
124 | - css_classes.add('public') |
125 | - beta = getattr(view, 'beta_features', []) |
126 | - if beta != []: |
127 | - css_classes.add('global-notification-visible') |
128 | - return ' '.join(list(css_classes)) |
129 | +<<<<<<< TREE |
130 | + css_classes.add('public') |
131 | + beta = getattr(view, 'beta_features', []) |
132 | + if beta != []: |
133 | + css_classes.add('global-notification-visible') |
134 | + return ' '.join(list(css_classes)) |
135 | +======= |
136 | + css_classes.add('public') |
137 | + beta = getattr(view, 'beta_features', []) |
138 | + if beta != []: |
139 | + css_classes.add('global-notification-visible') |
140 | + return ' '.join(list(css_classes)) |
141 | + |
142 | +>>>>>>> MERGE-SOURCE |
143 | |
144 | def _getSaneBreadcrumbDetail(self, breadcrumb): |
145 | text = breadcrumb.detail |
146 | |
147 | === modified file 'lib/lp/app/browser/tests/test_launchpad.py' |
148 | === modified file 'lib/lp/app/doc/tales.txt' |
149 | === modified file 'lib/lp/app/templates/banner-macros.pt' |
150 | --- lib/lp/app/templates/banner-macros.pt 2012-05-30 13:59:24 +0000 |
151 | +++ lib/lp/app/templates/banner-macros.pt 2012-06-01 11:55:34 +0000 |
152 | @@ -1,3 +1,4 @@ |
153 | +<<<<<<< TREE |
154 | <macros |
155 | xmlns="http://www.w3.org/1999/xhtml" |
156 | xmlns:tal="http://xml.zope.org/namespaces/tal" |
157 | @@ -54,3 +55,52 @@ |
158 | </metal:beta> |
159 | |
160 | </macros> |
161 | +======= |
162 | +<macros |
163 | + xmlns="http://www.w3.org/1999/xhtml" |
164 | + xmlns:tal="http://xml.zope.org/namespaces/tal" |
165 | + xmlns:metal="http://xml.zope.org/namespaces/metal" |
166 | + xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
167 | + i18n:domain="launchpad" |
168 | + tal:omit-tag="" |
169 | +> |
170 | + |
171 | +<metal:privacy define-macro="privacy-banner"> |
172 | + <tal:show-banner condition="view/private"> |
173 | + <div class="yui3-widget yui3-banner yui3-privacybanner"> |
174 | + <div class="yui3-privacybanner-content"> |
175 | + <div class="global-notification"> |
176 | + <span class="sprite notification-private"></span> |
177 | + <span class="banner-text">The information on this page is private.</span> |
178 | + </div> |
179 | + </div> |
180 | + </div> |
181 | + </tal:show-banner> |
182 | +</metal:privacy> |
183 | + |
184 | +<metal:beta define-macro="beta-banner"> |
185 | + <tal:show-banner condition="view/beta_features"> |
186 | + <div class="yui3-widget yui3-banner yui3-betabanner"> |
187 | + <div class="yui3-betabanner-content"> |
188 | + <div class="global-notification"> |
189 | + <span class="beta-warning">BETA!</span> |
190 | + <span class="banner-text"> |
191 | + Some parts of this page are in beta: |
192 | + <span class="beta-feature"> |
193 | + <tal:features |
194 | + repeat="feature view/beta_features"> |
195 | + <tal:feature replace="feature/title" /> |
196 | + <tal:link condition="feature/url"> |
197 | + (<a tal:attributes="href feature/url" class="info-link">read more</a>) |
198 | + </tal:link> |
199 | + </tal:features> |
200 | + </span> |
201 | + </span> |
202 | + </div> |
203 | + </div> |
204 | + </div> |
205 | + </tal:show-banner> |
206 | +</metal:beta> |
207 | + |
208 | +</macros> |
209 | +>>>>>>> MERGE-SOURCE |
210 | |
211 | === modified file 'lib/lp/archivepublisher/debian_installer.py' |
212 | --- lib/lp/archivepublisher/debian_installer.py 2012-05-30 10:25:43 +0000 |
213 | +++ lib/lp/archivepublisher/debian_installer.py 2012-06-01 11:55:34 +0000 |
214 | @@ -16,7 +16,22 @@ |
215 | import os |
216 | import shutil |
217 | |
218 | +<<<<<<< TREE |
219 | from lp.archivepublisher.customupload import CustomUpload |
220 | +======= |
221 | +from lp.archivepublisher.customupload import ( |
222 | + CustomUpload, |
223 | + CustomUploadError, |
224 | + ) |
225 | + |
226 | + |
227 | +class DebianInstallerAlreadyExists(CustomUploadError): |
228 | + """A build for this type, architecture, and version already exists.""" |
229 | + def __init__(self, arch, version): |
230 | + message = ('installer build %s for architecture %s already exists' % |
231 | + (arch, version)) |
232 | + CustomUploadError.__init__(self, message) |
233 | +>>>>>>> MERGE-SOURCE |
234 | |
235 | |
236 | class DebianInstallerUpload(CustomUpload): |
237 | @@ -42,13 +57,21 @@ |
238 | |
239 | def setTargetDirectory(self, archive_root, tarfile_path, distroseries): |
240 | tarfile_base = os.path.basename(tarfile_path) |
241 | +<<<<<<< TREE |
242 | _, self.version, self.arch = tarfile_base.split("_") |
243 | self.arch = self.arch.split(".")[0] |
244 | |
245 | +======= |
246 | + components = tarfile_base.split('_') |
247 | + self.version = components[1] |
248 | + self.arch = components[2].split('.')[0] |
249 | + |
250 | +>>>>>>> MERGE-SOURCE |
251 | self.targetdir = os.path.join( |
252 | archive_root, 'dists', distroseries, 'main', |
253 | 'installer-%s' % self.arch) |
254 | |
255 | +<<<<<<< TREE |
256 | @classmethod |
257 | def getSeriesKey(cls, tarfile_path): |
258 | try: |
259 | @@ -56,6 +79,10 @@ |
260 | return arch.split(".")[0] |
261 | except ValueError: |
262 | return None |
263 | +======= |
264 | + if os.path.exists(os.path.join(self.targetdir, self.version)): |
265 | + raise DebianInstallerAlreadyExists(self.arch, self.version) |
266 | +>>>>>>> MERGE-SOURCE |
267 | |
268 | def extract(self): |
269 | CustomUpload.extract(self) |
270 | |
271 | === modified file 'lib/lp/archivepublisher/tests/test_debian_installer.py' |
272 | --- lib/lp/archivepublisher/tests/test_debian_installer.py 2012-05-30 10:25:43 +0000 |
273 | +++ lib/lp/archivepublisher/tests/test_debian_installer.py 2012-06-01 11:55:34 +0000 |
274 | @@ -1,3 +1,4 @@ |
275 | +<<<<<<< TREE |
276 | # Copyright 2012 Canonical Ltd. This software is licensed under the |
277 | # GNU Affero General Public License version 3 (see the file LICENSE). |
278 | |
279 | @@ -166,3 +167,152 @@ |
280 | "package_1.0.tar.gz")) |
281 | self.assertIsNone(DebianInstallerUpload.getSeriesKey( |
282 | "one_two_three_four_5.tar.gz")) |
283 | +======= |
284 | +# Copyright 2012 Canonical Ltd. This software is licensed under the |
285 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
286 | + |
287 | +"""Test debian-installer custom uploads. |
288 | + |
289 | +See also lp.soyuz.tests.test_distroseriesqueue_debian_installer for |
290 | +high-level tests of debian-installer upload and queue manipulation. |
291 | +""" |
292 | + |
293 | +import os |
294 | + |
295 | +from lp.archivepublisher.customupload import CustomUploadBadUmask |
296 | +from lp.archivepublisher.debian_installer import ( |
297 | + DebianInstallerAlreadyExists, |
298 | + process_debian_installer, |
299 | + ) |
300 | +from lp.services.tarfile_helpers import LaunchpadWriteTarFile |
301 | +from lp.testing import TestCase |
302 | + |
303 | + |
304 | +class TestDebianInstaller(TestCase): |
305 | + |
306 | + def setUp(self): |
307 | + super(TestDebianInstaller, self).setUp() |
308 | + self.temp_dir = self.makeTemporaryDirectory() |
309 | + self.suite = "distroseries" |
310 | + # CustomUpload.installFiles requires a umask of 022. |
311 | + old_umask = os.umask(022) |
312 | + self.addCleanup(os.umask, old_umask) |
313 | + |
314 | + def openArchive(self): |
315 | + self.version = "20070214ubuntu1" |
316 | + self.arch = "i386" |
317 | + self.path = os.path.join( |
318 | + self.temp_dir, |
319 | + "debian-installer-images_%s_%s.tar.gz" % (self.version, self.arch)) |
320 | + self.buffer = open(self.path, "wb") |
321 | + self.archive = LaunchpadWriteTarFile(self.buffer) |
322 | + |
323 | + def addFile(self, path, contents): |
324 | + self.archive.add_file( |
325 | + "installer-%s/%s/%s" % (self.arch, self.version, path), contents) |
326 | + |
327 | + def addSymlink(self, path, target): |
328 | + self.archive.add_symlink( |
329 | + "installer-%s/%s/%s" % (self.arch, self.version, path), target) |
330 | + |
331 | + def process(self): |
332 | + self.archive.close() |
333 | + self.buffer.close() |
334 | + process_debian_installer(self.temp_dir, self.path, self.suite) |
335 | + |
336 | + def getInstallerPath(self, versioned_filename=None): |
337 | + installer_path = os.path.join( |
338 | + self.temp_dir, "dists", self.suite, "main", |
339 | + "installer-%s" % self.arch) |
340 | + if versioned_filename is not None: |
341 | + installer_path = os.path.join( |
342 | + installer_path, self.version, versioned_filename) |
343 | + return installer_path |
344 | + |
345 | + def test_basic(self): |
346 | + # Processing a simple correct tar file succeeds. |
347 | + self.openArchive() |
348 | + self.addFile("hello", "world") |
349 | + self.process() |
350 | + |
351 | + def test_already_exists(self): |
352 | + # If the target directory already exists, processing fails. |
353 | + self.openArchive() |
354 | + os.makedirs(self.getInstallerPath(".")) |
355 | + self.assertRaises(DebianInstallerAlreadyExists, self.process) |
356 | + |
357 | + def test_bad_umask(self): |
358 | + # The umask must be 022 to avoid incorrect permissions. |
359 | + self.openArchive() |
360 | + self.addFile("dir/file", "foo") |
361 | + os.umask(002) # cleanup already handled by setUp |
362 | + self.assertRaises(CustomUploadBadUmask, self.process) |
363 | + |
364 | + def test_current_symlink(self): |
365 | + # A "current" symlink is created to the last version. |
366 | + self.openArchive() |
367 | + self.addFile("hello", "world") |
368 | + self.process() |
369 | + installer_path = self.getInstallerPath() |
370 | + self.assertContentEqual( |
371 | + [self.version, "current"], os.listdir(installer_path)) |
372 | + self.assertEqual( |
373 | + self.version, os.readlink(os.path.join(installer_path, "current"))) |
374 | + |
375 | + def test_correct_file(self): |
376 | + # Files in the tarball are extracted correctly. |
377 | + self.openArchive() |
378 | + directory = ("images/netboot/ubuntu-installer/i386/" |
379 | + "pxelinux.cfg.serial-9600") |
380 | + filename = os.path.join(directory, "default") |
381 | + long_filename = os.path.join( |
382 | + directory, "very_very_very_very_very_very_long_filename") |
383 | + self.addFile(filename, "hey") |
384 | + self.addFile(long_filename, "long") |
385 | + self.process() |
386 | + with open(self.getInstallerPath(filename)) as f: |
387 | + self.assertEqual("hey", f.read()) |
388 | + with open(self.getInstallerPath(long_filename)) as f: |
389 | + self.assertEqual("long", f.read()) |
390 | + |
391 | + def test_correct_symlink(self): |
392 | + # Symbolic links in the tarball are extracted correctly. |
393 | + self.openArchive() |
394 | + foo_path = "images/netboot/foo" |
395 | + foo_target = "ubuntu-installer/i386/pxelinux.cfg.serial-9600/default" |
396 | + link_to_dir_path = "images/netboot/link_to_dir" |
397 | + link_to_dir_target = "ubuntu-installer/i386/pxelinux.cfg.serial-9600" |
398 | + self.addSymlink(foo_path, foo_target) |
399 | + self.addSymlink(link_to_dir_path, link_to_dir_target) |
400 | + self.process() |
401 | + self.assertEqual( |
402 | + foo_target, os.readlink(self.getInstallerPath(foo_path))) |
403 | + self.assertEqual( |
404 | + link_to_dir_target, |
405 | + os.path.normpath(os.readlink( |
406 | + self.getInstallerPath(link_to_dir_path)))) |
407 | + |
408 | + def test_top_level_permissions(self): |
409 | + # Top-level directories are set to mode 0755 (see bug 107068). |
410 | + self.openArchive() |
411 | + self.addFile("hello", "world") |
412 | + self.process() |
413 | + installer_path = self.getInstallerPath() |
414 | + self.assertEqual(0755, os.stat(installer_path).st_mode & 0777) |
415 | + self.assertEqual( |
416 | + 0755, |
417 | + os.stat(os.path.join(installer_path, os.pardir)).st_mode & 0777) |
418 | + |
419 | + def test_extracted_permissions(self): |
420 | + # Extracted files and directories are set to 0644/0755. |
421 | + self.openArchive() |
422 | + directory = ("images/netboot/ubuntu-installer/i386/" |
423 | + "pxelinux.cfg.serial-9600") |
424 | + filename = os.path.join(directory, "default") |
425 | + self.addFile(filename, "hey") |
426 | + self.process() |
427 | + self.assertEqual( |
428 | + 0644, os.stat(self.getInstallerPath(filename)).st_mode & 0777) |
429 | + self.assertEqual( |
430 | + 0755, os.stat(self.getInstallerPath(directory)).st_mode & 0777) |
431 | +>>>>>>> MERGE-SOURCE |
432 | |
433 | === modified file 'lib/lp/archivepublisher/tests/test_dist_upgrader.py' |
434 | --- lib/lp/archivepublisher/tests/test_dist_upgrader.py 2012-05-30 10:25:43 +0000 |
435 | +++ lib/lp/archivepublisher/tests/test_dist_upgrader.py 2012-06-01 11:55:34 +0000 |
436 | @@ -1,3 +1,4 @@ |
437 | +<<<<<<< TREE |
438 | # Copyright 2012 Canonical Ltd. This software is licensed under the |
439 | # GNU Affero General Public License version 3 (see the file LICENSE). |
440 | |
441 | @@ -104,3 +105,91 @@ |
442 | "package_1.0.tar.gz")) |
443 | self.assertIsNone(DistUpgraderUpload.getSeriesKey( |
444 | "one_two_three_four_5.tar.gz")) |
445 | +======= |
446 | +# Copyright 2012 Canonical Ltd. This software is licensed under the |
447 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
448 | + |
449 | +"""Test dist-upgrader custom uploads. |
450 | + |
451 | +See also lp.soyuz.tests.test_distroseriesqueue_dist_upgrader for high-level |
452 | +tests of dist-upgrader upload and queue manipulation. |
453 | +""" |
454 | + |
455 | +import os |
456 | + |
457 | +from lp.archivepublisher.customupload import CustomUploadBadUmask |
458 | +from lp.archivepublisher.dist_upgrader import ( |
459 | + DistUpgraderAlreadyExists, |
460 | + DistUpgraderBadVersion, |
461 | + process_dist_upgrader, |
462 | + ) |
463 | +from lp.services.tarfile_helpers import LaunchpadWriteTarFile |
464 | +from lp.testing import TestCase |
465 | + |
466 | + |
467 | +class TestDistUpgrader(TestCase): |
468 | + |
469 | + def setUp(self): |
470 | + super(TestDistUpgrader, self).setUp() |
471 | + self.temp_dir = self.makeTemporaryDirectory() |
472 | + self.suite = "distroseries" |
473 | + # CustomUpload.installFiles requires a umask of 022. |
474 | + old_umask = os.umask(022) |
475 | + self.addCleanup(os.umask, old_umask) |
476 | + |
477 | + def openArchive(self, version): |
478 | + self.path = os.path.join( |
479 | + self.temp_dir, "dist-upgrader_%s_all.tar.gz" % version) |
480 | + self.buffer = open(self.path, "wb") |
481 | + self.archive = LaunchpadWriteTarFile(self.buffer) |
482 | + |
483 | + def process(self): |
484 | + self.archive.close() |
485 | + self.buffer.close() |
486 | + process_dist_upgrader(self.temp_dir, self.path, self.suite) |
487 | + |
488 | + def getUpgraderPath(self): |
489 | + return os.path.join( |
490 | + self.temp_dir, "dists", self.suite, "main", "dist-upgrader-all") |
491 | + |
492 | + def test_basic(self): |
493 | + # Processing a simple correct tar file works. |
494 | + self.openArchive("20060302.0120") |
495 | + self.archive.add_file("20060302.0120/hello", "world") |
496 | + self.process() |
497 | + |
498 | + def test_already_exists(self): |
499 | + # If the target directory already exists, processing fails. |
500 | + self.openArchive("20060302.0120") |
501 | + self.archive.add_file("20060302.0120/hello", "world") |
502 | + os.makedirs(os.path.join(self.getUpgraderPath(), "20060302.0120")) |
503 | + self.assertRaises(DistUpgraderAlreadyExists, self.process) |
504 | + |
505 | + def test_bad_umask(self): |
506 | + # The umask must be 022 to avoid incorrect permissions. |
507 | + self.openArchive("20060302.0120") |
508 | + self.archive.add_file("20060302.0120/file", "foo") |
509 | + os.umask(002) # cleanup already handled by setUp |
510 | + self.assertRaises(CustomUploadBadUmask, self.process) |
511 | + |
512 | + def test_current_symlink(self): |
513 | + # A "current" symlink is created to the last version. |
514 | + self.openArchive("20060302.0120") |
515 | + self.archive.add_file("20060302.0120/hello", "world") |
516 | + self.process() |
517 | + upgrader_path = self.getUpgraderPath() |
518 | + self.assertContentEqual( |
519 | + ["20060302.0120", "current"], os.listdir(upgrader_path)) |
520 | + self.assertEqual( |
521 | + "20060302.0120", |
522 | + os.readlink(os.path.join(upgrader_path, "current"))) |
523 | + self.assertContentEqual( |
524 | + ["hello"], |
525 | + os.listdir(os.path.join(upgrader_path, "20060302.0120"))) |
526 | + |
527 | + def test_bad_version(self): |
528 | + # Bad versions in the tarball are refused. |
529 | + self.openArchive("20070219.1234") |
530 | + self.archive.add_file("foobar/foobar/dapper.tar.gz", "") |
531 | + self.assertRaises(DistUpgraderBadVersion, self.process) |
532 | +>>>>>>> MERGE-SOURCE |
533 | |
534 | === modified file 'lib/lp/bugs/browser/bugtarget.py' |
535 | --- lib/lp/bugs/browser/bugtarget.py 2012-05-30 00:51:34 +0000 |
536 | +++ lib/lp/bugs/browser/bugtarget.py 2012-06-01 11:55:34 +0000 |
537 | @@ -388,6 +388,7 @@ |
538 | if self.redirect_ubuntu_filebug: |
539 | pass |
540 | LaunchpadFormView.initialize(self) |
541 | +<<<<<<< TREE |
542 | cache = IJSONRequestCache(self.request) |
543 | cache.objects['enable_bugfiling_duplicate_search'] = ( |
544 | IProjectGroup.providedBy(self.context) |
545 | @@ -408,6 +409,13 @@ |
546 | excluded_items=[BugTaskImportance.UNKNOWN]) |
547 | cache.objects['bugtask_importance_data'] = bugtask_importance_data |
548 | if (self.extra_data_token is not None and |
549 | +======= |
550 | + cache = IJSONRequestCache(self.request) |
551 | + cache.objects['enable_bugfiling_duplicate_search'] = ( |
552 | + IProjectGroup.providedBy(self.context) |
553 | + or self.context.enable_bugfiling_duplicate_search) |
554 | + if (self.extra_data_token is not None and |
555 | +>>>>>>> MERGE-SOURCE |
556 | not self.extra_data_to_process): |
557 | # self.extra_data has been initialized in publishTraverse(). |
558 | if self.extra_data.initial_summary: |
559 | |
560 | === modified file 'lib/lp/bugs/browser/tests/test_bugtarget_filebug.py' |
561 | --- lib/lp/bugs/browser/tests/test_bugtarget_filebug.py 2012-05-30 00:51:34 +0000 |
562 | +++ lib/lp/bugs/browser/tests/test_bugtarget_filebug.py 2012-06-01 11:55:34 +0000 |
563 | @@ -26,11 +26,18 @@ |
564 | BugTaskStatus, |
565 | ) |
566 | from lp.bugs.publisher import BugsLayer |
567 | +<<<<<<< TREE |
568 | from lp.registry.enums import ( |
569 | InformationType, |
570 | PRIVATE_INFORMATION_TYPES, |
571 | PUBLIC_INFORMATION_TYPES, |
572 | ) |
573 | +======= |
574 | +from lp.registry.enums import ( |
575 | + InformationType, |
576 | + PRIVATE_INFORMATION_TYPES, |
577 | + ) |
578 | +>>>>>>> MERGE-SOURCE |
579 | from lp.services.features.testing import FeatureFixture |
580 | from lp.services.webapp.servers import LaunchpadTestRequest |
581 | from lp.testing import ( |
582 | @@ -477,6 +484,7 @@ |
583 | notification.message |
584 | for notification in view.request.response.notifications]) |
585 | self.assertIn("Thank you for your bug report.", msg) |
586 | +<<<<<<< TREE |
587 | |
588 | |
589 | class TestFileBugGuidelinesRequestCache(TestCaseWithFactory): |
590 | @@ -609,3 +617,88 @@ |
591 | login_person(user) |
592 | view = create_initialized_view(project, '+filebug', principal=user) |
593 | self._assert_cache_values(view, True) |
594 | +======= |
595 | + |
596 | + |
597 | +class TestFileBugGuidelinesRequestCache(TestCaseWithFactory): |
598 | + # Tests to ensure the request cache contains the expected values for |
599 | + # file bug guidelines views. |
600 | + |
601 | + layer = DatabaseFunctionalLayer |
602 | + |
603 | + def _assert_cache_values(self, view, private_bugs, duplicate_search): |
604 | + cache = IJSONRequestCache(view.request).objects |
605 | + self.assertContentEqual(cache['private_types'], [ |
606 | + type.name for type in PRIVATE_INFORMATION_TYPES]) |
607 | + self.assertEqual(cache['bug_private_by_default'], private_bugs) |
608 | + self.assertEqual( |
609 | + cache['enable_bugfiling_duplicate_search'], duplicate_search) |
610 | + |
611 | + def test_product(self): |
612 | + project = self.factory.makeProduct(official_malone=True) |
613 | + user = self.factory.makePerson() |
614 | + login_person(user) |
615 | + view = create_initialized_view(project, |
616 | + '+filebug-reporting-guidelines', principal=user) |
617 | + self._assert_cache_values(view, False, True) |
618 | + |
619 | + def test_product_default_private(self): |
620 | + product = self.factory.makeProduct(official_malone=True) |
621 | + removeSecurityProxy(product).private_bugs = True |
622 | + user = self.factory.makePerson() |
623 | + login_person(user) |
624 | + view = create_initialized_view(product, |
625 | + '+filebug-reporting-guidelines', principal=user) |
626 | + self._assert_cache_values(view, True, True) |
627 | + |
628 | + def test_product_no_duplicate_search(self): |
629 | + product = self.factory.makeProduct(official_malone=True) |
630 | + removeSecurityProxy(product).enable_bugfiling_duplicate_search = False |
631 | + user = self.factory.makePerson() |
632 | + login_person(user) |
633 | + view = create_initialized_view(product, |
634 | + '+filebug-reporting-guidelines', principal=user) |
635 | + self._assert_cache_values(view, False, False) |
636 | + |
637 | + def test_project_group(self): |
638 | + project = self.factory.makeProject() |
639 | + user = self.factory.makePerson() |
640 | + login_person(user) |
641 | + view = create_initialized_view(project, |
642 | + '+filebug-reporting-guidelines', principal=user) |
643 | + self._assert_cache_values(view, False, True) |
644 | + |
645 | + |
646 | +class TestFileBugRequestCache(TestCaseWithFactory): |
647 | + # Tests to ensure the request cache contains the expected values for |
648 | + # file bug views. |
649 | + |
650 | + layer = DatabaseFunctionalLayer |
651 | + |
652 | + def _assert_cache_values(self, view, duplicate_search): |
653 | + cache = IJSONRequestCache(view.request).objects |
654 | + self.assertEqual( |
655 | + cache['enable_bugfiling_duplicate_search'], duplicate_search) |
656 | + |
657 | + def test_product(self): |
658 | + project = self.factory.makeProduct(official_malone=True) |
659 | + user = self.factory.makePerson() |
660 | + login_person(user) |
661 | + view = create_initialized_view(project, '+filebug', principal=user) |
662 | + self._assert_cache_values(view, True) |
663 | + |
664 | + def test_product_no_duplicate_search(self): |
665 | + product = self.factory.makeProduct(official_malone=True) |
666 | + removeSecurityProxy(product).enable_bugfiling_duplicate_search = False |
667 | + user = self.factory.makePerson() |
668 | + login_person(user) |
669 | + view = create_initialized_view(product, '+filebug', principal=user) |
670 | + self._assert_cache_values(view, False) |
671 | + |
672 | + def test_project_group(self): |
673 | + project = self.factory.makeProject() |
674 | + user = self.factory.makePerson() |
675 | + login_person(user) |
676 | + view = create_initialized_view(project, '+filebug', principal=user) |
677 | + self._assert_cache_values(view, True) |
678 | +>>>>>>> MERGE-SOURCE |
679 | |
680 | === modified file 'lib/lp/bugs/browser/tests/test_bugtask.py' |
681 | === modified file 'lib/lp/bugs/javascript/filebug.js' |
682 | --- lib/lp/bugs/javascript/filebug.js 2012-05-28 12:34:29 +0000 |
683 | +++ lib/lp/bugs/javascript/filebug.js 2012-06-01 11:55:34 +0000 |
684 | @@ -1,3 +1,4 @@ |
685 | +<<<<<<< TREE |
686 | /* Copyright 2012 Canonical Ltd. This software is licensed under the |
687 | * GNU Affero General Public License version 3 (see the file LICENSE). |
688 | * |
689 | @@ -81,3 +82,80 @@ |
690 | "base", "node", "event", "node-event-delegate", "lazr.choiceedit", |
691 | "lp.app.banner.privacy", "lp.app.choice", |
692 | "lp.bugs.filebug_dupefinder"]}); |
693 | +======= |
694 | +/* Copyright 2012 Canonical Ltd. This software is licensed under the |
695 | + * GNU Affero General Public License version 3 (see the file LICENSE). |
696 | + * |
697 | + * Provide functionality for the file bug pages. |
698 | + * |
699 | + * @module bugs |
700 | + * @submodule filebug |
701 | + */ |
702 | +YUI.add('lp.bugs.filebug', function(Y) { |
703 | + |
704 | +var namespace = Y.namespace('lp.bugs.filebug'); |
705 | + |
706 | +// For tests. |
707 | +var skip_animation; |
708 | + |
709 | +var setup_filebug = function(skip_anim) { |
710 | + skip_animation = skip_anim; |
711 | + if (LP.cache.enable_bugfiling_duplicate_search) { |
712 | + Y.lp.bugs.filebug_dupefinder.setup_dupe_finder(); |
713 | + Y.lp.bugs.filebug_dupefinder.setup_dupes(); |
714 | + } |
715 | + var search_button = Y.one(Y.DOM.byId('field.actions.projectgroupsearch')); |
716 | + if (Y.Lang.isValue(search_button )) { |
717 | + search_button.set('value', 'Check again'); |
718 | + } |
719 | + if (LP.cache.show_information_type_in_ui) { |
720 | + setup_information_type(); |
721 | + } else { |
722 | + setup_security_related(); |
723 | + } |
724 | + var filebug_privacy_text = "This report will be private. " + |
725 | + "You can disclose it later."; |
726 | + update_privacy_banner( |
727 | + LP.cache.bug_private_by_default, filebug_privacy_text); |
728 | +}; |
729 | + |
730 | +var update_privacy_banner = function(show, banner_text) { |
731 | + var banner = Y.lp.app.banner.privacy.getPrivacyBanner( |
732 | + banner_text, skip_animation); |
733 | + if (show) { |
734 | + banner.show(); |
735 | + } else { |
736 | + banner.hide(); |
737 | + } |
738 | +}; |
739 | + |
740 | +var setup_information_type = function() { |
741 | + var itypes_table = Y.one('.radio-button-widget'); |
742 | + itypes_table.delegate('click', function() { |
743 | + var private_type = (Y.Array.indexOf( |
744 | + LP.cache.private_types, this.get('value')) >= 0); |
745 | + update_privacy_banner(private_type); |
746 | + }, "input[name='field.information_type']"); |
747 | +}; |
748 | + |
749 | +var setup_security_related = function() { |
750 | + var sec = Y.one('[id="field.security_related"]'); |
751 | + if (!Y.Lang.isValue(sec)) { |
752 | + return; |
753 | + } |
754 | + var notification_text = "This report will be private " + |
755 | + "because it is a security " + |
756 | + "vulnerability. You can " + |
757 | + "disclose it later."; |
758 | + sec.on('change', function() { |
759 | + var checked = sec.get('checked'); |
760 | + update_privacy_banner(checked, notification_text); |
761 | + }); |
762 | +}; |
763 | + |
764 | +namespace.setup_filebug = setup_filebug; |
765 | + |
766 | +}, "0.1", {"requires": [ |
767 | + "base", "node", "event", "node-event-delegate", |
768 | + "lp.app.banner.privacy", "lp.bugs.filebug_dupefinder"]}); |
769 | +>>>>>>> MERGE-SOURCE |
770 | |
771 | === modified file 'lib/lp/bugs/javascript/tests/test_filebug.html' |
772 | --- lib/lp/bugs/javascript/tests/test_filebug.html 2012-05-28 12:34:29 +0000 |
773 | +++ lib/lp/bugs/javascript/tests/test_filebug.html 2012-06-01 11:55:34 +0000 |
774 | @@ -1,3 +1,4 @@ |
775 | +<<<<<<< TREE |
776 | <!DOCTYPE html> |
777 | <!-- |
778 | Copyright 2012 Canonical Ltd. This software is licensed under the |
779 | @@ -117,3 +118,108 @@ |
780 | </script> |
781 | </body> |
782 | </html> |
783 | +======= |
784 | +<!DOCTYPE html> |
785 | +<!-- |
786 | +Copyright 2012 Canonical Ltd. This software is licensed under the |
787 | +GNU Affero General Public License version 3 (see the file LICENSE). |
788 | +--> |
789 | + |
790 | +<html> |
791 | + <head> |
792 | + <title>File Bug View Tests</title> |
793 | + |
794 | + <!-- YUI and test setup --> |
795 | + <script type="text/javascript" |
796 | + src="../../../../../build/js/yui/yui/yui.js"> |
797 | + </script> |
798 | + <link rel="stylesheet" |
799 | + href="../../../../../build/js/yui/console/assets/console-core.css" /> |
800 | + <link rel="stylesheet" |
801 | + href="../../../../../build/js/yui/console/assets/skins/sam/console.css" /> |
802 | + <link rel="stylesheet" |
803 | + href="../../../../../build/js/yui/test/assets/skins/sam/test.css" /> |
804 | + |
805 | + <script type="text/javascript" |
806 | + src="../../../../../build/js/lp/app/testing/testrunner.js"></script> |
807 | + |
808 | + <link rel="stylesheet" href="../../../app/javascript/testing/test.css" /> |
809 | + |
810 | + <!-- Dependencies --> |
811 | + <script type="text/javascript" |
812 | + src="../../../../../build/js/lp/app/mustache.js"></script> |
813 | + <script type="text/javascript" |
814 | + src="../../../../../build/js/lp/app/expander.js"></script> |
815 | + <script type="text/javascript" |
816 | + src="../../../../../build/js/lp/app/formoverlay/formoverlay.js"></script> |
817 | + <script type="text/javascript" |
818 | + src="../../../../../build/js/lp/app/formwidgets/formwidgets.js"></script> |
819 | + <script type="text/javascript" |
820 | + src="../../../../../build/js/lp/app/formwidgets/resizing_textarea.js"></script> |
821 | + <script type="text/javascript" |
822 | + src="../../../../../build/js/lp/app/overlay/overlay.js"></script> |
823 | + <script type="text/javascript" |
824 | + src="../../../../../build/js/lp/app/anim/anim.js"></script> |
825 | + <script type="text/javascript" |
826 | + src="../../../../../build/js/lp/bugs/filebug_dupefinder.js"></script> |
827 | + <script type="text/javascript" |
828 | + src="../../../../../build/js/lp/app/effects/effects.js"></script> |
829 | + <script type="text/javascript" |
830 | + src="../../../../../build/js/lp/app/extras/extras.js"></script> |
831 | + <script type="text/javascript" |
832 | + src="../../../../../build/js/lp/app/banners/banner.js"></script> |
833 | + <script type="text/javascript" |
834 | + src="../../../../../build/js/lp/app/banners/privacy.js"></script> |
835 | + |
836 | + <!-- The module under test. --> |
837 | + <script type="text/javascript" src="../filebug.js"></script> |
838 | + |
839 | + <!-- The test suite --> |
840 | + <script type="text/javascript" src="test_filebug.js"></script> |
841 | + |
842 | + </head> |
843 | + <body class="yui3-skin-sam"> |
844 | + <ul id="suites"> |
845 | + <li>lp.bugs.filebug.test</li> |
846 | + </ul> |
847 | + <div class='login-logout'></div> |
848 | + <div id="fixture"></div> |
849 | + <script type="text/x-template" id="privacy-banner-template"> |
850 | + <table class="radio-button-widget"> |
851 | + <tbody> |
852 | + <tr> |
853 | + <td><input type="radio" value="PUBLIC" name="field.information_type" |
854 | + id="field.information_type.0" checked="checked" class="radioType"> |
855 | + </td> |
856 | + <td><label for="field.information_type.0">Public</label></td> |
857 | + </tr> |
858 | + <tr> |
859 | + <td><input type="radio" value="UNEMBARGOEDSECURITY" name="field.information_type" |
860 | + id="field.information_type.1"class="radioType"> |
861 | + </td> |
862 | + <td><label for="field.information_type.1">Unembargoed Security</label></td> |
863 | + </tr> |
864 | + <tr> |
865 | + <td><input type="radio" value="EMBARGOEDSECURITY" name="field.information_type" |
866 | + id="field.information_type.2"class="radioType"> |
867 | + </td> |
868 | + <td><label for="field.information_type.2">Embargoed Security</label></td> |
869 | + </tr> |
870 | + <tr> |
871 | + <td><input type="radio" value="USERDATA" name="field.information_type" |
872 | + id="field.information_type.3"class="radioType"> |
873 | + </td> |
874 | + <td><label for="field.information_type.3">User Data</label></td> |
875 | + </tr> |
876 | + <tr> |
877 | + <td><input type="radio" value="PROPRIETARY" name="field.information_type" |
878 | + id="field.information_type.4"class="radioType"> |
879 | + </td> |
880 | + <td><label for="field.information_type.4">Proprietary</label></td> |
881 | + </tr> |
882 | + </tbody> |
883 | + </table> |
884 | + </script> |
885 | + </body> |
886 | +</html> |
887 | +>>>>>>> MERGE-SOURCE |
888 | |
889 | === modified file 'lib/lp/bugs/javascript/tests/test_filebug.js' |
890 | --- lib/lp/bugs/javascript/tests/test_filebug.js 2012-05-30 21:36:01 +0000 |
891 | +++ lib/lp/bugs/javascript/tests/test_filebug.js 2012-06-01 11:55:34 +0000 |
892 | @@ -1,3 +1,4 @@ |
893 | +<<<<<<< TREE |
894 | /* Copyright (c) 2012, Canonical Ltd. All rights reserved. */ |
895 | |
896 | YUI.add('lp.bugs.filebug.test', function (Y) { |
897 | @@ -166,3 +167,118 @@ |
898 | 'lp.app.banner.privacy', 'lp.app.choice', |
899 | 'lp.bugs.filebug_dupefinder', 'lp.bugs.filebug' |
900 | ]}); |
901 | +======= |
902 | +/* Copyright (c) 2012, Canonical Ltd. All rights reserved. */ |
903 | + |
904 | +YUI.add('lp.bugs.filebug.test', function (Y) { |
905 | + |
906 | + var tests = Y.namespace('lp.bugs.filebug.test'); |
907 | + tests.suite = new Y.Test.Suite( |
908 | + 'lp.bugs.filebug Tests'); |
909 | + |
910 | + tests.suite.add(new Y.Test.Case({ |
911 | + name: 'lp.bugs.filebug_tests', |
912 | + |
913 | + setUp: function () { |
914 | + window.LP = { |
915 | + links: {}, |
916 | + cache: { |
917 | + private_types: ['EMBARGOEDSECURITY', 'USERDATA'] |
918 | + } |
919 | + }; |
920 | + this.fixture = Y.one('#fixture'); |
921 | + var banner = Y.Node.create( |
922 | + Y.one('#privacy-banner-template').getContent()); |
923 | + this.fixture.appendChild(banner); |
924 | + }, |
925 | + |
926 | + tearDown: function () { |
927 | + if (this.fixture !== null) { |
928 | + this.fixture.empty(true); |
929 | + } |
930 | + delete this.fixture; |
931 | + delete window.LP; |
932 | + }, |
933 | + |
934 | + test_library_exists: function () { |
935 | + Y.Assert.isObject(Y.lp.bugs.filebug, |
936 | + "Could not locate the " + |
937 | + "lp.bugs.filebug module"); |
938 | + }, |
939 | + |
940 | + // Filing a public bug does not show the privacy banner. |
941 | + test_setup_filebug_public: function () { |
942 | + Y.lp.bugs.filebug.setup_filebug(true); |
943 | + var banner_hidden = Y.one('.yui3-privacybanner-hidden'); |
944 | + Y.Assert.isNotNull(banner_hidden); |
945 | + }, |
946 | + |
947 | + // Filing a bug for a project with private bugs shows the privacy |
948 | + // banner. |
949 | + test_setup_filebug_private: function () { |
950 | + window.LP.cache.bug_private_by_default = true; |
951 | + Y.lp.bugs.filebug.setup_filebug(true); |
952 | + var banner_hidden = Y.one('.yui3-privacybanner-hidden'); |
953 | + Y.Assert.isNull(banner_hidden); |
954 | + var banner_text = Y.one('.banner-text').get('text'); |
955 | + Y.Assert.areEqual( |
956 | + 'This report will be private. ' + |
957 | + 'You can disclose it later.', banner_text); |
958 | + }, |
959 | + |
960 | + // Selecting a private info type turns on the privacy banner. |
961 | + test_select_private_info_type: function () { |
962 | + window.LP.cache.show_information_type_in_ui = true; |
963 | + Y.lp.bugs.filebug.setup_filebug(true); |
964 | + var banner_hidden = Y.one('.yui3-privacybanner-hidden'); |
965 | + Y.Assert.isNotNull(banner_hidden); |
966 | + Y.one('[id=field.information_type.2]').simulate('click'); |
967 | + banner_hidden = Y.one('.yui3-privacybanner-hidden'); |
968 | + Y.Assert.isNull(banner_hidden); |
969 | + var banner_text = Y.one('.banner-text').get('text'); |
970 | + Y.Assert.areEqual( |
971 | + 'This report will be private. ' + |
972 | + 'You can disclose it later.', banner_text); |
973 | + }, |
974 | + |
975 | + // Selecting a public info type turns off the privacy banner. |
976 | + test_select_public_info_type: function () { |
977 | + window.LP.cache.show_information_type_in_ui = true; |
978 | + window.LP.cache.bug_private_by_default = true; |
979 | + Y.lp.bugs.filebug.setup_filebug(true); |
980 | + var banner_hidden = Y.one('.yui3-privacybanner-hidden'); |
981 | + Y.Assert.isNull(banner_hidden); |
982 | + Y.one('[id=field.information_type.0]').simulate('click'); |
983 | + banner_hidden = Y.one('.yui3-privacybanner-hidden'); |
984 | + Y.Assert.isNotNull(banner_hidden); |
985 | + }, |
986 | + |
987 | + // The dupe finder functionality is setup. |
988 | + test_dupe_finder_setup: function () { |
989 | + window.LP.cache.enable_bugfiling_duplicate_search = true; |
990 | + var orig_setup_dupe_finder = |
991 | + Y.lp.bugs.filebug_dupefinder.setup_dupe_finder; |
992 | + var orig_setup_dupes = |
993 | + Y.lp.bugs.filebug_dupefinder.setup_dupes; |
994 | + var setup_dupe_finder_called = false; |
995 | + var setup_dupes_called = false; |
996 | + Y.lp.bugs.filebug_dupefinder.setup_dupe_finder = function() { |
997 | + setup_dupe_finder_called = true; |
998 | + }; |
999 | + Y.lp.bugs.filebug_dupefinder.setup_dupes = function() { |
1000 | + setup_dupes_called = true; |
1001 | + }; |
1002 | + Y.lp.bugs.filebug.setup_filebug(true); |
1003 | + Y.Assert.isTrue(setup_dupe_finder_called); |
1004 | + Y.Assert.isTrue(setup_dupes_called); |
1005 | + Y.lp.bugs.filebug_dupefinder.setup_dupes = orig_setup_dupes; |
1006 | + Y.lp.bugs.filebug_dupefinder.setup_dupe_finder |
1007 | + = orig_setup_dupe_finder; |
1008 | + } |
1009 | + })); |
1010 | + |
1011 | +}, '0.1', {'requires': ['test', 'console', 'event', 'node-event-simulate', |
1012 | + 'lp.app.banner.privacy', 'lp.bugs.filebug_dupefinder', |
1013 | + 'lp.bugs.filebug' |
1014 | + ]}); |
1015 | +>>>>>>> MERGE-SOURCE |
1016 | |
1017 | === modified file 'lib/lp/code/browser/tests/test_branch.py' |
1018 | === modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py' |
1019 | === modified file 'lib/lp/code/model/tests/test_branch.py' |
1020 | --- lib/lp/code/model/tests/test_branch.py 2012-05-31 03:54:13 +0000 |
1021 | +++ lib/lp/code/model/tests/test_branch.py 2012-06-01 11:55:34 +0000 |
1022 | @@ -2337,9 +2337,15 @@ |
1023 | |
1024 | def test_public_stacked_on_private_is_private(self): |
1025 | # A public branch stacked on a private branch is private. |
1026 | +<<<<<<< TREE |
1027 | stacked_on = self.factory.makeBranch( |
1028 | information_type=InformationType.USERDATA) |
1029 | branch = self.factory.makeBranch(stacked_on=stacked_on) |
1030 | +======= |
1031 | + stacked_on = self.factory.makeBranch(private=True) |
1032 | + branch = self.factory.makeBranch( |
1033 | + stacked_on=stacked_on, private=False) |
1034 | +>>>>>>> MERGE-SOURCE |
1035 | self.assertTrue(branch.private) |
1036 | self.assertEqual( |
1037 | stacked_on.information_type, branch.information_type) |
1038 | @@ -2347,10 +2353,16 @@ |
1039 | self.assertTrue(branch.explicitly_private) |
1040 | |
1041 | def test_private_stacked_on_public_is_private(self): |
1042 | +<<<<<<< TREE |
1043 | # A private branch stacked on a public branch is private. |
1044 | stacked_on = self.factory.makeBranch() |
1045 | branch = self.factory.makeBranch( |
1046 | stacked_on=stacked_on, information_type=InformationType.USERDATA) |
1047 | +======= |
1048 | + # A private branch stacked on a public branch is private. |
1049 | + stacked_on = self.factory.makeBranch(private=False) |
1050 | + branch = self.factory.makeBranch(stacked_on=stacked_on, private=True) |
1051 | +>>>>>>> MERGE-SOURCE |
1052 | self.assertTrue(branch.private) |
1053 | self.assertNotEqual( |
1054 | stacked_on.information_type, branch.information_type) |
1055 | @@ -2449,6 +2461,7 @@ |
1056 | branch.setPrivate, |
1057 | False, branch.owner) |
1058 | |
1059 | +<<<<<<< TREE |
1060 | def test_cannot_transition_with_private_stacked_on(self): |
1061 | # If a public branch is stacked on a private branch, it can not |
1062 | # change its information_type to public. |
1063 | @@ -2471,6 +2484,28 @@ |
1064 | self.assertEqual( |
1065 | InformationType.UNEMBARGOEDSECURITY, branch.information_type) |
1066 | |
1067 | +======= |
1068 | + def test_cannot_transition_with_private_stacked_on(self): |
1069 | + # If a public branch is stacked on a private branch, it can not |
1070 | + # change its information_type to public. |
1071 | + stacked_on = self.factory.makeBranch(private=True) |
1072 | + branch = self.factory.makeBranch(stacked_on=stacked_on) |
1073 | + self.assertRaises( |
1074 | + BranchCannotChangeInformationType, |
1075 | + branch.transitionToInformationType, InformationType.PUBLIC, |
1076 | + branch.owner) |
1077 | + |
1078 | + def test_can_transition_with_public_stacked_on(self): |
1079 | + # If a private branch is stacked on a public branch, it can change |
1080 | + # its information_type. |
1081 | + stacked_on = self.factory.makeBranch() |
1082 | + branch = self.factory.makeBranch(stacked_on=stacked_on, private=True) |
1083 | + branch.transitionToInformationType( |
1084 | + InformationType.UNEMBARGOEDSECURITY, branch.owner) |
1085 | + self.assertEqual( |
1086 | + InformationType.UNEMBARGOEDSECURITY, branch.information_type) |
1087 | + |
1088 | +>>>>>>> MERGE-SOURCE |
1089 | |
1090 | class TestBranchCommitsForDays(TestCaseWithFactory): |
1091 | """Tests for `Branch.commitsForDays`.""" |
1092 | |
1093 | === modified file 'lib/lp/code/model/tests/test_branchlookup.py' |
1094 | --- lib/lp/code/model/tests/test_branchlookup.py 2012-05-31 03:54:13 +0000 |
1095 | +++ lib/lp/code/model/tests/test_branchlookup.py 2012-06-01 11:55:34 +0000 |
1096 | @@ -148,9 +148,15 @@ |
1097 | # (this is for anonymous access) |
1098 | owner = self.factory.makePerson() |
1099 | private_branch = self.factory.makeAnyBranch( |
1100 | +<<<<<<< TREE |
1101 | owner=owner, information_type=InformationType.USERDATA) |
1102 | branch = self.factory.makeAnyBranch( |
1103 | stacked_on=private_branch, owner=owner) |
1104 | +======= |
1105 | + owner=owner, private=True) |
1106 | + branch = self.factory.makeAnyBranch( |
1107 | + stacked_on=private_branch, owner=owner) |
1108 | +>>>>>>> MERGE-SOURCE |
1109 | with person_logged_in(owner): |
1110 | path = branch_id_alias(branch) |
1111 | result = self.branch_set.getIdAndTrailingPath(path) |
1112 | |
1113 | === modified file 'lib/lp/code/model/tests/test_branchmergeproposal.py' |
1114 | === modified file 'lib/lp/code/model/tests/test_branchvisibility.py' |
1115 | --- lib/lp/code/model/tests/test_branchvisibility.py 2012-05-31 03:54:13 +0000 |
1116 | +++ lib/lp/code/model/tests/test_branchvisibility.py 2012-06-01 11:55:34 +0000 |
1117 | @@ -138,17 +138,26 @@ |
1118 | private_owner = self.factory.makePerson() |
1119 | test_branches = [] |
1120 | for x in range(5): |
1121 | +<<<<<<< TREE |
1122 | # We want the first 3 public and the last 3 private. |
1123 | information_type = InformationType.PUBLIC |
1124 | if x > 2: |
1125 | information_type = InformationType.USERDATA |
1126 | branch = self.factory.makeBranch( |
1127 | information_type=information_type) |
1128 | +======= |
1129 | + # We want the first 3 public and the last 3 private. |
1130 | + branch = self.factory.makeBranch(private=x > 2) |
1131 | +>>>>>>> MERGE-SOURCE |
1132 | test_branches.append(branch) |
1133 | test_branches.append( |
1134 | +<<<<<<< TREE |
1135 | self.factory.makeBranch( |
1136 | owner=private_owner, |
1137 | information_type=InformationType.USERDATA)) |
1138 | +======= |
1139 | + self.factory.makeBranch(private=True, owner=private_owner)) |
1140 | +>>>>>>> MERGE-SOURCE |
1141 | |
1142 | # Anonymous users see just the public branches. |
1143 | branch_info = [(branch, branch.private) |
1144 | |
1145 | === modified file 'lib/lp/code/model/tests/test_sourcepackagerecipe.py' |
1146 | === modified file 'lib/lp/code/xmlrpc/tests/test_branch.py' |
1147 | === modified file 'lib/lp/registry/templates/person-upcomingwork.pt' |
1148 | === modified file 'lib/lp/registry/tests/test_productjob.py' |
1149 | === modified file 'lib/lp/soyuz/model/queue.py' |
1150 | === modified file 'lib/lp/soyuz/tests/test_distroseriesqueue_debian_installer.py' |
1151 | --- lib/lp/soyuz/tests/test_distroseriesqueue_debian_installer.py 2012-05-28 12:50:34 +0000 |
1152 | +++ lib/lp/soyuz/tests/test_distroseriesqueue_debian_installer.py 2012-06-01 11:55:34 +0000 |
1153 | @@ -1,3 +1,4 @@ |
1154 | +<<<<<<< TREE |
1155 | # Copyright 2012 Canonical Ltd. This software is licensed under the |
1156 | # GNU Affero General Public License version 3 (see the file LICENSE). |
1157 | |
1158 | @@ -72,3 +73,79 @@ |
1159 | CustomUploadAlreadyExists, |
1160 | upload.queue_root.customfiles[0].publish, self.logger) |
1161 | self.assertEqual("ACCEPTED", upload.queue_root.status.name) |
1162 | +======= |
1163 | +# Copyright 2012 Canonical Ltd. This software is licensed under the |
1164 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
1165 | + |
1166 | +"""Test upload and queue manipulation of debian-installer custom uploads. |
1167 | + |
1168 | +See also lp.archivepublisher.tests.test_debian_installer for detailed tests |
1169 | +of debian-installer custom upload extraction. |
1170 | +""" |
1171 | + |
1172 | +import os |
1173 | + |
1174 | +import transaction |
1175 | + |
1176 | +from lp.archivepublisher.debian_installer import DebianInstallerAlreadyExists |
1177 | +from lp.archiveuploader.nascentupload import NascentUpload |
1178 | +from lp.archiveuploader.tests import ( |
1179 | + datadir, |
1180 | + getPolicy, |
1181 | + ) |
1182 | +from lp.services.log.logger import DevNullLogger |
1183 | +from lp.services.mail import stub |
1184 | +from lp.soyuz.tests.test_publishing import TestNativePublishingBase |
1185 | +from lp.testing.gpgkeys import import_public_test_keys |
1186 | + |
1187 | + |
1188 | +class TestDistroSeriesQueueDebianInstaller(TestNativePublishingBase): |
1189 | + |
1190 | + def setUp(self): |
1191 | + super(TestDistroSeriesQueueDebianInstaller, self).setUp() |
1192 | + import_public_test_keys() |
1193 | + # CustomUpload.installFiles requires a umask of 022. |
1194 | + old_umask = os.umask(022) |
1195 | + self.addCleanup(os.umask, old_umask) |
1196 | + self.anything_policy = getPolicy( |
1197 | + name="anything", distro="ubuntutest", distroseries=None) |
1198 | + self.logger = DevNullLogger() |
1199 | + |
1200 | + def uploadTestData(self): |
1201 | + upload = NascentUpload.from_changesfile_path( |
1202 | + datadir( |
1203 | + "debian-installer/" |
1204 | + "debian-installer_20070214ubuntu1_i386.changes"), |
1205 | + self.anything_policy, self.logger) |
1206 | + upload.process() |
1207 | + self.assertFalse(upload.is_rejected) |
1208 | + self.assertTrue(upload.do_accept()) |
1209 | + self.assertFalse(upload.rejection_message) |
1210 | + return upload |
1211 | + |
1212 | + def test_accepts_correct_upload(self): |
1213 | + upload = self.uploadTestData() |
1214 | + self.assertEqual(1, upload.queue_root.customfiles.count()) |
1215 | + |
1216 | + def test_generates_mail(self): |
1217 | + # Two e-mail messages were generated (acceptance and announcement). |
1218 | + self.anything_policy.setDistroSeriesAndPocket("hoary-test") |
1219 | + self.anything_policy.distroseries.changeslist = "announce@example.com" |
1220 | + self.uploadTestData() |
1221 | + self.assertEqual(2, len(stub.test_emails)) |
1222 | + |
1223 | + def test_bad_upload_remains_in_accepted(self): |
1224 | + # Bad debian-installer uploads remain in accepted. Simulate an |
1225 | + # on-disk conflict to force an error. |
1226 | + upload = self.uploadTestData() |
1227 | + # Make sure that we can use the librarian files. |
1228 | + transaction.commit() |
1229 | + os.makedirs(os.path.join( |
1230 | + self.config.distroroot, "ubuntutest", "dists", "hoary-test", |
1231 | + "main", "installer-i386", "20070214ubuntu1")) |
1232 | + self.assertFalse(upload.queue_root.realiseUpload(self.logger)) |
1233 | + self.assertRaises( |
1234 | + DebianInstallerAlreadyExists, |
1235 | + upload.queue_root.customfiles[0].publish, self.logger) |
1236 | + self.assertEqual("ACCEPTED", upload.queue_root.status.name) |
1237 | +>>>>>>> MERGE-SOURCE |
1238 | |
1239 | === modified file 'lib/lp/soyuz/tests/test_packageupload.py' |
1240 | === modified file 'lib/lp/testing/factory.py' |
1241 | --- lib/lp/testing/factory.py 2012-06-01 02:33:27 +0000 |
1242 | +++ lib/lp/testing/factory.py 2012-06-01 11:55:34 +0000 |
1243 | @@ -1073,8 +1073,13 @@ |
1244 | |
1245 | def makeBranch(self, branch_type=None, owner=None, |
1246 | name=None, product=_DEFAULT, url=_DEFAULT, registrant=None, |
1247 | +<<<<<<< TREE |
1248 | information_type=None, stacked_on=None, |
1249 | sourcepackage=None, reviewer=None, **optional_branch_args): |
1250 | +======= |
1251 | + private=None, information_type=None, stacked_on=None, |
1252 | + sourcepackage=None, reviewer=None, **optional_branch_args): |
1253 | +>>>>>>> MERGE-SOURCE |
1254 | """Create and return a new, arbitrary Branch of the given type. |
1255 | |
1256 | Any parameters for `IBranchNamespace.createBranch` can be specified to |
1257 | @@ -1120,9 +1125,21 @@ |
1258 | branch = namespace.createBranch( |
1259 | branch_type=branch_type, name=name, registrant=registrant, |
1260 | url=url, **optional_branch_args) |
1261 | - if information_type is not None: |
1262 | - removeSecurityProxy(branch).transitionToInformationType( |
1263 | - information_type, registrant, verify_policy=False) |
1264 | +<<<<<<< TREE |
1265 | + if information_type is not None: |
1266 | + removeSecurityProxy(branch).transitionToInformationType( |
1267 | + information_type, registrant, verify_policy=False) |
1268 | +======= |
1269 | + assert information_type is None or private is None, ( |
1270 | + "Can not specify both information_type and private") |
1271 | + if private is not None: |
1272 | + information_type = ( |
1273 | + InformationType.USERDATA if private else |
1274 | + InformationType.PUBLIC) |
1275 | + if information_type is not None: |
1276 | + removeSecurityProxy(branch).transitionToInformationType( |
1277 | + information_type, registrant, verify_policy=False) |
1278 | +>>>>>>> MERGE-SOURCE |
1279 | if stacked_on is not None: |
1280 | removeSecurityProxy(branch).branchChanged( |
1281 | removeSecurityProxy(stacked_on).unique_name, 'rev1', None, |