ytptube/app/tests/test_datastore_pagination.py
2025-11-13 17:15:05 +03:00

252 lines
8.9 KiB
Python

import json
import sqlite3
from datetime import UTC, datetime
from pathlib import Path
from tempfile import TemporaryDirectory
import pytest
from app.library.DataStore import DataStore, StoreType
from app.library.ItemDTO import ItemDTO
class TestDataStorePagination:
"""Test pagination functionality of DataStore."""
@pytest.fixture
def temp_db(self):
"""Create a temporary database with test data."""
with TemporaryDirectory() as tmpdir:
db_path = Path(tmpdir) / "test.db"
conn = sqlite3.connect(str(db_path))
conn.row_factory = sqlite3.Row
# Create the history table
conn.execute(
"""
CREATE TABLE IF NOT EXISTS "history" (
"id" TEXT PRIMARY KEY,
"type" TEXT NOT NULL,
"url" TEXT NOT NULL,
"data" TEXT NOT NULL,
"created_at" TEXT NOT NULL
)
"""
)
# Insert test data
base_time = datetime.now(UTC)
for i in range(100):
created_at = base_time.replace(
hour=(i // 4) % 24, minute=(i * 15) % 60, second=i % 60
).strftime("%Y-%m-%d %H:%M:%S")
item_data = {
"url": f"https://example.com/video{i}",
"title": f"Test Video {i}",
"id": f"video{i}",
"folder": "/downloads",
"status": "finished",
}
conn.execute(
'INSERT INTO "history" ("id", "type", "url", "data", "created_at") VALUES (?, ?, ?, ?, ?)',
(
f"test-id-{i}",
str(StoreType.HISTORY),
item_data["url"],
json.dumps(item_data),
created_at,
),
)
conn.commit()
yield conn
conn.close()
def test_get_total_count(self, temp_db):
"""Test getting total count of items."""
datastore = DataStore(type=StoreType.HISTORY, connection=temp_db)
count = datastore.get_total_count()
assert count == 100
def test_pagination_basic(self, temp_db):
"""Test basic pagination functionality."""
datastore = DataStore(type=StoreType.HISTORY, connection=temp_db)
# Get first page
items, total, page, total_pages = datastore.get_items_paginated(page=1, per_page=10)
assert len(items) == 10
assert total == 100
assert page == 1
assert total_pages == 10
# Verify items are ItemDTO instances
for _item_id, item in items:
assert isinstance(item, ItemDTO)
assert item._id.startswith("test-id-")
def test_pagination_last_page(self, temp_db):
"""Test pagination on last page."""
datastore = DataStore(type=StoreType.HISTORY, connection=temp_db)
# Get last page
items, total, page, total_pages = datastore.get_items_paginated(page=10, per_page=10)
assert len(items) == 10
assert total == 100
assert page == 10
assert total_pages == 10
def test_pagination_partial_page(self, temp_db):
"""Test pagination with partial last page."""
datastore = DataStore(type=StoreType.HISTORY, connection=temp_db)
# Get items with per_page that doesn't divide evenly
items, total, page, total_pages = datastore.get_items_paginated(page=4, per_page=30)
assert len(items) == 10 # 100 items / 30 per page = 3 full pages + 10 items
assert total == 100
assert page == 4
assert total_pages == 4
def test_pagination_out_of_range(self, temp_db):
"""Test pagination with page number out of range."""
datastore = DataStore(type=StoreType.HISTORY, connection=temp_db)
# Request page beyond total pages - should return last page
items, total, page, total_pages = datastore.get_items_paginated(page=999, per_page=10)
assert len(items) == 10
assert total == 100
assert page == 10 # Adjusted to last page
assert total_pages == 10
def test_pagination_order_desc(self, temp_db):
"""Test pagination with descending order (newest first)."""
datastore = DataStore(type=StoreType.HISTORY, connection=temp_db)
items, _, _, _ = datastore.get_items_paginated(page=1, per_page=5, order="DESC")
assert len(items) == 5
# Verify order - should be newest to oldest
# (note: exact order depends on the timestamp generation in fixture)
def test_pagination_order_asc(self, temp_db):
"""Test pagination with ascending order (oldest first)."""
datastore = DataStore(type=StoreType.HISTORY, connection=temp_db)
items, _, _, _ = datastore.get_items_paginated(page=1, per_page=5, order="ASC")
assert len(items) == 5
def test_pagination_invalid_page(self, temp_db):
"""Test pagination with invalid page number."""
datastore = DataStore(type=StoreType.HISTORY, connection=temp_db)
with pytest.raises(ValueError, match="page must be >= 1"):
datastore.get_items_paginated(page=0, per_page=10)
with pytest.raises(ValueError, match="page must be >= 1"):
datastore.get_items_paginated(page=-1, per_page=10)
def test_pagination_invalid_per_page(self, temp_db):
"""Test pagination with invalid per_page value."""
datastore = DataStore(type=StoreType.HISTORY, connection=temp_db)
with pytest.raises(ValueError, match="per_page must be >= 1"):
datastore.get_items_paginated(page=1, per_page=0)
with pytest.raises(ValueError, match="per_page must be >= 1"):
datastore.get_items_paginated(page=1, per_page=-10)
def test_pagination_invalid_order(self, temp_db):
"""Test pagination with invalid order parameter."""
datastore = DataStore(type=StoreType.HISTORY, connection=temp_db)
with pytest.raises(ValueError, match="order must be 'ASC' or 'DESC'"):
datastore.get_items_paginated(page=1, per_page=10, order="INVALID")
def test_pagination_empty_store(self):
"""Test pagination with empty datastore."""
with TemporaryDirectory() as tmpdir:
db_path = Path(tmpdir) / "empty.db"
conn = sqlite3.connect(str(db_path))
conn.row_factory = sqlite3.Row
# Create empty table
conn.execute(
"""
CREATE TABLE IF NOT EXISTS "history" (
"id" TEXT PRIMARY KEY,
"type" TEXT NOT NULL,
"url" TEXT NOT NULL,
"data" TEXT NOT NULL,
"created_at" TEXT NOT NULL
)
"""
)
conn.commit()
datastore = DataStore(type=StoreType.HISTORY, connection=conn)
items, total, page, total_pages = datastore.get_items_paginated(page=1, per_page=10)
assert len(items) == 0
assert total == 0
assert page == 1
assert total_pages == 1
conn.close()
def test_pagination_single_item(self):
"""Test pagination with single item."""
with TemporaryDirectory() as tmpdir:
db_path = Path(tmpdir) / "single.db"
conn = sqlite3.connect(str(db_path))
conn.row_factory = sqlite3.Row
# Create table with single item
conn.execute(
"""
CREATE TABLE IF NOT EXISTS "history" (
"id" TEXT PRIMARY KEY,
"type" TEXT NOT NULL,
"url" TEXT NOT NULL,
"data" TEXT NOT NULL,
"created_at" TEXT NOT NULL
)
"""
)
item_data = {
"url": "https://example.com/single",
"title": "Single Video",
"id": "single-video",
"folder": "/downloads",
"status": "finished",
}
conn.execute(
'INSERT INTO "history" ("id", "type", "url", "data", "created_at") VALUES (?, ?, ?, ?, ?)',
(
"single-id",
str(StoreType.HISTORY),
item_data["url"],
json.dumps(item_data),
datetime.now(UTC).strftime("%Y-%m-%d %H:%M:%S"),
),
)
conn.commit()
datastore = DataStore(type=StoreType.HISTORY, connection=conn)
items, total, page, total_pages = datastore.get_items_paginated(page=1, per_page=10)
assert len(items) == 1
assert total == 1
assert page == 1
assert total_pages == 1
conn.close()