Merge lp:~julian-edwards/maas/dup-boot-source-selections-part2-bug-1360280 into lp:~maas-committers/maas/trunk

Proposed by Julian Edwards
Status: Merged
Approved by: Julian Edwards
Approved revision: no longer in the source branch.
Merged at revision: 3367
Proposed branch: lp:~julian-edwards/maas/dup-boot-source-selections-part2-bug-1360280
Merge into: lp:~maas-committers/maas/trunk
Prerequisite: lp:~julian-edwards/maas/dup-boot-source-selections-bug-1360280
Diff against target: 466 lines (+321/-38)
4 files modified
src/maasserver/api/tests/test_boot_source_selections.py (+24/-13)
src/maasserver/forms.py (+56/-0)
src/maasserver/testing/factory.py (+6/-0)
src/maasserver/tests/test_forms_bootsourceselection.py (+235/-25)
To merge this branch: bzr merge lp:~julian-edwards/maas/dup-boot-source-selections-part2-bug-1360280
Reviewer Review Type Date Requested Status
Graham Binns (community) Approve
Review via email: mp+241472@code.launchpad.net

Commit message

Validate BootSourceSelection changes against the available selection that lives in BootSourceCache. Previously, bogus entries could be added.

Description of the change

Whoever reviews this, please double check that this won't affect custom images. I don't think it will, but ...

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) wrote :

Looks good. There's a don't-make-me-think nit inline, but otherwise this is fine.

review: Approve
Revision history for this message
Julian Edwards (julian-edwards) wrote :

On Wednesday 12 Nov 2014 07:37:38 you wrote:
> I can *hear* jtv, here and elsewhere, saying "What is this obsession with
> creating 3 _things_?"

Arf :)

> Also, I don't actually understand from the test why you're creating three
> mostly identical BootSourceCaches, here and elsewhere. What does it
> actually achieve? Wouldn't one do just as well?

You figured this out....

