import importlib import importlib.util from pathlib import Path from fastapi.testclient import TestClient def load_app_module(): try: return importlib.import_module("app") except ModuleNotFoundError: app_path = Path("/app/app.py") spec = importlib.util.spec_from_file_location("app", app_path) if spec is None or spec.loader is None: raise mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod def test_files_read_not_found_detail_string(tmp_path, monkeypatch): app_mod = load_app_module() workloads = tmp_path / "workloads" workloads.mkdir() monkeypatch.setattr(app_mod, "WORKLOADS_DIR", str(workloads)) client = TestClient(app_mod.app) r = client.get("/files/read", params={"path": "systemd/nope.txt"}) assert r.status_code == 404 assert r.json()["detail"] == "Not found" def test_files_read_is_directory_detail_string(tmp_path, monkeypatch): app_mod = load_app_module() workloads = tmp_path / "workloads" (workloads / "systemd").mkdir(parents=True) monkeypatch.setattr(app_mod, "WORKLOADS_DIR", str(workloads)) client = TestClient(app_mod.app) r = client.get("/files/read", params={"path": "systemd"}) assert r.status_code == 403 assert r.json()["detail"] == "Is a directory" def test_files_delete_directory_error_string(tmp_path, monkeypatch): app_mod = load_app_module() workloads = tmp_path / "workloads" (workloads / "systemd").mkdir(parents=True) monkeypatch.setattr(app_mod, "WORKLOADS_DIR", str(workloads)) client = TestClient(app_mod.app) r = client.delete("/files/delete", params={"path": "systemd"}) assert r.status_code == 400 assert r.json()["detail"] == "Kan niet verwijderen: is directory" def test_files_mkdir_prefix_systemd_and_keyset(tmp_path, monkeypatch): app_mod = load_app_module() workloads = tmp_path / "workloads" workloads.mkdir() monkeypatch.setattr(app_mod, "WORKLOADS_DIR", str(workloads)) client = TestClient(app_mod.app) r = client.post("/files/mkdir", params={"path": "abc"}) assert r.status_code == 200 body = r.json() assert set(body.keys()) == {"status", "path"} assert body["path"] == "systemd/abc" def test_files_rmdir_refuse_root_detail_string(tmp_path, monkeypatch): app_mod = load_app_module() workloads = tmp_path / "workloads" workloads.mkdir() monkeypatch.setattr(app_mod, "WORKLOADS_DIR", str(workloads)) client = TestClient(app_mod.app) r = client.delete("/files/rmdir", params={"path": "systemd"}) assert r.status_code == 400 assert r.json()["detail"] == "Refusing to delete systemd root" def test_files_rmdir_only_systemd_subtree_detail_string(tmp_path, monkeypatch): app_mod = load_app_module() workloads = tmp_path / "workloads" workloads.mkdir() monkeypatch.setattr(app_mod, "WORKLOADS_DIR", str(workloads)) client = TestClient(app_mod.app) r = client.delete("/files/rmdir", params={"path": "not_systemd/x"}) assert r.status_code == 400 assert r.json()["detail"] == "Only systemd subtree is allowed" def test_files_rmdir_nonempty_409_detail_shape_exact(tmp_path, monkeypatch): app_mod = load_app_module() workloads = tmp_path / "workloads" d = workloads / "systemd" / "dir1" d.mkdir(parents=True) (d / "a.txt").write_text("x", encoding="utf-8") monkeypatch.setattr(app_mod, "WORKLOADS_DIR", str(workloads)) client = TestClient(app_mod.app) r = client.delete("/files/rmdir", params={"path": "systemd/dir1"}) assert r.status_code == 409 body = r.json() assert set(body.keys()) == {"detail"} detail = body["detail"] assert set(detail.keys()) == {"error", "dirs", "files"} assert detail["error"] == "directory not empty" assert "a.txt" in detail["files"] def test_files_safe_join_forbidden_path_detail_string(tmp_path, monkeypatch): app_mod = load_app_module() workloads = tmp_path / "workloads" workloads.mkdir() monkeypatch.setattr(app_mod, "WORKLOADS_DIR", str(workloads)) client = TestClient(app_mod.app) r = client.get("/files/read", params={"path": "../escape.txt"}) assert r.status_code == 403 assert r.json()["detail"] == "Forbidden path"