Skip to content

Commit 2ce4e2b

Browse files
authored
test: content-type handling with SPARQLStore + CONSTRUCT queries (#2092)
Confirm various content type values are handled correctly with CONSTRUCT queries and SPARQLStore. This aims to confirm that #1195 is fixed.
1 parent 3a9076d commit 2ce4e2b

File tree

4 files changed

+157
-38
lines changed

4 files changed

+157
-38
lines changed

test/conftest.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
pytest.register_assert_rewrite("test.utils")
44

5+
from typing import Generator # noqa: E402
6+
57
from rdflib import Graph
68

79
from .data import TEST_DATA_DIR
810
from .utils.earl import EARLReporter # noqa: E402
11+
from .utils.httpservermock import ServedBaseHTTPServerMock # noqa: E402
912

1013
pytest_plugins = [EARLReporter.__module__]
1114

@@ -16,3 +19,17 @@
1619
@pytest.fixture(scope="session")
1720
def rdfs_graph() -> Graph:
1821
return Graph().parse(TEST_DATA_DIR / "defined_namespaces/rdfs.ttl", format="turtle")
22+
23+
24+
@pytest.fixture(scope="session")
25+
def session_httpmock() -> Generator[ServedBaseHTTPServerMock, None, None]:
26+
with ServedBaseHTTPServerMock() as httpmock:
27+
yield httpmock
28+
29+
30+
@pytest.fixture(scope="function")
31+
def function_httpmock(
32+
session_httpmock: ServedBaseHTTPServerMock,
33+
) -> Generator[ServedBaseHTTPServerMock, None, None]:
34+
session_httpmock.reset()
35+
yield session_httpmock

test/test_graph/test_graph_http.py

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
ServedBaseHTTPServerMock,
1010
ctx_http_server,
1111
)
12-
from typing import Generator
1312
from urllib.error import HTTPError
1413

1514
import pytest
@@ -232,24 +231,10 @@ def test_5xx(self):
232231
assert raised.value.code == 500
233232

234233

235-
@pytest.fixture(scope="module")
236-
def module_httpmock() -> Generator[ServedBaseHTTPServerMock, None, None]:
237-
with ServedBaseHTTPServerMock() as httpmock:
238-
yield httpmock
239-
240-
241-
@pytest.fixture(scope="function")
242-
def httpmock(
243-
module_httpmock: ServedBaseHTTPServerMock,
244-
) -> Generator[ServedBaseHTTPServerMock, None, None]:
245-
module_httpmock.reset()
246-
yield module_httpmock
247-
248-
249-
def test_iri_source(httpmock: ServedBaseHTTPServerMock) -> None:
234+
def test_iri_source(function_httpmock: ServedBaseHTTPServerMock) -> None:
250235
diverse_triples_path = TEST_DATA_DIR / "variants/diverse_triples.ttl"
251236

