""" REAL integration tests for desktop system RPC functions. These make actual HTTP requests to a running Django server. No RequestFactory, no mocks, no shortcuts. """ import json import os import platform from pathlib import Path from django.test import LiveServerTestCase from urllib.request import urlopen, Request class RealHTTPMixin: """Makes real HTTP requests to the live server.""" def _session_init(self): """Hit /session/ to get CSRF cookie, like DjareaProvider does.""" url = f"{self.live_server_url}/api/djarea/session/" req = Request(url) resp = urlopen(req) # Extract csrftoken from Set-Cookie header cookies = resp.headers.get_all("Set-Cookie") or [] for cookie in cookies: if "csrftoken=" in cookie: self._csrf_token = cookie.split("csrftoken=")[1].split(";")[0] self._cookies = f"csrftoken={self._csrf_token}" return self._csrf_token = None self._cookies = "" def _call(self, fn: str, args: dict | None = None): """Make a real POST to /api/djarea/call/ with CSRF token.""" url = f"{self.live_server_url}/api/djarea/call/" body = json.dumps({"fn": fn, "args": args or {}}).encode() req = Request(url, data=body, method="POST") req.add_header("Content-Type", "application/json") if self._csrf_token: req.add_header("X-CSRFToken", self._csrf_token) if self._cookies: req.add_header("Cookie", self._cookies) resp = urlopen(req) return json.loads(resp.read()) class SystemInfoTests(RealHTTPMixin, LiveServerTestCase): """system_info over real HTTP.""" def setUp(self): self._session_init() def test_system_info_returns_os_data(self): data = self._call("system_info") self.assertFalse(data["error"]) self.assertEqual(data["data"]["os_name"], platform.system()) self.assertEqual(data["data"]["hostname"], platform.node()) self.assertGreater(data["data"]["cpu_count"], 0) def test_system_info_returns_paths(self): data = self._call("system_info") self.assertFalse(data["error"]) self.assertEqual(data["data"]["home_dir"], str(Path.home())) self.assertEqual(data["data"]["cwd"], os.getcwd()) def test_disk_usage(self): data = self._call("disk_usage", {"path": "/"}) self.assertFalse(data["error"]) self.assertGreater(data["data"]["total_gb"], 0) self.assertGreater(data["data"]["free_gb"], 0) self.assertGreaterEqual(data["data"]["percent_used"], 0) self.assertLessEqual(data["data"]["percent_used"], 100) def test_app_info(self): data = self._call("app_info") self.assertFalse(data["error"]) self.assertEqual(data["data"]["app_name"], "Djarea Desktop") self.assertGreater(data["data"]["uptime_seconds"], 0) class FileSystemTests(RealHTTPMixin, LiveServerTestCase): """File system RPC over real HTTP.""" def setUp(self): self._session_init() self.test_dir = Path.home() / ".djarea-test" self.test_dir.mkdir(exist_ok=True) def tearDown(self): import shutil if self.test_dir.exists(): shutil.rmtree(self.test_dir) def test_list_files_home(self): data = self._call("list_files", {"directory": "~"}) self.assertFalse(data["error"]) self.assertEqual(data["data"]["directory"], str(Path.home())) self.assertIsInstance(data["data"]["entries"], list) def test_list_files_root_has_no_parent(self): data = self._call("list_files", {"directory": "/"}) self.assertFalse(data["error"]) self.assertIsNone(data["data"]["parent"]) def test_write_and_read_file(self): """Full round-trip over real HTTP: write, read back, verify.""" test_path = str(self.test_dir / "test-note.txt") test_content = "Hello from a REAL HTTP integration test!" # Write write_data = self._call("write_file", {"path": test_path, "content": test_content}) self.assertFalse(write_data["error"]) self.assertEqual(write_data["data"]["path"], test_path) # Read back read_data = self._call("read_file", {"path": test_path}) self.assertFalse(read_data["error"]) self.assertEqual(read_data["data"]["content"], test_content) def test_write_outside_home_rejected(self): """Server should reject writes outside home directory.""" from urllib.error import HTTPError try: data = self._call("write_file", {"path": "/tmp/escape.txt", "content": "nope"}) # If we get here, check the response has an error self.assertTrue(data["error"]) self.assertEqual(data["code"], "FORBIDDEN") except HTTPError as e: # 403 is also acceptable self.assertEqual(e.code, 403) def test_delete_file(self): test_path = str(self.test_dir / "to-delete.txt") (self.test_dir / "to-delete.txt").write_text("delete me") data = self._call("delete_file", {"path": test_path}) self.assertFalse(data["error"]) self.assertTrue(data["data"]["deleted"]) self.assertFalse(Path(test_path).exists()) def test_file_entries_have_metadata(self): (self.test_dir / "metadata-test.txt").write_text("hello") data = self._call("list_files", {"directory": str(self.test_dir)}) self.assertFalse(data["error"]) self.assertGreater(len(data["data"]["entries"]), 0) entry = data["data"]["entries"][0] self.assertIn("name", entry) self.assertIn("path", entry) self.assertIn("is_dir", entry) self.assertIn("size", entry) self.assertIn("modified", entry)