
    iL                        d Z ddlZddlZddlZddlmZ ddlmZmZm	Z	 ddl
Z
ej                  j                  d e ee      j                         j                   j                                 e
j"                         d        Z e
j"                         d        Z G d d      Z G d	 d
      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      ZdedefdZy)u   GLM MCP Server 테스트 스위트.

헤임달(테스터) 역할로 작성된 테스트입니다.
z.ai API 잔액 부족(429) 상황을 고려하여 전부 mock으로 처리합니다.
    N)Path)	MagicMockcallpatchc                  V    t               } d| j                  d   j                  _        | S )u6   단일 성공 API 응답 mock을 반환하는 fixture.mock response textr   r   choicesmessagecontent)responses    P/home/jay/workspace/.worktrees/task-2116-dev1/tools/glm-mcp/tests/test_server.pymock_api_responser      s)     {H*>HQ'O    c              #      K   t        d      5 }| |j                  j                  j                  _        | ddd       y# 1 sw Y   yxY ww)u2   client.chat.completions.create를 mock한 fixture.server.clientN)r   chatcompletionscreatereturn_value)r   patched_clients     r   mock_clientr       sF      
	 >>O''..;  s   A*A	AA
Ac                       e Zd Zd Zd Zy)TestSystemPromptsDefinitionc                 ~    ddl }h d}t        |j                  j                               }||k(  sJ d||z
          y)uB   SYSTEM_PROMPTS에 4개 역할이 모두 정의되었는지 확인.r   N>   uxuitesterbackendfrontendu   누락된 역할: )serversetSYSTEM_PROMPTSkeys)selfr    required_rolesdefined_roless       r   test_system_prompts_definedz7TestSystemPromptsDefinition.test_system_prompts_defined.   sN     	B F116689 . 	
 -!? @A	
.r   c                     ddl }|j                  j                         D ]E  \  }}t        |t              s
J | d       t        |j                               dkD  r=J | d        y)uA   각 역할의 system prompt가 빈 문자열이 아닌지 확인.r   Nu!    prompt는 str이어야 합니다u    prompt가 비어 있습니다)r    r"   items
isinstancestrlenstrip)r$   r    roleprompts       r   test_system_prompts_not_emptyz9TestSystemPromptsDefinition.test_system_prompts_not_empty=   sl    "11779 	TLD&fc*Vtf4U,VV*v||~&*Stf4R,SS*	Tr   N)__name__
__module____qualname__r'   r0    r   r   r   r   -   s    
Tr   r   c                       e Zd Zd Zd Zd Zy)TestGlmGenerateBasicc                 l   ddl }dd}|j                  |      }|j                  j                  j                  j                          |j                  j                  j                  j                  }|j                  d   |k(  sJ |j                  d   }t        fd|D              sJ |d	k(  sJ y)
uB   glm_generate가 올바른 인자로 API를 호출하는지 확인.r   NzHello, GLM!glm-4.7-flash)r/   modelr9   messagesc              3   B   K   | ]  }|d    dk(  xr |d   k(    yw)r.   userr   Nr4   ).0mr/   s     r   	<genexpr>z?TestGlmGenerateBasic.test_glm_generate_basic.<locals>.<genexpr>\   s+     Ta1V9&A1Y<6+AATs   r   )	r    glm_generater   r   r   assert_called_once	call_argskwargsany)r$   r   r    r9   resultcall_kwargsr:   r/   s          @r   test_glm_generate_basicz,TestGlmGenerateBasic.test_glm_generate_basicL   s      $$F%$@ 	$$++>>@!&&2299CC!!'*e333%%j1T8TTTT----r   c                 T    ddl }|j                  d      }t        |t              sJ y)u4   glm_generate가 문자열을 반환하는지 확인.r   Ntestr/   )r    r@   r*   r+   r$   r   r    rE   s       r    test_glm_generate_returns_stringz5TestGlmGenerateBasic.test_glm_generate_returns_string_   s(    $$F$3&#&&&r   c                     ddl }|j                  d       |j                  j                  j                  j
                  }|j                  d   dk(  sJ y)u<   glm_generate의 기본 모델이 glm-4.7-flash인지 확인.r   NrI   rJ   r9   r8   )r    r@   r   r   r   rB   rC   r$   r   r    rF   s       r   test_glm_generate_default_modelz4TestGlmGenerateBasic.test_glm_generate_default_modelg   sL    6*!&&2299CC!!'*o===r   N)r1   r2   r3   rG   rL   rO   r4   r   r   r6   r6   K   s    .&'>r   r6   c                       e Zd Zd Zd Zd Zy)TestGlmGenerateWithSystemPromptc                     ddl }d}d}|j                  ||       |j                  j                  j                  j
                  }|j                  d   }|D cg c]  }|d   dk(  s| }}t        |      d	k(  sJ |d   d
   |k(  sJ yc c}w )uW   system_prompt 지정 시 messages에 system 역할 메시지가 추가되는지 확인.r   Nu   당신은 전문가입니다.u   FastAPI 예제 작성r/   system_promptr:   r.   system   r   r    r@   r   r   r   rB   rC   r,   )	r$   r   r    rT   r/   rF   r:   r>   system_messagess	            r   $test_glm_generate_with_system_promptzDTestGlmGenerateWithSystemPrompt.test_glm_generate_with_system_promptw   s     8( 	6G "&&2299CC%%j1&.H!F)x2G1HH?#q(((q!),=== Is   B'Bc                     ddl }|j                  dd       |j                  j                  j                  j
                  }|j                  d   }|D cg c]  }|d   dk(  s| }}t        |      dk(  sJ yc c}w )	uH   system_prompt 미지정 시 system 역할 메시지가 없는지 확인.r   NrI    rS   r:   r.   rU   rW   )r$   r   r    rF   r:   r>   rX   s          r   9test_glm_generate_without_system_prompt_no_system_messagezYTestGlmGenerateWithSystemPrompt.test_glm_generate_without_system_prompt_no_system_message   s     	6< "&&2299CC%%j1&.H!F)x2G1HH?#q((( Is   A:#A:c                    ddl }|j                  dd       |j                  j                  j                  j
                  }|j                  d   }|D cg c]  }|d   	 }}|j                  d      |j                  d	      k  sJ yc c}w )
