Files
mizan/desktop/tests/test_system.py
Ryth Azhur c866142770 Rename djarea to mizan and fix React casing conventions
Rename the package from djarea to mizan across the entire codebase —
Python package, React library, generators, tests, and examples. Fix
JSX/hook casing (MizanProvider, useMizan, etc.) that broke when the
original PascalCase names were lowercased during the rename.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 15:41:31 -04:00

168 lines
5.8 KiB
Python

"""
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 mizanProvider does."""
url = f"{self.live_server_url}/api/mizan/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/mizan/call/ with CSRF token."""
url = f"{self.live_server_url}/api/mizan/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"], "mizan 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() / ".mizan-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)