Ë
    mÆjš"  ã                   óÊ   — d 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dlZ
ddlmZ ddlmZ dZdZdZdZd	„ Zd
„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zedk(  r e«        yy)aú  
Staged multi-merchant load test: CloudLayer Direct API -> MastercardSimulator.

Each stage sends ONE payment per merchant for the first N merchants in the
keys CSV, all fired at the same moment (a barrier releases every thread
together), then checks the simulator's /admin/stats to confirm every
merchant's payment actually arrived there.

    python3 scripts/bulk_load_test.py --stages 10,50,100,250,500,1000

Stdlib only. API keys are read from the CSV and never printed or written to
the results file.
é    N)ÚThreadPoolExecutor)Údatetimez:https://mercurypay.aritic.app/pn/pgpayments/api/direct/payzhttp://localhost:4444zmerchant.BULKTEST0001Úbulk_password_123c                  ót  — t        j                  t        t         j                  ¬«      } | j	                  ddd¬«       | j	                  dt
        d¬«       | j	                  dd	d
¬«       | j	                  dt        dd¬«       | j	                  dt        dd¬«       | j	                  ddd¬«       | j	                  dd¬«       | j	                  dd¬«       | j	                  dt        d¬«       | j	                  ddd¬«       | j	                  d dd!¬«       | j	                  d"d d#¬«       | j                  «       S )$N)ÚdescriptionÚformatter_classz--keysz/home/priyanka/bulk_keys.csvz1bulk_keys.csv (user_id,email,merchant_id,api_key))ÚdefaultÚhelpz--urlz/CloudLayer Direct /pay endpoint (4056 instance)z--stagesz10,50,100,250,500,1000zcomma-separated merchant countsz--pauseé
   zseconds to wait between stages)Útyper	   r
   z	--timeouté<   zper-request timeout in secondsz--cardÚ5123450000000008ztest card (default approves)z--amountz10.00)r	   z
--currencyÚAEDz--simz+simulator base URL, for /admin/stats checksz--stop-on-failÚ
store_truez6stop before the next stage if this one had any failure)Úactionr
   z--yeszdon't ask for confirmationz--outz3results CSV (default: load_results_<timestamp>.csv))	ÚargparseÚArgumentParserÚ__doc__ÚRawDescriptionHelpFormatterÚadd_argumentÚDEFAULT_URLÚfloatÚDEFAULT_SIMÚ
