diff --git a/music-lab/app/db.py b/music-lab/app/db.py index 559d7fe..cf7fd86 100644 --- a/music-lab/app/db.py +++ b/music-lab/app/db.py @@ -131,7 +131,8 @@ def init_db() -> None: rpm_usd REAL NOT NULL DEFAULT 0.0, country TEXT NOT NULL DEFAULT '', source TEXT NOT NULL DEFAULT 'manual', - created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')) + created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')), + UNIQUE(yt_video_id, record_month, country) ) """) conn.execute("CREATE INDEX IF NOT EXISTS idx_rr_month ON revenue_records(record_month DESC)") @@ -567,7 +568,7 @@ def get_revenue_dashboard() -> dict: ).fetchone() by_month = conn.execute( """SELECT record_month, SUM(revenue_usd) as revenue, SUM(views) as views, - AVG(rpm_usd) as avg_rpm FROM revenue_records + CASE WHEN SUM(views) > 0 THEN ROUND(SUM(revenue_usd) / SUM(views) * 1000, 4) ELSE 0.0 END as avg_rpm FROM revenue_records GROUP BY record_month ORDER BY record_month DESC LIMIT 12""" ).fetchall() by_country = conn.execute( diff --git a/music-lab/tests/test_db_video.py b/music-lab/tests/test_db_video.py index d32f75c..83dbed8 100644 --- a/music-lab/tests/test_db_video.py +++ b/music-lab/tests/test_db_video.py @@ -1,3 +1,6 @@ +import pytest + + def test_create_and_get_video_project(tmp_db): from app.db import init_db, create_video_project, get_video_project init_db() @@ -62,7 +65,6 @@ def test_create_revenue_record(tmp_db): def test_revenue_dashboard(tmp_db): from app.db import init_db, create_revenue_record, get_revenue_dashboard - import pytest init_db() create_revenue_record({"yt_video_id": "v1", "record_month": "2026-04", "views": 5000, "revenue_usd": 10.0}) create_revenue_record({"yt_video_id": "v2", "record_month": "2026-04", "views": 5000, "revenue_usd": 15.0}) @@ -70,3 +72,54 @@ def test_revenue_dashboard(tmp_db): assert dash["total_revenue_usd"] == pytest.approx(25.0) assert dash["total_views"] == 10000 assert len(dash["by_month"]) == 1 + + +def test_create_revenue_record_zero_views(tmp_db): + from app.db import init_db, create_revenue_record + init_db() + rec = create_revenue_record({ + "yt_video_id": "zero", + "record_month": "2026-04", + "views": 0, + "revenue_usd": 0.0, + }) + assert rec["rpm_usd"] == 0.0 + + +def test_update_revenue_record(tmp_db): + from app.db import init_db, create_revenue_record, update_revenue_record + init_db() + create_revenue_record({"yt_video_id": "x", "record_month": "2026-04", "views": 1000, "revenue_usd": 5.0}) + updated = update_revenue_record(1, {"views": 2000, "revenue_usd": 8.0}) + assert updated["rpm_usd"] == pytest.approx(4.0) + assert update_revenue_record(999, {}) is None + + +def test_delete_revenue_record(tmp_db): + from app.db import init_db, create_revenue_record, delete_revenue_record, get_all_revenue_records + init_db() + create_revenue_record({"yt_video_id": "del", "record_month": "2026-04", "views": 100, "revenue_usd": 1.0}) + assert delete_revenue_record(1) is True + assert delete_revenue_record(99) is False + assert get_all_revenue_records(yt_video_id="del") == [] + + +def test_video_project_status_failed(tmp_db): + from app.db import init_db, create_video_project, update_video_project_status, get_video_project + init_db() + create_video_project({"track_id": 1, "format": "visualizer"}) + update_video_project_status(1, "failed", error="FFmpeg error") + proj = get_video_project(1) + assert proj["status"] == "failed" + assert proj["completed_at"] is not None + assert proj["error"] == "FFmpeg error" + + +def test_video_project_status_rendering_no_completed_at(tmp_db): + from app.db import init_db, create_video_project, update_video_project_status, get_video_project + init_db() + create_video_project({"track_id": 1, "format": "visualizer"}) + update_video_project_status(1, "rendering") + proj = get_video_project(1) + assert proj["status"] == "rendering" + assert proj["completed_at"] is None