
    iB                       d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z	 ddlZdZej                  j!                  dej                  j#                  ej                  j%                  e      d             ddlmZmZ ddZdd	Zdd
ZddZddZddZddZddZg dZddZ g dZ!ddZ"ddZ#e$dk(  r ejJ                   e#              yy# e$ r dZY w xY w)u  
Lightpanda 기능 검증 테스트 (Phase 3) — 독립 실행 스크립트
실행: python3 tools/tests/test_lightpanda_integration.py

주요 발견사항:
- Lightpanda는 단일 브라우저 컨텍스트만 지원 (병렬 page 생성 불가)
- 순차 크롤링은 완전히 안정적
- fetch_many() 사용 시 concurrency=1 로 설정해야 안전
- Chrome은 /devtools/browser/<UUID> 엔드포인트 사용 필요
    )annotationsNTFz../..)CrawlResultLightpandaCrawlerc                 x   t         rDt        j                  t        j                               } | j                         j                  dz  S 	 t        d      5 }|D ]:  }|j                  d      st        |j                         d         c cddd       S  	 ddd       y# 1 sw Y   yxY w# t        $ r Y yw xY w)uB   현재 프로세스 RSS(Resident Set Size)를 KB 단위로 반환.i   z/proc/self/statuszVmRSS:   N)_HAS_PSUTILpsutilProcessosgetpidmemory_inforssopen
startswithintsplit	Exception)procflines      X/home/jay/workspace/.worktrees/task-2116-dev1/tools/tests/test_lightpanda_integration.py_get_rss_kbr   '   s    ~~biik*!%%--%& 	0! 0??8,tzz|A//	0 	00	0 	0   sB   B- B!/B!	B- B!B- !B*&B- *B- -	B98B9c                     t         j                  j                  dd      5 } t        j                  | j                               }ddd       |d   S # 1 sw Y   d   S xY w)uA   Chrome CDP의 browser-level WebSocket URL을 동적으로 조회.z"http://127.0.0.1:9222/json/version   )timeoutNwebSocketDebuggerUrl)urllibrequesturlopenjsonloadsread)respinfos     r   _get_chrome_ws_urlr&   6   sY    			 Da		P 'TXzz$))+&'&'''&''s   $AA c                T    t        dd        t        d|         t        d        y )N
zF======================================================================  print)titles    r   _sectionr-   =   s(    	Bvh-	Bug,	VH    c                     t        d|         y )Nz	  [PASS] r*   msgs    r   _okr2   C       	IcU
r.   c                     t        d|         y )Nz	  [FAIL] r*   r0   s    r   _failr5   G   r3   r.   c                     t        d|         y )Nz	  [INFO] r*   r0   s    r   _infor7   K   r3   r.   c            	       K   t        d       dg d} 	 t        dd      4 d {   }|j                  d       d {   }d d d       d {    t        dj                          t        d	|j
                  d
d       t        d|j                         t        d|j                  d d        t        dt        |j                                |j                  d d D ]  }t        d|         d}|j                  dk(  rt        d       n<t        d|j                  d       | d   j                  d|j                         d}d|j                  v rt        d       n!t        d       | d   j                  d       d}t        d |j                  D              }|r-|j                  D cg c]	  }d|v s| }}t        d|        n/t        d|j                   d       | d   j                  d        d}| j                  ||j                  |j                  d d t        |j                        |j
                  |j                  d!       | S 7 <7 &7 # 1 d {  7  sw Y   *xY wc c}w # t        $ rJ}t        d"|        t!        j"                          | d   j                  t%        |             Y d }~| S d }~ww xY ww)#Nu"   3-1. 기본 테스트: example.comFpassedissuesws://127.0.0.1:9333ws://127.0.0.1:9222)cdp_endpointchrome_endpointhttps://example.com   엔진: elapsed_ms: .1f mstitle: u   text (앞 100자): d   u   links 수: r   u
     링크: TzExample Domainztitle == 'Example Domain'u   title 불일치: u    (기대값: 'Example Domain')r;   u   text에 'Example Domain' 포함u"   text에 'Example Domain' 미포함u   text에 'Example Domain' 없음c              3  $   K   | ]  }d |v  
 yw)iana.orgN ).0lnks     r   	<genexpr>z#test_example_com.<locals>.<genexpr>v   s     Css*Cs   rH   u   links에 iana.org 포함: u+   links에 iana.org 미포함 (전체 links: )u   iana.org 링크 없음)r:   r,   text_previewlinks_count
