o
    Œ„†jt"  ã                
   @   sø   d Z ddlZddlm  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mZmZ ddlmZ ej dej ej ej e¡¡¡¡ ddlZG dd„ dƒZG dd„ dejƒZG d	d
„ d
ejƒZG dd„ dejƒZedkrzejdd� dS dS )a  
test_logger_setup.py

Covers the switch from a single ever-growing, size-rotated sip_bot.log
to one dated file per trading day (logs/sip_bot_YYYY-MM-DD.log), plus
retention pruning of old daily files.

Run:
    python -m pytest tests/test_logger_setup.py -v
é    N)ÚdateÚ	timedelta)Úpatchc                   @   s&   e Zd ZdZdefdd„Zdd„ ZdS )ÚFakeEtDatetimez‡Stand-in for market_time.now_et()'s return value -- only .date()
    is exercised by logger_setup, so that's all this needs to support.Údc                 C   s
   || _ d S ©N©Ú_d)Úselfr   © r   úS/var/www/screener/trade/premarket_backup_2026-09-08_2010/tests/test_logger_setup.pyÚ__init__   s   
zFakeEtDatetime.__init__c                 C   s   | j S r   r   ©r
   r   r   r   r       s   zFakeEtDatetime.dateN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r   r   r   r      s    r   c                   @   sF   e Zd Zdd„ Zdd„ Zddd„Zdd	„ Zd
d„ Zdd„ Zdd„ Z	dS )ÚTestDailyFileHandlerc                 C   ó    t  ¡ | _tdƒ | j¡| _d S ©NÚpathlib©ÚtempfileÚmkdtempÚtmpdirÚ
__import__ÚPathÚlog_dirr   r   r   r   ÚsetUp%   ó   
zTestDailyFileHandler.setUpc                 C   ó   t j| jdd� d S ©NT©Úignore_errors©ÚshutilÚrmtreer   r   r   r   r   ÚtearDown)   ó   zTestDailyFileHandler.tearDownÚhelloc              	   C   s"   dd l }|jd|jtd|dd d�S )Nr   zsip_bot.testé   r   )ÚnameÚlevelÚpathnameÚlinenoÚmsgÚargsÚexc_info)ÚloggingÚ	LogRecordÚINFOÚ__file__)r
   r/   r2   r   r   r   Ú_make_record,   s
   þz!TestDailyFileHandler._make_recordc              	   C   sØ   t dddƒ}tjtjdt|ƒd�� t | jd¡}| d ¡ | 	|  
d¡¡ W d   ƒ n1 s0w   Y  | jd }|  | ¡ d	|› d
t| j ¡ ƒ› �¡ t|ƒ�}|  d| ¡ ¡ W d   ƒ d S 1 sew   Y  d S )Néê  é   é   Únow_et©Úreturn_valueÚsip_botzfirst messageúsip_bot_2026-08-19.logú	expected z to exist, found: )r   r   ÚobjectÚlogger_setupÚmarket_timer   Ú_DailyFileHandlerr   ÚsetFormatterÚemitr6   Ú
assertTrueÚexistsÚlistÚiterdirÚopenÚassertInÚread)r
   ÚtodayÚhandlerÚexpected_pathÚfr   r   r   Ú*test_active_file_is_named_with_todays_date3   s   
ý

ÿ
"ÿz?TestDailyFileHandler.test_active_file_is_named_with_todays_datec                 C   sð   t dddƒ}tjtjdt|ƒd��$ t | jd¡}| d ¡ | 	|  
d¡¡ | 	|  
d¡¡ W d   ƒ n1 s8w   Y  t t| jd	 ƒ¡}|  t|ƒd
d¡ t|d ƒ�}| ¡ }W d   ƒ n1 sew   Y  |  d|¡ |  d|¡ d S )Nr7   r8   r9   r:   r;   r=   zmessage onezmessage twor>   r*   z,should still be exactly one file for the dayr   )r   r   r@   rA   rB   r   rC   r   rD   rE   r6   ÚglobÚstrÚassertEqualÚlenrJ   rL   rK   )r
   rM   rN   Úmatching_filesrP   Úcontentr   r   r   Ú,test_same_day_writes_append_to_the_same_file@   s   
