Files
falah-mobile/tests/__pycache__/qa-learn-prod.cpython-312.pyc
T

196 lines
37 KiB
Plaintext
Raw Normal View History

Ë
†];jpãó¸dZddlZddlZddlZddlZddlZddlZddlZddl Zddl
Z
ddl Z ddl m
Z
mZddlmZddlmZej&j)dd«adad \aaagZd
Zd Zd Zd
ZdZdZ dZ!dZ"dZ#dZ$e
jJ«Z&d'dZ'd(dZ(dZ)dZ*dZ+gd¢Z,dZ-dZ.dZ/Gdde«Z0dZ1d „Z2d!„Z3gd"¢Z4d#„Z5d$„Z6d%„Z7e8d&k(re7«yy))u 
Falah Mobile Production QA — Learn Feature + Full Suite
======================================================
8-Layer QA with browser testing, auth flows, and CAB compliance.
Usage:
/usr/bin/python3.12 tests/qa-learn-prod.py [--url https://falahos.my/mobile]
éN)Ú dataclassÚfield)Ú
HTMLParser)ÚPathÚBASE_URLzhttps://falahos.my/mobileF)rrrzzzzzcó|tdz
atdtdtd|«tj d|f«y)ú u✓ú ÚPASS)r ÚprintÚREPORTÚappend©Úmsgs ú9/root/falah-core/apps/falah-mobile/tests/qa-learn-prod.pyÚokró6œD !™G˜D¤U¨R´¨s°#´a°S¸¸#¸Ð+?Ô%@Ä&Ç-Á-ÐQWÐX[ÐP\ÕB]ócó|tdz
atdtdtd|«tj d|f«y)Nr r
õ✗r ÚFAIL)rr
ÚRrrrrs rÚfailrrrcó|tdz
atdtdtd|«tj d|f«y)Nr r
uâš r ÚWARN)rr
ÚYrrrrs rÚwarnr rrcóštdtdt«ttd|t«ttdt«y)
ulâ•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•r
©r
ÚCr©Útitles rÚsecr'˜œ1˜#ðJôKLðJMðNôOôQVôZ[ðY\ð\^ð_dð^eôfgðehðWiôQjôlqôuvðtwðwcôdeðcfðrgõlhrcó<tdtd|dt«y)Nr"u── u ──r#r%s rÚsubr)s˜œ1˜#˜W U G¨7´1°#Ð7rcóÀtjd«d|jd«}dddœ}|r|j|«|r|j «nd}t j
«} t jj||||¬«} t jj| |t¬«5}
|
j«} | jdd¬ «} |
jt|
j«| t j
«|z
d
œcddd«S#1swYyxYw#t j j"$rd}
|
j«} |
j$t|
j«| jdd¬ «t j
«|z
d
œcYd}
~
Sd}
~
wt&$r/}
d it)|
«t j
«|z
d
œcYd}
~
Sd}
~
wwxYw) /zFalah-QA-Prod/1.0z*/*)z
User-AgentÚAccept)ÚdataÚheadersÚmethod)ÚtimeoutÚcontextzutf-8Úreplace)Úerrors)Ústatusr.ÚtextÚelapsedr)rÚrstripÚlstripÚupdateÚencodeÚtimeÚurllibÚrequestÚRequestÚurlopenÚctxÚreadÚdecoder4Údictr.ÚerrorÚ HTTPErrorÚcodeÚ ExceptionÚstr)Úpathr/r.Úbodyr0ÚurlÚhdrsr-Út0ÚrespÚrawr5Úes rÚreqrRÜ
_‰_˜
" ! D§K¡K°Ó$4Ð#5Ð
6€CØÑ ?€DÙ ˜GÔ ˆ4;‰;Œ= d€DÜ
€Bð
WÜ N‰N× " 3¨T¸Ð OˆÜ
^‰^×
# A¨wÄÐ
 sÈØ—)‘)“+ˆCØ—::˜g¨i8ˆ"Ÿk™k´d¸4¿<¹<Ó6HÐRVÔcg×clÑclÓcnÐoqÑcqÑ s÷ sò sûô <‰<× HØf‰fhˆØŸ&™&¬T°!·)±)«_ÀcÇjÁjÐQXÐajÀjÓFkÔx|÷yBñyBóyDðEGñyGñHõ HûÜ òWب´C¸³FÄtÇyÁyÃ{ÐSUÁ~ÑVûðWúsQÁ+A D&Â4ADÄ D&ÄD#ÄD&Ä#D&Ä&GÅAF"ÆGÆ" GÆ.$GÇGÇGcórt||||«}tj|d«|d<|S#d|d<Y|SxYw)Nr5Újson)rRrTÚloads)rIr/r.rJrNs rÚjson_reqrV/sAÜ ˆD&˜' (€AÜ—ZZ  &¡ Óˆ6‰à €Høð˜ˆAˆfŠIØ €Hús,¬6c
ó”tdddditjdddœ«¬«}|d r|d jd
«r|d d
Sy ) zLogin and return JWT token.zapi/auth/loginÚPOSTú Content-Typezapplication/jsonzdemo@falahos.myÚ password123)ÚemailÚpassword)r.rJrTÚtokenN)rVrTÚdumpsÚget)rNs rÚ get_tokenr`5sWäÐ! Ð!3Ð
Z‰ZÐ!2¸
 O€Að ˆyQvY—]‘] ‰y˜Ñ rc óätd«ddddhfdddhfdd dhfd
d dhfd d
dhfddddhfg}|D]v\}}}t|«}|ddk(rt|d|d|ddd«Œ4|d|vr"t|d|d|dd|ddzdd«Œ]t|d|d|dd|d«Œxt d«d D]8}t|«}|dd!k(rt|d"«Œ%t |d#|dd$«Œ:y)%Nu1LAYER 1: SYSTEM — Route Existence & HTTP Statusr+ú Landing pageéÈi4ú/learnzLearn catalog pageú/verify/ABC123zCertificate verificationú /api/healthú
Health APIú/api/learn/courseszLearn courses APIz /api/learn/courses/atomic-habitszCourse detail (no auth)é‘r4rú (u) — CONNECTION FAILED: r5éPu) → z in r6éèú.0fÚmsz (expected ú)uNon-existent routes → 404)z/this-does-not-existz/api/nonexistentz/learn/nonexistent-routeé”u → 404õ → z (expected 404))r'rRrrr)r )ÚroutesrIÚlabelÚexpectedrNs rÚ layer_systemruAsoÜÐ ˆn˜s C˜Ð'¨#¨ÐÐ5¸°uИ  s eÐÐ2°S°EÐ:Ø +Ð-FÈÈcÈ
Ð
€Fð"(òNшˆe ‹IˆØ ˆX‰;˜ Ü E7˜"˜T˜FÐ";¸A¸f¹IÀcÀr¸NÐ;KÐ
ˆx‰[˜
%˜˜4˜&  ¡{ m°4¸¸ ÀTÑ8IÈ#Ð7NÈbÐ E7˜"˜T˜F ¨8©¨
°[ÀÀ
È!Ð NôÐÜ ‹IˆØ ˆX‰;˜#Ò Ü $ Õ D6˜˜q ™{˜m¨?Ð =rcóøtd«td«td«}|drP|djd«dk(r9t d|djd«d |djd
d «d d
«nt dt
|d«dd«td«td«}|ddk7rt d|d«y|d}|rd|vrt dt
|«dd«yt|dt«s t d«yt dt|d«d«t|d«D]x\}}hd£}|t|j««z
}|r%t d|d|jdd«d|«ŒMt d|d|dd |d!d"|d#d$|d%d&|d' «Œztd(«td)«}|dd*k(r t d+«ntd,|dd-«td.«t«}|s t d/«ytd)d0d1|i¬2«}|ddk7rt d3|d«y|d}|s t d4«yd5|vrt d6t
|«dd«y|d5}hd7£}|t|j««z
}|rt d8|«nt d9|dd:|d#d;«d<|vst|d<t«s t d=«n³|d<} t d>t| «d?«t| «D]ˆ\}}
hd@£} | t|
j««z
} | r%t dA|d|
jdd«dB| «ŒMt|
jdCg««}
t dA|dDzd|
ddE|
dFd&|
dG «ŒŠtdH«tdI«}|ddk(r,t dJ« |d}t dKt
|«dd«ytdM|d«y#t dL«YyxYw)NNu)LAYER 2: API — Response Shape ContractszContract: Health APIz
api/healthrTr4ruHealth API — status=ok, db=Údbz , uptime=ÚuptimerrmÚsuHealth API — unexpected: édzContract: Learn Courses APIúapi/learn/coursesrcuCourses API → HTTP Úcoursesu'Courses API — missing 'courses' key: u'Courses API — 'courses' is not a listuCourses API — z course(s) returned> ÚidÚslugr&ÚauthorÚpriceFlhÚpriceUsdÚ
difficultyÚ descriptionÚ moduleCountÚ totalMinutesÚsubscriptionOnlyzCourse #z ('r&ú?u') — missing fields: z: 'z' by ru — r„z
modules, r…zmin, ru)Contract: Course Detail (no auth → 401)úapi/learn/courses/atomic-habitsriu,Course detail without auth → 401 (correct)uCourse detail without auth → z (expected 401)z#Contract: Course Detail (with auth)u"Cannot get auth token — skippingÚ
AuthorizationúBearer ©r.u!Course detail with auth → HTTP uCourse detail — not JSONÚcourseu(Course detail — missing 'course' key: > r}r~r&rÚ giteaPathrr„r…u"Course detail — missing fields: uCourse detail — 'z', z modulesÚmodulesu4Course detail — missing or invalid 'modules' arrayuCourse detail — z module(s) with content+quiz>r}r~Úorderr&ÚcontentÚdurationÚquizDataÚ keyTakeawayzModule #u') — missing: rr õ' — rz quiz Qsz"Contract: Certificate Verificationú
verify/ABC123uVerify page — 200 OKuVerify — JSON response: u(Verify — HTML response (rendered page)õ Verify → )r'r)rVr_rrrHÚ
isinstanceÚlistÚlenÚ enumerateÚsetÚkeysr r`)rNÚrequiredÚmissingÚr_unauthr]Úr_authÚmodsÚmreqÚmmissingÚ
quiz_countÚr_verifyÚjvs rÚ layer_apir«`sÜÐÐÔÜÓ€A؈‚yQv‘Y—]‘] 8ÓÒ
Ð
*¨1¨V©9¯=©=¸Ó+>Ð*?¸È6ÉÏÉÐW_Ð`aÓIbÐcfÐHgÐghÐ  Ð*¬3¨q°©y«>¸$¸3Ð+?Ð*@Ð
ÐÐ%€A؈{Ü Ð$ Q x¡[ 
Ø ˆ&‰ €AÙ  Ñ Ð6´s¸1³v¸d¸s°|°nÐ
Ü a˜ ‘l¤DÔ  ÐÜÐ œ#˜a  ™lÓ,Ð,?И!˜I™,ÓJˆˆ1ò]ˆØœS §¡£›]ÑÙ Ü 8˜A˜3˜c !§%¡%¨°Ó"4Ð!5Ð5LÈWÈIÐ ˜!˜˜C  
˜|¨5°°8±°
¸UÀ1À]ÑCSÐBTÐT^Ð_`ÐaoÑ_pÐ^qÐqvÐwxðzFñxGðwHðIõ
Jð
JôÐÐ:€HØÑ˜SÒ Ü
Ð  Ð.¨x¸Ñ/AÐ.BÀ/Ð
Ð ‹K€EÙ Ü Ð
Ü
Ð7À/ÐU\Ð]bÐ\cÐSdÐAeÔ
f€FØ
ˆhј3ÒÜ Ð¸Ñ1AÐ0BÐ
؈v‰€AÙ Ü Ð
ØÜ иA»¸tÀ¸ °~Ð
Ø ˆ(‰ €AÚy€HØœ˜QŸV™V›X›Ñ&€GÙÜ Ð1°'°Ð

Ð
  7¡  ¨C°°-Ñ0@Ð/AÀÐ ˜Ñ¤¨A¨i©L¼$Ô!?Ü Ð
‰|ˆÜ
Ð
¤ D£ ˜{Ð*FÐ ˜d“Oò b‰DˆAˆeˆœc !§&¡&£(+ˆÜx ˜s # a§e¡e¨G°CÓ&8Ð%9Ð9IÈ(ÈÐ  §¡ z°2Ó!6Ó7
ÜX˜™c˜U # a¨¡j ¸¸*¹
°ÀeÈJÈ<ÐW_Ð bôИÓ(€HØÑ˜SÒ Ü
Ð ˜!ˆ Ð+¬C°«G°D°S¨M¨?Ð 
ˆ{˜8 
0øð Ð :ús Î8O*Ï*
O9)
zInvalid responsezInternal Server ErrorzApplication errorzCannot read properties ofzundefined is notÚ TypeErrorzFailed to fetchz 500 InternalzJSON Parse errorzUnexpected tokenzCannot find modulezMinified React errorz not foundc
ó‚td«ddddgfdddd gfd
d d d
gfg}|D]\}}}t|«}|d}t|«dkrt|d|dt|«d«ŒDtDcgc]*}t j ||t
j«sŒ)|Œ,}}|rt|d|d|«nt|d|dt|«d«|j«}|D]=} | j«|vrt|d|d| d«Œ*t|d|d| d«Œ?Œtd«tD]€}
g} dD]E}t j |
t|«dt
j«sŒ5| j|«ŒG| r!td|
ddj| ««Œrtd|
d«Œ‚ycc}w)Nu+LAYER 3: RENDER — HTML Content Validationr+ÚLandingÚFalahÚAssalamualaikumrdz
Learn CatalogÚLearnÚCourserezVerify CertificateÚVerifyÚ Certificater5éôrju
) — small (zB)u) — ERROR in HTML: u
) — clean (u) — contains "ú"u) — MISSING "zGlobal error pattern scan©r+rdrez Pattern "z" on: ú, u " — absent)r'rRr™r ÚERROR_PATTERNSÚreÚsearchÚ
IGNORECASErrÚlowerr)rÚjoin) ÚpagesrIrsrtrNÚhtmlÚpr3rÚesÚpatÚhitss rÚ layer_renderrÅÈÜÐ ˆi˜'Ð#4Ð? W¨hÐ$7ÐÐ/°(¸MÐ1JÐ
€Eð
"'óˆˆe ‹IˆØ‰yˆÜ ˆt9sŠ?Ü E7˜"˜T˜F -´°D³ ¨{¸ ÜQ˜¬r¯y©y¸¸DÄ"Ç-Á-Õ/PQˆÐ Ü E7˜"˜T˜FÐ"7¸°xÐ %˜˜4˜& 
¬c°$«i¨[¸Ð —*‘*“,ˆØò ?ˆBØx‰xz˜eW˜B˜t˜fÐ$5°b°T¸Ð˜w˜b  Ð&6°r°d¸?ô(ÐòØˆØ ˆAÜy‰y˜œc !f V™n¬b¯m©mÕ ˜A•ð ñ Ü :˜c˜U '¨$¯)©)°D«/Ð):Ð ˜C˜5 
Ð 0ùòRs Á.*F<ÂF<có¶td«td«dD]9}t|«}|ddk(rtd|d«Œ&t d|d|d«Œ;td «t «}|rtd
|dd d |d
dd«n t
d«ytd«td«}|drGt|djdg««dkDr&|ddd}|d}td|dd|d«n t
d«ytd«td|dd|i¬«}|drp|djd«r\|dd}td t|«d!«|D]6}td"|dd#|d$d%t|jd&g««d'«Œ8n t
d(«td)«td*«} | ddk(r td+«yt d,| d«y)-Nu(LAYER 4: SCENARIO — Real User Journeysz0Scenario A: First-time visitor (unauthenticated))r+rdr4rczUnauthenticated u — accessiblerqzScenario B: Login flowuLogin — obtained token (éú...éüÿÿÿrouLogin — no tokenz*Scenario C: Browse courses (authenticated)r{rTr|rr~uCourses listed — r&z (slug: zNo courses foundz+Scenario D: View course detail with modulesúapi/learn/courses/r‰ruCourse detail loaded — z
module(s)z Module: 'r”rz min, quiz: rz Qsu#Course detail — no modules loadedz$Scenario E: Certificate verificationr•z#Certificate verification page loadsr)
r'r)rRrr r`rrVr™r_)
rIrNr]Úr_listrŒr~Úr_detailr¤Úr_vers
rÚlayer_scenariorÎñs(ÜÐÐòÜ ‹IˆØ ˆX‰;˜#Ò Ü Ð! $  Ð Ð# D ¨q°©{¨mÐ Ð Ô ‹K€EÙ Ü
Ð
¨c¨r¨
 |°3°u¸R¸S°z°lÀ!Ð  Ð
ôÐ
Ð
*€FØ
ˆf‚~œ#˜f V™n׸BÓ@À1Ò˜  Ñ*¨1ÑØf‰~ˆÜ
Ð
 ¨¡Ð 1°¸$¸¸qÐ  Ð
Ô ØäÐÐ,¨T¨FÐ3¸oÐQXÐY^ÐX_ÐO`Ð=aÔb€HØÒ˜H VÑԘѠ ÑÜ
Ð
&¤s¨4£y Ð ò iˆAÜ ˜Q˜w™Z˜L¨¨q°©}¨o¸[ÌÈQÏUÉUÐS]Ð^`ÓMaÓIbÐHcÐcfÐ  iô
Ð
Ð Ó €EØ ˆX˜#ÒÜ
Ð  ˆ{˜5 ™?Ð
-rc óÌtd«td«d}dD]@}t|d|i¬«}|ddvrt|d |dd
«Œ.t |d |d«ŒBtd «d D]R}d
|d|fD]C}t |«}|ddvrtd|ddd|d|d«Œ0t d|d|d«ŒEŒTtd«dD]@}t d
|«}|ddvrtd|d|d«Œ-t d|d|d«ŒBtd«dD]F}t d|«}|ddvrtd|ddd|d«Œ0t d|ddd|d«ŒHtd«gŠˆfd „}t
d!«Dcgc]}tj||f¬"«Œ}}tj«} |D]}
|
j«Œ|D]}
|
j«Œtj«| z
} td#„D««} td$„D««t«z d%z}
| d!k(rtd&|
d'd(| d)d*«yt d+| d,|
d'd-«ycc}w).Nu-LAYER 5: EDGE — Resilience & Error Handlingz+Edge: Invalid auth token on learn endpointsz6Bearer eyJhbGciOiJIUzI1NiJ9.eyJpZCI6ImZha2UifQ.invalid)rˆr‰rr4)rircu with bad token → z (graceful)zEdge: SQL injection attempts)z
' OR 1=1--z'; DROP TABLE courses;--z " OR "1"="1rÊzlearn/)rpérizSQLi 'éz...' on rqzSQLi on z#Edge: Path traversal in course slug)z../../../etc/passwdz..%2F..%2F..%2Fetc%2FpasswdzPath traversal 'u' → zEdge: Invalid verify codes)Úz INVALID!@#$Áèaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaazverify/)rcrpz
Verify code 'ézEdge: Rapid fire (burst test)cóPtd«}j||d|df«y)Nr{r4r6)rRr)ÚnrNÚresultss €rÚfirezlayer_edge.<locals>.fireMs)ø€Ü Рؘ˜1˜X™;¨¨)© Ð6ré
)ÚtargetÚargsc3ó4K|]\}}}|dk(sŒ
dŒy­w)rcr )Ú.0Ú_rys rú <genexpr>zlayer_edge.<locals>.<genexpr>Usèø€Ò8™˜˜A˜q¨q°C«x”1Ñ8ùsc3ó(K|]
\}}}|Œ y­w©NrÝ)rQs rzlayer_edge.<locals>.<genexpr>Vsèø€Ò*wq˜!˜Q”Ñ*ùsrluBurst — 10/10 OK (avg rmz
ms, total z.1fzs)u
Burst — z /10 OK (avg zms))r'r)rVrr rRÚrangeÚ threadingÚThreadr;Ústartr¾Úsumr™)ÚbadrIrNÚpayloadr~rFÚthreadsrMÚtr6Úok_countÚavg_msr×s @rÚ