
     iI              	      z   U d Z ddlmZ ddlZddlmc m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 dddd	d
ddddZded<   dddddddddZded<   g dg dddg dg ddg d g d!dd"Zd#ed$<   d:d%Zd;d&Zd<d=d'Z	 d>	 	 	 	 	 	 	 	 	 d?d(Z	 	 	 	 	 	 	 	 d@d)Z G d* d+      Z G d, d-      Z G d. d/      Z  G d0 d1      Z! G d2 d3      Z" G d4 d5      Z# G d6 d7      Z$e%d8k(  r ejL                  ed9g       yy)Au   utils/bot_status.py — BotStatusManager 단위 테스트 스위트

작성자: 하누만 (dev4-team)
대상:   BotStatusManager 클래스 전 메서드
전략:   tmp_path로 격리된 파일시스템, 실제 constants.json 데이터 재현
    )annotationsN)Path)BotStatusManagerbot-bbot-cbot-dbot-ebot-fbot-gbot-hbot-i)	dev1-team	dev2-team	dev3-teamz	dev4-teamz	dev5-teamz	dev6-teamz	dev7-teamz	dev8-teamzdict[str, str]TEAM_TO_BOTdev1dev2dev3dev4dev5dev6dev7dev8TEAMS)u   배너u	   이미지u	   디자인u   시안u   광고 크리에이티브u   카드뉴스 디자인u	   비주얼u	   포스터)u   HTML 수정u
   CSS 버그u   코드 수정u   렌더러 수정u8   비주얼 창작 전문. 코드 수정은 dev팀 소관.)keywordsanti_keywordsdescription)u   카피u   마케팅 전략u   광고 문구SEOu   콘텐츠 전략u   캠페인 기획u   마케팅/카피 전문.)u   블로그 작성u   콘텐츠 제작u   포스팅 작성u   콘텐츠 제작 전문.)design	marketingcontentdictLOGICAL_TEAMSc                    | dz  }|j                  dd       |dz  }|j                  t        j                  t        t
        t        dd             |S )u8   tmp_path/config/constants.json 생성 후 경로 반환.configTparentsexist_okzconstants.json)team_to_botteamslogical_teamsFensure_ascii)mkdir
write_textjsondumpsr   r   r#   )tmp_path
config_dirconstants_paths      2/home/jay/workspace/utils/tests/test_bot_status.pymake_constantsr6   J   s_    H$JTD1"22N

*!.
 	
	     c                    | dz  }|j                  dd       |dz  }|j                  t        j                  d|id             |S )u:   tmp_path/memory/task-timers.json 생성 후 경로 반환.memoryTr&   ztask-timers.jsontasksFr,   )r.   r/   r0   r1   )r2   r:   
memory_dirtimers_paths       r5   make_task_timersr=   \   sN    H$JTD111K4::w&6UKLr7   c                L    t        |        |t        | |       t        |       S )u   constants + task-timers를 tmp_path에 준비하고 BotStatusManager 반환.

    tasks=None 이면 task-timers.json을 생성하지 않는다.
    )workspace_root)r6   r=   r   )r2   r:   s     r5   make_managerr@   e   s'    
 85)844r7   c                    | ||ddd |dS )Nrunning2026-04-04T00:00:00+00:00task_idteam_idr   status
start_timeend_timebot )rE   rF   rJ   r   s       r5   running_taskrL   u   s#     "1 r7   c                    | |dddd|dS )Nu   완료된 작업	completedrC   z2026-04-04T01:00:00+00:00rD   rK   )rE   rF   rJ   s      r5   completed_taskrO      s#     )1/ r7   c                  @    e Zd ZdZd	dZd	dZd	dZd	dZd	dZd	dZ	y)
TestGetBusyBotsu0   get_busy_bots() — running 봇 조회 테스트c           	     0   t        |dt        ddd      i      }|j                         }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}|d   d   }d}||k(  }|st        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }	t        j                  d      dz   d|	iz  }
t        t        j                  |
            dx}x}}|d   d   }d}||k(  }|st        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }	t        j                  d      dz   d|	iz  }
t        t        j                  |
            dx}x}}y)u1   running 작업 1개 → 해당 봇 정보 반환.z
