diff options
| -rw-r--r-- | client/src/leap/soledad/client/_database/blobs.py | 26 | ||||
| -rw-r--r-- | server/src/leap/soledad/server/_blobs.py | 11 | ||||
| -rw-r--r-- | testing/tests/blobs/test_blob_manager.py | 13 | ||||
| -rw-r--r-- | testing/tests/blobs/test_fs_backend.py | 8 | ||||
| -rw-r--r-- | testing/tests/server/test_blobs_server.py | 11 | 
5 files changed, 67 insertions, 2 deletions
diff --git a/client/src/leap/soledad/client/_database/blobs.py b/client/src/leap/soledad/client/_database/blobs.py index 4976fe4d..da2711de 100644 --- a/client/src/leap/soledad/client/_database/blobs.py +++ b/client/src/leap/soledad/client/_database/blobs.py @@ -291,6 +291,18 @@ class BlobManager(object):          logger.info("Finished download: (%s, %d)" % (blob_id, size))          defer.returnValue((fd, size)) +    @defer.inlineCallbacks +    def delete(self, blob_id): +        logger.info("Staring deletion of blob: %s" % blob_id) +        yield self._delete_from_remote(blob_id) +        if (yield self.local.exists(blob_id)): +            yield self.local.delete(blob_id) + +    def _delete_from_remote(self, blob_id): +        # TODO this needs to be connected in a tube +        uri = urljoin(self.remote, self.user + '/' + blob_id) +        return self._client.delete(uri) +  class SQLiteBlobBackend(object): @@ -427,6 +439,11 @@ def testit(reactor):          'get', help='get blob from local db, get if needed')      parser_get.add_argument('blob_id') +    # parse delete command +    parser_get = subparsers.add_parser( +        'delete', help='delete blob from local and remote db') +    parser_get.add_argument('blob_id') +      # parse list command      parser_get = subparsers.add_parser(          'list', help='list local and remote blob ids') @@ -494,6 +511,13 @@ def testit(reactor):          logger.info(":: Finished full get: %s" % blob_id)      @defer.inlineCallbacks +    def _delete(blob_id): +        logger.info(":: Starting deletion of: %s" % blob_id) +        manager = _manager() +        yield manager.delete(blob_id) +        logger.info(":: Finished deletion of: %s" % blob_id) + +    @defer.inlineCallbacks      def _list():          logger.info(":: Listing local blobs")          manager = _manager() @@ -525,6 +549,8 @@ def testit(reactor):          yield _put(args.blob_id, args.payload)      elif args.action == 'get':          yield _get(args.blob_id) +    elif args.action == 'delete': +        yield _delete(args.blob_id)      elif args.action == 'list':          yield _list()      elif args.action == 'send_missing': diff --git a/server/src/leap/soledad/server/_blobs.py b/server/src/leap/soledad/server/_blobs.py index 1595a549..44abeb44 100644 --- a/server/src/leap/soledad/server/_blobs.py +++ b/server/src/leap/soledad/server/_blobs.py @@ -157,8 +157,9 @@ class FilesystemBlobsBackend(object):      def get_total_storage(self, user):          return self._get_disk_usage(self._get_path(user)) -    def delete_blob(user, blob_id): -        raise NotImplementedError +    def delete_blob(self, user, blob_id): +        blob_path = self._get_path(user, blob_id) +        os.unlink(blob_path)      def get_blob_size(user, blob_id):          raise NotImplementedError @@ -219,6 +220,12 @@ class BlobsResource(resource.Resource):          self._handler.tag_header(user, blob_id, request)          return self._handler.read_blob(user, blob_id, request) +    def render_DELETE(self, request): +        logger.info("http put: %s" % request.path) +        user, blob_id = self._validate(request) +        self._handler.delete_blob(user, blob_id) +        return '' +      def render_PUT(self, request):          logger.info("http put: %s" % request.path)          user, blob_id = self._validate(request) diff --git a/testing/tests/blobs/test_blob_manager.py b/testing/tests/blobs/test_blob_manager.py index 69a272c8..4d04e09d 100644 --- a/testing/tests/blobs/test_blob_manager.py +++ b/testing/tests/blobs/test_blob_manager.py @@ -130,3 +130,16 @@ class BlobManagerTestCase(unittest.TestCase):          with pytest.raises(BlobAlreadyExistsError):              yield self.manager.put(doc2, len(content))          self.assertFalse(self.manager._encrypt_and_upload.called) + +    @defer.inlineCallbacks +    @pytest.mark.usefixtures("method_tmpdir") +    def test_delete_from_local_and_remote(self): +        self.manager._encrypt_and_upload = Mock(return_value=None) +        self.manager._delete_from_remote = Mock(return_value=None) +        content = "Blob content" +        doc1 = BlobDoc(BytesIO(content), 'blob_id') +        yield self.manager.put(doc1, len(content)) +        yield self.manager.delete('blob_id') +        local_list = yield self.manager.local_list() +        self.assertEquals(0, len(local_list)) +        self.manager._delete_from_remote.assert_called_with('blob_id') diff --git a/testing/tests/blobs/test_fs_backend.py b/testing/tests/blobs/test_fs_backend.py index f6f2db2d..83a5708e 100644 --- a/testing/tests/blobs/test_fs_backend.py +++ b/testing/tests/blobs/test_fs_backend.py @@ -120,3 +120,11 @@ class FilesystemBackendTestCase(unittest.TestCase):              yield backend.write_blob('valid', '../../../', DummyRequest(['']))          with pytest.raises(Exception):              yield backend.write_blob('../../../', 'valid', DummyRequest([''])) + +    @pytest.mark.usefixtures("method_tmpdir") +    @mock.patch('leap.soledad.server._blobs.os.unlink') +    def test_delete_blob(self, unlink_mock): +        backend = _blobs.FilesystemBlobsBackend(self.tempdir) +        backend.delete_blob('user', 'blob_id') +        unlink_mock.assert_called_once_with(backend._get_path('user', +                                                              'blob_id')) diff --git a/testing/tests/server/test_blobs_server.py b/testing/tests/server/test_blobs_server.py index cd39833f..2fd66224 100644 --- a/testing/tests/server/test_blobs_server.py +++ b/testing/tests/server/test_blobs_server.py @@ -100,3 +100,14 @@ class BlobServerTestCase(unittest.TestCase):          result = yield manager.local.get(blob_id)          self.assertIsNotNone(result)          self.assertEquals(result.getvalue(), "X") + +    @defer.inlineCallbacks +    @pytest.mark.usefixtures("method_tmpdir") +    def test_upload_then_delete_updates_list(self): +        manager = BlobManager('', self.uri, self.secret, +                              self.secret, 'user') +        yield manager._encrypt_and_upload('blob_id1', BytesIO("1")) +        yield manager._encrypt_and_upload('blob_id2', BytesIO("2")) +        yield manager._delete_from_remote('blob_id1') +        blobs_list = yield manager.remote_list() +        self.assertEquals(set(['blob_id2']), set(blobs_list))  | 
