Files
llm/tests/1c/test_audit_1c_adapter_coverage.py
T

223 lines
8.7 KiB
Python

from __future__ import annotations
import json
import sys
from pathlib import Path
from typing import Any
import pytest
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
import scripts.audit_1c_adapter_coverage as coverage # noqa: E402
def test_record_ref_from_public_reference_value() -> None:
ref = "0123456789ABCDEF0123456789ABCDEF"
assert coverage.record_ref_from_row({"ref": ref}) == ref
assert coverage.record_ref_from_row({"ref": {"type": "reference", "hex": ref}}) == ref
assert coverage.record_ref_from_row({"period": "2026-01-01"}) is None
def test_audit_data_kind_runs_complete_read_chain() -> None:
calls: list[tuple[str, dict[str, Any]]] = []
ref = "0123456789ABCDEF0123456789ABCDEF"
def fake_rpc(_url: str, _token: str, method: str, payload: dict[str, Any], _timeout: float) -> dict[str, Any]:
calls.append((method, payload))
responses = {
"metadata.objects.list": {"status": "ok", "objects": [{"kind": "Catalog", "name": "Товары", "ref": "Catalog.Товары"}]},
"data.schema": {"status": "ok", "table": {"name": "_Reference1"}, "fields": [{"name": "ref"}]},
"data.list": {"status": "ok", "rows": [{"ref": {"type": "reference", "hex": ref}}]},
"data.count": {"status": "ok", "count": 7},
"data.get": {"status": "ok", "rows": [{"ref": ref}]},
}
return responses[method]
result = coverage.audit_data_kind(
"http://adapter",
"upo_test",
"secret",
"Catalog",
10,
True,
fake_rpc,
)
assert result["status"] == "ok"
assert [method for method, _ in calls] == [
"metadata.objects.list",
"data.schema",
"data.list",
"data.count",
"data.get",
]
assert calls[-1][1]["record_ref"] == ref
assert result["operations"]["data.count"]["count"] == 7
def test_audit_data_kind_marks_get_not_applicable_for_register_row() -> None:
def fake_rpc(_url: str, _token: str, method: str, _payload: dict[str, Any], _timeout: float) -> dict[str, Any]:
responses = {
"metadata.objects.list": {"status": "ok", "objects": [{"kind": "InformationRegister", "name": "Курсы"}]},
"data.schema": {"status": "ok", "table": {"name": "_InfoRg1"}, "fields": [{"name": "period"}]},
"data.list": {"status": "ok", "rows": [{"period": "2026-01-01"}]},
"data.count": {"status": "ok", "count": 1},
}
return responses[method]
result = coverage.audit_data_kind(
"http://adapter", "upo_test", "secret", "InformationRegister", 10, True, fake_rpc
)
assert result["status"] == "ok"
assert result["operations"]["data.get"] == {
"status": "not_applicable",
"reason": "object_has_no_reference_key",
"duration_ms": 0,
}
def test_audit_data_kind_does_not_mark_get_not_applicable_when_list_failed() -> None:
def fake_rpc(_url: str, _token: str, method: str, _payload: dict[str, Any], _timeout: float) -> dict[str, Any]:
responses = {
"metadata.objects.list": {"status": "ok", "objects": [{"kind": "Document", "name": "Продажа"}]},
"data.schema": {"status": "ok", "table": {"name": "_Document1"}, "fields": [{"name": "ref"}]},
"data.list": {"status": "transport_error", "diagnostics": {"message": "timed out"}},
"data.count": {"status": "ok", "count": 3},
}
return responses[method]
result = coverage.audit_data_kind(
"http://adapter", "upo_test", "secret", "Document", 10, True, fake_rpc
)
assert result["status"] == "degraded"
assert result["operations"]["data.get"]["status"] == "blocked"
assert result["operations"]["data.get"]["reason"] == "data_list_failed"
def test_run_data_checks_saves_and_resumes_checkpoint(tmp_path: Path) -> None:
checkpoint = tmp_path / "coverage.checkpoint.json"
calls: list[str] = []
def fake_rpc(_url: str, _token: str, method: str, payload: dict[str, Any], _timeout: float) -> dict[str, Any]:
calls.append(f"{method}:{payload.get('kind', '')}")
if method == "metadata.objects.list":
return {"status": "ok", "objects": [{"kind": payload["kind"], "name": payload["kind"]}]}
if method == "data.schema":
return {"status": "ok", "table": {"name": "_Data1"}, "fields": []}
raise AssertionError(method)
first, resumed = coverage.run_data_checks(
"http://adapter", "upo_test", "secret", ["Catalog", "Document"], 10, False, 2, checkpoint, False, False, fake_rpc
)
assert resumed == 0
assert set(first) == {"Catalog", "Document"}
saved = json.loads(checkpoint.read_text(encoding="utf-8"))
assert saved["include_reads"] is False
assert set(saved["checks"]) == {"Catalog", "Document"}
calls.clear()
second, resumed = coverage.run_data_checks(
"http://adapter", "upo_test", "secret", ["Catalog", "Document"], 10, False, 2, checkpoint, True, False, fake_rpc
)
assert resumed == 2
assert second == first
assert calls == []
def test_run_data_checks_can_retry_only_degraded_entries(tmp_path: Path) -> None:
checkpoint = tmp_path / "coverage.checkpoint.json"
checkpoint.write_text(
json.dumps(
{
"schema": "onec_adapter_data_audit_checkpoint.v1",
"base_url": "http://adapter",
"base_id": "upo_test",
"include_reads": False,
"checks": {
"Catalog": {"kind": "Catalog", "status": "ok"},
"Document": {"kind": "Document", "status": "degraded"},
},
}
),
encoding="utf-8",
)
calls: list[str] = []
def fake_rpc(_url: str, _token: str, method: str, payload: dict[str, Any], _timeout: float) -> dict[str, Any]:
calls.append(method)
if method == "metadata.objects.list":
return {"status": "ok", "objects": [{"kind": payload["kind"], "name": "Продажа"}]}
if method == "data.schema":
return {"status": "ok", "table": {"name": "_Document1"}, "fields": []}
raise AssertionError(method)
checks, resumed = coverage.run_data_checks(
"http://adapter", "upo_test", "secret", ["Catalog", "Document"], 10, False, 1, checkpoint, True, True, fake_rpc
)
assert resumed == 1
assert checks["Catalog"]["status"] == "ok"
assert checks["Document"]["status"] == "ok"
assert calls == ["metadata.objects.list", "data.schema"]
def test_checkpoint_rejects_schema_only_resume_for_full_reads(tmp_path: Path) -> None:
checkpoint = tmp_path / "coverage.checkpoint.json"
checkpoint.write_text(
json.dumps(
{
"schema": "onec_adapter_data_audit_checkpoint.v1",
"base_url": "http://adapter",
"base_id": "upo_test",
"include_reads": False,
"checks": {},
}
),
encoding="utf-8",
)
with pytest.raises(ValueError, match="another data audit mode"):
coverage.load_checkpoint(checkpoint, "http://adapter", "upo_test", True, True)
def test_build_report_does_not_treat_unchecked_non_data_kind_as_list_failure() -> None:
def fake_rpc(_url: str, _token: str, method: str, payload: dict[str, Any], _timeout: float) -> dict[str, Any]:
if method == "metadata.adapter.audit":
return {
"status": "ok",
"optional_deep_reads": [
{"kind": "DocumentJournal", "property": "column_types", "flag": "include_column_types=true"}
],
"metadata_kinds": [
{"kind": "Catalog", "kind_ru": "Справочник", "count": 1, "capabilities": ["list"]},
{"kind": "CommonModule", "kind_ru": "ОбщийМодуль", "count": 1, "capabilities": ["list"]},
],
}
if method == "metadata.objects.list":
return {"status": "ok", "objects": [{"kind": payload["kind"], "name": "Товары"}]}
if method == "data.schema":
return {"status": "ok", "table": {"name": "_Reference1"}, "fields": []}
raise AssertionError(method)
report = coverage.build_report(
"http://adapter",
"upo_test",
"secret",
10,
True,
True,
workers=1,
rpc_call=fake_rpc,
)
assert report["status"] == "ok"
assert report["list_failures"] == []
assert report["counts"]["data_kinds_checked"] == 1
assert report["optional_deep_reads"][0]["property"] == "column_types"
common_module = next(row for row in report["matrix"] if row["kind"] == "CommonModule")
assert "list_status" not in common_module