elapsed_msengine   예외 발생: )r-   r   fetchr7   rQ   rP   r,   textlenlinksr2   r5   appendanyupdater   	traceback	print_excstr)	result_datacrawlerresultrK   r:   
iana_foundlmatchedes	            r   test_example_comrd   S   s    12#(B7K4-$.1
 	M 	M (/6K(L"LF		M 	M 	()V..s3378'()#FKK$5#89:C-./0<<# 	&CJse$%	& <<+++,%fll%55STU!((76<<2B)CDFv{{*1267!(()JKFCfllCC
"(,,BQ*/qBGB,WI67?~QOP!(()ABF\\"KK-v||, ++mm
 	 k	M #M		M 	M 	M 	M@ C   -s#$H$$SV,,-s   KJ I!J I*I$I*J I'E,J ;	J J 	BJ K!J $I*'J *I=0I31I=8J 	K?KKKKc            	     x  K   t        d       dg d} t        d       t        d       	 t               }t        d|        t        d|d	      4 d {   }|j	                  d
       d {   }d d d       d {    t        dj
                          t        d|j                  dd       t        d|j                         t        d|j                  d d        d}t        d |j                  D              }|rt        d       n!t        d       | d   j                  d       d}d|j                  vrt        d       n!t        d       | d   j                  d       d}d|j                  v rt        d       n!t        d       | d   j                  d       d}t        d        	 t        d!dd"	      4 d {   }|j	                  d
       d {   }d d d       d {    t        d#j                          | j#                  ||j                  |j                  d d |j                  |j
                  |d(       | S 7 7 7 # 1 d {  7  sw Y   xY w7 7 7 # 1 d {  7  sw Y   xY w# t        $ rK}t        d$t        |      j                   d%t!        |      d d&         t!        |      d d | d'<   Y d }~d }~ww xY w# t        $ rJ}	t        d)|	        t%        j&                          | d   j                  t!        |	             Y d }	~	| S d }	~	ww xY ww)*NuC   3-2. 한글 페이지 크롤링: ko.wikipedia.org/wiki/대한민국Fr9   u^   주의: Lightpanda는 대형 한글 페이지(ko.wikipedia.org)에서 TargetClosedError 발생u;   Chrome fallback을 통해 한글 인코딩 테스트 수행Chrome WS URL: ws://invalid:00u  r>   r?   
timeout_mszBhttps://ko.wikipedia.org/wiki/%EB%8C%80%ED%95%9C%EB%AF%BC%EA%B5%ADrA   rB   rC   rD   rE   u   text (앞 200자):    Tc              3  <   K   | ]  }d |cxk  xr dk  nc   yw)u   가u   힣NrI   )rJ   chs     r   rL   z#test_korean_page.<locals>.<genexpr>   s     JR3833J   u#   text에 한글 문자 포함 확인u6   text에 한글 문자 없음 (인코딩 문제 가능)r;   u   한글 문자 없음u   �u   인코딩 깨짐(U+FFFD) 없음u"   인코딩 깨짐(U+FFFD) 감지됨u   인코딩 깨짐u   대한민국u   text에 '대한민국' 포함u    text에 '대한민국' 미포함u   '대한민국' 텍스트 없음u0   
  [Lightpanda 직접 시도 (에러 확인용)]r<   i N  u/     Lightpanda 성공 (예상치 못한 결과): u     Lightpanda 예상 실패: z: x   lp_error)r:   r,   rN   rP   rQ   
has_hangulrR   )r-   r7   r&   r   rS   rQ   rP   r,   rT   rX   r2   r5   rW   r   type__name__r\   rY   rZ   r[   )
r]   	chrome_wsr^   r_   r:   rq   
lp_crawler	lp_resultlp_errrc   s
             r   test_korean_pagerx      s;    RS#(B7K 

