Coverage for .github / scripts / verify_inference_streaming_bundle_freshness.py: 100.00%

57 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-09-14 22:07 +0000

1#!/usr/bin/env python3 

2"""CI-only regression for the real ignored inference streaming bundle. 

3 

4The check deliberately damages ``lambda/inference-streaming-proxy-build`` and 

5then enters the production ``StackManager.synth`` and ``StackManager.diff`` 

6paths. Only ``_run_cdk`` is mocked, so no CDK process runs during this check; 

7the real pinned npm builder must repair the real ignored asset both times. 

8""" 

9 

10from __future__ import annotations 

11 

12import json 

13import subprocess 

14import sys 

15from pathlib import Path 

16from unittest.mock import patch 

17 

18_PROJECT_ROOT = Path(__file__).resolve().parents[2] 

19sys.path.insert(0, str(_PROJECT_ROOT)) 

20 

21from cli.stacks import StackManager # noqa: E402 

22 

23_PACKAGE_FILES = ("index.mjs", "package.json", "package-lock.json") 

24 

25 

26def _dependency_markers(source_dir: Path, build_dir: Path) -> tuple[Path, ...]: 

27 package_data = json.loads((source_dir / "package.json").read_text(encoding="utf-8")) 

28 dependencies = package_data.get("dependencies") 

29 if not isinstance(dependencies, dict) or not dependencies: 

30 raise AssertionError("Inference streaming package has no production dependencies") 

31 return tuple( 

32 build_dir / "node_modules" / name / "package.json" for name in sorted(dependencies) 

33 ) 

34 

35 

36def _transitive_dependency_file(source_dir: Path, build_dir: Path) -> Path: 

37 package_data = json.loads((source_dir / "package.json").read_text(encoding="utf-8")) 

38 direct_dependencies = set(package_data.get("dependencies", {})) 

39 for marker in sorted((build_dir / "node_modules").rglob("package.json")): 

40 relative = marker.relative_to(build_dir / "node_modules") 

41 if len(relative.parts) < 2: 

42 continue 

43 package_name = ( 

44 "/".join(relative.parts[:2]) if relative.parts[0].startswith("@") else relative.parts[0] 

45 ) 

46 if package_name not in direct_dependencies: 

47 return marker 

48 raise AssertionError("Inference streaming bundle has no transitive dependency marker") 

49 

50 

51def _assert_fresh(manager: StackManager, source_dir: Path, build_dir: Path) -> None: 

52 if not manager._inference_streaming_build_is_fresh(source_dir, build_dir): 

53 raise AssertionError("Inference streaming bundle is not source-current") 

54 for name in _PACKAGE_FILES: 

55 if (build_dir / name).read_bytes() != (source_dir / name).read_bytes(): 

56 raise AssertionError(f"Inference streaming bundle did not restore {name}") 

57 for marker in _dependency_markers(source_dir, build_dir): 

58 if not marker.is_file(): 

59 raise AssertionError( 

60 f"Inference streaming bundle did not restore dependency marker {marker}" 

61 ) 

62 

63 

64def main() -> None: 

65 project_root = _PROJECT_ROOT 

66 source_dir = project_root / "lambda" / "inference-streaming-proxy" 

67 build_dir = project_root / "lambda" / "inference-streaming-proxy-build" 

68 manager = object.__new__(StackManager) 

69 manager.project_root = project_root 

70 

71 _assert_fresh(manager, source_dir, build_dir) 

72 

73 stale_handler = (source_dir / "index.mjs").read_bytes() + b"\n// deliberate CI staleness\n" 

74 (build_dir / "index.mjs").write_bytes(stale_handler) 

75 if manager._inference_streaming_build_is_fresh(source_dir, build_dir): 

76 raise AssertionError("Changed handler bytes were incorrectly accepted as fresh") 

77 

78 synth_result = subprocess.CompletedProcess( 

79 args=["cdk", "synth"], 

80 returncode=0, 

81 stdout="mocked synth", 

82 stderr="", 

83 ) 

84 with patch.object(manager, "_run_cdk", return_value=synth_result) as run_cdk: 

85 if manager.synth("gco-api-gateway") != "mocked synth": 

86 raise AssertionError("Unexpected mocked synth result") 

87 run_cdk.assert_called_once_with( 

88 ["synth", "gco-api-gateway", "--quiet"], capture_output=True 

89 ) 

90 _assert_fresh(manager, source_dir, build_dir) 

91 

92 transitive_marker = _transitive_dependency_file(source_dir, build_dir) 

93 transitive_relative = transitive_marker.relative_to(build_dir) 

94 transitive_marker.unlink() 

95 if manager._inference_streaming_build_is_fresh(source_dir, build_dir): 

96 raise AssertionError( 

97 f"Missing transitive dependency file was accepted as fresh: {transitive_relative}" 

98 ) 

99 

100 diff_result = subprocess.CompletedProcess( 

101 args=["cdk", "diff"], 

102 returncode=1, 

103 stdout="", 

104 stderr="mocked diff", 

105 ) 

106 with patch.object(manager, "_run_cdk", return_value=diff_result) as run_cdk: 

107 if manager.diff("gco-api-gateway") != "mocked diff": 

108 raise AssertionError("Unexpected mocked diff result") 

109 run_cdk.assert_called_once_with( 

110 ["diff", "--no-color", "gco-api-gateway"], capture_output=True 

111 ) 

112 _assert_fresh(manager, source_dir, build_dir) 

113 if not (build_dir / transitive_relative).is_file(): 

114 raise AssertionError(f"Inference streaming bundle did not restore {transitive_relative}") 

115 

116 print("Real inference streaming bundle freshness verified for synth and diff") 

117 

118 

119if __name__ == "__main__": 

120 main()