#!/usr/bin/env python3 """ Test that Ansible variables produce proper boolean types, not strings. This prevents issues with Ansible 12.0.0's strict type checking. """ import jinja2 def render_template(template_str, variables=None): """Render a Jinja2 template with given variables.""" env = jinja2.Environment() template = env.from_string(template_str) return template.render(variables or {}) class TestBooleanVariables: """Test that critical variables produce actual booleans.""" def test_ipv6_support_produces_boolean(self): """Ensure ipv6_support produces boolean, not string 'true'/'false'.""" # Test with gateway defined (should be boolean True) template = "{{ ansible_default_ipv6['gateway'] is defined }}" vars_with_gateway = {"ansible_default_ipv6": {"gateway": "fe80::1"}} result = render_template(template, vars_with_gateway) assert result == "True" # Jinja2 renders boolean True as string "True" # Test without gateway (should be boolean False) vars_no_gateway = {"ansible_default_ipv6": {}} result = render_template(template, vars_no_gateway) assert result == "False" # Jinja2 renders boolean False as string "False" # The key is that we're NOT producing string literals "true" or "false" bad_template = "{% if ansible_default_ipv6['gateway'] is defined %}true{% else %}false{% endif %}" result_bad = render_template(bad_template, vars_no_gateway) assert result_bad == "false" # This is a string literal, not a boolean # Verify our fix doesn't produce string literals assert result != "false" # Our fix produces "False" (from boolean), not "false" (string literal) def test_algo_variables_boolean_fallbacks(self): """Ensure algo_* variables produce booleans in their fallback cases.""" # Test the fixed template (produces boolean) good_template = "{% if var is defined %}{{ var | bool }}{%- else %}{{ false }}{% endif %}" result_good = render_template(good_template, {}) assert result_good == "False" # Boolean False renders as "False" # Test the old broken template (produces string) bad_template = "{% if var is defined %}{{ var | bool }}{%- else %}false{% endif %}" result_bad = render_template(bad_template, {}) assert result_bad == "false" # String literal "false" # Verify they're different assert result_good != result_bad assert result_good == "False" and result_bad == "false" def test_boolean_filter_on_strings(self): """Test that the bool filter correctly converts string values.""" # Since we can't test Ansible's bool filter directly in Jinja2, # we test the pattern we're using in our templates # Test that our templates don't use raw string "true"/"false" # which would fail in Ansible 12 bad_pattern = "{%- else %}false{% endif %}" good_pattern = "{%- else %}{{ false }}{% endif %}" # The bad pattern produces a string literal result_bad = render_template("{% if var is defined %}something" + bad_pattern, {}) assert "false" in result_bad # String literal # The good pattern produces a boolean value result_good = render_template("{% if var is defined %}something" + good_pattern, {}) assert "False" in result_good # Boolean False rendered as "False" def test_ansible_12_conditional_compatibility(self): """ Test that our fixes work with Ansible 12's strict type checking. This simulates what Ansible 12 will do with our variables. """ # Our fixed template - produces actual boolean fixed_ipv6 = "{{ ansible_default_ipv6['gateway'] is defined }}" fixed_algo = "{% if var is defined %}{{ var | bool }}{%- else %}{{ false }}{% endif %}" # Simulate the boolean value in a conditional context # In Ansible 12, this would fail if it's a string "true"/"false" vars_with_gateway = {"ansible_default_ipv6": {"gateway": "fe80::1"}} ipv6_result = render_template(fixed_ipv6, vars_with_gateway) # The result should be "True" (boolean rendered), not "true" (string literal) assert ipv6_result == "True" assert ipv6_result != "true" # Test algo variable fallback algo_result = render_template(fixed_algo, {}) assert algo_result == "False" assert algo_result != "false" def test_regression_no_string_booleans(self): """ Regression test: ensure we never produce string literals 'true' or 'false'. This is what breaks Ansible 12.0.0. """ # These patterns should NOT appear in our fixed code bad_patterns = [ "{}true{}", "{}false{}", "{%- else %}true{% endif %}", "{%- else %}false{% endif %}", ] # Test that our fixed templates don't produce string boolean literals fixed_template = "{{ ansible_default_ipv6['gateway'] is defined }}" for _pattern in bad_patterns: assert "true" not in fixed_template.replace(" ", "") assert "false" not in fixed_template.replace(" ", "") # Test algo variable fix fixed_algo = "{% if var is defined %}{{ var | bool }}{%- else %}{{ false }}{% endif %}" assert "{}false{}" not in fixed_algo.replace(" ", "") assert "{{ false }}" in fixed_algo