Merge ~dbungert/curtin:py35-fixes into curtin:release/23.1

Proposed by Dan Bungert
Status: Merged
Merged at revision: 6d27dc64d9a53694848d52e5c14b615453b6a388
Proposed branch: ~dbungert/curtin:py35-fixes
Merge into: curtin:release/23.1
Prerequisite: ~dbungert/curtin:series-fixes
Diff against target: 646 lines (+127/-96)
10 files modified
curtin/commands/__init__.py (+1/-0)
curtin/commands/block_meta_v2.py (+11/-15)
curtin/commands/install.py (+9/-9)
tests/integration/test_block_meta.py (+44/-30)
tests/integration/webserv.py (+16/-4)
tests/unittests/test_commands_block_meta.py (+23/-22)
tests/unittests/test_curthooks.py (+5/-3)
tests/unittests/test_distro.py (+6/-6)
tests/unittests/test_storage_config.py (+9/-4)
tests/unittests/test_util.py (+3/-3)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Michael Hudson-Doyle Approve
Review via email: mp+443616@code.launchpad.net

This proposal supersedes a proposal from 2023-05-25.

Commit message

Several fixes for compatibility with python 3.5

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

Thank you for keeping this stuff off master :-)

review: Approve
Revision history for this message
Dan Bungert (dbungert) :
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Hudson-Doyle (mwhudson) :
Revision history for this message
Olivier Gayot (ogayot) :
Revision history for this message
Olivier Gayot (ogayot) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/curtin/commands/__init__.py b/curtin/commands/__init__.py
2index 51b91c6..2d784db 100644
3--- a/curtin/commands/__init__.py
4+++ b/curtin/commands/__init__.py
5@@ -1,5 +1,6 @@
6 # This file is part of curtin. See LICENSE file for copyright and license info.
7
8+
9 class MutuallyExclusiveGroup:
10 def __init__(self, entries) -> None:
11 self.entries = entries
12diff --git a/curtin/commands/block_meta_v2.py b/curtin/commands/block_meta_v2.py
13index ca82522..0dfc812 100644
14--- a/curtin/commands/block_meta_v2.py
15+++ b/curtin/commands/block_meta_v2.py
16@@ -1,10 +1,6 @@
17 # This file is part of curtin. See LICENSE file for copyright and license info.
18
19 import os
20-from typing import (
21- List,
22- Optional,
23- )
24
25 import attr
26
27@@ -26,21 +22,21 @@ from curtin.storage_config import (
28 from curtin.udev import udevadm_settle
29
30
31-@attr.s(auto_attribs=True)
32+@attr.s()
33 class PartTableEntry:
34 # The order listed here matches the order sfdisk represents these fields
35 # when using the --dump argument.
36- number: int
37- start: int
38- size: int
39- type: str
40- uuid: Optional[str]
41+ number = attr.ib(default=None)
42+ start = attr.ib(default=None)
43+ size = attr.ib(default=None)
44+ type = attr.ib(default=None)
45+ uuid = attr.ib(default=None)
46 # name here is the sfdisk term - quoted descriptive text of the partition -
47 # not to be confused with what make_dname() does.
48 # Offered in the partition command as 'partition_name'.
49- name: Optional[str]
50- attrs: Optional[List[str]]
51- bootable: bool = False
52+ name = attr.ib(default=None)
53+ attrs = attr.ib(default=None)
54+ bootable = attr.ib(default=False)
55
56 def render(self):
57 r = '{}: '.format(self.number)
58@@ -128,8 +124,8 @@ class SFDiskPartTable:
59 self._sector_bytes = sector_bytes
60 if ONE_MIB_BYTES % sector_bytes != 0:
61 raise Exception(
62- f"sector_bytes {sector_bytes} does not divide 1MiB, cannot "
63- "continue!")
64+ "sector_bytes {} does not divide 1MiB, cannot "
65+ "continue!".format(sector_bytes))
66 self.one_mib_sectors = ONE_MIB_BYTES // sector_bytes
67
68 def bytes2sectors(self, amount):
69diff --git a/curtin/commands/install.py b/curtin/commands/install.py
70index 7ccad87..bd1016a 100644
71--- a/curtin/commands/install.py
72+++ b/curtin/commands/install.py
73@@ -112,16 +112,16 @@ def writeline(fname, output):
74 pass
75
76
77-@attr.s(auto_attribs=True)
78+@attr.s()
79 class WorkingDir:
80- target: str
81- top: str
82- scratch: str
83- interfaces: str
84- netconf: str
85- netstate: str
86- fstab: str
87- config_file: str
88+ target = attr.ib()
89+ top = attr.ib()
90+ scratch = attr.ib()
91+ interfaces = attr.ib()
92+ netconf = attr.ib()
93+ netstate = attr.ib()
94+ fstab = attr.ib()
95+ config_file = attr.ib()
96
97 @classmethod
98 def import_existing(cls, config):
99diff --git a/tests/integration/test_block_meta.py b/tests/integration/test_block_meta.py
100index 87f8802..d7628b5 100644
101--- a/tests/integration/test_block_meta.py
102+++ b/tests/integration/test_block_meta.py
103@@ -1,17 +1,15 @@
104 # This file is part of curtin. See LICENSE file for copyright and license info.
105
106-import dataclasses
107-from dataclasses import dataclass
108 import contextlib
109 import json
110 import os
111-from parameterized import parameterized
112 import re
113 import sys
114-from typing import Optional
115 from unittest import skipIf
116 import yaml
117
118+import attr
119+
120 from curtin import block, compat, distro, log, udev, util
121 from curtin.commands.block_meta import _get_volume_fstype
122 from curtin.commands.block_meta_v2 import ONE_MIB_BYTES
123@@ -38,22 +36,25 @@ def loop_dev(image, sector_size=512):
124 util.subp(['losetup', '--detach', dev])
125
126
127-@dataclass(order=True)
128+@attr.s(init=True, cmp=False)
129 class PartData:
130- number: Optional[int] = None
131- offset: Optional[int] = None
132- size: Optional[int] = None
133- boot: Optional[bool] = None
134- partition_type: Optional[str] = None
135+ number = attr.ib(default=None)
136+ offset = attr.ib(default=None)
137+ size = attr.ib(default=None)
138+ boot = attr.ib(default=None)
139+ partition_type = attr.ib(default=None)
140
141 # test cases may initialize the values they care about
142 # test utilities shall initialize all fields
143 def assertFieldsAreNotNone(self):
144- for field in dataclasses.fields(self):
145+ for field in attr.fields(self.__class__):
146 assert getattr(self, field.name) is not None
147
148+ def __lt__(self, other):
149+ return self.number < other.number
150+
151 def __eq__(self, other):
152- for field in dataclasses.fields(self):
153+ for field in attr.fields(self.__class__):
154 myval = getattr(self, field.name)
155 otherval = getattr(other, field.name)
156 if myval is not None and otherval is not None \
157@@ -64,7 +65,7 @@ class PartData:
158
159 def _get_ext_size(dev, part_action):
160 num = part_action['number']
161- cmd = ['dumpe2fs', '-h', f'{dev}p{num}']
162+ cmd = ['dumpe2fs', '-h', '{}p{}'.format(dev, num)]
163 out = util.subp(cmd, capture=True)[0]
164 for line in out.splitlines():
165 if line.startswith('Block count'):
166@@ -79,7 +80,7 @@ def _get_ntfs_size(dev, part_action):
167 cmd = ['ntfsresize',
168 '--no-action',
169 '--force', # needed post-resize, which otherwise demands a CHKDSK
170- '--info', f'{dev}p{num}']
171+ '--info', '{}p{}'.format(dev, num)]
172 out = util.subp(cmd, capture=True)[0]
173 # Sample input:
174 # Current volume size: 41939456 bytes (42 MB)
175@@ -101,7 +102,7 @@ _get_fs_sizers = {
176
177 def _get_filesystem_size(dev, part_action, fstype='ext4'):
178 if fstype not in _get_fs_sizers.keys():
179- raise Exception(f'_get_filesystem_size: no support for {fstype}')
180+ raise Exception('_get_filesystem_size: no support for %s' % fstype)
181 return _get_fs_sizers[fstype](dev, part_action)
182
183
184@@ -124,7 +125,7 @@ def summarize_partitions(dev):
185 (unused, s_number, s_offset, s_size) = [
186 entry for entry in sysfs_data
187 if '/dev/' + entry[0] == node][0]
188- assert node.startswith(f'{dev}p')
189+ assert node.startswith(dev + 'p')
190 number = int(node[len(dev) + 1:])
191 ptype = part['type']
192 offset = part['start'] * sectorsize
193@@ -206,13 +207,13 @@ class TestBlockMeta(IntegrationTestCase):
194 def mount(self, dev, partition_cfg):
195 mnt_point = self.tmp_dir()
196 num = partition_cfg['number']
197- with util.mount(f'{dev}p{num}', mnt_point):
198+ with util.mount('{}p{}'.format(dev, num), mnt_point):
199 yield mnt_point
200
201 @contextlib.contextmanager
202 def open_file_on_part(self, dev, part_action, mode):
203 with self.mount(dev, part_action) as mnt_point:
204- with open(f'{mnt_point}/data.txt', mode) as fp:
205+ with open(mnt_point + '/data.txt', mode) as fp:
206 yield fp
207
208 def create_data(self, dev, part_action):
209@@ -232,7 +233,7 @@ class TestBlockMeta(IntegrationTestCase):
210 tolerance = 512 * 10
211 actual_fssize = _get_filesystem_size(dev, part_action, fstype)
212 diff = expected - actual_fssize
213- self.assertTrue(0 <= diff <= tolerance, f'difference of {diff}')
214+ self.assertTrue(0 <= diff <= tolerance, 'difference of ' + str(diff))
215
216 def run_bm(self, config, *args, **kwargs):
217 config_path = self.tmp_path('config.yaml')
218@@ -602,7 +603,7 @@ class TestBlockMeta(IntegrationTestCase):
219 }
220 with loop_dev(img) as dev:
221 try:
222- self.run_bm(curtin_cfg, f'--devices={dev}', env=cmd_env)
223+ self.run_bm(curtin_cfg, '--devices=' + dev, env=cmd_env)
224 finally:
225 util.subp(['umount', mnt_point])
226 udev.udevadm_settle()
227@@ -622,7 +623,7 @@ class TestBlockMeta(IntegrationTestCase):
228 fstype=fstype)
229 self.run_bm(config.render())
230 with loop_dev(img) as dev:
231- self.assertEqual(fstype, _get_volume_fstype(f'{dev}p1'))
232+ self.assertEqual(fstype, _get_volume_fstype(dev + 'p1'))
233 self.create_data(dev, p1)
234 self.assertEqual(
235 summarize_partitions(dev), [
236@@ -651,7 +652,7 @@ class TestBlockMeta(IntegrationTestCase):
237 p1['size'] = size
238 self.run_bm(config.render())
239 with loop_dev(img) as dev:
240- self.assertEqual('ntfs', _get_volume_fstype(f'{dev}p1'))
241+ self.assertEqual('ntfs', _get_volume_fstype(dev + 'p1'))
242 self.create_data(dev, p1)
243 self.assertEqual(
244 summarize_partitions(dev), [
245@@ -959,11 +960,11 @@ class TestBlockMeta(IntegrationTestCase):
246 with self.mount(dev, p1) as mnt_point:
247 # Attempt to create files across the partition with gaps
248 for i in range(1, 41):
249- with open(f'{mnt_point}/{str(i)}', 'wb') as fp:
250+ with open('{}/{}'.format(mnt_point, i), 'wb') as fp:
251 fp.write(bytes([i]) * (2 << 20))
252 for i in range(1, 41):
253 if i % 5 != 0:
254- os.remove(f'{mnt_point}/{str(i)}')
255+ os.remove('{}/{}'.format(mnt_point, i))
256
257 config = StorageConfigBuilder(version=2)
258 config.add_image(path=img, size='100M', ptable='gpt')
259@@ -981,7 +982,7 @@ class TestBlockMeta(IntegrationTestCase):
260 ])
261 with self.mount(dev, p1) as mnt_point:
262 for i in range(5, 41, 5):
263- with open(f'{mnt_point}/{i}', 'rb') as fp:
264+ with open('{}/{}'.format(mnt_point, i), 'rb') as fp:
265 self.assertEqual(bytes([i]) * (2 << 20), fp.read())
266
267 def test_parttype_dos(self):
268@@ -1043,8 +1044,7 @@ class TestBlockMeta(IntegrationTestCase):
269 PartData(number=4, offset=80 << 20, size=19 << 20,
270 partition_type=winre))
271
272- @parameterized.expand([('msdos',), ('gpt',)])
273- def test_disk_label_id_persistent(self, ptable):
274+ def _test_disk_label_id_persistent(self, ptable):
275 # when the disk is preserved, the disk label id shall also be preserved
276 self.img = self.tmp_path('image.img')
277 config = StorageConfigBuilder(version=2)
278@@ -1063,6 +1063,12 @@ class TestBlockMeta(IntegrationTestCase):
279 with loop_dev(self.img) as dev:
280 self.assertEqual(orig_label_id, _get_disk_label_id(dev))
281
282+ def test_disk_label_id_persistent_msdos(self):
283+ self._test_disk_label_id_persistent('msdos')
284+
285+ def test_disk_label_id_persistent_gpt(self):
286+ self._test_disk_label_id_persistent('gpt')
287+
288 def test_gpt_uuid_persistent(self):
289 # A persistent partition with an unspecified uuid shall keep the uuid
290 self.img = self.tmp_path('image.img')
291@@ -1099,7 +1105,7 @@ class TestBlockMeta(IntegrationTestCase):
292 actual_name = sfdisk_info['partitions'][0]['name']
293 self.assertEqual(name, actual_name)
294
295- def test_gpt_name_persistent(self):
296+ def _test_gpt_name_persistent(self, title, name):
297 self.img = self.tmp_path('image.img')
298 name = self.random_string()
299 config = StorageConfigBuilder(version=2)
300@@ -1123,6 +1129,9 @@ class TestBlockMeta(IntegrationTestCase):
301 actual_name = sfdisk_info['partitions'][0]['name']
302 self.assertEqual(name, actual_name)
303
304+ def test_gpt_name_persistent_random(self):
305+ self._test_gpt_name_persistent('random', CiTestCase.random_string())
306+
307 def test_gpt_set_single_attr(self):
308 self.img = self.tmp_path('image.img')
309 config = StorageConfigBuilder(version=2)
310@@ -1267,8 +1276,7 @@ table-length: 256'''.encode()
311 self.assertPartitions(
312 PartData(number=1, offset=1 << 20, size=1 << 20))
313
314- @parameterized.expand(((1,), (2,)))
315- def test_swap(self, sv):
316+ def _test_swap(self, sv):
317 self.img = self.tmp_path('image.img')
318 config = StorageConfigBuilder(version=sv)
319 config.add_image(path=self.img, create=True, size='20M',
320@@ -1279,3 +1287,9 @@ table-length: 256'''.encode()
321 self.assertPartitions(
322 PartData(number=1, offset=1 << 20, size=1 << 20, boot=False,
323 partition_type='82'))
324+
325+ def test_swap_sv1(self):
326+ self._test_swap(1)
327+
328+ def test_swap_sv2(self):
329+ self._test_swap(2)
330diff --git a/tests/integration/webserv.py b/tests/integration/webserv.py
331index f4ce4e4..de30e04 100644
332--- a/tests/integration/webserv.py
333+++ b/tests/integration/webserv.py
334@@ -1,8 +1,10 @@
335 # This file is part of curtin. See LICENSE file for copyright and license info.
336
337-import threading
338-import socketserver
339 from http.server import SimpleHTTPRequestHandler
340+import socketserver
341+import threading
342+import os
343+
344 from tests.vmtests.image_sync import IMAGE_DIR
345
346
347@@ -12,7 +14,17 @@ class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
348
349 class ImageHTTPRequestHandler(SimpleHTTPRequestHandler):
350 def __init__(self, *args, **kwargs):
351- super().__init__(*args, directory=IMAGE_DIR, **kwargs)
352+ try:
353+ super().__init__(*args, directory=IMAGE_DIR, **kwargs)
354+ except TypeError:
355+ # SimpleHTTPRequestHandler in python < 3.7 doesn't take a directory
356+ # arg, fake it.
357+ curdir = os.getcwd()
358+ os.chdir(IMAGE_DIR)
359+ try:
360+ super().__init__(*args, **kwargs)
361+ finally:
362+ os.chdir(curdir)
363
364
365 class ImageServer:
366@@ -50,4 +62,4 @@ class ImageServer:
367 if self.server is not None:
368 ip, port = self.server.server_address
369
370- return f"http://{ip}:{port}"
371+ return "http://{}:{}".format(ip, port)
372diff --git a/tests/unittests/test_commands_block_meta.py b/tests/unittests/test_commands_block_meta.py
373index dc03359..25d92ab 100644
374--- a/tests/unittests/test_commands_block_meta.py
375+++ b/tests/unittests/test_commands_block_meta.py
376@@ -3038,10 +3038,10 @@ label: gpt
377 table = block_meta_v2.GPTPartTable(512)
378 table.add(dict(number=1, offset=1 << 20, size=9 << 20,
379 flag='boot', partition_type=ptype))
380- expected = f'''\
381+ expected = '''\
382 label: gpt
383
384-1: start=2048 size=18432 type={ptype}'''
385+1: start=2048 size=18432 type={}'''.format(ptype)
386 self.assertEqual(expected, table.render())
387
388 def test_gpt_name(self):
389@@ -3050,10 +3050,10 @@ label: gpt
390 table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
391 partition_name=name))
392 type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
393- expected = f'''\
394+ expected = '''\
395 label: gpt
396
397-1: start=2048 size=18432 type={type_id} name="{name}"'''
398+1: start=2048 size=18432 type={} name="{}"'''.format(type_id, name)
399 self.assertEqual(expected, table.render())
400
401 def test_gpt_name_spaces(self):
402@@ -3062,10 +3062,10 @@ label: gpt
403 table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
404 partition_name=name))
405 type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
406- expected = f'''\
407+ expected = '''\
408 label: gpt
409
410-1: start=2048 size=18432 type={type_id} name="{name}"'''
411+1: start=2048 size=18432 type={} name="{}"'''.format(type_id, name)
412 self.assertEqual(expected, table.render())
413
414 def test_gpt_attrs_none(self):
415@@ -3073,10 +3073,10 @@ label: gpt
416 table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
417 attrs=None))
418 type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
419- expected = f'''\
420+ expected = '''\
421 label: gpt
422
423-1: start=2048 size=18432 type={type_id}'''
424+1: start=2048 size=18432 type={}'''.format(type_id)
425 self.assertEqual(expected, table.render())
426
427 def test_gpt_attrs_empty(self):
428@@ -3084,10 +3084,10 @@ label: gpt
429 table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
430 attrs=[]))
431 type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
432- expected = f'''\
433+ expected = '''\
434 label: gpt
435
436-1: start=2048 size=18432 type={type_id}'''
437+1: start=2048 size=18432 type={}'''.format(type_id)
438 self.assertEqual(expected, table.render())
439
440 def test_gpt_attrs_required(self):
441@@ -3095,10 +3095,10 @@ label: gpt
442 table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
443 attrs=['RequiredPartition']))
444 type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
445- expected = f'''\
446+ expected = '''\
447 label: gpt
448
449-1: start=2048 size=18432 type={type_id} attrs="RequiredPartition"'''
450+1: start=2048 size=18432 type={} attrs="RequiredPartition"'''.format(type_id)
451 self.assertEqual(expected, table.render())
452
453 def test_gpt_attrs_bit(self):
454@@ -3106,10 +3106,10 @@ label: gpt
455 table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
456 attrs=['GUID:51']))
457 type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
458- expected = f'''\
459+ expected = '''\
460 label: gpt
461
462-1: start=2048 size=18432 type={type_id} attrs="GUID:51"'''
463+1: start=2048 size=18432 type={} attrs="GUID:51"'''.format(type_id)
464 self.assertEqual(expected, table.render())
465
466 def test_gpt_attrs_multi(self):
467@@ -3117,10 +3117,11 @@ label: gpt
468 table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
469 attrs=['RequiredPartition', 'GUID:51']))
470 type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
471- expected = f'''\
472+ attrs = 'RequiredPartition GUID:51'
473+ expected = '''\
474 label: gpt
475
476-1: start=2048 size=18432 type={type_id} attrs="RequiredPartition GUID:51"'''
477+1: start=2048 size=18432 type={} attrs="{}"'''.format(type_id, attrs)
478 self.assertEqual(expected, table.render())
479
480 def test_dos_basic(self):
481@@ -3144,10 +3145,10 @@ label: dos
482 table = block_meta_v2.DOSPartTable(512)
483 table.add(dict(number=1, offset=1 << 20, size=9 << 20,
484 flag='boot', partition_type=ptype))
485- expected = f'''\
486+ expected = '''\
487 label: dos
488
489-1: start=2048 size=18432 type={ptype} bootable'''
490+1: start=2048 size=18432 type={} bootable'''.format(ptype)
491 self.assertEqual(expected, table.render())
492
493 def test_preserve_labelid_gpt(self):
494@@ -3243,20 +3244,20 @@ label: dos
495 number=1, start=2, size=3, type='04', bootable=True,
496 uuid=uuid, name='name',
497 attrs=['stuff', 'things'])
498- expected = f'1: start=2 size=3 type=04 uuid={uuid} ' + \
499+ expected = '1: start=2 size=3 type=04 uuid={} '.format(uuid) + \
500 'name="name" attrs="stuff things" bootable'
501 self.assertEqual(expected, pte.render())
502
503 def test_gpt_entry_preserve(self):
504 uuid = str(random_uuid())
505 name = self.random_string()
506- attrs = f'{self.random_string()} {self.random_string()}'
507+ attrs = '{} {}'.format(self.random_string(), self.random_string())
508 pte = block_meta_v2.PartTableEntry(
509 number=1, start=2, size=3, type='04', bootable=False,
510 uuid=None, name=None, attrs=None)
511 pte.preserve({'uuid': uuid, 'name': name, 'attrs': attrs})
512- expected = f'1: start=2 size=3 type=04 uuid={uuid} ' + \
513- f'name="{name}" attrs="{attrs}"'
514+ expected = '1: start=2 size=3 type=04 uuid={} '.format(uuid) + \
515+ 'name="{}" attrs="{}"'.format(name, attrs)
516 self.assertEqual(expected, pte.render())
517
518 def test_v2_dos_is_logical(self):
519diff --git a/tests/unittests/test_curthooks.py b/tests/unittests/test_curthooks.py
520index 9e4fa87..a96f5fd 100644
521--- a/tests/unittests/test_curthooks.py
522+++ b/tests/unittests/test_curthooks.py
523@@ -2286,19 +2286,21 @@ class TestDoAptConfig(CiTestCase):
524 def test_apt_config_dict(self):
525 with patch(self.handle_apt_sym) as m_handle_apt:
526 curthooks.do_apt_config({"apt": {}}, target="/")
527- m_handle_apt.assert_called()
528+ m_handle_apt.assert_any_call({}, '/')
529
530 def test_with_apt_config(self):
531 with patch(self.handle_apt_sym) as m_handle_apt:
532 curthooks.do_apt_config(
533 {"apt": {"proxy": {"http_proxy": "http://proxy:3128"}}},
534 target="/")
535- m_handle_apt.assert_called_once()
536+ m_handle_apt.assert_any_call(
537+ {'proxy': {'http_proxy': 'http://proxy:3128'}}, '/')
538
539 def test_with_debconf_selections(self):
540 # debconf_selections are translated to apt config
541 with patch(self.handle_apt_sym) as m_handle_apt:
542 curthooks.do_apt_config({"debconf_selections": "foo"}, target="/")
543- m_handle_apt.assert_called_once()
544+ m_handle_apt.assert_any_call({'debconf_selections': 'foo'}, '/')
545+
546
547 # vi: ts=4 expandtab syntax=python
548diff --git a/tests/unittests/test_distro.py b/tests/unittests/test_distro.py
549index 5743475..516a422 100644
550--- a/tests/unittests/test_distro.py
551+++ b/tests/unittests/test_distro.py
552@@ -311,7 +311,7 @@ class TestAptInstall(CiTestCase):
553 ]
554
555 distro.run_apt_command('install', ['foobar', 'wark'])
556- m_apt_update.assert_called_once()
557+ self.assertEqual(1, m_apt_update.call_count)
558 m_apt_install.assert_has_calls(expected_calls)
559 m_subp.assert_called_once_with(['apt-get', 'clean'], target='/')
560
561@@ -321,7 +321,7 @@ class TestAptInstall(CiTestCase):
562
563 # no clean option
564 distro.run_apt_command('install', ['foobar', 'wark'], clean=False)
565- m_apt_update.assert_called_once()
566+ self.assertEqual(1, m_apt_update.call_count)
567 m_subp.assert_has_calls(expected_calls[:-1])
568
569 @mock.patch.object(util.ChrootableTarget, "__enter__", new=lambda a: a)
570@@ -334,11 +334,11 @@ class TestAptInstall(CiTestCase):
571 ]
572
573 expected_calls = [
574- mock.call(cmd_prefix + ['install', '--download-only']
575- + ['foobar', 'wark'],
576+ mock.call(cmd_prefix +
577+ ['install', '--download-only'] +
578+ ['foobar', 'wark'],
579 env=None, target='/', retries=None),
580- mock.call(cmd_prefix + ['install']
581- + ['foobar', 'wark'],
582+ mock.call(cmd_prefix + ['install', 'foobar', 'wark'],
583 env=None, target='/'),
584 ]
585
586diff --git a/tests/unittests/test_storage_config.py b/tests/unittests/test_storage_config.py
587index a538ece..adab329 100644
588--- a/tests/unittests/test_storage_config.py
589+++ b/tests/unittests/test_storage_config.py
590@@ -1109,9 +1109,11 @@ class TestExtractStorageConfig(CiTestCase):
591 config = extracted['storage']['config']
592 disks = [cfg for cfg in config if cfg['type'] == 'disk']
593 expected_count = len([
594- 1 for bd_name, bd_data in self.probe_data['blockdev'].items()
595- if bd_data.get('DM_UUID', '').startswith('mpath-')
596- or bd_name.startswith('/dev/dasd') and bd_data['DEVTYPE'] == 'disk'
597+ 1
598+ for bd_name, bd_data in self.probe_data['blockdev'].items()
599+ if bd_data.get('DM_UUID', '').startswith('mpath-') or
600+ bd_name.startswith('/dev/dasd') and
601+ bd_data['DEVTYPE'] == 'disk'
602 ])
603 self.assertEqual(expected_count, len(disks))
604
605@@ -1170,7 +1172,10 @@ class TestSelectConfigs(CiTestCase):
606 id1 = {'a': 1, 'c': 3}
607 sc = {'id0': id0, 'id1': id1}
608
609- self.assertEqual([id0, id1], select_configs(sc, a=1))
610+ actual = select_configs(sc, a=1)
611+ self.assertEqual(2, len(actual))
612+ self.assertIn(id0, actual)
613+ self.assertIn(id1, actual)
614
615 def test_not_found(self):
616 id0 = {'a': 1, 'b': 2}
617diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
618index 6a0c951..306e963 100644
619--- a/tests/unittests/test_util.py
620+++ b/tests/unittests/test_util.py
621@@ -1179,7 +1179,7 @@ class TestNotExclusiveRetry(CiTestCase):
622 f = mock.Mock(side_effect=[util.NotExclusiveError, 'success'])
623
624 self.assertEqual(util.not_exclusive_retry(f, 1, 2, 3), 'success')
625- sleep.assert_called_once()
626+ self.assertEqual(1, sleep.call_count)
627
628 @mock.patch('curtin.util.time.sleep')
629 def test_not_exclusive_retry_not_exclusive_twice(self, sleep):
630@@ -1187,7 +1187,7 @@ class TestNotExclusiveRetry(CiTestCase):
631
632 with self.assertRaises(util.NotExclusiveError):
633 util.not_exclusive_retry(f, 1, 2, 3)
634- sleep.assert_called_once()
635+ self.assertEqual(1, sleep.call_count)
636
637 @mock.patch('curtin.util.time.sleep')
638 def test_not_exclusive_retry_not_exclusive_once_then_error(self, sleep):
639@@ -1195,6 +1195,6 @@ class TestNotExclusiveRetry(CiTestCase):
640
641 with self.assertRaises(OSError):
642 util.not_exclusive_retry(f, 1, 2, 3)
643- sleep.assert_called_once()
644+ self.assertEqual(1, sleep.call_count)
645
646 # vi: ts=4 expandtab syntax=python

Subscribers

People subscribed via source and target branches