diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_server.py | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/tests/test_server.py b/tests/test_server.py index c7f93d5..3a80e80 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -10,8 +10,11 @@ import unittest from unittest.mock import patch from sailfish_devel_mcp.config import ( + AndroidBuildHostConfig, BUNDLED_BUILD_HELPER, Config, + DEFAULT_ANDROID_BUILD_PROJECT_DIR, + DEFAULT_ANDROID_BUILD_SSH_TARGET, DeviceConfig, PathConfig, load_config, @@ -69,6 +72,9 @@ class McpServerTests(unittest.TestCase): self.assertIn("sailfish_device_user_session_command", names) self.assertIn("sailfish_device_browser_launch", names) self.assertIn("sailfish_sdk_refresh_metadata", names) + self.assertIn("sailfish_android_build_hosts", names) + self.assertIn("sailfish_android_build", names) + self.assertIn("sailfish_android_build_status", names) self.assertIn("sailfish_qml_check_translator_ternaries", names) def test_qml_ternary_checker_reports_inline_ternary_qstrid(self) -> None: @@ -235,6 +241,15 @@ class McpServerTests(unittest.TestCase): self.assertIsNone(config.paths.local_sdk) self.assertTrue(config.paths.build_sailfishos.exists()) self.assertNotIn("build-sailfishos-skill", str(config.paths.build_sailfishos)) + self.assertEqual(config.default_android_build_host, "android-builder") + self.assertEqual( + config.android_build_hosts["android-builder"].ssh_target, + DEFAULT_ANDROID_BUILD_SSH_TARGET, + ) + self.assertEqual( + config.android_build_hosts["android-builder"].project_dir, + DEFAULT_ANDROID_BUILD_PROJECT_DIR, + ) def test_config_loads_local_sdk_from_paths(self) -> None: with tempfile.TemporaryDirectory() as tmp: @@ -459,6 +474,87 @@ class McpServerTests(unittest.TestCase): self.assertIn("DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/100000/dbus/user_bus_socket", remote) self.assertIn("systemctl --user status app.service", remote) + def test_device_install_rpm_keeps_single_remote_path_override(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + rpm = root / "sample.rpm" + rpm.write_text("rpm", encoding="utf-8") + server = self.make_server(root) + with patch("sailfish_devel_mcp.tools.run") as mocked_run: + mocked_run.side_effect = [ + CommandResult(("scp",), 0, "", ""), + CommandResult(("ssh",), 0, "installed\n", ""), + ] + response = server.handle( + { + "jsonrpc": "2.0", + "id": 18, + "method": "tools/call", + "params": { + "name": "sailfish_device_install_rpm", + "arguments": { + "rpm_path": str(rpm), + "remote_path": "/tmp/custom.rpm", + }, + }, + } + ) + + self.assertFalse(response["result"].get("isError", False)) + calls = [list(call.args[0]) for call in mocked_run.call_args_list] + self.assertEqual(len(calls), 2) + self.assertEqual(calls[0][-1], "root@test:/tmp/custom.rpm") + self.assertEqual(calls[1][-1], "pkcon install-local -y /tmp/custom.rpm") + self.assertEqual( + response["result"]["structuredContent"]["remote_paths"], + ["/tmp/custom.rpm"], + ) + + def test_device_install_rpm_installs_multiple_rpms_together(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + rpm_a = root / "sample.rpm" + rpm_b = root / "sample-deps.rpm" + rpm_a.write_text("rpm", encoding="utf-8") + rpm_b.write_text("rpm", encoding="utf-8") + server = self.make_server(root) + with patch("sailfish_devel_mcp.tools.run") as mocked_run: + mocked_run.side_effect = [ + CommandResult(("ssh",), 0, "", ""), + CommandResult(("scp",), 0, "", ""), + CommandResult(("scp",), 0, "", ""), + CommandResult(("ssh",), 0, "installed\n", ""), + ] + response = server.handle( + { + "jsonrpc": "2.0", + "id": 19, + "method": "tools/call", + "params": { + "name": "sailfish_device_install_rpm", + "arguments": { + "rpm_paths": [str(rpm_a), str(rpm_b)], + "remote_dir": "/tmp/test-rpms", + "installer": "rpm", + }, + }, + } + ) + + self.assertFalse(response["result"].get("isError", False)) + calls = [list(call.args[0]) for call in mocked_run.call_args_list] + self.assertEqual(calls[0][-1], "mkdir -p /tmp/test-rpms") + self.assertEqual(calls[1][-1], "root@test:/tmp/test-rpms/sample.rpm") + self.assertEqual(calls[2][-1], "root@test:/tmp/test-rpms/sample-deps.rpm") + self.assertEqual( + calls[3][-1], + "rpm -Uvh --replacepkgs /tmp/test-rpms/sample.rpm /tmp/test-rpms/sample-deps.rpm", + ) + self.assertEqual( + response["result"]["structuredContent"]["remote_paths"], + ["/tmp/test-rpms/sample.rpm", "/tmp/test-rpms/sample-deps.rpm"], + ) + def test_browser_launch_uses_display_env_and_reports_topmost_pid(self) -> None: with tempfile.TemporaryDirectory() as tmp: server = self.make_server(Path(tmp)) @@ -713,6 +809,131 @@ class McpServerTests(unittest.TestCase): self.assertIn("--arch", argv) self.assertIn("aarch64", argv) + def test_android_build_starts_remote_nohup_job(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + config = Config( + path=None, + default_device="phone", + devices={"phone": DeviceConfig(name="phone", ssh_target="root@phone")}, + paths=PathConfig(git_root=root, ssh_config=root / "ssh_config"), + default_android_build_host="android-builder", + android_build_hosts={ + "android-builder": AndroidBuildHostConfig( + name="android-builder", + ssh_target="builder@example.invalid", + project_dir="/remote/a15", + state_dir="/remote/state/android-builds", + ) + }, + ) + server = McpServer(config) + with patch("sailfish_devel_mcp.tools.run") as mocked_run: + mocked_run.return_value = CommandResult( + ("ssh",), + 0, + "job_id: android-test\npid: 1234\n", + "", + ) + response = server.handle( + { + "jsonrpc": "2.0", + "id": 16, + "method": "tools/call", + "params": { + "name": "sailfish_android_build", + "arguments": { + "job_id": "android-test", + "shell_command": "source build/envsetup.sh && m services", + }, + }, + } + ) + + self.assertFalse(response["result"].get("isError", False)) + self.assertEqual( + response["result"]["structuredContent"]["job_id"], + "android-test", + ) + argv = list(mocked_run.call_args.args[0]) + self.assertEqual(argv[:3], ["ssh", "-F", str(root / "ssh_config")]) + self.assertIn("builder@example.invalid", argv) + remote = argv[-1] + self.assertIn("nohup", remote) + self.assertIn("/remote/a15", remote) + self.assertIn("/remote/state/android-builds/android-test", remote) + self.assertIn("base64 -d", remote) + + def test_android_build_requires_configured_project_dir(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + server = self.make_server(Path(tmp)) + response = server.handle( + { + "jsonrpc": "2.0", + "id": 16, + "method": "tools/call", + "params": { + "name": "sailfish_android_build", + "arguments": { + "job_id": "android-test", + "shell_command": "source build/envsetup.sh && m services", + }, + }, + } + ) + + self.assertTrue(response["result"].get("isError", False)) + self.assertIn( + "project_dir is required", + response["result"]["content"][0]["text"], + ) + + def test_android_build_status_tails_remote_job_log(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + server = self.make_server(root) + with patch("sailfish_devel_mcp.tools.run") as mocked_run: + mocked_run.return_value = CommandResult( + ("ssh",), + 0, + "\n".join( + [ + "job_id: android-test", + "state: finished", + "returncode: 7", + "pid: 1234", + "log_path: /remote/state/android-test/build.log", + "", + "build failed", + ] + ), + "", + ) + response = server.handle( + { + "jsonrpc": "2.0", + "id": 17, + "method": "tools/call", + "params": { + "name": "sailfish_android_build_status", + "arguments": { + "job_id": "android-test", + "state_dir": "/remote/state", + "lines": 25, + }, + }, + } + ) + + self.assertTrue(response["result"].get("isError", False)) + self.assertEqual(response["result"]["structuredContent"]["returncode"], 7) + argv = list(mocked_run.call_args.args[0]) + self.assertEqual(argv[:3], ["ssh", "-F", str(root / "ssh_config")]) + self.assertIn("builder@example.invalid", argv) + remote = argv[-1] + self.assertIn("tail -n \"$lines\" \"$log_path\"", remote) + self.assertIn("lines=25", remote) + def write_fake_target( self, root: Path, |
