From 4587bfcfcacc30180b10454b334ec20c64526332 Mon Sep 17 00:00:00 2001 From: drebs Date: Wed, 2 Jul 2014 12:23:45 -0300 Subject: Split tests and fix for new sync (#4710). --- .../soledad/common/tests/test_sync_deferred.py | 227 +++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 common/src/leap/soledad/common/tests/test_sync_deferred.py (limited to 'common/src/leap/soledad/common/tests/test_sync_deferred.py') diff --git a/common/src/leap/soledad/common/tests/test_sync_deferred.py b/common/src/leap/soledad/common/tests/test_sync_deferred.py new file mode 100644 index 00000000..48e3150f --- /dev/null +++ b/common/src/leap/soledad/common/tests/test_sync_deferred.py @@ -0,0 +1,227 @@ +# -*- coding: utf-8 -*- +# test_sync_deferred.py +# Copyright (C) 2014 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +""" +Test Leap backend bits: sync with deferred encryption/decryption. +""" +import time +import os +import random +import string +from urlparse import urljoin + +from leap.soledad.common.tests import u1db_tests as tests, ADDRESS +from leap.soledad.common.tests.u1db_tests import test_sync + +from leap.soledad.common.document import SoledadDocument +from leap.soledad.common import couch +from leap.soledad.client import target +from leap.soledad.client.sync import SoledadSynchronizer + +# Just to make clear how this test is different... :) +DEFER_DECRYPTION = True + +WAIT_STEP = 1 +MAX_WAIT = 10 + +from leap.soledad.common.tests import test_sqlcipher as ts +from leap.soledad.server import SoledadApp + + +from leap.soledad.client.sqlcipher import open as open_sqlcipher +from leap.soledad.common.tests.util import SoledadWithCouchServerMixin +from leap.soledad.common.tests.util import make_soledad_app + + +DBPASS = "pass" + + +class BaseSoledadDeferredEncTest(SoledadWithCouchServerMixin): + """ + Another base class for testing the deferred encryption/decryption during + the syncs, using the intermediate database. + """ + defer_sync_encryption = True + + def setUp(self): + # config info + self.db1_file = os.path.join(self.tempdir, "db1.u1db") + self.db_pass = DBPASS + self.email = ADDRESS + + # get a random prefix for each test, so we do not mess with + # concurrency during initialization and shutting down of + # each local db. + self.rand_prefix = ''.join( + map(lambda x: random.choice(string.ascii_letters), range(6))) + # initialize soledad by hand so we can control keys + self._soledad = self._soledad_instance( + prefix=self.rand_prefix, user=self.email) + + # open test dbs: db1 will be the local sqlcipher db + # (which instantiates a syncdb) + self.db1 = open_sqlcipher(self.db1_file, DBPASS, create=True, + document_factory=SoledadDocument, + crypto=self._soledad._crypto, + defer_encryption=True) + self.db2 = couch.CouchDatabase.open_database( + urljoin( + 'http://localhost:' + str(self.wrapper.port), 'test'), + create=True, + ensure_ddocs=True) + + def tearDown(self): + self.db1.close() + self.db2.close() + self._soledad.close() + + # XXX should not access "private" attrs + for f in [self._soledad._local_db_path, + self._soledad._secrets_path, + self.db1._sync_db_path]: + if os.path.isfile(f): + os.unlink(f) + + +#SQLCIPHER_SCENARIOS = [ +# ('http', { +# #'make_app_with_state': test_sync_target.make_token_soledad_app, +# 'make_app_with_state': make_soledad_app, +# 'make_database_for_test': ts.make_sqlcipher_database_for_test, +# 'copy_database_for_test': ts.copy_sqlcipher_database_for_test, +# 'make_document_for_test': ts.make_document_for_test, +# 'token': True +# }), +#] + + +class SyncTimeoutError(Exception): + """ + Dummy exception to notify timeout during sync. + """ + pass + + +class TestSoledadDbSyncDeferredEncDecr( + BaseSoledadDeferredEncTest, + test_sync.TestDbSync): + """ + Test db.sync remote sync shortcut. + Case with deferred encryption and decryption: using the intermediate + syncdb. + """ + + scenarios = [ + ('http', { + 'make_app_with_state': make_soledad_app, + 'make_database_for_test': tests.make_memory_database_for_test, + }), + ] + + oauth = False + token = True + + def setUp(self): + """ + Need to explicitely invoke inicialization on all bases. + """ + tests.TestCaseWithServer.setUp(self) + self.main_test_class = test_sync.TestDbSync + BaseSoledadDeferredEncTest.setUp(self) + self.startServer() + self.syncer = None + + def tearDown(self): + """ + Need to explicitely invoke destruction on all bases. + """ + BaseSoledadDeferredEncTest.tearDown(self) + tests.TestCaseWithServer.tearDown(self) + + def do_sync(self, target_name): + """ + Perform sync using SoledadSynchronizer, SoledadSyncTarget + and Token auth. + """ + if self.token: + extra = dict(creds={'token': { + 'uuid': 'user-uuid', + 'token': 'auth-token', + }}) + target_url = self.getURL(target_name) + syncdb = getattr(self.db1, "_sync_db", None) + + syncer = SoledadSynchronizer( + self.db1, + target.SoledadSyncTarget( + target_url, + crypto=self._soledad._crypto, + sync_db=syncdb, + **extra)) + # Keep a reference to be able to know when the sync + # has finished. + self.syncer = syncer + return syncer.sync( + autocreate=True, defer_decryption=DEFER_DECRYPTION) + else: + return test_sync.TestDbSync.do_sync(self, target_name) + + def wait_for_sync(self): + """ + Wait for sync to finish. + """ + wait = 0 + syncer = self.syncer + if syncer is not None: + while syncer.syncing: + time.sleep(WAIT_STEP) + wait += WAIT_STEP + if wait >= MAX_WAIT: + raise SyncTimeoutError + + def test_db_sync(self): + """ + Test sync. + + Adapted to check for encrypted content. + """ + doc1 = self.db1.create_doc_from_json(tests.simple_doc) + doc2 = self.db2.create_doc_from_json(tests.nested_doc) + + import time + # need to give time to the encryption to proceed + # TODO should implement a defer list to subscribe to the all-decrypted + # event + time.sleep(2) + + local_gen_before_sync = self.do_sync('test') + self.wait_for_sync() + + gen, _, changes = self.db1.whats_changed(local_gen_before_sync) + self.assertEqual(1, len(changes)) + + self.assertEqual(doc2.doc_id, changes[0][0]) + self.assertEqual(1, gen - local_gen_before_sync) + + self.assertGetEncryptedDoc( + self.db2, doc1.doc_id, doc1.rev, tests.simple_doc, False) + self.assertGetEncryptedDoc( + self.db1, doc2.doc_id, doc2.rev, tests.nested_doc, False) + + def test_db_sync_autocreate(self): + pass + +load_tests = tests.load_with_scenarios -- cgit v1.2.3