Skip to content

Commit f1577b4

Browse files
committed
update tests with additional validation
1 parent dd69f0f commit f1577b4

1 file changed

Lines changed: 205 additions & 13 deletions

File tree

integration/combination/test_function_with_capacity_provider.py

Lines changed: 205 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@ class TestFunctionWithCapacityProvider(BaseTest):
1616
def companion_stack_outputs(self, get_companion_stack_outputs):
1717
self.companion_stack_outputs = get_companion_stack_outputs
1818

19-
def test_function_with_capacity_provider_custom_role(self):
20-
"""Test Lambda function with CapacityProviderConfig using custom operator role."""
21-
# Phase 1: Prepare parameters from companion stack
22-
parameters = [
19+
def generate_lmi_parameters(self):
20+
return [
2321
self.generate_parameter("SubnetId", self.companion_stack_outputs["LMISubnetId"]),
2422
self.generate_parameter("SecurityGroup", self.companion_stack_outputs["LMISecurityGroupId"]),
2523
self.generate_parameter("KMSKeyArn", self.companion_stack_outputs["LMIKMSKeyArn"]),
2624
]
2725

26+
def test_function_with_capacity_provider_custom_role(self):
27+
"""Test Lambda function with CapacityProviderConfig using custom operator role."""
28+
# Phase 1: Prepare parameters from companion stack
29+
parameters = self.generate_lmi_parameters()
30+
2831
# Phase 2: Deploy and verify against expected JSON
2932
self.create_and_verify_stack("combination/function_lmi_custom", parameters)
3033

@@ -35,17 +38,61 @@ def test_function_with_capacity_provider_custom_role(self):
3538
capacity_provider_resources = self.get_stack_resources("AWS::Lambda::CapacityProvider")
3639
self.assertEqual(len(capacity_provider_resources), 1, "Should create exactly one CapacityProvider")
3740

38-
iam_role_resources = self.get_stack_resources("AWS::IAM::Role")
39-
self.assertEqual(len(iam_role_resources), 2, "Should create exactly two IAM roles")
41+
# Phase 4: Validate function capacity provider configuration
42+
lambda_function = lambda_resources[0]
43+
capacity_provider = capacity_provider_resources[0]
44+
45+
function_capacity_provider_config = self.get_function_capacity_provider_config(
46+
lambda_function["PhysicalResourceId"]
47+
)
48+
self.assertIsNotNone(function_capacity_provider_config, "Function should have capacity provider configuration")
49+
self.assertIn(
50+
"LambdaManagedInstancesCapacityProviderConfig",
51+
function_capacity_provider_config,
52+
"Function should have LambdaManagedInstancesCapacityProviderConfig",
53+
)
54+
55+
lmi_config = function_capacity_provider_config["LambdaManagedInstancesCapacityProviderConfig"]
56+
function_capacity_provider_arn = lmi_config.get("CapacityProviderArn")
57+
self.assertIsNotNone(function_capacity_provider_arn, "Function should reference a capacity provider ARN")
58+
59+
# Phase 5: Validate capacity provider details
60+
capacity_provider_config = self.get_lambda_capacity_provider_config(capacity_provider)
61+
self.assertIsNotNone(capacity_provider_config, "Capacity provider should have configuration")
62+
self.assertEqual(capacity_provider_config["State"], "Active", "Capacity provider should be in Active state")
63+
64+
# Verify the function uses the correct capacity provider ARN
65+
actual_capacity_provider_arn = capacity_provider_config.get("CapacityProviderArn")
66+
self.assertEqual(
67+
function_capacity_provider_arn,
68+
actual_capacity_provider_arn,
69+
"Function should reference the correct capacity provider ARN",
70+
)
71+
72+
# Phase 6: Verify capacity provider uses custom operator role
73+
permissions_config = capacity_provider_config.get("PermissionsConfig")
74+
self.assertIsNotNone(permissions_config, "Capacity provider should have permissions configuration")
75+
76+
capacity_provider_operator_role_arn = permissions_config.get("CapacityProviderOperatorRoleArn")
77+
self.assertIsNotNone(
78+
capacity_provider_operator_role_arn, "Capacity provider should have custom operator role ARN"
79+
)
80+
81+
# Get the physical ID of the custom role using its logical ID
82+
custom_operator_role_physical_id = self.get_physical_id_by_logical_id("MyCapacityProviderCustomRole")
83+
self.assertIsNotNone(custom_operator_role_physical_id, "MyCapacityProviderCustomRole should exist in the stack")
84+
85+
# Verify the capacity provider uses the custom role by comparing physical IDs
86+
self.assertIn(
87+
custom_operator_role_physical_id,
88+
capacity_provider_operator_role_arn,
89+
f"Capacity provider should use the custom operator role with physical ID {custom_operator_role_physical_id}",
90+
)
4091

4192
def test_function_with_capacity_provider_default_role(self):
4293
"""Test Lambda function with CapacityProviderConfig using default operator role."""
4394
# Phase 1: Prepare parameters from companion stack
44-
parameters = [
45-
self.generate_parameter("SubnetId", self.companion_stack_outputs["LMISubnetId"]),
46-
self.generate_parameter("SecurityGroup", self.companion_stack_outputs["LMISecurityGroupId"]),
47-
self.generate_parameter("KMSKeyArn", self.companion_stack_outputs["LMIKMSKeyArn"]),
48-
]
95+
parameters = self.generate_lmi_parameters()
4996

5097
# Phase 2: Deploy and verify against expected JSON
5198
self.create_and_verify_stack("combination/function_lmi_default", parameters)
@@ -57,5 +104,150 @@ def test_function_with_capacity_provider_default_role(self):
57104
capacity_provider_resources = self.get_stack_resources("AWS::Lambda::CapacityProvider")
58105
self.assertEqual(len(capacity_provider_resources), 2, "Should create exactly two CapacityProviders")
59106

60-
iam_role_resources = self.get_stack_resources("AWS::IAM::Role")
61-
self.assertEqual(len(iam_role_resources), 3, "Should create exactly three IAM roles")
107+
# Phase 4: Validate function capacity provider configuration
108+
simple_capacity_provider = next(
109+
r for r in capacity_provider_resources if r["LogicalResourceId"] == "SimpleCapacityProvider"
110+
)
111+
advanced_capacity_provider = next(
112+
r for r in capacity_provider_resources if r["LogicalResourceId"] == "AdvancedCapacityProvider"
113+
)
114+
my_function = lambda_resources[0]
115+
116+
function_config = self.get_function_capacity_provider_config(my_function["PhysicalResourceId"])
117+
self.assertIsNotNone(function_config, "Function should have capacity provider configuration")
118+
self.assertIn(
119+
"LambdaManagedInstancesCapacityProviderConfig",
120+
function_config,
121+
"Function should have LambdaManagedInstancesCapacityProviderConfig",
122+
)
123+
124+
lmi_config = function_config["LambdaManagedInstancesCapacityProviderConfig"]
125+
function_capacity_provider_arn = lmi_config.get("CapacityProviderArn")
126+
self.assertIsNotNone(function_capacity_provider_arn, "Function should reference a capacity provider ARN")
127+
128+
# Phase 5: Validate SimpleCapacityProvider configuration
129+
simple_cp_config = self.get_lambda_capacity_provider_config(simple_capacity_provider)
130+
self.assertIsNotNone(simple_cp_config, "SimpleCapacityProvider should have configuration")
131+
self.assertEqual(simple_cp_config["State"], "Active", "SimpleCapacityProvider should be in Active state")
132+
133+
# Verify the function uses SimpleCapacityProvider
134+
simple_cp_arn = simple_cp_config.get("CapacityProviderArn")
135+
self.assertEqual(
136+
function_capacity_provider_arn, simple_cp_arn, "Function should reference SimpleCapacityProvider ARN"
137+
)
138+
139+
# Verify SimpleCapacityProvider VPC configuration
140+
simple_vpc_config = simple_cp_config.get("VpcConfig")
141+
self.assertIsNotNone(simple_vpc_config, "SimpleCapacityProvider should have VPC configuration")
142+
self.assertIn(
143+
self.companion_stack_outputs["LMISubnetId"],
144+
simple_vpc_config["SubnetIds"],
145+
"SimpleCapacityProvider should use the correct subnet",
146+
)
147+
self.assertIn(
148+
self.companion_stack_outputs["LMISecurityGroupId"],
149+
simple_vpc_config["SecurityGroupIds"],
150+
"SimpleCapacityProvider should use the correct security group",
151+
)
152+
153+
# Verify SimpleCapacityProvider uses SAM-generated default operator role
154+
simple_permissions_config = simple_cp_config.get("PermissionsConfig")
155+
self.assertIsNotNone(simple_permissions_config, "SimpleCapacityProvider should have permissions configuration")
156+
simple_operator_arn = simple_permissions_config.get("CapacityProviderOperatorRoleArn")
157+
self.assertIsNotNone(simple_operator_arn, "SimpleCapacityProvider should have operator role ARN")
158+
159+
# Phase 6: Validate AdvancedCapacityProvider configuration
160+
advanced_cp_config = self.get_lambda_capacity_provider_config(advanced_capacity_provider)
161+
self.assertIsNotNone(advanced_cp_config, "AdvancedCapacityProvider should have configuration")
162+
self.assertEqual(advanced_cp_config["State"], "Active", "AdvancedCapacityProvider should be in Active state")
163+
164+
# Verify AdvancedCapacityProvider VPC configuration
165+
advanced_vpc_config = advanced_cp_config.get("VpcConfig")
166+
self.assertIsNotNone(advanced_vpc_config, "AdvancedCapacityProvider should have VPC configuration")
167+
self.assertIn(
168+
self.companion_stack_outputs["LMISubnetId"],
169+
advanced_vpc_config["SubnetIds"],
170+
"AdvancedCapacityProvider should use the correct subnet",
171+
)
172+
self.assertIn(
173+
self.companion_stack_outputs["LMISecurityGroupId"],
174+
advanced_vpc_config["SecurityGroupIds"],
175+
"AdvancedCapacityProvider should use the correct security group",
176+
)
177+
178+
# Verify AdvancedCapacityProvider permissions configuration
179+
advanced_permissions_config = advanced_cp_config.get("PermissionsConfig")
180+
self.assertIsNotNone(
181+
advanced_permissions_config,
182+
"AdvancedCapacityProvider should have permissions configuration",
183+
)
184+
185+
# Verify AdvancedCapacityProvider instance requirements
186+
instance_requirements = advanced_cp_config.get("InstanceRequirements")
187+
self.assertIsNotNone(instance_requirements, "AdvancedCapacityProvider should have instance requirements")
188+
self.assertIn(
189+
"x86_64",
190+
instance_requirements.get("Architectures", []),
191+
"AdvancedCapacityProvider should have x86_64 architecture",
192+
)
193+
allowed_types = instance_requirements.get("AllowedInstanceTypes", [])
194+
self.assertIn("m5.large", allowed_types, "AdvancedCapacityProvider should allow m5.large")
195+
self.assertIn("m5.xlarge", allowed_types, "AdvancedCapacityProvider should allow m5.xlarge")
196+
self.assertIn("m5.2xlarge", allowed_types, "AdvancedCapacityProvider should allow m5.2xlarge")
197+
198+
# Verify AdvancedCapacityProvider scaling configuration
199+
scaling_config = advanced_cp_config.get("CapacityProviderScalingConfig")
200+
self.assertIsNotNone(scaling_config, "AdvancedCapacityProvider should have scaling configuration")
201+
self.assertEqual(
202+
scaling_config.get("MaxVCpuCount"), 64, "AdvancedCapacityProvider should have MaxVCpuCount of 64"
203+
)
204+
scaling_policies = scaling_config.get("ScalingPolicies", [])
205+
self.assertTrue(len(scaling_policies) > 0, "AdvancedCapacityProvider should have scaling policies")
206+
cpu_policy = next(
207+
(
208+
p
209+
for p in scaling_policies
210+
if p.get("PredefinedMetricType") == "LambdaCapacityProviderAverageCPUUtilization"
211+
),
212+
None,
213+
)
214+
self.assertIsNotNone(cpu_policy, "AdvancedCapacityProvider should have CPU utilization scaling policy")
215+
self.assertEqual(
216+
cpu_policy.get("TargetValue"), 70.0, "AdvancedCapacityProvider should have CPU utilization target of 70"
217+
)
218+
219+
# Verify AdvancedCapacityProvider KMS key
220+
self.assertEqual(
221+
advanced_cp_config.get("KmsKeyArn"),
222+
self.companion_stack_outputs["LMIKMSKeyArn"],
223+
"AdvancedCapacityProvider should use the correct KMS key",
224+
)
225+
226+
def get_function_capacity_provider_config(self, function_name, alias_name=None):
227+
lambda_client = self.client_provider.lambda_client
228+
229+
try:
230+
# Build the function identifier - include alias if provided
231+
function_identifier = f"{function_name}:{alias_name}" if alias_name else function_name
232+
# Get the function configuration
233+
response = lambda_client.get_function_configuration(FunctionName=function_identifier)
234+
# Return the CapacityProviderConfig if it exists
235+
return response.get("CapacityProviderConfig")
236+
except Exception as e:
237+
# Log the error and return None for graceful handling
238+
print(f"Error getting function capacity provider config: {e}")
239+
return None
240+
241+
def get_lambda_capacity_provider_config(self, capacity_provider_resource):
242+
lambda_client = self.client_provider.lambda_client
243+
244+
try:
245+
# Extract capacity provider name from resource dict
246+
capacity_provider_name = capacity_provider_resource["PhysicalResourceId"]
247+
# Get the capacity provider configuration
248+
response = lambda_client.get_capacity_provider(CapacityProviderName=capacity_provider_name)
249+
return response.get("CapacityProvider")
250+
except Exception as e:
251+
# Log the error and return None for graceful handling
252+
print(f"Error getting capacity provider config for {capacity_provider_resource}: {e}")
253+
return None

0 commit comments

Comments
 (0)