
    ;Dim;                        d Z ddlZddlZddlZddlZddlmZ dddZg dZg dZ	d	e
d
ee
   dede
fdZde
deee
ef      fdZdeee
ef      deee
ef      fdZdeee
ef      de
deee
ef      fdZd'de
de
de
de
fdZdeee
ef      de
de
fdZde
de
fdZde
de
de
de
de
d e
d!e
d"e
dee
ef   fd#Z	 	 	 d(d	e
d
ee
   dede
de
deee
ef      fd$Zd)d%Zed&k(  r e        yy)*uG   scenario_generator.py — LLM 기반 시나리오 YAML 초안 생성기    N)Any      )r   2   )      )smoke
regression	edge-casesecurityperformancee2e)
subprocesscurlpytest
playwrighttask_contentchanged_fileslevelreturnc                     t         j                  |d      \  }}dj                  d |D              }d|  d| d| d| d| d	}|S )
u1   LLM에 전달할 프롬프트를 생성합니다.r   
c              3   &   K   | ]	  }d |   yw)z  - N ).0fs     9/home/jay/workspace/teams/shared/qc/scenario_generator.py	<genexpr>zbuild_prompt.<locals>.<genexpr>   s     "E!T!:"Es   u   당신은 QA 엔지니어입니다. 아래 task 내용과 변경 파일 목록을 분석하여 테스트 시나리오 YAML 초안을 생성하세요.

## Task 내용
u   

## 변경 파일 목록
u   

## 요구사항
- ~u7   개의 시나리오를 생성하세요 (작업 레벨: u  )
- 각 시나리오는 아래 필드를 포함해야 합니다:
  - id: SC-GEN-{task_id}-{순번:03d} 형식
  - category: smoke / regression / edge-case / security / performance / e2e 중 하나
  - target: 관련 파일 목록 (리스트)
  - type: subprocess / curl / pytest / playwright 중 하나
  - steps: action과 expect_contains로 구성된 단계 목록
  - priority: must / should / nice 중 하나
  - automatable: false  # 반드시 false로 설정
  - description: 시나리오 설명 (한국어)
- 모든 시나리오의 automatable은 반드시 false여야 합니다
- YAML 형식으로만 응답하세요 (```yaml ... ``` 블록 사용)

## 카테고리별 가이드
- smoke: 기본 동작 확인 (임포트, 기동, 핵심 API 응답)
- regression: 기존 기능 유지 확인 (변경 전 동작과 동일한지)
- edge-case: 빈 값, 경계값, 예외 경로 처리
- security: 인증/인가, 입력 검증, 권한 확인
- performance: 응답 시간, 부하 처리
- e2e: 전체 흐름 통합 확인

응답 예시:
```yaml
- id: SC-GEN-task-100-001
  category: smoke
  target: ["changed_file.py"]
  type: subprocess
  steps:
    - action: "python3 -c 'import module'"
      expect_contains: ""
  priority: must
  automatable: false
  description: "모듈 임포트 확인"
```
)LEVEL_RANGESgetjoin)r   r   r   	min_count	max_countchanged_files_textprompts          r   build_promptr(      sw    '++E8<Iy"E}"EE      +QykPQVPW "X,FZ M    response_textc                 ~   t        j                  dt         j                        }|j                  |       }|r|j	                  d      j                         n| j                         }	 t        j                  |      }t        |t              r|S t        |t              r|gS g S # t        j                  $ r g cY S w xY w)u   LLM 응답(YAML 문자열)을 파싱하여 시나리오 리스트 반환.

    YAML 블록이 ```yaml ... ``` 안에 있을 수도 있고, 바로 YAML일 수도 있음.
    파싱 실패 시 빈 리스트 반환.
    z```(?:yaml)?\s*\n(.*?)```   )recompileDOTALLsearchgroupstripyaml	safe_load
