Skip to content

Commit a668286

Browse files
committed
chore(golden): tighten test assertions, drop dead code, document known limitations
Cleanups surfaced by the code-quality review of PR 1: - harness.run_package_pipeline: drop the dead first _export_global_artifacts_pass(original) call. The original template was read, mutated by that pass, and then never referenced again — the artifact rewrite operates on a deep-copied build_output, so the first pass had no observable effect. Update the docstring to match. - harness._walk_artifact_properties: replace the bare `-> List:` return type with `-> List[Tuple[str, str, Dict[str, Any]]]` so downstream callers and reviewers can see the shape without reading the body. - harness module docstring: add a Known limitations subsection covering four issues that the next contributor should expect (image / ECR over-rewrite, _stub_local_uris_for_translator drift, GoldenS3Uploader not subclassing S3Uploader, missing AWS::Include sentinel). They will be addressed by PR 2 / corpus growth. - test_harness_package.test_package_sam_case_rewrites_code_to_s3_uri: replace the lenient `s3_uri_field == "golden-bucket"` short-circuit with two specific assertions that the dict has the expected keys. - test_harness_build: drop unused `tmp_path` fixture parameters from two tests. - update_goldens.py / check_semver_bump.py: silence mypy `[unreachable]` on the script-form sys.path bootstrap added in the previous fix.
1 parent 3802cb9 commit a668286

5 files changed

Lines changed: 50 additions & 24 deletions

File tree

tests/golden/check_semver_bump.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
# When run as a script, Python does not auto-add the repo root to sys.path,
1313
# so absolute imports rooted at `tests.golden...` would fail. This script
1414
# happens to have no such imports today, but keep the guard symmetrical with
15-
# update_goldens.py so future imports do not silently regress the script form.
15+
# update_goldens.py so future imports do not silently regress the script
16+
# form. mypy treats the __main__ guard as always-False, hence the
17+
# `type: ignore`.
1618
if __name__ == "__main__" and __package__ is None:
17-
import sys
18-
from pathlib import Path
19+
import sys # type: ignore[unreachable] # noqa: E402
20+
from pathlib import Path # noqa: E402
1921

2022
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
2123

