- Move backend/frontend/messenger/ old paths to _archive/ - Reorganize scripts into scripts/deploy, check, push, setup, misc - Move docs (pptx, docx) to docs/ - Add .claude agents and skills for fullstack/folder-cleanup harness - workspace/ projects remain intact Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
100 lines
3.7 KiB
Python
100 lines
3.7 KiB
Python
"""테스트 코드 배포 + 단위/통합 테스트 실행"""
|
|
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()
|