jk	
GHI-&(		{+, %)%
 	 	 (/T) #F	 	 	()V..s3378'()#FKK$5#89: JfkkJJ
56JK!(()?@F 6;;&1267!(();<FV[[(/045!(()JKF 	AB	8(2 0    ","2"2X# 	  CIOOCTUV
 	\\"KK- ++mm$
 	 M	
#	 	 	 	V
     	80f1F1F0Gr#f+VZWZJ[I\]^&)&k$3&7K
#	8  -s#$H$$SV,,-s  'L:*K$ IK$ I-I.I2K$ =I>D7K$ 6J I2	J I8!I4"I8&J 1I62J AK$ L:K$ IK$ I/"I%#I/*K$ 2J 4I86J 8J
>J?J
J 	K!AKK$ K!!K$ $	L7-?L2,L:2L77L:)r@   https://example.org;https://en.wikipedia.org/wiki/Python_(programming_language)(https://en.wikipedia.org/wiki/JavaScript#https://en.wikipedia.org/wiki/Linuxz9https://en.wikipedia.org/wiki/Rust_(programming_language)z7https://en.wikipedia.org/wiki/Go_(programming_language)z(https://en.wikipedia.org/wiki/TypeScriptz)https://en.wikipedia.org/wiki/WebAssemblyz/https://en.wikipedia.org/wiki/Docker_(software)z(https://en.wikipedia.org/wiki/Kubernetesz(https://en.wikipedia.org/wiki/PostgreSQLc                 \  K   t        dt        t               d       dg d} t        d       t	               }t        d| d       	 t        dd	d
      4 d {   }t        j                         }|j                  t        d       d {   }t        j                         |z
  dz  }d d d       d {    t	               }t        d| d||z
   d       d}t        d D              }|rt        dt        |       d       nt        d       d}t        ddd|dz  dd       t        d|t        |      z  dd       t                t        ddd d!d"d#d!d$d%       t        dd& d!d' d!d(        |D ][  }	|	j                  j                  d)d*      }
|
j                  d+d,      }
t        d|
d d!|	j                  d#d!|	j                   d-       ] | j#                  |t        |      ||||D 	cg c]%  }	|	j                  |	j                   |	j                  f' c}	d.       | S 7 7 7 # 1 d {  7  sw Y   xY wc c}	w # t$        $ rJ}t        d/|        t'        j(                          | d0   j+                  t-        |             Y d }~| S d }~ww xY ww)1Nu   3-3. 대량 크롤링 (u   개 URL)Fr9   u]   주의: Lightpanda는 단일 컨텍스트만 지원하므로 concurrency=1 (순차 크롤링)u   시작 전 메모리 RSS: z KBr<   r=   rh   ri   r   concurrency  u   종료 후 메모리 RSS: u    KB  (증가: z KB)Tc              3  <   K   | ]  }t        |t                y wN)
isinstancer   rJ   rs     r   rL   z"test_bulk_crawl.<locals>.<genexpr>  s     Kaz![9Krn   u   모든 u&   개 결과가 CrawlResult 인스턴스u&   일부 결과가 CrawlResult가 아님u   총 소요 시간: z.0fz ms (.2fu    초)u   평균 소요 시간: u    ms/페이지r)   URL65s u   엔진12srP   z>10szA-----------------------------------------------------------------z------------z
----------https://en.wikipedia.org/wiki/wp::https:// z>10.1f)r:   	url_counttotal_msmem_before_kbmem_after_kbindividual_msrR   r;   )r-   rU   	BULK_URLSr7   r   r   time	monotonic
fetch_manyallr2   r5   r+   urlreplacerQ   rP   rY   r   rZ   r[   rW   r\   )r]   
mem_beforer^   t_startresultsr   	mem_afterr:   all_crawl_resultr   	short_urlrc   s               r   test_bulk_crawlr      s    &s9~&6h?@#(B7K	
ijJ	&zl#
67.-$.1
 	; 	; nn&G#..ya.HHG(72d:H	; 	;  M	*9+^IPZDZC[[_`aK7KK'#g,'MNO:;F#HS>x}S6IOP&xG'<S&AOP5+QxnAl4-@AB6(!F81VH-. 	MA&FOI!))*b9IByoQqxxnAall65JKL	M
 	W '%GNO!quuallAHH=O
 	 _	; I	; 	; 	; 	;N P  -s#$H$$SV,,-s   AJ,	I H2I /H;H5H;-I 8H89EI =*I'	I 0J,2I 5H;8I ;III	I 	J)?J$J,$J))J,)r@   ry   rz   r|   r{   c                 
  K   t        d       dg d} g }g }d}d}	 t               }t        d|        t        d       	 t        d	d
