elemes/load-test/locustfile_db.py

105 lines
3.3 KiB
Python

"""
Locust scenario khusus migrasi database (CSV → PostgreSQL).
Menargetkan endpoint yang persistence-nya berubah:
- /api/login + /api/validate-token (identitas: CSV → PG users/access_tokens)
- /api/track-progress (write progress: CSV → PG student_progress)
- /api/progress-report.json (report guru — baca semua siswa)
Data token diambil dari test_data.json (hasilkan dulu:
python content_parser.py --content-dir ../../content --num-tokens 50
→ token sintetis LOCUST_TEST_* di-seed ke PostgreSQL bila DATABASE_URL ter-set)
Usage (dari elemes/load-test/):
locust -f locustfile_db.py
→ set host ke URL Elemes (mis. https://sinau-c-dev.manakin-gentoo.ts.net)
"""
import json
import logging
import os
import random
from pathlib import Path
from locust import HttpUser, between, events, task
TEST_DATA_FILE = Path(__file__).parent / 'test_data.json'
API = os.environ.get('API_PREFIX', '/api')
def load_test_data() -> dict:
if not TEST_DATA_FILE.exists():
raise FileNotFoundError(
f'{TEST_DATA_FILE} tidak ada. Jalankan: python content_parser.py'
)
with open(TEST_DATA_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
try:
TEST_DATA = load_test_data()
except FileNotFoundError as e:
logging.error(str(e))
TEST_DATA = {'tokens': [], 'teacher_token': '', 'lessons': []}
STUDENT_TOKENS = [t for t in TEST_DATA.get('tokens', []) if t != TEST_DATA.get('teacher_token')]
TEACHER_TOKEN = TEST_DATA.get('teacher_token', '')
LESSON_SLUGS = [l['filename'].replace('.md', '') for l in TEST_DATA.get('lessons', [])]
if not STUDENT_TOKENS:
logging.warning('test_data.json tidak punya token siswa — hanya teacher')
class StudentUser(HttpUser):
"""Siswa: login → baca lesson → track progress (random status)."""
wait_time = between(1, 4)
def on_start(self):
self.token = random.choice(STUDENT_TOKENS) if STUDENT_TOKENS else ''
if not self.token:
return
self.client.post(f'{API}/login', json={'token': self.token})
@task(2)
def validate_token(self):
self.client.post(f'{API}/validate-token', json={'token': self.token})
@task(3)
def read_lesson(self):
if not LESSON_SLUGS:
return
slug = random.choice(LESSON_SLUGS)
self.client.get(f'/bab/dasar-pemrograman/{slug}', name='/bab/.../{slug}')
@task(3)
def track_progress(self):
if not LESSON_SLUGS:
return
slug = random.choice(LESSON_SLUGS)
status = random.choice(['completed', 'not_started', '3/4', '2/5'])
self.client.post(
f'{API}/track-progress',
json={'token': self.token, 'lesson_name': slug, 'status': status},
)
class TeacherUser(HttpUser):
"""Guru: login → report keseluruhan (beban baca berat di PG)."""
wait_time = between(3, 8)
def on_start(self):
if TEACHER_TOKEN:
self.client.post(f'{API}/login', json={'token': TEACHER_TOKEN})
@task(1)
def progress_report(self):
if TEACHER_TOKEN:
self.client.get(f'{API}/progress-report.json?token={TEACHER_TOKEN}')
@task(1)
def export_csv(self):
if TEACHER_TOKEN:
self.client.get(f'{API}/progress-report/export-csv?token={TEACHER_TOKEN}')