if get delete error move to processed
This commit is contained in:
parent
d454cf1577
commit
9f55eeeecb
@ -41,6 +41,12 @@ class InputFileScanResult:
|
|||||||
skipped_files: list[RemoteFile]
|
skipped_files: list[RemoteFile]
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessedCopySucceededDeleteFailedError(RuntimeError):
|
||||||
|
def __init__(self, message: str, target_path: str) -> None:
|
||||||
|
super().__init__(message)
|
||||||
|
self.target_path = target_path
|
||||||
|
|
||||||
|
|
||||||
class SMBClientConnection:
|
class SMBClientConnection:
|
||||||
def __init__(
|
def __init__(
|
||||||
self, smb_base_path: str, user_params: dict[str, str] | None = None
|
self, smb_base_path: str, user_params: dict[str, str] | None = None
|
||||||
@ -455,11 +461,12 @@ def _samba_move_file(path_from: str, path_to: str, samba_conn) -> None:
|
|||||||
samba_conn.delete(path_from)
|
samba_conn.delete(path_from)
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
target_exists = _safe_path_exists(path_to, samba_conn)
|
target_exists = _safe_path_exists(path_to, samba_conn)
|
||||||
raise RuntimeError(
|
raise ProcessedCopySucceededDeleteFailedError(
|
||||||
"SMB move failed at delete stage after successful copy: "
|
"SMB move failed at delete stage after successful copy: "
|
||||||
f"source='{path_from}', target='{path_to}', "
|
f"source='{path_from}', target='{path_to}', "
|
||||||
f"target_exists={target_exists}, {_format_smb_exception(exc)}"
|
f"target_exists={target_exists}, {_format_smb_exception(exc)}"
|
||||||
f"{_format_rename_attempt(rename_error)}"
|
f"{_format_rename_attempt(rename_error)}",
|
||||||
|
target_path=path_to,
|
||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ from .config import (
|
|||||||
join_path,
|
join_path,
|
||||||
)
|
)
|
||||||
from .file_manager import (
|
from .file_manager import (
|
||||||
|
ProcessedCopySucceededDeleteFailedError,
|
||||||
check_dir_write_access,
|
check_dir_write_access,
|
||||||
check_input_dir_access,
|
check_input_dir_access,
|
||||||
connect_samba,
|
connect_samba,
|
||||||
@ -331,6 +332,16 @@ def _process_files(
|
|||||||
log_lines.append(
|
log_lines.append(
|
||||||
f"{_now()} | success -> processed: {remote_file.path} => {moved_to}"
|
f"{_now()} | success -> processed: {remote_file.path} => {moved_to}"
|
||||||
)
|
)
|
||||||
|
except ProcessedCopySucceededDeleteFailedError as exc:
|
||||||
|
moved_to = exc.target_path
|
||||||
|
message = (
|
||||||
|
f"{message} Файл скопирован в Processed, "
|
||||||
|
"но исходник не удален из входной папки из-за ограничений доступа."
|
||||||
|
)
|
||||||
|
log_lines.append(
|
||||||
|
f"{_now()} | success with delete warning: "
|
||||||
|
f"{remote_file.path} => {moved_to}. {exc}"
|
||||||
|
)
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
status = "partial"
|
status = "partial"
|
||||||
message = f"{message} Не удалось переместить в Processed: {exc}"
|
message = f"{message} Не удалось переместить в Processed: {exc}"
|
||||||
|
|||||||
@ -62,6 +62,14 @@ class FakeSamba:
|
|||||||
shutil.copy2(source, target)
|
shutil.copy2(source, target)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeSambaDeleteDeniedForXml(FakeSamba):
|
||||||
|
def delete(self, path: str) -> None:
|
||||||
|
normalized = path.replace("/", "\\").lower()
|
||||||
|
if normalized.endswith(".xml") and "\\test\\" in normalized:
|
||||||
|
raise PermissionError("STATUS_ACCESS_DENIED")
|
||||||
|
super().delete(path)
|
||||||
|
|
||||||
|
|
||||||
def _valid_xml() -> str:
|
def _valid_xml() -> str:
|
||||||
return """<?xml version="1.0" encoding="UTF-8"?>
|
return """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<СообщОперКО xmlns="urn:test">
|
<СообщОперКО xmlns="urn:test">
|
||||||
@ -113,3 +121,30 @@ def test_run_batch_smoke_and_idempotency(tmp_path: Path, monkeypatch) -> None:
|
|||||||
)
|
)
|
||||||
assert second.status == "success"
|
assert second.status == "success"
|
||||||
assert second.processed == 0
|
assert second.processed == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_batch_success_when_delete_denied_after_copy(
|
||||||
|
tmp_path: Path, monkeypatch
|
||||||
|
) -> None:
|
||||||
|
samba = FakeSambaDeleteDeniedForXml(tmp_path)
|
||||||
|
in_dir_local = tmp_path / "Exchange" / "SMBDEMO" / "test"
|
||||||
|
in_dir_local.mkdir(parents=True)
|
||||||
|
file_name = "SKO115FZ_01_123456789_20260616_X00001.xml"
|
||||||
|
(in_dir_local / file_name).write_text(_valid_xml(), encoding="utf-8")
|
||||||
|
|
||||||
|
from app.pipeline import service
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
service, "connect_samba", lambda smb_base_path, user_params: samba
|
||||||
|
)
|
||||||
|
|
||||||
|
result = run_batch(
|
||||||
|
smb_base_path="//test-server/share",
|
||||||
|
input_dir="Exchange\\SMBDEMO\\test",
|
||||||
|
samba_user="user",
|
||||||
|
samba_password="pass",
|
||||||
|
launcher="tester",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result.status == "success"
|
||||||
|
assert result.processed == 1
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user