You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
6.5 KiB
137 lines
6.5 KiB
|
9 hours ago
|
# -*- coding: utf-8 -*-
|
||
|
|
"""acceptance-probe-testenv.py — 测试环境(https://ai.itc.vip/crm-api)验收前探针。
|
||
|
|
|
||
|
|
目的:验收开始前一次性回答四件事——
|
||
|
|
1) 服务可达(ping 401 = 鉴权门活着,属正常)
|
||
|
|
2) verify profile / debug token 可用(demo 免登前提)
|
||
|
|
3) 数据状态:mine/pool 存量 + 四个关键字典组(含 W-01 contact_source 观察点)
|
||
|
|
4) 构建新鲜度判别(D-03 无写库副作用):POST /api/customer/edit 不带 version
|
||
|
|
→ 67005 = 含 customer-defectfix 修复的新构建;67001+「乐观锁」= 旧构建(验收会全部误报未修)
|
||
|
|
|
||
|
|
只读探测:edit 探针在 CAS 校验前置失败,不产生任何写库。
|
||
|
|
用法:py -X utf8 .scratch/customer-defectfix/acceptance-probe-testenv.py
|
||
|
|
产物:acceptance-probe-testenv-result.json(与本脚本同目录)
|
||
|
|
"""
|
||
|
|
import io
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
import sys
|
||
|
|
import time
|
||
|
|
|
||
|
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||
|
|
import requests
|
||
|
|
|
||
|
|
BASE = 'https://ai.itc.vip/crm-api'
|
||
|
|
ADMIN = '739564171091247104' # 罗伟健(admin)
|
||
|
|
OUT = os.path.dirname(os.path.abspath(__file__))
|
||
|
|
RESULT = os.path.join(OUT, 'acceptance-probe-testenv-result.json')
|
||
|
|
|
||
|
|
ev = {'base': BASE, 'ts': time.strftime('%Y-%m-%d %H:%M:%S')}
|
||
|
|
VERDICT = []
|
||
|
|
|
||
|
|
|
||
|
|
def note(msg):
|
||
|
|
print(msg)
|
||
|
|
VERDICT.append(msg)
|
||
|
|
|
||
|
|
|
||
|
|
# ---- 1. ping(鉴权门)----
|
||
|
|
try:
|
||
|
|
r = requests.get(f'{BASE}/api/customer/ping', timeout=15)
|
||
|
|
ev['ping_http'] = r.status_code
|
||
|
|
note(f"1. ping → HTTP {r.status_code}" + ("(401 = 鉴权门活着,服务在)" if r.status_code == 401 else ""))
|
||
|
|
except Exception as e:
|
||
|
|
ev['ping_error'] = str(e)[:200]
|
||
|
|
note(f"1. ping 连接失败: {str(e)[:160]} —— 测试环境不通(nginx/FRP/服务链路),验收无法开始")
|
||
|
|
json.dump(ev, open(RESULT, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
|
||
|
|
sys.exit(1)
|
||
|
|
|
||
|
|
# ---- 2. debug token ----
|
||
|
|
tok = None
|
||
|
|
try:
|
||
|
|
r = requests.get(f'{BASE}/api/auth/debug/token', params={'userId': ADMIN}, timeout=15)
|
||
|
|
body = r.json() if r.status_code == 200 else {}
|
||
|
|
d = body.get('data')
|
||
|
|
tok = d if isinstance(d, str) else (d or {}).get('token')
|
||
|
|
ev['debug_token_http'] = r.status_code
|
||
|
|
except Exception as e:
|
||
|
|
ev['debug_token_error'] = str(e)[:200]
|
||
|
|
if not tok:
|
||
|
|
note("2. debug token 不可用 —— verify profile 未激活或端点被拦;demo 免登会失败,需检查测试环境启动配置")
|
||
|
|
json.dump(ev, open(RESULT, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
|
||
|
|
sys.exit(1)
|
||
|
|
note("2. debug token OK(verify profile 激活,demo 可免登)")
|
||
|
|
H = {'Authorization': f'Bearer {tok}'}
|
||
|
|
|
||
|
|
S = requests.Session()
|
||
|
|
S.headers.update(H)
|
||
|
|
|
||
|
|
|
||
|
|
def code_of(r):
|
||
|
|
try:
|
||
|
|
return (r.json() or {}).get('code')
|
||
|
|
except Exception:
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
# ---- 3. 数据状态 ----
|
||
|
|
try:
|
||
|
|
m = S.post(f'{BASE}/api/customer/workspace/mine/page', data={'current': 1, 'size': 3}, timeout=20).json()
|
||
|
|
p = S.post(f'{BASE}/api/customer/workspace/pool/page', data={'current': 1, 'size': 3}, timeout=20).json()
|
||
|
|
md, pd = m.get('data') or {}, p.get('data') or {}
|
||
|
|
ev['mine_total'], ev['pool_total'] = md.get('total'), pd.get('total')
|
||
|
|
note(f"3. 数据态:mine total={md.get('total')} pool total={pd.get('total')}")
|
||
|
|
for row in (md.get('content') or [])[:3]:
|
||
|
|
print(f" - {row.get('customerNo')} {row.get('customerName')}")
|
||
|
|
if not md.get('total') and not pd.get('total'):
|
||
|
|
note(" ⚠ 测试环境无客户数据 —— 需先跑 demo_showcase.py --base https://ai.itc.vip/crm-api --skip-db 造验收数据")
|
||
|
|
for g in ('customer_type', 'follow_way', 'industry', 'contact_source'):
|
||
|
|
try:
|
||
|
|
d = S.get(f'{BASE}/api/dict/item/enabled-list', params={'groupCode': g}, timeout=15).json()
|
||
|
|
items = d.get('data') or []
|
||
|
|
ev[f'dict_{g}'] = len(items)
|
||
|
|
print(f" dict {g}: {len(items)} 项" + (" ⚠ 空(W-01 同款观察点)" if not items else ""))
|
||
|
|
except Exception as e:
|
||
|
|
print(f" dict {g}: 探测失败 {str(e)[:80]}")
|
||
|
|
except Exception as e:
|
||
|
|
note(f"3. 数据态探测失败: {str(e)[:160]}")
|
||
|
|
|
||
|
|
# ---- 4. 构建新鲜度判别(D-03,无写库)----
|
||
|
|
try:
|
||
|
|
rows = ((S.post(f'{BASE}/api/customer/workspace/mine/page', data={'current': 1, 'size': 1}, timeout=20).json()).get('data') or {}).get('content') or []
|
||
|
|
if not rows:
|
||
|
|
note("4. 构建判别跳过:mine 无客户可取样(先造数再判构建)")
|
||
|
|
else:
|
||
|
|
fid = rows[0]['id']
|
||
|
|
det = S.get(f'{BASE}/api/customer/detail', params={'id': fid}, timeout=20).json()
|
||
|
|
d = det.get('data') or {}
|
||
|
|
form = {
|
||
|
|
'customerName': d.get('customerName') or rows[0].get('customerName'),
|
||
|
|
'customerType': d.get('customerType'), 'provinceCode': d.get('provinceCode'),
|
||
|
|
'cityCode': d.get('cityCode'), 'districtCode': d.get('districtCode'),
|
||
|
|
'industryCode': d.get('industryCode'), 'customerStarLevel': d.get('customerStarLevel') or 3,
|
||
|
|
'relationStarLevel': d.get('relationStarLevel') or 3,
|
||
|
|
'isBizNegotiated': d.get('isBizNegotiated') if d.get('isBizNegotiated') is not None else 0,
|
||
|
|
'isChild': d.get('isChild') if d.get('isChild') is not None else 0,
|
||
|
|
}
|
||
|
|
# 刻意不带 version:CAS 前置失败,无写库
|
||
|
|
t0 = time.time()
|
||
|
|
r = S.post(f'{BASE}/api/customer/edit', params={'id': fid}, data=form, timeout=60)
|
||
|
|
got = code_of(r)
|
||
|
|
ev['d03_probe'] = {'customer_id': str(fid), 'http': r.status_code, 'code': got,
|
||
|
|
'message': str((r.json() or {}).get('message'))[:80] if r.headers.get('content-type', '').startswith('application/json') else '',
|
||
|
|
'elapsed_sec': round(time.time() - t0, 2)}
|
||
|
|
msg = ev['d03_probe']['message']
|
||
|
|
if str(got) == '67005':
|
||
|
|
note("4. 构建判别:缺 version → 67005 —— **含 D-02/03/04/05/07 修复的新构建**,可以开始验收")
|
||
|
|
elif str(got) == '67001' and '乐观锁' in msg:
|
||
|
|
note("4. 构建判别:缺 version → 67001(乐观锁)—— **旧构建(缺陷修复未部署)**,验收前须先发新 jar(mvn clean package → 上传 → deploy/restart.sh)")
|
||
|
|
else:
|
||
|
|
note(f"4. 构建判别结果异常:code={got} msg={msg} —— 需人工看一眼(请求形态可能被必填校验先拦)")
|
||
|
|
except Exception as e:
|
||
|
|
note(f"4. 构建判别失败: {str(e)[:160]}")
|
||
|
|
|
||
|
|
ev['verdict'] = VERDICT
|
||
|
|
json.dump(ev, open(RESULT, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
|
||
|
|
print(f"\n证据已落盘 {RESULT}")
|