mirror of
https://github.com/hpd840321/starRiverProperty.git
synced 2026-06-09 16:30:29 +08:00
Initial commit: reorganized source tree
- backend/: 13 Maven modules (cw-elevator-application, cloudwalk-cloud, intelligent-cwoscomponent, ninca-crk, etc.) - frontend/: 4 Vue projects (elevator-front, cwos-portal, alarm-front, front_acs) + decompiled + scripts - scripts/: build, test-env, tools (Docker Compose, service templates, API parity) - docs/: AGENTS.md, superpowers specs, architecture docs - .gitignore: standard Java/Maven exclusions Moved from legacy maven-*/ root layout to backend/ organized structure.
This commit is contained in:
+58
@@ -0,0 +1,58 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from parity.body_variants import iter_parity_request_cases
|
||||
from parity.catalog_loader import include_in_parity as cb_parity
|
||||
from parity.catalog_loader import load as load_catalog
|
||||
from parity.client import call_both
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("two_instances_ready")
|
||||
@pytest.mark.live
|
||||
def test_parity_from_catalog(
|
||||
request,
|
||||
base_old,
|
||||
base_new,
|
||||
session_http,
|
||||
):
|
||||
"""按 api_catalog 双端对拍(仅 ``include_in_parity`` 为 true 的条目)。
|
||||
|
||||
基线体 + 可选 ``boundary_patches``(需 ``ELEVATOR_PARITY_BOUNDARY=1``)对入参做边界/范围扩展。
|
||||
compare_mode: deep | code_only | status_only
|
||||
"""
|
||||
cat = load_catalog()["endpoints"] # type: ignore[operator]
|
||||
for ep in cat:
|
||||
if not cb_parity(ep):
|
||||
continue
|
||||
name = ep["id"]
|
||||
display = ep.get("name", name)
|
||||
for case_id, body in iter_parity_request_cases(ep):
|
||||
case_label = f"{name}:{case_id}" if case_id != "default" else name
|
||||
call_name = f"{display} [{case_id}]" if case_id != "default" else display
|
||||
pr = call_both(
|
||||
name=call_name,
|
||||
method=ep.get("method", "POST"),
|
||||
path=ep["path"],
|
||||
body=body,
|
||||
base_old=base_old,
|
||||
base_new=base_new,
|
||||
session=session_http,
|
||||
compare_mode=ep.get("compare_mode", "code_only"),
|
||||
)
|
||||
row = {
|
||||
"id": case_label,
|
||||
"name": call_name,
|
||||
"case_id": case_id,
|
||||
"method": pr.method,
|
||||
"path": pr.path,
|
||||
"old_status": pr.old_status,
|
||||
"new_status": pr.new_status,
|
||||
"match": pr.match,
|
||||
"message": pr.message,
|
||||
}
|
||||
request.config._parity_rows.append(row) # type: ignore
|
||||
assert pr.match, (
|
||||
f"{case_label} mismatch: {pr.message}\n"
|
||||
f"old_http={pr.old_status} new_http={pr.new_status}\n"
|
||||
f"old_head={pr.old_text[:500]!r}\nnew_head={pr.new_text[:500]!r}"
|
||||
)
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
from __future__ import annotations
|
||||
|
||||
"""全 catalog 双端对拍(仅 include_in_parity=true 的条目,与 test_parity_from_catalog 范围一致,但每接口独立用例)。"""
|
||||
|
||||
import pytest
|
||||
from parity.catalog_loader import endpoint_body as cb_body
|
||||
from parity.catalog_loader import include_in_parity as cb_parity
|
||||
from parity.catalog_loader import load as load_catalog
|
||||
from parity.client import call_both
|
||||
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
if "catalog_ep" not in metafunc.fixturenames:
|
||||
return
|
||||
cat_all = list((load_catalog() or {}).get("endpoints") or [])
|
||||
# 与 test_parity_from_catalog 对齐:全 catalog 用例同样尊重 include_in_parity
|
||||
cat = [ep for ep in cat_all if cb_parity(ep)]
|
||||
ids = [str(ep.get("id", i)) for i, ep in enumerate(cat)]
|
||||
metafunc.parametrize("catalog_ep", cat, ids=ids)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("two_instances_ready")
|
||||
@pytest.mark.live
|
||||
def test_parity_single_endpoint(
|
||||
request,
|
||||
base_old,
|
||||
base_new,
|
||||
session_http,
|
||||
catalog_ep: dict,
|
||||
):
|
||||
name = catalog_ep["id"]
|
||||
body = cb_body(catalog_ep)
|
||||
pr = call_both(
|
||||
name=catalog_ep.get("name", name),
|
||||
method=catalog_ep.get("method", "POST"),
|
||||
path=catalog_ep["path"],
|
||||
body=body,
|
||||
base_old=base_old,
|
||||
base_new=base_new,
|
||||
session=session_http,
|
||||
compare_mode=catalog_ep.get("compare_mode", "code_only"),
|
||||
)
|
||||
row = {
|
||||
"id": name,
|
||||
"name": catalog_ep.get("name", name),
|
||||
"method": pr.method,
|
||||
"path": pr.path,
|
||||
"old_status": pr.old_status,
|
||||
"new_status": pr.new_status,
|
||||
"match": pr.match,
|
||||
"message": pr.message,
|
||||
}
|
||||
request.config._parity_rows.append(row) # type: ignore
|
||||
assert pr.match, (
|
||||
f"{name} mismatch: {pr.message}\n"
|
||||
f"old_http={pr.old_status} new_http={pr.new_status}\n"
|
||||
f"old_head={pr.old_text[:500]!r}\nnew_head={pr.new_text[:500]!r}"
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from parity.catalog_loader import endpoint_body as cb_body
|
||||
from parity.catalog_loader import include_in_smoke as cb_smoke
|
||||
from parity.catalog_loader import load as load_catalog
|
||||
from parity.client import call_single
|
||||
|
||||
"""单机按 catalog 逐接口 POST/GET,写入 _smoke_rows(sessionfinish 落盘)。"""
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("smoke_instance_ready")
|
||||
@pytest.mark.smoke
|
||||
def test_smoke_from_catalog(request, smoke_base, smoke_label, session_http):
|
||||
cat = load_catalog()["endpoints"]
|
||||
for ep in cat:
|
||||
if not cb_smoke(ep):
|
||||
continue
|
||||
name = ep["id"]
|
||||
body = cb_body(ep)
|
||||
row = call_single(
|
||||
name=ep.get("name", name),
|
||||
method=ep.get("method", "POST"),
|
||||
path=ep["path"],
|
||||
body=body,
|
||||
base_url=smoke_base,
|
||||
session=session_http,
|
||||
)
|
||||
row["id"] = name
|
||||
row["label"] = smoke_label
|
||||
request.config._smoke_rows.append(row) # type: ignore
|
||||
@@ -0,0 +1,41 @@
|
||||
"""不依赖联调机:纯比较逻辑自测。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from parity import compare as C
|
||||
from parity import body_variants as BV
|
||||
|
||||
|
||||
def test_normalize_equal():
|
||||
a = {"b": 2, "a": 1, "c": {"z": 1, "y": 2}}
|
||||
b = {"c": {"y": 2, "z": 1}, "a": 1, "b": 2}
|
||||
assert C.normalize(a) == C.normalize(b)
|
||||
|
||||
|
||||
def test_business_code_from_cloudwalk_result():
|
||||
j = '{"code":"0","data":{}}'
|
||||
p = C.parse_json_loose(j)
|
||||
assert C.business_code(p) == "0"
|
||||
|
||||
|
||||
def test_deep_merge_nested():
|
||||
base = {"a": 1, "nested": {"x": 1, "y": 2}}
|
||||
patch = {"nested": {"y": 99}, "b": 2}
|
||||
m = BV.deep_merge(base, patch)
|
||||
assert m == {"a": 1, "b": 2, "nested": {"x": 1, "y": 99}}
|
||||
|
||||
|
||||
def test_iter_parity_request_cases_respects_env(monkeypatch):
|
||||
monkeypatch.delenv("ELEVATOR_PARITY_BOUNDARY", raising=False)
|
||||
ep = {
|
||||
"id": "x",
|
||||
"body": {"p": 1},
|
||||
"boundary_patches": [{"id": "zero", "patch": {"p": 0}}],
|
||||
}
|
||||
cases = list(BV.iter_parity_request_cases(ep))
|
||||
assert cases == [("default", {"p": 1})]
|
||||
|
||||
monkeypatch.setenv("ELEVATOR_PARITY_BOUNDARY", "1")
|
||||
cases2 = list(BV.iter_parity_request_cases(ep))
|
||||
assert cases2[0] == ("default", {"p": 1})
|
||||
assert cases2[1] == ("zero", {"p": 0})
|
||||
Reference in New Issue
Block a user