241 lines
7.4 KiB
Python
241 lines
7.4 KiB
Python
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from books.models import Author, Book
|
|
from scrobbles.tasks import enrich_book_metadata
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@patch("books.models.lookup_book_from_ol")
|
|
def test_enrich_book_metadata_tags_success(mock_lookup):
|
|
mock_lookup.return_value = {
|
|
"title": "Test Book",
|
|
"openlibrary_id": "OL12345",
|
|
"summary": "A test summary",
|
|
"authors": ["Test Author"],
|
|
}
|
|
book = Book.objects.create(title="Test Book", pages=100)
|
|
|
|
enrich_book_metadata(book.id)
|
|
|
|
book.refresh_from_db()
|
|
assert book.openlibrary_id == "OL12345"
|
|
assert book.summary == "A test summary"
|
|
assert book.authors.filter(name="Test Author").exists()
|
|
assert "book-enriched" in book.tags.names()
|
|
assert "enrichment-failed" not in book.tags.names()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@patch("books.models.lookup_book_from_ol", return_value={})
|
|
@patch("books.models.lookup_comic_from_locg", return_value={})
|
|
@patch("books.models.lookup_book_from_google", return_value={})
|
|
def test_enrich_book_metadata_tags_failure_when_no_match(
|
|
mock_google, mock_locg, mock_ol
|
|
):
|
|
book = Book.objects.create(title="Unknown Book", pages=100)
|
|
|
|
enrich_book_metadata(book.id)
|
|
|
|
book.refresh_from_db()
|
|
assert "book-enriched" not in book.tags.names()
|
|
assert "enrichment-failed" in book.tags.names()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@patch("books.models.lookup_book_from_ol", side_effect=Exception("boom"))
|
|
@patch("books.models.lookup_comic_from_locg", side_effect=Exception("boom"))
|
|
@patch("books.models.lookup_book_from_google", side_effect=Exception("boom"))
|
|
def test_enrich_book_metadata_tags_failure_on_exception(
|
|
mock_google, mock_locg, mock_ol
|
|
):
|
|
book = Book.objects.create(title="Test Book", pages=100)
|
|
|
|
enrich_book_metadata(book.id)
|
|
|
|
book.refresh_from_db()
|
|
assert "book-enriched" not in book.tags.names()
|
|
assert "enrichment-failed" in book.tags.names()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_enrich_book_metadata_skips_missing_book():
|
|
enrich_book_metadata(99999)
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_enrich_book_metadata_preserves_koreader_title_on_mismatch():
|
|
from unittest.mock import Mock
|
|
|
|
with patch("books.models.lookup_book_from_ol") as mock_lookup:
|
|
mock_lookup.return_value = {
|
|
"title": "Completely Different Title",
|
|
"openlibrary_id": "OL999",
|
|
}
|
|
book = Book.objects.create(title="Test Book", pages=100)
|
|
|
|
enrich_book_metadata(book.id)
|
|
|
|
book.refresh_from_db()
|
|
assert book.title == "Test Book"
|
|
assert book.openlibrary_id == "OL999"
|
|
assert "book-enriched" in book.tags.names()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_create_book_from_row_dispatches_enrichment():
|
|
from books.koreader import create_book_from_row
|
|
|
|
row = [
|
|
1,
|
|
"Test Book - Author Name",
|
|
"Test Author",
|
|
0,
|
|
0,
|
|
0,
|
|
300,
|
|
"",
|
|
"",
|
|
"abc123def456",
|
|
3600,
|
|
120,
|
|
]
|
|
with patch("scrobbles.tasks.enrich_book_metadata.delay") as mock_delay:
|
|
book = create_book_from_row(row)
|
|
mock_delay.assert_called_once_with(book.id)
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_fix_metadata_does_not_crash_on_locg_data_with_isbn():
|
|
from unittest.mock import Mock
|
|
|
|
with patch("books.models.lookup_book_from_ol", return_value={}):
|
|
with patch("books.models.lookup_comic_from_locg") as mock_locg:
|
|
mock_locg.return_value = {
|
|
"title": "Test Book",
|
|
"summary": "A comic summary",
|
|
"isbn": "1234567890",
|
|
}
|
|
book = Book.objects.create(title="Test Book", pages=100)
|
|
enriched = book.fix_metadata()
|
|
assert enriched is True
|
|
book.refresh_from_db()
|
|
assert book.summary == "A comic summary"
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_find_or_create_returns_existing_by_title():
|
|
book = Book.objects.create(original_title="Dune", title="Dune")
|
|
with patch("books.models.lookup_book_from_google") as mock_google:
|
|
found = Book.find_or_create("Dune")
|
|
assert found.id == book.id
|
|
mock_google.assert_not_called()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@patch("books.models.lookup_comic_from_comicvine", return_value={})
|
|
@patch("books.models.lookup_book_from_ol", return_value={})
|
|
@patch("books.models.lookup_book_from_google")
|
|
def test_find_or_create_reuses_existing_by_google_books_id(
|
|
mock_google, mock_ol, mock_comicvine
|
|
):
|
|
existing = Book.objects.create(
|
|
original_title="Dune - 50th Anniversary",
|
|
title="Dune",
|
|
google_books_id="gbooks_123",
|
|
)
|
|
mock_google.return_value = {
|
|
"title": "Dune",
|
|
"google_books_id": "gbooks_123",
|
|
"authors": ["Frank Herbert"],
|
|
"pages": 412,
|
|
}
|
|
|
|
found = Book.find_or_create("Dune")
|
|
|
|
assert found.id == existing.id
|
|
assert Book.objects.filter(original_title="Dune").count() == 0
|
|
assert Book.objects.count() == 1
|
|
assert found.authors.filter(name="Frank Herbert").exists()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@patch("books.models.lookup_comic_from_comicvine", return_value={})
|
|
@patch("books.models.lookup_book_from_ol", return_value={})
|
|
@patch("books.models.lookup_book_from_google")
|
|
def test_find_or_create_matches_by_title_and_author(
|
|
mock_google, mock_ol, mock_comicvine
|
|
):
|
|
author = Author.objects.create(name="Frank Herbert")
|
|
existing = Book.objects.create(original_title="Dune - Part 1", title="Dune")
|
|
existing.authors.add(author)
|
|
mock_google.return_value = {
|
|
"title": "Dune",
|
|
"authors": ["Frank Herbert"],
|
|
"pages": 412,
|
|
}
|
|
|
|
found = Book.find_or_create("Dune", author="Frank Herbert")
|
|
|
|
assert found.id == existing.id
|
|
assert Book.objects.count() == 1
|
|
|
|
|
|
@pytest.mark.django_db
|
|
@patch("books.models.lookup_comic_from_comicvine", return_value={})
|
|
@patch("books.models.lookup_book_from_ol", return_value={})
|
|
@patch("books.models.lookup_book_from_google")
|
|
def test_find_or_create_stores_google_books_id(mock_google, mock_ol, mock_comicvine):
|
|
mock_google.return_value = {
|
|
"title": "Dune",
|
|
"google_books_id": "gbooks_456",
|
|
"authors": ["Frank Herbert"],
|
|
"pages": 412,
|
|
}
|
|
|
|
book = Book.find_or_create("Dune")
|
|
|
|
assert book.google_books_id == "gbooks_456"
|
|
assert book.authors.filter(name="Frank Herbert").exists()
|
|
|
|
|
|
@patch("books.sources.google.requests.get")
|
|
def test_lookup_book_from_google_captures_volume_id(mock_get):
|
|
from books.sources.google import lookup_book_from_google
|
|
|
|
mock_response = mock_get.return_value
|
|
mock_response.status_code = 200
|
|
mock_response.content = b"""
|
|
{"items": [
|
|
{
|
|
"id": "gbooks_789",
|
|
"volumeInfo": {
|
|
"title": "Dune",
|
|
"authors": ["Frank Herbert"],
|
|
"publishedDate": "1965",
|
|
"pageCount": 412
|
|
}
|
|
}
|
|
]}
|
|
"""
|
|
|
|
result = lookup_book_from_google("Dune")
|
|
|
|
assert result["google_books_id"] == "gbooks_789"
|
|
assert result["authors"] == ["Frank Herbert"]
|
|
assert result["first_publish_year"] == 1965
|
|
|
|
|
|
@patch("books.sources.google.requests.get")
|
|
def test_lookup_book_from_google_includes_author_in_query(mock_get):
|
|
from books.sources.google import lookup_book_from_google
|
|
|
|
mock_response = mock_get.return_value
|
|
mock_response.status_code = 200
|
|
mock_response.content = b'{"items": []}'
|
|
|
|
lookup_book_from_google("Dune", author="Frank Herbert")
|
|
|
|
args, kwargs = mock_get.call_args
|
|
assert "inauthor:Frank Herbert" in kwargs["params"]["q"]
|