tests/golden/harness.py

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,38 @@
3636
matches the user-visible behavior of ``sam build`` on such a template
3737
(the LE construct is preserved verbatim for CloudFormation server-side
3838
expansion).
39+
40+
Known limitations (deferred to follow-up PRs / corpus growth):
41+
42+
- Image-based Lambdas / ECR artifacts: ``_packageable_replacement`` always
43+
rewrites ``AWS::Lambda::Function`` ``Code`` to an S3Bucket/S3Key dict and
44+
``Code.ImageUri`` to an ECR URI string, but it does not enforce that
45+
exactly one of those properties is set on a given resource. A template
46+
with both shapes will be over-rewritten. No image sentinel exists yet to
47+
surface this — PR 2's corpus expansion will add one.
48+
- ``_stub_local_uris_for_translator`` duplicates the rewrite logic in
49+
``SamTemplateValidator._replace_local_codeuri``. The two will drift if
50+
upstream extends the validator's set of properties or recognized URI
51+
shapes. Until the harness can call the validator without pulling in
52+
AWS-credential side-effects (boto Session at construction time), this
53+
duplication is accepted.
54+
- ``GoldenS3Uploader`` reimplements the surface ``S3Uploader`` exposes
55+
rather than subclassing it, to keep the harness off the boto Session
56+
path. If the package code starts using S3Uploader methods we have not
57+
stubbed, the next failure will say so. Subclassing is the cleaner long
58+
term fix.
59+
- No ``AWS::Include`` sentinel: the ``_export_global_artifacts_pass`` call
60+
in ``run_package_pipeline`` is exercised only indirectly. A corpus case
61+
with ``AWS::Include`` should be added so that pass has explicit
62+
coverage; deferred to follow-up.
3963
"""
4064

4165
from __future__ import annotations
4266

4367
import copy
4468
import hashlib
4569
from pathlib import Path
46-
from typing import Any, Dict, List, Optional
70+
from typing import Any, Dict, List, Optional, Tuple
4771

4872
import yaml
4973

@@ -64,9 +88,11 @@ def _load_template(template_path: Path) -> Dict[str, Any]:
6488
return yaml.safe_load(f) or {}
6589

6690

67-
def _walk_artifact_properties(template: Dict[str, Any]) -> List:
91+
def _walk_artifact_properties(
92+
template: Dict[str, Any],
93+
) -> List[Tuple[str, str, Dict[str, Any]]]:
6894
"""Collect (resource_id, property_path, resource_dict) for every packageable artifact."""
69-
results = []
95+
results: List[Tuple[str, str, Dict[str, Any]]] = []
7096
resources = template.get("Resources", {}) or {}
7197
for resource_id, resource in resources.items():
7298
if not isinstance(resource, dict):
@@ -312,28 +338,22 @@ def run_package_pipeline(
312338
) -> Dict[str, Any]:
313339
"""In-process equivalent of `sam package` for one template + build output.
314340
315-
1. Run _export_global_artifacts_pass on the original template (the pre-LE
316-
AWS::Include pass added in PR #9030).
317-
2. Walk packageable artifact properties on the build output and replace
341+
1. Walk packageable artifact properties on the build output and replace
318342
each local path with an s3://golden-bucket/<sha256> URI.
319-
3. Re-run _export_global_artifacts_pass on the result to handle any
320-
AWS::Include nested in the LE-expanded template.
321-
4. Return the final dict.
343+
2. Run _export_global_artifacts_pass on the rewritten template to
344+
handle any AWS::Include structural nodes.
345+
3. Return the final dict.
322346
"""
323347
from samcli.lib.package.artifact_exporter import _export_global_artifacts_pass
324348

325349
template_dir = str(template_path.parent)
326350
uploader = GoldenS3Uploader(template_dir)
327351

328-
# Pre-LE AWS::Include pass on the original template's structural form.
329-
original = _load_template(template_path)
330-
_export_global_artifacts_pass(original, uploader, template_dir)
331-
332352
# Walk build_output's artifact properties and rewrite local paths.
333353
pkg = copy.deepcopy(build_output)
334354
_rewrite_artifacts_to_s3(pkg, uploader, template_dir)
335355

336-
# Post-expansion AWS::Include pass to catch any remaining structural nodes.
356+
# AWS::Include pass on the rewritten template.
337357
_export_global_artifacts_pass(pkg, uploader, template_dir)
338358
return pkg
339359

@@ -353,6 +373,9 @@ def _rewrite_artifacts_to_s3(template: Dict[str, Any], uploader, template_dir: s
353373
if not isinstance(current, str):
354374
continue
355375
rtype = resource.get("Type")
376+
if not isinstance(rtype, str):
377+
# _walk_artifact_properties already filters, but re-narrow for mypy.
378+
continue
356379
replacement = _packageable_replacement(
357380
rtype, prop_path, current, template_dir, resource_id
358381
)

tests/golden/test_harness_build.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
CASES_ROOT = Path(__file__).parent / "templates"
88

99

10-
def test_build_sam_case_replaces_codeuri_with_placeholder(tmp_path):
10+
def test_build_sam_case_replaces_codeuri_with_placeholder():
1111
case = CASES_ROOT / "sam_resources" / "serverless_function_zip"
1212
result = run_build_pipeline(case / "template.yaml", language_extensions=False)
1313
func = result["Resources"]["HelloFunction"]
@@ -16,7 +16,7 @@ def test_build_sam_case_replaces_codeuri_with_placeholder(tmp_path):
1616
assert func["Properties"]["Code"] == "<<BUILT_ARTIFACT>>"
1717

1818

19-
def test_build_le_case_expands_foreach(tmp_path):
19+
def test_build_le_case_expands_foreach():
2020
case = CASES_ROOT / "language_extensions" / "foreach_static_zip"
2121
result = run_build_pipeline(case / "template.yaml", language_extensions=True)
2222
assert "AlphaFunction" in result["Resources"]

tests/golden/test_harness_package.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ def test_package_sam_case_rewrites_code_to_s3_uri():
1313
pkg_out = run_package_pipeline(case / "template.yaml", build_out)
1414
code = pkg_out["Resources"]["HelloFunction"]["Properties"]["Code"]
1515
assert isinstance(code, dict) # CFN Lambda Code becomes S3Bucket/S3Key dict
16-
s3_uri_field = code.get("S3Bucket") or code.get("ImageUri") or ""
17-
assert s3_uri_field == "golden-bucket"
16+
assert code["S3Bucket"] == "golden-bucket"
17+
assert "S3Key" in code
1818

1919

2020
def test_package_le_case_rewrites_each_expanded_codeuri():

tests/golden/update_goldens.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@
1313
# Allow direct script invocation (`python tests/golden/update_goldens.py`)
1414
# in addition to module form (`python -m tests.golden.update_goldens`).
1515
# When run as a script, Python does not auto-add the repo root to sys.path,
16-
# so the absolute `from tests.golden...` imports below would fail.
16+
# so the absolute `from tests.golden...` imports below would fail. mypy
17+
# treats the __main__ guard as always-False, hence the `type: ignore`.
1718
if __name__ == "__main__" and __package__ is None:
18-
import sys
19-
from pathlib import Path
19+
import sys # type: ignore[unreachable] # noqa: E402
20+
from pathlib import Path # noqa: E402
2021

2122
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
2223

0 commit comments

Comments
 (0)