import unittest import sys from pathlib import Path from unittest import mock # Allow imports from ca_core (same pattern as existing tests) code_path = Path(__file__).parent.parent / "ca_core" sys.path.insert(0, str(code_path)) from ca_core.crypto.zenroom_client import ZenroomDockerClient, ZenroomError class TestZenroomDockerClient(unittest.TestCase): def _fake_completed(self, returncode=0, stdout="", stderr=""): cp = mock.Mock() cp.returncode = returncode cp.stdout = stdout cp.stderr = stderr return cp @mock.patch("crypto.zenroom_client.subprocess.run") def test_run_builds_expected_docker_command(self, m_run): m_run.return_value = self._fake_completed(stdout='{"ok": true}') client = ZenroomDockerClient(image="zenroom/zenroom:latest") # Patch temp dir so we can assert paths deterministically with mock.patch("crypto.zenroom_client.tempfile.TemporaryDirectory") as m_td: m_td.return_value.__enter__.return_value = "/tmp/zenroom_test" m_td.return_value.__exit__.return_value = False res = client.run("print('hi')", data={"a": 1}, keys={"k": "v"}, conf={"c": 2}) self.assertEqual(res, {"ok": True}) args, kwargs = m_run.call_args cmd = args[0] self.assertIn("docker", cmd[0]) self.assertIn("run", cmd) self.assertIn("zenroom/zenroom:latest", cmd) # Mount and workdir self.assertIn("-v", cmd) self.assertIn("/tmp/zenroom_test:/work", cmd) self.assertIn("-w", cmd) self.assertIn("/work", cmd) # Zenroom base args self.assertIn("zenroom", cmd) self.assertIn("-z", cmd) # Input files flags should be present self.assertIn("-a", cmd) self.assertIn("/work/data.json", cmd) self.assertIn("-k", cmd) self.assertIn("/work/keys.json", cmd) self.assertIn("-c", cmd) self.assertIn("/work/conf.json", cmd) # Script at end self.assertEqual(cmd[-1], "/work/script.zen") # subprocess.run called with capture_output/text self.assertTrue(kwargs.get("capture_output")) self.assertTrue(kwargs.get("text")) @mock.patch("crypto.zenroom_client.subprocess.run") def test_run_returns_raw_stdout_when_not_json(self, m_run): m_run.return_value = self._fake_completed(stdout="hello") client = ZenroomDockerClient() with mock.patch("crypto.zenroom_client.tempfile.TemporaryDirectory") as m_td: m_td.return_value.__enter__.return_value = "/tmp/zenroom_test" m_td.return_value.__exit__.return_value = False out = client.run("print('hi')") self.assertEqual(out, "hello") @mock.patch("crypto.zenroom_client.subprocess.run") def test_run_raises_on_nonzero_exit(self, m_run): m_run.return_value = self._fake_completed(returncode=1, stderr="boom") client = ZenroomDockerClient() with mock.patch("crypto.zenroom_client.tempfile.TemporaryDirectory") as m_td: m_td.return_value.__enter__.return_value = "/tmp/zenroom_test" m_td.return_value.__exit__.return_value = False with self.assertRaises(ZenroomError) as ctx: client.run("print('hi')") self.assertIn("boom", str(ctx.exception)) def test_run_requires_non_empty_script(self): client = ZenroomDockerClient() with self.assertRaises(ValueError): client.run(" ")