task-100.1r   r   inz%(py1)s in %(py3)sresultpy1py3u,   bot-b는 busy 봇 목록에 있어야 한다
>assert %(py5)spy5NrE   ==z%(py1)s == %(py4)srX   py4   task_id가 일치해야 한다
>assert %(py6)spy6rF   u   team_id가 일치해야 한다r@   rL   get_busy_bots
@pytest_ar_call_reprcompare	_saferepr@py_builtinslocals_should_repr_global_name_format_assertmsgAssertionError_format_explanationselfr2   mgrrV   @py_assert0@py_assert2@py_format4@py_format6@py_assert3@py_format5@py_format7s              r5   $test_single_running_task_returns_botz4TestGetBusyBots.test_single_running_task_returns_bot   sY   <k7KL

 ""$Pw& PPPw&PPPwPPPPPP&PPP&PPPP"PPPPPPPgy)[\[)\9[[[)\[[[)[[[\[[[;[[[[[[[[gy)Z[Z)[8ZZZ)[ZZZ)ZZZ[ZZZ:ZZZZZZZZr7   c           	        t        |dt        ddd      i      }|j                         }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}y)uF   논리적 팀(design)이 bot-b 점유 → bot-b가 busy 봇에 포함.z
task-200.1r   r   rS   rU   rV   rW   uC   design 팀이 bot-b를 점유하면 bot-b가 반환되어야 한다rZ   r[   NrF   r\   r^   r_   zassert %(py6)src   rd   ro   s              r5   'test_logical_team_design_occupies_bot_bz7TestGetBusyBots.test_logical_team_design_occupies_bot_b   s    <hHI

 ""$gw& gggw&gggwgggggg&ggg&gggg"ggggggggy)5X5)X5555)X555)555X5555555r7   c           	        t        |dt        ddd      i      }|j                         }d}||v}|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      d	z   d
|iz  }t        t        j                  |            dx}}y)u*   completed 작업은 busy 봇에서 제외.z
task-300.1r   r   not inz%(py1)s not in %(py3)srV   rW   u:   completed 작업의 봇은 busy 목록에 없어야 한다rZ   r[   N)r@   rO   re   rf   rg   rh   ri   rj   rk   rl   rm   rn   rp   r2   rq   rV   rr   rs   rt   ru   s           r5   test_completed_task_excludedz,TestGetBusyBots.test_completed_task_excluded   s    >,WMN

 ""$bwf$bbbwfbbbwbbbbbbfbbbfbbbb&bbbbbbbr7   c           	        t        |dt        ddd      i      }|j                  d      }d}||v}|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d	      d
z   d|iz  }t        t        j                  |            dx}}y)u:   exclude_task_id 지정 시 해당 작업의 봇은 제외.z
task-400.1r   r   )exclude_task_idr}   r   rV   rW   u?   자기 자신 task_id를 제외하면 bot-c는 없어야 한다rZ   r[   Nrd   r   s           r5   %test_exclude_task_id_removes_own_taskz5TestGetBusyBots.test_exclude_task_id_removes_own_task   s    <k7KL

 ""<"@gwf$gggwfgggwggggggfgggfgggg&gggggggr7   c                   t        |d      }|j                         }i }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d      dz   d	|iz  }t        t        j                  |            dx}}y)
uE   task-timers.json 없으면 빈 dict 반환 (파일 없음 케이스).Nr:   r\   z%(py0)s == %(py3)srV   py0rY   u=   task-timers.json이 없으면 빈 dict를 반환해야 한다rZ   r[   )r@   re   rf   rg   ri   rj   rk   rh   rl   rm   rn   rp   r2   rq   rV   rs   @py_assert1rt   ru   s           r5   +test_missing_timers_file_returns_empty_dictz;TestGetBusyBots.test_missing_timers_file_returns_empty_dict   s}    840""$\v|\\\v\\\\\\v\\\v\\\\\\\\\\\\\r7   c           
     6   t        |t        ddd      t        ddd      t        ddd	      d
      }|j                         }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}}d	}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}}t        |      }d}||k(  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  t              rt        j
                  t              nddt        j                         v st        j                  |      rt        j
                  |      ndt        j
                  |      t        j
                  |      dz  }
