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
1diff --git a/lib/lp/oci/browser/tests/test_ocirecipe.py b/lib/lp/oci/browser/tests/test_ocirecipe.py
2index 97fc3c9..b135ed8 100644
3--- a/lib/lp/oci/browser/tests/test_ocirecipe.py
4+++ b/lib/lp/oci/browser/tests/test_ocirecipe.py
5@@ -336,7 +336,8 @@ class TestOCIRecipeAddView(OCIConfigHelperMixin, BaseTestOCIRecipeView):
6 self.assertContentEqual(["386", "amd64", "hppa"], processors.value)
7
8 def test_create_new_recipe_display_restricted_processors(self):
9- # A restricted processor is shown disabled in the UI.
10+ # A restricted processor is shown with a disabled (greyed out)
11+ # checkbox in the UI.
12 self.setUpDistroSeries()
13 oci_project = self.factory.makeOCIProject(pillar=self.distribution)
14 proc_armhf = self.factory.makeProcessor(
15@@ -900,8 +901,8 @@ class TestOCIRecipeEditView(OCIConfigHelperMixin, BaseTestOCIRecipeView):
16 self.assertRecipeProcessors(recipe, ["amd64", "armel"])
17
18 def test_edit_processors_restricted(self):
19- # A restricted processor is shown disabled in the UI and cannot be
20- # enabled.
21+ # A restricted processor is shown with a disabled (greyed out)
22+ # checkbox in the UI, and the processor cannot be enabled.
23 self.setUpDistroSeries()
24 proc_armhf = self.factory.makeProcessor(
25 name="armhf", restricted=True, build_by_default=False)
26@@ -929,10 +930,11 @@ class TestOCIRecipeEditView(OCIConfigHelperMixin, BaseTestOCIRecipeView):
27 browser.getControl("Update OCI recipe").click)
28
29 def test_edit_processors_restricted_already_enabled(self):
30- # A restricted processor that is already enabled is shown disabled
31- # in the UI. This causes form submission to omit it, but the
32- # validation code fixes that up behind the scenes so that we don't
33- # get CannotModifyOCIRecipeProcessor.
34+ # A restricted processor that is already enabled is shown with a
35+ # disabled (greyed out) checkbox in the UI. This causes form
36+ # submission to omit it, but the validation code fixes that up
37+ # behind the scenes so that we don't get
38+ # CannotModifyOCIRecipeProcessor.
39 proc_386 = getUtility(IProcessorSet).getByName("386")
40 proc_amd64 = getUtility(IProcessorSet).getByName("amd64")
41 proc_armhf = self.factory.makeProcessor(
42diff --git a/lib/lp/registry/browser/distribution.py b/lib/lp/registry/browser/distribution.py
43index 303ea20..5fccb6c 100644
44--- a/lib/lp/registry/browser/distribution.py
45+++ b/lib/lp/registry/browser/distribution.py
46@@ -1078,6 +1078,14 @@ class DistributionEditView(RegistryEditFormView,
47 official_malone = data.get('official_malone', False)
48 if not official_malone:
49 data['enable_bug_expiration'] = False
50+ if 'processors' in data:
51+ widget = self.widgets['processors']
52+ for processor in self.context.main_archive.processors:
53+ if processor not in data['processors']:
54+ if processor.name in widget.disabled_items:
55+ # This processor is restricted and currently
56+ # enabled. Leave it untouched.
57+ data['processors'].append(processor)
58
59 def change_archive_fields(self, data):
60 # Update context.main_archive.
61diff --git a/lib/lp/registry/browser/tests/test_distribution_views.py b/lib/lp/registry/browser/tests/test_distribution_views.py
62index 44ddf0d..e50d458 100644
63--- a/lib/lp/registry/browser/tests/test_distribution_views.py
64+++ b/lib/lp/registry/browser/tests/test_distribution_views.py
65@@ -1,8 +1,12 @@
66 # Copyright 2009-2015 Canonical Ltd. This software is licensed under the
67 # GNU Affero General Public License version 3 (see the file LICENSE).
68
69+from fixtures import FakeLogger
70 import soupmatchers
71-from testtools.matchers import MatchesStructure
72+from testtools.matchers import (
73+ MatchesSetwise,
74+ MatchesStructure,
75+ )
76 import transaction
77 from zope.component import getUtility
78
79@@ -17,12 +21,15 @@ from lp.registry.interfaces.distributionmirror import (
80 MirrorContent,
81 MirrorStatus,
82 )
83+from lp.services.webapp.publisher import canonical_url
84 from lp.services.webapp.servers import LaunchpadTestRequest
85 from lp.services.worlddata.interfaces.country import ICountrySet
86+from lp.soyuz.interfaces.archive import CannotModifyArchiveProcessor
87 from lp.testing import (
88 login,
89 login_celebrity,
90 login_person,
91+ person_logged_in,
92 record_two_runs,
93 TestCaseWithFactory,
94 )
95@@ -255,6 +262,70 @@ class TestDistroEditView(OCIConfigHelperMixin, TestCaseWithFactory):
96
97 self.assertContentEqual([], self.distribution.main_archive.processors)
98
99+ def assertArchiveProcessors(self, archive, names):
100+ with person_logged_in(archive.owner):
101+ self.assertContentEqual(
102+ names, [processor.name for processor in archive.processors])
103+
104+ def assertProcessorControls(self, processors_control, enabled, disabled):
105+ matchers = [
106+ MatchesStructure.byEquality(optionValue=name, disabled=False)
107+ for name in enabled]
108+ matchers.extend([
109+ MatchesStructure.byEquality(optionValue=name, disabled=True)
110+ for name in disabled])
111+ self.assertThat(processors_control.controls, MatchesSetwise(*matchers))
112+
113+ def test_edit_processors_restricted(self):
114+ # A restricted processor is shown with a disabled (greyed out)
115+ # checkbox in the UI, and the processor cannot be enabled.
116+ self.useFixture(FakeLogger())
117+ self.factory.makeProcessor(
118+ name="riscv64", restricted=True, build_by_default=False)
119+ login_person(self.distribution.owner)
120+ browser = self.getUserBrowser(
121+ canonical_url(self.distribution) + "/+edit",
122+ user=self.distribution.owner)
123+ processors = browser.getControl(name="field.processors")
124+ self.assertContentEqual(["386", "amd64", "hppa"], processors.value)
125+ self.assertProcessorControls(
126+ processors, ["386", "amd64", "hppa"], ["riscv64"])
127+ # Even if the user works around the disabled checkbox and forcibly
128+ # enables it, they can't enable the restricted processor.
129+ for control in processors.controls:
130+ if control.optionValue == "riscv64":
131+ del control._control.attrs["disabled"]
132+ processors.value = ["386", "amd64", "riscv64"]
133+ self.assertRaises(
134+ CannotModifyArchiveProcessor,
135+ browser.getControl(name="field.actions.change").click)
136+
137+ def test_edit_processors_restricted_already_enabled(self):
138+ # A restricted processor that is already enabled is shown with a
139+ # disabled (greyed out) checkbox in the UI. This causes form
140+ # submission to omit it, but the validation code fixes that up
141+ # behind the scenes so that we don't get
142+ # CannotModifyArchiveProcessor.
143+ proc_386 = getUtility(IProcessorSet).getByName("386")
144+ proc_amd64 = getUtility(IProcessorSet).getByName("amd64")
145+ proc_riscv64 = self.factory.makeProcessor(
146+ name="riscv64", restricted=True, build_by_default=False)
147+ login_person(self.distribution.owner)
148+ archive = self.distribution.main_archive
149+ archive.setProcessors([proc_386, proc_amd64, proc_riscv64])
150+ self.assertArchiveProcessors(archive, ["386", "amd64", "riscv64"])
151+ browser = self.getUserBrowser(
152+ canonical_url(self.distribution) + "/+edit",
153+ user=self.distribution.owner)
154+ processors = browser.getControl(name="field.processors")
155+ # riscv64 is checked but disabled.
156+ self.assertContentEqual(["386", "amd64", "riscv64"], processors.value)
157+ self.assertProcessorControls(
158+ processors, ["386", "amd64", "hppa"], ["riscv64"])
159+ processors.value = ["386"]
160+ browser.getControl(name="field.actions.change").click()
161+ self.assertArchiveProcessors(archive, ["386", "riscv64"])
162+
163 def test_package_derivatives_email(self):
164 # Test that the edit form allows changing package_derivatives_email
165 edit_form = self.getDefaultEditDict()
166diff --git a/lib/lp/snappy/browser/tests/test_snap.py b/lib/lp/snappy/browser/tests/test_snap.py
167index d3f4bca..fc683c4 100644
168--- a/lib/lp/snappy/browser/tests/test_snap.py
169+++ b/lib/lp/snappy/browser/tests/test_snap.py
170@@ -629,7 +629,8 @@ class TestSnapAddView(BaseTestSnapView):
171 self.assertContentEqual(["386", "amd64", "hppa"], processors.value)
172
173 def test_create_new_snap_display_restricted_processors(self):
174- # A restricted processor is shown disabled in the UI.
175+ # A restricted processor is shown with a disabled (greyed out)
176+ # checkbox in the UI.
177 self.useFixture(BranchHostingFixture(blob=b""))
178 branch = self.factory.makeAnyBranch()
179 distroseries = self.setUpDistroSeries()
180@@ -1311,8 +1312,8 @@ class TestSnapEditView(BaseTestSnapView):
181 self.assertSnapProcessors(snap, ["amd64", "armel"])
182
183 def test_edit_processors_restricted(self):
184- # A restricted processor is shown disabled in the UI and cannot be
185- # enabled.
186+ # A restricted processor is shown with a disabled (greyed out)
187+ # checkbox in the UI, and the processor cannot be enabled.
188 distroseries, snappyseries = self.setUpSeries()
189 proc_armhf = self.factory.makeProcessor(
190 name="armhf", restricted=True, build_by_default=False)
191@@ -1339,10 +1340,10 @@ class TestSnapEditView(BaseTestSnapView):
192 browser.getControl("Update snap package").click)
193
194 def test_edit_processors_restricted_already_enabled(self):
195- # A restricted processor that is already enabled is shown disabled
196- # in the UI. This causes form submission to omit it, but the
197- # validation code fixes that up behind the scenes so that we don't
198- # get CannotModifySnapProcessor.
199+ # A restricted processor that is already enabled is shown with a
200+ # disabled (greyed out) checkbox in the UI. This causes form
201+ # submission to omit it, but the validation code fixes that up
202+ # behind the scenes so that we don't get CannotModifySnapProcessor.
203 proc_386 = getUtility(IProcessorSet).getByName("386")
204 proc_amd64 = getUtility(IProcessorSet).getByName("amd64")
205 proc_armhf = self.factory.makeProcessor(
206diff --git a/lib/lp/soyuz/browser/tests/test_archive.py b/lib/lp/soyuz/browser/tests/test_archive.py
207index 07e8614..040a1e4 100644
208--- a/lib/lp/soyuz/browser/tests/test_archive.py
209+++ b/lib/lp/soyuz/browser/tests/test_archive.py
210@@ -125,8 +125,8 @@ class TestArchiveEditView(TestCaseWithFactory):
211 self.assertArchiveProcessors(ppa, ["amd64", "armel"])
212
213 def test_edit_processors_restricted(self):
214- # A restricted processor is shown disabled in the UI and cannot be
215- # enabled.
216+ # A restricted processor is shown with a disabled (greyed out)
217+ # checkbox in the UI, and the processor cannot be enabled.
218 self.useFixture(FakeLogger())
219 proc_armhf = self.factory.makeProcessor(
220 name="armhf", restricted=True, build_by_default=False)
221@@ -151,10 +151,11 @@ class TestArchiveEditView(TestCaseWithFactory):
222 CannotModifyArchiveProcessor, browser.getControl("Save").click)
223
224 def test_edit_processors_restricted_already_enabled(self):
225- # A restricted processor that is already enabled is shown disabled
226- # in the UI. This causes form submission to omit it, but the
227- # validation code fixes that up behind the scenes so that we don't
228- # get CannotModifyArchiveProcessor.
229+ # A restricted processor that is already enabled is shown with a
230+ # disabled (greyed out) checkbox in the UI. This causes form
231+ # submission to omit it, but the validation code fixes that up
232+ # behind the scenes so that we don't get
233+ # CannotModifyArchiveProcessor.
234 proc_386 = getUtility(IProcessorSet).getByName("386")
235 proc_amd64 = getUtility(IProcessorSet).getByName("amd64")
236 proc_armhf = self.factory.makeProcessor(

Subscribers

People subscribed via source and target branches

to status/vote changes: