Skip to content

Commit

Permalink
Merge branch 'master' into ah/1446-cyclical-dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
zaro0508 committed Mar 5, 2024
2 parents 74b260c + f3b7e51 commit 5904a5a
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 7 deletions.
29 changes: 27 additions & 2 deletions sceptre/stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import logging

from typing import List, Any, Optional
from typing import List, Dict, Union, Any, Optional
from deprecation import deprecated

from sceptre import __version__
Expand All @@ -26,6 +26,7 @@
ResolvableValueProperty,
RecursiveResolve,
PlaceholderType,
Resolver,
)
from sceptre.template import Template

Expand Down Expand Up @@ -262,7 +263,7 @@ def __init__(
)

self.s3_details = s3_details
self.parameters = parameters or {}
self.parameters = self._ensure_parameters(parameters or {})
self.sceptre_user_data = sceptre_user_data or {}
self.notifications = notifications or []

Expand All @@ -275,6 +276,30 @@ def _ensure_boolean(self, config_name: str, value: Any) -> bool:
)
return value

def _ensure_parameters(
self, parameters: Dict[str, Any]
) -> Dict[str, Union[str, List[Union[str, Resolver]], Resolver]]:
"""Ensure CloudFormation parameters are of valid types"""

def is_valid(value: Any) -> bool:
return (
isinstance(value, str)
or (
isinstance(value, list)
and all(
isinstance(item, str) or isinstance(item, Resolver)
for item in value
)
)
or isinstance(value, Resolver)
)

if not all(is_valid(value) for value in parameters.values()):
raise InvalidConfigFileError(
f"{self.name}: Values for parameters must be strings, lists or resolvers, got {parameters}"
)
return parameters

def __repr__(self):
return (
"sceptre.stack.Stack("
Expand Down
51 changes: 46 additions & 5 deletions tests/test_stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ def stack_factory(**kwargs):
return Stack(**call_kwargs)


class FakeResolver(Resolver):
def resolve(self):
return "Fake"


class TestStack(object):
def setup_method(self, test_method):
self.stack = Stack(
Expand Down Expand Up @@ -183,6 +188,46 @@ def test_init__non_boolean_obsolete_value__raises_invalid_config_file_error(self
obsolete="true",
)

@pytest.mark.parametrize(
"parameters",
[
{"someNum": 1},
{"someBool": True},
{"aBadList": [1, 2, 3]},
{"aDict": {"foo": "bar"}},
],
)
def test_init__invalid_parameters_raise_invalid_config_file_error(self, parameters):
with pytest.raises(InvalidConfigFileError):
Stack(
name="stack_name",
project_code="project_code",
template_handler_config={"type": "file"},
region="region",
parameters=parameters,
)

@pytest.mark.parametrize(
"parameters",
[
{"someNum": "1"},
{"someBool": "true"},
{"aList": ["aString", FakeResolver()]},
{"aResolver": FakeResolver()},
],
)
def test_init__valid_parameters_do_not_raise_invalid_config_file_error(
self, parameters
):
stack = Stack(
name="stack_name",
project_code="project_code",
template_handler_config={"type": "file"},
region="region",
parameters=parameters,
)
assert isinstance(stack, Stack)

def test_stack_repr(self):
assert (
self.stack.__repr__() == "sceptre.stack.Stack("
Expand Down Expand Up @@ -248,14 +293,10 @@ def resolve(self):
def test_configuration_manager__sceptre_role_returns_value__returns_connection_manager_with_that_role(
self,
):
class FakeResolver(Resolver):
def resolve(self):
return "role"

self.stack.sceptre_role = FakeResolver()

connection_manager = self.stack.connection_manager
assert connection_manager.sceptre_role == "role"
assert connection_manager.sceptre_role == "Fake"

@fail_if_not_removed
def test_iam_role__is_removed_on_removal_version(self):
Expand Down

0 comments on commit 5904a5a

Please sign in to comment.