summaryrefslogtreecommitdiff
path: root/tests/unittests/test_dmi.py
diff options
context:
space:
mode:
authorBrett Holman <bholman.devel@gmail.com>2021-12-03 13:11:46 -0700
committerGitHub <noreply@github.com>2021-12-03 13:11:46 -0700
commit039c40f9b3d88ee8158604bb18ca4bf2fb5d5e51 (patch)
tree5f1b09486ccaf98ee8159de58d9a2a1ef0af5dc1 /tests/unittests/test_dmi.py
parentffa6fc88249aa080aa31811a45569a45e567418a (diff)
downloadvyos-cloud-init-039c40f9b3d88ee8158604bb18ca4bf2fb5d5e51.tar.gz
vyos-cloud-init-039c40f9b3d88ee8158604bb18ca4bf2fb5d5e51.zip
Reorganize unit test locations under tests/unittests (#1126)
This attempts to standardize unit test file location under test/unittests/ such that any source file located at cloudinit/path/to/file.py may have a corresponding unit test file at test/unittests/path/to/test_file.py. Noteworthy Comments: ==================== Four different duplicate test files existed: test_{gpg,util,cc_mounts,cc_resolv_conf}.py Each of these duplicate file pairs has been merged together. This is a break in git history for these files. The test suite appears to have a dependency on test order. Changing test order causes some tests to fail. This should be rectified, but for now some tests have been modified in tests/unittests/config/test_set_passwords.py. A helper class name starts with "Test" which causes pytest to try executing it as a test case, which then throws warnings "due to Class having __init__()". Silence by changing the name of the class. # helpers.py is imported in many test files, import paths change cloudinit/tests/helpers.py -> tests/unittests/helpers.py # Move directories: cloudinit/distros/tests -> tests/unittests/distros cloudinit/cmd/devel/tests -> tests/unittests/cmd/devel cloudinit/cmd/tests -> tests/unittests/cmd/ cloudinit/sources/helpers/tests -> tests/unittests/sources/helpers cloudinit/sources/tests -> tests/unittests/sources cloudinit/net/tests -> tests/unittests/net cloudinit/config/tests -> tests/unittests/config cloudinit/analyze/tests/ -> tests/unittests/analyze/ # Standardize tests already in tests/unittests/ test_datasource -> sources test_distros -> distros test_vmware -> sources/vmware test_handler -> config # this contains cloudconfig module tests test_runs -> runs
Diffstat (limited to 'tests/unittests/test_dmi.py')
-rw-r--r--tests/unittests/test_dmi.py154
1 files changed, 154 insertions, 0 deletions
diff --git a/tests/unittests/test_dmi.py b/tests/unittests/test_dmi.py
new file mode 100644
index 00000000..674e7b98
--- /dev/null
+++ b/tests/unittests/test_dmi.py
@@ -0,0 +1,154 @@
+from tests.unittests import helpers
+from cloudinit import dmi
+from cloudinit import util
+from cloudinit import subp
+
+import os
+import tempfile
+import shutil
+from unittest import mock
+
+
+class TestReadDMIData(helpers.FilesystemMockingTestCase):
+
+ def setUp(self):
+ super(TestReadDMIData, self).setUp()
+ self.new_root = tempfile.mkdtemp()
+ self.addCleanup(shutil.rmtree, self.new_root)
+ self.reRoot(self.new_root)
+ p = mock.patch("cloudinit.dmi.is_container", return_value=False)
+ self.addCleanup(p.stop)
+ self._m_is_container = p.start()
+ p = mock.patch("cloudinit.dmi.is_FreeBSD", return_value=False)
+ self.addCleanup(p.stop)
+ self._m_is_FreeBSD = p.start()
+
+ def _create_sysfs_parent_directory(self):
+ util.ensure_dir(os.path.join('sys', 'class', 'dmi', 'id'))
+
+ def _create_sysfs_file(self, key, content):
+ """Mocks the sys path found on Linux systems."""
+ self._create_sysfs_parent_directory()
+ dmi_key = "/sys/class/dmi/id/{0}".format(key)
+ util.write_file(dmi_key, content)
+
+ def _configure_dmidecode_return(self, key, content, error=None):
+ """
+ In order to test a missing sys path and call outs to dmidecode, this
+ function fakes the results of dmidecode to test the results.
+ """
+ def _dmidecode_subp(cmd):
+ if cmd[-1] != key:
+ raise subp.ProcessExecutionError()
+ return (content, error)
+
+ self.patched_funcs.enter_context(
+ mock.patch("cloudinit.dmi.subp.which", side_effect=lambda _: True))
+ self.patched_funcs.enter_context(
+ mock.patch("cloudinit.dmi.subp.subp", side_effect=_dmidecode_subp))
+
+ def _configure_kenv_return(self, key, content, error=None):
+ """
+ In order to test a FreeBSD system call outs to kenv, this
+ function fakes the results of kenv to test the results.
+ """
+ def _kenv_subp(cmd):
+ if cmd[-1] != dmi.DMIDECODE_TO_KERNEL[key].freebsd:
+ raise subp.ProcessExecutionError()
+ return (content, error)
+
+ self.patched_funcs.enter_context(
+ mock.patch("cloudinit.dmi.subp.subp", side_effect=_kenv_subp))
+
+ def patch_mapping(self, new_mapping):
+ self.patched_funcs.enter_context(
+ mock.patch('cloudinit.dmi.DMIDECODE_TO_KERNEL',
+ new_mapping))
+
+ def test_sysfs_used_with_key_in_mapping_and_file_on_disk(self):
+ self.patch_mapping({'mapped-key': dmi.kdmi('mapped-value', None)})
+ expected_dmi_value = 'sys-used-correctly'
+ self._create_sysfs_file('mapped-value', expected_dmi_value)
+ self._configure_dmidecode_return('mapped-key', 'wrong-wrong-wrong')
+ self.assertEqual(expected_dmi_value, dmi.read_dmi_data('mapped-key'))
+
+ def test_dmidecode_used_if_no_sysfs_file_on_disk(self):
+ self.patch_mapping({})
+ self._create_sysfs_parent_directory()
+ expected_dmi_value = 'dmidecode-used'
+ self._configure_dmidecode_return('use-dmidecode', expected_dmi_value)
+ with mock.patch("cloudinit.util.os.uname") as m_uname:
+ m_uname.return_value = ('x-sysname', 'x-nodename',
+ 'x-release', 'x-version', 'x86_64')
+ self.assertEqual(expected_dmi_value,
+ dmi.read_dmi_data('use-dmidecode'))
+
+ def test_dmidecode_not_used_on_arm(self):
+ self.patch_mapping({})
+ print("current =%s", subp)
+ self._create_sysfs_parent_directory()
+ dmi_val = 'from-dmidecode'
+ dmi_name = 'use-dmidecode'
+ self._configure_dmidecode_return(dmi_name, dmi_val)
+ print("now =%s", subp)
+
+ expected = {'armel': None, 'aarch64': dmi_val, 'x86_64': dmi_val}
+ found = {}
+ # we do not run the 'dmi-decode' binary on some arches
+ # verify that anything requested that is not in the sysfs dir
+ # will return None on those arches.
+ with mock.patch("cloudinit.util.os.uname") as m_uname:
+ for arch in expected:
+ m_uname.return_value = ('x-sysname', 'x-nodename',
+ 'x-release', 'x-version', arch)
+ print("now2 =%s", subp)
+ found[arch] = dmi.read_dmi_data(dmi_name)
+ self.assertEqual(expected, found)
+
+ def test_none_returned_if_neither_source_has_data(self):
+ self.patch_mapping({})
+ self._configure_dmidecode_return('key', 'value')
+ self.assertIsNone(dmi.read_dmi_data('expect-fail'))
+
+ def test_none_returned_if_dmidecode_not_in_path(self):
+ self.patched_funcs.enter_context(
+ mock.patch.object(subp, 'which', lambda _: False))
+ self.patch_mapping({})
+ self.assertIsNone(dmi.read_dmi_data('expect-fail'))
+
+ def test_empty_string_returned_instead_of_foxfox(self):
+ # uninitialized dmi values show as \xff, return empty string
+ my_len = 32
+ dmi_value = b'\xff' * my_len + b'\n'
+ expected = ""
+ dmi_key = 'system-product-name'
+ sysfs_key = 'product_name'
+ self._create_sysfs_file(sysfs_key, dmi_value)
+ self.assertEqual(expected, dmi.read_dmi_data(dmi_key))
+
+ def test_container_returns_none(self):
+ """In a container read_dmi_data should always return None."""
+
+ # first verify we get the value if not in container
+ self._m_is_container.return_value = False
+ key, val = ("system-product-name", "my_product")
+ self._create_sysfs_file('product_name', val)
+ self.assertEqual(val, dmi.read_dmi_data(key))
+
+ # then verify in container returns None
+ self._m_is_container.return_value = True
+ self.assertIsNone(dmi.read_dmi_data(key))
+
+ def test_container_returns_none_on_unknown(self):
+ """In a container even bogus keys return None."""
+ self._m_is_container.return_value = True
+ self._create_sysfs_file('product_name', "should-be-ignored")
+ self.assertIsNone(dmi.read_dmi_data("bogus"))
+ self.assertIsNone(dmi.read_dmi_data("system-product-name"))
+
+ def test_freebsd_uses_kenv(self):
+ """On a FreeBSD system, kenv is called."""
+ self._m_is_FreeBSD.return_value = True
+ key, val = ("system-product-name", "my_product")
+ self._configure_kenv_return(key, val)
+ self.assertEqual(dmi.read_dmi_data(key), val)