
    qi L                     *   d Z ddlZddlmc m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    6/home/jay/workspace/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                 0   ddl }h d}t        |j                  j                               }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  |      rt	        j                  |      nddz  }t	        j                  d	||z
         d
z   d|iz  }t        t	        j                  |            d}y)uB   SYSTEM_PROMPTS에 4개 역할이 모두 정의되었는지 확인.r   N>   uxuitesterbackendfrontend==)z%(py0)s == %(py2)srequired_rolesdefined_roles)py0py2u   누락된 역할: z
>assert %(py4)spy4)serversetSYSTEM_PROMPTSkeys
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanation)selfr'   r"   r#   @py_assert1@py_format3@py_format5s          r   test_system_prompts_definedz7TestSystemPromptsDefinition.test_system_prompts_defined.   s     	B F116689 . 	
 	
~ 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  "/ 	
 	
 		 "/ 	
 	
  !-!? @A	
 	
 	
 	
 	
r   c           
         ddl }|j                  j                         D ]  \  }}t        |t              }|s$t        j                  | d      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}|j                  } |       }t        |      }d}	||	kD  }
|
s7t        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                  |      t        j                  |      t        j                  |	      dz  }t        j                  | d      dz   d|iz  }t        t        j                  |            dx}x}x}x}
}	 y)uA   각 역할의 system prompt가 빈 문자열이 아닌지 확인.r   Nu!    prompt는 str이어야 합니다z7
>assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstancepromptstrr$   py1r%   r&   )>)zb%(py7)s
{%(py7)s = %(py0)s(%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.strip
}()
})
} > %(py10)slen)r$   r>   py3py5py7py10u    prompt가 비어 있습니다z
>assert %(py12)spy12)r'   r)   itemsr:   r<   r+   r1   r-   r.   r/   r0   r2   r3   stripr@   r,   )r4   r'   roler;   @py_assert3r7   @py_assert2@py_assert4@py_assert6@py_assert9@py_assert8@py_format11@py_format13s                r   test_system_prompts_not_emptyz9TestSystemPromptsDefinition.test_system_prompts_not_empty=   s   "11779 	TLD&fc*V*VVtf4U,VVVVVVV:VVV:VVVVVVfVVVfVVVVVVcVVVcVVV*VVVVVV||S|~S3~&SS&*SSS&SSSSSS3SSS3SSSSSSvSSSvSSS|SSS~SSS&SSSSSStf4R,SSSSSSSS	Tr   N)__name__
__module____qualname__r8   rQ    r   r   r   r   -   s    
Tr   r   c                       e Zd Zd Zd Zd Zy)TestGlmGenerateBasicc                    ddl }dd}|j                  |      }|j                  j                  j                  j                          |j                  j                  j                  j                  }|j                  d   }||k(  }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndd	z  }d
d|iz  }	t        t        j                  |	            dx}}|j                  d   }
fd|
D        }t!        |      }|sddt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }d
d|iz  }	t        t        j                  |	            dx}}y)uB   glm_generate가 올바른 인자로 API를 호출하는지 확인.r   NzHello, GLM!glm-4.7-flash)r;   modelrZ   r    z%(py1)s == %(py3)sr>   rA   assert %(py5)srB   messagesc              3   B   K   | ]  }|d    dk(  xr |d   k(    yw)rH   userr   NrU   ).0mr;   s     r   	<genexpr>z?TestGlmGenerateBasic.test_glm_generate_basic.<locals>.<genexpr>\   s+     Ta1V9&A1Y<6+AATs   ,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyr$   r%   r&   r   z%(py0)s == %(py3)sresultr$   rA   )r'   glm_generater   r   r   assert_called_once	call_argskwargsr+   r,   r0   r-   r.   r/   r2   r3   re   )r4   r   r'   rZ   rh   call_kwargs@py_assert0rJ   @py_format4@py_format6r^   r5   rI   r7   r;   s                 @r   test_glm_generate_basicz,TestGlmGenerateBasic.test_glm_generate_basicL   s     $$F%$@ 	$$++>>@!&&2299CC!!'*3*e3333*e333*333333e333e3333333%%j1T8TTsTTTTTTTTTsTTTsTTTTTTTTTTTTTT--v-----v-------v---v-----------r   c                 p   ddl }|j                  d      }t        |t              }|sd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)
u4   glm_generate가 문자열을 반환하는지 확인.r   Ntestr;   z5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}r:   rh   r<   r=   )r'   rj   r:   r<   r-   r.   r+   r/   r0   r2   r3   )r4   r   r'   rh   rI   r7   s         r    test_glm_generate_returns_stringz5TestGlmGenerateBasic.test_glm_generate_returns_string_   s    $$F$3&#&&&&&&&&z&&&z&&&&&&&&&&&&&&&&&#&&&#&&&&&&&&&&r   c                    ddl }|j                  d       |j                  j                  j                  j
                  }|j                  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)u<   glm_generate의 기본 모델이 glm-4.7-flash인지 확인.r   Nrt   ru   rZ   rY   r    z%(py1)s == %(py4)sr>   r&   assert %(py6)spy6)r'   rj   r   r   r   rl   rm   r+   r,   r0   r2   r3   	r4   r   r'   rn   ro   rI   rJ   r7   @py_format7s	            r   test_glm_generate_default_modelz4TestGlmGenerateBasic.test_glm_generate_default_modelg   s    6*!&&2299CC!!'*=o=*o====*o===*===o=======r   N)rR   rS   rT   rr   rv   r~   rU   r   r   rW   rW   K   s    .&'>r   rW   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(  }|st        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  }dd|iz  }t        t        j                  |            dx}	x}}
