diff --git a/chainqueue/store/__init__.py b/chainqueue/store/__init__.py new file mode 100644 index 0000000..32bc4f9 --- /dev/null +++ b/chainqueue/store/__init__.py @@ -0,0 +1,5 @@ +from .base import ( + to_key, + from_key, + Store, + ) diff --git a/chainqueue/store.py b/chainqueue/store/base.py similarity index 100% rename from chainqueue/store.py rename to chainqueue/store/base.py diff --git a/chainqueue/store/fs.py b/chainqueue/store/fs.py new file mode 100644 index 0000000..aa49a63 --- /dev/null +++ b/chainqueue/store/fs.py @@ -0,0 +1,70 @@ +# standard imports +import os +import logging + +# external imports +from leveldir.hex import HexDir + +logg = logging.getLogger(__name__) + + +class IndexStore(HexDir): + + def __init__(self, root_path, digest_bytes=32): + os.path.join(root_path, 'contents') + self.store = HexDir(root_path, digest_bytes) + + + def put(self, k, v): + kb = bytes.fromhex(k) + vb = v.encode('utf-8') + self.store.add(kb, vb) + + + def get(self, k): + fp = self.store.to_filepath(k) + f = open(fp, 'rb') + v = f.read() + f.close() + return v.decode('utf-8') + + +class CounterStore: + + def __init__(self, root_path): + try: + os.stat(root_path) + except FileNotFoundError: + os.makedirs(root_path) + + fp = os.path.join(root_path, '.counter') + f = None + try: + f = open(fp, 'rb+') + except FileNotFoundError: + logg.debug('counter not found, creating new in {}'.format(fp)) + f = open(fp, 'wb+') + f.write(b'\x00' * 8) + f.close() + f = open(fp, 'rb+') + + v = f.read(8) + self.count = int.from_bytes(v, byteorder='big') + logg.info('counter starts at {}'.format(self.count)) + + f.seek(0) + + self.f = f + + + def __del__(self): + self.f.close() + + + def next(self): + c = self.count + self.count += 1 + v = self.count.to_bytes(8, 'big') + self.f.write(v) + self.f.seek(0) + return c diff --git a/tests/base_shep.py b/tests/base_shep.py index 46bbe12..1c97f6c 100644 --- a/tests/base_shep.py +++ b/tests/base_shep.py @@ -1,6 +1,7 @@ # standard imports import tempfile import unittest +import shutil # external imports from shep.store.file import SimpleFileStoreFactory @@ -13,22 +14,10 @@ from chainqueue import ( ) # test imports -from tests.common import MockCounter - - - -class MockContentStore: - - def __init__(self): - self.store = {} - - - def put(self, k, v): - self.store[k] = v - - - def get(self, k): - return self.store.get(k) +from tests.common import ( + MockCounter, + MockContentStore, + ) class TestShepBase(unittest.TestCase): @@ -41,3 +30,7 @@ class TestShepBase(unittest.TestCase): counter = MockCounter() chain_spec = ChainSpec('foo', 'bar', 42, 'baz') self.store = Store(chain_spec, self.state, content_store, counter) + + + def tearDown(self): + shutil.rmtree(self.path) diff --git a/tests/common.py b/tests/common.py index 59c1efe..0861cb5 100644 --- a/tests/common.py +++ b/tests/common.py @@ -79,7 +79,6 @@ class MockCacheTokenTx(CacheTokenTx): z = h.digest() tx_hash = z.hex() - #tx = CacheTokenTx(normalizer=self.normalizer) self.init(tx_hash, nonce, sender, recipient, value) self.set('src_token', token) self.set('dst_token', token) @@ -90,4 +89,15 @@ class MockCacheTokenTx(CacheTokenTx): return self +class MockContentStore: + def __init__(self): + self.store = {} + + + def put(self, k, v): + self.store[k] = v + + + def get(self, k): + return self.store.get(k) diff --git a/tests/test_integrate.py b/tests/test_integrate.py index 4337337..33da5b5 100644 --- a/tests/test_integrate.py +++ b/tests/test_integrate.py @@ -18,6 +18,7 @@ from tests.common import ( MockCounter, MockTokenCache, MockCacheTokenTx, + MockContentStore, ) from tests.base_shep import TestShepBase @@ -25,20 +26,6 @@ logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() -class MockContentStore: - - def __init__(self): - self.store = {} - - - def put(self, k, v): - self.store[k] = v - - - def get(self, k): - return self.store.get(k) - - class TestIntegrateBase(TestShepBase): def setUp(self): diff --git a/tests/test_store.py b/tests/test_store.py new file mode 100644 index 0000000..a352140 --- /dev/null +++ b/tests/test_store.py @@ -0,0 +1,52 @@ +# standard imports +import os +import tempfile +import unittest +import logging +import shutil + +# external imports + +# local imports +from chainqueue.store.fs import ( + IndexStore, + CounterStore, + ) + + +logging.basicConfig(level=logging.DEBUG) +logg = logging.getLogger() + +class TestStoreImplementations(unittest.TestCase): + + def setUp(self): + self.path = tempfile.mkdtemp() + + + def tearDown(self): + shutil.rmtree(self.path) + + + def test_basic_index(self): + store = IndexStore(self.path) + hx = os.urandom(32).hex() + data = 'foo_bar_baz' + store.put(hx, data) + r = store.get(hx) + self.assertEqual(data, r) + + + def test_basic_counter(self): + store = CounterStore(self.path) + v = store.next() + self.assertEqual(v, 0) + v = store.next() + self.assertEqual(v, 1) + + store = CounterStore(self.path) + v = store.next() + self.assertEqual(v, 2) + + +if __name__ == '__main__': + unittest.main()