isinstancelistdict	YAMLError)r*   code_block_patternmatch	yaml_textdatas        r   parse_llm_responser=   M   s     $@"))L%%m4E*/A$$&]5H5H5JI	~~i(dD!Kd#6MI>> 	s   (&B$ B$ "B$ $B<;B<	scenariosc                     | D ]  }d|d<   	 | S )u=   모든 시나리오에 automatable: false를 강제합니다.Fautomatabler   )r>   scs     r   ensure_automatable_falserB   e   s!     "!="r)   task_idc                 l    |j                  dd      }t        | d      D ]  \  }}d| d|d|d<    | S )uK   시나리오에 고유 ID를 부여합니다. SC-GEN-{task_id}-{순번:03d}.-r,   )startSC-GEN-03did)replace	enumerate)r>   rC   safe_task_ididxrA   s        r   generate_scenario_idsrO   l   sL     ??3,LYa0 6R\N!C9546r)   projectbase_dirc                 V    |sd}t         j                  j                  |d| d| d      S )u   출력 YAML 파일 경로를 반환합니다.

    기본: {base_dir}/scenarios/{project}/generated/{task_id}.yaml
    base_dir 미지정 시: /home/jay/workspace/teams/shared/qc
    z#/home/jay/workspace/teams/shared/qcr>   	generatedz.yaml)ospathr#   )rP   rC   rQ   s      r   get_output_pathrV   u   s/     877<<+wyPUEVWWr)   output_pathc                     t        j                  t         j                  j                  |      d       t	        |dd      5 }t        j                  | |ddd       ddd       |S # 1 sw Y   |S xY w)	u/   시나리오를 YAML 파일로 저장합니다.T)exist_okwutf-8encodingF)allow_unicode	sort_keysdefault_flow_styleN)rT   makedirsrU   dirnameopenr3   dump)r>   rW   r   s      r   save_scenariosre      s_    KK,t<	k3	1 _Q		)QdeX]^__s   A((A2	file_pathc                     | j                         }|j                  d      s|j                  d      sd|v sd|v ryd|v sd|v sd|v sd	|v ry
|j                  d      ryy)u;   파일 경로/확장자로 시나리오 type 자동 결정.z.tsxz.jsxfrontenduir   apirouterendpointviewr   .pyr   r   )lowerendswith)rf   ro   s     r   _determine_typerq      sh    OOE~~f!7:;NRVZ_R_~U*jE.AVu_~~er)   sc_idcategorytarget_filesc_typeactionexpect_containsprioritydescriptionc           	      "    | ||g|||dg|d|dS )u4   단일 시나리오 딕셔너리를 생성합니다.)rv   rw   F)rJ   rs   targettypestepsrx   r@   ry   r   rr   rs   rt   ru   rv   rw   rx   ry   s           r   _make_scenarior      s0     -#HI"	 	r)   c                 f   t         j                  |d      \  }}|r|j                  dd      ndg }ddt        ffd}|r|ndg}	|	D ]  }
t	        |
      }t
        j                  j                  |
      }|j                  d	d
      j                  dd      }|dk(  r	d|
 d}d}n|dk(  rd}d}n|dk(  rd}d}nd| d}d}|j                  t         |       d|
|||d| d             |dk(  r	d|
 d}d}n|dk(  rd}d}n|dk(  rd}d}nd|
 d }d
}|j                  t         |       d!|
|||d| d"             |j                  t         |       d#|
|d$| d%d&d'| d(             |j                  t         |       d#|
d)d*| d%d+d'| d,             |j                  t         |       d-|
|d.| d%d/d'| d0              |d1k\  r|	D ]  }
t
        j                  j                  |
      }t	        |
      }|j                  t         |       d2|
|d3| d4d5d6| d7             |j                  t         |       d8|
|d9| d%d:d'| d;             |j                  t         |       d#|
d)d<| d%d=d'| d>             |j                  t         |       d-|
|d?| d%d@d'| dA             |j                  t         |       d!|
|dB| d%dCd6| dD              t        |      |k  rt        |      t        |	      z  }|	|   }
t
        j                  j                  |
      }t	        |
      }t        t        |      t        t              z     }|j                  t         |       ||
|dEdz
   dF| d%dGd6| dHdz
                t        |      |k  r|dI| S )JuT  LLM 없이 템플릿 기반으로 시나리오 초안을 생성합니다.

    LLM API가 없는 환경에서도 동작하도록, 변경 파일 목록과 task 내용을 기반으로
    카테고리별 시나리오 템플릿을 생성합니다.

    이 함수가 메인 생성 로직입니다. LLM은 선택적 보강 수단입니다.
    r   rE   rF   taskr,   r   c                  $    d dd} dz  | S )NrH   rF   rI   r,   r   )rr   counterrM   s    r   next_idz1generate_scenarios_from_template.<locals>.next_id   s%    ,q61r)   unknownrn    _r   zpytest z -v --tb=shortpassedr   z%curl -sf http://localhost:8000/healthokr   zplaywright test --grep smokezpython3 -c 'import z' 2>&1 || echo 'ok'r
   mustu    기본 동작 확인r~   z -v -k 'not slow'z3curl -sf -X GET http://localhost:8000/api/v1/status200z!playwright test --grep regressionzpython3 z --help 2>&1 || truer   u    기존 기능 유지 확인r   z(python3 -c "print('empty input test for z')"zempty input testshouldu(    빈 값 입력 시 예외 처리 확인r   z+python3 -c "print('boundary value test for zboundary value testu    경계값 처리 확인r   z"python3 -c "print('auth check for z