|d   d   }||k(  }	|	st        j                  d
|	fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}}	yc c}w )uW   system_prompt 지정 시 messages에 system 역할 메시지가 추가되는지 확인.r   Nu   당신은 전문가입니다.u   FastAPI 예제 작성r;   system_promptr^   rH   system   r    z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr@   system_messagesr$   r>   rA   r{   assert %(py8)spy8r   r[   r   r\   r]   rB   r'   rj   r   r   r   rl   rm   r@   r+   r,   r-   r.   r/   r0   r2   r3   )r4   r   r'   r   r;   rn   r^   rb   r   rJ   @py_assert5rK   r}   @py_format9ro   rp   rq   s                    r   $test_glm_generate_with_system_promptzDTestGlmGenerateWithSystemPrompt.test_glm_generate_with_system_promptw   so    8( 	6G "&&2299CC%%j1&.H!F)x2G1HH?#(q(#q((((#q((((((s(((s((((((?(((?(((#(((q(((((((q!),=,====,===,================ Is   H*'H*c                    ddl }|j                  dd       |j                  j                  j                  j
                  }|j                  d   }|D cg c]  }|d   dk(  s| }}t        |      }d}||k(  }	|	st        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  }
dd|
iz  }t        t        j                  |            dx}x}	}yc c}w )uH   system_prompt 미지정 시 system 역할 메시지가 없는지 확인.r   Nrt    r   r^   rH   r   r    r   r@   r   r   r   r   r   )r4   r   r'   rn   r^   rb   r   rJ   r   rK   r}   r   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(#q((((#q((((((s(((s((((((?(((?(((#(((q((((((( Is   E:#E:c                    ddl }|j                  dd       |j                  j                  j                  j
                  }|j                  d   }|D cg c]  }|d   	 }}|j                  }d} ||      }	|j                  }
d	} |
|      }|	|k  }|s>t        j                  d
|fd|	|f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |	      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |
      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}	x}x}
