diff --git a/test/test_persistent_dict.py b/test/test_persistent_dict.py index 7904a03bea7c375843928c413ca394b9cd5a373c..775d3b69a35b4d47a8ebd2dc39c0da2e453d123b 100644 --- a/test/test_persistent_dict.py +++ b/test/test_persistent_dict.py @@ -2,96 +2,236 @@ from __future__ import division, with_statement, absolute_import import pytest # noqa import sys # noqa +import tempfile +import shutil +import warnings + from six.moves import range from six.moves import zip +from pytools.persistent_dict import (PersistentDict, + WriteOncePersistentDict, + NoSuchEntryError, + ReadOnlyEntryError) -def test_persistent_dict(): - from pytools.persistent_dict import PersistentDict - pdict = PersistentDict("pytools-test") - pdict.clear() - from random import randrange +# {{{ type for testing - def rand_str(n=20): - return "".join( - chr(65+randrange(26)) - for i in range(n)) +class PDictTestingKeyOrValue(object): - keys = [(randrange(2000), rand_str(), None) for i in range(20)] - values = [randrange(2000) for i in range(20)] + def __init__(self, val, hash_key=None): + self.val = val + if hash_key is None: + hash_key = val + self.hash_key = hash_key - d = dict(list(zip(keys, values))) + def __getstate__(self): + return {"val": self.val, "hash_key": self.hash_key} - for k, v in zip(keys, values): - pdict[k] = v - pdict.store(k, v, info_files={"hey": str(v)}) + def __eq__(self, other): + return self.val == other.val - for k, v in list(d.items()): - assert d[k] == pdict[k] + def __ne__(self, other): + return not self.__eq__(other) - for k, v in zip(keys, values): - pdict.store(k, v+1, info_files={"hey": str(v)}) + def update_persistent_hash(self, key_hash, key_builder): + key_builder.rec(key_hash, self.hash_key) - for k, v in list(d.items()): - assert d[k] + 1 == pdict[k] +# }}} -class PDictTestValue(object): +def test_persistent_dict_storage_and_lookup(): + try: + tmpdir = tempfile.mkdtemp() + pdict = PersistentDict(tmpdir) - def __init__(self, val): - self.val = val + from random import randrange - def __getstate__(self): - return {"val": self.val} + def rand_str(n=20): + return "".join( + chr(65+randrange(26)) + for i in range(n)) - def update_persistent_hash(self, key_hash, key_builder): - key_builder.rec(key_hash, self.val) + keys = [(randrange(2000), rand_str(), None) for i in range(20)] + values = [randrange(2000) for i in range(20)] + + d = dict(list(zip(keys, values))) + + # {{{ check lookup + + for k, v in zip(keys, values): + pdict[k] = v + + for k, v in d.items(): + assert d[k] == pdict[k] + + # }}} + + # {{{ check updating + + for k, v in zip(keys, values): + pdict[k] = v + 1 + + for k, v in d.items(): + assert d[k] + 1 == pdict[k] + + # }}} + + # {{{ check not found + + with pytest.raises(NoSuchEntryError): + pdict[3000] + + # }}} + + finally: + shutil.rmtree(tmpdir) + + +def test_persistent_dict_deletion(): + try: + tmpdir = tempfile.mkdtemp() + pdict = PersistentDict(tmpdir) + + pdict[0] = 0 + del pdict[0] + + with pytest.raises(NoSuchEntryError): + pdict[0] + + with pytest.raises(NoSuchEntryError): + del pdict[1] + + finally: + shutil.rmtree(tmpdir) + + +def test_persistent_dict_synchronization(): + try: + tmpdir = tempfile.mkdtemp() + pdict1 = PersistentDict(tmpdir) + pdict2 = PersistentDict(tmpdir) + + # check lookup + pdict1[0] = 1 + assert pdict2[0] == 1 + + # check updating + pdict1[0] = 2 + assert pdict2[0] == 2 + + # check deletion + del pdict1[0] + with pytest.raises(NoSuchEntryError): + pdict2[0] + + finally: + shutil.rmtree(tmpdir) + + +def test_persistent_dict_cache_collisions(): + try: + tmpdir = tempfile.mkdtemp() + pdict = PersistentDict(tmpdir) + + key1 = PDictTestingKeyOrValue(1, hash_key=0) + key2 = PDictTestingKeyOrValue(2, hash_key=0) + + pdict[key1] = 1 + + # Suppress pdict collision warnings. + with warnings.catch_warnings(): + # check lookup + with pytest.raises(NoSuchEntryError): + pdict[key2] + + # check deletion + with pytest.raises(NoSuchEntryError): + del pdict[key2] + + finally: + shutil.rmtree(tmpdir) + + +def test_write_once_persistent_dict_storage_and_lookup(): + try: + tmpdir = tempfile.mkdtemp() + pdict = WriteOncePersistentDict(tmpdir) + + # check lookup + pdict[0] = 1 + assert pdict[0] == 1 + + # check updating + with pytest.raises(ReadOnlyEntryError): + pdict[0] = 2 + + finally: + shutil.rmtree(tmpdir) + + +def test_write_once_persistent_dict_lru_policy(): + try: + tmpdir = tempfile.mkdtemp() + pdict = WriteOncePersistentDict(tmpdir, in_mem_cache_size=3) + + pdict[1] = PDictTestingKeyOrValue(1) + pdict[2] = PDictTestingKeyOrValue(2) + pdict[3] = PDictTestingKeyOrValue(3) + pdict[4] = PDictTestingKeyOrValue(4) + + val1 = pdict[1] + assert pdict[1] is val1 + pdict[2] + assert pdict[1] is val1 + pdict[3] + assert pdict[1] is val1 + pdict[2] + assert pdict[1] is val1 + pdict[4] + assert pdict[1] is not val1 -def test_persistent_dict_in_memory_cache(): - from pytools.persistent_dict import PersistentDict - pdict = PersistentDict("pytools-in-memory-cache-test", in_mem_cache_size=3) - pdict.clear() + finally: + shutil.rmtree(tmpdir) - pdict[1] = PDictTestValue(1) - pdict[2] = PDictTestValue(2) - pdict[3] = PDictTestValue(3) - pdict[4] = PDictTestValue(4) - # {{{ test LRU policy +def test_write_once_persistent_dict_synchronization(): + try: + tmpdir = tempfile.mkdtemp() + pdict1 = WriteOncePersistentDict(tmpdir) + pdict2 = WriteOncePersistentDict(tmpdir) - val1 = pdict[1] - val1.val = 0 + # check lookup + pdict1[1] = 0 + assert pdict2[1] == 0 - assert pdict[1].val == 0 - pdict[2] - assert pdict[1].val == 0 - pdict[3] - assert pdict[1].val == 0 - pdict[2] - assert pdict[1].val == 0 - pdict[4] - assert pdict[1].val == 1 + # check updating + with pytest.raises(ReadOnlyEntryError): + pdict2[1] = 1 - # }}} + finally: + shutil.rmtree(tmpdir) - # {{{ test cache invalidation by versioning - assert pdict[1].val == 1 - pdict2 = PersistentDict("pytools-in-memory-cache-test") - pdict2[1] = PDictTestValue(5) - assert pdict[1].val == 5 +def test_write_once_persistent_dict_cache_collisions(): + try: + tmpdir = tempfile.mkdtemp() + pdict = WriteOncePersistentDict(tmpdir) - # }}} + key1 = PDictTestingKeyOrValue(1, hash_key=0) + key2 = PDictTestingKeyOrValue(2, hash_key=0) - # {{{ test cache invalidation by deletion + pdict[key1] = 1 - del pdict2[1] - pdict2[1] = PDictTestValue(10) - assert pdict[1].val == 10 + # Suppress pdict collision warnings. + with warnings.catch_warnings(): + # check lookup + with pytest.raises(NoSuchEntryError): + pdict[key2] - # }}} + finally: + shutil.rmtree(tmpdir) if __name__ == "__main__":