decomposer: generate files for Create a production-suitable Dockerfile and minimal Docker Compose configuration for packaging and running the completed FastAPI endpoint monitoring service.
This commit is contained in:
61
tests/test_containerizer.py
Normal file
61
tests/test_containerizer.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from containerizer import containerize
|
||||||
|
|
||||||
|
|
||||||
|
class ContainerizerTests(unittest.TestCase):
|
||||||
|
def service(self, health=True):
|
||||||
|
temp = tempfile.TemporaryDirectory()
|
||||||
|
root = Path(temp.name)
|
||||||
|
(root / "app").mkdir()
|
||||||
|
route = '@app.get("/health")\n' if health else ""
|
||||||
|
(root / "app/main.py").write_text(
|
||||||
|
"from fastapi import FastAPI\napp = FastAPI()\n" + route)
|
||||||
|
(root / "requirements.lock").write_text("fastapi==0.115.6\nuvicorn==0.34.0\n")
|
||||||
|
return temp, root
|
||||||
|
|
||||||
|
def payload(self, health="/health"):
|
||||||
|
return {
|
||||||
|
"service_specification": {"container": {
|
||||||
|
"startup_module": "app.main:app", "port": 8000,
|
||||||
|
"health_endpoint": health}},
|
||||||
|
"target_management_implementation": {"preserved": 1},
|
||||||
|
"endpoint_check_implementation": {"preserved": 2},
|
||||||
|
"current_status_implementation": {"preserved": 3},
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_writes_artifacts_and_preserves_contract(self):
|
||||||
|
temp, root = self.service()
|
||||||
|
self.addCleanup(temp.cleanup)
|
||||||
|
output = containerize(self.payload(), root)
|
||||||
|
self.assertEqual(output["target_management_implementation"], {"preserved": 1})
|
||||||
|
self.assertEqual(set(output["container_artifacts"]["files"]),
|
||||||
|
{"Dockerfile", "compose.yaml", ".dockerignore"})
|
||||||
|
self.assertIn("USER 10001:10001", (root / "Dockerfile").read_text())
|
||||||
|
self.assertIn('uvicorn", "app.main:app', (root / "Dockerfile").read_text())
|
||||||
|
self.assertIn("healthcheck:", (root / "compose.yaml").read_text())
|
||||||
|
|
||||||
|
def test_omits_healthcheck_without_matching_configuration(self):
|
||||||
|
temp, root = self.service(health=False)
|
||||||
|
self.addCleanup(temp.cleanup)
|
||||||
|
containerize(self.payload(health=None), root)
|
||||||
|
self.assertNotIn("healthcheck:", (root / "compose.yaml").read_text())
|
||||||
|
|
||||||
|
def test_rejects_healthcheck_not_present_in_app(self):
|
||||||
|
temp, root = self.service(health=False)
|
||||||
|
self.addCleanup(temp.cleanup)
|
||||||
|
with self.assertRaisesRegex(ValueError, "not found"):
|
||||||
|
containerize(self.payload(), root)
|
||||||
|
|
||||||
|
def test_rejects_unpinned_dependencies(self):
|
||||||
|
temp, root = self.service()
|
||||||
|
self.addCleanup(temp.cleanup)
|
||||||
|
(root / "requirements.lock").write_text("fastapi>=0.100\n")
|
||||||
|
with self.assertRaisesRegex(ValueError, "exact"):
|
||||||
|
containerize(self.payload(), root)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user