uG   system 메시지가 user 메시지보다 앞에 위치하는지 확인.r   NrI   zsystem contentrS   r:   r.   rU   r<   )r    r@   r   r   r   rB   rC   index)r$   r   r    rF   r:   r>   roless          r   test_glm_generate_message_orderz?TestGlmGenerateWithSystemPrompt.test_glm_generate_message_order   s    69IJ!&&2299CC%%j1$,-q6--{{8$u{{6':::: .s   B	N)r1   r2   r3   rY   r\   r`   r4   r   r   rQ   rQ   v   s    >$)	;r   rQ   c                   $    e Zd Zd Zd Zd Zd Zy)TestGlmCodeWithReviewc                 $   ddl }t        d      t        d      t        d      g|j                  j                  j                  _        |j                  dd      }|j                  j                  j                  j                  d	k(  sJ |dk(  sJ y)
u   glm_code가 1회 리뷰 사이클 시 총 3번 API를 호출하는지 확인.

        호출 순서: 초기 코드 생성 → 리뷰 → 수정
        r   Ninitial codereview feedback
fixed codeu   유틸 함수 작성rV   taskreview_cycles   )r    _make_responser   r   r   side_effectglm_code
call_countrK   s       r   test_glm_code_with_reviewz/TestGlmCodeWithReview.test_glm_code_with_review   s    
 	 >*,-<(;
$$++7 &<AN ++22==BBB%%%r   c                     ddl }|j                  dd       |j                  j                  j                  j
                  dk(  sJ y)uL   review_cycles=0 시 API가 1번만 호출(초기 생성만)되는지 확인.r   Nu   간단한 함수rg   rV   r    rm   r   r   r   rn   r$   r   r    s      r    test_glm_code_zero_review_cyclesz6TestGlmCodeWithReview.test_glm_code_zero_review_cycles   s@     	/qA ++22==BBBr   c                    ddl }t        d      t        d      t        d      g|j                  j                  j                  _        |j                  dd       |j                  j                  j                  j                  d   }|j                  d	   }|D cg c]  }|d
   dk(  s| }}t        d |D              sJ yc c}w )u?   리뷰 메시지에 생성된 코드가 포함되는지 확인.r   Ngenerated code contentre   rf      작업rV   rg   r:   r.   r<   c              3   *   K   | ]  }d |d   v   yw)ru   r   Nr4   r=   r>   s     r   r?   zSTestGlmCodeWithReview.test_glm_code_review_messages_include_code.<locals>.<genexpr>   s     S+q|;S   