d      4 d {   }t        j                         }|j                  t        d       d {   }t        j                         |z
  dz  }d d d       d {    |D ]Z  }	|	j                  j                  dd      j                  dd      }
t        d|
dd|	j                  dd|	j                  dd       \ 	 t        d       	 t        d
|d      4 d {   }t        j                         }|j                  t        d       d {   }t        j                         |z
  dz  }d d d       d {    |D ]Z  }	|	j                  j                  dd      j                  dd      }
t        d|
dd|	j                  dd|	j                  dd       \ 	 t                |r^|r[t        dd d!d"d#d$d"d%d$       t        dd& d"d' d"d'        t        dd(d!d"|d)d*|d)d+       t        dd,d!d"|t%        |      z  d)d*|t%        |      z  d)d+       |d-kD  r5|d-kD  r0||k  r||z  }t'        d.|d/d0       n||z  }t        d1|d/d2       t)        d3 |D              }t)        d4 |D              }t        d5|        t        d6|        |d7hk(  rt'        d8       n%t	        d9|        | d   j                  d:|        |d;hk(  rt'        d<       n%t	        d=|        | d   j                  d=|        | j+                  t-        |xr |      |||D 	cg c]%  }	|	j                  |	j                  |	j                  f' c}	|D 	cg c]%  }	|	j                  |	j                  |	j                  f' c}	d>       | S # t        $ r1}t	        d|        | d   j                  d|        | cY d }~S d }~ww xY w7 7 7 w# 1 d {  7  sw Y   xY w# t        $ rD}t	        d|        t!        j"                          | d   j                  d|        Y d }~sd }~ww xY w7 ]7 -7 # 1 d {  7  sw Y   xY w# t        $ rD}t	        d|        t!        j"                          | d   j                  d|        Y d }~d }~ww xY wc c}	w c c}	w w)?Nu'   3-4. Chrome vs Lightpanda 성능 비교Fr9   g        rf   u   Chrome WS URL 조회 실패: r;   u(   
  [Lightpanda 전용 — concurrency=1]r<   rg   rh   ri   r   r~   r   r   r   r   r   r)   55sz	  engine=r   z>8.1frD   u   Lightpanda 크롤링 실패: zLightpanda: u$   
  [Chrome 전용 — concurrency=5]r   u   Chrome 크롤링 실패: zChrome: u   항목35sr   
Lightpandaz>15sChromez#-----------------------------------z---------------u   총 소요 시간 (5페이지)z>12.0fzms msu   평균 소요 시간r   u   Lightpanda가 Chrome보다 r   u+   배 빠름 (순차 vs 병렬 비교 주의)u+   Chrome(병렬)이 Lightpanda(순차)보다 u
   배 빠름c              3  4   K   | ]  }|j                     y wr   rQ   r   s     r   rL   z.test_performance_comparison.<locals>.<genexpr>  s     6a6   c              3  4   K   | ]  }|j                     y wr   r   r   s     r   rL   z.test_performance_comparison.<locals>.<genexpr>  s     >!QXX>r   u!   Lightpanda 결과 엔진 집합: u   Chrome 결과 엔진 집합: 