parse_args)Úps    úscripts/bulk_load_test.pyr   r   #   s  € Ü×Ñ¬GÄX×EiÑEiÔj€AØ‡N�N�8Ð%CÐJ}€NÔ~Ø‡N�N�7¤KÐ6g€NÔhØ‡N�N�:Ð'?ÐFg€NÔhØ‡N�N�9¤5°"Ð;[€NÔ\Ø‡N�N�;¤U°BÐ=]€NÔ^Ø‡N�N�8Ð%7Ð>\€NÔ]Ø‡N�N�: w€NÔ/Ø‡N�N�<¨€NÔ/Ø‡N�N�7¤KÐ6c€NÔdØ‡N�NÐ#¨LÐ?w€NÔxØ‡N�N�7 <Ð6R€NÔSØ‡N�N�7 DÐ/d€NÔeØ�<‰<‹>Ðó    c                 ó  — t        | d¬«      5 }t        j                  |«      D �cg c](  }|j                  d«      sŒ|j                  d«      sŒ'|‘Œ* }}d d d «       j	                  d„ ¬«       |S c c}w # 1 sw Y   Œ#xY w)NÚ ©ÚnewlineÚapi_keyÚmerchant_idc                 ó   — | d   S )Nr#   © )Úrs    r   ú<lambda>z load_merchants.<locals>.<lambda>7   s   € ˜A˜mÑ,€ r   ©Úkey)ÚopenÚcsvÚ
DictReaderÚgetÚsort)ÚpathÚfr&   Úrowss       r   Úload_merchantsr2   4   ss   € Ü	ˆd˜BÔ	ð [ 1ÜŸ>™>¨!Ó,ÖZ�a°·±°iÕ0@ÀQÇUÁUÈ=ÕEY’ÐZˆÐZ÷[à‡I�IÑ,€IÔ-Ø€Kùò [÷[ð [ús'   ŽA7¦A2½A2ÁA2ÁA7Á2A7Á7B c                 ó„  — t         j                  j                  | |z   «      }t        j                  t
        › dt        › �j                  «       «      j                  «       }|j                  dd|z   «       t         j                  j                  |d¬«      5 }t        j                  |«      cd d d «       S # 1 sw Y   y xY w)Nú:ÚAuthorizationzBasic é   ©Útimeout)ÚurllibÚrequestÚRequestÚbase64Ú	b64encodeÚSIM_USERÚSIM_PASSÚencodeÚdecodeÚ
add_headerÚurlopenÚjsonÚload)Úsimr/   ÚreqÚtokenr&   s        r   Úsim_getrI   ;   s“   € Ü
�.‰.×
 Ñ
   t¡Ó
,€CÜ×Ñ¤˜z¨¬8¨*Ð5×<Ñ<Ó>Ó?×FÑFÓH€EØ‡N�N�? H¨uÑ$4Ô5Ü	�‰×	Ñ	 ¨RÐ	Ó	0ð °AÜ�y‰y˜‹|÷÷ ò ús   ÂB6Â6B?c                 ó&  — d|› d|› d|d   › �}t        j                  | j                  | j                  |d| j                  ddddd	œd
œ«      j                  «       }t        j                  j                  | j                  |d¬«      }|j                  dd«       |j                  dd|d   z   «       ||d   |ddddddœ}|j                  «        t        j                  «       }		 t        j                  j                  || j                  ¬«      5 }
|
j                   |d<   t        j"                  |
j%                  «       xs d«      }d d d «       t5        t        j                  «       |	z
  dz  d«      |d<   t7        j9                  dd«      «      |d<   t7        |j9                  dd«      «      |d<   t7        |j9                  d|j9                  d d«      «      «      d d! |d<   |S # 1 sw Y   ŒŸxY w# t        j&                  j(                  $ rT}|j*                  |d<   	 t        j"                  |j%                  «       xs d«      }n# t,        $ r i }Y nw xY wY d }~�Œd }~wt.        $ r'}dt1        |«      j2                  › d|› �i}Y d }~�Œ<d }~ww xY w)"NÚLTz-Sú-r#   z	Load TestÚ12Ú27Ú123)ÚnumberÚexpiry_monthÚexpiry_yearÚsecurity_codeÚname_on_card)ÚamountÚcurrencyÚorder_idÚcustomer_nameÚcardÚPOST)ÚdataÚmethodzContent-Typezapplication/jsonr5   zBearer r"   r   r   ç        )Ústager#   rW   ÚhttpÚstatusÚstatus_codeÚmessageÚ
latency_msr7   r_   s   {}rb   ú: iè  é   rc   r`   ra   Úerroréx   )rD   ÚdumpsrU   rV   rY   r@   r9   r:   r;   ÚurlrB   ÚwaitÚtimeÚperf_counterrC   r8   r`   ÚloadsÚreadrf   Ú	HTTPErrorÚcodeÚ
ValueErrorÚ	Exceptionr   Ú__name__ÚroundÚstrr-   )ÚargsÚmerchantÚrun_idr^   ÚbarrierrW   ÚbodyrG   ÚresultÚstartr&   r[   Úes                r   Úpayr~   C   sX  € Ø�F�8˜2˜e˜W A h¨}Ñ&=Ð%>Ð?€HÜ�:‰:Ø—+‘+Ø—M‘MØØ$à—i‘iØ ØØ"Ø'ñ
ñó ÷ �vƒxð 	ô �.‰.×
 Ñ
  §¡°¸VÐ
 Ó
