Skip to content

Commit

Permalink
new testcase class for testing TripleStore class w/o any actual tripl…
Browse files Browse the repository at this point in the history
…estore running
  • Loading branch information
staffanm committed Oct 16, 2013
1 parent a5b720b commit 845d112
Show file tree
Hide file tree
Showing 12 changed files with 215 additions and 26 deletions.
52 changes: 26 additions & 26 deletions ferenda/triplestore.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def __del__(self):

def add_serialized(self, data, format, context=None):
"""Add the serialized RDF statements in the string *data* directly to the repository."""
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def add_serialized_file(self, filename, format, context=None):
"""Add the serialized RDF statements contained in the file *filename* directly to the repository."""
Expand All @@ -117,7 +117,7 @@ def add_serialized_file(self, filename, format, context=None):
def get_serialized(self, format="nt", context=None):
"""Returns a string containing all statements in the store,
serialized in the selected format. Returns byte string, not unicode array!"""
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def get_serialized_file(self, filename, format="nt", context=None):
"""Saves all statements in the store to *filename*."""
Expand All @@ -139,7 +139,7 @@ def select(self, query, format="sparql"):
:type format: str
"""
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def construct(self, query):
"""
Expand All @@ -148,15 +148,15 @@ def construct(self, query):
:param query: A SPARQL query with all neccessary prefixes defined.
:type query: str
"""
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def triple_count(self, context=None):
"""Returns the number of triples in the repository."""
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def clear(self, context=None):
"""Removes all statements from the repository (without removing the repository as such)."""
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def close(self):
"""Close all connections to the triplestore. Needed if using RDFLib-based triple store, a no-op if using HTTP based stores."""
Expand Down Expand Up @@ -268,7 +268,7 @@ def remove_repository(self):
# returns a string we can pass as store parameter to the ConjunctiveGraph
# constructor, see __init__
def _storeid(self):
raise NotImplementedError
raise NotImplementedError # pragma: no cover

def _getcontextgraph(self, context):
if context:
Expand Down Expand Up @@ -513,8 +513,8 @@ def triple_count(self, context=None):
return int(ret.text)

def ping(self):
requests.get(self.location + '/protocol')
return r.text
resp = requests.get(self.location + '/protocol')
return resp.text

def initialize_repository(self):
# For Sesame:
Expand Down Expand Up @@ -625,20 +625,20 @@ def get_serialized(self, format="nt", context=None):
g.parse(data=named, format=format)
return g.serialize(format=format)

def get_serialized_file(self, filename, format="nt", context=None):
ret = super(FusekiStore, self).get_serialized_file(filename, format, context)
if context is not None:
return ret
else:
context = "urn:x-arq:UnionGraph"
named = super(FusekiStore, self).get_serialized(format, context)
if format == "nt":
# just append
with open(filename, "ab") as fp:
fp.write(named)
else:
g = Graph()
g.parse(filename, format=format)
g.parse(data=named, format=format)
with open(filename, "wb") as fp:
fp.write(g.serialize(format=format))
# def get_serialized_file(self, filename, format="nt", context=None):
# ret = super(FusekiStore, self).get_serialized_file(filename, format, context)
# if context is not None:
# return ret
# else:
# context = "urn:x-arq:UnionGraph"
# named = super(FusekiStore, self).get_serialized(format, context)
# if format == "nt":
# # just append
# with open(filename, "ab") as fp:
# fp.write(named)
# else:
# g = Graph()
# g.parse(filename, format=format)
# g.parse(data=named, format=format)
# with open(filename, "wb") as fp:
# fp.write(g.serialize(format=format))
2 changes: 2 additions & 0 deletions test/files/triplestore/combinedgraph.nt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<http://localhost/publ/dir/2012:36> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rinfo.lagrummet.se/ns/2008/11/rinfo/publ#Direktiv> .
<http://localhost/publ/dir/2012:35> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rinfo.lagrummet.se/ns/2008/11/rinfo/publ#Direktiv> .
4 changes: 4 additions & 0 deletions test/files/triplestore/combinedgraph.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

<http://localhost/publ/dir/2012:36> a <http://rinfo.lagrummet.se/ns/2008/11/rinfo/publ#Direktiv> .
<http://localhost/publ/dir/2012:35> a <http://rinfo.lagrummet.se/ns/2008/11/rinfo/publ#Direktiv> .
1 change: 1 addition & 0 deletions test/files/triplestore/defaultgraph.nt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://localhost/publ/dir/2012:36> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rinfo.lagrummet.se/ns/2008/11/rinfo/publ#Direktiv> .
4 changes: 4 additions & 0 deletions test/files/triplestore/defaultgraph.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

<http://localhost/publ/dir/2012:36> a <http://rinfo.lagrummet.se/ns/2008/11/rinfo/publ#Direktiv> .

1 change: 1 addition & 0 deletions test/files/triplestore/namedgraph.nt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<http://localhost/publ/dir/2012:35> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rinfo.lagrummet.se/ns/2008/11/rinfo/publ#Direktiv> .
3 changes: 3 additions & 0 deletions test/files/triplestore/namedgraph.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

<http://localhost/publ/dir/2012:35> a <http://rinfo.lagrummet.se/ns/2008/11/rinfo/publ#Direktiv> .
1 change: 1 addition & 0 deletions test/files/triplestore/ping.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5
13 changes: 13 additions & 0 deletions test/files/triplestore/triplecount-18.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<sparql xmlns="http://www.w3.org/2005/sparql-results#">
<head>
<variable name=".1"/>
</head>
<results>
<result>
<binding name=".1">
<literal datatype="http://www.w3.org/2001/XMLSchema#integer">18</literal>
</binding>
</result>
</results>
</sparql>
13 changes: 13 additions & 0 deletions test/files/triplestore/triplecount-21.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<sparql xmlns="http://www.w3.org/2005/sparql-results#">
<head>
<variable name=".1"/>
</head>
<results>
<result>
<binding name=".1">
<literal datatype="http://www.w3.org/2001/XMLSchema#integer">21</literal>
</binding>
</result>
</results>
</sparql>
13 changes: 13 additions & 0 deletions test/files/triplestore/triplecount-39.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<sparql xmlns="http://www.w3.org/2005/sparql-results#">
<head>
<variable name=".1"/>
</head>
<results>
<result>
<binding name=".1">
<literal datatype="http://www.w3.org/2001/XMLSchema#integer">39</literal>
</binding>
</result>
</results>
</sparql>
134 changes: 134 additions & 0 deletions test/testTripleStore.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

# the main idea is to just make sure every line of code is run once,
# not to instantiate all eight different
# implementations/configurations and run them all. This will make the
# test code mimick the implementation to some extent, but as the plan
# is to mock all http requests/RDFLib calls (neither of which is
# idempotent), that is sort of unavoidable.

from ferenda.compat import patch, Mock, unittest
from ferenda import util
from ferenda.testutil import FerendaTestCase

# SUT
from ferenda import TripleStore

# we could have a switch in canned() that, if set, actually calls
# the request.get or post methods and writes the result to the
# given files.
def canned(*responses):
returned = []
def makeresponse(*args, **kwargs):
if len(returned) > len(responses):
raise IndexError("Ran out of canned responses after %s calls" % len(returned))
resp = Mock()
resp.status_code = responses[len(returned)][0]
responsefile = responses[len(returned)][1]
if responsefile:
responsefile = "test/files/triplestore/" + responsefile
resp.content = util.readfile(responsefile, "rb")
resp.text = util.readfile(responsefile)
returned.append(True)
return resp
return makeresponse

class UnitTripleStore(unittest.TestCase, FerendaTestCase):

@patch('ferenda.triplestore.util.runcmd')
def test_curl(self, runcmd_mock):
# needs to test add_serialized, add_serialized_file, get_serialized
# and get_serialized_file. We'll patch util.runcmd and make sure that
# the command line is correct. We should also have util.runcmd return
# a non-zero return code once.
# our util.runcmd replacement should, for the get_serialized file,
# create a suitable temp file
store = TripleStore.connect("FUSEKI", "", "", curl=True)

@patch('requests.get', side_effect=canned(("200", "defaultgraph.nt"),
("200", "namedgraph.nt"),
("200", "namedgraph.nt"),
("200", "defaultgraph.ttl"),
("200", "namedgraph.ttl")))
def test_fuseki_get_serialized_file(self, mock_get):
# test 1: imagine that server has data in the default graph
# and in one named graph
rf = util.readfile
store = TripleStore.connect("FUSEKI", "", "")
# test 1.1: Get everything, assert that the result is a combo
store.get_serialized_file("out.nt") # no ctx, will result in 2 gets
self.assertEqual(mock_get.call_count, 2)
self.assertEqual(rf("test/files/triplestore/combinedgraph.nt"),
rf("out.nt"))
# test 1.2: Get only namedgraph, assert that only that is returned
store.get_serialized_file("out.nt", context="namedgraph") # 1 get
self.assertEqual(rf("test/files/triplestore/namedgraph.nt"),
rf("out.nt"))
self.assertEqual(mock_get.call_count, 3)
# test 1.3: Get everything in a different format
store.get_serialized_file("out.ttl", format="turtle") # results in 2 gets
self.assertEqualGraphs("test/files/triplestore/combinedgraph.ttl",
"out.ttl")
self.assertEqual(mock_get.call_count, 5)

@patch('requests.get', side_effect=canned(("200", "namedgraph.nt"),))
def test_fuseki_get_serialized(self, mock_get):
store = TripleStore.connect("FUSEKI", "", "", curl=False)
# test 1: a namedgraph (cases with no context are already run by
# test_fuseki_get_serialized_file)
want = util.readfile("test/files/triplestore/namedgraph.nt", "rb")
got = store.get_serialized(context="namedgraph") # results in single get
self.assertEqual(want, got)

@patch('requests.delete')
def test_fuseki_clear(self, mock_delete):
store = TripleStore.connect("FUSEKI", "", "")
store.clear()
self.assertEqual(mock_delete.call_count, 2)


@patch('requests.get', side_effect=canned(("200", "triplecount-21.xml"),
("200", "triplecount-18.xml"),
("200", "triplecount-18.xml")))
def test_fuseki_triple_count(self, mock_get):
store = TripleStore.connect("FUSEKI", "", "")
self.assertEqual(39, store.triple_count())
self.assertEqual(mock_get.call_count, 2)
self.assertEqual(18, store.triple_count(context="namedgraph"))
self.assertEqual(mock_get.call_count, 3)

@patch('requests.get', side_effect=canned(("200", "ping.txt"),))
def test_sesame_ping(self, mock_get):
store = TripleStore.connect("SESAME", "", "")
self.assertEqual("5", store.ping())

@patch('requests.get', side_effect=canned(("200", "combinedgraph.nt"),
("200", "namedgraph.nt")))
def test_sesame_get_serialized(self, mock_get):
store = TripleStore.connect("SESAME", "", "")
want = util.readfile("test/files/triplestore/combinedgraph.nt", "rb")
got = store.get_serialized()
self.assertEqual(want, got)
self.assertEqual(mock_get.call_count, 1)

want = util.readfile("test/files/triplestore/namedgraph.nt", "rb")
got = store.get_serialized(context="namedgraph") # results in single get
self.assertEqual(want, got)
self.assertEqual(mock_get.call_count, 2)

@patch('requests.post', side_effect=canned((204, None),
(204, None)))
def test_sesame_add_serialized(self, mock_post):
store = TripleStore.connect("SESAME", "", "")
rf = util.readfile
store.add_serialized(rf("test/files/triplestore/defaultgraph.ttl"),
format="turtle")
self.assertEqual(mock_post.call_count, 1)

store.add_serialized(rf("test/files/triplestore/namedgraph.nt"),
format="nt",
context="namedgraph")
self.assertEqual(mock_post.call_count, 2)


0 comments on commit 845d112

Please sign in to comment.