chore: remainder — backend test infra, agent config, docker, i18n, frontend ui

- Backend: alembic env, config manager/models, dependencies, translate plugin
- Backend tests: async_sync_regression, integration tests, git services, test_agent
- Docker: docker-compose.yml updates
- Agent: qa-tester.md update, semantics-testing SKILL.md update
- Frontend: TopNavbar, sidebarNavigation, FeaturesSettings, FeatureGate
- i18n: assistant.json en/ru locale updates
- New: frontend/src/lib/components/agent/ directory
This commit is contained in:
2026-06-10 15:06:36 +03:00
parent 2b303f92b3
commit 143f14d516
34 changed files with 5693 additions and 178 deletions

View File

@@ -0,0 +1,192 @@
# #region TestAgentChat.DocumentParser [C:2] [TYPE Module] [SEMANTICS test,agent,document,parser]
# @BRIEF Tests for document parser — PDF, XLSX, unsupported formats, empty files, errors.
# @RELATION BINDS_TO -> [AgentChat.Document.Parser]
import sys
from pathlib import Path
sys.path.append(str(Path(__file__).parent.parent.parent / "src"))
import os
import tempfile
import pytest
from src.agent.document_parser import parse_pdf, parse_xlsx, parse_upload, ParseError
# #region TestAgentChat.DocumentParser.PDF [C:2] [TYPE Function] [SEMANTICS test,parser,pdf]
# @BRIEF PDF parsing: extracts text from valid PDF, handles empty and encrypted PDFs gracefully.
def test_parse_pdf_valid():
"""Parse a valid PDF and verify text extraction."""
# Create a minimal valid PDF
pdf_content = (
b"%PDF-1.4\n"
b"1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj\n"
b"2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj\n"
b"3 0 obj<</Type/Page/Parent 2 0 R/MediaBox[0 0 612 792]"
b"/Contents 4 0 R/Resources<</Font<</F1 5 0 R>>>>>>endobj\n"
b"4 0 obj<</Length 44>>stream\n"
b"BT /F1 12 Tf 100 700 Td (Hello PDF) Tj ET\n"
b"endstream\nendobj\n"
b"5 0 obj<</Type/Font/Subtype/Type1/BaseFont/Helvetica>>endobj\n"
b"xref\n"
b"0 6\n"
b"trailer<</Size 6/Root 1 0 R>>\n"
b"startxref\n"
b"169\n"
b"%%EOF"
)
with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as f:
f.write(pdf_content)
tmp_path = f.name
try:
result = parse_pdf(tmp_path)
assert isinstance(result, str)
assert "Hello" in result
finally:
os.unlink(tmp_path)
def test_parse_pdf_empty():
"""Empty/non-existent PDF file raises ParseError."""
with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as f:
f.write(b"")
tmp_path = f.name
try:
with pytest.raises(ParseError):
parse_pdf(tmp_path)
finally:
os.unlink(tmp_path)
def test_parse_pdf_nonexistent():
"""Non-existent PDF file raises ParseError."""
with pytest.raises((ParseError, FileNotFoundError)):
parse_pdf("/tmp/nonexistent_file_12345.pdf")
# #endregion TestAgentChat.DocumentParser.PDF
# #region TestAgentChat.DocumentParser.XLSX [C:2] [TYPE Function] [SEMANTICS test,parser,xlsx]
# @BRIEF XLSX parsing: extracts sheet names and cell data.
def test_parse_xlsx_valid():
"""Parse a valid XLSX and verify sheet+cell extraction."""
import openpyxl
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Sheet1"
ws["A1"] = "Name"
ws["B1"] = "Value"
ws["A2"] = "Test"
ws["B2"] = 42
with tempfile.NamedTemporaryFile(suffix=".xlsx", delete=False) as f:
wb.save(f.name)
tmp_path = f.name
try:
result = parse_xlsx(tmp_path)
assert isinstance(result, str)
assert "Sheet1" in result
assert "Name" in result
assert "Value" in result
assert "Test" in result
assert "42" in result
finally:
os.unlink(tmp_path)
def test_parse_xlsx_empty_sheet():
"""XLSX with empty sheet returns headers but no data rows."""
import openpyxl
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "EmptySheet"
with tempfile.NamedTemporaryFile(suffix=".xlsx", delete=False) as f:
wb.save(f.name)
tmp_path = f.name
try:
result = parse_xlsx(tmp_path)
assert isinstance(result, str)
assert "EmptySheet" in result
finally:
os.unlink(tmp_path)
def test_parse_xlsx_not_excel():
"""Non-XLSX file raises ParseError."""
with tempfile.NamedTemporaryFile(suffix=".xlsx", delete=False) as f:
f.write(b"not an excel file")
tmp_path = f.name
try:
with pytest.raises(ParseError):
parse_xlsx(tmp_path)
finally:
os.unlink(tmp_path)
# #endregion TestAgentChat.DocumentParser.XLSX
# #region TestAgentChat.DocumentParser.ParseUpload [C:2] [TYPE Function] [SEMANTICS test,parser,upload]
# @BRIEF parse_upload dispatches to correct parser based on extension. Unsupported → error.
def test_parse_upload_txt():
"""Parse a .txt file returns its content."""
with tempfile.NamedTemporaryFile(suffix=".txt", mode="w", delete=False) as f:
f.write("Hello, world!")
tmp_path = f.name
try:
result = parse_upload(tmp_path)
assert "Hello" in result
finally:
os.unlink(tmp_path)
def test_parse_upload_json():
"""Parse a .json file returns its text."""
with tempfile.NamedTemporaryFile(suffix=".json", mode="w", delete=False) as f:
f.write('{"key": "value"}')
tmp_path = f.name
try:
result = parse_upload(tmp_path)
assert "key" in result
finally:
os.unlink(tmp_path)
def test_parse_upload_unsupported():
"""Unsupported format raises ParseError."""
with tempfile.NamedTemporaryFile(suffix=".exe", delete=False) as f:
f.write(b"binary")
tmp_path = f.name
try:
with pytest.raises(ParseError, match="Unsupported format"):
parse_upload(tmp_path)
finally:
os.unlink(tmp_path)
def test_parse_upload_dict():
"""parse_upload accepts dict with name+path (Gradio file format)."""
with tempfile.NamedTemporaryFile(suffix=".txt", mode="w", delete=False) as f:
f.write("Dict test")
tmp_path = f.name
try:
result = parse_upload({"name": "test.txt", "path": tmp_path})
assert "Dict test" in result
finally:
os.unlink(tmp_path)
# #endregion TestAgentChat.DocumentParser.ParseUpload
# #endregion TestAgentChat.DocumentParser