x}}yc c}w )uG   system 메시지가 user 메시지보다 앞에 위치하는지 확인.r   Nrt   zsystem contentr   r^   rH   r   r`   )<)z%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.index
}(%(py4)s)
} < %(py14)s
{%(py14)s = %(py10)s
{%(py10)s = %(py8)s.index
}(%(py12)s)
}roles)r$   r%   r&   r{   r   rD   rE   py14zassert %(py16)spy16)r'   rj   r   r   r   rl   rm   indexr+   r,   r-   r.   r/   r0   r2   r3   )r4   r   r'   rn   r^   rb   r   r5   rI   r   rM   @py_assert11@py_assert13@py_assert7@py_format15@py_format17s                   r   test_glm_generate_message_orderz?TestGlmGenerateWithSystemPrompt.test_glm_generate_message_order   sE   69IJ!&&2299CC%%j1$,-q6--{{:8:{8$:u{{:6:{6'::$':::::$':::::::u:::u:::{:::8:::$::::::u:::u:::{:::6:::'::::::::: .s   G$N)rR   rS   rT   r   r   r   rU   r   r   r   r   v   s    >$)	;r   r   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(  }	|	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                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}x}x}x}x}	}d}||k(  }|st        j                  d
|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y)u   glm_code가 1회 리뷰 사이클 시 총 3번 API를 호출하는지 확인.

        호출 순서: 초기 코드 생성 → 리뷰 → 수정
        r   Ninitial codereview feedback
fixed codeu   유틸 함수 작성r   taskreview_cycles   r    z%(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.chat
}.completions
}.create
}.call_count
} == %(py11)sr   r$   r%   r&   r{   r   py11assert %(py13)spy13rg   rh   ri   r]   rB   )r'   _make_responser   r   r   side_effectglm_code
call_countr+   r,   r-   r.   r/   r0   r2   r3   )r4   r   r'   rh   r5   rI   r   r   @py_assert10rM   @py_format12@py_format14rJ   rp   rq   s                  r   test_glm_code_with_reviewz/TestGlmCodeWithReview.test_glm_code_with_review   sk   
 	 >*,-<(;
$$++7 &<AN B++B+22B2==BB=BBBB=BBBBBB{BBB{BBBBBB+BBB2BBB=BBBBBBBBBBB%%v%%%%v%%%%%%v%%%v%%%%%%%%%%r   c           	         ddl }|j                  dd       |j                  }|j                  }|j                  }|j
                  }d}||k(  }|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                  |      t        j                  |      d	z  }	d
d|	iz  }
t        t        j                  |
            dx}x}x}x}x}}y)uL   review_cycles=0 시 API가 1번만 호출(초기 생성만)되는지 확인.r   Nu   간단한 함수r   r   r    r   r   r   r   r   r'   r   r   r   r   r   r+   r,   r-   r.   r/   r0   r2   r3   r4   r   r'   r5   rI   r   r   r   rM   r   r   s              r    test_glm_code_zero_review_cyclesz6TestGlmCodeWithReview.test_glm_code_zero_review_cycles   s     	/qA B++B+22B2==BB=BBBB=BBBBBB{BBB{BBBBBB+BBB2BBB=BBBBBBBB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| }}d |D        }t        |      }|sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }	t        t        j                   |	            dx}}yc c}w )u?   리뷰 메시지에 생성된 코드가 포함되는지 확인.r   Ngenerated code contentr   r      작업r   r   r^   rH   r`   c              3   *   K   | ]  }d |d   v   yw)r   r   NrU   ra   rb   s     r   rc   zSTestGlmCodeWithReview.test_glm_code_review_messages_include_code.<locals>.<genexpr>   s     S+q|;S   rd   re   rf   r'   r   r   r   r   r   r   call_args_listrm   re   r-   r.   r+   r/   r0   r2   r3   )
