| """§50.3.3 有用按鈕 endpoint 測試。""" |
| from __future__ import annotations |
|
|
| import pytest |
| from fastapi.testclient import TestClient |
|
|
| from app.auth.passwords import hash_password |
| from app.db import _utcnow, get_conn |
| from app.main import app |
|
|
| PWD = "TestPw123!" |
|
|
|
|
| @pytest.fixture() |
| def client(): |
| return TestClient(app) |
|
|
|
|
| def _mkuser(name, role="user", dept="業務部"): |
| c = get_conn() |
| c.execute( |
| "INSERT INTO users (username, email, password_hash, role, department, " |
| "created_at, is_active) VALUES (?,?,?,?,?,?,1)", |
| (name, f"{name}@x.tw", hash_password(PWD), role, dept, _utcnow()), |
| ) |
| return c.execute("SELECT id FROM users WHERE username=?", (name,)).fetchone()["id"] |
|
|
|
|
| def _mkdoc(author_id, vis="public", dept="業務部"): |
| now = _utcnow() |
| cur = get_conn().execute( |
| "INSERT INTO documents (title, category, tags, summary, body, author_id, " |
| "owner_department, visibility, allowed_departments, access_list, status, " |
| "created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,'[]','[]','active',?,?)", |
| ("t", "知識/筆記", "[]", "s", "b", author_id, dept, vis, now, now), |
| ) |
| return cur.lastrowid |
|
|
|
|
| def _login(c, u): |
| return c.post("/api/auth/login", json={"username": u, "password": PWD}).json()["access_token"] |
|
|
|
|
| def _auth(t): |
| return {"Authorization": f"Bearer {t}"} |
|
|
|
|
| def test_toggle_helpful_on(client): |
| a = _mkuser("author") |
| did = _mkdoc(a) |
| u = _mkuser("voter") |
| tok = _login(client, "voter") |
| r = client.post(f"/api/documents/{did}/helpful", headers=_auth(tok)) |
| assert r.status_code == 200 |
| j = r.json() |
| assert j["helpful"] is True |
| assert j["count"] == 1 |
|
|
|
|
| def test_toggle_helpful_off(client): |
| a = _mkuser("author") |
| did = _mkdoc(a) |
| _mkuser("voter") |
| tok = _login(client, "voter") |
| client.post(f"/api/documents/{did}/helpful", headers=_auth(tok)) |
| r = client.post(f"/api/documents/{did}/helpful", headers=_auth(tok)) |
| j = r.json() |
| assert j["helpful"] is False |
| assert j["count"] == 0 |
|
|
|
|
| def test_helpful_count_multi_user(client): |
| a = _mkuser("author") |
| did = _mkdoc(a) |
| for name in ("v1", "v2", "v3"): |
| _mkuser(name) |
| tok = _login(client, name) |
| client.post(f"/api/documents/{did}/helpful", headers=_auth(tok)) |
| cnt = get_conn().execute("SELECT helpful_count FROM documents WHERE id=?", (did,)).fetchone()["helpful_count"] |
| assert cnt == 3 |
|
|
|
|
| def test_get_helpful_status(client): |
| a = _mkuser("author") |
| did = _mkdoc(a) |
| _mkuser("voter") |
| tok = _login(client, "voter") |
| |
| r1 = client.get(f"/api/documents/{did}/helpful", headers=_auth(tok)) |
| assert r1.json()["helpful"] is False |
| |
| client.post(f"/api/documents/{did}/helpful", headers=_auth(tok)) |
| r2 = client.get(f"/api/documents/{did}/helpful", headers=_auth(tok)) |
| assert r2.json()["helpful"] is True |
| assert r2.json()["count"] == 1 |
|
|
|
|
| def test_helpful_404_missing_doc(client): |
| _mkuser("voter") |
| tok = _login(client, "voter") |
| r = client.post("/api/documents/99999/helpful", headers=_auth(tok)) |
| assert r.status_code == 404 |
|
|
|
|
| def test_helpful_respects_visibility(client): |
| a = _mkuser("author", dept="業務部") |
| did = _mkdoc(a, vis="department", dept="業務部") |
| _mkuser("outsider", dept="研發部") |
| tok = _login(client, "outsider") |
| r = client.post(f"/api/documents/{did}/helpful", headers=_auth(tok)) |
| assert r.status_code == 404 |
|
|
|
|
| def test_helpful_unauth(client): |
| a = _mkuser("author") |
| did = _mkdoc(a) |
| r = client.post(f"/api/documents/{did}/helpful") |
| assert r.status_code in (401, 403) |
|
|
|
|
| |
|
|
| def test_helpful_count_always_equals_vote_rows(client): |
| """stored helpful_count 永遠 == COUNT(helpful_votes),且 toggle 冪等不漂移。""" |
| aid = _mkuser("a1", "admin") |
| _mkuser("u1", "user") |
| _mkuser("u2", "user") |
| did = _mkdoc(aid, "public", "業務部") |
|
|
| def _stored_vs_real(): |
| c = get_conn() |
| stored = c.execute("SELECT helpful_count FROM documents WHERE id=?", (did,)).fetchone()["helpful_count"] |
| real = c.execute("SELECT COUNT(*) AS n FROM helpful_votes WHERE document_id=?", (did,)).fetchone()["n"] |
| return stored, real |
|
|
| t1 = _login(client, "u1"); t2 = _login(client, "u2") |
| client.post(f"/api/documents/{did}/helpful", headers=_auth(t1)) |
| client.post(f"/api/documents/{did}/helpful", headers=_auth(t2)) |
| s, r = _stored_vs_real(); assert s == r == 2 |
| |
| client.post(f"/api/documents/{did}/helpful", headers=_auth(t1)) |
| s, r = _stored_vs_real(); assert s == r == 1 |
| |
| last = client.post(f"/api/documents/{did}/helpful", headers=_auth(t1)).json() |
| s, r = _stored_vs_real(); assert s == r == 2 |
| assert last["count"] == 2 and last["helpful"] is True |
|
|