Skip to content

Commit b97c752

Browse files
committed
Validate test
1 parent 7856668 commit b97c752

File tree

4 files changed

+89
-11
lines changed

4 files changed

+89
-11
lines changed

localstack-core/localstack/services/cloudformation/v2/provider.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from localstack.aws.api import RequestContext, handler
99
from localstack.aws.api.cloudformation import (
10+
Account,
1011
CallAs,
1112
Changes,
1213
ChangeSetNameOrId,
@@ -29,6 +30,7 @@
2930
DeletionMode,
3031
DescribeChangeSetOutput,
3132
DescribeStackEventsOutput,
33+
DescribeStackInstanceOutput,
3234
DescribeStackResourcesOutput,
3335
DescribeStackSetOperationOutput,
3436
DescribeStacksOutput,
@@ -47,10 +49,14 @@
4749
NextToken,
4850
Parameter,
4951
PhysicalResourceId,
52+
Region,
5053
RetainExceptOnCreate,
5154
RetainResources,
5255
RoleARN,
5356
RollbackConfiguration,
57+
StackDriftStatus,
58+
StackInstanceComprehensiveStatus,
59+
StackInstanceDetailedStatus,
5460
StackName,
5561
StackNameOrId,
5662
StackSetName,
@@ -65,6 +71,9 @@
6571
UpdateStackOutput,
6672
UpdateTerminationProtectionOutput,
6773
)
74+
from localstack.aws.api.cloudformation import (
75+
StackInstance as ApiStackInstance,
76+
)
6877
from localstack.aws.connect import connect_to
6978
from localstack.services.cloudformation import api_utils
7079
from localstack.services.cloudformation.engine import template_preparer
@@ -826,6 +835,49 @@ def describe_stack_set_operation(
826835

827836
return DescribeStackSetOperationOutput(StackSetOperation=result)
828837

838+
@handler("DescribeStackInstance")
839+
def describe_stack_instance(
840+
self,
841+
context: RequestContext,
842+
stack_set_name: StackSetName,
843+
stack_instance_account: Account,
844+
stack_instance_region: Region,
845+
call_as: CallAs | None = None,
846+
**kwargs,
847+
) -> DescribeStackInstanceOutput:
848+
state = get_cloudformation_store(context.account_id, context.region)
849+
stack_set = find_stack_set_v2(state, stack_set_name)
850+
if not stack_set:
851+
# TODO: message parity
852+
raise RuntimeError(f"Could not find stack set '{stack_set_name}'")
853+
854+
for instance in stack_set.stack_instances:
855+
if instance.account_id != stack_instance_account:
856+
continue
857+
if instance.region_name != stack_instance_region:
858+
continue
859+
860+
return DescribeStackInstanceOutput(
861+
StackInstance=ApiStackInstance(
862+
StackSetId=stack_set.stack_set_id,
863+
Region=instance.region_name,
864+
Account=instance.account_id,
865+
StackId=instance.stack_id,
866+
DriftStatus=StackDriftStatus.NOT_CHECKED,
867+
LastOperationId=instance.operation_id,
868+
# TODO: fixed
869+
StackInstanceStatus=StackInstanceComprehensiveStatus(
870+
DetailedStatus=StackInstanceDetailedStatus.SUCCEEDED
871+
),
872+
Status=instance.status,
873+
)
874+
)
875+
876+
# TODO: message parity
877+
raise RuntimeError(
878+
f"Could not find stack instance for account '{stack_instance_account}' and region '{stack_instance_region}'"
879+
)
880+
829881
@handler("DeleteStackInstances", expand=False)
830882
def delete_stack_instances(
831883
self,

tests/aws/services/cloudformation/v2/ported_from_v1/resources/test_stack_sets.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,17 +70,25 @@ def setup_account_for_stack_sets(aws_client):
7070
)
7171

7272

73-
@markers.aws.manual_setup_required
73+
@markers.aws.validated
7474
@pytest.mark.usefixtures("setup_account_for_stack_sets")
75+
@markers.snapshot.skip_snapshot_verify(
76+
paths=[
77+
"$..LastOperationId",
78+
"$..OrganizationalUnitId",
79+
"$..ParameterOverrides",
80+
"$..StatusReason",
81+
]
82+
)
7583
def test_create_stack_set_with_stack_instances(
7684
account_id,
7785
region_name,
7886
aws_client,
7987
snapshot,
8088
wait_stack_set_operation,
8189
):
82-
""" "Account <...> should have 'AWSCloudFormationStackSetAdministrationRole' role with trust relationship to CloudFormation service."""
83-
snapshot.add_transformer(snapshot.transform.key_value("StackSetId", "stack-set-id"))
90+
snapshot.add_transformer(snapshot.transform.key_value("StackSetId"))
91+
snapshot.add_transformer(snapshot.transform.key_value("StackId"))
8492

8593
stack_set_name = f"StackSet-{short_uid()}"
8694

@@ -118,11 +126,14 @@ def test_create_stack_set_with_stack_instances(
118126
wait_stack_set_operation(stack_set_name, create_instances_result["OperationId"])
119127

120128
# check the resources actually exist
121-
stack_instance_stack_id = aws_client.cloudformation.describe_stack_instance(
129+
stack_instance = aws_client.cloudformation.describe_stack_instance(
122130
StackSetName=stack_set_name,
123131
StackInstanceAccount=account_id,
124132
StackInstanceRegion=region_name,
125-
)["StackInstance"]["StackId"]
133+
)["StackInstance"]
134+
snapshot.match("describe-stack-instance", stack_instance)
135+
136+
stack_instance_stack_id = stack_instance["StackId"]
126137
aws_client.cloudformation.get_waiter("stack_create_complete").wait(
127138
StackName=stack_instance_stack_id,
128139
WaiterConfig={

tests/aws/services/cloudformation/v2/ported_from_v1/resources/test_stack_sets.snapshot.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"tests/aws/services/cloudformation/v2/ported_from_v1/resources/test_stack_sets.py::test_create_stack_set_with_stack_instances": {
3-
"recorded-date": "28-07-2025, 21:37:27",
3+
"recorded-date": "28-07-2025, 21:51:09",
44
"recorded-content": {
55
"create_stack_set": {
66
"StackSetId": "<stack-set-id:1>",
@@ -15,6 +15,21 @@
1515
"HTTPHeaders": {},
1616
"HTTPStatusCode": 200
1717
}
18+
},
19+
"describe-stack-instance": {
20+
"Account": "111111111111",
21+
"DriftStatus": "NOT_CHECKED",
22+
"LastOperationId": "<uuid:2>",
23+
"OrganizationalUnitId": "",
24+
"ParameterOverrides": [],
25+
"Region": "<region>",
26+
"StackId": "<stack-id:1>",
27+
"StackInstanceStatus": {
28+
"DetailedStatus": "SUCCEEDED"
29+
},
30+
"StackSetId": "<stack-set-id:1>",
31+
"Status": "CURRENT",
32+
"StatusReason": "No updates are to be performed."
1833
}
1934
}
2035
},

tests/aws/services/cloudformation/v2/ported_from_v1/resources/test_stack_sets.validation.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
22
"tests/aws/services/cloudformation/v2/ported_from_v1/resources/test_stack_sets.py::test_create_stack_set_with_stack_instances": {
3-
"last_validated_date": "2025-07-28T21:37:55+00:00",
3+
"last_validated_date": "2025-07-28T21:51:31+00:00",
44
"durations_in_seconds": {
5-
"setup": 44.93,
6-
"call": 85.45,
7-
"teardown": 27.96,
8-
"total": 158.34
5+
"setup": 44.54,
6+
"call": 48.24,
7+
"teardown": 21.74,
8+
"total": 114.52
99
}
1010
},
1111
"tests/aws/services/cloudformation/v2/ported_from_v1/resources/test_stack_sets.py::test_delete_nonexistent_stack_set": {

0 commit comments

Comments
 (0)