From 56f6a2dc3bd82535c2d06332c49e84491582243c Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Mon, 14 Jul 2025 00:04:13 +0200 Subject: [PATCH] Solved default variable bug --- filter_plugins/get_app_conf.py | 12 +++--- roles/cmp-rdbms/vars/database.yml | 4 +- .../unit/filter_plugins/test_get_app_conf.py | 42 +++++++++++++++++++ 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/filter_plugins/get_app_conf.py b/filter_plugins/get_app_conf.py index 1cbe3a88..140acde6 100644 --- a/filter_plugins/get_app_conf.py +++ b/filter_plugins/get_app_conf.py @@ -10,7 +10,7 @@ class AppConfigKeyError(AnsibleFilterError, ValueError): """ pass -def get_app_conf(applications, application_id, config_path, strict=True): +def get_app_conf(applications, application_id, config_path, strict=True, default=None): def access(obj, key, path_trace): m = re.match(r"^([a-zA-Z0-9_-]+)(?:\[(\d+)\])?$", key) if not m: @@ -31,7 +31,7 @@ def get_app_conf(applications, application_id, config_path, strict=True): f"application_id: {application_id}\n" f"config_path: {config_path}" ) - return False + return default if default is not None else False obj = obj[k] else: if strict: @@ -42,7 +42,7 @@ def get_app_conf(applications, application_id, config_path, strict=True): f"application_id: {application_id}\n" f"config_path: {config_path}" ) - return False + return default if default is not None else False if idx is not None: if not isinstance(obj, list): if strict: @@ -53,7 +53,7 @@ def get_app_conf(applications, application_id, config_path, strict=True): f"application_id: {application_id}\n" f"config_path: {config_path}" ) - return False + return default if default is not None else False i = int(idx) if i >= len(obj): if strict: @@ -64,7 +64,7 @@ def get_app_conf(applications, application_id, config_path, strict=True): f"application_id: {application_id}\n" f"config_path: {config_path}" ) - return False + return default if default is not None else False obj = obj[i] return obj @@ -83,7 +83,7 @@ def get_app_conf(applications, application_id, config_path, strict=True): path_trace.append(part) obj = access(obj, part, path_trace) if obj is False and not strict: - return False + return default if default is not None else False return obj class FilterModule(object): diff --git a/roles/cmp-rdbms/vars/database.yml b/roles/cmp-rdbms/vars/database.yml index 8d969b5a..ea68ca28 100644 --- a/roles/cmp-rdbms/vars/database.yml +++ b/roles/cmp-rdbms/vars/database.yml @@ -1,8 +1,8 @@ database_id: "svc-db-{{ database_type }}" database_instance: "{{ applications[ database_id ].hostname if applications | get_app_conf(database_application_id, 'features.central_database', False) else database_application_id }}" database_host: "{{ applications[ database_id ].hostname if applications | get_app_conf(database_application_id, 'features.central_database', False) else 'database' }}" -database_name: "{{ applications | get_app_conf(database_application_id, 'database.name', False) | default( database_application_id ) }}" # The overwritte configuration is needed by bigbluebutton -database_username: "{{ applications | get_app_conf(database_application_id, 'database.username', False) | default( database_application_id )}}" # The overwritte configuration is needed by bigbluebutton +database_name: "{{ applications | get_app_conf(database_application_id, 'database.name', false, database_application_id ) }}" # The overwritte configuration is needed by bigbluebutton +database_username: "{{ applications | get_app_conf(database_application_id, 'database.username', false, database_application_id )}}" # The overwritte configuration is needed by bigbluebutton database_password: "{{ applications | get_app_conf(database_application_id, 'credentials.database_password', true) }}" database_port: "{{ ports.localhost.database[ database_id ] }}" database_env: "{{docker_compose.directories.env}}{{database_type}}.env" diff --git a/tests/unit/filter_plugins/test_get_app_conf.py b/tests/unit/filter_plugins/test_get_app_conf.py index 0bf98487..77c0c00f 100644 --- a/tests/unit/filter_plugins/test_get_app_conf.py +++ b/tests/unit/filter_plugins/test_get_app_conf.py @@ -112,6 +112,48 @@ class TestGetAppConf(unittest.TestCase): "myapp": "repo/myapp" } self.assertEqual(result, expected) + + def test_default_used_non_strict(self): + """non-strict + default: bei fehlendem Key liefert default.""" + result = get_app_conf(self.applications, "myapp", "features.baz", strict=False, default="mydefault") + self.assertEqual(result, "mydefault") + + def test_default_none_non_strict(self): + """non-strict + default=None: bei fehlendem Key liefert False.""" + result = get_app_conf(self.applications, "myapp", "features.baz", strict=False, default=None) + self.assertFalse(result) + + def test_default_ignored_when_present(self): + """default wird ignoriert, wenn der Pfad existiert.""" + result = get_app_conf(self.applications, "myapp", "features.foo", strict=False, default="should_not_be_used") + self.assertTrue(result) + + def test_access_primitive_strict_false(self): + """non-strict: Zugriff auf tieferes Feld in primitive → default.""" + # features.foo ist bool, .bar existiert nicht → default + result = get_app_conf(self.applications, "myapp", "features.foo.bar", strict=False, default="defval") + self.assertEqual(result, "defval") + + def test_access_primitive_strict_true(self): + """strict: Zugriff auf tieferes Feld in primitive → Exception.""" + with self.assertRaises(AnsibleFilterError): + get_app_conf(self.applications, "myapp", "features.foo.bar", strict=True) + + def test_invalid_key_format_strict(self): + """strict: ungültiges Key-Format (z.B. index nicht numerisch) → Error.""" + with self.assertRaises(AppConfigKeyError): + get_app_conf(self.applications, "myapp", "features.foo[abc]", strict=True) + + def test_invalid_key_format_non_strict(self): + """non-strict: ungültiges Key-Format → immer noch Error (Format-Check ist immer strict).""" + with self.assertRaises(AppConfigKeyError): + get_app_conf(self.applications, "myapp", "features.foo[abc]", strict=False) + + def test_list_indexing_negative_with_default(self): + """non-strict + default bei Listen-Index-Out-Of-Range.""" + apps = {"app": {"foo": [{"bar": "x"}]}} + result = get_app_conf(apps, "app", "foo[1].bar", strict=False, default="fallback") + self.assertEqual(result, "fallback") if __name__ == '__main__': unittest.main()