class BindServerTest(unittest.TestCase): def setUp(self): self.tmpdir = os.path.join(os.environ.get('WORKSPACE', ''), 'tmp') self.addCleanup(clean_dir, self.tmpdir) if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) self.local_test_folder = tempfile.mkdtemp(u'-nxdrive-temp-config', dir=self.tmpdir) self.nxdrive_conf_folder = os.path.join(self.local_test_folder, u'nuxeo-drive-conf') self.nuxeo_url = os.environ.get('NXDRIVE_TEST_NUXEO_URL', "http://localhost:8080/nuxeo") self.user = os.environ.get('NXDRIVE_TEST_USER', "Administrator") self.password = os.environ.get('NXDRIVE_TEST_PASSWORD', "Administrator") def tearDown(self): Manager._singleton = None @Options.mock() def test_bind_local_folder_on_config_folder(self): Options.delay = TEST_DEFAULT_DELAY Options.nxdrive_home = self.nxdrive_conf_folder self.manager = Manager() self.addCleanup(self.manager.unbind_all) self.addCleanup(self.manager.dispose_all) with self.assertRaises(FolderAlreadyUsed): self.manager.bind_server(self.nxdrive_conf_folder, self.nuxeo_url, self.user, self.password, start_engine=False)
class ReportTest(unittest.TestCase): def setUp(self): self.folder = tempfile.mkdtemp(u'-nxdrive-tests') from mock import Mock options = Mock() options.debug = False options.force_locale = None options.proxy_server = None options.log_level_file = None options.update_site_url = None options.beta_update_site_url = None options.nxdrive_home = self.folder self.manager = Manager(options) def tearDown(self): # Remove singleton self.manager.dispose_db() Manager._singleton = None clean_dir(self.folder) def testLogs(self): from nxdrive.osi import AbstractOSIntegration if AbstractOSIntegration.is_windows(): raise SkipTest("Temporarily skipped, need to investigate") # NXDRIVE-358 report = Report(self.manager, os.path.join(self.folder, "report.zip")) log.debug("Strange encoding \xe9") log.debug(u"Unicode encoding \xe8") report.generate()
class BindServerTest(unittest.TestCase): def setUp(self): self.tmpdir = os.path.join(os.environ.get('WORKSPACE', ''), 'tmp') self.addCleanup(clean_dir, self.tmpdir) if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) self.local_test_folder = tempfile.mkdtemp(u'-nxdrive-temp-config', dir=self.tmpdir) self.nxdrive_conf_folder = os.path.join(self.local_test_folder, u'nuxeo-drive-conf') self.nuxeo_url = os.environ.get('NXDRIVE_TEST_NUXEO_URL', "http://localhost:8080/nuxeo") self.user = os.environ.get('NXDRIVE_TEST_USER', "Administrator") self.password = os.environ.get('NXDRIVE_TEST_PASSWORD', "Administrator") def tearDown(self): Manager._singleton = None @Options.mock() def test_bind_local_folder_on_config_folder(self): Options.delay = TEST_DEFAULT_DELAY Options.nxdrive_home = self.nxdrive_conf_folder self.manager = Manager() self.addCleanup(self.manager.unbind_all) self.addCleanup(self.manager.dispose_all) with self.assertRaises(FolderAlreadyUsed): self.manager.bind_server( self.nxdrive_conf_folder, self.nuxeo_url, self.user, self.password, start_engine=False)
class BindServerTest(unittest.TestCase): def setUp(self): self.tmpdir = os.path.join(os.environ.get("WORKSPACE", ""), "tmp") self.addCleanup(clean_dir, self.tmpdir) if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) self.local_test_folder = tempfile.mkdtemp( "-nxdrive-temp-config", dir=self.tmpdir ) self.nxdrive_conf_folder = os.path.join( self.local_test_folder, "nuxeo-drive-conf" ) def tearDown(self): Manager._singleton = None @Options.mock() def test_bind_local_folder_on_config_folder(self): Options.delay = TEST_DEFAULT_DELAY Options.nxdrive_home = self.nxdrive_conf_folder self.manager = Manager() self.addCleanup(self.manager.unbind_all) self.addCleanup(self.manager.dispose_all) with pytest.raises(FolderAlreadyUsed): self.manager.bind_server( self.nxdrive_conf_folder, pytest.nuxeo_url, pytest.user, pytest.password, start_engine=False, )
def _make_manager(home: str = "", with_engine: bool = True): manager = Manager(home or tmp()) # Force deletion behavior to real deletion for all tests manager.dao.update_config("deletion_behavior", "delete_server") manager.dao.store_bool("show_deletion_prompt", False) request.addfinalizer(manager.close) log.info(f"[FIXTURE] Created {manager}") if with_engine: conf_folder = manager.home / "nuxeo-conf" user = user_factory() manager.bind_server(conf_folder, nuxeo_url, user.uid, user.password, start_engine=False) # Let the possibility to access user's attributes from the manager manager.user_details = user engine = None for engine_ in manager.engines.values(): engine = engine_ return manager, engine return manager
def test_logs(): log = get_logger(__name__) folder = tempfile.mkdtemp(u'-nxdrive-tests') Options.nxdrive_home = folder manager = Manager() try: log.debug("Strange encoding \xe9") log.debug(u"Unicode encoding \xe8") # Crafted problematic logRecord try: raise ValueError(u'[tests] folder/\xeatre ou ne pas \xeatre.odt') except ValueError as e: log.exception('Oups!') log.exception(repr(e)) log.exception(unicode(e)) # Works but not recommended with pytest.raises(UnicodeEncodeError): log.exception(str(e)) # Using the syntax below will raise the same UnicodeEncodeError # but the logging module takes care of it and just prints out # the exception without raising it. So I let it there FI. # log.exception(e) report = Report(manager, os.path.join(folder, 'report')) report.generate() finally: manager.dispose_db() Manager._singleton = None
def setUp(self): self.folder = tempfile.mkdtemp(u'-nxdrive-tests') from mock import Mock options = Mock() options.debug = False options.force_locale = None options.proxy_server = None options.log_level_file = None options.update_site_url = None options.beta_update_site_url = None options.nxdrive_home = self.folder self.manager = Manager(options)
def test_bind_local_folder_on_config_folder(self): Options.delay = TEST_DEFAULT_DELAY Options.nxdrive_home = self.nxdrive_conf_folder self.manager = Manager() self.addCleanup(self.manager.unbind_all) self.addCleanup(self.manager.dispose_all) with self.assertRaises(FolderAlreadyUsed): self.manager.bind_server(self.nxdrive_conf_folder, self.nuxeo_url, self.user, self.password, start_engine=False)
def test_csv_generation(tmp): session = Session( uid=2, remote_path="/default-domain/UserWorkspaces/Administrator/test_csv", remote_ref="08716a45-7154-4c2a-939c-bb70a7a2805e", status=TransferStatus.DONE, uploaded_items=10, total_items=10, engine="f513f5b371cc11eb85d008002733076e", created_on="2021-02-18 15:15:38", completed_on="2021-02-18 15:15:39", description="icons-svg (+9)", planned_items=10, ) with Manager(tmp()) as manager: session_csv = SessionCsv(manager, session) assert session_csv.output_file.name == "session_2021-02-18_15-15-39.csv" assert session_csv.output_tmp.name == "session_2021-02-18_15-15-39.tmp" session_csv.create_tmp() assert session_csv.output_tmp.is_file() assert not session_csv.output_file.is_file() session_csv.store_data([{ "path": "/default-domain/UserWorkspaces/Administrator/test_csv/toto.txt", "properties": { "dc:title": "Toto file" }, "type": "File", }]) assert not session_csv.output_tmp.is_file() assert session_csv.output_file.is_file()
def test_logs(tmp): log = getLogger(__name__) with Manager(tmp()) as manager: log.info("Strange encoding \xe8 \xe9") # Crafted problematic logRecord try: raise ValueError("[Mock] folder/\xeatre ou ne pas \xeatre.odt") except ValueError as e: log.exception("Oups!") log.exception(repr(e)) log.exception(str(e)) log.exception(e) # Test raw report (calling the Report class manually) report = Report(manager) report.generate() path = report.get_path() assert path.is_file() assert path.suffix == ".zip" # Test the report managed by the Manager path_managed = manager.generate_report() assert path_managed.is_file() assert path_managed.suffix == ".zip"
def test_temporary_csv_cleanup(tmp, user_factory, nuxeo_url): session = Session( uid=2, remote_path="/default-domain/UserWorkspaces/Administrator/test_csv", remote_ref="08716a45-7154-4c2a-939c-bb70a7a2805e", status=TransferStatus.DONE, uploaded_items=10, total_items=10, engine="f513f5b371cc11eb85d008002733076e", created_on="2021-02-18 15:15:38", completed_on="2021-02-18 15:15:39", description="icons-svg (+9)", planned_items=10, ) with Manager(tmp()) as manager: session_csv = SessionCsv(manager, session) session_csv.create_tmp() assert session_csv.output_tmp.is_file() assert not session_csv.output_file.is_file() conf_folder = manager.home / "nuxeo-conf" user = user_factory() manager.bind_server( conf_folder, nuxeo_url, user.uid, password=user.properties["password"], start_engine=False, ) assert not session_csv.output_tmp.is_file()
class BindServerTest(unittest.TestCase): def setUp(self): self.build_workspace = os.environ.get('WORKSPACE') self.tmp_dir = None if self.build_workspace is not None: self.tmp_dir = os.path.join(self.build_workspace, "tmp") if not os.path.isdir(self.tmp_dir): os.makedirs(self.tmp_dir) self.local_test_folder = tempfile.mkdtemp(u'-nxdrive-temp-config', dir=self.tmp_dir) self.nxdrive_conf_folder = os.path.join(self.local_test_folder, u'nuxeo-drive-conf') self.nuxeo_url = os.environ.get('NXDRIVE_TEST_NUXEO_URL', "http://localhost:8080/nuxeo") self.user = os.environ.get('NXDRIVE_TEST_USER', "Administrator") self.password = os.environ.get('NXDRIVE_TEST_PASSWORD', "Administrator") def tearDown(self): self.manager.unbind_all() self.manager.dispose_all() Manager._singleton = None clean_dir(self.local_test_folder) def test_bind_local_folder_on_config_folder(self): options = Mock() options.debug = False options.delay = TEST_DEFAULT_DELAY options.force_locale = None options.proxy_server = None options.log_level_file = None options.update_site_url = None options.beta_update_site_url = None options.nxdrive_home = self.nxdrive_conf_folder self.manager = Manager(options) with self.assertRaises(FolderAlreadyUsed): self.manager.bind_server(self.nxdrive_conf_folder, self.nuxeo_url, self.user, self.password, start_engine=False)
def test_bind_local_folder_on_config_folder(self): options = Mock() options.debug = False options.delay = TEST_DEFAULT_DELAY options.force_locale = None options.proxy_server = None options.log_level_file = None options.update_site_url = None options.beta_update_site_url = None options.nxdrive_home = self.nxdrive_conf_folder self.manager = Manager(options) with self.assertRaises(FolderAlreadyUsed): self.manager.bind_server(self.nxdrive_conf_folder, self.nuxeo_url, self.user, self.password, start_engine=False)
def test_cli_args(tmp): url = "http://*****:*****@localhost:8899" Options.set("proxy_server", url, setter="cli") with Manager(tmp()) as manager: proxy = manager.proxy assert isinstance(proxy, ManualProxy) assert proxy.url == url settings = proxy.settings() assert settings["http"] == settings["https"] == url
def test_bind_local_folder_on_config_folder(self): Options.delay = TEST_DEFAULT_DELAY Options.nxdrive_home = self.nxdrive_conf_folder self.manager = Manager() self.addCleanup(self.manager.unbind_all) self.addCleanup(self.manager.dispose_all) with self.assertRaises(FolderAlreadyUsed): self.manager.bind_server( self.nxdrive_conf_folder, self.nuxeo_url, self.user, self.password, start_engine=False)
def _create_manager(self): options = Mock() options.debug = False options.force_locale = None options.log_level_file = None options.proxy_server = None options.update_site_url = None options.beta_update_site_url = None options.nxdrive_home = self.test_folder manager = Manager(options) return manager
def test_logs(): log = getLogger(__name__) folder = tempfile.mkdtemp("-nxdrive-tests") Options.nxdrive_home = folder manager = Manager() try: log.debug("Strange encoding \xe8 \xe9") # Crafted problematic logRecord try: raise ValueError("[tests] folder/\xeatre ou ne pas \xeatre.odt") except ValueError as e: log.exception("Oups!") log.exception(repr(e)) log.exception(str(e)) log.exception(e) report = Report(manager, os.path.join(folder, "report")) report.generate() finally: manager.dispose_db() Manager._singleton = None
def test_cli_args(): url = "http://*****:*****@localhost:8899" Options.set("proxy_server", url, setter="cli") manager = Manager() proxy = manager.proxy assert proxy assert isinstance(proxy, ManualProxy) assert proxy.authenticated assert proxy.scheme == "http" assert proxy.host == "localhost" assert proxy.port == 8899 assert proxy.username == "username" assert proxy.password == "password" settings = proxy.settings() assert settings["http"] == settings["https"] == url manager.stop() manager.unbind_all() manager.dispose_all() Manager._singleton = None
def test_notifications(tmp): from nxdrive.notification import Notification notif = Notification("warning", flags=Notification.FLAG_DISCARDABLE) notif2 = Notification("plop") with Manager(tmp()) as manager: dao = manager.dao dao.insert_notification(notif) dao.insert_notification(notif2) assert len(dao.get_notifications()) == 2 dao.discard_notification(notif.uid) assert len(dao.get_notifications(discarded=False)) == 1 assert len(dao.get_notifications()) == 2 dao.remove_notification(notif.uid) assert len(dao.get_notifications()) == 1 dao.discard_notification(notif2.uid) assert len(dao.get_notifications()) == 1 assert len(dao.get_notifications(discarded=True)) == 1
def test_autolock(tmp): with Manager(tmp()) as manager: dao = manager.dao dao.lock_path("/test_1", 1, "doc_id_1") dao.lock_path("/test_2", 2, "doc_id_2") dao.lock_path("/test_3", 3, "doc_id_3") # Verify that it does fail dao.lock_path("/test_3", 4, "doc_id_4") assert len(dao.get_locked_paths()) == 3 dao.unlock_path("/test") assert len(dao.get_locked_paths()) == 3 dao.unlock_path("/test_1") locks = dao.get_locks() assert len(locks) == 2 assert locks[0].path == "/test_2" assert locks[0].process == 2 assert locks[0].remote_id == "doc_id_2" assert locks[1].path == "/test_3" # Verify it has auto-update assert locks[1].process == 4 assert locks[1].remote_id == "doc_id_4"
def get_manager(self, options): from nxdrive.manager import Manager return Manager(options)
class UnitTestCase(unittest.TestCase): def setUpApp(self, server_profile=None): # Check the Nuxeo server test environment self.nuxeo_url = os.environ.get("NXDRIVE_TEST_NUXEO_URL") self.admin_user = os.environ.get("NXDRIVE_TEST_USER") self.password = os.environ.get("NXDRIVE_TEST_PASSWORD") self.build_workspace = os.environ.get("WORKSPACE") self.result = None self.tearedDown = False # Take default parameter if none has been set if self.nuxeo_url is None: self.nuxeo_url = "http://localhost:8080/nuxeo" if self.admin_user is None: self.admin_user = "******" if self.password is None: self.password = "******" self.tmpdir = None if self.build_workspace is not None: self.tmpdir = os.path.join(self.build_workspace, "tmp") if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) if None in (self.nuxeo_url, self.admin_user, self.password): raise unittest.SkipTest("No integration server configuration found in environment.") # Check the local filesystem test environment self.local_test_folder_1 = tempfile.mkdtemp(u"-nxdrive-tests-user-1", dir=self.tmpdir) self.local_test_folder_2 = tempfile.mkdtemp(u"-nxdrive-tests-user-2", dir=self.tmpdir) self.local_nxdrive_folder_1 = os.path.join(self.local_test_folder_1, u"Nuxeo Drive") os.mkdir(self.local_nxdrive_folder_1) self.local_nxdrive_folder_2 = os.path.join(self.local_test_folder_2, u"Nuxeo Drive") os.mkdir(self.local_nxdrive_folder_2) self.nxdrive_conf_folder_1 = os.path.join(self.local_test_folder_1, u"nuxeo-drive-conf") os.mkdir(self.nxdrive_conf_folder_1) self.nxdrive_conf_folder_2 = os.path.join(self.local_test_folder_2, u"nuxeo-drive-conf") os.mkdir(self.nxdrive_conf_folder_2) from mock import Mock options = Mock() options.debug = False options.delay = TEST_DEFAULT_DELAY options.force_locale = None options.proxy_server = None options.log_level_file = None options.update_site_url = None options.beta_update_site_url = None options.autolock_interval = 30 options.nxdrive_home = self.nxdrive_conf_folder_1 self.manager_1 = Manager(options) import nxdrive nxdrive_path = os.path.dirname(nxdrive.__file__) i18n_path = os.path.join(nxdrive_path, "tests", "resources", "i18n.js") Translator(self.manager_1, i18n_path) options.nxdrive_home = self.nxdrive_conf_folder_2 Manager._singleton = None self.manager_2 = Manager(options) self.version = __version__ # Long timeout for the root client that is responsible for the test # environment set: this client is doing the first query on the Nuxeo # server and might need to wait for a long time without failing for # Nuxeo to finish initialize the repo on the first request after # startup root_remote_client = RemoteDocumentClient( self.nuxeo_url, self.admin_user, u"nxdrive-test-administrator-device", self.version, password=self.password, base_folder=u"/", timeout=60, ) # Activate given profile if needed, eg. permission hierarchy if server_profile is not None: root_remote_client.activate_profile(server_profile) # Call the Nuxeo operation to setup the integration test environment credentials = root_remote_client.execute( "NuxeoDrive.SetupIntegrationTests", userNames="user_1, user_2", permission="ReadWrite" ) credentials = [c.strip().split(u":") for c in credentials.split(u",")] self.user_1, self.password_1 = credentials[0] self.user_2, self.password_2 = credentials[1] self.engine_1 = self.manager_1.bind_server( self.local_nxdrive_folder_1, self.nuxeo_url, self.user_1, self.password_1, start_engine=False ) self.engine_2 = self.manager_2.bind_server( self.local_nxdrive_folder_2, self.nuxeo_url, self.user_2, self.password_2, start_engine=False ) self.engine_1.syncCompleted.connect(self.app.sync_completed) self.engine_1.get_remote_watcher().remoteScanFinished.connect(self.app.remote_scan_completed) self.engine_1.get_remote_watcher().changesFound.connect(self.app.remote_changes_found) self.engine_1.get_remote_watcher().noChangesFound.connect(self.app.no_remote_changes_found) self.engine_2.syncCompleted.connect(self.app.sync_completed) self.engine_2.get_remote_watcher().remoteScanFinished.connect(self.app.remote_scan_completed) self.engine_2.get_remote_watcher().changesFound.connect(self.app.remote_changes_found) self.engine_2.get_remote_watcher().noChangesFound.connect(self.app.no_remote_changes_found) self.queue_manager_1 = self.engine_1.get_queue_manager() self.queue_manager_2 = self.engine_2.get_queue_manager() ws_info = root_remote_client.fetch(TEST_WORKSPACE_PATH) self.workspace = ws_info[u"uid"] self.workspace_title = ws_info[u"title"] self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1, self.workspace_title) self.sync_root_folder_2 = os.path.join(self.local_nxdrive_folder_2, self.workspace_title) self.local_root_client_1 = self.engine_1.get_local_client() self.local_root_client_2 = self.engine_2.get_local_client() self.local_client_1 = LocalClient(os.path.join(self.local_nxdrive_folder_1, self.workspace_title)) self.local_client_2 = LocalClient(os.path.join(self.local_nxdrive_folder_2, self.workspace_title)) # Document client to be used to create remote test documents # and folders self.upload_tmp_dir = tempfile.mkdtemp(u"-nxdrive-uploads", dir=self.tmpdir) remote_document_client_1 = RemoteDocumentClient( self.nuxeo_url, self.user_1, u"nxdrive-test-device-1", self.version, password=self.password_1, base_folder=self.workspace, upload_tmp_dir=self.upload_tmp_dir, ) remote_document_client_2 = RemoteDocumentClient( self.nuxeo_url, self.user_2, u"nxdrive-test-device-2", self.version, password=self.password_2, base_folder=self.workspace, upload_tmp_dir=self.upload_tmp_dir, ) # File system client to be used to create remote test documents # and folders remote_file_system_client_1 = RemoteFileSystemClient( self.nuxeo_url, self.user_1, u"nxdrive-test-device-1", self.version, password=self.password_1, upload_tmp_dir=self.upload_tmp_dir, ) remote_file_system_client_2 = RemoteFileSystemClient( self.nuxeo_url, self.user_2, u"nxdrive-test-device-2", self.version, password=self.password_2, upload_tmp_dir=self.upload_tmp_dir, ) self.remote_restapi_client_1 = RestAPIClient( self.nuxeo_url, self.user_1, u"nxdrive-test-device-1", self.version, password=self.password_1 ) self.remote_restapi_client_2 = RestAPIClient( self.nuxeo_url, self.user_2, u"nxdrive-test-device-2", self.version, password=self.password_2 ) # Register root remote_document_client_1.register_as_root(self.workspace) remote_document_client_2.register_as_root(self.workspace) self.root_remote_client = root_remote_client self.remote_document_client_1 = remote_document_client_1 self.remote_document_client_2 = remote_document_client_2 self.remote_file_system_client_1 = remote_file_system_client_1 self.remote_file_system_client_2 = remote_file_system_client_2 self._wait_sync = {self.engine_1.get_uid(): True, self.engine_2.get_uid(): True} self._wait_remote_scan = {self.engine_1.get_uid(): True, self.engine_2.get_uid(): True} self._remote_changes_count = {self.engine_1.get_uid(): 0, self.engine_2.get_uid(): 0} self._no_remote_changes = {self.engine_1.get_uid(): False, self.engine_2.get_uid(): False} def wait_sync( self, wait_for_async=False, timeout=DEFAULT_WAIT_SYNC_TIMEOUT, fail_if_timeout=True, wait_for_engine_1=True, wait_for_engine_2=False, wait_win=False, ): log.debug("Wait for sync") # First wait for server if needed if wait_for_async: self.wait() if sys.platform == "win32" and wait_win: from nxdrive.engine.watcher.local_watcher import WIN_MOVE_RESOLUTION_PERIOD log.trace("Need to wait for Windows delete resolution") sleep(WIN_MOVE_RESOLUTION_PERIOD / 1000) self._wait_sync = {self.engine_1.get_uid(): wait_for_engine_1, self.engine_2.get_uid(): wait_for_engine_2} self._no_remote_changes = { self.engine_1.get_uid(): not wait_for_engine_1, self.engine_2.get_uid(): not wait_for_engine_2, } while timeout > 0: sleep(1) if sum(self._wait_sync.values()) == 0: if wait_for_async: log.debug( "Sync completed, _wait_remote_scan = %r, remote changes count = %r," " no remote changes = %r", self._wait_remote_scan, self._remote_changes_count, self._no_remote_changes, ) wait_remote_scan = False if wait_for_engine_1: wait_remote_scan = self._wait_remote_scan[self.engine_1.get_uid()] if wait_for_engine_2: wait_remote_scan = wait_remote_scan or self._wait_remote_scan[self.engine_2.get_uid()] is_remote_changes = True is_change_summary_over = True if wait_for_engine_1: is_remote_changes = self._remote_changes_count[self.engine_1.get_uid()] > 0 is_change_summary_over = self._no_remote_changes[self.engine_1.get_uid()] if wait_for_engine_2: is_remote_changes = ( is_remote_changes and self._remote_changes_count[self.engine_2.get_uid()] > 0 ) is_change_summary_over = ( is_change_summary_over and self._no_remote_changes[self.engine_2.get_uid()] ) if not wait_remote_scan or is_remote_changes and is_change_summary_over: self._wait_remote_scan = { self.engine_1.get_uid(): wait_for_engine_1, self.engine_2.get_uid(): wait_for_engine_2, } self._remote_changes_count = {self.engine_1.get_uid(): 0, self.engine_2.get_uid(): 0} self._no_remote_changes = {self.engine_1.get_uid(): False, self.engine_2.get_uid(): False} log.debug( "Ended wait for sync, setting _wait_remote_scan values to True," " _remote_changes_count values to 0 and _no_remote_changes values to False" ) return else: log.debug("Sync completed, ended wait for sync") return timeout = timeout - 1 if fail_if_timeout: log.warn("Wait for sync timeout has expired") self.fail("Wait for sync timeout expired") else: log.debug("Wait for sync timeout") def wait_remote_scan( self, timeout=DEFAULT_WAIT_REMOTE_SCAN_TIMEOUT, wait_for_engine_1=True, wait_for_engine_2=False ): log.debug("Wait for remote scan") self._wait_remote_scan = { self.engine_1.get_uid(): wait_for_engine_1, self.engine_2.get_uid(): wait_for_engine_2, } while timeout > 0: sleep(1) if sum(self._wait_remote_scan.values()) == 0: log.debug("Ended wait for remote scan") return timeout = timeout - 1 self.fail("Wait for remote scan timeout expired") def is_profiling(self): return "DRIVE_YAPPI" in os.environ and yappi is not None def setup_profiler(self): if not self.is_profiling(): return yappi.start() def teardown_profiler(self): if not self.is_profiling(): return path = os.environ["DRIVE_YAPPI"] if not os.path.exists(path): os.mkdir(path) report_path = os.path.join(path, self.id() + "-yappi-threads") with open(report_path, "w") as fd: columns = {0: ("name", 80), 1: ("tid", 15), 2: ("ttot", 8), 3: ("scnt", 10)} yappi.get_thread_stats().print_all(out=fd, columns=columns) report_path = os.path.join(path, self.id() + "-yappi-fcts") with open(report_path, "w") as fd: columns = {0: ("name", 80), 1: ("ncall", 5), 2: ("tsub", 8), 3: ("ttot", 8), 4: ("tavg", 8)} stats = yappi.get_func_stats() stats.strip_dirs() stats.print_all(out=fd, columns=columns) log.debug("Profiler Report generated in '%s'", report_path) def run(self, result=None): self.app = TestQApplication([], self) self.setUpApp() self.result = result # TODO Should use a specific application def launch_test(): log.debug("UnitTest thread started") sleep(1) self.setup_profiler() super(UnitTestCase, self).run(result) self.teardown_profiler() self.app.quit() log.debug("UnitTest thread finished") sync_thread = Thread(target=launch_test) sync_thread.start() self.app.exec_() sync_thread.join(30) self.tearDownApp() del self.app log.debug("UnitTest run finished") def tearDown(self): unittest.TestCase.tearDown(self) if not self.tearedDown: self.tearDownApp() def tearDownApp(self, server_profile=None): if self.tearedDown: return import sys if sys.exc_info() != (None, None, None): self.generate_report() elif self.result is not None: if hasattr(self.result, "wasSuccessful") and not self.result.wasSuccessful(): self.generate_report() log.debug("TearDown unit test") # Unbind all self.manager_1.unbind_all() self.manager_1.dispose_db() self.manager_2.unbind_all() self.manager_2.dispose_db() Manager._singleton = None # Don't need to revoke tokens for the file system remote clients # since they use the same users as the remote document clients self.root_remote_client.execute("NuxeoDrive.TearDownIntegrationTests") # Deactivate given profile if needed, eg. permission hierarchy if server_profile is not None: self.root_remote_client.deactivate_profile(server_profile) clean_dir(self.upload_tmp_dir) clean_dir(self.local_test_folder_1) clean_dir(self.local_test_folder_2) del self.engine_1 self.engine_1 = None del self.engine_2 self.engine_2 = None del self.local_client_1 self.local_client_1 = None del self.local_client_2 self.local_client_2 = None del self.remote_document_client_1 self.remote_document_client_1 = None del self.remote_document_client_2 self.remote_document_client_2 = None del self.remote_file_system_client_1 self.remote_file_system_client_1 = None del self.remote_file_system_client_2 self.remote_file_system_client_2 = None self.tearedDown = True def _interact(self, pause=0): self.app.processEvents() if pause > 0: sleep(pause) while self.app.hasPendingEvents(): self.app.processEvents() def make_local_tree(self, root=None, local_client=None): if local_client is None: local_client = self.local_root_client_1 if root is None: root = u"/" + self.workspace_title if not local_client.exists(root): local_client.make_folder(u"/", self.workspace_title) # create some folders folder_1 = local_client.make_folder(root, u"Folder 1") folder_1_1 = local_client.make_folder(folder_1, u"Folder 1.1") folder_1_2 = local_client.make_folder(folder_1, u"Folder 1.2") folder_2 = local_client.make_folder(root, u"Folder 2") # create some files local_client.make_file(folder_2, u"Duplicated File.txt", content=b"Some content.") local_client.make_file(folder_1, u"File 1.txt", content=b"aaa") local_client.make_file(folder_1_1, u"File 2.txt", content=b"bbb") local_client.make_file(folder_1_2, u"File 3.txt", content=b"ccc") local_client.make_file(folder_2, u"File 4.txt", content=b"ddd") local_client.make_file(root, u"File 5.txt", content=b"eee") return (6, 5) def make_server_tree(self): remote_client = self.remote_document_client_1 # create some folders on the server folder_1 = remote_client.make_folder(self.workspace, u"Folder 1") folder_1_1 = remote_client.make_folder(folder_1, u"Folder 1.1") folder_1_2 = remote_client.make_folder(folder_1, u"Folder 1.2") folder_2 = remote_client.make_folder(self.workspace, u"Folder 2") # create some files on the server remote_client.make_file(folder_2, u"Duplicated File.txt", content=b"Some content.") remote_client.make_file(folder_2, u"Duplicated File.txt", content=b"Other content.") remote_client.make_file(folder_1, u"File 1.txt", content=b"aaa") remote_client.make_file(folder_1_1, u"File 2.txt", content=b"bbb") remote_client.make_file(folder_1_2, u"File 3.txt", content=b"ccc") remote_client.make_file(folder_2, u"File 4.txt", content=b"ddd") remote_client.make_file(self.workspace, u"File 5.txt", content=b"eee") return (7, 4) def get_full_queue(self, queue, dao=None): if dao is None: dao = self.engine_1.get_dao() result = [] while len(queue) > 0: result.append(dao.get_state_from_id(queue.pop().id)) return result def generate_report(self): if "REPORT_PATH" not in os.environ: return report_path = os.path.join(os.environ["REPORT_PATH"], self.id()) self.manager_1.generate_report(report_path) log.debug("Report generated in '%s'", report_path) def wait(self, retry=3): try: self.root_remote_client.wait() except Exception as e: log.debug("Exception while waiting for server : %r", e) # Not the nicest if retry > 0: log.debug("Retry to wait") self.wait(retry - 1)
class UnitTestCase(unittest.TestCase): def setUpServer(self, server_profile=None): # Long timeout for the root client that is responsible for the test # environment set: this client is doing the first query on the Nuxeo # server and might need to wait for a long time without failing for # Nuxeo to finish initialize the repo on the first request after # startup self.root_remote_client = RemoteDocumentClient( self.nuxeo_url, self.admin_user, u'nxdrive-test-administrator-device', self.version, password=self.password, base_folder=u'/', timeout=60) # Activate given profile if needed, eg. permission hierarchy if server_profile is not None: self.root_remote_client.activate_profile(server_profile) # Call the Nuxeo operation to setup the integration test environment credentials = self.root_remote_client.execute( "NuxeoDrive.SetupIntegrationTests", userNames="user_1, user_2", permission='ReadWrite') credentials = [c.strip().split(u":") for c in credentials.split(u",")] self.user_1, self.password_1 = credentials[0] self.user_2, self.password_2 = credentials[1] ws_info = self.root_remote_client.fetch(u'/default-domain/workspaces/') children = self.root_remote_client.get_children(ws_info['uid']) log.debug("SuperWorkspace info: %r", ws_info) log.debug("SuperWorkspace children: %r", children) ws_info = self.root_remote_client.fetch(TEST_WORKSPACE_PATH) log.debug("Workspace info: %r", ws_info) self.workspace = ws_info[u'uid'] self.workspace_title = ws_info[u'title'] self.workspace_1 = self.workspace self.workspace_2 = self.workspace self.workspace_title_1 = self.workspace_title self.workspace_title_2 = self.workspace_title def tearDownServer(self, server_profile=None): # Don't need to revoke tokens for the file system remote clients # since they use the same users as the remote document clients self.root_remote_client.execute("NuxeoDrive.TearDownIntegrationTests") # Deactivate given profile if needed, eg. permission hierarchy if server_profile is not None: self.root_remote_client.deactivate_profile(server_profile) def get_local_client(self, path): if AbstractOSIntegration.is_windows(): from nxdrive.tests.win_local_client import WindowsLocalClient return WindowsLocalClient(path) if AbstractOSIntegration.is_mac(): from nxdrive.tests.mac_local_client import MacLocalClient return MacLocalClient(path) return LocalClient(path) def setUpApp(self, server_profile=None): # Check the Nuxeo server test environment self.nuxeo_url = os.environ.get('NXDRIVE_TEST_NUXEO_URL') self.admin_user = os.environ.get('NXDRIVE_TEST_USER') self.password = os.environ.get('NXDRIVE_TEST_PASSWORD') self.build_workspace = os.environ.get('WORKSPACE') self.result = None self.tearedDown = False # Take default parameter if none has been set if self.nuxeo_url is None: self.nuxeo_url = "http://localhost:8080/nuxeo" if self.admin_user is None: self.admin_user = "******" if self.password is None: self.password = "******" self.tmpdir = None if self.build_workspace is not None: self.tmpdir = os.path.join(self.build_workspace, "tmp") if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) self.upload_tmp_dir = tempfile.mkdtemp(u'-nxdrive-uploads', dir=self.tmpdir) if None in (self.nuxeo_url, self.admin_user, self.password): raise unittest.SkipTest( "No integration server configuration found in environment.") # Check the local filesystem test environment self.local_test_folder_1 = tempfile.mkdtemp(u'drive-1', dir=self.tmpdir) self.local_test_folder_2 = tempfile.mkdtemp(u'drive-2', dir=self.tmpdir) self.local_nxdrive_folder_1 = os.path.join(self.local_test_folder_1, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_1) self.local_nxdrive_folder_2 = os.path.join(self.local_test_folder_2, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_2) self.nxdrive_conf_folder_1 = os.path.join(self.local_test_folder_1, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_1) self.nxdrive_conf_folder_2 = os.path.join(self.local_test_folder_2, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_2) from mock import Mock options = Mock() options.debug = False options.delay = TEST_DEFAULT_DELAY options.force_locale = None options.proxy_server = None options.log_level_file = None options.update_site_url = None options.beta_update_site_url = None options.autolock_interval = 30 options.nxdrive_home = self.nxdrive_conf_folder_1 self.manager_1 = Manager(options) self.connected = False import nxdrive nxdrive_path = os.path.dirname(nxdrive.__file__) i18n_path = os.path.join(nxdrive_path, 'tests', 'resources', "i18n.js") Translator(self.manager_1, i18n_path) options.nxdrive_home = self.nxdrive_conf_folder_2 Manager._singleton = None self.manager_2 = Manager(options) self.version = __version__ url = self.nuxeo_url log.debug("Will use %s as url", url) if '#' in url: # Remove the engine type for the rest of the test self.nuxeo_url = url.split('#')[0] self.setUpServer(server_profile) self.engine_1 = self.manager_1.bind_server(self.local_nxdrive_folder_1, url, self.user_1, self.password_1, start_engine=False) self.engine_2 = self.manager_2.bind_server(self.local_nxdrive_folder_2, url, self.user_2, self.password_2, start_engine=False) self.engine_1.syncCompleted.connect(self.app.sync_completed) self.engine_1.get_remote_watcher().remoteScanFinished.connect( self.app.remote_scan_completed) self.engine_1.get_remote_watcher().changesFound.connect( self.app.remote_changes_found) self.engine_1.get_remote_watcher().noChangesFound.connect( self.app.no_remote_changes_found) self.engine_2.syncCompleted.connect(self.app.sync_completed) self.engine_2.get_remote_watcher().remoteScanFinished.connect( self.app.remote_scan_completed) self.engine_2.get_remote_watcher().changesFound.connect( self.app.remote_changes_found) self.engine_2.get_remote_watcher().noChangesFound.connect( self.app.no_remote_changes_found) self.queue_manager_1 = self.engine_1.get_queue_manager() self.queue_manager_2 = self.engine_2.get_queue_manager() self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1, self.workspace_title_1) self.sync_root_folder_2 = os.path.join(self.local_nxdrive_folder_2, self.workspace_title_2) self.local_root_client_1 = self.engine_1.get_local_client() self.local_root_client_2 = self.engine_2.get_local_client() self.local_client_1 = self.get_local_client( os.path.join(self.local_nxdrive_folder_1, self.workspace_title)) self.local_client_2 = self.get_local_client( os.path.join(self.local_nxdrive_folder_2, self.workspace_title)) # Document client to be used to create remote test documents # and folders remote_document_client_1 = RemoteDocumentClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, base_folder=self.workspace_1, upload_tmp_dir=self.upload_tmp_dir) remote_document_client_2 = RemoteDocumentClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, base_folder=self.workspace_2, upload_tmp_dir=self.upload_tmp_dir) # File system client to be used to create remote test documents # and folders remote_file_system_client_1 = RemoteFileSystemClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, upload_tmp_dir=self.upload_tmp_dir) remote_file_system_client_2 = RemoteFileSystemClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, upload_tmp_dir=self.upload_tmp_dir) self.remote_restapi_client_1 = RestAPIClient(self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1) self.remote_restapi_client_2 = RestAPIClient(self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2) self.remote_restapi_client_admin = RestAPIClient( self.nuxeo_url, self.admin_user, u'nxdrive-test-device-2', self.version, password=self.password) # Register root remote_document_client_1.register_as_root(self.workspace_1) remote_document_client_2.register_as_root(self.workspace_2) self.remote_document_client_1 = remote_document_client_1 self.remote_document_client_2 = remote_document_client_2 self.remote_file_system_client_1 = remote_file_system_client_1 self.remote_file_system_client_2 = remote_file_system_client_2 self._wait_sync = { self.engine_1.get_uid(): True, self.engine_2.get_uid(): True } self._wait_remote_scan = { self.engine_1.get_uid(): True, self.engine_2.get_uid(): True } self._remote_changes_count = { self.engine_1.get_uid(): 0, self.engine_2.get_uid(): 0 } self._no_remote_changes = { self.engine_1.get_uid(): False, self.engine_2.get_uid(): False } def wait_sync(self, wait_for_async=False, timeout=DEFAULT_WAIT_SYNC_TIMEOUT, fail_if_timeout=True, wait_for_engine_1=True, wait_for_engine_2=False, wait_win=False, enforce_errors=True): log.debug("Wait for sync") # First wait for server if needed if wait_for_async: self.wait() if sys.platform == "win32" and wait_win: from nxdrive.engine.watcher.local_watcher import WIN_MOVE_RESOLUTION_PERIOD log.trace("Need to wait for Windows delete resolution") sleep(WIN_MOVE_RESOLUTION_PERIOD / 1000) self._wait_sync = { self.engine_1.get_uid(): wait_for_engine_1, self.engine_2.get_uid(): wait_for_engine_2 } self._no_remote_changes = { self.engine_1.get_uid(): not wait_for_engine_1, self.engine_2.get_uid(): not wait_for_engine_2 } if enforce_errors: if not self.connected: self.engine_1.syncPartialCompleted.connect( self.engine_1.get_queue_manager().requeue_errors) self.engine_2.syncPartialCompleted.connect( self.engine_1.get_queue_manager().requeue_errors) self.connected = True elif self.connected: self.engine_1.syncPartialCompleted.disconnect( self.engine_1.get_queue_manager().requeue_errors) self.engine_2.syncPartialCompleted.disconnect( self.engine_1.get_queue_manager().requeue_errors) self.connected = False while timeout > 0: sleep(1) timeout = timeout - 1 if sum(self._wait_sync.values()) == 0: if wait_for_async: log.debug( 'Sync completed, _wait_remote_scan = %r, remote changes count = %r,' ' no remote changes = %r', self._wait_remote_scan, self._remote_changes_count, self._no_remote_changes) wait_remote_scan = False if wait_for_engine_1: wait_remote_scan = self._wait_remote_scan[ self.engine_1.get_uid()] if wait_for_engine_2: wait_remote_scan = wait_remote_scan or self._wait_remote_scan[ self.engine_2.get_uid()] is_remote_changes = True is_change_summary_over = True if wait_for_engine_1: is_remote_changes = self._remote_changes_count[ self.engine_1.get_uid()] > 0 is_change_summary_over = self._no_remote_changes[ self.engine_1.get_uid()] if wait_for_engine_2: is_remote_changes = ( is_remote_changes and self._remote_changes_count[self.engine_2.get_uid()] > 0) is_change_summary_over = ( is_change_summary_over and self._no_remote_changes[self.engine_2.get_uid()]) if (not wait_remote_scan or is_remote_changes and is_change_summary_over): self._wait_remote_scan = { self.engine_1.get_uid(): wait_for_engine_1, self.engine_2.get_uid(): wait_for_engine_2 } self._remote_changes_count = { self.engine_1.get_uid(): 0, self.engine_2.get_uid(): 0 } self._no_remote_changes = { self.engine_1.get_uid(): False, self.engine_2.get_uid(): False } log.debug( 'Ended wait for sync, setting _wait_remote_scan values to True,' ' _remote_changes_count values to 0 and _no_remote_changes values to False' ) return else: log.debug("Sync completed, ended wait for sync") return if fail_if_timeout: log.warn("Wait for sync timeout has expired") if wait_for_engine_1 and self.engine_1.get_dao().get_syncing_count( ) != 0: self.fail("Wait for sync timeout expired") if wait_for_engine_2 and self.engine_2.get_dao().get_syncing_count( ) != 0: self.fail("Wait for sync timeout expired") else: log.debug("Wait for sync timeout") def wait_remote_scan(self, timeout=DEFAULT_WAIT_REMOTE_SCAN_TIMEOUT, wait_for_engine_1=True, wait_for_engine_2=False): log.debug("Wait for remote scan") self._wait_remote_scan = { self.engine_1.get_uid(): wait_for_engine_1, self.engine_2.get_uid(): wait_for_engine_2 } while timeout > 0: sleep(1) if sum(self._wait_remote_scan.values()) == 0: log.debug("Ended wait for remote scan") return timeout = timeout - 1 self.fail("Wait for remote scan timeout expired") def is_profiling(self): return 'DRIVE_YAPPI' in os.environ and yappi is not None def setup_profiler(self): if not self.is_profiling(): return yappi.start() def teardown_profiler(self): if not self.is_profiling(): return path = os.environ["DRIVE_YAPPI"] if not os.path.exists(path): os.mkdir(path) report_path = os.path.join(path, self.id() + '-yappi-threads') with open(report_path, 'w') as fd: columns = { 0: ("name", 80), 1: ("tid", 15), 2: ("ttot", 8), 3: ("scnt", 10) } yappi.get_thread_stats().print_all(out=fd, columns=columns) report_path = os.path.join(path, self.id() + '-yappi-fcts') with open(report_path, 'w') as fd: columns = { 0: ("name", 80), 1: ("ncall", 5), 2: ("tsub", 8), 3: ("ttot", 8), 4: ("tavg", 8) } stats = yappi.get_func_stats() stats.strip_dirs() stats.print_all(out=fd, columns=columns) log.debug("Profiler Report generated in '%s'", report_path) def run(self, result=None): self.logger = log repeat = 1 testMethod = getattr(self, self._testMethodName) if hasattr(testMethod, '_repeat'): repeat = testMethod._repeat while repeat > 0: self.app = TestQApplication([], self) self.setUpApp() self.result = result # TODO Should use a specific application def launch_test(): log.debug("UnitTest thread started") sleep(1) self.setup_profiler() super(UnitTestCase, self).run(result) self.teardown_profiler() self.app.quit() log.debug("UnitTest thread finished") sync_thread = Thread(target=launch_test) sync_thread.start() self.app.exec_() sync_thread.join(30) self.tearDownApp() del self.app repeat -= 1 log.debug("UnitTest run finished") def tearDown(self): unittest.TestCase.tearDown(self) if not self.tearedDown: self.tearDownApp() def tearDownApp(self, server_profile=None): if self.tearedDown: return if sys.exc_info() != (None, None, None): self.generate_report() elif self.result is not None: if hasattr(self.result, "wasSuccessful") and not self.result.wasSuccessful(): self.generate_report() log.debug("TearDown unit test") # Unbind all self.manager_1.unbind_all() self.manager_1.dispose_db() self.manager_2.unbind_all() self.manager_2.dispose_db() Manager._singleton = None self.tearDownServer(server_profile) clean_dir(self.upload_tmp_dir) clean_dir(self.local_test_folder_1) clean_dir(self.local_test_folder_2) del self.engine_1 self.engine_1 = None del self.engine_2 self.engine_2 = None del self.local_client_1 self.local_client_1 = None del self.local_client_2 self.local_client_2 = None del self.remote_document_client_1 self.remote_document_client_1 = None del self.remote_document_client_2 self.remote_document_client_2 = None del self.remote_file_system_client_1 self.remote_file_system_client_1 = None del self.remote_file_system_client_2 self.remote_file_system_client_2 = None self.tearedDown = True def _interact(self, pause=0): self.app.processEvents() if pause > 0: sleep(pause) while (self.app.hasPendingEvents()): self.app.processEvents() def make_local_tree(self, root=None, local_client=None): if local_client is None: local_client = self.local_root_client_1 if root is None: root = u"/" + self.workspace_title if not local_client.exists(root): local_client.make_folder(u"/", self.workspace_title) # create some folders folder_1 = local_client.make_folder(root, u'Folder 1') folder_1_1 = local_client.make_folder(folder_1, u'Folder 1.1') folder_1_2 = local_client.make_folder(folder_1, u'Folder 1.2') folder_2 = local_client.make_folder(root, u'Folder 2') # create some files local_client.make_file(folder_2, u'Duplicated File.txt', content=b"Some content.") local_client.make_file(folder_1, u'File 1.txt', content=b"aaa") local_client.make_file(folder_1_1, u'File 2.txt', content=b"bbb") local_client.make_file(folder_1_2, u'File 3.txt', content=b"ccc") local_client.make_file(folder_2, u'File 4.txt', content=b"ddd") local_client.make_file(root, u'File 5.txt', content=b"eee") return (6, 5) def make_server_tree(self, deep=True): remote_client = self.remote_document_client_1 # create some folders on the server folder_1 = remote_client.make_folder(self.workspace, u'Folder 1') folder_2 = remote_client.make_folder(self.workspace, u'Folder 2') if deep: folder_1_1 = remote_client.make_folder(folder_1, u'Folder 1.1') folder_1_2 = remote_client.make_folder(folder_1, u'Folder 1.2') # create some files on the server if deep: self._duplicate_file_1 = remote_client.make_file( folder_2, u'Duplicated File.txt', content=b"Some content.") self._duplicate_file_2 = remote_client.make_file( folder_2, u'Duplicated File.txt', content=b"Other content.") if deep: remote_client.make_file(folder_1, u'File 1.txt', content=b"aaa") remote_client.make_file(folder_1_1, u'File 2.txt', content=b"bbb") remote_client.make_file(folder_1_2, u'File 3.txt', content=b"ccc") remote_client.make_file(folder_2, u'File 4.txt', content=b"ddd") remote_client.make_file(self.workspace, u'File 5.txt', content=b"eee") return (7, 4) if deep else (1, 2) def get_local_child_count(self, path): dir_count = 0 file_count = 0 for _, dirnames, filenames in os.walk(path): dir_count += len(dirnames) file_count += len(filenames) if os.path.exists(os.path.join(path, '.partials')): dir_count -= 1 return (dir_count, file_count) def get_full_queue(self, queue, dao=None): if dao is None: dao = self.engine_1.get_dao() result = [] while (len(queue) > 0): result.append(dao.get_state_from_id(queue.pop().id)) return result def generate_report(self): if "REPORT_PATH" not in os.environ: return report_path = os.path.join(os.environ["REPORT_PATH"], self.id()) self.manager_1.generate_report(report_path) log.debug("Report generated in '%s'", report_path) def wait(self, retry=3): try: self.root_remote_client.wait() except Exception as e: log.debug("Exception while waiting for server : %r", e) # Not the nicest if retry > 0: log.debug("Retry to wait") self.wait(retry - 1) def _set_read_permission(self, user, doc_path, grant): op_input = "doc:" + doc_path if grant: self.root_remote_client.execute("Document.SetACE", op_input=op_input, user=user, permission="Read", grant="true") else: self.root_remote_client.block_inheritance(doc_path) def generate_random_jpg(self, filename, size): try: import numpy from PIL import Image except: # Create random file with open(filename, 'wb') as f: f.write(os.urandom(1024 * size)) return a = numpy.random.rand(size, size, 3) * 255 im_out = Image.fromarray(a.astype('uint8')).convert('RGBA') im_out.save(filename) def assertNxPart(self, path, name=None, present=True): os_path = self.local_client_1._abspath(path) children = os.listdir(os_path) for child in children: if len(child) < 8: continue if name is not None and len(child) < len(name) + 8: continue if child[0] == "." and child[-7:] == ".nxpart": if name is None or child[1:len(name) + 1] == name: if present: return else: self.fail("nxpart found in : '%s'" % (path)) if present: self.fail("nxpart not found in : '%s'" % (path)) def get_dao_state_from_engine_1(self, path): """ Returns the pair from dao of engine 1 according to the path. :param path: The path to document (from workspace, ex: /Folder is converted to /{{workspace_title_1}}/Folder). :return: The pair from dao of engine 1 according to the path. """ abs_path = '/' + self.workspace_title_1 + path return self.engine_1.get_dao().get_state_from_local(abs_path)
def _append_user_attrs(self, number: int, register_roots: bool) -> None: """Create all stuff needed for one user. Ugly but useful.""" # Create all what we need local_test_folder = self.tmpdir / str(number) local_nxdrive_folder = local_test_folder / "drive" local_nxdrive_folder.mkdir(parents=True) nxdrive_conf_folder = local_test_folder / "conf" nxdrive_conf_folder.mkdir() manager = Manager(nxdrive_conf_folder) user = getattr(self, f"user_{number}") password = getattr(self, f"password_{number}") engine = self.bind_engine( number, start_engine=False, manager=manager, user=user, password=password, folder=local_nxdrive_folder, ) queue_manager = engine.queue_manager sync_root_folder = local_nxdrive_folder / self.workspace_title local_root_client = self.get_local_client(engine.local.base_folder) local = self.get_local_client(sync_root_folder) remote_document_client = DocRemote( self.nuxeo_url, getattr(self, f"user_{number}"), f"nxdrive-test-device-{number}", self.version, password=getattr(self, f"password_{number}"), base_folder=self.workspace, upload_tmp_dir=self.upload_tmp_dir, dao=engine.dao, ) remote = RemoteBase( self.nuxeo_url, getattr(self, f"user_{number}"), f"nxdrive-test-device-{number}", self.version, password=getattr(self, f"password_{number}"), base_folder=self.workspace, upload_tmp_dir=self.upload_tmp_dir, dao=engine.dao, ) if register_roots: remote.register_as_root(self.workspace) # Force deletion behavior to real deletion for all tests manager.set_config("deletion_behavior", "delete_server") manager.dao.store_bool("show_deletion_prompt", False) # And now persist in attributes setattr(self, f"manager_{number}", manager) setattr(self, f"local_test_folder_{number}", local_test_folder) setattr(self, f"local_nxdrive_folder_{number}", local_nxdrive_folder) setattr(self, f"nxdrive_conf_folder_{number}", nxdrive_conf_folder) setattr(self, f"queue_manager_{number}", queue_manager) setattr(self, f"sync_root_folder_{number}", sync_root_folder) setattr(self, f"local_root_client_{number}", local_root_client) setattr(self, f"local_{number}", local) setattr(self, f"remote_document_client_{number}", remote_document_client) setattr(self, f"remote_{number}", remote)
def setUpApp(self, server_profile=None): # Check the Nuxeo server test environment self.nuxeo_url = os.environ.get('NXDRIVE_TEST_NUXEO_URL') self.admin_user = os.environ.get('NXDRIVE_TEST_USER') self.password = os.environ.get('NXDRIVE_TEST_PASSWORD') self.build_workspace = os.environ.get('WORKSPACE') self.result = None self.tearedDown = False # Take default parameter if none has been set if self.nuxeo_url is None: self.nuxeo_url = "http://localhost:8080/nuxeo" if self.admin_user is None: self.admin_user = "******" if self.password is None: self.password = "******" self.tmpdir = None if self.build_workspace is not None: self.tmpdir = os.path.join(self.build_workspace, "tmp") if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) self.upload_tmp_dir = tempfile.mkdtemp(u'-nxdrive-uploads', dir=self.tmpdir) if None in (self.nuxeo_url, self.admin_user, self.password): raise unittest.SkipTest( "No integration server configuration found in environment.") # Check the local filesystem test environment self.local_test_folder_1 = tempfile.mkdtemp(u'drive-1', dir=self.tmpdir) self.local_test_folder_2 = tempfile.mkdtemp(u'drive-2', dir=self.tmpdir) self.local_nxdrive_folder_1 = os.path.join(self.local_test_folder_1, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_1) self.local_nxdrive_folder_2 = os.path.join(self.local_test_folder_2, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_2) self.nxdrive_conf_folder_1 = os.path.join(self.local_test_folder_1, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_1) self.nxdrive_conf_folder_2 = os.path.join(self.local_test_folder_2, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_2) from mock import Mock options = Mock() options.debug = False options.delay = TEST_DEFAULT_DELAY options.force_locale = None options.proxy_server = None options.log_level_file = None options.update_site_url = None options.beta_update_site_url = None options.autolock_interval = 30 options.nxdrive_home = self.nxdrive_conf_folder_1 self.manager_1 = Manager(options) self.connected = False import nxdrive nxdrive_path = os.path.dirname(nxdrive.__file__) i18n_path = os.path.join(nxdrive_path, 'tests', 'resources', "i18n.js") Translator(self.manager_1, i18n_path) options.nxdrive_home = self.nxdrive_conf_folder_2 Manager._singleton = None self.manager_2 = Manager(options) self.version = __version__ url = self.nuxeo_url log.debug("Will use %s as url", url) if '#' in url: # Remove the engine type for the rest of the test self.nuxeo_url = url.split('#')[0] self.setUpServer(server_profile) self.engine_1 = self.manager_1.bind_server(self.local_nxdrive_folder_1, url, self.user_1, self.password_1, start_engine=False) self.engine_2 = self.manager_2.bind_server(self.local_nxdrive_folder_2, url, self.user_2, self.password_2, start_engine=False) self.engine_1.syncCompleted.connect(self.app.sync_completed) self.engine_1.get_remote_watcher().remoteScanFinished.connect( self.app.remote_scan_completed) self.engine_1.get_remote_watcher().changesFound.connect( self.app.remote_changes_found) self.engine_1.get_remote_watcher().noChangesFound.connect( self.app.no_remote_changes_found) self.engine_2.syncCompleted.connect(self.app.sync_completed) self.engine_2.get_remote_watcher().remoteScanFinished.connect( self.app.remote_scan_completed) self.engine_2.get_remote_watcher().changesFound.connect( self.app.remote_changes_found) self.engine_2.get_remote_watcher().noChangesFound.connect( self.app.no_remote_changes_found) self.queue_manager_1 = self.engine_1.get_queue_manager() self.queue_manager_2 = self.engine_2.get_queue_manager() self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1, self.workspace_title_1) self.sync_root_folder_2 = os.path.join(self.local_nxdrive_folder_2, self.workspace_title_2) self.local_root_client_1 = self.engine_1.get_local_client() self.local_root_client_2 = self.engine_2.get_local_client() self.local_client_1 = self.get_local_client( os.path.join(self.local_nxdrive_folder_1, self.workspace_title)) self.local_client_2 = self.get_local_client( os.path.join(self.local_nxdrive_folder_2, self.workspace_title)) # Document client to be used to create remote test documents # and folders remote_document_client_1 = RemoteDocumentClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, base_folder=self.workspace_1, upload_tmp_dir=self.upload_tmp_dir) remote_document_client_2 = RemoteDocumentClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, base_folder=self.workspace_2, upload_tmp_dir=self.upload_tmp_dir) # File system client to be used to create remote test documents # and folders remote_file_system_client_1 = RemoteFileSystemClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, upload_tmp_dir=self.upload_tmp_dir) remote_file_system_client_2 = RemoteFileSystemClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, upload_tmp_dir=self.upload_tmp_dir) self.remote_restapi_client_1 = RestAPIClient(self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1) self.remote_restapi_client_2 = RestAPIClient(self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2) self.remote_restapi_client_admin = RestAPIClient( self.nuxeo_url, self.admin_user, u'nxdrive-test-device-2', self.version, password=self.password) # Register root remote_document_client_1.register_as_root(self.workspace_1) remote_document_client_2.register_as_root(self.workspace_2) self.remote_document_client_1 = remote_document_client_1 self.remote_document_client_2 = remote_document_client_2 self.remote_file_system_client_1 = remote_file_system_client_1 self.remote_file_system_client_2 = remote_file_system_client_2 self._wait_sync = { self.engine_1.get_uid(): True, self.engine_2.get_uid(): True } self._wait_remote_scan = { self.engine_1.get_uid(): True, self.engine_2.get_uid(): True } self._remote_changes_count = { self.engine_1.get_uid(): 0, self.engine_2.get_uid(): 0 } self._no_remote_changes = { self.engine_1.get_uid(): False, self.engine_2.get_uid(): False }
def setUpApp(self, server_profile=None, register_roots=True): if Manager._singleton: Manager._singleton = None # Install callback early to be called the last self.addCleanup(self._check_cleanup) self.report_path = os.environ.get("REPORT_PATH") self.tmpdir = os.path.join(os.environ.get("WORKSPACE", ""), "tmp") self.addCleanup(clean_dir, self.tmpdir) if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) self.upload_tmp_dir = tempfile.mkdtemp("-nxdrive-uploads", dir=self.tmpdir) # Check the local filesystem test environment self.local_test_folder_1 = tempfile.mkdtemp("drive-1", dir=self.tmpdir) self.local_test_folder_2 = tempfile.mkdtemp("drive-2", dir=self.tmpdir) # Correct the casing of the temp folders for windows if WINDOWS: import win32api self.local_test_folder_1 = win32api.GetLongPathNameW( self.local_test_folder_1) self.local_test_folder_2 = win32api.GetLongPathNameW( self.local_test_folder_2) self.local_nxdrive_folder_1 = os.path.join(self.local_test_folder_1, "Nuxeo Drive") os.mkdir(self.local_nxdrive_folder_1) self.local_nxdrive_folder_2 = os.path.join(self.local_test_folder_2, "Nuxeo Drive") os.mkdir(self.local_nxdrive_folder_2) self.nxdrive_conf_folder_1 = os.path.join(self.local_test_folder_1, "nuxeo-drive-conf") os.mkdir(self.nxdrive_conf_folder_1) self.nxdrive_conf_folder_2 = os.path.join(self.local_test_folder_2, "nuxeo-drive-conf") os.mkdir(self.nxdrive_conf_folder_2) Options.delay = TEST_DEFAULT_DELAY Options.nxdrive_home = self.nxdrive_conf_folder_1 self.manager_1 = Manager() self.connected = False i18n_path = self.location + "/resources/i18n" Translator(self.manager_1, i18n_path) Options.nxdrive_home = self.nxdrive_conf_folder_2 Manager._singleton = None self.manager_2 = Manager() self.setUpServer(server_profile) self.addCleanup(self.tearDownServer, server_profile) self.addCleanup(self._stop_managers) self.addCleanup(self.generate_report) self._wait_sync = {} self._wait_remote_scan = {} self._remote_changes_count = {} self._no_remote_changes = {} # Set engine_1 and engine_2 attributes self.bind_engine(1, start_engine=False) self.queue_manager_1 = self.engine_1.get_queue_manager() self.bind_engine(2, start_engine=False) self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1, self.workspace_title_1) self.sync_root_folder_2 = os.path.join(self.local_nxdrive_folder_2, self.workspace_title_2) self.local_root_client_1 = self.engine_1.local self.local_1 = self.get_local_client(self.sync_root_folder_1) self.local_2 = self.get_local_client(self.sync_root_folder_2) # Document client to be used to create remote test documents # and folders self.remote_document_client_1 = DocRemote( pytest.nuxeo_url, self.user_1, "nxdrive-test-device-1", pytest.version, password=self.password_1, base_folder=self.workspace_1, upload_tmp_dir=self.upload_tmp_dir, ) self.remote_document_client_2 = DocRemote( pytest.nuxeo_url, self.user_2, "nxdrive-test-device-2", pytest.version, password=self.password_2, base_folder=self.workspace_2, upload_tmp_dir=self.upload_tmp_dir, ) # File system client to be used to create remote test documents # and folders self.remote_1 = RemoteBase( pytest.nuxeo_url, self.user_1, "nxdrive-test-device-1", pytest.version, password=self.password_1, base_folder=self.workspace_1, upload_tmp_dir=self.upload_tmp_dir, ) self.remote_2 = RemoteBase( pytest.nuxeo_url, self.user_2, "nxdrive-test-device-2", pytest.version, password=self.password_2, base_folder=self.workspace_2, upload_tmp_dir=self.upload_tmp_dir, ) # Register sync roots if register_roots: self.remote_1.register_as_root(self.workspace_1) self.addCleanup(self._unregister, self.workspace_1) self.remote_2.register_as_root(self.workspace_2) self.addCleanup(self._unregister, self.workspace_2)
def _create_manager(self): Options.nxdrive_home = self.test_folder manager = Manager() return manager
def get_manager(self, options): from nxdrive.manager import Manager setattr(options, 'version', __version__) return Manager(options)
def setUpApp(self, server_profile=None): # Check the Nuxeo server test environment self.nuxeo_url = os.environ.get('NXDRIVE_TEST_NUXEO_URL') self.admin_user = os.environ.get('NXDRIVE_TEST_USER') self.password = os.environ.get('NXDRIVE_TEST_PASSWORD') self.build_workspace = os.environ.get('WORKSPACE') self.result = None self.tearedDown = False # Take default parameter if none has been set if self.nuxeo_url is None: self.nuxeo_url = "http://localhost:8080/nuxeo" if self.admin_user is None: self.admin_user = "******" if self.password is None: self.password = "******" self.tmpdir = None if self.build_workspace is not None: self.tmpdir = os.path.join(self.build_workspace, "tmp") if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) self.upload_tmp_dir = tempfile.mkdtemp(u'-nxdrive-uploads', dir=self.tmpdir) if None in (self.nuxeo_url, self.admin_user, self.password): raise unittest.SkipTest( "No integration server configuration found in environment.") # Check the local filesystem test environment self.local_test_folder_1 = tempfile.mkdtemp(u'-nxdrive-tests-user-1', dir=self.tmpdir) self.local_test_folder_2 = tempfile.mkdtemp(u'-nxdrive-tests-user-2', dir=self.tmpdir) self.local_nxdrive_folder_1 = os.path.join( self.local_test_folder_1, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_1) self.local_nxdrive_folder_2 = os.path.join( self.local_test_folder_2, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_2) self.nxdrive_conf_folder_1 = os.path.join( self.local_test_folder_1, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_1) self.nxdrive_conf_folder_2 = os.path.join( self.local_test_folder_2, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_2) from mock import Mock options = Mock() options.debug = False options.delay = TEST_DEFAULT_DELAY options.force_locale = None options.proxy_server = None options.log_level_file = None options.update_site_url = None options.beta_update_site_url = None options.autolock_interval = 30 options.nxdrive_home = self.nxdrive_conf_folder_1 self.manager_1 = Manager(options) self.connected = False import nxdrive nxdrive_path = os.path.dirname(nxdrive.__file__) i18n_path = os.path.join(nxdrive_path, 'tests', 'resources', "i18n.js") Translator(self.manager_1, i18n_path) options.nxdrive_home = self.nxdrive_conf_folder_2 Manager._singleton = None self.manager_2 = Manager(options) self.version = __version__ url = self.nuxeo_url log.debug("Will use %s as url", url) if '#' in url: # Remove the engine type for the rest of the test self.nuxeo_url = url.split('#')[0] self.setUpServer(server_profile) self.engine_1 = self.manager_1.bind_server(self.local_nxdrive_folder_1, url, self.user_1, self.password_1, start_engine=False) self.engine_2 = self.manager_2.bind_server(self.local_nxdrive_folder_2, url, self.user_2, self.password_2, start_engine=False) self.engine_1.syncCompleted.connect(self.app.sync_completed) self.engine_1.get_remote_watcher().remoteScanFinished.connect(self.app.remote_scan_completed) self.engine_1.get_remote_watcher().changesFound.connect(self.app.remote_changes_found) self.engine_1.get_remote_watcher().noChangesFound.connect(self.app.no_remote_changes_found) self.engine_2.syncCompleted.connect(self.app.sync_completed) self.engine_2.get_remote_watcher().remoteScanFinished.connect(self.app.remote_scan_completed) self.engine_2.get_remote_watcher().changesFound.connect(self.app.remote_changes_found) self.engine_2.get_remote_watcher().noChangesFound.connect(self.app.no_remote_changes_found) self.queue_manager_1 = self.engine_1.get_queue_manager() self.queue_manager_2 = self.engine_2.get_queue_manager() self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1, self.workspace_title_1) self.sync_root_folder_2 = os.path.join(self.local_nxdrive_folder_2, self.workspace_title_2) self.local_root_client_1 = self.engine_1.get_local_client() self.local_root_client_2 = self.engine_2.get_local_client() self.local_client_1 = LocalClient(os.path.join(self.local_nxdrive_folder_1, self.workspace_title_1)) self.local_client_2 = LocalClient(os.path.join(self.local_nxdrive_folder_2, self.workspace_title_2)) # Document client to be used to create remote test documents # and folders remote_document_client_1 = RemoteDocumentClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, base_folder=self.workspace_1, upload_tmp_dir=self.upload_tmp_dir) remote_document_client_2 = RemoteDocumentClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, base_folder=self.workspace_2, upload_tmp_dir=self.upload_tmp_dir) # File system client to be used to create remote test documents # and folders remote_file_system_client_1 = RemoteFileSystemClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, upload_tmp_dir=self.upload_tmp_dir) remote_file_system_client_2 = RemoteFileSystemClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, upload_tmp_dir=self.upload_tmp_dir) self.remote_restapi_client_1 = RestAPIClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1 ) self.remote_restapi_client_2 = RestAPIClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2 ) # Register root remote_document_client_1.register_as_root(self.workspace_1) remote_document_client_2.register_as_root(self.workspace_2) self.remote_document_client_1 = remote_document_client_1 self.remote_document_client_2 = remote_document_client_2 self.remote_file_system_client_1 = remote_file_system_client_1 self.remote_file_system_client_2 = remote_file_system_client_2 self._wait_sync = {self.engine_1.get_uid(): True, self.engine_2.get_uid(): True} self._wait_remote_scan = {self.engine_1.get_uid(): True, self.engine_2.get_uid(): True} self._remote_changes_count = {self.engine_1.get_uid(): 0, self.engine_2.get_uid(): 0} self._no_remote_changes = {self.engine_1.get_uid(): False, self.engine_2.get_uid(): False}
def setUpApp(self, server_profile=None): # Check the Nuxeo server test environment self.nuxeo_url = os.environ.get('NXDRIVE_TEST_NUXEO_URL') self.admin_user = os.environ.get('NXDRIVE_TEST_USER') self.password = os.environ.get('NXDRIVE_TEST_PASSWORD') self.build_workspace = os.environ.get('WORKSPACE') self.result = None self.tearedDown = False # Take default parameter if none has been set if self.nuxeo_url is None: self.nuxeo_url = "http://localhost:8080/nuxeo" if self.admin_user is None: self.admin_user = "******" if self.password is None: self.password = "******" self.tmpdir = None if self.build_workspace is not None: self.tmpdir = os.path.join(self.build_workspace, "tmp") if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) if None in (self.nuxeo_url, self.admin_user, self.password): raise unittest.SkipTest( "No integration server configuration found in environment.") # Check the local filesystem test environment self.local_test_folder_1 = tempfile.mkdtemp(u'-nxdrive-tests-user-1', dir=self.tmpdir) self.local_test_folder_2 = tempfile.mkdtemp(u'-nxdrive-tests-user-2', dir=self.tmpdir) self.local_nxdrive_folder_1 = os.path.join( self.local_test_folder_1, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_1) self.local_nxdrive_folder_2 = os.path.join( self.local_test_folder_2, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_2) self.nxdrive_conf_folder_1 = os.path.join( self.local_test_folder_1, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_1) self.nxdrive_conf_folder_2 = os.path.join( self.local_test_folder_2, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_2) from mock import Mock options = Mock() options.debug = False options.delay = TEST_DEFAULT_DELAY options.force_locale = None options.proxy_server = None options.log_level_file = None options.update_site_url = None options.beta_update_site_url = None options.autolock_interval = 30 options.nxdrive_home = self.nxdrive_conf_folder_1 self.manager_1 = Manager(options) import nxdrive nxdrive_path = os.path.dirname(nxdrive.__file__) i18n_path = os.path.join(nxdrive_path, 'tests', 'resources', "i18n.js") Translator(self.manager_1, i18n_path) options.nxdrive_home = self.nxdrive_conf_folder_2 Manager._singleton = None self.manager_2 = Manager(options) self.version = __version__ # Long timeout for the root client that is responsible for the test # environment set: this client is doing the first query on the Nuxeo # server and might need to wait for a long time without failing for # Nuxeo to finish initialize the repo on the first request after # startup root_remote_client = RemoteDocumentClient( self.nuxeo_url, self.admin_user, u'nxdrive-test-administrator-device', self.version, password=self.password, base_folder=u'/', timeout=60) # Activate given profile if needed, eg. permission hierarchy if server_profile is not None: root_remote_client.activate_profile(server_profile) # Call the Nuxeo operation to setup the integration test environment credentials = root_remote_client.execute( "NuxeoDrive.SetupIntegrationTests", userNames="user_1, user_2", permission='ReadWrite') credentials = [c.strip().split(u":") for c in credentials.split(u",")] self.user_1, self.password_1 = credentials[0] self.user_2, self.password_2 = credentials[1] self.engine_1 = self.manager_1.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url, self.user_1, self.password_1, start_engine=False) self.engine_2 = self.manager_2.bind_server(self.local_nxdrive_folder_2, self.nuxeo_url, self.user_2, self.password_2, start_engine=False) self.engine_1.syncCompleted.connect(self.app.sync_completed) self.engine_1.get_remote_watcher().remoteScanFinished.connect(self.app.remote_scan_completed) self.engine_1.get_remote_watcher().changesFound.connect(self.app.remote_changes_found) self.engine_1.get_remote_watcher().noChangesFound.connect(self.app.no_remote_changes_found) self.engine_2.syncCompleted.connect(self.app.sync_completed) self.engine_2.get_remote_watcher().remoteScanFinished.connect(self.app.remote_scan_completed) self.engine_2.get_remote_watcher().changesFound.connect(self.app.remote_changes_found) self.engine_2.get_remote_watcher().noChangesFound.connect(self.app.no_remote_changes_found) self.queue_manager_1 = self.engine_1.get_queue_manager() self.queue_manager_2 = self.engine_2.get_queue_manager() ws_info = root_remote_client.fetch(TEST_WORKSPACE_PATH) self.workspace = ws_info[u'uid'] self.workspace_title = ws_info[u'title'] self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1, self.workspace_title) self.sync_root_folder_2 = os.path.join(self.local_nxdrive_folder_2, self.workspace_title) self.local_root_client_1 = self.engine_1.get_local_client() self.local_root_client_2 = self.engine_2.get_local_client() self.local_client_1 = LocalClient(os.path.join(self.local_nxdrive_folder_1, self.workspace_title)) self.local_client_2 = LocalClient(os.path.join(self.local_nxdrive_folder_2, self.workspace_title)) # Document client to be used to create remote test documents # and folders self.upload_tmp_dir = tempfile.mkdtemp(u'-nxdrive-uploads', dir=self.tmpdir) remote_document_client_1 = RemoteDocumentClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, base_folder=self.workspace, upload_tmp_dir=self.upload_tmp_dir) remote_document_client_2 = RemoteDocumentClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, base_folder=self.workspace, upload_tmp_dir=self.upload_tmp_dir) # File system client to be used to create remote test documents # and folders remote_file_system_client_1 = RemoteFileSystemClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, upload_tmp_dir=self.upload_tmp_dir) remote_file_system_client_2 = RemoteFileSystemClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, upload_tmp_dir=self.upload_tmp_dir) self.remote_restapi_client_1 = RestAPIClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1 ) self.remote_restapi_client_2 = RestAPIClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2 ) # Register root remote_document_client_1.register_as_root(self.workspace) remote_document_client_2.register_as_root(self.workspace) self.root_remote_client = root_remote_client self.remote_document_client_1 = remote_document_client_1 self.remote_document_client_2 = remote_document_client_2 self.remote_file_system_client_1 = remote_file_system_client_1 self.remote_file_system_client_2 = remote_file_system_client_2 self._wait_sync = {self.engine_1.get_uid(): True, self.engine_2.get_uid(): True} self._wait_remote_scan = {self.engine_1.get_uid(): True, self.engine_2.get_uid(): True} self._remote_changes_count = {self.engine_1.get_uid(): 0, self.engine_2.get_uid(): 0} self._no_remote_changes = {self.engine_1.get_uid(): False, self.engine_2.get_uid(): False}
class UnitTestCase(SimpleUnitTestCase): def setUpServer(self, server_profile=None): # Save the current path for test files self.location = dirname(__file__) # Long timeout for the root client that is responsible for the test # environment set: this client is doing the first query on the Nuxeo # server and might need to wait for a long time without failing for # Nuxeo to finish initialize the repo on the first request after # startup self.root_remote_client = RemoteDocumentClientForTests( self.nuxeo_url, self.admin_user, u'nxdrive-test-administrator-device', self.version, password=self.password, base_folder=u'/', timeout=60) # Activate given profile if needed, eg. permission hierarchy if server_profile is not None: self.root_remote_client.activate_profile(server_profile) # Call the Nuxeo operation to setup the integration test environment credentials = self.root_remote_client.execute( "NuxeoDrive.SetupIntegrationTests", userNames="user_1, user_2", permission='ReadWrite') credentials = [c.strip().split(u":") for c in credentials.split(u",")] self.user_1, self.password_1 = credentials[0] self.user_2, self.password_2 = credentials[1] ws_info = self.root_remote_client.fetch(u'/default-domain/workspaces/') children = self.root_remote_client.get_children(ws_info['uid']) log.debug("SuperWorkspace info: %r", ws_info) log.debug("SuperWorkspace children: %r", children) ws_info = self.root_remote_client.fetch(TEST_WORKSPACE_PATH) log.debug("Workspace info: %r", ws_info) self.workspace = ws_info[u'uid'] self.workspace_title = ws_info[u'title'] self.workspace_1 = self.workspace self.workspace_2 = self.workspace self.workspace_title_1 = self.workspace_title self.workspace_title_2 = self.workspace_title def tearDownServer(self, server_profile=None): # Don't need to revoke tokens for the file system remote clients # since they use the same users as the remote document clients self.root_remote_client.execute('NuxeoDrive.TearDownIntegrationTests') # Deactivate given profile if needed, eg. permission hierarchy if server_profile is not None: self.root_remote_client.deactivate_profile(server_profile) def get_local_client(self, path): if AbstractOSIntegration.is_windows(): from tests.win_local_client import WindowsLocalClient return WindowsLocalClient(path) if AbstractOSIntegration.is_mac(): from tests.mac_local_client import MacLocalClient return MacLocalClient(path) return LocalClient(path) @Options.mock() def setUpApp(self, server_profile=None, register_roots=True): if Manager._singleton: Manager._singleton = None # Save the current path for test files self.location = dirname(__file__) # Install callback early to be called the last self.addCleanup(self._check_cleanup) # Check the Nuxeo server test environment self.nuxeo_url = os.environ.get('NXDRIVE_TEST_NUXEO_URL', 'http://localhost:8080/nuxeo') self.admin_user = os.environ.get('NXDRIVE_TEST_USER', 'Administrator') self.password = os.environ.get('NXDRIVE_TEST_PASSWORD', 'Administrator') self.report_path = os.environ.get('REPORT_PATH') self.tearedDown = False self.tmpdir = os.path.join(os.environ.get('WORKSPACE', ''), 'tmp') self.addCleanup(clean_dir, self.tmpdir) if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) self.upload_tmp_dir = tempfile.mkdtemp(u'-nxdrive-uploads', dir=self.tmpdir) # Check the local filesystem test environment self.local_test_folder_1 = tempfile.mkdtemp(u'drive-1', dir=self.tmpdir) self.local_test_folder_2 = tempfile.mkdtemp(u'drive-2', dir=self.tmpdir) # Correct the casing of the temp folders for windows if sys.platform == 'win32': import win32api self.local_test_folder_1 = win32api.GetLongPathNameW( self.local_test_folder_1) self.local_test_folder_2 = win32api.GetLongPathNameW( self.local_test_folder_2) self.local_nxdrive_folder_1 = os.path.join(self.local_test_folder_1, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_1) self.local_nxdrive_folder_2 = os.path.join(self.local_test_folder_2, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_2) self.nxdrive_conf_folder_1 = os.path.join(self.local_test_folder_1, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_1) self.nxdrive_conf_folder_2 = os.path.join(self.local_test_folder_2, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_2) Options.delay = TEST_DEFAULT_DELAY # Options.autolock_interval = 30 Options.nxdrive_home = self.nxdrive_conf_folder_1 self.manager_1 = Manager() self.connected = False i18n_path = self.location + '/resources/i18n.js' Translator(self.manager_1, i18n_path) Options.nxdrive_home = self.nxdrive_conf_folder_2 Manager._singleton = None self.manager_2 = Manager() self.version = __version__ url = self.nuxeo_url log.debug("Will use %s as url", url) if '#' in url: # Remove the engine type for the rest of the test self.nuxeo_url = url.split('#')[0] self.setUpServer(server_profile) self.addCleanup(self.tearDownServer, server_profile) self.addCleanup(self._stop_managers) self._wait_sync = {} self._wait_remote_scan = {} self._remote_changes_count = {} self._no_remote_changes = {} # Set engine_1 and engine_2 attributes self.bind_engine(1, start_engine=False) self.queue_manager_1 = self.engine_1.get_queue_manager() self.bind_engine(2, start_engine=False) self.queue_manager_2 = self.engine_2.get_queue_manager() self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1, self.workspace_title_1) self.sync_root_folder_2 = os.path.join(self.local_nxdrive_folder_2, self.workspace_title_2) self.local_root_client_1 = self.engine_1.get_local_client() self.local_root_client_2 = self.engine_2.get_local_client() self.local_client_1 = self.get_local_client(self.sync_root_folder_1) self.local_client_2 = self.get_local_client(self.sync_root_folder_2) # Document client to be used to create remote test documents # and folders self.remote_document_client_1 = RemoteDocumentClientForTests( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, base_folder=self.workspace_1, upload_tmp_dir=self.upload_tmp_dir) self.remote_document_client_2 = RemoteDocumentClientForTests( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, base_folder=self.workspace_2, upload_tmp_dir=self.upload_tmp_dir) # File system client to be used to create remote test documents # and folders self.remote_file_system_client_1 = RemoteFileSystemClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, upload_tmp_dir=self.upload_tmp_dir) self.remote_file_system_client_2 = RemoteFileSystemClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, upload_tmp_dir=self.upload_tmp_dir) self.remote_restapi_client_admin = RestAPIClient( self.nuxeo_url, self.admin_user, u'nxdrive-test-device-2', self.version, password=self.password) # Register sync roots if register_roots: self.remote_document_client_1.register_as_root(self.workspace_1) self.addCleanup(self._unregister, self.workspace_1) self.remote_document_client_2.register_as_root(self.workspace_2) self.addCleanup(self._unregister, self.workspace_2) def _unregister(self, workspace): """ Skip HTTP errors when cleaning up the test. """ try: self.root_remote_client.unregister_as_root(workspace) except URLError: pass def bind_engine(self, number, start_engine=True): number_str = str(number) manager = getattr(self, 'manager_' + number_str) local_folder = getattr(self, 'local_nxdrive_folder_' + number_str) user = getattr(self, 'user_' + number_str) password = getattr(self, 'password_' + number_str) engine = manager.bind_server(local_folder, self.nuxeo_url, user, password, start_engine=start_engine) engine.syncCompleted.connect(self.app.sync_completed) engine.get_remote_watcher().remoteScanFinished.connect( self.app.remote_scan_completed) engine.get_remote_watcher().changesFound.connect( self.app.remote_changes_found) engine.get_remote_watcher().noChangesFound.connect( self.app.no_remote_changes_found) engine_uid = engine.uid self._wait_sync[engine_uid] = True self._wait_remote_scan[engine_uid] = True self._remote_changes_count[engine_uid] = 0 self._no_remote_changes[engine_uid] = False setattr(self, 'engine_' + number_str, engine) def unbind_engine(self, number): number_str = str(number) engine = getattr(self, 'engine_' + number_str) manager = getattr(self, 'manager_' + number_str) manager.unbind_engine(engine.uid) delattr(self, 'engine_' + number_str) def send_bind_engine(self, number, start_engine=True): self.app.bindEngine.emit(number, start_engine) def send_unbind_engine(self, number): self.app.unbindEngine.emit(number) def wait_bind_engine(self, number, timeout=DEFAULT_WAIT_SYNC_TIMEOUT): engine = 'engine_' + str(number) while timeout > 0: sleep(1) timeout = timeout - 1 if hasattr(self, engine): return self.fail("Wait for bind engine expired") def wait_unbind_engine(self, number, timeout=DEFAULT_WAIT_SYNC_TIMEOUT): engine = 'engine_' + str(number) while timeout > 0: sleep(1) timeout = timeout - 1 if not hasattr(self, engine): return self.fail("Wait for unbind engine expired") def wait_sync( self, wait_for_async=False, timeout=DEFAULT_WAIT_SYNC_TIMEOUT, fail_if_timeout=True, wait_for_engine_1=True, wait_for_engine_2=False, wait_win=False, enforce_errors=True, fatal=False, ): log.debug('Wait for sync') # First wait for server if needed if wait_for_async: self.wait() if wait_win: log.trace('Need to wait for Windows delete resolution') sleep(WIN_MOVE_RESOLUTION_PERIOD / 1000) self._wait_sync = { self.engine_1.uid: wait_for_engine_1, self.engine_2.uid: wait_for_engine_2 } self._no_remote_changes = { self.engine_1.uid: not wait_for_engine_1, self.engine_2.uid: not wait_for_engine_2 } if enforce_errors: if not self.connected: self.engine_1.syncPartialCompleted.connect( self.engine_1.get_queue_manager().requeue_errors) self.engine_2.syncPartialCompleted.connect( self.engine_1.get_queue_manager().requeue_errors) self.connected = True elif self.connected: self.engine_1.syncPartialCompleted.disconnect( self.engine_1.get_queue_manager().requeue_errors) self.engine_2.syncPartialCompleted.disconnect( self.engine_1.get_queue_manager().requeue_errors) self.connected = False while timeout > 0: sleep(1) timeout -= 1 if sum(self._wait_sync.values()) == 0: if wait_for_async: log.debug( 'Sync completed, ' '_wait_remote_scan = %r, ' 'remote changes count = %r, ' 'no remote changes = %r', self._wait_remote_scan, self._remote_changes_count, self._no_remote_changes) wait_remote_scan = False if wait_for_engine_1: wait_remote_scan = self._wait_remote_scan[ self.engine_1.uid] if wait_for_engine_2: wait_remote_scan = wait_remote_scan or self._wait_remote_scan[ self.engine_2.uid] is_remote_changes = True is_change_summary_over = True if wait_for_engine_1: is_remote_changes = self._remote_changes_count[ self.engine_1.uid] > 0 is_change_summary_over = self._no_remote_changes[ self.engine_1.uid] if wait_for_engine_2: is_remote_changes = ( is_remote_changes and self._remote_changes_count[self.engine_2.uid] > 0) is_change_summary_over = ( is_change_summary_over and self._no_remote_changes[self.engine_2.uid]) if (not wait_remote_scan or is_remote_changes and is_change_summary_over): self._wait_remote_scan = { self.engine_1.uid: wait_for_engine_1, self.engine_2.uid: wait_for_engine_2 } self._remote_changes_count = { self.engine_1.uid: 0, self.engine_2.uid: 0 } self._no_remote_changes = { self.engine_1.uid: False, self.engine_2.uid: False } log.debug('Ended wait for sync, setting ' '_wait_remote_scan values to True, ' '_remote_changes_count values to 0 and ' '_no_remote_changes values to False') return else: log.debug('Sync completed, ended wait for sync') return if fail_if_timeout: if wait_for_engine_1 and self.engine_1.get_dao().get_syncing_count( ): err = ('Wait for sync timeout expired for engine 1 (%d)' % self.engine_1.get_dao().get_syncing_count()) elif wait_for_engine_2 and self.engine_2.get_dao( ).get_syncing_count(): err = ('Wait for sync timeout expired for engine 2 (%d)' % self.engine_2.get_dao().get_syncing_count()) else: err = 'Wait for sync timeout has expired' if fatal: self.fail(err) else: log.warn(err) else: log.debug('Wait for sync timeout') def wait_remote_scan(self, timeout=DEFAULT_WAIT_REMOTE_SCAN_TIMEOUT, wait_for_engine_1=True, wait_for_engine_2=False): log.debug("Wait for remote scan") self._wait_remote_scan = { self.engine_1.uid: wait_for_engine_1, self.engine_2.uid: wait_for_engine_2 } while timeout > 0: sleep(1) if sum(self._wait_remote_scan.values()) == 0: log.debug("Ended wait for remote scan") return timeout -= 1 self.fail("Wait for remote scan timeout expired") @staticmethod def is_profiling(): return YAPPI_PATH and yappi is not None def setup_profiler(self): if self.is_profiling(): yappi.start() def teardown_profiler(self): if not self.is_profiling(): return if not os.path.exists(YAPPI_PATH): os.mkdir(YAPPI_PATH) report_path = os.path.join( YAPPI_PATH, self.id() + '-' + sys.platform + '_yappi.txt') with open(report_path, 'w') as fd: fd.write('Threads\n=======\n') columns = { 0: ('name', 80), 1: ('tid', 15), 2: ('ttot', 8), 3: ('scnt', 10) } yappi.get_thread_stats().print_all(out=fd, columns=columns) fd.write('\n\n\nMethods\n=======\n') columns = { 0: ('name', 80), 1: ('ncall', 5), 2: ('tsub', 8), 3: ('ttot', 8), 4: ('tavg', 8) } stats = yappi.get_func_stats() stats.strip_dirs() stats.print_all(out=fd, columns=columns) log.debug('Profiler Report generated in %r', report_path) def reinit(self): self.tearDown() self.tearDownApp() self.setUpApp() try: self.setUp() except StandardError: # We can end on a wait timeout. Just ignore it, the test should # fail and will be launched again. pass def run(self, result=None): self.app = StubQApplication([], self) self.setUpApp() def launch_test(): self.root_remote_client.log_on_server('>>> testing: ' + self.id()) log.debug('UnitTest thread started') sleep(1) self.setup_profiler() super(UnitTestCase, self).run(result) self.teardown_profiler() self.app.quit() log.debug('UnitTest thread finished') sync_thread = Thread(target=launch_test) sync_thread.start() self.app.exec_() sync_thread.join(30) self.tearDownApp() del self.app log.debug('UnitTest run finished') def tearDown(self): self.generate_report() try: super(UnitTestCase, self).tearDown() except StandardError: pass try: self.tearDownApp() except StandardError: pass def tearDownApp(self): if self.tearedDown: return log.debug('TearDown unit test') if hasattr(self, 'engine_1'): del self.engine_1 self.engine_1 = None if hasattr(self, 'engine_2'): del self.engine_2 self.engine_2 = None del self.local_client_1 self.local_client_1 = None del self.local_client_2 self.local_client_2 = None del self.remote_document_client_1 self.remote_document_client_1 = None del self.remote_document_client_2 self.remote_document_client_2 = None del self.remote_file_system_client_1 self.remote_file_system_client_1 = None del self.remote_file_system_client_2 self.remote_file_system_client_2 = None self.tearedDown = True def _stop_managers(self): """ Called by self.addCleanup() to stop all managers. """ try: methods = itertools.product( ((self.manager_1, 1), (self.manager_2, 2)), ('unbind_all', 'dispose_all')) for (manager, idx), method in methods: func = getattr(manager, method, None) if func: log.debug('Calling self.manager_%d.%s()', idx, method) try: func() except: pass finally: Manager._singleton = None self.tearedDown = True def _check_cleanup(self): """ Called by self.addCleanup() to ensure folders are deleted. """ try: for root, _, files in os.walk(self.tmpdir): log.error('tempdir not cleaned-up: %r (%d)', root, len(files)) except OSError: pass def _interact(self, pause=0): self.app.processEvents() if pause > 0: sleep(pause) while self.app.hasPendingEvents(): self.app.processEvents() def make_local_tree(self, root=None, local_client=None): nb_files, nb_folders = 6, 4 if not local_client: local_client = self.local_root_client_1 if not root: root = u"/" + self.workspace_title if not local_client.exists(root): local_client.make_folder(u"/", self.workspace_title) nb_folders += 1 # create some folders folder_1 = local_client.make_folder(root, u'Folder 1') folder_1_1 = local_client.make_folder(folder_1, u'Folder 1.1') folder_1_2 = local_client.make_folder(folder_1, u'Folder 1.2') folder_2 = local_client.make_folder(root, u'Folder 2') # create some files local_client.make_file(folder_2, u'Duplicated File.txt', content=b"Some content.") local_client.make_file(folder_1, u'File 1.txt', content=b"aaa") local_client.make_file(folder_1_1, u'File 2.txt', content=b"bbb") local_client.make_file(folder_1_2, u'File 3.txt', content=b"ccc") local_client.make_file(folder_2, u'File 4.txt', content=b"ddd") local_client.make_file(root, u'File 5.txt', content=b"eee") return nb_files, nb_folders def make_server_tree(self, deep=True): remote_client = self.remote_document_client_1 # create some folders on the server folder_1 = remote_client.make_folder(self.workspace, u'Folder 1') folder_2 = remote_client.make_folder(self.workspace, u'Folder 2') if deep: folder_1_1 = remote_client.make_folder(folder_1, u'Folder 1.1') folder_1_2 = remote_client.make_folder(folder_1, u'Folder 1.2') # create some files on the server self._duplicate_file_1 = remote_client.make_file( folder_2, u'Duplicated File.txt', content=b"Some content.") self._duplicate_file_2 = remote_client.make_file( folder_2, u'Duplicated File.txt', content=b"Other content.") remote_client.make_file(folder_1, u'File 1.txt', content=b"aaa") remote_client.make_file(folder_1_1, u'File 2.txt', content=b"bbb") remote_client.make_file(folder_1_2, u'File 3.txt', content=b"ccc") remote_client.make_file(folder_2, u'File 4.txt', content=b"ddd") remote_client.make_file(self.workspace, u'File 5.txt', content=b"eee") return (7, 4) if deep else (1, 2) def get_local_child_count(self, path): dir_count = 0 file_count = 0 for _, dirnames, filenames in os.walk(path): dir_count += len(dirnames) file_count += len(filenames) if os.path.exists(os.path.join(path, '.partials')): dir_count -= 1 return (dir_count, file_count) def get_full_queue(self, queue, dao=None): if dao is None: dao = self.engine_1.get_dao() result = [] while len(queue) > 0: result.append(dao.get_state_from_id(queue.pop().id)) return result def wait(self, retry=3): try: self.root_remote_client.wait() except Exception as e: log.debug("Exception while waiting for server : %r", e) # Not the nicest if retry > 0: log.debug("Retry to wait") self.wait(retry - 1) def generate_report(self): success = vars(self._resultForDoCleanups).get('_excinfo') is None if success or not self.report_path: return path = os.path.join(self.report_path, self.id() + '-' + sys.platform) if sys.platform == 'win32': path = '\\\\?\\' + path.replace('/', os.path.sep) self.manager_1.generate_report(path) def _set_read_permission(self, user, doc_path, grant): op_input = "doc:" + doc_path if grant: self.root_remote_client.execute("Document.SetACE", op_input=op_input, user=user, permission="Read", grant="true") else: self.root_remote_client.block_inheritance(doc_path) @staticmethod def generate_random_png(filename=None, size=None): """ Generate a random PNG file. :param filename: The output file name. If None, returns picture content. :param size: The number of black pixels of the picture. :return mixed: None if given filename else bytes """ if not size: size = random.randint(1, 42) else: size = max(1, size) pack = struct.pack def chunk(header, data): return (pack('>I', len(data)) + header + data + pack('>I', zlib.crc32(header + data) & 0xffffffff)) magic = pack('>8B', 137, 80, 78, 71, 13, 10, 26, 10) png_filter = pack('>B', 0) scanline = pack('>{}B'.format(size * 3), *[0] * (size * 3)) content = [png_filter + scanline for _ in range(size)] png = (magic + chunk(b'IHDR', pack('>2I5B', size, size, 8, 2, 0, 0, 0)) + chunk(b'IDAT', zlib.compress(b''.join(content))) + chunk(b'IEND', b'')) if not filename: return png with open(filename, 'wb') as fileo: fileo.write(png) def assertNxPart(self, path, name=None, present=True): os_path = self.local_client_1.abspath(path) children = os.listdir(os_path) for child in children: if len(child) < 8: continue if name is not None and len(child) < len(name) + 8: continue if child[0] == "." and child[-7:] == ".nxpart": if name is None or child[1:len(name) + 1] == name: if present: return else: self.fail("nxpart found in : '%s'" % (path)) if present: self.fail("nxpart not found in : '%s'" % (path)) def get_dao_state_from_engine_1(self, path): """ Returns the pair from dao of engine 1 according to the path. :param path: The path to document (from workspace, ex: /Folder is converted to /{{workspace_title_1}}/Folder). :return: The pair from dao of engine 1 according to the path. """ abs_path = '/' + self.workspace_title_1 + path return self.engine_1.get_dao().get_state_from_local(abs_path)
def get_manager(self): from nxdrive.manager import Manager return Manager()
class UnitTestCase(unittest.TestCase): def setUpServer(self, server_profile=None): # Long timeout for the root client that is responsible for the test # environment set: this client is doing the first query on the Nuxeo # server and might need to wait for a long time without failing for # Nuxeo to finish initialize the repo on the first request after # startup self.root_remote_client = RemoteDocumentClient( self.nuxeo_url, self.admin_user, u'nxdrive-test-administrator-device', self.version, password=self.password, base_folder=u'/', timeout=60) # Activate given profile if needed, eg. permission hierarchy if server_profile is not None: self.root_remote_client.activate_profile(server_profile) # Call the Nuxeo operation to setup the integration test environment credentials = self.root_remote_client.execute( "NuxeoDrive.SetupIntegrationTests", userNames="user_1, user_2", permission='ReadWrite') credentials = [c.strip().split(u":") for c in credentials.split(u",")] self.user_1, self.password_1 = credentials[0] self.user_2, self.password_2 = credentials[1] ws_info = self.root_remote_client.fetch(TEST_WORKSPACE_PATH) self.workspace = ws_info[u'uid'] self.workspace_title = ws_info[u'title'] self.workspace_1 = self.workspace self.workspace_2 = self.workspace self.workspace_title_1 = self.workspace_title self.workspace_title_2 = self.workspace_title def tearDownServer(self, server_profile=None): # Don't need to revoke tokens for the file system remote clients # since they use the same users as the remote document clients self.root_remote_client.execute("NuxeoDrive.TearDownIntegrationTests") # Deactivate given profile if needed, eg. permission hierarchy if server_profile is not None: self.root_remote_client.deactivate_profile(server_profile) def setUpApp(self, server_profile=None): # Check the Nuxeo server test environment self.nuxeo_url = os.environ.get('NXDRIVE_TEST_NUXEO_URL') self.admin_user = os.environ.get('NXDRIVE_TEST_USER') self.password = os.environ.get('NXDRIVE_TEST_PASSWORD') self.build_workspace = os.environ.get('WORKSPACE') self.result = None self.tearedDown = False # Take default parameter if none has been set if self.nuxeo_url is None: self.nuxeo_url = "http://localhost:8080/nuxeo" if self.admin_user is None: self.admin_user = "******" if self.password is None: self.password = "******" self.tmpdir = None if self.build_workspace is not None: self.tmpdir = os.path.join(self.build_workspace, "tmp") if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) self.upload_tmp_dir = tempfile.mkdtemp(u'-nxdrive-uploads', dir=self.tmpdir) if None in (self.nuxeo_url, self.admin_user, self.password): raise unittest.SkipTest( "No integration server configuration found in environment.") # Check the local filesystem test environment self.local_test_folder_1 = tempfile.mkdtemp(u'-nxdrive-tests-user-1', dir=self.tmpdir) self.local_test_folder_2 = tempfile.mkdtemp(u'-nxdrive-tests-user-2', dir=self.tmpdir) self.local_nxdrive_folder_1 = os.path.join( self.local_test_folder_1, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_1) self.local_nxdrive_folder_2 = os.path.join( self.local_test_folder_2, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_2) self.nxdrive_conf_folder_1 = os.path.join( self.local_test_folder_1, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_1) self.nxdrive_conf_folder_2 = os.path.join( self.local_test_folder_2, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_2) from mock import Mock options = Mock() options.debug = False options.delay = TEST_DEFAULT_DELAY options.force_locale = None options.proxy_server = None options.log_level_file = None options.update_site_url = None options.beta_update_site_url = None options.autolock_interval = 30 options.nxdrive_home = self.nxdrive_conf_folder_1 self.manager_1 = Manager(options) self.connected = False import nxdrive nxdrive_path = os.path.dirname(nxdrive.__file__) i18n_path = os.path.join(nxdrive_path, 'tests', 'resources', "i18n.js") Translator(self.manager_1, i18n_path) options.nxdrive_home = self.nxdrive_conf_folder_2 Manager._singleton = None self.manager_2 = Manager(options) self.version = __version__ url = self.nuxeo_url log.debug("Will use %s as url", url) if '#' in url: # Remove the engine type for the rest of the test self.nuxeo_url = url.split('#')[0] self.setUpServer(server_profile) self.engine_1 = self.manager_1.bind_server(self.local_nxdrive_folder_1, url, self.user_1, self.password_1, start_engine=False) self.engine_2 = self.manager_2.bind_server(self.local_nxdrive_folder_2, url, self.user_2, self.password_2, start_engine=False) self.engine_1.syncCompleted.connect(self.app.sync_completed) self.engine_1.get_remote_watcher().remoteScanFinished.connect(self.app.remote_scan_completed) self.engine_1.get_remote_watcher().changesFound.connect(self.app.remote_changes_found) self.engine_1.get_remote_watcher().noChangesFound.connect(self.app.no_remote_changes_found) self.engine_2.syncCompleted.connect(self.app.sync_completed) self.engine_2.get_remote_watcher().remoteScanFinished.connect(self.app.remote_scan_completed) self.engine_2.get_remote_watcher().changesFound.connect(self.app.remote_changes_found) self.engine_2.get_remote_watcher().noChangesFound.connect(self.app.no_remote_changes_found) self.queue_manager_1 = self.engine_1.get_queue_manager() self.queue_manager_2 = self.engine_2.get_queue_manager() self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1, self.workspace_title_1) self.sync_root_folder_2 = os.path.join(self.local_nxdrive_folder_2, self.workspace_title_2) self.local_root_client_1 = self.engine_1.get_local_client() self.local_root_client_2 = self.engine_2.get_local_client() self.local_client_1 = LocalClient(os.path.join(self.local_nxdrive_folder_1, self.workspace_title_1)) self.local_client_2 = LocalClient(os.path.join(self.local_nxdrive_folder_2, self.workspace_title_2)) # Document client to be used to create remote test documents # and folders remote_document_client_1 = RemoteDocumentClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, base_folder=self.workspace_1, upload_tmp_dir=self.upload_tmp_dir) remote_document_client_2 = RemoteDocumentClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, base_folder=self.workspace_2, upload_tmp_dir=self.upload_tmp_dir) # File system client to be used to create remote test documents # and folders remote_file_system_client_1 = RemoteFileSystemClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, upload_tmp_dir=self.upload_tmp_dir) remote_file_system_client_2 = RemoteFileSystemClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, upload_tmp_dir=self.upload_tmp_dir) self.remote_restapi_client_1 = RestAPIClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1 ) self.remote_restapi_client_2 = RestAPIClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2 ) # Register root remote_document_client_1.register_as_root(self.workspace_1) remote_document_client_2.register_as_root(self.workspace_2) self.remote_document_client_1 = remote_document_client_1 self.remote_document_client_2 = remote_document_client_2 self.remote_file_system_client_1 = remote_file_system_client_1 self.remote_file_system_client_2 = remote_file_system_client_2 self._wait_sync = {self.engine_1.get_uid(): True, self.engine_2.get_uid(): True} self._wait_remote_scan = {self.engine_1.get_uid(): True, self.engine_2.get_uid(): True} self._remote_changes_count = {self.engine_1.get_uid(): 0, self.engine_2.get_uid(): 0} self._no_remote_changes = {self.engine_1.get_uid(): False, self.engine_2.get_uid(): False} def wait_sync(self, wait_for_async=False, timeout=DEFAULT_WAIT_SYNC_TIMEOUT, fail_if_timeout=True, wait_for_engine_1=True, wait_for_engine_2=False, wait_win=False, enforce_errors=True): log.debug("Wait for sync") # First wait for server if needed if wait_for_async: self.wait() if sys.platform == "win32" and wait_win: from nxdrive.engine.watcher.local_watcher import WIN_MOVE_RESOLUTION_PERIOD log.trace("Need to wait for Windows delete resolution") sleep(WIN_MOVE_RESOLUTION_PERIOD/1000) self._wait_sync = { self.engine_1.get_uid(): wait_for_engine_1, self.engine_2.get_uid(): wait_for_engine_2 } self._no_remote_changes = {self.engine_1.get_uid(): not wait_for_engine_1, self.engine_2.get_uid(): not wait_for_engine_2} if enforce_errors: if not self.connected: self.engine_1.syncPartialCompleted.connect(self.engine_1.get_queue_manager().requeue_errors) self.engine_2.syncPartialCompleted.connect(self.engine_1.get_queue_manager().requeue_errors) self.connected = True elif self.connected: self.engine_1.syncPartialCompleted.disconnect(self.engine_1.get_queue_manager().requeue_errors) self.engine_2.syncPartialCompleted.disconnect(self.engine_1.get_queue_manager().requeue_errors) self.connected = False while timeout > 0: sleep(1) timeout = timeout - 1 if sum(self._wait_sync.values()) == 0: if wait_for_async: log.debug('Sync completed, _wait_remote_scan = %r, remote changes count = %r,' ' no remote changes = %r', self._wait_remote_scan, self._remote_changes_count, self._no_remote_changes) wait_remote_scan = False if wait_for_engine_1: wait_remote_scan = self._wait_remote_scan[self.engine_1.get_uid()] if wait_for_engine_2: wait_remote_scan = wait_remote_scan or self._wait_remote_scan[self.engine_2.get_uid()] is_remote_changes = True is_change_summary_over = True if wait_for_engine_1: is_remote_changes = self._remote_changes_count[self.engine_1.get_uid()] > 0 is_change_summary_over = self._no_remote_changes[self.engine_1.get_uid()] if wait_for_engine_2: is_remote_changes = (is_remote_changes and self._remote_changes_count[self.engine_2.get_uid()] > 0) is_change_summary_over = (is_change_summary_over and self._no_remote_changes[self.engine_2.get_uid()]) if (not wait_remote_scan or is_remote_changes and is_change_summary_over): self._wait_remote_scan = {self.engine_1.get_uid(): wait_for_engine_1, self.engine_2.get_uid(): wait_for_engine_2} self._remote_changes_count = {self.engine_1.get_uid(): 0, self.engine_2.get_uid(): 0} self._no_remote_changes = {self.engine_1.get_uid(): False, self.engine_2.get_uid(): False} log.debug('Ended wait for sync, setting _wait_remote_scan values to True,' ' _remote_changes_count values to 0 and _no_remote_changes values to False') return else: log.debug("Sync completed, ended wait for sync") return if fail_if_timeout: log.warn("Wait for sync timeout has expired") if wait_for_engine_1 and self.engine_1.get_dao().get_syncing_count() != 0: self.fail("Wait for sync timeout expired") if wait_for_engine_2 and self.engine_2.get_dao().get_syncing_count() != 0: self.fail("Wait for sync timeout expired") else: log.debug("Wait for sync timeout") def wait_remote_scan(self, timeout=DEFAULT_WAIT_REMOTE_SCAN_TIMEOUT, wait_for_engine_1=True, wait_for_engine_2=False): log.debug("Wait for remote scan") self._wait_remote_scan = {self.engine_1.get_uid(): wait_for_engine_1, self.engine_2.get_uid(): wait_for_engine_2} while timeout > 0: sleep(1) if sum(self._wait_remote_scan.values()) == 0: log.debug("Ended wait for remote scan") return timeout = timeout - 1 self.fail("Wait for remote scan timeout expired") def is_profiling(self): return 'DRIVE_YAPPI' in os.environ and yappi is not None def setup_profiler(self): if not self.is_profiling(): return yappi.start() def teardown_profiler(self): if not self.is_profiling(): return path = os.environ["DRIVE_YAPPI"] if not os.path.exists(path): os.mkdir(path) report_path = os.path.join(path, self.id() + '-yappi-threads') with open(report_path, 'w') as fd: columns = {0: ("name", 80), 1: ("tid", 15), 2: ("ttot", 8), 3: ("scnt", 10)} yappi.get_thread_stats().print_all(out=fd, columns=columns) report_path = os.path.join(path, self.id() + '-yappi-fcts') with open(report_path, 'w') as fd: columns = {0: ("name", 80), 1: ("ncall", 5), 2: ("tsub", 8), 3: ("ttot", 8), 4: ("tavg", 8)} stats = yappi.get_func_stats() stats.strip_dirs() stats.print_all(out=fd, columns=columns) log.debug("Profiler Report generated in '%s'", report_path) def run(self, result=None): self.app = TestQApplication([], self) self.setUpApp() self.result = result # TODO Should use a specific application def launch_test(): log.debug("UnitTest thread started") sleep(1) self.setup_profiler() super(UnitTestCase, self).run(result) self.teardown_profiler() self.app.quit() log.debug("UnitTest thread finished") sync_thread = Thread(target=launch_test) sync_thread.start() self.app.exec_() sync_thread.join(30) self.tearDownApp() del self.app log.debug("UnitTest run finished") def tearDown(self): unittest.TestCase.tearDown(self) if not self.tearedDown: self.tearDownApp() def tearDownApp(self, server_profile=None): if self.tearedDown: return if sys.exc_info() != (None, None, None): self.generate_report() elif self.result is not None: if hasattr(self.result, "wasSuccessful") and not self.result.wasSuccessful(): self.generate_report() log.debug("TearDown unit test") # Unbind all self.manager_1.unbind_all() self.manager_1.dispose_db() self.manager_2.unbind_all() self.manager_2.dispose_db() Manager._singleton = None self.tearDownServer(server_profile) clean_dir(self.upload_tmp_dir) clean_dir(self.local_test_folder_1) clean_dir(self.local_test_folder_2) del self.engine_1 self.engine_1 = None del self.engine_2 self.engine_2 = None del self.local_client_1 self.local_client_1 = None del self.local_client_2 self.local_client_2 = None del self.remote_document_client_1 self.remote_document_client_1 = None del self.remote_document_client_2 self.remote_document_client_2 = None del self.remote_file_system_client_1 self.remote_file_system_client_1 = None del self.remote_file_system_client_2 self.remote_file_system_client_2 = None self.tearedDown = True def _interact(self, pause=0): self.app.processEvents() if pause > 0: sleep(pause) while (self.app.hasPendingEvents()): self.app.processEvents() def make_local_tree(self, root=None, local_client=None): if local_client is None: local_client = self.local_root_client_1 if root is None: root = u"/" + self.workspace_title if not local_client.exists(root): local_client.make_folder(u"/", self.workspace_title) # create some folders folder_1 = local_client.make_folder(root, u'Folder 1') folder_1_1 = local_client.make_folder(folder_1, u'Folder 1.1') folder_1_2 = local_client.make_folder(folder_1, u'Folder 1.2') folder_2 = local_client.make_folder(root, u'Folder 2') # create some files local_client.make_file(folder_2, u'Duplicated File.txt', content=b"Some content.") local_client.make_file(folder_1, u'File 1.txt', content=b"aaa") local_client.make_file(folder_1_1, u'File 2.txt', content=b"bbb") local_client.make_file(folder_1_2, u'File 3.txt', content=b"ccc") local_client.make_file(folder_2, u'File 4.txt', content=b"ddd") local_client.make_file(root, u'File 5.txt', content=b"eee") return (6, 5) def make_server_tree(self, deep=True): remote_client = self.remote_document_client_1 # create some folders on the server folder_1 = remote_client.make_folder(self.workspace, u'Folder 1') folder_2 = remote_client.make_folder(self.workspace, u'Folder 2') if deep: folder_1_1 = remote_client.make_folder(folder_1, u'Folder 1.1') folder_1_2 = remote_client.make_folder(folder_1, u'Folder 1.2') # create some files on the server if deep: self._duplicate_file_1 = remote_client.make_file(folder_2, u'Duplicated File.txt', content=b"Some content.") self._duplicate_file_2 = remote_client.make_file(folder_2, u'Duplicated File.txt', content=b"Other content.") if deep: remote_client.make_file(folder_1, u'File 1.txt', content=b"aaa") remote_client.make_file(folder_1_1, u'File 2.txt', content=b"bbb") remote_client.make_file(folder_1_2, u'File 3.txt', content=b"ccc") remote_client.make_file(folder_2, u'File 4.txt', content=b"ddd") remote_client.make_file(self.workspace, u'File 5.txt', content=b"eee") return (7, 4) if deep else (1, 2) def get_local_child_count(self, path): dir_count = 0 file_count = 0 for _, dirnames, filenames in os.walk(path): dir_count += len(dirnames) file_count += len(filenames) if os.path.exists(os.path.join(path, '.partials')): dir_count -= 1 return (dir_count, file_count) def get_full_queue(self, queue, dao=None): if dao is None: dao = self.engine_1.get_dao() result = [] while (len(queue) > 0): result.append(dao.get_state_from_id(queue.pop().id)) return result def generate_report(self): if "REPORT_PATH" not in os.environ: return report_path = os.path.join(os.environ["REPORT_PATH"], self.id()) self.manager_1.generate_report(report_path) log.debug("Report generated in '%s'", report_path) def wait(self, retry=3): try: self.root_remote_client.wait() except Exception as e: log.debug("Exception while waiting for server : %r", e) # Not the nicest if retry > 0: log.debug("Retry to wait") self.wait(retry - 1) def generate_random_jpg(self, filename, size): try: import numpy from PIL import Image except: # Create random file with open(filename, 'wb') as f: f.write(os.urandom(1024 * size)) return a = numpy.random.rand(size, size, 3) * 255 im_out = Image.fromarray(a.astype('uint8')).convert('RGBA') im_out.save(filename) def assertNxPart(self, path, name=None, present=True): os_path = self.local_client_1._abspath(path) children = os.listdir(os_path) for child in children: if len(child) < 8: continue if name is not None and len(child) < len(name) + 8: continue if child[0] == "." and child[-7:] == ".nxpart": if name is None or child[1:len(name)+1] == name: if present: return else: self.fail("nxpart found in : '%s'" % (path)) if present: self.fail("nxpart not found in : '%s'" % (path)) def get_dao_state_from_engine_1(self, path): """ Returns the pair from dao of engine 1 according to the path. :param path: The path to document (from workspace, ex: /Folder is converted to /{{workspace_title_1}}/Folder). :return: The pair from dao of engine 1 according to the path. """ abs_path = '/' + self.workspace_title_1 + path return self.engine_1.get_dao().get_state_from_local(abs_path)
def setUpApp(self, server_profile=None, register_roots=True): if Manager._singleton: Manager._singleton = None # Save the current path for test files self.location = dirname(__file__) # Install callback early to be called the last self.addCleanup(self._check_cleanup) # Check the Nuxeo server test environment self.nuxeo_url = os.environ.get('NXDRIVE_TEST_NUXEO_URL', 'http://localhost:8080/nuxeo') self.admin_user = os.environ.get('NXDRIVE_TEST_USER', 'Administrator') self.password = os.environ.get('NXDRIVE_TEST_PASSWORD', 'Administrator') self.report_path = os.environ.get('REPORT_PATH') self.tearedDown = False self.tmpdir = os.path.join(os.environ.get('WORKSPACE', ''), 'tmp') self.addCleanup(clean_dir, self.tmpdir) if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) self.upload_tmp_dir = tempfile.mkdtemp(u'-nxdrive-uploads', dir=self.tmpdir) # Check the local filesystem test environment self.local_test_folder_1 = tempfile.mkdtemp(u'drive-1', dir=self.tmpdir) self.local_test_folder_2 = tempfile.mkdtemp(u'drive-2', dir=self.tmpdir) # Correct the casing of the temp folders for windows if sys.platform == 'win32': import win32api self.local_test_folder_1 = win32api.GetLongPathNameW( self.local_test_folder_1) self.local_test_folder_2 = win32api.GetLongPathNameW( self.local_test_folder_2) self.local_nxdrive_folder_1 = os.path.join(self.local_test_folder_1, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_1) self.local_nxdrive_folder_2 = os.path.join(self.local_test_folder_2, u'Nuxeo Drive') os.mkdir(self.local_nxdrive_folder_2) self.nxdrive_conf_folder_1 = os.path.join(self.local_test_folder_1, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_1) self.nxdrive_conf_folder_2 = os.path.join(self.local_test_folder_2, u'nuxeo-drive-conf') os.mkdir(self.nxdrive_conf_folder_2) Options.delay = TEST_DEFAULT_DELAY # Options.autolock_interval = 30 Options.nxdrive_home = self.nxdrive_conf_folder_1 self.manager_1 = Manager() self.connected = False i18n_path = self.location + '/resources/i18n.js' Translator(self.manager_1, i18n_path) Options.nxdrive_home = self.nxdrive_conf_folder_2 Manager._singleton = None self.manager_2 = Manager() self.version = __version__ url = self.nuxeo_url log.debug("Will use %s as url", url) if '#' in url: # Remove the engine type for the rest of the test self.nuxeo_url = url.split('#')[0] self.setUpServer(server_profile) self.addCleanup(self.tearDownServer, server_profile) self.addCleanup(self._stop_managers) self._wait_sync = {} self._wait_remote_scan = {} self._remote_changes_count = {} self._no_remote_changes = {} # Set engine_1 and engine_2 attributes self.bind_engine(1, start_engine=False) self.queue_manager_1 = self.engine_1.get_queue_manager() self.bind_engine(2, start_engine=False) self.queue_manager_2 = self.engine_2.get_queue_manager() self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1, self.workspace_title_1) self.sync_root_folder_2 = os.path.join(self.local_nxdrive_folder_2, self.workspace_title_2) self.local_root_client_1 = self.engine_1.get_local_client() self.local_root_client_2 = self.engine_2.get_local_client() self.local_client_1 = self.get_local_client(self.sync_root_folder_1) self.local_client_2 = self.get_local_client(self.sync_root_folder_2) # Document client to be used to create remote test documents # and folders self.remote_document_client_1 = RemoteDocumentClientForTests( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, base_folder=self.workspace_1, upload_tmp_dir=self.upload_tmp_dir) self.remote_document_client_2 = RemoteDocumentClientForTests( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, base_folder=self.workspace_2, upload_tmp_dir=self.upload_tmp_dir) # File system client to be used to create remote test documents # and folders self.remote_file_system_client_1 = RemoteFileSystemClient( self.nuxeo_url, self.user_1, u'nxdrive-test-device-1', self.version, password=self.password_1, upload_tmp_dir=self.upload_tmp_dir) self.remote_file_system_client_2 = RemoteFileSystemClient( self.nuxeo_url, self.user_2, u'nxdrive-test-device-2', self.version, password=self.password_2, upload_tmp_dir=self.upload_tmp_dir) self.remote_restapi_client_admin = RestAPIClient( self.nuxeo_url, self.admin_user, u'nxdrive-test-device-2', self.version, password=self.password) # Register sync roots if register_roots: self.remote_document_client_1.register_as_root(self.workspace_1) self.addCleanup(self._unregister, self.workspace_1) self.remote_document_client_2.register_as_root(self.workspace_2) self.addCleanup(self._unregister, self.workspace_2)
class UnitTestCase(TestCase): # Save the current path for test files location = dirname(__file__) def setUpServer(self, server_profile=None): # Long timeout for the root client that is responsible for the test # environment set: this client is doing the first query on the Nuxeo # server and might need to wait for a long time without failing for # Nuxeo to finish initialize the repo on the first request after # startup # Activate given profile if needed, eg. permission hierarchy if server_profile is not None: pytest.root_remote.activate_profile(server_profile) # Call the Nuxeo operation to setup the integration test environment credentials = pytest.root_remote.operations.execute( command="NuxeoDrive.SetupIntegrationTests", userNames="user_1, user_2", permission="ReadWrite", ) credentials = [ c.strip().split(":") for c in credentials.decode("utf-8").split(",") ] self.user_1, self.password_1 = credentials[0] self.user_2, self.password_2 = credentials[1] ws_info = pytest.root_remote.fetch("/default-domain/workspaces/") children = pytest.root_remote.get_children(ws_info["uid"]) log.debug("SuperWorkspace info: %r", ws_info) log.debug("SuperWorkspace children: %r", children) ws_info = pytest.root_remote.fetch(TEST_WORKSPACE_PATH) log.debug("Workspace info: %r", ws_info) self.workspace = ws_info["uid"] self.workspace_title = ws_info["title"] self.workspace_1 = self.workspace self.workspace_2 = self.workspace self.workspace_title_1 = self.workspace_title self.workspace_title_2 = self.workspace_title def tearDownServer(self, server_profile=None): # Don't need to revoke tokens for the file system remote clients # since they use the same users as the remote document clients pytest.root_remote.operations.execute( command="NuxeoDrive.TearDownIntegrationTests") # Deactivate given profile if needed, eg. permission hierarchy if server_profile is not None: pytest.root_remote.deactivate_profile(server_profile) def setUpApp(self, server_profile=None, register_roots=True): if Manager._singleton: Manager._singleton = None # Install callback early to be called the last self.addCleanup(self._check_cleanup) self.report_path = os.environ.get("REPORT_PATH") self.tmpdir = os.path.join(os.environ.get("WORKSPACE", ""), "tmp") self.addCleanup(clean_dir, self.tmpdir) if not os.path.isdir(self.tmpdir): os.makedirs(self.tmpdir) self.upload_tmp_dir = tempfile.mkdtemp("-nxdrive-uploads", dir=self.tmpdir) # Check the local filesystem test environment self.local_test_folder_1 = tempfile.mkdtemp("drive-1", dir=self.tmpdir) self.local_test_folder_2 = tempfile.mkdtemp("drive-2", dir=self.tmpdir) # Correct the casing of the temp folders for windows if WINDOWS: import win32api self.local_test_folder_1 = win32api.GetLongPathNameW( self.local_test_folder_1) self.local_test_folder_2 = win32api.GetLongPathNameW( self.local_test_folder_2) self.local_nxdrive_folder_1 = os.path.join(self.local_test_folder_1, "Nuxeo Drive") os.mkdir(self.local_nxdrive_folder_1) self.local_nxdrive_folder_2 = os.path.join(self.local_test_folder_2, "Nuxeo Drive") os.mkdir(self.local_nxdrive_folder_2) self.nxdrive_conf_folder_1 = os.path.join(self.local_test_folder_1, "nuxeo-drive-conf") os.mkdir(self.nxdrive_conf_folder_1) self.nxdrive_conf_folder_2 = os.path.join(self.local_test_folder_2, "nuxeo-drive-conf") os.mkdir(self.nxdrive_conf_folder_2) Options.delay = TEST_DEFAULT_DELAY Options.nxdrive_home = self.nxdrive_conf_folder_1 self.manager_1 = Manager() self.connected = False i18n_path = self.location + "/resources/i18n" Translator(self.manager_1, i18n_path) Options.nxdrive_home = self.nxdrive_conf_folder_2 Manager._singleton = None self.manager_2 = Manager() self.setUpServer(server_profile) self.addCleanup(self.tearDownServer, server_profile) self.addCleanup(self._stop_managers) self.addCleanup(self.generate_report) self._wait_sync = {} self._wait_remote_scan = {} self._remote_changes_count = {} self._no_remote_changes = {} # Set engine_1 and engine_2 attributes self.bind_engine(1, start_engine=False) self.queue_manager_1 = self.engine_1.get_queue_manager() self.bind_engine(2, start_engine=False) self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1, self.workspace_title_1) self.sync_root_folder_2 = os.path.join(self.local_nxdrive_folder_2, self.workspace_title_2) self.local_root_client_1 = self.engine_1.local self.local_1 = self.get_local_client(self.sync_root_folder_1) self.local_2 = self.get_local_client(self.sync_root_folder_2) # Document client to be used to create remote test documents # and folders self.remote_document_client_1 = DocRemote( pytest.nuxeo_url, self.user_1, "nxdrive-test-device-1", pytest.version, password=self.password_1, base_folder=self.workspace_1, upload_tmp_dir=self.upload_tmp_dir, ) self.remote_document_client_2 = DocRemote( pytest.nuxeo_url, self.user_2, "nxdrive-test-device-2", pytest.version, password=self.password_2, base_folder=self.workspace_2, upload_tmp_dir=self.upload_tmp_dir, ) # File system client to be used to create remote test documents # and folders self.remote_1 = RemoteBase( pytest.nuxeo_url, self.user_1, "nxdrive-test-device-1", pytest.version, password=self.password_1, base_folder=self.workspace_1, upload_tmp_dir=self.upload_tmp_dir, ) self.remote_2 = RemoteBase( pytest.nuxeo_url, self.user_2, "nxdrive-test-device-2", pytest.version, password=self.password_2, base_folder=self.workspace_2, upload_tmp_dir=self.upload_tmp_dir, ) # Register sync roots if register_roots: self.remote_1.register_as_root(self.workspace_1) self.addCleanup(self._unregister, self.workspace_1) self.remote_2.register_as_root(self.workspace_2) self.addCleanup(self._unregister, self.workspace_2) def tearDownApp(self): try: self.engine_1.remote.client._session.close() except AttributeError: pass try: self.engine_2.remote.client._session.close() except AttributeError: pass attrs = ( "engine_1", "engine_2", "local_client_1", "local_client_2", "remote_1", "remote_2", "remote_document_client_1", "remote_document_client_2", "remote_file_system_client_1", "remote_file_system_client_2", ) for attr in attrs: try: delattr(self, attr) except AttributeError: pass def get_local_client(self, path: str): """ Return an OS specific LocalClient class by default to simulate user actions on: - Explorer (Windows) - File Manager (macOS) On GNU/Linux, there is not specific behavior so the original LocalClient will be used. """ if LINUX: client = LocalTest elif MAC: from .mac_local_client import MacLocalClient as client elif WINDOWS: from .win_local_client import WindowsLocalClient as client return client(path) def _unregister(self, workspace): """ Skip HTTP errors when cleaning up the test. """ try: pytest.root_remote.unregister_as_root(workspace) except (HTTPError, ConnectionError): pass def bind_engine(self, number: int, start_engine: bool = True) -> None: number_str = str(number) manager = getattr(self, "manager_" + number_str) local_folder = getattr(self, "local_nxdrive_folder_" + number_str) user = getattr(self, "user_" + number_str) password = getattr(self, "password_" + number_str) engine = manager.bind_server(local_folder, pytest.nuxeo_url, user, password, start_engine=start_engine) engine.syncCompleted.connect(self.app.sync_completed) engine.get_remote_watcher().remoteScanFinished.connect( self.app.remote_scan_completed) engine.get_remote_watcher().changesFound.connect( self.app.remote_changes_found) engine.get_remote_watcher().noChangesFound.connect( self.app.no_remote_changes_found) engine_uid = engine.uid self._wait_sync[engine_uid] = True self._wait_remote_scan[engine_uid] = True self._remote_changes_count[engine_uid] = 0 self._no_remote_changes[engine_uid] = False setattr(self, "engine_" + number_str, engine) def unbind_engine(self, number: int) -> None: number_str = str(number) engine = getattr(self, "engine_" + number_str) manager = getattr(self, "manager_" + number_str) manager.unbind_engine(engine.uid) delattr(self, "engine_" + number_str) def send_bind_engine(self, number: int, start_engine: bool = True) -> None: self.app.bindEngine.emit(number, start_engine) def send_unbind_engine(self, number: int) -> None: self.app.unbindEngine.emit(number) def wait_bind_engine(self, number: int, timeout: int = DEFAULT_WAIT_SYNC_TIMEOUT) -> None: engine = "engine_" + str(number) while timeout > 0: sleep(1) timeout -= 1 if getattr(self, engine, False): return self.fail("Wait for bind engine expired") def wait_unbind_engine(self, number: int, timeout: int = DEFAULT_WAIT_SYNC_TIMEOUT) -> None: engine = "engine_" + str(number) while timeout > 0: sleep(1) timeout -= 1 if not getattr(self, engine, False): return self.fail("Wait for unbind engine expired") def wait_sync( self, wait_for_async=False, timeout=DEFAULT_WAIT_SYNC_TIMEOUT, fail_if_timeout=True, wait_for_engine_1=True, wait_for_engine_2=False, wait_win=False, enforce_errors=True, ): log.debug("Wait for sync") # First wait for server if needed if wait_for_async: self.wait() if wait_win: log.trace("Need to wait for Windows delete resolution") sleep(WIN_MOVE_RESOLUTION_PERIOD / 1000) self._wait_sync = { self.engine_1.uid: wait_for_engine_1, self.engine_2.uid: wait_for_engine_2, } self._no_remote_changes = { self.engine_1.uid: not wait_for_engine_1, self.engine_2.uid: not wait_for_engine_2, } if enforce_errors: if not self.connected: self.engine_1.syncPartialCompleted.connect( self.engine_1.get_queue_manager().requeue_errors) self.engine_2.syncPartialCompleted.connect( self.engine_1.get_queue_manager().requeue_errors) self.connected = True elif self.connected: self.engine_1.syncPartialCompleted.disconnect( self.engine_1.get_queue_manager().requeue_errors) self.engine_2.syncPartialCompleted.disconnect( self.engine_1.get_queue_manager().requeue_errors) self.connected = False while timeout > 0: sleep(1) timeout -= 1 if sum(self._wait_sync.values()) == 0: if wait_for_async: log.debug( "Sync completed, " "wait_remote_scan=%r, " "remote_changes_count=%r, " "no_remote_changes=%r", self._wait_remote_scan, self._remote_changes_count, self._no_remote_changes, ) wait_remote_scan = False if wait_for_engine_1: wait_remote_scan |= self._wait_remote_scan[ self.engine_1.uid] if wait_for_engine_2: wait_remote_scan |= self._wait_remote_scan[ self.engine_2.uid] is_remote_changes = True is_change_summary_over = True if wait_for_engine_1: is_remote_changes &= ( self._remote_changes_count[self.engine_1.uid] > 0) is_change_summary_over &= self._no_remote_changes[ self.engine_1.uid] if wait_for_engine_2: is_remote_changes &= ( self._remote_changes_count[self.engine_2.uid] > 0) is_change_summary_over &= self._no_remote_changes[ self.engine_2.uid] if all({ not wait_remote_scan, not is_remote_changes, is_change_summary_over, }): self._wait_remote_scan = { self.engine_1.uid: wait_for_engine_1, self.engine_2.uid: wait_for_engine_2, } self._remote_changes_count = { self.engine_1.uid: 0, self.engine_2.uid: 0, } self._no_remote_changes = { self.engine_1.uid: False, self.engine_2.uid: False, } log.debug("Ended wait for sync, setting " "wait_remote_scan values to True, " "remote_changes_count values to 0 and " "no_remote_changes values to False") return else: log.debug("Sync completed, ended wait for sync") return if fail_if_timeout: count1 = self.engine_1.get_dao().get_syncing_count() count2 = self.engine_2.get_dao().get_syncing_count() if wait_for_engine_1 and count1: err = "Wait for sync timeout expired for engine 1 (%d)" % count1 elif wait_for_engine_2 and count2: err = "Wait for sync timeout expired for engine 2 (%d)" % count2 else: err = "Wait for sync timeout has expired" log.warning(err) else: log.debug("Wait for sync timeout") def run(self, result=None): self.app = StubQApplication([], self) self.setUpApp() def launch_test(): log.debug("UnitTest thread started") pytest.root_remote.log_on_server(">>> testing: " + self.id()) # Note: we cannot use super().run(result) here super(UnitTestCase, self).run(result) self.app.quit() log.debug("UnitTest thread finished") sync_thread = Thread(target=launch_test) sync_thread.start() self.app.exec_() sync_thread.join(30) self.tearDownApp() del self.app log.debug("UnitTest run finished") def _stop_managers(self): """ Called by self.addCleanup() to stop all managers. """ try: methods = itertools.product( ((self.manager_1, 1), (self.manager_2, 2)), ("unbind_all", "dispose_all"), ) for (manager, idx), method in methods: func = getattr(manager, method, None) if func: log.debug("Calling self.manager_%d.%s()", idx, method) try: func() except: pass finally: Manager._singleton = None def _check_cleanup(self): """ Called by self.addCleanup() to ensure folders are deleted. """ try: for root, _, files in os.walk(self.tmpdir): if files: log.error("tempdir not cleaned-up: %r", root) except OSError: pass def _interact(self, pause=0): self.app.processEvents() if pause > 0: sleep(pause) while self.app.hasPendingEvents(): self.app.processEvents() def make_local_tree(self, root=None, local_client=None): nb_files, nb_folders = 6, 4 if not local_client: local_client = self.local_root_client_1 if not root: root = "/" + self.workspace_title if not local_client.exists(root): local_client.make_folder("/", self.workspace_title) nb_folders += 1 # create some folders folder_1 = local_client.make_folder(root, "Folder 1") folder_1_1 = local_client.make_folder(folder_1, "Folder 1.1") folder_1_2 = local_client.make_folder(folder_1, "Folder 1.2") folder_2 = local_client.make_folder(root, "Folder 2") # create some files local_client.make_file(folder_2, "Duplicated File.txt", content=b"Some content.") local_client.make_file(folder_1, "File 1.txt", content=b"aaa") local_client.make_file(folder_1_1, "File 2.txt", content=b"bbb") local_client.make_file(folder_1_2, "File 3.txt", content=b"ccc") local_client.make_file(folder_2, "File 4.txt", content=b"ddd") local_client.make_file(root, "File 5.txt", content=b"eee") return nb_files, nb_folders def make_server_tree(self, deep: bool = True) -> Tuple[int, int]: """ Create some folders on the server. Returns a tuple (files_count, folders_count). """ remote = self.remote_document_client_1 folder_1 = remote.make_folder(self.workspace, "Folder 1") folder_2 = remote.make_folder(self.workspace, "Folder 2") if deep: folder_1_1 = remote.make_folder(folder_1, "Folder 1.1") folder_1_2 = remote.make_folder(folder_1, "Folder 1.2") # Those 2 attrs are used in test_synchronization.py self._duplicate_file_1 = remote.make_file(folder_2, "Duplicated File.txt", content=b"Some content.") self._duplicate_file_2 = remote.make_file( folder_2, "Duplicated File.txt", content=b"Other content.") remote.make_file(folder_1, "File 1.txt", content=b"aaa") remote.make_file(folder_1_1, "File 2.txt", content=b"bbb") remote.make_file(folder_1_2, "File 3.txt", content=b"ccc") remote.make_file(folder_2, "File 4.txt", content=b"ddd") remote.make_file(self.workspace, "File 5.txt", content=b"eee") return (7, 4) if deep else (1, 2) def get_local_child_count(self, path: str) -> Tuple[int, int]: """ Create some folders on the server. Returns a tuple (files_count, folders_count). """ dir_count = file_count = 0 for _, dirnames, filenames in os.walk(path): dir_count += len(dirnames) file_count += len(filenames) if os.path.exists(os.path.join(path, ".partials")): dir_count -= 1 return file_count, dir_count def get_full_queue(self, queue, dao=None): if dao is None: dao = self.engine_1.get_dao() result = [] while queue: result.append(dao.get_state_from_id(queue.pop().id)) return result def wait(self, retry=3): try: pytest.root_remote.wait() except Exception as e: log.debug("Exception while waiting for server : %r", e) # Not the nicest if retry > 0: log.debug("Retry to wait") self.wait(retry - 1) def generate_report(self): """ Generate a report on failure. """ if not self.report_path: return # Track any exception that could happen, specially those we would not # see if the test succeed. for _, error in vars(self._outcome).get("errors"): exception = str(error[1]).lower() message = str(error[2]).lower() if "mock" not in exception and "mock" not in message: break else: # No break => no unexpected exceptions return path = os.path.join(self.report_path, self.id() + "-" + sys.platform) if WINDOWS: path = "\\\\?\\" + path.replace("/", os.path.sep) self.manager_1.generate_report(path) def _set_read_permission(self, user, doc_path, grant): input_obj = "doc:" + doc_path remote = pytest.root_remote if grant: remote.operations.execute( command="Document.SetACE", input_obj=input_obj, user=user, permission="Read", grant=True, ) else: remote.block_inheritance(doc_path) @staticmethod def generate_random_png(filename: str = None, size: int = 0) -> Union[None, bytes]: """ Generate a random PNG file. :param filename: The output file name. If None, returns the picture content. :param size: The number of black pixels of the picture. :return: None if given filename else bytes """ if not size: size = random.randint(1, 42) else: size = max(1, size) pack = struct.pack def chunk(header, data): return (pack(">I", len(data)) + header + data + pack(">I", zlib.crc32(header + data) & 0xffffffff)) magic = pack(">8B", 137, 80, 78, 71, 13, 10, 26, 10) png_filter = pack(">B", 0) scanline = pack(">{}B".format(size * 3), *[0] * (size * 3)) content = [png_filter + scanline for _ in range(size)] png = (magic + chunk(b"IHDR", pack(">2I5B", size, size, 8, 2, 0, 0, 0)) + chunk(b"IDAT", zlib.compress(b"".join(content))) + chunk(b"IEND", b"")) if not filename: return png with open(filename, "wb") as fileo: fileo.write(png) def assertNxPart(self, path: str, name: str): for child in os.listdir(self.local_1.abspath(path)): if len(child) < 8: continue if name is not None and len(child) < len(name) + 8: continue if (child[0] == "." and child.endswith(".nxpart") and (name is None or child[1:len(name) + 1] == name)): self.fail("nxpart found in %r" % path) def get_dao_state_from_engine_1(self, path: str): """ Returns the pair from dao of engine 1 according to the path. :param path: The path to document (from workspace, ex: /Folder is converted to /{{workspace_title_1}}/Folder). :return: The pair from dao of engine 1 according to the path. """ abs_path = "/" + self.workspace_title_1 + path return self.engine_1.get_dao().get_state_from_local(abs_path) def set_readonly(self, user: str, doc_path: str, grant: bool = True): """ Mark a document as RO or RW. :param user: Affected username. :param doc_path: The document, either a folder or a file. :param grant: Set RO if True else RW. """ remote = pytest.root_remote input_obj = "doc:" + doc_path if grant: remote.operations.execute( command="Document.SetACE", input_obj=input_obj, user=user, permission="Read", ) remote.block_inheritance(doc_path, overwrite=False) else: remote.operations.execute( command="Document.SetACE", input_obj=input_obj, user=user, permission="ReadWrite", grant=True, )