|
# retoor <retoor@molodetz.nl>
|
|
|
|
import json
|
|
import time
|
|
|
|
import requests
|
|
|
|
from tests.conftest import BASE_URL
|
|
|
|
JSON = {"Accept": "application/json"}
|
|
|
|
_counter = [0]
|
|
|
|
CHOICE = {
|
|
"kind": "single_choice",
|
|
"prompt": "Which journal mode allows concurrent readers?",
|
|
"points": 2,
|
|
"options": "DELETE\nWAL\nMEMORY",
|
|
"correct_indexes": "1",
|
|
}
|
|
|
|
NUMERIC = {
|
|
"kind": "numeric",
|
|
"prompt": "How many bytes are in a kibibyte?",
|
|
"points": 1,
|
|
"numeric_value": "1024",
|
|
"numeric_tolerance": "0",
|
|
}
|
|
|
|
TRUE_FALSE = {
|
|
"kind": "true_false",
|
|
"prompt": "A partial index can carry a WHERE clause.",
|
|
"points": 1,
|
|
"correct_boolean": "1",
|
|
}
|
|
|
|
FREE_TEXT = {
|
|
"kind": "free_text",
|
|
"prompt": "Why does a partial index help here?",
|
|
"points": 3,
|
|
"expected_answer": "It keeps the live query off a one bucket index.",
|
|
"grading_criteria": "Accept any answer that mentions the planner.",
|
|
}
|
|
|
|
DOCUMENT = {
|
|
"title": "Imported quiz",
|
|
"description": "Created from a document.",
|
|
"settings": {"reveal_answers": True, "pass_percent": 60, "allow_review": True},
|
|
"questions": [
|
|
{
|
|
"kind": "single_choice",
|
|
"prompt": "Which journal mode allows concurrent readers?",
|
|
"points": 2,
|
|
"options": [{"label": "DELETE"}, {"label": "WAL", "is_correct": True}],
|
|
},
|
|
{
|
|
"kind": "numeric",
|
|
"prompt": "How many bytes are in a kibibyte?",
|
|
"points": 1,
|
|
"numeric_value": 1024,
|
|
},
|
|
],
|
|
}
|
|
|
|
|
|
def signup(prefix="qz"):
|
|
_counter[0] += 1
|
|
name = f"{prefix}{int(time.time() * 1000)}{_counter[0]}"
|
|
session = requests.Session()
|
|
session.post(
|
|
f"{BASE_URL}/auth/signup",
|
|
data={
|
|
"username": name,
|
|
"email": f"{name}@t.dev",
|
|
"password": "secret123",
|
|
"confirm_password": "secret123",
|
|
},
|
|
allow_redirects=True,
|
|
)
|
|
return session, name
|
|
|
|
|
|
def create_quiz(session, title="Test quiz", **settings):
|
|
payload = {"title": title, "description": "A quiz."}
|
|
payload.update(settings)
|
|
response = session.post(f"{BASE_URL}/quizzes/create", data=payload, headers=JSON)
|
|
return response.json()["data"]["slug"]
|
|
|
|
|
|
def add_question(session, slug, payload):
|
|
return session.post(f"{BASE_URL}/quizzes/{slug}/questions", data=payload, headers=JSON)
|
|
|
|
|
|
def publish(session, slug):
|
|
return session.post(f"{BASE_URL}/quizzes/{slug}/publish", headers=JSON)
|
|
|
|
|
|
def build_published(session, questions=(CHOICE, NUMERIC), title="Playable quiz", **settings):
|
|
slug = create_quiz(session, title, **settings)
|
|
for question in questions:
|
|
add_question(session, slug, question)
|
|
publish(session, slug)
|
|
return slug
|
|
|
|
|
|
def import_quiz(session, document=None):
|
|
payload = {"document": json.dumps(document or DOCUMENT)}
|
|
response = session.post(f"{BASE_URL}/quizzes/import", data=payload, headers=JSON)
|
|
return response
|
|
|
|
|
|
def start_attempt(session, slug):
|
|
response = session.post(f"{BASE_URL}/quizzes/{slug}/attempts", headers=JSON)
|
|
return response.json()["data"]["uid"]
|
|
|
|
|
|
def attempt_state(session, slug, attempt_uid):
|
|
return session.get(
|
|
f"{BASE_URL}/quizzes/{slug}/attempts/{attempt_uid}", headers=JSON
|
|
).json()
|
|
|
|
|
|
def answer_correctly(session, slug, attempt_uid, question):
|
|
payload = {"question_uid": question["uid"]}
|
|
if question["kind"] == "single_choice":
|
|
correct = next(
|
|
(option["uid"] for option in question["options"] if option.get("is_correct")), None
|
|
)
|
|
payload["option_uids"] = correct or question["options"][1]["uid"]
|
|
elif question["kind"] == "numeric":
|
|
payload["answer_text"] = "1024"
|
|
elif question["kind"] == "true_false":
|
|
payload["answer_text"] = "true"
|
|
else:
|
|
payload["answer_text"] = "the planner picks a bad index for live rows"
|
|
return session.post(
|
|
f"{BASE_URL}/quizzes/{slug}/attempts/{attempt_uid}/answer", data=payload, headers=JSON
|
|
)
|