fix test failed
(cherry picked from commit 88323bd0cafa413aac57443c958b375e31874548)
This commit is contained in:
parent
bee4bcfb88
commit
f3ddeb00b8
@ -0,0 +1,73 @@
|
||||
From 463d36cc237435084e5ddb4d7468f5546e7ece28 Mon Sep 17 00:00:00 2001
|
||||
From: Chad Smith <chad.smith@canonical.com>
|
||||
Date: Wed, 6 Mar 2024 07:51:34 -0700
|
||||
Subject: [PATCH] bug(tests): mock reads of host's /sys/class/net via
|
||||
get_sys_class_path
|
||||
|
||||
Avoid leaking reads to the underlying host's /sys/class/net files.
|
||||
Some test environments contain virtual network hardware and
|
||||
configuration such as Calico network devices which provide
|
||||
duplicated MAC addresses for each device in /sys/class/net. This
|
||||
results in errors from unittests calling cloudinit.net.get_interfaces.
|
||||
|
||||
Provide a disable_sysfs_net` fixture and use it in net-related
|
||||
modules or functions to avoid unrelated test failures due to
|
||||
environmental differences.
|
||||
|
||||
Provide the ability to turn off this fixture for tests which
|
||||
need to write to the mocked sysfs tmp directory so test artifacts
|
||||
do not pollute other tests.
|
||||
|
||||
This fixture can be disabled by passing False to the disable_sysfs_net
|
||||
via request.param. We want to avoid polluting tox.ini with pytest.marks
|
||||
for infrequently used cases like this.
|
||||
|
||||
Also fix whitespace in tox.ini
|
||||
---
|
||||
tests/unittests/conftest.py | 20 ++++++++++++++++++++
|
||||
tox.ini | 2 +-
|
||||
2 files changed, 21 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tests/unittests/conftest.py b/tests/unittests/conftest.py
|
||||
index 91dbd06..22bc189 100644
|
||||
--- a/tests/unittests/conftest.py
|
||||
+++ b/tests/unittests/conftest.py
|
||||
@@ -61,6 +61,26 @@ def fake_filesystem(mocker, tmpdir):
|
||||
mocker.patch.object(mod, f, trap_func)
|
||||
|
||||
|
||||
+@pytest.fixture(scope="session", autouse=True)
|
||||
+def disable_sysfs_net(request, tmpdir_factory):
|
||||
+ """Avoid tests which read the undertying host's /syc/class/net.
|
||||
+
|
||||
+ To allow unobscured reads of /sys/class/net on the host we can
|
||||
+ parametrize the fixture with:
|
||||
+
|
||||
+ @pytest.mark.parametrize("disable_sysfs_net", [False], indirect=True)
|
||||
+ """
|
||||
+ if hasattr(request, "param") and getattr(request, "param") is False:
|
||||
+ # Test disabled this fixture, perform no mocks.
|
||||
+ yield
|
||||
+ return
|
||||
+ mock_sysfs = f"{tmpdir_factory.mktemp('sysfs')}/"
|
||||
+ with mock.patch(
|
||||
+ "cloudinit.net.get_sys_class_path", return_value=mock_sysfs
|
||||
+ ):
|
||||
+ yield mock_sysfs
|
||||
+
|
||||
+
|
||||
@pytest.fixture(autouse=True)
|
||||
def disable_dns_lookup(request):
|
||||
if "allow_dns_lookup" in request.keywords:
|
||||
diff --git a/tox.ini b/tox.ini
|
||||
index 5f01a9a..cd261f3 100644
|
||||
--- a/tox.ini
|
||||
+++ b/tox.ini
|
||||
@@ -323,4 +323,4 @@ markers =
|
||||
serial: tests that do not work in parallel, skipped with py3-fast
|
||||
unstable: skip this test because it is flakey
|
||||
user_data: the user data to be passed to the test instance
|
||||
- allow_dns_lookup: disable autochecking for host network configuration
|
||||
+ allow_dns_lookup: disable autochecking for host network configuration
|
||||
--
|
||||
2.33.0
|
||||
457
backport-fix-unpin-jsonschema-and-update-tests.patch
Normal file
457
backport-fix-unpin-jsonschema-and-update-tests.patch
Normal file
@ -0,0 +1,457 @@
|
||||
From c948e4182b9557f2befeb6210a055d0aa1c2df21 Mon Sep 17 00:00:00 2001
|
||||
From: James Falcon <james.falcon@canonical.com>
|
||||
Date: Wed, 14 Feb 2024 16:25:11 -0600
|
||||
Subject: [PATCH] fix: unpin jsonschema and update tests (#4882)
|
||||
|
||||
In 034a5cd , we pinned jsonschema version due to failing tests. Test
|
||||
failures were due to jsonschema library changing error messages.
|
||||
This commit unpins the version and updates tests accordingly.
|
||||
|
||||
Fixes GH-4783
|
||||
|
||||
Co-authored-by: dermotbradley <dermot_bradley@yahoo.com>
|
||||
---
|
||||
.../unittests/config/test_cc_apk_configure.py | 5 +++--
|
||||
.../unittests/config/test_cc_apt_configure.py | 14 ++++++-------
|
||||
tests/unittests/config/test_cc_bootcmd.py | 17 +++++++++++-----
|
||||
tests/unittests/config/test_cc_ca_certs.py | 10 +++++++---
|
||||
tests/unittests/config/test_cc_chef.py | 5 +++--
|
||||
tests/unittests/config/test_cc_lxd.py | 2 +-
|
||||
tests/unittests/config/test_cc_mounts.py | 10 ++++++++--
|
||||
.../test_cc_package_update_upgrade_install.py | 3 ++-
|
||||
tests/unittests/config/test_cc_runcmd.py | 3 ++-
|
||||
.../unittests/config/test_cc_set_passwords.py | 9 +++++++--
|
||||
tests/unittests/config/test_cc_snap.py | 20 +++++++++++++------
|
||||
tests/unittests/config/test_cc_write_files.py | 6 +++++-
|
||||
.../unittests/config/test_cc_yum_add_repo.py | 2 +-
|
||||
tests/unittests/helpers.py | 8 ++++++++
|
||||
tests/unittests/test_merging.py | 2 +-
|
||||
15 files changed, 81 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/tests/unittests/config/test_cc_apk_configure.py b/tests/unittests/config/test_cc_apk_configure.py
|
||||
index 8854670..e9533a1 100644
|
||||
--- a/tests/unittests/config/test_cc_apk_configure.py
|
||||
+++ b/tests/unittests/config/test_cc_apk_configure.py
|
||||
@@ -18,6 +18,7 @@ from cloudinit.config.schema import (
|
||||
validate_cloudconfig_schema,
|
||||
)
|
||||
from tests.unittests.helpers import (
|
||||
+ SCHEMA_EMPTY_ERROR,
|
||||
FilesystemMockingTestCase,
|
||||
mock,
|
||||
skipUnlessJsonSchema,
|
||||
@@ -355,7 +356,7 @@ class TestApkConfigureSchema:
|
||||
(
|
||||
{"apk_repos": {"alpine_repo": {}}},
|
||||
"apk_repos.alpine_repo: 'version' is a required property,"
|
||||
- " apk_repos.alpine_repo: {} does not have enough properties",
|
||||
+ f" apk_repos.alpine_repo: {{}} {SCHEMA_EMPTY_ERROR}",
|
||||
),
|
||||
(
|
||||
{"apk_repos": {"alpine_repo": True}},
|
||||
@@ -368,7 +369,7 @@ class TestApkConfigureSchema:
|
||||
),
|
||||
(
|
||||
{"apk_repos": {}},
|
||||
- "apk_repos: {} does not have enough properties",
|
||||
+ f"apk_repos: {{}} {SCHEMA_EMPTY_ERROR}",
|
||||
),
|
||||
(
|
||||
{"apk_repos": {"local_repo_base_url": None}},
|
||||
diff --git a/tests/unittests/config/test_cc_apt_configure.py b/tests/unittests/config/test_cc_apt_configure.py
|
||||
index 18e6663..4fff316 100644
|
||||
--- a/tests/unittests/config/test_cc_apt_configure.py
|
||||
+++ b/tests/unittests/config/test_cc_apt_configure.py
|
||||
@@ -12,7 +12,7 @@ from cloudinit.config.schema import (
|
||||
get_schema,
|
||||
validate_cloudconfig_schema,
|
||||
)
|
||||
-from tests.unittests.helpers import skipUnlessJsonSchema
|
||||
+from tests.unittests.helpers import SCHEMA_EMPTY_ERROR, skipUnlessJsonSchema
|
||||
from tests.unittests.util import get_cloud
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class TestAPTConfigureSchema:
|
||||
" ('boguskey' was unexpected)"
|
||||
),
|
||||
),
|
||||
- ({"apt": {}}, "apt: {} does not have enough properties"),
|
||||
+ ({"apt": {}}, f"apt: {{}} {SCHEMA_EMPTY_ERROR}"),
|
||||
(
|
||||
{"apt": {"preserve_sources_list": 1}},
|
||||
"apt.preserve_sources_list: 1 is not of type 'boolean'",
|
||||
@@ -45,7 +45,7 @@ class TestAPTConfigureSchema:
|
||||
),
|
||||
(
|
||||
{"apt": {"disable_suites": []}},
|
||||
- re.escape("apt.disable_suites: [] is too short"),
|
||||
+ re.escape("apt.disable_suites: [] ") + SCHEMA_EMPTY_ERROR,
|
||||
),
|
||||
(
|
||||
{"apt": {"disable_suites": [1]}},
|
||||
@@ -65,7 +65,7 @@ class TestAPTConfigureSchema:
|
||||
),
|
||||
(
|
||||
{"apt": {"primary": []}},
|
||||
- re.escape("apt.primary: [] is too short"),
|
||||
+ re.escape("apt.primary: [] ") + SCHEMA_EMPTY_ERROR,
|
||||
),
|
||||
(
|
||||
{"apt": {"primary": ["nonobj"]}},
|
||||
@@ -102,7 +102,7 @@ class TestAPTConfigureSchema:
|
||||
),
|
||||
(
|
||||
{"apt": {"primary": [{"arches": ["amd64"], "search": []}]}},
|
||||
- re.escape("apt.primary.0.search: [] is too short"),
|
||||
+ re.escape("apt.primary.0.search: [] ") + SCHEMA_EMPTY_ERROR,
|
||||
),
|
||||
(
|
||||
{
|
||||
@@ -134,7 +134,7 @@ class TestAPTConfigureSchema:
|
||||
),
|
||||
(
|
||||
{"apt": {"debconf_selections": {}}},
|
||||
- "apt.debconf_selections: {} does not have enough properties",
|
||||
+ f"apt.debconf_selections: {{}} {SCHEMA_EMPTY_ERROR}",
|
||||
),
|
||||
(
|
||||
{"apt": {"sources_list": True}},
|
||||
@@ -170,7 +170,7 @@ class TestAPTConfigureSchema:
|
||||
),
|
||||
(
|
||||
{"apt": {"sources": {"opaquekey": {}}}},
|
||||
- "apt.sources.opaquekey: {} does not have enough properties",
|
||||
+ f"apt.sources.opaquekey: {{}} {SCHEMA_EMPTY_ERROR}",
|
||||
),
|
||||
(
|
||||
{"apt": {"sources": {"opaquekey": {"boguskey": True}}}},
|
||||
diff --git a/tests/unittests/config/test_cc_bootcmd.py b/tests/unittests/config/test_cc_bootcmd.py
|
||||
index f6772df..b938732 100644
|
||||
--- a/tests/unittests/config/test_cc_bootcmd.py
|
||||
+++ b/tests/unittests/config/test_cc_bootcmd.py
|
||||
@@ -11,7 +11,12 @@ from cloudinit.config.schema import (
|
||||
get_schema,
|
||||
validate_cloudconfig_schema,
|
||||
)
|
||||
-from tests.unittests.helpers import CiTestCase, mock, skipUnlessJsonSchema
|
||||
+from tests.unittests.helpers import (
|
||||
+ SCHEMA_EMPTY_ERROR,
|
||||
+ CiTestCase,
|
||||
+ mock,
|
||||
+ skipUnlessJsonSchema,
|
||||
+)
|
||||
from tests.unittests.util import get_cloud
|
||||
|
||||
|
||||
@@ -128,12 +133,14 @@ class TestBootCMDSchema:
|
||||
"Cloud config schema errors: bootcmd: 1 is not of type"
|
||||
" 'array'",
|
||||
),
|
||||
- ({"bootcmd": []}, re.escape("bootcmd: [] is too short")),
|
||||
(
|
||||
{"bootcmd": []},
|
||||
- re.escape(
|
||||
- "Cloud config schema errors: bootcmd: [] is too short"
|
||||
- ),
|
||||
+ re.escape("bootcmd: [] ") + SCHEMA_EMPTY_ERROR,
|
||||
+ ),
|
||||
+ (
|
||||
+ {"bootcmd": []},
|
||||
+ re.escape("Cloud config schema errors: bootcmd: [] ")
|
||||
+ + SCHEMA_EMPTY_ERROR,
|
||||
),
|
||||
(
|
||||
{
|
||||
diff --git a/tests/unittests/config/test_cc_ca_certs.py b/tests/unittests/config/test_cc_ca_certs.py
|
||||
index b93fda7..cb5712b 100644
|
||||
--- a/tests/unittests/config/test_cc_ca_certs.py
|
||||
+++ b/tests/unittests/config/test_cc_ca_certs.py
|
||||
@@ -17,7 +17,11 @@ from cloudinit.config.schema import (
|
||||
get_schema,
|
||||
validate_cloudconfig_schema,
|
||||
)
|
||||
-from tests.unittests.helpers import TestCase, skipUnlessJsonSchema
|
||||
+from tests.unittests.helpers import (
|
||||
+ SCHEMA_EMPTY_ERROR,
|
||||
+ TestCase,
|
||||
+ skipUnlessJsonSchema,
|
||||
+)
|
||||
from tests.unittests.util import get_cloud
|
||||
|
||||
|
||||
@@ -398,7 +402,7 @@ class TestCACertsSchema:
|
||||
),
|
||||
(
|
||||
{"ca_certs": {}},
|
||||
- re.escape("ca_certs: {} does not have enough properties"),
|
||||
+ re.escape("ca_certs: {} ") + SCHEMA_EMPTY_ERROR,
|
||||
),
|
||||
(
|
||||
{"ca_certs": {"boguskey": 1}},
|
||||
@@ -417,7 +421,7 @@ class TestCACertsSchema:
|
||||
),
|
||||
(
|
||||
{"ca_certs": {"trusted": []}},
|
||||
- re.escape("ca_certs.trusted: [] is too short"),
|
||||
+ re.escape("ca_certs.trusted: [] ") + SCHEMA_EMPTY_ERROR,
|
||||
),
|
||||
),
|
||||
)
|
||||
diff --git a/tests/unittests/config/test_cc_chef.py b/tests/unittests/config/test_cc_chef.py
|
||||
index 9d8ba1f..6fad6a7 100644
|
||||
--- a/tests/unittests/config/test_cc_chef.py
|
||||
+++ b/tests/unittests/config/test_cc_chef.py
|
||||
@@ -15,6 +15,7 @@ from cloudinit.config.schema import (
|
||||
validate_cloudconfig_schema,
|
||||
)
|
||||
from tests.unittests.helpers import (
|
||||
+ SCHEMA_EMPTY_ERROR,
|
||||
FilesystemMockingTestCase,
|
||||
ResponsesTestCase,
|
||||
cloud_init_project_dir,
|
||||
@@ -306,7 +307,7 @@ class TestBootCMDSchema:
|
||||
),
|
||||
(
|
||||
{"chef": {}},
|
||||
- re.escape(" chef: {} does not have enough properties"),
|
||||
+ re.escape(" chef: {} ") + SCHEMA_EMPTY_ERROR,
|
||||
),
|
||||
(
|
||||
{"chef": {"boguskey": True}},
|
||||
@@ -321,7 +322,7 @@ class TestBootCMDSchema:
|
||||
),
|
||||
(
|
||||
{"chef": {"directories": []}},
|
||||
- re.escape("chef.directories: [] is too short"),
|
||||
+ re.escape("chef.directories: [] ") + SCHEMA_EMPTY_ERROR,
|
||||
),
|
||||
(
|
||||
{"chef": {"directories": [1]}},
|
||||
diff --git a/tests/unittests/config/test_cc_lxd.py b/tests/unittests/config/test_cc_lxd.py
|
||||
index 648fc33..320bfdb 100644
|
||||
--- a/tests/unittests/config/test_cc_lxd.py
|
||||
+++ b/tests/unittests/config/test_cc_lxd.py
|
||||
@@ -385,7 +385,7 @@ class TestLXDSchema:
|
||||
# Require bridge.mode
|
||||
({"lxd": {"bridge": {}}}, "bridge: 'mode' is a required property"),
|
||||
# Require init or bridge keys
|
||||
- ({"lxd": {}}, "lxd: {} does not have enough properties"),
|
||||
+ ({"lxd": {}}, f"lxd: {{}} {t_help.SCHEMA_EMPTY_ERROR}"),
|
||||
# Require some non-empty preseed config of type string
|
||||
({"lxd": {"preseed": {}}}, "not of type 'string'"),
|
||||
({"lxd": {"preseed": ""}}, None),
|
||||
diff --git a/tests/unittests/config/test_cc_mounts.py b/tests/unittests/config/test_cc_mounts.py
|
||||
index a2dada8..4795357 100644
|
||||
--- a/tests/unittests/config/test_cc_mounts.py
|
||||
+++ b/tests/unittests/config/test_cc_mounts.py
|
||||
@@ -583,9 +583,15 @@ class TestMountsSchema:
|
||||
"config, error_msg",
|
||||
[
|
||||
# We expect to see one mount if provided in user-data.
|
||||
- ({"mounts": []}, re.escape("mounts: [] is too short")),
|
||||
+ (
|
||||
+ {"mounts": []},
|
||||
+ re.escape("mounts: [] ") + test_helpers.SCHEMA_EMPTY_ERROR,
|
||||
+ ),
|
||||
# Disallow less than 1 item per mount entry
|
||||
- ({"mounts": [[]]}, re.escape("mounts.0: [] is too short")),
|
||||
+ (
|
||||
+ {"mounts": [[]]},
|
||||
+ re.escape("mounts.0: [] ") + test_helpers.SCHEMA_EMPTY_ERROR,
|
||||
+ ),
|
||||
# Disallow more than 6 items per mount entry
|
||||
({"mounts": [["1"] * 7]}, "mounts.0:.* is too long"),
|
||||
# Disallow mount_default_fields will anything other than 6 items
|
||||
diff --git a/tests/unittests/config/test_cc_package_update_upgrade_install.py b/tests/unittests/config/test_cc_package_update_upgrade_install.py
|
||||
index 9ba7f17..b3d43a1 100644
|
||||
--- a/tests/unittests/config/test_cc_package_update_upgrade_install.py
|
||||
+++ b/tests/unittests/config/test_cc_package_update_upgrade_install.py
|
||||
@@ -14,6 +14,7 @@ from cloudinit.config.schema import (
|
||||
from cloudinit.distros import PackageInstallerError
|
||||
from cloudinit.subp import SubpResult
|
||||
from tests.unittests.helpers import skipUnlessJsonSchema
|
||||
+from tests.unittests.helpers import SCHEMA_EMPTY_ERROR
|
||||
from tests.unittests.util import get_cloud
|
||||
|
||||
|
||||
@@ -188,7 +189,7 @@ class TestPackageUpdateUpgradeSchema:
|
||||
# packages list with three entries (2 required)
|
||||
({"packages": ["p1", ["p2", "p3", "p4"]]}, ""),
|
||||
# empty packages list
|
||||
- ({"packages": []}, "is too short"),
|
||||
+ ({"packages": []}, SCHEMA_EMPTY_ERROR),
|
||||
(
|
||||
{"apt_update": False},
|
||||
(
|
||||
diff --git a/tests/unittests/config/test_cc_runcmd.py b/tests/unittests/config/test_cc_runcmd.py
|
||||
index a8636bb..f69cd9d 100644
|
||||
--- a/tests/unittests/config/test_cc_runcmd.py
|
||||
+++ b/tests/unittests/config/test_cc_runcmd.py
|
||||
@@ -14,6 +14,7 @@ from cloudinit.config.schema import (
|
||||
validate_cloudconfig_schema,
|
||||
)
|
||||
from tests.unittests.helpers import (
|
||||
+ SCHEMA_EMPTY_ERROR,
|
||||
FilesystemMockingTestCase,
|
||||
skipUnlessJsonSchema,
|
||||
)
|
||||
@@ -90,7 +91,7 @@ class TestRunCmdSchema:
|
||||
({"runcmd": ["echo bye", "echo bye"]}, None),
|
||||
# Invalid schemas
|
||||
({"runcmd": 1}, "1 is not of type 'array'"),
|
||||
- ({"runcmd": []}, r"runcmd: \[\] is too short"),
|
||||
+ ({"runcmd": []}, rf"runcmd: \[\] {SCHEMA_EMPTY_ERROR}"),
|
||||
(
|
||||
{
|
||||
"runcmd": [
|
||||
diff --git a/tests/unittests/config/test_cc_set_passwords.py b/tests/unittests/config/test_cc_set_passwords.py
|
||||
index 1a9fcd3..ef34a8c 100644
|
||||
--- a/tests/unittests/config/test_cc_set_passwords.py
|
||||
+++ b/tests/unittests/config/test_cc_set_passwords.py
|
||||
@@ -12,7 +12,11 @@ from cloudinit.config.schema import (
|
||||
get_schema,
|
||||
validate_cloudconfig_schema,
|
||||
)
|
||||
-from tests.unittests.helpers import does_not_raise, skipUnlessJsonSchema
|
||||
+from tests.unittests.helpers import (
|
||||
+ SCHEMA_EMPTY_ERROR,
|
||||
+ does_not_raise,
|
||||
+ skipUnlessJsonSchema,
|
||||
+)
|
||||
from tests.unittests.util import get_cloud
|
||||
|
||||
MODPATH = "cloudinit.config.cc_set_passwords."
|
||||
@@ -718,7 +722,8 @@ class TestSetPasswordsSchema:
|
||||
(
|
||||
{"chpasswd": {"list": []}},
|
||||
pytest.raises(
|
||||
- SchemaValidationError, match=r"\[\] is too short"
|
||||
+ SchemaValidationError,
|
||||
+ match=rf"\[\] {SCHEMA_EMPTY_ERROR}",
|
||||
),
|
||||
),
|
||||
],
|
||||
diff --git a/tests/unittests/config/test_cc_snap.py b/tests/unittests/config/test_cc_snap.py
|
||||
index 65088dd..573ade9 100644
|
||||
--- a/tests/unittests/config/test_cc_snap.py
|
||||
+++ b/tests/unittests/config/test_cc_snap.py
|
||||
@@ -14,7 +14,12 @@ from cloudinit.config.schema import (
|
||||
get_schema,
|
||||
validate_cloudconfig_schema,
|
||||
)
|
||||
-from tests.unittests.helpers import CiTestCase, mock, skipUnlessJsonSchema
|
||||
+from tests.unittests.helpers import (
|
||||
+ SCHEMA_EMPTY_ERROR,
|
||||
+ CiTestCase,
|
||||
+ mock,
|
||||
+ skipUnlessJsonSchema,
|
||||
+)
|
||||
from tests.unittests.util import get_cloud
|
||||
|
||||
M_PATH = "cloudinit.config.cc_snap."
|
||||
@@ -288,15 +293,18 @@ class TestSnapSchema:
|
||||
{"snap": {"commands": ["ls"], "invalid-key": ""}},
|
||||
"Additional properties are not allowed",
|
||||
),
|
||||
- ({"snap": {}}, "{} does not have enough properties"),
|
||||
+ ({"snap": {}}, f"{{}} {SCHEMA_EMPTY_ERROR}"),
|
||||
(
|
||||
{"snap": {"commands": "broken"}},
|
||||
"'broken' is not of type 'object', 'array'",
|
||||
),
|
||||
- ({"snap": {"commands": []}}, r"snap.commands: \[\] is too short"),
|
||||
+ (
|
||||
+ {"snap": {"commands": []}},
|
||||
+ rf"snap.commands: \[\] {SCHEMA_EMPTY_ERROR}",
|
||||
+ ),
|
||||
(
|
||||
{"snap": {"commands": {}}},
|
||||
- r"snap.commands: {} does not have enough properties",
|
||||
+ rf"snap.commands: {{}} {SCHEMA_EMPTY_ERROR}",
|
||||
),
|
||||
({"snap": {"commands": [123]}}, ""),
|
||||
({"snap": {"commands": {"01": 123}}}, ""),
|
||||
@@ -311,10 +319,10 @@ class TestSnapSchema:
|
||||
{"snap": {"assertions": "broken"}},
|
||||
"'broken' is not of type 'object', 'array'",
|
||||
),
|
||||
- ({"snap": {"assertions": []}}, r"\[\] is too short"),
|
||||
+ ({"snap": {"assertions": []}}, rf"\[\] {SCHEMA_EMPTY_ERROR}"),
|
||||
(
|
||||
{"snap": {"assertions": {}}},
|
||||
- r"\{} does not have enough properties",
|
||||
+ rf"\{{}} {SCHEMA_EMPTY_ERROR}",
|
||||
),
|
||||
],
|
||||
)
|
||||
diff --git a/tests/unittests/config/test_cc_write_files.py b/tests/unittests/config/test_cc_write_files.py
|
||||
index 210edf7..ea9cf8a 100644
|
||||
--- a/tests/unittests/config/test_cc_write_files.py
|
||||
+++ b/tests/unittests/config/test_cc_write_files.py
|
||||
@@ -18,6 +18,7 @@ from cloudinit.config.schema import (
|
||||
validate_cloudconfig_schema,
|
||||
)
|
||||
from tests.unittests.helpers import (
|
||||
+ SCHEMA_EMPTY_ERROR,
|
||||
CiTestCase,
|
||||
FilesystemMockingTestCase,
|
||||
skipUnlessJsonSchema,
|
||||
@@ -222,7 +223,10 @@ class TestWriteFilesSchema:
|
||||
[
|
||||
# Top-level write_files type validation
|
||||
({"write_files": 1}, "write_files: 1 is not of type 'array'"),
|
||||
- ({"write_files": []}, re.escape("write_files: [] is too short")),
|
||||
+ (
|
||||
+ {"write_files": []},
|
||||
+ re.escape("write_files: [] ") + SCHEMA_EMPTY_ERROR,
|
||||
+ ),
|
||||
(
|
||||
{"write_files": [{}]},
|
||||
"write_files.0: 'path' is a required property",
|
||||
diff --git a/tests/unittests/config/test_cc_yum_add_repo.py b/tests/unittests/config/test_cc_yum_add_repo.py
|
||||
index d2c2912..e7392f2 100644
|
||||
--- a/tests/unittests/config/test_cc_yum_add_repo.py
|
||||
+++ b/tests/unittests/config/test_cc_yum_add_repo.py
|
||||
@@ -139,7 +139,7 @@ class TestAddYumRepoSchema:
|
||||
),
|
||||
(
|
||||
{"yum_repos": {}},
|
||||
- re.escape("yum_repos: {} does not have enough properties"),
|
||||
+ re.escape("yum_repos: {} ") + helpers.SCHEMA_EMPTY_ERROR,
|
||||
),
|
||||
# baseurl required
|
||||
(
|
||||
diff --git a/tests/unittests/helpers.py b/tests/unittests/helpers.py
|
||||
index 96f407f..42cc2e9 100644
|
||||
--- a/tests/unittests/helpers.py
|
||||
+++ b/tests/unittests/helpers.py
|
||||
@@ -47,6 +47,14 @@ except ImportError:
|
||||
HAS_APT_PKG = False
|
||||
|
||||
|
||||
+# Used by tests to verify the error message when a jsonschema structure
|
||||
+# is empty but should not be.
|
||||
+# Version 4.20.0 of jsonschema changed the error messages for empty structures.
|
||||
+SCHEMA_EMPTY_ERROR = (
|
||||
+ "(is too short|should be non-empty|does not have enough properties)"
|
||||
+)
|
||||
+
|
||||
+
|
||||
# Makes the old path start
|
||||
# with new base instead of whatever
|
||||
# it previously had
|
||||
diff --git a/tests/unittests/test_merging.py b/tests/unittests/test_merging.py
|
||||
index 891031e..52abaa7 100644
|
||||
--- a/tests/unittests/test_merging.py
|
||||
+++ b/tests/unittests/test_merging.py
|
||||
@@ -270,7 +270,7 @@ class TestMergingSchema:
|
||||
[
|
||||
({"merge_how": "list()+dict()+str()"}, None),
|
||||
({"merge_type": "list()+dict()+str()"}, None),
|
||||
- ({"merge_how": []}, "\\[\\] is too short"),
|
||||
+ ({"merge_how": []}, f"\\[\\] {helpers.SCHEMA_EMPTY_ERROR}"),
|
||||
(
|
||||
{"merge_how": {"name": "list", "settings": ["append"]}},
|
||||
"is not of type",
|
||||
--
|
||||
2.27.0
|
||||
72
backport-test-fix-disable_sysfs_net-mock.patch
Normal file
72
backport-test-fix-disable_sysfs_net-mock.patch
Normal file
@ -0,0 +1,72 @@
|
||||
From dc0eafbc7d88be99e11301081adb41ad7b50338e Mon Sep 17 00:00:00 2001
|
||||
From: James Falcon <james.falcon@canonical.com>
|
||||
Date: Mon, 11 Mar 2024 19:37:48 -0500
|
||||
Subject: [PATCH] test: fix `disable_sysfs_net` mock (#5065)
|
||||
|
||||
The fixture parametrization ability added in 9baf31c doesn't work
|
||||
as expected. When you have a session-wide fixture, the setup is run
|
||||
once, then further invocations of the fixture (including autouse) uses a
|
||||
cached version of the fixture. Teardown for the session fixture happens
|
||||
at the end of all test runs. This also applies to mock patching. Since
|
||||
the mock patching happens only once, parametrizing the fixture to yield
|
||||
without patching doesn't undo the initial mock setup; the
|
||||
parametrization of `disable_sys_net` effectively does nothing.
|
||||
|
||||
The good news is that patches stack, so current tests that patch
|
||||
`get_sys_class_path` differently will still work fine. If we need to
|
||||
disable the patching entirely, that is also possible by saving the
|
||||
original `get_sys_class_path` before applying the global disable mock,
|
||||
then having a separate mock that has a side effect of calling
|
||||
the original function.
|
||||
|
||||
Reference:https://github.com/canonical/cloud-init/commit/dc0eafbc7d88be99e11301081adb41ad7b50338e
|
||||
Conflict:NA
|
||||
---
|
||||
tests/unittests/conftest.py | 14 ++------------
|
||||
tests/unittests/net/test_init.py | 5 +----
|
||||
2 files changed, 3 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/tests/unittests/conftest.py b/tests/unittests/conftest.py
|
||||
index 22bc189..bdd21c3 100644
|
||||
--- a/tests/unittests/conftest.py
|
||||
+++ b/tests/unittests/conftest.py
|
||||
@@ -62,18 +62,8 @@ def fake_filesystem(mocker, tmpdir):
|
||||
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
-def disable_sysfs_net(request, tmpdir_factory):
|
||||
- """Avoid tests which read the undertying host's /syc/class/net.
|
||||
-
|
||||
- To allow unobscured reads of /sys/class/net on the host we can
|
||||
- parametrize the fixture with:
|
||||
-
|
||||
- @pytest.mark.parametrize("disable_sysfs_net", [False], indirect=True)
|
||||
- """
|
||||
- if hasattr(request, "param") and getattr(request, "param") is False:
|
||||
- # Test disabled this fixture, perform no mocks.
|
||||
- yield
|
||||
- return
|
||||
+def disable_sysfs_net(tmpdir_factory):
|
||||
+ """Avoid tests which read the underlying host's /syc/class/net."""
|
||||
mock_sysfs = f"{tmpdir_factory.mktemp('sysfs')}/"
|
||||
with mock.patch(
|
||||
"cloudinit.net.get_sys_class_path", return_value=mock_sysfs
|
||||
diff --git a/tests/unittests/net/test_init.py b/tests/unittests/net/test_init.py
|
||||
index a7b75ab..51e54d0 100644
|
||||
--- a/tests/unittests/net/test_init.py
|
||||
+++ b/tests/unittests/net/test_init.py
|
||||
@@ -42,10 +42,7 @@ class TestSysDevPath:
|
||||
|
||||
class TestReadSysNet:
|
||||
@pytest.fixture(autouse=True)
|
||||
- @pytest.mark.parametrize(
|
||||
- "disable_sysfs_net", [False], indirect=["disable_sysfs_net"]
|
||||
- )
|
||||
- def setup(self, disable_sysfs_net, tmpdir_factory):
|
||||
+ def setup(self, tmpdir_factory):
|
||||
# We mock invididual numbered tmpdirs here because these tests write
|
||||
# to the sysfs directory and stale test artifacts break later tests.
|
||||
mock_sysfs = f"{tmpdir_factory.mktemp('sysfs', numbered=True)}/"
|
||||
--
|
||||
2.43.0
|
||||
|
||||
37
backport-test-fix-tmpdir-in-test_cc_apk_configure.patch
Normal file
37
backport-test-fix-tmpdir-in-test_cc_apk_configure.patch
Normal file
@ -0,0 +1,37 @@
|
||||
From 4ed78b116774dcbf78cfc556c823bdb7f8384068 Mon Sep 17 00:00:00 2001
|
||||
From: James Falcon <james.falcon@canonical.com>
|
||||
Date: Tue, 20 Feb 2024 11:08:13 -0600
|
||||
Subject: [PATCH] test: fix tmpdir in test_cc_apk_configure (#4914)
|
||||
|
||||
cc_apk_configure uses temp_utils.py, which has special logic to return
|
||||
if the user is root that can't be retargeted using our current fixtures.
|
||||
Fix it by setting that tmpdir in the test setup.
|
||||
---
|
||||
tests/unittests/config/test_cc_apk_configure.py | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tests/unittests/config/test_cc_apk_configure.py b/tests/unittests/config/test_cc_apk_configure.py
|
||||
index 72ed82242ee..47777b4701a 100644
|
||||
--- a/tests/unittests/config/test_cc_apk_configure.py
|
||||
+++ b/tests/unittests/config/test_cc_apk_configure.py
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
import pytest
|
||||
|
||||
-from cloudinit import cloud, helpers, util
|
||||
+from cloudinit import cloud, helpers, temp_utils, util
|
||||
from cloudinit.config import cc_apk_configure
|
||||
from cloudinit.config.schema import (
|
||||
SchemaValidationError,
|
||||
@@ -60,6 +60,11 @@ def setUp(self):
|
||||
self.name = "apk_configure"
|
||||
self.cloud = cloud.Cloud(None, self.paths, None, None, None)
|
||||
self.args = []
|
||||
+ temp_utils._TMPDIR = self.new_root
|
||||
+
|
||||
+ def tearDown(self):
|
||||
+ super().tearDown()
|
||||
+ temp_utils._TMPDIR = None
|
||||
|
||||
@mock.patch(CC_APK + "._write_repositories_file")
|
||||
def test_no_repo_settings(self, m_write_repos):
|
||||
672
backport-tests-drop-CiTestCase-and-convert-to-pytest.patch
Normal file
672
backport-tests-drop-CiTestCase-and-convert-to-pytest.patch
Normal file
@ -0,0 +1,672 @@
|
||||
From 9baf31c7108b031d469e6476b949e042aba249ea Mon Sep 17 00:00:00 2001
|
||||
From: Chad Smith <chad.smith@canonical.com>
|
||||
Date: Wed, 6 Mar 2024 09:47:36 -0700
|
||||
Subject: [PATCH] tests: drop CiTestCase and convert to pytest
|
||||
|
||||
Prevent disable_sysfs_net fixture from impacting TestSysDevPath
|
||||
and TestReadSysNet in order to avoid shared mocks of /sys/class/net.
|
||||
This avoid test artifact pollution for TestReadSysNet.
|
||||
|
||||
Adapt the following tests, dropping CiTestCase to use pytest:
|
||||
TestDHCPDiscoveryClean, TestSysDevPath, TestReadSysNet,
|
||||
TestGenerateFallbackConfig, TestNetFailOver, TestConvertNetJson
|
||||
|
||||
Fixes GH-4973
|
||||
|
||||
Reference:https://github.com/canonical/cloud-init/commit/9baf31c7108b031d469e6476b949e042aba249ea
|
||||
Confilct:don't change test_dhcp.py, otherwise, it will introduce many test case failures (eg.
|
||||
test_provided_nic_does_not_exist). Some failed tests will be deleted in
|
||||
21b2b6e4423b0fec325b32042c05ef4274cdd301.
|
||||
---
|
||||
tests/unittests/net/test_init.py | 298 +++++++++---------
|
||||
.../sources/helpers/test_openstack.py | 17 +-
|
||||
2 files changed, 149 insertions(+), 166 deletions(-)
|
||||
|
||||
diff --git a/tests/unittests/net/test_init.py b/tests/unittests/net/test_init.py
|
||||
index 561d515..a7b75ab 100644
|
||||
--- a/tests/unittests/net/test_init.py
|
||||
+++ b/tests/unittests/net/test_init.py
|
||||
@@ -17,49 +17,55 @@ from cloudinit import subp
|
||||
from cloudinit.net.ephemeral import EphemeralIPv4Network, EphemeralIPv6Network
|
||||
from cloudinit.subp import ProcessExecutionError
|
||||
from cloudinit.util import ensure_file, write_file
|
||||
-from tests.unittests.helpers import CiTestCase, ResponsesTestCase
|
||||
+from tests.unittests.helpers import (
|
||||
+ CiTestCase,
|
||||
+ ResponsesTestCase,
|
||||
+ random_string,
|
||||
+)
|
||||
from tests.unittests.util import MockDistro
|
||||
|
||||
|
||||
-class TestSysDevPath(CiTestCase):
|
||||
+class TestSysDevPath:
|
||||
def test_sys_dev_path(self):
|
||||
"""sys_dev_path returns a path under SYS_CLASS_NET for a device."""
|
||||
dev = "something"
|
||||
path = "attribute"
|
||||
- expected = net.SYS_CLASS_NET + dev + "/" + path
|
||||
- self.assertEqual(expected, net.sys_dev_path(dev, path))
|
||||
+ expected = net.get_sys_class_path() + dev + "/" + path
|
||||
+ assert expected == net.sys_dev_path(dev, path)
|
||||
|
||||
def test_sys_dev_path_without_path(self):
|
||||
"""When path param isn't provided it defaults to empty string."""
|
||||
dev = "something"
|
||||
- expected = net.SYS_CLASS_NET + dev + "/"
|
||||
- self.assertEqual(expected, net.sys_dev_path(dev))
|
||||
-
|
||||
+ expected = net.get_sys_class_path() + dev + "/"
|
||||
+ assert expected == net.sys_dev_path(dev)
|
||||
|
||||
-class TestReadSysNet(CiTestCase):
|
||||
- with_logs = True
|
||||
|
||||
- def setUp(self):
|
||||
- super(TestReadSysNet, self).setUp()
|
||||
- sys_mock = mock.patch("cloudinit.net.get_sys_class_path")
|
||||
- self.m_sys_path = sys_mock.start()
|
||||
- self.sysdir = self.tmp_dir() + "/"
|
||||
- self.m_sys_path.return_value = self.sysdir
|
||||
- self.addCleanup(sys_mock.stop)
|
||||
+class TestReadSysNet:
|
||||
+ @pytest.fixture(autouse=True)
|
||||
+ @pytest.mark.parametrize(
|
||||
+ "disable_sysfs_net", [False], indirect=["disable_sysfs_net"]
|
||||
+ )
|
||||
+ def setup(self, disable_sysfs_net, tmpdir_factory):
|
||||
+ # We mock invididual numbered tmpdirs here because these tests write
|
||||
+ # to the sysfs directory and stale test artifacts break later tests.
|
||||
+ mock_sysfs = f"{tmpdir_factory.mktemp('sysfs', numbered=True)}/"
|
||||
+ with mock.patch(
|
||||
+ "cloudinit.net.get_sys_class_path", return_value=mock_sysfs
|
||||
+ ):
|
||||
+ self.sysdir = mock_sysfs
|
||||
+ yield
|
||||
|
||||
def test_read_sys_net_strips_contents_of_sys_path(self):
|
||||
"""read_sys_net strips whitespace from the contents of a sys file."""
|
||||
content = "some stuff with trailing whitespace\t\r\n"
|
||||
write_file(os.path.join(self.sysdir, "dev", "attr"), content)
|
||||
- self.assertEqual(content.strip(), net.read_sys_net("dev", "attr"))
|
||||
+ assert content.strip() == net.read_sys_net("dev", "attr")
|
||||
|
||||
def test_read_sys_net_reraises_oserror(self):
|
||||
"""read_sys_net raises OSError/IOError when file doesn't exist."""
|
||||
# Non-specific Exception because versions of python OSError vs IOError.
|
||||
- with self.assertRaises(Exception) as context_manager: # noqa: H202
|
||||
+ with pytest.raises(Exception, match="No such file or directory"):
|
||||
net.read_sys_net("dev", "attr")
|
||||
- error = context_manager.exception
|
||||
- self.assertIn("No such file or directory", str(error))
|
||||
|
||||
def test_read_sys_net_handles_error_with_on_enoent(self):
|
||||
"""read_sys_net handles OSError/IOError with on_enoent if provided."""
|
||||
@@ -70,30 +76,27 @@ class TestReadSysNet(CiTestCase):
|
||||
|
||||
net.read_sys_net("dev", "attr", on_enoent=on_enoent)
|
||||
error = handled_errors[0]
|
||||
- self.assertIsInstance(error, Exception)
|
||||
- self.assertIn("No such file or directory", str(error))
|
||||
+ assert isinstance(error, Exception)
|
||||
+ assert "No such file or directory" in str(error)
|
||||
|
||||
def test_read_sys_net_translates_content(self):
|
||||
"""read_sys_net translates content when translate dict is provided."""
|
||||
content = "you're welcome\n"
|
||||
write_file(os.path.join(self.sysdir, "dev", "attr"), content)
|
||||
translate = {"you're welcome": "de nada"}
|
||||
- self.assertEqual(
|
||||
- "de nada", net.read_sys_net("dev", "attr", translate=translate)
|
||||
+ assert "de nada" == net.read_sys_net(
|
||||
+ "dev", "attr", translate=translate
|
||||
)
|
||||
|
||||
- def test_read_sys_net_errors_on_translation_failures(self):
|
||||
+ def test_read_sys_net_errors_on_translation_failures(self, caplog):
|
||||
"""read_sys_net raises a KeyError and logs details on failure."""
|
||||
content = "you're welcome\n"
|
||||
write_file(os.path.join(self.sysdir, "dev", "attr"), content)
|
||||
- with self.assertRaises(KeyError) as context_manager:
|
||||
+ with pytest.raises(KeyError, match='"you\'re welcome"'):
|
||||
net.read_sys_net("dev", "attr", translate={})
|
||||
- error = context_manager.exception
|
||||
- self.assertEqual('"you\'re welcome"', str(error))
|
||||
- self.assertIn(
|
||||
+ assert (
|
||||
"Found unexpected (not translatable) value 'you're welcome' in "
|
||||
- "'{0}dev/attr".format(self.sysdir),
|
||||
- self.logs.getvalue(),
|
||||
+ "'{0}dev/attr".format(self.sysdir) in caplog.text
|
||||
)
|
||||
|
||||
def test_read_sys_net_handles_handles_with_onkeyerror(self):
|
||||
@@ -107,63 +110,63 @@ class TestReadSysNet(CiTestCase):
|
||||
|
||||
net.read_sys_net("dev", "attr", translate={}, on_keyerror=on_keyerror)
|
||||
error = handled_errors[0]
|
||||
- self.assertIsInstance(error, KeyError)
|
||||
- self.assertEqual('"you\'re welcome"', str(error))
|
||||
+ assert isinstance(error, KeyError)
|
||||
+ assert '"you\'re welcome"' == str(error)
|
||||
|
||||
def test_read_sys_net_safe_false_on_translate_failure(self):
|
||||
"""read_sys_net_safe returns False on translation failures."""
|
||||
content = "you're welcome\n"
|
||||
write_file(os.path.join(self.sysdir, "dev", "attr"), content)
|
||||
- self.assertFalse(net.read_sys_net_safe("dev", "attr", translate={}))
|
||||
+ assert not net.read_sys_net_safe("dev", "attr", translate={})
|
||||
|
||||
def test_read_sys_net_safe_returns_false_on_noent_failure(self):
|
||||
"""read_sys_net_safe returns False on file not found failures."""
|
||||
- self.assertFalse(net.read_sys_net_safe("dev", "attr"))
|
||||
+ assert not net.read_sys_net_safe("dev", "attr")
|
||||
|
||||
def test_read_sys_net_int_returns_none_on_error(self):
|
||||
"""read_sys_net_safe returns None on failures."""
|
||||
- self.assertFalse(net.read_sys_net_int("dev", "attr"))
|
||||
+ assert not net.read_sys_net_int("dev", "attr")
|
||||
|
||||
def test_read_sys_net_int_returns_none_on_valueerror(self):
|
||||
"""read_sys_net_safe returns None when content is not an int."""
|
||||
write_file(os.path.join(self.sysdir, "dev", "attr"), "NOTINT\n")
|
||||
- self.assertFalse(net.read_sys_net_int("dev", "attr"))
|
||||
+ assert not net.read_sys_net_int("dev", "attr")
|
||||
|
||||
def test_read_sys_net_int_returns_integer_from_content(self):
|
||||
"""read_sys_net_safe returns None on failures."""
|
||||
write_file(os.path.join(self.sysdir, "dev", "attr"), "1\n")
|
||||
- self.assertEqual(1, net.read_sys_net_int("dev", "attr"))
|
||||
+ assert 1 == net.read_sys_net_int("dev", "attr")
|
||||
|
||||
def test_is_up_true(self):
|
||||
"""is_up is True if sys/net/devname/operstate is 'up' or 'unknown'."""
|
||||
for state in ["up", "unknown"]:
|
||||
write_file(os.path.join(self.sysdir, "eth0", "operstate"), state)
|
||||
- self.assertTrue(net.is_up("eth0"))
|
||||
+ assert net.is_up("eth0")
|
||||
|
||||
def test_is_up_false(self):
|
||||
"""is_up is False if sys/net/devname/operstate is 'down' or invalid."""
|
||||
for state in ["down", "incomprehensible"]:
|
||||
write_file(os.path.join(self.sysdir, "eth0", "operstate"), state)
|
||||
- self.assertFalse(net.is_up("eth0"))
|
||||
+ assert not net.is_up("eth0")
|
||||
|
||||
def test_is_bridge(self):
|
||||
"""is_bridge is True when /sys/net/devname/bridge exists."""
|
||||
- self.assertFalse(net.is_bridge("eth0"))
|
||||
+ assert not net.is_bridge("eth0")
|
||||
ensure_file(os.path.join(self.sysdir, "eth0", "bridge"))
|
||||
- self.assertTrue(net.is_bridge("eth0"))
|
||||
+ assert net.is_bridge("eth0")
|
||||
|
||||
def test_is_bond(self):
|
||||
"""is_bond is True when /sys/net/devname/bonding exists."""
|
||||
- self.assertFalse(net.is_bond("eth0"))
|
||||
+ assert not net.is_bond("eth0")
|
||||
ensure_file(os.path.join(self.sysdir, "eth0", "bonding"))
|
||||
- self.assertTrue(net.is_bond("eth0"))
|
||||
+ assert net.is_bond("eth0")
|
||||
|
||||
def test_get_master(self):
|
||||
"""get_master returns the path when /sys/net/devname/master exists."""
|
||||
- self.assertIsNone(net.get_master("enP1s1"))
|
||||
+ assert net.get_master("enP1s1") is None
|
||||
master_path = os.path.join(self.sysdir, "enP1s1", "master")
|
||||
ensure_file(master_path)
|
||||
- self.assertEqual(master_path, net.get_master("enP1s1"))
|
||||
+ assert master_path == net.get_master("enP1s1")
|
||||
|
||||
def test_master_is_bridge_or_bond(self):
|
||||
bridge_mac = "aa:bb:cc:aa:bb:cc"
|
||||
@@ -173,8 +176,8 @@ class TestReadSysNet(CiTestCase):
|
||||
write_file(os.path.join(self.sysdir, "eth1", "address"), bridge_mac)
|
||||
write_file(os.path.join(self.sysdir, "eth2", "address"), bond_mac)
|
||||
|
||||
- self.assertFalse(net.master_is_bridge_or_bond("eth1"))
|
||||
- self.assertFalse(net.master_is_bridge_or_bond("eth2"))
|
||||
+ assert not net.master_is_bridge_or_bond("eth1")
|
||||
+ assert not net.master_is_bridge_or_bond("eth2")
|
||||
|
||||
# masters without bridge/bonding => False
|
||||
write_file(os.path.join(self.sysdir, "br0", "address"), bridge_mac)
|
||||
@@ -183,15 +186,15 @@ class TestReadSysNet(CiTestCase):
|
||||
os.symlink("../br0", os.path.join(self.sysdir, "eth1", "master"))
|
||||
os.symlink("../bond0", os.path.join(self.sysdir, "eth2", "master"))
|
||||
|
||||
- self.assertFalse(net.master_is_bridge_or_bond("eth1"))
|
||||
- self.assertFalse(net.master_is_bridge_or_bond("eth2"))
|
||||
+ assert not net.master_is_bridge_or_bond("eth1")
|
||||
+ assert not net.master_is_bridge_or_bond("eth2")
|
||||
|
||||
# masters with bridge/bonding => True
|
||||
write_file(os.path.join(self.sysdir, "br0", "bridge"), "")
|
||||
write_file(os.path.join(self.sysdir, "bond0", "bonding"), "")
|
||||
|
||||
- self.assertTrue(net.master_is_bridge_or_bond("eth1"))
|
||||
- self.assertTrue(net.master_is_bridge_or_bond("eth2"))
|
||||
+ assert net.master_is_bridge_or_bond("eth1")
|
||||
+ assert net.master_is_bridge_or_bond("eth2")
|
||||
|
||||
def test_master_is_openvswitch(self):
|
||||
ovs_mac = "bb:cc:aa:bb:cc:aa"
|
||||
@@ -199,7 +202,7 @@ class TestReadSysNet(CiTestCase):
|
||||
# No master => False
|
||||
write_file(os.path.join(self.sysdir, "eth1", "address"), ovs_mac)
|
||||
|
||||
- self.assertFalse(net.master_is_bridge_or_bond("eth1"))
|
||||
+ assert not net.master_is_bridge_or_bond("eth1")
|
||||
|
||||
# masters without ovs-system => False
|
||||
write_file(os.path.join(self.sysdir, "ovs-system", "address"), ovs_mac)
|
||||
@@ -208,7 +211,7 @@ class TestReadSysNet(CiTestCase):
|
||||
"../ovs-system", os.path.join(self.sysdir, "eth1", "master")
|
||||
)
|
||||
|
||||
- self.assertFalse(net.master_is_openvswitch("eth1"))
|
||||
+ assert not net.master_is_openvswitch("eth1")
|
||||
|
||||
# masters with ovs-system => True
|
||||
os.symlink(
|
||||
@@ -216,15 +219,15 @@ class TestReadSysNet(CiTestCase):
|
||||
os.path.join(self.sysdir, "eth1", "upper_ovs-system"),
|
||||
)
|
||||
|
||||
- self.assertTrue(net.master_is_openvswitch("eth1"))
|
||||
+ assert net.master_is_openvswitch("eth1")
|
||||
|
||||
def test_is_vlan(self):
|
||||
"""is_vlan is True when /sys/net/devname/uevent has DEVTYPE=vlan."""
|
||||
ensure_file(os.path.join(self.sysdir, "eth0", "uevent"))
|
||||
- self.assertFalse(net.is_vlan("eth0"))
|
||||
+ assert not net.is_vlan("eth0")
|
||||
content = "junk\nDEVTYPE=vlan\njunk\n"
|
||||
write_file(os.path.join(self.sysdir, "eth0", "uevent"), content)
|
||||
- self.assertTrue(net.is_vlan("eth0"))
|
||||
+ assert net.is_vlan("eth0")
|
||||
|
||||
|
||||
class TestGenerateFallbackConfig(CiTestCase):
|
||||
@@ -1453,134 +1456,121 @@ class TestExtractPhysdevs(CiTestCase):
|
||||
net.extract_physdevs({"version": 3, "awesome_config": []})
|
||||
|
||||
|
||||
-class TestNetFailOver(CiTestCase):
|
||||
- def setUp(self):
|
||||
- super(TestNetFailOver, self).setUp()
|
||||
- self.add_patch("cloudinit.net.util", "m_util")
|
||||
- self.add_patch("cloudinit.net.read_sys_net", "m_read_sys_net")
|
||||
- self.add_patch("cloudinit.net.device_driver", "m_device_driver")
|
||||
+class TestNetFailOver:
|
||||
+ @pytest.fixture(autouse=True)
|
||||
+ def setup(self, mocker):
|
||||
+ mocker.patch("cloudinit.net.util")
|
||||
+ self.device_driver = mocker.patch("cloudinit.net.device_driver")
|
||||
+ self.read_sys_net = mocker.patch("cloudinit.net.read_sys_net")
|
||||
|
||||
def test_get_dev_features(self):
|
||||
- devname = self.random_string()
|
||||
- features = self.random_string()
|
||||
- self.m_read_sys_net.return_value = features
|
||||
+ devname = random_string()
|
||||
+ features = random_string()
|
||||
+ self.read_sys_net.return_value = features
|
||||
|
||||
- self.assertEqual(features, net.get_dev_features(devname))
|
||||
- self.assertEqual(1, self.m_read_sys_net.call_count)
|
||||
- self.assertEqual(
|
||||
- mock.call(devname, "device/features"),
|
||||
- self.m_read_sys_net.call_args_list[0],
|
||||
- )
|
||||
+ assert features == net.get_dev_features(devname)
|
||||
+ assert 1 == self.read_sys_net.call_count
|
||||
+ self.read_sys_net.assert_called_once_with(devname, "device/features")
|
||||
|
||||
def test_get_dev_features_none_returns_empty_string(self):
|
||||
- devname = self.random_string()
|
||||
- self.m_read_sys_net.side_effect = Exception("error")
|
||||
- self.assertEqual("", net.get_dev_features(devname))
|
||||
- self.assertEqual(1, self.m_read_sys_net.call_count)
|
||||
- self.assertEqual(
|
||||
- mock.call(devname, "device/features"),
|
||||
- self.m_read_sys_net.call_args_list[0],
|
||||
- )
|
||||
+ devname = random_string()
|
||||
+ self.read_sys_net.side_effect = Exception("error")
|
||||
+ assert "" == net.get_dev_features(devname)
|
||||
+ assert 1 == self.read_sys_net.call_count
|
||||
+ self.read_sys_net.assert_called_once_with(devname, "device/features")
|
||||
|
||||
@mock.patch("cloudinit.net.get_dev_features")
|
||||
def test_has_netfail_standby_feature(self, m_dev_features):
|
||||
- devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
standby_features = ("0" * 62) + "1" + "0"
|
||||
m_dev_features.return_value = standby_features
|
||||
- self.assertTrue(net.has_netfail_standby_feature(devname))
|
||||
+ assert net.has_netfail_standby_feature(devname)
|
||||
|
||||
@mock.patch("cloudinit.net.get_dev_features")
|
||||
def test_has_netfail_standby_feature_short_is_false(self, m_dev_features):
|
||||
- devname = self.random_string()
|
||||
- standby_features = self.random_string()
|
||||
+ devname = random_string()
|
||||
+ standby_features = random_string()
|
||||
m_dev_features.return_value = standby_features
|
||||
- self.assertFalse(net.has_netfail_standby_feature(devname))
|
||||
+ assert not net.has_netfail_standby_feature(devname)
|
||||
|
||||
@mock.patch("cloudinit.net.get_dev_features")
|
||||
def test_has_netfail_standby_feature_not_present_is_false(
|
||||
self, m_dev_features
|
||||
):
|
||||
- devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
standby_features = "0" * 64
|
||||
m_dev_features.return_value = standby_features
|
||||
- self.assertFalse(net.has_netfail_standby_feature(devname))
|
||||
+ assert not net.has_netfail_standby_feature(devname)
|
||||
|
||||
@mock.patch("cloudinit.net.get_dev_features")
|
||||
def test_has_netfail_standby_feature_no_features_is_false(
|
||||
self, m_dev_features
|
||||
):
|
||||
- devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
standby_features = None
|
||||
m_dev_features.return_value = standby_features
|
||||
- self.assertFalse(net.has_netfail_standby_feature(devname))
|
||||
+ assert not net.has_netfail_standby_feature(devname)
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
def test_is_netfail_master(self, m_exists, m_standby):
|
||||
- devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
driver = "virtio_net"
|
||||
m_exists.return_value = False # no master sysfs attr
|
||||
m_standby.return_value = True # has standby feature flag
|
||||
- self.assertTrue(net.is_netfail_master(devname, driver))
|
||||
+ assert net.is_netfail_master(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.sys_dev_path")
|
||||
def test_is_netfail_master_checks_master_attr(self, m_sysdev):
|
||||
- devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
driver = "virtio_net"
|
||||
- m_sysdev.return_value = self.random_string()
|
||||
- self.assertFalse(net.is_netfail_master(devname, driver))
|
||||
- self.assertEqual(1, m_sysdev.call_count)
|
||||
- self.assertEqual(
|
||||
- mock.call(devname, path="master"), m_sysdev.call_args_list[0]
|
||||
- )
|
||||
+ m_sysdev.return_value = random_string()
|
||||
+ assert not net.is_netfail_master(devname, driver)
|
||||
+ assert 1 == m_sysdev.call_count
|
||||
+ m_sysdev.assert_called_once_with(devname, path="master")
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
def test_is_netfail_master_wrong_driver(self, m_exists, m_standby):
|
||||
- devname = self.random_string()
|
||||
- driver = self.random_string()
|
||||
- self.assertFalse(net.is_netfail_master(devname, driver))
|
||||
+ devname = random_string()
|
||||
+ driver = random_string()
|
||||
+ assert not net.is_netfail_master(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
def test_is_netfail_master_has_master_attr(self, m_exists, m_standby):
|
||||
- devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
driver = "virtio_net"
|
||||
m_exists.return_value = True # has master sysfs attr
|
||||
- self.assertFalse(net.is_netfail_master(devname, driver))
|
||||
+ assert not net.is_netfail_master(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
def test_is_netfail_master_no_standby_feat(self, m_exists, m_standby):
|
||||
- devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
driver = "virtio_net"
|
||||
m_exists.return_value = False # no master sysfs attr
|
||||
m_standby.return_value = False # no standby feature flag
|
||||
- self.assertFalse(net.is_netfail_master(devname, driver))
|
||||
+ assert not net.is_netfail_master(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
@mock.patch("cloudinit.net.sys_dev_path")
|
||||
def test_is_netfail_primary(self, m_sysdev, m_exists, m_standby):
|
||||
- devname = self.random_string()
|
||||
- driver = self.random_string() # device not virtio_net
|
||||
- master_devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
+ driver = random_string() # device not virtio_net
|
||||
+ master_devname = random_string()
|
||||
m_sysdev.return_value = "%s/%s" % (
|
||||
- self.random_string(),
|
||||
+ random_string(),
|
||||
master_devname,
|
||||
)
|
||||
m_exists.return_value = True # has master sysfs attr
|
||||
- self.m_device_driver.return_value = "virtio_net" # master virtio_net
|
||||
+ self.device_driver.return_value = "virtio_net" # master virtio_net
|
||||
m_standby.return_value = True # has standby feature flag
|
||||
- self.assertTrue(net.is_netfail_primary(devname, driver))
|
||||
- self.assertEqual(1, self.m_device_driver.call_count)
|
||||
- self.assertEqual(
|
||||
- mock.call(master_devname), self.m_device_driver.call_args_list[0]
|
||||
- )
|
||||
- self.assertEqual(1, m_standby.call_count)
|
||||
- self.assertEqual(
|
||||
- mock.call(master_devname), m_standby.call_args_list[0]
|
||||
- )
|
||||
+ assert net.is_netfail_primary(devname, driver)
|
||||
+ self.device_driver.assert_called_once_with(master_devname)
|
||||
+ assert 1 == m_standby.call_count
|
||||
+ m_standby.assert_called_once_with(master_devname)
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
@@ -1588,18 +1578,18 @@ class TestNetFailOver(CiTestCase):
|
||||
def test_is_netfail_primary_wrong_driver(
|
||||
self, m_sysdev, m_exists, m_standby
|
||||
):
|
||||
- devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
driver = "virtio_net"
|
||||
- self.assertFalse(net.is_netfail_primary(devname, driver))
|
||||
+ assert not net.is_netfail_primary(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
@mock.patch("cloudinit.net.sys_dev_path")
|
||||
def test_is_netfail_primary_no_master(self, m_sysdev, m_exists, m_standby):
|
||||
- devname = self.random_string()
|
||||
- driver = self.random_string() # device not virtio_net
|
||||
+ devname = random_string()
|
||||
+ driver = random_string() # device not virtio_net
|
||||
m_exists.return_value = False # no master sysfs attr
|
||||
- self.assertFalse(net.is_netfail_primary(devname, driver))
|
||||
+ assert not net.is_netfail_primary(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
@@ -1607,16 +1597,16 @@ class TestNetFailOver(CiTestCase):
|
||||
def test_is_netfail_primary_bad_master(
|
||||
self, m_sysdev, m_exists, m_standby
|
||||
):
|
||||
- devname = self.random_string()
|
||||
- driver = self.random_string() # device not virtio_net
|
||||
- master_devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
+ driver = random_string() # device not virtio_net
|
||||
+ master_devname = random_string()
|
||||
m_sysdev.return_value = "%s/%s" % (
|
||||
- self.random_string(),
|
||||
+ random_string(),
|
||||
master_devname,
|
||||
)
|
||||
m_exists.return_value = True # has master sysfs attr
|
||||
- self.m_device_driver.return_value = "XXXX" # master not virtio_net
|
||||
- self.assertFalse(net.is_netfail_primary(devname, driver))
|
||||
+ self.device_driver.return_value = "XXXX" # master not virtio_net
|
||||
+ assert not net.is_netfail_primary(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
@@ -1624,77 +1614,77 @@ class TestNetFailOver(CiTestCase):
|
||||
def test_is_netfail_primary_no_standby(
|
||||
self, m_sysdev, m_exists, m_standby
|
||||
):
|
||||
- devname = self.random_string()
|
||||
- driver = self.random_string() # device not virtio_net
|
||||
- master_devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
+ driver = random_string() # device not virtio_net
|
||||
+ master_devname = random_string()
|
||||
m_sysdev.return_value = "%s/%s" % (
|
||||
- self.random_string(),
|
||||
+ random_string(),
|
||||
master_devname,
|
||||
)
|
||||
m_exists.return_value = True # has master sysfs attr
|
||||
- self.m_device_driver.return_value = "virtio_net" # master virtio_net
|
||||
+ self.device_driver.return_value = "virtio_net" # master virtio_net
|
||||
m_standby.return_value = False # master has no standby feature flag
|
||||
- self.assertFalse(net.is_netfail_primary(devname, driver))
|
||||
+ assert not net.is_netfail_primary(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
def test_is_netfail_standby(self, m_exists, m_standby):
|
||||
- devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
driver = "virtio_net"
|
||||
m_exists.return_value = True # has master sysfs attr
|
||||
m_standby.return_value = True # has standby feature flag
|
||||
- self.assertTrue(net.is_netfail_standby(devname, driver))
|
||||
+ assert net.is_netfail_standby(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
def test_is_netfail_standby_wrong_driver(self, m_exists, m_standby):
|
||||
- devname = self.random_string()
|
||||
- driver = self.random_string()
|
||||
- self.assertFalse(net.is_netfail_standby(devname, driver))
|
||||
+ devname = random_string()
|
||||
+ driver = random_string()
|
||||
+ assert not net.is_netfail_standby(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
def test_is_netfail_standby_no_master(self, m_exists, m_standby):
|
||||
- devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
driver = "virtio_net"
|
||||
m_exists.return_value = False # has master sysfs attr
|
||||
- self.assertFalse(net.is_netfail_standby(devname, driver))
|
||||
+ assert not net.is_netfail_standby(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.has_netfail_standby_feature")
|
||||
@mock.patch("cloudinit.net.os.path.exists")
|
||||
def test_is_netfail_standby_no_standby_feature(self, m_exists, m_standby):
|
||||
- devname = self.random_string()
|
||||
+ devname = random_string()
|
||||
driver = "virtio_net"
|
||||
m_exists.return_value = True # has master sysfs attr
|
||||
m_standby.return_value = False # has standby feature flag
|
||||
- self.assertFalse(net.is_netfail_standby(devname, driver))
|
||||
+ assert not net.is_netfail_standby(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.is_netfail_standby")
|
||||
@mock.patch("cloudinit.net.is_netfail_primary")
|
||||
def test_is_netfailover_primary(self, m_primary, m_standby):
|
||||
- devname = self.random_string()
|
||||
- driver = self.random_string()
|
||||
+ devname = random_string()
|
||||
+ driver = random_string()
|
||||
m_primary.return_value = True
|
||||
m_standby.return_value = False
|
||||
- self.assertTrue(net.is_netfailover(devname, driver))
|
||||
+ assert net.is_netfailover(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.is_netfail_standby")
|
||||
@mock.patch("cloudinit.net.is_netfail_primary")
|
||||
def test_is_netfailover_standby(self, m_primary, m_standby):
|
||||
- devname = self.random_string()
|
||||
- driver = self.random_string()
|
||||
+ devname = random_string()
|
||||
+ driver = random_string()
|
||||
m_primary.return_value = False
|
||||
m_standby.return_value = True
|
||||
- self.assertTrue(net.is_netfailover(devname, driver))
|
||||
+ assert net.is_netfailover(devname, driver)
|
||||
|
||||
@mock.patch("cloudinit.net.is_netfail_standby")
|
||||
@mock.patch("cloudinit.net.is_netfail_primary")
|
||||
def test_is_netfailover_returns_false(self, m_primary, m_standby):
|
||||
- devname = self.random_string()
|
||||
- driver = self.random_string()
|
||||
+ devname = random_string()
|
||||
+ driver = random_string()
|
||||
m_primary.return_value = False
|
||||
m_standby.return_value = False
|
||||
- self.assertFalse(net.is_netfailover(devname, driver))
|
||||
+ assert not net.is_netfailover(devname, driver)
|
||||
|
||||
|
||||
class TestOpenvswitchIsInstalled:
|
||||
diff --git a/tests/unittests/sources/helpers/test_openstack.py b/tests/unittests/sources/helpers/test_openstack.py
|
||||
index ac8e2a3..4d85ec3 100644
|
||||
--- a/tests/unittests/sources/helpers/test_openstack.py
|
||||
+++ b/tests/unittests/sources/helpers/test_openstack.py
|
||||
@@ -3,14 +3,13 @@
|
||||
from unittest import mock
|
||||
|
||||
from cloudinit.sources.helpers import openstack
|
||||
-from tests.unittests import helpers as test_helpers
|
||||
|
||||
|
||||
@mock.patch(
|
||||
"cloudinit.net.is_openvswitch_internal_interface",
|
||||
mock.Mock(return_value=False),
|
||||
)
|
||||
-class TestConvertNetJson(test_helpers.CiTestCase):
|
||||
+class TestConvertNetJson:
|
||||
def test_phy_types(self):
|
||||
"""Verify the different known physical types are handled."""
|
||||
# network_data.json example from
|
||||
@@ -54,11 +53,8 @@ class TestConvertNetJson(test_helpers.CiTestCase):
|
||||
|
||||
for t in openstack.KNOWN_PHYSICAL_TYPES:
|
||||
net_json["links"][0]["type"] = t
|
||||
- self.assertEqual(
|
||||
- expected,
|
||||
- openstack.convert_net_json(
|
||||
- network_json=net_json, known_macs=macs
|
||||
- ),
|
||||
+ assert expected == openstack.convert_net_json(
|
||||
+ network_json=net_json, known_macs=macs
|
||||
)
|
||||
|
||||
def test_subnet_dns(self):
|
||||
@@ -113,9 +109,6 @@ class TestConvertNetJson(test_helpers.CiTestCase):
|
||||
|
||||
for t in openstack.KNOWN_PHYSICAL_TYPES:
|
||||
net_json["links"][0]["type"] = t
|
||||
- self.assertEqual(
|
||||
- expected,
|
||||
- openstack.convert_net_json(
|
||||
- network_json=net_json, known_macs=macs
|
||||
- ),
|
||||
+ assert expected == openstack.convert_net_json(
|
||||
+ network_json=net_json, known_macs=macs
|
||||
)
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
Name: cloud-init
|
||||
Version: 23.4.1
|
||||
Release: 1
|
||||
Release: 2
|
||||
Summary: the defacto multi-distribution package that handles early initialization of a cloud instance.
|
||||
License: ASL 2.0 or GPLv3
|
||||
URL: http://launchpad.net/cloud-init
|
||||
@ -14,13 +14,19 @@ Patch3: add-variable-to-forbid-tmp-dir.patch
|
||||
Patch5: Do-not-write-NM_CONTROLLED-no-in-generated-interface-config.patch
|
||||
Patch6: delete-config-nopasswd-all.patch
|
||||
|
||||
Patch6000: backport-fix-unpin-jsonschema-and-update-tests.patch
|
||||
Patch6001: backport-test-fix-tmpdir-in-test_cc_apk_configure.patch
|
||||
Patch6002: backport-bug-tests-mock-reads-of-host-s-sys-class-net-via-get.patch
|
||||
Patch6003: backport-tests-drop-CiTestCase-and-convert-to-pytest.patch
|
||||
Patch6004: backport-test-fix-disable_sysfs_net-mock.patch
|
||||
|
||||
BuildRequires: pkgconfig(systemd) python3-devel python3-setuptools systemd
|
||||
BuildRequires: iproute python3-configobj python3-responses
|
||||
BuildRequires: python3-jinja2 python3-jsonpatch python3-jsonschema
|
||||
BuildRequires: python3-mock python3-oauthlib python3-prettytable
|
||||
BuildRequires: python3-pyserial python3-PyYAML python3-requests
|
||||
BuildRequires: dnf %{_vendor}-release python3-pytest passwd python3-netifaces
|
||||
BuildRequires: python3-pytest-mock
|
||||
BuildRequires: python3-pytest-mock python3-passlib
|
||||
|
||||
Requires: e2fsprogs iproute python3-libselinux net-tools python3-policycoreutils
|
||||
Requires: procps python3-configobj python3-jinja2 python3-jsonpatch xfsprogs
|
||||
@ -55,7 +61,31 @@ install -D -m 0644 %{SOURCE1} %{buildroot}/%{_tmpfilesdir}/%{name}.conf
|
||||
install -D -m 0644 tools/21-cloudinit.conf %{buildroot}/%{_sysconfdir}/rsyslog.d/21-cloudinit.conf
|
||||
|
||||
%check
|
||||
SKIP_TESTS=""
|
||||
|
||||
# 检测是否存在多个网卡的MAC地址是ee:ee:ee:ee:ee:ee
|
||||
# https://docs.tigera.io/calico/latest/reference/faq#why-do-all-cali-interfaces-have-the-mac-address-eeeeeeeeeeee
|
||||
MAC_ADDR="ee:ee:ee:ee:ee:ee"
|
||||
interfaces=$(ls /sys/class/net)
|
||||
duplicate_mac_matched_count=0
|
||||
for iface in $interfaces; do
|
||||
if [ -e "/sys/class/net/$iface/address" ]; then
|
||||
iface_mac=$(cat /sys/class/net/$iface/address)
|
||||
if [ "$iface_mac" == "$MAC_ADDR" ]; then
|
||||
duplicate_mac_matched_count=$((duplicate_mac_matched_count+1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$duplicate_mac_matched_count" -gt 1 ]; then
|
||||
SKIP_TESTS="not test_dhcp.py and not test_network_state.py"
|
||||
fi
|
||||
|
||||
if [ -n "$SKIP_TESTS" ]; then
|
||||
python3 -m pytest tests/unittests/ -k "$SKIP_TESTS"
|
||||
else
|
||||
python3 -m pytest tests/unittests/
|
||||
fi
|
||||
|
||||
%pre
|
||||
|
||||
@ -119,6 +149,18 @@ fi
|
||||
%exclude /usr/share/doc/*
|
||||
|
||||
%changelog
|
||||
* Wed Apr 03 2024 shixuantong <shixuantong1@huawei.com> - 23.4.1-2
|
||||
- Type:bugfix
|
||||
- CVE:NA
|
||||
- SUG:NA
|
||||
- DESC:add python3-passlib to BuildRequires
|
||||
skip some test if there are multiple NICs with the MAC address 'ee:ee:ee:ee:ee:ee'
|
||||
fix: unpin jsonschema and update tests
|
||||
test: fix tmpdir in test_cc_apk_configure
|
||||
bug(tests): mock reads of host's /sys/class/net via get_sys_class_path
|
||||
test: fix disable_sysfs_net mock
|
||||
tests: drop CiTestCase and convert to pytest
|
||||
|
||||
* Wed Jan 24 2024 shixuantong <shixuantong1@huawei.com> - 23.4.1-1
|
||||
- Type:enhancement
|
||||
- CVE:NA
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user