Skip to content

Commit 7682cad

Browse files
authored
Merge pull request seanboyce#63 from singhgarima/dev
(Issue seanboyce#59 and Issue seanboyce#54) Allow scanning a book without Author
2 parents 8ba68c0 + f1379cb commit 7682cad

8 files changed

Lines changed: 591 additions & 190 deletions

File tree

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ cover/
6565
local_settings.py
6666
db.sqlite3
6767
db.sqlite3-journal
68+
sql_app.db
6869

6970
# Flask stuff:
7071
instance/
@@ -196,4 +197,6 @@ pyrightconfig.json
196197
# End of https://www.toptal.com/developers/gitignore/api/python,visualstudiocode
197198

198199
config/
199-
secret_key.txt
200+
secret_key.txt
201+
sign_key.txt
202+
verify_key.txt

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ aiofiles==24.1.0
1515
pillow==12.2.0
1616
uuid==1.30
1717
requests==2.32.2
18+
responses==0.25.8

tests/routers/books/__init__.py

Whitespace-only changes.
Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
from urllib.parse import urlencode
2+
3+
from pytest import MonkeyPatch
4+
import responses
5+
import pytest
6+
7+
from ubiblio.routers.books.book_metadata_client import BookMetadataClient
8+
9+
10+
class TestBookMetadataClientGoogleBooksByIsbn:
11+
@responses.activate
12+
def test_google_books_by_isbn_should_return_book_metadata(self, monkeypatch: MonkeyPatch) -> None:
13+
# Arrange
14+
isbn = "9780123456789"
15+
api_key = "test-api-key"
16+
monkeypatch.setattr(
17+
"ubiblio.routers.books.book_metadata_client.GOOGLE_BOOKS_API_KEY", api_key
18+
)
19+
query = urlencode({"q": f"+isbn:{isbn}", "key": api_key})
20+
url = f"{BookMetadataClient.GOOGLE_BOOKS_API}?{query}"
21+
responses.add(
22+
responses.GET,
23+
url,
24+
json={
25+
"items": [
26+
{
27+
"volumeInfo": {
28+
"title": "Test Title",
29+
"authors": ["A. Reader"],
30+
"description": "A fine book.",
31+
}
32+
}
33+
]
34+
},
35+
status=200,
36+
)
37+
38+
client = BookMetadataClient()
39+
40+
# Act
41+
book, status = client.google_books_by_isbn(isbn)
42+
43+
# Assert
44+
assert status == 200
45+
assert book == {
46+
"Title": "Test Title",
47+
"Author": "A. Reader",
48+
"Summary": "A fine book."
49+
}
50+
assert len(responses.calls) == 1
51+
assert responses.calls[0].request.url == url
52+
53+
@responses.activate
54+
def test_google_books_by_isbn_should_return_error_when_api_key_is_missing(self, monkeypatch: MonkeyPatch) -> None:
55+
# Arrange
56+
isbn = "9780123456789"
57+
monkeypatch.setattr(
58+
"ubiblio.routers.books.book_metadata_client.GOOGLE_BOOKS_API_KEY", None
59+
)
60+
client = BookMetadataClient()
61+
62+
# Act
63+
book, status = client.google_books_by_isbn(isbn)
64+
65+
# Assert
66+
assert status is None
67+
assert book == {}
68+
69+
@responses.activate
70+
def test_google_books_by_isbn_should_return_error_when_response_is_not_ok(self, monkeypatch: MonkeyPatch) -> None:
71+
# Arrange
72+
isbn = "9780123456789"
73+
api_key = "test-api-key"
74+
monkeypatch.setattr(
75+
"ubiblio.routers.books.book_metadata_client.GOOGLE_BOOKS_API_KEY", api_key
76+
)
77+
query = urlencode({"q": f"+isbn:{isbn}", "key": api_key})
78+
url = f"{BookMetadataClient.GOOGLE_BOOKS_API}?{query}"
79+
responses.add(
80+
responses.GET,
81+
url,
82+
json={"error": "notfound", "key": "/isbn/invalid"},
83+
status=404,
84+
)
85+
86+
client = BookMetadataClient()
87+
88+
# Act
89+
book, status = client.google_books_by_isbn(isbn)
90+
91+
# Assert
92+
assert status == 404
93+
assert book == {}
94+
95+
96+
class TestBookMetadataClientOpenLibraryByIsbn:
97+
@responses.activate
98+
def test_open_library_by_isbn_should_return_book_metadata(self, monkeypatch: MonkeyPatch) -> None:
99+
# Arrange
100+
isbn = "9780123456789"
101+
102+
responses.add(
103+
responses.GET,
104+
f"{BookMetadataClient.OPEN_LIBRARY_API}/api/books?bibkeys=9780123456789&format=json&jscmd=details",
105+
json={
106+
f"{isbn}": {
107+
"details": {
108+
"title": "Test Title",
109+
"authors": [
110+
{
111+
"key": "/authors/OL1607920A",
112+
"name": "A. Reader"
113+
}
114+
],
115+
"description": {
116+
"value": "A fine book.",
117+
}
118+
}
119+
}
120+
},
121+
status=200,
122+
)
123+
124+
client = BookMetadataClient()
125+
126+
# Act
127+
book, status = client.open_library_by_isbn(isbn)
128+
# Assert
129+
assert status == 200
130+
assert book == {
131+
"Title": "Test Title",
132+
"Author": "A. Reader",
133+
"Summary": "A fine book.",
134+
}
135+
assert len(responses.calls) == 1
136+
assert responses.calls[0].request.url == f"{BookMetadataClient.OPEN_LIBRARY_API}/api/books?bibkeys={isbn}&format=json&jscmd=details"
137+
138+
@responses.activate
139+
@pytest.mark.parametrize("arthur_value", [[], [{}], [{"key": "/authors/OL1607920A"}]])
140+
def test_open_library_by_isbn_should_return_book_metadata_even_if_no_author_is_found(self, arthur_value: list[dict[str, str]]) -> None:
141+
# Arrange
142+
isbn = "9780123456789"
143+
144+
responses.add(
145+
responses.GET,
146+
f"{BookMetadataClient.OPEN_LIBRARY_API}/api/books?bibkeys={isbn}&format=json&jscmd=details",
147+
json={
148+
f"{isbn}": {
149+
"details": {
150+
"title": "Test Title",
151+
"authors": arthur_value,
152+
"description": {
153+
"value": "A fine book.",
154+
}
155+
}
156+
}
157+
},
158+
status=200,
159+
)
160+
161+
client = BookMetadataClient()
162+
163+
# Act
164+
book, status = client.open_library_by_isbn(isbn)
165+
166+
# Assert
167+
assert status == 200
168+
assert book == {
169+
"Title": "Test Title",
170+
"Summary": "A fine book.",
171+
"Author": "",
172+
}
173+
assert len(responses.calls) == 1
174+
assert responses.calls[0].request.url == f"{BookMetadataClient.OPEN_LIBRARY_API}/api/books?bibkeys={isbn}&format=json&jscmd=details"
175+
176+
@responses.activate
177+
def test_open_library_by_isbn_should_return_book_metadata_even_if_no_description_is_found(self, monkeypatch: MonkeyPatch) -> None:
178+
# Arrange
179+
isbn = "9780123456789"
180+
181+
responses.add(
182+
responses.GET,
183+
f"{BookMetadataClient.OPEN_LIBRARY_API}/api/books?bibkeys={isbn}&format=json&jscmd=details",
184+
json={
185+
f"{isbn}": {
186+
"details": {
187+
"title": "Test Title",
188+
}
189+
}
190+
},
191+
status=200,
192+
)
193+
194+
client = BookMetadataClient()
195+
196+
# Act
197+
book, status = client.open_library_by_isbn(isbn)
198+
199+
# Assert
200+
assert status == 200
201+
assert book == {
202+
"Title": "Test Title",
203+
"Summary": "",
204+
"Author": "",
205+
}
206+
assert len(responses.calls) == 1
207+
assert responses.calls[0].request.url == f"{BookMetadataClient.OPEN_LIBRARY_API}/api/books?bibkeys={isbn}&format=json&jscmd=details"
208+
209+
@responses.activate
210+
def test_open_library_by_isbn_should_return_error_when_response_is_not_ok(self) -> None:
211+
# Arrange
212+
isbn = "9780123456789"
213+
responses.add(
214+
responses.GET,
215+
f"{BookMetadataClient.OPEN_LIBRARY_API}/api/books?bibkeys={isbn}&format=json&jscmd=details",
216+
json={},
217+
status=404,
218+
)
219+
client = BookMetadataClient()
220+
221+
# Act
222+
book, status = client.open_library_by_isbn(isbn)
223+
224+
# Assert
225+
assert status == 404
226+
assert book == {}
227+
228+
229+
class TestBookMetadataClientOpenWikiByIsbn:
230+
@responses.activate
231+
def test_open_wiki_by_isbn_should_return_book_metadata(self) -> None:
232+
# Arrange
233+
isbn = "9780123456789"
234+
responses.add(
235+
responses.GET,
236+
f"{BookMetadataClient.OPEN_WIKI_API}isbn/{isbn}.json",
237+
json=[
238+
{
239+
"key": "F5GJ7RVZ",
240+
"title": "Effective Book",
241+
"author": [
242+
[
243+
"First",
244+
"Last"
245+
]
246+
]
247+
}
248+
]
249+
250+
)
251+
client = BookMetadataClient()
252+
253+
# Act
254+
book, status = client.open_wiki_by_isbn(isbn)
255+
256+
# Assert
257+
assert status == 200
258+
assert book == {
259+
"Title": "Effective Book",
260+
"Author": "First Last",
261+
"Summary": "",
262+
}
263+
assert len(responses.calls) == 1
264+
assert responses.calls[0].request.url == f"{BookMetadataClient.OPEN_WIKI_API}isbn/{isbn}.json"
265+
266+
@responses.activate
267+
def test_open_wiki_by_isbn_should_return_error_when_response_is_not_ok(self) -> None:
268+
# Arrange
269+
isbn = "9780123456789"
270+
responses.add(
271+
responses.GET,
272+
f"{BookMetadataClient.OPEN_WIKI_API}isbn/{isbn}.json",
273+
json={},
274+
status=404,
275+
)
276+
client = BookMetadataClient()
277+
278+
# Act
279+
book, status = client.open_wiki_by_isbn(isbn)
280+
# Assert
281+
assert status == 404
282+
assert book == {}

ubiblio/routers/books/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .api import router
2+
3+
__all__ = ["router"]

0 commit comments

Comments
 (0)