r    rk   r   r   r   rl   rm   call_args_listrC   rD   )r$   r   r    review_callreview_messagesr>   user_messagess          r   *test_glm_code_review_messages_include_codez@TestGlmCodeWithReview.test_glm_code_review_messages_include_code   s     34,-<(;
$$++7 	XQ7 "&&2299HHK%,,Z8$3KqqyF7JKKS]SSSS L   C)Cc                    ddl }t        d      t        d      t        d      g|j                  j                  j                  _        |j                  dd       |j                  j                  j                  j                  d	   }|j                  d
   }|D cg c]  }|d   dk(  s| }}t        d |D              sJ yc c}w )uF   코드 수정 메시지에 리뷰 피드백이 포함되는지 확인.r   Nrd   critical review feedbackrf   rv   rV   rg      r:   r.   r<   c              3   *   K   | ]  }d |d   v   yw)r   r   Nr4   rx   s     r   r?   zTTestGlmCodeWithReview.test_glm_code_fix_messages_include_feedback.<locals>.<genexpr>   s     U!-9=Ury   rz   )r$   r   r    fix_callfix_messagesr>   r~   s          r   +test_glm_code_fix_messages_include_feedbackzATestGlmCodeWithReview.test_glm_code_fix_messages_include_feedback   s     >*56<(;
$$++7 	XQ7 ##//66EEaHz2$0HqAfI4GHHU}UUUU Ir   N)r1   r2   r3   ro   rs   r   r   r4   r   r   rb   rb      s    &*CT$Vr   rb   c                   $    e Zd Zd Zd Zd Zd Zy)TestGlmCodeReviewCyclesClampedc                     ddl }|j                  dd       |j                  j                  j                  j
                  dk(  sJ y)u\   review_cycles가 음수이면 0으로 클램핑되어 API가 1번만 호출되는지 확인.r   Nrv   rg   rV   rq   rr   s      r   %test_review_cycles_clamped_below_zerozDTestGlmCodeReviewCyclesClamped.test_review_cycles_clamped_below_zero   s;    XR8++22==BBBr   c                 *   ddl }t        d      D cg c]  }t        d|        c}|j                  j                  j
                  _        |j                  dd       |j                  j                  j
                  j                  dk(  sJ yc c}w )u   review_cycles가 3을 초과하면 3으로 클램핑되는지 확인.

        API 호출 횟수: 초기(1) + 3사이클 × 2(리뷰+수정) = 7
        r   N   	response_rv   d   rg   	r    rangerk   r   r   r   rl   rm   rn   r$   r   r    is       r   &test_review_cycles_clamped_above_threezETestGlmCodeReviewCyclesClamped.test_review_cycles_clamped_above_three   s    
 	 6;1X;
01NYqc?+;
$$++7 	XS9++22==BBB;
   Bc                     ddl }|j                  dd       |j                  j                  j                  j
                  dk(  sJ y)u+   review_cycles=0 경계값: API 1회 호출.r   Nrv   rg   rV   rq   rr   s      r   #test_review_cycles_at_boundary_zerozBTestGlmCodeReviewCyclesClamped.test_review_cycles_at_boundary_zero	  s;    XQ7++22==BBBr   c                 *   ddl }t        d      D cg c]  }t        d|        c}|j                  j                  j
                  _        |j                  dd       |j                  j                  j
                  j                  dk(  sJ yc c}w )u+   review_cycles=3 경계값: API 7회 호출.r   Nr   r   rv   rj   rg   r   r   s       r   $test_review_cycles_at_boundary_threezCTestGlmCodeReviewCyclesClamped.test_review_cycles_at_boundary_three  s}     6;1X;