ü
ÿzATestDailyFileHandler.test_same_day_writes_append_to_the_same_filec                 C   s‚  t dddƒ}t dddƒ}t | jd¡}| d ¡ tjtjdt|ƒd�� | 	|  
d¡¡ W d   ƒ n1 s6w   Y  tjtjdt|ƒd�� | 	|  
d	¡¡ W d   ƒ n1 sYw   Y  | jd
 }| jd }|  | ¡ ¡ |  | ¡ ¡ t|ƒ�}|  d| ¡ ¡ |  d	| ¡ ¡ W d   ƒ n1 s•w   Y  t|ƒ�}|  d	| ¡ ¡ |  d| ¡ ¡ W d   ƒ d S 1 sºw   Y  d S )Nr7   r8   r9   é   r=   r:   r;   zday one messagezday two messager>   zsip_bot_2026-08-20.log)r   rA   rC   r   rD   r   r@   rB   r   rE   r6   rF   rG   rJ   rK   rL   ÚassertNotIn)r
   Úday1Úday2rN   Ú	day1_pathÚ	day2_pathrP   r   r   r   Ú-test_crossing_midnight_opens_a_new_dated_fileO   s,   
ÿÿ


þ
"þzBTestDailyFileHandler.test_crossing_midnight_opens_a_new_dated_filec                 C   s‚   t dddƒ}tjtjdt|ƒd�� t | jd¡}| d¡ | 	|  
d¡¡ W d  ƒ n1 s0w   Y  |  | jd	  ¡ ¡ dS )
zyThe old behavior wrote to a single logs/sip_bot.log -- confirm
        that filename is never touched by the new handler.r7   r8   r9   r:   r;   r=   Nr)   úsip_bot.log)r   r   r@   rA   rB   r   rC   r   rD   rE   r6   ÚassertFalserG   )r
   rM   rN   r   r   r   Ú)test_no_stale_sip_bot_log_file_is_createdh   s   
ýz>TestDailyFileHandler.test_no_stale_sip_bot_log_file_is_createdN)r)   )
r   r   r   r   r'   r6   rQ   rX   r_   rb   r   r   r   r   r   $   s    
r   c                   @   s4   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	d
„ ZdS )ÚTestPruneOldLogsc                 C   r   r   r   r   r   r   r   r   u   r   zTestPruneOldLogs.setUpc                 C   r    r!   r$   r   r   r   r   r'   y   r(   zTestPruneOldLogs.tearDownc                 C   s   | j |  d¡ d S )Nzlog content
)r   Ú
write_text)r
   Úfilenamer   r   r   Ú_touch|   r(   zTestPruneOldLogs._touchc                 C   s0  t dddƒ}|tdd� }|tdd� }|  d| ¡ › d�¡ |  d| ¡ › d�¡ |  d| ¡ › d�¡ |  d	¡ tjtjd
t|ƒd�� tj	| j
ddd� W d   ƒ n1 sYw   Y  dd„ | j
 ¡ D ƒ}|  d| ¡ › d�|d¡ |  d| ¡ › d�|d¡ |  d| ¡ › d�|d¡ |  d	|d¡ d S )Nr7   r8   rY   é-   )Údaysé   Úsip_bot_ú.logznot_a_dated_file.logr:   r;   r=   é   ©Úretention_daysc                 S   s   h | ]}|j ’qS r   )r+   )Ú.0Úpr   r   r   Ú	<setcomp>Œ   s    zOTestPruneOldLogs.test_prunes_files_older_than_retention_days.<locals>.<setcomp>z/file older than retention_days should be prunedz)file within retention_days should be keptztoday's file should be keptz2non-dated files should never be touched by pruning)r   r   rf   Ú	isoformatr   r@   rA   rB   r   Ú_prune_old_logsr   rI   rZ   rK   )r
   rM   Úold_dateÚrecent_dateÚ	remainingr   r   r   Ú+test_prunes_files_older_than_retention_days   s.   