D€CØ‡N�N�>Ð#5Ô6Ø‡N�N�? I°¸Ñ0CÑ$CÔDà¨X°mÑ-DÐRZØ 2°bÀRÐWZñ\€Fð ‡L�L„NÜ×ÑÓ€Eð7Ü�^‰^×#Ñ# C°·±Ð#Ó>ð 	1À!ØŸX™XˆF�6‰NÜ—:‘:˜aŸf™f›hÒ/¨%Ó0ˆD÷	1ô !¤$×"3Ñ"3Ó"5¸Ñ"=ÀÑ!EÀqÓI€Fˆ<Ñä˜4Ÿ8™8 H¨bÓ1Ó2€Fˆ8ÑÜ §¡¨¸Ó ;Ó<€Fˆ=ÑÜ˜DŸH™H Y°·±¸À"Ó0EÓFÓGÈÈÐM€Fˆ9ÑØ€M÷!	1ð 	1ûô �<‰<×!Ñ!ò ØŸ™ˆˆv‰ð	Ü—:‘:˜aŸf™f›hÒ/¨%Ó0‰DøÜò 	ØŠDð	ÿüäò 7Øœd 1›g×.Ñ.Ð/¨r°!°Ð5Ð6Žûð7ús`   Ã%+G1 Ä7G%ÅG1 Ç%G.Ç*G1 Ç1JÈIÈ'IÉIÉIÉIÉIÉIÉJÉ)JÊJc                 óœ   — | syt        | «      } | t        t        | «      dz
  t        t	        |dz  t        | «      dz
  z  «      «      «         S )Nr]   re   éd   )ÚsortedÚminÚlenÚintrt   )ÚvaluesÚqs     r   Úpctr‡   p   sF   € ÙØÜ�F‹^€FØ”#”c˜&“k A‘o¤s¬5°°S±¼CÀ»KÈ!¹OÑ1LÓ+MÓ'NÓOÑPÐPr   c           	      ó:  ‡ ‡‡‡— t        j                  t        |«      «      Št        j                  «       }t        t        |«      ¬«      5 }t        |j                  ˆ ˆˆˆfd„|«      «      }d d d «       t        j                  «       |z
  }|fS # 1 sw Y   Œ$xY w)N)Úmax_workersc                 ó"   •— t        ‰| ‰‰‰«      S )N)r~   )Úmrv   ry   rx   r^   s    €€€€r   r'   zrun_stage.<locals>.<lambda>{   s   ø€ ¬#¨d°A°v¸uÀgÓ*N€ r   )Ú	threadingÚBarrierrƒ   rk   rl   r   ÚlistÚmap)	rv   Ú	merchantsrx   r^   Út0ÚpoolÚresultsÚwallry   s	   ` ``    @r   Ú	run_stager•   w   s€   û€ Ü×Ñ¤ I£Ó/€GÜ	×	Ñ	Ó	€BÜ	¬¨I«Ô	7ð \¸4Ü�t—x‘xÖ NÐPYÓZÓ[ˆ÷\ä×ÑÓ Ñ#€DØ�Dˆ=Ð÷\ð \ús   Á"BÂBc                 óÌ  — |D �cg c]  }|d   dk(  sŒ|‘Œ }}|D �cg c]  }|d   dk7  sŒ|‘Œ }}|D �cg c]  }|d   ‘Œ	 }	}t        d| › dt        |«      › d�«       t        dt        |«      › dt        |«      › �«       t        d	t        |	d
«      d›dt        |	d«      d›dt        |	«      d›dt	        j
                  |	«      d›�«       t        d|d›dt        |«      |z  d›d�«       |r¨i }
|D ]B  }d|d   › d|d   xs d› d|d   xs d› �}|
j                  |g «      j                  |d   «       ŒD t        d«       t        |
j                  «       d„ ¬«      D ]5  \  }}t        dt        |«      d›d |› d!d"j                  |d d# «      › �«       Œ7 |�r(|d$   |d$   z
  }|D �cg c]i  }t        |d%   j                  |d   i «      j                  «       «      t        |d%   j                  |d   i «      j                  «       «      z
  d&k  r|d   ‘Œk }}|d'   j                  «       D ��ci c]6  \  }}||d'   j                  |d(«      z
  r|||d'   j                  |d(«      z
  “Œ8 }}}t        d)|› d*|› �«       |r7t        d+t        |«      › d,d"j                  |d d- «      › �«       t        |«      S t        d.«       t        |«      S c c}w c c}w c c}w c c}w c c}}w )/Nr`   Úsuccessrc   u   
