309 lines
7.9 KiB
Python
309 lines
7.9 KiB
Python
# standard imports
|
||
import os
|
||
import stat
|
||
import unittest
|
||
import shutil
|
||
import tempfile
|
||
import logging
|
||
|
||
# local imports
|
||
from chainsyncer.session import SyncSession
|
||
from chainsyncer.error import (
|
||
LockError,
|
||
FilterDone,
|
||
IncompleteFilterError,
|
||
SyncDone,
|
||
)
|
||
from chainsyncer.unittest import (
|
||
MockFilter,
|
||
MockItem,
|
||
)
|
||
|
||
logging.STATETRACE = 5
|
||
logg = logging.getLogger(__name__)
|
||
logg.setLevel(logging.STATETRACE)
|
||
|
||
|
||
def state_change_callback(k, old_state, new_state):
|
||
logg.log(logging.STATETRACE, 'state change: {} {} -> {}'.format(k, old_state, new_state))
|
||
|
||
|
||
def filter_change_callback(k, old_state, new_state):
|
||
logg.log(logging.STATETRACE, 'filter change: {} {} -> {}'.format(k, old_state, new_state))
|
||
|
||
|
||
class TestStoreBase(unittest.TestCase):
|
||
|
||
def setUp(self):
|
||
self.path = tempfile.mkdtemp()
|
||
self.store_factory = None
|
||
self.persist = True
|
||
|
||
|
||
@classmethod
|
||
def link(cls, target):
|
||
for v in [
|
||
"default",
|
||
"store_start",
|
||
"store_resume",
|
||
"sync_process_nofilter",
|
||
"sync_process_onefilter",
|
||
"sync_process_outoforder",
|
||
"sync_process_interrupt",
|
||
"sync_process_reset",
|
||
"sync_process_done",
|
||
"sync_head_future",
|
||
"sync_history_interrupted",
|
||
"sync_history_complete",
|
||
]:
|
||
setattr(target, 'test_' + v, getattr(cls, 't_' + v))
|
||
|
||
|
||
def tearDown(self):
|
||
shutil.rmtree(self.path)
|
||
|
||
|
||
def t_default(self):
|
||
bogus_item = MockItem(0, 0, 0, 0)
|
||
store = self.store_factory()
|
||
|
||
fp = os.path.join(self.path, store.session_id)
|
||
session_id = store.session_id
|
||
st = None
|
||
try:
|
||
st = os.stat(fp)
|
||
except FileNotFoundError as e:
|
||
logg.warning('error {} persist {}'.format(e, self.persist))
|
||
if self.persist:
|
||
raise e
|
||
|
||
if st != None:
|
||
self.assertTrue(stat.S_ISDIR(st.st_mode))
|
||
self.assertTrue(store.is_default)
|
||
|
||
fpd = os.path.join(self.path, 'default')
|
||
try:
|
||
st = os.stat(fpd)
|
||
except FileNotFoundError as e:
|
||
logg.warning('error {} persist {}'.format(e, self.persist))
|
||
if self.persist:
|
||
raise e
|
||
if st != None:
|
||
self.assertTrue(stat.S_ISDIR(st.st_mode))
|
||
self.assertTrue(store.is_default)
|
||
|
||
fpd = os.path.realpath(fpd)
|
||
self.assertEqual(fpd, fp)
|
||
|
||
store.stop(bogus_item)
|
||
store = self.store_factory()
|
||
fpr = os.path.join(self.path, session_id)
|
||
self.assertEqual(fp, fpr)
|
||
self.assertTrue(store.is_default)
|
||
|
||
store.stop(bogus_item)
|
||
store = self.store_factory('default')
|
||
fpr = os.path.join(self.path, session_id)
|
||
self.assertEqual(fp, fpr)
|
||
self.assertTrue(store.is_default)
|
||
|
||
store.stop(bogus_item)
|
||
store = self.store_factory('foo')
|
||
fpf = os.path.join(self.path, 'foo')
|
||
try:
|
||
st = os.stat(fpf)
|
||
except FileNotFoundError as e:
|
||
logg.warning('error {} persist {}'.format(e, self.persist))
|
||
if self.persist:
|
||
raise e
|
||
if st != None:
|
||
self.assertTrue(stat.S_ISDIR(st.st_mode))
|
||
self.assertFalse(store.is_default)
|
||
|
||
|
||
def t_store_start(self):
|
||
bogus_item = MockItem(0, 0, 0, 0)
|
||
store = self.store_factory()
|
||
store.start(42)
|
||
self.assertTrue(store.first)
|
||
|
||
store.stop(bogus_item)
|
||
|
||
if self.persist:
|
||
store = self.store_factory()
|
||
store.start()
|
||
self.assertFalse(store.first)
|
||
|
||
|
||
def t_store_resume(self):
|
||
store = self.store_factory()
|
||
store.start(13)
|
||
self.assertTrue(store.first)
|
||
# todo not done
|
||
|
||
|
||
def t_sync_process_nofilter(self):
|
||
store = self.store_factory()
|
||
session = SyncSession(store)
|
||
session.start()
|
||
o = session.get(0)
|
||
with self.assertRaises(FilterDone):
|
||
o.advance()
|
||
|
||
|
||
def t_sync_process_onefilter(self):
|
||
store = self.store_factory()
|
||
session = SyncSession(store)
|
||
|
||
fltr_one = MockFilter('foo')
|
||
store.register(fltr_one)
|
||
|
||
session.start()
|
||
o = session.get(0)
|
||
o.advance()
|
||
o.release()
|
||
|
||
|
||
def t_sync_process_outoforder(self):
|
||
store = self.store_factory()
|
||
session = SyncSession(store)
|
||
|
||
fltr_one = MockFilter('foo')
|
||
store.register(fltr_one)
|
||
fltr_two = MockFilter('two')
|
||
store.register(fltr_two)
|
||
|
||
session.start()
|
||
o = session.get(0)
|
||
o.advance()
|
||
with self.assertRaises(LockError):
|
||
o.advance()
|
||
|
||
o.release()
|
||
with self.assertRaises(LockError):
|
||
o.release()
|
||
|
||
o.advance()
|
||
o.release()
|
||
|
||
|
||
def t_sync_process_interrupt(self):
|
||
store = self.store_factory()
|
||
session = SyncSession(store)
|
||
|
||
fltr_one = MockFilter('foo')
|
||
store.register(fltr_one)
|
||
fltr_two = MockFilter('bar')
|
||
store.register(fltr_two)
|
||
|
||
session.start()
|
||
o = session.get(0)
|
||
o.advance()
|
||
o.release(interrupt=True)
|
||
with self.assertRaises(FilterDone):
|
||
o.advance()
|
||
|
||
|
||
def t_sync_process_reset(self):
|
||
store = self.store_factory()
|
||
session = SyncSession(store)
|
||
|
||
fltr_one = MockFilter('foo')
|
||
store.register(fltr_one)
|
||
fltr_two = MockFilter('bar')
|
||
store.register(fltr_two)
|
||
|
||
session.start()
|
||
o = session.get(0)
|
||
o.advance()
|
||
with self.assertRaises(LockError):
|
||
o.reset()
|
||
o.release()
|
||
with self.assertRaises(IncompleteFilterError):
|
||
o.reset()
|
||
|
||
o.advance()
|
||
o.release()
|
||
|
||
with self.assertRaises(FilterDone):
|
||
o.advance()
|
||
|
||
o.reset()
|
||
|
||
|
||
def t_sync_process_done(self):
|
||
store = self.store_factory()
|
||
session = SyncSession(store)
|
||
|
||
fltr_one = MockFilter('foo')
|
||
store.register(fltr_one)
|
||
|
||
session.start(target=0)
|
||
o = session.get(0)
|
||
o.advance()
|
||
o.release()
|
||
with self.assertRaises(FilterDone):
|
||
o.advance()
|
||
o.reset()
|
||
with self.assertRaises(SyncDone):
|
||
o.next(advance_block=True)
|
||
|
||
|
||
def t_sync_head_future(self):
|
||
store = self.store_factory('foo')
|
||
session = SyncSession(store)
|
||
|
||
session.start()
|
||
o = session.get(0)
|
||
o.next(advance_block=True)
|
||
o.next(advance_block=True)
|
||
session.stop(o)
|
||
|
||
if self.persist:
|
||
store = self.store_factory('foo')
|
||
store.start()
|
||
o = store.get(2)
|
||
|
||
|
||
def t_sync_history_interrupted(self):
|
||
if not self.persist:
|
||
return
|
||
|
||
bogus_item = MockItem(0, 0, 0, 0)
|
||
store = self.store_factory('foo')
|
||
session = SyncSession(store)
|
||
|
||
session.start(target=13)
|
||
o = session.get(0)
|
||
o.next(advance_block=True)
|
||
o.next(advance_block=True)
|
||
session.stop(o)
|
||
|
||
store.stop(bogus_item)
|
||
store = self.store_factory('foo')
|
||
store.start()
|
||
o = store.get(0)
|
||
self.assertEqual(o.cursor, 2)
|
||
self.assertEqual(o.target, 13)
|
||
o.next(advance_block=True)
|
||
o.next(advance_block=True)
|
||
|
||
store.stop(bogus_item)
|
||
store = self.store_factory('foo')
|
||
store.start()
|
||
self.assertEqual(o.cursor, 4)
|
||
self.assertEqual(o.target, 13)
|
||
|
||
|
||
def t_sync_history_complete(self):
|
||
store = self.store_factory('foo')
|
||
session = SyncSession(store)
|
||
|
||
session.start(target=3)
|
||
o = session.get(0)
|
||
o.next(advance_block=True)
|
||
o.next(advance_block=True)
|
||
o.next(advance_block=True)
|
||
with self.assertRaises(SyncDone):
|
||
o.next(advance_block=True)
|