import pytest @pytest.mark.anyio async def test_metadata_export_returns_core_tables(api_client) -> None: response = await api_client.get("/api/exports/metadata") assert response.status_code == 200 payload = response.json() assert "exported_at" in payload assert "users" in payload["data"] assert "directories" in payload["data"] assert "backends" in payload["data"] assert isinstance(payload["data"]["users"], list) @pytest.mark.anyio async def test_metadata_validate_reports_invalid_snapshot(api_client) -> None: response = await api_client.post( "/api/exports/metadata/validate", json={"data": {"users": [], "directories": []}}, ) assert response.status_code == 200 payload = response.json() assert payload["ok"] is False assert any("root directory" in issue for issue in payload["issues"]) @pytest.mark.anyio async def test_restore_plan_returns_validation_token_for_valid_snapshot(api_client) -> None: export_response = await api_client.get("/api/exports/metadata") snapshot = export_response.json()["data"] response = await api_client.post( "/api/exports/metadata/restore-plan", json={"data": snapshot}, ) assert response.status_code == 200 payload = response.json() assert payload["ok"] is True assert payload["validation_token"] assert payload["summary"]["users"] >= 1 @pytest.mark.anyio async def test_metadata_integrity_reports_ok_for_clean_runtime(api_client) -> None: response = await api_client.get("/api/exports/metadata/integrity") assert response.status_code == 200 assert response.json()["ok"] is True assert response.json()["issues"] == [] @pytest.mark.anyio async def test_metadata_import_restores_exported_snapshot(api_client, raw_api_client) -> None: export_response = await api_client.get("/api/exports/metadata") assert export_response.status_code == 200 snapshot = export_response.json()["data"] plan_response = await api_client.post( "/api/exports/metadata/restore-plan", json={"data": snapshot}, ) validation_token = plan_response.json()["validation_token"] import_response = await api_client.post( "/api/exports/metadata/import", json={"data": snapshot, "confirm_replace": True, "validation_token": validation_token}, ) assert import_response.status_code == 200 assert "users" in import_response.json()["imported_tables"] assert "reconcile_all_files" in import_response.json()["scheduled_jobs"] login_response = await raw_api_client.post( "/api/auth/login", json={"username": "admin", "password": "changeme-iron"}, ) assert login_response.status_code == 200 @pytest.mark.anyio async def test_metadata_import_rejects_invalid_snapshot(api_client) -> None: response = await api_client.post( "/api/exports/metadata/import", json={"data": {"users": [], "directories": []}, "confirm_replace": True, "validation_token": "bad"}, ) assert response.status_code == 400 assert response.json()["error"]["code"] == "validation_error" @pytest.mark.anyio async def test_metadata_import_requires_explicit_confirmation(api_client) -> None: export_response = await api_client.get("/api/exports/metadata") snapshot = export_response.json()["data"] response = await api_client.post( "/api/exports/metadata/import", json={"data": snapshot}, ) assert response.status_code == 400 assert response.json()["error"]["code"] == "validation_error" @pytest.mark.anyio async def test_metadata_import_requires_current_validation_token(api_client) -> None: export_response = await api_client.get("/api/exports/metadata") snapshot = export_response.json()["data"] response = await api_client.post( "/api/exports/metadata/import", json={"data": snapshot, "confirm_replace": True, "validation_token": "stale-token"}, ) assert response.status_code == 400 assert response.json()["error"]["code"] == "validation_error"