test_lmdb_store.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. import pytest
  2. from shutil import rmtree
  3. from rdflib import Namespace, URIRef
  4. from lakesuperior.store_layouts.ldp_rs.lmdb_store import LmdbStore
  5. @pytest.fixture(scope='class')
  6. def store():
  7. store = LmdbStore('/tmp/test_lmdbstore')
  8. yield store
  9. store.close()
  10. rmtree('/tmp/test_lmdbstore')
  11. @pytest.mark.usefixtures('store')
  12. class TestStoreInit:
  13. '''
  14. Tests for intializing and shutting down store and transactions.
  15. '''
  16. def test_open_close(self, store):
  17. '''
  18. Test opening and closing a store.
  19. '''
  20. tmpstore = LmdbStore('/tmp/test_lmdbstore_init')
  21. assert tmpstore.is_open
  22. tmpstore.close()
  23. assert not tmpstore.is_open
  24. def test_wtxn(self, store):
  25. '''
  26. Test opening and closing the main write transaction.
  27. '''
  28. store.begin()
  29. assert store.is_wtxn_open
  30. store.commit()
  31. assert not store.is_wtxn_open
  32. store.begin()
  33. store.rollback()
  34. assert not store.is_wtxn_open
  35. def test_rollback(self, store):
  36. '''
  37. Test rolling back a transaction.
  38. '''
  39. store.begin()
  40. store.add((
  41. URIRef('urn:nogo:s'), URIRef('urn:nogo:p'), URIRef('urn:nogo:o')))
  42. store.rollback()
  43. res = set(store.triples((None, None, None)))
  44. assert len(res) == 0
  45. @pytest.mark.usefixtures('store')
  46. class TestBasicOps:
  47. '''
  48. High-level tests for basic operations.
  49. '''
  50. def test_create_triple(self, store):
  51. '''
  52. Test creation of a single triple.
  53. '''
  54. store.begin()
  55. store.add((
  56. URIRef('urn:test:s'), URIRef('urn:test:p'), URIRef('urn:test:o')))
  57. store.commit()
  58. import pdb; pdb.set_trace()
  59. res1 = set(store.triples((None, None, None)))
  60. res2 = set(store.triples((
  61. URIRef('urn:test:s'), URIRef('urn:test:p'), URIRef('urn:test:o'))))
  62. assert len(res1) == 1
  63. assert len(res2) == 1
  64. assert (
  65. URIRef('urn:test:s'), URIRef('urn:test:p'),
  66. URIRef('urn:test:o')) in res1 & res2
  67. def test_triple_match_1bound(self, store):
  68. '''
  69. Test triple patterns matching one bound term.
  70. '''
  71. res1 = set(store.triples((URIRef('urn:test:s'), None, None)))
  72. res2 = set(store.triples((None, URIRef('urn:test:p'), None)))
  73. res3 = set(store.triples((None, None, URIRef('urn:test:o'))))
  74. assert res1 == {(
  75. URIRef('urn:test:s'), URIRef('urn:test:p'), URIRef('urn:test:o'))}
  76. assert res2 == res1
  77. assert res3 == res2
  78. def test_triple_match_2bound(self, store):
  79. '''
  80. Test triple patterns matching two bound terms.
  81. '''
  82. res1 = set(store.triples(
  83. (URIRef('urn:test:s'), URIRef('urn:test:p'), None)))
  84. res2 = set(store.triples(
  85. (URIRef('urn:test:s'), None, URIRef('urn:test:o'))))
  86. res3 = set(store.triples(
  87. (None, URIRef('urn:test:p'), URIRef('urn:test:o'))))
  88. assert res1 == {(
  89. URIRef('urn:test:s'), URIRef('urn:test:p'), URIRef('urn:test:o'))}
  90. assert res2 == res1
  91. assert res3 == res2
  92. def test_triple_no_match(self, store):
  93. '''
  94. Test various mismatches.
  95. '''
  96. store.begin()
  97. store.add((
  98. URIRef('urn:test:s'),
  99. URIRef('urn:test:p2'), URIRef('urn:test:o2')))
  100. store.add((
  101. URIRef('urn:test:s3'),
  102. URIRef('urn:test:p3'), URIRef('urn:test:o3')))
  103. store.commit()
  104. res1 = set(store.triples((None, None, None)))
  105. assert len(res1) == 3
  106. res1 = set(store.triples(
  107. (URIRef('urn:test:s2'), URIRef('urn:test:p'), None)))
  108. res2 = set(store.triples(
  109. (URIRef('urn:test:s3'), None, URIRef('urn:test:o'))))
  110. res3 = set(store.triples(
  111. (None, URIRef('urn:test:p3'), URIRef('urn:test:o2'))))
  112. assert len(res1) == len(res2) == len(res3) == 0
  113. def test_remove(self, store):
  114. '''
  115. Test removing one or more triples.
  116. '''
  117. store.begin()
  118. store.remove((URIRef('urn:test:s3'),
  119. URIRef('urn:test:p3'), URIRef('urn:test:o3')))
  120. store.commit()
  121. res1 = set(store.triples((None, None, None)))
  122. assert len(res1) == 2
  123. store.begin()
  124. store.remove((URIRef('urn:test:s'), None, None))
  125. store.commit()
  126. res2 = set(store.triples((None, None, None)))
  127. assert len(res2) == 0
  128. @pytest.mark.usefixtures('store')
  129. class TestBindings:
  130. '''
  131. Tests for namespace bindings.
  132. '''
  133. @pytest.fixture
  134. def bindings(self):
  135. return (
  136. ('ns1', Namespace('http://test.org/ns#')),
  137. ('ns2', Namespace('http://my_org.net/ns#')),
  138. ('ns3', Namespace('urn:test:')),
  139. ('ns4', Namespace('info:myinst/graph#')),
  140. )
  141. def test_ns(self, store, bindings):
  142. '''
  143. Test namespace bindings.
  144. '''
  145. store.begin()
  146. for b in bindings:
  147. store.bind(*b)
  148. store.commit()
  149. nslist = list(store.namespaces())
  150. assert len(nslist) == len(bindings)
  151. for i in range(len(bindings)):
  152. assert nslist[i] == bindings[i]
  153. def test_ns2pfx(self, store, bindings):
  154. '''
  155. Test namespace to prefix conversion.
  156. '''
  157. for b in bindings:
  158. pfx, ns = b
  159. assert store.namespace(pfx) == ns
  160. def test_pfx2ns(self, store, bindings):
  161. '''
  162. Test namespace to prefix conversion.
  163. '''
  164. for b in bindings:
  165. pfx, ns = b
  166. assert store.prefix(ns) == pfx
  167. @pytest.mark.usefixtures('store')
  168. class TestContext:
  169. '''
  170. Tests for context handling.
  171. '''
  172. # Add empty graph
  173. # Query graph → return graph
  174. # Add triples to graph
  175. # Query triples in graph → triples
  176. # Query triples in default graph → no results
  177. # Add another empty graph
  178. # Delete graph with triples
  179. # Query graph → no results
  180. # Query triples → no results
  181. # Delete empty graph
  182. # Query graph → no results
  183. def test_add_graph(self, store):
  184. '''
  185. Test creating an empty and a non-empty graph.
  186. '''
  187. gr_uri = URIRef('urn:bogus:graph#a')
  188. store.begin()
  189. store.add_graph(gr_uri)
  190. store.commit()
  191. assert gr_uri in store.contexts()
  192. def test_add_trp_to_ctx(self, store):
  193. '''
  194. Test adding triples to a graph.
  195. '''
  196. gr_uri = URIRef('urn:bogus:graph#a') # From previous test
  197. gr2_uri = URIRef('urn:bogus:graph#b') # Never created before
  198. trp1 = (URIRef('urn:s:1'), URIRef('urn:p:1'), URIRef('urn:o:1'))
  199. trp2 = (URIRef('urn:s:2'), URIRef('urn:p:2'), URIRef('urn:o:2'))
  200. trp3 = (URIRef('urn:s:3'), URIRef('urn:p:3'), URIRef('urn:o:3'))
  201. store.begin()
  202. store.add(trp1, gr_uri)
  203. store.add(trp2, gr_uri)
  204. store.add(trp2, store.DEFAULT_GRAPH_URI)
  205. store.add(trp3, gr2_uri)
  206. store.add(trp3)
  207. store.commit()
  208. assert len(set(store.triples((None, None, None)))) == 2
  209. assert len(set(store.triples((None, None, None), gr_uri))) == 2
  210. assert len(set(store.triples((None, None, None), gr2_uri))) == 1
  211. assert gr2_uri in store.contexts()
  212. assert trp1 not in store.triples((None, None, None))
  213. assert trp1 not in store.triples((None, None, None),
  214. store.DEFAULT_GRAPH_URI)
  215. assert trp2 in store.triples((None, None, None), gr_uri)
  216. assert trp2 in store.triples((None, None, None))
  217. assert trp3 in store.triples((None, None, None), gr2_uri)
  218. assert trp3 in store.triples((None, None, None),
  219. store.DEFAULT_GRAPH_URI)
  220. def test_delete_from_ctx(self, store):
  221. '''
  222. Delete triples from a named graph and from the default graph.
  223. '''
  224. gr_uri = URIRef('urn:bogus:graph#a') # From previous test
  225. gr2_uri = URIRef('urn:bogus:graph#b') # Never created before
  226. store.begin()
  227. store.remove((None, None, None))
  228. store.remove((None, None, None), gr2_uri)
  229. store.commit()
  230. assert len(set(store.triples((None, None, None)))) == 0
  231. assert len(set(store.triples((None, None, None), gr_uri))) == 2
  232. assert len(set(store.triples((None, None, None), gr2_uri))) == 0