
    (<i#                     F   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mZ ddlZej                  j                  d e ee      j                  j                  j                               ddlmZmZ dedee   fdZ G d d	      Z G d
 d      Z G d d      Z G d d      Zy)u)   utils/audit_logger.py 테스트 스위트    N)Path)log_batch_operationslog_file_operationpathreturnc                     g }| j                         r\| j                  d      j                         D ]9  }|j                         }|s|j	                  t        j                  |             ; |S )u5   JSONL 파일을 파싱하여 레코드 목록 반환.zutf-8)encoding)exists	read_text
splitlinesstripappendjsonloads)r   recordslines      N/home/jay/workspace/.worktrees/task-2057-dev2/utils/tests/test_audit_logger.py_read_jsonlr      s]    G{{}NNGN4??A 	1D::<Dtzz$/0	1 N    c                   :    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
y	)
TestLogFileOperationBasicu,   log_file_operation() 기본 동작 테스트c                 t    |dz  }t        dddt        |             t        |      }t        |      dk(  sJ y)u&   레코드가 audit 파일에 기록됨audit-trail.jsonlztask-001/tmp/foo.pyWrite
audit_path   N)r   strr   lenselftmp_pathtrailr   s       r   test_record_written_to_filez5TestLogFileOperationBasic.test_record_written_to_file)   s;    ..:}g#e*Ue$7|q   r   c                     |dz  }t        dddt        |             t        |      d   }|d   dk(  sJ |d   dk(  sJ |d	   dk(  sJ |d
   dk(  sJ |d   dk(  sJ d|v sJ y)u.   레코드에 필수 필드가 모두 포함됨r   ztask-002z/tmp/bar.pyEditr   r   task_idfiletool	operationwriteagentsubagenttsNr   r   r   r"   r#   r$   recs       r   test_record_fields_presentz4TestLogFileOperationBasic.test_record_fields_present0   s    ..:}fUT% #9~+++6{m+++6{f$$$;7***7|z)))s{{r   c                     ddl m } |dz  }t        dddt        |             t        |      d   }|j	                  |d   j                  d	d
            }|J y)u   ts 필드가 ISO 8601 형식임r   )datetimer   ztask-003	/tmp/x.pyr   r   r/   Zz+00:00N)r5   r   r   r   fromisoformatreplace)r"   r#   r5   r$   r2   dts         r   test_ts_is_iso8601z,TestLogFileOperationBasic.test_ts_is_iso8601<   s\    %..:{GE
