92 lines
4.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding:utf-8 -*-
"""P1 项目隔离 E2E批次落项目归属 + 跨项目不可见 + 平台级本机构可见 + 存量归平台级。"""
import asyncio, json, os, sys, time
W="/d/pipeline/pipeline-app"; os.chdir(W); sys.path.insert(0,W)
from appPublic.folderUtils import ProgramPath
from appPublic.jsonConfig import getConfig
from appPublic.event_dispatcher import EventDispatcher
from sqlor.dbpools import DBPools
from ahserver.serverenv import ServerEnv
from ahserver.globalEnv import initEnv
p=ProgramPath(); c=getConfig(W,{"workdir":W,"ProgramPath":p}); DBPools(c.databases)
se=ServerEnv(); se.event_dispatcher=EventDispatcher(); se.get_module_dbname=lambda m:"pipeline"
initEnv()
PID_A=os.environ.get("P1_PROJECT_ID","")
FAIL=[]
def check(n,cond,d=""):
print("[%s] %s %s"%("OK " if cond else "FAIL",n,str(d)[:180]))
if not cond: FAIL.append(n)
async def m():
from pipeline_opportunity import opp_ability
ab=opp_ability.register_opp_ability()
# 找同机构的第二个商机项目做跨项目测试
async with DBPools().sqlorContext("pipeline") as sor:
r=await sor.sqlExe("SELECT id FROM sd_projects WHERE pipeline_id='opportunity_general' AND id<>${a}$ LIMIT 1",{"a":PID_A})
await sor.sqlExe("COMMIT",{})
PID_B=r[0].id if r else ""
print("项目A:",PID_A,"项目B:",PID_B or "(无第二项目,跳过跨项目实测)")
ctxA={"project_id":PID_A,"user_id":"user-01","org_id":"0","pipeline_id":"opportunity_general",
"space":"opportunity_general","session_id":"e2e-proj","workspace_dir":"/tmp"}
async def call(t,p_,ctx):
async with DBPools().sqlorContext("pipeline") as sor:
return await ab.handlers[t](sor,p_,ctx)
# 1. 项目A启动 targeted 批次(小数据快)
out=await call("opp_start_mining",{"scope":"targeted","keyword":"公众号","days":3650},ctxA)
check("A项目启动",out.startswith("OK:"),out[:100])
bid=out.split("batch_id=")[1].split("")[0]
t0=time.time()
while time.time()-t0<300:
d=json.loads(await call("opp_mining_status",{"batch_id":bid},ctxA))
if d.get("status") in ("done","failed"): break
await asyncio.sleep(10)
check("批次done",d.get("status")=="done",d.get("status")+" "+str(d.get("error_msg"))[:80])
# 2. 落库 project_id 验证
async with DBPools().sqlorContext("pipeline") as sor:
r=await sor.sqlExe("SELECT project_id FROM opp_mining_batches WHERE id=${b}$",{"b":bid})
await sor.sqlExe("COMMIT",{})
check("批次落项目A",str(r[0].project_id or "")==PID_A,r[0].project_id)
# 3. 项目B查A的批次 → 拒绝
if PID_B:
ctxB=dict(ctxA); ctxB["project_id"]=PID_B
s=await call("opp_mining_status",{"batch_id":bid},ctxB)
check("跨项目查批次被拒",s.startswith("ERROR:") and "其他项目" in s,s[:120])
s2=await call("opp_list_clusters",{"batch_id":bid},ctxB)
check("跨项目查类别被拒",s2.startswith("ERROR:"),s2[:120])
# B 的列表不含 A 的批次
lst=json.loads(await call("opp_mining_status",{},ctxB))
ids=[x["id"] for x in (lst if isinstance(lst,list) else [])]
check("B列表不含A批次",bid not in ids,ids[:5])
# 4. A 的列表含本批次 + 存量平台级批次(project_id='')
lst=json.loads(await call("opp_mining_status",{},ctxA))
ids=[x["id"] for x in (lst if isinstance(lst,list) else [])]
check("A列表含本批次",bid in ids,ids[:5])
plat=[x for x in (lst if isinstance(lst,list) else []) if not str(x.get("project_id") or "")]
check("存量批次归平台级可见",len(plat)>=1,"平台级批次数=%d"%len(plat))
# 5. 无项目会话只见平台级(不见A的批次)
ctx0=dict(ctxA); ctx0["project_id"]=""
lst0=json.loads(await call("opp_mining_status",{},ctx0))
ids0=[x["id"] for x in (lst0 if isinstance(lst0,list) else [])]
check("无项目会话不见A批次",bid not in ids0 and all(not str(x.get("project_id") or "") for x in (lst0 if isinstance(lst0,list) else [])),ids0[:5])
s=await call("opp_mining_status",{"batch_id":bid},ctx0)
check("无项目会话查A批次被拒",s.startswith("ERROR:"),s[:100])
# 6. cluster_detail 经批次可见性(项目B查A批次里的类别)
if PID_B:
cl=json.loads(await call("opp_list_clusters",{"batch_id":bid},ctxA))
rows=cl.get("排名") or []
if rows:
ctxB=dict(ctxA); ctxB["project_id"]=PID_B
s=await call("opp_cluster_detail",{"cluster_id":rows[0]["cluster_id"]},ctxB)
check("跨项目查类内明细被拒",s.startswith("ERROR:"),s[:120])
print("\n%s (%d fail)"%("PROJ-ISOLATION PASS" if not FAIL else "FAIL: "+",".join(FAIL),len(FAIL)))
sys.exit(1 if FAIL else 0)
asyncio.run(m())