t        j                  d      dz   d|
iz  }t        t        j                  |            dx}x}	}y)u3   여러 running 작업 → 관련 봇 모두 반환.
task-500.1r   r   
task-500.2r   r   
task-500.3r   r   )r   r   r   rS   rU   rV   rW   u   bot-b가 포함되어야 한다rZ   r[   Nu   bot-c가 포함되어야 한다u   bot-d가 포함되어야 한다   r\   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenr   rX   rY   rc   u.   총 3개의 busy 봇이 반환되어야 한다
>assert %(py8)spy8)r@   rL   re   rf   rg   rh   ri   rj   rk   rl   rm   rn   r   )rp   r2   rq   rV   rr   rs   rt   ru   @py_assert5@py_assert4rx   @py_format9s               r5   (test_multiple_running_tasks_all_returnedz8TestGetBusyBots.test_multiple_running_tasks_all_returned   s   *<gN*<gN*<gN
 ""$Cw& CCCw&CCCwCCCCCC&CCC&CCCC"CCCCCCCCw& CCCw&CCCwCCCCCC&CCC&CCCC"CCCCCCCCw& CCCw&CCCwCCCCCC&CCC&CCCC"CCCCCCC6{QaQ{aQQQ{aQQQQQQsQQQsQQQQQQ6QQQ6QQQ{QQQaQQQ!QQQQQQQQr7   Nr2   r   returnNone)
__name__
__module____qualname____doc__ry   r{   r   r   r   r   rK   r7   r5   rQ   rQ      s(    :[
6	c	h]Rr7   rQ   c                  (    e Zd ZdZddZddZddZy)TestGetIdleBotsu/   get_idle_bots() — 유휴 봇 목록 테스트c                   t        |i       }|j                         }t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  dt        |             d	z   d
|iz  }t        t        j                  |            dx}x}}y)u,   모든 봇이 유휴 상태 → 8개 반환.r      r\   r   r   rV   r   u)   유휴 봇은 8개여야 한다, 실제: r   r   N)r@   get_idle_botsr   rf   rg   ri   rj   rk   rh   rl   rm   rn   )	rp   r2   rq   rV   rs   r   r   rx   r   s	            r5    test_all_bots_idle_returns_eightz0TestGetIdleBots.test_all_bots_idle_returns_eight   s    82.""$6{ZaZ{aZZZ{aZZZZZZsZZZsZZZZZZ6ZZZ6ZZZ{ZZZaZZZ#LSQW[M!ZZZZZZZZr7   c           	        t        |t        ddd      t        ddd      d      }|j                         }t        |      }d}||k(  }|st	        j
                  d	|fd
||f      dt        j                         v st	        j                  t              rt	        j                  t              nddt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }t	        j                  dt        |             dz   d|iz  }t        t	        j                  |            dx}x}}d}	|	|v}|st	        j
                  d|fd|	|f      t	        j                  |	      dt        j                         v st	        j                  |      rt	        j                  |      nddz  }
t	        j                  d      dz   d|
iz  }t        t	        j                  |            dx}	}d}	|	|v}|st	        j
                  d|fd|	|f      t	        j                  |	      dt        j                         v st	        j                  |      rt	        j                  |      nddz  }
t	        j                  d      dz   d|
iz  }t        t	        j                  |            dx}	}y)u"   2개 봇 busy → 유휴 봇 6개.
task-600.1r   r   
task-600.2r   r   )r   r      r\   r   r   rV   r   u)   유휴 봇은 6개여야 한다, 실제: r   r   Nr}   r   rW   u*   bot-b는 유휴 목록에 없어야 한다rZ   r[   u*   bot-c는 유휴 목록에 없어야 한다)r@   rL   r   r   rf   rg   ri   rj   rk   rh   rl   rm   rn   )rp   r2   rq   rV   rs   r   r   rx   r   rr   rt   ru   s               r5   test_two_busy_returns_six_idlez.TestGetIdleBots.test_two_busy_returns_six_idle   s   *<gN*<gN
 ""$6{ZaZ{aZZZ{aZZZZZZsZZZsZZZZZZ6ZZZ6ZZZ{ZZZaZZZ#LSQW[M!ZZZZZZZZRwf$RRRwfRRRwRRRRRRfRRRfRRRR&RRRRRRRRwf$RRRwfRRRwRRRRRRfRRRfRRRR&RRRRRRRr7   c                .   t        g dd      D ci c]  \  }}d| t        d| d| d|       }}}t        ||      }|j                         }g }||k(  }|st	        j
                  d|fd||f      d	t        j                         v st	        j                  |      rt	        j                  |      nd	t	        j                  |      d
z  }	t	        j                  d      dz   d|	iz  }
t        t	        j                  |
            dx}}yc c}}w )u'   8개 봇 모두 busy → 빈 리스트.)r   r   r   r	   r
   r   r   r      )startz	task-700.devz-teamr\   r   rV   r   u=   모든 봇이 busy이면 빈 리스트를 반환해야 한다rZ   r[   N)	enumeraterL   r@   r   rf   rg   ri   rj   rk   rh   rl   rm   rn   )rp   r2   irJ   r:   rq   rV   rs   r   rt   ru   s              r5   %test_all_bots_busy_returns_empty_listz5TestGetIdleBots.test_all_bots_busy_returns_empty_list  s     $X	
 3 sO\A33qc 
 
 8U+""$\v|\\\v\\\\\\v\\\v\\\\\\\\\\\\\
