Spaces:
Sleeping
Sleeping
| # Manual E2E run against a live server on :8765. | |
| # Exercises the entire student happy path: register → skills → target role → | |
| # analyze → recommendations → checkpoint toggle → upgrade suggestions → apply | |
| # → re-analyze, plus the claim checks that live HTTP can see. | |
| set -u | |
| API="http://127.0.0.1:8765/api" | |
| say() { printf '\n\033[1;36m== %s ==\033[0m\n' "$*"; } | |
| ok() { printf '\033[32m[ok]\033[0m %s\n' "$*"; } | |
| fail(){ printf '\033[31m[FAIL]\033[0m %s\n' "$*"; } | |
| # Unique email so re-runs don't collide with the previous state. | |
| TAG="e2e$RANDOM" | |
| # --------------------------------------------------------------------------- | |
| # CLAIM #2 (weak password accepted) — live HTTP verification | |
| # --------------------------------------------------------------------------- | |
| say "CLAIM #2: weak password accepted at /register/" | |
| R=$(curl -s -o /tmp/r.json -w '%{http_code}' \ | |
| -H 'Content-Type: application/json' \ | |
| -d "{\"name\":\"w\",\"email\":\"weak_${TAG}@x.com\",\"password\":\"abc\",\"password_confirm\":\"abc\"}" \ | |
| "$API/auth/register/") | |
| [ "$R" = "201" ] && ok "weak password 'abc' was accepted (HTTP 201) — CLAIM CONFIRMED" \ | |
| || fail "unexpected HTTP $R" | |
| # --------------------------------------------------------------------------- | |
| # CLAIM #3 (email case-sensitive uniqueness) — live HTTP | |
| # --------------------------------------------------------------------------- | |
| say "CLAIM #3: email uniqueness is case-sensitive" | |
| UPPER="Case_${TAG}@x.com" | |
| LOWER="case_${TAG}@x.com" | |
| R1=$(curl -s -o /dev/null -w '%{http_code}' \ | |
| -H 'Content-Type: application/json' \ | |
| -d "{\"name\":\"u\",\"email\":\"$UPPER\",\"password\":\"StrongPass123!\",\"password_confirm\":\"StrongPass123!\"}" \ | |
| "$API/auth/register/") | |
| R2=$(curl -s -o /dev/null -w '%{http_code}' \ | |
| -H 'Content-Type: application/json' \ | |
| -d "{\"name\":\"l\",\"email\":\"$LOWER\",\"password\":\"StrongPass123!\",\"password_confirm\":\"StrongPass123!\"}" \ | |
| "$API/auth/register/") | |
| [ "$R1" = "201" ] && [ "$R2" = "201" ] && ok "Both $UPPER and $LOWER registered — CLAIM CONFIRMED" \ | |
| || fail "upper=$R1 lower=$R2" | |
| # --------------------------------------------------------------------------- | |
| # Full student happy path | |
| # --------------------------------------------------------------------------- | |
| say "REGISTER student" | |
| REG=$(curl -s -H 'Content-Type: application/json' \ | |
| -d "{\"name\":\"Student\",\"email\":\"student_${TAG}@x.com\",\"password\":\"StrongPass123!\",\"password_confirm\":\"StrongPass123!\"}" \ | |
| "$API/auth/register/") | |
| ACCESS=$(echo "$REG" | python -c "import json,sys;print(json.load(sys.stdin)['access'])") | |
| [ -n "$ACCESS" ] && ok "got JWT access token" || { fail "no access token"; exit 1; } | |
| H=(-H "Authorization: Bearer $ACCESS" -H 'Content-Type: application/json') | |
| say "LIST skills catalog" | |
| N_SKILLS=$(curl -s "${H[@]}" "$API/skills/?page_size=200" \ | |
| | python -c "import json,sys;d=json.load(sys.stdin);print(d['count'])") | |
| ok "skills count = $N_SKILLS" | |
| say "LIST roles" | |
| N_ROLES=$(curl -s "${H[@]}" "$API/roles/" \ | |
| | python -c "import json,sys;print(len(json.load(sys.stdin)))") | |
| ok "roles count = $N_ROLES" | |
| say "Pick Data Scientist role" | |
| DS_ID=$(curl -s "${H[@]}" "$API/roles/" \ | |
| | python -c "import json,sys;print(next(r['id'] for r in json.load(sys.stdin) if r['role_name']=='Data Scientist'))") | |
| ok "DS role_id = $DS_ID" | |
| say "SET TARGET ROLE -> Data Scientist" | |
| curl -s "${H[@]}" -d "{\"role_id\":$DS_ID}" "$API/target-role/" > /dev/null | |
| ok "target role set" | |
| say "SET USER SKILLS (Python=70, SQL=90)" | |
| PY_ID=$(curl -s "${H[@]}" "$API/skills/?page_size=200" \ | |
| | python -c "import json,sys;print(next(s['id'] for s in json.load(sys.stdin)['results'] if s['skill_name']=='Python'))") | |
| SQL_ID=$(curl -s "${H[@]}" "$API/skills/?page_size=200" \ | |
| | python -c "import json,sys;print(next(s['id'] for s in json.load(sys.stdin)['results'] if s['skill_name']=='SQL'))") | |
| curl -s "${H[@]}" -d "{\"skill_id\":$PY_ID,\"proficiency\":70}" "$API/user-skills/" > /dev/null | |
| curl -s "${H[@]}" -d "{\"skill_id\":$SQL_ID,\"proficiency\":90}" "$API/user-skills/" > /dev/null | |
| ok "Python=70, SQL=90 set" | |
| say "GAP ANALYSIS" | |
| GAP=$(curl -s "${H[@]}" "$API/analysis/") | |
| R=$(echo "$GAP" | python -c "import json,sys;d=json.load(sys.stdin);print(d['readiness'],d['band'],d['mandatory_cap_applied'])") | |
| ok "readiness/band/cap = $R" | |
| say "RECOMMENDATIONS" | |
| REC=$(curl -s "${H[@]}" "$API/recommendations/") | |
| N_GAPS=$(echo "$REC" | python -c "import json,sys;d=json.load(sys.stdin);print(len(d['recommendations']))") | |
| ok "gap-skill keys in recs = $N_GAPS" | |
| # Pick any skill that has recommendations for the checkpoint-toggle test. | |
| RES_TITLE=$(echo "$REC" | python -c " | |
| import json,sys | |
| d = json.load(sys.stdin) | |
| for sid, items in d['recommendations'].items(): | |
| if items: | |
| print(items[0]['resource_id'], items[0]['title']); break | |
| ") | |
| RES_ID=$(echo "$RES_TITLE" | awk '{print $1}') | |
| ok "top rec resource_id = $RES_ID" | |
| say "GET resource detail (checkpoints?)" | |
| DET=$(curl -s "${H[@]}" "$API/resources/$RES_ID/") | |
| N_CP=$(echo "$DET" | python -c "import json,sys;print(len(json.load(sys.stdin)['checkpoints']))") | |
| ok "checkpoints = $N_CP" | |
| if [ "$N_CP" -gt 0 ]; then | |
| say "TOGGLE all checkpoints" | |
| for CP in $(echo "$DET" | python -c "import json,sys;print(*(c['id'] for c in json.load(sys.stdin)['checkpoints']))"); do | |
| curl -s "${H[@]}" -X POST "$API/progress/checkpoint/$CP/toggle/" -d '{"completed":true}' > /dev/null | |
| done | |
| PROG=$(curl -s "${H[@]}" "$API/progress/resource/$RES_ID/" \ | |
| | python -c "import json,sys;d=json.load(sys.stdin);print(d['status'], d['progress'])") | |
| ok "resource status/progress after all toggles = $PROG" | |
| else | |
| say "MANUAL slider to 100 (no checkpoints on this resource)" | |
| curl -s "${H[@]}" -X POST "$API/progress/resource/$RES_ID/" -d '{"progress":100}' > /dev/null | |
| ok "marked COMPLETED via slider" | |
| fi | |
| say "UPGRADE SUGGESTIONS" | |
| SUG=$(curl -s "${H[@]}" "$API/progress/upgrade-suggestions/") | |
| N_SUG=$(echo "$SUG" | python -c "import json,sys;print(len(json.load(sys.stdin)['suggestions']))") | |
| ok "pending suggestions = $N_SUG" | |
| if [ "$N_SUG" -gt 0 ]; then | |
| FIRST_SKILL=$(echo "$SUG" | python -c "import json,sys;print(json.load(sys.stdin)['suggestions'][0]['skill_id'])") | |
| say "CLAIM #1: apply the upgrade THREE TIMES in a row on the same completion" | |
| for i in 1 2 3 4; do | |
| R=$(curl -s "${H[@]}" -X POST "$API/progress/upgrade-suggestions/$FIRST_SKILL/apply/") | |
| APPLIED=$(echo "$R" | python -c "import json,sys;d=json.load(sys.stdin);print(d.get('applied'), d.get('already_applied'), d.get('user_skill',{}).get('proficiency'))") | |
| ok "call #$i applied/already/prof = $APPLIED" | |
| done | |
| echo "→ If the spec held, only call #1 would show 'applied=True'." | |
| fi | |
| say "POST-UPGRADE GAP ANALYSIS" | |
| GAP2=$(curl -s "${H[@]}" "$API/analysis/") | |
| R2=$(echo "$GAP2" | python -c "import json,sys;d=json.load(sys.stdin);print(d['readiness'],d['band'],d['mandatory_cap_applied'])") | |
| ok "readiness/band/cap = $R2" | |