def test_synchronize_deleted_blob(self):
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Launch first synchronization
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn = ctl.synchronizer
        syn.loop(delay=0.1, max_loops=1)

        # Get local and remote clients
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_document_client_1

        # Create a doc with a blob in the remote root workspace
        # then synchronize
        remote.make_file('/', 'test.odt', 'Some content.')

        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(local.exists('/test.odt'))

        # Delete the blob from the remote doc then synchronize
        remote.delete_content('/test.odt')

        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0.1, max_loops=1)
        self.assertFalse(local.exists('/test.odt'))
    def test_drive_edit_doc_becoming_synced(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        local = LocalClient(self.local_nxdrive_folder_1)
        remote = self.remote_document_client_1
        syn = ctl.synchronizer

        # Create file in test workspace (non sync root)
        doc_id = remote.make_file('/', 'test.odt', 'Some content.')

        # Drive edit file
        ctl.download_edit(self.nuxeo_url, 'default', doc_id, 'test.odt',
                          open_file=False)

        # Check file is downloaded to the Locally Edited folder
        self.assertTrue(local.exists('/%s/test.odt'
                                     % LOCALLY_EDITED_FOLDER_NAME))

        # Register test workspace as a sync root
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)
        self._sync(syn)
        self.assertTrue(local.exists('/%s/test.odt' % self.workspace_title))

        # Update file in local sync root
        time.sleep(OS_STAT_MTIME_RESOLUTION)
        local.update_content('/%s/test.odt' % self.workspace_title,
                             'Content updated from local sync root.')
        self._sync(syn, wait_for_async=False)
        self.assertEquals(remote.get_content('/test.odt'),
                          'Content updated from local sync root.')
        self._sync(syn)
        self.assertEquals(local.get_content('/%s/test.odt'
                                    % LOCALLY_EDITED_FOLDER_NAME),
                                    'Content updated from local sync root.')

        # Update locally edited file
        time.sleep(OS_STAT_MTIME_RESOLUTION)
        local.update_content('/%s/test.odt' % LOCALLY_EDITED_FOLDER_NAME,
                             'Content updated from Locally Edited.')
        self._sync(syn, wait_for_async=False)
        self.assertEquals(remote.get_content('/test.odt'),
                          'Content updated from Locally Edited.')
        self._sync(syn)
        self.assertEquals(local.get_content('/%s/test.odt'
                                    % self.workspace_title),
                                    'Content updated from Locally Edited.')

        # Update file in remote sync root
        remote.update_content('/test.odt',
                             'Content updated from remote sync root.')
        self._sync(syn)
        self.assertEquals(local.get_content('/%s/test.odt'
                                    % self.workspace_title),
                                    'Content updated from remote sync root.')
        self.assertEquals(local.get_content('/%s/test.odt'
                                    % LOCALLY_EDITED_FOLDER_NAME),
                                    'Content updated from remote sync root.')
    def test_delete_local_folder_delay_remote_changes_fetch(self):

        # Get local and remote clients
        local = LocalClient(self.local_nxdrive_folder_1)
        remote = self.remote_document_client_1

        # Bind server and test workspace for nuxeoDriveTestUser_user_1
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Launch first synchronization
        self.wait_audit_change_finder_if_needed()
        self.wait()
        sync = ctl.synchronizer
        sync.loop(delay=0.1, max_loops=1)

        # Test workspace should be created locally
        self.assertTrue(local.exists('/Nuxeo Drive Test Workspace'))

        # Create a local folder in the test workspace and a file inside
        # this folder, then synchronize
        local.make_folder('/Nuxeo Drive Test Workspace', 'Test folder')
        local.make_file('/Nuxeo Drive Test Workspace/Test folder',
                        'test.odt', 'Some content.')

        sync.loop(delay=0.1, max_loops=1)

        # Test folder should be created remotely in the test workspace
        self.assertTrue(remote.exists('/Test folder'))
        self.assertTrue(remote.exists('/Test folder/test.odt'))

        # Delete Test folder locally before fetching remote changes,
        # then synchronize
        local.delete('/Nuxeo Drive Test Workspace/Test folder')
        self.assertFalse(local.exists(
                                    '/Nuxeo Drive Test Workspace/Test folder'))

        self.wait_audit_change_finder_if_needed()
        self.wait()
        sync.loop(delay=0.1, max_loops=1)

        # Test folder should be deleted remotely in the test workspace.
        # Even though fetching the remote changes will send
        # 'documentCreated' events for Test folder and its child file
        # as a result of the previous synchronization loop, since the folder
        # will not have been renamed nor moved since last synchronization,
        # its remote pair state will not be marked as 'modified',
        # see Model.update_remote().
        # Thus the pair state will be ('deleted', 'synchronized'), resolved as
        # 'locally_deleted'.
        self.assertFalse(remote.exists('Test folder'))

        # Check Test folder has not been re-created locally
        self.assertFalse(local.exists(
                                    '/Nuxeo Drive Test Workspace/Test folder'))
Exemple #4
0
    def test_sync_delete_root(self):
        user_workspace_uid = None
        try:
            # Get remote and local clients
            admin_remote_client = self.root_remote_client
            user_remote_client = RemoteDocumentClient(
                self.nuxeo_url,
                self.user_1,
                u'nxdrive-test-device-1',
                self.version,
                password=self.password_1,
                upload_tmp_dir=self.upload_tmp_dir)
            local_client = LocalClient(self.local_nxdrive_folder_1)

            # Make sure user workspace is created and fetch its uid
            user_workspace_uid = user_remote_client.make_file_in_user_workspace(
                'File in user workspace', filename='USFile.txt')['parentRef']

            # Create test folder in user workspace as test user
            test_folder_uid = user_remote_client.make_folder(
                user_workspace_uid, 'test_folder')
            # Create a document in the test folder
            user_remote_client.make_file(test_folder_uid, 'test_file.txt',
                                         "Some content.")

            # Register test folder as a sync root
            user_remote_client.register_as_root(test_folder_uid)

            # Start engine
            self.engine_1.start()

            # Wait for synchronization
            self.wait_sync(wait_for_async=True)

            # Check locally synchronized content
            self.assertTrue(local_client.exists('/My Docs/test_folder'))
            self.assertTrue(
                local_client.exists('/My Docs/test_folder/test_file.txt'))

            # Delete test folder
            user_remote_client.delete(test_folder_uid)

            # Wait for synchronization
            self.wait_sync(wait_for_async=True)

            # Check locally synchronized content
            self.assertFalse(local_client.exists('/My Docs/test_folder'))
            self.assertEquals(len(local_client.get_children_info('/My Docs')),
                              0)
        finally:
            # Cleanup user workspace
            if user_workspace_uid is not None and admin_remote_client.exists(
                    user_workspace_uid):
                admin_remote_client.delete(user_workspace_uid, use_trash=False)
    def test_synchronize_deep_folders(self):
        # Increase Automation execution timeout for NuxeoDrive.GetChangeSummary
        # because of the recursive parent FileSystemItem adaptation
        ctl = self.controller_1
        ctl.timeout = 40
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)
        syn = ctl.synchronizer

        # Fetch the workspace sync root
        syn.loop(delay=0, max_loops=1)
        self.assertEquals(ctl.list_pending(), [])

        # Create a file deep down in the hierarchy
        remote = self.remote_document_client_1

        folder_name = '0123456789'
        folder_depth = 40
        folder = '/'
        for _ in range(folder_depth):
            folder = remote.make_folder(folder, folder_name)

        remote.make_file(folder, "File.odt", content="Fake non-zero content.")

        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0, max_loops=5)
        self.assertEquals(ctl.list_pending(), [])

        local = LocalClient(self.local_nxdrive_folder_1)
        expected_folder_path = (
            '/' + self.workspace_title + ('/' + folder_name) * folder_depth)

        expected_file_path = expected_folder_path + '/File.odt'
        self.assertTrue(local.exists(expected_folder_path))
        self.assertTrue(local.exists(expected_file_path))
        self.assertEquals(local.get_content(expected_file_path),
                          "Fake non-zero content.")

        # Delete the nested folder structure on the remote server
        # and synchronize again
        remote.delete('/' + folder_name)

        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0, max_loops=5)
        self.assertEquals(ctl.list_pending(), [])

        self.assertFalse(local.exists(expected_folder_path))
        self.assertFalse(local.exists(expected_file_path))
