
    -iJ              	       h   d 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 ddl	Z	 ed      Z
ej                  j                  d ee
             d Z e       Zej                   Zdeded	d
fdZd deded	efdZd Zd Zd Zd Zd Zdeded	dfdZded	efdZd Zd Zd!dededed	dfdZd Zd Z d Z!y)"u$  
stale 재발 방지 테스트
대상:
  - memory/task-timer.py  :: TaskTimer.cleanup_stale()
  - dispatch.py           :: _cleanup_reserved()
  - dashboard/server.py   :: DataLoader.get_team_stats() stale 카운팅
                             DataLoader.get_tasks_info() is_stale 플래그
    N)datetime	timedelta)Pathz/home/jay/workspacec                      t         j                  j                  dt        t        dz  dz              } t         j                  j                  |       }| j                  j                  |       |S )N
task_timermemoryztask-timer.py)	importlibutilspec_from_file_locationstr	WORKSPACEmodule_from_specloaderexec_module)specmods     4/home/jay/workspace/teams/dev1/test_stale_cleanup.py_load_task_timer_moduler      sW    >>11c)h.@AD ..
)
)$
/CKKC J    tmp_pathinitial_tasksreturn	TaskTimerc                     | dz  }|j                  dd       |dz  }|j                  t        j                  d|idd      d	
       t	        t        |             S )u7   tmp_path 기반 격리된 TaskTimer 인스턴스 생성r   Tparentsexist_oktask-timers.jsontasksF   ensure_asciiindentutf-8encoding)workspace_path)mkdir
write_textjsondumpsr   r   )r   r   
memory_dir
timer_files       r   _make_timerr.   )   sf    H$JTD100J