r4   r   r'   review_callreview_messagesrb   user_messagesr5   rI   r7   s
             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SsSSSSSSSSSsSSSsSSSSSSSSSSSSSS L   E)E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| }}d |D        }t        |      }|sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }	t        t        j                   |	            dx}}yc c}w )uF   코드 수정 메시지에 리뷰 피드백이 포함되는지 확인.r   Nr   critical review feedbackr   r   r   r      r^   rH   r`   c              3   *   K   | ]  }d |d   v   yw)r   r   NrU   r   s     r   rc   zTTestGlmCodeWithReview.test_glm_code_fix_messages_include_feedback.<locals>.<genexpr>   s     U!-9=Ur   rd   re   rf   r   )
r4   r   r'   fix_callfix_messagesrb   r   r5   rI   r7   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UsUUUUUUUUUsUUUsUUUUUUUUUUUUUU Ir   N)rR   rS   rT   r   r   r   r   rU   r   r   r   r      s    &*CT$Vr   r   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(  }|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                  |      t        j                  |      d
z  }	dd|	iz  }
t        t        j                  |
            dx}x}x}x}x}}y)u\   review_cycles가 음수이면 0으로 클램핑되어 API가 1번만 호출되는지 확인.r   Nr   r   r   r    r   r   r   r   r   r   r   s              r   %test_review_cycles_clamped_below_zerozDTestGlmCodeReviewCyclesClamped.test_review_cycles_clamped_below_zero   s    XR8B++B+22B2==BB=BBBB=BBBBBB{BBB{BBBBBB+BBB2BBB=BBBBBBBB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(  }	|	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                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                   |            dx}x}x}x}x}	}yc c}w )u   review_cycles가 3을 초과하면 3으로 클램핑되는지 확인.

        API 호출 횟수: 초기(1) + 3사이클 × 2(리뷰+수정) = 7
        r   N   	response_r   d   r   r    r   r   r   r   r   r'   ranger   r   r   r   r   r   r   r+   r,   r-   r.   r/   r0   r2   r3   r4   r   r'   ir5   rI   r   r   r   rM   r   r   s               r   &test_review_cycles_clamped_above_threezETestGlmCodeReviewCyclesClamped.test_review_cycles_clamped_above_three   s   
 	 6;1X;
01NYqc?+;
$$++7 	XS9B++B+22B2==BB=BBBB=BBBBBB{BBB{BBBBBB+BBB2BBB=BBBBBBBBBBB;
   Fc           	         ddl }|j                  dd       |j                  }|j                  }|j                  }|j
                  }d}||k(  }|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                  |      t        j                  |      d	z  }	d
d|	iz  }
t        t        j                  |
            dx}x}x}x}x}}y)u+   review_cycles=0 경계값: API 1회 호출.r   Nr   r   r   r    r   r   r   r   r   r   r   s              r   #test_review_cycles_at_boundary_zerozBTestGlmCodeReviewCyclesClamped.test_review_cycles_at_boundary_zero	  s    XQ7B++B+22B2==BB=BBBB=BBBBBB{BBB{BBBBBB+BBB2BBB=BBBBBBBB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(  }	|	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                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                   |            dx}x}x}x}x}	}yc c}w )u+   review_cycles=3 경계값: API 7회 호출.r   Nr   r   r   r   r   r    r   r   r   r   r   r   r   s               r   $test_review_cycles_at_boundary_threezCTestGlmCodeReviewCyclesClamped.test_review_cycles_at_boundary_three  s    6;1X;
01NYqc?+;
$$++7 	XQ7B++B+22B2==BB=BBBB=BBBBBB{BBB{BBBBBB+BBB2BBB=BBBBBBBBBBB;
r   N)rR   rS   rT   r   r   r   r   rU   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(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)u6   glm_backend가 glm-5 모델을 사용하는지 확인.r   Nu	   DB 설계r   rZ   zglm-5.1r    rx   ry   rz   r{   )r'   glm_backendr   r   r   rl   rm   r+   r,   r0   r2   r3   r|   s	            r   #test_glm_backend_uses_correct_modelz7TestGlmBackendModel.test_glm_backend_uses_correct_model$  s     	, "&&2299CC!!'*7i7*i7777*i777*777i7777777r   N)rR   rS   rT   r   rU   r   r   r   r   #  s    	8r   r   c                       e Zd Zd Zy)TestGlmFrontendModelc                    ddl }|j                  d       |j                  j                  j                  j
                  }|j                  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)u?   glm_frontend가 glm-4.7-flash 모델을 사용하는지 확인.r   Nu   React 컴포넌트 작성r   rZ   zglm-5r    rx   ry   rz   r{   )r'   glm_frontendr   r   r   rl   rm   r+   r,   r0   r2   r3   r|   s	            r   $test_glm_frontend_uses_correct_modelz9TestGlmFrontendModel.test_glm_frontend_uses_correct_model6  s     	!<= "&&2299CC!!'*5g5*g5555*g555*555g5555555r   N)rR   rS   rT   r   rU   r   r   r   r   5  s    	6r   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(  }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }	t        t        j                   |	            dx}}y)uC   glm_backend가 SYSTEM_PROMPTS['backend']를 사용하는지 확인.r   Nr   r   r^   c              3   8   K   | ]  }|d    dk(  s|d     ywrH   r   r   NrU   r   s     r   rc   zVTestRoleToolsUseCorrectPrompts.test_glm_backend_uses_backend_prompt.<locals>.<genexpr>P  $      
ai8.CAiL
   
r   r    rg   system_contentri   r]   rB   )r'   r   r   r   r   rl   rm   nextr)   r+   r,   r-   r.   r/   r0   r2   r3   
r4   r   r'   rn   r^   r   rJ   r5   rp   rq   s
             r   $test_glm_backend_uses_backend_promptzCTestRoleToolsUseCorrectPrompts.test_glm_backend_uses_backend_promptH  s    )!&&2299CC%%j1 
"*
 
 "(!6!6y!AA~!AAAAA~!AAAAAAA~AAA~AAA!AAAAAAAAr   c                 ,   ddl }|j                  d       |j                  j                  j                  j
                  }|j                  d   }t        d |D              }|j                  d   }||k(  }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }	t        t        j                   |	            dx}}y)uE   glm_frontend가 SYSTEM_PROMPTS['frontend']를 사용하는지 확인.r   Nr   r   r^   c              3   8   K   | ]  }|d    dk(  s|d     ywr   rU   r   s     r   rc   zXTestRoleToolsUseCorrectPrompts.test_glm_frontend_uses_frontend_prompt.<locals>.<genexpr>]  r   r   r   r    rg   r   ri   r]   rB   )r'   r   r   r   r   rl   rm   r   r)   r+   r,   r-   r.   r/   r0   r2   r3   r   s
             r   &test_glm_frontend_uses_frontend_promptzETestRoleToolsUseCorrectPrompts.test_glm_frontend_uses_frontend_promptU  s    *!&&2299CC%%j1 
"*
 
 "(!6!6z!BB~!BBBBB~!BBBBBBB~BBB~BBB!BBBBBBBBr   c                 ,   ddl }|j                  d       |j                  j                  j                  j
                  }|j                  d   }t        d |D              }|j                  d   }||k(  }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }	t        t        j                   |	            dx}}y)u=   glm_uxui가 SYSTEM_PROMPTS['uxui']를 사용하는지 확인.r   Nr   r   r^   c              3   8   K   | ]  }|d    dk(  s|d     ywr   rU   r   s     r   rc   zPTestRoleToolsUseCorrectPrompts.test_glm_uxui_uses_uxui_prompt.<locals>.<genexpr>j  r   r   r   r    rg   r   ri   r]   rB   )r'   glm_uxuir   r   r   rl   rm   r   r)   r+   r,   r-   r.   r/   r0   r2   r3   r   s
             r   test_glm_uxui_uses_uxui_promptz=TestRoleToolsUseCorrectPrompts.test_glm_uxui_uses_uxui_promptb  s    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(  }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }	t        t        j                   |	            dx}}y)uA   glm_tester가 SYSTEM_PROMPTS['tester']를 사용하는지 확인.r   Nr   r   r^   c              3   8   K   | ]  }|d    dk(  s|d     ywr   rU   r   s     r   rc   zTTestRoleToolsUseCorrectPrompts.test_glm_tester_uses_tester_prompt.<locals>.<genexpr>w  r   r   r   r    rg   r   ri   r]   rB   )r'   
glm_testerr   r   r   rl   rm   r   r)   r+   r,   r-   r.   r/   r0   r2   r3   r   s
             r   "test_glm_tester_uses_tester_promptzATestRoleToolsUseCorrectPrompts.test_glm_tester_uses_tester_prompto  s    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(  }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }	t        t        j                   |	            dx}}y)uT   glm_code의 기본 role(backend)이 backend system prompt를 사용하는지 확인.r   Nr   r   r^   c              3   8   K   | ]  }|d    dk(  s|d     ywr   rU   r   s     r   rc   z`TestRoleToolsUseCorrectPrompts.test_glm_code_default_role_uses_backend_prompt.<locals>.<genexpr>  r   r   r   r    rg   r   ri   r]   rB   )r'   r   r   r   r   rl   rm   r   r)   r+   r,   r-   r.   r/   r0   r2   r3   r   s
             r   .test_glm_code_default_role_uses_backend_promptzMTestRoleToolsUseCorrectPrompts.test_glm_code_default_role_uses_backend_prompt|  s    XQ7!&&2299CC%%j1 
