Skip to content

Commit cda1008

Browse files
committed
feat: single layer, parallel stacks before cleanup
1 parent d14f354 commit cda1008

File tree

8 files changed

+66
-26
lines changed

8 files changed

+66
-26
lines changed

tests/e2e/conftest.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from tests.e2e.utils.infrastructure import LambdaLayerStack, deploy_once
44

55

6-
@pytest.fixture(autouse=True, scope="session")
6+
@pytest.fixture(scope="session")
77
def lambda_layer_deployment(request: pytest.FixtureRequest, tmp_path_factory: pytest.TempPathFactory, worker_id: str):
88
"""Setup and teardown logic for E2E test infrastructure
99
@@ -22,5 +22,9 @@ def lambda_layer_deployment(request: pytest.FixtureRequest, tmp_path_factory: py
2222
CloudFormation Outputs from deployed infrastructure
2323
"""
2424
yield from deploy_once(
25-
stack=LambdaLayerStack, request=request, tmp_path_factory=tmp_path_factory, worker_id=worker_id
25+
stack=LambdaLayerStack,
26+
request=request,
27+
tmp_path_factory=tmp_path_factory,
28+
worker_id=worker_id,
29+
layer_arn="",
2630
)

tests/e2e/logger/conftest.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
from pathlib import Path
2+
13
import pytest
24

35
from tests.e2e.logger.infrastructure import LoggerStack
4-
from tests.e2e.utils.infrastructure import deploy_once
56

67

78
@pytest.fixture(autouse=True, scope="module")
8-
def infrastructure(request: pytest.FixtureRequest, tmp_path_factory: pytest.TempPathFactory, worker_id: str):
9+
def infrastructure(
10+
request: pytest.FixtureRequest,
11+
tmp_path_factory: pytest.TempPathFactory,
12+
worker_id: str,
13+
lambda_layer_deployment: dict,
14+
):
915
"""Setup and teardown logic for E2E test infrastructure
1016
1117
Parameters
@@ -22,4 +28,9 @@ def infrastructure(request: pytest.FixtureRequest, tmp_path_factory: pytest.Temp
2228
Dict[str, str]
2329
CloudFormation Outputs from deployed infrastructure
2430
"""
25-
yield from deploy_once(stack=LoggerStack, request=request, tmp_path_factory=tmp_path_factory, worker_id=worker_id)
31+
layer_arn = lambda_layer_deployment.get("LayerArn")
32+
stack = LoggerStack(handlers_dir=Path(f"{request.path.parent}/handlers"), layer_arn=layer_arn)
33+
try:
34+
yield stack.deploy()
35+
finally:
36+
stack.delete()

tests/e2e/logger/infrastructure.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55

66
class LoggerStack(BaseInfrastructureV2):
7-
def __init__(self, handlers_dir: Path, feature_name: str = "logger") -> None:
8-
super().__init__(feature_name, handlers_dir)
7+
def __init__(self, handlers_dir: Path, feature_name: str = "logger", layer_arn: str = "") -> None:
8+
super().__init__(feature_name, handlers_dir, layer_arn)
99

1010
def create_resources(self):
1111
self.create_lambda_functions()

tests/e2e/metrics/conftest.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
from pathlib import Path
2+
13
import pytest
24

35
from tests.e2e.metrics.infrastructure import MetricsStack
4-
from tests.e2e.utils.infrastructure import deploy_once
56

67

78
@pytest.fixture(autouse=True, scope="module")
8-
def infrastructure(request: pytest.FixtureRequest, tmp_path_factory: pytest.TempPathFactory, worker_id: str):
9+
def infrastructure(
10+
request: pytest.FixtureRequest,
11+
tmp_path_factory: pytest.TempPathFactory,
12+
worker_id: str,
13+
lambda_layer_deployment: dict,
14+
):
915
"""Setup and teardown logic for E2E test infrastructure
1016
1117
Parameters
@@ -22,4 +28,9 @@ def infrastructure(request: pytest.FixtureRequest, tmp_path_factory: pytest.Temp
2228
Dict[str, str]
2329
CloudFormation Outputs from deployed infrastructure
2430
"""
25-
yield from deploy_once(stack=MetricsStack, request=request, tmp_path_factory=tmp_path_factory, worker_id=worker_id)
31+
layer_arn = lambda_layer_deployment.get("LayerArn")
32+
stack = MetricsStack(handlers_dir=Path(f"{request.path.parent}/handlers"), layer_arn=layer_arn)
33+
try:
34+
yield stack.deploy()
35+
finally:
36+
stack.delete()

tests/e2e/metrics/infrastructure.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55

66
class MetricsStack(BaseInfrastructureV2):
7-
def __init__(self, handlers_dir: Path, feature_name: str = "metrics") -> None:
8-
super().__init__(feature_name, handlers_dir)
7+
def __init__(self, handlers_dir: Path, feature_name: str = "metrics", layer_arn: str = "") -> None:
8+
super().__init__(feature_name, handlers_dir, layer_arn)
99

1010
def create_resources(self):
1111
self.create_lambda_functions()

tests/e2e/tracer/conftest.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
from pathlib import Path
2+
13
import pytest
24

35
from tests.e2e.tracer.infrastructure import TracerStack
4-
from tests.e2e.utils.infrastructure import deploy_once
56

67

