From 03bea763f15ea29c8591f01891888375346fd6df Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Sat, 29 Nov 2025 13:40:31 +0100 Subject: [PATCH] Ensure deterministic ordering of web health expectations and add unit tests This update sorts all expectation keys alphabetically to guarantee idempotent Ansible deployments and stable systemd unit generation. Added two unit tests to validate proper key ordering for canonical domains, aliases, redirects, and WWW mappings. Reference: https://chatgpt.com/share/692ae99b-dd88-800f-8fad-2ff62666e295 --- .../filter_plugins/web_health_expectations.py | 3 ++- .../test_web_health_expectations.py | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/roles/sys-ctl-hlth-webserver/filter_plugins/web_health_expectations.py b/roles/sys-ctl-hlth-webserver/filter_plugins/web_health_expectations.py index f217db55..cc7b488c 100644 --- a/roles/sys-ctl-hlth-webserver/filter_plugins/web_health_expectations.py +++ b/roles/sys-ctl-hlth-webserver/filter_plugins/web_health_expectations.py @@ -193,7 +193,8 @@ def web_health_expectations(applications, www_enabled: bool = False, group_names if d.startswith("www."): expectations[d] = [301] - return expectations + ordered = {k: expectations[k] for k in sorted(expectations.keys())} + return ordered class FilterModule(object): diff --git a/tests/unit/roles/sys-ctl-hlth-webserver/filter_plugins/test_web_health_expectations.py b/tests/unit/roles/sys-ctl-hlth-webserver/filter_plugins/test_web_health_expectations.py index 8c2b22e3..67eca895 100644 --- a/tests/unit/roles/sys-ctl-hlth-webserver/filter_plugins/test_web_health_expectations.py +++ b/tests/unit/roles/sys-ctl-hlth-webserver/filter_plugins/test_web_health_expectations.py @@ -397,5 +397,30 @@ class TestWebHealthExpectationsFilter(unittest.TestCase): self.assertEqual(out["v1.l11.example.org"], [301, 307]) # per-key list self.assertEqual(out["v2.l11.example.org"], [301, 307]) + def test_expectations_keys_are_sorted_alphabetically (self ): + apps ={"app-sort":{}} + self ._configure_returns ({ + ("app-sort","server.domains.canonical"):["b.example.org","a.example.org","c.example.org"], + ("app-sort","server.domains.aliases"):["alias.example.org"], + ("app-sort","server.status_codes"):{"default":200 }, + }) + out =self .mod .web_health_expectations (apps ,group_names =["app-sort"]) + + keys =list (out .keys ()) + self .assertEqual (keys ,sorted (keys )) + + + def test_expectations_keys_sorted_with_redirects_and_www (self ): + apps ={} + out =self .mod .web_health_expectations ( + apps , + group_names =["dummy-app"], + www_enabled =True , + redirect_maps =[{"source":"redir-b.example.org"},{"source":"redir-a.example.org"}], + ) + + keys =list (out .keys ()) + self .assertEqual (keys ,sorted (keys )) + if __name__ == "__main__": unittest.main()