diff options
| -rw-r--r-- | openstack.py | 60 | ||||
| -rw-r--r-- | tests/__init__.py | 33 | 
2 files changed, 81 insertions, 12 deletions
diff --git a/openstack.py b/openstack.py index 8bbae8d8..7b7e656f 100644 --- a/openstack.py +++ b/openstack.py @@ -30,7 +30,9 @@ class OpenStackDatabase(CommonBackend):          raise NotImplementedError(self.set_document_size_limit)      def whats_changed(self, old_generation=0): -        raise NotImplementedError(self.whats_changed) +        # This method is implemented in TransactionLog because testing is +        # easier like this for now, but it can be moved to here afterwards. +        return self._transaction_log.whats_changed(old_generation)      def get_doc(self, doc_id, include_deleted=False):          # TODO: support deleted docs? @@ -179,22 +181,29 @@ class OpenStackSyncTarget(HTTPSyncTarget):  class SimpleLog(object): -    def __init__(self, log=None): +    def __init__(self):          self._log = [] -        if log: -            self._log = log + +    def _set_log(self, log): +        self._log = log + +    def _get_log(self): +        return self._log + +    log = property( +        _get_log, _set_log, doc="Log contents.")      def append(self, msg):          self._log.append(msg)      def reduce(self, func, initializer=None): -        return reduce(func, self._log, initializer) +        return reduce(func, self.log, initializer)      def map(self, func): -        return map(func, self._log) +        return map(func, self.log)      def filter(self, func): -        return filter(func, self._log) +        return filter(func, self.log)  class TransactionLog(SimpleLog): @@ -202,6 +211,15 @@ class TransactionLog(SimpleLog):      A list of (generation, doc_id, transaction_id) tuples.      """ +    def _set_log(self, log): +        self._log = log + +    def _get_log(self): +        return sorted(self._log, reverse=True) + +    log = property( +        _get_log, _set_log, doc="Log contents.") +      def get_generation(self):          """          Return the current generation. @@ -229,6 +247,30 @@ class TransactionLog(SimpleLog):              return None          return log[2] +    def whats_changed(self, old_generation): +        results = self.filter(lambda x: x[0] > old_generation) +        seen = set() +        changes = [] +        newest_trans_id = '' +        for generation, doc_id, trans_id in results: +            if doc_id not in seen: +                changes.append((doc_id, generation, trans_id)) +                seen.add(doc_id) +        if changes: +            cur_gen = changes[0][1]  # max generation +            newest_trans_id = changes[0][2] +            changes.reverse() +        else: +            results = self.log +            if not results: +                cur_gen = 0 +                newest_trans_id = '' +            else: +                cur_gen, _, newest_trans_id = results[0] + +        return cur_gen, newest_trans_id, changes +         +  class SyncLog(SimpleLog):      """ @@ -236,7 +278,7 @@ class SyncLog(SimpleLog):      """      def find_by_replica_uid(self, replica_uid): -        if not self._log: +        if not self.log:              return ()          return self.reduce(lambda x, y: y if y[0] == replica_uid else x) @@ -256,7 +298,7 @@ class SyncLog(SimpleLog):          Set the last-known generation and transaction id for the other          database replica.          """ -        self._log = self.filter(lambda x: x[0] != other_replica_uid) +        self.log = self.filter(lambda x: x[0] != other_replica_uid)          self.append((other_replica_uid, other_generation,                       other_transaction_id)) diff --git a/tests/__init__.py b/tests/__init__.py index 50c99dd4..4f63648e 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -8,7 +8,11 @@ import os  import u1db  from soledad import leap, GPGWrapper -from soledad.openstack import SimpleLog, TransactionLog, SyncLog +from soledad.openstack import ( +    SimpleLog, +    TransactionLog, +    SyncLog, +  )  class EncryptedSyncTestCase(unittest.TestCase): @@ -53,7 +57,8 @@ class LogTestCase(unittest.TestCase):            (3, "doc_2", "tran_2"),            (1, "doc_1", "tran_1")          ] -        log = TransactionLog(data) +        log = TransactionLog() +        log.log = data          self.assertEqual(log.get_generation(), 3, 'error getting generation')          self.assertEqual(log.get_generation_info(), (3, 'tran_2'),                           'error getting generation info') @@ -70,7 +75,8 @@ class LogTestCase(unittest.TestCase):            ("replica_2", 2, "tran_2"),            ("replica_1", 1, "tran_1")          ] -        log = SyncLog(data) +        log = SyncLog() +        log.log = data          # test getting          self.assertEqual(log.get_replica_gen_and_trans_id('replica_3'),              (3, 'tran_3'), 'error getting replica gen and trans id') @@ -88,6 +94,27 @@ class LogTestCase(unittest.TestCase):          self.assertEqual(log.get_replica_gen_and_trans_id('replica_3'),              (3, 'tran_3'), 'error setting replica gen and trans id') +    def test_whats_changed(self): +        data = [ +          (2, "doc_3", "tran_3"), +          (3, "doc_2", "tran_2"), +          (1, "doc_1", "tran_1") +        ] +        log = TransactionLog() +        log.log = data +        self.assertEqual( +          log.whats_changed(3), +          (3, "tran_2", []), +          'error getting whats changed.') +        self.assertEqual( +          log.whats_changed(2), +          (3, "tran_2", [("doc_2",3,"tran_2")]), +          'error getting whats changed.') +        self.assertEqual( +          log.whats_changed(1), +          (3, "tran_2", [("doc_3",2,"tran_3"),("doc_2",3,"tran_2")]), +          'error getting whats changed.') +  # Key material for testing  KEY_FINGERPRINT = "E36E738D69173C13D709E44F2F455E2824D18DDF"  | 