01NYqc?+;
$$++7 	XQ7++22==BBB;
r   N)r1   r2   r3   r   r   r   r   r4   r   r   r   r      s    CCC
Cr   r   c                       e Zd Zd Zy)TestGlmBackendModelc                     ddl }|j                  d       |j                  j                  j                  j
                  }|j                  d   dk(  sJ y)u6   glm_backend가 glm-5 모델을 사용하는지 확인.r   Nu	   DB 설계rh   r9   glm-5)r    glm_backendr   r   r   rB   rC   rN   s       r   #test_glm_backend_uses_correct_modelz7TestGlmBackendModel.test_glm_backend_uses_correct_model$  sP     	, "&&2299CC!!'*g555r   N)r1   r2   r3   r   r4   r   r   r   r   #      	6r   r   c                       e Zd Zd Zy)TestGlmFrontendModelc                     ddl }|j                  d       |j                  j                  j                  j
                  }|j                  d   dk(  sJ y)u?   glm_frontend가 glm-4.7-flash 모델을 사용하는지 확인.r   Nu   React 컴포넌트 작성r   r9   r   )r    glm_frontendr   r   r   rB   rC   rN   s       r   $test_glm_frontend_uses_correct_modelz9TestGlmFrontendModel.test_glm_frontend_uses_correct_model6  sQ     	!<= "&&2299CC!!'*g555r   N)r1   r2   r3   r   r4   r   r   r   r   5  r   r   r   c                   *    e Zd Zd Zd Zd Zd Zd Zy)TestRoleToolsUseCorrectPromptsc                     ddl }|j                  d       |j                  j                  j                  j
                  }|j                  d   }t        d |D              }||j                  d   k(  sJ y)uC   glm_backend가 SYSTEM_PROMPTS['backend']를 사용하는지 확인.r   Nrv   r   r:   c              3   8   K   | ]  }|d    dk(  s|d     ywr.   rU   r   Nr4   rx   s     r   r?   zVTestRoleToolsUseCorrectPrompts.test_glm_backend_uses_backend_prompt.<locals>.<genexpr>P  $      
ai8.CAiL
   
r   )	r    r   r   r   r   rB   rC   nextr"   r$   r   r    rF   r:   system_contents         r   $test_glm_backend_uses_backend_promptzCTestRoleToolsUseCorrectPrompts.test_glm_backend_uses_backend_promptH  su    )!&&2299CC%%j1 
"*
 
 !6!6y!AAAAr   c                     ddl }|j                  d       |j                  j                  j                  j
                  }|j                  d   }t        d |D              }||j                  d   k(  sJ y)uE   glm_frontend가 SYSTEM_PROMPTS['frontend']를 사용하는지 확인.r   Nrv   r   r:   c              3   8   K   | ]  }|d    dk(  s|d     ywr   r4   rx   s     r   r?   zXTestRoleToolsUseCorrectPrompts.test_glm_frontend_uses_frontend_prompt.<locals>.<genexpr>]  r   r   r   )	r    r   r   r   r   rB   rC   r   r"   r   s         r   &test_glm_frontend_uses_frontend_promptzETestRoleToolsUseCorrectPrompts.test_glm_frontend_uses_frontend_promptU  su    *!&&2299CC%%j1 
"*
 
 !6!6z!BBBBr   c                     ddl }|j                  d       |j                  j                  j                  j
                  }|j                  d   }t        d |D              }||j                  d   k(  sJ y)u=   glm_uxui가 SYSTEM_PROMPTS['uxui']를 사용하는지 확인.r   Nrv   r   r:   c              3   8   K   | ]  }|d    dk(  s|d     ywr   r4   rx   s     r   r?   zPTestRoleToolsUseCorrectPrompts.test_glm_uxui_uses_uxui_prompt.<locals>.<genexpr>j  r   r   r   )	r    glm_uxuir   r   r   rB   rC   r   r"   r   s         r   test_glm_uxui_uses_uxui_promptz=TestRoleToolsUseCorrectPrompts.test_glm_uxui_uses_uxui_promptb  sr    X&!&&2299CC%%j1 