78
@pytest.fixture(autouse=True, scope="module")
8-
def infrastructure(request: pytest.FixtureRequest, tmp_path_factory: pytest.TempPathFactory, worker_id: str):
9+
def infrastructure(
10+
request: pytest.FixtureRequest,
11+
tmp_path_factory: pytest.TempPathFactory,
12+
worker_id: str,
13+
lambda_layer_deployment: dict,
14+
):
915
"""Setup and teardown logic for E2E test infrastructure
1016
1117
Parameters
@@ -22,4 +28,9 @@ def infrastructure(request: pytest.FixtureRequest, tmp_path_factory: pytest.Temp
2228
Dict[str, str]
2329
CloudFormation Outputs from deployed infrastructure
2430
"""
25-
yield from deploy_once(stack=TracerStack, request=request, tmp_path_factory=tmp_path_factory, worker_id=worker_id)
31+
layer_arn = lambda_layer_deployment.get("LayerArn")
32+
stack = TracerStack(handlers_dir=Path(f"{request.path.parent}/handlers"), layer_arn=layer_arn)
33+
try:
34+
yield stack.deploy()
35+
finally:
36+
stack.delete()

tests/e2e/tracer/infrastructure.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ class TracerStack(BaseInfrastructureV2):
99
# we could move after handler response or adopt env vars usage in e2e tests
1010
SERVICE_NAME: str = build_service_name()
1111

12-
def __init__(self, handlers_dir: Path, feature_name: str = "tracer") -> None:
13-
super().__init__(feature_name, handlers_dir)
12+
def __init__(self, handlers_dir: Path, feature_name: str = "tracer", layer_arn: str = "") -> None:
13+
super().__init__(feature_name, handlers_dir, layer_arn)
1414

1515
def create_resources(self) -> None:
1616
env_vars = {"POWERTOOLS_SERVICE_NAME": self.SERVICE_NAME}

tests/e2e/utils/infrastructure.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class PythonVersion(Enum):
3838
class BaseInfrastructureV2(ABC):
3939
STACKS_OUTPUT: dict = {}
4040

41-
def __init__(self, feature_name: str, handlers_dir: Path) -> None:
41+
def __init__(self, feature_name: str, handlers_dir: Path, layer_arn: str = "") -> None:
4242
self.feature_name = feature_name
4343
self.stack_name = f"test-{feature_name}-{uuid4()}"
4444
self.handlers_dir = handlers_dir
@@ -48,6 +48,7 @@ def __init__(self, feature_name: str, handlers_dir: Path) -> None:
4848
self.stack = Stack(self.app, self.stack_name)
4949
self.session = boto3.Session()
5050
self.cfn: CloudFormationClient = self.session.client("cloudformation")
51+
self.layer_arn = layer_arn
5152

5253
# NOTE: CDK stack account and region are tokens, we need to resolve earlier
5354
self.account_id = self.session.client("sts").get_caller_identity()["Account"]
@@ -85,9 +86,10 @@ def create_lambda_functions(self, function_props: Optional[Dict] = None):
8586
handlers = list(self.handlers_dir.rglob("*.py"))
8687
source = Code.from_asset(f"{self.handlers_dir}")
8788
props_override = function_props or {}
88-
layer = LayerVersion.from_layer_version_arn(
89-
self.stack, "layer-arn", layer_version_arn=LambdaLayerStack.get_lambda_layer_arn()
90-
)
89+
if not self.layer_arn:
90+
self.layer_arn = LambdaLayerStack.get_lambda_layer_arn()
91+
92+
layer = LayerVersion.from_layer_version_arn(self.stack, "layer-arn", layer_version_arn=self.layer_arn)
9193

9294
for fn in handlers:
9395
fn_name = fn.stem
@@ -215,6 +217,7 @@ def deploy_once(
215217
request: pytest.FixtureRequest,
216218
tmp_path_factory: pytest.TempPathFactory,
217219
worker_id: str,
220+
layer_arn: str,
218221
) -> Generator[Dict[str, str], None, None]:
219222
"""Deploys provided stack once whether CPU parallelization is enabled or not
220223
@@ -240,9 +243,9 @@ def deploy_once(
240243
except AttributeError:
241244
# session fixture has a slightly different object
242245
# luckily it only runs Lambda Layer Stack which doesn't deploy Lambda fns
243-
handlers_dir = ""
246+
handlers_dir = f"{request.node.path.parent}/handlers"
244247

245-
stack = stack(handlers_dir=Path(handlers_dir))
248+
stack = stack(handlers_dir=Path(handlers_dir), layer_arn=layer_arn)
246249

247250
try:
248251
if worker_id == "master":
@@ -255,7 +258,7 @@ def deploy_once(
255258
# cache and lock must be unique per stack
256259
# otherwise separate processes deploy the first stack collected only
257260
# since the original lock was based on parallel workers cache tmp dir
258-
cache = root_tmp_dir / f"{id(stack)}_cache.json"
261+
cache = root_tmp_dir / "cache.json"
259262

260263
with FileLock(f"{cache}.lock"):
261264
# If cache exists, return stack outputs back
@@ -274,8 +277,8 @@ def deploy_once(
274277
class LambdaLayerStack(BaseInfrastructureV2):
275278
FEATURE_NAME = "lambda-layer"
276279

277-
def __init__(self, handlers_dir: Path = "", feature_name: str = FEATURE_NAME) -> None:
278-
super().__init__(feature_name, handlers_dir)
280+
def __init__(self, handlers_dir: Path, feature_name: str = FEATURE_NAME, layer_arn: str = "") -> None:
281+
super().__init__(feature_name, handlers_dir, layer_arn)
279282

280283
def create_resources(self):
281284
layer = self._create_layer()

0 commit comments

Comments
 (0)