163 lines
6.1 KiB
Python
163 lines
6.1 KiB
Python
"""Ссылки на результат обработки: на файл -> на папку запуска.
|
||
|
||
Ссылка на папку запуска собирается по пути в формате адресной строки
|
||
веб-интерфейса OpenCloud и есть всегда, поэтому без ссылки пользователь не
|
||
останется, а обработка из-за ссылок не падает.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from pathlib import Path
|
||
from unittest.mock import Mock
|
||
|
||
import requests
|
||
|
||
from app import opencloud_access
|
||
from app.opencloud_access import OpenCloudUploadResult
|
||
from app.pipeline import service
|
||
from app.pipeline.config import build_date_parts
|
||
from app.pipeline.service import BatchResult, run_batch
|
||
from main import _result_links
|
||
from tests.smoke.test_batch_smoke import _patch_opencloud, _valid_xml
|
||
|
||
WEB_SPACE = "https://docs.raisa.go.rshbank.ru/files/spaces/personal"
|
||
|
||
|
||
def _loose_xml(tmp_path: Path) -> Path:
|
||
path = tmp_path / "SKO115FZ_01_123456789_20260616_X00001.xml"
|
||
path.write_text(_valid_xml(), encoding="utf-8")
|
||
return path
|
||
|
||
|
||
def _run(tmp_path: Path):
|
||
return run_batch(
|
||
input_paths=[_loose_xml(tmp_path)],
|
||
launcher="tester",
|
||
opencloud_username="test-user",
|
||
opencloud_access_token="token-123",
|
||
)
|
||
|
||
|
||
def _run_folder_path() -> str:
|
||
year, month, day, _ = build_date_parts()
|
||
return f"Out/{year}/{month}/{day}/1"
|
||
|
||
|
||
def test_links_open_files_and_run_folder_in_web_ui(tmp_path: Path, monkeypatch) -> None:
|
||
_patch_opencloud(monkeypatch)
|
||
folder_requests: list[str] = []
|
||
|
||
def _folder_file_id(dav_url, username, token):
|
||
folder_requests.append(dav_url)
|
||
return "store$space!folder"
|
||
|
||
monkeypatch.setattr(service, "resolve_opencloud_file_id", _folder_file_id)
|
||
|
||
result = _run(tmp_path)
|
||
|
||
assert result.status == "success"
|
||
assert result.report_url.startswith("https://opencloud.test/f/")
|
||
assert result.report_url.endswith(".xlsx")
|
||
assert result.protocol_url.startswith("https://opencloud.test/f/")
|
||
assert result.log_url.endswith(".log")
|
||
# Формат — как в адресной строке интерфейса: путь + fileId папки.
|
||
assert result.folder_url == (
|
||
f"{WEB_SPACE}/test-user/{_run_folder_path()}" "?fileId=store%24space%21folder"
|
||
)
|
||
# fileId запрашивается именно для папки запуска Out/год/месяц/день/номер.
|
||
assert folder_requests == [
|
||
f"https://docs.raisa.go.rshbank.ru/dav/spaces/personal-space-1/"
|
||
f"{_run_folder_path()}"
|
||
]
|
||
# WebDAV-адреса остаются для протокола и отладки.
|
||
assert "/Out/" in result.report_path
|
||
assert not any("веб-интерфейсе" in message for message in result.messages)
|
||
|
||
|
||
def test_file_without_link_falls_back_to_run_folder(
|
||
tmp_path: Path, monkeypatch
|
||
) -> None:
|
||
_patch_opencloud(monkeypatch)
|
||
|
||
def _upload_without_link(
|
||
local_path, space_id, folder_segments, file_name, username, token
|
||
):
|
||
return OpenCloudUploadResult(dav_url=f"https://dav.test/{file_name}")
|
||
|
||
monkeypatch.setattr(service, "upload_local_file_to_opencloud", _upload_without_link)
|
||
|
||
result = _run(tmp_path)
|
||
|
||
assert result.status == "success"
|
||
assert result.folder_url.startswith(f"{WEB_SPACE}/test-user/Out/")
|
||
assert result.report_url == result.folder_url
|
||
assert result.protocol_url == result.folder_url
|
||
assert result.log_url == result.folder_url
|
||
assert any("веб-интерфейсе" in message for message in result.messages)
|
||
|
||
|
||
def test_nothing_resolved_still_gives_run_folder_link(
|
||
tmp_path: Path, monkeypatch
|
||
) -> None:
|
||
"""Сквозной сценарий на уровне requests: в ответе на PUT нет OC-FileId,
|
||
PROPFIND за ссылками падает, Graph API не вернул driveAlias — обработка
|
||
успешна, все кнопки ведут в папку запуска (путь из логина, без fileId)."""
|
||
calls: list[tuple[str, str]] = []
|
||
|
||
def _get(url, **kwargs):
|
||
return Mock(
|
||
status_code=200,
|
||
json=lambda: {"value": [{"id": "s$p", "driveType": "personal"}]},
|
||
)
|
||
|
||
def _request(method, url, **kwargs):
|
||
depth = kwargs.get("headers", {}).get("Depth")
|
||
calls.append((method, depth))
|
||
if method == "PROPFIND" and depth == "1":
|
||
return Mock(status_code=404, text="")
|
||
if method == "MKCOL":
|
||
return Mock(status_code=201, text="")
|
||
raise requests.ConnectionError("PROPFIND за ссылкой не прошёл")
|
||
|
||
def _put(url, **kwargs):
|
||
return Mock(status_code=201, text="", headers={})
|
||
|
||
monkeypatch.setattr(opencloud_access.requests, "get", _get)
|
||
monkeypatch.setattr(opencloud_access.requests, "request", _request)
|
||
monkeypatch.setattr(opencloud_access.requests, "put", _put)
|
||
|
||
result = _run(tmp_path)
|
||
|
||
assert result.status == "success"
|
||
assert result.folder_url == f"{WEB_SPACE}/test-user/{_run_folder_path()}"
|
||
assert result.report_url == result.folder_url
|
||
assert result.protocol_url == result.folder_url
|
||
assert result.log_url == result.folder_url
|
||
assert result.report_path.startswith(
|
||
"https://docs.raisa.go.rshbank.ru/dav/spaces/s$p/Out/"
|
||
)
|
||
# Три файла без OC-FileId + папка запуска: по одному PROPFIND (Depth: 0).
|
||
assert calls.count(("PROPFIND", "0")) == 4
|
||
|
||
|
||
def test_result_link_buttons_skip_missing_addresses() -> None:
|
||
result = BatchResult(
|
||
status="success",
|
||
processed=1,
|
||
partial=0,
|
||
errors=0,
|
||
report_path="dav-report",
|
||
protocol_path="dav-protocol",
|
||
log_path="dav-log",
|
||
report_url="https://x/f/1",
|
||
protocol_url="https://x/f/2",
|
||
log_url="",
|
||
folder_url="https://x/f/3",
|
||
)
|
||
|
||
assert _result_links(result) == [
|
||
("Открыть отчёт", "https://x/f/1"),
|
||
("Протокол", "https://x/f/2"),
|
||
("Папка с результатами", "https://x/f/3"),
|
||
]
|