From a49a955bac1d696f0b72cc1bf61bf2f2ba275b9a Mon Sep 17 00:00:00 2001 From: minulo Date: Tue, 13 Oct 2026 02:43:42 -0400 Subject: [PATCH 1/3] test: adopt -Werror in unit tests Run the unit suites of the four charms with filterwarnings = ["error"] so a deprecation, a leaked file handle or a misused library fails the test instead of scrolling past in the log. Charm Tech is making this the Charmcraft default and asked existing charms to opt in. Each integration env opts out with --override-ini=filterwarnings=. Turning it on surfaced warnings that are fixed here: - haproxy-operator's TLS test fixtures called the deprecated generate_private_key(), generate_csr(), generate_ca() and generate_certificate() helpers; they now use the replacements the warnings name. The CA is now signed with the key the fixture returns. - The legacy mock_requirer_charm fixture never cleaned up its Harness, so its temporary directory was reclaimed by the garbage collector with a ResourceWarning that failed whichever test was running. - haproxy-route-policy's WhiteNoise middleware warned about the missing static directory in tests; the test settings now enable autorefresh. Left as narrow ignores: ops' Harness deprecation, scoped to the three legacy Harness test modules, and JujuVersion.from_environ() from the vendored data_platform_libs lib in haproxy-route-policy-operator. haproxy-route-policy runs Django's test runner rather than pytest, so its unit envs use python -W error instead. --- .../pyproject.toml | 8 +++++++ haproxy-ddos-protection-configurator/tox.toml | 4 ++++ haproxy-operator/pyproject.toml | 9 ++++++++ haproxy-operator/tests/unit/conftest.py | 21 +++++++++++-------- haproxy-operator/tests/unit/legacy/test_ha.py | 6 ++++++ .../unit/legacy/test_haproxy_route_lib.py | 12 +++++++++-- .../tests/unit/legacy/test_tls_relation.py | 6 ++++++ haproxy-operator/tox.toml | 4 ++++ haproxy-route-policy-operator/pyproject.toml | 12 +++++++++++ haproxy-route-policy-operator/tox.toml | 4 ++++ .../haproxy_route_policy/test_settings.py | 6 ++++++ .../test_settings_authenticated.py | 6 ++++++ haproxy-route-policy/tox.toml | 11 ++++++++++ haproxy-spoe-auth-operator/pyproject.toml | 8 +++++++ haproxy-spoe-auth-operator/tox.toml | 4 ++++ 15 files changed, 110 insertions(+), 11 deletions(-) diff --git a/haproxy-ddos-protection-configurator/pyproject.toml b/haproxy-ddos-protection-configurator/pyproject.toml index e0b32b414..110b9ea99 100644 --- a/haproxy-ddos-protection-configurator/pyproject.toml +++ b/haproxy-ddos-protection-configurator/pyproject.toml @@ -102,6 +102,14 @@ skip = "build,lib,venv,icon.svg,.tox,.git,.mypy_cache,.ruff_cache,.coverage,html [tool.pytest.ini_options] minversion = "6.0" log_cli_level = "INFO" +# Turn warnings into errors so deprecations and resource leaks fail the unit +# suite rather than accumulating unnoticed. The charm's own code and +# tests raise none. The integration env opts +# out (see tox.toml) because any warnings there come from the deployment +# tooling and are not this charm's to fix. +filterwarnings = [ + "error", +] [tool.coverage.run] branch = true diff --git a/haproxy-ddos-protection-configurator/tox.toml b/haproxy-ddos-protection-configurator/tox.toml index ff5ea7786..c9f0c7094 100644 --- a/haproxy-ddos-protection-configurator/tox.toml +++ b/haproxy-ddos-protection-configurator/tox.toml @@ -129,6 +129,10 @@ commands = [ "--ignore={toxinidir}/haproxy-operator", "--log-cli-level=INFO", "-s", + # pyproject.toml promotes warnings to errors for the unit tests; the + # integration suite runs against real deployment tooling whose warnings + # are not this charm's to fix, so it keeps pytest's default handling. + "--override-ini=filterwarnings=", { replace = "posargs", extend = "true" }, ], ] diff --git a/haproxy-operator/pyproject.toml b/haproxy-operator/pyproject.toml index 099ccc9f5..77567f7b2 100644 --- a/haproxy-operator/pyproject.toml +++ b/haproxy-operator/pyproject.toml @@ -117,6 +117,15 @@ ignore-words-list = "iif" [tool.pytest.ini_options] minversion = "6.0" log_cli_level = "INFO" +# Turn warnings into errors so deprecations and resource leaks fail the unit +# suite rather than accumulating unnoticed. The charm's own code and the +# Scenario tests raise none; the legacy Harness tests under tests/unit/legacy +# carry a module-scoped ignore for ops' Harness deprecation. The integration env opts +# out (see tox.toml) because any warnings there come from the deployment +# tooling and are not this charm's to fix. +filterwarnings = [ + "error", +] [tool.coverage.run] branch = true diff --git a/haproxy-operator/tests/unit/conftest.py b/haproxy-operator/tests/unit/conftest.py index c6a4f7811..edd44036c 100644 --- a/haproxy-operator/tests/unit/conftest.py +++ b/haproxy-operator/tests/unit/conftest.py @@ -16,10 +16,6 @@ CertificateRequestAttributes, CertificateSigningRequest, PrivateKey, - generate_ca, - generate_certificate, - generate_csr, - generate_private_key, ) from charms.haproxy.v0.spoe_auth import SpoeAuthProviderAppData, SpoeAuthProviderUnitData from charms.haproxy.v1.haproxy_route_tcp import ( @@ -80,8 +76,12 @@ def mocks_tls_ca_write_fixture(monkeypatch: pytest.MonkeyPatch): @pytest.fixture(scope="function", name="ca_certificate_and_key") def ca_certificate_and_key_fixture() -> typing.Tuple[Certificate, PrivateKey]: """Ca Certificate and private key.""" - private_key_ca = generate_private_key() - ca = generate_ca(generate_private_key(), timedelta(days=10), "caname") + private_key_ca = PrivateKey.generate() + ca = Certificate.generate_self_signed_ca( + CertificateRequestAttributes(common_name="caname", is_ca=True), + private_key_ca, + timedelta(days=10), + ) return ca, private_key_ca @@ -91,9 +91,12 @@ def csr_certificate_and_key_fixture( ) -> typing.Tuple[CertificateSigningRequest, Certificate, PrivateKey]: """Ca Certificate and private key.""" ca, private_key_ca = ca_certificate_and_key - private_key = generate_private_key() - csr = generate_csr(private_key, TEST_EXTERNAL_HOSTNAME_CONFIG) - certificate = generate_certificate(csr, ca, private_key_ca, timedelta(days=5)) + private_key = PrivateKey.generate() + csr_attributes = CertificateRequestAttributes(common_name=TEST_EXTERNAL_HOSTNAME_CONFIG) + csr = csr_attributes.generate_csr(private_key) + certificate = Certificate.generate( + csr=csr, ca=ca, ca_private_key=private_key_ca, validity=timedelta(days=5) + ) return csr, certificate, private_key diff --git a/haproxy-operator/tests/unit/legacy/test_ha.py b/haproxy-operator/tests/unit/legacy/test_ha.py index 27489c80f..825627b19 100644 --- a/haproxy-operator/tests/unit/legacy/test_ha.py +++ b/haproxy-operator/tests/unit/legacy/test_ha.py @@ -8,6 +8,12 @@ from state.ha import HACLUSTER_INTEGRATION, HAInformation, HAInformationValidationError +# These legacy tests still use Harness, which ops marks as deprecated with a +# PendingDeprecationWarning. The unit suite runs with warnings promoted to +# errors (see pyproject.toml), so ignore that one warning here until the tests +# are ported to ops.testing.Context like the rest of tests/unit. +pytestmark = pytest.mark.filterwarnings("ignore:Harness is deprecated:PendingDeprecationWarning") + def test_ha_information(harness: Harness): """ diff --git a/haproxy-operator/tests/unit/legacy/test_haproxy_route_lib.py b/haproxy-operator/tests/unit/legacy/test_haproxy_route_lib.py index 92a6df713..f0b83feec 100644 --- a/haproxy-operator/tests/unit/legacy/test_haproxy_route_lib.py +++ b/haproxy-operator/tests/unit/legacy/test_haproxy_route_lib.py @@ -26,6 +26,12 @@ from ops.testing import Harness from pydantic import ValidationError +# These legacy tests still use Harness, which ops marks as deprecated with a +# PendingDeprecationWarning. The unit suite runs with warnings promoted to +# errors (see pyproject.toml), so ignore that one warning here until the tests +# are ported to ops.testing.Context like the rest of tests/unit. +pytestmark = pytest.mark.filterwarnings("ignore:Harness is deprecated:PendingDeprecationWarning") + logger = logging.getLogger() MOCK_RELATION_NAME = "haproxy-route" MOCK_ADDRESS = "10.0.0.1" @@ -67,8 +73,10 @@ def mock_provider_app_data_fixture(): @pytest.fixture(name="mock_requirer_charm") def mock_requirer_charm_fixture(): - """Create mock unit data.""" - return Harness(ops.CharmBase, meta=MOCK_REQUIRER_CHARM_META) + """Create a harness for a mock requirer charm and clean up its files afterwards.""" + harness = Harness(ops.CharmBase, meta=MOCK_REQUIRER_CHARM_META) + yield harness + harness.cleanup() def test_requirer_application_data_validation(): diff --git a/haproxy-operator/tests/unit/legacy/test_tls_relation.py b/haproxy-operator/tests/unit/legacy/test_tls_relation.py index d71358f15..9fbeb6f54 100644 --- a/haproxy-operator/tests/unit/legacy/test_tls_relation.py +++ b/haproxy-operator/tests/unit/legacy/test_tls_relation.py @@ -17,6 +17,12 @@ from state.tls import HaproxyPeerRelationAppData, TLSInformation, TLSNotReadyError from tls_relation import TLSRelationService +# These legacy tests still use Harness, which ops marks as deprecated with a +# PendingDeprecationWarning. The unit suite runs with warnings promoted to +# errors (see pyproject.toml), so ignore that one warning here until the tests +# are ported to ops.testing.Context like the rest of tests/unit. +pytestmark = pytest.mark.filterwarnings("ignore:Harness is deprecated:PendingDeprecationWarning") + TEST_EXTERNAL_HOSTNAME_CONFIG = "haproxy.internal" diff --git a/haproxy-operator/tox.toml b/haproxy-operator/tox.toml index d58ca0a89..e54ca7541 100644 --- a/haproxy-operator/tox.toml +++ b/haproxy-operator/tox.toml @@ -125,6 +125,10 @@ commands = [ "--ignore={toxinidir}/haproxy_spoe_auth_operator", "--log-cli-level=INFO", "-s", + # pyproject.toml promotes warnings to errors for the unit tests; the + # integration suite runs against real deployment tooling whose warnings + # are not this charm's to fix, so it keeps pytest's default handling. + "--override-ini=filterwarnings=", { replace = "posargs", extend = "true" }, ], ] diff --git a/haproxy-route-policy-operator/pyproject.toml b/haproxy-route-policy-operator/pyproject.toml index 39f9f0a0c..0eb34b0c7 100644 --- a/haproxy-route-policy-operator/pyproject.toml +++ b/haproxy-route-policy-operator/pyproject.toml @@ -85,6 +85,18 @@ skip = "build,lib,venv,icon.svg,.tox,.git,.mypy_cache,.ruff_cache,.coverage,html [tool.pytest.ini_options] minversion = "6.0" log_cli_level = "INFO" +# Turn warnings into errors so deprecations and resource leaks fail the unit +# suite rather than accumulating unnoticed. The ignore below is anchored to +# a specific message and is for third-party code; the charm's own code raises +# none. The integration env opts +# out (see tox.toml) because any warnings there come from the deployment +# tooling and are not this charm's to fix. +filterwarnings = [ + "error", + # Raised by the vendored data_platform_libs charm lib; the fix belongs + # upstream in canonical/data-platform-libs. + "ignore:JujuVersion.from_environ\\(\\) is deprecated:DeprecationWarning", +] [tool.coverage.run] branch = true diff --git a/haproxy-route-policy-operator/tox.toml b/haproxy-route-policy-operator/tox.toml index d23cbc68a..236a43e28 100644 --- a/haproxy-route-policy-operator/tox.toml +++ b/haproxy-route-policy-operator/tox.toml @@ -129,6 +129,10 @@ commands = [ "--ignore={[vars]tst_path}unit", "--log-cli-level=INFO", "-s", + # pyproject.toml promotes warnings to errors for the unit tests; the + # integration suite runs against real deployment tooling whose warnings + # are not this charm's to fix, so it keeps pytest's default handling. + "--override-ini=filterwarnings=", { replace = "posargs", extend = "true" }, ], ] diff --git a/haproxy-route-policy/haproxy_route_policy/test_settings.py b/haproxy-route-policy/haproxy_route_policy/test_settings.py index 91c46a6cc..51aa80bd5 100644 --- a/haproxy-route-policy/haproxy_route_policy/test_settings.py +++ b/haproxy-route-policy/haproxy_route_policy/test_settings.py @@ -21,3 +21,9 @@ "rest_framework.permissions.AllowAny", ], } + +# The tests run without `collectstatic`, so STATIC_ROOT does not exist and +# WhiteNoise would warn "No directory at ..." when its middleware starts. The +# unit tox envs promote warnings to errors, so serve static files on demand +# instead of from a pre-collected directory. +WHITENOISE_AUTOREFRESH = True diff --git a/haproxy-route-policy/haproxy_route_policy/test_settings_authenticated.py b/haproxy-route-policy/haproxy_route_policy/test_settings_authenticated.py index c3090bfc0..caad4415b 100644 --- a/haproxy-route-policy/haproxy_route_policy/test_settings_authenticated.py +++ b/haproxy-route-policy/haproxy_route_policy/test_settings_authenticated.py @@ -14,3 +14,9 @@ "NAME": ":memory:", } } + +# The tests run without `collectstatic`, so STATIC_ROOT does not exist and +# WhiteNoise would warn "No directory at ..." when its middleware starts. The +# unit tox envs promote warnings to errors, so serve static files on demand +# instead of from a pre-collected directory. +WHITENOISE_AUTOREFRESH = True diff --git a/haproxy-route-policy/tox.toml b/haproxy-route-policy/tox.toml index 3923feee0..cb3ca75a3 100644 --- a/haproxy-route-policy/tox.toml +++ b/haproxy-route-policy/tox.toml @@ -18,8 +18,15 @@ PY_COLORS = "1" [env.unit] description = "Run unit tests" +# -W error promotes every Python warning to a test failure, mirroring the +# filterwarnings = ["error"] setting the charms in this repository use with +# pytest; Django's test runner has no equivalent setting of its own. commands = [ [ + "python", + "-W", + "error", + "-m", "coverage", "run", "manage.py", @@ -37,6 +44,10 @@ dependency_groups = ["unit"] description = "Run auth unit tests" commands = [ [ + "python", + "-W", + "error", + "-m", "coverage", "run", "manage.py", diff --git a/haproxy-spoe-auth-operator/pyproject.toml b/haproxy-spoe-auth-operator/pyproject.toml index 02bb3b268..ecc3263f9 100644 --- a/haproxy-spoe-auth-operator/pyproject.toml +++ b/haproxy-spoe-auth-operator/pyproject.toml @@ -114,6 +114,14 @@ skip = "build,lib,venv,icon.svg,.tox,.git,.mypy_cache,.ruff_cache,.coverage,html [tool.pytest.ini_options] minversion = "6.0" log_cli_level = "INFO" +# Turn warnings into errors so deprecations and resource leaks fail the unit +# suite rather than accumulating unnoticed. The charm's own code and +# tests raise none. The integration env opts +# out (see tox.toml) because any warnings there come from the deployment +# tooling and are not this charm's to fix. +filterwarnings = [ + "error", +] [tool.coverage.run] branch = true diff --git a/haproxy-spoe-auth-operator/tox.toml b/haproxy-spoe-auth-operator/tox.toml index 7529f9110..51a6bd929 100644 --- a/haproxy-spoe-auth-operator/tox.toml +++ b/haproxy-spoe-auth-operator/tox.toml @@ -120,6 +120,10 @@ commands = [ "--ignore={[vars]tst_path}unit", "--log-cli-level=INFO", "-s", + # pyproject.toml promotes warnings to errors for the unit tests; the + # integration suite runs against real deployment tooling whose warnings + # are not this charm's to fix, so it keeps pytest's default handling. + "--override-ini=filterwarnings=", { replace = "posargs", extend = "true" }, ], ] From d07fabd888ded5461061ab0507a3ced1fe0c5287 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Oct 2026 10:00:15 +0000 Subject: [PATCH 2/3] Shorten warnings configuration comments Co-authored-by: Thanhphan1147 <42444001+Thanhphan1147@users.noreply.github.com> --- haproxy-ddos-protection-configurator/pyproject.toml | 6 +----- haproxy-operator/pyproject.toml | 7 +------ haproxy-route-policy-operator/pyproject.toml | 7 +------ haproxy-spoe-auth-operator/pyproject.toml | 6 +----- 4 files changed, 4 insertions(+), 22 deletions(-) diff --git a/haproxy-ddos-protection-configurator/pyproject.toml b/haproxy-ddos-protection-configurator/pyproject.toml index 52d7659aa..5c1f513da 100644 --- a/haproxy-ddos-protection-configurator/pyproject.toml +++ b/haproxy-ddos-protection-configurator/pyproject.toml @@ -102,11 +102,7 @@ skip = "build,lib,venv,icon.svg,.tox,.git,.mypy_cache,.ruff_cache,.coverage,html [tool.pytest.ini_options] minversion = "6.0" log_cli_level = "INFO" -# Turn warnings into errors so deprecations and resource leaks fail the unit -# suite rather than accumulating unnoticed. The charm's own code and -# tests raise none. The integration env opts -# out (see tox.toml) because any warnings there come from the deployment -# tooling and are not this charm's to fix. +# promote warnings to test failures filterwarnings = [ "error", ] diff --git a/haproxy-operator/pyproject.toml b/haproxy-operator/pyproject.toml index 4562113a4..113d893d3 100644 --- a/haproxy-operator/pyproject.toml +++ b/haproxy-operator/pyproject.toml @@ -117,12 +117,7 @@ ignore-words-list = "iif" [tool.pytest.ini_options] minversion = "6.0" log_cli_level = "INFO" -# Turn warnings into errors so deprecations and resource leaks fail the unit -# suite rather than accumulating unnoticed. The charm's own code and the -# Scenario tests raise none; the legacy Harness tests under tests/unit/legacy -# carry a module-scoped ignore for ops' Harness deprecation. The integration env opts -# out (see tox.toml) because any warnings there come from the deployment -# tooling and are not this charm's to fix. +# promote warnings to test failures filterwarnings = [ "error", ] diff --git a/haproxy-route-policy-operator/pyproject.toml b/haproxy-route-policy-operator/pyproject.toml index 0eb34b0c7..e217e8231 100644 --- a/haproxy-route-policy-operator/pyproject.toml +++ b/haproxy-route-policy-operator/pyproject.toml @@ -85,12 +85,7 @@ skip = "build,lib,venv,icon.svg,.tox,.git,.mypy_cache,.ruff_cache,.coverage,html [tool.pytest.ini_options] minversion = "6.0" log_cli_level = "INFO" -# Turn warnings into errors so deprecations and resource leaks fail the unit -# suite rather than accumulating unnoticed. The ignore below is anchored to -# a specific message and is for third-party code; the charm's own code raises -# none. The integration env opts -# out (see tox.toml) because any warnings there come from the deployment -# tooling and are not this charm's to fix. +# promote warnings to test failures filterwarnings = [ "error", # Raised by the vendored data_platform_libs charm lib; the fix belongs diff --git a/haproxy-spoe-auth-operator/pyproject.toml b/haproxy-spoe-auth-operator/pyproject.toml index 4621bb73b..5620cde5b 100644 --- a/haproxy-spoe-auth-operator/pyproject.toml +++ b/haproxy-spoe-auth-operator/pyproject.toml @@ -114,11 +114,7 @@ skip = "build,lib,venv,icon.svg,.tox,.git,.mypy_cache,.ruff_cache,.coverage,html [tool.pytest.ini_options] minversion = "6.0" log_cli_level = "INFO" -# Turn warnings into errors so deprecations and resource leaks fail the unit -# suite rather than accumulating unnoticed. The charm's own code and -# tests raise none. The integration env opts -# out (see tox.toml) because any warnings there come from the deployment -# tooling and are not this charm's to fix. +# promote warnings to test failures filterwarnings = [ "error", ] From 2a6d06c7fcdd2bf82952b9acbb38223a9fc5f57e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Oct 2026 10:03:42 +0000 Subject: [PATCH 3/3] Shorten integration warning comments Co-authored-by: Thanhphan1147 <42444001+Thanhphan1147@users.noreply.github.com> --- haproxy-ddos-protection-configurator/tox.toml | 4 +--- haproxy-operator/tox.toml | 4 +--- haproxy-route-policy-operator/tox.toml | 4 +--- haproxy-spoe-auth-operator/tox.toml | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/haproxy-ddos-protection-configurator/tox.toml b/haproxy-ddos-protection-configurator/tox.toml index c9f0c7094..c81661d9a 100644 --- a/haproxy-ddos-protection-configurator/tox.toml +++ b/haproxy-ddos-protection-configurator/tox.toml @@ -129,9 +129,7 @@ commands = [ "--ignore={toxinidir}/haproxy-operator", "--log-cli-level=INFO", "-s", - # pyproject.toml promotes warnings to errors for the unit tests; the - # integration suite runs against real deployment tooling whose warnings - # are not this charm's to fix, so it keeps pytest's default handling. + # Don't promote warnings for integration tests "--override-ini=filterwarnings=", { replace = "posargs", extend = "true" }, ], diff --git a/haproxy-operator/tox.toml b/haproxy-operator/tox.toml index e54ca7541..8b125fc4e 100644 --- a/haproxy-operator/tox.toml +++ b/haproxy-operator/tox.toml @@ -125,9 +125,7 @@ commands = [ "--ignore={toxinidir}/haproxy_spoe_auth_operator", "--log-cli-level=INFO", "-s", - # pyproject.toml promotes warnings to errors for the unit tests; the - # integration suite runs against real deployment tooling whose warnings - # are not this charm's to fix, so it keeps pytest's default handling. + # Don't promote warnings for integration tests "--override-ini=filterwarnings=", { replace = "posargs", extend = "true" }, ], diff --git a/haproxy-route-policy-operator/tox.toml b/haproxy-route-policy-operator/tox.toml index 236a43e28..14dc4b2d4 100644 --- a/haproxy-route-policy-operator/tox.toml +++ b/haproxy-route-policy-operator/tox.toml @@ -129,9 +129,7 @@ commands = [ "--ignore={[vars]tst_path}unit", "--log-cli-level=INFO", "-s", - # pyproject.toml promotes warnings to errors for the unit tests; the - # integration suite runs against real deployment tooling whose warnings - # are not this charm's to fix, so it keeps pytest's default handling. + # Don't promote warnings for integration tests "--override-ini=filterwarnings=", { replace = "posargs", extend = "true" }, ], diff --git a/haproxy-spoe-auth-operator/tox.toml b/haproxy-spoe-auth-operator/tox.toml index 51a6bd929..e82ed1672 100644 --- a/haproxy-spoe-auth-operator/tox.toml +++ b/haproxy-spoe-auth-operator/tox.toml @@ -120,9 +120,7 @@ commands = [ "--ignore={[vars]tst_path}unit", "--log-cli-level=INFO", "-s", - # pyproject.toml promotes warnings to errors for the unit tests; the - # integration suite runs against real deployment tooling whose warnings - # are not this charm's to fix, so it keeps pytest's default handling. + # Don't promote warnings for integration tests "--override-ini=filterwarnings=", { replace = "posargs", extend = "true" }, ],