> > + boot_caches.append(factory.make_BootSourceCache(
> > + boot_source, arch=factory.make_name('arch'),
> > + os=os, release=release))
> > +
> > + params = {
> > + 'os': os,
> > + 'release': release,
> > + 'arches': [boot_caches[0].arch, boot_caches[2].arch],
>
> Ah, I get it now; you're combining the valid values for the field you're
> testing on from some but not all of the BootSourceCaches you've created.
>
> Consider moving the for loop into a helper. Also, add a comment (or a
> docstring on the helper so that you're not having to C&P comments all over
> the shop) explaining why you're creating multiple BootSourceCaches and what
> they'll be used for.

I've been staring at the code for so long that it didn't look that bad any
more. I guess I'll try for a helper - I ran out of brain juice on this one.

Thanks for reviewing!

Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (22.0 KiB)

The attempt to merge lp:~julian-edwards/maas/dup-boot-source-selections-part2-bug-1360280 into lp:maas failed. Below is the output from the failed tests.

Ign http://security.ubuntu.com trusty-security InRelease
Get:1 http://security.ubuntu.com trusty-security Release.gpg [933 B]
Ign http://nova.clouds.archive.ubuntu.com trusty InRelease
Get:2 http://security.ubuntu.com trusty-security Release [62.0 kB]
Ign http://nova.clouds.archive.ubuntu.com trusty-updates InRelease
Hit http://nova.clouds.archive.ubuntu.com trusty Release.gpg
Get:3 http://nova.clouds.archive.ubuntu.com trusty-updates Release.gpg [933 B]
Hit http://nova.clouds.archive.ubuntu.com trusty Release
Get:4 http://nova.clouds.archive.ubuntu.com trusty-updates Release [62.0 kB]
Get:5 http://security.ubuntu.com trusty-security/main Sources [49.5 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty/main Sources
Get:6 http://security.ubuntu.com trusty-security/universe Sources [13.1 kB]
Get:7 http://security.ubuntu.com trusty-security/main amd64 Packages [153 kB]
Get:8 http://security.ubuntu.com trusty-security/universe amd64 Packages [60.5 kB]
Hit http://security.ubuntu.com trusty-security/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Sources
Hit http://security.ubuntu.com trusty-security/universe Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/main amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/universe amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en
Get:9 http://nova.clouds.archive.ubuntu.com trusty-updates/main Sources [136 kB]
Get:10 http://nova.clouds.archive.ubuntu.com trusty-updates/universe Sources [89.5 kB]
Get:11 http://nova.clouds.archive.ubuntu.com trusty-updates/main amd64 Packages [356 kB]
Get:12 http://nova.clouds.archive.ubuntu.com trusty-updates/universe amd64 Packages [217 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/universe Translation-en
Ign http://nova.clouds.archive.ubuntu.com trusty/main Translation-en_US
Ign http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en_US
Fetched 1,200 kB in 2s (411 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
     --no-install-recommends install apache2 authbind bind9 bind9utils build-essential bzr-builddeb curl daemontools debhelper dh-apport distro-info dnsutils firefox freeipmi-tools gjs ipython isc-dhcp-common libjs-raphael libjs-yui3-full libjs-yui3-min libpq-dev make pep8 postgresql pyflakes python-amqplib python-bzrlib python-celery python-convoy python-crochet python-cssselect python-curtin python-dev python-distro-info python-django python-django-piston python-django-south python-djorm-ext-pgarray python-docutils python-extras python-fixtures python-flake8 python-formencode python-hivex python-httplib2 python-jinja2 python-jsonschema python-lockfile python-lxml python-mimeparse python-mock python-netaddr python-netifaces python-nose python-oauth python-oops python-oops-amqp python-oops-datedir-repo python-oops-twi...

Revision history for this message
Julian Edwards (julian-edwards) wrote :

Thanks for pushing me to write a helper Graham, it was needed in the API tests that had become broken because of the extra validation!

Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (22.9 KiB)

The attempt to merge lp:~julian-edwards/maas/dup-boot-source-selections-part2-bug-1360280 into lp:maas failed. Below is the output from the failed tests.

Ign http://security.ubuntu.com trusty-security InRelease
Get:1 http://security.ubuntu.com trusty-security Release.gpg [933 B]
Ign http://nova.clouds.archive.ubuntu.com trusty InRelease
Get:2 http://security.ubuntu.com trusty-security Release [62.0 kB]
Ign http://nova.clouds.archive.ubuntu.com trusty-updates InRelease
Hit http://nova.clouds.archive.ubuntu.com trusty Release.gpg
Get:3 http://nova.clouds.archive.ubuntu.com trusty-updates Release.gpg [933 B]
Hit http://nova.clouds.archive.ubuntu.com trusty Release
Get:4 http://nova.clouds.archive.ubuntu.com trusty-updates Release [62.0 kB]
Get:5 http://security.ubuntu.com trusty-security/main Sources [49.5 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty/main Sources
Get:6 http://security.ubuntu.com trusty-security/universe Sources [13.1 kB]
Get:7 http://security.ubuntu.com trusty-security/main amd64 Packages [153 kB]
Get:8 http://security.ubuntu.com trusty-security/universe amd64 Packages [60.5 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Sources
Hit http://nova.clouds.archive.ubuntu.com trusty/main amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/universe amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en
Get:9 http://nova.clouds.archive.ubuntu.com trusty-updates/main Sources [136 kB]
Hit http://security.ubuntu.com trusty-security/main Translation-en
Hit http://security.ubuntu.com trusty-security/universe Translation-en
Get:10 http://nova.clouds.archive.ubuntu.com trusty-updates/universe Sources [89.5 kB]
Get:11 http://nova.clouds.archive.ubuntu.com trusty-updates/main amd64 Packages [356 kB]
Get:12 http://nova.clouds.archive.ubuntu.com trusty-updates/universe amd64 Packages [217 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/universe Translation-en
Ign http://nova.clouds.archive.ubuntu.com trusty/main Translation-en_US
Ign http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en_US
Fetched 1,200 kB in 2s (411 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
     --no-install-recommends install apache2 authbind bind9 bind9utils build-essential bzr-builddeb curl daemontools debhelper dh-apport distro-info dnsutils firefox freeipmi-tools gjs ipython isc-dhcp-common libjs-raphael libjs-yui3-full libjs-yui3-min libpq-dev make pep8 postgresql pyflakes python-amqplib python-bzrlib python-celery python-convoy python-crochet python-cssselect python-curtin python-dev python-distro-info python-django python-django-piston python-django-south python-djorm-ext-pgarray python-docutils python-extras python-fixtures python-flake8 python-formencode python-hivex python-httplib2 python-jinja2 python-jsonschema python-lockfile python-lxml python-mimeparse python-mock python-netaddr python-netifaces python-nose python-oauth python-oops python-oops-amqp python-oops-datedir-repo python-oops-twi...

Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (21.7 KiB)

The attempt to merge lp:~julian-edwards/maas/dup-boot-source-selections-part2-bug-1360280 into lp:maas failed. Below is the output from the failed tests.

Ign http://security.ubuntu.com trusty-security InRelease
Get:1 http://security.ubuntu.com trusty-security Release.gpg [933 B]
Get:2 http://security.ubuntu.com trusty-security Release [62.0 kB]
Ign http://nova.clouds.archive.ubuntu.com trusty InRelease
Ign http://nova.clouds.archive.ubuntu.com trusty-updates InRelease
Hit http://nova.clouds.archive.ubuntu.com trusty Release.gpg
Get:3 http://nova.clouds.archive.ubuntu.com trusty-updates Release.gpg [933 B]
Hit http://nova.clouds.archive.ubuntu.com trusty Release
Get:4 http://nova.clouds.archive.ubuntu.com trusty-updates Release [62.0 kB]
Get:5 http://security.ubuntu.com trusty-security/main Sources [49.5 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty/main Sources
Get:6 http://security.ubuntu.com trusty-security/universe Sources [13.1 kB]
Get:7 http://security.ubuntu.com trusty-security/main amd64 Packages [153 kB]
Get:8 http://security.ubuntu.com trusty-security/universe amd64 Packages [60.5 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Sources
Hit http://nova.clouds.archive.ubuntu.com trusty/main amd64 Packages
Hit http://security.ubuntu.com trusty-security/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/universe amd64 Packages
Hit http://nova.clouds.archive.ubuntu.com trusty/main Translation-en
Hit http://security.ubuntu.com trusty-security/universe Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en
Get:9 http://nova.clouds.archive.ubuntu.com trusty-updates/main Sources [136 kB]
Get:10 http://nova.clouds.archive.ubuntu.com trusty-updates/universe Sources [89.5 kB]
Get:11 http://nova.clouds.archive.ubuntu.com trusty-updates/main amd64 Packages [356 kB]
Get:12 http://nova.clouds.archive.ubuntu.com trusty-updates/universe amd64 Packages [217 kB]
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/main Translation-en
Hit http://nova.clouds.archive.ubuntu.com trusty-updates/universe Translation-en
Ign http://nova.clouds.archive.ubuntu.com trusty/main Translation-en_US
Ign http://nova.clouds.archive.ubuntu.com trusty/universe Translation-en_US
Fetched 1,200 kB in 2s (418 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
     --no-install-recommends install apache2 authbind bind9 bind9utils build-essential bzr-builddeb curl daemontools debhelper dh-apport distro-info dnsutils firefox freeipmi-tools gjs ipython isc-dhcp-common libjs-raphael libjs-yui3-full libjs-yui3-min libpq-dev make pep8 postgresql pyflakes python-amqplib python-bzrlib python-celery python-convoy python-crochet python-cssselect python-curtin python-dev python-distro-info python-django python-django-piston python-django-south python-djorm-ext-pgarray python-docutils python-extras python-fixtures python-flake8 python-formencode python-hivex python-httplib2 python-jinja2 python-jsonschema python-lockfile python-lxml python-mimeparse python-mock python-netaddr python-netifaces python-nose python-oauth python-oops python-oops-amqp python-oops-datedir-repo python-oops-twi...

Revision history for this message
Julian Edwards (julian-edwards) wrote :

It would help if I remembered to push my changes up.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/maasserver/api/tests/test_boot_source_selections.py'
--- src/maasserver/api/tests/test_boot_source_selections.py 2014-10-23 15:26:37 +0000
+++ src/maasserver/api/tests/test_boot_source_selections.py 2014-11-13 03:13:37 +0000
@@ -117,17 +117,20 @@
117 boot_source_selection = factory.make_BootSourceSelection()117 boot_source_selection = factory.make_BootSourceSelection()
118 new_os = factory.make_name('os')118 new_os = factory.make_name('os')
119 new_release = factory.make_name('release')119 new_release = factory.make_name('release')
120 boot_source_caches = factory.make_many_BootSourceCaches(
121 2, boot_source=boot_source_selection.boot_source, os=new_os,
122 release=new_release)
120 new_values = {123 new_values = {
121 'os': new_os,124 'os': new_os,
122 'release': new_release,125 'release': new_release,
123 'arches': [factory.make_name('arch'), factory.make_name('arch')],126 'arches': [boot_source_caches[0].arch, boot_source_caches[1].arch],
124 'subarches': [127 'subarches': [
125 factory.make_name('subarch'), factory.make_name('subarch')],128 boot_source_caches[0].subarch, boot_source_caches[1].subarch],
126 'labels': [factory.make_name('label')],129 'labels': [boot_source_caches[0].label],
127 }130 }
128 response = self.client_put(131 response = self.client_put(
129 get_boot_source_selection_uri(boot_source_selection), new_values)132 get_boot_source_selection_uri(boot_source_selection), new_values)
130 self.assertEqual(httplib.OK, response.status_code)133 self.assertEqual(httplib.OK, response.status_code, response.content)
131 boot_source_selection = reload_object(boot_source_selection)134 boot_source_selection = reload_object(boot_source_selection)
132 self.assertAttributes(boot_source_selection, new_values)135 self.assertAttributes(boot_source_selection, new_values)
133136
@@ -216,12 +219,15 @@
216 self.become_admin()219 self.become_admin()
217 boot_source_selection = factory.make_BootSourceSelection()220 boot_source_selection = factory.make_BootSourceSelection()
218 new_release = factory.make_name('release')221 new_release = factory.make_name('release')
222 boot_source_caches = factory.make_many_BootSourceCaches(
223 2, boot_source=boot_source_selection.boot_source,
224 release=new_release)
219 new_values = {225 new_values = {
220 'release': new_release,226 'release': new_release,
221 'arches': [factory.make_name('arch'), factory.make_name('arch')],227 'arches': [boot_source_caches[0].arch, boot_source_caches[1].arch],
222 'subarches': [228 'subarches': [
223 factory.make_name('subarch'), factory.make_name('subarch')],229 boot_source_caches[0].subarch, boot_source_caches[1].subarch],
224 'labels': [factory.make_name('label')],230 'labels': [boot_source_caches[0].label],
225 }231 }
226 response = self.client_put(232 response = self.client_put(
227 get_boot_source_selection_backward_uri(233 get_boot_source_selection_backward_uri(
@@ -279,12 +285,15 @@
279 self.become_admin()285 self.become_admin()
280 boot_source = factory.make_BootSource()286 boot_source = factory.make_BootSource()
281 new_release = factory.make_name('release')287 new_release = factory.make_name('release')
288 boot_source_caches = factory.make_many_BootSourceCaches(
289 2, boot_source=boot_source,
290 release=new_release)
282 params = {291 params = {
283 'release': new_release,292 'release': new_release,
284 'arches': [factory.make_name('arch'), factory.make_name('arch')],293 'arches': [boot_source_caches[0].arch, boot_source_caches[1].arch],
285 'subarches': [294 'subarches': [
286 factory.make_name('subarch'), factory.make_name('subarch')],295 boot_source_caches[0].subarch, boot_source_caches[1].subarch],
287 'labels': [factory.make_name('label')],296 'labels': [boot_source_caches[0].label],
288 }297 }
289 response = self.client.post(298 response = self.client.post(
290 reverse(299 reverse(
@@ -373,12 +382,14 @@
373 self.become_admin()382 self.become_admin()
374 boot_source = factory.make_BootSource()383 boot_source = factory.make_BootSource()
375 new_release = factory.make_name('release')384 new_release = factory.make_name('release')
385 boot_source_caches = factory.make_many_BootSourceCaches(
386 2, boot_source=boot_source, release=new_release)
376 params = {387 params = {
377 'release': new_release,388 'release': new_release,
378 'arches': [factory.make_name('arch'), factory.make_name('arch')],389 'arches': [boot_source_caches[0].arch, boot_source_caches[1].arch],
379 'subarches': [390 'subarches': [
380 factory.make_name('subarch'), factory.make_name('subarch')],391 boot_source_caches[0].subarch, boot_source_caches[1].subarch],
381 'labels': [factory.make_name('label')],392 'labels': [boot_source_caches[0].label],
382 }393 }
383 response = self.client.post(self.get_uri(boot_source), params)394 response = self.client.post(self.get_uri(boot_source), params)
384 self.assertEqual(httplib.OK, response.status_code)395 self.assertEqual(httplib.OK, response.status_code)
385396
=== modified file 'src/maasserver/forms.py'
--- src/maasserver/forms.py 2014-11-07 15:33:47 +0000
+++ src/maasserver/forms.py 2014-11-13 03:13:37 +0000
@@ -109,6 +109,7 @@
109 BootResourceFile,109 BootResourceFile,
110 BootResourceSet,110 BootResourceSet,
111 BootSource,111 BootSource,
112 BootSourceCache,
112 BootSourceSelection,113 BootSourceSelection,
113 Config,114 Config,
114 DownloadProgress,115 DownloadProgress,
@@ -2354,6 +2355,61 @@
2354 else:2355 else:
2355 self.boot_source = boot_source2356 self.boot_source = boot_source
23562357
2358 def clean(self):
2359 cleaned_data = super(BootSourceSelectionForm, self).clean()
2360
2361 # Don't filter on OS if not provided. This is to maintain
2362 # backwards compatibility for when OS didn't exist in the API.
2363 if cleaned_data['os']:
2364 cache = BootSourceCache.objects.filter(
2365 boot_source=self.boot_source, os=cleaned_data['os'],
2366 release=cleaned_data['release'])
2367 else:
2368 cache = BootSourceCache.objects.filter(
2369 boot_source=self.boot_source, release=cleaned_data['release'])
2370
2371 if not cache.exists():
2372 set_form_error(
2373 self, "os",
2374 "OS %s with release %s has no available images for download" %
2375 (cleaned_data['os'], cleaned_data['release']))
2376 return cleaned_data
2377
2378 values = cache.values_list("arch", "subarch", "label")
2379 arches, subarches, labels = zip(*values)
2380
2381 # Validate architectures.
2382 required_arches_set = set(arch for arch in cleaned_data['arches'])
2383 wildcard_arches = '*' in required_arches_set
2384 if not wildcard_arches and not required_arches_set <= set(arches):
2385 set_form_error(
2386 self, "arches",
2387 "No available images to download for %s" %
2388 cleaned_data['arches'])
2389
2390 # Validate subarchitectures.
2391 required_subarches_set = set(sa for sa in cleaned_data['subarches'])
2392 wildcard_subarches = '*' in required_subarches_set
2393 if (
2394 not wildcard_subarches and
2395 not required_subarches_set <= set(subarches)
2396 ):
2397 set_form_error(
2398 self, "subarches",
2399 "No available images to download for %s" %
2400 cleaned_data['subarches'])
2401
2402 # Validate labels.
2403 required_labels_set = set(label for label in cleaned_data['labels'])
2404 wildcard_labels = '*' in required_labels_set
2405 if not wildcard_labels and not required_labels_set <= set(labels):
2406 set_form_error(
2407 self, "labels",
2408 "No available images to download for %s" %
2409 cleaned_data['labels'])
2410
2411 return cleaned_data
2412
2357 def save(self, *args, **kwargs):2413 def save(self, *args, **kwargs):
2358 boot_source_selection = super(2414 boot_source_selection = super(
2359 BootSourceSelectionForm, self).save(commit=False)2415 BootSourceSelectionForm, self).save(commit=False)
23602416
=== modified file 'src/maasserver/testing/factory.py'
--- src/maasserver/testing/factory.py 2014-11-07 16:54:51 +0000
+++ src/maasserver/testing/factory.py 2014-11-13 03:13:37 +0000
@@ -891,6 +891,12 @@
891 boot_source=boot_source, os=os, arch=arch,891 boot_source=boot_source, os=os, arch=arch,
892 subarch=subarch, release=release, label=label)892 subarch=subarch, release=release, label=label)
893893
894 def make_many_BootSourceCaches(self, number, **kwargs):
895 caches = list()
896 for _ in range(number):
897 caches.append(self.make_BootSourceCache(**kwargs))
898 return caches
899
894 def make_BootSourceSelection(self, boot_source=None, os=None,900 def make_BootSourceSelection(self, boot_source=None, os=None,
895 release=None, arches=None, subarches=None,901 release=None, arches=None, subarches=None,
896 labels=None):902 labels=None):
897903
=== modified file 'src/maasserver/tests/test_forms_bootsourceselection.py'
--- src/maasserver/tests/test_forms_bootsourceselection.py 2014-11-11 05:15:23 +0000
+++ src/maasserver/tests/test_forms_bootsourceselection.py 2014-11-13 03:13:37 +0000
@@ -24,16 +24,47 @@
24class TestBootSourceSelectionForm(MAASServerTestCase):24class TestBootSourceSelectionForm(MAASServerTestCase):
25 """Tests for `BootSourceSelectionForm`."""25 """Tests for `BootSourceSelectionForm`."""
2626
27 def make_valid_source_selection_params(self, boot_source=None):
28 # Helper that creates a valid BootSourceCache and parameters for
29 # a BootSourceSelectionForm that will validate against the
30 # cache.
31 if boot_source is None:
32 boot_source = factory.make_BootSource()
33 arch = factory.make_name('arch')
34 arch2 = factory.make_name('arch')
35 subarch = factory.make_name('subarch')
36 subarch2 = factory.make_name('subarch')
37 label = factory.make_name('label')
38 label2 = factory.make_name('label')
39 params = {
40 'os': factory.make_name('os'),
41 'release': factory.make_name('release'),
42 'arches': [arch, arch2],
43 'subarches': [subarch, subarch2],
44 'labels': [label, label2],
45 }
46 factory.make_BootSourceCache(
47 boot_source=boot_source,
48 os=params['os'],
49 release=params['release'],
50 arch=arch,
51 subarch=subarch,
52 label=label,
53 )
54 factory.make_BootSourceCache(
55 boot_source=boot_source,
56 os=params['os'],
57 release=params['release'],
58 arch=arch2,
59 subarch=subarch2,
60 label=label2,
61 )
62 return params
63
27 def test_edits_boot_source_selection_object(self):64 def test_edits_boot_source_selection_object(self):
28 boot_source_selection = factory.make_BootSourceSelection()65 boot_source_selection = factory.make_BootSourceSelection()
29 params = {66 boot_source = boot_source_selection.boot_source
30 'os': factory.make_name('os'),67 params = self.make_valid_source_selection_params(boot_source)
31 'release': factory.make_name('release'),
32 'arches': [factory.make_name('arch'), factory.make_name('arch')],
33 'subarches': [
34 factory.make_name('subarch'), factory.make_name('subarch')],
35 'labels': [factory.make_name('label'), factory.make_name('label')],
36 }
37 form = BootSourceSelectionForm(68 form = BootSourceSelectionForm(
38 instance=boot_source_selection, data=params)69 instance=boot_source_selection, data=params)
39 self.assertTrue(form.is_valid(), form._errors)70 self.assertTrue(form.is_valid(), form._errors)
@@ -43,14 +74,7 @@
4374
44 def test_creates_boot_source_selection_object(self):75 def test_creates_boot_source_selection_object(self):
45 boot_source = factory.make_BootSource()76 boot_source = factory.make_BootSource()
46 params = {77 params = self.make_valid_source_selection_params(boot_source)
47 'os': factory.make_name('os'),
48 'release': factory.make_name('release'),
49 'arches': [factory.make_name('arch'), factory.make_name('arch')],
50 'subarches': [
51 factory.make_name('subarch'), factory.make_name('subarch')],
52 'labels': [factory.make_name('label'), factory.make_name('label')],
53 }
54 form = BootSourceSelectionForm(boot_source=boot_source, data=params)78 form = BootSourceSelectionForm(boot_source=boot_source, data=params)
55 self.assertTrue(form.is_valid(), form._errors)79 self.assertTrue(form.is_valid(), form._errors)
56 boot_source_selection = form.save()80 boot_source_selection = form.save()
@@ -58,15 +82,9 @@
5882
59 def test_cannot_create_duplicate_entry(self):83 def test_cannot_create_duplicate_entry(self):
60 boot_source = factory.make_BootSource()84 boot_source = factory.make_BootSource()
61 params = {85 params = self.make_valid_source_selection_params(boot_source)
62 'os': factory.make_name('os'),86 form = BootSourceSelectionForm(
63 'release': factory.make_name('release'),87 boot_source=boot_source, data=params)
64 'arches': [factory.make_name('arch'), factory.make_name('arch')],
65 'subarches': [
66 factory.make_name('subarch'), factory.make_name('subarch')],
67 'labels': [factory.make_name('label'), factory.make_name('label')],
68 }
69 form = BootSourceSelectionForm(boot_source=boot_source, data=params)
70 self.assertTrue(form.is_valid(), form._errors)88 self.assertTrue(form.is_valid(), form._errors)
71 form.save()89 form.save()
7290
@@ -79,3 +97,195 @@
79 form = BootSourceSelectionForm(97 form = BootSourceSelectionForm(
80 boot_source=boot_source, data=dup_params)98 boot_source=boot_source, data=dup_params)
81 self.assertRaises(ValidationError, form.save)99 self.assertRaises(ValidationError, form.save)
100
101 def test_validates_if_boot_source_cache_has_same_os_and_release(self):
102 boot_source = factory.make_BootSource()
103 boot_cache = factory.make_BootSourceCache(boot_source)
104
105 params = {
106 'os': boot_cache.os,
107 'release': boot_cache.release,
108 }
109 form = BootSourceSelectionForm(boot_source=boot_source, data=params)
110 self.assertTrue(form.is_valid(), form._errors)
111
112 def test_rejects_if_boot_source_cache_has_different_os(self):
113 boot_source = factory.make_BootSource()
114 boot_cache = factory.make_BootSourceCache(boot_source)
115
116 params = {
117 'os': factory.make_name('os'),
118 'release': boot_cache.release,
119 }
120 form = BootSourceSelectionForm(boot_source=boot_source, data=params)
121 self.assertFalse(form.is_valid())
122 self.assertEqual(
123 {
124 "os": [
125 "OS %s with release %s has no available images "
126 "for download" % (params['os'], boot_cache.release)
127 ]
128 },
129 form._errors)
130
131 def test_rejects_if_boot_source_cache_has_different_release(self):
132 boot_source = factory.make_BootSource()
133 boot_cache = factory.make_BootSourceCache(boot_source)
134
135 params = {
136 'os': boot_cache.os,
137 'release': factory.make_name('release'),
138 }
139 form = BootSourceSelectionForm(boot_source=boot_source, data=params)
140 self.assertFalse(form.is_valid())
141 self.assertEqual(
142 {
143 "os": [
144 "OS %s with release %s has no available images "
145 "for download" % (boot_cache.os, params['release'])
146 ]
147 },
148 form._errors)
149
150 def make_some_caches(self, boot_source, os, release):
151 # Make a few BootSourceCache records that the following tests can use
152 # to validate against when using BootSourceSelectionForm.
153 return factory.make_many_BootSourceCaches(
154 3, boot_source=boot_source, os=os, release=release)
155
156 def test_validates_if_boot_source_cache_has_arch(self):
157 boot_source = factory.make_BootSource()
158 os = factory.make_name('os')
159 release = factory.make_name('release')
160 boot_caches = self.make_some_caches(boot_source, os, release)
161
162 # Request arches that are in two of the cache records.
163 params = {
164 'os': os,
165 'release': release,
166 'arches': [boot_caches[0].arch, boot_caches[2].arch],
167 }
168
169 form = BootSourceSelectionForm(boot_source=boot_source, data=params)
170 self.assertTrue(form.is_valid(), form._errors)
171
172 def test_rejects_if_boot_source_cache_does_not_have_arch(self):
173 boot_source = factory.make_BootSource()
174 os = factory.make_name('os')
175 release = factory.make_name('release')
176 factory.make_BootSourceCache(
177 boot_source, os=os, release=release)
178
179 params = {
180 'os': os,
181 'release': release,
182 'arches': [factory.make_name('arch')],
183 }
184
185 form = BootSourceSelectionForm(boot_source=boot_source, data=params)
186 self.assertFalse(form.is_valid())
187 self.assertEqual(
188 {
189 "arches": [
190 "No available images to download for %s" %
191 params['arches']
192 ]
193 },
194 form._errors)
195
196 def test_validates_if_boot_source_cache_has_subarch(self):
197 boot_source = factory.make_BootSource()
198 os = factory.make_name('os')
199 release = factory.make_name('release')
200 boot_caches = self.make_some_caches(boot_source, os, release)
201
202 # Request subarches that are in two of the cache records.
203 params = {
204 'os': os,
205 'release': release,
206 'subarches': [boot_caches[0].subarch, boot_caches[2].subarch],
207 }
208
209 form = BootSourceSelectionForm(boot_source=boot_source, data=params)
210 self.assertTrue(form.is_valid(), form._errors)
211
212 def test_rejects_if_boot_source_cache_does_not_have_subarch(self):
213 boot_source = factory.make_BootSource()
214 os = factory.make_name('os')
215 release = factory.make_name('release')
216 factory.make_BootSourceCache(
217 boot_source, os=os, release=release)
218
219 params = {
220 'os': os,
221 'release': release,
222 'subarches': [factory.make_name('subarch')],
223 }
224
225 form = BootSourceSelectionForm(boot_source=boot_source, data=params)
226 self.assertFalse(form.is_valid())
227 self.assertEqual(
228 {
229 "subarches": [
230 "No available images to download for %s" %
231 params['subarches']
232 ]
233 },
234 form._errors)
235
236 def test_validates_if_boot_source_cache_has_label(self):
237 boot_source = factory.make_BootSource()
238 os = factory.make_name('os')
239 release = factory.make_name('release')
240 boot_caches = self.make_some_caches(boot_source, os, release)
241
242 # Request labels that are in two of the cache records.
243 params = {
244 'os': os,
245 'release': release,
246 'labels': [boot_caches[0].label, boot_caches[2].label],
247 }
248
249 form = BootSourceSelectionForm(boot_source=boot_source, data=params)
250 self.assertTrue(form.is_valid(), form._errors)
251
252 def test_rejects_if_boot_source_cache_does_not_have_label(self):
253 boot_source = factory.make_BootSource()
254 os = factory.make_name('os')
255 release = factory.make_name('release')
256 factory.make_BootSourceCache(
257 boot_source, os=os, release=release)
258
259 params = {
260 'os': os,
261 'release': release,
262 'labels': [factory.make_name('label')],
263 }
264
265 form = BootSourceSelectionForm(boot_source=boot_source, data=params)
266 self.assertFalse(form.is_valid())
267 self.assertEqual(
268 {
269 "labels": [
270 "No available images to download for %s" %
271 params['labels']
272 ]
273 },
274 form._errors)
275
276 def test_star_values_in_request_validate_against_any_cache(self):
277 boot_source = factory.make_BootSource()
278 os = factory.make_name('os')
279 release = factory.make_name('release')
280 factory.make_BootSourceCache(
281 boot_source, os=os, release=release)
282 params = {
283 'os': os,
284 'release': release,
285 'arches': ['*'],
286 'subarches': ['*'],
287 'labels': ['*'],
288 }
289
290 form = BootSourceSelectionForm(boot_source=boot_source, data=params)
291 self.assertTrue(form.is_valid(), form._errors)