summaryrefslogtreecommitdiff
path: root/src/leap/soledad
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/soledad')
-rw-r--r--src/leap/soledad/openstack.py60
-rw-r--r--src/leap/soledad/tests/__init__.py33
2 files changed, 81 insertions, 12 deletions
diff --git a/src/leap/soledad/openstack.py b/src/leap/soledad/openstack.py
index 8bbae8d8..7b7e656f 100644
--- a/src/leap/soledad/openstack.py
+++ b/src/leap/soledad/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/src/leap/soledad/tests/__init__.py b/src/leap/soledad/tests/__init__.py
index 50c99dd4..4f63648e 100644
--- a/src/leap/soledad/tests/__init__.py
+++ b/src/leap/soledad/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"