"*
 
 !6!6v!>>>>r   c                     ddl }|j                  d       |j                  j                  j                  j
                  }|j                  d   }t        d |D              }||j                  d   k(  sJ y)uA   glm_tester가 SYSTEM_PROMPTS['tester']를 사용하는지 확인.r   Nrv   r   r:   c              3   8   K   | ]  }|d    dk(  s|d     ywr   r4   rx   s     r   r?   zTTestRoleToolsUseCorrectPrompts.test_glm_tester_uses_tester_prompt.<locals>.<genexpr>w  r   r   r   )	r    
glm_testerr   r   r   rB   rC   r   r"   r   s         r   "test_glm_tester_uses_tester_promptzATestRoleToolsUseCorrectPrompts.test_glm_tester_uses_tester_prompto  su    x(!&&2299CC%%j1 
"*
 
 !6!6x!@@@@r   c                     ddl }|j                  dd       |j                  j                  j                  j
                  }|j                  d   }t        d |D              }||j                  d   k(  sJ y)uT   glm_code의 기본 role(backend)이 backend system prompt를 사용하는지 확인.r   Nrv   rg   r:   c              3   8   K   | ]  }|d    dk(  s|d     ywr   r4   rx   s     r   r?   z`TestRoleToolsUseCorrectPrompts.test_glm_code_default_role_uses_backend_prompt.<locals>.<genexpr>  r   r   r   )	r    rm   r   r   r   rB   rC   r   r"   r   s         r   .test_glm_code_default_role_uses_backend_promptzMTestRoleToolsUseCorrectPrompts.test_glm_code_default_role_uses_backend_prompt|  st    XQ7!&&2299CC%%j1 
"*
 
 !6!6y!AAAAr   N)r1   r2   r3   r   r   r   r   r   r4   r   r   r   r   G  s    BC?ABr   r   c                   *    e Zd Zd Zd Zd Zd Zd Zy)TestApiRetryOnFailurec                    ddl }t        d      5 }t        d      5 }t        d      t        d      t        d      g|j                  j
                  j                  _        |j                  dd	d
gdd      }ddd       ddd       dk(  sJ j                  j
                  j                  j                  dk(  sJ j                  dk(  sJ y# 1 sw Y   YxY w# 1 sw Y   ]xY w)uB   API 실패 시 MAX_RETRIES 횟수만큼 재시도하는지 확인.r   Nr   server.time.sleepu   첫 번째 실패u   두 번째 실패u   최종 성공r<   rI   r.   r   r8   r   r:   r9   
max_tokensrj   r   )
r    r   	Exceptionrk   r   r   r   rl   	_call_apirn   )r$   r    r   
mock_sleeprE   s        r   test_api_retry_on_failurez/TestApiRetryOnFailure.test_api_retry_on_failure  s     ?# 	{E5
 	-.-./?K((//; %%#)f=>% & F	 	" (((++22==BBB$$))))	 	 	 	s#   CAC8CC	CC%c                 x   ddl }t        d      5 }t        d      5  t        d      |j                  j                  j
                  _        t        j                  t        d      5  |j                  dd	d
gdd       ddd       ddd       ddd       y# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   yxY w)uC   모든 재시도 실패 시 RuntimeError가 발생하는지 확인.r   Nr   r      항상 실패u   API 호출 실패)matchr<   rI   r   r8   r   r   )r    r   r   r   r   r   rl   pytestraisesRuntimeErrorr   )r$   r    r   s      r   9test_api_raises_runtime_error_after_all_retries_exhaustedzOTestApiRetryOnFailure.test_api_raises_runtime_error_after_all_retries_exhausted  s    ?# 	{E:M4N 	>G>XK((//;|3FG   '-&AB)" ! 	 	 	 	 	 	 	s;   B0A
B$&B?B$B0B!B$$B-	)B00B9c                    ddl }t        d      5 }t        d      5  t        d      |j                  j                  j
                  _        t        j                  t              5  |j                  dddgd	d
       ddd       ddd       ddd       |j                  dz   }j                  j                  j
                  j                  |k(  sJ y# 1 sw Y   XxY w# 1 sw Y   \xY w# 1 sw Y   `xY w)u2   총 시도 횟수가 MAX_RETRIES + 1인지 확인.r   Nr   r   r   r<   rI   r   r8   r   r   rV   )r    r   r   r   r   r   rl   r   r   r   r   MAX_RETRIESrn   )r$   r    r   expected_callss       r   9test_api_retry_total_attempts_equals_max_retries_plus_onezOTestApiRetryOnFailure.test_api_retry_total_attempts_equals_max_retries_plus_one  s    ?# 	{E:M4N 	>G>XK((//;|,   '-&AB)" ! 	 	  ++a/++22==OOO 	 	 	 	s;   C,AC $C=C C,CC  C)	%C,,C5c                 2   ddl }t        d      5 }t        d      5  t        d      |j                  j                  j
                  _        |j                  d      }ddd       ddd       j                  d      sJ y# 1 sw Y   %xY w# 1 sw Y   )xY w)	u]   glm_generate가 API 전체 실패 시 [오류] 접두어 문자열을 반환하는지 확인.r   Nr   r      실패rI   rJ   u   [오류])	r    r   r   r   r   r   rl   r@   
