Merge ~cjwatson/launchpad:distribution-edit-restricted-processors into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 1a20416ad6350ba8d4003d22304b991e4538b0ed
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:distribution-edit-restricted-processors
Merge into: launchpad:master
Diff against target: 236 lines (+104/-21)
5 files modified
lib/lp/oci/browser/tests/test_ocirecipe.py (+9/-7)
lib/lp/registry/browser/distribution.py (+8/-0)
lib/lp/registry/browser/tests/test_distribution_views.py (+72/-1)
lib/lp/snappy/browser/tests/test_snap.py (+8/-7)
lib/lp/soyuz/browser/tests/test_archive.py (+7/-6)
Reviewer Review Type Date Requested Status
Jürgen Gmach Approve
Review via email: mp+423186@code.launchpad.net

Commit message

Fix Distribution:+edit crash with enabled restricted processors

Description of the change

The main archive of a distribution may have an enabled processor which is restricted, such that the owners of that distribution aren't necessarily authorized to enable or disable it; riscv64 is one such for Ubuntu at the moment. This shouldn't prevent distribution owners from making other changes in the distribution's +edit view.

PPAs already had a similar validation tweak.

To post a comment you must log in.
Revision history for this message
Jürgen Gmach (jugmac00) wrote :

I assume you have thought through all the alternatives.

LGishTM :-)