â”€â”€ Stage rd   u    merchants â”€â”€z  CloudLayer   success z  |  not success z  latency ms   p50 é2   ú.0fz  p95 é_   z  max z  mean z  wall time    z.1fzs  ->  z payments/szhttp=r_   z status=rL   z msg=rb   r#   z  failures:c                 ó    — t        | d   «       S )Nre   )rƒ   )Úkvs    r   r'   zsummarise.<locals>.<lambda>‘   s   € ÄÀBÀqÁEÃ
¸{€ r   r(   z    z>4u    Ã— z   e.g. z, é   ÚtotalÚby_merchantre   Ú	by_statusr   z  simulator    +z transactions u     âš  z3 merchants have no new simulator transaction, e.g. é   u8     âœ“ every merchant in this stage reached the simulator)Úprintrƒ   r‡   ÚmaxÚ
statisticsÚmeanÚ
setdefaultÚappendr�   ÚitemsÚjoinÚsumr-   r…   )r^   r“   r”   ÚbeforeÚafterÚsim_okr&   ÚokÚfailedÚlatÚgroupsr)   ÚmidsÚdeltaÚmissingÚkÚvÚstatus_deltas                     r   Ú	summariser¸   €   sW  € ØÖ	9�  (¡¨yÓ 8Š!Ð	9€BÐ	9Ø Ö=�A A h¡K°9Ó$<ŠaÐ=€FÐ=Ø$+Ö
,˜qˆ1ˆ\‹?Ð
,€CÐ
,ä	ˆO˜E˜7 "¤S¨£\ NÐ2CÐ
DÔEÜ	Ð#¤C¨£G 9Ð,=¼cÀ&»k¸]Ð
KÔLÜ	Ð¤ C¨£¨SÐ1°¼¸CÀ»ÀSÐ7IÈÔPSÐTWÓPXÐY\È~ð ^Ü—/‘/ #Ó& sÐ+ð-ô .ä	ˆO˜D ˜: W¬S°«\¸DÑ-@ÀÐ,EÀ[Ð
QÔRáØˆØò 	@ˆAØ˜!˜F™)˜ H¨Q¨x©[Ò-?¸CÐ,@ÀÀaÈ	ÁlÒFYÐVYÐEZÐ[ˆCØ×Ñ˜c 2Ó&×-Ñ-¨a°Ñ.>Õ?ð	@ô 	ˆmÔÜ §¡£Ñ4JÔKò 	O‰IˆC�Ü�Dœ˜T› 2˜ d¨3¨%¨x¸¿	¹	À$ÀrÈÀ(Ó8KÐ7LÐMÕNð	Oò Ø�g‘ ¨¡Ñ0ˆØ-4ö X¨Ü˜% Ñ.×2Ñ2°1°]Ñ3CÀRÓH×OÑOÓQÓRÜ˜ Ñ.×2Ñ2°1°]Ñ3CÀRÓH×OÑOÓQÓRñSØUVòWð �]Ó#ð Xˆð Xð %*¨+Ñ$6×$<Ñ$<Ó$>÷eÙ ˜A˜qÀ!ÀfÈ[ÑFY×F]ÑF]Ð^_ÐabÓFcÒBcð ˜1˜v kÑ2×6Ñ6°q¸!Ó<Ñ<Ñ<ð eˆñ eäÐ    ~°l°^ÐDÔEÙÜ�Fœ3˜w›<˜.Ð([Ð\`×\eÑ\eÐfmÐnpÐopÐfqÓ\rÐ[sÐtÔuô ˆv‹;Ðô ÐLÔMÜˆv‹;Ðùò? 
:ùÚ=ùÚ
,ùò&Xùóes&   …K“K�K«KµKÆ(A.KÈ.;K c            
      ó   — t        «       } | j                  j                  d«      D �cg c]  }|j                  «       sŒt	        |«      ‘Œ  }}t        | j                  «      }t        |«      t        |«      kD  r.t        j                  dt        |«      › dt        |«      › d�«       t        |«      }t        d| j                  › �«       t        dt        |«      › d| j                  › �«       t        d|› d	|› d
| j                  d›d�«       t        d| j                  d d › d| j                  dd  › d| j                   › d| j"                  › �«       t        d«       | j$                  s?t'        d«      j                  «       j)                  «       dk7  rt        j                  d«       t+        j,                  «       j/                  d«      }| j0                  xs d|› d�}g }t3        |«      D �],  \  }}		 t5        | j6                  d«      }
d}t;        | |d |	 ||	«      \  }}|j=                  |«       d }|r	 t5        | j6                  d«      }t?        |	|||
||«      }tA        |d d!¬"«      5 }tC        jD                  |tG        |d#   j                  «       «      ¬$«      }|jI                  «        |jK                  |«       d d d «       |r | jL                  rt        d%|	› d&|› d'�«        n5|t        |«      d(z
  k  s�ŒtO        jP                  | j                  «       �Œ/ t        d)|› �«       y c c}w # t8        $ r}t        d|› d�«       d\  }
}Y d }~�ŒGd }~ww xY w# t8        $ r}t        d|› d�«       d}Y d }~�Œ/d }~ww xY w# 1 sw Y   ŒÇxY w)*Nú,zLargest stage is z but the CSV only has z
 merchantszEndpoint : zMerchants: z in zStages   : z  (z payments in total, r™   zs pause between stages)zCard     : é   u   â€¦éüÿÿÿz	  amount ú zYEvery payment is a real CloudLayer transaction (pg_transactions) for a BULKTEST merchant.zProceed? [y/N] ÚyzAborted.z
