Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/60048.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed sysrc.managed raising TypeError in test mode when the value is a non-string (e.g. YAML coerces an unquoted YES to a bool)
2 changes: 1 addition & 1 deletion salt/states/sysrc.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def managed(name, value, **kwargs):
ret["comment"] = f'The value of "{name}" will be changed!'
ret["changes"] = {
"old": current_state,
"new": name + " = " + value + " will be set.",
"new": f"{name} = {value} will be set.",
}

# When test=true return none
Expand Down
53 changes: 53 additions & 0 deletions tests/pytests/unit/states/test_sysrc.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,59 @@ def test_managed():
assert sysrc.managed("salt", "stack") == ret


def test_managed_test_mode_bool_value_60048():
"""
Test mode must not raise TypeError when the value is a non-string
(e.g. YAML coerces an unquoted ``YES`` to the bool ``True``).

Regression test for #60048.
"""
# sysrc.get returns None -> variable not yet set, so managed() falls
# through to the __opts__["test"] preview branch.
mock_get = MagicMock(return_value=None)
with patch.dict(sysrc.__salt__, {"sysrc.get": mock_get}):
# __opts__["test"] = True exercises the test-mode preview path.
with patch.dict(sysrc.__opts__, {"test": True}):
ret = sysrc.managed("vm_enable", True)
assert ret["result"] is None
assert ret["comment"] == 'The value of "vm_enable" will be changed!'
assert ret["changes"] == {
"old": None,
"new": "vm_enable = True will be set.",
}


def test_managed_test_mode_string_value_60048():
"""
Inverse of the #60048 regression: a normal string value must render
identically before and after the f-string change, so this passes both
with and without the fix and guards against an output regression.
"""
mock_get = MagicMock(return_value=None)
with patch.dict(sysrc.__salt__, {"sysrc.get": mock_get}):
with patch.dict(sysrc.__opts__, {"test": True}):
ret = sysrc.managed("syslogd_flags", "-ss")
assert ret["result"] is None
assert ret["changes"] == {
"old": None,
"new": "syslogd_flags = -ss will be set.",
}


def test_managed_test_mode_int_value_60048():
"""
Peripheral coverage for the test-mode preview: an integer value
(e.g. YAML ``value: 22``) is coerced to its string form rather than
raising TypeError.
"""
mock_get = MagicMock(return_value=None)
with patch.dict(sysrc.__salt__, {"sysrc.get": mock_get}):
with patch.dict(sysrc.__opts__, {"test": True}):
ret = sysrc.managed("sshd_port", 22)
assert ret["result"] is None
assert ret["changes"]["new"] == "sshd_port = 22 will be set."


def test_absent():
"""
Test to ensure a sysrc variable is absent.
Expand Down
Loading