Skip to content

Commit f89a200

Browse files
committed
feat: Add contract test for /search/authors endpoint.
1 parent 8fa3aa9 commit f89a200

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

openlibrary/tests/fastapi/test_api_contract.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ def webpy_client(mock_work_search, mock_fulltext_search, mock_run_solr_query):
9696
"""
9797
from openlibrary.plugins.inside.code import search_inside_json
9898
from openlibrary.plugins.worksearch.code import (
99+
author_search_json,
99100
list_search_json,
100101
search_json,
101102
subject_search_json,
@@ -111,6 +112,8 @@ def webpy_client(mock_work_search, mock_fulltext_search, mock_run_solr_query):
111112
'subject_search_json',
112113
'/search/lists',
113114
'list_search_json',
115+
'/search/authors',
116+
'author_search_json',
114117
)
115118

116119
# Create app with all handlers in the global namespace
@@ -121,6 +124,7 @@ def webpy_client(mock_work_search, mock_fulltext_search, mock_run_solr_query):
121124
'search_inside_json': search_inside_json,
122125
'subject_search_json': subject_search_json,
123126
'list_search_json': list_search_json,
127+
'author_search_json': author_search_json,
124128
},
125129
)
126130

@@ -306,6 +310,79 @@ def test_both_search_inside_endpoints_call_search_with_same_params(
306310
f"FastAPI={fastapi_val}, webpy={webpy_val}"
307311
)
308312

313+
@pytest.mark.parametrize(
314+
('params', 'description'),
315+
[
316+
({'q': 'shakespeare'}, 'basic query'),
317+
({'q': 'twain', 'offset': '5', 'limit': '10'}, 'pagination'),
318+
],
319+
)
320+
def test_both_authors_endpoints_call_search_with_same_params(
321+
self,
322+
fastapi_client,
323+
webpy_client,
324+
mock_async_run_solr_query,
325+
mock_run_solr_query,
326+
params,
327+
description,
328+
):
329+
"""Verify both webpy and FastAPI search/authors endpoints pass equivalent parameters.
330+
331+
This test makes real HTTP requests to both FastAPI and webpy search/authors endpoints,
332+
then compares the arguments passed to their respective solr query functions.
333+
"""
334+
query_string = urlencode(params, doseq=True)
335+
336+
# === Call FastAPI endpoint ===
337+
fastapi_response = fastapi_client.get(f'/search/authors.json?{query_string}')
338+
assert fastapi_response.status_code == 200, f"FastAPI failed for: {description}"
339+
340+
mock_async_run_solr_query.assert_called_once()
341+
fastapi_call_args = mock_async_run_solr_query.call_args
342+
343+
# === Call webpy endpoint ===
344+
webpy_response = webpy_client.get(f'/search/authors?{query_string}')
345+
assert webpy_response.status_code == 200, f"webpy failed for: {description}"
346+
347+
mock_run_solr_query.assert_called_once()
348+
webpy_call_args = mock_run_solr_query.call_args
349+
350+
# === Compare the call arguments ===
351+
# Both call their respective solr query functions with scheme, param dict, and kwargs
352+
353+
# Compare param dict (second positional arg)
354+
fastapi_param = fastapi_call_args[0][1]
355+
webpy_param = webpy_call_args[0][1]
356+
357+
for key in ['q']:
358+
fastapi_val = fastapi_param.get(key)
359+
webpy_val = webpy_param.get(key)
360+
assert fastapi_val == webpy_val, (
361+
f"Parameter '{key}' mismatch for {description}: "
362+
f"FastAPI={fastapi_val}, webpy={webpy_val}"
363+
)
364+
365+
# Compare kwargs
366+
fastapi_kwargs = {
367+
k: v for k, v in fastapi_call_args[1].items() if k not in ['scheme']
368+
}
369+
webpy_kwargs = {
370+
k: v for k, v in webpy_call_args[1].items() if k not in ['scheme']
371+
}
372+
373+
for key in ['offset', 'rows', 'fields', 'sort', 'request_label']:
374+
fastapi_val = fastapi_kwargs.get(key)
375+
webpy_val = webpy_kwargs.get(key)
376+
377+
# Handle offset: FastAPI may pass None, webpy defaults to 0
378+
if key == 'offset' and fastapi_val is None and webpy_val == 0:
379+
continue
380+
381+
assert fastapi_val == webpy_val, (
382+
f"Parameter '{key}' mismatch for {description}: "
383+
f"FastAPI={fastapi_val}, webpy={webpy_val}"
384+
)
385+
309386
@pytest.mark.parametrize(
310387
('params', 'description'),
311388
[

0 commit comments

Comments
 (0)