252-
httpmock.responses[MethodName.GET].append(
237+
function_httpmock.responses[MethodName.GET].append(
253238
MockHTTPResponse(
254239
200,
255240
"OK",
@@ -258,9 +243,9 @@ def test_iri_source(httpmock: ServedBaseHTTPServerMock) -> None:
258243
)
259244
)
260245
g = Graph()
261-
g.parse(f"{httpmock.url}/resource/Almería")
262-
assert httpmock.call_count == 1
246+
g.parse(f"{function_httpmock.url}/resource/Almería")
247+
assert function_httpmock.call_count == 1
263248
GraphHelper.assert_triple_sets_equals(cached_graph((diverse_triples_path,)), g)
264249

265-
req = httpmock.requests[MethodName.GET].pop(0)
250+
req = function_httpmock.requests[MethodName.GET].pop(0)
266251
assert req.path == "/resource/Almer%C3%ADa"

test/test_sparql/test_service.py

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from typing import (
1010
Dict,
1111
FrozenSet,
12-
Generator,
1312
List,
1413
Mapping,
1514
Optional,
@@ -258,20 +257,6 @@ def test_service_node_types():
258257
assert expected == freeze_bindings(results.bindings)
259258

260259

261-
@pytest.fixture(scope="module")
262-
def module_httpmock() -> Generator[ServedBaseHTTPServerMock, None, None]:
263-
with ServedBaseHTTPServerMock() as httpmock:
264-
yield httpmock
265-
266-
267-
@pytest.fixture(scope="function")
268-
def httpmock(
269-
module_httpmock: ServedBaseHTTPServerMock,
270-
) -> Generator[ServedBaseHTTPServerMock, None, None]:
271-
module_httpmock.reset()
272-
yield module_httpmock
273-
274-
275260
@pytest.mark.parametrize(
276261
("response_bindings", "expected_result"),
277262
[
@@ -313,7 +298,7 @@ def httpmock(
313298
],
314299
)
315300
def test_with_mock(
316-
httpmock: ServedBaseHTTPServerMock,
301+
function_httpmock: ServedBaseHTTPServerMock,
317302
response_bindings: List[Dict[str, str]],
318303
expected_result: Union[List[Identifier], Type[Exception]],
319304
) -> None:
@@ -330,12 +315,12 @@ def test_with_mock(
330315
}
331316
}
332317
"""
333-
query = query.replace("REMOTE_URL", httpmock.url)
318+
query = query.replace("REMOTE_URL", function_httpmock.url)
334319
response = {
335320
"head": {"vars": ["var"]},
336321
"results": {"bindings": [{"var": item} for item in response_bindings]},
337322
}
338-
httpmock.responses[MethodName.GET].append(
323+
function_httpmock.responses[MethodName.GET].append(
339324
MockHTTPResponse(
340325
200,
341326
"OK",
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
from __future__ import annotations
2+
3+
import itertools
4+
import logging
5+
from test.utils import GraphHelper
6+
from test.utils.httpservermock import (
7+
MethodName,
8+
MockHTTPResponse,
9+
ServedBaseHTTPServerMock,
10+
)
11+
from typing import Dict, Iterable, List, Optional, Set, Tuple
12+
13+
import pytest
14+
from _pytest.mark.structures import ParameterSet
15+
16+
from rdflib.graph import Graph
17+
18+
19+
def make_test_query_construct_format_cases() -> Iterable[ParameterSet]:
20+
"""
21+
This only tests with application/rdf+xml as other result formats are not
22+
supported.
23+
"""
24+
graphs: List[Tuple[str, Graph]] = [
25+
(
26+
"basic",
27+
Graph().parse(
28+
format="turtle",
29+
data="""
30+
@prefix egdc: <http://example.com/> .
31+
32+
egdc:s0 egdc:p0 egdc:o0;
33+
egdc:p1 egdc:o1;
34+
egdc:p2 "o2";
35+
egdc:p3 _:o3.
36+
37+
38+
egdc:s1 egdc:p4 egdc:o4;
39+
egdc:p5 egdc:o5;
40+
egdc:p6 "o6";
41+
egdc:p7 _:o7;
42+
egdc:p8 _:03.
43+
""",
44+
),
45+
)
46+
]
47+
response_format_encodings: List[Tuple[str, str, Set[Optional[str]]]] = [
48+
(
49+
"application/rdf+xml",
50+
"utf-8",
51+
{
52+
"application/rdf+xml",
53+
"application/rdf+xml;charset=utf-8",
54+
"application/rdf+xml; charset=utf-8",
55+
"application/rdf+xml; charset=UTF-8",
56+
},
57+
),
58+
]
59+
for (mime_type, encoding, content_types), (
60+
graph_label,
61+
expected_graph,
62+
) in itertools.product(response_format_encodings, graphs):
63+
response_body = expected_graph.serialize(format=mime_type, encoding=encoding)
64+
65+
for content_type in content_types:
66+
if content_type is None:
67+
content_type = f"{mime_type};charset={encoding}"
68+
response_headers: Dict[str, List[str]] = {"Content-Type": [content_type]}
69+
yield pytest.param(
70+
expected_graph,
71+
response_body,
72+
response_headers,
73+
id=f"{mime_type}-{encoding}-{graph_label}-ContentType_{content_type}",
74+
)
75+
76+
77+
@pytest.mark.parametrize(
78+
[
79+
"expected_graph",
80+
"response_body",
81+
"response_headers",
82+
],
83+
make_test_query_construct_format_cases(),
84+
)
85+
def test_query_construct_format(
86+
function_httpmock: ServedBaseHTTPServerMock,
87+
expected_graph: Graph,
88+
response_body: bytes,
89+
response_headers: Dict[str, List[str]],
90+
) -> None:
91+
"""
92+
This tests that bindings for a variable named var
93+
"""
94+
logging.debug("response_headers = %s", response_headers)
95+
graph = Graph(
96+
# store_factory(mime_type),
97+
"SPARQLStore",
98+
identifier="http://example.com",
99+
bind_namespaces="none",
100+
)
101+
url = f"{function_httpmock.url}/query"
102+
logging.debug("opening %s", url)
103+
graph.open(url)
104+
query = """
105+
CONSTRUCT {
106+
?s ?p ?o
107+
}
108+
WHERE {
109+
?s ?p ?o
110+
}
111+
"""
112+
113+
function_httpmock.responses[MethodName.GET].append(
114+
MockHTTPResponse(
115+
200,
116+
"OK",
117+
response_body,
118+
response_headers,
119+
)
120+
)
121+
122+
logging.debug("sending query %s", query)
123+
result = graph.query(query)
124+
logging.debug("result = %s", result)
125+
assert result.type == "CONSTRUCT"
126+
assert result.graph is not None
127+
GraphHelper.assert_isomorphic(expected_graph, result.graph)
128+
129+
request = function_httpmock.requests[MethodName.GET].pop()
130+
logging.debug("request = %s", request)
131+
logging.debug("request.headers = %s", request.headers.as_string())
132+
assert request.path_query["query"][0] == query

0 commit comments

Comments
 (0)