Skip to content
Merged
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
5 changes: 5 additions & 0 deletions snowcap/data_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,11 @@ def _cast_param_value(raw_value: str, param_type: str) -> Any:
return float(raw_value)
except ValueError:
raise Exception(f"Unsupported number type: {raw_value}")
elif param_type == "FLOAT":
try:
return float(raw_value)
except ValueError:
raise Exception(f"Unsupported float type: {raw_value}")
elif param_type == "STRING":
return str(raw_value) if raw_value else None
else:
Expand Down
43 changes: 43 additions & 0 deletions tests/test_data_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,20 @@ def test_invalid_number_raises(self):
with pytest.raises(Exception, match="Unsupported number type"):
_cast_param_value("not_a_number", "NUMBER")

def test_float(self):
"""SHOW PARAMETERS reports INITIAL_REPLICATION_SIZE_LIMIT_IN_TB (and other
decimal-valued parameters) with type FLOAT, not NUMBER. Falling through to the
raw-string default left the fetched value a str while the YAML-declared value
parses to a Python float, so plan compared "10.0" != 10.0 and proposed an UPDATE
that never converges."""
result = _cast_param_value("10.0", "FLOAT")
assert result == 10.0
assert isinstance(result, float)

def test_invalid_float_raises(self):
with pytest.raises(Exception, match="Unsupported float type"):
_cast_param_value("not_a_float", "FLOAT")


class TestParamsResultToDict:
"""Tests for params_result_to_dict helper function."""
Expand All @@ -687,6 +701,35 @@ def test_basic_params(self):
assert result["param3"] == "hello"


class TestFetchAccountParameter:
"""Regression test for the exact reported symptom: `snowcap apply` proposed an UPDATE
for INITIAL_REPLICATION_SIZE_LIMIT_IN_TB on every run because SHOW PARAMETERS reports
it with type FLOAT, which _cast_param_value didn't handle."""

@patch("snowcap.data_provider.execute")
def test_fetches_float_typed_parameter_as_a_float(self, mock_execute):
from snowcap.data_provider import fetch_account_parameter
from snowcap.identifiers import FQN
from snowcap.resource_name import ResourceName

mock_execute.return_value = [
{
"key": "INITIAL_REPLICATION_SIZE_LIMIT_IN_TB",
"value": "10.0",
"default": "10.0",
"level": "ACCOUNT",
"type": "FLOAT",
}
]
fqn = FQN(name=ResourceName("INITIAL_REPLICATION_SIZE_LIMIT_IN_TB"))

result = fetch_account_parameter(MagicMock(), fqn)

assert result is not None
assert result["value"] == 10.0
assert isinstance(result["value"], float)


class TestOptionsResultToList:
"""Tests for options_result_to_list helper function."""

Expand Down
Loading