summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Falcon <james.falcon@canonical.com>2023-03-29 10:37:46 -0500
committerJames Falcon <james.falcon@canonical.com>2023-03-29 10:37:46 -0500
commit247bba7aa3afa18880f642734f5fb18bda5c4e80 (patch)
tree3bd84cd60953efaa8998084993e3e7b201bc39ff
parentd68a0d7b06844f00cb93ecb1bc3e64b5d51cff0e (diff)
parentd7bdba6f941ed04dc39e97af215e46e2baf07507 (diff)
downloadcloud-init-git-247bba7aa3afa18880f642734f5fb18bda5c4e80.tar.gz
merge from upstream/main at 23.1-41-gd7bdba6f
-rw-r--r--.github/workflows/unit.yml26
-rw-r--r--.travis.yml34
-rw-r--r--cloudinit/config/schema.py9
-rw-r--r--cloudinit/sources/azure/imds.py9
-rw-r--r--integration-requirements.txt1
-rw-r--r--tests/integration_tests/bugs/test_gh626.py7
-rw-r--r--tests/integration_tests/bugs/test_gh632.py7
-rw-r--r--tests/integration_tests/bugs/test_gh668.py7
-rw-r--r--tests/integration_tests/bugs/test_gh671.py3
-rw-r--r--tests/integration_tests/bugs/test_gh868.py10
-rw-r--r--tests/integration_tests/bugs/test_lp1835584.py16
-rw-r--r--tests/integration_tests/bugs/test_lp1897099.py6
-rw-r--r--tests/integration_tests/bugs/test_lp1898997.py12
-rw-r--r--tests/integration_tests/bugs/test_lp1901011.py3
-rw-r--r--tests/integration_tests/bugs/test_lp1910835.py4
-rw-r--r--tests/integration_tests/bugs/test_lp1912844.py6
-rw-r--r--tests/integration_tests/clouds.py65
-rw-r--r--tests/integration_tests/cmd/test_status.py16
-rw-r--r--tests/integration_tests/conftest.py25
-rw-r--r--tests/integration_tests/datasources/test_detect_openstack.py3
-rw-r--r--tests/integration_tests/datasources/test_ec2_ipv6.py3
-rw-r--r--tests/integration_tests/datasources/test_lxd_discovery.py15
-rw-r--r--tests/integration_tests/datasources/test_lxd_hotplug.py17
-rw-r--r--tests/integration_tests/datasources/test_network_dependency.py8
-rw-r--r--tests/integration_tests/datasources/test_nocloud.py7
-rw-r--r--tests/integration_tests/datasources/test_oci_networking.py7
-rw-r--r--tests/integration_tests/datasources/test_tmp_noexec.py10
-rw-r--r--tests/integration_tests/integration_settings.py6
-rw-r--r--tests/integration_tests/modules/test_ansible.py18
-rw-r--r--tests/integration_tests/modules/test_apt.py39
-rw-r--r--tests/integration_tests/modules/test_ca_certs.py5
-rw-r--r--tests/integration_tests/modules/test_combined.py37
-rw-r--r--tests/integration_tests/modules/test_disk_setup.py21
-rw-r--r--tests/integration_tests/modules/test_growpart.py8
-rw-r--r--tests/integration_tests/modules/test_hotplug.py26
-rw-r--r--tests/integration_tests/modules/test_keys_to_console.py13
-rw-r--r--tests/integration_tests/modules/test_lxd.py46
-rw-r--r--tests/integration_tests/modules/test_package_update_upgrade_install.py4
-rw-r--r--tests/integration_tests/modules/test_persistence.py5
-rw-r--r--tests/integration_tests/modules/test_power_state_change.py9
-rw-r--r--tests/integration_tests/modules/test_set_password.py6
-rw-r--r--tests/integration_tests/modules/test_ssh_keys_provided.py4
-rw-r--r--tests/integration_tests/modules/test_ssh_keysfile.py20
-rw-r--r--tests/integration_tests/modules/test_ubuntu_advantage.py31
-rw-r--r--tests/integration_tests/modules/test_ubuntu_autoinstall.py4
-rw-r--r--tests/integration_tests/modules/test_ubuntu_drivers.py3
-rw-r--r--tests/integration_tests/modules/test_user_events.py20
-rw-r--r--tests/integration_tests/modules/test_users_groups.py15
-rw-r--r--tests/integration_tests/modules/test_version_change.py13
-rw-r--r--tests/integration_tests/modules/test_wireguard.py22
-rw-r--r--tests/integration_tests/releases.py92
-rw-r--r--tests/integration_tests/test_paths.py6
-rw-r--r--tests/integration_tests/test_upgrade.py29
-rw-r--r--tests/unittests/config/test_schema.py5
-rw-r--r--tests/unittests/helpers.py14
-rw-r--r--tests/unittests/net/test_dhcp.py2
-rw-r--r--tests/unittests/sources/azure/test_imds.py1
-rw-r--r--tests/unittests/sources/test_azure.py4
-rw-r--r--tests/unittests/test_util.py38
-rw-r--r--tox.ini11
60 files changed, 527 insertions, 386 deletions
diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml
index 26c278d5..2c72a2a4 100644
--- a/.github/workflows/unit.yml
+++ b/.github/workflows/unit.yml
@@ -12,15 +12,24 @@ jobs:
strategy:
matrix:
python-version: [ "3.6", "3.7", "3.8", "3.9", "3.10", "3.11" ]
- name: Python ${{matrix.python-version}} unittest
+ toxenv: [ py3 ]
+ experimental: [false]
+ include:
+ - python-version: "3.12-dev"
+ toxenv: py3
+ experimental: true
+ - python-version: "3.6"
+ toxenv: lowest-supported
+ experimental: false
+ name: unittest / ${{ matrix.toxenv }} / python ${{matrix.python-version}}
runs-on: ubuntu-20.04
+ continue-on-error: ${{ matrix.experimental }}
steps:
- - name: "Checkout #1"
- uses: actions/checkout@v3.0.0
- - name: "Checkout #2 (for tools/read-version)"
- run: |
- git fetch --unshallow
- git remote add upstream https://git.launchpad.net/cloud-init
+ - name: "Checkout"
+ uses: actions/checkout@v3
+ with:
+ # Fetch all tags for tools/read-version
+ fetch-depth: 0
- name: Install Python ${{matrix.python-version}}
uses: actions/setup-python@v4
with:
@@ -29,6 +38,5 @@ jobs:
run: pip install tox
- name: Run unittest
env:
- TOXENV: py3
PYTEST_ADDOPTS: -v
- run: tox
+ run: tox -e ${{ matrix.toxenv }}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 7422c2cb..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-language: python
-dist: focal
-
-cache: pip
-
-install:
- # Required so `git describe` will definitely find a tag; see
- # https://github.com/travis-ci/travis-ci/issues/7422
- - git fetch --unshallow
- # Not pinning setuptools can cause failures on python 3.7 and 3.8 builds
- # See https://github.com/pypa/setuptools/issues/3118
- - pip install setuptools==59.6.0
- - pip install tox
-
-script:
- - tox
-
-env:
- TOXENV=py3
- PYTEST_ADDOPTS=-v # List all tests run by pytest
-
-matrix:
- fast_finish: true
- include:
- - python: 3.6
- env:
- TOXENV=lowest-supported
- PYTEST_ADDOPTS=-v # List all tests run by pytest
- dist: bionic
- # Test all supported Python versions (but at the end, so we schedule
- # longer-running jobs first)
- - python: 3.12-dev
- allow_failures:
- - python: 3.12-dev
diff --git a/cloudinit/config/schema.py b/cloudinit/config/schema.py
index 0669defc..9886bde6 100644
--- a/cloudinit/config/schema.py
+++ b/cloudinit/config/schema.py
@@ -319,8 +319,7 @@ def get_jsonschema_validator():
# type jsonschema attributes in cloud-init's schema.
# This allows #cloud-config to provide valid yaml "content: !!binary | ..."
- strict_metaschema = deepcopy(Draft4Validator.META_SCHEMA)
- strict_metaschema["additionalProperties"] = False
+ meta_schema = deepcopy(Draft4Validator.META_SCHEMA)
# This additional label allows us to specify a different name
# than the property key when generating docs.
@@ -328,10 +327,11 @@ def get_jsonschema_validator():
# otherwise the property label in the generated docs will be a
# regular expression.
# http://json-schema.org/understanding-json-schema/reference/object.html#pattern-properties
- strict_metaschema["properties"]["label"] = {"type": "string"}
+ meta_schema["properties"]["label"] = {"type": "string"}
validator_kwargs = {}
if hasattr(Draft4Validator, "TYPE_CHECKER"): # jsonschema 3.0+
+ meta_schema["additionalProperties"] = False # Unsupported in 2.6.0
type_checker = Draft4Validator.TYPE_CHECKER.redefine(
"string", is_schema_byte_string
)
@@ -339,6 +339,7 @@ def get_jsonschema_validator():
"type_checker": type_checker,
}
else: # jsonschema 2.6 workaround
+ # pylint:disable-next=no-member
types = Draft4Validator.DEFAULT_TYPES # pylint: disable=E1101
# Allow bytes as well as string (and disable a spurious unsupported
# assignment-operation pylint warning which appears because this
@@ -354,7 +355,7 @@ def get_jsonschema_validator():
validators["anyOf"] = _anyOf
cloudinitValidator = create(
- meta_schema=strict_metaschema,
+ meta_schema=meta_schema,
validators=validators,
version="draft4",
**validator_kwargs,
diff --git a/cloudinit/sources/azure/imds.py b/cloudinit/sources/azure/imds.py
index 5e4046d0..1f5cf008 100644
--- a/cloudinit/sources/azure/imds.py
+++ b/cloudinit/sources/azure/imds.py
@@ -51,13 +51,14 @@ class ReadUrlRetryHandler:
# Check for connection errors which may occur early boot, but
# are otherwise indicative that we are not connecting with the
# primary NIC.
- if isinstance(
- exception.cause, (requests.ConnectionError, requests.Timeout)
- ):
+ if isinstance(exception.cause, requests.ConnectionError):
self.max_connection_errors -= 1
if self.max_connection_errors < 0:
retry = False
- elif exception.code not in self.retry_codes:
+ elif (
+ exception.code is not None
+ and exception.code not in self.retry_codes
+ ):
retry = False
if self._request_count >= self._logging_threshold:
diff --git a/integration-requirements.txt b/integration-requirements.txt
index 03d4fc25..85e2efcb 100644
--- a/integration-requirements.txt
+++ b/integration-requirements.txt
@@ -3,3 +3,4 @@
#
pycloudlib==1!1
pytest
+packaging
diff --git a/tests/integration_tests/bugs/test_gh626.py b/tests/integration_tests/bugs/test_gh626.py
index b80b677a..6df52d9c 100644
--- a/tests/integration_tests/bugs/test_gh626.py
+++ b/tests/integration_tests/bugs/test_gh626.py
@@ -9,6 +9,7 @@ import yaml
from tests.integration_tests import random_mac_address
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
MAC_ADDRESS = random_mac_address()
NETWORK_CONFIG = """\
@@ -28,8 +29,10 @@ iface eth0 inet dhcp
ethernet-wol g"""
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ PLATFORM not in ["lxd_container", "lxd_vm"],
+ reason="Test requires custom networking provided by LXD",
+)
@pytest.mark.lxd_config_dict(
{
"user.network-config": NETWORK_CONFIG,
diff --git a/tests/integration_tests/bugs/test_gh632.py b/tests/integration_tests/bugs/test_gh632.py
index d83d244b..9e67fe59 100644
--- a/tests/integration_tests/bugs/test_gh632.py
+++ b/tests/integration_tests/bugs/test_gh632.py
@@ -6,12 +6,15 @@ no traceback if the metadata disk cannot be found.
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import verify_clean_log
# With some datasource hacking, we can run this on a NoCloud instance
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ PLATFORM not in ["lxd_container", "lxd_vm"],
+ reason="Tested behavior is emulated using NoCloud",
+)
def test_datasource_rbx_no_stacktrace(client: IntegrationInstance):
client.write_to_file(
"/etc/cloud/cloud.cfg.d/90_dpkg.cfg",
diff --git a/tests/integration_tests/bugs/test_gh668.py b/tests/integration_tests/bugs/test_gh668.py
index 95edb48d..2a97c488 100644
--- a/tests/integration_tests/bugs/test_gh668.py
+++ b/tests/integration_tests/bugs/test_gh668.py
@@ -9,6 +9,7 @@ import pytest
from tests.integration_tests import random_mac_address
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
DESTINATION_IP = "172.16.0.10"
GATEWAY_IP = "10.0.0.100"
@@ -32,8 +33,10 @@ ethernets:
EXPECTED_ROUTE = "{} via {}".format(DESTINATION_IP, GATEWAY_IP)
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ PLATFORM not in ["lxd_container", "lxd_vm"],
+ reason="Test requires custom networking provided by LXD",
+)
@pytest.mark.lxd_config_dict(
{
"user.network-config": NETWORK_CONFIG,
diff --git a/tests/integration_tests/bugs/test_gh671.py b/tests/integration_tests/bugs/test_gh671.py
index 2d7c8118..e93bd70b 100644
--- a/tests/integration_tests/bugs/test_gh671.py
+++ b/tests/integration_tests/bugs/test_gh671.py
@@ -10,6 +10,7 @@ import crypt
import pytest
from tests.integration_tests.clouds import IntegrationCloud
+from tests.integration_tests.integration_settings import PLATFORM
OLD_PASSWORD = "DoIM33tTheComplexityRequirements!??"
NEW_PASSWORD = "DoIM33tTheComplexityRequirementsNow!??"
@@ -22,7 +23,7 @@ def _check_password(instance, unhashed_password):
assert shadow_password == hashed_password
-@pytest.mark.azure
+@pytest.mark.skipif(PLATFORM != "azure", reason="Test is Azure specific")
def test_update_default_password(setup_image, session_cloud: IntegrationCloud):
os_profile = {
"os_profile": {
diff --git a/tests/integration_tests/bugs/test_gh868.py b/tests/integration_tests/bugs/test_gh868.py
index a62e8b36..67ac9b3a 100644
--- a/tests/integration_tests/bugs/test_gh868.py
+++ b/tests/integration_tests/bugs/test_gh868.py
@@ -2,6 +2,7 @@
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import verify_clean_log
USERDATA = """\
@@ -15,12 +16,9 @@ chef:
@pytest.mark.adhoc # Can't be regularly reaching out to chef install script
-@pytest.mark.ec2
-@pytest.mark.gce
-@pytest.mark.azure
-@pytest.mark.oci
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ "openstack" == PLATFORM, reason="Firewall preventing openstack run"
+)
@pytest.mark.user_data(USERDATA)
def test_chef_license(client: IntegrationInstance):
log = client.read_from_file("/var/log/cloud-init.log")
diff --git a/tests/integration_tests/bugs/test_lp1835584.py b/tests/integration_tests/bugs/test_lp1835584.py
index 4e732446..7f110379 100644
--- a/tests/integration_tests/bugs/test_lp1835584.py
+++ b/tests/integration_tests/bugs/test_lp1835584.py
@@ -30,9 +30,11 @@ import re
import pytest
from pycloudlib.cloud import ImageType
-from tests.integration_tests.clouds import ImageSpecification, IntegrationCloud
+from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.conftest import get_validated_source
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE
def _check_iid_insensitive_across_kernel_upgrade(
@@ -67,17 +69,15 @@ def _check_iid_insensitive_across_kernel_upgrade(
assert 1 == ssh_runs, "config_ssh ran too many times {}".format(ssh_runs)
-@pytest.mark.azure
+@pytest.mark.skipif(PLATFORM != "azure", reason="Test is Azure specific")
@pytest.mark.integration_cloud_args(image_type=ImageType.PRO_FIPS)
def test_azure_kernel_upgrade_case_insensitive_uuid(
session_cloud: IntegrationCloud,
):
- cfg_image_spec = ImageSpecification.from_os_image()
- if (cfg_image_spec.os, cfg_image_spec.release) != ("ubuntu", "bionic"):
+ if (CURRENT_RELEASE.os, CURRENT_RELEASE.series) != ("ubuntu", "bionic"):
pytest.skip(
- "Test only supports ubuntu:bionic not {0.os}:{0.release}".format(
- cfg_image_spec
- )
+ f"Test only supports ubuntu:bionic not {CURRENT_RELEASE.os}: "
+ f"{CURRENT_RELEASE.series}"
)
source = get_validated_source(session_cloud)
if not source.installs_new_version():
@@ -87,7 +87,7 @@ def test_azure_kernel_upgrade_case_insensitive_uuid(
with session_cloud.launch(
launch_kwargs={
"image_id": session_cloud.cloud_instance.daily_image(
- cfg_image_spec.image_id, image_type=ImageType.PRO_FIPS
+ CURRENT_RELEASE.image_id, image_type=ImageType.PRO_FIPS
)
}
) as instance:
diff --git a/tests/integration_tests/bugs/test_lp1897099.py b/tests/integration_tests/bugs/test_lp1897099.py
index 1f5030ce..b0981790 100644
--- a/tests/integration_tests/bugs/test_lp1897099.py
+++ b/tests/integration_tests/bugs/test_lp1897099.py
@@ -7,6 +7,8 @@ https://bugs.launchpad.net/cloud-init/+bug/1897099
import pytest
+from tests.integration_tests.integration_settings import PLATFORM
+
USER_DATA = """\
#cloud-config
bootcmd:
@@ -19,7 +21,9 @@ swap:
@pytest.mark.user_data(USER_DATA)
-@pytest.mark.no_container("Containers cannot configure swap")
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot configure swap"
+)
def test_fallocate_fallback(client):
log = client.read_from_file("/var/log/cloud-init.log")
assert "/swap.img" in client.execute("cat /proc/swaps")
diff --git a/tests/integration_tests/bugs/test_lp1898997.py b/tests/integration_tests/bugs/test_lp1898997.py
index d8ea54c3..ec92aeb6 100644
--- a/tests/integration_tests/bugs/test_lp1898997.py
+++ b/tests/integration_tests/bugs/test_lp1898997.py
@@ -12,6 +12,8 @@ default gateway.
import pytest
from tests.integration_tests import random_mac_address
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL
from tests.integration_tests.util import verify_clean_log
MAC_ADDRESS = random_mac_address()
@@ -44,10 +46,14 @@ version: 2
"volatile.eth0.hwaddr": MAC_ADDRESS,
}
)
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ PLATFORM != "lxd_vm",
+ reason="Test requires custom networking provided by LXD",
+)
+@pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL, reason="Tested on Focal and above"
+)
@pytest.mark.lxd_use_exec
-@pytest.mark.not_bionic
-@pytest.mark.ubuntu
class TestInterfaceListingWithOpenvSwitch:
def test_ovs_member_interfaces_not_excluded(self, client):
# We need to install openvswitch for our provided network configuration
diff --git a/tests/integration_tests/bugs/test_lp1901011.py b/tests/integration_tests/bugs/test_lp1901011.py
index 7de8bd77..e94caf9b 100644
--- a/tests/integration_tests/bugs/test_lp1901011.py
+++ b/tests/integration_tests/bugs/test_lp1901011.py
@@ -7,9 +7,10 @@ See https://github.com/canonical/cloud-init/pull/800
import pytest
from tests.integration_tests.clouds import IntegrationCloud
+from tests.integration_tests.integration_settings import PLATFORM
-@pytest.mark.azure
+@pytest.mark.skipif(PLATFORM != "azure", reason="Test is Azure specific")
@pytest.mark.parametrize(
"instance_type,is_ephemeral",
[
diff --git a/tests/integration_tests/bugs/test_lp1910835.py b/tests/integration_tests/bugs/test_lp1910835.py
index 1844594c..aa0fb75c 100644
--- a/tests/integration_tests/bugs/test_lp1910835.py
+++ b/tests/integration_tests/bugs/test_lp1910835.py
@@ -19,13 +19,15 @@ will match.
"""
import pytest
+from tests.integration_tests.integration_settings import PLATFORM
+
USER_DATA_TMPL = """\
#cloud-config
ssh_authorized_keys:
- {}"""
-@pytest.mark.azure
+@pytest.mark.skipif(PLATFORM != "azure", reason="Test is Azure specific")
def test_crlf_in_azure_metadata_ssh_keys(session_cloud, setup_image):
authorized_keys_path = "/home/{}/.ssh/authorized_keys".format(
session_cloud.cloud_instance.username
diff --git a/tests/integration_tests/bugs/test_lp1912844.py b/tests/integration_tests/bugs/test_lp1912844.py
index 55511ed2..b5aafa76 100644
--- a/tests/integration_tests/bugs/test_lp1912844.py
+++ b/tests/integration_tests/bugs/test_lp1912844.py
@@ -17,6 +17,7 @@ the traceback that they cause. We work around this by calling
import pytest
from tests.integration_tests import random_mac_address
+from tests.integration_tests.integration_settings import PLATFORM
MAC_ADDRESS = random_mac_address()
@@ -85,7 +86,10 @@ def ovs_enabled_session_cloud(session_cloud):
session_cloud.snapshot_id = old_snapshot_id
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ PLATFORM != "lxd_vm",
+ reason="Test requires custom networking provided by LXD",
+)
def test_get_interfaces_by_mac_doesnt_traceback(ovs_enabled_session_cloud):
"""Launch our OVS-enabled image and confirm the bug doesn't reproduce."""
launch_kwargs = {
diff --git a/tests/integration_tests/clouds.py b/tests/integration_tests/clouds.py
index 945a5fb6..404d0a08 100644
--- a/tests/integration_tests/clouds.py
+++ b/tests/integration_tests/clouds.py
@@ -7,7 +7,7 @@ import re
import string
from abc import ABC, abstractmethod
from copy import deepcopy
-from typing import Optional, Type
+from typing import Type
from uuid import UUID
from pycloudlib import (
@@ -28,6 +28,7 @@ import cloudinit
from cloudinit.subp import ProcessExecutionError, subp
from tests.integration_tests import integration_settings
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.releases import CURRENT_RELEASE
from tests.integration_tests.util import emit_dots_on_travis
log = logging.getLogger("integration_testing")
@@ -46,52 +47,6 @@ def _get_ubuntu_series() -> list:
return out.splitlines()
-class ImageSpecification:
- """A specification of an image to launch for testing.
-
- If either of ``os`` and ``release`` are not specified, an attempt will be
- made to infer the correct values for these on instantiation.
-
- :param image_id:
- The image identifier used by the rest of the codebase to launch this
- image.
- :param os:
- An optional string describing the operating system this image is for
- (e.g. "ubuntu", "rhel", "freebsd").
- :param release:
- A optional string describing the operating system release (e.g.
- "focal", "8"; the exact values here will depend on the OS).
- """
-
- def __init__(
- self,
- image_id: str,
- os: Optional[str] = None,
- release: Optional[str] = None,
- ):
- if image_id in _get_ubuntu_series():
- if os is None:
- os = "ubuntu"
- if release is None:
- release = image_id
-
- self.image_id = image_id
- self.os = os
- self.release = release
- log.info(
- "Detected image: image_id=%s os=%s release=%s",
- self.image_id,
- self.os,
- self.release,
- )
-
- @classmethod
- def from_os_image(cls):
- """Return an ImageSpecification for integration_settings.OS_IMAGE."""
- parts = integration_settings.OS_IMAGE.split("::", 2)
- return cls(*parts)
-
-
class IntegrationCloud(ABC):
datasource: str
cloud_instance: BaseCloud
@@ -127,12 +82,9 @@ class IntegrationCloud(ABC):
raise NotImplementedError
def _get_initial_image(self, **kwargs) -> str:
- image = ImageSpecification.from_os_image()
- try:
- return self.cloud_instance.daily_image(image.image_id, **kwargs)
- except (ValueError, IndexError) as ex:
- log.debug("Exception while executing `daily_image`: %s", ex)
- return image.image_id
+ return CURRENT_RELEASE.image_id or self.cloud_instance.daily_image(
+ CURRENT_RELEASE.series, **kwargs
+ )
def _perform_launch(self, launch_kwargs, **kwargs) -> BaseInstance:
pycloudlib_instance = self.cloud_instance.launch(**launch_kwargs)
@@ -398,17 +350,16 @@ class OpenstackCloud(IntegrationCloud):
)
def _get_initial_image(self, **kwargs):
- image = ImageSpecification.from_os_image()
try:
- UUID(image.image_id)
+ UUID(CURRENT_RELEASE.image_id)
except ValueError as e:
raise RuntimeError(
"When using Openstack, `OS_IMAGE` MUST be specified with "
"a 36-character UUID image ID. Passing in a release name is "
"not valid here.\n"
- "OS image id: {}".format(image.image_id)
+ "OS image id: {}".format(CURRENT_RELEASE.image_id)
) from e
- return image.image_id
+ return CURRENT_RELEASE.image_id
class IbmCloud(IntegrationCloud):
diff --git a/tests/integration_tests/cmd/test_status.py b/tests/integration_tests/cmd/test_status.py
index 2582855d..bc65bff5 100644
--- a/tests/integration_tests/cmd/test_status.py
+++ b/tests/integration_tests/cmd/test_status.py
@@ -3,8 +3,10 @@ from time import sleep
import pytest
-from tests.integration_tests.clouds import ImageSpecification, IntegrationCloud
+from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU, JAMMY
# We're implementing our own here in case cloud-init status --wait
@@ -37,8 +39,11 @@ def _remove_nocloud_dir_and_reboot(client: IntegrationInstance):
client.instance._wait_for_execute(old_boot_id=old_boot_id)
-@pytest.mark.ubuntu
-@pytest.mark.lxd_container
+@pytest.mark.skipif(not IS_UBUNTU, reason="Only ever tested on Ubuntu")
+@pytest.mark.skipif(
+ PLATFORM != "lxd_container",
+ reason="Test is LXD specific",
+)
def test_wait_when_no_datasource(session_cloud: IntegrationCloud, setup_image):
"""Ensure that when no datasource is found, we get status: disabled
@@ -59,10 +64,7 @@ def test_wait_when_no_datasource(session_cloud: IntegrationCloud, setup_image):
# No ubuntu user if cloud-init didn't run
client.instance.username = "root"
# Jammy and above will use LXD datasource by default
- if ImageSpecification.from_os_image().release in [
- "bionic",
- "focal",
- ]:
+ if CURRENT_RELEASE < JAMMY:
_remove_nocloud_dir_and_reboot(client)
status_out = _wait_for_cloud_init(client).stdout.strip()
assert "status: disabled" in status_out
diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py
index fabeb608..a4815f42 100644
--- a/tests/integration_tests/conftest.py
+++ b/tests/integration_tests/conftest.py
@@ -18,7 +18,6 @@ from tests.integration_tests.clouds import (
Ec2Cloud,
GceCloud,
IbmCloud,
- ImageSpecification,
IntegrationCloud,
LxdContainerCloud,
LxdVmCloud,
@@ -58,34 +57,10 @@ def pytest_runtest_setup(item):
platform, then skip the test. If platform specific marks are not
specified, then we assume the test can be run anywhere.
"""
- all_platforms = platforms.keys()
test_marks = [mark.name for mark in item.iter_markers()]
- supported_platforms = set(all_platforms).intersection(test_marks)
- current_platform = integration_settings.PLATFORM
- unsupported_message = "Cannot run on platform {}".format(current_platform)
- if "no_container" in test_marks:
- if "lxd_container" in test_marks:
- raise RuntimeError(
- "lxd_container and no_container marks simultaneously set "
- "on test"
- )
- if current_platform == "lxd_container":
- pytest.skip(unsupported_message)
- if supported_platforms and current_platform not in supported_platforms:
- pytest.skip(unsupported_message)
-
- image = ImageSpecification.from_os_image()
- current_os = image.os
- supported_os_set = set(os_list).intersection(test_marks)
- if current_os and supported_os_set and current_os not in supported_os_set:
- pytest.skip("Cannot run on OS {}".format(current_os))
if "unstable" in test_marks and not integration_settings.RUN_UNSTABLE:
pytest.skip("Test marked unstable. Manually remove mark to run it")
- current_release = image.release
- if "not_{}".format(current_release) in test_marks:
- pytest.skip("Cannot run on release {}".format(current_release))
-
# disable_subp_usage is defined at a higher level, but we don't
# want it applied here
diff --git a/tests/integration_tests/datasources/test_detect_openstack.py b/tests/integration_tests/datasources/test_detect_openstack.py
index c70e9815..73246f8f 100644
--- a/tests/integration_tests/datasources/test_detect_openstack.py
+++ b/tests/integration_tests/datasources/test_detect_openstack.py
@@ -1,10 +1,11 @@
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
-@pytest.mark.lxd_vm
@pytest.mark.lxd_use_exec
+@pytest.mark.skipif(PLATFORM != "lxd_vm", reason="Modifies grub config")
def test_lxd_datasource_kernel_override(client: IntegrationInstance):
"""This test is twofold: it tests kernel commandline override, which also
validates OpenStack Ironic requirements. OpenStack Ironic does not
diff --git a/tests/integration_tests/datasources/test_ec2_ipv6.py b/tests/integration_tests/datasources/test_ec2_ipv6.py
index 7bb45b40..aff7ddd2 100644
--- a/tests/integration_tests/datasources/test_ec2_ipv6.py
+++ b/tests/integration_tests/datasources/test_ec2_ipv6.py
@@ -3,6 +3,7 @@ import re
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
def _test_crawl(client, ip):
@@ -18,7 +19,7 @@ def _test_crawl(client, ip):
assert float(result[0]) < 20
-@pytest.mark.ec2
+@pytest.mark.skipif(PLATFORM != "ec2", reason="test is ec2 specific")
def test_dual_stack(client: IntegrationInstance):
# Drop IPv4 responses
assert client.execute("iptables -I INPUT -s 169.254.169.254 -j DROP").ok
diff --git a/tests/integration_tests/datasources/test_lxd_discovery.py b/tests/integration_tests/datasources/test_lxd_discovery.py
index f3ca7158..4f907434 100644
--- a/tests/integration_tests/datasources/test_lxd_discovery.py
+++ b/tests/integration_tests/datasources/test_lxd_discovery.py
@@ -3,8 +3,9 @@ import json
import pytest
import yaml
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU
from tests.integration_tests.util import lxd_has_nocloud, verify_clean_log
@@ -36,7 +37,7 @@ def _customize_environment(client: IntegrationInstance):
"datasource_list: [LXD, NoCloud]\n",
)
# This is also to ensure that NoCloud can be detected
- if ImageSpecification.from_os_image().release == "jammy":
+ if CURRENT_RELEASE.series == "jammy":
# Add nocloud-net seed files because Jammy no longer delivers NoCloud
# (LP: #1958460).
client.execute("mkdir -p /var/lib/cloud/seed/nocloud-net")
@@ -48,9 +49,11 @@ def _customize_environment(client: IntegrationInstance):
client.restart()
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
-@pytest.mark.ubuntu # Because netplan
+@pytest.mark.skipif(not IS_UBUNTU, reason="Netplan usage")
+@pytest.mark.skipif(
+ PLATFORM not in ["lxd_container", "lxd_vm"],
+ reason="Test is LXD specific",
+)
def test_lxd_datasource_discovery(client: IntegrationInstance):
"""Test that DataSourceLXD is detected instead of NoCloud."""
@@ -95,7 +98,7 @@ def test_lxd_datasource_discovery(client: IntegrationInstance):
] == sorted(list(ds_cfg.keys()))
if (
client.settings.PLATFORM == "lxd_vm"
- and ImageSpecification.from_os_image().release == "bionic"
+ and CURRENT_RELEASE.series == "bionic"
):
# pycloudlib injects user.vendor_data for lxd_vm on bionic
# to start the lxd-agent.
diff --git a/tests/integration_tests/datasources/test_lxd_hotplug.py b/tests/integration_tests/datasources/test_lxd_hotplug.py
index 81cff252..536f4e36 100644
--- a/tests/integration_tests/datasources/test_lxd_hotplug.py
+++ b/tests/integration_tests/datasources/test_lxd_hotplug.py
@@ -5,9 +5,10 @@ import pytest
from cloudinit import safeyaml
from cloudinit.subp import subp
from cloudinit.util import is_true
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.decorators import retry
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, JAMMY
from tests.integration_tests.util import (
get_feature_flag_value,
lxd_has_nocloud,
@@ -62,8 +63,11 @@ def _prefer_lxd_datasource_over_nocloud(client: IntegrationInstance):
# TODO: Once LXD adds MACs to the devices endpoint, support LXD VMs here
# Currently the names are too unpredictable to be worth testing on VMs.
-@pytest.mark.lxd_container
@pytest.mark.user_data(USER_DATA)
+@pytest.mark.skipif(
+ PLATFORM != "lxd_container",
+ reason="Test is LXD specific",
+)
class TestLxdHotplug:
@pytest.fixture(autouse=True, scope="class")
def class_teardown(self, class_client: IntegrationInstance):
@@ -113,14 +117,7 @@ class TestLxdHotplug:
assert "eth2" not in client.execute("ip address")
pre_netplan = client.read_from_file("/etc/netplan/50-cloud-init.yaml")
assert "eth2" not in pre_netplan
- if ImageSpecification.from_os_image().release in [
- "bionic",
- "focal",
- ]: # pyright: ignore
- top_key = "user"
- else:
- top_key = "cloud-init"
-
+ top_key = "user" if CURRENT_RELEASE < JAMMY else "cloud-init"
assert subp(
[
"lxc",
diff --git a/tests/integration_tests/datasources/test_network_dependency.py b/tests/integration_tests/datasources/test_network_dependency.py
index bd7fe658..7b692047 100644
--- a/tests/integration_tests/datasources/test_network_dependency.py
+++ b/tests/integration_tests/datasources/test_network_dependency.py
@@ -1,6 +1,8 @@
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import IS_UBUNTU
def _customize_environment(client: IntegrationInstance):
@@ -15,8 +17,10 @@ def _customize_environment(client: IntegrationInstance):
# This test should be able to work on any cloud whose datasource specifies
# a NETWORK dependency
-@pytest.mark.gce
-@pytest.mark.ubuntu # Because netplan
+@pytest.mark.skipif(not IS_UBUNTU, reason="Netplan usage")
+@pytest.mark.skipif(
+ PLATFORM != "gce", reason="Datasource doesn't specify a NETWORK dependency"
+)
def test_network_activation_disabled(client: IntegrationInstance):
"""Test that the network is not activated during init mode."""
_customize_environment(client)
diff --git a/tests/integration_tests/datasources/test_nocloud.py b/tests/integration_tests/datasources/test_nocloud.py
index d9410410..1b4c1abc 100644
--- a/tests/integration_tests/datasources/test_nocloud.py
+++ b/tests/integration_tests/datasources/test_nocloud.py
@@ -4,6 +4,7 @@ from pycloudlib.lxd.instance import LXDInstance
from cloudinit.subp import subp
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
VENDOR_DATA = """\
#cloud-config
@@ -57,10 +58,12 @@ def setup_nocloud(instance: LXDInstance):
)
-# Only running on LXD container because we need NoCloud with custom setup
-@pytest.mark.lxd_container
@pytest.mark.lxd_setup.with_args(setup_nocloud)
@pytest.mark.lxd_use_exec
+@pytest.mark.skipif(
+ PLATFORM != "lxd_container",
+ reason="Requires NoCloud with custom setup",
+)
def test_nocloud_seedfrom_vendordata(client: IntegrationInstance):
"""Integration test for #570.
diff --git a/tests/integration_tests/datasources/test_oci_networking.py b/tests/integration_tests/datasources/test_oci_networking.py
index dc0d343b..802e8ec7 100644
--- a/tests/integration_tests/datasources/test_oci_networking.py
+++ b/tests/integration_tests/datasources/test_oci_networking.py
@@ -6,6 +6,7 @@ import yaml
from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import verify_clean_log
DS_CFG = """\
@@ -43,7 +44,7 @@ def extract_interface_names(network_config: dict) -> Set[str]:
return set(interfaces)
-@pytest.mark.oci
+@pytest.mark.skipif(PLATFORM != "oci", reason="Test is OCI specific")
def test_oci_networking_iscsi_instance(client: IntegrationInstance, tmpdir):
customize_environment(client, tmpdir, configure_secondary_nics=False)
result_net_files = client.execute("ls /run/net-*.conf")
@@ -92,7 +93,7 @@ def client_with_secondary_vnic(
client.instance.remove_network_interface(ip_address)
-@pytest.mark.oci
+@pytest.mark.skipif(PLATFORM != "oci", reason="Test is OCI specific")
def test_oci_networking_iscsi_instance_secondary_vnics(
client_with_secondary_vnic: IntegrationInstance, tmpdir
):
@@ -142,7 +143,7 @@ def customize_netcfg(
client.restart()
-@pytest.mark.oci
+@pytest.mark.skipif(PLATFORM != "oci", reason="Test is OCI specific")
def test_oci_networking_system_cfg(client: IntegrationInstance, tmpdir):
customize_netcfg(client, tmpdir)
log = client.read_from_file("/var/log/cloud-init.log")
diff --git a/tests/integration_tests/datasources/test_tmp_noexec.py b/tests/integration_tests/datasources/test_tmp_noexec.py
index a060e20f..5aa8537d 100644
--- a/tests/integration_tests/datasources/test_tmp_noexec.py
+++ b/tests/integration_tests/datasources/test_tmp_noexec.py
@@ -1,6 +1,7 @@
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import verify_clean_log
@@ -14,11 +15,10 @@ def customize_client(client: IntegrationInstance):
@pytest.mark.adhoc
-@pytest.mark.azure
-@pytest.mark.ec2
-@pytest.mark.gce
-@pytest.mark.oci
-@pytest.mark.openstack
+@pytest.mark.skipif(
+ PLATFORM not in ["azure", "ec2", "gce", "oci", "openstack"],
+ reason=f"Test hasn't been tested on {PLATFORM}",
+)
def test_dhcp_tmp_noexec(client: IntegrationInstance):
customize_client(client)
assert (
diff --git a/tests/integration_tests/integration_settings.py b/tests/integration_tests/integration_settings.py
index c4f28fcb..aca5bf91 100644
--- a/tests/integration_tests/integration_settings.py
+++ b/tests/integration_tests/integration_settings.py
@@ -33,9 +33,9 @@ INSTANCE_TYPE: Optional[str] = None
# Determines the base image to use or generate new images from.
#
# This can be the name of an Ubuntu release, or in the format
-# <image_id>[::<os>[::<release>]]. If given, os and release should describe
-# the image specified by image_id. (Ubuntu releases are converted to this
-# format internally; in this case, to "focal::ubuntu::focal".)
+# <image_id>[::<os>[::<release>[::<version>]]. If given, os and release should
+# describe the image specified by image_id. (Ubuntu releases are converted
+# to this format internally; in this case, to "None::ubuntu::focal::20.04".)
OS_IMAGE = "focal"
# Populate if you want to use a pre-launched instance instead of
diff --git a/tests/integration_tests/modules/test_ansible.py b/tests/integration_tests/modules/test_ansible.py
index 3d0f96cb..aea29b7d 100644
--- a/tests/integration_tests/modules/test_ansible.py
+++ b/tests/integration_tests/modules/test_ansible.py
@@ -1,5 +1,7 @@
import pytest
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL
from tests.integration_tests.util import verify_clean_log
# This works by setting up a local repository and web server
@@ -291,7 +293,9 @@ def test_ansible_pull_pip(client):
# Ansible packaged in bionic is 2.5.1. This test relies on ansible collections,
# which requires Ansible 2.9+, so no bionic. The functionality is covered
# in `test_ansible_pull_pip` using pip rather than the bionic package.
-@pytest.mark.not_bionic
+@pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL, reason="Test requires Ansible 2.9+"
+)
@pytest.mark.user_data(
USER_DATA + INSTALL_METHOD.format(package="ansible", method="distro")
)
@@ -300,10 +304,14 @@ def test_ansible_pull_distro(client):
@pytest.mark.user_data(ANSIBLE_CONTROL)
-@pytest.mark.lxd_vm
-# Not bionic because test uses pip install and version in pip is removing
-# support for python version in bionic
-@pytest.mark.not_bionic
+@pytest.mark.skipif(
+ PLATFORM != "lxd_vm",
+ reason="Test requires starting LXD containers",
+)
+@pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL,
+ reason="Pip install is not supported for Ansible on release",
+)
def test_ansible_controller(client):
log = client.read_from_file("/var/log/cloud-init.log")
verify_clean_log(log)
diff --git a/tests/integration_tests/modules/test_apt.py b/tests/integration_tests/modules/test_apt.py
index 27ce2c5a..45c7a45a 100644
--- a/tests/integration_tests/modules/test_apt.py
+++ b/tests/integration_tests/modules/test_apt.py
@@ -5,8 +5,9 @@ import pytest
from cloudinit import gpg
from cloudinit.config import cc_apt_configure
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU
USER_DATA = """\
#cloud-config
@@ -114,7 +115,7 @@ TEST_KEY = "1FF0 D853 5EF7 E719 E5C8 1B9C 083D 06FB E4D3 04DF"
TEST_SIGNED_BY_KEY = "A2EB 2DEC 0BD7 519B 7B38 BE38 376A 290E C806 8B11"
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Apt usage")
@pytest.mark.user_data(USER_DATA)
class TestApt:
def get_keys(self, class_client: IntegrationInstance):
@@ -165,10 +166,11 @@ class TestApt:
Ported from
tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.py
"""
- release = ImageSpecification.from_os_image().release
ppa_path_contents = class_client.read_from_file(
"/etc/apt/sources.list.d/"
- "simplestreams-dev-ubuntu-trunk-{}.list".format(release)
+ "simplestreams-dev-ubuntu-trunk-{}.list".format(
+ CURRENT_RELEASE.series
+ )
)
assert (
"://ppa.launchpad.net/simplestreams-dev/trunk/ubuntu"
@@ -181,11 +183,10 @@ class TestApt:
def test_signed_by(self, class_client: IntegrationInstance):
"""Test the apt signed-by functionality."""
- release = ImageSpecification.from_os_image().release
source = (
"deb [signed-by=/etc/apt/cloud-init.gpg.d/test_signed_by.gpg] "
"http://ppa.launchpad.net/juju/stable/ubuntu"
- " {} main".format(release)
+ " {} main".format(CURRENT_RELEASE.series)
)
path_contents = class_client.read_from_file(
"/etc/apt/sources.list.d/test_signed_by.list"
@@ -251,27 +252,27 @@ class TestApt:
def test_sources_write(self, class_client: IntegrationInstance):
"""Test overwrite or append to sources file"""
- release = ImageSpecification.from_os_image().release
test_write_content = class_client.read_from_file(
"/etc/apt/sources.list.d/test_write.list"
)
expected_contents = (
"deb [signed-by=/etc/apt/cloud-init.gpg.d/test_write.gpg] "
- f"http://ppa.launchpad.net/juju/devel/ubuntu {release} main"
+ "http://ppa.launchpad.net/juju/devel/ubuntu "
+ f"{CURRENT_RELEASE.series} main"
)
assert expected_contents.strip() == test_write_content.strip()
def test_sources_append(self, class_client: IntegrationInstance):
- release = ImageSpecification.from_os_image().release
+ series = CURRENT_RELEASE.series
test_append_content = class_client.read_from_file(
"/etc/apt/sources.list.d/test_append.list"
)
expected_contents = (
"deb [signed-by=/etc/apt/cloud-init.gpg.d/test_append.gpg] "
- f"http://ppa.launchpad.net/juju/stable/ubuntu {release} main\n"
+ f"http://ppa.launchpad.net/juju/stable/ubuntu {series} main\n"
"deb [signed-by=/etc/apt/cloud-init.gpg.d/test_append.gpg] "
- f"http://ppa.launchpad.net/juju/devel/ubuntu {release} main"
+ f"http://ppa.launchpad.net/juju/devel/ubuntu {series} main"
)
assert expected_contents.strip() == test_append_content.strip()
@@ -290,10 +291,12 @@ apt:
DEFAULT_DATA = _DEFAULT_DATA.format(uri="")
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Apt usage")
@pytest.mark.user_data(DEFAULT_DATA)
class TestDefaults:
- @pytest.mark.openstack
+ @pytest.mark.skipif(
+ PLATFORM != "openstack", reason="Test is Openstack specific"
+ )
def test_primary_on_openstack(self, class_client: IntegrationInstance):
"""Test apt default primary source on openstack.
@@ -312,12 +315,12 @@ class TestDefaults:
sources_list = class_client.read_from_file("/etc/apt/sources.list")
# 3 lines from main, universe, and multiverse
- release = ImageSpecification.from_os_image().release
- sec_url = f"deb http://security.ubuntu.com/ubuntu {release}-security"
+ series = CURRENT_RELEASE.series
+ sec_url = f"deb http://security.ubuntu.com/ubuntu {series}-security"
if class_client.settings.PLATFORM == "azure":
sec_url = (
f"deb http://azure.archive.ubuntu.com/ubuntu/"
- f" {release}-security"
+ f" {series}-security"
)
sec_src_url = sec_url.replace("deb ", "# deb-src ")
assert 3 == sources_list.count(sec_url)
@@ -354,7 +357,7 @@ apt_pipelining: false
"""
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Apt usage")
@pytest.mark.user_data(DISABLED_DATA)
class TestDisabled:
def test_disable_suites(self, class_client: IntegrationInstance):
@@ -390,7 +393,7 @@ apt:
"""
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Apt usage")
@pytest.mark.user_data(APT_PROXY_DATA)
def test_apt_proxy(client: IntegrationInstance):
"""Test the apt proxy data gets written correctly."""
diff --git a/tests/integration_tests/modules/test_ca_certs.py b/tests/integration_tests/modules/test_ca_certs.py
index 2baedda9..65f8f4d7 100644
--- a/tests/integration_tests/modules/test_ca_certs.py
+++ b/tests/integration_tests/modules/test_ca_certs.py
@@ -11,6 +11,7 @@ import os.path
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.releases import IS_UBUNTU
from tests.integration_tests.util import get_inactive_modules, verify_clean_log
USER_DATA = """\
@@ -57,7 +58,9 @@ ca_certs:
"""
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not IS_UBUNTU, reason="CA cert functionality is distro specific"
+)
@pytest.mark.user_data(USER_DATA)
class TestCaCerts:
def test_certs_updated(self, class_client: IntegrationInstance):
diff --git a/tests/integration_tests/modules/test_combined.py b/tests/integration_tests/modules/test_combined.py
index 8481b454..3c238e1f 100644
--- a/tests/integration_tests/modules/test_combined.py
+++ b/tests/integration_tests/modules/test_combined.py
@@ -16,9 +16,10 @@ import pytest
import cloudinit.config
from cloudinit.util import is_true
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.decorators import retry
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU
from tests.integration_tests.util import (
get_feature_flag_value,
get_inactive_modules,
@@ -83,7 +84,7 @@ timezone: US/Aleutian
@pytest.mark.ci
@pytest.mark.user_data(USER_DATA)
class TestCombined:
- @pytest.mark.ubuntu # Because netplan
+ @pytest.mark.skipif(not IS_UBUNTU, reason="Uses netplan")
def test_netplan_permissions(self, class_client: IntegrationInstance):
"""
Test that netplan config file is generated with proper permissions
@@ -303,19 +304,20 @@ class TestCombined:
assert data["base64_encoded_keys"] == []
assert data["merged_cfg"] == "redacted for non-root user"
- image_spec = ImageSpecification.from_os_image()
- image_spec = ImageSpecification.from_os_image()
- assert data["sys_info"]["dist"][0] == image_spec.os
+ assert data["sys_info"]["dist"][0] == CURRENT_RELEASE.os
v1_data = data["v1"]
assert re.match(r"\d\.\d+\.\d+-\d+", v1_data["kernel_release"])
- assert v1_data["variant"] == image_spec.os
- assert v1_data["distro"] == image_spec.os
- assert v1_data["distro_release"] == image_spec.release
+ assert v1_data["variant"] == CURRENT_RELEASE.os
+ assert v1_data["distro"] == CURRENT_RELEASE.os
+ assert v1_data["distro_release"] == CURRENT_RELEASE.series
assert v1_data["machine"] == "x86_64"
assert re.match(r"3.\d+\.\d+", v1_data["python_version"])
- @pytest.mark.lxd_container
+ @pytest.mark.skipif(
+ PLATFORM != "lxd_container",
+ reason="Test is LXD container specific",
+ )
def test_instance_json_lxd(self, class_client: IntegrationInstance):
client = class_client
instance_json_file = client.read_from_file(
@@ -351,7 +353,7 @@ class TestCombined:
assert v1_data["local_hostname"] == client.instance.name
assert v1_data["region"] is None
- @pytest.mark.lxd_vm
+ @pytest.mark.skipif(PLATFORM != "lxd_vm", reason="Test is LXD VM specific")
def test_instance_json_lxd_vm(self, class_client: IntegrationInstance):
client = class_client
instance_json_file = client.read_from_file(
@@ -396,7 +398,7 @@ class TestCombined:
assert v1_data["local_hostname"] == client.instance.name
assert v1_data["region"] is None
- @pytest.mark.ec2
+ @pytest.mark.skipif(PLATFORM != "ec2", reason="Test is ec2 specific")
def test_instance_json_ec2(self, class_client: IntegrationInstance):
client = class_client
instance_json_file = client.read_from_file(
@@ -419,7 +421,7 @@ class TestCombined:
assert v1_data["local_hostname"].startswith("ip-")
assert v1_data["region"] == client.cloud.cloud_instance.region
- @pytest.mark.gce
+ @pytest.mark.skipif(PLATFORM != "gce", reason="Test is GCE specific")
def test_instance_json_gce(self, class_client: IntegrationInstance):
client = class_client
instance_json_file = client.read_from_file(
@@ -438,10 +440,13 @@ class TestCombined:
assert v1_data["instance_id"] == client.instance.instance_id
assert v1_data["local_hostname"] == client.instance.name
- @pytest.mark.lxd_container
- @pytest.mark.azure
- @pytest.mark.gce
- @pytest.mark.ec2
+ @pytest.mark.skipif(
+ PLATFORM not in ["lxd_container", "azure", "gce", "ec2"],
+ reason=(
+ f"Test was written for {PLATFORM} but can likely run on "
+ "other platforms."
+ ),
+ )
def test_instance_cloud_id_across_reboot(
self, class_client: IntegrationInstance
):
diff --git a/tests/integration_tests/modules/test_disk_setup.py b/tests/integration_tests/modules/test_disk_setup.py
index 1aa22ef0..084f03f5 100644
--- a/tests/integration_tests/modules/test_disk_setup.py
+++ b/tests/integration_tests/modules/test_disk_setup.py
@@ -7,6 +7,8 @@ from pycloudlib.lxd.instance import LXDInstance
from cloudinit.subp import subp
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL, IS_UBUNTU
from tests.integration_tests.util import verify_clean_log
DISK_PATH = "/tmp/test_disk_setup_{}".format(uuid4())
@@ -52,8 +54,10 @@ mounts:
@pytest.mark.user_data(ALIAS_USERDATA)
@pytest.mark.lxd_setup.with_args(setup_and_mount_lxd_disk)
-@pytest.mark.ubuntu
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(not IS_UBUNTU, reason="Only ever tested on Ubuntu")
+@pytest.mark.skipif(
+ PLATFORM != "lxd_vm", reason="Test requires additional mounted device"
+)
class TestDeviceAliases:
"""Test devices aliases work on disk setup/mount"""
@@ -124,8 +128,10 @@ mounts:
@pytest.mark.user_data(PARTPROBE_USERDATA)
@pytest.mark.lxd_setup.with_args(setup_and_mount_lxd_disk)
-@pytest.mark.ubuntu
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(not IS_UBUNTU, reason="Only ever tested on Ubuntu")
+@pytest.mark.skipif(
+ PLATFORM != "lxd_vm", reason="Test requires additional mounted device"
+)
class TestPartProbeAvailability:
"""Test disk setup works with partprobe
@@ -149,9 +155,10 @@ class TestPartProbeAvailability:
assert sdb["children"][0]["mountpoints"] == ["/mnt1"]
assert sdb["children"][1]["mountpoints"] == ["/mnt2"]
- # Not bionic because the LXD agent gets in the way of us
- # changing the userdata
- @pytest.mark.not_bionic
+ @pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL,
+ reason="LXD agent gets in the way of changing userdata",
+ )
def test_disk_setup_when_mounted(
self, create_disk, client: IntegrationInstance
):
diff --git a/tests/integration_tests/modules/test_growpart.py b/tests/integration_tests/modules/test_growpart.py
index 67251817..b42c016c 100644
--- a/tests/integration_tests/modules/test_growpart.py
+++ b/tests/integration_tests/modules/test_growpart.py
@@ -8,6 +8,8 @@ from pycloudlib.lxd.instance import LXDInstance
from cloudinit.subp import subp
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import IS_UBUNTU
DISK_PATH = "/tmp/test_disk_setup_{}".format(uuid4())
@@ -48,8 +50,10 @@ runcmd:
@pytest.mark.user_data(ALIAS_USERDATA)
@pytest.mark.lxd_setup.with_args(setup_and_mount_lxd_disk)
-@pytest.mark.ubuntu
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(not IS_UBUNTU, reason="Only ever tested on Ubuntu")
+@pytest.mark.skipif(
+ PLATFORM != "lxd_vm", reason="Test requires additional mounted device"
+)
class TestGrowPart:
"""Test growpart"""
diff --git a/tests/integration_tests/modules/test_hotplug.py b/tests/integration_tests/modules/test_hotplug.py
index 0bad761e..120715e4 100644
--- a/tests/integration_tests/modules/test_hotplug.py
+++ b/tests/integration_tests/modules/test_hotplug.py
@@ -5,6 +5,8 @@ import pytest
import yaml
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL
USER_DATA = """\
#cloud-config
@@ -40,11 +42,17 @@ def _get_ip_addr(client):
return ips
-@pytest.mark.openstack
-# On Bionic, we traceback when attempting to detect the hotplugged
-# device in the updated metadata. This is because Bionic is specifically
-# configured not to provide network metadata.
-@pytest.mark.not_bionic
+@pytest.mark.skipif(
+ PLATFORM != "openstack",
+ reason=(
+ f"Test was written for {PLATFORM} but can likely run on "
+ "other platforms."
+ ),
+)
+@pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL,
+ reason="Openstack network metadata support was added in focal.",
+)
@pytest.mark.user_data(USER_DATA)
def test_hotplug_add_remove(client: IntegrationInstance):
ips_before = _get_ip_addr(client)
@@ -85,7 +93,13 @@ def test_hotplug_add_remove(client: IntegrationInstance):
)
-@pytest.mark.openstack
+@pytest.mark.skipif(
+ PLATFORM != "openstack",
+ reason=(
+ f"Test was written for {PLATFORM} but can likely run on "
+ "other platforms."
+ ),
+)
def test_no_hotplug_in_userdata(client: IntegrationInstance):
ips_before = _get_ip_addr(client)
log = client.read_from_file("/var/log/cloud-init.log")
diff --git a/tests/integration_tests/modules/test_keys_to_console.py b/tests/integration_tests/modules/test_keys_to_console.py
index 5e2b3645..b10cbc60 100644
--- a/tests/integration_tests/modules/test_keys_to_console.py
+++ b/tests/integration_tests/modules/test_keys_to_console.py
@@ -6,6 +6,7 @@ import pytest
from tests.integration_tests.decorators import retry
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import get_console_log
BLACKLIST_USER_DATA = """\
@@ -88,11 +89,13 @@ class TestKeysToConsoleDisabled:
@pytest.mark.user_data(ENABLE_KEYS_TO_CONSOLE_USER_DATA)
@retry(tries=30, delay=1)
-@pytest.mark.ec2
-@pytest.mark.lxd_container
-@pytest.mark.oci
-@pytest.mark.openstack
-# No Azure because no console log on Azure
+@pytest.mark.skipif(
+ PLATFORM not in ["ec2", "lxd_container", "oci", "openstack"],
+ reason=(
+ "No Azure because no console log on Azure. "
+ "Other platforms need testing."
+ ),
+)
def test_duplicate_messaging_console_log(client: IntegrationInstance):
"""Test that output can be enabled disabled."""
assert (
diff --git a/tests/integration_tests/modules/test_lxd.py b/tests/integration_tests/modules/test_lxd.py
index f84cdff6..40941ab4 100644
--- a/tests/integration_tests/modules/test_lxd.py
+++ b/tests/integration_tests/modules/test_lxd.py
@@ -8,8 +8,10 @@ import warnings
import pytest
import yaml
-from tests.integration_tests.clouds import ImageSpecification, IntegrationCloud
+from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL
from tests.integration_tests.util import verify_clean_log
BRIDGE_USER_DATA = """\
@@ -149,7 +151,9 @@ lxd:
"""
-@pytest.mark.no_container
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot run LXD"
+)
@pytest.mark.user_data(BRIDGE_USER_DATA)
class TestLxdBridge:
@pytest.mark.parametrize("binary_name", ["lxc", "lxd"])
@@ -202,7 +206,7 @@ def validate_preseed_storage_pools(client, preseed_cfg):
def validate_preseed_projects(client: IntegrationInstance, preseed_cfg):
# Support for projects by lxd init --preseed was added in lxd 4.12
# https://discuss.linuxcontainers.org/t/lxd-4-12-has-been-released/10424#projects-now-supported-by-lxd-init-dump-and-preseed-9
- if ImageSpecification.from_os_image().release in ("bionic", "focal"):
+ if CURRENT_RELEASE.series in ("bionic", "focal"):
return
for src_project in preseed_cfg.get("projects", []):
proj_name = src_project["name"]
@@ -226,17 +230,23 @@ def validate_preseed_projects(client: IntegrationInstance, preseed_cfg):
assert project == src_project
-@pytest.mark.no_container
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot manipulate storage"
+)
@pytest.mark.user_data(STORAGE_USER_DATA.format("btrfs"))
def test_storage_btrfs(client):
validate_storage(client, "btrfs-progs", "mkfs.btrfs")
-@pytest.mark.no_container
-@pytest.mark.not_bionic
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot manipulate LXD"
+)
+@pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL, reason="tested on Focal and later"
+)
def test_storage_preseed_btrfs(setup_image, session_cloud: IntegrationCloud):
- cfg_image_spec = ImageSpecification.from_os_image()
- if cfg_image_spec.release in ("bionic",):
+ # TODO: If test is marked as not bionic, why is there a bionic section?
+ if CURRENT_RELEASE.series in ("bionic",):
nictype = "nictype: bridged"
parent = "parent: lxdbr0"
network = ""
@@ -256,7 +266,9 @@ def test_storage_preseed_btrfs(setup_image, session_cloud: IntegrationCloud):
validate_preseed_projects(client, preseed_cfg)
-@pytest.mark.no_container
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot manipulate LVM"
+)
@pytest.mark.user_data(STORAGE_USER_DATA.format("lvm"))
def test_storage_lvm(client):
log = client.read_from_file("/var/log/cloud-init.log")
@@ -281,17 +293,23 @@ def test_basic_preseed(client):
validate_preseed_projects(client, preseed_cfg)
-@pytest.mark.no_container
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot manipulate ZFS"
+)
@pytest.mark.user_data(STORAGE_USER_DATA.format("zfs"))
def test_storage_zfs(client):
validate_storage(client, "zfsutils-linux", "zpool")
-@pytest.mark.no_container
-@pytest.mark.not_bionic
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot manipulate LXD"
+)
+@pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL, reason="Tested on focal and later"
+)
def test_storage_preseed_zfs(setup_image, session_cloud: IntegrationCloud):
- cfg_image_spec = ImageSpecification.from_os_image()
- if cfg_image_spec.release in ("bionic",):
+ # TODO: If test is marked as not bionic, why is there a bionic section?
+ if CURRENT_RELEASE.series in ("bionic",):
nictype = "nictype: bridged"
parent = "parent: lxdbr0"
network = ""
diff --git a/tests/integration_tests/modules/test_package_update_upgrade_install.py b/tests/integration_tests/modules/test_package_update_upgrade_install.py
index d668d81c..c54365b8 100644
--- a/tests/integration_tests/modules/test_package_update_upgrade_install.py
+++ b/tests/integration_tests/modules/test_package_update_upgrade_install.py
@@ -16,6 +16,8 @@ import re
import pytest
+from tests.integration_tests.releases import IS_UBUNTU
+
USER_DATA = """\
#cloud-config
packages:
@@ -26,7 +28,7 @@ package_upgrade: true
"""
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Uses Apt")
@pytest.mark.user_data(USER_DATA)
class TestPackageUpdateUpgradeInstall:
def assert_package_installed(self, pkg_out, name, version=None):
diff --git a/tests/integration_tests/modules/test_persistence.py b/tests/integration_tests/modules/test_persistence.py
index 9979cc06..67f48284 100644
--- a/tests/integration_tests/modules/test_persistence.py
+++ b/tests/integration_tests/modules/test_persistence.py
@@ -5,6 +5,7 @@ from pathlib import Path
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import (
ASSETS_DIR,
verify_ordered_items_in_text,
@@ -14,7 +15,9 @@ PICKLE_PATH = Path("/var/lib/cloud/instance/obj.pkl")
TEST_PICKLE = ASSETS_DIR / "trusty_with_mime.pkl"
-@pytest.mark.lxd_container
+@pytest.mark.skipif(
+ PLATFORM != "lxd_container", reason=f"Not tested on {PLATFORM}"
+)
def test_log_message_on_missing_version_file(client: IntegrationInstance):
client.push_file(TEST_PICKLE, PICKLE_PATH)
client.restart()
diff --git a/tests/integration_tests/modules/test_power_state_change.py b/tests/integration_tests/modules/test_power_state_change.py
index 5cd19764..dd5bd478 100644
--- a/tests/integration_tests/modules/test_power_state_change.py
+++ b/tests/integration_tests/modules/test_power_state_change.py
@@ -9,6 +9,8 @@ import pytest
from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import IS_UBUNTU
from tests.integration_tests.util import verify_ordered_items_in_text
USER_DATA = """\
@@ -51,8 +53,11 @@ def _can_connect(instance):
# run anywhere, I can only get it to run in an lxd container, and even then
# occasionally some timing issues will crop up.
@pytest.mark.unstable
-@pytest.mark.ubuntu
-@pytest.mark.lxd_container
+@pytest.mark.skipif(not IS_UBUNTU, reason="Only ever tested on Ubuntu")
+@pytest.mark.skipif(
+ PLATFORM != "lxd_container",
+ reason="Test is unstable but most stable on lxd containers",
+)
class TestPowerChange:
@pytest.mark.parametrize(
"mode,delay,timeout,expected",
diff --git a/tests/integration_tests/modules/test_set_password.py b/tests/integration_tests/modules/test_set_password.py
index 765dd30c..48fe536c 100644
--- a/tests/integration_tests/modules/test_set_password.py
+++ b/tests/integration_tests/modules/test_set_password.py
@@ -11,8 +11,8 @@ only specify one user-data per instance.
import pytest
import yaml
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.decorators import retry
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU
from tests.integration_tests.util import get_console_log
COMMON_USER_DATA = """\
@@ -182,7 +182,7 @@ class Mixin:
def test_sshd_config_file(self, class_client):
"""Test that SSH config is written in the correct file."""
- if ImageSpecification.from_os_image().release in {"bionic"}:
+ if CURRENT_RELEASE.series == "bionic":
sshd_file_target = "/etc/ssh/sshd_config"
else:
sshd_file_target = "/etc/ssh/sshd_config.d/50-cloud-init.conf"
@@ -191,7 +191,7 @@ class Mixin:
# We look for the exact line match, to avoid a commented line matching
assert "PasswordAuthentication yes" in sshd_config.splitlines()
- @pytest.mark.ubuntu
+ @pytest.mark.skipif(not IS_UBUNTU, reason="Use of systemctl")
def test_check_ssh_service(self, class_client):
"""Ensure we check the sshd status because we modified the config"""
log = class_client.read_from_file("/var/log/cloud-init.log")
diff --git a/tests/integration_tests/modules/test_ssh_keys_provided.py b/tests/integration_tests/modules/test_ssh_keys_provided.py
index b6069376..576b78eb 100644
--- a/tests/integration_tests/modules/test_ssh_keys_provided.py
+++ b/tests/integration_tests/modules/test_ssh_keys_provided.py
@@ -9,7 +9,7 @@ system.
import pytest
-from tests.integration_tests.clouds import ImageSpecification
+from tests.integration_tests.releases import CURRENT_RELEASE
USER_DATA = """\
#cloud-config
@@ -143,7 +143,7 @@ class TestSshKeysProvided:
"HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub",
"HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub",
)
- if ImageSpecification.from_os_image().release in {"bionic"}:
+ if CURRENT_RELEASE.series == "bionic":
sshd_config_path = "/etc/ssh/sshd_config"
else:
sshd_config_path = "/etc/ssh/sshd_config.d/50-cloud-init.conf"
diff --git a/tests/integration_tests/modules/test_ssh_keysfile.py b/tests/integration_tests/modules/test_ssh_keysfile.py
index 8330a1ce..628ad91f 100644
--- a/tests/integration_tests/modules/test_ssh_keysfile.py
+++ b/tests/integration_tests/modules/test_ssh_keysfile.py
@@ -4,8 +4,8 @@ import paramiko
import pytest
from paramiko.ssh_exception import SSHException
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU
from tests.integration_tests.util import get_test_rsa_keypair
TEST_USER1_KEYS = get_test_rsa_keypair("test1")
@@ -91,7 +91,7 @@ def common_verify(client, expected_keys):
home_dir = "/home/{}".format(user)
# Home permissions aren't consistent between releases. On ubuntu
# this can change to 750 once focal is unsupported.
- if ImageSpecification.from_os_image().release in ("bionic", "focal"):
+ if CURRENT_RELEASE.series in ("bionic", "focal"):
home_perms = "755"
else:
home_perms = "750"
@@ -125,7 +125,9 @@ def common_verify(client, expected_keys):
DEFAULT_KEYS_USERDATA = _USERDATA.format(bootcmd='""')
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not IS_UBUNTU, reason="Tests permissions specific to Ubuntu releases"
+)
@pytest.mark.user_data(DEFAULT_KEYS_USERDATA)
def test_authorized_keys_default(client: IntegrationInstance):
expected_keys = [
@@ -154,7 +156,9 @@ AUTHORIZED_KEYS2_USERDATA = _USERDATA.format(
)
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not IS_UBUNTU, reason="Tests permissions specific to Ubuntu releases"
+)
@pytest.mark.user_data(AUTHORIZED_KEYS2_USERDATA)
def test_authorized_keys2(client: IntegrationInstance):
expected_keys = [
@@ -183,7 +187,9 @@ NESTED_KEYS_USERDATA = _USERDATA.format(
)
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not IS_UBUNTU, reason="Tests permissions specific to Ubuntu releases"
+)
@pytest.mark.user_data(NESTED_KEYS_USERDATA)
def test_nested_keys(client: IntegrationInstance):
expected_keys = [
@@ -204,7 +210,9 @@ EXTERNAL_KEYS_USERDATA = _USERDATA.format(
)
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not IS_UBUNTU, reason="Tests permissions specific to Ubuntu releases"
+)
@pytest.mark.user_data(EXTERNAL_KEYS_USERDATA)
def test_external_keys(client: IntegrationInstance):
expected_keys = [
diff --git a/tests/integration_tests/modules/test_ubuntu_advantage.py b/tests/integration_tests/modules/test_ubuntu_advantage.py
index 547ec9e7..0b3ed2d7 100644
--- a/tests/integration_tests/modules/test_ubuntu_advantage.py
+++ b/tests/integration_tests/modules/test_ubuntu_advantage.py
@@ -5,12 +5,20 @@ import os
import pytest
from pycloudlib.cloud import ImageType
-from tests.integration_tests.clouds import ImageSpecification, IntegrationCloud
+from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.conftest import get_validated_source
from tests.integration_tests.instances import (
CloudInitSource,
IntegrationInstance,
)
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import (
+ BIONIC,
+ CURRENT_RELEASE,
+ FOCAL,
+ IS_UBUNTU,
+ JAMMY,
+)
from tests.integration_tests.util import verify_clean_log
LOG = logging.getLogger("integration_testing.test_ubuntu_advantage")
@@ -109,7 +117,7 @@ def get_services_status(client: IntegrationInstance) -> dict:
@pytest.mark.adhoc
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Test is Ubuntu specific")
@pytest.mark.skipif(
not CLOUD_INIT_UA_TOKEN, reason="CLOUD_INIT_UA_TOKEN env var not provided"
)
@@ -136,12 +144,11 @@ class TestUbuntuAdvantage:
def maybe_install_cloud_init(session_cloud: IntegrationCloud):
- cfg_image_spec = ImageSpecification.from_os_image()
source = get_validated_source(session_cloud)
launch_kwargs = {
"image_id": session_cloud.cloud_instance.daily_image(
- cfg_image_spec.image_id, image_type=ImageType.PRO
+ CURRENT_RELEASE.image_id, image_type=ImageType.PRO
)
}
@@ -192,16 +199,16 @@ def maybe_install_cloud_init(session_cloud: IntegrationCloud):
return {"image_id": session_cloud.snapshot_id}
-@pytest.mark.azure
-@pytest.mark.ec2
-@pytest.mark.gce
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not all([IS_UBUNTU, CURRENT_RELEASE in [BIONIC, FOCAL, JAMMY]]),
+ reason="Test runs on Ubuntu LTS releases only",
+)
+@pytest.mark.skipif(
+ PLATFORM not in ["azure", "ec2", "gce"],
+ reason=f"Pro isn't offered on {PLATFORM}.",
+)
class TestUbuntuAdvantagePro:
def test_custom_services(self, session_cloud: IntegrationCloud):
- release = ImageSpecification.from_os_image().release
- if release not in {"bionic", "focal", "jammy"}:
- pytest.skip(f"Cannot run on non LTS release: {release}")
-
launch_kwargs = maybe_install_cloud_init(session_cloud)
with session_cloud.launch(
user_data=AUTO_ATTACH_CUSTOM_SERVICES,
diff --git a/tests/integration_tests/modules/test_ubuntu_autoinstall.py b/tests/integration_tests/modules/test_ubuntu_autoinstall.py
index d340afc5..ad077977 100644
--- a/tests/integration_tests/modules/test_ubuntu_autoinstall.py
+++ b/tests/integration_tests/modules/test_ubuntu_autoinstall.py
@@ -2,6 +2,8 @@
import pytest
+from tests.integration_tests.releases import IS_UBUNTU
+
USER_DATA = """\
#cloud-config
autoinstall:
@@ -16,7 +18,7 @@ snap:
LOG_MSG = "Valid autoinstall schema. Config will be processed by subiquity"
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Test is Ubuntu specific")
@pytest.mark.user_data(USER_DATA)
class TestUbuntuAutoinstall:
def test_autoinstall_schema_valid_when_snap_present(self, class_client):
diff --git a/tests/integration_tests/modules/test_ubuntu_drivers.py b/tests/integration_tests/modules/test_ubuntu_drivers.py
index 4fbfba3c..66649c17 100644
--- a/tests/integration_tests/modules/test_ubuntu_drivers.py
+++ b/tests/integration_tests/modules/test_ubuntu_drivers.py
@@ -3,6 +3,7 @@ import re
import pytest
from tests.integration_tests.clouds import IntegrationCloud
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import verify_clean_log
USER_DATA = """\
@@ -16,7 +17,7 @@ drivers:
@pytest.mark.adhoc # Expensive instance type
-@pytest.mark.oci
+@pytest.mark.skipif(PLATFORM != "oci", reason="Test is OCI specific")
def test_ubuntu_drivers_installed(session_cloud: IntegrationCloud):
with session_cloud.launch(
launch_kwargs={"instance_type": "VM.GPU2.1"}, user_data=USER_DATA
diff --git a/tests/integration_tests/modules/test_user_events.py b/tests/integration_tests/modules/test_user_events.py
index e4a4241f..79d88022 100644
--- a/tests/integration_tests/modules/test_user_events.py
+++ b/tests/integration_tests/modules/test_user_events.py
@@ -9,6 +9,7 @@ import pytest
import yaml
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
def _add_dummy_bridge_to_netplan(client: IntegrationInstance):
@@ -26,12 +27,11 @@ def _add_dummy_bridge_to_netplan(client: IntegrationInstance):
client.write_to_file("/etc/netplan/50-cloud-init.yaml", dumped_netplan)
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
-@pytest.mark.ec2
-@pytest.mark.gce
-@pytest.mark.oci
-@pytest.mark.openstack
+@pytest.mark.skipif(
+ PLATFORM
+ not in ["lxd_container", "lxd_vm", "ec2", "gce", "oci", "openstack"],
+ reason="Default boot events testing is datasource specific",
+)
def test_boot_event_disabled_by_default(client: IntegrationInstance):
log = client.read_from_file("/var/log/cloud-init.log")
if "network config is disabled" in log:
@@ -92,7 +92,13 @@ def _test_network_config_applied_on_reboot(client: IntegrationInstance):
assert "dummy0" not in client.execute("ls /sys/class/net")
-@pytest.mark.azure
+@pytest.mark.skipif(
+ PLATFORM != "azure",
+ reason=(
+ f"{PLATFORM} doesn't support updates every boot event by default "
+ "(or hasn't been testing for it)."
+ ),
+)
def test_boot_event_enabled_by_default(client: IntegrationInstance):
_test_network_config_applied_on_reboot(client)
diff --git a/tests/integration_tests/modules/test_users_groups.py b/tests/integration_tests/modules/test_users_groups.py
index 91eca345..cc6a4bfb 100644
--- a/tests/integration_tests/modules/test_users_groups.py
+++ b/tests/integration_tests/modules/test_users_groups.py
@@ -8,8 +8,8 @@ import re
import pytest
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU, JAMMY
from tests.integration_tests.util import verify_clean_log
USER_DATA = """\
@@ -56,7 +56,7 @@ class TestUsersGroups:
confirms that they have been configured correctly in the system under test.
"""
- @pytest.mark.ubuntu
+ @pytest.mark.skipif(not IS_UBUNTU, reason="Test assumes 'ubuntu' user")
@pytest.mark.parametrize(
"getent_args,regex",
[
@@ -108,6 +108,10 @@ class TestUsersGroups:
@pytest.mark.user_data(USER_DATA)
+@pytest.mark.skipif(
+ CURRENT_RELEASE < JAMMY,
+ reason="Requires version of sudo not available in older releases",
+)
def test_sudoers_includedir(client: IntegrationInstance):
"""Ensure we don't add additional #includedir to sudoers.
@@ -117,13 +121,6 @@ def test_sudoers_includedir(client: IntegrationInstance):
https://github.com/canonical/cloud-init/pull/783
"""
- if ImageSpecification.from_os_image().release in [
- "bionic",
- "focal",
- ]:
- raise pytest.skip(
- "Test requires version of sudo installed on groovy and later"
- )
client.execute("sed -i 's/#include/@include/g' /etc/sudoers")
sudoers = client.read_from_file("/etc/sudoers")
diff --git a/tests/integration_tests/modules/test_version_change.py b/tests/integration_tests/modules/test_version_change.py
index 3168cd60..9df436b8 100644
--- a/tests/integration_tests/modules/test_version_change.py
+++ b/tests/integration_tests/modules/test_version_change.py
@@ -3,6 +3,7 @@ from pathlib import Path
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import ASSETS_DIR, verify_clean_log
PICKLE_PATH = Path("/var/lib/cloud/instance/obj.pkl")
@@ -41,12 +42,12 @@ def test_reboot_without_version_change(client: IntegrationInstance):
)
-@pytest.mark.ec2
-@pytest.mark.gce
-@pytest.mark.oci
-@pytest.mark.openstack
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ PLATFORM
+ not in ["ec2", "gce", "oci", "openstack", "lxd_container", "lxd_vm"],
+ reason=f"Test hasn't been tested on {PLATFORM}.",
+)
+# TODO: The below comment likely isn't true anymore
# No Azure because the cache gets purged every reboot, so we'll never
# get to the point where we need to purge cache due to version change
def test_cache_purged_on_version_change(client: IntegrationInstance):
diff --git a/tests/integration_tests/modules/test_wireguard.py b/tests/integration_tests/modules/test_wireguard.py
index e658a9df..e685a269 100644
--- a/tests/integration_tests/modules/test_wireguard.py
+++ b/tests/integration_tests/modules/test_wireguard.py
@@ -4,6 +4,8 @@ from pycloudlib.lxd.instance import LXDInstance
from cloudinit.subp import subp
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import IS_UBUNTU
ASCII_TEXT = "ASCII text"
@@ -55,13 +57,13 @@ def load_wireguard_kernel_module_lxd(instance: LXDInstance):
@pytest.mark.ci
@pytest.mark.user_data(USER_DATA)
-@pytest.mark.lxd_vm
-@pytest.mark.gce
-@pytest.mark.ec2
-@pytest.mark.azure
-@pytest.mark.openstack
-@pytest.mark.oci
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not IS_UBUNTU, reason="Hasn't been tested on other distros"
+)
+@pytest.mark.skipif(
+ PLATFORM not in ["lxd_vm", "gce", "ec2", "azure", "openstack", "oci"],
+ reason=f"Test hasn't been tested on {PLATFORM}",
+)
class TestWireguard:
@pytest.mark.parametrize(
"cmd,expected_out",
@@ -119,8 +121,10 @@ class TestWireguard:
@pytest.mark.ci
@pytest.mark.user_data(USER_DATA)
@pytest.mark.lxd_setup.with_args(load_wireguard_kernel_module_lxd)
-@pytest.mark.lxd_container
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ PLATFORM != "lxd_container", reason=f"Not testing on {PLATFORM}"
+)
+@pytest.mark.skipif(not IS_UBUNTU, reason="Has only been tested on Ubuntu")
class TestWireguardWithoutKmod:
def test_wireguard_tools_installed(
self, class_client: IntegrationInstance
diff --git a/tests/integration_tests/releases.py b/tests/integration_tests/releases.py
new file mode 100644
index 00000000..b2ab9cee
--- /dev/null
+++ b/tests/integration_tests/releases.py
@@ -0,0 +1,92 @@
+import functools
+import logging
+from typing import Optional
+
+from packaging import version
+
+from cloudinit import subp
+from cloudinit.subp import ProcessExecutionError
+from tests.integration_tests import integration_settings
+
+log = logging.getLogger("integration_testing")
+
+
+def get_all_ubuntu_series() -> list:
+ """Use distro-info-data's ubuntu.csv to get a list of Ubuntu series"""
+ out = ""
+ try:
+ out, _err = subp.subp(["ubuntu-distro-info", "-a"])
+ except ProcessExecutionError:
+ log.info(
+ "ubuntu-distro-info (from the distro-info package) must be"
+ " installed to guess Ubuntu os/release"
+ )
+ return out.splitlines()
+
+
+def ubuntu_version_from_series(series) -> str:
+ try:
+ out, _err = subp.subp(
+ ["ubuntu-distro-info", "--release", "--series", series]
+ )
+ except subp.ProcessExecutionError as e:
+ raise ValueError(
+ f"'{series}' is not a recognized Ubuntu release"
+ ) from e
+ return out.strip().rstrip(" LTS")
+
+
+@functools.total_ordering
+class Release:
+ def __init__(
+ self,
+ os: str,
+ series: str,
+ version: str,
+ image_id: Optional[str] = None,
+ ):
+ self.os = os
+ self.series = series
+ self.version = version
+ self.image_id = image_id
+
+ def __repr__(self):
+ return f"Release({self.os}, {self.version})"
+
+ def __lt__(self, other: "Release"):
+ if self.os != other.os:
+ raise ValueError(f"{self.os} cannot be compared to {other.os}!")
+ return version.parse(self.version) < version.parse(other.version)
+
+ @classmethod
+ def from_os_image(
+ cls,
+ os_image: str = integration_settings.OS_IMAGE,
+ ) -> "Release":
+ """Get the individual parts from an OS_IMAGE definition.
+
+ Returns a namedtuple containing id, os, and release of the image."""
+ parts = os_image.split("::", 2)
+ if len(parts) == 1:
+ image_id = None
+ os = "ubuntu"
+ series = parts[0]
+ version = ubuntu_version_from_series(series)
+ elif len(parts) == 4:
+ image_id, os, series, version = parts
+ else:
+ raise ValueError(
+ "OS_IMAGE must either contain release name or be in the form "
+ "of <image_id>[::<os>[::<release>[::<version>]]]"
+ )
+ return cls(os, series, version, image_id)
+
+
+BIONIC = Release("ubuntu", "bionic", "18.04")
+FOCAL = Release("ubuntu", "focal", "20.04")
+JAMMY = Release("ubuntu", "jammy", "22.04")
+KINETIC = Release("ubuntu", "kinetic", "22.10")
+LUNAR = Release("ubuntu", "lunar", "23.04")
+
+CURRENT_RELEASE = Release.from_os_image()
+IS_UBUNTU = CURRENT_RELEASE.os == "ubuntu"
diff --git a/tests/integration_tests/test_paths.py b/tests/integration_tests/test_paths.py
index 14513c82..b63da5a4 100644
--- a/tests/integration_tests/test_paths.py
+++ b/tests/integration_tests/test_paths.py
@@ -10,6 +10,7 @@ from cloudinit.cmd.devel.logs import (
INSTALLER_APPORT_SENSITIVE_FILES,
)
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL
from tests.integration_tests.util import verify_clean_log
DEFAULT_CLOUD_DIR = "/var/lib/cloud"
@@ -111,7 +112,10 @@ class TestHonorCloudDir:
# because the test ensures nothing is running under /var/lib/cloud.
# Since LXD is doing this and not cloud-init, we should just not run
# on Bionic to avoid it.
- @pytest.mark.not_bionic
+ @pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL,
+ reason="LXD inserts conflicting setup on releases prior to focal",
+ )
def test_honor_cloud_dir(self, custom_client: IntegrationInstance):
"""Integration test for LP: #1976564
diff --git a/tests/integration_tests/test_upgrade.py b/tests/integration_tests/test_upgrade.py
index 5ef82e88..787bda44 100644
--- a/tests/integration_tests/test_upgrade.py
+++ b/tests/integration_tests/test_upgrade.py
@@ -4,8 +4,10 @@ import os
import pytest
-from tests.integration_tests.clouds import ImageSpecification, IntegrationCloud
+from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.conftest import get_validated_source
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL, IS_UBUNTU
from tests.integration_tests.util import verify_clean_log
LOG = logging.getLogger("integration_testing.test_upgrade")
@@ -41,23 +43,20 @@ hostname: SRU-worked
"""
+# The issues that we see on Bionic VMs don't appear anywhere
+# else, including when calling KVM directly. It likely has to
+# do with the extra lxd-agent setup happening on bionic.
+# Given that we still have Bionic covered on all other platforms,
+# the risk of skipping bionic here seems low enough.
+@pytest.mark.skipif(
+ PLATFORM == "lxd_vm" and CURRENT_RELEASE < FOCAL,
+ reason="Update test doesn't run on Bionic LXD VMs",
+)
def test_clean_boot_of_upgraded_package(session_cloud: IntegrationCloud):
source = get_validated_source(session_cloud)
if not source.installs_new_version():
pytest.skip(UNSUPPORTED_INSTALL_METHOD_MSG.format(source))
return # type checking doesn't understand that skip raises
- if (
- ImageSpecification.from_os_image().release == "bionic"
- and session_cloud.settings.PLATFORM == "lxd_vm"
- ):
- # The issues that we see on Bionic VMs don't appear anywhere
- # else, including when calling KVM directly. It likely has to
- # do with the extra lxd-agent setup happening on bionic.
- # Given that we still have Bionic covered on all other platforms,
- # the risk of skipping bionic here seems low enough.
- pytest.skip("Upgrade test doesn't run on LXD VMs and bionic")
- return
-
launch_kwargs = {
"image_id": session_cloud.initial_image_id,
}
@@ -172,11 +171,11 @@ def test_clean_boot_of_upgraded_package(session_cloud: IntegrationCloud):
@pytest.mark.ci
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Only ever tested on Ubuntu")
def test_subsequent_boot_of_upgraded_package(session_cloud: IntegrationCloud):
source = get_validated_source(session_cloud)
if not source.installs_new_version():
- if os.environ.get("TRAVIS"):
+ if os.environ.get("GITHUB_ACTIONS"):
# If this isn't running on CI, we should know
pytest.fail(UNSUPPORTED_INSTALL_METHOD_MSG.format(source))
else:
diff --git a/tests/unittests/config/test_schema.py b/tests/unittests/config/test_schema.py
index 8276511d..0e49dbf3 100644
--- a/tests/unittests/config/test_schema.py
+++ b/tests/unittests/config/test_schema.py
@@ -51,6 +51,7 @@ from tests.unittests.helpers import (
mock,
skipUnlessHypothesisJsonSchema,
skipUnlessJsonSchema,
+ skipUnlessJsonSchemaVersionGreaterThan,
)
from tests.unittests.util import FakeDataSource
@@ -422,7 +423,7 @@ class TestValidateCloudConfigSchema:
context_mgr.value
)
- @skipUnlessJsonSchema()
+ @skipUnlessJsonSchemaVersionGreaterThan(version=(3, 0, 0))
def test_validateconfig_strict_metaschema_do_not_raise_exception(
self, caplog
):
@@ -1770,7 +1771,7 @@ class TestStrictMetaschema:
else:
logging.warning("module %s has no schema definition", name)
- @skipUnlessJsonSchema()
+ @skipUnlessJsonSchemaVersionGreaterThan(version=(3, 0, 0))
def test_validate_bad_module(self):
"""Throw exception by default, don't throw if throw=False
diff --git a/tests/unittests/helpers.py b/tests/unittests/helpers.py
index 32503fb8..0656da33 100644
--- a/tests/unittests/helpers.py
+++ b/tests/unittests/helpers.py
@@ -491,9 +491,23 @@ try:
import jsonschema
assert jsonschema # avoid pyflakes error F401: import unused
+ _jsonschema_version = tuple(
+ int(part) for part in jsonschema.__version__.split(".") # type: ignore
+ )
_missing_jsonschema_dep = False
except ImportError:
_missing_jsonschema_dep = True
+ _jsonschema_version = (0, 0, 0)
+
+
+def skipUnlessJsonSchemaVersionGreaterThan(version=(0, 0, 0)):
+ return skipIf(
+ _jsonschema_version <= version,
+ reason=(
+ f"python3-jsonschema {_jsonschema_version} not greater than"
+ f" {version}"
+ ),
+ )
def skipUnlessJsonSchema():
diff --git a/tests/unittests/net/test_dhcp.py b/tests/unittests/net/test_dhcp.py
index 2b680e1f..4c30dd64 100644
--- a/tests/unittests/net/test_dhcp.py
+++ b/tests/unittests/net/test_dhcp.py
@@ -802,7 +802,7 @@ class TestEphemeralDhcpNoNetworkSetup(ResponsesTestCase):
) as lease:
self.assertEqual(fake_lease, lease)
# Ensure that dhcp discovery occurs
- m_dhcp.called_once_with()
+ m_dhcp.assert_called_once()
@pytest.mark.parametrize(
diff --git a/tests/unittests/sources/azure/test_imds.py b/tests/unittests/sources/azure/test_imds.py
index 03f66502..9a8aad88 100644
--- a/tests/unittests/sources/azure/test_imds.py
+++ b/tests/unittests/sources/azure/test_imds.py
@@ -549,7 +549,6 @@ class TestFetchReprovisionData:
"terminal_error",
[
requests.ConnectionError("Fake connection error"),
- requests.Timeout("Fake connection timeout"),
],
)
def test_retry_until_failure(
diff --git a/tests/unittests/sources/test_azure.py b/tests/unittests/sources/test_azure.py
index 9815c913..6c3e9281 100644
--- a/tests/unittests/sources/test_azure.py
+++ b/tests/unittests/sources/test_azure.py
@@ -2921,8 +2921,8 @@ class TestPreprovisioningHotAttachNics(CiTestCase):
# Re-run tests to verify max connection error retries.
m_request.reset_mock()
m_request.side_effect = [
- requests.Timeout("Fake connection timeout")
- ] * 9 + [requests.ConnectionError("Fake Network Unreachable")] * 9
+ requests.ConnectionError("Fake Network Unreachable")
+ ] * 15
dsa = dsaz.DataSourceAzure({}, distro=distro, paths=self.paths)
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index 865f202a..e5243ef3 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -854,64 +854,66 @@ class TestBlkid(CiTestCase):
)
-@mock.patch("cloudinit.subp.which")
-@mock.patch("cloudinit.subp.subp")
+@mock.patch("cloudinit.util.subp.which")
+@mock.patch("cloudinit.util.subp.subp")
class TestUdevadmSettle(CiTestCase):
- def test_with_no_params(self, m_which, m_subp):
+ def test_with_no_params(self, m_subp, m_which):
"""called with no parameters."""
m_which.side_effect = lambda m: m in ("udevadm",)
util.udevadm_settle()
- m_subp.called_once_with(mock.call(["udevadm", "settle"]))
+ m_subp.assert_called_once_with(["udevadm", "settle"])
- def test_udevadm_not_present(self, m_which, m_subp):
+ def test_udevadm_not_present(self, m_subp, m_which):
"""where udevadm program does not exist should not invoke subp."""
m_which.side_effect = lambda m: m in ("",)
util.udevadm_settle()
- m_subp.called_once_with(["which", "udevadm"])
+ m_which.assert_called_once_with("udevadm")
+ m_subp.assert_not_called()
- def test_with_exists_and_not_exists(self, m_which, m_subp):
+ def test_with_exists_and_not_exists(self, m_subp, m_which):
"""with exists=file where file does not exist should invoke subp."""
m_which.side_effect = lambda m: m in ("udevadm",)
mydev = self.tmp_path("mydev")
util.udevadm_settle(exists=mydev)
- m_subp.called_once_with(
+ m_subp.assert_called_once_with(
["udevadm", "settle", "--exit-if-exists=%s" % mydev]
)
- def test_with_exists_and_file_exists(self, m_which, m_subp):
+ def test_with_exists_and_file_exists(self, m_subp, m_which):
"""with exists=file where file does exist should only invoke subp
once for 'which' call."""
m_which.side_effect = lambda m: m in ("udevadm",)
mydev = self.tmp_path("mydev")
util.write_file(mydev, "foo\n")
util.udevadm_settle(exists=mydev)
- m_subp.called_once_with(["which", "udevadm"])
+ m_which.assert_called_once_with("udevadm")
+ m_subp.assert_not_called()
- def test_with_timeout_int(self, m_which, m_subp):
+ def test_with_timeout_int(self, m_subp, m_which):
"""timeout can be an integer."""
m_which.side_effect = lambda m: m in ("udevadm",)
timeout = 9
util.udevadm_settle(timeout=timeout)
- m_subp.called_once_with(
+ m_subp.assert_called_once_with(
["udevadm", "settle", "--timeout=%s" % timeout]
)
- def test_with_timeout_string(self, m_which, m_subp):
+ def test_with_timeout_string(self, m_subp, m_which):
"""timeout can be a string."""
m_which.side_effect = lambda m: m in ("udevadm",)
timeout = "555"
util.udevadm_settle(timeout=timeout)
- m_subp.called_once_with(
+ m_subp.assert_called_once_with(
["udevadm", "settle", "--timeout=%s" % timeout]
)
- def test_with_exists_and_timeout(self, m_which, m_subp):
+ def test_with_exists_and_timeout(self, m_subp, m_which):
"""test call with both exists and timeout."""
m_which.side_effect = lambda m: m in ("udevadm",)
mydev = self.tmp_path("mydev")
timeout = "3"
- util.udevadm_settle(exists=mydev)
- m_subp.called_once_with(
+ util.udevadm_settle(exists=mydev, timeout=timeout)
+ m_subp.assert_called_once_with(
[
"udevadm",
"settle",
@@ -920,7 +922,7 @@ class TestUdevadmSettle(CiTestCase):
]
)
- def test_subp_exception_raises_to_caller(self, m_which, m_subp):
+ def test_subp_exception_raises_to_caller(self, m_subp, m_which):
m_which.side_effect = lambda m: m in ("udevadm",)
m_subp.side_effect = subp.ProcessExecutionError("BOOM")
self.assertRaises(subp.ProcessExecutionError, util.udevadm_settle)
diff --git a/tox.ini b/tox.ini
index b49272ac..c0a3b868 100644
--- a/tox.ini
+++ b/tox.ini
@@ -296,27 +296,16 @@ markers =
adhoc: only run on adhoc basis, not in any CI environment (travis or jenkins)
allow_all_subp: allow all subp usage (disable_subp_usage)
allow_subp_for: allow subp usage for the given commands (disable_subp_usage)
- azure: test will only run on Azure platform
ci: run this integration test as part of CI test runs
ds_sys_cfg: a sys_cfg dict to be used by datasource fixtures
- ec2: test will only run on EC2 platform
- gce: test will only run on GCE platform
hypothesis_slow: hypothesis test too slow to run as unit test
- ibm: test will only run on IBM platform
instance_name: the name to be used for the test instance
integration_cloud_args: args for IntegrationCloud customization
is_iscsi: whether is an instance has iscsi net cfg or not
lxd_config_dict: set the config_dict passed on LXD instance creation
- lxd_container: test will only run in LXD container
lxd_setup: specify callable to be called between init and start
lxd_use_exec: `execute` will use `lxc exec` instead of SSH
- lxd_vm: test will only run in LXD VM
- no_container: test cannot run in a container
- not_bionic: test cannot run on the bionic release
- oci: test will only run on OCI platform
- openstack: test will only run on openstack platform
serial: tests that do not work in parallel, skipped with py3-fast
- ubuntu: this test should run on Ubuntu
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