From 82ffc53273927bfc8d71e7f0c858753552d85cf1 Mon Sep 17 00:00:00 2001 From: James Falcon Date: Thu, 1 Oct 2020 15:32:35 -0500 Subject: Initial implementation of integration testing infrastructure (#581) --- tox.ini | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tox.ini') diff --git a/tox.ini b/tox.ini index a92c63e0..3bc83a2a 100644 --- a/tox.ini +++ b/tox.ini @@ -139,8 +139,15 @@ deps = [pytest] # TODO: s/--strict/--strict-markers/ once xenial support is dropped +testpaths = cloudinit tests/unittests addopts = --strict markers = allow_subp_for: allow subp usage for the given commands (disable_subp_usage) allow_all_subp: allow all subp usage (disable_subp_usage) 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 + azure: test will only run on Azure platform + oci: test will only run on OCI platform + lxd_container: test will only run in LXD container + user_data: the user data to be passed to the test instance -- cgit v1.2.3 From b4f1abf9a2470adf447d8032a56a0ee17947f929 Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Mon, 5 Oct 2020 13:22:55 -0400 Subject: tox.ini: add integration-tests testenv definition (#595) --- tox.ini | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tox.ini') diff --git a/tox.ini b/tox.ini index 3bc83a2a..1160072a 100644 --- a/tox.ini +++ b/tox.ini @@ -137,6 +137,15 @@ passenv = HOME TRAVIS deps = -r{toxinidir}/integration-requirements.txt +[testenv:integration-tests] +basepython = python3 +commands = {envpython} -m pytest --log-cli-level=INFO {posargs:tests/integration_tests} +passenv = CLOUD_INIT_* +# test-requirements.txt is required for ./conftest.py to import successfully +deps = + -r{toxinidir}/integration-requirements.txt + -r{toxinidir}/test-requirements.txt + [pytest] # TODO: s/--strict/--strict-markers/ once xenial support is dropped testpaths = cloudinit tests/unittests -- cgit v1.2.3 From 5435205decf3c8582258d0782dc54aebdd154212 Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Tue, 6 Oct 2020 10:52:20 -0400 Subject: conftest.py: remove top-level import of httpretty (#599) This means that the integration tests do not need to install test-requirements.txt in order to successfully import `conftest.py`. --- conftest.py | 12 +++++++++++- tox.ini | 2 -- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'tox.ini') diff --git a/conftest.py b/conftest.py index 76e9000a..459b708a 100644 --- a/conftest.py +++ b/conftest.py @@ -1,8 +1,16 @@ +"""Global conftest.py + +This conftest is used for unit tests in ``cloudinit/`` and ``tests/unittests/`` +as well as the integration tests in ``tests/integration_tests/``. + +Any imports that are performed at the top-level here must be installed wherever +any of these tests run: that is to say, they must be listed in +``integration-requirements.txt`` and in ``test-requirements.txt``. +""" import os from unittest import mock import pytest -import httpretty as _httpretty from cloudinit import helpers, subp @@ -156,6 +164,8 @@ def httpretty(): unset http_proxy in os.environ if present (to work around https://github.com/gabrielfalcao/HTTPretty/issues/122). """ + import httpretty as _httpretty + restore_proxy = os.environ.pop("http_proxy", None) _httpretty.HTTPretty.allow_net_connect = False _httpretty.reset() diff --git a/tox.ini b/tox.ini index 1160072a..a8681197 100644 --- a/tox.ini +++ b/tox.ini @@ -141,10 +141,8 @@ deps = basepython = python3 commands = {envpython} -m pytest --log-cli-level=INFO {posargs:tests/integration_tests} passenv = CLOUD_INIT_* -# test-requirements.txt is required for ./conftest.py to import successfully deps = -r{toxinidir}/integration-requirements.txt - -r{toxinidir}/test-requirements.txt [pytest] # TODO: s/--strict/--strict-markers/ once xenial support is dropped -- cgit v1.2.3 From d619f5171ac0ce5b626ef4575ad5f4468e94c987 Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Mon, 2 Nov 2020 13:40:10 -0500 Subject: integration_tests: various launch improvements (#638) * integration_tests: fix passing launch_kwargs to session_cloud.launch * integration_tests: log the launch_kwargs before launching instances * integration_tests: add support for specifying instance name for tests Co-authored-by: Rick Harding --- tests/integration_tests/clouds.py | 11 ++++++++--- tests/integration_tests/conftest.py | 10 +++++++++- tox.ini | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) (limited to 'tox.ini') diff --git a/tests/integration_tests/clouds.py b/tests/integration_tests/clouds.py index 06f1c623..08c86198 100644 --- a/tests/integration_tests/clouds.py +++ b/tests/integration_tests/clouds.py @@ -54,13 +54,18 @@ class IntegrationCloud(ABC): self.settings.EXISTING_INSTANCE_ID ) return - launch_kwargs = { + kwargs = { 'image_id': self.image_id, 'user_data': user_data, 'wait': False, } - launch_kwargs.update(launch_kwargs) - pycloudlib_instance = self.cloud_instance.launch(**launch_kwargs) + kwargs.update(launch_kwargs) + log.info( + "Launching instance with launch_kwargs:\n{}".format( + "\n".join("{}={}".format(*item) for item in kwargs.items()) + ) + ) + pycloudlib_instance = self.cloud_instance.launch(**kwargs) pycloudlib_instance.wait(raise_on_cloudinit_failure=False) log.info('Launched instance: %s', pycloudlib_instance) return self.get_instance(pycloudlib_instance, settings) diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py index 9163ac66..34e674e9 100644 --- a/tests/integration_tests/conftest.py +++ b/tests/integration_tests/conftest.py @@ -111,7 +111,15 @@ def _client(request, fixture_utils, session_cloud): """ user_data = fixture_utils.closest_marker_first_arg_or( request, 'user_data', None) - with session_cloud.launch(user_data=user_data) as instance: + name = fixture_utils.closest_marker_first_arg_or( + request, 'instance_name', None + ) + launch_kwargs = {} + if name is not None: + launch_kwargs = {"name": name} + with session_cloud.launch( + user_data=user_data, launch_kwargs=launch_kwargs + ) as instance: yield instance diff --git a/tox.ini b/tox.ini index a8681197..816e6e8e 100644 --- a/tox.ini +++ b/tox.ini @@ -158,3 +158,4 @@ markers = oci: test will only run on OCI platform lxd_container: test will only run in LXD container user_data: the user data to be passed to the test instance + instance_name: the name to be used for the test instance -- cgit v1.2.3 From db2ff11dea5d884093e4e29393eeac70d3315bbb Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Tue, 10 Nov 2020 12:01:29 -0500 Subject: split integration and cloud_tests requirements (#652) The cloud_tests and the integration_tests (via pycloudlib) have conflicting requirements. This commit splits up their requirements files, so we can accurately express the requirements for each. --- cloud-tests-requirements.txt | 28 ++++++++++++++++++++++++++++ integration-requirements.txt | 29 ++--------------------------- tox.ini | 4 +++- 3 files changed, 33 insertions(+), 28 deletions(-) create mode 100644 cloud-tests-requirements.txt (limited to 'tox.ini') diff --git a/cloud-tests-requirements.txt b/cloud-tests-requirements.txt new file mode 100644 index 00000000..b4cd18d5 --- /dev/null +++ b/cloud-tests-requirements.txt @@ -0,0 +1,28 @@ +# PyPI requirements for cloud-init cloud tests +# https://cloudinit.readthedocs.io/en/latest/topics/cloud_tests.html +# +# Note: Changes to this requirements may require updates to +# the packages/pkg-deps.json file as well. +# + +# ec2 backend +boto3==1.14.53 + +# ssh communication +paramiko==2.7.2 +cryptography==3.1 + +# lxd backend +pylxd==2.2.11 + +# finds latest image information +git+https://git.launchpad.net/simplestreams + +# azure backend +azure-storage==0.36.0 +msrestazure==0.6.1 +azure-common==1.1.23 +azure-mgmt-compute==7.0.0 +azure-mgmt-network==5.0.0 +azure-mgmt-resource==4.0.0 +azure-mgmt-storage==6.0.0 diff --git a/integration-requirements.txt b/integration-requirements.txt index 64455c79..7060841c 100644 --- a/integration-requirements.txt +++ b/integration-requirements.txt @@ -1,30 +1,5 @@ # PyPI requirements for cloud-init integration testing -# https://cloudinit.readthedocs.io/en/latest/topics/tests.html -# -# Note: Changes to this requirements may require updates to -# the packages/pkg-deps.json file as well. +# https://cloudinit.readthedocs.io/en/latest/topics/integration_tests.html # +pycloudlib @ git+https://github.com/canonical/pycloudlib.git pytest -git+https://github.com/canonical/pycloudlib.git - -# ec2 backend -boto3==1.14.53 - -# ssh communication -paramiko==2.7.2 -cryptography==3.1 - -# lxd backend -pylxd==2.2.11 - -# finds latest image information -git+https://git.launchpad.net/simplestreams - -# azure backend -azure-storage==0.36.0 -msrestazure==0.6.1 -azure-common==1.1.23 -azure-mgmt-compute==7.0.0 -azure-mgmt-network==5.0.0 -azure-mgmt-resource==4.0.0 -azure-mgmt-storage==6.0.0 diff --git a/tox.ini b/tox.ini index 816e6e8e..32174dee 100644 --- a/tox.ini +++ b/tox.ini @@ -26,6 +26,7 @@ deps = pylint==2.6.0 # test-requirements because unit tests are now present in cloudinit tree -r{toxinidir}/test-requirements.txt + -r{toxinidir}/cloud-tests-requirements.txt -r{toxinidir}/integration-requirements.txt commands = {envpython} -m pylint {posargs:cloudinit tests tools} @@ -128,6 +129,7 @@ deps = pylint # test-requirements -r{toxinidir}/test-requirements.txt + -r{toxinidir}/cloud-tests-requirements.txt -r{toxinidir}/integration-requirements.txt [testenv:citest] @@ -135,7 +137,7 @@ basepython = python3 commands = {envpython} -m tests.cloud_tests {posargs} passenv = HOME TRAVIS deps = - -r{toxinidir}/integration-requirements.txt + -r{toxinidir}/cloud-tests-requirements.txt [testenv:integration-tests] basepython = python3 -- cgit v1.2.3 From cd752df6154c403e6dccaf5e797c1d4f8396f756 Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Wed, 18 Nov 2020 09:48:47 -0500 Subject: only run a subset of integration tests in CI (#672) This introduces the "ci" mark, used to indicate a test which should run as part of our CI integration testing run and the integration-tests-ci tox environment, which runs only those tests. Travis has been adjusted to use this tox environment. (All current module tests have been marked with the "ci" mark, but the one bug test that we have has not.) --- .travis.yml | 2 +- .../integration_tests/modules/test_apt_configure_sources_list.py | 1 + tests/integration_tests/modules/test_ntp_servers.py | 1 + tests/integration_tests/modules/test_runcmd.py | 1 + tests/integration_tests/modules/test_seed_random_data.py | 1 + tests/integration_tests/modules/test_set_hostname.py | 1 + tests/integration_tests/modules/test_set_password.py | 2 ++ tests/integration_tests/modules/test_snap.py | 1 + tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py | 1 + tests/integration_tests/modules/test_ssh_generate.py | 1 + tests/integration_tests/modules/test_ssh_import_id.py | 1 + tests/integration_tests/modules/test_ssh_keys_provided.py | 1 + tests/integration_tests/modules/test_timezone.py | 1 + tests/integration_tests/modules/test_users_groups.py | 1 + tests/integration_tests/modules/test_write_files.py | 1 + tox.ini | 8 ++++++++ 16 files changed, 24 insertions(+), 1 deletion(-) (limited to 'tox.ini') diff --git a/.travis.yml b/.travis.yml index 496c1a81..6d25f477 100644 --- a/.travis.yml +++ b/.travis.yml @@ -199,7 +199,7 @@ matrix: fi # Use sudo to get a new shell where we're in the sbuild group - sudo -E su $USER -c 'sbuild --nolog --no-run-lintian --verbose --dist=xenial cloud-init_*.dsc' - - sg lxd -c 'CLOUD_INIT_IMAGE_SOURCE="$(ls *.deb)" tox -e integration-tests' & + - sg lxd -c 'CLOUD_INIT_IMAGE_SOURCE="$(ls *.deb)" tox -e integration-tests-ci' & - | SECONDS=0 while [ -e /proc/$! ]; do diff --git a/tests/integration_tests/modules/test_apt_configure_sources_list.py b/tests/integration_tests/modules/test_apt_configure_sources_list.py index d64b3956..d2bcc61a 100644 --- a/tests/integration_tests/modules/test_apt_configure_sources_list.py +++ b/tests/integration_tests/modules/test_apt_configure_sources_list.py @@ -39,6 +39,7 @@ EXPECTED_REGEXES = [ ] +@pytest.mark.ci class TestAptConfigureSourcesList: @pytest.mark.user_data(USER_DATA) diff --git a/tests/integration_tests/modules/test_ntp_servers.py b/tests/integration_tests/modules/test_ntp_servers.py index 4cad8926..e72389c1 100644 --- a/tests/integration_tests/modules/test_ntp_servers.py +++ b/tests/integration_tests/modules/test_ntp_servers.py @@ -22,6 +22,7 @@ ntp: EXPECTED_SERVERS = yaml.safe_load(USER_DATA)["ntp"]["servers"] +@pytest.mark.ci @pytest.mark.user_data(USER_DATA) class TestNtpServers: diff --git a/tests/integration_tests/modules/test_runcmd.py b/tests/integration_tests/modules/test_runcmd.py index eabe778d..50d1851e 100644 --- a/tests/integration_tests/modules/test_runcmd.py +++ b/tests/integration_tests/modules/test_runcmd.py @@ -16,6 +16,7 @@ runcmd: """ +@pytest.mark.ci class TestRuncmd: @pytest.mark.user_data(USER_DATA) diff --git a/tests/integration_tests/modules/test_seed_random_data.py b/tests/integration_tests/modules/test_seed_random_data.py index db3d2193..b365fa98 100644 --- a/tests/integration_tests/modules/test_seed_random_data.py +++ b/tests/integration_tests/modules/test_seed_random_data.py @@ -19,6 +19,7 @@ random_seed: """ +@pytest.mark.ci class TestSeedRandomData: @pytest.mark.user_data(USER_DATA) diff --git a/tests/integration_tests/modules/test_set_hostname.py b/tests/integration_tests/modules/test_set_hostname.py index ff46feb9..2bfa403d 100644 --- a/tests/integration_tests/modules/test_set_hostname.py +++ b/tests/integration_tests/modules/test_set_hostname.py @@ -25,6 +25,7 @@ fqdn: cloudinit2.i9n.cloud-init.io """ +@pytest.mark.ci class TestHostname: @pytest.mark.user_data(USER_DATA_HOSTNAME) diff --git a/tests/integration_tests/modules/test_set_password.py b/tests/integration_tests/modules/test_set_password.py index ae6fdefc..b13f76fb 100644 --- a/tests/integration_tests/modules/test_set_password.py +++ b/tests/integration_tests/modules/test_set_password.py @@ -139,11 +139,13 @@ class Mixin: assert "PasswordAuthentication yes" in sshd_config.splitlines() +@pytest.mark.ci @pytest.mark.user_data(LIST_USER_DATA) class TestPasswordList(Mixin): """Launch an instance with LIST_USER_DATA, ensure Mixin tests pass.""" +@pytest.mark.ci @pytest.mark.user_data(STRING_USER_DATA) class TestPasswordListString(Mixin): """Launch an instance with STRING_USER_DATA, ensure Mixin tests pass.""" diff --git a/tests/integration_tests/modules/test_snap.py b/tests/integration_tests/modules/test_snap.py index d78a0b1e..b626f6b0 100644 --- a/tests/integration_tests/modules/test_snap.py +++ b/tests/integration_tests/modules/test_snap.py @@ -19,6 +19,7 @@ snap: """ +@pytest.mark.ci class TestSnap: @pytest.mark.user_data(USER_DATA) diff --git a/tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py b/tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py index e88d9a02..b9b0d85e 100644 --- a/tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py +++ b/tests/integration_tests/modules/test_ssh_auth_key_fingerprints.py @@ -28,6 +28,7 @@ ssh_authorized_keys: """ # noqa +@pytest.mark.ci class TestSshAuthkeyFingerprints: @pytest.mark.user_data(USER_DATA_SSH_AUTHKEY_DISABLE) diff --git a/tests/integration_tests/modules/test_ssh_generate.py b/tests/integration_tests/modules/test_ssh_generate.py index 8c60fb87..60c36982 100644 --- a/tests/integration_tests/modules/test_ssh_generate.py +++ b/tests/integration_tests/modules/test_ssh_generate.py @@ -20,6 +20,7 @@ authkey_hash: sha512 """ +@pytest.mark.ci @pytest.mark.user_data(USER_DATA) class TestSshKeysGenerate: diff --git a/tests/integration_tests/modules/test_ssh_import_id.py b/tests/integration_tests/modules/test_ssh_import_id.py index 2f2ac92c..45d37d6c 100644 --- a/tests/integration_tests/modules/test_ssh_import_id.py +++ b/tests/integration_tests/modules/test_ssh_import_id.py @@ -17,6 +17,7 @@ ssh_import_id: """ +@pytest.mark.ci class TestSshImportId: @pytest.mark.user_data(USER_DATA) diff --git a/tests/integration_tests/modules/test_ssh_keys_provided.py b/tests/integration_tests/modules/test_ssh_keys_provided.py index 4699518d..dc6d2fc1 100644 --- a/tests/integration_tests/modules/test_ssh_keys_provided.py +++ b/tests/integration_tests/modules/test_ssh_keys_provided.py @@ -78,6 +78,7 @@ ssh_keys: """ # noqa +@pytest.mark.ci @pytest.mark.user_data(USER_DATA) class TestSshKeysProvided: diff --git a/tests/integration_tests/modules/test_timezone.py b/tests/integration_tests/modules/test_timezone.py index 6080d79e..111d53f7 100644 --- a/tests/integration_tests/modules/test_timezone.py +++ b/tests/integration_tests/modules/test_timezone.py @@ -15,6 +15,7 @@ timezone: US/Aleutian """ +@pytest.mark.ci class TestTimezone: @pytest.mark.user_data(USER_DATA) diff --git a/tests/integration_tests/modules/test_users_groups.py b/tests/integration_tests/modules/test_users_groups.py index b1fa8c22..6a085a8f 100644 --- a/tests/integration_tests/modules/test_users_groups.py +++ b/tests/integration_tests/modules/test_users_groups.py @@ -38,6 +38,7 @@ AHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/ """ +@pytest.mark.ci @pytest.mark.user_data(USER_DATA) class TestUsersGroups: @pytest.mark.parametrize( diff --git a/tests/integration_tests/modules/test_write_files.py b/tests/integration_tests/modules/test_write_files.py index d7032a0c..15832ae3 100644 --- a/tests/integration_tests/modules/test_write_files.py +++ b/tests/integration_tests/modules/test_write_files.py @@ -44,6 +44,7 @@ write_files: """.format(B64_CONTENT.decode("ascii")) +@pytest.mark.ci @pytest.mark.user_data(USER_DATA) class TestWriteFiles: diff --git a/tox.ini b/tox.ini index 32174dee..4320ab87 100644 --- a/tox.ini +++ b/tox.ini @@ -146,6 +146,13 @@ passenv = CLOUD_INIT_* deps = -r{toxinidir}/integration-requirements.txt +[testenv:integration-tests-ci] +commands = {[testenv:integration-tests]commands} +passenv = {[testenv:integration-tests]passenv} +deps = {[testenv:integration-tests]deps} +setenv = + PYTEST_ADDOPTS="-k ci" + [pytest] # TODO: s/--strict/--strict-markers/ once xenial support is dropped testpaths = cloudinit tests/unittests @@ -153,6 +160,7 @@ addopts = --strict markers = allow_subp_for: allow subp usage for the given commands (disable_subp_usage) allow_all_subp: allow all subp usage (disable_subp_usage) + 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 -- cgit v1.2.3 From 49d5de92d60af4ef483a67bd4c75148e6fdc58a3 Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Thu, 19 Nov 2020 00:09:49 -0500 Subject: tox.ini: only select "ci" marked tests for CI runs (#677) `-k` will select tests or marks whose names match. `-m` selects only tests which have the specified mark, so is more appropriate. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tox.ini') diff --git a/tox.ini b/tox.ini index 4320ab87..c86d38e9 100644 --- a/tox.ini +++ b/tox.ini @@ -151,7 +151,7 @@ commands = {[testenv:integration-tests]commands} passenv = {[testenv:integration-tests]passenv} deps = {[testenv:integration-tests]deps} setenv = - PYTEST_ADDOPTS="-k ci" + PYTEST_ADDOPTS="-m ci" [pytest] # TODO: s/--strict/--strict-markers/ once xenial support is dropped -- cgit v1.2.3 From 5d4a9a4a50a496d27510f63217bcc0c25d9a8939 Mon Sep 17 00:00:00 2001 From: Daniel Watkins Date: Fri, 20 Nov 2020 14:12:54 -0500 Subject: add integration test for LP: #1900837 (#679) As the first test of this SRU cycle, this also introduces the sru_2020_11 mark to allow us to easily identify the set of tests generated for this SRU. --- tests/integration_tests/bugs/test_lp1900837.py | 28 ++++++++++++++++++++++++++ tox.ini | 1 + 2 files changed, 29 insertions(+) create mode 100644 tests/integration_tests/bugs/test_lp1900837.py (limited to 'tox.ini') diff --git a/tests/integration_tests/bugs/test_lp1900837.py b/tests/integration_tests/bugs/test_lp1900837.py new file mode 100644 index 00000000..3fe7d0d0 --- /dev/null +++ b/tests/integration_tests/bugs/test_lp1900837.py @@ -0,0 +1,28 @@ +"""Integration test for LP: #1900836. + +This test mirrors the reproducing steps from the reported bug: it changes the +permissions on cloud-init.log to 600 and confirms that they remain 600 after a +reboot. +""" +import pytest + + +def _get_log_perms(client): + return client.execute("stat -c %a /var/log/cloud-init.log") + + +@pytest.mark.sru_2020_11 +class TestLogPermissionsNotResetOnReboot: + def test_permissions_unchanged(self, client): + # Confirm that the current permissions aren't 600 + assert "644" == _get_log_perms(client) + + # Set permissions to 600 and confirm our assertion passes pre-reboot + client.execute("chmod 600 /var/log/cloud-init.log") + assert "600" == _get_log_perms(client) + + # Reboot + client.instance.restart() + + # Check that permissions are not reset on reboot + assert "600" == _get_log_perms(client) diff --git a/tox.ini b/tox.ini index c86d38e9..066f923a 100644 --- a/tox.ini +++ b/tox.ini @@ -169,3 +169,4 @@ markers = lxd_container: test will only run in LXD container user_data: the user data to be passed to the test instance instance_name: the name to be used for the test instance + sru_2020_11: test is part of the 2020/11 SRU verification -- cgit v1.2.3 From e454dea5855019a5acdd6acafdef2ae07d069235 Mon Sep 17 00:00:00 2001 From: James Falcon Date: Mon, 23 Nov 2020 11:50:57 -0600 Subject: Integration test for fallocate falling back to dd (#681) See #585 --- tests/integration_tests/bugs/test_lp1897099.py | 31 ++++++++++++++++++++++++++ tests/integration_tests/conftest.py | 15 ++++++++++--- tox.ini | 1 + 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 tests/integration_tests/bugs/test_lp1897099.py (limited to 'tox.ini') diff --git a/tests/integration_tests/bugs/test_lp1897099.py b/tests/integration_tests/bugs/test_lp1897099.py new file mode 100644 index 00000000..27c8927f --- /dev/null +++ b/tests/integration_tests/bugs/test_lp1897099.py @@ -0,0 +1,31 @@ +""" Integration test for LP #187099 + +Ensure that if fallocate fails during mkswap that we fall back to using dd + +https://bugs.launchpad.net/cloud-init/+bug/1897099 +""" + +import pytest + + +USER_DATA = """\ +#cloud-config +bootcmd: + - echo 'whoops' > /usr/bin/fallocate +swap: + filename: /swap.img + size: 10000000 + maxsize: 10000000 +""" + + +@pytest.mark.sru_2020_11 +@pytest.mark.user_data(USER_DATA) +@pytest.mark.no_container('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') + assert '/swap.img' in client.execute('cat /etc/fstab') + assert 'fallocate swap creation failed, will attempt with dd' in log + assert "Running command ['dd', 'if=/dev/zero', 'of=/swap.img'" in log + assert 'SUCCESS: config-mounts ran successfully' in log diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py index e31a9192..54867096 100644 --- a/tests/integration_tests/conftest.py +++ b/tests/integration_tests/conftest.py @@ -37,11 +37,20 @@ def pytest_runtest_setup(item): specified, then we assume the test can be run anywhere. """ all_platforms = platforms.keys() - supported_platforms = set(all_platforms).intersection( - mark.name for mark in item.iter_markers()) + 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 Exception( + '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('Cannot run on platform {}'.format(current_platform)) + pytest.skip(unsupported_message) # disable_subp_usage is defined at a higher level, but we don't diff --git a/tox.ini b/tox.ini index 066f923a..f08e0f03 100644 --- a/tox.ini +++ b/tox.ini @@ -167,6 +167,7 @@ markers = azure: test will only run on Azure platform oci: test will only run on OCI platform lxd_container: test will only run in LXD container + no_container: test cannot run in a container user_data: the user data to be passed to the test instance instance_name: the name to be used for the test instance sru_2020_11: test is part of the 2020/11 SRU verification -- cgit v1.2.3 From 8a493bf08d8b09d4f3a35dae725756d157844201 Mon Sep 17 00:00:00 2001 From: James Falcon Date: Mon, 23 Nov 2020 12:12:52 -0600 Subject: LXD VM support in integration tests (#678) --- integration-requirements.txt | 2 +- tests/integration_tests/clouds.py | 78 +++++++++++++++++++++++++----------- tests/integration_tests/conftest.py | 4 +- tests/integration_tests/instances.py | 2 +- tox.ini | 1 + 5 files changed, 61 insertions(+), 26 deletions(-) (limited to 'tox.ini') diff --git a/integration-requirements.txt b/integration-requirements.txt index 61d2e504..e8ddb648 100644 --- a/integration-requirements.txt +++ b/integration-requirements.txt @@ -1,5 +1,5 @@ # PyPI requirements for cloud-init integration testing # https://cloudinit.readthedocs.io/en/latest/topics/integration_tests.html # -pycloudlib @ git+https://github.com/canonical/pycloudlib.git@e6b2b3732a2a17d48bdf1167f56eb14576215d3c +pycloudlib @ git+https://github.com/canonical/pycloudlib.git@9211c0e5b34794595565d4626bc41ddbe14994f2 pytest diff --git a/tests/integration_tests/clouds.py b/tests/integration_tests/clouds.py index 2841261b..88ac4408 100644 --- a/tests/integration_tests/clouds.py +++ b/tests/integration_tests/clouds.py @@ -2,7 +2,8 @@ from abc import ABC, abstractmethod import logging -from pycloudlib import EC2, GCE, Azure, OCI, LXD +from pycloudlib import EC2, GCE, Azure, OCI, LXDContainer, LXDVirtualMachine +from pycloudlib.lxd.instance import LXDInstance import cloudinit from cloudinit.subp import subp @@ -12,7 +13,7 @@ from tests.integration_tests.instances import ( IntegrationGceInstance, IntegrationAzureInstance, IntegrationInstance, IntegrationOciInstance, - IntegrationLxdContainerInstance, + IntegrationLxdInstance, ) try: @@ -143,20 +144,48 @@ class OciCloud(IntegrationCloud): ) -class LxdContainerCloud(IntegrationCloud): - datasource = 'lxd_container' - integration_instance_cls = IntegrationLxdContainerInstance +class _LxdIntegrationCloud(IntegrationCloud): + integration_instance_cls = IntegrationLxdInstance def _get_cloud_instance(self): - return LXD(tag='lxd-integration-test') + return self.pycloudlib_instance_cls(tag=self.instance_tag) + + @staticmethod + def _get_or_set_profile_list(release): + return None + + @staticmethod + def _mount_source(instance: LXDInstance): + target_path = '/usr/lib/python3/dist-packages/cloudinit' + format_variables = { + 'name': instance.name, + 'source_path': cloudinit.__path__[0], + 'container_path': target_path, + } + log.info( + 'Mounting source {source_path} directly onto LXD container/vm ' + 'named {name} at {container_path}'.format(**format_variables)) + command = ( + 'lxc config device add {name} host-cloud-init disk ' + 'source={source_path} ' + 'path={container_path}' + ).format(**format_variables) + subp(command.split()) def _perform_launch(self, launch_kwargs): launch_kwargs['inst_type'] = launch_kwargs.pop('instance_type', None) launch_kwargs.pop('wait') + release = launch_kwargs.pop('image_id') + + try: + profile_list = launch_kwargs['profile_list'] + except KeyError: + profile_list = self._get_or_set_profile_list(release) pycloudlib_instance = self.cloud_instance.init( launch_kwargs.pop('name', None), - launch_kwargs.pop('image_id'), + release, + profile_list=profile_list, **launch_kwargs ) if self.settings.CLOUD_INIT_SOURCE == 'IN_PLACE': @@ -165,19 +194,22 @@ class LxdContainerCloud(IntegrationCloud): pycloudlib_instance.wait(raise_on_cloudinit_failure=False) return pycloudlib_instance - def _mount_source(self, instance): - container_path = '/usr/lib/python3/dist-packages/cloudinit' - format_variables = { - 'name': instance.name, - 'cloudinit_path': cloudinit.__path__[0], - 'container_path': container_path, - } - log.info( - 'Mounting source {cloudinit_path} directly onto LXD container/vm ' - 'named {name} at {container_path}'.format(**format_variables)) - command = ( - 'lxc config device add {name} host-cloud-init disk ' - 'source={cloudinit_path} ' - 'path={container_path}' - ).format(**format_variables) - subp(command.split()) + +class LxdContainerCloud(_LxdIntegrationCloud): + datasource = 'lxd_container' + pycloudlib_instance_cls = LXDContainer + instance_tag = 'lxd-container-integration-test' + + +class LxdVmCloud(_LxdIntegrationCloud): + datasource = 'lxd_vm' + pycloudlib_instance_cls = LXDVirtualMachine + instance_tag = 'lxd-vm-integration-test' + _profile_list = None + + def _get_or_set_profile_list(self, release): + if self._profile_list: + return self._profile_list + self._profile_list = self.cloud_instance.build_necessary_profiles( + release) + return self._profile_list diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py index 54867096..73b44bfc 100644 --- a/tests/integration_tests/conftest.py +++ b/tests/integration_tests/conftest.py @@ -12,6 +12,7 @@ from tests.integration_tests.clouds import ( AzureCloud, OciCloud, LxdContainerCloud, + LxdVmCloud, ) @@ -25,6 +26,7 @@ platforms = { 'azure': AzureCloud, 'oci': OciCloud, 'lxd_container': LxdContainerCloud, + 'lxd_vm': LxdVmCloud, } @@ -87,7 +89,7 @@ def setup_image(session_cloud): if integration_settings.CLOUD_INIT_SOURCE == 'NONE': pass # that was easy elif integration_settings.CLOUD_INIT_SOURCE == 'IN_PLACE': - if session_cloud.datasource != 'lxd_container': + if session_cloud.datasource not in ['lxd_container', 'lxd_vm']: raise ValueError( 'IN_PLACE as CLOUD_INIT_SOURCE only works for LXD') # The mount needs to happen after the instance is created, so diff --git a/tests/integration_tests/instances.py b/tests/integration_tests/instances.py index 67a6fb92..ca0b38d5 100644 --- a/tests/integration_tests/instances.py +++ b/tests/integration_tests/instances.py @@ -125,5 +125,5 @@ class IntegrationOciInstance(IntegrationInstance): pass -class IntegrationLxdContainerInstance(IntegrationInstance): +class IntegrationLxdInstance(IntegrationInstance): use_sudo = False diff --git a/tox.ini b/tox.ini index f08e0f03..30b11398 100644 --- a/tox.ini +++ b/tox.ini @@ -167,6 +167,7 @@ markers = azure: test will only run on Azure platform oci: test will only run on OCI platform lxd_container: test will only run in LXD container + lxd_vm: test will only run in LXD VM no_container: test cannot run in a container user_data: the user data to be passed to the test instance instance_name: the name to be used for the test instance -- cgit v1.2.3 From 87df9d6cac95112560e5c652a68b74a28f4a6785 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Tue, 24 Nov 2020 07:39:56 -0700 Subject: tox: avoid tox testenv subsvars for xenial support (#684) Xenial tox 2.3.1 still suffers from https://github.com/tox-dev/tox/issues/208. As a result we cannot use testenv substvars if we want to support running tox on xenial systems. Drop the {[testenv:integration-tests]*} substitutions to avoid tracebacks when running `tox -e xenial-dev` which has the signature: "No support for the %s substitution type" % sub_type) tox.ConfigError: ConfigError: No support for the posargs substitution type --- tox.ini | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'tox.ini') diff --git a/tox.ini b/tox.ini index 30b11398..022b918d 100644 --- a/tox.ini +++ b/tox.ini @@ -139,6 +139,12 @@ passenv = HOME TRAVIS deps = -r{toxinidir}/cloud-tests-requirements.txt +# Until Xenial tox support is dropped or bumps to tox:2.3.2, reflect changes to +# deps into testenv:integration-tests-ci: commands, passenv and deps. +# This is due to (https://github.com/tox-dev/tox/issues/208) which means that +# the {posargs} handling and substitutions won't do what we want until tox 2.3.2 +# Once Xenial is dropped, integration-tests-ci can use proper substitution +# commands = {[testenv:integration-tests]commands} [testenv:integration-tests] basepython = python3 commands = {envpython} -m pytest --log-cli-level=INFO {posargs:tests/integration_tests} @@ -147,9 +153,10 @@ deps = -r{toxinidir}/integration-requirements.txt [testenv:integration-tests-ci] -commands = {[testenv:integration-tests]commands} -passenv = {[testenv:integration-tests]passenv} -deps = {[testenv:integration-tests]deps} +commands = {envpython} -m pytest --log-cli-level=INFO {posargs:tests/integration_tests} +passenv = CLOUD_INIT_* +deps = + -r{toxinidir}/integration-requirements.txt setenv = PYTEST_ADDOPTS="-m ci" -- cgit v1.2.3