From 18297dd550ff63ac248fecb3a6e2e2befafe5d18 Mon Sep 17 00:00:00 2001 From: demo-bot Date: Sun, 9 Aug 2026 15:10:49 +0000 Subject: [PATCH] decomposer: generate files for Create a production-suitable Dockerfile and minimal Docker Compose configuration for packaging and running the completed FastAPI endpoint monitoring service. --- tests/test_containerizer.py | 61 +++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tests/test_containerizer.py diff --git a/tests/test_containerizer.py b/tests/test_containerizer.py new file mode 100644 index 0000000..6c0697d --- /dev/null +++ b/tests/test_containerizer.py @@ -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()