sap_client: ZAA_ICF JSON 규약 대응 (2026-09-14 XML→JSON 전환)

- 요청은 INPUT 래퍼 없이 입력 필드만, 응답은 JSON {"RETURN","RESULT"}. 첫 글자로 asXML 구버전도 자동 판별
- 실측: ZMP_ICF 에서 ZFI01 목록 177건, 프로그램 2본(include 10, T코드 2) 수집 → normalize 정상
- sap/README.md 규약 갱신, tests: JSON/XML 파서·요청 본문 검증

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
byeongwook.choi
2026-09-21 14:41:14 +09:00
co-authored by Claude Fable 5.1
parent 921b8ce229
commit e23140b7af
3 changed files with 87 additions and 4 deletions
+38
View File
@@ -111,3 +111,41 @@ def test_dry_run_writes_nothing(tmp_path, sap):
stats = from_sap.run(["ZFI01"], tmp_path, dry_run=True)
assert stats["listed"] == 2 and stats["fetched"] == 0
assert list(tmp_path.iterdir()) == []
def test_sap_client_parses_json_and_xml_responses():
from sap.sap_client import parse_response
js = parse_response('{"RETURN":{"TYPE":"W","MESSAGE":"잘림","TOTAL_ROWS":177},"RESULT":[{"OBJ_NAME":"ZFI0000"}],"INCLUDE_LIST":[]}'.encode("utf-8"))
assert js["error"] is None and js["return"] == {"type": "W", "message": "잘림"}
assert js["parsed"]["RESULT"][0]["OBJ_NAME"] == "ZFI0000" and js["parsed"]["INCLUDE_LIST"] == []
xml = parse_response(b'\xef\xbb\xbf<?xml version="1.0" encoding="utf-16"?><asx:abap xmlns:asx="x"><asx:values><DATA>'
b'<RETURN><TYPE>S</TYPE><MESSAGE/></RETURN><RESULT/></DATA></asx:values></asx:abap>')
assert xml["error"] is None and xml["return"]["type"] == "S" and xml["parsed"]["RESULT"] == []
bad = parse_response(b"<html>login</html>")
assert bad["return"]["type"] == "X"
def test_sap_call_sends_fields_without_wrapper(monkeypatch):
import sap.sap_client as client
captured = {}
class _Resp:
status = 200
def __enter__(self): return self
def __exit__(self, *a): return False
def read(self): return b'{"RETURN":{"TYPE":"S","MESSAGE":"","TOTAL_ROWS":0},"RESULT":[]}'
def fake_urlopen(req, context=None, timeout=None):
captured["body"] = json.loads(req.data.decode("utf-8"))
captured["url"] = req.full_url
return _Resp()
monkeypatch.setattr(client.urllib.request, "urlopen", fake_urlopen)
res = client.sap_call("GET_PROGRAM_LIST", {"IV_PACKAGE": "ZFI01", "IV_PATTERN": "", "IV_MAX_ROWS": 5})
assert captured["body"] == {"IV_PACKAGE": "ZFI01", "IV_MAX_ROWS": 5} # 래퍼 없음, 빈 값 제외, 숫자 유지
assert captured["url"].endswith("/GET_PROGRAM_LIST")
assert res["return"]["type"] == "S" and res["parsed"]["RESULT"] == []