feat: add KOSync server
- Add KOSync device management - Add API key auth middleware for devices to authenticate - Add KOSync-compatible progress sync endpoints - Add basic tests for KOSync compatible hashes
This commit is contained in:
98
backend/tests/integration/test_file_hash.py
Normal file
98
backend/tests/integration/test_file_hash.py
Normal file
@@ -0,0 +1,98 @@
|
||||
"""Tests for KOReader-compatible file hash generation."""
|
||||
|
||||
import pytest
|
||||
from httpx import AsyncClient
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
# Known KOReader hashes for test files
|
||||
TEST_FILES = {
|
||||
"Moby Dick; Or, The Whale - Herman Melville.epub": {
|
||||
"path": Path("tests/data_files/Moby Dick; Or, The Whale - Herman Melville.epub"),
|
||||
"hash": "ceeef909ec65653ba77e1380dff998fb",
|
||||
"content_type": "application/epub+zip",
|
||||
},
|
||||
"Calculus Made Easy - Silvanus Thompson.pdf": {
|
||||
"path": Path("tests/data_files/Calculus Made Easy - Silvanus Thompson.pdf"),
|
||||
"hash": "ace67d512efd1efdea20f3c2436b6075",
|
||||
"content_type": "application/pdf",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("book_name",),
|
||||
[(name,) for name in TEST_FILES.keys()],
|
||||
)
|
||||
async def test_upload_book_generates_correct_hash(
|
||||
authenticated_client: AsyncClient,
|
||||
book_name: str,
|
||||
) -> None:
|
||||
"""Test that uploading a book generates the correct KOReader-compatible hash."""
|
||||
book_info = TEST_FILES[book_name]
|
||||
file_content = book_info["path"].read_bytes()
|
||||
|
||||
files = [("files", (book_name, file_content, book_info["content_type"]))]
|
||||
data = {"library_id": "1"}
|
||||
|
||||
response = await authenticated_client.post(
|
||||
"/books?library_id=1",
|
||||
files=files,
|
||||
data=data,
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
book_data = response.json()
|
||||
|
||||
assert len(book_data["files"]) == 1
|
||||
file_metadata = book_data["files"][0]
|
||||
|
||||
assert "hash" in file_metadata
|
||||
assert file_metadata["hash"] == book_info["hash"]
|
||||
|
||||
|
||||
async def test_add_file_to_book_generates_correct_hash(
|
||||
authenticated_client: AsyncClient,
|
||||
) -> None:
|
||||
"""Test that adding a file to an existing book generates the correct hash."""
|
||||
# Create a book with the first file
|
||||
first_book = TEST_FILES["Moby Dick; Or, The Whale - Herman Melville.epub"]
|
||||
first_content = first_book["path"].read_bytes()
|
||||
|
||||
files = [("files", (first_book["path"].name, first_content, first_book["content_type"]))]
|
||||
data = {"library_id": "1"}
|
||||
|
||||
create_response = await authenticated_client.post(
|
||||
"/books?library_id=1",
|
||||
files=files,
|
||||
data=data,
|
||||
)
|
||||
|
||||
assert create_response.status_code == 201
|
||||
book_id = create_response.json()["id"]
|
||||
|
||||
# Add the second file to the book
|
||||
second_book = TEST_FILES["Calculus Made Easy - Silvanus Thompson.pdf"]
|
||||
second_content = second_book["path"].read_bytes()
|
||||
|
||||
add_files = [("data", (second_book["path"].name, second_content, second_book["content_type"]))]
|
||||
|
||||
add_response = await authenticated_client.post(
|
||||
f"/books/{book_id}/files",
|
||||
files=add_files,
|
||||
)
|
||||
|
||||
assert add_response.status_code == 201
|
||||
updated_book = add_response.json()
|
||||
|
||||
# Verify both files have correct hashes
|
||||
assert len(updated_book["files"]) == 2
|
||||
|
||||
for file_metadata in updated_book["files"]:
|
||||
assert "hash" in file_metadata
|
||||
|
||||
epub_file = next(f for f in updated_book["files"] if f["path"].endswith(".epub"))
|
||||
pdf_file = next(f for f in updated_book["files"] if f["path"].endswith(".pdf"))
|
||||
|
||||
assert epub_file["hash"] == first_book["hash"]
|
||||
assert pdf_file["hash"] == second_book["hash"]
|
||||
Reference in New Issue
Block a user