"*
 
 "(!6!6y!AA~!AAAAA~!AAAAAAA~AAA~AAA!AAAAAAAAr   N)rR   rS   rT   r   r   r   r   r  rU   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(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                   |            dx}}j                  }|j
                  }	|	j                  }
|
j"                  }d}||k(  }|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                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}	x}
x}x}}j"                  }d}||k(  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}	}y# 1 sw Y   xY w# 1 sw Y   xY w) uB   API 실패 시 MAX_RETRIES 횟수만큼 재시도하는지 확인.r   Nr   server.time.sleepu   첫 번째 실패u   두 번째 실패u   최종 성공r`   rt   rH   r   rY   r   r^   rZ   
max_tokensr    rg   rh   ri   r]   rB   r   r   r   r   r   r   r   )z2%(py2)s
{%(py2)s = %(py0)s.call_count
} == %(py5)s
mock_sleep)r$   r%   rB   zassert %(py7)srC   )r'   r   	Exceptionr   r   r   r   r   	_call_apir+   r,   r-   r.   r/   r0   r2   r3   r   )r4   r'   r   r  rh   rJ   r5   rp   rq   rI   r   r   r   rM   r   r   rK   @py_format8s                     r   test_api_retry_on_failurez/TestApiRetryOnFailure.test_api_retry_on_failure  s0    ?# 	{E5
 	-.-./?K((//; %%#)f=>% & F	 	" )(v((((v((((((v(((v((((((((((B++B+22B2==BB=BBBB=BBBBBB{BBB{BBBBBB+BBB2BBB=BBBBBBBBBBB$$))$))))$))))))z)))z)))$)))))))))))	 	 	 	s#   L2AL%8L2%L/	*L22L<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`   rt   r  rY   r   r	  )r'   r   r  r   r   r   r   pytestraisesRuntimeErrorr  )r4   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           	      H   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t        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t        j                          v st        j"                  |      rt        j$                  |      nddz  }	dd|	iz  }
t'        t        j(                  |
            dx}x}x}x}}y# 1 sw Y   x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`   rt   r  rY   r   r	  r   r    )z%(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.chat
}.completions
}.create
}.call_count
} == %(py10)sr   expected_calls)r$   r%   r&   r{   r   rD   zassert %(py12)srE   )r'   r   r  r   r   r   r   r  r  r  r  MAX_RETRIESr   r+   r,   r-   r.   r/   r0   r2   r3   )r4   r'   r   r  r5   rI   r   r   rM   rO   rP   s              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/O++O+22O2==O=OOOO=OOOOOO{OOO{OOOOOO+OOO2OOO=OOOOOOOOOOOOOOOOO 	 	 	 	s;   HAH
$G==H
H=HH

H	HH!c                    ddl }t        d      5 }t        d      5  t        d      |j                  j                  j
                  _        |j                  d      }ddd       ddd       j                  }d} ||      }|sd	d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}x}}y# 1 sw Y   xY w# 1 sw Y   xY w)u]   glm_generate가 API 전체 실패 시 [오류] 접두어 문자열을 반환하는지 확인.r   Nr   r     실패rt   ru   u   [오류]zLassert %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.startswith
}(%(py4)s)
}rh   )r$   r%   r&   r{   )r'   r   r  r   r   r   r   rj   
startswithr-   r.   r+   r/   r0   r2   r3   )r4   r'   r   rh   r5   rI   r   r}   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
   ,, ,,,,,,,,v,,,v,,, ,,,,,,,,,,,,,	8 	8 	8 	8s#   D9AD-D9-D6	2D99E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`   rt   r  rY   r   r	  )r'   r   r  r   r   r   r   r   r  assert_called_withRETRY_INTERVAL)r4   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)rR   rS   rT   r  r  r  r  r"  rU   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
  }| }|s~t        j                  d|       dz   ddt        j                         v st        j                  |      rt        j                  |      ndiz  }t        t        j                  |            d}y)u5   6개 tool이 모두 MCP에 등록되었는지 확인.r   N>   r   r   r   r   r   rj   u   등록되지 않은 tool: z
