← Back to team overview

curtin-dev team mailing list archive

[Merge] ~dbungert/curtin:py35-fixes into curtin:master

 

Dan Bungert has proposed merging ~dbungert/curtin:py35-fixes into curtin:master with ~dbungert/curtin:series-fixes as a prerequisite.

Commit message:
Several fixes for compatibility with python 3.5

Requested reviews:
  curtin developers (curtin-dev)

For more details, see:
https://code.launchpad.net/~dbungert/curtin/+git/curtin/+merge/443614
-- 
Your team curtin developers is requested to review the proposed merge of ~dbungert/curtin:py35-fixes into curtin:master.
diff --git a/curtin/commands/block_meta_v2.py b/curtin/commands/block_meta_v2.py
index 570da83..ca0c94e 100644
--- a/curtin/commands/block_meta_v2.py
+++ b/curtin/commands/block_meta_v2.py
@@ -1,10 +1,6 @@
 # This file is part of curtin. See LICENSE file for copyright and license info.
 
 import os
-from typing import (
-    List,
-    Optional,
-    )
 
 import attr
 
@@ -26,7 +22,11 @@ from curtin.storage_config import (
 from curtin.udev import udevadm_settle
 
 
+<<<<<<< curtin/commands/block_meta_v2.py
 def to_utf8_hex_notation(string: str) -> str:
+=======
+def to_utf8_hex_notation(string):
+>>>>>>> curtin/commands/block_meta_v2.py
     ''' Convert a string into a valid ASCII string where all characters outside
     the alphanumerical range (according to bytes.isalnum()) are translated to
     their corresponding \\x notation. E.g.:
@@ -39,25 +39,34 @@ def to_utf8_hex_notation(string: str) -> str:
         if bytes([c]).isalnum():
             result += bytes([c]).decode()
         else:
+<<<<<<< curtin/commands/block_meta_v2.py
             result += f'\\x{c:02x}'
     return result
 
 
 @attr.s(auto_attribs=True)
+=======
+            result += '\\x{:02x}'.format(c)
+
+    return result
+
+
+@attr.s()
+>>>>>>> curtin/commands/block_meta_v2.py
 class PartTableEntry:
     # The order listed here matches the order sfdisk represents these fields
     # when using the --dump argument.
-    number: int
-    start: int
-    size: int
-    type: str
-    uuid: Optional[str]
+    number = attr.ib(default=None)
+    start = attr.ib(default=None)
+    size = attr.ib(default=None)
+    type = attr.ib(default=None)
+    uuid = attr.ib(default=None)
     # name here is the sfdisk term - quoted descriptive text of the partition -
     # not to be confused with what make_dname() does.
     # Offered in the partition command as 'partition_name'.
-    name: Optional[str]
-    attrs: Optional[List[str]]
-    bootable: bool = False
+    name = attr.ib(default=None)
+    attrs = attr.ib(default=None)
+    bootable = attr.ib(default=False)
 
     def render(self):
         r = '{}: '.format(self.number)
@@ -149,8 +158,8 @@ class SFDiskPartTable:
         self._sector_bytes = sector_bytes
         if ONE_MIB_BYTES % sector_bytes != 0:
             raise Exception(
-                f"sector_bytes {sector_bytes} does not divide 1MiB, cannot "
-                "continue!")
+                "sector_bytes {} does not divide 1MiB, cannot "
+                "continue!".format(sector_bytes))
         self.one_mib_sectors = ONE_MIB_BYTES // sector_bytes
 
     def bytes2sectors(self, amount):
diff --git a/curtin/commands/install.py b/curtin/commands/install.py
index 7ccad87..bd1016a 100644
--- a/curtin/commands/install.py
+++ b/curtin/commands/install.py
@@ -112,16 +112,16 @@ def writeline(fname, output):
         pass
 
 
-@attr.s(auto_attribs=True)
+@attr.s()
 class WorkingDir:
-    target: str
-    top: str
-    scratch: str
-    interfaces: str
-    netconf: str
-    netstate: str
-    fstab: str
-    config_file: str
+    target = attr.ib()
+    top = attr.ib()
+    scratch = attr.ib()
+    interfaces = attr.ib()
+    netconf = attr.ib()
+    netstate = attr.ib()
+    fstab = attr.ib()
+    config_file = attr.ib()
 
     @classmethod
     def import_existing(cls, config):
diff --git a/tests/integration/test_block_meta.py b/tests/integration/test_block_meta.py
index a2368e8..099a3b4 100644
--- a/tests/integration/test_block_meta.py
+++ b/tests/integration/test_block_meta.py
@@ -1,17 +1,23 @@
 # This file is part of curtin. See LICENSE file for copyright and license info.
 
-import dataclasses
-from dataclasses import dataclass
 import contextlib
 import json
 import os
-from parameterized import parameterized
+import pprint
 import re
 import sys
+<<<<<<< tests/integration/test_block_meta.py
 from typing import Optional
 from unittest import skipIf
 import yaml
 
+=======
+from unittest import skipIf
+import yaml
+
+import attr
+
+>>>>>>> tests/integration/test_block_meta.py
 from curtin import block, compat, distro, log, udev, util
 from curtin.commands.block_meta import _get_volume_fstype
 from curtin.commands.block_meta_v2 import ONE_MIB_BYTES
@@ -38,22 +44,25 @@ def loop_dev(image, sector_size=512):
         util.subp(['losetup', '--detach', dev])
 
 
-@dataclass(order=True)
+@attr.s(init=True, cmp=False)
 class PartData:
-    number: Optional[int] = None
-    offset: Optional[int] = None
-    size: Optional[int] = None
-    boot: Optional[bool] = None
-    partition_type: Optional[str] = None
+    number = attr.ib(default=None)
+    offset = attr.ib(default=None)
+    size = attr.ib(default=None)
+    boot = attr.ib(default=None)
+    partition_type = attr.ib(default=None)
 
     # test cases may initialize the values they care about
     # test utilities shall initialize all fields
     def assertFieldsAreNotNone(self):
-        for field in dataclasses.fields(self):
+        for field in attr.fields(self.__class__):
             assert getattr(self, field.name) is not None
 
+    def __lt__(self, other):
+        return self.number < other.number
+
     def __eq__(self, other):
-        for field in dataclasses.fields(self):
+        for field in attr.fields(self.__class__):
             myval = getattr(self, field.name)
             otherval = getattr(other, field.name)
             if myval is not None and otherval is not None \
@@ -64,7 +73,7 @@ class PartData:
 
 def _get_ext_size(dev, part_action):
     num = part_action['number']
-    cmd = ['dumpe2fs', '-h', f'{dev}p{num}']
+    cmd = ['dumpe2fs', '-h', '{}p{}'.format(dev, num)]
     out = util.subp(cmd, capture=True)[0]
     for line in out.splitlines():
         if line.startswith('Block count'):
@@ -79,7 +88,7 @@ def _get_ntfs_size(dev, part_action):
     cmd = ['ntfsresize',
            '--no-action',
            '--force',  # needed post-resize, which otherwise demands a CHKDSK
-           '--info', f'{dev}p{num}']
+           '--info', '{}p{}'.format(dev, num)]
     out = util.subp(cmd, capture=True)[0]
     # Sample input:
     # Current volume size: 41939456 bytes (42 MB)
@@ -101,7 +110,7 @@ _get_fs_sizers = {
 
 def _get_filesystem_size(dev, part_action, fstype='ext4'):
     if fstype not in _get_fs_sizers.keys():
-        raise Exception(f'_get_filesystem_size: no support for {fstype}')
+        raise Exception('_get_filesystem_size: no support for %s' % fstype)
     return _get_fs_sizers[fstype](dev, part_action)
 
 
@@ -124,7 +133,7 @@ def summarize_partitions(dev):
         (unused, s_number, s_offset, s_size) = [
                 entry for entry in sysfs_data
                 if '/dev/' + entry[0] == node][0]
-        assert node.startswith(f'{dev}p')
+        assert node.startswith(dev + 'p')
         number = int(node[len(dev) + 1:])
         ptype = part['type']
         offset = part['start'] * sectorsize
@@ -206,13 +215,13 @@ class TestBlockMeta(IntegrationTestCase):
     def mount(self, dev, partition_cfg):
         mnt_point = self.tmp_dir()
         num = partition_cfg['number']
-        with util.mount(f'{dev}p{num}', mnt_point):
+        with util.mount('{}p{}'.format(dev, num), mnt_point):
             yield mnt_point
 
     @contextlib.contextmanager
     def open_file_on_part(self, dev, part_action, mode):
         with self.mount(dev, part_action) as mnt_point:
-            with open(f'{mnt_point}/data.txt', mode) as fp:
+            with open(mnt_point + '/data.txt', mode) as fp:
                 yield fp
 
     def create_data(self, dev, part_action):
@@ -232,7 +241,7 @@ class TestBlockMeta(IntegrationTestCase):
             tolerance = 512 * 10
         actual_fssize = _get_filesystem_size(dev, part_action, fstype)
         diff = expected - actual_fssize
-        self.assertTrue(0 <= diff <= tolerance, f'difference of {diff}')
+        self.assertTrue(0 <= diff <= tolerance, 'difference of ' + str(diff))
 
     def run_bm(self, config, *args, **kwargs):
         config_path = self.tmp_path('config.yaml')
@@ -602,7 +611,7 @@ class TestBlockMeta(IntegrationTestCase):
             }
             with loop_dev(img) as dev:
                 try:
-                    self.run_bm(curtin_cfg, f'--devices={dev}', env=cmd_env)
+                    self.run_bm(curtin_cfg, '--devices=' + dev, env=cmd_env)
                 finally:
                     util.subp(['umount', mnt_point])
                     udev.udevadm_settle()
@@ -622,7 +631,7 @@ class TestBlockMeta(IntegrationTestCase):
                              fstype=fstype)
         self.run_bm(config.render())
         with loop_dev(img) as dev:
-            self.assertEqual(fstype, _get_volume_fstype(f'{dev}p1'))
+            self.assertEqual(fstype, _get_volume_fstype(dev + 'p1'))
             self.create_data(dev, p1)
             self.assertEqual(
                 summarize_partitions(dev), [
@@ -651,7 +660,11 @@ class TestBlockMeta(IntegrationTestCase):
             p1['size'] = size
             self.run_bm(config.render())
             with loop_dev(img) as dev:
+<<<<<<< tests/integration/test_block_meta.py
                 self.assertEqual('ntfs', _get_volume_fstype(f'{dev}p1'))
+=======
+                self.assertEqual('ntfs', _get_volume_fstype(dev + 'p1'))
+>>>>>>> tests/integration/test_block_meta.py
                 self.create_data(dev, p1)
                 self.assertEqual(
                     summarize_partitions(dev), [
@@ -959,11 +972,11 @@ class TestBlockMeta(IntegrationTestCase):
             with self.mount(dev, p1) as mnt_point:
                 # Attempt to create files across the partition with gaps
                 for i in range(1, 41):
-                    with open(f'{mnt_point}/{str(i)}', 'wb') as fp:
+                    with open('{}/{}'.format(mnt_point, i), 'wb') as fp:
                         fp.write(bytes([i]) * (2 << 20))
                 for i in range(1, 41):
                     if i % 5 != 0:
-                        os.remove(f'{mnt_point}/{str(i)}')
+                        os.remove('{}/{}'.format(mnt_point, i))
 
         config = StorageConfigBuilder(version=2)
         config.add_image(path=img, size='100M', ptable='gpt')
@@ -981,7 +994,7 @@ class TestBlockMeta(IntegrationTestCase):
                 ])
             with self.mount(dev, p1) as mnt_point:
                 for i in range(5, 41, 5):
-                    with open(f'{mnt_point}/{i}', 'rb') as fp:
+                    with open('{}/{}'.format(mnt_point, i), 'rb') as fp:
                         self.assertEqual(bytes([i]) * (2 << 20), fp.read())
 
     def test_parttype_dos(self):
@@ -1043,8 +1056,7 @@ class TestBlockMeta(IntegrationTestCase):
             PartData(number=4, offset=80 << 20, size=19 << 20,
                      partition_type=winre))
 
-    @parameterized.expand([('msdos',), ('gpt',)])
-    def test_disk_label_id_persistent(self, ptable):
+    def _test_disk_label_id_persistent(self, ptable):
         # when the disk is preserved, the disk label id shall also be preserved
         self.img = self.tmp_path('image.img')
         config = StorageConfigBuilder(version=2)
@@ -1063,6 +1075,12 @@ class TestBlockMeta(IntegrationTestCase):
         with loop_dev(self.img) as dev:
             self.assertEqual(orig_label_id, _get_disk_label_id(dev))
 
+    def test_disk_label_id_persistent_msdos(self):
+        self._test_disk_label_id_persistent('msdos')
+
+    def test_disk_label_id_persistent_gpt(self):
+        self._test_disk_label_id_persistent('gpt')
+
     def test_gpt_uuid_persistent(self):
         # A persistent partition with an unspecified uuid shall keep the uuid
         self.img = self.tmp_path('image.img')
@@ -1099,12 +1117,16 @@ class TestBlockMeta(IntegrationTestCase):
             actual_name = sfdisk_info['partitions'][0]['name']
         self.assertEqual(name, actual_name)
 
+<<<<<<< tests/integration/test_block_meta.py
     @parameterized.expand([
         ('random', CiTestCase.random_string(),),
         # "écrasé" means "overwritten"
         ('unicode', "'name' must not be écrasé/덮어쓴!"),
     ])
     def test_gpt_name_persistent(self, title, name):
+=======
+    def _test_gpt_name_persistent(self, title, name):
+>>>>>>> tests/integration/test_block_meta.py
         self.img = self.tmp_path('image.img')
         config = StorageConfigBuilder(version=2)
         config.add_image(path=self.img, size='20M', ptable='gpt')
@@ -1127,6 +1149,14 @@ class TestBlockMeta(IntegrationTestCase):
             actual_name = sfdisk_info['partitions'][0]['name']
         self.assertEqual(name, actual_name)
 
+    def test_gpt_name_persistent_random(self):
+        self._test_gpt_name_persistent('random', CiTestCase.random_string())
+
+    def test_gpt_name_persistent_unicode(self):
+        self._test_gpt_name_persistent('unicode',
+                                       "'name' must not be écrasé/덮어쓴!")
+
+
     def test_gpt_set_single_attr(self):
         self.img = self.tmp_path('image.img')
         config = StorageConfigBuilder(version=2)
@@ -1271,8 +1301,7 @@ table-length: 256'''.encode()
         self.assertPartitions(
             PartData(number=1, offset=1 << 20, size=1 << 20))
 
-    @parameterized.expand(((1,), (2,)))
-    def test_swap(self, sv):
+    def _test_swap(self, sv):
         self.img = self.tmp_path('image.img')
         config = StorageConfigBuilder(version=sv)
         config.add_image(path=self.img, create=True, size='20M',
@@ -1283,3 +1312,9 @@ table-length: 256'''.encode()
         self.assertPartitions(
             PartData(number=1, offset=1 << 20, size=1 << 20, boot=False,
                      partition_type='82'))
+
+    def test_swap_sv1(self):
+        self._test_swap(1)
+
+    def test_swap_sv2(self):
+        self._test_swap(2)
diff --git a/tests/integration/webserv.py b/tests/integration/webserv.py
index f4ce4e4..de30e04 100644
--- a/tests/integration/webserv.py
+++ b/tests/integration/webserv.py
@@ -1,8 +1,10 @@
 # This file is part of curtin. See LICENSE file for copyright and license info.
 
-import threading
-import socketserver
 from http.server import SimpleHTTPRequestHandler
+import socketserver
+import threading
+import os
+
 from tests.vmtests.image_sync import IMAGE_DIR
 
 
@@ -12,7 +14,17 @@ class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
 
 class ImageHTTPRequestHandler(SimpleHTTPRequestHandler):
     def __init__(self, *args, **kwargs):
-        super().__init__(*args, directory=IMAGE_DIR, **kwargs)
+        try:
+            super().__init__(*args, directory=IMAGE_DIR, **kwargs)
+        except TypeError:
+            # SimpleHTTPRequestHandler in python < 3.7 doesn't take a directory
+            # arg, fake it.
+            curdir = os.getcwd()
+            os.chdir(IMAGE_DIR)
+            try:
+                super().__init__(*args, **kwargs)
+            finally:
+                os.chdir(curdir)
 
 
 class ImageServer:
@@ -50,4 +62,4 @@ class ImageServer:
         if self.server is not None:
             ip, port = self.server.server_address
 
-        return f"http://{ip}:{port}";
+        return "http://{}:{}".format(ip, port)
diff --git a/tests/unittests/test_commands_block_meta.py b/tests/unittests/test_commands_block_meta.py
index 5599886..26e2a59 100644
--- a/tests/unittests/test_commands_block_meta.py
+++ b/tests/unittests/test_commands_block_meta.py
@@ -3066,10 +3066,10 @@ label: gpt
         table = block_meta_v2.GPTPartTable(512)
         table.add(dict(number=1, offset=1 << 20, size=9 << 20,
                        flag='boot', partition_type=ptype))
-        expected = f'''\
+        expected = '''\
 label: gpt
 
-1:  start=2048 size=18432 type={ptype}'''
+1:  start=2048 size=18432 type={}'''.format(ptype)
         self.assertEqual(expected, table.render())
 
     def test_gpt_name(self):
@@ -3079,10 +3079,17 @@ label: gpt
                        partition_name=name))
         type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
         to_hex = block_meta_v2.to_utf8_hex_notation
+<<<<<<< tests/unittests/test_commands_block_meta.py
         expected = f'''\
 label: gpt
 
 1:  start=2048 size=18432 type={type_id} name="{to_hex(name)}"'''
+=======
+        expected = '''\
+label: gpt
+
+1:  start=2048 size=18432 type={} name="{}"'''.format(type_id, to_hex(name))
+>>>>>>> tests/unittests/test_commands_block_meta.py
         self.assertEqual(expected, table.render())
 
     def test_gpt_name_free_text(self):
@@ -3096,10 +3103,14 @@ label: gpt
         table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
                        partition_name=name))
         type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
-        expected = f'''\
+        expected = '''\
 label: gpt
 
+<<<<<<< tests/unittests/test_commands_block_meta.py
 1:  start=2048 size=18432 type={type_id} name="{expected_name}"'''
+=======
+1:  start=2048 size=18432 type={} name="{}"'''.format(type_id, expected_name)
+>>>>>>> tests/unittests/test_commands_block_meta.py
         self.assertEqual(expected, table.render())
 
     def test_gpt_attrs_none(self):
@@ -3107,10 +3118,10 @@ label: gpt
         table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
                        attrs=None))
         type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
-        expected = f'''\
+        expected = '''\
 label: gpt
 
-1:  start=2048 size=18432 type={type_id}'''
+1:  start=2048 size=18432 type={}'''.format(type_id)
         self.assertEqual(expected, table.render())
 
     def test_gpt_attrs_empty(self):
@@ -3118,10 +3129,10 @@ label: gpt
         table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
                        attrs=[]))
         type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
-        expected = f'''\
+        expected = '''\
 label: gpt
 
-1:  start=2048 size=18432 type={type_id}'''
+1:  start=2048 size=18432 type={}'''.format(type_id)
         self.assertEqual(expected, table.render())
 
     def test_gpt_attrs_required(self):
@@ -3129,10 +3140,10 @@ label: gpt
         table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
                        attrs=['RequiredPartition']))
         type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
-        expected = f'''\
+        expected = '''\
 label: gpt
 
-1:  start=2048 size=18432 type={type_id} attrs="RequiredPartition"'''
+1:  start=2048 size=18432 type={} attrs="RequiredPartition"'''.format(type_id)
         self.assertEqual(expected, table.render())
 
     def test_gpt_attrs_bit(self):
@@ -3140,10 +3151,10 @@ label: gpt
         table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
                        attrs=['GUID:51']))
         type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
-        expected = f'''\
+        expected = '''\
 label: gpt
 
-1:  start=2048 size=18432 type={type_id} attrs="GUID:51"'''
+1:  start=2048 size=18432 type={} attrs="GUID:51"'''.format(type_id)
         self.assertEqual(expected, table.render())
 
     def test_gpt_attrs_multi(self):
@@ -3151,10 +3162,11 @@ label: gpt
         table.add(dict(number=1, offset=1 << 20, size=9 << 20, flag='boot',
                        attrs=['RequiredPartition', 'GUID:51']))
         type_id = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
-        expected = f'''\
+        attrs = 'RequiredPartition GUID:51'
+        expected = '''\
 label: gpt
 
-1:  start=2048 size=18432 type={type_id} attrs="RequiredPartition GUID:51"'''
+1:  start=2048 size=18432 type={} attrs="{}"'''.format(type_id, attrs)
         self.assertEqual(expected, table.render())
 
     def test_dos_basic(self):
@@ -3178,10 +3190,10 @@ label: dos
         table = block_meta_v2.DOSPartTable(512)
         table.add(dict(number=1, offset=1 << 20, size=9 << 20,
                        flag='boot', partition_type=ptype))
-        expected = f'''\
+        expected = '''\
 label: dos
 
-1:  start=2048 size=18432 type={ptype} bootable'''
+1:  start=2048 size=18432 type={} bootable'''.format(ptype)
         self.assertEqual(expected, table.render())
 
     def test_preserve_labelid_gpt(self):
@@ -3277,21 +3289,26 @@ label: dos
                 number=1, start=2, size=3, type='04', bootable=True,
                 uuid=uuid, name='name',
                 attrs=['stuff', 'things'])
-        expected = f'1:  start=2 size=3 type=04 uuid={uuid} ' + \
+        expected = '1:  start=2 size=3 type=04 uuid={} '.format(uuid) + \
             'name="name" attrs="stuff things" bootable'
         self.assertEqual(expected, pte.render())
 
     def test_gpt_entry_preserve(self):
         uuid = str(random_uuid())
         name = self.random_string()
-        attrs = f'{self.random_string()} {self.random_string()}'
+        attrs = '{} {}'.format(self.random_string(), self.random_string())
         pte = block_meta_v2.PartTableEntry(
                 number=1, start=2, size=3, type='04', bootable=False,
                 uuid=None, name=None, attrs=None)
         pte.preserve({'uuid': uuid, 'name': name, 'attrs': attrs})
         to_hex = block_meta_v2.to_utf8_hex_notation
+<<<<<<< tests/unittests/test_commands_block_meta.py
         expected = f'1:  start=2 size=3 type=04 uuid={uuid} ' + \
             f'name="{to_hex(name)}" attrs="{attrs}"'
+=======
+        expected = '1:  start=2 size=3 type=04 uuid={} '.format(uuid) + \
+            'name="{}" attrs="{}"'.format(to_hex(name), attrs)
+>>>>>>> tests/unittests/test_commands_block_meta.py
         self.assertEqual(expected, pte.render())
 
     def test_v2_dos_is_logical(self):
diff --git a/tests/unittests/test_curthooks.py b/tests/unittests/test_curthooks.py
index 9e4fa87..a96f5fd 100644
--- a/tests/unittests/test_curthooks.py
+++ b/tests/unittests/test_curthooks.py
@@ -2286,19 +2286,21 @@ class TestDoAptConfig(CiTestCase):
     def test_apt_config_dict(self):
         with patch(self.handle_apt_sym) as m_handle_apt:
             curthooks.do_apt_config({"apt": {}}, target="/")
-        m_handle_apt.assert_called()
+        m_handle_apt.assert_any_call({}, '/')
 
     def test_with_apt_config(self):
         with patch(self.handle_apt_sym) as m_handle_apt:
             curthooks.do_apt_config(
                     {"apt": {"proxy": {"http_proxy": "http://proxy:3128"}}},
                     target="/")
-        m_handle_apt.assert_called_once()
+        m_handle_apt.assert_any_call(
+                {'proxy': {'http_proxy': 'http://proxy:3128'}}, '/')
 
     def test_with_debconf_selections(self):
         # debconf_selections are translated to apt config
         with patch(self.handle_apt_sym) as m_handle_apt:
             curthooks.do_apt_config({"debconf_selections": "foo"}, target="/")
-        m_handle_apt.assert_called_once()
+        m_handle_apt.assert_any_call({'debconf_selections': 'foo'}, '/')
+
 
 # vi: ts=4 expandtab syntax=python
diff --git a/tests/unittests/test_distro.py b/tests/unittests/test_distro.py
index 5743475..a10ddbf 100644
--- a/tests/unittests/test_distro.py
+++ b/tests/unittests/test_distro.py
@@ -311,7 +311,7 @@ class TestAptInstall(CiTestCase):
         ]
 
         distro.run_apt_command('install', ['foobar', 'wark'])
-        m_apt_update.assert_called_once()
+        self.assertEqual(1, m_apt_update.call_count)
         m_apt_install.assert_has_calls(expected_calls)
         m_subp.assert_called_once_with(['apt-get', 'clean'], target='/')
 
@@ -321,7 +321,7 @@ class TestAptInstall(CiTestCase):
 
         # no clean option
         distro.run_apt_command('install', ['foobar', 'wark'], clean=False)
-        m_apt_update.assert_called_once()
+        self.assertEqual(1, m_apt_update.call_count)
         m_subp.assert_has_calls(expected_calls[:-1])
 
     @mock.patch.object(util.ChrootableTarget, "__enter__", new=lambda a: a)
diff --git a/tests/unittests/test_storage_config.py b/tests/unittests/test_storage_config.py
index a538ece..516d56a 100644
--- a/tests/unittests/test_storage_config.py
+++ b/tests/unittests/test_storage_config.py
@@ -1170,7 +1170,10 @@ class TestSelectConfigs(CiTestCase):
         id1 = {'a': 1, 'c': 3}
         sc = {'id0': id0, 'id1': id1}
 
-        self.assertEqual([id0, id1], select_configs(sc, a=1))
+        actual = select_configs(sc, a=1)
+        self.assertEqual(2, len(actual))
+        self.assertIn(id0, actual)
+        self.assertIn(id1, actual)
 
     def test_not_found(self):
         id0 = {'a': 1, 'b': 2}

Follow ups