G]+%J   CM22r   hoursminutesc                 f    t        | |      }t        j                         |z
  j                         S )uH   현재 기준 hours시간 + minutes분 전의 ISO 타임스탬프 반환)r/   r0   )r   r   now	isoformat)r/   r0   deltas      r   _pastr5   5   s(    E73ELLNU"--//r   c                    dddt        d      ddi}t        | |      }|j                  dd	      }t        |      d
k(  sJ d       |d   d   dk(  sJ |d   d   dk(  sJ |d   d   dk(  sJ t	        j
                  | dz  dz  j                               }|d   d   d   dk(  sJ |d   d   d   dk(  sJ d|d   d   v sJ y)uS   running 상태이고 start_time이 running_hours(기본 2h) 초과 → stale 전환ztask-1.1running   r/   	dev1-teamtask_idstatus
start_timeteam_id       @      >@running_hoursreserved_minutes   u&   1개 task가 stale 전환되어야 함r   r<   prev_statusstale_reasontimeout_runningr   r   r   r=   stalestale_atNr5   r.   cleanup_stalelenr*   loads	read_textr   r   timercleanedsaveds        r   test_cleanup_stale_runningrT   =   s    	!a."	
E %(E!!d!KGw<1FFF1:i J...1:m$	1111:n%):::: JJ8+.@@KKMNE>*%h/7:::>*%n59JJJJw
3333r   c                 f   dddt        d      di}t        | |      }|j                  dd      }t        |      d	k(  sJ |d
   d   dk(  sJ |d
   d   dk(  sJ |d
   d   dk(  sJ t	        j
                  | dz  dz  j                               }|d   d   d   dk(  sJ |d   d   d   dk(  sJ y)uY   reserved 상태이고 reserved_at이 reserved_minutes(기본 30m) 초과 → stale 전환ztask-2.1reserved-   r0   r<   r=   reserved_atr@   rA   rB   rE   r   r<   rF   rG   timeout_reservedr   r   r   r=   rI   NrK   rP   s        r   test_cleanup_stale_reservedr\   X   s     	!  ,
E %(E!!d!KGw<11:i J...1:m$
2221:n%);;;;JJ8+.@@KKMNE>*%h/7:::>*%n59KKKKr   c                 0   ddt        d      ddddt        d	
      dd}t        | |      }|j                  dd      }|g k(  sJ d       t        j                  | dz  dz  j                               }|d   d   d   dk(  sJ |d   d   d   dk(  sJ y)u@   running 1h (< 2h) / reserved 10m (< 30m) → stale 전환 없음task-3.1r7   rE   r9   r:   r;   task-3.2rV   
   rX   rY   )r^   r_   r@   rA   rB   u9   threshold 이내 task는 stale 전환되지 않아야 함r   r   r   r=   Nr5   r.   rL   r*   rN   rO   rP   s        r   test_cleanup_no_false_positiverb   p   s     "a."	
 "  ,
E %(E!!d!KGb=UUU=JJ8+.@@KKMNE>*%h/9<<<>*%h/:===r   c                    t        d      }ddd|t        d      dddi}t        | |      }|j                  d	d
      }|g k(  sJ d       t        j                  | dz  dz  j                               }|d   d   d   dk(  sJ y)u?   completed 작업은 cleanup_stale 후에도 그대로 completed   r9   ztask-4.1	completed         @r:   r<   r=   r>   end_timeduration_secondsr?   r@   rA   rB   u/   completed task는 stale 전환 대상이 아님r   r   r   r=   Nra   )r   	start_oldr   rQ   rR   rS   s         r    test_cleanup_completed_untouchedrl      s    AI!!#A &"
	E %(E!!d!KGb=KKK=JJ8+.@@KKMNE>*%h/;>>>r   c                    ddt        d      ddddt        d      d	dd
dt        d      dddt        d      dd}t        | |      }|j                  dd      }|D ch c]  }|d   	 }}d|v sJ d       d
|v sJ d       d|vsJ d       d|vsJ d       t        j                  | dz  dz  j                               }|d   d   d   dk(  sJ |d   d
   d   dk(  sJ |d   d   d   dk(  sJ |d   d   d   dk(  sJ yc c}w )uM   running_hours=0.1(6분), reserved_minutes=5 커스텀 threshold 동작 확인task-5.1r7   r`   rX   r:   r;   task-5.2r8   	dev2-teamtask-5.3rV      rY   task-5.4r    )rn   ro   rq   rs   g?g      @rB   r<   u   10분 running은 stale 대상u   7분 reserved는 stale 대상u#   3분 running은 stale 대상 아님u$   2분 reserved는 stale 대상 아님r   r   r   r=   rI   Nra   )r   r   rQ   rR   ccleaned_idsrS   s          r   test_cleanup_custom_thresholdsrv      s   
 "+"	
 "*"	
 "  +
 "  +
-E8 %(E!!c!JG)01A1Y<1K1$E&EE$$E&EE$[(O*OO([(P*PP(JJ8+.@@KKMNE>*%h/7:::>*%h/7:::>*%h/9<<<>*%h/:=== 2s   %D	r-   r   c                     | j                   j                  dd       | j                  t        j                  d|idd      d       y )	NTr   r   Fr    r!   r$   r%   )parentr(   r)   r*   r+   )r-   r   s     r   _write_timer_filery      sF    D48

GU#%B  r   c                 L    t        j                  | j                  d            S )Nr$   r%   )r*   rN   rO   )r-   s    r   _read_timer_filer{      s    ::j**G*<==r   c                     ddl }|j                  |d|        | dz  dz  }t        |ddt        j                         j                         di       |j                  d       t        |      }d|d	   vsJ d
       y)uJ   reserved 상태인 entry가 _cleanup_reserved() 호출 후 삭제되는지r   Nr   r   r   z	task-10.1rV   )r=   rZ   r   u%   reserved entry는 삭제되어야 함)dispatchsetattrry   r   r2   r3   _cleanup_reservedr{   r   monkeypatchr}   r-   rS   s        r   #test_cleanup_reserved_removes_entryr      s     +x8H$'99J$'||~779	
 {+Z(EeGn,U.UU,r   c           	         ddl }|j                  |d|        | dz  dz  }t        |dt        j                         j                         ddd	t        d
      t        j                         j                         ddd       |j                  d       t        |      }|d   d   d   dk(  sJ d       |j                  d       t        |      }|d   d   d   d	k(  sJ d       y)uU   running 또는 completed 상태인 task는 _cleanup_reserved()가 건드리지 않음r   Nr   r   r   r7   r:   )r=   r>   r?   re   rE   r9   rg   )r=   r>   ri   rj   )	task-11.1	task-11.2r   r   r=   u%   running은 삭제되지 않아야 함r   u'   completed는 삭제되지 않아야 함)	r}   r~   ry   r   r2   r3   r5   r   r{   r   s        r   (test_cleanup_reserved_skips_non_reservedr      s    +x8H$'99J $&lln668& &#!n$LLN446$*		
$ {+Z(E>+&x0I=f?ff= {+Z(E>+&x0K?jAjj?r   org_data
DataLoaderc                 X   ddl m} | dz  }|j                  dd       |dz  }|j                  t	        j
                  d|idd	
      d       |r.|dz  }|j                  t	        j
                  |dd	
      d        ||       }|j                          |r|j                          |S )u8   tmp_path 기반 격리된 DataLoader 인스턴스 생성r   )r   r   Tr   r   r   Fr    r!   r$   r%   zorganization-structure.json)workspace_dir)dashboard.serverr   r(   r)   r*   r+   
load_tasksload_organization)r   r   r   r   r,   	task_fileorg_filer   s           r   _make_data_loaderr   $  s    +H$JTD1 //I

GU#%B    ==JJxeA> 	 	

 h/F
  "Mr   c           
         ddt        d      ddddt        d      d	dd
dt        d      dt        d      ddddt        d      t        d      dddd}ddg idg idi}t        | ||      }|j                         }|d   dk(  sJ d|d           |d   dk(  sJ d|d           |d   dk(  sJ d|d           |d    d!k(  sJ d"|d            y#)$uT   running 상태이고 2시간 초과된 task는 stale_tasks로 카운트되어야 함	task-20.1r7   r8   r9   r:   r;   	task-20.2rE   rp   	task-20.3rI   rd   rH   r<   r=   r>   rG   rJ   r?   	task-20.4re   r    rg   rh   )r   r   r   r   	structureteamscenterscolumnsrowsr   stale_tasksu@   stale_tasks는 2여야 함 (3h running + 기존 stale), 실제: running_tasksu6   running_tasks는 1이어야 함 (1h running), 실제: completed_tasksu+   completed_tasks는 1이어야 함, 실제: total_tasksrf   u$   total_tasks는 4여야 함, 실제: Nr5   r   get_team_statsr   r   minimal_orgr   statss        r   "test_get_team_stats_stale_countingr   C  s`   
 #a."	
 #a."	
 #a.-A"
 #!a.A &"
3!EJ WbMIr? STKxEF!!#E1$ 
J5Q^K_J`a$ !Q& 
@AW@XY& "#q( 
5e<M6N5OP( 1$ 
.u]/C.DE$r   c                     ddt        d      dddt        d      dd}d	d
g idg idi}t        | ||      }|j                         }|d   dk(  sJ d|d           y)uS   reserved 상태이고 30분 초과된 task도 stale_tasks로 카운트되어야 함	task-21.1rV   rW   rX   rY   	task-21.2r`   )r   r   r   r   r   r   r   r   rE   u8   stale_tasks는 1이어야 함 (45분 reserved), 실제: Nr   r   s        r   +test_get_team_stats_reserved_stale_countingr   |  s    
 #  ,
 #  ,
E WbMIr? STKxEF!!#E1$ 
B5CWBXY$r   c                    ddt        d      ddddt        d      d	dd
dt        d      dt        d      ddddt        d      dddt        d      dddt        d      t        d      dddd}t        | |      }|j                         }|D ci c]  }|d   |d    }}|d   du sJ d       |d   d u sJ d!       |d
   du sJ d"       |d   du sJ d#       |d   d u sJ d$       |d   d u sJ d%       y&c c}w )'uM   get_tasks_info()가 is_stale 플래그를 올바르게 설정하는지 확인	task-30.1r7   r8   r9   r:   r;   	task-30.2rE   rp   	task-30.3rI   rd   rH   r   	task-30.4rV   rW   rX   rY   	task-30.5r`   	task-30.6re   r    rg   rh   )r   r   r   r   r   r   r<   is_staleTu   3h running은 is_stale=TrueFu   1h running은 is_stale=Falseu   status=stale은 is_stale=Trueu   45min reserved는 is_stale=Trueu    10min reserved는 is_stale=Falseu   completed는 is_stale=FalseN)r5   r   get_tasks_info)r   r   r   
tasks_infot	stale_maps         r   !test_get_tasks_info_is_stale_flagr     s   
 #a."	
 #a."	
 #a.-A"
 #  ,
 #  ,
 #!a.A &"
K-E^ x/F&&(J 7AA9q},AIA[!T)H+HH)[!U*J,JJ*[!T)J+JJ)[!T)L+LL)[!U*N,NN*[!U*I,II* Bs   D)        r   )N)"__doc__importlib.utilr	   r*   sysr   r   pathlibr   pytestr   pathinsertr   r   _task_timer_modr   dictr.   floatr5   rT   r\   rb   rl   rv   ry   r{   r   r   r   r   r   r    r   r   <module>r      s     
 (   &'	 3y> " *+%%		3$ 	3t 	3 	30 0u 0s 046L0>6?0+>d$ t  > >$ >V4 kN T T \ >6r8<Jr   