Merge ~dbungert/curtin:py35-fixes into curtin:release/23.1
- Git
- lp:~dbungert/curtin
- py35-fixes
- Merge into release/23.1
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) |
Related bugs: |
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
Description of the change
Server Team CI bot (server-team-bot) wrote : Posted in a previous version of this proposal | # |
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:17f2a1c6bec
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Michael Hudson-Doyle (mwhudson) wrote : | # |
Thank you for keeping this stuff off master :-)
Dan Bungert (dbungert) : | # |
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:6d27dc64d9a
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Michael Hudson-Doyle (mwhudson) : | # |
Olivier Gayot (ogayot) : | # |
Olivier Gayot (ogayot) : | # |
Preview Diff
1 | diff --git a/curtin/commands/__init__.py b/curtin/commands/__init__.py |
2 | index 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 |
12 | diff --git a/curtin/commands/block_meta_v2.py b/curtin/commands/block_meta_v2.py |
13 | index 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): |
69 | diff --git a/curtin/commands/install.py b/curtin/commands/install.py |
70 | index 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): |
99 | diff --git a/tests/integration/test_block_meta.py b/tests/integration/test_block_meta.py |
100 | index 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) |
330 | diff --git a/tests/integration/webserv.py b/tests/integration/webserv.py |
331 | index 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) |
372 | diff --git a/tests/unittests/test_commands_block_meta.py b/tests/unittests/test_commands_block_meta.py |
373 | index 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): |
519 | diff --git a/tests/unittests/test_curthooks.py b/tests/unittests/test_curthooks.py |
520 | index 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 |
548 | diff --git a/tests/unittests/test_distro.py b/tests/unittests/test_distro.py |
549 | index 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 | |
586 | diff --git a/tests/unittests/test_storage_config.py b/tests/unittests/test_storage_config.py |
587 | index 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} |
617 | diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py |
618 | index 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 |
FAILED: Continuous integration, rev:bd088e4abb1 1c676c5a8b0fa8f b18b00d7e64062 /jenkins. canonical. com/server- team/job/ curtin- ci/126/ /jenkins. canonical. com/server- team/job/ curtin- ci/nodes= metal-amd64/ 126/ /jenkins. canonical. com/server- team/job/ curtin- ci/nodes= metal-arm64/ 126/ /jenkins. canonical. com/server- team/job/ curtin- ci/nodes= metal-ppc64el/ 126/ /jenkins. canonical. com/server- team/job/ curtin- ci/nodes= metal-s390x/ 126/
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/server- team/job/ curtin- ci/126/ /rebuild
https:/