ÿÿÿÿÿz<TestPruneOldLogs.test_prunes_files_older_than_retention_daysc                 C   sj   t dddƒ}|  d| ¡ › d�¡ tj| jddd� tj| jdd d� |  | jd| ¡ › d�  ¡ ¡ d S )Niä  r*   rj   rk   r=   r   rm   )r   rf   rr   rA   rs   r   rF   rG   )r
   rt   r   r   r   Ú,test_zero_or_none_retention_disables_pruning–   s
   $z=TestPruneOldLogs.test_zero_or_none_retention_disables_pruningN)r   r   r   r   r'   rf   rw   rx   r   r   r   r   rc   t   s    rc   c                   @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	ÚTestConfigureRootIntegrationz¸Exercises get_logger()/_configure_root() end to end against the
    real config.json, confirming the wired-up logger actually produces
    a dated file rather than the old sip_bot.log.c                 C   s@   t  ¡ | _dt_dd l}| d¡}t|jƒD ]}| 	|¡ qd S )NFr   r=   )
r   r   r   rA   Ú_CONFIGUREDr2   Ú	getLoggerrH   ÚhandlersÚremoveHandler©r
   r2   ÚrootÚhr   r   r   r   ¥   s   

ÿz"TestConfigureRootIntegration.setUpc                 C   sF   t j| jdd� dt_dd l}| d¡}t|jƒD ]}| 	|¡ qd S )NTr"   Fr   r=   )
r%   r&   r   rA   rz   r2   r{   rH   r|   r}   r~   r   r   r   r'   ¯   s   
ÿz%TestConfigureRootIntegration.tearDownc              	      s  dd l }ddlm} tdddƒ}‡ fdd„}tjtd|d	��: tjtjd
t|ƒd�� t 	d¡}| 
d¡ | d¡jD ]}| ¡  q;W d   ƒ n1 sLw   Y  W d   ƒ n1 s[w   Y  |ˆ jƒd }ˆ  | ¡ d|› dt|ˆ jƒ ¡ ƒ› �¡ ˆ  |ˆ jƒd  ¡ ¡ d S )Nr   )r   r7   r8   r9   c                      s   dˆ j ddddœiS )Nr2   r4   r=   rl   )r   r,   Úfilename_prefixrn   )r   r   r   r   r   Úfake_get_config½   s   üÿzsTestConfigureRootIntegration.test_get_logger_writes_to_dated_file_under_configured_log_dir.<locals>.fake_get_configÚ
get_config)Úside_effectr:   r;   Útest_modulezintegration test messager=   r>   r?   z, found r`   )r2   r   r   r   r   r@   rA   rB   r   Ú
get_loggerÚinfor{   r|   Úflushr   rF   rG   rH   rI   ra   )r
   r2   r   Úfixed_todayr‚   Úlogr€   Úexpectedr   r   r   Ú=test_get_logger_writes_to_dated_file_under_configured_log_dir·   s$   
ÿ


ÿü€ *zZTestConfigureRootIntegration.test_get_logger_writes_to_dated_file_under_configured_log_dirN)r   r   r   r   r   r'   rŒ   r   r   r   r   ry       s
    
ry   Ú__main__é   )Ú	verbosity)r   ÚbuiltinsÚ@py_builtinsÚ_pytest.assertion.rewriteÚ	assertionÚrewriteÚ
@pytest_arÚsysÚosrR   r%   r   ÚunittestÚdatetimer   r   Úunittest.mockr   ÚpathÚinsertÚdirnameÚabspathr5   rA   r   ÚTestCaser   rc   ry   r   Úmainr   r   r   r   Ú<module>   s$    "&
P,8ÿ