SFM/tests/smoke/test_batch_smoke.py
Raykov-MS 7b90daa396 Remove SMB entirely, switch input to attached zip, add self-service token popover
- Drop SMB/SAMBA subsystem completely: app/samba_access.py, app/path_settings.py,
  app/path_store.py, app/pipeline/file_manager.py and their tests, plus the
  smbprotocol dependency and all related UI (login/password fields, path editor,
  SMB diagnostics) in main.py.
- run_batch now takes a .zip attached via Streamlit's file_uploader (same as the
  local dev tool) instead of reading from SMB or a fictitious OpenCloud "Attach"
  folder; renamed from run_local_zip_batch since it's now the single canonical
  batch entrypoint used by both main.py and scripts/local_zip_test_app.py.
- Fixed run number resolution: added next_opencloud_run_number() which lists the
  Out/year/month/day folder via WebDAV PROPFIND, so repeated runs land in
  incrementing subfolders instead of always overwriting "1".
- Added a self-service "Добавить токен" popover in main.py so users can link
  their own OpenCloud App Token to their Keycloak account (opencloud_token_store)
  without an admin running the CLI script; reworded the missing-token error to
  point at it.
2026-09-17 15:34:53 +03:00

188 lines
5.4 KiB
Python

from __future__ import annotations
import zipfile
from pathlib import Path
from app.pipeline import service
from app.pipeline.service import run_batch
def _valid_xml() -> str:
return """<?xml version="1.0" encoding="UTF-8"?>
<СообщОперКО xmlns="urn:test">
<СлужЧасть><ИдФайл>ID1</ИдФайл></СлужЧасть>
<ИнформЧасть>
<СведКО>
<Операция>
<ИдентификаторЗаписи>OP1</ИдентификаторЗаписи>
<УчастникОп><Тип>01</Тип></УчастникОп>
</Операция>
</СведКО>
</ИнформЧасть>
</СообщОперКО>
"""
def _fake_opencloud_upload(
local_path: Path, space_id, folder_segments, file_name, username, token
) -> str:
assert local_path.exists()
return f"https://opencloud.test/{'/'.join(folder_segments)}/{file_name}"
def _fake_resolve_personal_drive_id(username, token) -> str:
_ = (username, token)
return "personal-space-1"
def _fake_ensure_opencloud_folder(space_id, folder_segments, username, token) -> None:
_ = (space_id, folder_segments, username, token)
def _fake_next_opencloud_run_number(
space_id, day_folder_segments, username, token
) -> int:
_ = (space_id, day_folder_segments, username, token)
return 1
def _patch_opencloud(monkeypatch) -> None:
monkeypatch.setattr(
service, "upload_local_file_to_opencloud", _fake_opencloud_upload
)
monkeypatch.setattr(
service, "resolve_personal_drive_id", _fake_resolve_personal_drive_id
)
monkeypatch.setattr(
service, "ensure_opencloud_folder", _fake_ensure_opencloud_folder
)
monkeypatch.setattr(
service, "next_opencloud_run_number", _fake_next_opencloud_run_number
)
def test_run_batch_uses_run_number_from_opencloud(tmp_path: Path, monkeypatch) -> None:
_patch_opencloud(monkeypatch)
monkeypatch.setattr(service, "next_opencloud_run_number", lambda *args, **kwargs: 3)
zip_path = tmp_path / "batch.zip"
with zipfile.ZipFile(zip_path, "w") as archive:
archive.writestr("SKO115FZ_01_123456789_20260616_X00001.xml", _valid_xml())
result = run_batch(
zip_path=zip_path,
launcher="tester",
opencloud_username="test-user",
opencloud_access_token="token-123",
)
assert result.status == "success"
assert "/3/" in result.report_path
assert "_3.xlsx" in result.report_path
def test_run_batch_success(tmp_path: Path, monkeypatch) -> None:
_patch_opencloud(monkeypatch)
zip_path = tmp_path / "batch.zip"
with zipfile.ZipFile(zip_path, "w") as archive:
archive.writestr("SKO115FZ_01_123456789_20260616_X00001.xml", _valid_xml())
result = run_batch(
zip_path=zip_path,
launcher="tester",
opencloud_username="test-user",
opencloud_access_token="token-123",
)
assert result.status == "success"
assert result.processed == 1
assert result.errors == 0
assert result.report_path
assert result.protocol_path
assert result.log_path
def test_run_batch_bad_file_name_is_error(tmp_path: Path, monkeypatch) -> None:
_patch_opencloud(monkeypatch)
zip_path = tmp_path / "batch.zip"
with zipfile.ZipFile(zip_path, "w") as archive:
archive.writestr("bad_name.xml", _valid_xml())
result = run_batch(
zip_path=zip_path,
launcher="tester",
opencloud_username="test-user",
opencloud_access_token="token-123",
)
assert result.status == "error"
assert result.processed == 0
assert result.errors == 1
def test_run_batch_empty_archive(tmp_path: Path, monkeypatch) -> None:
_patch_opencloud(monkeypatch)
zip_path = tmp_path / "empty.zip"
with zipfile.ZipFile(zip_path, "w") as archive:
archive.writestr("readme.txt", "no xml here")
result = run_batch(
zip_path=zip_path,
launcher="tester",
opencloud_username="test-user",
opencloud_access_token="token-123",
)
assert result.status == "success"
assert result.processed == 0
def test_run_batch_missing_token(tmp_path: Path) -> None:
zip_path = tmp_path / "batch.zip"
with zipfile.ZipFile(zip_path, "w") as archive:
archive.writestr("SKO115FZ_01_123456789_20260616_X00001.xml", _valid_xml())
result = run_batch(
zip_path=zip_path,
launcher="tester",
opencloud_username="test-user",
opencloud_access_token="",
)
assert result.status == "error"
assert not result.report_path
def test_run_batch_missing_username(tmp_path: Path) -> None:
zip_path = tmp_path / "batch.zip"
with zipfile.ZipFile(zip_path, "w") as archive:
archive.writestr("SKO115FZ_01_123456789_20260616_X00001.xml", _valid_xml())
result = run_batch(
zip_path=zip_path,
launcher="tester",
opencloud_username="",
opencloud_access_token="token-123",
)
assert result.status == "error"
assert not result.report_path
def test_run_batch_bad_zip_file(tmp_path: Path) -> None:
zip_path = tmp_path / "not_a_zip.zip"
zip_path.write_bytes(b"this is not a zip file")
result = run_batch(
zip_path=zip_path,
launcher="tester",
opencloud_username="test-user",
opencloud_access_token="token-123",
)
assert result.status == "error"
assert any("распаковать" in message for message in result.messages)