From 30fa6f08a47ecae701a1b3e5dd0e5eaf5adfe6b3 Mon Sep 17 00:00:00 2001 From: Erik Flodin Date: Mon, 11 Nov 2024 22:30:41 +0100 Subject: [PATCH] Update testbed docker image * Update base image to Ubuntu 24.10. This uses a python version where j2cli no longer works when installed using pip so use the version from Ubuntu instead which has been patched to work. * Update shellcheck, pylint, pytest, isort, flake8, black and yamllint to the latest versions. This closes #502. * Use a longer expect timeout to fix tests failing when gpg is killed due to this timeout. * Explicitly flush gpg-agent's cached passwords to fix failing tests with latest gnupg. Also clean up after tests to avoid having gpg-agents running after the test (e.g. when running tests directly without docker). --- Makefile | 2 +- pyproject.toml | 1 + test/Dockerfile | 11 +++--- test/conftest.py | 39 +++++++++++++-------- test/pinentry-mock | 5 ++- test/requirements.txt | 12 +++---- test/test_alt.py | 1 + test/test_encryption.py | 2 -- test/test_help.py | 1 + test/test_list.py | 3 +- test/test_unit_choose_template_cmd.py | 7 ++-- test/test_unit_copy_perms.py | 1 + test/test_unit_exclude_encrypted.py | 1 + test/test_unit_issue_legacy_path_warning.py | 1 + test/test_unit_private_dirs.py | 1 + test/test_unit_query_distro.py | 1 + test/test_unit_query_distro_family.py | 1 + test/test_unit_record_score.py | 1 + test/test_unit_relative_path.py | 1 + test/test_unit_remove_stale_links.py | 1 + test/test_unit_report_invalid_alts.py | 1 + test/test_unit_score_file.py | 1 + test/test_unit_set_local_alt_values.py | 1 + test/test_unit_set_yadm_dir.py | 1 + test/test_unit_template_esh.py | 1 + test/test_unit_template_j2.py | 1 + test/test_unit_upgrade.py | 6 ++-- 27 files changed, 66 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index 5da0918..a28851f 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ PYTESTS = $(wildcard test/test_*.py) -IMAGE = docker.io/yadm/testbed:2023-07-12 +IMAGE = docker.io/yadm/testbed:2024-11-11 OCI = docker .PHONY: all diff --git a/pyproject.toml b/pyproject.toml index 1e51d44..e7eecfc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,7 @@ markers = [ [tool.pylint.design] max-args = 14 +max-positional-arguments = 10 max-locals = 28 max-attributes = 8 max-statements = 65 diff --git a/test/Dockerfile b/test/Dockerfile index 29d863e..a901d18 100644 --- a/test/Dockerfile +++ b/test/Dockerfile @@ -1,8 +1,7 @@ -FROM ubuntu:23.04 -MAINTAINER Tim Byrne +FROM ubuntu:24.10 # Shellcheck and esh versions -ARG SC_VER=0.9.0 +ARG SC_VER=0.10.0 ARG ESH_VER=0.3.2 # Install prerequisites and configure UTF-8 locale @@ -14,6 +13,7 @@ RUN \ expect \ git \ gnupg \ + j2cli \ locales \ lsb-release \ make \ @@ -39,10 +39,9 @@ RUN cd /opt \ && rm -f shellcheck-v$SC_VER.linux.x86_64.tar.xz \ && ln -s /opt/shellcheck-v$SC_VER/shellcheck /usr/local/bin -# Upgrade pip3 and install requirements +# Install requirements COPY test/requirements.txt /tmp/requirements.txt -RUN python3 -m pip install --break-system-packages --upgrade pip setuptools \ - && python3 -m pip install --break-system-packages --upgrade -r /tmp/requirements.txt \ +RUN python3 -m pip install --break-system-packages -r /tmp/requirements.txt \ && rm -f /tmp/requirements # Install esh diff --git a/test/conftest.py b/test/conftest.py index b18cae4..0699378 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -9,7 +9,6 @@ import pwd import shutil from subprocess import PIPE, Popen -import py import pytest @@ -26,37 +25,37 @@ def pytest_addoption(parser): @pytest.fixture(scope="session") def shellcheck_version(): """Version of shellcheck supported""" - return "0.9.0" + return "0.10.0" @pytest.fixture(scope="session") def pylint_version(): """Version of pylint supported""" - return "2.17.0" + return "3.3.1" @pytest.fixture(scope="session") def isort_version(): """Version of isort supported""" - return "5.12.0" + return "5.13.2" @pytest.fixture(scope="session") def flake8_version(): """Version of flake8 supported""" - return "6.0.0" + return "7.1.1" @pytest.fixture(scope="session") def black_version(): """Version of black supported""" - return "23.1.0" + return "24.10.0" @pytest.fixture(scope="session") def yamllint_version(): """Version of yamllint supported""" - return "1.30.0" + return "1.35.1" @pytest.fixture(scope="session") @@ -246,7 +245,7 @@ class Runner: if not expect: return cmdline = " ".join([f'"{w}"' for w in self.command]) - expect_script = f"set timeout 2\nspawn {cmdline}\n" + expect_script = f"set timeout 5\nspawn {cmdline}\n" for question, answer in expect: expect_script += "expect {\n" f'"{question}" {{send "{answer}\\r"}}\n' "timeout {close;exit 128}\n" "}\n" expect_script += "expect eof\n" "foreach {pid spawnid os_error_flag value} [wait] break\n" "exit $value" @@ -575,17 +574,21 @@ def ds1(ds1_work_copy, paths, ds1_dset): def gnupg(tmpdir_factory, runner): """Location of GNUPGHOME""" - def register_gpg_password(password): - """Publish a new GPG mock password""" - py.path.local("/tmp/mock-password").write(password) - home = tmpdir_factory.mktemp("gnupghome") home.chmod(0o700) conf = home.join("gpg.conf") conf.write("no-secmem-warning\n") conf.chmod(0o600) agentconf = home.join("gpg-agent.conf") - agentconf.write(f'pinentry-program {os.path.abspath("test/pinentry-mock")}\n' "max-cache-ttl 0\n") + agentconf.write( + f"""\ +pinentry-program {os.path.abspath("test/pinentry-mock")} +max-cache-ttl 0 +browser-socket none +extra-socket none +disable-scdaemon +""" + ) agentconf.chmod(0o600) data = collections.namedtuple("GNUPG", ["home", "pw"]) env = os.environ.copy() @@ -594,4 +597,12 @@ def gnupg(tmpdir_factory, runner): # this pre-populates std files in the GNUPGHOME runner(["gpg", "-k"], env=env) - return data(home, register_gpg_password) + def register_gpg_password(password): + """Publish a new GPG mock password and flush cached passwords""" + home.join("mock-password").write(password) + runner(["gpgconf", "--reload", "gpg-agent"], env=env) + + yield data(home, register_gpg_password) + + runner(["gpgconf", "--kill", "gpg-agent"], env=env) + runner(["gpgconf", "--remove-socketdir", "gpg-agent"], env=env) diff --git a/test/pinentry-mock b/test/pinentry-mock index 39da043..288616d 100755 --- a/test/pinentry-mock +++ b/test/pinentry-mock @@ -6,10 +6,9 @@ echo "OK Pleased to meet you" while read -r line; do if [[ $line =~ GETPIN ]]; then - password="$(cat /tmp/mock-password 2>/dev/null)" + password="$(cat "$GNUPGHOME/mock-password" 2>/dev/null)" if [ -n "$password" ]; then - echo -n "D " - echo "$password" + echo "D $password" echo "OK"; else echo "CANCEL"; diff --git a/test/requirements.txt b/test/requirements.txt index e71b349..1a4c3c1 100644 --- a/test/requirements.txt +++ b/test/requirements.txt @@ -1,8 +1,8 @@ -black==23.1.0 +black==24.10.0 envtpl -flake8==6.0.0 -isort==5.12.0 +flake8==7.1.1 +isort==5.13.2 j2cli -pylint==2.17.0 -pytest==7.2.2 -yamllint==1.30.0 +pylint==3.3.1 +pytest==8.3.3 +yamllint==1.35.1 diff --git a/test/test_alt.py b/test/test_alt.py index c429ad4..5d6706e 100644 --- a/test/test_alt.py +++ b/test/test_alt.py @@ -1,4 +1,5 @@ """Test alt""" + import os import string diff --git a/test/test_encryption.py b/test/test_encryption.py index 8c64222..23d8e37 100644 --- a/test/test_encryption.py +++ b/test/test_encryption.py @@ -2,7 +2,6 @@ import os import shlex -import time import pytest @@ -219,7 +218,6 @@ def test_symmetric_decrypt(runner, yadm_cmd, paths, decrypt_targets, gnupg, doli if bad_phrase: gnupg.pw("") - time.sleep(1) # allow gpg-agent cache to expire else: gnupg.pw(PASSPHRASE) diff --git a/test/test_help.py b/test/test_help.py index cbfabcc..4520329 100644 --- a/test/test_help.py +++ b/test/test_help.py @@ -1,4 +1,5 @@ """Test help""" + import pytest diff --git a/test/test_list.py b/test/test_list.py index afcea6f..e9d9e2c 100644 --- a/test/test_list.py +++ b/test/test_list.py @@ -20,7 +20,8 @@ def test_list(runner, yadm_cmd, paths, ds1, location): run_dir = paths.work elif location == "outside": run_dir = paths.work.join("..") - elif location == "subdir": + else: + assert location == "subdir" # first directory with tracked data run_dir = paths.work.join(ds1.tracked_dirs[0]) with run_dir.as_cwd(): diff --git a/test/test_unit_choose_template_cmd.py b/test/test_unit_choose_template_cmd.py index cf7600b..9948f80 100644 --- a/test/test_unit_choose_template_cmd.py +++ b/test/test_unit_choose_template_cmd.py @@ -1,4 +1,5 @@ """Unit tests: choose_template_cmd""" + import pytest @@ -19,7 +20,7 @@ def test_kind_default(runner, yadm, awk, label): script = f""" YADM_TEST=1 source {yadm} - function awk_available {{ { awk_avail}; }} + function awk_available {{ {awk_avail}; }} template="$(choose_template_cmd "{label}")" echo "TEMPLATE:$template" """ @@ -50,8 +51,8 @@ def test_kind_j2cli_envtpl(runner, yadm, envtpl, j2cli, label): script = f""" YADM_TEST=1 source {yadm} - function envtpl_available {{ { envtpl_avail}; }} - function j2cli_available {{ { j2cli_avail}; }} + function envtpl_available {{ {envtpl_avail}; }} + function j2cli_available {{ {j2cli_avail}; }} template="$(choose_template_cmd "{label}")" echo "TEMPLATE:$template" """ diff --git a/test/test_unit_copy_perms.py b/test/test_unit_copy_perms.py index c0ea04f..bde0d63 100644 --- a/test/test_unit_copy_perms.py +++ b/test/test_unit_copy_perms.py @@ -1,4 +1,5 @@ """Unit tests: copy_perms""" + import os import pytest diff --git a/test/test_unit_exclude_encrypted.py b/test/test_unit_exclude_encrypted.py index 8937a8b..99db336 100644 --- a/test/test_unit_exclude_encrypted.py +++ b/test/test_unit_exclude_encrypted.py @@ -1,4 +1,5 @@ """Unit tests: exclude_encrypted""" + import pytest diff --git a/test/test_unit_issue_legacy_path_warning.py b/test/test_unit_issue_legacy_path_warning.py index faae7fa..602a695 100644 --- a/test/test_unit_issue_legacy_path_warning.py +++ b/test/test_unit_issue_legacy_path_warning.py @@ -1,4 +1,5 @@ """Unit tests: issue_legacy_path_warning""" + import pytest diff --git a/test/test_unit_private_dirs.py b/test/test_unit_private_dirs.py index 58bd39c..6812ede 100644 --- a/test/test_unit_private_dirs.py +++ b/test/test_unit_private_dirs.py @@ -1,4 +1,5 @@ """Unit tests: private_dirs""" + import pytest diff --git a/test/test_unit_query_distro.py b/test/test_unit_query_distro.py index c32760b..18fc595 100644 --- a/test/test_unit_query_distro.py +++ b/test/test_unit_query_distro.py @@ -1,4 +1,5 @@ """Unit tests: query_distro""" + import pytest diff --git a/test/test_unit_query_distro_family.py b/test/test_unit_query_distro_family.py index 1935bf6..1dca5ee 100644 --- a/test/test_unit_query_distro_family.py +++ b/test/test_unit_query_distro_family.py @@ -1,4 +1,5 @@ """Unit tests: query_distro_family""" + import pytest diff --git a/test/test_unit_record_score.py b/test/test_unit_record_score.py index a82046c..3d67b0f 100644 --- a/test/test_unit_record_score.py +++ b/test/test_unit_record_score.py @@ -1,4 +1,5 @@ """Unit tests: record_score""" + import pytest INIT_VARS = """ diff --git a/test/test_unit_relative_path.py b/test/test_unit_relative_path.py index e0b32f5..cf440a7 100644 --- a/test/test_unit_relative_path.py +++ b/test/test_unit_relative_path.py @@ -1,4 +1,5 @@ """Unit tests: relative_path""" + import pytest diff --git a/test/test_unit_remove_stale_links.py b/test/test_unit_remove_stale_links.py index f389ed8..d92c96b 100644 --- a/test/test_unit_remove_stale_links.py +++ b/test/test_unit_remove_stale_links.py @@ -1,4 +1,5 @@ """Unit tests: remove_stale_links""" + import os import pytest diff --git a/test/test_unit_report_invalid_alts.py b/test/test_unit_report_invalid_alts.py index 996b1ef..3c7145f 100644 --- a/test/test_unit_report_invalid_alts.py +++ b/test/test_unit_report_invalid_alts.py @@ -1,4 +1,5 @@ """Unit tests: report_invalid_alts""" + import pytest diff --git a/test/test_unit_score_file.py b/test/test_unit_score_file.py index c84fb1e..0d3833e 100644 --- a/test/test_unit_score_file.py +++ b/test/test_unit_score_file.py @@ -1,4 +1,5 @@ """Unit tests: score_file""" + import pytest CONDITION = { diff --git a/test/test_unit_set_local_alt_values.py b/test/test_unit_set_local_alt_values.py index fa5749d..d27dedd 100644 --- a/test/test_unit_set_local_alt_values.py +++ b/test/test_unit_set_local_alt_values.py @@ -1,4 +1,5 @@ """Unit tests: set_local_alt_values""" + import pytest import utils diff --git a/test/test_unit_set_yadm_dir.py b/test/test_unit_set_yadm_dir.py index b56c98d..058f3f1 100644 --- a/test/test_unit_set_yadm_dir.py +++ b/test/test_unit_set_yadm_dir.py @@ -1,4 +1,5 @@ """Unit tests: set_yadm_dirs""" + import pytest diff --git a/test/test_unit_template_esh.py b/test/test_unit_template_esh.py index 2c91c20..8583b59 100644 --- a/test/test_unit_template_esh.py +++ b/test/test_unit_template_esh.py @@ -1,4 +1,5 @@ """Unit tests: template_esh""" + import os FILE_MODE = 0o754 diff --git a/test/test_unit_template_j2.py b/test/test_unit_template_j2.py index 750ee8c..3dbb8a7 100644 --- a/test/test_unit_template_j2.py +++ b/test/test_unit_template_j2.py @@ -1,4 +1,5 @@ """Unit tests: template_j2cli & template_envtpl""" + import os import pytest diff --git a/test/test_unit_upgrade.py b/test/test_unit_upgrade.py index cf4f6f4..5441e22 100644 --- a/test/test_unit_upgrade.py +++ b/test/test_unit_upgrade.py @@ -1,4 +1,5 @@ """Unit tests: upgrade""" + import pytest @@ -62,11 +63,10 @@ def test_upgrade(tmpdir, runner, yadm, condition): function git() {{ echo "$@" if [[ "$*" = *"submodule status" ]]; then - { 'echo " 1234567 mymodule (1.0)"' - if condition == 'submodules' else ':' } + {'echo " 1234567 mymodule (1.0)"' if condition == 'submodules' else ':'} fi if [[ "$*" = *ls-files* ]]; then - return { 1 if condition == 'untracked' else 0 } + return {1 if condition == 'untracked' else 0} fi return 0 }}