Exemple #6
0
    def test_single_quote_escaping(self):
        remote = self.remote_document_client_1
        local = LocalClient(self.local_nxdrive_folder_1)

        remote.unregister_as_root(self.workspace)
        self.engine_1.start()
        remote.make_folder('/', "APPEL D'OFFRES")
        remote.register_as_root("/APPEL D'OFFRES")
        self.wait_sync(wait_for_async=True)
        self.assertTrue(local.exists("/APPEL D'OFFRES"))

        remote.unregister_as_root("/APPEL D'OFFRES")
        self.wait_sync(wait_for_async=True)
        self.assertFalse(local.exists("/APPEL D'OFFRES"))
    def test_single_quote_escaping(self):
        remote = self.remote_document_client_1
        local = LocalClient(self.local_nxdrive_folder_1)

        remote.unregister_as_root(self.workspace)
        self.engine_1.start()
        remote.make_folder('/', "APPEL D'OFFRES")
        remote.register_as_root("/APPEL D'OFFRES")
        self.wait_sync(wait_for_async=True)
        self.assertTrue(local.exists("/APPEL D'OFFRES"))

        remote.unregister_as_root("/APPEL D'OFFRES")
        self.wait_sync(wait_for_async=True)
        self.assertFalse(local.exists("/APPEL D'OFFRES"))
    def test_self_conflict(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")
        ctl = self.controller_1
        sb = ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        if not ctl.get_top_level_state(self.local_nxdrive_folder_1).last_remote_modifier:
            raise SkipTest("Self-conflict automatic resolution not implemented in Nuxeo Platform %s"
                           % sb.server_version)
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_file_system_client_1
        syn = ctl.synchronizer

        # Launch first synchronization
        self._sync(syn)
        self.assertTrue(local.exists('/test.txt'))

        # Update content on both sides by the same user, remote last
        time.sleep(OS_STAT_MTIME_RESOLUTION)
        local.update_content('/test.txt', 'Local update')
        time.sleep(1.0)
        remote.update_content(self.file_id, 'Remote update')
        self._sync(syn, max_loops=2)

        self.assertEquals(len(local.get_children_info('/')), 1)
        self.assertTrue(local.exists('/test.txt'))
        self.assertEquals(local.get_content('/test.txt'), 'Remote update')

        remote_children = remote.get_children_info(self.workspace_id)
        self.assertEquals(len(remote_children), 1)
        self.assertEquals(remote_children[0].uid, self.file_id)
        self.assertEquals(remote_children[0].name, 'test.txt')
        self.assertEquals(remote.get_content(remote_children[0].uid), 'Remote update')

        # Update content on both sides by the same user, local last
        remote.update_content(self.file_id, 'Remote update 2')
        time.sleep(OS_STAT_MTIME_RESOLUTION)
        local.update_content('/test.txt', 'Local update 2')
        self._sync(syn, max_loops=2)

        self.assertEquals(len(local.get_children_info('/')), 1)
        self.assertTrue(local.exists('/test.txt'))
        self.assertEquals(local.get_content('/test.txt'), 'Local update 2')

        remote_children = remote.get_children_info(self.workspace_id)
        self.assertEquals(len(remote_children), 1)
        self.assertEquals(remote_children[0].uid, self.file_id)
        self.assertEquals(remote_children[0].name, 'test.txt')
        self.assertEquals(remote.get_content(remote_children[0].uid), 'Local update 2')
    def test_synchronize_local_filter_with_remote_trash(self):
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_document_client_1
        session = ctl.get_session()

        # Create documents in the remote root workspace
        # then synchronize
        remote.make_folder('/', 'Test')
        remote.make_file('/Test', 'joe.txt', 'Some content')

        syn = ctl.synchronizer
        self._synchronize(syn)
        self.assertTrue(local.exists('/Test'))
        self.assertTrue(local.exists('/Test/joe.txt'))

        # Add remote folder as filter then synchronize
        doc = remote.get_info('/Test')
        root_path = "/org.nuxeo.drive.service.impl.DefaultTopLevelFolderItemFactory#/defaultSyncRootFolderItemFactory#default#"
        root_path = root_path + doc.root
        doc_path = (root_path + "/defaultFileSystemItemFactory#default#"
                    + doc.uid)
        server_binding = ctl.get_server_binding(self.local_nxdrive_folder_1,
                                                session=session)
        Filter.add(session, server_binding, doc_path)
        self._synchronize(syn)
        self.assertFalse(local.exists('/Test'))

        # Delete remote folder then synchronize
        remote.delete('/Test')
        self._synchronize(syn)
        self.assertFalse(local.exists('/Test'))

        # Restore folder from trash then synchronize
        # Undeleting each item as following 'undelete' transition
        # doesn't act recursively, should use TrashService instead
        # through a dedicated operation
        remote.undelete('/Test')
        remote.undelete('/Test/joe.txt')
        # NXDRIVE-xx check that the folder is not created as it is filtered
        self._synchronize(syn)
        self.assertFalse(local.exists('/Test'))
    def test_sync_delete_root(self):
        user_workspaces_path = '/default-domain/UserWorkspaces/'
        user_workspace_title = 'nuxeoDriveTestUser-user-1'
        user_workspace_path = user_workspaces_path + user_workspace_title
        try:
            # Get remote and local clients
            admin_remote_client = self.root_remote_client
            user_remote_client = RemoteDocumentClient(
                self.nuxeo_url, self.user_1, u'nxdrive-test-device-1',
                self.version, password=self.password_1,
                upload_tmp_dir=self.upload_tmp_dir)
            local_client = LocalClient(self.local_nxdrive_folder_1)

            # Make sure user workspace is created
            user_remote_client.make_file_in_user_workspace('File in user workspace', filename='USFile.txt')

            # Create test folder in user workspace as test user
            user_remote_client.make_folder(user_workspace_path, 'test_folder')
            test_folder_path = user_workspace_path + '/test_folder'
            # Create a document in the test folder
            user_remote_client.make_file(test_folder_path, 'test_file.txt', "Some content.")

            # Register test folder as a sync root
            user_remote_client.register_as_root(test_folder_path)

            # Start engine
            self.engine_1.start()

            # Wait for synchronization
            self.wait_sync(wait_for_async=True)

            # Check locally synchronized content
            self.assertTrue(local_client.exists('/My Docs/test_folder'))
            self.assertTrue(local_client.exists('/My Docs/test_folder/test_file.txt'))

            # Delete test folder
            user_remote_client.delete(test_folder_path)

            # Wait for synchronization
            self.wait_sync(wait_for_async=True)

            # Check locally synchronized content
            self.assertFalse(local_client.exists('/My Docs/test_folder'))
            self.assertEquals(len(local_client.get_children_info('/My Docs')), 0)
        finally:
            # Cleanup user workspace
            if admin_remote_client.exists(user_workspace_path):
                admin_remote_client.delete(user_workspace_path,
                                           use_trash=False)
    def test_synchronize_local_filter_with_remote_trash(self):
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(
            os.path.join(self.local_nxdrive_folder_1, self.workspace_title))
        remote = self.remote_document_client_1
        session = ctl.get_session()

        # Create documents in the remote root workspace
        # then synchronize
        remote.make_folder('/', 'Test')
        remote.make_file('/Test', 'joe.txt', 'Some content')

        syn = ctl.synchronizer
        self._synchronize(syn)
        self.assertTrue(local.exists('/Test'))
        self.assertTrue(local.exists('/Test/joe.txt'))

        # Add remote folder as filter then synchronize
        doc = remote.get_info('/Test')
        root_path = "/org.nuxeo.drive.service.impl.DefaultTopLevelFolderItemFactory#/defaultSyncRootFolderItemFactory#default#"
        root_path = root_path + doc.root
        doc_path = (root_path + "/defaultFileSystemItemFactory#default#" +
                    doc.uid)
        server_binding = ctl.get_server_binding(self.local_nxdrive_folder_1,
                                                session=session)
        Filter.add(session, server_binding, doc_path)
        self._synchronize(syn)
        self.assertFalse(local.exists('/Test'))

        # Delete remote folder then synchronize
        remote.delete('/Test')
        self._synchronize(syn)
        self.assertFalse(local.exists('/Test'))

        # Restore folder from trash then synchronize
        # Undeleting each item as following 'undelete' transition
        # doesn't act recursively, should use TrashService instead
        # through a dedicated operation
        remote.undelete('/Test')
        remote.undelete('/Test/joe.txt')
        # NXDRIVE-xx check that the folder is not created as it is filtered
        self._synchronize(syn)
        self.assertFalse(local.exists('/Test'))
    def test_single_quote_escaping(self):
        remote = self.remote_document_client_1
        local = LocalClient(self.local_nxdrive_folder_1)
        self.setUpDrive_1(bind_root=False)

        remote.make_folder('/', "APPEL D'OFFRES")
        remote.register_as_root("/APPEL D'OFFRES")
        self.wait()
        self.ndrive()
        self.assertTrue(local.exists("/APPEL D'OFFRES"))

        remote.unregister_as_root("/APPEL D'OFFRES")
        self.wait()
        self.ndrive()
        self.assertFalse(local.exists("/APPEL D'OFFRES"))
    def test_local_rename_top_level_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = LocalClient(self.local_test_folder_1)
        session = ctl.get_session()

        # Check top level folder
        self.assertTrue(local_client.exists(u'/Nuxeo Drive'))
        top_level_folder_info = local_client.get_info(u'/Nuxeo Drive')
        self.assertEquals(top_level_folder_info.name, u'Nuxeo Drive')
        self.assertEquals(top_level_folder_info.filepath,
            os.path.join(self.local_test_folder_1, u'Nuxeo Drive'))
        # Check top level folder state
        top_level_folder_state = session.query(LastKnownState).filter_by(
            local_name=u'Nuxeo Drive').one()
        self.assertEquals(top_level_folder_state.local_path, '/')
        self.assertEquals(top_level_folder_state.local_name, u'Nuxeo Drive')

        # Rename top level folder
        local_client.rename(u'/Nuxeo Drive', u'Nuxeo Drive renamed')
        top_level_folder_info = local_client.get_info(u'/Nuxeo Drive renamed')
        self.assertEquals(top_level_folder_info.name, u'Nuxeo Drive renamed')
        self.assertEquals(top_level_folder_info.filepath,
            os.path.join(self.local_test_folder_1, u'Nuxeo Drive renamed'))

        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 1)

        # Check deleted server binding
        self.assertRaises(RuntimeError,
                          ctl.get_server_binding, self.local_nxdrive_folder_1,
                          raise_if_missing=True)
        # Check deleted pair state
        self.assertEquals(len(session.query(LastKnownState).all()), 0)
    def test_local_rename_top_level_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = LocalClient(self.local_test_folder_1)
        session = ctl.get_session()

        # Check top level folder
        self.assertTrue(local_client.exists(u'/Nuxeo Drive'))
        top_level_folder_info = local_client.get_info(u'/Nuxeo Drive')
        self.assertEquals(top_level_folder_info.name, u'Nuxeo Drive')
        self.assertEquals(
            top_level_folder_info.filepath,
            os.path.join(self.local_test_folder_1, u'Nuxeo Drive'))
        # Check top level folder state
        top_level_folder_state = session.query(LastKnownState).filter_by(
            local_name=u'Nuxeo Drive').one()
        self.assertEquals(top_level_folder_state.local_path, '/')
        self.assertEquals(top_level_folder_state.local_name, u'Nuxeo Drive')

        # Rename top level folder
        local_client.rename(u'/Nuxeo Drive', u'Nuxeo Drive renamed')
        top_level_folder_info = local_client.get_info(u'/Nuxeo Drive renamed')
        self.assertEquals(top_level_folder_info.name, u'Nuxeo Drive renamed')
        self.assertEquals(
            top_level_folder_info.filepath,
            os.path.join(self.local_test_folder_1, u'Nuxeo Drive renamed'))

        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 1)

        # Check deleted server binding
        self.assertRaises(RuntimeError,
                          ctl.get_server_binding,
                          self.local_nxdrive_folder_1,
                          raise_if_missing=True)
        # Check deleted pair state
        self.assertEquals(len(session.query(LastKnownState).all()), 0)
    def test_drive_edit_remote_move_sync_root_to_non_sync_root(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        local = LocalClient(self.local_nxdrive_folder_1)
        remote = self.remote_document_client_1
        syn = ctl.synchronizer

        # Create folder, register it as a sync root and create file inside it
        sync_root_id = remote.make_folder('/', 'syncRoot')
        ctl.bind_root(self.local_nxdrive_folder_1, sync_root_id)
        doc_id = remote.make_file(sync_root_id, 'test.odt', 'Some content.')

        # Launch first synchronization
        self._sync(syn)
        self.assertTrue(local.exists('/syncRoot/test.odt'))

        # Drive edit file
        ctl.download_edit(self.nuxeo_url, 'default', doc_id, 'test.odt',
                          open_file=False)

        # Check file is downloaded to the Locally Edited folder
        self.assertTrue(local.exists('/%s/test.odt'
                                     % LOCALLY_EDITED_FOLDER_NAME))

        # Update locally edited file
        # Let's first sync because of https://jira.nuxeo.com/browse/NXDRIVE-144
        self._sync(syn)
        time.sleep(OS_STAT_MTIME_RESOLUTION)
        local.update_content('/%s/test.odt' % LOCALLY_EDITED_FOLDER_NAME,
                             'Content updated from Locally Edited.')
        self._sync(syn, wait_for_async=False)
        self.assertEquals(remote.get_content('/syncRoot/test.odt'),
                          'Content updated from Locally Edited.')
        self._sync(syn)
        self.assertEquals(local.get_content('/syncRoot/test.odt'),
                          'Content updated from Locally Edited.')

        # Move file to non sync root workspace
        remote.move('/syncRoot/test.odt', self.workspace)
        self._sync(syn)
        self.assertFalse(local.exists('/syncRoot/test.odt'))
        self.assertTrue(local.exists('/%s/test.odt'
                                     % LOCALLY_EDITED_FOLDER_NAME))
        self.assertEquals(len(local.get_children_info('/%s'
                                    % LOCALLY_EDITED_FOLDER_NAME)), 1)
    def test_synchronize_deep_folders(self):
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)
        syn = ctl.synchronizer

        # Fetch the workspace sync root
        syn.loop(delay=0, max_loops=1)
        self.assertEquals(ctl.list_pending(), [])

        # Create a file deep down in the hierarchy
        remote = self.remote_document_client_1

        folder = '/'
        for i in range(10):
            folder = remote.make_folder(folder, '0123456789' * 3)

        remote.make_file(folder, "File.odt", content="Fake non-zero content.")

        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0, max_loops=1)
        self.assertEquals(ctl.list_pending(), [])

        local = LocalClient(self.local_nxdrive_folder_1)
        expected_folder_path = ('/' + self.workspace_title
                                + ('/' + '0123456789' * 3) * 10)
        expected_file_path = expected_folder_path + '/File.odt'
        self.assertTrue(local.exists(expected_folder_path))
        self.assertTrue(local.exists(expected_file_path))
        self.assertEquals(local.get_content(expected_file_path),
                          "Fake non-zero content.")

        # Delete the nested folder structure on the remote server and synchronize
        # again
        remote.delete('/' + '0123456789' * 3)

        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0, max_loops=1)
        self.assertEquals(ctl.list_pending(), [])

        self.assertFalse(local.exists(expected_folder_path))
        self.assertFalse(local.exists(expected_file_path))
    def test_drive_edit_non_synced_doc(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        local = LocalClient(self.local_nxdrive_folder_1)
        remote = self.remote_document_client_1
        syn = ctl.synchronizer

        # Create file in test workspace (non sync root)
        doc_id = remote.make_file('/', 'test.odt', 'Some content.')

        # Drive edit file
        ctl.download_edit(self.nuxeo_url, 'default', doc_id, 'test.odt',
                          open_file=False)

        # Check file is downloaded to the Locally Edited folder
        self.assertTrue(local.exists('/%s/test.odt'
                                     % LOCALLY_EDITED_FOLDER_NAME))
        self.assertEquals(local.get_content('/%s/test.odt'
                                            % LOCALLY_EDITED_FOLDER_NAME),
                          'Some content.')

        # Check Locally Edited collection exists, is registered as a sync root
        # for test user and file is member of it
        self.assertTrue(self.root_remote_client.exists(
                                                    self.locally_edited_path))
        sync_roots = remote.get_roots()
        self.assertEquals(len(sync_roots), 1)
        self.assertEquals(sync_roots[0].path, self.locally_edited_path)
        self.assertTrue(doc_id in
                        self.root_remote_client.get_collection_members(
                                                    self.locally_edited_path))

        # Update locally edited file
        # Let's first sync because of https://jira.nuxeo.com/browse/NXDRIVE-144
        self._sync(syn)
        time.sleep(OS_STAT_MTIME_RESOLUTION)
        local.update_content('/%s/test.odt' % LOCALLY_EDITED_FOLDER_NAME,
                             'Updated content.')
        self._sync(syn, wait_for_async=False)
        self.assertEquals(remote.get_content('/test.odt'), 'Updated content.')

        # Drive edit file a second time (should not download a new file but
        # detect the existing one)
        ctl.download_edit(self.nuxeo_url, 'default', doc_id, 'test.odt',
                          open_file=False)
        self.assertEquals(len(local.get_children_info('/%s'
                                            % LOCALLY_EDITED_FOLDER_NAME)), 1)
        # Update locally edited file
        time.sleep(OS_STAT_MTIME_RESOLUTION)
        local.update_content('/%s/test.odt' % LOCALLY_EDITED_FOLDER_NAME,
                             'Twice updated content.')
        self._sync(syn, wait_for_async=False)
        self.assertEquals(remote.get_content('/test.odt'),
                          'Twice updated content.')
    def test_synchronize_local_folder_rename_remote_deletion(self):
        """Test local folder rename followed by remote deletion"""
        raise SkipTest("Skipped waiting for"
                       " https://jira.nuxeo.com/browse/NXDRIVE-80 to be fixed")
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_document_client_1

        # Create a folder with a child file in the remote root workspace
        # then synchronize
        test_folder_uid = remote.make_folder('/', 'Test folder')
        remote.make_file(test_folder_uid, 'joe.odt', 'Some content')

        syn = ctl.synchronizer
        self._synchronize(syn)
        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.odt'))

        # Locally rename the folder then synchronize
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        local.rename('/Test folder', 'Test folder renamed')

        self._synchronize(syn)
        self.assertFalse(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder renamed'))
        self.assertEquals(remote.get_info(test_folder_uid).name,
                          'Test folder renamed')

        # Delete remote folder then synchronize
        remote.delete('/Test folder')

        self._synchronize(syn)
        self.assertFalse(remote.exists('/Test folder renamed'))
        self.assertFalse(local.exists('/Test folder renamed'))
    def test_synchronize_deep_folders(self):
        if sys.platform.startswith('linux'):
            raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")
        # Increase Automation execution timeout for NuxeoDrive.GetChangeSummary
        # because of the recursive parent FileSystemItem adaptation
        self.setUpDrive_1(firstSync=True)

        # Create a file deep down in the hierarchy
        remote = self.remote_document_client_1

        folder_name = '0123456789'
        folder_depth = 40
        folder = '/'
        for _ in range(folder_depth):
            folder = remote.make_folder(folder, folder_name)

        remote.make_file(folder, "File.odt", content="Fake non-zero content.")

        self.wait()
        self.ndrive()

        local = LocalClient(self.local_nxdrive_folder_1)
        expected_folder_path = (
            '/' + self.workspace_title + ('/' + folder_name) * folder_depth)

        expected_file_path = expected_folder_path + '/File.odt'
        self.assertTrue(local.exists(expected_folder_path))
        self.assertTrue(local.exists(expected_file_path))
        self.assertEquals(local.get_content(expected_file_path),
                          "Fake non-zero content.")

        # Delete the nested folder structure on the remote server
        # and synchronize again
        remote.delete('/' + folder_name)

        self.wait()
        self.ndrive()

        self.assertFalse(local.exists(expected_folder_path))
        self.assertFalse(local.exists(expected_file_path))
    def test_trash_modified_file(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")
        """Test deleting a remote folder while a file is locally created in it.

        See https://jira.nuxeo.com/browse/NXDRIVE-39
        See TestIntegrationRemoteDeletion.test_synchronize_remote_deletion_local_modification
        as the same use case is tested.
        """
        ctl = self.controller_1
        # Override the behavior to force use of trash
        ctl.trash_modified_file = lambda: True

        # Bind the server and root workspace
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_document_client_1

        syn = ctl.synchronizer

        # Create a remote folder then synchronize
        remote.make_folder('/', 'Test folder')
        self._synchronize(syn)
        self.assertTrue(remote.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder'))

        # Delete remote folder and create files in the local one then
        # synchronize
        remote.delete('/Test folder')
        local.make_file('/Test folder', 'joe.txt', 'My name is Joe.')
        self._synchronize(syn)

        self.assertFalse(remote.exists('/Test folder'))
        self.assertFalse(local.exists('/Test folder'))
    def test_synchronize_remote_copy(self):
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Launch first synchronization
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn = ctl.synchronizer
        syn.loop(delay=0.1, max_loops=1)

        # Get local and remote clients
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_document_client_1

        # Create a file and a folder in the remote root workspace
        # then synchronize
        remote.make_file('/', 'test.odt', 'Some content.')
        remote.make_folder('/', 'Test folder')

        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(local.exists('/test.odt'))
        self.assertTrue(local.exists('/Test folder'))

        # Copy the file to the folder remotely then synchronize
        remote.copy('/test.odt', '/Test folder')

        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(local.exists('/Test folder/test.odt'))
        self.assertEquals(local.get_content('/Test folder/test.odt'),
                          'Some content.')
Exemple #22
0
    def test_trash_modified_file(self):
        """Test deleting a remote folder while a file is locally created in it.

        See https://jira.nuxeo.com/browse/NXDRIVE-39
        See TestIntegrationRemoteDeletion.test_synchronize_remote_deletion_local_modification
        as the same use case is tested.
        """
        ctl = self.controller_1
        # Override the behavior to force use of trash
        ctl.trash_modified_file = lambda: True

        # Bind the server and root workspace
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(
            os.path.join(self.local_nxdrive_folder_1, self.workspace_title))
        remote = self.remote_document_client_1

        syn = ctl.synchronizer

        # Create a remote folder then synchronize
        remote.make_folder('/', 'Test folder')
        self._synchronize(syn)
        self.assertTrue(remote.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder'))

        # Delete remote folder and create files in the local one then
        # synchronize
        remote.delete('/Test folder')
        local.make_file('/Test folder', 'joe.txt', 'My name is Joe.')
        self._synchronize(syn)

        self.assertFalse(remote.exists('/Test folder'))
        self.assertFalse(local.exists('/Test folder'))
    def test_synchronize_remote_deletion(self):
        raise SkipTest("Skipped for the moment as it generates too much"
                       " error logs")

        """Test that deleting remote root document while uploading is handled

        See https://jira.nuxeo.com/browse/NXDRIVE-39
        See TestIntegrationSecurityUpdates.test_synchronize_denying_read_access
        as the same uses cases are tested
        """
        # Bind the server and root workspace
        ctl = self.controller_1
        # Override the behavior to force use of trash
        ctl.trash_modified_file = lambda: True
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_document_client_1

        syn = ctl.synchronizer
        self._synchronize(syn)
        # Create documents in the local root workspace
        # then synchronize
        local.make_folder('/', 'Test folder')
        i = 0
        while i < 400:
            local.make_file('/Test folder', ('joe%d.bin' % i), 'Some content')
            i += 1

        self._synchronize(syn)
        # All files should not be synchronized
        self.assertTrue(remote.exists('/Test folder'))
        self.assertTrue(remote.exists('/Test folder/joe0.bin'))
        self.assertFalse(remote.exists('/Test folder/joe399.bin'))

        # Delete remote folder then synchronize
        remote.delete('/Test folder')
        # Error counter should be in place
        self._synchronize(syn)
        self.assertFalse(local.exists('/Test folder'))
Exemple #24
0
    def test_synchronize_remote_deletion(self):
        raise SkipTest("Skipped for the moment as it generates too much"
                       " error logs")
        """Test that deleting remote root document while uploading is handled

        See https://jira.nuxeo.com/browse/NXDRIVE-39
        See TestIntegrationSecurityUpdates.test_synchronize_denying_read_access
        as the same uses cases are tested
        """
        # Bind the server and root workspace
        ctl = self.controller_1
        # Override the behavior to force use of trash
        ctl.trash_modified_file = lambda: True
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(
            os.path.join(self.local_nxdrive_folder_1, self.workspace_title))
        remote = self.remote_document_client_1

        syn = ctl.synchronizer
        self._synchronize(syn)
        # Create documents in the local root workspace
        # then synchronize
        local.make_folder('/', 'Test folder')
        i = 0
        while i < 400:
            local.make_file('/Test folder', ('joe%d.bin' % i), 'Some content')
            i += 1

        self._synchronize(syn)
        # All files should not be synchronized
        self.assertTrue(remote.exists('/Test folder'))
        self.assertTrue(remote.exists('/Test folder/joe0.bin'))
        self.assertFalse(remote.exists('/Test folder/joe399.bin'))

        # Delete remote folder then synchronize
        remote.delete('/Test folder')
        # Error counter should be in place
        self._synchronize(syn)
        self.assertFalse(local.exists('/Test folder'))
    def test_local_delete_top_level_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = LocalClient(self.local_test_folder_1)
        session = ctl.get_session()

        # Check top level folder
        self.assertTrue(local_client.exists(u'/Nuxeo Drive'))

        # Delete top level folder
        local_client.delete(u'/Nuxeo Drive')
        self.assertRaises(NotFound,
                          local_client.get_info, u'/Nuxeo Drive')

        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 1)

        # Check deleted server binding
        self.assertRaises(RuntimeError,
                          ctl.get_server_binding, self.local_nxdrive_folder_1,
                          raise_if_missing=True)
        # Check deleted pair state
        self.assertEquals(len(session.query(LastKnownState).all()), 0)
    def test_local_delete_top_level_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = LocalClient(self.local_test_folder_1)
        session = ctl.get_session()

        # Check top level folder
        self.assertTrue(local_client.exists(u'/Nuxeo Drive'))

        # Delete top level folder
        local_client.delete(u'/Nuxeo Drive')
        self.assertRaises(NotFound, local_client.get_info, u'/Nuxeo Drive')

        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 1)

        # Check deleted server binding
        self.assertRaises(RuntimeError,
                          ctl.get_server_binding,
                          self.local_nxdrive_folder_1,
                          raise_if_missing=True)
        # Check deleted pair state
        self.assertEquals(len(session.query(LastKnownState).all()), 0)
Exemple #27
0
class TestIntegrationVersioning(IntegrationTestCase):

    def setUp(self):
        super(TestIntegrationVersioning, self).setUp()

        self.controller_1.bind_server(self.local_nxdrive_folder_1,
            self.nuxeo_url, self.user_1, self.password_1)
        self.controller_2.bind_server(self.local_nxdrive_folder_2,
            self.nuxeo_url, self.user_2, self.password_2)
        self.controller_1.bind_root(self.local_nxdrive_folder_1,
            self.workspace)
        self.controller_2.bind_root(self.local_nxdrive_folder_2,
            self.workspace)

        self.syn_1 = self.controller_1.synchronizer
        self.syn_2 = self.controller_2.synchronizer
        self.syn_1.loop(delay=0.010, max_loops=1, no_event_init=True)
        self.syn_2.loop(delay=0.010, max_loops=1, no_event_init=True)

        # Fetch server bindings after sync loop as it closes the Session
        self.sb_1 = self.controller_1.get_server_binding(
            self.local_nxdrive_folder_1)
        self.sb_2 = self.controller_2.get_server_binding(
            self.local_nxdrive_folder_2)

        self.remote_client_1 = self.remote_document_client_1
        self.remote_client_2 = self.remote_document_client_2
        sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1,
                                       self.workspace_title)
        sync_root_folder_2 = os.path.join(self.local_nxdrive_folder_2,
                                       self.workspace_title)
        self.local_client_1 = LocalClient(sync_root_folder_1)
        self.local_client_2 = LocalClient(sync_root_folder_2)

        # Call the Nuxeo operation to set the versioning delay to 10 seconds
        self.versioning_delay = self.OS_STAT_MTIME_RESOLUTION * 10
        self.root_remote_client.execute(
            "NuxeoDrive.SetVersioningOptions",
            delay=str(self.versioning_delay))

    def test_versioning(self):
        # Create a file as user 1
        self.local_client_1.make_file('/', 'Test versioning.txt',
            "This is version 0")
        self._synchronize_and_assert(self.syn_1, self.sb_1, 1)
        doc = self.root_remote_client.fetch(
            self.TEST_WORKSPACE_PATH + '/Test versioning.txt')
        self._assert_version(doc, 0, 0)

        # Synchronize it for user 2
        self.assertTrue(self.remote_client_2.exists('/Test versioning.txt'))
        self._synchronize_and_assert(self.syn_2, self.sb_2, 1, wait=True)
        self.assertTrue(self.local_client_2.exists('/Test versioning.txt'))

        # Update it as user 2 => should be versioned
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        self.local_client_2.update_content('/Test versioning.txt',
            "Modified content")
        self._synchronize_and_assert(self.syn_2, self.sb_2, 1)
        doc = self.root_remote_client.fetch(
            self.TEST_WORKSPACE_PATH + '/Test versioning.txt')
        self._assert_version(doc, 0, 1)

        # Update it as user 2 => should NOT be versioned
        # since the versioning delay (10s) is not passed by
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        self.local_client_2.update_content('/Test versioning.txt',
            "Content twice modified")
        self._synchronize_and_assert(self.syn_2, self.sb_2, 1)
        doc = self.root_remote_client.fetch(
            self.TEST_WORKSPACE_PATH + '/Test versioning.txt')
        self._assert_version(doc, 0, 1)

        # Update it as user 2 after 10s => should be versioned
        # since the versioning delay is passed by
        time.sleep(self.versioning_delay + 0.1)
        self.local_client_2.update_content('/Test versioning.txt',
            "Updated again!!")
        self._synchronize_and_assert(self.syn_2, self.sb_2, 1)
        doc = self.root_remote_client.fetch(
            self.TEST_WORKSPACE_PATH + '/Test versioning.txt')
        self._assert_version(doc, 0, 2)

    def test_version_restore(self):
        remote_client = self.remote_client_1
        local_client = self.local_client_1

        # Create a remote doc
        doc = remote_client.make_file(self.workspace,
                                    'Document to restore.txt',
                                    content="Initial content.")
        self.wait_audit_change_finder_if_needed()
        self.wait()
        self._synchronize_and_assert(self.syn_1, self.sb_1, 1)
        self.assertTrue(local_client.exists('/Document to restore.txt'))
        self.assertEquals(local_client.get_content('/Document to restore.txt'),
                          "Initial content.")

        # Create version 1.0, update content, then restore version 1.0
        remote_client.create_version(doc, 'Major')
        # Ensure that modification time is different between the version
        # and the updated live document, otherwise the synchronizer won't
        # consider the restored document (with the modification date of
        # the version) as to be updated
        time.sleep(1.0)
        remote_client.update_content(doc, "Updated content.")
        self.wait_audit_change_finder_if_needed()
        self.wait()
        self._synchronize_and_assert(self.syn_1, self.sb_1, 1)
        self.assertEquals(local_client.get_content('/Document to restore.txt'),
                          "Updated content.")
        version_uid = remote_client.get_versions(doc)[0][0]
        remote_client.restore_version(version_uid)
        self.wait_audit_change_finder_if_needed()
        self.wait()
        self._synchronize_and_assert(self.syn_1, self.sb_1, 1)
        self.assertEquals(local_client.get_content('/Document to restore.txt'),
                          "Initial content.")

    def _synchronize_and_assert(self, synchronizer, server_binding,
        expected_synchronized, wait=False):
        if wait:
            # Wait for audit changes to be detected after the 1 second step
            self.wait_audit_change_finder_if_needed()
            self.wait()
        n_synchronized = synchronizer.update_synchronize_server(server_binding)
        self.assertEqual(n_synchronized, expected_synchronized)

    def _assert_version(self, doc, major, minor):
        self.assertEquals(doc['properties']['uid:major_version'], major)
        self.assertEquals(doc['properties']['uid:minor_version'], minor)
    def test_synchronize_denying_read_access_local_modification(self):
        """Test denying Read access with concurrent local modification

        Use cases:
          - Deny Read access on a regular folder and make some
            local and remote changes concurrently.
              => Only locally modified content should be kept
                 and should be marked as 'unsynchronized',
                 other content should be deleted.
                 Remote changes should not be impacted client side.
                 Local changes should not be impacted server side.
          - Grant Read access back.
              => Remote documents should be merged with
                 locally modified content which should be unmarked
                 as 'unsynchronized' and therefore synchronized upstream.

        See TestIntegrationRemoteDeletion
                .test_synchronize_remote_deletion_local_modification
        as the same uses cases are tested.

        Note that we use the .odt extension for test files to make sure
        that they are created as File and not Note documents on the server
        when synchronized upstream, as the current implementation of
        RemoteDocumentClient is File oriented.
        """
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_document_client_1
        root_remote = self.root_remote_client

        # Create documents in the remote root workspace
        # then synchronize
        remote.make_folder('/', 'Test folder')
        remote.make_file('/Test folder', 'joe.odt', 'Some content')
        remote.make_file('/Test folder', 'jack.odt', 'Some content')
        remote.make_folder('/Test folder', 'Sub folder 1')
        remote.make_file('/Test folder/Sub folder 1', 'sub file 1.txt',
                         'Content')

        syn = ctl.synchronizer
        self._synchronize(syn)
        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.odt'))
        self.assertTrue(local.exists('/Test folder/jack.odt'))
        self.assertTrue(local.exists('/Test folder/Sub folder 1'))
        self.assertTrue(local.exists(
                                '/Test folder/Sub folder 1/sub file 1.txt'))

        # Remove Read permission for test user on a regular folder
        # and make some local and remote changes concurrently then synchronize
        test_folder_path = self.TEST_WORKSPACE_PATH + '/Test folder'
        self._set_read_permission("nuxeoDriveTestUser_user_1",
                                  test_folder_path, False)
        # Local changes
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        # Create new file
        local.make_file('/Test folder', 'local.odt', 'New local content')
        # Create new folder with files
        local.make_folder('/Test folder', 'Local sub folder 2')
        local.make_file('/Test folder/Local sub folder 2',
                        'local sub file 2.txt', 'Other local content')
        # Update file
        local.update_content('/Test folder/joe.odt',
                             'Some locally updated content')
        # Remote changes
        # Create new file
        root_remote.make_file(test_folder_path, 'remote.odt',
                              'New remote content')
        # Create new folder with files
        root_remote.make_folder(test_folder_path, 'Remote sub folder 2')
        root_remote.make_file(test_folder_path + '/Remote sub folder 2',
                'remote sub file 2.txt', 'Other remote content')
        # Update file
        root_remote.update_content(test_folder_path + '/joe.odt',
                'Some remotely updated content')

        self._synchronize(syn)
        # Only locally modified content should exist
        # and should be marked as 'unsynchronized', other content should
        # have been deleted.
        # Remote changes should not be impacted client side.
        # Local changes should not be impacted server side.
        # Local check
        self.assertTrue(local.exists('/Test folder'))
        self.assertEquals(len(local.get_children_info('/Test folder')), 3)
        self.assertTrue(local.exists('/Test folder/joe.odt'))
        self.assertEquals(local.get_content('/Test folder/joe.odt'),
                          'Some locally updated content')
        self.assertTrue(local.exists('/Test folder/local.odt'))
        self.assertTrue(local.exists('/Test folder/Local sub folder 2'))
        self.assertTrue(local.exists(
                    '/Test folder/Local sub folder 2/local sub file 2.txt'))

        self.assertFalse(local.exists('/Test folder/jack.odt'))
        self.assertFalse(local.exists('/Test folder/remote.odt'))
        self.assertFalse(local.exists('/Test folder/Sub folder 1'))
        self.assertFalse(local.exists(
                                '/Test folder/Sub folder 1/sub file 1.txt'))
        self.assertFalse(local.exists('/Test folder/Remote sub folder 1'))
        self.assertFalse(local.exists(
                    '/Test folder/Remote sub folder 1/remote sub file 1.txt'))
        # State check
        session = ctl.get_session()
        self._check_pair_state(session, '/Test folder', 'unsynchronized')
        self._check_pair_state(session, '/Test folder/joe.odt',
                               'unsynchronized')
        self._check_pair_state(session, '/Test folder/local.odt',
                               'unsynchronized')
        self._check_pair_state(session, '/Test folder/Local sub folder 2',
                               'unsynchronized')
        self._check_pair_state(session,
                        '/Test folder/Local sub folder 2/local sub file 2.txt',
                        'unsynchronized')
        # Remote check
        test_folder_uid = root_remote.get_info(test_folder_path).uid
        self.assertEquals(len(root_remote.get_children_info(
                                                        test_folder_uid)), 5)
        self.assertTrue(root_remote.exists(test_folder_path + '/joe.odt'))
        self.assertEquals(root_remote.get_content(
                                            test_folder_path + '/joe.odt'),
                                            'Some remotely updated content')
        self.assertTrue(root_remote.exists(test_folder_path + '/jack.odt'))
        self.assertTrue(root_remote.exists(test_folder_path + '/remote.odt'))
        self.assertTrue(root_remote.exists(test_folder_path + '/Sub folder 1'))
        self.assertTrue(root_remote.exists(
            test_folder_path + '/Sub folder 1/sub file 1.txt'))
        self.assertTrue(root_remote.exists(
            test_folder_path + '/Remote sub folder 2'))
        self.assertTrue(root_remote.exists(
            test_folder_path + '/Remote sub folder 2/remote sub file 2.txt'))

        self.assertFalse(root_remote.exists(test_folder_path + '/local.odt'))
        self.assertFalse(root_remote.exists(
            test_folder_path + '/Local sub folder 2'))
        self.assertFalse(root_remote.exists(
            test_folder_path + '/Local sub folder 1/local sub file 2.txt'))

        # Add Read permission back for test user then synchronize
        self._set_read_permission("nuxeoDriveTestUser_user_1",
                                  self.TEST_WORKSPACE_PATH + '/Test folder',
                                  True)
        self._synchronize(syn)
        # Remote documents should be merged with locally modified content
        # which should be unmarked as 'unsynchronized' and therefore
        # synchronized upstream.
        # Local check
        self.assertTrue(local.exists('/Test folder'))
        children_info = local.get_children_info('/Test folder')
        self.assertEquals(len(children_info), 8)
        for info in children_info:
            if info.name == 'joe.odt':
                remote_version = info
            elif info.name.startswith('joe (') and info.name.endswith(').odt'):
                local_version = info
        self.assertTrue(remote_version is not None)
        self.assertTrue(local_version is not None)
        self.assertTrue(local.exists(remote_version.path))
        self.assertEquals(local.get_content(remote_version.path),
                          'Some remotely updated content')
        self.assertTrue(local.exists(local_version.path))
        self.assertEquals(local.get_content(local_version.path),
                          'Some locally updated content')
        self.assertTrue(local.exists('/Test folder/jack.odt'))
        self.assertTrue(local.exists('/Test folder/local.odt'))
        self.assertTrue(local.exists('/Test folder/remote.odt'))
        self.assertTrue(local.exists('/Test folder/Sub folder 1'))
        self.assertTrue(local.exists(
                                '/Test folder/Sub folder 1/sub file 1.txt'))
        self.assertTrue(local.exists('/Test folder/Local sub folder 2'))
        self.assertTrue(local.exists(
                    '/Test folder/Local sub folder 2/local sub file 2.txt'))
        self.assertTrue(local.exists('/Test folder/Remote sub folder 2'))
        self.assertTrue(local.exists(
                    '/Test folder/Remote sub folder 2/remote sub file 2.txt'))
        # State check
        self._check_pair_state(session, '/Test folder', 'synchronized')
        self._check_pair_state(session, '/Test folder/joe.odt',
                               'synchronized')
        self._check_pair_state(session, '/Test folder/local.odt',
                               'synchronized')
        self._check_pair_state(session, '/Test folder/Local sub folder 2',
                               'synchronized')
        self._check_pair_state(session,
                        '/Test folder/Local sub folder 2/local sub file 2.txt',
                        'synchronized')
        # Remote check
        self.assertTrue(remote.exists('/Test folder'))
        children_info = remote.get_children_info(test_folder_uid)
        self.assertEquals(len(children_info), 8)
        for info in children_info:
            if info.name == 'joe.odt':
                remote_version = info
            elif info.name.startswith('joe (') and info.name.endswith(').odt'):
                local_version = info
        self.assertTrue(remote_version is not None)
        self.assertTrue(local_version is not None)
        remote_version_ref_length = (len(remote_version.path)
                                     - len(self.TEST_WORKSPACE_PATH))
        remote_version_ref = remote_version.path[-remote_version_ref_length:]
        self.assertTrue(remote.exists(remote_version_ref))
        self.assertEquals(remote.get_content(remote_version_ref),
                          'Some remotely updated content')
        local_version_ref_length = (len(local_version.path)
                                     - len(self.TEST_WORKSPACE_PATH))
        local_version_ref = local_version.path[-local_version_ref_length:]
        self.assertTrue(remote.exists(local_version_ref))
        self.assertEquals(remote.get_content(local_version_ref),
                          'Some locally updated content')
        self.assertTrue(remote.exists('/Test folder/jack.odt'))
        self.assertTrue(remote.exists('/Test folder/local.odt'))
        self.assertTrue(remote.exists('/Test folder/remote.odt'))
        self.assertTrue(remote.exists('/Test folder/Sub folder 1'))
        self.assertTrue(remote.exists(
                                '/Test folder/Sub folder 1/sub file 1.txt'))
        self.assertTrue(remote.exists('/Test folder/Local sub folder 2'))
        self.assertTrue(remote.exists(
                    '/Test folder/Local sub folder 2/local sub file 2.txt'))
        self.assertTrue(remote.exists('/Test folder/Remote sub folder 2'))
        self.assertTrue(remote.exists(
                    '/Test folder/Remote sub folder 2/remote sub file 2.txt'))
Exemple #29
0
    def test_sync_delete_shared_folder(self):
        user_workspaces_path = '/default-domain/UserWorkspaces/'
        user1_workspace_title = 'nuxeoDriveTestUser-user-1'
        user1_workspace_path = user_workspaces_path + user1_workspace_title
        try:
            # Get remote and local clients
            admin_remote_client = self.root_remote_client
            user1_remote_client = RemoteDocumentClient(
                self.nuxeo_url,
                self.user_1,
                u'nxdrive-test-device-1',
                self.version,
                password=self.password_1,
                upload_tmp_dir=self.upload_tmp_dir)
            user2_remote_client = RemoteDocumentClient(
                self.nuxeo_url,
                self.user_2,
                u'nxdrive-test-device-2',
                self.version,
                password=self.password_2,
                upload_tmp_dir=self.upload_tmp_dir)
            local_client_1 = LocalClient(self.local_nxdrive_folder_1)

            # Activate permission hierarchy profile as Administrator
            admin_remote_client.activate_profile('permission')

            # Make sure user1 workspace is created
            user1_remote_client.make_file_in_user_workspace(
                'File in user workspace', filename='USFile.txt')

            # Register user workspace as a sync root for user1
            user1_remote_client.register_as_root(user1_workspace_path)

            # Bind server for user1
            ctl_1 = self.controller_1
            ctl_1.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                              self.user_1, self.password_1)
            syn_1 = ctl_1.synchronizer

            # Synchronize
            self._synchronize(syn_1)
            # Check locally synchronized content
            self.assertTrue(local_client_1.exists('/My Docs'))

            # Create test folder in user workspace as user1
            user1_remote_client.make_folder(user1_workspace_path,
                                            'test_folder')
            # Synchronize
            self._synchronize(syn_1)
            # Check locally synchronized content
            self.assertTrue(local_client_1.exists('/My Docs/test_folder'))

            # Grant ReadWrite permission to user2 on test folder
            test_folder_path = user1_workspace_path + '/test_folder'
            op_input = "doc:" + test_folder_path
            admin_remote_client.execute("Document.SetACE",
                                        op_input=op_input,
                                        user="******",
                                        permission="ReadWrite",
                                        grant="true")

            # Register test folder as a sync root for user2
            user2_remote_client.register_as_root(test_folder_path)

            # Wait for a while:
            time.sleep(2.0)

            # Delete test folder
            user1_remote_client.delete(test_folder_path)

            # Synchronize
            self._synchronize(syn_1)
            # Check locally synchronized content
            self.assertFalse(local_client_1.exists('/My Docs/test_folder'))
            self.assertEquals(
                len(local_client_1.get_children_info('/My Docs')), 1)
        finally:
            # Cleanup user workspace
            if admin_remote_client.exists(user1_workspace_path):
                admin_remote_client.delete(user1_workspace_path,
                                           use_trash=False)
            # Deactivate permission hierarchy profile
            admin_remote_client.deactivate_profile('permission')
    def test_delete_local_folder_2_clients(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")

        # Define 2 controllers, one for each device
        ctl1 = self.controller_1
        ctl2 = self.controller_2

        # Get local clients for each device and remote client
        local1 = LocalClient(self.local_nxdrive_folder_1)
        local2 = LocalClient(self.local_nxdrive_folder_2)
        remote = self.remote_document_client_1

        # Bind each device to the server with the same account:
        # nuxeoDriveTestUser_user_1 and bind test workspace
        ctl1.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl2.bind_server(self.local_nxdrive_folder_2, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl1.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Check synchronization roots for nuxeoDriveTestUser_user_1,
        # there should be 1, the test workspace
        sync_roots = remote.get_roots()
        self.assertEquals(len(sync_roots), 1)
        self.assertEquals(sync_roots[0].name, self.workspace_title)

        # Launch first synchronization on both devices
        self.wait()
        sync1 = ctl1.synchronizer
        sync2 = ctl2.synchronizer
        sync1.loop(delay=0.1, max_loops=1)
        sync2.loop(delay=0.1, max_loops=1)

        # Test workspace should be created locally on both devices
        self.assertTrue(local1.exists('/Nuxeo Drive Test Workspace'))
        self.assertTrue(local2.exists('/Nuxeo Drive Test Workspace'))

        # Make nuxeoDriveTestUser_user_1 create a remote folder in the
        # test workspace and a file inside this folder,
        # then synchronize both devices
        test_folder = remote.make_folder(self.workspace, 'Test folder')
        remote.make_file(test_folder, 'test.odt', 'Some content.')

        self.wait()
        sync1.loop(delay=0.1, max_loops=1)
        sync2.loop(delay=0.1, max_loops=1)

        # Test folder should be created locally on both devices
        self.assertTrue(local1.exists(
                        '/Nuxeo Drive Test Workspace/Test folder'))
        self.assertTrue(local1.exists(
                        '/Nuxeo Drive Test Workspace/Test folder/test.odt'))
        self.assertTrue(local2.exists(
                        '/Nuxeo Drive Test Workspace/Test folder'))
        self.assertTrue(local2.exists(
                        '/Nuxeo Drive Test Workspace/Test folder/test.odt'))

        # Delete Test folder locally on one of the devices
        local1.delete('/Nuxeo Drive Test Workspace/Test folder')
        self.assertFalse(local1.exists(
                                    '/Nuxeo Drive Test Workspace/Test folder'))

        # Launch synchronization on both devices in separate threads
        def sync1_loop():
            sync1.loop(delay=1.0, max_loops=3)

        def sync2_loop():
            sync2.loop(delay=1.0, max_loops=3)

        sync1_thread = Thread(target=sync1_loop)
        sync2_thread = Thread(target=sync2_loop)
        sync1_thread.start()
        sync2_thread.start()

        # Wait for synchronization threads to complete
        sync1_thread.join()
        sync2_thread.join()

        # Test folder should be deleted on the server and on both devices
        self.assertFalse(remote.exists(test_folder))
        self.assertFalse(local1.exists(
                                    '/Nuxeo Drive Test Workspace/Test folder'))
        self.assertFalse(local2.exists(
                                    '/Nuxeo Drive Test Workspace/Test folder'))
Exemple #31
0
    def test_remote_rename_sync_root_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        remote_client = self.remote_client_1
        local_client = LocalClient(self.local_nxdrive_folder_1)
        session = ctl.get_session()

        # Rename a sync root folder
        remote_client.rename(self.workspace_id,
                             u'Renamed Nuxeo Drive Test Workspace')
        self.assertEquals(
            remote_client.get_info(self.workspace_id).name,
            u'Renamed Nuxeo Drive Test Workspace')

        # Synchronize: only the sync root folder renaming is detected: all
        # the descendants are automatically realigned
        self.wait_audit_change_finder_if_needed()
        self.wait()
        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 1)

        # The client folder has been renamed
        self.assertFalse(local_client.exists(u'/Nuxeo Drive Test Workspace'))
        self.assertTrue(
            local_client.exists(u'/Renamed Nuxeo Drive Test Workspace'))

        renamed_workspace_path = os.path.join(
            self.local_nxdrive_folder_1, u'Renamed Nuxeo Drive Test Workspace')
        # The content of the renamed folder is left unchanged
        # Check child name
        self.assertTrue(
            local_client.exists(
                u'/Renamed Nuxeo Drive Test Workspace/Original File 1.txt'))
        file_1_local_info = local_client.get_info(
            u'/Renamed Nuxeo Drive Test Workspace/Original File 1.txt')
        file_1_parent_path = os.path.dirname(file_1_local_info.filepath)
        self.assertEquals(file_1_parent_path, renamed_workspace_path)
        # Check child state
        file_1_state = session.query(LastKnownState).filter_by(
            remote_name=u'Original File 1.txt').one()
        self.assertEquals(
            file_1_state.local_path,
            u'/Renamed Nuxeo Drive Test Workspace/Original File 1.txt')
        self.assertEquals(file_1_state.local_name, u'Original File 1.txt')

        # Check child name
        self.assertTrue(
            local_client.exists(
                u'/Renamed Nuxeo Drive Test Workspace/Original Folder 1'))
        folder_1_local_info = local_client.get_info(
            u'/Renamed Nuxeo Drive Test Workspace/Original Folder 1')
        folder_1_parent_path = os.path.dirname(folder_1_local_info.filepath)
        self.assertEquals(folder_1_parent_path, renamed_workspace_path)
        # Check child state
        folder_1_state = session.query(LastKnownState).filter_by(
            remote_name=u'Original Folder 1').one()
        self.assertEquals(
            folder_1_state.local_path,
            u'/Renamed Nuxeo Drive Test Workspace/Original Folder 1')
        self.assertEquals(folder_1_state.local_name, u'Original Folder 1')

        # Check child name
        self.assertTrue(
            local_client.exists(u'/Renamed Nuxeo Drive Test Workspace/'
                                u'Original Folder 1/Sub-Folder 1.1'))
        folder_1_1_local_info = local_client.get_info(
            u'/Renamed Nuxeo Drive Test Workspace/'
            u'Original Folder 1/Sub-Folder 1.1')
        folder_1_1_parent_path = os.path.dirname(
            folder_1_1_local_info.filepath)
        self.assertEquals(
            folder_1_1_parent_path,
            os.path.join(renamed_workspace_path, u'Original Folder 1'))
        # Check child state
        folder_1_1_state = session.query(LastKnownState).filter_by(
            remote_name=u'Sub-Folder 1.1').one()
        self.assertEquals(
            folder_1_1_state.local_path, u'/Renamed Nuxeo Drive Test Workspace'
            '/Original Folder 1/Sub-Folder 1.1')
        self.assertEquals(folder_1_1_state.local_name, u'Sub-Folder 1.1')

        # Check child name
        self.assertTrue(
            local_client.exists(u'/Renamed Nuxeo Drive Test Workspace/'
                                u'Original Folder 1/Original File 1.1.txt'))
        file_1_1_local_info = local_client.get_info(
            u'/Renamed Nuxeo Drive Test Workspace/'
            'Original Folder 1/Original File 1.1.txt')
        file_1_1_parent_path = os.path.dirname(file_1_1_local_info.filepath)
        self.assertEquals(
            file_1_1_parent_path,
            os.path.join(renamed_workspace_path, u'Original Folder 1'))
        # Check child state
        file_1_1_state = session.query(LastKnownState).filter_by(
            remote_name=u'Original File 1.1.txt').one()
        self.assertEquals(
            file_1_1_state.local_path, u'/Renamed Nuxeo Drive Test Workspace'
            '/Original Folder 1/Original File 1.1.txt')
        self.assertEquals(file_1_1_state.local_name, u'Original File 1.1.txt')

        # The more things change, the more they remain the same.
        self.wait_audit_change_finder_if_needed()
        self.wait()
        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 0)
    def test_delete_local_folder_2_clients(self):

        # Define 2 controllers, one for each device
        ctl1 = self.controller_1
        ctl2 = self.controller_2

        # Get local clients for each device and remote client
        local1 = LocalClient(self.local_nxdrive_folder_1)
        local2 = LocalClient(self.local_nxdrive_folder_2)
        remote = self.remote_document_client_1

        # Bind each device to the server with the same account:
        # nuxeoDriveTestUser_user_1 and bind test workspace
        ctl1.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl2.bind_server(self.local_nxdrive_folder_2, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl1.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Check synchronization roots for nuxeoDriveTestUser_user_1,
        # there should be 1, the test workspace
        sync_roots = remote.get_roots()
        self.assertEquals(len(sync_roots), 1)
        self.assertEquals(sync_roots[0].name, self.workspace_title)

        # Launch first synchronization on both devices
        self.wait_audit_change_finder_if_needed()
        self.wait()
        sync1 = ctl1.synchronizer
        sync2 = ctl2.synchronizer
        sync1.loop(delay=0.1, max_loops=1)
        sync2.loop(delay=0.1, max_loops=1)

        # Test workspace should be created locally on both devices
        self.assertTrue(local1.exists('/Nuxeo Drive Test Workspace'))
        self.assertTrue(local2.exists('/Nuxeo Drive Test Workspace'))

        # Make nuxeoDriveTestUser_user_1 create a remote folder in the
        # test workspace and a file inside this folder,
        # then synchronize both devices
        test_folder = remote.make_folder(self.workspace, 'Test folder')
        remote.make_file(test_folder, 'test.odt', 'Some content.')

        self.wait_audit_change_finder_if_needed()
        self.wait()
        sync1.loop(delay=0.1, max_loops=1)
        sync2.loop(delay=0.1, max_loops=1)

        # Test folder should be created locally on both devices
        self.assertTrue(local1.exists(
                        '/Nuxeo Drive Test Workspace/Test folder'))
        self.assertTrue(local1.exists(
                        '/Nuxeo Drive Test Workspace/Test folder/test.odt'))
        self.assertTrue(local2.exists(
                        '/Nuxeo Drive Test Workspace/Test folder'))
        self.assertTrue(local2.exists(
                        '/Nuxeo Drive Test Workspace/Test folder/test.odt'))

        # Delete Test folder locally on one of the devices
        local1.delete('/Nuxeo Drive Test Workspace/Test folder')
        self.assertFalse(local1.exists(
                                    '/Nuxeo Drive Test Workspace/Test folder'))

        # Launch synchronization on both devices in separate threads
        def sync1_loop():
            sync1.loop(delay=1.0, max_loops=3)

        def sync2_loop():
            sync2.loop(delay=1.0, max_loops=3)

        sync1_thread = Thread(target=sync1_loop)
        sync2_thread = Thread(target=sync2_loop)
        sync1_thread.start()
        sync2_thread.start()

        # Wait for synchronization threads to complete
        sync1_thread.join()
        sync2_thread.join()

        # Test folder should be deleted on the server and on both devices
        self.assertFalse(remote.exists(test_folder))
        self.assertFalse(local1.exists(
                                    '/Nuxeo Drive Test Workspace/Test folder'))
        self.assertFalse(local2.exists(
                                    '/Nuxeo Drive Test Workspace/Test folder'))
    def test_update_local_file_content_update_remote_file_property(self):

        # Get local and remote clients
        local = LocalClient(self.local_nxdrive_folder_1)
        remote = self.remote_document_client_1

        # Bind server and test workspace for nuxeoDriveTestUser_user_1
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Launch first synchronization
        self.wait_audit_change_finder_if_needed()
        self.wait()
        sync = ctl.synchronizer
        sync.loop(delay=0.1, max_loops=1)

        # Test workspace should be created locally
        self.assertTrue(local.exists('/Nuxeo Drive Test Workspace'))

        # Create a local file in the test workspace then synchronize
        local.make_file('/Nuxeo Drive Test Workspace',
                        'test.odt', 'Some content.')

        sync.loop(delay=0.1, max_loops=1)

        # Test file should be created remotely in the test workspace
        self.assertTrue(remote.exists('/test.odt'))

        # Locally update the file content and remotely update one of its
        # properties concurrently, then synchronize
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        local.update_content('/Nuxeo Drive Test Workspace/test.odt',
                             'Updated content.')
        self.assertEquals(local.get_content(
                                    '/Nuxeo Drive Test Workspace/test.odt'),
                          'Updated content.')
        test_file_ref = remote._check_ref('/test.odt')
        # Wait for 1 second to make sure the file's last modification time
        # will be different from the pair state's last remote update time
        time.sleep(self.REMOTE_MODIFICATION_TIME_RESOLUTION)
        remote.update(test_file_ref,
                      properties={'dc:description': 'Some description.'})
        test_file = remote.fetch(test_file_ref)
        self.assertEqual(test_file['properties']['dc:description'],
                         'Some description.')

        self.wait_audit_change_finder_if_needed()
        self.wait()
        sync.loop(delay=0.1, max_loops=2)

        # Test file should be updated remotely in the test workspace,
        # and no conflict should be detected.
        # Even though fetching the remote changes will send a
        # 'documentModified' event for the test file as a result of its
        # dc:description property update, since the file will not have been
        # renamed nor moved and its content not modified since last
        # synchronization, its remote pair state will not be marked as
        # 'modified', see Model.update_remote().
        # Thus the pair state will be ('modified', 'synchronized'), resolved as
        # 'locally_modified'.
        self.assertTrue(remote.exists('/test.odt'))
        self.assertEquals(remote.get_content('/test.odt'), 'Updated content.')
        test_file = remote.fetch(test_file_ref)
        self.assertEqual(test_file['properties']['dc:description'],
                         'Some description.')
        self.assertEqual(len(remote.get_children_info(self.workspace)), 1)

        # Check that the content of the test file has not changed
        self.assertTrue(local.exists('/Nuxeo Drive Test Workspace/test.odt'))
        self.assertEquals(local.get_content(
                                    '/Nuxeo Drive Test Workspace/test.odt'),
                          'Updated content.')
        self.assertEqual(len(local.get_children_info(
                                            '/Nuxeo Drive Test Workspace')), 1)
    def test_delete_local_folder_update_remote_folder_property(self):

        # Get local and remote clients
        local = LocalClient(self.local_nxdrive_folder_1)
        remote = self.remote_document_client_1

        # Bind server and test workspace for nuxeoDriveTestUser_user_1
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Launch first synchronization
        self.wait_audit_change_finder_if_needed()
        self.wait()
        sync = ctl.synchronizer
        sync.loop(delay=0.1, max_loops=1)

        # Test workspace should be created locally
        self.assertTrue(local.exists('/Nuxeo Drive Test Workspace'))

        # Create a local folder in the test workspace and a file inside
        # this folder, then synchronize
        local.make_folder('/Nuxeo Drive Test Workspace', 'Test folder')
        local.make_file('/Nuxeo Drive Test Workspace/Test folder',
                        'test.odt', 'Some content.')

        sync.loop(delay=0.1, max_loops=1)

        # Test folder should be created remotely in the test workspace
        self.assertTrue(remote.exists('/Test folder'))
        self.assertTrue(remote.exists('/Test folder/test.odt'))

        # Delete Test folder locally and remotely update one of its properties
        # concurrently, then synchronize
        local.delete('/Nuxeo Drive Test Workspace/Test folder')
        self.assertFalse(local.exists(
                                    '/Nuxeo Drive Test Workspace/Test folder'))
        test_folder_ref = remote._check_ref('/Test folder')
        # Wait for 1 second to make sure the folder's last modification time
        # will be different from the pair state's last remote update time
        time.sleep(self.REMOTE_MODIFICATION_TIME_RESOLUTION)
        remote.update(test_folder_ref,
                      properties={'dc:description': 'Some description.'})
        test_folder = remote.fetch(test_folder_ref)
        self.assertEqual(test_folder['properties']['dc:description'],
                         'Some description.')

        self.wait_audit_change_finder_if_needed()
        self.wait()
        sync.loop(delay=0.1, max_loops=1)

        # Test folder should be deleted remotely in the test workspace.
        # Even though fetching the remote changes will send a
        # 'documentModified' event for Test folder as a result of its
        # dc:description property update, since the folder will not have been
        # renamed nor moved since last synchronization, its remote pair state
        # will not be marked as 'modified', see Model.update_remote().
        # Thus the pair state will be ('deleted', 'synchronized'), resolved as
        # 'locally_deleted'.
        self.assertFalse(remote.exists('/Test folder'))

        # Check Test folder has not been re-created locally
        self.assertFalse(local.exists(
                                    '/Nuxeo Drive Test Workspace/Test folder'))
    def test_delete_local_folder_update_remote_folder_property(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")

        # Get local and remote clients
        local = LocalClient(self.local_nxdrive_folder_1)
        remote = self.remote_document_client_1

        # Bind server and test workspace for nuxeoDriveTestUser_user_1
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Launch first synchronization
        self.wait()
        sync = ctl.synchronizer
        sync.loop(delay=0.1, max_loops=1)

        # Test workspace should be created locally
        self.assertTrue(local.exists('/Nuxeo Drive Test Workspace'))

        # Create a local folder in the test workspace and a file inside
        # this folder, then synchronize
        local.make_folder('/Nuxeo Drive Test Workspace', 'Test folder')
        local.make_file('/Nuxeo Drive Test Workspace/Test folder',
                        'test.odt', 'Some content.')

        sync.loop(delay=0.1, max_loops=1)

        # Test folder should be created remotely in the test workspace
        self.assertTrue(remote.exists('/Test folder'))
        self.assertTrue(remote.exists('/Test folder/test.odt'))

        # Delete Test folder locally and remotely update one of its properties
        # concurrently, then synchronize
        local.delete('/Nuxeo Drive Test Workspace/Test folder')
        self.assertFalse(local.exists(
                                    '/Nuxeo Drive Test Workspace/Test folder'))
        test_folder_ref = remote._check_ref('/Test folder')
        # Wait for 1 second to make sure the folder's last modification time
        # will be different from the pair state's last remote update time
        time.sleep(REMOTE_MODIFICATION_TIME_RESOLUTION)
        remote.update(test_folder_ref,
                      properties={'dc:description': 'Some description.'})
        test_folder = remote.fetch(test_folder_ref)
        self.assertEqual(test_folder['properties']['dc:description'],
                         'Some description.')

        self.wait()
        sync.loop(delay=0.1, max_loops=1)

        # Test folder should be deleted remotely in the test workspace.
        # Even though fetching the remote changes will send a
        # 'documentModified' event for Test folder as a result of its
        # dc:description property update, since the folder will not have been
        # renamed nor moved since last synchronization, its remote pair state
        # will not be marked as 'modified', see Model.update_remote().
        # Thus the pair state will be ('deleted', 'synchronized'), resolved as
        # 'locally_deleted'.
        self.assertFalse(remote.exists('/Test folder'))

        # Check Test folder has not been re-created locally
        self.assertFalse(local.exists(
                                    '/Nuxeo Drive Test Workspace/Test folder'))
    def test_sync_delete_shared_folder(self):
        user_workspaces_path = '/default-domain/UserWorkspaces/'
        user1_workspace_title = 'nuxeoDriveTestUser-user-1'
        user1_workspace_path = user_workspaces_path + user1_workspace_title
        try:
            # Get remote and local clients
            admin_remote_client = self.root_remote_client
            user1_remote_client = RemoteDocumentClient(
                self.nuxeo_url, self.user_1, u'nxdrive-test-device-1',
                self.version, password=self.password_1,
                upload_tmp_dir=self.upload_tmp_dir)
            user2_remote_client = RemoteDocumentClient(
                self.nuxeo_url, self.user_2, u'nxdrive-test-device-2',
                self.version, password=self.password_2,
                upload_tmp_dir=self.upload_tmp_dir)
            local_client_1 = LocalClient(self.local_nxdrive_folder_1)

            # Activate permission hierarchy profile as Administrator
            admin_remote_client.activate_profile('permission')

            # Make sure user1 workspace is created
            user1_remote_client.make_file_in_user_workspace(
                                                    'File in user workspace',
                                                    filename='USFile.txt')

            # Register user workspace as a sync root for user1
            user1_remote_client.register_as_root(user1_workspace_path)

            # Bind server for user1
            ctl_1 = self.controller_1
            ctl_1.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                            self.user_1, self.password_1)
            syn_1 = ctl_1.synchronizer

            # Synchronize
            self._synchronize(syn_1)
            # Check locally synchronized content
            self.assertTrue(local_client_1.exists('/My Docs'))

            # Create test folder in user workspace as user1
            user1_remote_client.make_folder(user1_workspace_path,
                                            'test_folder')
            # Synchronize
            self._synchronize(syn_1)
            # Check locally synchronized content
            self.assertTrue(local_client_1.exists('/My Docs/test_folder'))

            # Grant ReadWrite permission to user2 on test folder
            test_folder_path = user1_workspace_path + '/test_folder'
            op_input = "doc:" + test_folder_path
            admin_remote_client.execute("Document.SetACE",
                op_input=op_input,
                user="******",
                permission="ReadWrite",
                grant="true")

            # Register test folder as a sync root for user2
            user2_remote_client.register_as_root(test_folder_path)

            # Wait for a while:
            time.sleep(2.0)

            # Delete test folder
            user1_remote_client.delete(test_folder_path)

            # Synchronize
            self._synchronize(syn_1)
            # Check locally synchronized content
            self.assertFalse(local_client_1.exists('/My Docs/test_folder'))
            self.assertEquals(len(local_client_1.get_children_info(
                                                            '/My Docs')), 1)
        finally:
            # Cleanup user workspace
            if admin_remote_client.exists(user1_workspace_path):
                admin_remote_client.delete(user1_workspace_path,
                                           use_trash=False)
            # Deactivate permission hierarchy profile
            admin_remote_client.deactivate_profile('permission')
    def test_update_local_file_content_update_remote_file_property(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")

        # Get local and remote clients
        local = LocalClient(self.local_nxdrive_folder_1)
        remote = self.remote_document_client_1

        # Bind server and test workspace for nuxeoDriveTestUser_user_1
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Launch first synchronization
        self.wait()
        sync = ctl.synchronizer
        sync.loop(delay=0.1, max_loops=1)

        # Test workspace should be created locally
        self.assertTrue(local.exists('/Nuxeo Drive Test Workspace'))

        # Create a local file in the test workspace then synchronize
        local.make_file('/Nuxeo Drive Test Workspace',
                        'test.odt', 'Some content.')

        sync.loop(delay=0.1, max_loops=1)

        # Test file should be created remotely in the test workspace
        self.assertTrue(remote.exists('/test.odt'))

        # Locally update the file content and remotely update one of its
        # properties concurrently, then synchronize
        time.sleep(OS_STAT_MTIME_RESOLUTION)
        local.update_content('/Nuxeo Drive Test Workspace/test.odt',
                             'Updated content.')
        self.assertEquals(local.get_content(
                                    '/Nuxeo Drive Test Workspace/test.odt'),
                          'Updated content.')
        test_file_ref = remote._check_ref('/test.odt')
        # Wait for 1 second to make sure the file's last modification time
        # will be different from the pair state's last remote update time
        time.sleep(REMOTE_MODIFICATION_TIME_RESOLUTION)
        remote.update(test_file_ref,
                      properties={'dc:description': 'Some description.'})
        test_file = remote.fetch(test_file_ref)
        self.assertEqual(test_file['properties']['dc:description'],
                         'Some description.')

        self.wait()
        sync.loop(delay=0.1, max_loops=2)

        # Test file should be updated remotely in the test workspace,
        # and no conflict should be detected.
        # Even though fetching the remote changes will send a
        # 'documentModified' event for the test file as a result of its
        # dc:description property update, since the file will not have been
        # renamed nor moved and its content not modified since last
        # synchronization, its remote pair state will not be marked as
        # 'modified', see Model.update_remote().
        # Thus the pair state will be ('modified', 'synchronized'), resolved as
        # 'locally_modified'.
        self.assertTrue(remote.exists('/test.odt'))
        self.assertEquals(remote.get_content('/test.odt'), 'Updated content.')
        test_file = remote.fetch(test_file_ref)
        self.assertEqual(test_file['properties']['dc:description'],
                         'Some description.')
        self.assertEqual(len(remote.get_children_info(self.workspace)), 1)

        # Check that the content of the test file has not changed
        self.assertTrue(local.exists('/Nuxeo Drive Test Workspace/test.odt'))
        self.assertEquals(local.get_content(
                                    '/Nuxeo Drive Test Workspace/test.odt'),
                          'Updated content.')
        self.assertEqual(len(local.get_children_info(
                                            '/Nuxeo Drive Test Workspace')), 1)
class TestDirectEdit(UnitTestCase):

    locally_edited_path = ('/default-domain/UserWorkspaces/'
                           + 'nuxeoDriveTestUser-user-1/Collections/'
                           + LOCALLY_EDITED_FOLDER_NAME)

    def setUpApp(self):
        super(TestDirectEdit, self).setUpApp()
        self.direct_edit = self.manager_1.direct_edit
        self.direct_edit._test = True
        self.direct_edit.directEditUploadCompleted.connect(self.app.sync_completed)
        self.direct_edit.start()

        self.remote = self.remote_document_client_1
        self.local = LocalClient(os.path.join(self.nxdrive_conf_folder_1, 'edit'))

    def tearDownApp(self):
        self.direct_edit.stop()
        super(TestDirectEdit, self).tearDownApp()

    def test_url_resolver(self):
        self.assertIsNotNone(self.direct_edit._get_engine(self.nuxeo_url, self.user_1))
        self.assertIsNone(self.direct_edit._get_engine(self.nuxeo_url, u'Administrator'))
        self.manager_1._engine_types['NXDRIVETESTURL'] = MockUrlTestEngine
        # HTTP EXPLICIT
        self.manager_1._engines['0'] = MockUrlTestEngine('http://localhost:80/nuxeo')
        self.assertIsNone(self.direct_edit._get_engine("http://localhost:8080/nuxeo", u'Administrator'))
        self.assertIsNotNone(self.direct_edit._get_engine("http://localhost:80/nuxeo", u'Administrator'))
        self.assertIsNotNone(self.direct_edit._get_engine("http://localhost/nuxeo/", u'Administrator'))
        # HTTP IMPLICIT
        self.manager_1._engines['0'] = MockUrlTestEngine('http://localhost/nuxeo')
        self.assertIsNone(self.direct_edit._get_engine("http://localhost:8080/nuxeo", u'Administrator'))
        self.assertIsNotNone(self.direct_edit._get_engine("http://localhost:80/nuxeo/", u'Administrator'))
        self.assertIsNotNone(self.direct_edit._get_engine("http://localhost/nuxeo", u'Administrator'))
        # HTTPS EXPLICIT
        self.manager_1._engines['0'] = MockUrlTestEngine('https://localhost:443/nuxeo')
        self.assertIsNone(self.direct_edit._get_engine("http://localhost:8080/nuxeo", u'Administrator'))
        self.assertIsNotNone(self.direct_edit._get_engine("https://localhost:443/nuxeo", u'Administrator'))
        self.assertIsNotNone(self.direct_edit._get_engine("https://localhost/nuxeo/", u'Administrator'))
        # HTTPS IMPLICIT
        self.manager_1._engines['0'] = MockUrlTestEngine('https://localhost/nuxeo')
        self.assertIsNone(self.direct_edit._get_engine("http://localhost:8080/nuxeo", u'Administrator'))
        self.assertIsNotNone(self.direct_edit._get_engine("https://localhost:443/nuxeo/", u'Administrator'))
        self.assertIsNotNone(self.direct_edit._get_engine("https://localhost/nuxeo", u'Administrator'))

    def test_note_edit(self):
        remote_fs_client = self.remote_file_system_client_1
        toplevel_folder_info = remote_fs_client.get_filesystem_root_info()
        workspace_id = remote_fs_client.get_children_info(
            toplevel_folder_info.uid)[0].uid
        file_1_id = remote_fs_client.make_file(workspace_id, u'Mode op\xe9ratoire.txt',
                                               "Content of file 1 Avec des accents h\xe9h\xe9.").uid
        doc_id = file_1_id.split('#')[-1]
        self._direct_edit_update(doc_id, u'Mode op\xe9ratoire.txt', 'Atol de PomPom Gali')

    def test_filename_encoding(self):
        filename = u'Mode op\xe9ratoire.txt'
        doc_id = self.remote.make_file('/', filename, 'Some content.')
        self._direct_edit_update(doc_id, filename, 'Test')

    def _test_locked_file_signal(self):
        self._received = True

    def test_locked_file(self):
        self._received = False
        filename = u'Mode operatoire.txt'
        doc_id = self.remote.make_file('/', filename, 'Some content.')
        self.remote_document_client_2.lock(doc_id)
        self.direct_edit.directEditLocked.connect(self._test_locked_file_signal)
        self.direct_edit._prepare_edit(self.nuxeo_url, doc_id)
        self.assertTrue(self._received)

    def test_self_locked_file(self):
        filename = u'Mode operatoire.txt'
        doc_id = self.remote.make_file('/', filename, 'Some content.')
        self.remote.lock(doc_id)
        self._direct_edit_update(doc_id, filename, 'Test')

    def _office_locker(self, path):
        return os.path.join(os.path.dirname(path), "~$" + os.path.basename(path)[2:])

    def _openoffice_locker(self, path):
        return os.path.join(os.path.dirname(path), ".~lock." + os.path.basename(path)[2:])

#     def test_autolock_office(self):
#         self._autolock(self._office_locker)

#     def test_autolock_openoffice(self):
#      LibreOffice as well
#         self._autolock(self._openoffice_locker)

    def _autolock(self, locker):
        global called_open, lock_file
        called_open = False
        filename = u'Document.docx'
        doc_id = self.remote.make_file('/', filename, 'Some content.')

        def open_local_file(path):
            global called_open, lock_file
            called_open = True
            # Lock file
            lock_file = locker(path)
            with open(lock_file, 'w') as f:
                f.write("plop")

        self.manager_1.open_local_file = open_local_file
        self.manager_1.set_direct_edit_auto_lock(1)
        self.direct_edit._manager.open_local_file = open_local_file
        self.direct_edit.edit(self.nuxeo_url, doc_id, filename=filename, user=self.user_1)
        self.wait_sync(timeout=2, fail_if_timeout=False)
        self.assertTrue(called_open, "Should have called open_local_file")
        # Should be able to test lock
        self.assertTrue(self.remote_document_client_1.is_locked(doc_id))
        os.remove(lock_file)
        self.wait_sync(timeout=2, fail_if_timeout=False)
        # Should be unlock
        self.assertFalse(self.remote_document_client_1.is_locked(doc_id))
        self.manager_1.set_direct_edit_auto_lock(0)
        with open(lock_file, 'w') as f:
            f.write("plop")
        self.wait_sync(timeout=2, fail_if_timeout=False)
        self.assertFalse(self.remote_document_client_1.is_locked(doc_id))

    def _direct_edit_update(self, doc_id, filename, content, url=None):
        # Download file
        local_path = u'/%s/%s' % (doc_id, filename)

        def open_local_file(path):
            pass

        self.manager_1.open_local_file = open_local_file
        if url is None:
            self.direct_edit._prepare_edit(self.nuxeo_url, doc_id)
        else:
            self.direct_edit.handle_url(url)
        self.assertTrue(self.local.exists(local_path))
        self.wait_sync(timeout=2, fail_if_timeout=False)
        self.local.delete_final(local_path)

        # Update file content
        self.local.update_content(local_path, content)
        self.wait_sync()
        self.assertEqual(self.remote.get_blob(self.remote.get_info(doc_id)), content)

        # Update file content twice
        update_content = content + ' updated'
        self.local.update_content(local_path, update_content)
        self.wait_sync()
        self.assertEqual(self.remote.get_blob(self.remote.get_info(doc_id)), update_content)

    def test_direct_edit_cleanup(self):
        filename = u'Mode op\xe9ratoire.txt'
        doc_id = self.remote.make_file('/', filename, 'Some content.')
        # Download file
        local_path = u'/%s/%s' % (doc_id, filename)

        def open_local_file(_):
            pass

        self.manager_1.open_local_file = open_local_file
        self.direct_edit._prepare_edit(self.nuxeo_url, doc_id)
        self.assertTrue(self.local.exists(local_path))
        self.wait_sync(timeout=2, fail_if_timeout=False)
        self.direct_edit.stop()

        # Update file content
        self.local.update_content(local_path, 'Test')
        # Create empty folder (NXDRIVE-598)
        self.local.make_folder('/', 'emptyfolder')

        # Verify the cleanup dont delete document
        self.direct_edit._cleanup()
        self.assertTrue(self.local.exists(local_path))
        self.assertNotEquals(self.remote.get_blob(self.remote.get_info(doc_id)), 'Test')

        # Verify it reupload it
        self.direct_edit.start()
        self.wait_sync(timeout=2, fail_if_timeout=False)
        self.assertTrue(self.local.exists(local_path))
        self.assertEqual(self.remote.get_blob(self.remote.get_info(doc_id)), 'Test')

        # Verify it is cleanup if sync
        self.direct_edit.stop()
        self.direct_edit._cleanup()
        self.assertFalse(self.local.exists(local_path))

    def test_user_name(self):
        # user_1 is drive_user_1, no more informations
        user = self.engine_1.get_user_full_name(self.user_1)
        self.assertEqual(user, self.user_1)

        # Create a complete user
        remote = self.root_remote_client
        remote.create_user('john', firstName='John', lastName='Doe')
        user = self.engine_1.get_user_full_name('john')
        self.assertEqual(user, 'John Doe')

        # Unknown user
        user = self.engine_1.get_user_full_name('unknown')
        self.assertEqual(user, 'unknown')
    def test_synchronize_remote_deletion_local_modification(self):
        """Test remote deletion with concurrent local modification

        Use cases:
          - Remotely delete a regular folder and make some
            local changes concurrently.
              => Only locally modified content should be kept
                 and should be marked as 'unsynchronized',
                 other content should be deleted.
          - Remotely restore folder from the trash.
              => Remote documents should be merged with
                 locally modified content which should be unmarked
                 as 'unsynchronized'.
          - Remotely delete a file and locally update its content concurrently.
              => File should be kept locally and be marked as 'unsynchronized'.
          - Remotely restore file from the trash.
              => Remote file should be merged with locally modified file with
                 a conflict detection and both files should be marked
                 as 'synchronized'.
          - Remotely delete a file and locally rename it concurrently.
              => File should be kept locally and be marked as 'synchronized'.
          - Remotely restore file from the trash.
              => Remote file should be merged with locally renamed file and
                 both files should be marked as 'synchronized'.

        See TestIntegrationSecurityUpdates
                .test_synchronize_denying_read_access_local_modification
        as the same uses cases are tested.

        Note that we use the .odt extension for test files to make sure
        that they are created as File and not Note documents on the server
        when synchronized upstream, as the current implementation of
        RemoteDocumentClient is File oriented.
        """
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_document_client_1

        # Create documents in the remote root workspace
        # then synchronize
        remote.make_folder('/', 'Test folder')
        remote.make_file('/Test folder', 'joe.odt', 'Some content')
        remote.make_file('/Test folder', 'jack.odt', 'Some content')
        remote.make_folder('/Test folder', 'Sub folder 1')
        remote.make_file('/Test folder/Sub folder 1', 'sub file 1.txt',
                         'Content')
        syn = ctl.synchronizer
        self._synchronize(syn)
        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.odt'))
        self.assertTrue(local.exists('/Test folder/jack.odt'))
        self.assertTrue(local.exists('/Test folder/Sub folder 1'))
        self.assertTrue(local.exists(
                                '/Test folder/Sub folder 1/sub file 1.txt'))

        # Delete remote folder and make some local changes
        # concurrently then synchronize
        remote.delete('/Test folder')
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        # Create new file
        local.make_file('/Test folder', 'new.odt', "New content")
        # Create new folder with files
        local.make_folder('/Test folder', 'Sub folder 2')
        local.make_file('/Test folder/Sub folder 2', 'sub file 2.txt',
                        'Other content')
        # Update file
        local.update_content('/Test folder/joe.odt', 'Some updated content')
        self._synchronize(syn)
        # Only locally modified content should exist
        # and should be marked as 'unsynchronized', other content should
        # have been deleted
        # Local check
        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.odt'))
        self.assertEquals(local.get_content('/Test folder/joe.odt'),
                          'Some updated content')
        self.assertTrue(local.exists('/Test folder/new.odt'))
        self.assertTrue(local.exists('/Test folder/Sub folder 2'))
        self.assertTrue(local.exists(
                                '/Test folder/Sub folder 2/sub file 2.txt'))

        self.assertFalse(local.exists('/Test folder/jack.odt'))
        self.assertFalse(local.exists('/Test folder/Sub folder 1'))
        self.assertFalse(local.exists(
                                '/Test folder/Sub folder 1/sub file 1.txt'))
        # State check
        session = ctl.get_session()
        self._check_pair_state(session, '/Test folder', 'unsynchronized')
        self._check_pair_state(session, '/Test folder/joe.odt',
                               'unsynchronized')
        self._check_pair_state(session, '/Test folder/new.odt',
                               'unsynchronized')
        self._check_pair_state(session, '/Test folder/Sub folder 2',
                               'unsynchronized')
        self._check_pair_state(session,
                               '/Test folder/Sub folder 2/sub file 2.txt',
                               'unsynchronized')
        # Remote check
        self.assertFalse(remote.exists('/Test folder'))

        # Restore remote folder and its children from trash then synchronize
        remote.undelete('/Test folder')
        remote.undelete('/Test folder/joe.odt')
        remote.undelete('/Test folder/jack.odt')
        remote.undelete('/Test folder/Sub folder 1')
        remote.undelete('/Test folder/Sub folder 1/sub file 1.txt')
        self._synchronize(syn)
        # Remotely restored documents should be merged with
        # locally modified content which should be unmarked
        # as 'unsynchronized' and therefore synchronized upstream
        # Local check
        self.assertTrue(local.exists('/Test folder'))
        children_info = local.get_children_info('/Test folder')
        self.assertEquals(len(children_info), 6)
        for info in children_info:
            if info.name == 'joe.odt':
                remote_version = info
            elif info.name.startswith('joe (') and info.name.endswith(').odt'):
                local_version = info
        self.assertTrue(remote_version is not None)
        self.assertTrue(local_version is not None)
        self.assertTrue(local.exists(remote_version.path))
        self.assertEquals(local.get_content(remote_version.path),
                          'Some content')
        self.assertTrue(local.exists(local_version.path))
        self.assertEquals(local.get_content(local_version.path),
                          'Some updated content')
        self.assertTrue(local.exists('/Test folder/jack.odt'))
        self.assertTrue(local.exists('/Test folder/new.odt'))
        self.assertTrue(local.exists('/Test folder/Sub folder 1'))
        self.assertTrue(local.exists(
                                '/Test folder/Sub folder 1/sub file 1.txt'))
        self.assertTrue(local.exists('/Test folder/Sub folder 2'))
        self.assertTrue(local.exists(
                                '/Test folder/Sub folder 2/sub file 2.txt'))
        # State check
        self._check_pair_state(session, '/Test folder', 'synchronized')
        self._check_pair_state(session, '/Test folder/joe.odt',
                               'synchronized')
        self._check_pair_state(session, '/Test folder/new.odt',
                               'synchronized')
        self._check_pair_state(session, '/Test folder/Sub folder 2',
                               'synchronized')
        self._check_pair_state(session,
                               '/Test folder/Sub folder 2/sub file 2.txt',
                               'synchronized')
        # Remote check
        self.assertTrue(remote.exists('/Test folder'))
        test_folder_uid = remote.get_info('/Test folder').uid
        children_info = remote.get_children_info(test_folder_uid)
        self.assertEquals(len(children_info), 6)
        for info in children_info:
            if info.name == 'joe.odt':
                remote_version = info
            elif info.name.startswith('joe (') and info.name.endswith(').odt'):
                local_version = info
        self.assertTrue(remote_version is not None)
        self.assertTrue(local_version is not None)
        remote_version_ref_length = (len(remote_version.path)
                                     - len(self.TEST_WORKSPACE_PATH))
        remote_version_ref = remote_version.path[-remote_version_ref_length:]
        self.assertTrue(remote.exists(remote_version_ref))
        self.assertEquals(remote.get_content(remote_version_ref),
                          'Some content')
        local_version_ref_length = (len(local_version.path)
                                     - len(self.TEST_WORKSPACE_PATH))
        local_version_ref = local_version.path[-local_version_ref_length:]
        self.assertTrue(remote.exists(local_version_ref))
        self.assertEquals(remote.get_content(local_version_ref),
                          'Some updated content')
        self.assertTrue(remote.exists('/Test folder/jack.odt'))
        self.assertTrue(remote.exists('/Test folder/new.odt'))
        self.assertTrue(remote.exists('/Test folder/Sub folder 1'))
        self.assertTrue(remote.exists(
                                '/Test folder/Sub folder 1/sub file 1.txt'))
        self.assertTrue(remote.exists('/Test folder/Sub folder 2'))
        self.assertTrue(remote.exists(
                    '/Test folder/Sub folder 2/sub file 2.txt'))

        # Delete remote file and update its local content
        # concurrently then synchronize
        remote.delete('/Test folder/jack.odt')
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        local.update_content('/Test folder/jack.odt', 'Some updated content')
        self._synchronize(syn)
        # File should be kept locally and be marked as 'unsynchronized'.
        # Local check
        self.assertTrue(local.exists('/Test folder/jack.odt'))
        self.assertEquals(local.get_content('/Test folder/jack.odt'),
                          'Some updated content')
        # Remote check
        self.assertFalse(remote.exists('/Test folder/jack.odt'))
        # State check
        session = ctl.get_session()
        self._check_pair_state(session, '/Test folder', 'synchronized')
        self._check_pair_state(session, '/Test folder/jack.odt',
                               'unsynchronized')

        # Remotely restore file from the trash then synchronize
        remote.undelete('/Test folder/jack.odt')
        self._synchronize(syn)
        # Remotely restored file should be merged with locally modified file
        # with a conflict detection and both files should be marked
        # as 'synchronized'
        # Local check
        children_info = local.get_children_info('/Test folder')
        for info in children_info:
            if info.name == 'jack.odt':
                remote_version = info
            elif (info.name.startswith('jack (')
                  and info.name.endswith(').odt')):
                local_version = info
        self.assertTrue(remote_version is not None)
        self.assertTrue(local_version is not None)
        self.assertTrue(local.exists(remote_version.path))
        self.assertEquals(local.get_content(remote_version.path),
                          'Some content')
        self.assertTrue(local.exists(local_version.path))
        self.assertEquals(local.get_content(local_version.path),
                          'Some updated content')
        # Remote check
        self.assertTrue(remote.exists(remote_version.path))
        self.assertEquals(remote.get_content(remote_version.path),
                          'Some content')
        local_version_path = self._truncate_remote_path(local_version.path)
        self.assertTrue(remote.exists(local_version_path))
        self.assertEquals(remote.get_content(local_version_path),
                          'Some updated content')
        # State check
        self._check_pair_state(session, remote_version.path,
                               'synchronized')
        self._check_pair_state(session, local_version.path,
                               'synchronized')

        # Delete remote file and rename it locally
        # concurrently then synchronize
        remote.delete('/Test folder/jack.odt')
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        local.rename('/Test folder/jack.odt', 'jack renamed.odt')
        self._synchronize(syn)
        # File should be kept locally and be marked as 'synchronized'
        # Local check
        self.assertFalse(local.exists('/Test folder/jack.odt'))
        self.assertTrue(local.exists('/Test folder/jack renamed.odt'))
        self.assertEquals(local.get_content('/Test folder/jack renamed.odt'),
                          'Some content')
        # Remote check
        self.assertFalse(remote.exists('/Test folder/jack.odt'))
        # State check
        session = ctl.get_session()
        self._check_pair_state(session, '/Test folder', 'synchronized')
        self._check_pair_state(session, '/Test folder/jack renamed.odt',
                               'synchronized')

        # Remotely restore file from the trash then synchronize
        remote.undelete('/Test folder/jack.odt')
        self._synchronize(syn)
        # Remotely restored file should be merged with locally renamed file
        # and both files should be marked as 'synchronized'
        # Local check
        self.assertTrue(local.exists('/Test folder/jack.odt'))
        self.assertEquals(local.get_content('/Test folder/jack.odt'),
                          'Some content')
        self.assertTrue(local.exists('/Test folder/jack renamed.odt'))
        self.assertEquals(local.get_content('/Test folder/jack renamed.odt'),
                          'Some content')
        # Remote check
        self.assertTrue(remote.exists('/Test folder/jack.odt'))
        self.assertEquals(remote.get_content('/Test folder/jack.odt'),
                          'Some content')
        self.assertTrue(remote.exists('/Test folder/jack renamed.odt'))
        self.assertEquals(remote.get_content('/Test folder/jack renamed.odt'),
                          'Some content')
        # State check
        self._check_pair_state(session, '/Test folder/jack.odt',
                               'synchronized')
        self._check_pair_state(session, '/Test folder/jack renamed.odt',
                               'synchronized')
    def test_binding_initialization_and_first_sync(self):
        ctl = self.controller_1
        # Create some documents in a Nuxeo workspace and bind this server to a
        # Nuxeo Drive local folder
        self.make_server_tree()
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)
        syn = ctl.synchronizer

        # The root binding operation does not create the local folder
        # yet.
        expected_folder = os.path.join(self.local_nxdrive_folder_1,
                                       self.workspace_title)
        local_client = LocalClient(self.local_nxdrive_folder_1)
        self.assertFalse(local_client.exists('/' + self.workspace_title))

        # By default only scan happen, hence their is no information on the
        # state of the documents on the local side (they don't exist there yet)
        states = ctl.children_states(expected_folder)
        self.assertEquals(states, [])

        # Only the root binding is stored in the DB
        self.assertEquals(len(self.get_all_states()), 1)

        # Trigger some scan manually
        syn.scan_local(self.local_nxdrive_folder_1)
        syn.scan_remote(self.local_nxdrive_folder_1)

        # Check the list of files and folders with synchronization pending
        pending = ctl.list_pending()
        self.assertEquals(len(pending), 12)
        remote_names = [p.remote_name for p in pending]
        remote_names.sort()
        self.assertEquals(remote_names, [
            u'Duplicated File.txt',
            u'Duplicated File.txt',
            u'File 1.txt',
            u'File 2.txt',
            u'File 3.txt',
            u'File 4.txt',
            u'File 5.txt',
            u'Folder 1',
            u'Folder 1.1',
            u'Folder 1.2',
            u'Folder 2',
            u'Nuxeo Drive Test Workspace',
        ])

        # It is also possible to restrict the list of pending document to a
        # specific server binding
        self.assertEquals(len(ctl.list_pending(
                          local_folder=self.local_nxdrive_folder_1)), 12)

        # It is also possible to restrict the number of pending tasks
        pending = ctl.list_pending(limit=2)
        self.assertEquals(len(pending), 2)

        # Synchronize the first document (ordered by hierarchy):
        self.assertEquals(syn.synchronize(
            self.local_nxdrive_folder_1, limit=1), 1)
        pending = ctl.list_pending()
        self.assertEquals(len(pending), 11)
        remote_names = [p.remote_name for p in pending]
        remote_names.sort()
        self.assertEquals(remote_names, [
            u'Duplicated File.txt',
            u'Duplicated File.txt',
            u'File 1.txt',
            u'File 2.txt',
            u'File 3.txt',
            u'File 4.txt',
            u'File 5.txt',
            u'Folder 1',
            u'Folder 1.1',
            u'Folder 1.2',
            u'Folder 2',
        ])
        states = ctl.children_states(self.local_nxdrive_folder_1)
        self.assertEquals(states, [
            (u'Nuxeo Drive Test Workspace', u'children_modified'),
        ])

        # The workspace folder is still unknown from the client point
        # of view
        states = ctl.children_states(expected_folder)
        self.assertEquals(states, [])

        # synchronize everything else
        self.assertEquals(syn.synchronize(), 11)
        self.assertEquals(ctl.list_pending(), [])
        states = ctl.children_states(expected_folder)
        expected_states = [
            (u'File 5.txt', 'synchronized'),
            (u'Folder 1', 'synchronized'),
            (u'Folder 2', 'synchronized'),
        ]
        self.assertEquals(states, expected_states)

        # The actual content of the file has been updated
        file_5_content = local_client.get_content(
            '/Nuxeo Drive Test Workspace/File 5.txt')
        self.assertEquals(file_5_content, "eee")

        states = ctl.children_states(expected_folder + '/Folder 1')
        expected_states = [
            (u'File 1.txt', 'synchronized'),
            (u'Folder 1.1', 'synchronized'),
            (u'Folder 1.2', 'synchronized'),
        ]
        self.assertEquals(states, expected_states)
        self.assertEquals(local_client.get_content(
            '/Nuxeo Drive Test Workspace/Folder 1/File 1.txt'),
            "aaa")

        self.assertEquals(local_client.get_content(
            '/Nuxeo Drive Test Workspace/Folder 1/Folder 1.1/File 2.txt'),
            "bbb")

        self.assertEquals(local_client.get_content(
            '/Nuxeo Drive Test Workspace/Folder 1/Folder 1.2/File 3.txt'),
            "ccc")

        self.assertEquals(local_client.get_content(
            '/Nuxeo Drive Test Workspace/Folder 2/File 4.txt'),
            "ddd")

        c1 = local_client.get_content(
            '/Nuxeo Drive Test Workspace/Folder 2/Duplicated File.txt')

        c2 = local_client.get_content(
            '/Nuxeo Drive Test Workspace/Folder 2/Duplicated File__1.txt')

        self.assertEquals(tuple(sorted((c1, c2))),
                          ("Other content.", "Some content."))

        # Nothing else left to synchronize
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(syn.synchronize(), 0)
        self.assertEquals(ctl.list_pending(), [])

        # Unbind root and resynchronize: smoke test
        ctl.unbind_root(self.local_nxdrive_folder_1, self.workspace)
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(syn.synchronize(), 0)
        self.assertEquals(ctl.list_pending(), [])
Exemple #41
0
    def test_sync_delete_root(self):
        user_workspaces_path = '/default-domain/UserWorkspaces/'
        user_workspace_title = 'nuxeoDriveTestUser-user-1'
        user_workspace_path = user_workspaces_path + user_workspace_title
        try:
            # Get remote and local clients
            admin_remote_client = self.root_remote_client
            user_remote_client = RemoteDocumentClient(
                self.nuxeo_url,
                self.user_1,
                u'nxdrive-test-device-1',
                self.version,
                password=self.password_1,
                upload_tmp_dir=self.upload_tmp_dir)
            local_client = LocalClient(self.local_nxdrive_folder_1)

            # Activate permission hierarchy profile as Administrator
            admin_remote_client.activate_profile('permission')

            # Make sure user workspace is created
            user_remote_client.make_file_in_user_workspace(
                'File in user workspace', filename='USFile.txt')
            # Bind server
            ctl = self.controller_1
            ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                            self.user_1, self.password_1)
            syn = ctl.synchronizer

            # Create test folder in user workspace as test user
            user_remote_client.make_folder(user_workspace_path, 'test_folder')
            test_folder_path = user_workspace_path + '/test_folder'
            # Create a document in the test folder
            user_remote_client.make_file(test_folder_path, 'test_file.txt',
                                         "Some content.")

            # Register test folder as a sync root
            user_remote_client.register_as_root(test_folder_path)

            # Synchronize
            self._synchronize(syn)

            # Check locally synchronized content
            self.assertTrue(local_client.exists('/My Docs/test_folder'))
            self.assertTrue(
                local_client.exists('/My Docs/test_folder/test_file.txt'))

            # Delete test folder
            user_remote_client.delete(test_folder_path)

            # Synchronize
            self._synchronize(syn)

            # Check locally synchronized content
            self.assertFalse(local_client.exists('/My Docs/test_folder'))
            self.assertEquals(len(local_client.get_children_info('/My Docs')),
                              0)
        finally:
            # Cleanup user workspace
            if admin_remote_client.exists(user_workspace_path):
                admin_remote_client.delete(user_workspace_path,
                                           use_trash=False)
            # Deactivate permission hierarchy profile
            admin_remote_client.deactivate_profile('permission')
    def test_concurrent_file_access(self):
        """Test update/deletion of a locally locked file.

        This is to simulate downstream synchronization of a file opened (thus
        locked) by any program under Windows, typically MS Word.
        The file should be blacklisted and not prevent synchronization of other
        pending items.
        Once the file is unlocked and the cooldown period is over it should be
        synchronized.
        """
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(
            os.path.join(self.local_nxdrive_folder_1, self.workspace_title))
        remote = self.remote_document_client_1

        # Create file in the remote root workspace
        remote.make_file('/', 'test_update.docx', 'Some content to update.')
        remote.make_file('/', 'test_delete.docx', 'Some content to delete.')

        # Launch first synchronization
        syn = ctl.synchronizer
        self._synchronize(syn)
        self.assertTrue(local.exists('/test_update.docx'))
        self.assertTrue(local.exists('/test_delete.docx'))

        # Open locally synchronized files to lock them and generate a
        # WindowsError when trying to update / delete them
        file1_path = local.get_info('/test_update.docx').filepath
        file1_desc = open(file1_path, 'rb')
        file2_path = local.get_info('/test_delete.docx').filepath
        file2_desc = open(file2_path, 'rb')

        # Update /delete existing remote files and create a new remote file
        remote.update_content('/test_update.docx', 'Updated content.')
        remote.delete('/test_delete.docx')
        remote.make_file('/', 'other.docx', 'Other content.')

        # Synchronize
        self._synchronize(syn)
        if sys.platform == 'win32':
            # As local file are locked, a WindowsError should occur during the
            # local update process, therefore:
            # - Temporary download file (.part) should be created locally but
            #   not renamed
            # - Opened local files should still exist and not have been
            #   modified
            # - Synchronization should not fail: doc pairs should be
            #   blacklisted, there should be 2 pending items and other remote
            #   modifications should be locally synchronized
            self.assertTrue(local.exists('/.test_update.docx.part'))
            self.assertTrue(local.exists('/test_update.docx'))
            self.assertEquals(local.get_content('/test_update.docx'),
                              'Some content to update.')
            self.assertTrue(local.exists('/test_delete.docx'))
            self.assertEquals(local.get_content('/test_delete.docx'),
                              'Some content to delete.')
            self.assertEquals(len(ctl.list_pending()), 2)
            self.assertTrue(local.exists('/other.docx'))
            self.assertEquals(local.get_content('/other.docx'),
                              'Other content.')

            # Synchronize again
            syn.loop(delay=0.1, max_loops=1)
            # Blacklisted files should be ignored as delay (300 seconds by
            # default) is not expired, nothing should have changed
            self.assertTrue(local.exists('/.test_update.docx.part'))
            self.assertTrue(local.exists('/test_update.docx'))
            self.assertEquals(local.get_content('/test_update.docx'),
                              'Some content to update.')
            self.assertTrue(local.exists('/test_delete.docx'))
            self.assertEquals(local.get_content('/test_delete.docx'),
                              'Some content to delete.')
            self.assertEquals(len(ctl.list_pending()), 2)

            # Release file locks by closing them
            file1_desc.close()
            file2_desc.close()
            # Reduce error skip delay to retry synchronization of pairs in
            # error
            syn.error_skip_period = 1.0
            time.sleep(syn.error_skip_period)
            syn.loop(delay=0.1, max_loops=1)
            # Previously blacklisted files should be updated / deleted locally,
            # temporary download file should not be there anymore and there
            # should be no pending items left
            self.assertTrue(local.exists('/test_update.docx'))
            self.assertEquals(local.get_content('/test_update.docx'),
                              'Updated content.')
            self.assertFalse(local.exists('/.test_update.docx.part'))
            self.assertFalse(local.exists('/test_delete.docx'))
            self.assertEquals(len(ctl.list_pending()), 0)
        else:
            self.assertTrue(local.exists('/test_update.docx'))
            self.assertEquals(local.get_content('/test_update.docx'),
                              'Updated content.')
            self.assertFalse(local.exists('/.test_update.docx.part'))
            self.assertFalse(local.exists('/test_delete.docx'))
            self.assertEquals(len(ctl.list_pending()), 0)
    def test_move_sync_root_child_to_user_workspace(self):
        """See https://jira.nuxeo.com/browse/NXP-14870"""
        admin_remote_client = self.root_remote_client
        user1_workspace_uid = None
        try:
            # Get remote  and local clients
            remote_user1 = RemoteDocumentClient(
                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_user2 = RemoteDocumentClient(
                self.nuxeo_url, self.user_2, u'nxdrive-test-device-2',
                self.version, password=self.password_2,
                upload_tmp_dir=self.upload_tmp_dir)
            local_user2 = LocalClient(self.local_nxdrive_folder_2)

            # Make sure personal workspace is created for user1 and fetch its uid
            user1_workspace_uid = remote_user1.make_file_in_user_workspace('File in user workspace',
                                                                           filename='UWFile.txt')['parentRef']

            # As user1 register personal workspace as a sync root
            remote_user1.register_as_root(user1_workspace_uid)

            # As user1 create a parent folder in user1's personal workspace
            parent_folder_uid = remote_user1.make_folder(user1_workspace_uid, 'Parent')

            # As user1 grant Everything permission to user2 on parent folder
            op_input = "doc:" + parent_folder_uid
            admin_remote_client.execute("Document.SetACE", op_input=op_input, user="******",
                                        permission="Everything", grant="true")

            # As user1 create a child folder in parent folder
            child_folder_uid = remote_user1.make_folder(parent_folder_uid, 'Child')

            # As user2 register parent folder as a sync root
            remote_user2.register_as_root(parent_folder_uid)
            remote_user2.unregister_as_root(self.workspace)
            # Start engine for user2
            self.engine_2.start()

            # Wait for synchronization
            self.wait_sync(wait_for_async=True, wait_for_engine_1=False, wait_for_engine_2=True)

            # Check locally synchronized content
            self.assertEquals(len(local_user2.get_children_info('/')), 1)
            self.assertTrue(local_user2.exists('/Parent'))
            self.assertTrue(local_user2.exists('/Parent/Child'))

            # As user1 move child folder to user1's personal workspace
            remote_user1.move(child_folder_uid, user1_workspace_uid)

            # Wait for synchronization
            self.wait_sync(wait_for_async=True, wait_for_engine_1=False, wait_for_engine_2=True)

            # Check locally synchronized content
            self.assertFalse(local_user2.exists('/Parent/Child'))

        finally:
            # Cleanup user1 personal workspace
            if user1_workspace_uid is not None and admin_remote_client.exists(user1_workspace_uid):
                admin_remote_client.delete(user1_workspace_uid,
                                           use_trash=False)
Exemple #44
0
    def test_sync_delete_shared_folder(self):
        user_workspace_uid = None
        try:
            # Get remote and local clients
            admin_remote_client = self.root_remote_client
            user1_remote_client = RemoteDocumentClient(
                self.nuxeo_url,
                self.user_1,
                u'nxdrive-test-device-1',
                self.version,
                password=self.password_1,
                upload_tmp_dir=self.upload_tmp_dir)
            user2_remote_client = RemoteDocumentClient(
                self.nuxeo_url,
                self.user_2,
                u'nxdrive-test-device-2',
                self.version,
                password=self.password_2,
                upload_tmp_dir=self.upload_tmp_dir)
            local_client_1 = LocalClient(self.local_nxdrive_folder_1)

            # Make sure user1 workspace is created and fetch its uid
            user_workspace_uid = user1_remote_client.make_file_in_user_workspace(
                'File in user workspace', filename='USFile.txt')['parentRef']

            # Register user workspace as a sync root for user1
            user1_remote_client.register_as_root(user_workspace_uid)

            # Start engine
            self.engine_1.start()

            # Wait for synchronization
            self.wait_sync(wait_for_async=True)
            # Check locally synchronized content
            self.assertTrue(local_client_1.exists('/My Docs'))

            # Create test folder in user workspace as user1
            test_folder_uid = user1_remote_client.make_folder(
                user_workspace_uid, 'test_folder')
            # Wait for synchronization
            self.wait_sync(wait_for_async=True)
            # Check locally synchronized content
            self.assertTrue(local_client_1.exists('/My Docs/test_folder'))

            # Grant ReadWrite permission to user2 on test folder
            op_input = "doc:" + test_folder_uid
            admin_remote_client.execute("Document.SetACE",
                                        op_input=op_input,
                                        user="******",
                                        permission="ReadWrite",
                                        grant="true")
            # Wait for synchronization
            self.wait_sync(wait_for_async=True)

            # Register test folder as a sync root for user2
            user2_remote_client.register_as_root(test_folder_uid)
            # Wait for synchronization
            self.wait_sync(wait_for_async=True)

            # Delete test folder
            user1_remote_client.delete(test_folder_uid)

            # Synchronize deletion
            self.wait_sync(wait_for_async=True)
            # Check locally synchronized content
            self.assertFalse(local_client_1.exists('/My Docs/test_folder'))
            self.assertEquals(
                len(local_client_1.get_children_info('/My Docs')), 1)
        finally:
            # Cleanup user workspace
            if user_workspace_uid is not None and admin_remote_client.exists(
                    user_workspace_uid):
                admin_remote_client.delete(user_workspace_uid, use_trash=False)
    def test_synchronize_paged_delete_detection(self):
        # Initialize a controller with page size = 1 for deleted items
        # detection query
        ctl = Controller(self.nxdrive_conf_folder_1, page_size=1)
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Launch first synchronization
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn = ctl.synchronizer
        syn.loop(delay=0.1, max_loops=1)

        # Get local and remote clients
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_document_client_1

        # Create a remote folder with 2 children then synchronize
        remote.make_folder('/', 'Remote folder',)
        remote.make_file('/Remote folder', 'Remote file 1.odt',
                         'Some content.')
        remote.make_file('/Remote folder', 'Remote file 2.odt',
                         'Other content.')

        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(local.exists('/Remote folder'))
        self.assertTrue(local.exists('/Remote folder/Remote file 1.odt'))
        self.assertTrue(local.exists('/Remote folder/Remote file 2.odt'))

        # Delete remote folder then synchronize
        remote.delete('/Remote folder')

        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0.1, max_loops=1)
        self.assertFalse(local.exists('/Remote folder'))
        self.assertFalse(local.exists('/Remote folder/Remote file 1.odt'))
        self.assertFalse(local.exists('/Remote folder/Remote file 2.odt'))

        # Create a local folder with 2 children then synchronize
        local.make_folder('/', 'Local folder')
        local.make_file('/Local folder', 'Local file 1.odt', 'Some content.')
        local.make_file('/Local folder', 'Local file 2.odt', 'Other content.')

        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(remote.exists('/Local folder'))
        self.assertTrue(remote.exists('/Local folder/Local file 1.odt'))
        self.assertTrue(remote.exists('/Local folder/Local file 2.odt'))

        # Delete local folder then synchronize
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        local.delete('/Local folder')

        syn.loop(delay=0.1, max_loops=1)
        self.assertFalse(remote.exists('/Local folder'))
        self.assertFalse(remote.exists('/Local folder/Local file 1.odt'))
        self.assertFalse(remote.exists('/Local folder/Local file 2.odt'))

        # Dispose dedicated Controller instantiated for this test
        ctl.dispose()
    def test_synchronize_denying_read_access(self):
        """Test that denying Read access server side is impacted client side

        Use cases:
          - Deny Read access on a regular folder
              => Folder should be locally deleted
          - Grant Read access back
              => Folder should be locally re-created
          - Deny Read access on a synchronization root
              => Synchronization root should be locally deleted
          - Grant Read access back
              => Synchronization root should be locally re-created

        See TestIntegrationRemoteDeletion.test_synchronize_remote_deletion
        as the same uses cases are tested
        """
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_document_client_1

        # Create documents in the remote root workspace
        # then synchronize
        remote.make_folder('/', 'Test folder')
        remote.make_file('/Test folder', 'joe.txt', 'Some content')

        syn = ctl.synchronizer
        self._synchronize(syn)
        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.txt'))

        # Remove Read permission for test user on a regular folder
        # then synchronize
        self._set_read_permission("nuxeoDriveTestUser_user_1",
                                  self.TEST_WORKSPACE_PATH + '/Test folder',
                                  False)
        self._synchronize(syn)
        self.assertFalse(local.exists('/Test folder'))

        # Add Read permission back for test user then synchronize
        self._set_read_permission("nuxeoDriveTestUser_user_1",
                                  self.TEST_WORKSPACE_PATH + '/Test folder',
                                  True)
        self._synchronize(syn)
        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.txt'))

        # Remove Read permission for test user on a sync root
        # then synchronize
        self._set_read_permission("nuxeoDriveTestUser_user_1",
                                  self.TEST_WORKSPACE_PATH,
                                  False)
        self._synchronize(syn)
        self.assertFalse(local.exists('/'))

        # Add Read permission back for test user then synchronize
        self._set_read_permission("nuxeoDriveTestUser_user_1",
                                  self.TEST_WORKSPACE_PATH,
                                  True)
        self._synchronize(syn)
        self.assertTrue(local.exists('/'))
        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.txt'))
Exemple #47
0
    def test_sync_unshared_folder(self):
        user_workspace_uid = None
        try:
            # Get remote and local clients
            admin_remote_client = self.root_remote_client
            user1_remote_client = RemoteDocumentClient(
                self.nuxeo_url,
                self.user_1,
                u'nxdrive-test-device-1',
                self.version,
                password=self.password_1,
                upload_tmp_dir=self.upload_tmp_dir)
            user2_remote_client = RemoteDocumentClient(
                self.nuxeo_url,
                self.user_2,
                u'nxdrive-test-device-2',
                self.version,
                password=self.password_2,
                upload_tmp_dir=self.upload_tmp_dir)
            local_client_1 = LocalClient(self.local_nxdrive_folder_1)
            local_client_2 = LocalClient(self.local_nxdrive_folder_2)

            # Make sure user1 workspace is created and fetch its uid
            user_workspace_uid = user1_remote_client.make_file_in_user_workspace(
                'File in user workspace', filename='USFile.txt')['parentRef']

            # Register user workspace as a sync root for user1
            user1_remote_client.register_as_root(user_workspace_uid)

            # Start engine
            self.engine_2.start()

            # Wait for synchronization
            self.wait_sync(wait_for_async=True,
                           wait_for_engine_2=True,
                           wait_for_engine_1=False)
            # Check locally synchronized content
            self.assertTrue(local_client_2.exists('/My Docs'))
            self.assertTrue(local_client_2.exists('/Other Docs'))

            # Create test folder in user workspace as user1
            test_folder_uid = user1_remote_client.make_folder(
                user_workspace_uid, 'Folder A')
            folder_b = user1_remote_client.make_folder(test_folder_uid,
                                                       'Folder B')
            folder_c = user1_remote_client.make_folder(folder_b, 'Folder C')
            folder_d = user1_remote_client.make_folder(folder_c, 'Folder D')
            folder_e = user1_remote_client.make_folder(folder_d, 'Folder E')

            # Grant ReadWrite permission to user2 on test folder
            op_input = "doc:" + test_folder_uid
            admin_remote_client.execute("Document.SetACE",
                                        op_input=op_input,
                                        user=self.user_2,
                                        permission="ReadWrite",
                                        grant="true")

            # Register test folder as a sync root for user2
            user2_remote_client.register_as_root(test_folder_uid)
            # Wait for synchronization
            self.wait_sync(wait_for_async=True,
                           wait_for_engine_2=True,
                           wait_for_engine_1=False)
            self.assertTrue(local_client_2.exists('/Other Docs/Folder A'))
            self.assertTrue(
                local_client_2.exists(
                    '/Other Docs/Folder A/Folder B/Folder C/Folder D/Folder E')
            )
            # Use for later get_fs_item checks
            folder_b_fs = local_client_2.get_remote_id(
                '/Other Docs/Folder A/Folder B')
            folder_a_fs = local_client_2.get_remote_id('/Other Docs/Folder A')
            # Unshare Folder A and share Folder C
            admin_remote_client.execute("Document.RemoveACL",
                                        op_input=op_input,
                                        acl='local')
            op_input = "doc:" + folder_c
            admin_remote_client.execute("Document.SetACE",
                                        op_input=op_input,
                                        user=self.user_2,
                                        permission="Read",
                                        grant="true")
            user2_remote_client.register_as_root(folder_c)
            self.wait_sync(wait_for_async=True,
                           wait_for_engine_2=True,
                           wait_for_engine_1=False)
            self.assertFalse(local_client_2.exists('/Other Docs/Folder A'))
            self.assertTrue(local_client_2.exists('/Other Docs/Folder C'))
            self.assertTrue(
                local_client_2.exists(
                    '/Other Docs/Folder C/Folder D/Folder E'))

            # Verify that we dont have any 403 errors
            self.assertIsNone(
                self.remote_file_system_client_2.get_fs_item(folder_a_fs))
            self.assertIsNone(
                self.remote_file_system_client_2.get_fs_item(folder_b_fs))
        finally:
            # Cleanup user workspace
            if user_workspace_uid is not None and admin_remote_client.exists(
                    user_workspace_uid):
                admin_remote_client.delete(user_workspace_uid, use_trash=False)
    def test_synchronize_remote_deletion(self):
        """Test that deleting remote documents is impacted client side

        Use cases:
          - Remotely delete a regular folder
              => Folder should be locally deleted
          - Remotely restore folder from the trash
              => Folder should be locally re-created
          - Remotely delete a synchronization root
              => Synchronization root should be locally deleted
          - Remotely restore synchronization root from the trash
              => Synchronization root should be locally re-created

        See TestIntegrationSecurityUpdates.test_synchronize_denying_read_access
        as the same uses cases are tested
        """
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_document_client_1

        # Create documents in the remote root workspace
        # then synchronize
        remote.make_folder('/', 'Test folder')
        remote.make_file('/Test folder', 'joe.txt', 'Some content')

        syn = ctl.synchronizer
        self._synchronize(syn)
        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.txt'))

        # Delete remote folder then synchronize
        remote.delete('/Test folder')
        self._synchronize(syn)
        self.assertFalse(local.exists('/Test folder'))

        # Restore folder from trash then synchronize
        # Undeleting each item as following 'undelete' transition
        # doesn't act recursively, should use TrashService instead
        # through a dedicated operation
        remote.undelete('/Test folder')
        remote.undelete('/Test folder/joe.txt')
        self._synchronize(syn)
        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.txt'))

        # Delete sync root then synchronize
        remote.delete('/')
        self._synchronize(syn)
        self.assertFalse(local.exists('/'))

        # Restore sync root from trash then synchronize
        remote.undelete('/')
        remote.undelete('/Test folder')
        remote.undelete('/Test folder/joe.txt')
        self._synchronize(syn)
        self.assertTrue(local.exists('/'))
        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.txt'))
    def test_remote_rename_sync_root_folder(self):
        remote_client = self.remote_client_1
        local_client = LocalClient(self.local_nxdrive_folder_1)

        # Rename a sync root folder
        remote_client.rename(self.workspace_id,
            u'Renamed Nuxeo Drive Test Workspace')
        self.assertEquals(remote_client.get_info(self.workspace_id).name,
            u'Renamed Nuxeo Drive Test Workspace')

        # Synchronize: only the sync root folder renaming is detected: all
        # the descendants are automatically realigned
        self.wait_sync(wait_for_async=True)

        # The client folder has been renamed
        self.assertFalse(local_client.exists(u'/Nuxeo Drive Test Workspace'))
        self.assertTrue(local_client.exists(
            u'/Renamed Nuxeo Drive Test Workspace'))

        renamed_workspace_path = os.path.join(self.local_nxdrive_folder_1,
            u'Renamed Nuxeo Drive Test Workspace')
        # The content of the renamed folder is left unchanged
        # Check child name
        self.assertTrue(local_client.exists(
            u'/Renamed Nuxeo Drive Test Workspace/Original File 1.txt'))
        file_1_local_info = local_client.get_info(
            u'/Renamed Nuxeo Drive Test Workspace/Original File 1.txt')
        file_1_parent_path = os.path.dirname(file_1_local_info.filepath)
        self.assertEquals(file_1_parent_path, renamed_workspace_path)
        # Check child state
        file_1_state = self._get_state(self.file_1_id)
        self.assertEquals(file_1_state.local_path,
            u'/Renamed Nuxeo Drive Test Workspace/Original File 1.txt')
        self.assertEquals(file_1_state.local_name, u'Original File 1.txt')

        # Check child name
        self.assertTrue(local_client.exists(
            u'/Renamed Nuxeo Drive Test Workspace/Original Folder 1'))
        folder_1_local_info = local_client.get_info(
            u'/Renamed Nuxeo Drive Test Workspace/Original Folder 1')
        folder_1_parent_path = os.path.dirname(folder_1_local_info.filepath)
        self.assertEquals(folder_1_parent_path, renamed_workspace_path)
        # Check child state
        folder_1_state = self._get_state(self.folder_1_id)
        self.assertEquals(folder_1_state.local_path,
            u'/Renamed Nuxeo Drive Test Workspace/Original Folder 1')
        self.assertEquals(folder_1_state.local_name, u'Original Folder 1')

        # Check child name
        self.assertTrue(local_client.exists(
            u'/Renamed Nuxeo Drive Test Workspace/'
            u'Original Folder 1/Sub-Folder 1.1'))
        folder_1_1_local_info = local_client.get_info(
            u'/Renamed Nuxeo Drive Test Workspace/'
            u'Original Folder 1/Sub-Folder 1.1')
        folder_1_1_parent_path = os.path.dirname(
            folder_1_1_local_info.filepath)
        self.assertEquals(folder_1_1_parent_path,
            os.path.join(renamed_workspace_path, u'Original Folder 1'))
        # Check child state
        folder_1_1_state = self._get_state(self.folder_1_1_id)
        self.assertEquals(folder_1_1_state.local_path,
            u'/Renamed Nuxeo Drive Test Workspace'
            '/Original Folder 1/Sub-Folder 1.1')
        self.assertEquals(folder_1_1_state.local_name, u'Sub-Folder 1.1')

        # Check child name
        self.assertTrue(local_client.exists(
            u'/Renamed Nuxeo Drive Test Workspace/'
            u'Original Folder 1/Original File 1.1.txt'))
        file_1_1_local_info = local_client.get_info(
            u'/Renamed Nuxeo Drive Test Workspace/'
            'Original Folder 1/Original File 1.1.txt')
        file_1_1_parent_path = os.path.dirname(file_1_1_local_info.filepath)
        self.assertEquals(file_1_1_parent_path,
            os.path.join(renamed_workspace_path, u'Original Folder 1'))
        # Check child state
        file_1_1_state = self._get_state(self.file_1_1_id)
        self.assertEquals(file_1_1_state.local_path,
                          u'/Renamed Nuxeo Drive Test Workspace'
                          '/Original Folder 1/Original File 1.1.txt')
        self.assertEquals(file_1_1_state.local_name, u'Original File 1.1.txt')
Exemple #50
0
    def test_synchronize_no_space_left_on_device(self):
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Launch first synchronization
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn = ctl.synchronizer
        syn.loop(delay=0.1, max_loops=1)

        # Get local and remote clients
        local = LocalClient(
            os.path.join(self.local_nxdrive_folder_1, self.workspace_title))
        remote = self.remote_document_client_1

        # Create a file in the remote root workspace
        remote.make_file('/', 'test_KO.odt', 'Some large content.')
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()

        # Synchronize simulating a "No space left on device" error
        error = IOError("No space left on device")
        ctl.make_local_raise(error)
        syn.loop(delay=0.1, max_loops=1)
        # Temporary download file (.part) should be created locally but not
        # renamed and synchronization should not fail: doc pair should be
        # blacklisted and there should be 1 pending item
        self.assertTrue(local.exists('/.test_KO.odt.part'))
        self.assertFalse(local.exists('/test_KO.odt'))
        self.assertEquals(len(ctl.list_pending()), 1)

        # Create another file in the remote root workspace
        remote.make_file('/', 'test_OK.odt', 'Some small content.')
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()

        # Synchronize without simulating any error
        ctl.make_local_raise(None)
        syn.loop(delay=0.1, max_loops=1)
        # Remote file should be created locally
        self.assertTrue(local.exists('/test_OK.odt'))
        # Blacklisted file should be ignored as delay (300 seconds by default)
        # is not expired, temporary download file from previously failed
        # synchronization should still be there and there should still be 1
        # pending item
        self.assertTrue(local.exists('/.test_KO.odt.part'))
        self.assertFalse(local.exists('/test_KO.odt'))
        self.assertEquals(len(ctl.list_pending()), 1)

        # Retry to synchronize blacklisted file still simulating a "No space
        # left on device" error
        ctl.make_local_raise(error)
        # Reduce error skip delay to retry synchronization of pairs in error
        syn.error_skip_period = 1.0
        syn.loop(delay=0.1, max_loops=1)
        # Temporary download file (.part) should be overridden but still not
        # renamed, doc pair should be blacklisted again and there should still
        # be 1 pending item
        self.assertTrue(local.exists('/.test_KO.odt.part'))
        self.assertFalse(local.exists('/test_KO.odt'))
        self.assertEquals(len(ctl.list_pending()), 1)
        # In the test workspace there should be 2 files but only 1 child taken
        # into account by the local client as it ignores .part suffixed files
        self.assertEquals(
            len(
                os.listdir(
                    os.path.join(self.local_nxdrive_folder_1,
                                 self.workspace_title))), 2)
        self.assertEquals(len(local.get_children_info('/')), 1)

        # Synchronize without simulating any error, as if space had been made
        # available on device
        ctl.make_local_raise(None)
        # Wait for error skip delay to retry synchronization of pairs in error
        time.sleep(syn.error_skip_period)
        syn.loop(delay=0.1, max_loops=1)
        # Previously blacklisted file should be created locally, temporary
        # download file should not be there anymore and there should be no
        # pending items left
        self.assertTrue(local.exists('/test_KO.odt'))
        self.assertFalse(local.exists('/.test_KO.odt.part'))
        self.assertEquals(len(ctl.list_pending()), 0)
        # In the test workspace there should be 2 files and 2 children taken
        # into account by the local client
        self.assertEquals(
            len(
                os.listdir(
                    os.path.join(self.local_nxdrive_folder_1,
                                 self.workspace_title))), 2)
        self.assertEquals(len(local.get_children_info('/')), 2)
Exemple #51
0
    def test_remote_rename_sync_root_folder(self):
        remote_client = self.remote_client_1
        local_client = LocalClient(self.local_nxdrive_folder_1)

        # Rename a sync root folder
        remote_client.rename(self.workspace_id,
                             u'Renamed Nuxeo Drive Test Workspace')
        self.assertEquals(
            remote_client.get_info(self.workspace_id).name,
            u'Renamed Nuxeo Drive Test Workspace')

        # Synchronize: only the sync root folder renaming is detected: all
        # the descendants are automatically realigned
        self.wait_sync(wait_for_async=True)

        # The client folder has been renamed
        self.assertFalse(local_client.exists(u'/Nuxeo Drive Test Workspace'))
        self.assertTrue(
            local_client.exists(u'/Renamed Nuxeo Drive Test Workspace'))

        renamed_workspace_path = os.path.join(
            self.local_nxdrive_folder_1, u'Renamed Nuxeo Drive Test Workspace')
        # The content of the renamed folder is left unchanged
        # Check child name
        self.assertTrue(
            local_client.exists(
                u'/Renamed Nuxeo Drive Test Workspace/Original File 1.txt'))
        file_1_local_info = local_client.get_info(
            u'/Renamed Nuxeo Drive Test Workspace/Original File 1.txt')
        file_1_parent_path = os.path.dirname(file_1_local_info.filepath)
        self.assertEquals(file_1_parent_path, renamed_workspace_path)
        # Check child state
        file_1_state = self._get_state(self.file_1_id)
        self.assertEquals(
            file_1_state.local_path,
            u'/Renamed Nuxeo Drive Test Workspace/Original File 1.txt')
        self.assertEquals(file_1_state.local_name, u'Original File 1.txt')

        # Check child name
        self.assertTrue(
            local_client.exists(
                u'/Renamed Nuxeo Drive Test Workspace/Original Folder 1'))
        folder_1_local_info = local_client.get_info(
            u'/Renamed Nuxeo Drive Test Workspace/Original Folder 1')
        folder_1_parent_path = os.path.dirname(folder_1_local_info.filepath)
        self.assertEquals(folder_1_parent_path, renamed_workspace_path)
        # Check child state
        folder_1_state = self._get_state(self.folder_1_id)
        self.assertEquals(
            folder_1_state.local_path,
            u'/Renamed Nuxeo Drive Test Workspace/Original Folder 1')
        self.assertEquals(folder_1_state.local_name, u'Original Folder 1')

        # Check child name
        self.assertTrue(
            local_client.exists(u'/Renamed Nuxeo Drive Test Workspace/'
                                u'Original Folder 1/Sub-Folder 1.1'))
        folder_1_1_local_info = local_client.get_info(
            u'/Renamed Nuxeo Drive Test Workspace/'
            u'Original Folder 1/Sub-Folder 1.1')
        folder_1_1_parent_path = os.path.dirname(
            folder_1_1_local_info.filepath)
        self.assertEquals(
            folder_1_1_parent_path,
            os.path.join(renamed_workspace_path, u'Original Folder 1'))
        # Check child state
        folder_1_1_state = self._get_state(self.folder_1_1_id)
        self.assertEquals(
            folder_1_1_state.local_path, u'/Renamed Nuxeo Drive Test Workspace'
            '/Original Folder 1/Sub-Folder 1.1')
        self.assertEquals(folder_1_1_state.local_name, u'Sub-Folder 1.1')

        # Check child name
        self.assertTrue(
            local_client.exists(u'/Renamed Nuxeo Drive Test Workspace/'
                                u'Original Folder 1/Original File 1.1.txt'))
        file_1_1_local_info = local_client.get_info(
            u'/Renamed Nuxeo Drive Test Workspace/'
            'Original Folder 1/Original File 1.1.txt')
        file_1_1_parent_path = os.path.dirname(file_1_1_local_info.filepath)
        self.assertEquals(
            file_1_1_parent_path,
            os.path.join(renamed_workspace_path, u'Original Folder 1'))
        # Check child state
        file_1_1_state = self._get_state(self.file_1_1_id)
        self.assertEquals(
            file_1_1_state.local_path, u'/Renamed Nuxeo Drive Test Workspace'
            '/Original Folder 1/Original File 1.1.txt')
        self.assertEquals(file_1_1_state.local_name, u'Original File 1.1.txt')
    def test_synchronize_local_filter(self):
        """Test that filtering remote documents is impacted client side

        Just do a single test as it is the same as
        test_integration_remote_deletion

        Use cases:
          - Filter delete a regular folder
              => Folder should be locally deleted
          - Unfilter restore folder from the trash
              => Folder should be locally re-created
          - Filter a synchronization root
              => Synchronization root should be locally deleted
          - Unfilter synchronization root from the trash
              => Synchronization root should be locally re-created

        See TestIntegrationSecurityUpdates.test_synchronize_denying_read_access
        as the same uses cases are tested
        """
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(
            os.path.join(self.local_nxdrive_folder_1, self.workspace_title))
        remote = self.remote_document_client_1

        # Create documents in the remote root workspace
        # then synchronize
        remote.make_folder('/', 'Test folder')
        remote.make_file('/Test folder', 'joe.txt', 'Some content')

        session = ctl.get_session()

        # Fake server binding with the unit test class
        syn = ctl.synchronizer
        self._synchronize(syn)
        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.txt'))

        # Add remote folder as filter then synchronize
        doc = remote.get_info('/Test folder')
        root_path = "/org.nuxeo.drive.service.impl.DefaultTopLevelFolderItemFactory#/defaultSyncRootFolderItemFactory#default#"
        root_path = root_path + doc.root
        doc_path = (root_path + "/defaultFileSystemItemFactory#default#" +
                    doc.uid)

        server_binding = ctl.get_server_binding(self.local_nxdrive_folder_1,
                                                session=session)
        Filter.add(session, server_binding, doc_path)
        self._synchronize(syn)
        self.assertFalse(local.exists('/Test folder'))

        # Restore folder from trash then synchronize
        # Undeleting each item as following 'undelete' transition
        # doesn't act recursively, should use TrashService instead
        # through a dedicated operation
        server_binding = ctl.get_server_binding(self.local_nxdrive_folder_1,
                                                session=session)
        Filter.remove(session, server_binding, doc_path)
        self._synchronize(syn, 2)

        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.txt'))

        # Delete sync root then synchronize
        server_binding = ctl.get_server_binding(self.local_nxdrive_folder_1,
                                                session=session)
        Filter.add(session, server_binding, root_path)
        self._synchronize(syn)
        self.assertFalse(local.exists('/'))

        server_binding = ctl.get_server_binding(self.local_nxdrive_folder_1,
                                                session=session)
        # Restore sync root from trash then synchronize
        Filter.remove(session, server_binding, root_path)
        self._synchronize(syn)
        self.assertTrue(local.exists('/'))
        self.assertTrue(local.exists('/Test folder'))
        self.assertTrue(local.exists('/Test folder/joe.txt'))
    def test_delete_root_folder(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")
        """Check that local delete of root maps to unbind_root on the server"""
        ctl = self.controller_1
        sb = ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                             self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)
        syn = ctl.synchronizer

        # Let's synchronize the new root
        self.assertEquals(syn.update_synchronize_server(sb), 1)
        self.assertEquals(ctl.list_pending(), [])

        self.assertEquals(self.get_all_states(), [
            (u'/',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace',
             u'synchronized', u'synchronized'),
        ])

        # Refetching the changes in the server audit log does not see any
        # change
        self.wait()
        self.assertEquals(syn.update_synchronize_server(sb), 0)
        self.assertEquals(ctl.list_pending(), [])

        # The workspace has been synced
        local = LocalClient(self.local_nxdrive_folder_1)
        self.assertTrue(local.exists('/' + self.workspace_title))

        # Let's create a subfolder and synchronize it
        local.make_folder('/' + self.workspace_title, 'Folder 3')
        self.assertEquals(syn.update_synchronize_server(sb), 1)
        self.assertEquals(ctl.list_pending(), [])

        self.assertEquals(self.get_all_states(), [
            (u'/',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 3',
             u'synchronized', u'synchronized'),
        ])

        # Let's delete the root locally
        local.delete('/' + self.workspace_title)
        self.assertFalse(local.exists('/' + self.workspace_title))
        self.assertEquals(syn.update_synchronize_server(sb), 1)

        self.assertEquals(self.get_all_states(), [
            (u'/',
             u'synchronized', u'synchronized'),
        ])

        # On the server this has been mapped to a root unregistration:
        # the workspace is still there
        self.assertTrue(self.remote_document_client_1.exists('/'))

        # The subfolder has not been deleted on the server
        self.assertTrue(self.remote_document_client_1.exists('/Folder 3'))

        # But the workspace folder is still not there on the client:
        self.assertFalse(local.exists('/' + self.workspace_title))
        self.assertEquals(ctl.list_pending(), [])

        # Synchronizing later does not refetch the workspace as it's not
        # mapped as a sync root.
        self.wait()
        self.assertEquals(syn.update_synchronize_server(sb), 0)
        self.assertEquals(self.get_all_states(), [
            (u'/',
             u'synchronized', u'synchronized'),
        ])
        self.assertFalse(local.exists('/' + self.workspace_title))

        # We can rebind the root and fetch back its content
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)
        self.wait()

        self.wait()
        syn.loop(delay=0, max_loops=1, no_event_init=True)
        self.assertEquals(ctl.list_pending(), [])
        self.assertTrue(local.exists('/' + self.workspace_title))
        self.assertTrue(local.exists('/' + self.workspace_title + '/Folder 3'))
        self.assertEquals(self.get_all_states(), [
            (u'/',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 3',
             u'synchronized', u'synchronized'),
        ])
    def test_synchronize_local_filter_with_move(self):
        # Bind the server and root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Get local and remote clients
        local = LocalClient(
            os.path.join(self.local_nxdrive_folder_1, self.workspace_title))
        remote = self.remote_document_client_1

        # Create documents in the remote root workspace
        # then synchronize
        remote.make_folder('/', 'Test')
        remote.make_file('/Test', 'joe.txt', 'Some content')
        remote.make_folder('/Test', 'Subfolder')
        remote.make_folder('/Test', 'Filtered')
        remote.make_file('/Test/Subfolder', 'joe2.txt', 'Some content')
        remote.make_file('/Test/Subfolder', 'joe3.txt', 'Somecossntent')
        remote.make_folder('/Test/Subfolder/', 'SubSubfolder')
        remote.make_file('/Test/Subfolder/SubSubfolder', 'joe4.txt',
                         'Some qwqwqontent')

        session = ctl.get_session()

        # Fake server binding with the unit test class
        syn = ctl.synchronizer
        self._synchronize(syn)
        self.assertTrue(local.exists('/Test'))
        self.assertTrue(local.exists('/Test/joe.txt'))
        self.assertTrue(local.exists('/Test/Filtered'))
        self.assertTrue(local.exists('/Test/Subfolder'))
        self.assertTrue(local.exists('/Test/Subfolder/joe2.txt'))
        self.assertTrue(local.exists('/Test/Subfolder/joe3.txt'))
        self.assertTrue(local.exists('/Test/Subfolder/SubSubfolder'))
        self.assertTrue(local.exists('/Test/Subfolder/SubSubfolder/joe4.txt'))

        # Add remote folder as filter then synchronize
        doc_file = remote.get_info('/Test/joe.txt')
        doc = remote.get_info('/Test')
        filtered_doc = remote.get_info('/Test/Filtered')
        root_path = "/org.nuxeo.drive.service.impl.DefaultTopLevelFolderItemFactory#/defaultSyncRootFolderItemFactory#default#"
        root_path = root_path + doc.root
        doc_path_filtered = (root_path +
                             "/defaultFileSystemItemFactory#default#" +
                             doc.uid +
                             "/defaultFileSystemItemFactory#default#" +
                             filtered_doc.uid)

        server_binding = ctl.get_server_binding(self.local_nxdrive_folder_1,
                                                session=session)
        Filter.add(session, server_binding, doc_path_filtered)
        self._synchronize(syn)
        self.assertFalse(local.exists('/Test/Filtered'))

        # Move joe.txt to filtered folder on the server
        remote.move(doc_file.uid, filtered_doc.uid)
        self._synchronize(syn)

        # It now delete on the client
        self.assertFalse(local.exists('/Test/joe.txt'))
        self.assertTrue(local.exists('/Test/Subfolder'))
        self.assertTrue(local.exists('/Test/Subfolder/joe2.txt'))
        self.assertTrue(local.exists('/Test/Subfolder/joe3.txt'))
        self.assertTrue(local.exists('/Test/Subfolder/SubSubfolder'))
        self.assertTrue(local.exists('/Test/Subfolder/SubSubfolder/joe4.txt'))

        # Now move the subfolder
        doc_file = remote.get_info('/Test/Subfolder')
        remote.move(doc_file.uid, filtered_doc.uid)
        self._synchronize(syn)

        # Check that all has been deleted
        self.assertFalse(local.exists('/Test/joe.txt'))
        self.assertFalse(local.exists('/Test/Subfolder'))
        self.assertFalse(local.exists('/Test/Subfolder/joe2.txt'))
        self.assertFalse(local.exists('/Test/Subfolder/joe3.txt'))
        self.assertFalse(local.exists('/Test/Subfolder/SubSubfolder'))
        self.assertFalse(local.exists('/Test/Subfolder/SubSubfolder/joe4.txt'))
    def test_synchronize_paged_delete_detection(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")
        # Initialize a controller with page size = 1 for deleted items
        # detection query
        # TODO NXDRIVE-170: refactor
        #ctl = Controller(self.nxdrive_conf_folder_1, page_size=1)
        ctl = None
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)

        # Launch first synchronization
        self.wait()
        syn = ctl.synchronizer
        syn.loop(delay=0.1, max_loops=1)

        # Get local and remote clients
        local = LocalClient(os.path.join(self.local_nxdrive_folder_1,
                                         self.workspace_title))
        remote = self.remote_document_client_1

        # Create a remote folder with 2 children then synchronize
        remote.make_folder('/', 'Remote folder',)
        remote.make_file('/Remote folder', 'Remote file 1.odt',
                         'Some content.')
        remote.make_file('/Remote folder', 'Remote file 2.odt',
                         'Other content.')

        self.wait()
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(local.exists('/Remote folder'))
        self.assertTrue(local.exists('/Remote folder/Remote file 1.odt'))
        self.assertTrue(local.exists('/Remote folder/Remote file 2.odt'))

        # Delete remote folder then synchronize
        remote.delete('/Remote folder')

        self.wait()
        syn.loop(delay=0.1, max_loops=1)
        self.assertFalse(local.exists('/Remote folder'))
        self.assertFalse(local.exists('/Remote folder/Remote file 1.odt'))
        self.assertFalse(local.exists('/Remote folder/Remote file 2.odt'))

        # Create a local folder with 2 children then synchronize
        local.make_folder('/', 'Local folder')
        local.make_file('/Local folder', 'Local file 1.odt', 'Some content.')
        local.make_file('/Local folder', 'Local file 2.odt', 'Other content.')

        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(remote.exists('/Local folder'))
        self.assertTrue(remote.exists('/Local folder/Local file 1.odt'))
        self.assertTrue(remote.exists('/Local folder/Local file 2.odt'))

        # Delete local folder then synchronize
        time.sleep(OS_STAT_MTIME_RESOLUTION)
        local.delete('/Local folder')

        syn.loop(delay=0.1, max_loops=1)
        self.assertFalse(remote.exists('/Local folder'))
        # Wait for async completion as recursive deletion of children is done
        # by the BulkLifeCycleChangeListener which is asynchronous
        self.wait()
        self.assertFalse(remote.exists('/Local folder/Local file 1.odt'))
        self.assertFalse(remote.exists('/Local folder/Local file 2.odt'))

        # Dispose dedicated Controller instantiated for this test
        ctl.dispose()
