EV 충전 플랫폼 초기 백업
This commit is contained in:
162
test_flow.py
Normal file
162
test_flow.py
Normal file
@@ -0,0 +1,162 @@
|
||||
"""전체 충전 흐름 테스트 스크립트
|
||||
|
||||
API 서버가 실행 중인 상태에서 실행.
|
||||
실제 토스 결제 없이 전체 흐름을 시뮬레이션.
|
||||
|
||||
사용법:
|
||||
pip3 install httpx
|
||||
python3 test_flow.py
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import httpx
|
||||
import json
|
||||
import sys
|
||||
|
||||
BASE_URL = "http://localhost:8000/api/v1"
|
||||
|
||||
G = "\033[92m"
|
||||
Y = "\033[93m"
|
||||
C = "\033[96m"
|
||||
R = "\033[91m"
|
||||
E = "\033[0m"
|
||||
|
||||
|
||||
def log(step, msg, data=None):
|
||||
print(f"\n{C}{'─'*50}{E}")
|
||||
print(f"{Y}[{step}]{E} {msg}")
|
||||
if data:
|
||||
print(f"{G}{json.dumps(data, indent=2, ensure_ascii=False, default=str)}{E}")
|
||||
|
||||
|
||||
def check(resp, step):
|
||||
"""응답 확인 - 실패 시 내용 출력 후 중단"""
|
||||
if resp.status_code >= 400:
|
||||
print(f"\n{R}{'━'*50}")
|
||||
print(f" ERROR at [{step}] - HTTP {resp.status_code}")
|
||||
print(f" {resp.json()}")
|
||||
print(f"{'━'*50}{E}\n")
|
||||
sys.exit(1)
|
||||
return resp.json()
|
||||
|
||||
|
||||
async def main():
|
||||
async with httpx.AsyncClient(base_url=BASE_URL, timeout=10.0) as c:
|
||||
|
||||
# 0. 헬스체크
|
||||
resp = await c.get("http://localhost:8000/health")
|
||||
log("0. 헬스체크", f"HTTP {resp.status_code}", resp.json())
|
||||
|
||||
# 1. 충전기 등록
|
||||
log("1. 충전기 등록", "CHARGER_001")
|
||||
resp = await c.post("/chargers/", json={
|
||||
"charge_box_id": "CHARGER_001",
|
||||
"name": "A동 주차장 1번",
|
||||
"location": "수원시 영통구 테스트 아파트 지하1층",
|
||||
"power_kw": 7.0,
|
||||
})
|
||||
if resp.status_code == 409:
|
||||
log("1. 충전기 등록", "이미 등록됨 - 건너뜀")
|
||||
else:
|
||||
log("1. 충전기 등록", f"결과: {resp.status_code}", resp.json())
|
||||
|
||||
# 1-1. 이전 테스트 잔여 세션 정리
|
||||
log("1-1. 세션 정리", "미완료 세션 취소")
|
||||
resp = await c.post("/sessions/reset/CHARGER_001")
|
||||
log("1-1. 세션 정리", "결과", resp.json())
|
||||
|
||||
# 2. 충전기 상태 -> Available
|
||||
log("2. 상태 업데이트", "충전기 Available 설정")
|
||||
resp = await c.post("/ocpp/status", json={
|
||||
"charge_box_id": "CHARGER_001",
|
||||
"connector_id": 1,
|
||||
"status": "Available",
|
||||
})
|
||||
log("2. 상태 업데이트", "결과", check(resp, "2"))
|
||||
|
||||
# 3. 세션 생성 (QR 스캔)
|
||||
log("3. 세션 생성", "QR 스캔 -> 세션 생성")
|
||||
resp = await c.post("/sessions/", json={
|
||||
"charge_box_id": "CHARGER_001",
|
||||
"connector_id": 1,
|
||||
})
|
||||
session = check(resp, "3")
|
||||
session_uid = session["session_uid"]
|
||||
id_tag = session["id_tag"]
|
||||
log("3. 세션 생성", f"세션: {session_uid} / tag: {id_tag}", session)
|
||||
|
||||
# 4. 결제 준비
|
||||
log("4. 결제 준비", "orderId 발급")
|
||||
resp = await c.post("/payments/prepare", json={
|
||||
"session_uid": session_uid,
|
||||
"amount": 10000,
|
||||
})
|
||||
payment = check(resp, "4")
|
||||
log("4. 결제 준비", f"주문: {payment['order_id']}", payment)
|
||||
|
||||
# 5. 결제 우회 (테스트용)
|
||||
log("5. 결제 우회", "토스 결제 없이 AUTHORIZED 강제 설정")
|
||||
print(f" {Y}(실제로는 토스페이먼츠 결제 UI -> POST /payments/confirm){E}")
|
||||
resp = await c.post(f"/sessions/{session_uid}/force-authorize")
|
||||
log("5. 결제 우회", "결과", check(resp, "5"))
|
||||
|
||||
# 6. StartTransaction (충전기 -> 서버)
|
||||
log("6. StartTransaction", "충전기가 충전 시작 보고")
|
||||
resp = await c.post("/ocpp/start-transaction", json={
|
||||
"charge_box_id": "CHARGER_001",
|
||||
"connector_id": 1,
|
||||
"id_tag": id_tag,
|
||||
"meter_start": 100000,
|
||||
"transaction_id": 1001,
|
||||
})
|
||||
result = check(resp, "6")
|
||||
log("6. StartTransaction", f"결과: {result.get('status')}", result)
|
||||
|
||||
# 7. MeterValues (충전 중 실시간 전력량)
|
||||
for i, wh in enumerate([105000, 110000, 115000, 120000]):
|
||||
kwh = (wh - 100000) / 1000
|
||||
log(f"7-{i+1}. MeterValues", f"{wh}Wh (누적 {kwh}kWh 충전)")
|
||||
await c.post("/ocpp/meter-values", json={
|
||||
"charge_box_id": "CHARGER_001",
|
||||
"connector_id": 1,
|
||||
"transaction_id": 1001,
|
||||
"value": wh,
|
||||
})
|
||||
|
||||
# 8. 충전 중 세션 상태 확인
|
||||
resp = await c.get(f"/sessions/{session_uid}")
|
||||
log("8. 세션 상태", "충전 중", check(resp, "8"))
|
||||
|
||||
# 9. StopTransaction (충전 종료)
|
||||
log("9. StopTransaction", "충전 종료 - 30kWh 충전 완료")
|
||||
resp = await c.post("/ocpp/stop-transaction", json={
|
||||
"charge_box_id": "CHARGER_001",
|
||||
"transaction_id": 1001,
|
||||
"meter_stop": 130000,
|
||||
"reason": "Local",
|
||||
})
|
||||
result = check(resp, "9")
|
||||
log("9. StopTransaction", "정산 결과", result)
|
||||
|
||||
# 10. 최종 정산
|
||||
resp = await c.get(f"/sessions/{session_uid}/billing")
|
||||
billing = check(resp, "10")
|
||||
log("10. 최종 정산", "요금 내역", billing)
|
||||
|
||||
# 11. 대시보드
|
||||
resp = await c.get("/dashboard/summary")
|
||||
log("11. 대시보드", "전체 요약", check(resp, "11"))
|
||||
|
||||
# 완료
|
||||
saved = billing.get("saved_vs_cpo", 0)
|
||||
total = billing.get("total_bill", 0)
|
||||
kwh = billing.get("charged_kwh", 0)
|
||||
print(f"\n{G}{'━'*50}")
|
||||
print(f" 충전 완료: {kwh}kWh")
|
||||
print(f" 요금: {total:,}원 (170원/kWh)")
|
||||
print(f" CPO 대비 절감: {saved:,}원")
|
||||
print(f"{'━'*50}{E}\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user