livrare lot 2
This commit is contained in:
commit
8ecc78e729
763 changed files with 164593 additions and 0 deletions
275
backend/scripts/integration/run-integration-tests.sh
Normal file
275
backend/scripts/integration/run-integration-tests.sh
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# DiDi — Teste de integrare Lot 1 (Platforma AI) <-> Lot 2 (Backend)
|
||||
# =============================================================================
|
||||
# Demonstreaza ca cele doua loturi colaboreaza pe mediul live, non-distructiv.
|
||||
#
|
||||
# Trei niveluri:
|
||||
# A. Conectivitate & contract — agent-v3 ajunge la fiecare serviciu Lot 1
|
||||
# B. End-to-end pe tip de continut — pipeline complet -> verdict persistat
|
||||
# C. Proprietati transversale — fail-open, rutare model local, gateway
|
||||
#
|
||||
# Fiecare test capteaza 3 artefacte: (1) request-ul, (2) access-log-ul
|
||||
# serviciului Lot 1 care dovedeste primirea, (3) verdictul persistat in PG.
|
||||
#
|
||||
# Utilizare: bash run-integration-tests.sh
|
||||
# Rezultate: results/results_<timestamp>.json + results/evidence_<timestamp>/
|
||||
# =============================================================================
|
||||
set -uo pipefail
|
||||
|
||||
# --- Config -----------------------------------------------------------------
|
||||
AGENT="${AGENT_URL:-http://localhost:24803}"
|
||||
KONG="${KONG_URL:-http://127.0.0.1:18000}"
|
||||
KC="${KEYCLOAK_URL:-http://localhost:28080}"
|
||||
USER_ID="${TEST_USER:-14142351-ad1e-466b-ac5d-4a7a0ff562bf}"
|
||||
PG_C="${PG_CONTAINER:-didi-postgres}"
|
||||
POLL_MAX="${POLL_MAX:-60}" # nr. maxim de poll-uri
|
||||
POLL_INT="${POLL_INT:-3}" # secunde intre poll-uri
|
||||
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
FIX="$HERE/fixtures"
|
||||
TS="$(date +%Y%m%d_%H%M%S)"
|
||||
OUT="$HERE/results"
|
||||
EVID="$OUT/evidence_$TS"
|
||||
RESULTS="$OUT/results_$TS.json"
|
||||
mkdir -p "$EVID"
|
||||
|
||||
PASS=0; FAIL=0; DEGR=0
|
||||
echo "[]" > "$RESULTS"
|
||||
|
||||
# --- Helpers ----------------------------------------------------------------
|
||||
pg() { docker exec "$PG_C" psql -U bos_interface -d DIDI -tA -c "$1" 2>/dev/null; }
|
||||
|
||||
# extrage un camp dintr-un JSON de pe stdin: jget '<path python>' ex: "data.status"
|
||||
jget() { python3 -c "import sys,json;
|
||||
try: d=json.load(sys.stdin)
|
||||
except: print(''); sys.exit()
|
||||
for k in '$1'.split('.'):
|
||||
d = d.get(k, '') if isinstance(d, dict) else ''
|
||||
print(d if d is not None else '')"; }
|
||||
|
||||
# inregistreaza un rezultat de test in JSON-ul agregat
|
||||
rec() { # id level name requirement target status detail evidence_file
|
||||
python3 - "$RESULTS" "$@" <<'PY'
|
||||
import json,sys
|
||||
f=sys.argv[1]; ida,lvl,name,req,tgt,st,detail,ev=sys.argv[2:10]
|
||||
data=json.load(open(f))
|
||||
data.append({"id":ida,"level":lvl,"name":name,"requirement":req,
|
||||
"target":tgt,"status":st,"detail":detail,"evidence":ev})
|
||||
json.dump(data,open(f,'w'),ensure_ascii=False,indent=2)
|
||||
PY
|
||||
case "$6" in PASS) PASS=$((PASS+1));; DEGRADED) DEGR=$((DEGR+1));; *) FAIL=$((FAIL+1));; esac
|
||||
printf ' [%-8s] %-4s %s\n' "$6" "$1" "$3"
|
||||
}
|
||||
|
||||
# probe de conectivitate din INTERIORUL agent-v3 (consumatorul real), via node fetch
|
||||
probe_from_agent() { # url -> printeaza "STATUS <code>" sau "ERR <msg>"
|
||||
docker exec didi-agent-v3 node -e "
|
||||
fetch('$1',{signal:AbortSignal.timeout(6000)})
|
||||
.then(r=>{console.log('STATUS '+r.status)})
|
||||
.catch(e=>{console.log('ERR '+e.message)})" 2>/dev/null
|
||||
}
|
||||
|
||||
# lanseaza o analiza async si asteapta verdictul; printeaza JSON-ul result
|
||||
analyze() { # media_type json_body
|
||||
local body="$2"
|
||||
local resp sid st
|
||||
resp="$(curl -sk --max-time 30 -X POST "$AGENT/api/v3/pipeline/analyze-async" \
|
||||
-H 'Content-Type: application/json' -d "$body" 2>/dev/null)"
|
||||
sid="$(echo "$resp" | jget 'data.session_id')"
|
||||
if [ -z "$sid" ]; then echo "{\"error\":\"dispatch_failed\",\"raw\":$(echo "$resp"|python3 -c 'import sys,json;print(json.dumps(sys.stdin.read()))')}"; return; fi
|
||||
local i=0
|
||||
while [ $i -lt "$POLL_MAX" ]; do
|
||||
st="$(curl -sk --max-time 10 "$AGENT/api/v3/pipeline/$sid/queue-status" | jget 'data.status')"
|
||||
[ -z "$st" ] && st="$(curl -sk --max-time 10 "$AGENT/api/v3/pipeline/$sid/queue-status" | jget 'status')"
|
||||
if [ "$st" = "completed" ] || [ "$st" = "failed" ]; then break; fi
|
||||
sleep "$POLL_INT"; i=$((i+1))
|
||||
done
|
||||
curl -sk --max-time 10 "$AGENT/api/v3/pipeline/$sid/result"
|
||||
echo "$sid" > /tmp/.last_sid
|
||||
}
|
||||
|
||||
# upload un fisier media -> printeaza public_url
|
||||
upload_media() { # filepath
|
||||
curl -sk --max-time 60 -X POST "$AGENT/api/v3/media/upload" \
|
||||
-F "file=@$1" -F "user_id=$USER_ID" 2>/dev/null | jget 'data.public_url'
|
||||
}
|
||||
|
||||
echo "============================================================"
|
||||
echo " DiDi — Teste integrare Lot1<->Lot2 $TS"
|
||||
echo " Agent: $AGENT User: ${USER_ID:0:8}... Evidence: $EVID"
|
||||
echo "============================================================"
|
||||
|
||||
# =============================================================================
|
||||
# NIVEL A — Conectivitate & contract (agent-v3 -> servicii Lot 1)
|
||||
# =============================================================================
|
||||
echo; echo "### NIVEL A — Conectivitate din agent-v3 catre serviciile Lot 1"
|
||||
|
||||
declare -A A_SVC=(
|
||||
[A1]="llm-api:14011|/health|LLM text (Qwen3.5)|extractoare/flux LLM"
|
||||
[A3]="audio-api:54300|/health|Whisper transcriere|extractor Whisper"
|
||||
[A4]="video-api:54600|/health|BusterX deepfake|extractor deepfake"
|
||||
[A5]="extractors:54400|/health|EXIF/NER/YOLO/OCR|extractoare NER/YOLO/OCR"
|
||||
[A6]="forensic:8080|/health|forensic media|analiza forensica media"
|
||||
[A7]="web-api:51100|/health|cautare web claims|modul web-crawl/evidence"
|
||||
[A8]="brain-api:8090|/health|RAG/fact-check cache|flux ML fact-check"
|
||||
)
|
||||
for id in A1 A3 A4 A5 A6 A7 A8; do
|
||||
IFS='|' read -r hp path label req <<< "${A_SVC[$id]}"
|
||||
out="$(probe_from_agent "http://$hp$path")"
|
||||
echo "$id $hp$path -> $out" >> "$EVID/A_connectivity.log"
|
||||
if echo "$out" | grep -q "STATUS 200"; then
|
||||
rec "$id" "A" "$label ($hp)" "$req" "$hp" "PASS" "$out" "A_connectivity.log"
|
||||
else
|
||||
rec "$id" "A" "$label ($hp)" "$req" "$hp" "FAIL" "$out" "A_connectivity.log"
|
||||
fi
|
||||
done
|
||||
|
||||
# A2 — LLM vision-capable: modelul qwen3.5 incarcat pe llm-api (rol vision)
|
||||
models="$(docker exec didi-agent-v3 node -e "fetch('http://llm-api:14011/v1/models',{signal:AbortSignal.timeout(6000)}).then(r=>r.json()).then(d=>console.log(JSON.stringify(d))).catch(e=>console.log('ERR'))" 2>/dev/null)"
|
||||
echo "A2 models: $models" >> "$EVID/A_connectivity.log"
|
||||
if echo "$models" | grep -q 'qwen3.5'; then
|
||||
rec "A2" "A" "LLM vision/OCR (llm-api)" "extractor OCR" "llm-api:14011" "PASS" "model qwen3.5 loaded" "A_connectivity.log"
|
||||
else
|
||||
rec "A2" "A" "LLM vision/OCR (llm-api)" "extractor OCR" "llm-api:14011" "FAIL" "$models" "A_connectivity.log"
|
||||
fi
|
||||
|
||||
# A9 — domain-check T4: apel real POST /api/v1/check/check
|
||||
dc="$(docker exec didi-agent-v3 node -e "
|
||||
fetch('http://domain-check-api:11000/api/v1/check/check',{method:'POST',
|
||||
headers:{'Content-Type':'application/json'},
|
||||
body:JSON.stringify({domain:'google.com',check_options:{whois:true,dns:true,ssl:true}}),
|
||||
signal:AbortSignal.timeout(30000)})
|
||||
.then(r=>r.json()).then(d=>console.log(JSON.stringify({ok:d.success,risk:(d.data||{}).risk_score}))).catch(e=>console.log('ERR '+e.message))" 2>/dev/null)"
|
||||
echo "A9 domain-check: $dc" >> "$EVID/A_connectivity.log"
|
||||
if echo "$dc" | grep -q '"ok":true'; then
|
||||
rec "A9" "A" "Domain-check T4 (WHOIS/DNS/SSL)" "scor credibilitate sursa" "domain-check-api:11000" "PASS" "$dc" "A_connectivity.log"
|
||||
else
|
||||
rec "A9" "A" "Domain-check T4 (WHOIS/DNS/SSL)" "scor credibilitate sursa" "domain-check-api:11000" "FAIL" "$dc" "A_connectivity.log"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# NIVEL B — End-to-end pe tip de continut
|
||||
# =============================================================================
|
||||
echo; echo "### NIVEL B — Analize end-to-end (pipeline complet -> verdict)"
|
||||
|
||||
run_e2e() { # id name media_type body req logcontainer logpattern
|
||||
local id="$1" name="$2" mt="$3" body="$4" req="$5" lc="$6" lp="$7"
|
||||
local since res verdict cat score status sid
|
||||
since="$(date -u +%Y-%m-%dT%H:%M:%S)"
|
||||
res="$(analyze "$mt" "$body")"
|
||||
sid="$(cat /tmp/.last_sid 2>/dev/null)"
|
||||
echo "$res" > "$EVID/B_${id}_result.json"
|
||||
status="$(echo "$res" | jget 'data.status')"; [ -z "$status" ] && status="$(echo "$res" | jget 'status')"
|
||||
score="$(echo "$res" | jget 'data.risk_score')"; [ -z "$score" ] && score="$(echo "$res" | jget 'risk_score')"
|
||||
cat="$(echo "$res" | jget 'data.risk_category')"; [ -z "$cat" ] && cat="$(echo "$res" | jget 'risk_category')"
|
||||
# dovada access-log Lot 1
|
||||
if [ -n "$lc" ]; then
|
||||
docker logs --since "$since" "$lc" 2>&1 | grep -iE "$lp" | tail -5 > "$EVID/B_${id}_lot1_${lc}.log" 2>/dev/null
|
||||
fi
|
||||
# dovada verdict din PG
|
||||
pg "SELECT input_type||'|'||status||'|'||COALESCE(risk_category,'')||'|'||COALESCE(risk_score::text,'') FROM bos_analysis.analysis_session WHERE session_id='$sid';" > "$EVID/B_${id}_pg.txt" 2>/dev/null
|
||||
local pgrow; pgrow="$(cat "$EVID/B_${id}_pg.txt")"
|
||||
if [ "$status" = "completed" ]; then
|
||||
rec "$id" "B" "$name" "$req" "$mt" "PASS" "verdict=$cat score=$score | PG:$pgrow" "B_${id}_result.json"
|
||||
else
|
||||
rec "$id" "B" "$name" "$req" "$mt" "FAIL" "status=$status | PG:$pgrow" "B_${id}_result.json"
|
||||
fi
|
||||
}
|
||||
|
||||
# B1 — text dezinformare
|
||||
run_e2e "B1" "Text dezinformare -> verdict LLM" "text" \
|
||||
"{\"media_type\":\"text\",\"text\":\"OMS a confirmat oficial ca vaccinurile anti-COVID contin microcipuri 5G folosite pentru controlul mintal al intregii populatii prin unde radio.\",\"user_id\":\"$USER_ID\"}" \
|
||||
"orchestrare + flux LLM" "didiAI-llm-api" "chat/completions"
|
||||
|
||||
# B2 — URL real (domeniu + web)
|
||||
run_e2e "B2" "URL -> componenta domain + web" "url" \
|
||||
"{\"media_type\":\"url\",\"url\":\"https://www.bbc.com/news\",\"user_id\":\"$USER_ID\"}" \
|
||||
"web-crawl/evidence + credibilitate sursa" "didiAI-domain-check" "check/check"
|
||||
|
||||
# B3 — imagine (OCR/vision)
|
||||
IMG_URL="$(upload_media "$FIX/fake_headline.jpg")"
|
||||
echo "B3 image url: $IMG_URL" > "$EVID/B_B3_upload.txt"
|
||||
run_e2e "B3" "Imagine -> OCR/vision + extractoare" "image" \
|
||||
"{\"media_type\":\"image\",\"media_url\":\"$IMG_URL\",\"user_id\":\"$USER_ID\"}" \
|
||||
"extractor OCR/vision" "didiAI-llm-api" "chat/completions"
|
||||
|
||||
# B4 — audio (Whisper)
|
||||
AUD_URL="$(upload_media "$FIX/jfk_speech.wav")"
|
||||
echo "B4 audio url: $AUD_URL" > "$EVID/B_B4_upload.txt"
|
||||
run_e2e "B4" "Audio -> transcriere Whisper -> verdict" "audio" \
|
||||
"{\"media_type\":\"audio\",\"media_url\":\"$AUD_URL\",\"user_id\":\"$USER_ID\"}" \
|
||||
"extractor Whisper" "didiAI-audio" "transcriptions|POST"
|
||||
|
||||
# B5 — video (BusterX)
|
||||
VID_URL="$(upload_media "$FIX/test_clip.mp4")"
|
||||
echo "B5 video url: $VID_URL" > "$EVID/B_B5_upload.txt"
|
||||
run_e2e "B5" "Video -> BusterX deepfake -> verdict" "video" \
|
||||
"{\"media_type\":\"video\",\"media_url\":\"$VID_URL\",\"user_id\":\"$USER_ID\"}" \
|
||||
"extractor deepfake" "didiAI-video-api" "POST|analyze|predict"
|
||||
|
||||
# =============================================================================
|
||||
# NIVEL C — Proprietati transversale
|
||||
# =============================================================================
|
||||
echo; echo "### NIVEL C — Fail-open, rutare model local, gateway"
|
||||
|
||||
# C1 — FAIL-OPEN: opresc web-api, rulez o analiza, verific ca se TERMINA (degradat)
|
||||
echo " [C1] opresc temporar didiAI-web-api pentru testul de fail-open..."
|
||||
docker stop didiAI-web-api >/dev/null 2>&1
|
||||
sleep 2
|
||||
since="$(date -u +%Y-%m-%dT%H:%M:%S)"
|
||||
res="$(analyze "text" "{\"media_type\":\"text\",\"text\":\"Presedintele a anuntat ieri o crestere economica de 15% intr-o singura luna, cel mai mare salt din istoria tarii.\",\"user_id\":\"$USER_ID\"}")"
|
||||
echo "$res" > "$EVID/C1_failopen_result.json"
|
||||
c1status="$(echo "$res" | jget 'data.status')"; [ -z "$c1status" ] && c1status="$(echo "$res" | jget 'status')"
|
||||
docker start didiAI-web-api >/dev/null 2>&1
|
||||
echo " [C1] didiAI-web-api repornit."
|
||||
if [ "$c1status" = "completed" ]; then
|
||||
rec "C1" "C" "Fail-open (web-api oprit -> analiza se termina)" "reziliza/fail-open servicii AI" "didiAI-web-api" "DEGRADED" "analiza completa fara web-api: status=$c1status" "C1_failopen_result.json"
|
||||
else
|
||||
rec "C1" "C" "Fail-open (web-api oprit -> analiza se termina)" "reziliza/fail-open servicii AI" "didiAI-web-api" "FAIL" "status=$c1status (nu a degradat gratios)" "C1_failopen_result.json"
|
||||
fi
|
||||
|
||||
# C2 — RUTARE MODEL LOCAL: analiza text, dovada apel local qwen3.5, zero OpenRouter
|
||||
since="$(date -u +%Y-%m-%dT%H:%M:%S)"
|
||||
res="$(analyze "text" "{\"media_type\":\"text\",\"text\":\"Guvernul a decis marirea salariului minim incepand cu luna urmatoare, conform anuntului oficial.\",\"user_id\":\"$USER_ID\"}")"
|
||||
sid="$(cat /tmp/.last_sid)"
|
||||
docker logs --since "$since" didiAI-llm-api 2>&1 | grep -iE "chat/completions" | tail -5 > "$EVID/C2_llm_access.log"
|
||||
llmhits="$(wc -l < "$EVID/C2_llm_access.log" 2>/dev/null | tr -d ' ')"
|
||||
usage="$(pg "SELECT COALESCE(llm_usage::text,'{}') FROM bos_analysis.analysis_session WHERE session_id='$sid';")"
|
||||
echo "$usage" > "$EVID/C2_llm_usage.json"
|
||||
# provider din DB pentru modelul primar
|
||||
prov="$(pg "SELECT p.provider_code||'|'||p.base_url FROM bos_parammgmt.llm_provider p JOIN bos_parammgmt.llm_model m ON m.provider_id=p.provider_id WHERE m.model_code='qwen3.5' LIMIT 1;")"
|
||||
echo "provider: $prov" >> "$EVID/C2_llm_usage.json"
|
||||
if [ "${llmhits:-0}" -ge 1 ] && echo "$prov" | grep -q 'llm-api:14011'; then
|
||||
rec "C2" "C" "Rutare model local (Qwen3.5, fara fallback platit)" "flux LLM local" "llm-api:14011" "PASS" "llm-api hits=$llmhits provider=$prov" "C2_llm_access.log"
|
||||
else
|
||||
rec "C2" "C" "Rutare model local (Qwen3.5, fara fallback platit)" "flux LLM local" "llm-api:14011" "FAIL" "llm-api hits=$llmhits provider=$prov" "C2_llm_access.log"
|
||||
fi
|
||||
|
||||
# C3 — GATEWAY: Kong pazeste lantul AI (401 fara token pe calea pipeline)
|
||||
code_notoken="$(curl -sk --max-time 10 -H 'Host: localhost' -o /dev/null -w '%{http_code}' \
|
||||
-X POST "$KONG/agent-v3/api/v3/pipeline/analyze-async" -H 'Content-Type: application/json' \
|
||||
-d '{"media_type":"text","text":"aaaaaaaaaa","user_id":"x"}' 2>/dev/null)"
|
||||
echo "Kong /agent-v3/.../analyze-async fara token -> $code_notoken" > "$EVID/C3_gateway.log"
|
||||
if [ "$code_notoken" = "401" ]; then
|
||||
rec "C3" "C" "Gateway Kong pazeste lantul AI (401 fara JWT)" "API Gateway + securitate" "kong:8000" "PASS" "analyze-async fara token -> $code_notoken" "C3_gateway.log"
|
||||
else
|
||||
rec "C3" "C" "Gateway Kong pazeste lantul AI (401 fara JWT)" "API Gateway + securitate" "kong:8000" "FAIL" "cod neasteptat: $code_notoken" "C3_gateway.log"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Sumar
|
||||
# =============================================================================
|
||||
echo; echo "============================================================"
|
||||
echo " SUMAR: PASS=$PASS DEGRADED=$DEGR FAIL=$FAIL"
|
||||
echo " JSON: $RESULTS"
|
||||
echo " Dovezi: $EVID"
|
||||
echo "============================================================"
|
||||
python3 - "$RESULTS" "$PASS" "$DEGR" "$FAIL" "$TS" <<'PY'
|
||||
import json,sys
|
||||
f,p,d,fa,ts=sys.argv[1:6]
|
||||
data=json.load(open(f))
|
||||
out={"timestamp":ts,"summary":{"pass":int(p),"degraded":int(d),"fail":int(fa),"total":len(data)},"tests":data}
|
||||
json.dump(out,open(f,'w'),ensure_ascii=False,indent=2)
|
||||
print("Scris:",f)
|
||||
PY
|
||||
Loading…
Add table
Add a link
Reference in a new issue