S% ###CI$5$5c8$DE~~r   c           	          |dz  }t        d      D ]"  }t        d|dd| ddt        |             $ t        |      }t	        |      dk(  sJ y	)
u.   여러 번 호출하면 레코드가 누적됨r      task-03d/tmp/f.pyr   r   N)ranger   r   r   r    )r"   r#   r$   ir   s        r   test_multiple_calls_appendz4TestLogFileOperationBasic.test_multiple_calls_appendG   sc    ..q 	aAqg&3UXY^U_`	ae$7|q   r   c           	      p    |dz  }t        ddddt        |             t        |      d   }|d   dk(  sJ y	)
u0   operation 파라미터가 레코드에 반영됨r   ztask-004z	/tmp/z.pyr   delete)r+   r   r   r+   Nr0   r1   s       r   test_custom_operation_parameterz9TestLogFileOperationBasic.test_custom_operation_parameterO   sF    ..:{Gx\_`e\fg% #;8+++r   c                     |dz  dz  dz  }t        dddt        |             |j                         sJ t        |      }t	        |      dk(  sJ y	)
u>   audit 파일 부모 디렉토리가 없어도 자동 생성됨nesteddeepr   ztask-005z/tmp/abc.pyr   r   r   N)r   r   r
   r   r    r!   s       r   test_creates_parent_directoryz7TestLogFileOperationBasic.test_creates_parent_directoryV   sS    8#f,/BB:}g#e*U||~~e$7|q   r   c           	      J   |dz  }t        d      D ]!  }t        d| d| ddt        |             # |j                         j	                         D cg c]  }|j                         s| }}|D ])  }t        j                  |      }t        |t              r)J  yc c}w )	u   각 줄이 유효한 JSON임r      r>   r@   rA   r   r   N)
rB   r   r   r   r   r   r   r   
isinstancedict)r"   r#   r$   rC   l	raw_linesr   parseds           r   test_each_line_is_valid_jsonz6TestLogFileOperationBasic.test_each_line_is_valid_json_   s    ..q 	]Aqc{fQCsOWQTUZQ[\	] % 1 < < >L1!'')QL	L 	,DZZ%Ffd+++	, Ms   B +B N)__name__
__module____qualname____doc__r%   r3   r;   rD   rG   rK   rS    r   r   r   r   &   s(    6!
	!,!,r   r   c                   (    e Zd ZdZd Zd Zd Zd Zy)TestLogFileOperationInvalidArgsu!   잘못된 인자 처리 테스트c           	          |dz  }t        j                  t        t        f      5  t	        dddt        |             ddd       y# 1 sw Y   yxY w)u    빈 task_id는 ValueError 발생r    r   r   r   Npytestraises
ValueError	TypeErrorr   r   r"   r#   r$   s      r   test_empty_task_id_raisesz9TestLogFileOperationInvalidArgs.test_empty_task_id_raisesr   sI    ..]]J	23 	Rr='c%jQ	R 	R 	R   AAc           	          |dz  }t        j                  t        t        f      5  t	        dddt        |             ddd       y# 1 sw Y   yxY w)u   None task_id는 예외 발생r   Nr   r   r   r]   rb   s      r   test_none_task_id_raisesz8TestLogFileOperationInvalidArgs.test_none_task_id_raisesx   sI    ..]]J	23 	Tt]GE
S	T 	T 	Trd   c           	          |dz  }t        j                  t        t        f      5  t	        dddt        |             ddd       y# 1 sw Y   yxY w)u!   빈 filepath는 ValueError 발생r   task-xr\   r   r   Nr]   rb   s      r   test_empty_filepath_raisesz:TestLogFileOperationInvalidArgs.test_empty_filepath_raises~   sI    ..]]J	23 	MxWUL	M 	M 	Mrd   c           	          |dz  }t        j                  t        t        f      5  t	        dddt        |             ddd       y# 1 sw Y   yxY w)u   빈 tool은 ValueError 발생r   rh   r   r\   r   Nr]   rb   s      r   test_empty_tool_raisesz6TestLogFileOperationInvalidArgs.test_empty_tool_raises   sI    ..]]J	23 	Sxs5zR	S 	S 	Srd   N)rT   rU   rV   rW   rc   rf   ri   rk   rX   r   r   rZ   rZ   o   s    +RTMSr   rZ   c                   (    e Zd ZdZd Zd Zd Zd Zy)TestLogBatchOperationsu    log_batch_operations() 테스트c                     |dz  }t        d      D cg c]  }d| d
 }}t        d|dt        |             t        |      }t	        |      dk(  sJ yc c}w )	u5   배치 함수가 모든 파일 레코드를 기록함r      z	/tmp/filerA   ztask-010r   r   N)rB   r   r   r   r    )r"   r#   r$   rC   	filepathsr   s         r   test_batch_writes_all_filesz2TestLogBatchOperations.test_batch_writes_all_files   s`    ..16q:Ay3':	:ZGE
Se$7|q    ;s   Ac                 t    |dz  }t        dg dt        |             t        |      }t        |      dk(  sJ y)u5   빈 파일 목록은 레코드를 기록하지 않음r   ztask-011r   r   r   N)r   r   r   r    r!   s       r   $test_batch_empty_list_writes_nothingz;TestLogBatchOperations.test_batch_empty_list_writes_nothing   s;    ..ZWULe$7|q   r   c                     |dz  }g d}t        d|dt        |             t        |      }t        d |D              sJ y)u,   배치 레코드 모두 task_id가 동일함r   )z	/tmp/a.pyz	/tmp/b.pyz	/tmp/c.pytask-012r'   r   c              3   ,   K   | ]  }|d    dk(    yw)r(   ru   NrX   ).0rs     r   	<genexpr>zQTestLogBatchOperations.test_batch_records_have_correct_task_id.<locals>.<genexpr>   s     ?!1Y<:-?s   N)r   r   r   all)r"   r#   r$   rp   r   s        r   'test_batch_records_have_correct_task_idz>TestLogBatchOperations.test_batch_records_have_correct_task_id   sB    ..;	ZFs5zRe$?w????r   c                     |dz  }ddg}t        d|dt        |             t        |      D ch c]  }|d   	 }}|t        |      k(  sJ yc c}w )	u=   배치 레코드의 file 필드가 입력 경로와 일치함r   r6   z	/tmp/y.pyztask-013r   r   r)   N)r   r   r   set)r"   r#   r$   rp   rx   recorded_filess         r   $test_batch_records_correct_filepathsz;TestLogBatchOperations.test_batch_records_correct_filepaths   s]    .. +.	ZGE
S-8-?@!F)@@Y/// As   AN)rT   rU   rV   rW   rq   rs   r{   r   rX   r   r   rm   rm      s    *!!@0r   rm   c                       e Zd ZdZd Zd Zy)TestConcurrentWritesu9   동시 쓰기 시 파일 락으로 안전하게 기록됨c                 D  	 |dz  	d}g dt         f	fd}t        |      D cg c]  }t        j                  ||f       }}|D ]  }|j	                           |D ]  }|j                           r
J d        t        	      }t        |      |k(  sJ yc c}w )uC   N개 스레드가 동시에 기록해도 모든 레코드가 남음r      idxc                     	 t        d| dd|  ddt                     y # t        $ r}j                  |       Y d }~y d }~ww xY w)Nr>   r?   z/tmp/concurrent_rA   r   r   )r   r   	Exceptionr   )r   eerrorsr$   s     r   workerzHTestConcurrentWrites.test_concurrent_writes_no_data_loss.<locals>.worker   sP    !"U3s)#48HS6QSZgjkpgqr !a  !s    $ 	AAAtargetargsu   스레드 오류 발생: N)intrB   	threadingThreadstartjoinr   r    )
r"   r#   	n_threadsr   rC   threadstr   r   r$   s
           @@r   #test_concurrent_writes_no_data_lossz8TestConcurrentWrites.test_concurrent_writes_no_data_loss   s    ..	"$	! 	! HMYGWX!9##6=XX 	AGGI	 	AFFH	 ?6vh??ze$7|y((( Ys   Bc                   
 |dz  
