import os
import ast
import sys
import importlib
import subprocess
from typing import List, Tuple
from testapp.constants import SCRIPTS_DIRECTORY, MAX_BLOCK
from my_logger import Logger
[docs]
class ClassVisitor(ast.NodeVisitor):
def __init__(self):
[docs]
self.found_classes = []
[docs]
def visit_ClassDef(self, node):
self.found_classes.append(node.name)
self.generic_visit(node)
[docs]
def find_classes() -> List[Tuple[str, List[str]]]:
"""
주어진 디렉토리 내의 모든 파이썬 파일에서 정의된 클래스를 찾습니다.
Returns:
List[Tuple[str, List[str]]]: 모듈 이름과 클래스 이름 리스트의 튜플 리스트
"""
directory = SCRIPTS_DIRECTORY
result = []
for filename in os.listdir(directory):
if filename.endswith('.py') and not filename.startswith("_"):
filepath = os.path.join(directory, filename)
with open(filepath, 'r', encoding='utf-8') as file:
node = ast.parse(file.read(), filename=filename)
visitor = ClassVisitor()
visitor.visit(node)
if visitor.found_classes:
module_name = filename[:-3] # .py 확장자 제거
result.append((module_name, visitor.found_classes))
return result
[docs]
def get_test_scripts() -> dict[str, str]:
"""
테스트 스크립트를 반환합니다.
Returns:
Dict[str, str]: 테스트 스크립트 딕셔너리 {테스트 이름: 스크립트 절대 경로}
"""
class_info = find_classes()
ret_dict = {}
for module_name, class_names in class_info:
for class_name in class_names:
ret_dict[class_name] = SCRIPTS_DIRECTORY / f"{module_name}.py"
return ret_dict
[docs]
def get_classes() -> List[object]:
"""
CommandInterface를 구현한 클래스 객체들을 반환합니다.
Returns:
List[object]: 클래스 객체 리스트
"""
class_info = find_classes()
class_list = []
original_sys_path = sys.path.copy()
try:
sys.path.append(os.getcwd()) # 현재 디렉토리를 sys.path에 추가
for module_name, class_names in class_info:
module = importlib.import_module(module_name)
for class_name in class_names:
class_list.append(getattr(module, class_name))
finally:
sys.path = original_sys_path # 원래 sys.path 복원
return class_list
[docs]
def print_log(result, use_print, start_loc, end_loc):
if use_print:
Logger().info(result.stdout[start_loc:end_loc])
else:
Logger().debug(result.stdout[start_loc:end_loc])
[docs]
def run_script(script_name: str, use_print: bool = False) -> bool:
"""
주어진 스크립트를 실행합니다.
Args:
script_name (str): 실행할 스크립트 이름
use_print (bool): 콘솔 창에 출력할지 말지 결정
Returns:
bool: 스크립트 실행 성공 여부
"""
try:
result = subprocess.run(['python', script_name], capture_output=True, text=True)
# result.returncode가 0이면 성공, 그렇지 않으면 실패
if result.stdout:
result_size = len(result.stdout)
curr_loc = 0
while curr_loc < result_size:
if curr_loc + MAX_BLOCK < result_size:
print_log(result, use_print, curr_loc, curr_loc + MAX_BLOCK)
curr_loc += MAX_BLOCK
else:
print_log(result, use_print, curr_loc, result_size)
break
elif result.stderr:
Logger().debug(result.stderr)
return result.returncode == 0
except Exception as e:
Logger().debug(f"Error running script: {e}")
return False
[docs]
def run_test_script_file(list_file: str):
"""
주어진 파일에 있는 테스트 스크립트를 순차적으로 실행합니다.
Args:
list_file (str): 테스트 스크립트 목록 파일
"""
ts_dict = get_test_scripts()
with open(list_file, 'r', encoding='utf-8') as f:
for test_id in f.readlines():
test_id = test_id.strip()
print(f"{test_id:30} --- ", end="")
if test_id in ts_dict.keys():
print("Run...", end="", flush=True)
if run_script(ts_dict[test_id]):
print('PASS')
else:
print('FAIL!')
return
else:
print("NOT FOUND!")
if __name__ == '__main__':
from pprint import pprint
[docs]
script_dict = get_test_scripts()
pprint(script_dict)
res = run_script(script_dict['TestApp1'])
print(res)