startswith)r$   r    r   rE   s       r   5test_glm_generate_returns_error_string_on_api_failurezKTestApiRetryOnFailure.test_glm_generate_returns_error_string_on_api_failure  s    ?# 	8{E:M4N 	8>G>QK((//;(((7F	8 	8
   ,,,	8 	8 	8 	8s#   BABBB
	BBc                 d   ddl }t        d      5 }t        d      5 }t        d      t        d      g|j                  j
                  j                  _        |j                  ddd	gd
d       ddd       ddd       j                  |j                         y# 1 sw Y   -xY w# 1 sw Y   1xY w)uG   재시도 간 sleep이 RETRY_INTERVAL 값으로 호출되는지 확인.r   Nr   r   r   u   성공r<   rI   r   r8   r   r   )r    r   r   rk   r   r   r   rl   r   assert_called_withRETRY_INTERVAL)r$   r    r   r   s       r   )test_api_sleep_interval_is_retry_intervalz?TestApiRetryOnFailure.test_api_sleep_interval_is_retry_interval  s    ?# 	{E5
 	(#x(?K((//;
 #)f=>%  	 	 	%%f&;&;<	 	 	 	s#   B&AB.B&B#	B&&B/N)r1   r2   r3   r   r   r   r   r   r4   r   r   r   r     s    *6P"	-=r   r   c                       e Zd Zd Zd Zy)TestMcpToolsRegisteredc                     ddl }h d}t        |j                  j                  j                  j                               }||z
  }|r
J d|        y)u5   6개 tool이 모두 MCP에 등록되었는지 확인.r   N>   rm   r   r   r   r   r@   u   등록되지 않은 tool: )r    r!   mcp_tool_manager_toolsr#   )r$   r    expected_tools
registeredmissings        r   test_mcp_tools_registeredz0TestMcpToolsRegistered.test_mcp_tools_registered  sT    
 1188==?@
 !:-B8	BB{7r   c                 l    ddl }|j                  j                  j                  }t	        |      dk(  sJ y)u9   MCP에 등록된 tool 수가 정확히 6개인지 확인.r   N   )r    r   r   r   r,   )r$   r    r   s      r   test_mcp_tools_countz+TestMcpToolsRegistered.test_mcp_tools_count  s,    ZZ--44
:!###r   N)r1   r2   r3   r   r   r4   r   r   r   r     s    C*$r   r   r   returnc                 V    t               }| |j                  d   j                  _        |S )uF   지정된 content를 가진 API 응답 mock 객체를 생성합니다.r   r	   )r   r   s     r   rk   rk     s'    {H*1HQ'Or   )__doc__	importlibsystypespathlibr   unittest.mockr   r   r   r   pathinsertr+   __file__resolveparentfixturer   r   r   r6   rQ   rb   r   r   r   r   r   r   rk   r4   r   r   <module>r      s    
   0 0  3tH~--/66==> ?    T T<#> #>V); );bBV BVT*C *Cd
6 
6$
6 
6$@B @BPX= X=@$ $FC I r   