diff options
-rw-r--r-- | src/leap/soledad/client/_db/blobs/__init__.py | 12 | ||||
-rw-r--r-- | src/leap/soledad/client/_db/blobs/sql.py | 1 | ||||
-rw-r--r-- | src/leap/soledad/client/_db/blobs/sync.py | 4 | ||||
-rw-r--r-- | tests/blobs/test_blob_manager.py | 13 |
4 files changed, 27 insertions, 3 deletions
diff --git a/src/leap/soledad/client/_db/blobs/__init__.py b/src/leap/soledad/client/_db/blobs/__init__.py index a5b7d6e3..3c7492c6 100644 --- a/src/leap/soledad/client/_db/blobs/__init__.py +++ b/src/leap/soledad/client/_db/blobs/__init__.py @@ -207,7 +207,7 @@ class BlobManager(BlobsSynchronizer): def local_list_status(self, status, namespace=''): return self.local.list_status(status, namespace) - def put(self, doc, size, namespace=''): + def put(self, doc, size, namespace='', local_only=False): """ Put a blob in local storage and upload it to server. @@ -215,14 +215,16 @@ class BlobManager(BlobsSynchronizer): :type doc: leap.soledad.client._document.BlobDoc :param size: The size of the blob. :type size: int + :param local_only: Avoids sync (doesn't send to server). + :type local_only: bool :param namespace: Optional parameter to restrict operation to a given namespace. :type namespace: str """ - return self.semaphore.run(self._put, doc, size, namespace) + return self.semaphore.run(self._put, doc, size, namespace, local_only) @defer.inlineCallbacks - def _put(self, doc, size, namespace): + def _put(self, doc, size, namespace, local_only=False): if (yield self.local.exists(doc.blob_id, namespace=namespace)): error_message = "Blob already exists: %s" % doc.blob_id raise BlobAlreadyExistsError(error_message) @@ -230,6 +232,10 @@ class BlobManager(BlobsSynchronizer): # TODO this is a tee really, but ok... could do db and upload # concurrently. not sure if we'd gain something. yield self.local.put(doc.blob_id, fd, size=size, namespace=namespace) + if local_only: + yield self.local.update_sync_status( + doc.blob_id, SyncStatus.LOCAL_ONLY) + defer.returnValue(None) yield self.local.update_sync_status( doc.blob_id, SyncStatus.PENDING_UPLOAD) # In fact, some kind of pipe is needed here, where each write on db diff --git a/src/leap/soledad/client/_db/blobs/sql.py b/src/leap/soledad/client/_db/blobs/sql.py index 5337ab87..ebd6c095 100644 --- a/src/leap/soledad/client/_db/blobs/sql.py +++ b/src/leap/soledad/client/_db/blobs/sql.py @@ -42,6 +42,7 @@ class SyncStatus: FAILED_UPLOAD = 4 FAILED_DOWNLOAD = 5 PENDING_DELETE = 6 + LOCAL_ONLY = 7 UNAVAILABLE_STATUSES = (3, 5) diff --git a/src/leap/soledad/client/_db/blobs/sync.py b/src/leap/soledad/client/_db/blobs/sync.py index bdfbb983..3ee60305 100644 --- a/src/leap/soledad/client/_db/blobs/sync.py +++ b/src/leap/soledad/client/_db/blobs/sync.py @@ -77,6 +77,10 @@ class BlobsSynchronizer(object): remote_deletions = self.remote_list(namespace=namespace, deleted=True) remote_deletions = yield remote_deletions yield self.local.batch_delete(remote_deletions) + yield self.local.update_batch_sync_status( + remote_deletions, + SyncStatus.SYNCED, + namespace=namespace) @defer.inlineCallbacks def send_missing(self, namespace=''): diff --git a/tests/blobs/test_blob_manager.py b/tests/blobs/test_blob_manager.py index 58f99790..c7bbb0d3 100644 --- a/tests/blobs/test_blob_manager.py +++ b/tests/blobs/test_blob_manager.py @@ -83,6 +83,19 @@ class BlobManagerTestCase(unittest.TestCase): @defer.inlineCallbacks @pytest.mark.usefixtures("method_tmpdir") + def test_put_local_only_doesnt_send_to_server(self): + self.manager._encrypt_and_upload = Mock(return_value=None) + msg, blob_id = "Hey Joe", uuid4().hex + doc = BlobDoc(BytesIO(msg), blob_id=blob_id) + yield self.manager.put(doc, size=len(msg), local_only=True) + result = yield self.manager.local.get(blob_id) + status, _ = yield self.manager.local.get_sync_status(blob_id) + self.assertEquals(result.getvalue(), msg) + self.assertEquals(status, SyncStatus.LOCAL_ONLY) + self.assertFalse(self.manager._encrypt_and_upload.called) + + @defer.inlineCallbacks + @pytest.mark.usefixtures("method_tmpdir") def test_put_then_get_using_real_file_descriptor(self): self.manager._encrypt_and_upload = Mock(return_value=None) self.manager._download_and_decrypt = Mock(return_value=None) |