| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- #!/usr/bin/env bash
- # R3-SHORTAGE-EVALUATOR-1 regression script (dev/test only, aidopdev).
- #
- # Drives the safe debug endpoint /api/aidop/s8/watch-debug/run-once twice and
- # verifies SHORTAGE end-to-end while ensuring TIMEOUT and OUT_OF_RANGE compat
- # paths do not regress:
- # 1. only ONE active (status != CLOSED) exception per dedup_key for SHORTAGE;
- # 2. last_detected_at refreshed between runs;
- # 3. source_payload contains target_qty / actual_qty / shortage_qty /
- # shortage_ratio / __ruleType / __sourceObjectType / __sourceObjectId /
- # __exceptionTypeCode metadata;
- # 4. TIMEOUT G01 still duplicate-skip against id=52;
- # 5. OUT_OF_RANGE G01 still duplicate-skip against id=34;
- # 6. baseline 13 unchanged.
- #
- # Requires the same prerequisites as r2-timeout-regression.sh (mysql client,
- # python3, aidopdev backend on http://localhost:5005, dev override of
- # WatchScheduler:DebugEndpointEnabled, populated Playwright storage state).
- set -euo pipefail
- PROJECT_DIR="${PROJECT_DIR:-/home/yy968/work/New9S/AiDOPWarehouse}"
- STORAGE_STATE="${PROJECT_DIR}/Web/tests/e2e/.auth/storage-state.json"
- BACKEND_BASE="${BACKEND_BASE:-http://localhost:5005}"
- TENANT_ID="${TENANT_ID:-1}"
- FACTORY_ID="${FACTORY_ID:-1}"
- DB_HOST="${DB_HOST:-123.60.180.165}"
- DB_PORT="${DB_PORT:-3306}"
- DB_NAME="${DB_NAME:-aidopdev}"
- DB_USER="${DB_USER:-aidopremote}"
- DB_PASS="${DB_PASS:-1234567890aiDOP#}"
- fail() { echo "FAIL: $*" >&2; exit 1; }
- ok() { echo "OK: $*"; }
- [[ "${DB_NAME}" == "aidopdev" ]] || fail "DB_NAME must be aidopdev, got ${DB_NAME}"
- [[ -f "${STORAGE_STATE}" ]] || fail "storage state not found: ${STORAGE_STATE}"
- AT="$(python3 -c "
- import json,sys
- d=json.load(open(sys.argv[1]))
- for kv in d['origins'][0]['localStorage']:
- if kv['name']=='admin.net:access-token':
- print(kv['value'].strip('\"')); break
- " "${STORAGE_STATE}")"
- XAT="$(python3 -c "
- import json,sys
- d=json.load(open(sys.argv[1]))
- for kv in d['origins'][0]['localStorage']:
- if kv['name']=='admin.net:x-access-token':
- print(kv['value'].strip('\"')); break
- " "${STORAGE_STATE}")"
- [[ -n "${AT}" && "${AT}" != "null" ]] || fail "access-token missing in storage-state"
- [[ -n "${XAT}" && "${XAT}" != "null" ]] || fail "x-access-token missing in storage-state"
- mysql_query() {
- MYSQL_PWD="${DB_PASS}" mysql -h "${DB_HOST}" -P "${DB_PORT}" -u "${DB_USER}" "${DB_NAME}" \
- --default-character-set=utf8mb4 --connect-timeout=8 -N -B -e "$1" 2>/dev/null
- }
- run_once() {
- curl -fsS --max-time 15 -X POST \
- -H "Authorization: Bearer ${AT}" -H "X-Access-Token: ${XAT}" \
- "${BACKEND_BASE}/api/aidop/s8/watch-debug/run-once?tenantId=${TENANT_ID}&factoryId=${FACTORY_ID}"
- }
- precheck=$(mysql_query "SELECT COUNT(*) FROM ado_s8_watch_rule WHERE rule_code='G01_TEST_SHORTAGE' AND enabled=1;")
- [[ "${precheck}" == "1" ]] || fail "G01_TEST_SHORTAGE not present or disabled (got '${precheck}')"
- ok "G01_TEST_SHORTAGE enabled"
- baseline=$(mysql_query "SELECT COUNT(*) FROM ado_s8_exception_type WHERE tenant_id=0 AND factory_id=0;")
- [[ "${baseline}" == "13" ]] || fail "baseline regression: expected 13, got ${baseline}"
- ok "baseline = 13"
- resp1="$(run_once)"
- count1=$(printf '%s' "${resp1}" | python3 -c "import json,sys;print(json.load(sys.stdin).get('count',0))")
- [[ "${count1}" -ge 3 ]] || fail "first run-once expected at least 3 results (OOR + TIMEOUT + SHORTAGE), got ${count1}"
- ok "first run-once HTTP 200, count=${count1}"
- # OUT_OF_RANGE compat
- oor_ok=$(printf '%s' "${resp1}" | python3 -c "
- import json,sys
- d=json.load(sys.stdin)
- hit=any(r for r in d.get('results',[]) if str(r.get('sourceRuleId'))=='1' and r.get('skipped') and str(r.get('matchedExceptionId'))=='34')
- print('YES' if hit else 'NO')
- ")
- [[ "${oor_ok}" == "YES" ]] || fail "OUT_OF_RANGE G01 regression: expected skipped duplicate id=34"
- ok "OUT_OF_RANGE G01 compat path: skipped duplicate id=34"
- # TIMEOUT compat
- timeout_ok=$(printf '%s' "${resp1}" | python3 -c "
- import json,sys
- d=json.load(sys.stdin)
- hit=any(r for r in d.get('results',[]) if str(r.get('sourceRuleId'))=='5' and r.get('skipped') and str(r.get('matchedExceptionId'))=='52')
- print('YES' if hit else 'NO')
- ")
- [[ "${timeout_ok}" == "YES" ]] || fail "TIMEOUT G01 regression: expected skipped duplicate id=52"
- ok "TIMEOUT G01: skipped duplicate id=52"
- before_ts=$(mysql_query "SELECT IFNULL(MAX(last_detected_at), '1970-01-01') FROM ado_s8_exception WHERE source_rule_code='G01_TEST_SHORTAGE' AND status<>'CLOSED' AND is_deleted=0;")
- ok "pre-second-run SHORTAGE last_detected_at=${before_ts}"
- sleep 1
- resp2="$(run_once)"
- count2=$(printf '%s' "${resp2}" | python3 -c "import json,sys;print(json.load(sys.stdin).get('count',0))")
- ok "second run-once HTTP 200, count=${count2}"
- active_count=$(mysql_query "SELECT COUNT(*) FROM ado_s8_exception WHERE source_rule_code='G01_TEST_SHORTAGE' AND status<>'CLOSED' AND is_deleted=0;")
- [[ "${active_count}" == "1" ]] || fail "expected exactly 1 active SHORTAGE exception, got ${active_count}"
- ok "active SHORTAGE exception count = 1"
- after_ts=$(mysql_query "SELECT MAX(last_detected_at) FROM ado_s8_exception WHERE source_rule_code='G01_TEST_SHORTAGE' AND status<>'CLOSED' AND is_deleted=0;")
- [[ "${after_ts}" > "${before_ts}" ]] || fail "SHORTAGE last_detected_at did not refresh"
- ok "SHORTAGE last_detected_at refreshed: ${before_ts} -> ${after_ts}"
- payload=$(mysql_query "SELECT source_payload FROM ado_s8_exception WHERE source_rule_code='G01_TEST_SHORTAGE' AND status<>'CLOSED' AND is_deleted=0 ORDER BY id DESC LIMIT 1;")
- for field in target_qty actual_qty shortage_qty shortage_ratio __ruleType __sourceObjectType __sourceObjectId __exceptionTypeCode; do
- echo "${payload}" | grep -q "${field}" || fail "source_payload missing ${field}"
- done
- ok "SHORTAGE source_payload contains target/actual/shortage/ratio + 4 metadata fields"
- ok "R3-SHORTAGE regression PASSED"
|