s   "DNr   )r   r   r   r   r   r   r   rK   r7   r5   r   r      s    9[S ]r7   r   c                       e Zd ZdZddZddZy)TestIsBotAvailableu2   is_bot_available() — 봇 가용 여부 테스트c                D   t        |i       }|j                  }d} ||      }d}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }t        j                  d      d	z   d
|iz  }	t        t        j                  |	            dx}x}x}x}}y)u   유휴 봇 → True.r   r   TiszV%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.is_bot_available
}(%(py4)s)
} is %(py9)srq   r   py2r`   rc   py9u'   유휴 봇은 available이어야 한다
>assert %(py11)spy11N)r@   is_bot_availablerf   rg   ri   rj   rk   rh   rl   rm   rn   
rp   r2   rq   r   rv   r   @py_assert8@py_assert7@py_format10@py_format12s
             r5   test_idle_bot_is_availablez-TestIsBotAvailable.test_idle_bot_is_available"  s    82.##_G_#G,__,4___,______s___s___#___G___,______6________r7   c           	     \   t        |dt        ddd      i      }|j                  }d} ||      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }t        j                  d	      d
z   d|iz  }	t        t        j                  |	            dx}x}x}x}}y)u   busy 봇 → False.z
task-800.1r   r   Fr   r   rq   r   u=   running 작업 중인 봇은 available이 아니어야 한다r   r   N)r@   rL   r   rf   rg   ri   rj   rk   rh   rl   rm   rn   r   s
             r5   test_busy_bot_is_not_availablez1TestIsBotAvailable.test_busy_bot_is_not_available(  s    <k7KL

 ##vGv#G,vv,5vvv,vvvvvvsvvvsvvv#vvvGvvv,vvvvvv7vvvvvvvvr7   Nr   )r   r   r   r   r   r   rK   r7   r5   r   r     s    <`wr7   r   c                  (    e Zd ZdZddZddZddZy)TestGetTeamStatusu4   get_team_status() — 팀 상태 문자열 테스트c           	        t        |dt        ddd      i      }|j                  d      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d	|      d
z   d|iz  }t        t        j                  |            dx}}y)u0   dev팀이 running 작업 있음 → '작업중'.z
task-900.1r   r   u	   작업중r\   r   rG   r   uE   running 작업이 있는 팀은 '작업중'이어야 한다, 실제: rZ   r[   N)r@   rL   get_team_statusrf   rg   ri   rj   rk   rh   rl   rm   rn   rp   r2   rq   rG   rs   r   rt   ru   s           r5   /test_dev_team_with_running_task_returns_workingzATestGetTeamStatus.test_dev_team_with_running_task_returns_working:  s    <k7KL

 $$[1$xv$xxxvxxxxxxvxxxvxxxxxx(mntmw&xxxxxxxr7   c           	        t        |dt        ddd      i      }|j                  d      }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      ndd	z  }t        j                  d