d}dt         f
fd}t        |      D cg c]  }t        j                  ||f       }}|D ]  }|j	                           |D ]  }|j                           
j                         j                         D cg c]  }|j                         s| }}t        |      |k(  sJ |D ]  }	t        j                  |	        yc c}w c c}w )u7   동시 쓰기 후에도 모든 줄이 유효한 JSON임r      r   c                 D    t        d|  d|  ddt                     y )Nr>   r@   rA   r   r   )r   r   )r   r$   s    r   r   zJTestConcurrentWrites.test_concurrent_writes_all_valid_json.<locals>.worker   s'    se}se3.?UXY^U_`r   r   N)r   rB   r   r   r   r   r   r   r   r    r   r   )r"   r#   r   r   rC   r   r   rP   rQ   r   r$   s             @r   %test_concurrent_writes_all_valid_jsonz:TestConcurrentWrites.test_concurrent_writes_all_valid_json   s    ..		a 	a HMYGWX!9##6=XX 	AGGI	 	AFFH	 !& 1 < < >L1!'')QL	L9~*** 	DJJt	 Y Ms   CC'CN)rT   rU   rV   rW   r   r   rX   r   r   r   r      s    C),r   r   )rW   r   ossysr   timepathlibr   r^   r   insertr   __file__parentutils.audit_loggerr   r   listrO   r   r   rZ   rm   r   rX   r   r   <module>r      s    /  	 
     3tH~,,33::; < Gd tDz  A, A,RS SB 0  0P* *r   