372 lines
14 KiB
Python
372 lines
14 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
API 테스트 스크립트
|
|
각 엔드포인트가 제대로 작동하는지 테스트합니다.
|
|
"""
|
|
import os
|
|
import sys
|
|
import base64
|
|
import time
|
|
import requests
|
|
import json
|
|
from pathlib import Path
|
|
|
|
# 프로젝트 루트를 Python 경로에 추가
|
|
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
sys.path.insert(0, project_root)
|
|
|
|
class APITester:
|
|
def __init__(self, base_url="http://localhost:8000"):
|
|
self.base_url = base_url
|
|
self.test_images_dir = os.path.join(project_root, "tests", "images")
|
|
self.results_dir = os.path.join(project_root, "tests", "results")
|
|
|
|
# 결과 디렉토리 생성
|
|
os.makedirs(self.results_dir, exist_ok=True)
|
|
|
|
print(f"🚀 API 테스터 초기화 완료")
|
|
print(f" 서버 URL: {base_url}")
|
|
print(f" 테스트 이미지: {self.test_images_dir}")
|
|
print(f" 결과 저장: {self.results_dir}")
|
|
|
|
def image_to_base64(self, image_path):
|
|
"""이미지를 base64로 인코딩"""
|
|
try:
|
|
with open(image_path, "rb") as image_file:
|
|
encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
|
|
return encoded_string
|
|
except Exception as e:
|
|
print(f"❌ 이미지 인코딩 실패: {e}")
|
|
return None
|
|
|
|
def save_base64_image(self, base64_string, filename):
|
|
"""base64 이미지를 파일로 저장"""
|
|
try:
|
|
image_data = base64.b64decode(base64_string)
|
|
filepath = os.path.join(self.results_dir, filename)
|
|
with open(filepath, "wb") as f:
|
|
f.write(image_data)
|
|
print(f" 💾 결과 이미지 저장: {filename}")
|
|
return True
|
|
except Exception as e:
|
|
print(f"❌ 이미지 저장 실패: {e}")
|
|
return False
|
|
|
|
def test_health(self):
|
|
"""헬스 체크 테스트"""
|
|
print("\n🏥 헬스 체크 테스트...")
|
|
try:
|
|
response = requests.get(f"{self.base_url}/health", timeout=10)
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
print(f" ✅ 서버 상태: {data.get('status', 'unknown')}")
|
|
print(f" 📊 가동 시간: {data.get('uptime', 0):.2f}초")
|
|
return True
|
|
else:
|
|
print(f" ❌ 서버 응답 실패: {response.status_code}")
|
|
return False
|
|
except Exception as e:
|
|
print(f" ❌ 연결 실패: {e}")
|
|
return False
|
|
|
|
def test_server_config(self):
|
|
"""서버 설정 정보 테스트"""
|
|
print("\n⚙️ 서버 설정 정보 테스트...")
|
|
try:
|
|
response = requests.get(f"{self.base_url}/api/v1/server-config", timeout=10)
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
print(f" ✅ 서버 설정 조회 성공")
|
|
print(f" 🖥️ 시스템: {'Jetson Xavier' if data.get('is_jetson') else 'x86_64'}")
|
|
print(f" 🎮 디바이스: {data.get('device', 'unknown')}")
|
|
print(f" 📁 최대 파일 크기: {data.get('max_file_size', 0)}MB")
|
|
print(f" 🎯 사용 가능한 모델: {len(data.get('models', []))}개")
|
|
return True
|
|
else:
|
|
print(f" ❌ 서버 설정 조회 실패: {response.status_code}")
|
|
return False
|
|
except Exception as e:
|
|
print(f" ❌ 연결 실패: {e}")
|
|
return False
|
|
|
|
def test_inpaint(self, image_name="test_image_512.png", mask_name="test_mask_512.png"):
|
|
"""인페인팅 API 테스트"""
|
|
print(f"\n🎨 인페인팅 테스트 ({image_name} + {mask_name})...")
|
|
|
|
# 이미지 파일 경로
|
|
image_path = os.path.join(self.test_images_dir, image_name)
|
|
mask_path = os.path.join(self.test_images_dir, mask_name)
|
|
|
|
if not os.path.exists(image_path) or not os.path.exists(mask_path):
|
|
print(f" ❌ 테스트 이미지 파일이 없습니다")
|
|
return False
|
|
|
|
try:
|
|
# 이미지를 base64로 인코딩
|
|
image_base64 = self.image_to_base64(image_path)
|
|
mask_base64 = self.image_to_base64(mask_path)
|
|
|
|
if not image_base64 or not mask_base64:
|
|
return False
|
|
|
|
# 인페인팅 요청
|
|
payload = {
|
|
"image": image_base64,
|
|
"mask": mask_base64,
|
|
"model_name": "simple-lama",
|
|
"sd_seed": 42,
|
|
"prompt": "beautiful landscape",
|
|
"negative_prompt": "ugly, blurry",
|
|
"num_inference_steps": 20,
|
|
"guidance_scale": 7.5,
|
|
"strength": 1.0
|
|
}
|
|
|
|
start_time = time.time()
|
|
response = requests.post(
|
|
f"{self.base_url}/api/v1/inpaint",
|
|
json=payload,
|
|
timeout=60
|
|
)
|
|
processing_time = time.time() - start_time
|
|
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
print(f" ✅ 인페인팅 성공!")
|
|
print(f" ⏱️ 처리 시간: {data.get('processing_time', processing_time):.2f}초")
|
|
print(f" 🎲 사용된 시드: {data.get('seed', 'unknown')}")
|
|
|
|
# 결과 이미지 저장
|
|
if data.get('image'):
|
|
self.save_base64_image(data['image'], f"inpaint_result_{image_name}")
|
|
|
|
return True
|
|
else:
|
|
print(f" ❌ 인페인팅 실패: {response.status_code}")
|
|
try:
|
|
error_data = response.json()
|
|
print(f" 📝 에러 메시지: {error_data.get('detail', 'unknown error')}")
|
|
except:
|
|
print(f" 📝 응답 내용: {response.text}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f" ❌ 인페인팅 테스트 실패: {e}")
|
|
return False
|
|
|
|
def test_remove_bg(self, image_name="test_image_512.png"):
|
|
"""배경 제거 API 테스트"""
|
|
print(f"\n🖼️ 배경 제거 테스트 ({image_name})...")
|
|
|
|
# 이미지 파일 경로
|
|
image_path = os.path.join(self.test_images_dir, image_name)
|
|
|
|
if not os.path.exists(image_path):
|
|
print(f" ❌ 테스트 이미지 파일이 없습니다")
|
|
return False
|
|
|
|
try:
|
|
# 이미지를 base64로 인코딩
|
|
image_base64 = self.image_to_base64(image_path)
|
|
|
|
if not image_base64:
|
|
return False
|
|
|
|
# 배경 제거 요청
|
|
payload = {
|
|
"image": image_base64,
|
|
"model_name": "rembg"
|
|
}
|
|
|
|
start_time = time.time()
|
|
response = requests.post(
|
|
f"{self.base_url}/api/v1/remove_bg",
|
|
json=payload,
|
|
timeout=60
|
|
)
|
|
processing_time = time.time() - start_time
|
|
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
print(f" ✅ 배경 제거 성공!")
|
|
print(f" ⏱️ 처리 시간: {data.get('processing_time', processing_time):.2f}초")
|
|
|
|
# 결과 이미지와 마스크 저장
|
|
if data.get('image'):
|
|
self.save_base64_image(data['image'], f"rembg_result_{image_name}")
|
|
if data.get('mask'):
|
|
self.save_base64_image(data['mask'], f"rembg_mask_{image_name}")
|
|
|
|
return True
|
|
else:
|
|
print(f" ❌ 배경 제거 실패: {response.status_code}")
|
|
try:
|
|
error_data = response.json()
|
|
print(f" 📝 에러 메시지: {error_data.get('detail', 'unknown error')}")
|
|
except:
|
|
print(f" 📝 응답 내용: {response.text}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f" ❌ 배경 제거 테스트 실패: {e}")
|
|
return False
|
|
|
|
def test_plugin_generate_image(self, image_name="test_image_512.png"):
|
|
"""플러그인 이미지 생성 테스트"""
|
|
print(f"\n🔌 플러그인 이미지 생성 테스트 ({image_name})...")
|
|
|
|
# 이미지 파일 경로
|
|
image_path = os.path.join(self.test_images_dir, image_name)
|
|
|
|
if not os.path.exists(image_path):
|
|
print(f" ❌ 테스트 이미지 파일이 없습니다")
|
|
return False
|
|
|
|
try:
|
|
# 이미지를 base64로 인코딩
|
|
image_base64 = self.image_to_base64(image_path)
|
|
|
|
if not image_base64:
|
|
return False
|
|
|
|
# 플러그인 요청
|
|
payload = {
|
|
"name": "rembg",
|
|
"image": image_base64,
|
|
"model_name": "rembg"
|
|
}
|
|
|
|
start_time = time.time()
|
|
response = requests.post(
|
|
f"{self.base_url}/api/v1/run_plugin_gen_image",
|
|
json=payload,
|
|
timeout=60
|
|
)
|
|
processing_time = time.time() - start_time
|
|
|
|
if response.status_code == 200:
|
|
data = response.json()
|
|
print(f" ✅ 플러그인 이미지 생성 성공!")
|
|
print(f" ⏱️ 처리 시간: {data.get('processing_time', processing_time):.2f}초")
|
|
|
|
# 결과 이미지 저장
|
|
if data.get('image'):
|
|
self.save_base64_image(data['image'], f"plugin_result_{image_name}")
|
|
|
|
return True
|
|
else:
|
|
print(f" ❌ 플러그인 이미지 생성 실패: {response.status_code}")
|
|
try:
|
|
error_data = response.json()
|
|
print(f" 📝 에러 메시지: {error_data.get('detail', 'unknown error')}")
|
|
except:
|
|
print(f" 📝 응답 내용: {response.text}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f" ❌ 플러그인 테스트 실패: {e}")
|
|
return False
|
|
|
|
def test_samplers(self):
|
|
"""샘플러 목록 테스트"""
|
|
print("\n🎲 샘플러 목록 테스트...")
|
|
try:
|
|
response = requests.get(f"{self.base_url}/api/v1/samplers", timeout=10)
|
|
if response.status_code == 200:
|
|
samplers = response.json()
|
|
print(f" ✅ 샘플러 목록 조회 성공")
|
|
print(f" 📊 사용 가능한 샘플러: {len(samplers)}개")
|
|
print(f" 🎯 샘플러들: {', '.join(samplers[:5])}{'...' if len(samplers) > 5 else ''}")
|
|
return True
|
|
else:
|
|
print(f" ❌ 샘플러 목록 조회 실패: {response.status_code}")
|
|
return False
|
|
except Exception as e:
|
|
print(f" ❌ 연결 실패: {e}")
|
|
return False
|
|
|
|
def run_all_tests(self):
|
|
"""모든 테스트 실행"""
|
|
print("🧪 전체 API 테스트 시작")
|
|
print("=" * 50)
|
|
|
|
test_results = []
|
|
|
|
# 1. 헬스 체크
|
|
test_results.append(("헬스 체크", self.test_health()))
|
|
|
|
# 2. 서버 설정 정보
|
|
test_results.append(("서버 설정 정보", self.test_server_config()))
|
|
|
|
# 3. 샘플러 목록
|
|
test_results.append(("샘플러 목록", self.test_samplers()))
|
|
|
|
# 4. 인페인팅 테스트 (작은 이미지)
|
|
test_results.append(("인페인팅 (256x256)", self.test_inpaint("test_image_256.png", "test_mask_256.png")))
|
|
|
|
# 5. 인페인팅 테스트 (기본 이미지)
|
|
test_results.append(("인페인팅 (512x512)", self.test_inpaint("test_image_512.png", "test_mask_512.png")))
|
|
|
|
# 6. 배경 제거 테스트
|
|
test_results.append(("배경 제거", self.test_remove_bg("test_image_512.png")))
|
|
|
|
# 7. 플러그인 테스트
|
|
test_results.append(("플러그인 이미지 생성", self.test_plugin_generate_image("test_image_512.png")))
|
|
|
|
# 결과 요약
|
|
print("\n" + "=" * 50)
|
|
print("📊 테스트 결과 요약")
|
|
print("=" * 50)
|
|
|
|
passed = 0
|
|
total = len(test_results)
|
|
|
|
for test_name, result in test_results:
|
|
status = "✅ PASS" if result else "❌ FAIL"
|
|
print(f"{test_name:<25} {status}")
|
|
if result:
|
|
passed += 1
|
|
|
|
print("=" * 50)
|
|
print(f"전체: {total}개, 성공: {passed}개, 실패: {total - passed}개")
|
|
|
|
if passed == total:
|
|
print("🎉 모든 테스트가 성공했습니다!")
|
|
else:
|
|
print("⚠️ 일부 테스트가 실패했습니다.")
|
|
|
|
return passed == total
|
|
|
|
def main():
|
|
"""메인 함수"""
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser(description="API 테스트 스크립트")
|
|
parser.add_argument("--url", default="http://localhost:8000", help="테스트할 서버 URL")
|
|
parser.add_argument("--single", help="단일 테스트 실행 (health, config, inpaint, rembg, plugin)")
|
|
|
|
args = parser.parse_args()
|
|
|
|
tester = APITester(args.url)
|
|
|
|
if args.single:
|
|
# 단일 테스트 실행
|
|
if args.single == "health":
|
|
tester.test_health()
|
|
elif args.single == "config":
|
|
tester.test_server_config()
|
|
elif args.single == "inpaint":
|
|
tester.test_inpaint()
|
|
elif args.single == "rembg":
|
|
tester.test_remove_bg()
|
|
elif args.single == "plugin":
|
|
tester.test_plugin_generate_image()
|
|
else:
|
|
print(f"❌ 알 수 없는 테스트: {args.single}")
|
|
else:
|
|
# 전체 테스트 실행
|
|
tester.run_all_tests()
|
|
|
|
if __name__ == "__main__":
|
|
main()
|