diff options
Diffstat (limited to 'common')
6 files changed, 112 insertions, 11 deletions
| diff --git a/common/changes/feature_4836_allow-sync-of-large-files b/common/changes/feature_4836_allow-sync-of-large-files new file mode 100644 index 00000000..f124e899 --- /dev/null +++ b/common/changes/feature_4836_allow-sync-of-large-files @@ -0,0 +1 @@ +  o Allow sync of large files (~100MB) (#4836). diff --git a/common/src/leap/soledad/common/couch.py b/common/src/leap/soledad/common/couch.py index 45ca4282..3ca3f408 100644 --- a/common/src/leap/soledad/common/couch.py +++ b/common/src/leap/soledad/common/couch.py @@ -27,7 +27,7 @@ import socket  from couchdb.client import Server -from couchdb.http import ResourceNotFound, Unauthorized, ServerError +from couchdb.http import ResourceNotFound, Unauthorized, ServerError, Session  from u1db import query_parser, vectorclock  from u1db.errors import (      DatabaseDoesNotExist, @@ -50,6 +50,9 @@ from leap.soledad.common.document import SoledadDocument  logger = logging.getLogger(__name__) +COUCH_TIMEOUT = 120  # timeout for transfers between Soledad server and Couch + +  class InvalidURLError(Exception):      """      Exception raised when Soledad encounters a malformed URL. @@ -275,6 +278,8 @@ class CouchDatabase(CommonBackend):          # save params          self._url = url          self._full_commit = full_commit +        if session is None: +            session = Session(timeout=COUCH_TIMEOUT)          self._session = session          self._factory = CouchDocument          self._real_replica_uid = None diff --git a/common/src/leap/soledad/common/tests/couchdb.ini.template b/common/src/leap/soledad/common/tests/couchdb.ini.template index 217ae201..1fc2205b 100644 --- a/common/src/leap/soledad/common/tests/couchdb.ini.template +++ b/common/src/leap/soledad/common/tests/couchdb.ini.template @@ -6,7 +6,7 @@  database_dir = %(tempdir)s/lib  view_index_dir = %(tempdir)s/lib  max_document_size = 4294967296 ; 4 GB -os_process_timeout = 5000 ; 5 seconds. for view and external servers. +os_process_timeout = 120000 ; 120 seconds. for view and external servers.  max_dbs_open = 100  delayed_commits = true ; set this to false to ensure an fsync before 201 Created is returned  uri_file = %(tempdir)s/lib/couch.uri diff --git a/common/src/leap/soledad/common/tests/test_couch.py b/common/src/leap/soledad/common/tests/test_couch.py index 0e07575d..dc0ea906 100644 --- a/common/src/leap/soledad/common/tests/test_couch.py +++ b/common/src/leap/soledad/common/tests/test_couch.py @@ -81,9 +81,10 @@ class CouchDBWrapper(object):          mkdir_p(os.path.join(self.tempdir, 'lib'))          mkdir_p(os.path.join(self.tempdir, 'log'))          args = ['couchdb', '-n', '-a', confPath] -        #null = open('/dev/null', 'w') +        null = open('/dev/null', 'w') +          self.process = subprocess.Popen( -            args, env=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, +            args, env=None, stdout=null.fileno(), stderr=null.fileno(),              close_fds=True)          # find port          logPath = os.path.join(self.tempdir, 'log', 'couch.log') @@ -126,21 +127,21 @@ class CouchDBTestCase(unittest.TestCase):      TestCase base class for tests against a real CouchDB server.      """ -    def setUp(self): +    @classmethod +    def setUpClass(cls):          """          Make sure we have a CouchDB instance for a test.          """ -        self.wrapper = CouchDBWrapper() -        self.wrapper.start() +        cls.wrapper = CouchDBWrapper() +        cls.wrapper.start()          #self.db = self.wrapper.db -        unittest.TestCase.setUp(self) -    def tearDown(self): +    @classmethod +    def tearDownClass(cls):          """          Stop CouchDB instance for test.          """ -        self.wrapper.stop() -        unittest.TestCase.tearDown(self) +        cls.wrapper.stop()  #----------------------------------------------------------------------------- diff --git a/common/src/leap/soledad/common/tests/test_couch_operations_atomicity.py b/common/src/leap/soledad/common/tests/test_couch_operations_atomicity.py index 8b001859..5384d465 100644 --- a/common/src/leap/soledad/common/tests/test_couch_operations_atomicity.py +++ b/common/src/leap/soledad/common/tests/test_couch_operations_atomicity.py @@ -100,6 +100,7 @@ class CouchAtomicityTestCase(CouchDBTestCase, TestCaseWithServer):          self.tempdir = tempfile.mkdtemp(prefix="leap_tests-")      def tearDown(self): +        self.db.delete_database()          CouchDBTestCase.tearDown(self)          TestCaseWithServer.tearDown(self) diff --git a/common/src/leap/soledad/common/tests/test_server.py b/common/src/leap/soledad/common/tests/test_server.py index 83df192b..06595ed2 100644 --- a/common/src/leap/soledad/common/tests/test_server.py +++ b/common/src/leap/soledad/common/tests/test_server.py @@ -25,6 +25,7 @@ import tempfile  import simplejson as json  import mock  import time +import binascii  from leap.common.testing.basetest import BaseLeapTest @@ -376,6 +377,7 @@ class EncryptedSyncTestCase(          doc2 = doclist[0]          # assert incoming doc is equal to the first sent doc          self.assertEqual(doc1, doc2) +        db.delete_database()      def test_encrypted_sym_sync_with_unicode_passphrase(self):          """ @@ -434,8 +436,93 @@ class EncryptedSyncTestCase(          doc2 = doclist[0]          # assert incoming doc is equal to the first sent doc          self.assertEqual(doc1, doc2) +        db.delete_database() + +    def test_sync_very_large_files(self): +        """ +        Test if Soledad can sync very large files. +        """ +        # define the size of the "very large file" +        length = 100*(10**6)  # 100 MB +        self.startServer() +        # instantiate soledad and create a document +        sol1 = self._soledad_instance( +            # token is verified in test_target.make_token_soledad_app +            auth_token='auth-token' +        ) +        _, doclist = sol1.get_all_docs() +        self.assertEqual([], doclist) +        content = binascii.hexlify(os.urandom(length/2))  # len() == length +        doc1 = sol1.create_doc({'data': content}) +        # sync with server +        sol1._server_url = self.getURL() +        sol1.sync() +        # instantiate soledad with empty db, but with same secrets path +        sol2 = self._soledad_instance(prefix='x', auth_token='auth-token') +        _, doclist = sol2.get_all_docs() +        self.assertEqual([], doclist) +        sol2._secrets_path = sol1.secrets_path +        sol2._load_secrets() +        sol2._set_secret_id(sol1._secret_id) +        # sync the new instance +        sol2._server_url = self.getURL() +        sol2.sync() +        _, doclist = sol2.get_all_docs() +        self.assertEqual(1, len(doclist)) +        doc2 = doclist[0] +        # assert incoming doc is equal to the first sent doc +        self.assertEqual(doc1, doc2) +        # delete remote database +        db = CouchDatabase( +            self._couch_url, +            # the name of the user database is "user-<uuid>". +            'user-user-uuid', +        ) +        db.delete_database() +    def test_sync_many_small_files(self): +        """ +        Test if Soledad can sync many smallfiles. +        """ +        number_of_docs = 100 +        self.startServer() +        # instantiate soledad and create a document +        sol1 = self._soledad_instance( +            # token is verified in test_target.make_token_soledad_app +            auth_token='auth-token' +        ) +        _, doclist = sol1.get_all_docs() +        self.assertEqual([], doclist) +        # create many small files +        for i in range(0, number_of_docs): +            sol1.create_doc(json.loads(simple_doc)) +        # sync with server +        sol1._server_url = self.getURL() +        sol1.sync() +        # instantiate soledad with empty db, but with same secrets path +        sol2 = self._soledad_instance(prefix='x', auth_token='auth-token') +        _, doclist = sol2.get_all_docs() +        self.assertEqual([], doclist) +        sol2._secrets_path = sol1.secrets_path +        sol2._load_secrets() +        sol2._set_secret_id(sol1._secret_id) +        # sync the new instance +        sol2._server_url = self.getURL() +        sol2.sync() +        _, doclist = sol2.get_all_docs() +        self.assertEqual(number_of_docs, len(doclist)) +        # assert incoming docs are equal to sent docs +        for doc in doclist: +            self.assertEqual(sol1.get_doc(doc.doc_id), doc) +        # delete remote database +        db = CouchDatabase( +            self._couch_url, +            # the name of the user database is "user-<uuid>". +            'user-user-uuid', +        ) +        db.delete_database() +  class LockResourceTestCase(          CouchDBTestCase, TestCaseWithServer):      """ @@ -461,6 +548,12 @@ class LockResourceTestCase(      def tearDown(self):          CouchDBTestCase.tearDown(self)          TestCaseWithServer.tearDown(self) +        # delete remote database +        db = CouchDatabase( +            self._couch_url, +            'shared', +        ) +        db.delete_database()      def test__try_obtain_filesystem_lock(self):          responder = mock.Mock() | 