|      dz   d|iz  }t        t        j                  |            dx}}y)uW   dev1-team의 봇(bot-b)이 논리적 팀(design)에 점유 → '봇점유(...)' 포함.ztask-1000.1r   r   r   u	   봇점유rS   rU   rG   rW   uA   봇 점유 상태는 '봇점유'를 포함해야 한다, 실제: rZ   r[   N)r@   rL   r   rf   rg   rh   ri   rj   rk   rl   rm   rn   )rp   r2   rq   rG   rr   rs   rt   ru   s           r5   6test_dev_team_bot_occupied_by_logical_returns_occupiedzHTestGetTeamStatus.test_dev_team_bot_occupied_by_logical_returns_occupiedE  s    L'JK

 $$[1t{f$ttt{fttt{ttttttftttftttt(ijpis&tttttttr7   c                   t        |i       }|j                  d      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d|      d	z   d
|iz  }t        t        j                  |            dx}}y)u&   아무 작업 없는 팀 → '유휴'.r   r   u   유휴r\   r   rG   r   u4   작업 없는 팀은 '유휴'여야 한다, 실제: rZ   r[   N)r@   r   rf   rg   ri   rj   rk   rh   rl   rm   rn   r   s           r5   $test_team_with_no_tasks_returns_idlez6TestGetTeamStatus.test_team_with_no_tasks_returns_idleP  s    82.$$[1!dv!dddvddddddvdddvdddddd%YZ`Yc#dddddddr7   Nr   )r   r   r   r   r   r   r   rK   r7   r5   r   r   7  s    >	y	uer7   r   c                  0    e Zd ZdZddZddZddZddZy)TestGetBotOccupationu;   get_bot_occupation() — 물리 봇 점유 탐지 테스트c           	     b   t        |dt        ddd      i      }|j                         }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d	      d
z   d|iz  }t        t        j                  |            dx}}|d   d   }d}||k(  }|st        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }	t        j                  d      dz   d|	iz  }
t        t        j                  |
            dx}x}}|d   d   }d}||k(  }|st        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }	t        j                  d      dz   d|	iz  }
t        t        j                  |
            dx}x}}|d   d   }d}||k(  }|st        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }	t        j                  d      dz   d|	iz  }
t        t        j                  |
            dx}x}}y)u9   design 팀이 bot-b 점유 → dev1 점유 정보 반환.ztask-1100.1r   r   r   rS   rU   rV   rW   u8   bot-b를 점유하면 dev1 엔트리가 있어야 한다rZ   r[   Nteamr\   r^   r_   u$   점유 팀이 design이어야 한다rb   rc   bot_idu#   점유 봇이 bot-b이어야 한다rE   ra   r@   rL   get_bot_occupationrf   rg   rh   ri   rj   rk   rl   rm   rn   ro   s              r5   ,test_design_occupies_bot_b_returns_dev1_infozATestGetBotOccupation.test_design_occupies_bot_b_returns_dev1_infoa  s   L'JK

 '')[v[[[v[[[v[[[[[[[[[[[[[![[[[[[[f~f%YY%1YYY%YYY%YYYYYY3YYYYYYYYf~h'Y7Y'72YYY'7YYY'YYY7YYY4YYYYYYYYf~i([M[(M9[[[(M[[[([[[M[[[;[[[[[[[[r7   c           	        t        |dt        ddd      i      }|j                         }d}||v}|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d	      d
z   d|iz  }t        t        j                  |            dx}}y)uQ   dev1-team 자체 작업은 봇 점유(cross-team occupation)로 잡히지 않음.ztask-1200.1r   r   r   r}   r   rV   rW   u:   자기 팀 작업은 타팀 점유로 잡혀선 안 된다rZ   r[   Nr   r   s           r5   (test_dev_team_own_task_not_in_occupationz=TestGetBotOccupation.test_dev_team_own_task_not_in_occupationo  s    LWMN

 '')avV#aaavVaaavaaaaaaVaaaVaaaa%aaaaaaar7   c                   ddddddd}t        |d|i      }|j                         }i }||k(  }|st        j                  d|fd	||f      d
t	        j
                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}}y)u7   bot 필드 없는 작업은 점유 탐지에서 무시.ztask-1300.1r   u   봇 미지정 작업rB   rC   N)rE   rF   r   rG   rH   rI   r\   r   rV   r   u=   bot 필드 없는 작업은 점유 결과가 비어야 한다rZ   r[   )r@   r   rf   rg   ri   rj   rk   rh   rl   rm   rn   )	rp   r2   task_no_botrq   rV   rs   r   rt   ru   s	            r5   &test_task_without_bot_field_is_ignoredz;TestGetBotOccupation.test_task_without_bot_field_is_ignoredz  s     %15
 8m[%AB'')\v|\\\v\\\\\\v\\\v\\\\\\\\\\\\\r7   c           	        t        |dt        ddd      i      }|j                         }d}||v}|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }t        j                  d	      d
z   d|iz  }t        t        j                  |            dx}}y)u6   completed 작업은 봇 점유에 포함되지 않음.ztask-1400.1r   r   r   r}   r   rV   rW   u2   완료된 작업은 점유로 잡혀선 안 된다rZ   r[   N)r@   rO   r   rf   rg   rh   ri   rj   rk   rl   rm   rn   r   s           r5   %test_completed_task_not_in_occupationz:TestGetBotOccupation.test_completed_task_not_in_occupation  s    N=(GLM

 '')YvV#YYYvVYYYvYYYYYYVYYYVYYYY%YYYYYYYr7   Nr   )r   r   r   r   r   r   r   r   rK   r7   r5   r   r   ^  s    E\	b]"	Zr7   r   c                  8    e Zd ZdZddZddZddZddZddZy)	TestSuggestTeamu8   suggest_team() — 키워드 기반 팀 추천 테스트c                   t        |i       }|j                  d      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d|      d	z   d
|iz  }t        t        j                  |            dx}}y)u(   디자인 키워드 → 'design' 추천.r   !   신제품 배너 디자인 제작r   r\   r   rV   r   u@   디자인 키워드는 'design'을 추천해야 한다, 실제: rZ   r[   Nr@   suggest_teamrf   rg   ri   rj   rk   rh   rl   rm   rn   r   s           r5   "test_design_keyword_returns_designz2TestSuggestTeam.test_design_keyword_returns_design  s    82.!!"EF!pv!pppvppppppvpppvpppppp%efleo#pppppppr7   c                   t        |i       }|j                  d      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d|      d	z   d
|iz  }t        t        j                  |            dx}}y)u+   마케팅 키워드 → 'marketing' 추천.r   u)   신규 캠페인 기획 및 카피 작성r    r\   r   rV   r   uC   마케팅 키워드는 'marketing'을 추천해야 한다, 실제: rZ   r[   Nr   r   s           r5   (test_marketing_keyword_returns_marketingz8TestSuggestTeam.test_marketing_keyword_returns_marketing  s    82.!!"MN$vv$vvvvvvvvvvvvvvvvvvvvv(klrku&vvvvvvvr7   c                   t        |i       }|j                  d      }d}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d|      d	z   d
|iz  }t        t        j                  |            dx}}y)u!   매칭 키워드 없음 → None.r   u$   서버 배포 파이프라인 점검Nr   z%(py0)s is %(py3)srV   r   u/   매칭 없으면 None이어야 한다, 실제: rZ   r[   r   r   s           r5   %test_no_matching_keyword_returns_nonez5TestSuggestTeam.test_no_matching_keyword_returns_none  s    82.!!"HI[v~[[[v[[[[[[v[[[v[[[[[[!PQWPZ[[[[[[[r7   c                   t        |i       }|j                  d      }d}||k7  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d|      d	z   d
|iz  }t        t        j                  |            dx}}y)u?   anti-keyword가 포함되면 해당 팀은 추천에서 제외.r   u   배너 HTML 수정 요청r   )!=)z%(py0)s != %(py3)srV   r   uK   anti-keyword가 있으면 design은 추천되지 않아야 한다, 실제: rZ   r[   Nr   r   s           r5   test_anti_keyword_excludes_teamz/TestSuggestTeam.test_anti_keyword_excludes_team  s    82. !!"=>!{v!{{{v{{{{{{v{{{v{{{{{{%pqwpz#{{{{{{{r7   c                   t        |i       }|j                  d      }d}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d|      d	z   d
|iz  }t        t        j                  |            dx}}y)u   빈 문자열 → None.r    Nr   r   rV   r   u/   빈 문자열은 None이어야 한다, 실제: rZ   r[   r   r   s           r5   test_empty_string_returns_nonez.TestSuggestTeam.test_empty_string_returns_none  s    82.!!"%[v~[[[v[[[[[[v[[[v[[[[[[!PQWPZ[[[[[[[r7   Nr   )	r   r   r   r   r   r   r   r   r   rK   r7   r5   r   r     s#    Bqw\|\r7   r   c                  0    e Zd ZdZddZddZddZddZy)TestValidateRoutingu8   validate_routing() — 라우팅 검증 경고 테스트c                <   t        |i       }|j                  dd      }d}||u}|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d	      d
z   d|iz  }t        t        j                  |            dx}}t        |t              }|s-t        j                  dt        |             dz   dt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      nddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }	t        t        j                  |	            d}y)u>   dev팀에 디자인 작업 배정 → 경고 문자열 반환.r   r   r   N)is not)z%(py0)s is not %(py3)srV   r   u;   dev팀에 디자인 작업은 경고를 반환해야 한다rZ   r[   u-   경고는 문자열이어야 한다, 실제: z7
>assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstancestr)r   rX   r   r`   )r@   validate_routingrf   rg   ri   rj   rk   rh   rl   rm   rn   r   r   type)
rp   r2   rq   rV   rs   r   rt   ru   rv   rw   s
             r5   .test_dev_team_with_design_task_returns_warningzBTestValidateRouting.test_dev_team_with_design_task_returns_warning  s&   82.%%k3VW!`vT!```vT``````v```v```T```#```````&#&f&ff*WX\]cXdWe(fffffffzfffzffffff&fff&ffffff#fff#fff&ffffffr7   c                   t        |i       }|j                  dd      }d}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d	|      d