auth checku    인증/인가 확인r	   r   z=python3 -c "import time; start=time.time(); print('perf test z/'); print(f'elapsed={time.time()-start:.3f}s')"z	perf testniceu    응답 시간 확인r   z%python3 -c "print('e2e flow test for ze2e flow testu    전체 흐름 통합 확인z'python3 -c "print('null input test for znull input testu    None/null 입력 처리 확인z'python3 -c "print('injection check for zinjection checku    인젝션 공격 방어 확인z-python3 -c "print('rollback safety check for zrollback safety checku    롤백 안전성 확인z%python3 -c "print('supplemental test z for zsupplemental testu    보충 시나리오 N)r!   r"   rK   strrq   rT   rU   basenameappendr   len
CATEGORIES)r   r   r   rP   rC   r$   r%   r>   r   filesrf   ru   	file_namemodule_namesmoke_actionsmoke_expect
reg_action
reg_expectfill_idxrs   r   rM   s                       @@r    generate_scenarios_from_templater      s    (++E8<Iy077??3,VL&(IGS  +ME Y	!),GG$$Y/	''r2::3D h$YK~>L#LBLL$9L#L0=PQLL)!($+%:;	
 		 h"9+->?J!JNJJ$<J!J#I;.BCJJ)!!&$+%AB	
 		 	) !>ykN.$+%MN	
 		 	) ! A)DQ1$+%=>	
 		 	)!84H($+%:;	
 		aYx z >	I((3I%i0G ^i&%WXaWb  cU  V +(k)>?	 	 ^i%?	{$O /!(k)EF	 	 ^i$%$A)DQ 1!(k)HI	 	 ^i#%A)DQ 1!(k)HI	 	 ^i%%G	{RVW 7(k)AB	 	k>	B i.9
$	NSZ/(O	GG$$Y/	!),c)ns:>?)!;GAI;eI;VZ[/$+%:7Q;-H	
 		 i.9
$& Zi  r)   c                     t        j                  d      } | j                  ddd       | j                  ddd	
       | j                  dt        dd       | j                  ddd
       | j                  ddd
       | j                  ddd
       | j	                         }t        |j                  dd      5 }|j                         }d d d        |j                  rH|j                  j                  d      D cg c]#  }|j                         s|j                         % c}ng }t        ||j                  |j                  |j                        }|j                  r|j                  n t!        |j                  |j                        }t#        ||       t%        dt'        |              t%        d|        y # 1 sw Y   xY wc c}w )Nu-   LLM 기반 시나리오 YAML 초안 생성기)ry   z--task-fileTu   task 파일 경로)requiredhelpz--changed-filesr   u$   변경 파일 목록 (콤마 구분))defaultr   z--levelr   u   작업 레벨 (3 또는 4))r|   r   r   z	--projectu   프로젝트명z	--task-idztask IDz--outputu+   출력 파일 경로 (미지정 시 자동)rr[   r\   ,)r   r   r   rP   rC   )rP   rC   u   생성된 시나리오 수: u   출력 파일: )argparseArgumentParseradd_argumentint
parse_argsrc   	task_filereadr   splitr2   r   r   rP   rC   outputrV   re   printr   )parserargsr   r   r   r>   rW   s          r   mainr   |  s   $$1`aF
;OP
)2<bc
	Q=YZ
R6GH
Ri@

B5bcD 
dnncG	4  vvx   !..44S9GqQWWYG  1!#jjI "&$++/3K 9k*	(Y(8
9:	OK=
)*;   
 	Hs   <G>GGG__main__)r   )r   r   r   )r   N)__doc__r   rT   r-   r3   typingr   r!   r   TYPESr   r6   r   r(   r7   r=   rB   rO   rV   re   rq   r   r   r   __name__r   r)   r   <module>r      s    M  	 	  
  T
 	72s 249 2S 2S 2jc d4S>.B 0T#s(^(< d3PS8nAU T$sCx.%9 C DQUVY[^V^Q_L` XS X3 X# Xs Xd4S>2   	s 	s 	  	
     
#s(^4 N!N!9N! N! 	N!
 N! 
$sCx.N!b(+V zF r)   