Exemple #56
0
    def test_move_sync_root_child_to_user_workspace(self):
        """See https://jira.nuxeo.com/browse/NXP-14870"""
        admin_remote_client = self.root_remote_client
        user1_workspace_uid = None
        try:
            # Get remote  and local clients
            remote_user1 = RemoteDocumentClientForTests(
                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_user2 = RemoteDocumentClientForTests(
                self.nuxeo_url, self.user_2, u'nxdrive-test-device-2',
                self.version, password=self.password_2,
                upload_tmp_dir=self.upload_tmp_dir)
            local_user2 = LocalClient(self.local_nxdrive_folder_2)

            # Make sure personal workspace is created for user1 and fetch its uid
            user1_workspace_uid = remote_user1.make_file_in_user_workspace('File in user workspace',
                                                                           filename='UWFile.txt')['parentRef']

            # As user1 register personal workspace as a sync root
            remote_user1.register_as_root(user1_workspace_uid)

            # As user1 create a parent folder in user1's personal workspace
            parent_folder_uid = remote_user1.make_folder(user1_workspace_uid, 'Parent')

            # As user1 grant Everything permission to user2 on parent folder
            op_input = "doc:" + parent_folder_uid
            admin_remote_client.execute("Document.SetACE", op_input=op_input, user=self.user_2,
                                        permission="Everything", grant="true")

            # As user1 create a child folder in parent folder
            child_folder_uid = remote_user1.make_folder(parent_folder_uid, 'Child')

            # As user2 register parent folder as a sync root
            remote_user2.register_as_root(parent_folder_uid)
            remote_user2.unregister_as_root(self.workspace)
            # Start engine for user2
            self.engine_2.start()

            # Wait for synchronization
            self.wait_sync(wait_for_async=True, wait_for_engine_1=False, wait_for_engine_2=True)

            # Check locally synchronized content
            self.assertEqual(len(local_user2.get_children_info('/')), 1)
            self.assertTrue(local_user2.exists('/Parent'))
            self.assertTrue(local_user2.exists('/Parent/Child'))

            # As user1 move child folder to user1's personal workspace
            remote_user1.move(child_folder_uid, user1_workspace_uid)

            # Wait for synchronization
            self.wait_sync(wait_for_async=True, wait_for_engine_1=False, wait_for_engine_2=True)

            # Check locally synchronized content
            self.assertFalse(local_user2.exists('/Parent/Child'))

        finally:
            # Cleanup user1 personal workspace
            if user1_workspace_uid is not None and admin_remote_client.exists(user1_workspace_uid):
                admin_remote_client.delete(user1_workspace_uid,
                                           use_trash=False)