Files
ABAP-Indexing/tests/test_search_logic.py
T

97 lines
4.2 KiB
Python

"""/search/logic, /chunks/{id}, /programs/{name}/chunks — 로직 조각 검색·조회 API."""
from __future__ import annotations
import pytest
from fastapi.testclient import TestClient
from config.settings import settings
import summarize.runner as runner
PAYLOAD = {
"MAIN_PROGRAM": "ZLOGIC_T1",
"DESCRIPTION": "로직 검색 테스트",
"INCLUDE_PROGRAM": [{
"INCLUDE": "ZLOGIC_T1",
"SOURCE_CODE": (
"REPORT zlogic_t1.\n"
"START-OF-SELECTION.\n"
" PERFORM get_gr.\n"
"FORM get_gr.\n"
" SELECT mblnr FROM mseg INTO TABLE gt_mseg WHERE bwart = '101'.\n"
" SORT gt_mseg BY mblnr.\n"
"ENDFORM."
),
}],
}
class StubLLM:
usage = {"calls": 0, "prompt_tokens": 0, "completion_tokens": 0, "cost_usd": 0.0}
def complete_json(self, system: str, user: str) -> dict:
if "[작업] program_summary" in user:
return {"program": "x", "business_purpose_ko": "구매오더 입고 자재문서 조회", "confidence": 0.8}
if "name: GET_GR" in user:
return {"unit_purpose_ko": "입고 자재문서 조회", "chunks": [{
"line_start": 5, "line_end": 6, "first_line": "SELECT mblnr FROM mseg INTO TABLE gt_mseg WHERE bwart = '101'.",
"kind": "sql_select", "purpose_ko": "이동유형 101(입고) 자재문서를 MSEG 에서 조회",
"purpose_en": "Read goods receipt material documents (movement type 101) from MSEG",
"keywords_ko": ["입고", "자재문서", "이동유형 101"], "keywords_en": ["goods receipt", "GR"],
"sap_objects": ["MSEG", "BWART"], "confidence": 0.9}]}
return {"unit_purpose_ko": "요약", "chunks": []}
@pytest.fixture()
def client(tmp_path, monkeypatch):
import query.api as api
monkeypatch.setattr(settings, "database_url", f"sqlite:///{tmp_path / 'index.db'}")
monkeypatch.setattr(settings, "data_normalized", tmp_path / "normalized")
monkeypatch.setattr(settings, "data_parsed", tmp_path / "parsed")
monkeypatch.setattr(settings, "llm_base_url", "")
monkeypatch.setattr(runner, "create_llm", lambda fake=False, **kw: StubLLM())
c = TestClient(api.app)
assert c.post("/ingest", json=PAYLOAD).json()["status"] == "loaded"
runner.summarize_units("ZLOGIC_T1", None, fake=False, dry_run=False, trigger="test")
return c
def test_search_logic_groups_by_program(client):
r = client.get("/search/logic", params={"q": "입고 처리하는 로직"}).json()
assert r["total"] >= 1
g = r["programs"][0]
assert g["program"] == "ZLOGIC_T1"
assert g["purpose"].startswith("구매오더 입고")
c = g["chunks"][0]
assert c["unit"] == "GET_GR" and c["kind"] == "sql_select"
assert (c["line_start"], c["line_end"]) == (5, 6)
assert c["tables_read"] == ["MSEG"]
# 영어 · 객체명으로도 맞는다
assert client.get("/search/logic", params={"q": "goods receipt"}).json()["total"] >= 1
assert client.get("/search/logic", params={"q": "MSEG"}).json()["total"] >= 1
assert client.get("/search/logic", params={"q": "MSEG", "kind": "db_write"}).json()["total"] == 0
def test_chunk_code_and_program_chunks(client):
from urllib.parse import quote
chunk_id = client.get("/search/logic", params={"q": "입고"}).json()["programs"][0]["chunks"][0]["chunk_id"]
r = client.get(f"/chunks/{quote(chunk_id, safe='')}").json() # chunk_id 의 '#' 은 URL 인코딩 필요
assert r["code"].startswith(" SELECT mblnr FROM mseg")
assert r["unit_lines"] == "4-7"
assert client.get("/chunks/NOPE#C9").status_code == 404
lst = client.get("/programs/ZLOGIC_T1/chunks").json()["chunks"]
assert len(lst) == 1 and lst[0]["chunk_id"] == chunk_id
s = client.get("/programs/ZLOGIC_T1/summary").json()
assert s["structure"]["logic_chunks"][0]["chunk_id"] == chunk_id
assert s["summary"]["business_purpose_ko"].startswith("구매오더")
u = client.get("/programs/ZLOGIC_T1/units/GET_GR/code").json()
assert u["chunks"][0]["chunk_id"] == chunk_id
assert client.get("/health").json()["logic_chunks"] == 1
st = client.get("/summaries/status").json()
assert st["programs"][0]["chunks"] == 1 and st["programs"][0]["program_summary"] == "done"