diff options
-rw-r--r-- | client/src/leap/soledad/client/_blobs.py | 9 | ||||
-rw-r--r-- | testing/tests/blobs/test_local_backend.py | 15 |
2 files changed, 24 insertions, 0 deletions
diff --git a/client/src/leap/soledad/client/_blobs.py b/client/src/leap/soledad/client/_blobs.py index 6f692f6b..1475b302 100644 --- a/client/src/leap/soledad/client/_blobs.py +++ b/client/src/leap/soledad/client/_blobs.py @@ -194,6 +194,9 @@ class BlobManager(object): @defer.inlineCallbacks def put(self, doc, size): + if (yield self.local.exists(doc.blob_id)): + error_message = "Blob already exists: %s" % doc.blob_id + raise BlobAlreadyExistsError(error_message) fd = doc.blob_fd # TODO this is a tee really, but ok... could do db and upload # concurrently. not sure if we'd gain something. @@ -326,6 +329,12 @@ class SQLiteBlobBackend(object): else: defer.returnValue([]) + @defer.inlineCallbacks + def exists(self, blob_id): + query = 'SELECT blob_id from blobs WHERE blob_id = ?' + result = yield self.dbpool.runQuery(query, (blob_id,)) + defer.returnValue(bool(len(result))) + def _init_blob_table(conn): maybe_create = ( diff --git a/testing/tests/blobs/test_local_backend.py b/testing/tests/blobs/test_local_backend.py index 5caa7463..b5a14de4 100644 --- a/testing/tests/blobs/test_local_backend.py +++ b/testing/tests/blobs/test_local_backend.py @@ -20,6 +20,7 @@ Tests for sqlcipher backend on blobs client. from twisted.trial import unittest from twisted.internet import defer from leap.soledad.client._blobs import BlobManager, BlobDoc, FIXED_REV +from leap.soledad.client._blobs import BlobAlreadyExistsError from io import BytesIO from mock import Mock import pytest @@ -115,3 +116,17 @@ class BlobManagerTestCase(unittest.TestCase): call_blob_id, call_fd = call_list[0][0] self.assertEquals('missing_id', call_blob_id) self.assertEquals('test', call_fd.getvalue()) + + @defer.inlineCallbacks + @pytest.mark.usefixtures("method_tmpdir") + def test_duplicated_blob_error_on_put(self): + self.manager._encrypt_and_upload = Mock(return_value=None) + content = "Blob content" + doc1 = BlobDoc(BytesIO(content), 'existing_id') + yield self.manager.put(doc1, len(content)) + doc2 = BlobDoc(BytesIO(content), 'existing_id') + # reset mock, so we can check that upload wasnt called + self.manager._encrypt_and_upload = Mock(return_value=None) + with pytest.raises(BlobAlreadyExistsError): + yield self.manager.put(doc2, len(content)) + self.assertFalse(self.manager._encrypt_and_upload.called) |