z   d|iz  }t        t        j                  |            dx}}y)u1   dev팀에 코딩 작업 → 경고 없음 (None).r   r   u6   API 엔드포인트 구현 및 유닛 테스트 작성Nr   r   rV   r   uD   dev팀 코딩 작업은 경고 없이 None이어야 한다, 실제: rZ   r[   r@   r   rf   rg   ri   rj   rk   rh   rl   rm   rn   r   s           r5   +test_dev_team_with_coding_task_returns_nonez?TestValidateRouting.test_dev_team_with_coding_task_returns_none  s    82.%%k3klpv~pppvppppppvpppvpppppp!efleopppppppr7   c                   t        |i       }|j                  dd      }d}||u }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d	|      d
z   d|iz  }t        t        j                  |            dx}}y)u<   논리적 팀(design)에 디자인 작업 → 경고 없음.r   r   u   배너 디자인 시안 작성Nr   r   rV   r   uF   design 팀의 디자인 작업은 경고가 없어야 한다, 실제: rZ   r[   r   r   s           r5   ,test_logical_team_with_own_task_returns_nonez@TestValidateRouting.test_logical_team_with_own_task_returns_none  s    82.%%h0PQrv~rrrvrrrrrrvrrrvrrrrrr!ghngqrrrrrrrr7   c                   t        |i       }|j                  ddd      }d}||u }|st        j                  d|fd||f      d	t	        j
                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