>assert not %(py0)sr$   missing)r'   r(   mcp_tool_manager_toolsr*   r+   r1   r-   r.   r/   r0   r2   r3   )r4   r'   expected_tools
registeredr&  r5   @py_format2s          r   test_mcp_tools_registeredz0TestMcpToolsRegistered.test_mcp_tools_registered  s    
 1188==?@
 !:-{B{BB8	BBBBBBB7BBB7BBBBBBr   c                 l   ddl }|j                  j                  j                  }t	        |      }d}||k(  }|st        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  }d	d
|iz  }t        t        j                  |            dx}x}}y)u9   MCP에 등록된 tool 수가 정확히 6개인지 확인.r   N   r    r   r@   r+  r   r   r   )r'   r'  r(  r)  r@   r+   r,   r-   r.   r/   r0   r2   r3   )r4   r'   r+  rJ   r   rK   r}   r   s           r   test_mcp_tools_countz+TestMcpToolsRegistered.test_mcp_tools_count  s    ZZ--44
:#!#!####!######s###s######:###:######!#######r   N)rR   rS   rT   r-  r0  rU   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   r   r     s'    {H*1HQ'Or   )%__doc__builtinsr-   _pytest.assertion.rewrite	assertionrewriter+   	importlibsystypespathlibr   unittest.mockr   r   r   r  pathinsertr<   __file__resolveparentfixturer   r   r   rW   r   r   r   r   r   r   r  r$  r   rU   r   r   <module>rC     s      
   0 0  3tH~--/66==> ?    T T<#> #>V); );bBV BVT*C *Cd
8 
8$
6 
6$@B @BPX= X=@$ $FC I r   