lightpandau,   Lightpanda 결과 모두 engine='lightpanda'u   Lightpanda 엔진 혼재: u   LP 엔진 혼재: chromeu$   Chrome 결과 모두 engine='chrome'u   Chrome 엔진 혼재: )r:   lp_total_mschrome_total_mslp_individualchrome_individual)r-   r&   r7   r   r5   rW   r+   r   r   r   r   COMPARE_URLSr   r   rQ   rP   rZ   r[   rU   r2   setrY   bool)r]   
lp_resultschrome_resultsr   r   rt   rc   r^   r   r   shortratio
lp_engineschrome_enginess                 r   test_performance_comparisonr   H  so    67#(B7K$&J(*NK O&(		{+, 

569$.,
 	> 	> nn&G&11,A1NNJ>>+g5=K	> 	>  	TAEEMM"BFKSST^_abEBuSk188C.1<<:NcRS	T 

125$)%
 	B 	B nn&G#*#5#5lPQ#5#RRN#~~/'9TAO	B 	B   	TAEEMM"BFKSST^_abEBuSk188C.1<<:NcRS	T 
Gn8C.,t!4Aht_EF6(!F81VH-.3C8+f9MSQ`agPhhjkl)#.aC
O0KF/SSVWfgjkygzWz  |B  WC  CE  F  	G?2_,'+51%<ghi#o5CE#;jYZ 6:66
>~>>1*>?-n-=>?,'>?.zl;<!((+=j\)JKhZ'67*>*:;<!((+A.AQ)RSz4n5"*CMNa155!,,9NGUV!quuallAHH=V  s  -aS12H$$qc%:;	> O	> 	> 	> 	>  9-aS12H$$|A3%7889	B S	B 	B 	B 	B  5)!-.H$$xs^445V OVsV  TO# T P? P P? /P)P#P)$P? /P&0A#P? T R. 2R3R. 6/R%R&RR. RA#R. 3FT>*S>(T.*TT#	P,&PPTPT P? #P)&P? )P</P20P<7P? ?	R9RTRTR. RR. R+R!R+&R. .	S;79S60T6S;;Tc                   K   t        d       t        d       t        dt        j                  d             t        d       i } t                d {   | d<   t	                d {   | d<   t                d {   | d<   t                d {   | d	<   t        d
       d}| j                         D ][  \  }}|j                  d      rdnd}|j                  d      sd}|j                  dg       }|rd| nd}t        d| d| |        ] t                |rt        d       nt        d       t        j                  |rd       y d       y 7 7 7 7 ˭w)NzG
######################################################################u.     Lightpanda 기능 검증 테스트 (Phase 3)u     실행 시각:z%Y-%m-%d %H:%M:%SzF######################################################################z3-1_example_comz3-2_korean_pagez3-3_bulk_crawlz3-4_perf_compareu   최종 요약Tr:   PASSFAILFr;   u   
    -> 이슈: r   z  [z] u(     최종 결과: 모든 테스트 통과u<     최종 결과: 일부 테스트 실패 (위 이슈 확인)r   r   )r+   r   strftimerd   rx   r   r   r-   itemsgetsysexit)summary
all_passednamedatastatusr;   	issue_strs          r   mainr     sA    	/	
:;	
dmm,?@A	(O!G'7'9!9G'7'9!9G&5&7 7G(C(E"EG _Jmmo 1
d88H-6xx!J(B'4:'x0	F82dVI;/01 
G89LMHH*Q$!$- ":!9 7"EsI   AEEE'E(E<E=EECEEEE__main__)returnr   )r   r\   )r,   r\   r   None)r1   r\   r   r   )r   dict)r   r   )&__doc__
__future__r   asyncior!   r   r   r   rZ   unicodedataurllib.requestr   r
   r	   ImportErrorpathinsertjoindirname__file__tools.lightpanda_crawlerr   r   r   r&   r-   r2   r5   r7   rd   rx   r   r   r   r   r   rs   runrI   r.   r   <module>r      s   	 #   	 
    K 277<< 97C D C(:BTv	 9@fZ%B zGKK w  Ks   C C#"C#