"""테스트 코드 배포 + 단위/통합 테스트 실행""" import paramiko, sys, os sys.stdout.reconfigure(encoding='utf-8', errors='replace') from pathlib import Path client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=30) sftp = client.open_sftp() def run(label, cmd, timeout=120): print(f'\n{"="*55}\n[{label}]') _, o, e = client.exec_command(cmd, timeout=timeout) out = o.read().decode('utf-8', errors='replace').strip() if out: print(out[-800:]) return out # 테스트 파일 업로드 LOCAL = Path(r'C:\GUARDiA\workspace\guardia-itsm\tests') REMOTE = '/opt/guardia/app/tests' run('tests 디렉토리 생성', f'mkdir -p {REMOTE}/unit {REMOTE}/integration') for f in LOCAL.rglob('*.py'): rel = f.relative_to(LOCAL).as_posix() rp = f'{REMOTE}/{rel}' rdir = '/'.join(rp.split('/')[:-1]) client.exec_command(f"mkdir -p '{rdir}'") import time; time.sleep(0.03) sftp.put(str(f), rp) print(f' OK {rel}') sftp.close() # pytest 설치 확인 run('pytest + httpx 설치', """ /opt/guardia/venv/bin/pip install pytest httpx -q && echo "OK" """) # ── 단위 테스트 실행 ────────────────────────────────────────────────────────── print('\n' + '='*55) print('단위 테스트 실행') run('단위 테스트', """ cd /opt/guardia/app /opt/guardia/venv/bin/pytest tests/unit/ \ -v --tb=short --no-header \ --junitxml=/tmp/unit-results.xml \ 2>&1 """, timeout=60) # ── 통합 테스트 실행 ────────────────────────────────────────────────────────── print('\n' + '='*55) print('통합 테스트 실행') run('통합 테스트', """ cd /opt/guardia/app /opt/guardia/venv/bin/pytest tests/integration/ \ -v --tb=short --no-header \ --junitxml=/tmp/integration-results.xml \ 2>&1 """, timeout=60) # ── 결과 요약 ───────────────────────────────────────────────────────────────── run('테스트 결과 요약', """ echo "=== 단위 테스트 결과 ===" /opt/guardia/venv/bin/python3 -c " import xml.etree.ElementTree as ET try: t = ET.parse('/tmp/unit-results.xml').getroot() total = int(t.get('tests',0)) fail = int(t.get('failures',0)) + int(t.get('errors',0)) skip = int(t.get('skipped',0)) print(f' 총: {total} 성공: {total-fail-skip} 실패: {fail} 스킵: {skip}') for tc in t.iter('testcase'): f = tc.find('failure') e = tc.find('error') if f is not None or e is not None: print(f' FAIL: {tc.get(\"classname\",\"\")}.{tc.get(\"name\",\"\")}') except Exception as ex: print('결과 파일 없음:', ex) " 2>/dev/null echo "=== 통합 테스트 결과 ===" /opt/guardia/venv/bin/python3 -c " import xml.etree.ElementTree as ET try: t = ET.parse('/tmp/integration-results.xml').getroot() total = int(t.get('tests',0)) fail = int(t.get('failures',0)) + int(t.get('errors',0)) skip = int(t.get('skipped',0)) print(f' 총: {total} 성공: {total-fail-skip} 실패: {fail} 스킵: {skip}') for tc in t.iter('testcase'): f = tc.find('failure') e = tc.find('error') if f is not None or e is not None: print(f' FAIL: {tc.get(\"classname\",\"\")}.{tc.get(\"name\",\"\")}') except Exception as ex: print('결과 파일 없음:', ex) " 2>/dev/null """) client.close()