Files
ITOSMPiano-BachToBasics/backend/tests/test_library_db.py
T
이창현 89f66c3bee
CI / Frontend - type-check & test (push) Canceled after 0s
초보자용 1분 양손 MIDI 연습곡 다섯 개를 추가함
직접 만든 연습곡 다섯 파일을 공개 보관함에 등록했다. 별빛 계단은 입문과 쉬움 두 단계로 제공한다.

MIDI 파서 검사와 백엔드 단위 테스트 5개를 통과했다. 운영 백업은 /home/syskiller/piano/backups/bach-to-basics/20261009-beginner-midi 에 있다. 백엔드만 갱신했고 비회원 목록과 다운로드를 확인했다. 실제 USB MIDI 장치 검사는 남아 있다. 사전 훅은 로컬 pnpm 의존성 불일치로 실행되지 않아 관련 검사를 직접 수행했다.
2026-10-09 23:06:17 +09:00

83 lines
3.2 KiB
Python

from __future__ import annotations
import importlib
import os
import tempfile
import unittest
from pathlib import Path
class LibraryDatabaseTest(unittest.TestCase):
def setUp(self) -> None:
self.temp = tempfile.TemporaryDirectory()
os.environ["LIBRARY_DATA_DIR"] = self.temp.name
os.environ.pop("BOOTSTRAP_ADMIN_USERNAME", None)
os.environ.pop("BOOTSTRAP_ADMIN_PASSWORD_FILE", None)
import library_db
self.db = importlib.reload(library_db)
self.db.initialize_database()
def tearDown(self) -> None:
self.temp.cleanup()
def test_password_hash_is_salted_and_verifiable(self) -> None:
first = self.db.hash_password("safe-password-123")
second = self.db.hash_password("safe-password-123")
self.assertNotEqual(first, second)
self.assertTrue(self.db.verify_password("safe-password-123", first))
self.assertFalse(self.db.verify_password("wrong-password", first))
def test_session_round_trip(self) -> None:
with self.db.connect() as connection:
cursor = connection.execute(
"""
INSERT INTO users (username, display_name, password_hash, created_at)
VALUES ('tester', '테스터', ?, ?)
""",
(self.db.hash_password("safe-password-123"), self.db.utc_now()),
)
user_id = cursor.lastrowid
token, csrf = self.db.create_session(user_id)
user = self.db.get_user_for_session(token)
self.assertIsNotNone(user)
self.assertEqual(user["username"], "tester")
self.assertEqual(user["csrf_token"], csrf)
self.db.delete_session(token)
self.assertIsNone(self.db.get_user_for_session(token))
def test_database_directory_is_private_project_data(self) -> None:
self.assertTrue(Path(self.temp.name, "library.sqlite3").is_file())
self.assertTrue(Path(self.temp.name, "midi").is_dir())
def test_graded_samples_are_two_hand_piano_solos(self) -> None:
for sample in self.db.SAMPLES:
self.assertEqual(sample["arrangement"], "piano_solo")
self.assertIn("양손", sample["tags"])
self.assertNotIn("오른손", sample["tags"])
self.assertNotIn("쉬운 반주", sample["tags"])
def test_self_composed_beginner_midis_are_seeded_as_public(self) -> None:
names = {
"starlight-steps-beginner.mid",
"starlight-steps-easy.mid",
"evening-waltz-beginner.mid",
"sunrise-arpeggio-easy.mid",
"black-key-pentatonic-beginner.mid",
}
with self.db.connect() as connection:
rows = connection.execute(
"SELECT seed_key, visibility, min_tier, owner_id FROM midi_items WHERE seed_key IS NOT NULL"
).fetchall()
matching = {row["seed_key"]: row for row in rows if row["seed_key"] in names}
self.assertEqual(set(matching), names)
for name, row in matching.items():
self.assertEqual(row["visibility"], "public")
self.assertEqual(row["min_tier"], 0)
self.assertIsNone(row["owner_id"])
self.assertTrue(Path(self.temp.name, "midi", name).is_file())
if __name__ == "__main__":
unittest.main()