launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #08455
[Merge] lp:~stub/launchpad/pending-db-changes into lp:launchpad
Stuart Bishop has proposed merging lp:~stub/launchpad/pending-db-changes into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~stub/launchpad/pending-db-changes/+merge/108323
= 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.
--
https://code.launchpad.net/~stub/launchpad/pending-db-changes/+merge/108323
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stub/launchpad/pending-db-changes into lp:launchpad.
=== added file 'database/schema/patch-2209-21-4.sql'
--- database/schema/patch-2209-21-4.sql 1970-01-01 00:00:00 +0000
+++ database/schema/patch-2209-21-4.sql 2012-06-01 11:55:34 +0000
@@ -0,0 +1,111 @@
+CREATE OR REPLACE FUNCTION update_database_disk_utilization() RETURNS void
+ LANGUAGE sql SECURITY DEFINER
+ SET search_path TO public
+ AS $$
+ INSERT INTO DatabaseDiskUtilization
+ SELECT
+ CURRENT_TIMESTAMP AT TIME ZONE 'UTC',
+ namespace, name,
+ sub_namespace, sub_name,
+ kind,
+ (namespace || '.' || name || COALESCE(
+ '/' || sub_namespace || '.' || sub_name, '')) AS sort,
+ (stat).table_len,
+ (stat).tuple_count,
+ (stat).tuple_len,
+ (stat).tuple_percent,
+ (stat).dead_tuple_count,
+ (stat).dead_tuple_len,
+ (stat).dead_tuple_percent,
+ (stat).free_space,
+ (stat).free_percent
+ FROM (
+ -- Tables
+ SELECT
+ pg_namespace.nspname AS namespace,
+ pg_class.relname AS name,
+ NULL AS sub_namespace,
+ NULL AS sub_name,
+ pg_class.relkind AS kind,
+ pgstattuple(pg_class.oid) AS stat
+ FROM pg_class, pg_namespace
+ WHERE
+ pg_class.relnamespace = pg_namespace.oid
+ AND pg_class.relkind = 'r'
+ AND pg_table_is_visible(pg_class.oid)
+
+ UNION ALL
+
+ -- Indexes
+ SELECT
+ pg_namespace_table.nspname AS namespace,
+ pg_class_table.relname AS name,
+ pg_namespace_index.nspname AS sub_namespace,
+ pg_class_index.relname AS sub_name,
+ pg_class_index.relkind AS kind,
+ pgstattuple(pg_class_index.oid) AS stat
+ FROM
+ pg_namespace AS pg_namespace_table,
+ pg_namespace AS pg_namespace_index,
+ pg_class AS pg_class_table,
+ pg_class AS pg_class_index,
+ pg_index,
+ pg_am
+ WHERE
+ pg_class_index.relkind = 'i'
+ AND pg_am.amname <> 'gin' -- pgstattuple doesn't support GIN
+ AND pg_table_is_visible(pg_class_table.oid)
+ AND pg_class_index.relnamespace = pg_namespace_index.oid
+ AND pg_class_table.relnamespace = pg_namespace_table.oid
+ AND pg_class_index.relam = pg_am.oid
+ AND pg_index.indexrelid = pg_class_index.oid
+ AND pg_index.indrelid = pg_class_table.oid
+
+ UNION ALL
+
+ -- TOAST tables
+ SELECT
+ pg_namespace_table.nspname AS namespace,
+ pg_class_table.relname AS name,
+ pg_namespace_toast.nspname AS sub_namespace,
+ pg_class_toast.relname AS sub_name,
+ pg_class_toast.relkind AS kind,
+ pgstattuple(pg_class_toast.oid) AS stat
+ FROM
+ pg_namespace AS pg_namespace_table,
+ pg_namespace AS pg_namespace_toast,
+ pg_class AS pg_class_table,
+ pg_class AS pg_class_toast
+ WHERE
+ pg_class_toast.relnamespace = pg_namespace_toast.oid
+ AND pg_table_is_visible(pg_class_table.oid)
+ AND pg_class_table.relnamespace = pg_namespace_table.oid
+ AND pg_class_toast.oid = pg_class_table.reltoastrelid
+
+ UNION ALL
+
+ -- TOAST indexes
+ SELECT
+ pg_namespace_table.nspname AS namespace,
+ pg_class_table.relname AS name,
+ pg_namespace_index.nspname AS sub_namespace,
+ pg_class_index.relname AS sub_name,
+ pg_class_index.relkind AS kind,
+ pgstattuple(pg_class_index.oid) AS stat
+ FROM
+ pg_namespace AS pg_namespace_table,
+ pg_namespace AS pg_namespace_index,
+ pg_class AS pg_class_table,
+ pg_class AS pg_class_index,
+ pg_class AS pg_class_toast
+ WHERE
+ pg_class_table.relnamespace = pg_namespace_table.oid
+ AND pg_table_is_visible(pg_class_table.oid)
+ AND pg_class_index.relnamespace = pg_namespace_index.oid
+ AND pg_class_table.reltoastrelid = pg_class_toast.oid
+ AND pg_class_index.oid = pg_class_toast.reltoastidxid
+ ) AS whatever;
+$$;
+
+INSERT INTO LaunchpadDatabaseRevision VALUES (2209, 21, 4);
+
=== modified file 'lib/lp/app/browser/tales.py'
--- lib/lp/app/browser/tales.py 2012-05-31 02:20:41 +0000
+++ lib/lp/app/browser/tales.py 2012-06-01 11:55:34 +0000
@@ -666,11 +666,20 @@
css_classes.add('private')
css_classes.add('global-notification-visible')
else:
- css_classes.add('public')
- beta = getattr(view, 'beta_features', [])
- if beta != []:
- css_classes.add('global-notification-visible')
- return ' '.join(list(css_classes))
+<<<<<<< TREE
+ css_classes.add('public')
+ beta = getattr(view, 'beta_features', [])
+ if beta != []:
+ css_classes.add('global-notification-visible')
+ return ' '.join(list(css_classes))
+=======
+ css_classes.add('public')
+ beta = getattr(view, 'beta_features', [])
+ if beta != []:
+ css_classes.add('global-notification-visible')
+ return ' '.join(list(css_classes))
+
+>>>>>>> MERGE-SOURCE
def _getSaneBreadcrumbDetail(self, breadcrumb):
text = breadcrumb.detail
=== modified file 'lib/lp/app/browser/tests/test_launchpad.py'
=== modified file 'lib/lp/app/doc/tales.txt'
=== modified file 'lib/lp/app/templates/banner-macros.pt'
--- lib/lp/app/templates/banner-macros.pt 2012-05-30 13:59:24 +0000
+++ lib/lp/app/templates/banner-macros.pt 2012-06-01 11:55:34 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
<macros
xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal"
@@ -54,3 +55,52 @@
</metal:beta>
</macros>
+=======
+<macros
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="launchpad"
+ tal:omit-tag=""
+>
+
+<metal:privacy define-macro="privacy-banner">
+ <tal:show-banner condition="view/private">
+ <div class="yui3-widget yui3-banner yui3-privacybanner">
+ <div class="yui3-privacybanner-content">
+ <div class="global-notification">
+ <span class="sprite notification-private"></span>
+ <span class="banner-text">The information on this page is private.</span>
+ </div>
+ </div>
+ </div>
+ </tal:show-banner>
+</metal:privacy>
+
+<metal:beta define-macro="beta-banner">
+ <tal:show-banner condition="view/beta_features">
+ <div class="yui3-widget yui3-banner yui3-betabanner">
+ <div class="yui3-betabanner-content">
+ <div class="global-notification">
+ <span class="beta-warning">BETA!</span>
+ <span class="banner-text">
+ Some parts of this page are in beta:
+ <span class="beta-feature">
+ <tal:features
+ repeat="feature view/beta_features">
+ <tal:feature replace="feature/title" />
+ <tal:link condition="feature/url">
+ (<a tal:attributes="href feature/url" class="info-link">read more</a>)
+ </tal:link>
+ </tal:features>
+ </span>
+ </span>
+ </div>
+ </div>
+ </div>
+ </tal:show-banner>
+</metal:beta>
+
+</macros>
+>>>>>>> MERGE-SOURCE
=== modified file 'lib/lp/archivepublisher/debian_installer.py'
--- lib/lp/archivepublisher/debian_installer.py 2012-05-30 10:25:43 +0000
+++ lib/lp/archivepublisher/debian_installer.py 2012-06-01 11:55:34 +0000
@@ -16,7 +16,22 @@
import os
import shutil
+<<<<<<< TREE
from lp.archivepublisher.customupload import CustomUpload
+=======
+from lp.archivepublisher.customupload import (
+ CustomUpload,
+ CustomUploadError,
+ )
+
+
+class DebianInstallerAlreadyExists(CustomUploadError):
+ """A build for this type, architecture, and version already exists."""
+ def __init__(self, arch, version):
+ message = ('installer build %s for architecture %s already exists' %
+ (arch, version))
+ CustomUploadError.__init__(self, message)
+>>>>>>> MERGE-SOURCE
class DebianInstallerUpload(CustomUpload):
@@ -42,13 +57,21 @@
def setTargetDirectory(self, archive_root, tarfile_path, distroseries):
tarfile_base = os.path.basename(tarfile_path)
+<<<<<<< TREE
_, self.version, self.arch = tarfile_base.split("_")
self.arch = self.arch.split(".")[0]
+=======
+ components = tarfile_base.split('_')
+ self.version = components[1]
+ self.arch = components[2].split('.')[0]
+
+>>>>>>> MERGE-SOURCE
self.targetdir = os.path.join(
archive_root, 'dists', distroseries, 'main',
'installer-%s' % self.arch)
+<<<<<<< TREE
@classmethod
def getSeriesKey(cls, tarfile_path):
try:
@@ -56,6 +79,10 @@
return arch.split(".")[0]
except ValueError:
return None
+=======
+ if os.path.exists(os.path.join(self.targetdir, self.version)):
+ raise DebianInstallerAlreadyExists(self.arch, self.version)
+>>>>>>> MERGE-SOURCE
def extract(self):
CustomUpload.extract(self)
=== modified file 'lib/lp/archivepublisher/tests/test_debian_installer.py'
--- lib/lp/archivepublisher/tests/test_debian_installer.py 2012-05-30 10:25:43 +0000
+++ lib/lp/archivepublisher/tests/test_debian_installer.py 2012-06-01 11:55:34 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
# Copyright 2012 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
@@ -166,3 +167,152 @@
"package_1.0.tar.gz"))
self.assertIsNone(DebianInstallerUpload.getSeriesKey(
"one_two_three_four_5.tar.gz"))
+=======
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Test debian-installer custom uploads.
+
+See also lp.soyuz.tests.test_distroseriesqueue_debian_installer for
+high-level tests of debian-installer upload and queue manipulation.
+"""
+
+import os
+
+from lp.archivepublisher.customupload import CustomUploadBadUmask
+from lp.archivepublisher.debian_installer import (
+ DebianInstallerAlreadyExists,
+ process_debian_installer,
+ )
+from lp.services.tarfile_helpers import LaunchpadWriteTarFile
+from lp.testing import TestCase
+
+
+class TestDebianInstaller(TestCase):
+
+ def setUp(self):
+ super(TestDebianInstaller, self).setUp()
+ self.temp_dir = self.makeTemporaryDirectory()
+ self.suite = "distroseries"
+ # CustomUpload.installFiles requires a umask of 022.
+ old_umask = os.umask(022)
+ self.addCleanup(os.umask, old_umask)
+
+ def openArchive(self):
+ self.version = "20070214ubuntu1"
+ self.arch = "i386"
+ self.path = os.path.join(
+ self.temp_dir,
+ "debian-installer-images_%s_%s.tar.gz" % (self.version, self.arch))
+ self.buffer = open(self.path, "wb")
+ self.archive = LaunchpadWriteTarFile(self.buffer)
+
+ def addFile(self, path, contents):
+ self.archive.add_file(
+ "installer-%s/%s/%s" % (self.arch, self.version, path), contents)
+
+ def addSymlink(self, path, target):
+ self.archive.add_symlink(
+ "installer-%s/%s/%s" % (self.arch, self.version, path), target)
+
+ def process(self):
+ self.archive.close()
+ self.buffer.close()
+ process_debian_installer(self.temp_dir, self.path, self.suite)
+
+ def getInstallerPath(self, versioned_filename=None):
+ installer_path = os.path.join(
+ self.temp_dir, "dists", self.suite, "main",
+ "installer-%s" % self.arch)
+ if versioned_filename is not None:
+ installer_path = os.path.join(
+ installer_path, self.version, versioned_filename)
+ return installer_path
+
+ def test_basic(self):
+ # Processing a simple correct tar file succeeds.
+ self.openArchive()
+ self.addFile("hello", "world")
+ self.process()
+
+ def test_already_exists(self):
+ # If the target directory already exists, processing fails.
+ self.openArchive()
+ os.makedirs(self.getInstallerPath("."))
+ self.assertRaises(DebianInstallerAlreadyExists, self.process)
+
+ def test_bad_umask(self):
+ # The umask must be 022 to avoid incorrect permissions.
+ self.openArchive()
+ self.addFile("dir/file", "foo")
+ os.umask(002) # cleanup already handled by setUp
+ self.assertRaises(CustomUploadBadUmask, self.process)
+
+ def test_current_symlink(self):
+ # A "current" symlink is created to the last version.
+ self.openArchive()
+ self.addFile("hello", "world")
+ self.process()
+ installer_path = self.getInstallerPath()
+ self.assertContentEqual(
+ [self.version, "current"], os.listdir(installer_path))
+ self.assertEqual(
+ self.version, os.readlink(os.path.join(installer_path, "current")))
+
+ def test_correct_file(self):
+ # Files in the tarball are extracted correctly.
+ self.openArchive()
+ directory = ("images/netboot/ubuntu-installer/i386/"
+ "pxelinux.cfg.serial-9600")
+ filename = os.path.join(directory, "default")
+ long_filename = os.path.join(
+ directory, "very_very_very_very_very_very_long_filename")
+ self.addFile(filename, "hey")
+ self.addFile(long_filename, "long")
+ self.process()
+ with open(self.getInstallerPath(filename)) as f:
+ self.assertEqual("hey", f.read())
+ with open(self.getInstallerPath(long_filename)) as f:
+ self.assertEqual("long", f.read())
+
+ def test_correct_symlink(self):
+ # Symbolic links in the tarball are extracted correctly.
+ self.openArchive()
+ foo_path = "images/netboot/foo"
+ foo_target = "ubuntu-installer/i386/pxelinux.cfg.serial-9600/default"
+ link_to_dir_path = "images/netboot/link_to_dir"
+ link_to_dir_target = "ubuntu-installer/i386/pxelinux.cfg.serial-9600"
+ self.addSymlink(foo_path, foo_target)
+ self.addSymlink(link_to_dir_path, link_to_dir_target)
+ self.process()
+ self.assertEqual(
+ foo_target, os.readlink(self.getInstallerPath(foo_path)))
+ self.assertEqual(
+ link_to_dir_target,
+ os.path.normpath(os.readlink(
+ self.getInstallerPath(link_to_dir_path))))
+
+ def test_top_level_permissions(self):
+ # Top-level directories are set to mode 0755 (see bug 107068).
+ self.openArchive()
+ self.addFile("hello", "world")
+ self.process()
+ installer_path = self.getInstallerPath()
+ self.assertEqual(0755, os.stat(installer_path).st_mode & 0777)
+ self.assertEqual(
+ 0755,
+ os.stat(os.path.join(installer_path, os.pardir)).st_mode & 0777)
+
+ def test_extracted_permissions(self):
+ # Extracted files and directories are set to 0644/0755.
+ self.openArchive()
+ directory = ("images/netboot/ubuntu-installer/i386/"
+ "pxelinux.cfg.serial-9600")
+ filename = os.path.join(directory, "default")
+ self.addFile(filename, "hey")
+ self.process()
+ self.assertEqual(
+ 0644, os.stat(self.getInstallerPath(filename)).st_mode & 0777)
+ self.assertEqual(
+ 0755, os.stat(self.getInstallerPath(directory)).st_mode & 0777)
+>>>>>>> MERGE-SOURCE
=== modified file 'lib/lp/archivepublisher/tests/test_dist_upgrader.py'
--- lib/lp/archivepublisher/tests/test_dist_upgrader.py 2012-05-30 10:25:43 +0000
+++ lib/lp/archivepublisher/tests/test_dist_upgrader.py 2012-06-01 11:55:34 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
# Copyright 2012 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
@@ -104,3 +105,91 @@
"package_1.0.tar.gz"))
self.assertIsNone(DistUpgraderUpload.getSeriesKey(
"one_two_three_four_5.tar.gz"))
+=======
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Test dist-upgrader custom uploads.
+
+See also lp.soyuz.tests.test_distroseriesqueue_dist_upgrader for high-level
+tests of dist-upgrader upload and queue manipulation.
+"""
+
+import os
+
+from lp.archivepublisher.customupload import CustomUploadBadUmask
+from lp.archivepublisher.dist_upgrader import (
+ DistUpgraderAlreadyExists,
+ DistUpgraderBadVersion,
+ process_dist_upgrader,
+ )
+from lp.services.tarfile_helpers import LaunchpadWriteTarFile
+from lp.testing import TestCase
+
+
+class TestDistUpgrader(TestCase):
+
+ def setUp(self):
+ super(TestDistUpgrader, self).setUp()
+ self.temp_dir = self.makeTemporaryDirectory()
+ self.suite = "distroseries"
+ # CustomUpload.installFiles requires a umask of 022.
+ old_umask = os.umask(022)
+ self.addCleanup(os.umask, old_umask)
+
+ def openArchive(self, version):
+ self.path = os.path.join(
+ self.temp_dir, "dist-upgrader_%s_all.tar.gz" % version)
+ self.buffer = open(self.path, "wb")
+ self.archive = LaunchpadWriteTarFile(self.buffer)
+
+ def process(self):
+ self.archive.close()
+ self.buffer.close()
+ process_dist_upgrader(self.temp_dir, self.path, self.suite)
+
+ def getUpgraderPath(self):
+ return os.path.join(
+ self.temp_dir, "dists", self.suite, "main", "dist-upgrader-all")
+
+ def test_basic(self):
+ # Processing a simple correct tar file works.
+ self.openArchive("20060302.0120")
+ self.archive.add_file("20060302.0120/hello", "world")
+ self.process()
+
+ def test_already_exists(self):
+ # If the target directory already exists, processing fails.
+ self.openArchive("20060302.0120")
+ self.archive.add_file("20060302.0120/hello", "world")
+ os.makedirs(os.path.join(self.getUpgraderPath(), "20060302.0120"))
+ self.assertRaises(DistUpgraderAlreadyExists, self.process)
+
+ def test_bad_umask(self):
+ # The umask must be 022 to avoid incorrect permissions.
+ self.openArchive("20060302.0120")
+ self.archive.add_file("20060302.0120/file", "foo")
+ os.umask(002) # cleanup already handled by setUp
+ self.assertRaises(CustomUploadBadUmask, self.process)
+
+ def test_current_symlink(self):
+ # A "current" symlink is created to the last version.
+ self.openArchive("20060302.0120")
+ self.archive.add_file("20060302.0120/hello", "world")
+ self.process()
+ upgrader_path = self.getUpgraderPath()
+ self.assertContentEqual(
+ ["20060302.0120", "current"], os.listdir(upgrader_path))
+ self.assertEqual(
+ "20060302.0120",
+ os.readlink(os.path.join(upgrader_path, "current")))
+ self.assertContentEqual(
+ ["hello"],
+ os.listdir(os.path.join(upgrader_path, "20060302.0120")))
+
+ def test_bad_version(self):
+ # Bad versions in the tarball are refused.
+ self.openArchive("20070219.1234")
+ self.archive.add_file("foobar/foobar/dapper.tar.gz", "")
+ self.assertRaises(DistUpgraderBadVersion, self.process)
+>>>>>>> MERGE-SOURCE
=== modified file 'lib/lp/bugs/browser/bugtarget.py'
--- lib/lp/bugs/browser/bugtarget.py 2012-05-30 00:51:34 +0000
+++ lib/lp/bugs/browser/bugtarget.py 2012-06-01 11:55:34 +0000
@@ -388,6 +388,7 @@
if self.redirect_ubuntu_filebug:
pass
LaunchpadFormView.initialize(self)
+<<<<<<< TREE
cache = IJSONRequestCache(self.request)
cache.objects['enable_bugfiling_duplicate_search'] = (
IProjectGroup.providedBy(self.context)
@@ -408,6 +409,13 @@
excluded_items=[BugTaskImportance.UNKNOWN])
cache.objects['bugtask_importance_data'] = bugtask_importance_data
if (self.extra_data_token is not None and
+=======
+ cache = IJSONRequestCache(self.request)
+ cache.objects['enable_bugfiling_duplicate_search'] = (
+ IProjectGroup.providedBy(self.context)
+ or self.context.enable_bugfiling_duplicate_search)
+ if (self.extra_data_token is not None and
+>>>>>>> MERGE-SOURCE
not self.extra_data_to_process):
# self.extra_data has been initialized in publishTraverse().
if self.extra_data.initial_summary:
=== modified file 'lib/lp/bugs/browser/tests/test_bugtarget_filebug.py'
--- lib/lp/bugs/browser/tests/test_bugtarget_filebug.py 2012-05-30 00:51:34 +0000
+++ lib/lp/bugs/browser/tests/test_bugtarget_filebug.py 2012-06-01 11:55:34 +0000
@@ -26,11 +26,18 @@
BugTaskStatus,
)
from lp.bugs.publisher import BugsLayer
+<<<<<<< TREE
from lp.registry.enums import (
InformationType,
PRIVATE_INFORMATION_TYPES,
PUBLIC_INFORMATION_TYPES,
)
+=======
+from lp.registry.enums import (
+ InformationType,
+ PRIVATE_INFORMATION_TYPES,
+ )
+>>>>>>> MERGE-SOURCE
from lp.services.features.testing import FeatureFixture
from lp.services.webapp.servers import LaunchpadTestRequest
from lp.testing import (
@@ -477,6 +484,7 @@
notification.message
for notification in view.request.response.notifications])
self.assertIn("Thank you for your bug report.", msg)
+<<<<<<< TREE
class TestFileBugGuidelinesRequestCache(TestCaseWithFactory):
@@ -609,3 +617,88 @@
login_person(user)
view = create_initialized_view(project, '+filebug', principal=user)
self._assert_cache_values(view, True)
+=======
+
+
+class TestFileBugGuidelinesRequestCache(TestCaseWithFactory):
+ # Tests to ensure the request cache contains the expected values for
+ # file bug guidelines views.
+
+ layer = DatabaseFunctionalLayer
+
+ def _assert_cache_values(self, view, private_bugs, duplicate_search):
+ cache = IJSONRequestCache(view.request).objects
+ self.assertContentEqual(cache['private_types'], [
+ type.name for type in PRIVATE_INFORMATION_TYPES])
+ self.assertEqual(cache['bug_private_by_default'], private_bugs)
+ self.assertEqual(
+ cache['enable_bugfiling_duplicate_search'], duplicate_search)
+
+ def test_product(self):
+ project = self.factory.makeProduct(official_malone=True)
+ user = self.factory.makePerson()
+ login_person(user)
+ view = create_initialized_view(project,
+ '+filebug-reporting-guidelines', principal=user)
+ self._assert_cache_values(view, False, True)
+
+ def test_product_default_private(self):
+ product = self.factory.makeProduct(official_malone=True)
+ removeSecurityProxy(product).private_bugs = True
+ user = self.factory.makePerson()
+ login_person(user)
+ view = create_initialized_view(product,
+ '+filebug-reporting-guidelines', principal=user)
+ self._assert_cache_values(view, True, True)
+
+ def test_product_no_duplicate_search(self):
+ product = self.factory.makeProduct(official_malone=True)
+ removeSecurityProxy(product).enable_bugfiling_duplicate_search = False
+ user = self.factory.makePerson()
+ login_person(user)
+ view = create_initialized_view(product,
+ '+filebug-reporting-guidelines', principal=user)
+ self._assert_cache_values(view, False, False)
+
+ def test_project_group(self):
+ project = self.factory.makeProject()
+ user = self.factory.makePerson()
+ login_person(user)
+ view = create_initialized_view(project,
+ '+filebug-reporting-guidelines', principal=user)
+ self._assert_cache_values(view, False, True)
+
+
+class TestFileBugRequestCache(TestCaseWithFactory):
+ # Tests to ensure the request cache contains the expected values for
+ # file bug views.
+
+ layer = DatabaseFunctionalLayer
+
+ def _assert_cache_values(self, view, duplicate_search):
+ cache = IJSONRequestCache(view.request).objects
+ self.assertEqual(
+ cache['enable_bugfiling_duplicate_search'], duplicate_search)
+
+ def test_product(self):
+ project = self.factory.makeProduct(official_malone=True)
+ user = self.factory.makePerson()
+ login_person(user)
+ view = create_initialized_view(project, '+filebug', principal=user)
+ self._assert_cache_values(view, True)
+
+ def test_product_no_duplicate_search(self):
+ product = self.factory.makeProduct(official_malone=True)
+ removeSecurityProxy(product).enable_bugfiling_duplicate_search = False
+ user = self.factory.makePerson()
+ login_person(user)
+ view = create_initialized_view(product, '+filebug', principal=user)
+ self._assert_cache_values(view, False)
+
+ def test_project_group(self):
+ project = self.factory.makeProject()
+ user = self.factory.makePerson()
+ login_person(user)
+ view = create_initialized_view(project, '+filebug', principal=user)
+ self._assert_cache_values(view, True)
+>>>>>>> MERGE-SOURCE
=== modified file 'lib/lp/bugs/browser/tests/test_bugtask.py'
=== modified file 'lib/lp/bugs/javascript/filebug.js'
--- lib/lp/bugs/javascript/filebug.js 2012-05-28 12:34:29 +0000
+++ lib/lp/bugs/javascript/filebug.js 2012-06-01 11:55:34 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
/* Copyright 2012 Canonical Ltd. This software is licensed under the
* GNU Affero General Public License version 3 (see the file LICENSE).
*
@@ -81,3 +82,80 @@
"base", "node", "event", "node-event-delegate", "lazr.choiceedit",
"lp.app.banner.privacy", "lp.app.choice",
"lp.bugs.filebug_dupefinder"]});
+=======
+/* Copyright 2012 Canonical Ltd. This software is licensed under the
+ * GNU Affero General Public License version 3 (see the file LICENSE).
+ *
+ * Provide functionality for the file bug pages.
+ *
+ * @module bugs
+ * @submodule filebug
+ */
+YUI.add('lp.bugs.filebug', function(Y) {
+
+var namespace = Y.namespace('lp.bugs.filebug');
+
+// For tests.
+var skip_animation;
+
+var setup_filebug = function(skip_anim) {
+ skip_animation = skip_anim;
+ if (LP.cache.enable_bugfiling_duplicate_search) {
+ Y.lp.bugs.filebug_dupefinder.setup_dupe_finder();
+ Y.lp.bugs.filebug_dupefinder.setup_dupes();
+ }
+ var search_button = Y.one(Y.DOM.byId('field.actions.projectgroupsearch'));
+ if (Y.Lang.isValue(search_button )) {
+ search_button.set('value', 'Check again');
+ }
+ if (LP.cache.show_information_type_in_ui) {
+ setup_information_type();
+ } else {
+ setup_security_related();
+ }
+ var filebug_privacy_text = "This report will be private. " +
+ "You can disclose it later.";
+ update_privacy_banner(
+ LP.cache.bug_private_by_default, filebug_privacy_text);
+};
+
+var update_privacy_banner = function(show, banner_text) {
+ var banner = Y.lp.app.banner.privacy.getPrivacyBanner(
+ banner_text, skip_animation);
+ if (show) {
+ banner.show();
+ } else {
+ banner.hide();
+ }
+};
+
+var setup_information_type = function() {
+ var itypes_table = Y.one('.radio-button-widget');
+ itypes_table.delegate('click', function() {
+ var private_type = (Y.Array.indexOf(
+ LP.cache.private_types, this.get('value')) >= 0);
+ update_privacy_banner(private_type);
+ }, "input[name='field.information_type']");
+};
+
+var setup_security_related = function() {
+ var sec = Y.one('[id="field.security_related"]');
+ if (!Y.Lang.isValue(sec)) {
+ return;
+ }
+ var notification_text = "This report will be private " +
+ "because it is a security " +
+ "vulnerability. You can " +
+ "disclose it later.";
+ sec.on('change', function() {
+ var checked = sec.get('checked');
+ update_privacy_banner(checked, notification_text);
+ });
+};
+
+namespace.setup_filebug = setup_filebug;
+
+}, "0.1", {"requires": [
+ "base", "node", "event", "node-event-delegate",
+ "lp.app.banner.privacy", "lp.bugs.filebug_dupefinder"]});
+>>>>>>> MERGE-SOURCE
=== modified file 'lib/lp/bugs/javascript/tests/test_filebug.html'
--- lib/lp/bugs/javascript/tests/test_filebug.html 2012-05-28 12:34:29 +0000
+++ lib/lp/bugs/javascript/tests/test_filebug.html 2012-06-01 11:55:34 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
<!DOCTYPE html>
<!--
Copyright 2012 Canonical Ltd. This software is licensed under the
@@ -117,3 +118,108 @@
</script>
</body>
</html>
+=======
+<!DOCTYPE html>
+<!--
+Copyright 2012 Canonical Ltd. This software is licensed under the
+GNU Affero General Public License version 3 (see the file LICENSE).
+-->
+
+<html>
+ <head>
+ <title>File Bug View Tests</title>
+
+ <!-- YUI and test setup -->
+ <script type="text/javascript"
+ src="../../../../../build/js/yui/yui/yui.js">
+ </script>
+ <link rel="stylesheet"
+ href="../../../../../build/js/yui/console/assets/console-core.css" />
+ <link rel="stylesheet"
+ href="../../../../../build/js/yui/console/assets/skins/sam/console.css" />
+ <link rel="stylesheet"
+ href="../../../../../build/js/yui/test/assets/skins/sam/test.css" />
+
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/app/testing/testrunner.js"></script>
+
+ <link rel="stylesheet" href="../../../app/javascript/testing/test.css" />
+
+ <!-- Dependencies -->
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/app/mustache.js"></script>
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/app/expander.js"></script>
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/app/formoverlay/formoverlay.js"></script>
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/app/formwidgets/formwidgets.js"></script>
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/app/formwidgets/resizing_textarea.js"></script>
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/app/overlay/overlay.js"></script>
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/app/anim/anim.js"></script>
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/bugs/filebug_dupefinder.js"></script>
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/app/effects/effects.js"></script>
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/app/extras/extras.js"></script>
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/app/banners/banner.js"></script>
+ <script type="text/javascript"
+ src="../../../../../build/js/lp/app/banners/privacy.js"></script>
+
+ <!-- The module under test. -->
+ <script type="text/javascript" src="../filebug.js"></script>
+
+ <!-- The test suite -->
+ <script type="text/javascript" src="test_filebug.js"></script>
+
+ </head>
+ <body class="yui3-skin-sam">
+ <ul id="suites">
+ <li>lp.bugs.filebug.test</li>
+ </ul>
+ <div class='login-logout'></div>
+ <div id="fixture"></div>
+ <script type="text/x-template" id="privacy-banner-template">
+ <table class="radio-button-widget">
+ <tbody>
+ <tr>
+ <td><input type="radio" value="PUBLIC" name="field.information_type"
+ id="field.information_type.0" checked="checked" class="radioType">
+ </td>
+ <td><label for="field.information_type.0">Public</label></td>
+ </tr>
+ <tr>
+ <td><input type="radio" value="UNEMBARGOEDSECURITY" name="field.information_type"
+ id="field.information_type.1"class="radioType">
+ </td>
+ <td><label for="field.information_type.1">Unembargoed Security</label></td>
+ </tr>
+ <tr>
+ <td><input type="radio" value="EMBARGOEDSECURITY" name="field.information_type"
+ id="field.information_type.2"class="radioType">
+ </td>
+ <td><label for="field.information_type.2">Embargoed Security</label></td>
+ </tr>
+ <tr>
+ <td><input type="radio" value="USERDATA" name="field.information_type"
+ id="field.information_type.3"class="radioType">
+ </td>
+ <td><label for="field.information_type.3">User Data</label></td>
+ </tr>
+ <tr>
+ <td><input type="radio" value="PROPRIETARY" name="field.information_type"
+ id="field.information_type.4"class="radioType">
+ </td>
+ <td><label for="field.information_type.4">Proprietary</label></td>
+ </tr>
+ </tbody>
+ </table>
+ </script>
+ </body>
+</html>
+>>>>>>> MERGE-SOURCE
=== modified file 'lib/lp/bugs/javascript/tests/test_filebug.js'
--- lib/lp/bugs/javascript/tests/test_filebug.js 2012-05-30 21:36:01 +0000
+++ lib/lp/bugs/javascript/tests/test_filebug.js 2012-06-01 11:55:34 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
/* Copyright (c) 2012, Canonical Ltd. All rights reserved. */
YUI.add('lp.bugs.filebug.test', function (Y) {
@@ -166,3 +167,118 @@
'lp.app.banner.privacy', 'lp.app.choice',
'lp.bugs.filebug_dupefinder', 'lp.bugs.filebug'
]});
+=======
+/* Copyright (c) 2012, Canonical Ltd. All rights reserved. */
+
+YUI.add('lp.bugs.filebug.test', function (Y) {
+
+ var tests = Y.namespace('lp.bugs.filebug.test');
+ tests.suite = new Y.Test.Suite(
+ 'lp.bugs.filebug Tests');
+
+ tests.suite.add(new Y.Test.Case({
+ name: 'lp.bugs.filebug_tests',
+
+ setUp: function () {
+ window.LP = {
+ links: {},
+ cache: {
+ private_types: ['EMBARGOEDSECURITY', 'USERDATA']
+ }
+ };
+ this.fixture = Y.one('#fixture');
+ var banner = Y.Node.create(
+ Y.one('#privacy-banner-template').getContent());
+ this.fixture.appendChild(banner);
+ },
+
+ tearDown: function () {
+ if (this.fixture !== null) {
+ this.fixture.empty(true);
+ }
+ delete this.fixture;
+ delete window.LP;
+ },
+
+ test_library_exists: function () {
+ Y.Assert.isObject(Y.lp.bugs.filebug,
+ "Could not locate the " +
+ "lp.bugs.filebug module");
+ },
+
+ // Filing a public bug does not show the privacy banner.
+ test_setup_filebug_public: function () {
+ Y.lp.bugs.filebug.setup_filebug(true);
+ var banner_hidden = Y.one('.yui3-privacybanner-hidden');
+ Y.Assert.isNotNull(banner_hidden);
+ },
+
+ // Filing a bug for a project with private bugs shows the privacy
+ // banner.
+ test_setup_filebug_private: function () {
+ window.LP.cache.bug_private_by_default = true;
+ Y.lp.bugs.filebug.setup_filebug(true);
+ var banner_hidden = Y.one('.yui3-privacybanner-hidden');
+ Y.Assert.isNull(banner_hidden);
+ var banner_text = Y.one('.banner-text').get('text');
+ Y.Assert.areEqual(
+ 'This report will be private. ' +
+ 'You can disclose it later.', banner_text);
+ },
+
+ // Selecting a private info type turns on the privacy banner.
+ test_select_private_info_type: function () {
+ window.LP.cache.show_information_type_in_ui = true;
+ Y.lp.bugs.filebug.setup_filebug(true);
+ var banner_hidden = Y.one('.yui3-privacybanner-hidden');
+ Y.Assert.isNotNull(banner_hidden);
+ Y.one('[id=field.information_type.2]').simulate('click');
+ banner_hidden = Y.one('.yui3-privacybanner-hidden');
+ Y.Assert.isNull(banner_hidden);
+ var banner_text = Y.one('.banner-text').get('text');
+ Y.Assert.areEqual(
+ 'This report will be private. ' +
+ 'You can disclose it later.', banner_text);
+ },
+
+ // Selecting a public info type turns off the privacy banner.
+ test_select_public_info_type: function () {
+ window.LP.cache.show_information_type_in_ui = true;
+ window.LP.cache.bug_private_by_default = true;
+ Y.lp.bugs.filebug.setup_filebug(true);
+ var banner_hidden = Y.one('.yui3-privacybanner-hidden');
+ Y.Assert.isNull(banner_hidden);
+ Y.one('[id=field.information_type.0]').simulate('click');
+ banner_hidden = Y.one('.yui3-privacybanner-hidden');
+ Y.Assert.isNotNull(banner_hidden);
+ },
+
+ // The dupe finder functionality is setup.
+ test_dupe_finder_setup: function () {
+ window.LP.cache.enable_bugfiling_duplicate_search = true;
+ var orig_setup_dupe_finder =
+ Y.lp.bugs.filebug_dupefinder.setup_dupe_finder;
+ var orig_setup_dupes =
+ Y.lp.bugs.filebug_dupefinder.setup_dupes;
+ var setup_dupe_finder_called = false;
+ var setup_dupes_called = false;
+ Y.lp.bugs.filebug_dupefinder.setup_dupe_finder = function() {
+ setup_dupe_finder_called = true;
+ };
+ Y.lp.bugs.filebug_dupefinder.setup_dupes = function() {
+ setup_dupes_called = true;
+ };
+ Y.lp.bugs.filebug.setup_filebug(true);
+ Y.Assert.isTrue(setup_dupe_finder_called);
+ Y.Assert.isTrue(setup_dupes_called);
+ Y.lp.bugs.filebug_dupefinder.setup_dupes = orig_setup_dupes;
+ Y.lp.bugs.filebug_dupefinder.setup_dupe_finder
+ = orig_setup_dupe_finder;
+ }
+ }));
+
+}, '0.1', {'requires': ['test', 'console', 'event', 'node-event-simulate',
+ 'lp.app.banner.privacy', 'lp.bugs.filebug_dupefinder',
+ 'lp.bugs.filebug'
+ ]});
+>>>>>>> MERGE-SOURCE
=== modified file 'lib/lp/code/browser/tests/test_branch.py'
=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
=== modified file 'lib/lp/code/model/tests/test_branch.py'
--- lib/lp/code/model/tests/test_branch.py 2012-05-31 03:54:13 +0000
+++ lib/lp/code/model/tests/test_branch.py 2012-06-01 11:55:34 +0000
@@ -2337,9 +2337,15 @@
def test_public_stacked_on_private_is_private(self):
# A public branch stacked on a private branch is private.
+<<<<<<< TREE
stacked_on = self.factory.makeBranch(
information_type=InformationType.USERDATA)
branch = self.factory.makeBranch(stacked_on=stacked_on)
+=======
+ stacked_on = self.factory.makeBranch(private=True)
+ branch = self.factory.makeBranch(
+ stacked_on=stacked_on, private=False)
+>>>>>>> MERGE-SOURCE
self.assertTrue(branch.private)
self.assertEqual(
stacked_on.information_type, branch.information_type)
@@ -2347,10 +2353,16 @@
self.assertTrue(branch.explicitly_private)
def test_private_stacked_on_public_is_private(self):
+<<<<<<< TREE
# A private branch stacked on a public branch is private.
stacked_on = self.factory.makeBranch()
branch = self.factory.makeBranch(
stacked_on=stacked_on, information_type=InformationType.USERDATA)
+=======
+ # A private branch stacked on a public branch is private.
+ stacked_on = self.factory.makeBranch(private=False)
+ branch = self.factory.makeBranch(stacked_on=stacked_on, private=True)
+>>>>>>> MERGE-SOURCE
self.assertTrue(branch.private)
self.assertNotEqual(
stacked_on.information_type, branch.information_type)
@@ -2449,6 +2461,7 @@
branch.setPrivate,
False, branch.owner)
+<<<<<<< TREE
def test_cannot_transition_with_private_stacked_on(self):
# If a public branch is stacked on a private branch, it can not
# change its information_type to public.
@@ -2471,6 +2484,28 @@
self.assertEqual(
InformationType.UNEMBARGOEDSECURITY, branch.information_type)
+=======
+ def test_cannot_transition_with_private_stacked_on(self):
+ # If a public branch is stacked on a private branch, it can not
+ # change its information_type to public.
+ stacked_on = self.factory.makeBranch(private=True)
+ branch = self.factory.makeBranch(stacked_on=stacked_on)
+ self.assertRaises(
+ BranchCannotChangeInformationType,
+ branch.transitionToInformationType, InformationType.PUBLIC,
+ branch.owner)
+
+ def test_can_transition_with_public_stacked_on(self):
+ # If a private branch is stacked on a public branch, it can change
+ # its information_type.
+ stacked_on = self.factory.makeBranch()
+ branch = self.factory.makeBranch(stacked_on=stacked_on, private=True)
+ branch.transitionToInformationType(
+ InformationType.UNEMBARGOEDSECURITY, branch.owner)
+ self.assertEqual(
+ InformationType.UNEMBARGOEDSECURITY, branch.information_type)
+
+>>>>>>> MERGE-SOURCE
class TestBranchCommitsForDays(TestCaseWithFactory):
"""Tests for `Branch.commitsForDays`."""
=== modified file 'lib/lp/code/model/tests/test_branchlookup.py'
--- lib/lp/code/model/tests/test_branchlookup.py 2012-05-31 03:54:13 +0000
+++ lib/lp/code/model/tests/test_branchlookup.py 2012-06-01 11:55:34 +0000
@@ -148,9 +148,15 @@
# (this is for anonymous access)
owner = self.factory.makePerson()
private_branch = self.factory.makeAnyBranch(
+<<<<<<< TREE
owner=owner, information_type=InformationType.USERDATA)
branch = self.factory.makeAnyBranch(
stacked_on=private_branch, owner=owner)
+=======
+ owner=owner, private=True)
+ branch = self.factory.makeAnyBranch(
+ stacked_on=private_branch, owner=owner)
+>>>>>>> MERGE-SOURCE
with person_logged_in(owner):
path = branch_id_alias(branch)
result = self.branch_set.getIdAndTrailingPath(path)
=== modified file 'lib/lp/code/model/tests/test_branchmergeproposal.py'
=== modified file 'lib/lp/code/model/tests/test_branchvisibility.py'
--- lib/lp/code/model/tests/test_branchvisibility.py 2012-05-31 03:54:13 +0000
+++ lib/lp/code/model/tests/test_branchvisibility.py 2012-06-01 11:55:34 +0000
@@ -138,17 +138,26 @@
private_owner = self.factory.makePerson()
test_branches = []
for x in range(5):
+<<<<<<< TREE
# We want the first 3 public and the last 3 private.
information_type = InformationType.PUBLIC
if x > 2:
information_type = InformationType.USERDATA
branch = self.factory.makeBranch(
information_type=information_type)
+=======
+ # We want the first 3 public and the last 3 private.
+ branch = self.factory.makeBranch(private=x > 2)
+>>>>>>> MERGE-SOURCE
test_branches.append(branch)
test_branches.append(
+<<<<<<< TREE
self.factory.makeBranch(
owner=private_owner,
information_type=InformationType.USERDATA))
+=======
+ self.factory.makeBranch(private=True, owner=private_owner))
+>>>>>>> MERGE-SOURCE
# Anonymous users see just the public branches.
branch_info = [(branch, branch.private)
=== modified file 'lib/lp/code/model/tests/test_sourcepackagerecipe.py'
=== modified file 'lib/lp/code/xmlrpc/tests/test_branch.py'
=== modified file 'lib/lp/registry/templates/person-upcomingwork.pt'
=== modified file 'lib/lp/registry/tests/test_productjob.py'
=== modified file 'lib/lp/soyuz/model/queue.py'
=== modified file 'lib/lp/soyuz/tests/test_distroseriesqueue_debian_installer.py'
--- lib/lp/soyuz/tests/test_distroseriesqueue_debian_installer.py 2012-05-28 12:50:34 +0000
+++ lib/lp/soyuz/tests/test_distroseriesqueue_debian_installer.py 2012-06-01 11:55:34 +0000
@@ -1,3 +1,4 @@
+<<<<<<< TREE
# Copyright 2012 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
@@ -72,3 +73,79 @@
CustomUploadAlreadyExists,
upload.queue_root.customfiles[0].publish, self.logger)
self.assertEqual("ACCEPTED", upload.queue_root.status.name)
+=======
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Test upload and queue manipulation of debian-installer custom uploads.
+
+See also lp.archivepublisher.tests.test_debian_installer for detailed tests
+of debian-installer custom upload extraction.
+"""
+
+import os
+
+import transaction
+
+from lp.archivepublisher.debian_installer import DebianInstallerAlreadyExists
+from lp.archiveuploader.nascentupload import NascentUpload
+from lp.archiveuploader.tests import (
+ datadir,
+ getPolicy,
+ )
+from lp.services.log.logger import DevNullLogger
+from lp.services.mail import stub
+from lp.soyuz.tests.test_publishing import TestNativePublishingBase
+from lp.testing.gpgkeys import import_public_test_keys
+
+
+class TestDistroSeriesQueueDebianInstaller(TestNativePublishingBase):
+
+ def setUp(self):
+ super(TestDistroSeriesQueueDebianInstaller, self).setUp()
+ import_public_test_keys()
+ # CustomUpload.installFiles requires a umask of 022.
+ old_umask = os.umask(022)
+ self.addCleanup(os.umask, old_umask)
+ self.anything_policy = getPolicy(
+ name="anything", distro="ubuntutest", distroseries=None)
+ self.logger = DevNullLogger()
+
+ def uploadTestData(self):
+ upload = NascentUpload.from_changesfile_path(
+ datadir(
+ "debian-installer/"
+ "debian-installer_20070214ubuntu1_i386.changes"),
+ self.anything_policy, self.logger)
+ upload.process()
+ self.assertFalse(upload.is_rejected)
+ self.assertTrue(upload.do_accept())
+ self.assertFalse(upload.rejection_message)
+ return upload
+
+ def test_accepts_correct_upload(self):
+ upload = self.uploadTestData()
+ self.assertEqual(1, upload.queue_root.customfiles.count())
+
+ def test_generates_mail(self):
+ # Two e-mail messages were generated (acceptance and announcement).
+ self.anything_policy.setDistroSeriesAndPocket("hoary-test")
+ self.anything_policy.distroseries.changeslist = "announce@xxxxxxxxxxx"
+ self.uploadTestData()
+ self.assertEqual(2, len(stub.test_emails))
+
+ def test_bad_upload_remains_in_accepted(self):
+ # Bad debian-installer uploads remain in accepted. Simulate an
+ # on-disk conflict to force an error.
+ upload = self.uploadTestData()
+ # Make sure that we can use the librarian files.
+ transaction.commit()
+ os.makedirs(os.path.join(
+ self.config.distroroot, "ubuntutest", "dists", "hoary-test",
+ "main", "installer-i386", "20070214ubuntu1"))
+ self.assertFalse(upload.queue_root.realiseUpload(self.logger))
+ self.assertRaises(
+ DebianInstallerAlreadyExists,
+ upload.queue_root.customfiles[0].publish, self.logger)
+ self.assertEqual("ACCEPTED", upload.queue_root.status.name)
+>>>>>>> MERGE-SOURCE
=== modified file 'lib/lp/soyuz/tests/test_packageupload.py'
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2012-06-01 02:33:27 +0000
+++ lib/lp/testing/factory.py 2012-06-01 11:55:34 +0000
@@ -1073,8 +1073,13 @@
def makeBranch(self, branch_type=None, owner=None,
name=None, product=_DEFAULT, url=_DEFAULT, registrant=None,
+<<<<<<< TREE
information_type=None, stacked_on=None,
sourcepackage=None, reviewer=None, **optional_branch_args):
+=======
+ private=None, information_type=None, stacked_on=None,
+ sourcepackage=None, reviewer=None, **optional_branch_args):
+>>>>>>> MERGE-SOURCE
"""Create and return a new, arbitrary Branch of the given type.
Any parameters for `IBranchNamespace.createBranch` can be specified to
@@ -1120,9 +1125,21 @@
branch = namespace.createBranch(
branch_type=branch_type, name=name, registrant=registrant,
url=url, **optional_branch_args)
- if information_type is not None:
- removeSecurityProxy(branch).transitionToInformationType(
- information_type, registrant, verify_policy=False)
+<<<<<<< TREE
+ if information_type is not None:
+ removeSecurityProxy(branch).transitionToInformationType(
+ information_type, registrant, verify_policy=False)
+=======
+ assert information_type is None or private is None, (
+ "Can not specify both information_type and private")
+ if private is not None:
+ information_type = (
+ InformationType.USERDATA if private else
+ InformationType.PUBLIC)
+ if information_type is not None:
+ removeSecurityProxy(branch).transitionToInformationType(
+ information_type, registrant, verify_policy=False)
+>>>>>>> MERGE-SOURCE
if stacked_on is not None:
removeSecurityProxy(branch).branchChanged(
removeSecurityProxy(stacked_on).unique_name, 'rev1', None,
Follow ups