z  }t        j                  d|      dz   d|iz  }t        t        j                  |            dx}}y)u6   override_routing=True → 경고 억제 (None 반환).r   r   r   T)override_routingNr   r   rV   r   uG   override_routing=True 이면 경고가 억제되어야 한다, 실제: rZ   r[   r   r   s           r5   (test_override_routing_suppresses_warningz<TestValidateRouting.test_override_routing_suppresses_warning  s    82.%%k3Vim%nsv~sssvssssssvsssvssssss!hiohrsssssssr7   Nr   )r   r   r   r   r   r   r   r  rK   r7   r5   r   r     s    Bgqstr7   r   __main__z-v)r2   r   r   r   )r2   r   r:   r"   r   r   )N)r2   r   r:   zdict | Noner   r   )u   작업 설명)
rE   r   rF   r   rJ   r   r   r   r   r"   )rE   r   rF   r   rJ   r   r   r"   )'r   
__future__r   builtinsri   _pytest.assertion.rewrite	assertionrewriterf   r0   syspathlibr   pytestpathinsertr   __file__parentutils.bot_statusr   r   __annotations__r   r#   r6   r=   r@   rL   rO   rQ   r   r   r   r   r   r   r   mainrK   r7   r5   <module>r     s   #    
   3tH~,,33::; < - 	^ 	 	~ 	 T[Q s1 Q1t 0$5( '	 
 	
 
" 
 
	*JR JRd*] *]dw w0e eN6Z 6Z|*\ *\d"t "tJ zFKK4 ! r7   