252 lines
8.9 KiB
Python
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()
|