from rdflib import Graph, Namespace
from http.server import BaseHTTPRequestHandler
from urllib.error import HTTPError
from .testutils import SimpleHTTPMock, MockHTTPResponse, ctx_http_server, GraphHelper
import unittest
"""
Test that correct content negoation headers are passed
by graph.parse
"""
xmltestdoc = """
"""
n3testdoc = """@prefix : .
:a :b :c .
"""
nttestdoc = " .\n"
class ContentNegotiationHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200, "OK")
# fun fun fun parsing accept header.
acs = self.headers["Accept"].split(",")
acq = [x.split(";") for x in acs if ";" in x]
acn = [(x, "q=1") for x in acs if ";" not in x]
acs = [(x[0], float(x[1].strip()[2:])) for x in acq + acn]
ac = sorted(acs, key=lambda x: x[1])
ct = ac[-1]
if "application/rdf+xml" in ct:
rct = "application/rdf+xml"
content = xmltestdoc
elif "text/n3" in ct:
rct = "text/n3"
content = n3testdoc
elif "text/plain" in ct:
rct = "text/plain"
content = nttestdoc
self.send_header("Content-type", rct)
self.end_headers()
self.wfile.write(content.encode("utf-8"))
def log_message(self, *args):
pass
class TestGraphHTTP(unittest.TestCase):
def content_negotiation(self) -> None:
EG = Namespace("http://example.org/")
expected = Graph()
expected.add((EG["a"], EG["b"], EG["c"]))
expected_triples = GraphHelper.triple_set(expected)
with ctx_http_server(ContentNegotiationHandler) as server:
(host, port) = server.server_address
url = f"http://{host}:{port}/foo"
for format in ("xml", "n3", "nt"):
graph = Graph()
graph.parse(url, format=format)
self.assertEqual(expected_triples, GraphHelper.triple_set(graph))
def test_3xx(self) -> None:
EG = Namespace("http://example.com/")
expected = Graph()
expected.add((EG["a"], EG["b"], EG["c"]))
expected_triples = GraphHelper.triple_set(expected)
httpmock = SimpleHTTPMock()
with ctx_http_server(httpmock.Handler) as server:
(host, port) = server.server_address
url = f"http://{host}:{port}/"
for idx in range(3):
httpmock.do_get_responses.append(
MockHTTPResponse(
302, "FOUND", "".encode(), {"Location": [f"{url}loc/302/{idx}"]}
)
)
for idx in range(3):
httpmock.do_get_responses.append(
MockHTTPResponse(
303,
"See Other",
"".encode(),
{"Location": [f"{url}loc/303/{idx}"]},
)
)
for idx in range(3):
httpmock.do_get_responses.append(
MockHTTPResponse(
308,
"Permanent Redirect",
"".encode(),
{"Location": [f"{url}loc/308/{idx}"]},
)
)
httpmock.do_get_responses.append(
MockHTTPResponse(
200,
"OK",
f"<{EG['a']}> <{EG['b']}> <{EG['c']}>.".encode(),
{"Content-Type": ["text/turtle"]},
)
)
graph = Graph()
graph.parse(location=url, format="turtle")
self.assertEqual(expected_triples, GraphHelper.triple_set(graph))
httpmock.do_get_mock.assert_called()
assert len(httpmock.do_get_requests) == 10
for request in httpmock.do_get_requests:
self.assertRegex(request.headers.get("Accept"), "text/turtle")
request_paths = [request.path for request in httpmock.do_get_requests]
self.assertEqual(
request_paths,
[
"/",
"/loc/302/0",
"/loc/302/1",
"/loc/302/2",
"/loc/303/0",
"/loc/303/1",
"/loc/303/2",
"/loc/308/0",
"/loc/308/1",
"/loc/308/2",
],
)
def test_5xx(self):
httpmock = SimpleHTTPMock()
with ctx_http_server(httpmock.Handler) as server:
(host, port) = server.server_address
url = f"http://{host}:{port}/"
response = MockHTTPResponse(500, "Internal Server Error", "".encode(), {})
httpmock.do_get_responses.append(response)
graph = Graph()
with self.assertRaises(HTTPError) as raised:
graph.parse(location=url, format="turtle")
self.assertEqual(raised.exception.code, 500)
if __name__ == "__main__":
unittest.main()