%m%d%H%M%SÚload_results_z.csvz/admin/statsTz   (simulator stats unavailable: ú))NFFÚwr   r    r   )Ú
fieldnamesz
Stopping: stage z had z failures (--stop-on-fail).re   z
Per-request results: ))r   ÚstagesÚsplitÚstripr„   r2   Úkeysr£   rƒ   ÚsysÚexitrª   r¢   ri   ÚpauserY   rU   rV   ÚyesÚinputÚlowerr   ÚnowÚstrftimeÚoutÚ	enumeraterI   rF   rr   r•   Úextendr¸   r*   r+   Ú
DictWriterrŽ   ÚwriteheaderÚ	writerowsÚstop_on_failrk   Úsleep)rv   ÚsrÃ   r�   rž   rx   rÏ   Úall_resultsÚir^   r«   r­   r}   r“   r”   r¬   Úfailuresr0   rÁ   s                      r   ÚmainrÛ   £   s-  € Ü‹<€DØ"Ÿk™k×/Ñ/°Ó4ÖB˜¸¿¹½	Œc�!�fÐB€FÐBÜ˜tŸy™yÓ)€Iä
ˆ6ƒ{”S˜“^Ò#Ü�‰Ð$¤S¨£[ MÐ1GÌÈIËÐGWÐWaÐbÔcä�‹K€EÜ	ˆK˜Ÿ™�zÐ
"Ô#Ü	ˆKœ˜I›Ð' t¨D¯I©I¨;Ð
7Ô8Ü	ˆK˜�x˜s 5 'Ð)=¸d¿j¹jÈÐ=MÐMdÐ
eÔfÜ	ˆK˜Ÿ	™	 " 1˜� c¨$¯)©)°B°C¨.Ð)9¸À4Ç;Á;À-ÈqÐQU×Q^ÑQ^ÐP_Ð
`ÔaÜ	Ð
eÔfà�8Š8œÐ/Ó0×6Ñ6Ó8×>Ñ>Ó@ÀCÒGÜ�‰�Ôä�\‰\‹^×$Ñ$ \Ó2€FØ
�(‰(Ò
2˜ f X¨TÐ2€CØ€Kä˜fÓ%ó #‰ˆˆ5ð	)Ü˜TŸX™X ~Ó6ˆFØˆFô
 " $¨	°&°5Ð(9¸6À5ÓI‰ˆ�Ø×Ñ˜7Ô#àˆÙðÜ §¡¨.Ó9�ô
 ˜U G¨T°6¸5À&ÓIˆä�#�s BÔ'ð 	%¨1Ü—‘˜q¬T°+¸a±.×2EÑ2EÓ2GÓ-HÔIˆAØ�M‰MŒOØ�K‰K˜Ô$÷	%ñ
 ˜×)Ò)ÜÐ& u g¨U°8°*Ð<WÐXÔYÙØŒs�6‹{˜Q‰ÔÜ�J‰J�t—z‘zÖ"ð=#ô@ 
Ð# C 5Ð
)Õ*ùòi Cøô0 ò 	)ÜÐ4°Q°C°qÐ9Ô:Ø(‰NˆF–Fûð	)ûô ò ÜÐ8¸¸¸1Ð=Ô>Ø–ûðú÷	%ð 	%úsG   ¨L,¾L,Ç5L1È7MÉ+ANÌ1	MÌ:MÍMÍ	NÍ%M<Í<NÎN	Ú__main__)r   r   r<   r+   rD   r¤   rÇ   rŒ   rk   Úurllib.errorr9   Úurllib.requestÚconcurrent.futuresr   r   r   r   r>   r?   r   r2   rI   r~   r‡   r•   r¸   rÛ   rs   r%   r   r   ú<module>rà      s„   ðñó Û Û 
Û Û Û 
Û Û Û Û Ý 1Ý àJ€Ø%€Ø"€Ø€òò"òò*òZQòò òF6+ðr ˆzÒÙ…Fð r   