review: Approve
Revision history for this message
Colin Watson (cjwatson) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/lib/lp/oci/browser/tests/test_ocirecipe.py b/lib/lp/oci/browser/tests/test_ocirecipe.py
index 97fc3c9..b135ed8 100644
--- a/lib/lp/oci/browser/tests/test_ocirecipe.py
+++ b/lib/lp/oci/browser/tests/test_ocirecipe.py
@@ -336,7 +336,8 @@ class TestOCIRecipeAddView(OCIConfigHelperMixin, BaseTestOCIRecipeView):
336 self.assertContentEqual(["386", "amd64", "hppa"], processors.value)336 self.assertContentEqual(["386", "amd64", "hppa"], processors.value)
337337
338 def test_create_new_recipe_display_restricted_processors(self):338 def test_create_new_recipe_display_restricted_processors(self):
339 # A restricted processor is shown disabled in the UI.339 # A restricted processor is shown with a disabled (greyed out)
340 # checkbox in the UI.
340 self.setUpDistroSeries()341 self.setUpDistroSeries()
341 oci_project = self.factory.makeOCIProject(pillar=self.distribution)342 oci_project = self.factory.makeOCIProject(pillar=self.distribution)
342 proc_armhf = self.factory.makeProcessor(343 proc_armhf = self.factory.makeProcessor(
@@ -900,8 +901,8 @@ class TestOCIRecipeEditView(OCIConfigHelperMixin, BaseTestOCIRecipeView):
900 self.assertRecipeProcessors(recipe, ["amd64", "armel"])901 self.assertRecipeProcessors(recipe, ["amd64", "armel"])
901902
902 def test_edit_processors_restricted(self):903 def test_edit_processors_restricted(self):
903 # A restricted processor is shown disabled in the UI and cannot be904 # A restricted processor is shown with a disabled (greyed out)
904 # enabled.905 # checkbox in the UI, and the processor cannot be enabled.
905 self.setUpDistroSeries()906 self.setUpDistroSeries()
906 proc_armhf = self.factory.makeProcessor(907 proc_armhf = self.factory.makeProcessor(
907 name="armhf", restricted=True, build_by_default=False)908 name="armhf", restricted=True, build_by_default=False)
@@ -929,10 +930,11 @@ class TestOCIRecipeEditView(OCIConfigHelperMixin, BaseTestOCIRecipeView):
929 browser.getControl("Update OCI recipe").click)930 browser.getControl("Update OCI recipe").click)
930931
931 def test_edit_processors_restricted_already_enabled(self):932 def test_edit_processors_restricted_already_enabled(self):
932 # A restricted processor that is already enabled is shown disabled933 # A restricted processor that is already enabled is shown with a
933 # in the UI. This causes form submission to omit it, but the934 # disabled (greyed out) checkbox in the UI. This causes form
934 # validation code fixes that up behind the scenes so that we don't935 # submission to omit it, but the validation code fixes that up
935 # get CannotModifyOCIRecipeProcessor.936 # behind the scenes so that we don't get
937 # CannotModifyOCIRecipeProcessor.
936 proc_386 = getUtility(IProcessorSet).getByName("386")938 proc_386 = getUtility(IProcessorSet).getByName("386")
937 proc_amd64 = getUtility(IProcessorSet).getByName("amd64")939 proc_amd64 = getUtility(IProcessorSet).getByName("amd64")
938 proc_armhf = self.factory.makeProcessor(940 proc_armhf = self.factory.makeProcessor(
diff --git a/lib/lp/registry/browser/distribution.py b/lib/lp/registry/browser/distribution.py
index 303ea20..5fccb6c 100644
--- a/lib/lp/registry/browser/distribution.py
+++ b/lib/lp/registry/browser/distribution.py
@@ -1078,6 +1078,14 @@ class DistributionEditView(RegistryEditFormView,
1078 official_malone = data.get('official_malone', False)1078 official_malone = data.get('official_malone', False)
1079 if not official_malone:1079 if not official_malone:
1080 data['enable_bug_expiration'] = False1080 data['enable_bug_expiration'] = False
1081 if 'processors' in data:
1082 widget = self.widgets['processors']
1083 for processor in self.context.main_archive.processors:
1084 if processor not in data['processors']:
1085 if processor.name in widget.disabled_items:
1086 # This processor is restricted and currently
1087 # enabled. Leave it untouched.
1088 data['processors'].append(processor)
10811089
1082 def change_archive_fields(self, data):1090 def change_archive_fields(self, data):
1083 # Update context.main_archive.1091 # Update context.main_archive.
diff --git a/lib/lp/registry/browser/tests/test_distribution_views.py b/lib/lp/registry/browser/tests/test_distribution_views.py
index 44ddf0d..e50d458 100644
--- a/lib/lp/registry/browser/tests/test_distribution_views.py
+++ b/lib/lp/registry/browser/tests/test_distribution_views.py
@@ -1,8 +1,12 @@
1# Copyright 2009-2015 Canonical Ltd. This software is licensed under the1# Copyright 2009-2015 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4from fixtures import FakeLogger
4import soupmatchers5import soupmatchers
5from testtools.matchers import MatchesStructure6from testtools.matchers import (
7 MatchesSetwise,
8 MatchesStructure,
9 )
6import transaction10import transaction
7from zope.component import getUtility11from zope.component import getUtility
812
@@ -17,12 +21,15 @@ from lp.registry.interfaces.distributionmirror import (
17 MirrorContent,21 MirrorContent,
18 MirrorStatus,22 MirrorStatus,
19 )23 )
24from lp.services.webapp.publisher import canonical_url
20from lp.services.webapp.servers import LaunchpadTestRequest25from lp.services.webapp.servers import LaunchpadTestRequest
21from lp.services.worlddata.interfaces.country import ICountrySet26from lp.services.worlddata.interfaces.country import ICountrySet
27from lp.soyuz.interfaces.archive import CannotModifyArchiveProcessor
22from lp.testing import (28from lp.testing import (
23 login,29 login,
24 login_celebrity,30 login_celebrity,
25 login_person,31 login_person,
32 person_logged_in,
26 record_two_runs,33 record_two_runs,
27 TestCaseWithFactory,34 TestCaseWithFactory,
28 )35 )
@@ -255,6 +262,70 @@ class TestDistroEditView(OCIConfigHelperMixin, TestCaseWithFactory):
255262
256 self.assertContentEqual([], self.distribution.main_archive.processors)263 self.assertContentEqual([], self.distribution.main_archive.processors)
257264
265 def assertArchiveProcessors(self, archive, names):
266 with person_logged_in(archive.owner):
267 self.assertContentEqual(
268 names, [processor.name for processor in archive.processors])
269
270 def assertProcessorControls(self, processors_control, enabled, disabled):
271 matchers = [
272 MatchesStructure.byEquality(optionValue=name, disabled=False)
273 for name in enabled]
274 matchers.extend([
275 MatchesStructure.byEquality(optionValue=name, disabled=True)
276 for name in disabled])
277 self.assertThat(processors_control.controls, MatchesSetwise(*matchers))
278
279 def test_edit_processors_restricted(self):
280 # A restricted processor is shown with a disabled (greyed out)
281 # checkbox in the UI, and the processor cannot be enabled.
282 self.useFixture(FakeLogger())
283 self.factory.makeProcessor(
284 name="riscv64", restricted=True, build_by_default=False)
285 login_person(self.distribution.owner)
286 browser = self.getUserBrowser(
287 canonical_url(self.distribution) + "/+edit",
288 user=self.distribution.owner)
289 processors = browser.getControl(name="field.processors")
290 self.assertContentEqual(["386", "amd64", "hppa"], processors.value)
291 self.assertProcessorControls(
292 processors, ["386", "amd64", "hppa"], ["riscv64"])
293 # Even if the user works around the disabled checkbox and forcibly
294 # enables it, they can't enable the restricted processor.
295 for control in processors.controls:
296 if control.optionValue == "riscv64":
297 del control._control.attrs["disabled"]
298 processors.value = ["386", "amd64", "riscv64"]
299 self.assertRaises(
300 CannotModifyArchiveProcessor,
301 browser.getControl(name="field.actions.change").click)
302
303 def test_edit_processors_restricted_already_enabled(self):
304 # A restricted processor that is already enabled is shown with a
305 # disabled (greyed out) checkbox in the UI. This causes form
306 # submission to omit it, but the validation code fixes that up
307 # behind the scenes so that we don't get
308 # CannotModifyArchiveProcessor.
309 proc_386 = getUtility(IProcessorSet).getByName("386")
310 proc_amd64 = getUtility(IProcessorSet).getByName("amd64")
311 proc_riscv64 = self.factory.makeProcessor(
312 name="riscv64", restricted=True, build_by_default=False)
313 login_person(self.distribution.owner)
314 archive = self.distribution.main_archive
315 archive.setProcessors([proc_386, proc_amd64, proc_riscv64])
316 self.assertArchiveProcessors(archive, ["386", "amd64", "riscv64"])
317 browser = self.getUserBrowser(
318 canonical_url(self.distribution) + "/+edit",
319 user=self.distribution.owner)
320 processors = browser.getControl(name="field.processors")
321 # riscv64 is checked but disabled.
322 self.assertContentEqual(["386", "amd64", "riscv64"], processors.value)
323 self.assertProcessorControls(
324 processors, ["386", "amd64", "hppa"], ["riscv64"])
325 processors.value = ["386"]
326 browser.getControl(name="field.actions.change").click()
327 self.assertArchiveProcessors(archive, ["386", "riscv64"])
328
258 def test_package_derivatives_email(self):329 def test_package_derivatives_email(self):
259 # Test that the edit form allows changing package_derivatives_email330 # Test that the edit form allows changing package_derivatives_email
260 edit_form = self.getDefaultEditDict()331 edit_form = self.getDefaultEditDict()
diff --git a/lib/lp/snappy/browser/tests/test_snap.py b/lib/lp/snappy/browser/tests/test_snap.py
index d3f4bca..fc683c4 100644
--- a/lib/lp/snappy/browser/tests/test_snap.py
+++ b/lib/lp/snappy/browser/tests/test_snap.py
@@ -629,7 +629,8 @@ class TestSnapAddView(BaseTestSnapView):
629 self.assertContentEqual(["386", "amd64", "hppa"], processors.value)629 self.assertContentEqual(["386", "amd64", "hppa"], processors.value)
630630
631 def test_create_new_snap_display_restricted_processors(self):631 def test_create_new_snap_display_restricted_processors(self):
632 # A restricted processor is shown disabled in the UI.632 # A restricted processor is shown with a disabled (greyed out)
633 # checkbox in the UI.
633 self.useFixture(BranchHostingFixture(blob=b""))634 self.useFixture(BranchHostingFixture(blob=b""))
634 branch = self.factory.makeAnyBranch()635 branch = self.factory.makeAnyBranch()
635 distroseries = self.setUpDistroSeries()636 distroseries = self.setUpDistroSeries()
@@ -1311,8 +1312,8 @@ class TestSnapEditView(BaseTestSnapView):
1311 self.assertSnapProcessors(snap, ["amd64", "armel"])1312 self.assertSnapProcessors(snap, ["amd64", "armel"])
13121313
1313 def test_edit_processors_restricted(self):1314 def test_edit_processors_restricted(self):
1314 # A restricted processor is shown disabled in the UI and cannot be1315 # A restricted processor is shown with a disabled (greyed out)
1315 # enabled.1316 # checkbox in the UI, and the processor cannot be enabled.
1316 distroseries, snappyseries = self.setUpSeries()1317 distroseries, snappyseries = self.setUpSeries()
1317 proc_armhf = self.factory.makeProcessor(1318 proc_armhf = self.factory.makeProcessor(
1318 name="armhf", restricted=True, build_by_default=False)1319 name="armhf", restricted=True, build_by_default=False)
@@ -1339,10 +1340,10 @@ class TestSnapEditView(BaseTestSnapView):
1339 browser.getControl("Update snap package").click)1340 browser.getControl("Update snap package").click)
13401341
1341 def test_edit_processors_restricted_already_enabled(self):1342 def test_edit_processors_restricted_already_enabled(self):
1342 # A restricted processor that is already enabled is shown disabled1343 # A restricted processor that is already enabled is shown with a
1343 # in the UI. This causes form submission to omit it, but the1344 # disabled (greyed out) checkbox in the UI. This causes form
1344 # validation code fixes that up behind the scenes so that we don't1345 # submission to omit it, but the validation code fixes that up
1345 # get CannotModifySnapProcessor.1346 # behind the scenes so that we don't get CannotModifySnapProcessor.
1346 proc_386 = getUtility(IProcessorSet).getByName("386")1347 proc_386 = getUtility(IProcessorSet).getByName("386")
1347 proc_amd64 = getUtility(IProcessorSet).getByName("amd64")1348 proc_amd64 = getUtility(IProcessorSet).getByName("amd64")
1348 proc_armhf = self.factory.makeProcessor(1349 proc_armhf = self.factory.makeProcessor(
diff --git a/lib/lp/soyuz/browser/tests/test_archive.py b/lib/lp/soyuz/browser/tests/test_archive.py
index 07e8614..040a1e4 100644
--- a/lib/lp/soyuz/browser/tests/test_archive.py
+++ b/lib/lp/soyuz/browser/tests/test_archive.py
@@ -125,8 +125,8 @@ class TestArchiveEditView(TestCaseWithFactory):
125 self.assertArchiveProcessors(ppa, ["amd64", "armel"])125 self.assertArchiveProcessors(ppa, ["amd64", "armel"])
126126
127 def test_edit_processors_restricted(self):127 def test_edit_processors_restricted(self):
128 # A restricted processor is shown disabled in the UI and cannot be128 # A restricted processor is shown with a disabled (greyed out)
129 # enabled.129 # checkbox in the UI, and the processor cannot be enabled.
130 self.useFixture(FakeLogger())130 self.useFixture(FakeLogger())
131 proc_armhf = self.factory.makeProcessor(131 proc_armhf = self.factory.makeProcessor(
132 name="armhf", restricted=True, build_by_default=False)132 name="armhf", restricted=True, build_by_default=False)
@@ -151,10 +151,11 @@ class TestArchiveEditView(TestCaseWithFactory):
151 CannotModifyArchiveProcessor, browser.getControl("Save").click)151 CannotModifyArchiveProcessor, browser.getControl("Save").click)
152152
153 def test_edit_processors_restricted_already_enabled(self):153 def test_edit_processors_restricted_already_enabled(self):
154 # A restricted processor that is already enabled is shown disabled154 # A restricted processor that is already enabled is shown with a
155 # in the UI. This causes form submission to omit it, but the155 # disabled (greyed out) checkbox in the UI. This causes form
156 # validation code fixes that up behind the scenes so that we don't156 # submission to omit it, but the validation code fixes that up
157 # get CannotModifyArchiveProcessor.157 # behind the scenes so that we don't get
158 # CannotModifyArchiveProcessor.
158 proc_386 = getUtility(IProcessorSet).getByName("386")159 proc_386 = getUtility(IProcessorSet).getByName("386")
159 proc_amd64 = getUtility(IProcessorSet).getByName("amd64")160 proc_amd64 = getUtility(IProcessorSet).getByName("amd64")
160 proc_armhf = self.factory.makeProcessor(161 proc_armhf = self.factory.makeProcessor(

Subscribers

People subscribed via source and target branches

to status/vote changes: