from __future__ import annotations from pathlib import Path from unittest.mock import Mock, patch import pytest import requests from app.opencloud_access import ( OpenCloudDriveResolutionError, OpenCloudUploadError, build_opencloud_url, resolve_personal_drive, upload_local_file_to_opencloud, ) def test_build_opencloud_url_encodes_cyrillic_and_spaces() -> None: url = build_opencloud_url( space_id="storage123$space456", folder_segments=("Райков М.С.",), file_name="report 2026.xlsx", ) assert url == ( "https://docs.raisa.go.rshbank.ru/dav/spaces/storage123$space456/" "%D0%A0%D0%B0%D0%B9%D0%BA%D0%BE%D0%B2%20%D0%9C.%D0%A1./" "report%202026.xlsx" ) def test_build_opencloud_url_without_folder() -> None: url = build_opencloud_url( space_id="abc", folder_segments=(), file_name="report.xlsx" ) assert url == "https://docs.raisa.go.rshbank.ru/dav/spaces/abc/report.xlsx" def test_build_opencloud_url_requires_space_id() -> None: with pytest.raises(OpenCloudUploadError): build_opencloud_url(space_id="", folder_segments=(), file_name="report.xlsx") def test_upload_local_file_to_opencloud_success(tmp_path: Path) -> None: local_file = tmp_path / "report.xlsx" local_file.write_bytes(b"fake-xlsx-bytes") fake_response = Mock(status_code=201, text="") with patch("app.opencloud_access.requests.put", return_value=fake_response) as put: url = upload_local_file_to_opencloud( local_file, space_id="abc$def", folder_segments=("Райков М.С.",), file_name="report.xlsx", access_token="token-123", ) assert url.endswith("/report.xlsx") _, kwargs = put.call_args assert kwargs["headers"]["Authorization"] == "Bearer token-123" def test_upload_local_file_to_opencloud_missing_token(tmp_path: Path) -> None: local_file = tmp_path / "report.xlsx" local_file.write_bytes(b"data") with pytest.raises(OpenCloudUploadError): upload_local_file_to_opencloud( local_file, space_id="abc", folder_segments=(), file_name="report.xlsx", access_token="", ) def test_upload_local_file_to_opencloud_missing_local_file(tmp_path: Path) -> None: missing_file = tmp_path / "does-not-exist.xlsx" with pytest.raises(OpenCloudUploadError): upload_local_file_to_opencloud( missing_file, space_id="abc", folder_segments=(), file_name="report.xlsx", access_token="token-123", ) def test_upload_local_file_to_opencloud_http_error(tmp_path: Path) -> None: local_file = tmp_path / "report.xlsx" local_file.write_bytes(b"data") fake_response = Mock(status_code=401, text="Unauthorized") with patch("app.opencloud_access.requests.put", return_value=fake_response): with pytest.raises(OpenCloudUploadError): upload_local_file_to_opencloud( local_file, space_id="abc", folder_segments=(), file_name="report.xlsx", access_token="token-123", ) def test_resolve_personal_drive_success() -> None: fake_response = Mock( status_code=200, json=lambda: { "value": [ {"driveType": "project", "id": "irrelevant$irrelevant"}, { "driveType": "personal", "id": "storage123$space456", "root": { "webDavUrl": "https://example.test/dav/spaces/storage123$space456" }, }, ] }, ) with patch("app.opencloud_access.requests.get", return_value=fake_response) as get: drive = resolve_personal_drive("token-123") assert drive == { "id": "storage123$space456", "web_dav_url": "https://example.test/dav/spaces/storage123$space456", } _, kwargs = get.call_args assert kwargs["headers"]["Authorization"] == "Bearer token-123" def test_resolve_personal_drive_missing_token() -> None: with pytest.raises(OpenCloudDriveResolutionError): resolve_personal_drive("") def test_resolve_personal_drive_unauthorized() -> None: fake_response = Mock(status_code=401, text="Unauthorized") with patch("app.opencloud_access.requests.get", return_value=fake_response): with pytest.raises(OpenCloudDriveResolutionError): resolve_personal_drive("token-123") def test_resolve_personal_drive_no_personal_drive_found() -> None: fake_response = Mock( status_code=200, json=lambda: {"value": [{"driveType": "project", "id": "abc$def"}]}, ) with patch("app.opencloud_access.requests.get", return_value=fake_response): with pytest.raises(OpenCloudDriveResolutionError): resolve_personal_drive("token-123") def test_resolve_personal_drive_network_error() -> None: with patch( "app.opencloud_access.requests.get", side_effect=requests.RequestException("boom"), ): with pytest.raises(OpenCloudDriveResolutionError): resolve_personal_drive("token-123")