109 lines
3.7 KiB
Python
109 lines
3.7 KiB
Python
from typing import Callable, Optional
|
|
|
|
import pytest
|
|
|
|
from bibapi import sru
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_sru_xml() -> bytes:
|
|
"""Return a small SRU searchRetrieveResponse (MARCXML) as bytes.
|
|
|
|
Tests can use this raw bytes payload to simulate SRU responses.
|
|
"""
|
|
xml = b"""<?xml version="1.0" encoding="UTF-8"?>
|
|
<zs:searchRetrieveResponse xmlns:zs="http://www.loc.gov/zing/srw/"
|
|
xmlns:marc="http://www.loc.gov/MARC21/slim">
|
|
<zs:version>1.1</zs:version>
|
|
<zs:numberOfRecords>1</zs:numberOfRecords>
|
|
<zs:records>
|
|
<zs:record>
|
|
<zs:recordSchema>marcxml</zs:recordSchema>
|
|
<zs:recordPacking>xml</zs:recordPacking>
|
|
<zs:recordData>
|
|
<marc:record>
|
|
<marc:leader>-----nam a22</marc:leader>
|
|
<marc:controlfield tag="001">PPN123</marc:controlfield>
|
|
<marc:datafield tag="245" ind1=" " ind2=" ">
|
|
<marc:subfield code="a">Example Title</marc:subfield>
|
|
<marc:subfield code="b">Subtitle</marc:subfield>
|
|
</marc:datafield>
|
|
<marc:datafield tag="264" ind1=" " ind2="1">
|
|
<marc:subfield code="c">2001</marc:subfield>
|
|
<marc:subfield code="b">Example Publisher</marc:subfield>
|
|
</marc:datafield>
|
|
</marc:record>
|
|
</zs:recordData>
|
|
<zs:recordPosition>1</zs:recordPosition>
|
|
</zs:record>
|
|
</zs:records>
|
|
<zs:echoedSearchRetrieveRequest>
|
|
<zs:version>1.1</zs:version>
|
|
<zs:query>pica.tit=Example</zs:query>
|
|
<zs:maximumRecords>10</zs:maximumRecords>
|
|
<zs:recordPacking>xml</zs:recordPacking>
|
|
<zs:recordSchema>marcxml</zs:recordSchema>
|
|
</zs:echoedSearchRetrieveRequest>
|
|
</zs:searchRetrieveResponse>
|
|
"""
|
|
return xml
|
|
|
|
|
|
@pytest.fixture
|
|
def sru_api_factory(monkeypatch) -> Callable[[str, Optional[bytes]], sru.Api]:
|
|
"""Factory to create an `sru.Api` (or subclass) with network calls mocked.
|
|
|
|
Usage:
|
|
def test_x(sru_api_factory, sample_sru_xml):
|
|
api = sru_api_factory('SWB', sample_sru_xml)
|
|
books = api.getBooks(['pica.tit=Example'])
|
|
|
|
The fixture monkeypatches requests.Session.get on the Api instance to return
|
|
a fake Response with the provided bytes payload. If `response_bytes` is
|
|
None the real network call will be performed (not recommended in unit tests).
|
|
"""
|
|
|
|
def _make(site: str, response_bytes: Optional[bytes] = None) -> sru.Api:
|
|
mapping = {"SWB": sru.SWB, "DNB": sru.Api}
|
|
if site == "SWB":
|
|
api = sru.SWB()
|
|
elif site == "DNB":
|
|
# DNB Api class is the base Api configured differently in sru module
|
|
api = sru.Api(
|
|
sru.DNBData.NAME.value,
|
|
sru.DNBData.URL.value,
|
|
sru.DNBData.ARGSCHEMA.value,
|
|
)
|
|
else:
|
|
# allow custom site/url/prefix via tuple passed as site: (site, url, prefix)
|
|
if isinstance(site, tuple) and len(site) == 3:
|
|
api = sru.Api(site[0], site[1], site[2])
|
|
else:
|
|
raise ValueError("Unknown site for factory: %r" % (site,))
|
|
|
|
if response_bytes is not None:
|
|
|
|
class FakeResp:
|
|
status_code = 200
|
|
|
|
def __init__(self, content: bytes):
|
|
self.content = content
|
|
|
|
def fake_get(url, headers=None, timeout=None):
|
|
return FakeResp(response_bytes)
|
|
|
|
# Patch only this instance's session.get
|
|
monkeypatch.setattr(api._session, "get", fake_get)
|
|
|
|
return api
|
|
|
|
return _make
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture
|
|
def sru_data():
|
|
return {"bib_id": 20735, "sigil": "Frei129"}
|