コード例 #1
0
def test_synchronization_loop():
    ctl.bind_server(LOCAL_NXDRIVE_FOLDER, NUXEO_URL, USER, PASSWORD)
    ctl.bind_root(LOCAL_NXDRIVE_FOLDER, TEST_WORKSPACE)
    expected_folder = os.path.join(LOCAL_NXDRIVE_FOLDER, TEST_WORKSPACE_TITLE)

    assert_equal(ctl.list_pending(), [])
    assert_equal(ctl.synchronize(), 0)

    # Let's create some document on the client and the server
    local = LocalClient(expected_folder)
    local.make_folder("/", "Folder 3")
    make_server_tree()

    # Run the full synchronization loop a limited amount of times
    ctl.loop(full_local_scan=True, full_remote_scan=True, delay=0.010, max_loops=3, fault_tolerant=False)

    # All is synchronized
    assert_equal(len(ctl.list_pending()), 0)
    assert_equal(
        ctl.children_states(expected_folder),
        [
            (u"/File 5.txt", u"synchronized"),
            (u"/Folder 1", u"synchronized"),
            (u"/Folder 2", u"synchronized"),
            (u"/Folder 3", u"synchronized"),
        ],
    )
    def test_synchronization_loop(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
        expected_folder = os.path.join(self.local_nxdrive_folder_1,
                                       self.workspace_title)

        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(syn.synchronize(), 0)

        # Perform first scan and sync
        syn.loop(delay=0, max_loops=3)
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(syn.synchronize(), 0)

        # Let's create some document on the client and the server
        local = LocalClient(expected_folder)
        local.make_folder('/', 'Folder 3')
        self.make_server_tree()
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        self.wait()

        # Run the full synchronization loop a limited amount of times
        syn.loop(delay=0.010, max_loops=3)

        # All is synchronized
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(ctl.children_states(expected_folder), [
            (u'File 5.txt', u'synchronized'),
            (u'Folder 1', u'synchronized'),
            (u'Folder 2', u'synchronized'),
            (u'Folder 3', u'synchronized'),
        ])
コード例 #3
0
    def test_local_replace(self):
        local = LocalClient(self.local_test_folder_1)
        remote = self.remote_document_client_1
        self.engine_1.start()
        self.wait_sync(wait_for_async=True)

        # Create 2 files with the same name but different content
        # in separate folders
        local.make_file('/', 'test.odt', 'Some content.')
        local.make_folder('/', 'folder')
        copyfile(os.path.join(self.local_test_folder_1, 'test.odt'),
                 os.path.join(self.local_test_folder_1, 'folder', 'test.odt'))
        local.update_content('/folder/test.odt', 'Updated content.')

        # Copy the newest file to the root workspace and synchronize it
        sync_root = os.path.join(self.local_nxdrive_folder_1,
                                 self.workspace_title)
        test_file = os.path.join(self.local_test_folder_1, 'folder',
                                 'test.odt')
        copyfile(test_file, os.path.join(sync_root, 'test.odt'))
        self.wait_sync()
        self.assertTrue(remote.exists('/test.odt'))
        self.assertEquals(remote.get_content('/test.odt'), 'Updated content.')

        # Copy the oldest file to the root workspace and synchronize it.
        # First wait a bit for file time stamps to increase enough.
        time.sleep(OS_STAT_MTIME_RESOLUTION)
        copyfile(os.path.join(self.local_test_folder_1, 'test.odt'),
                 os.path.join(sync_root, 'test.odt'))
        self.wait_sync()
        self.assertTrue(remote.exists('/test.odt'))
        self.assertEquals(remote.get_content('/test.odt'), 'Some content.')
コード例 #4
0
ファイル: test_windows.py プロジェクト: jresende/nuxeo-drive
    def test_local_replace(self):
        local = LocalClient(self.local_test_folder_1)
        remote = self.remote_document_client_1
        self.engine_1.start()
        self.wait_sync(wait_for_async=True)

        # Create 2 files with the same name but different content
        # in separate folders
        local.make_file('/', 'test.odt', 'Some content.')
        local.make_folder('/', 'folder')
        shutil.copyfile(
            os.path.join(self.local_test_folder_1, 'test.odt'),
            os.path.join(self.local_test_folder_1, 'folder', 'test.odt'))
        local.update_content('/folder/test.odt', 'Updated content.')

        # Copy the newest file to the root workspace and synchronize it
        sync_root = os.path.join(self.local_nxdrive_folder_1,
                                 self.workspace_title)
        test_file = os.path.join(self.local_test_folder_1, 'folder',
                                 'test.odt')
        shutil.copyfile(test_file, os.path.join(sync_root, 'test.odt'))
        self.wait_sync()
        self.assertTrue(remote.exists('/test.odt'))
        self.assertEqual(remote.get_content('/test.odt'), 'Updated content.')

        # Copy the oldest file to the root workspace and synchronize it.
        # First wait a bit for file time stamps to increase enough.
        time.sleep(OS_STAT_MTIME_RESOLUTION)
        shutil.copyfile(os.path.join(self.local_test_folder_1, 'test.odt'),
                        os.path.join(sync_root, 'test.odt'))
        self.wait_sync()
        self.assertTrue(remote.exists('/test.odt'))
        self.assertEqual(remote.get_content('/test.odt'), 'Some content.')
    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'))
コード例 #6
0
    def test_synchronization_modification_on_created_file(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")
        ctl = self.controller_1
        # Regression test: a file is created locally, then modification is
        # detected before first upload
        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
        expected_folder = os.path.join(self.local_nxdrive_folder_1,
                                       self.workspace_title)
        self.assertEquals(ctl.list_pending(), [])

        self.wait()
        syn.loop(delay=0.010, max_loops=1)

        # Let's create some document on the client and the server
        local = LocalClient(expected_folder)
        local.make_folder('/', 'Folder')
        local.make_file('/Folder', 'File.txt', content='Some content.')

        # First local scan (assuming the network is offline):
        syn.scan_local(self.local_nxdrive_folder_1)
        self.assertEquals(len(ctl.list_pending()), 2)
        self.assertEquals(ctl.children_states(expected_folder), [
            (u'Folder', 'children_modified'),
        ])
        self.assertEquals(ctl.children_states(expected_folder + '/Folder'), [
            (u'File.txt', u'unknown'),
        ])

        # Wait a bit for file time stamps to increase enough: on most OS
        # the file modification time resolution is 1s
        time.sleep(OS_STAT_MTIME_RESOLUTION)

        # Let's modify it offline and rescan locally
        local.update_content('/Folder/File.txt', content='Some content.')
        syn.scan_local(self.local_nxdrive_folder_1)
        self.assertEquals(len(ctl.list_pending()), 2)
        self.assertEquals(ctl.children_states(expected_folder), [
            (u'Folder', u'children_modified'),
        ])
        self.assertEquals(ctl.children_states(expected_folder + '/Folder'), [
            (u'File.txt', u'locally_modified'),
        ])

        # Assume the computer is back online, the synchronization should occur
        # as if the document was just created and not trigger an update
        self.wait()
        syn.loop(delay=0.010, max_loops=1)
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(ctl.children_states(expected_folder), [
            (u'Folder', u'synchronized'),
        ])
        self.assertEquals(ctl.children_states(expected_folder + '/Folder'), [
            (u'File.txt', u'synchronized'),
        ])
コード例 #7
0
    def test_create_content_in_readonly_area(self):
        # XXX: implement permission checks on the client and leverage this
        # info in the synchronizer to not try to sync unsyncable stuff
        # and avoid logging errors in that case (just debug info)

        # Let's bind a the server but no root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        syn = ctl.synchronizer
        self.wait()

        syn.loop(delay=0.1, max_loops=1)
        self.assertEquals(ctl.list_pending(), [])

        # Let's create a subfolder of the main readonly folder
        local = LocalClient(self.local_nxdrive_folder_1)
        local.make_folder('/', 'Folder 3')
        local.make_file('/Folder 3', 'File 1.txt', content='Some content.')
        local.make_folder('/Folder 3', 'Sub Folder 1')
        local.make_file('/Folder 3/Sub Folder 1', 'File 2.txt',
                        content='Some other content.')
        syn.loop(delay=0.1, max_loops=1)

        # Pairs have been created for the subfolder and its content,
        # marked as synchronized
        self.assertEquals(self.get_all_states(), [
            (u'/', u'synchronized', u'synchronized'),
            (u'/Folder 3', u'synchronized', u'synchronized'),
            (u'/Folder 3/File 1.txt', u'synchronized', u'synchronized'),
            (u'/Folder 3/Sub Folder 1', u'synchronized', u'synchronized'),
            (u'/Folder 3/Sub Folder 1/File 2.txt',
             u'synchronized', u'synchronized'),
        ])
        self.assertEquals(ctl.list_pending(), [])

        # Let's create a file in the main readonly folder
        local.make_file('/', 'A file in a readonly folder.txt',
            content='Some Content')
        syn.loop(delay=0.1, max_loops=1)

        # A pair has been created, marked as synchronized
        self.assertEquals(self.get_all_states(), [
            (u'/', u'synchronized', u'synchronized'),
            (u'/A file in a readonly folder.txt',
             u'synchronized', u'synchronized'),
            (u'/Folder 3', u'synchronized', u'synchronized'),
            (u'/Folder 3/File 1.txt', u'synchronized', u'synchronized'),
            (u'/Folder 3/Sub Folder 1', u'synchronized', u'synchronized'),
            (u'/Folder 3/Sub Folder 1/File 2.txt',
             u'synchronized', u'synchronized'),
        ])
        self.assertEquals(len(ctl.list_pending(ignore_in_error=300)), 0)
コード例 #8
0
    def test_synchronization_offline(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)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)
        syn = ctl.synchronizer
        expected_folder = os.path.join(self.local_nxdrive_folder_1,
                                       self.workspace_title)

        # Bound root but nothing is synced yet
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(syn.synchronize(), 0)

        # Perform first scan and sync
        syn.loop(delay=0, max_loops=3)
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(syn.synchronize(), 0)

        # Let's create some document on the client and the server
        local = LocalClient(expected_folder)
        local.make_folder('/', 'Folder 3')
        self.make_server_tree()
        self.wait()

        # Find various ways to simulate a network or server failure
        errors = [
            urllib2.URLError('Test error'),
            socket.error('Test error'),
            httplib.HTTPException('Test error'),
        ]
        for error in errors:
            ctl.make_remote_raise(error)
            # Synchronization does not occur but does not fail either
            syn.loop(delay=0, max_loops=1)
            # Only the local change has been detected
            self.assertEquals(len(ctl.list_pending()), 1)

        # Reenable network
        ctl.make_remote_raise(None)
        syn.loop(delay=0, max_loops=2)

        # All is synchronized
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(ctl.children_states(expected_folder), [
            (u'File 5.txt', u'synchronized'),
            (u'Folder 1', u'synchronized'),
            (u'Folder 2', u'synchronized'),
            (u'Folder 3', u'synchronized'),
        ])
コード例 #9
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'))
コード例 #10
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'))
コード例 #11
0
    def test_local_replace(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
        self.wait_audit_change_finder_if_needed()
        self.wait()
        syn = ctl.synchronizer
        syn.loop(delay=0.1, max_loops=1)

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

        # Create 2 files with the same name but different content
        # in separate folders
        local.make_file('/', 'test.odt', 'Some content.')
        local.make_folder('/', 'folder')
        copyfile(os.path.join(self.local_test_folder_1, 'test.odt'),
                 os.path.join(self.local_test_folder_1, 'folder', 'test.odt'))
        local.update_content('/folder/test.odt', 'Updated content.')

        # Copy the newest file to the root workspace and synchronize it
        sync_root = os.path.join(self.local_nxdrive_folder_1,
                                 self.workspace_title)
        test_file = os.path.join(self.local_test_folder_1, 'folder',
                                 'test.odt')
        copyfile(test_file, os.path.join(sync_root, 'test.odt'))
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(remote.exists('/test.odt'))
        self.assertEquals(remote.get_content('/test.odt'), 'Updated content.')

        # Copy the oldest file to the root workspace and synchronize it.
        # First wait a bit for file time stamps to increase enough.
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        copyfile(os.path.join(self.local_test_folder_1, 'test.odt'),
                 os.path.join(sync_root, 'test.odt'))
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(remote.exists('/test.odt'))
        self.assertEquals(remote.get_content('/test.odt'), 'Some content.')
コード例 #12
0
    def test_local_replace(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(self.local_test_folder_1)
        remote = self.remote_document_client_1

        # Create 2 files with the same name but different content
        # in separate folders
        local.make_file('/', 'test.odt', 'Some content.')
        local.make_folder('/', 'folder')
        copyfile(os.path.join(self.local_test_folder_1, 'test.odt'),
                 os.path.join(self.local_test_folder_1, 'folder', 'test.odt'))
        local.update_content('/folder/test.odt', 'Updated content.')

        # Copy the newest file to the root workspace and synchronize it
        sync_root = os.path.join(self.local_nxdrive_folder_1,
                                 self.workspace_title)
        copyfile(os.path.join(self.local_test_folder_1, 'folder', 'test.odt'),
                 os.path.join(sync_root, 'test.odt'))
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(remote.exists('/test.odt'))
        self.assertEquals(remote.get_content('/test.odt'), 'Updated content.')

        # Copy the oldest file to the root workspace and synchronize it.
        # First wait a bit for file time stamps to increase enough.
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        copyfile(os.path.join(self.local_test_folder_1, 'test.odt'),
                 os.path.join(sync_root, 'test.odt'))
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(remote.exists('/test.odt'))
        self.assertEquals(remote.get_content('/test.odt'), 'Some content.')
コード例 #13
0
def setup_temp_folder():
    global lcclient, LOCAL_TEST_FOLDER, TEST_WORKSPACE
    build_workspace = os.environ.get('WORKSPACE')
    tmpdir = None
    if build_workspace is not None:
        tmpdir = os.path.join(build_workspace, "tmp")
        if not os.path.isdir(tmpdir):
            os.makedirs(tmpdir)
    LOCAL_TEST_FOLDER = tempfile.mkdtemp(u'-nuxeo-drive-tests', dir=tmpdir)
    lcclient = LocalClient(LOCAL_TEST_FOLDER)
    TEST_WORKSPACE = lcclient.make_folder(u'/', u'Some Workspace')
コード例 #14
0
def setup_temp_folder():
    global lcclient, LOCAL_TEST_FOLDER, TEST_WORKSPACE
    build_workspace = os.environ.get('WORKSPACE')
    tmpdir = None
    if build_workspace is not None:
        tmpdir = os.path.join(build_workspace, "tmp")
        if not os.path.isdir(tmpdir):
            os.makedirs(tmpdir)
    LOCAL_TEST_FOLDER = tempfile.mkdtemp(u'-nuxeo-drive-tests', dir=tmpdir)
    lcclient = LocalClient(LOCAL_TEST_FOLDER)
    TEST_WORKSPACE = lcclient.make_folder(u'/', u'Some Workspace')
コード例 #15
0
    def test_local_replace(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(self.local_test_folder_1)
        remote = self.remote_document_client_1

        # Create 2 files with the same name but different content
        # in separate folders
        local.make_file("/", "test.odt", "Some content.")
        local.make_folder("/", "folder")
        copyfile(
            os.path.join(self.local_test_folder_1, "test.odt"),
            os.path.join(self.local_test_folder_1, "folder", "test.odt"),
        )
        local.update_content("/folder/test.odt", "Updated content.")

        # Copy the newest file to the root workspace and synchronize it
        sync_root = os.path.join(self.local_nxdrive_folder_1, self.workspace_title)
        copyfile(os.path.join(self.local_test_folder_1, "folder", "test.odt"), os.path.join(sync_root, "test.odt"))
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(remote.exists("/test.odt"))
        self.assertEquals(remote.get_content("/test.odt"), "Updated content.")

        # Copy the oldest file to the root workspace and synchronize it.
        # First wait a bit for file time stamps to increase enough.
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        copyfile(os.path.join(self.local_test_folder_1, "test.odt"), os.path.join(sync_root, "test.odt"))
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(remote.exists("/test.odt"))
        self.assertEquals(remote.get_content("/test.odt"), "Some content.")
コード例 #16
0
def test_synchronization_offline():
    ctl.bind_server(LOCAL_NXDRIVE_FOLDER, NUXEO_URL, USER, PASSWORD)
    ctl.bind_root(LOCAL_NXDRIVE_FOLDER, TEST_WORKSPACE)
    expected_folder = os.path.join(LOCAL_NXDRIVE_FOLDER, TEST_WORKSPACE_TITLE)

    assert_equal(ctl.list_pending(), [])
    assert_equal(ctl.synchronize(), 0)

    # Let's create some document on the client and the server
    local = LocalClient(expected_folder)
    local.make_folder("/", "Folder 3")
    make_server_tree()

    # Find various ways to similate network or server failure
    errors = [urllib2.URLError("Test error"), socket.error("Test error"), httplib.HTTPException("Test error")]
    for error in errors:
        ctl.make_remote_raise(error)
        # Synchronization does not occur but does not fail either
        ctl.loop(full_local_scan=True, full_remote_scan=True, delay=0, max_loops=1, fault_tolerant=False)
        # Only the local change has been detected
        assert_equal(len(ctl.list_pending()), 1)

    # Reenable network
    ctl.make_remote_raise(None)
    ctl.loop(full_local_scan=True, full_remote_scan=True, delay=0, max_loops=1, fault_tolerant=False)

    # All is synchronized
    assert_equal(len(ctl.list_pending()), 0)
    assert_equal(
        ctl.children_states(expected_folder),
        [
            (u"/File 5.txt", u"synchronized"),
            (u"/Folder 1", u"synchronized"),
            (u"/Folder 2", u"synchronized"),
            (u"/Folder 3", u"synchronized"),
        ],
    )
コード例 #17
0
def test_synchronization_modification_on_created_file():
    # Regression test: a file is created locally, then modification is detected
    # before first upload
    ctl.bind_server(LOCAL_NXDRIVE_FOLDER, NUXEO_URL, USER, PASSWORD)
    ctl.bind_root(LOCAL_NXDRIVE_FOLDER, TEST_WORKSPACE)
    expected_folder = os.path.join(LOCAL_NXDRIVE_FOLDER, TEST_WORKSPACE_TITLE)
    assert_equal(ctl.list_pending(), [])

    # Let's create some document on the client and the server
    local = LocalClient(expected_folder)
    local.make_folder("/", "Folder")
    local.make_file("/Folder", "File.txt", content="Some content.")

    # First local scan (assuming the network is offline):
    ctl.scan_local(expected_folder)
    assert_equal(len(ctl.list_pending()), 2)
    assert_equal(ctl.children_states(expected_folder), [(u"/Folder", "children_modified")])
    assert_equal(ctl.children_states(expected_folder + "/Folder"), [(u"/Folder/File.txt", u"unknown")])

    # Wait a bit for file time stamps to increase enough: on most OS the file
    # modification time resolution is 1s
    time.sleep(1.0)

    # Let's modify it offline and rescan locally
    local.update_content("/Folder/File.txt", content="Some content.")
    ctl.scan_local(expected_folder)
    assert_equal(len(ctl.list_pending()), 2)
    assert_equal(ctl.children_states(expected_folder), [(u"/Folder", u"children_modified")])
    assert_equal(ctl.children_states(expected_folder + "/Folder"), [(u"/Folder/File.txt", u"locally_modified")])

    # Assume the computer is back online, the synchronization should occur as if
    # the document was just created and not trigger an update
    ctl.loop(full_local_scan=True, full_remote_scan=True, delay=0.010, max_loops=1, fault_tolerant=False)
    assert_equal(len(ctl.list_pending()), 0)
    assert_equal(ctl.children_states(expected_folder), [(u"/Folder", u"synchronized")])
    assert_equal(ctl.children_states(expected_folder + "/Folder"), [(u"/Folder/File.txt", u"synchronized")])
コード例 #18
0
    def test_create_content_in_readonly_area(self):
        # XXX: implement permission checks on the client and leverage this
        # info in the synchronizer to not try to sync unsyncable stuff
        # and avoid logging errors in that case (just debug info)

        # Let's bind a the server but no root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        syn = ctl.synchronizer
        self.wait()

        syn.loop(delay=0.1, max_loops=1)
        self.assertEquals(ctl.list_pending(), [])

        # Let's create a subfolder of the main readonly folder
        local = LocalClient(self.local_nxdrive_folder_1)
        local.make_folder('/', 'Folder 3')
        syn.loop(delay=0.1, max_loops=1)

        # The remote folder has not been created
        self.assertEquals(self.get_all_states(), [
            (u'/',
             u'synchronized', u'synchronized'),
            (u'/Folder 3',
             u'created', u'unknown'),
        ])
        self.assertEquals(len(ctl.list_pending()), 1)
        pending = ctl.list_pending()[0]
        self.assertEquals(pending.local_name, 'Folder 3')

        # The folder is not synchronized as this folder was black
        # listed for 5 minutes
        self.assertEquals(len(ctl.list_pending(ignore_in_error=300)), 0)
        syn.loop(delay=0.1, max_loops=1)
        self.assertEquals(len(ctl.list_pending(ignore_in_error=300)), 0)
    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'))
コード例 #20
0
    def test_create_content_in_readonly_area(self):
        self.engine_1.start()
        self.wait_sync(wait_for_async=True)

        # Let's create a subfolder of the main readonly folder
        local = LocalClient(self.local_nxdrive_folder_1)
        local.make_folder('/', 'Folder 3')
        local.make_file('/Folder 3', 'File 1.txt', content='Some content.')
        local.make_folder('/Folder 3', 'Sub Folder 1')
        local.make_file('/Folder 3/Sub Folder 1',
                        'File 2.txt',
                        content='Some other content.')
        self.wait_sync()

        # States have been created for the subfolder and its content,
        # subfolder is marked as unsynchronized
        states = self.engine_1.get_dao().get_states_from_partial_local('/')
        self.assertEquals(len(states), 6)
        sorted_states = sorted(states, key=lambda x: x.local_path)
        self.assertEquals(sorted_states[0].local_name, '')
        self.assertEquals(sorted_states[0].pair_state, 'synchronized')
        self.assertEquals(sorted_states[1].local_name, 'Folder 3')
        self.assertEquals(sorted_states[1].pair_state, 'unsynchronized')
        self.assertEquals(sorted_states[2].local_name, 'File 1.txt')
        self.assertTrue(sorted_states[2].pair_state in ('locally_created',
                                                        'unsynchronized'))
        self.assertEquals(sorted_states[3].local_name, 'Sub Folder 1')
        self.assertTrue(sorted_states[3].pair_state in ('locally_created',
                                                        'unsynchronized'))
        self.assertEquals(sorted_states[4].local_name, 'File 2.txt')
        self.assertTrue(sorted_states[4].pair_state in ('locally_created',
                                                        'unsynchronized'))
        self.assertEquals(sorted_states[5].local_name, self.workspace_title)
        self.assertEquals(sorted_states[5].pair_state, 'synchronized')

        # Let's create a file in the main readonly folder
        local.make_file('/',
                        'A file in a readonly folder.txt',
                        content='Some Content')
        self.wait_sync()

        # A state has been created, marked as unsynchronized
        # Other states are unchanged
        states = self.engine_1.get_dao().get_states_from_partial_local('/')
        self.assertEquals(len(states), 7)
        sorted_states = sorted(states, key=lambda x: x.local_path)
        self.assertEquals(sorted_states[0].local_name, '')
        self.assertEquals(sorted_states[0].pair_state, 'synchronized')
        self.assertEquals(sorted_states[1].local_name,
                          'A file in a readonly folder.txt')
        self.assertEquals(sorted_states[1].pair_state, 'unsynchronized')
        self.assertEquals(sorted_states[2].local_name, 'Folder 3')
        self.assertEquals(sorted_states[2].pair_state, 'unsynchronized')
        self.assertEquals(sorted_states[3].local_name, 'File 1.txt')
        self.assertTrue(sorted_states[3].pair_state in ('locally_created',
                                                        'unsynchronized'))
        self.assertEquals(sorted_states[4].local_name, 'Sub Folder 1')
        self.assertTrue(sorted_states[4].pair_state in ('locally_created',
                                                        'unsynchronized'))
        self.assertEquals(sorted_states[5].local_name, 'File 2.txt')
        self.assertTrue(sorted_states[5].pair_state in ('locally_created',
                                                        'unsynchronized'))
        self.assertEquals(sorted_states[6].local_name, self.workspace_title)
        self.assertEquals(sorted_states[6].pair_state, 'synchronized')

        # Let's create a file and a folder in a folder on which the Write
        # permission has been removed. Thanks to NXP-13119, this permission
        # change will be detected server-side, thus fetched by the client
        # in the remote change summary, and the remote_can_create_child flag
        # on which the synchronizer relies to check if creation is allowed
        # will be set to False and no attempt to create the remote file
        # will be made.
        # States will be marked as unsynchronized.

        # Create local folder and synchronize it remotely
        local = self.local_client_1
        local.make_folder(u'/', u'Readonly folder')
        self.wait_sync()

        remote = self.remote_document_client_1
        self.assertTrue(remote.exists(u'/Readonly folder'))

        # Check remote_can_create_child flag in pair state
        readonly_folder_state = self.engine_1.get_dao().get_state_from_local(
            '/' + self.workspace_title + '/Readonly folder')
        self.assertTrue(readonly_folder_state.remote_can_create_child)

        # Wait again for synchronization to detect remote folder creation triggered
        # by last synchronization and make sure we get a clean state at
        # next change summary
        self.wait_sync(wait_for_async=True)
        readonly_folder_state = self.engine_1.get_dao().get_state_from_local(
            '/' + self.workspace_title + '/Readonly folder')
        self.assertTrue(readonly_folder_state.remote_can_create_child)

        # Set remote folder as readonly for test user
        readonly_folder_path = TEST_WORKSPACE_PATH + u'/Readonly folder'
        op_input = "doc:" + readonly_folder_path
        self.root_remote_client.execute("Document.SetACE",
                                        op_input=op_input,
                                        user=self.user_1,
                                        permission="Read")
        self.root_remote_client.block_inheritance(readonly_folder_path,
                                                  overwrite=False)

        # Wait to make sure permission change is detected.
        self.wait_sync(wait_for_async=True)
        # Re-fetch folder state and check remote_can_create_child flag has been updated
        readonly_folder_state = self.engine_1.get_dao().get_state_from_local(
            '/' + self.workspace_title + '/Readonly folder')
        self.assertFalse(readonly_folder_state.remote_can_create_child)

        # Try to create a local file and folder in the readonly folder,
        # they should not be created remotely and be marked as unsynchronized.
        local.make_file(u'/Readonly folder', u'File in readonly folder',
                        u"File content")
        local.make_folder(u'/Readonly folder', u'Folder in readonly folder')
        self.wait_sync()
        self.assertFalse(
            remote.exists(u'/Readonly folder/File in readonly folder'))
        self.assertFalse(
            remote.exists(u'/Readonly folder/Folder in readonly folder'))

        states = self.engine_1.get_dao().get_states_from_partial_local(
            '/' + self.workspace_title + '/Readonly folder')
        self.assertEquals(len(states), 3)
        sorted_states = sorted(states, key=lambda x: x.local_path)
        self.assertEquals(sorted_states[0].local_name, 'Readonly folder')
        self.assertEquals(sorted_states[0].pair_state, 'synchronized')
        self.assertEquals(sorted_states[1].local_name,
                          'File in readonly folder')
        self.assertEquals(sorted_states[1].pair_state, 'unsynchronized')
        self.assertEquals(sorted_states[2].local_name,
                          'Folder in readonly folder')
        self.assertEquals(sorted_states[2].pair_state, 'unsynchronized')
コード例 #21
0
    def test_create_content_in_readonly_area(self):
        # TODO: ensure that a Write permission change is fetched by the client
        # in the remote change summary to update the remote_can_create_child
        # flag on which the synchronizer relies to check if creation
        # is allowed.
        # This way it won't try to sync unsyncable stuff and will avoid
        # logging errors in that case (just debug info)
        # See https://jira.nuxeo.com/browse/NXP-11159

        # Let's bind a the server but no root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        syn = ctl.synchronizer
        self.wait()

        syn.loop(delay=0.1, max_loops=1)
        self.assertEquals(ctl.list_pending(), [])

        # Let's create a subfolder of the main readonly folder
        local = LocalClient(self.local_nxdrive_folder_1)
        local.make_folder('/', 'Folder 3')
        local.make_file('/Folder 3', 'File 1.txt', content='Some content.')
        local.make_folder('/Folder 3', 'Sub Folder 1')
        local.make_file('/Folder 3/Sub Folder 1', 'File 2.txt',
                        content='Some other content.')
        syn.loop(delay=0.1, max_loops=1)

        # Pairs have been created for the subfolder and its content,
        # marked as synchronized
        self.assertEquals(self.get_all_states(), [
            (u'/', u'synchronized', u'synchronized'),
            (u'/Folder 3', u'synchronized', u'synchronized'),
            (u'/Folder 3/File 1.txt', u'synchronized', u'synchronized'),
            (u'/Folder 3/Sub Folder 1', u'synchronized', u'synchronized'),
            (u'/Folder 3/Sub Folder 1/File 2.txt',
             u'synchronized', u'synchronized'),
        ])
        self.assertEquals(ctl.list_pending(), [])

        # Let's create a file in the main readonly folder
        local.make_file('/', 'A file in a readonly folder.txt',
            content='Some Content')
        syn.loop(delay=0.1, max_loops=1)

        # A pair has been created, marked as synchronized
        self.assertEquals(self.get_all_states(), [
            (u'/', u'synchronized', u'synchronized'),
            (u'/A file in a readonly folder.txt',
             u'synchronized', u'synchronized'),
            (u'/Folder 3', u'synchronized', u'synchronized'),
            (u'/Folder 3/File 1.txt', u'synchronized', u'synchronized'),
            (u'/Folder 3/Sub Folder 1', u'synchronized', u'synchronized'),
            (u'/Folder 3/Sub Folder 1/File 2.txt',
             u'synchronized', u'synchronized'),
        ])
        self.assertEquals(len(ctl.list_pending(ignore_in_error=300)), 0)

        # Let's create a file and a folder in a folder on which the Write
        # permission has been removed. Waiting for NXP-11159, this permission
        # change will not be detected server-side, thus nor by the client,
        # so an attempt to create the remote file will be made and the server
        # will return a 403 status code. In this case the client should only
        # blacklist the file.

        # Bind root workspace, create local folder and synchronize it remotely
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0.1, max_loops=1)

        local = LocalClient(
            os.path.join(self.local_nxdrive_folder_1, self.workspace_title))
        local.make_folder(u'/', u'Readonly folder')
        syn.loop(delay=0.1, max_loops=1)

        remote = self.remote_document_client_1
        self.assertTrue(remote.exists(u'/Readonly folder'))

        # Check remote_can_create_child flag in pair state
        session = ctl.get_session()
        readonly_folder_state = session.query(LastKnownState).filter_by(
            local_name=u'Readonly folder').one()
        self.assertTrue(readonly_folder_state.remote_can_create_child)

        # Make one sync loop to detect remote folder creation triggered
        # by last synchronization and make sure we get a clean state at
        # next change summary
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(readonly_folder_state.remote_can_create_child)

        # Set remote folder as readonly for test user
        readonly_folder_path = self.TEST_WORKSPACE_PATH + u'/Readonly folder'
        op_input = "doc:" + readonly_folder_path
        self.root_remote_client.execute("Document.SetACE",
            op_input=op_input,
            user="******",
            permission="Write",
            grant="false")

        # Wait to make sure permission change is detected, if such detection
        # is implemented server-side.
        # Waiting for NXP-11159 it is not, so the remote_can_create_child flag
        # should not be updated.
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        syn.loop(delay=0.1, max_loops=1)
        self.assertTrue(readonly_folder_state.remote_can_create_child)

        # Try to create a local file and folder in the readonly folder,
        # they should not be created remotely and be blacklisted
        local.make_file(u'/Readonly folder', u'File in readonly folder',
                        u"File content")
        local.make_folder(u'/Readonly folder', u'Folder in readonly folder')
        syn.loop(delay=0.1, max_loops=1)
        self.assertFalse(remote.exists(
            u'/Readonly folder/File in readonly folder'))
        self.assertFalse(remote.exists(
            u'/Readonly folder/Folder in readonly folder'))
        readonly_file_state = session.query(LastKnownState).filter_by(
            local_name=u'File in readonly folder').one()
        readonly_sub_folder_state = session.query(LastKnownState).filter_by(
            local_name=u'Folder in readonly folder').one()
        self.assertIsNotNone(readonly_file_state.last_sync_error_date)
        self.assertIsNotNone(readonly_sub_folder_state.last_sync_error_date)
コード例 #22
0
    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')
コード例 #23
0
    def test_binding_synchronization_empty_start(self):
        ctl = self.controller_1
        remote_client = self.remote_document_client_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
        expected_folder = os.path.join(self.local_nxdrive_folder_1,
                                       self.workspace_title)

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

        # Let's create some document on the server
        self.make_server_tree()

        # By default nothing is detected
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(ctl.children_states(expected_folder), [])

        # Let's scan manually
        syn.scan_remote(self.local_nxdrive_folder_1)

        # Changes on the remote server have been detected...
        self.assertEquals(len(ctl.list_pending()), 12)

        # ...but nothing is yet visible locally as those files don't exist
        # there yet.
        self.assertEquals(ctl.children_states(expected_folder), [])

        # Let's perform the synchronization
        self.assertEquals(syn.synchronize(limit=100), 12)

        # We should now be fully synchronized
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(ctl.children_states(expected_folder), [
            (u'File 5.txt', u'synchronized'),
            (u'Folder 1', u'synchronized'),
            (u'Folder 2', u'synchronized'),
        ])
        local_client = LocalClient(self.local_nxdrive_folder_1)
        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."))

        # Wait a bit for file time stamps to increase enough: on OSX HFS+ the
        # file modification time resolution is 1s for instance
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)

        # Let do some local and remote changes concurrently
        local_client.delete('/Nuxeo Drive Test Workspace/File 5.txt')
        local_client.update_content(
            '/Nuxeo Drive Test Workspace/Folder 1/File 1.txt', 'aaaa')

        # The remote client use in this test is handling paths relative to
        # the 'Nuxeo Drive Test Workspace'
        remote_client.update_content('/Folder 1/Folder 1.1/File 2.txt',
                                     'bbbb')
        remote_client.delete('/Folder 2')
        f3 = remote_client.make_folder(self.workspace, 'Folder 3')
        remote_client.make_file(f3, 'File 6.txt', content='ffff')
        local_client.make_folder('/Nuxeo Drive Test Workspace', 'Folder 4')

        # Rescan
        syn.scan_local(self.local_nxdrive_folder_1)
        syn.scan_remote(self.local_nxdrive_folder_1)
        self.assertEquals(ctl.children_states(expected_folder), [
            (u'File 5.txt', u'locally_deleted'),
            (u'Folder 1', u'children_modified'),
            (u'Folder 2', u'children_modified'),  # what do we want for this?
            # Folder 3 is not yet visible has not sync has happen to give it a
            # local path yet
            (u'Folder 4', u'unknown'),
        ])
        # The information on the remote state of Folder 3 has been stored in
        # the database though
        session = ctl.get_session()
        f3_state = session.query(LastKnownState).filter_by(
            remote_name='Folder 3').one()
        self.assertEquals(f3_state.local_path, None)

        states = ctl.children_states(expected_folder + '/Folder 1')
        expected_states = [
            (u'File 1.txt', 'locally_modified'),
            (u'Folder 1.1', 'children_modified'),
            (u'Folder 1.2', 'synchronized'),
        ]
        self.assertEquals(states, expected_states)
        states = ctl.children_states(expected_folder + '/Folder 1/Folder 1.1')
        expected_states = [
            (u'File 2.txt', u'remotely_modified'),
        ]
        self.assertEquals(states, expected_states)
        states = ctl.children_states(expected_folder + '/Folder 2')
        expected_states = [
            (u'Duplicated File.txt', u'remotely_deleted'),
            (u'Duplicated File__1.txt', u'remotely_deleted'),
            (u'File 4.txt', u'remotely_deleted'),
        ]
        self.assertEquals(states, expected_states)

        # Perform synchronization: deleted folder content are not
        # counted in the summary
        self.assertEquals(syn.synchronize(limit=100), 7)

        # We should now be fully synchronized again
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(ctl.children_states(expected_folder), [
            (u'Folder 1', 'synchronized'),
            (u'Folder 3', 'synchronized'),
            (u'Folder 4', 'synchronized'),
        ])
        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)
        local = LocalClient(expected_folder)
        self.assertEquals(local.get_content(
            '/Folder 1/File 1.txt'),
            "aaaa")
        self.assertEquals(local.get_content(
            '/Folder 1/Folder 1.1/File 2.txt'),
            "bbbb")
        self.assertEquals(local.get_content(
            '/Folder 3/File 6.txt'),
            "ffff")
        self.assertEquals(remote_client.get_content(
            '/Folder 1/File 1.txt'),
            "aaaa")
        self.assertEquals(remote_client.get_content(
            '/Folder 1/Folder 1.1/File 2.txt'),
            "bbbb")
        self.assertEquals(remote_client.get_content(
            '/Folder 3/File 6.txt'),
            "ffff")

        # Rescan: no change to detect we should reach a fixpoint
        syn.scan_local(self.local_nxdrive_folder_1)
        syn.scan_remote(self.local_nxdrive_folder_1)
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(ctl.children_states(expected_folder), [
            (u'Folder 1', 'synchronized'),
            (u'Folder 3', 'synchronized'),
            (u'Folder 4', 'synchronized'),
        ])

        # Send some binary data that is not valid in utf-8 or ascii
        # (to test the HTTP / Multipart transform layer).
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        local.update_content('/Folder 1/File 1.txt', "\x80")
        remote_client.update_content('/Folder 1/Folder 1.1/File 2.txt', '\x80')
        syn.scan_local(self.local_nxdrive_folder_1)
        syn.scan_remote(self.local_nxdrive_folder_1)
        self.assertEquals(syn.synchronize(limit=100), 2)
        self.assertEquals(remote_client.get_content('/Folder 1/File 1.txt'),
                          "\x80")
        self.assertEquals(local.get_content('/Folder 1/Folder 1.1/File 2.txt'),
                          "\x80")
コード例 #24
0
    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()
コード例 #25
0
    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'))
コード例 #26
0
    def test_synchronization_give_up(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")
        ctl = self.controller_1

        # Override to only 2 errors
        ctl.get_max_errors = lambda: 2
        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
        syn.error_skip_period = 1
        expected_folder = os.path.join(self.local_nxdrive_folder_1,
                                       self.workspace_title)

        # Bound root but nothing is synced yet
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(syn.synchronize(), 0)

        # Perform first scan and sync
        syn.loop(delay=1, max_loops=2)
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(syn.synchronize(), 0)

        # Let's create some document on the client and the server
        local = LocalClient(expected_folder)
        local.make_folder('/', 'Folder 3')
        self.make_server_tree()
        self.wait()

        ctl.remote_filtered_fs_client_factory = RemoteTestClient
        ctl.invalidate_client_cache()
        # First check that socket error doesnt count
        ctl.make_remote_raise(socket.error('Test error'))
        syn.loop(delay=1, max_loops=2)
        self.assertEquals(len(ctl.list_on_errors()), 0)

        # Find various ways to simulate a network or server failure
        error = httplib.HTTPException('Test error')
        error.code = 500
        ctl.make_remote_raise(error)

        # Synchronization does not occur but does not fail either
        syn.loop(delay=1, max_loops=3)

        # All is synchronized
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(len(ctl.list_on_errors()), 7)

        # Increase the max number of errors
        ctl.get_max_errors = lambda: 3
        self.assertEquals(len(ctl.list_pending()), 7)
        self.assertEquals(len(ctl.list_on_errors()), 0)

        # Synchronization does not occur but does not fail either
        syn.loop(delay=1, max_loops=2)

        # Everything should be on errors again
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(len(ctl.list_on_errors()), 7)

        # Remove faulty client
        ctl.make_remote_raise(None)
        ctl.remote_filtered_fs_client_factory = RemoteFilteredFileSystemClient
        ctl.invalidate_client_cache()

        for doc_pair in ctl.list_on_errors():
            doc_pair.error_count = 0
        # Verify that we will sync now
        self.assertEquals(len(ctl.list_pending()), 7)
        syn.loop(delay=0, max_loops=3)
        # Everything should be ok now
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(len(ctl.list_on_errors()), 0)
コード例 #27
0
class TestIntegrationLocalRootDeletion(IntegrationTestCase):
    def setUp(self):
        super(TestIntegrationLocalRootDeletion, self).setUp()

        self.sb_1 = self.controller_1.bind_server(self.local_nxdrive_folder_1,
                                                  self.nuxeo_url, self.user_1,
                                                  self.password_1)

        self.controller_1.bind_root(self.local_nxdrive_folder_1,
                                    self.workspace)

        # Deactivate Watchdog as it prevents the Nuxeo Drive folder from being
        # well removed later on by shutil.rmtree, thus re-created by the
        # synchronizer during rollback if activated.
        def no_watchdog():
            return False

        self.controller_1.use_watchdog = no_watchdog

        self.controller_1.synchronizer.update_synchronize_server(self.sb_1)

        self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1,
                                               self.workspace_title)
        self.local_client_1 = LocalClient(self.sync_root_folder_1)

        self.local_client_1.make_file(
            '/',
            u'Original File 1.txt',
            content=u'Some Content 1'.encode('utf-8'))

        self.local_client_1.make_file(
            '/',
            u'Original File 2.txt',
            content=u'Some Content 2'.encode('utf-8'))

        self.local_client_1.make_folder(u'/', u'Original Folder 1')
        self.local_client_1.make_folder(u'/Original Folder 1',
                                        u'Sub-Folder 1.1')
        self.local_client_1.make_folder(u'/Original Folder 1',
                                        u'Sub-Folder 1.2')
        self.local_client_1.make_file(
            u'/Original Folder 1',
            u'Original File 1.1.txt',
            content=u'Some Content 1'.encode('utf-8'))  # Same content as OF1

        self.local_client_1.make_folder('/', 'Original Folder 2')
        self.local_client_1.make_file(
            '/Original Folder 2',
            u'Original File 3.txt',
            content=u'Some Content 3'.encode('utf-8'))

        self.controller_1.synchronizer.update_synchronize_server(self.sb_1)
        self.local_client_1.unlock_path(self.sync_root_folder_1)
        # Force the write mode under Windows
        import stat
        if os.access(self.local_nxdrive_folder_1, os.W_OK):
            os.chmod(
                self.local_nxdrive_folder_1, stat.S_IXUSR | stat.S_IRGRP
                | stat.S_IXGRP | stat.S_IRUSR | stat.S_IWGRP | stat.S_IWUSR)
        shutil.rmtree(self.local_nxdrive_folder_1, False)

    def test_without_rollback(self):
        sb, ctl = self.sb_1, self.controller_1
        ctl.synchronizer.update_synchronize_server(sb)
        self.assertFalse(os.path.exists(self.local_nxdrive_folder_1))
        self.assertFalse(sb in ctl.list_server_bindings())

    def test_with_rollback(self):
        sb, ctl = self.sb_1, self.controller_1

        def rollback():
            return True

        ctl.local_rollback = rollback

        ctl.synchronizer.update_synchronize_server(sb)
        self.assertTrue(os.path.exists(self.local_nxdrive_folder_1))
        sb = ctl.list_server_bindings()[0]
        ctl.synchronizer.update_synchronize_server(sb)
        self.assertTrue(os.path.exists(self.sync_root_folder_1))
コード例 #28
0
def setup_temp_folder():
    global lcclient, LOCAL_TEST_FOLDER, TEST_WORKSPACE
    LOCAL_TEST_FOLDER = tempfile.mkdtemp('-nuxeo-drive-tests')
    lcclient = LocalClient(LOCAL_TEST_FOLDER)
    TEST_WORKSPACE = lcclient.make_folder('/', 'Some Workspace')
コード例 #29
0
    def test_create_content_in_readonly_area(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")
        # Let's bind a the server but no root workspace
        ctl = self.controller_1
        ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        syn = ctl.synchronizer
        self.wait()

        syn.loop(delay=0.1, max_loops=1)
        self.assertEquals(ctl.list_pending(), [])

        # Let's create a subfolder of the main readonly folder
        local = LocalClient(self.local_nxdrive_folder_1)
        local.make_folder('/', 'Folder 3')
        local.make_file('/Folder 3', 'File 1.txt', content='Some content.')
        local.make_folder('/Folder 3', 'Sub Folder 1')
        local.make_file('/Folder 3/Sub Folder 1', 'File 2.txt',
                        content='Some other content.')
        syn.loop(delay=0.1, max_loops=1)

        # Pairs have been created for the subfolder and its content,
        # marked as synchronized
        self.assertEquals(self.get_all_states(get_pair_state=True), [
            (u'/', u'synchronized', u'synchronized', u'synchronized'),
            (u'/Folder 3', u'created', u'unknown', u'unsynchronized'),
            (u'/Folder 3/File 1.txt', u'created', u'unknown',
             u'unsynchronized'),
            (u'/Folder 3/Sub Folder 1', u'created', u'unknown',
             u'unsynchronized'),
            (u'/Folder 3/Sub Folder 1/File 2.txt',
             u'created', u'unknown', u'unsynchronized'),
        ])
        self.assertEquals(ctl.list_pending(), [])

        # Let's create a file in the main readonly folder
        local.make_file('/', 'A file in a readonly folder.txt',
            content='Some Content')
        syn.loop(delay=0.1, max_loops=1)

        # A pair has been created, marked as synchronized
        self.assertEquals(self.get_all_states(get_pair_state=True), [
            (u'/', u'synchronized', u'synchronized', u'synchronized'),
            (u'/A file in a readonly folder.txt',
             u'created', u'unknown', u'unsynchronized'),
            (u'/Folder 3', u'created', u'unknown', u'unsynchronized'),
            (u'/Folder 3/File 1.txt', u'created', u'unknown',
             u'unsynchronized'),
            (u'/Folder 3/Sub Folder 1', u'created', u'unknown',
             u'unsynchronized'),
            (u'/Folder 3/Sub Folder 1/File 2.txt',
             u'created', u'unknown', u'unsynchronized'),
        ])
        self.assertEquals(len(ctl.list_pending(ignore_in_error=300)), 0)

        # Let's create a file and a folder in a folder on which the Write
        # permission has been removed. Thanks to NXP-13119, this permission
        # change will be detected server-side, thus fetched by the client
        # in the remote change summary, and the remote_can_create_child flag
        # on which the synchronizer relies to check if creation is allowed
        # will be set to False and no attempt to create the remote file
        # will be made.

        # Bind root workspace, create local folder and synchronize it remotely
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)
        self.wait()
        syn.loop(delay=0.1, max_loops=1)

        local = LocalClient(
            os.path.join(self.local_nxdrive_folder_1, self.workspace_title))
        local.make_folder(u'/', u'Readonly folder')
        syn.loop(delay=0.1, max_loops=1)

        remote = self.remote_document_client_1
        self.assertTrue(remote.exists(u'/Readonly folder'))

        # Check remote_can_create_child flag in pair state
        session = ctl.get_session()
        readonly_folder_state = session.query(LastKnownState).filter_by(
            local_name=u'Readonly folder').one()
        self.assertTrue(readonly_folder_state.remote_can_create_child)

        # Make one sync loop to detect remote folder creation triggered
        # by last synchronization and make sure we get a clean state at
        # next change summary
        self.wait()
        syn.loop(delay=0.1, max_loops=1)
        # Re-fetch folder state as sync loop closes the Session
        readonly_folder_state = session.query(LastKnownState).filter_by(
            local_name=u'Readonly folder').one()
        self.assertTrue(readonly_folder_state.remote_can_create_child)

        # Set remote folder as readonly for test user
        readonly_folder_path = TEST_WORKSPACE_PATH + u'/Readonly folder'
        op_input = "doc:" + readonly_folder_path
        self.root_remote_client.execute("Document.SetACE",
            op_input=op_input,
            user="******",
            permission="Read")
        self.root_remote_client.block_inheritance(readonly_folder_path,
                                                  overwrite=False)

        # Wait to make sure permission change is detected.
        self.wait()
        syn.loop(delay=0.1, max_loops=1)
        # Re-fetch folder state as sync loop closes the Session
        readonly_folder_state = session.query(LastKnownState).filter_by(
            local_name=u'Readonly folder').one()
        self.assertFalse(readonly_folder_state.remote_can_create_child)

        # Try to create a local file and folder in the readonly folder,
        # they should not be created remotely.
        local.make_file(u'/Readonly folder', u'File in readonly folder',
                        u"File content")
        local.make_folder(u'/Readonly folder', u'Folder in readonly folder')
        syn.loop(delay=0.1, max_loops=1)
        self.assertFalse(remote.exists(
            u'/Readonly folder/File in readonly folder'))
        self.assertFalse(remote.exists(
            u'/Readonly folder/Folder in readonly folder'))
コード例 #30
0
    def test_rebind_without_duplication(self):
        raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170")
        """Check rebinding an existing folder won't duplicate everything"""
        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
        self.assertEquals(ctl.list_pending(), [])

        # Let's create some document on the client and the server
        local = LocalClient(self.local_nxdrive_folder_1)
        local.make_folder('/', self.workspace_title)
        local.make_folder('/' + self.workspace_title, 'Folder 3')
        self.make_server_tree()
        self.wait()

        syn.loop(delay=0, max_loops=3)
        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/File 5.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 1',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 1/File 1.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 1/Folder 1.1',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 1/Folder 1.1/File 2.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 1/Folder 1.2',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 1/Folder 1.2/File 3.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 2',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 2/Duplicated File.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 2/Duplicated File__1.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 2/File 4.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 3',
             u'synchronized', u'synchronized')
        ])
        self.assertEquals(
            len(local.get_children_info('/Nuxeo Drive Test Workspace')), 4)

        # Unbind: the state database is emptied
        ctl.unbind_server(self.local_nxdrive_folder_1)
        self.assertEquals(self.get_all_states(), [])

        # Previously synchronized files are still there, untouched
        self.assertEquals(
            len(local.get_children_info('/Nuxeo Drive Test Workspace')), 4)

        # Lets rebind the same folder to the same 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)
        syn.loop(delay=0, max_loops=3)
        self.assertEquals(ctl.list_pending(), [])

        # Check that the sync that occurs right after the bind automatically
        # detects the file alignments and hence everything is synchronized
        # without duplication
        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/File 5.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 1',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 1/File 1.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 1/Folder 1.1',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 1/Folder 1.1/File 2.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 1/Folder 1.2',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 1/Folder 1.2/File 3.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 2',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 2/Duplicated File.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 2/Duplicated File__1.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 2/File 4.txt',
             u'synchronized', u'synchronized'),
            (u'/Nuxeo Drive Test Workspace/Folder 3',
             u'synchronized', u'synchronized')
        ])
        self.assertEquals(ctl.list_pending(), [])
        # Previously synchronized files are still there, untouched
        self.assertEquals(
            len(local.get_children_info('/Nuxeo Drive Test Workspace')), 4)
コード例 #31
0
    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'))
コード例 #32
0
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')
コード例 #33
0
class TestIntegrationLocalMoveAndRename(IntegrationTestCase):

    # Sets up the following local hierarchy:
    # Nuxeo Drive Test Workspace
    #    |-- Original File 1.txt
    #    |-- Original File 2.txt
    #    |-- Original Folder 1
    #    |       |-- Sub-Folder 1.1
    #    |       |-- Sub-Folder 1.2
    #    |       |-- Original File 1.1.txt
    #    |-- Original Folder 2
    #    |       |-- Original File 3.txt
    def setUp(self):
        super(TestIntegrationLocalMoveAndRename, self).setUp()

        self.sb_1 = self.controller_1.bind_server(self.local_nxdrive_folder_1,
                                                  self.nuxeo_url, self.user_1,
                                                  self.password_1)

        self.controller_1.bind_root(self.local_nxdrive_folder_1,
                                    self.workspace)

        self.controller_1.synchronizer.update_synchronize_server(self.sb_1)

        self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1,
                                               self.workspace_title)
        self.local_client_1 = LocalClient(self.sync_root_folder_1)

        self.local_client_1.make_file(
            '/',
            u'Original File 1.txt',
            content=u'Some Content 1'.encode('utf-8'))

        self.local_client_1.make_file(
            '/',
            u'Original File 2.txt',
            content=u'Some Content 2'.encode('utf-8'))

        self.local_client_1.make_folder(u'/', u'Original Folder 1')
        self.local_client_1.make_folder(u'/Original Folder 1',
                                        u'Sub-Folder 1.1')
        self.local_client_1.make_folder(u'/Original Folder 1',
                                        u'Sub-Folder 1.2')
        self.local_client_1.make_file(
            u'/Original Folder 1',
            u'Original File 1.1.txt',
            content=u'Some Content 1'.encode('utf-8'))  # Same content as OF1

        self.local_client_1.make_folder('/', 'Original Folder 2')
        self.local_client_1.make_file(
            '/Original Folder 2',
            u'Original File 3.txt',
            content=u'Some Content 3'.encode('utf-8'))

        self.controller_1.synchronizer.update_synchronize_server(self.sb_1)

    def test_local_rename_file(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Rename /Original File 1.txt to /Renamed File 1.txt
        original_file_1_uid = remote_client.get_info(
            u'/Original File 1.txt').uid
        local_client.rename(u'/Original File 1.txt', u'Renamed File 1.txt')
        self.assertFalse(local_client.exists(u'/Original File 1.txt'))
        self.assertTrue(local_client.exists(u'/Renamed File 1.txt'))

        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 1)
        self.assertFalse(local_client.exists(u'/Original File 1.txt'))
        self.assertTrue(local_client.exists(u'/Renamed File 1.txt'))
        original_file_1_remote_info = remote_client.get_info(
            original_file_1_uid)
        self.assertEquals(original_file_1_remote_info.name,
                          u'Renamed File 1.txt')

        # Rename 'Renamed File 1.txt' to 'Renamed Again File 1.txt'
        # and 'Original File 1.1.txt' to
        # 'Renamed File 1.1.txt' at the same time as they share
        # the same digest but do not live in the same folder
        original_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Original File 1.1.txt').uid
        local_client.rename(u'/Original Folder 1/Original File 1.1.txt',
                            u'Renamed File 1.1 \xe9.txt')
        self.assertFalse(
            local_client.exists('/Original Folder 1/Original File 1.1.txt'))
        self.assertTrue(
            local_client.exists(
                u'/Original Folder 1/Renamed File 1.1 \xe9.txt'))
        local_client.rename('/Renamed File 1.txt', 'Renamed Again File 1.txt')
        self.assertFalse(local_client.exists(u'/Renamed File 1.txt'))
        self.assertTrue(local_client.exists(u'/Renamed Again File 1.txt'))

        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 2)
        self.assertFalse(local_client.exists(u'/Renamed File 1.txt'))
        self.assertTrue(local_client.exists(u'/Renamed Again File 1.txt'))
        self.assertFalse(
            local_client.exists(u'/Original Folder 1/Original File 1.1.txt'))
        self.assertTrue(
            local_client.exists(
                u'/Original Folder 1/Renamed File 1.1 \xe9.txt'))

        file_1_remote_info = remote_client.get_info(original_file_1_uid)
        self.assertEquals(file_1_remote_info.name, u'Renamed Again File 1.txt')

        # User 1 does not have the rights to see the parent container
        # of the test workspace, hence set fetch_parent_uid=False
        parent_of_file_1_remote_info = remote_client.get_info(
            file_1_remote_info.parent_uid, fetch_parent_uid=False)
        self.assertEquals(parent_of_file_1_remote_info.name,
                          self.workspace_title)

        file_1_1_remote_info = remote_client.get_info(original_1_1_uid)
        self.assertEquals(file_1_1_remote_info.name,
                          u'Renamed File 1.1 \xe9.txt')

        parent_of_file_1_1_remote_info = remote_client.get_info(
            file_1_1_remote_info.parent_uid)
        self.assertEquals(parent_of_file_1_1_remote_info.name,
                          u'Original Folder 1')

    def test_local_rename_file_uppercase(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Rename /Original File 1.txt to /Renamed File 1.txt

        # Rename 'Renamed File 1.txt' to 'Renamed Again File 1.txt'
        # and 'Original File 1.1.txt' to
        # 'Renamed File 1.1.txt' at the same time as they share
        # the same digest but do not live in the same folder
        original_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Original File 1.1.txt').uid
        local_client.rename(u'/Original Folder 1/Original File 1.1.txt',
                            u'original File 1.1.txt')

        ctl.synchronizer.update_synchronize_server(sb)

        file_1_1_remote_info = remote_client.get_info(original_1_1_uid)
        self.assertEquals(file_1_1_remote_info.name, u'original File 1.1.txt')

        parent_of_file_1_1_remote_info = remote_client.get_info(
            file_1_1_remote_info.parent_uid)
        self.assertEquals(parent_of_file_1_1_remote_info.name,
                          u'Original Folder 1')

    def test_local_move_file(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Rename /Original File 1.txt to /Renamed File 1.txt
        original_file_1_uid = remote_client.get_info(
            u'/Original File 1.txt').uid
        local_client.move(u'/Original File 1.txt', u'/Original Folder 1')
        self.assertFalse(local_client.exists(u'/Original File 1.txt'))
        self.assertTrue(
            local_client.exists(u'/Original Folder 1/Original File 1.txt'))

        ctl.synchronizer.update_synchronize_server(sb)
        self.assertFalse(local_client.exists(u'/Original File 1.txt'))
        self.assertTrue(
            local_client.exists(u'/Original Folder 1/Original File 1.txt'))

        file_1_remote_info = remote_client.get_info(original_file_1_uid)
        self.assertEquals(file_1_remote_info.name, u'Original File 1.txt')
        parent_of_file_1_remote_info = remote_client.get_info(
            file_1_remote_info.parent_uid)
        self.assertEquals(parent_of_file_1_remote_info.name,
                          u'Original Folder 1')

    def test_local_move_and_rename_file(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Rename /Original File 1.txt to /Renamed File 1.txt
        original_file_1_uid = remote_client.get_info(
            u'/Original File 1.txt').uid

        local_client.rename(u'/Original File 1.txt',
                            u'Renamed File 1 \xe9.txt')
        local_client.move(u'/Renamed File 1 \xe9.txt', u'/Original Folder 1')
        self.assertFalse(local_client.exists(u'/Original File 1.txt'))
        self.assertTrue(
            local_client.exists(u'/Original Folder 1/Renamed File 1 \xe9.txt'))

        ctl.synchronizer.update_synchronize_server(sb)
        self.assertFalse(local_client.exists(u'/Original File 1.txt'))
        self.assertTrue(
            local_client.exists(u'/Original Folder 1/Renamed File 1 \xe9.txt'))

        file_1_remote_info = remote_client.get_info(original_file_1_uid)
        self.assertEquals(file_1_remote_info.name, u'Renamed File 1 \xe9.txt')
        parent_of_file_1_remote_info = remote_client.get_info(
            file_1_remote_info.parent_uid)
        self.assertEquals(parent_of_file_1_remote_info.name,
                          u'Original Folder 1')

        # Nothing left to do
        self.wait_audit_change_finder_if_needed()
        self.wait()
        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 0)

    def test_local_rename_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Save the uid of some files and folders prior to renaming
        original_folder_1_uid = remote_client.get_info(
            u'/Original Folder 1').uid
        original_file_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Original File 1.1.txt').uid
        original_sub_folder_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Sub-Folder 1.1').uid

        # Rename a non empty folder with some content
        local_client.rename(u'/Original Folder 1', u'Renamed Folder 1 \xe9')
        self.assertFalse(local_client.exists(u'/Original Folder 1'))
        self.assertTrue(local_client.exists(u'/Renamed Folder 1 \xe9'))

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

        # The server folder has been renamed: the uid stays the same
        new_remote_name = remote_client.get_info(original_folder_1_uid).name
        self.assertEquals(new_remote_name, u"Renamed Folder 1 \xe9")

        # The content of the renamed folder is left unchanged
        file_1_1_info = remote_client.get_info(original_file_1_1_uid)
        self.assertEquals(file_1_1_info.name, u"Original File 1.1.txt")
        self.assertEquals(file_1_1_info.parent_uid, original_folder_1_uid)

        sub_folder_1_1_info = remote_client.get_info(
            original_sub_folder_1_1_uid)
        self.assertEquals(sub_folder_1_1_info.name, u"Sub-Folder 1.1")
        self.assertEquals(sub_folder_1_1_info.parent_uid,
                          original_folder_1_uid)

        # 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_local_move_folder(self):
        raise SkipTest("Skipped waiting for"
                       " https://jira.nuxeo.com/browse/NXDRIVE-80 to be fixed")
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Save the uid of some files and folders prior to move
        original_folder_1_uid = remote_client.get_info(
            u'/Original Folder 1').uid
        original_folder_2_uid = remote_client.get_info(
            u'/Original Folder 2').uid
        original_file_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Original File 1.1.txt').uid
        original_sub_folder_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Sub-Folder 1.1').uid

        # Move a non empty folder with some content
        local_client.move(u'/Original Folder 1', u'/Original Folder 2')
        self.assertFalse(local_client.exists(u'/Original Folder 1'))
        self.assertTrue(
            local_client.exists(u'/Original Folder 2/Original Folder 1'))

        # Synchronize: only the folder move is detected: all
        # the descendants are automatically realigned
        ctl.synchronizer.update_synchronize_server(sb)
        # The server folder has been moved: the uid stays the same
        remote_folder_info = remote_client.get_info(original_folder_1_uid)

        # The parent folder is now folder 2
        self.assertEquals(remote_folder_info.parent_uid, original_folder_2_uid)

        # The content of the renamed folder is left unchanged
        file_1_1_info = remote_client.get_info(original_file_1_1_uid)
        self.assertEquals(file_1_1_info.name, u"Original File 1.1.txt")
        self.assertEquals(file_1_1_info.parent_uid, original_folder_1_uid)

        sub_folder_1_1_info = remote_client.get_info(
            original_sub_folder_1_1_uid)
        self.assertEquals(sub_folder_1_1_info.name, u"Sub-Folder 1.1")
        self.assertEquals(sub_folder_1_1_info.parent_uid,
                          original_folder_1_uid)

        # 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_concurrent_local_rename_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Save the uid of some files and folders prior to renaming
        folder_1_uid = remote_client.get_info(u'/Original Folder 1').uid
        file_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Original File 1.1.txt').uid
        folder_2_uid = remote_client.get_info(u'/Original Folder 2').uid
        file_3_uid = remote_client.get_info(
            u'/Original Folder 2/Original File 3.txt').uid

        # Rename a non empty folders concurrently
        local_client.rename(u'/Original Folder 1', u'Renamed Folder 1')
        local_client.rename(u'/Original Folder 2', u'Renamed Folder 2')
        self.assertFalse(local_client.exists(u'/Original Folder 1'))
        self.assertTrue(local_client.exists(u'/Renamed Folder 1'))
        self.assertFalse(local_client.exists(u'/Original Folder 2'))
        self.assertTrue(local_client.exists(u'/Renamed Folder 2'))

        # Synchronize: only the folder renamings are detected: all
        # the descendants are automatically realigned
        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 2)

        # The server folders have been renamed: the uid stays the same
        folder_1_info = remote_client.get_info(folder_1_uid)
        self.assertEquals(folder_1_info.name, u"Renamed Folder 1")

        folder_2_info = remote_client.get_info(folder_2_uid)
        self.assertEquals(folder_2_info.name, u"Renamed Folder 2")

        # The content of the folder has been left unchanged
        file_1_1_info = remote_client.get_info(file_1_1_uid)
        self.assertEquals(file_1_1_info.name, u"Original File 1.1.txt")
        self.assertEquals(file_1_1_info.parent_uid, folder_1_uid)

        file_3_info = remote_client.get_info(file_3_uid)
        self.assertEquals(file_3_info.name, u"Original File 3.txt")
        self.assertEquals(file_3_info.parent_uid, folder_2_uid)

        # 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_local_rename_sync_root_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        # Use the Administrator to be able to introspect the container of the
        # test workspace.
        remote_client = RemoteDocumentClient(
            self.nuxeo_url,
            self.admin_user,
            'nxdrive-test-administrator-device',
            self.version,
            password=self.password,
            base_folder=self.workspace)

        folder_1_uid = remote_client.get_info(u'/Original Folder 1').uid

        # Create new clients to be able to introspect the test sync root
        toplevel_local_client = LocalClient(self.local_nxdrive_folder_1)

        toplevel_local_client.rename('/' + self.workspace_title,
                                     'Renamed Nuxeo Drive Test Workspace')
        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 1)

        workspace_info = remote_client.get_info(self.workspace)
        self.assertEquals(workspace_info.name,
                          u"Renamed Nuxeo Drive Test Workspace")

        folder_1_info = remote_client.get_info(folder_1_uid)
        self.assertEquals(folder_1_info.name, u"Original Folder 1")
        self.assertEquals(folder_1_info.parent_uid, self.workspace)

    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_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_rename_readonly_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1
        session = ctl.get_session()

        # Check local folder
        self.assertTrue(local_client.exists(u'/Original Folder 1'))
        folder_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original Folder 1').one()
        self.assertTrue(folder_1_state.remote_can_rename)

        # Set remote folder as readonly for test user
        folder_1_path = self.TEST_WORKSPACE_PATH + u'/Original Folder 1'
        op_input = "doc:" + folder_1_path
        self.root_remote_client.execute("Document.SetACE",
                                        op_input=op_input,
                                        user="******",
                                        permission="Read")
        self.root_remote_client.block_inheritance(folder_1_path,
                                                  overwrite=False)

        # Check can_rename flag in pair state
        folder_1_state.refresh_remote(self.remote_file_system_client_1)
        self.assertFalse(folder_1_state.remote_can_rename)

        # Rename local folder
        local_client.rename(u'/Original Folder 1', u'Renamed Folder 1 \xe9')
        self.assertFalse(local_client.exists(u'/Original Folder 1'))
        self.assertTrue(local_client.exists(u'/Renamed Folder 1 \xe9'))

        ctl.synchronizer.update_synchronize_server(sb)

        # Check remote folder has not been renamed
        folder_1_remote_info = remote_client.get_info(u'/Original Folder 1')
        self.assertEquals(folder_1_remote_info.name, u'Original Folder 1')

        # Check state of local folder and its children
        folder_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Renamed Folder 1 \xe9').one()
        self.assertEquals(folder_1_state.remote_name, u'Original Folder 1')

        self.assertTrue(
            local_client.exists(
                u'/Renamed Folder 1 \xe9/Original File 1.1.txt'))
        file_1_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original File 1.1.txt').one()
        self.assertEquals(file_1_1_state.local_name, u'Original File 1.1.txt')
        self.assertEquals(file_1_1_state.remote_name, u'Original File 1.1.txt')

        self.assertTrue(
            local_client.exists(u'/Renamed Folder 1 \xe9/Sub-Folder 1.1'))
        folder_1_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Sub-Folder 1.1').one()
        self.assertEquals(folder_1_1_state.local_name, u'Sub-Folder 1.1')
        self.assertEquals(folder_1_1_state.remote_name, u'Sub-Folder 1.1')

        self.assertTrue(
            local_client.exists(u'/Renamed Folder 1 \xe9/Sub-Folder 1.2'))
        folder_1_2_state = session.query(LastKnownState).filter_by(
            local_name=u'Sub-Folder 1.2').one()
        self.assertEquals(folder_1_2_state.local_name, u'Sub-Folder 1.2')
        self.assertEquals(folder_1_2_state.remote_name, u'Sub-Folder 1.2')

    def test_local_rename_readonly_folder_with_rollback(self):
        sb, ctl = self.sb_1, self.controller_1

        def watchdog():
            return False

        def rollback():
            return True

        ctl.use_watchdog = watchdog
        ctl.synchronizer.local_full_scan = []
        ctl.local_rollback = rollback
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1
        session = ctl.get_session()

        # Check local folder
        self.assertTrue(local_client.exists(u'/Original Folder 1'))
        folder_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original Folder 1').one()
        self.assertTrue(folder_1_state.remote_can_rename)

        # Set remote folder as readonly for test user
        folder_1_path = self.TEST_WORKSPACE_PATH + u'/Original Folder 1'
        op_input = "doc:" + folder_1_path
        self.root_remote_client.execute("Document.SetACE",
                                        op_input=op_input,
                                        user="******",
                                        permission="Read")
        self.root_remote_client.block_inheritance(folder_1_path,
                                                  overwrite=False)

        # Check can_rename flag in pair state
        folder_1_state.refresh_remote(self.remote_file_system_client_1)
        self.assertFalse(folder_1_state.remote_can_rename)

        # Rename local folder
        local_client.rename(u'/Original Folder 1', u'Renamed Folder 1 \xe9')
        self.assertFalse(local_client.exists(u'/Original Folder 1'))
        self.assertTrue(local_client.exists(u'/Renamed Folder 1 \xe9'))

        ctl.synchronizer.update_synchronize_server(sb)

        # Check remote folder has not been renamed
        folder_1_remote_info = remote_client.get_info(u'/Original Folder 1')
        self.assertEquals(folder_1_remote_info.name, u'Original Folder 1')

        # Check state of local folder and its children
        folder_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original Folder 1').one()
        self.assertEquals(folder_1_state.remote_name, u'Original Folder 1')

        self.assertTrue(
            local_client.exists(u'/Original Folder 1/Original File 1.1.txt'))
        file_1_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original File 1.1.txt').one()
        self.assertEquals(file_1_1_state.local_name, u'Original File 1.1.txt')
        self.assertEquals(file_1_1_state.remote_name, u'Original File 1.1.txt')

        self.assertTrue(
            local_client.exists(u'/Original Folder 1/Sub-Folder 1.1'))
        folder_1_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Sub-Folder 1.1').one()
        self.assertEquals(folder_1_1_state.local_name, u'Sub-Folder 1.1')
        self.assertEquals(folder_1_1_state.remote_name, u'Sub-Folder 1.1')

    def test_local_move_with_remote_error(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Check local folder
        self.assertTrue(local_client.exists(u'/Original Folder 1'))
        remote_client._remote_error = IOError
        local_client.rename(u'/Original Folder 1', u'IOErrorTest')
        ctl.synchronizer.update_synchronize_server(sb)
        remote_client._remote_error = None
        folder_1 = remote_client.get_info(u'/Original Folder 1')
        self.assertTrue(folder_1 is not None, 'Move has happen')
        self.assertTrue(local_client.exists(u'/IOErrorTest'))
        ctl.synchronizer.update_synchronize_server(sb)
        folder_1 = remote_client.get_info(folder_1.uid)
        self.assertEquals(folder_1.name, u'IOErrorTest', 'Move has not happen')
        self.assertTrue(local_client.exists(u'/IOErrorTest'))

    def test_local_delete_readonly_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1
        session = ctl.get_session()

        # Check local folder
        self.assertTrue(local_client.exists(u'/Original Folder 1'))
        folder_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original Folder 1').one()
        self.assertTrue(folder_1_state.remote_can_delete)

        # Set remote folder as readonly for test user
        folder_1_path = self.TEST_WORKSPACE_PATH + u'/Original Folder 1'
        op_input = "doc:" + folder_1_path
        self.root_remote_client.execute("Document.SetACE",
                                        op_input=op_input,
                                        user="******",
                                        permission="Read")
        self.root_remote_client.block_inheritance(folder_1_path,
                                                  overwrite=False)

        # Check can_delete flag in pair state
        folder_1_state.refresh_remote(self.remote_file_system_client_1)
        self.assertFalse(folder_1_state.remote_can_delete)

        # Delete local folder
        local_client.delete(u'/Original Folder 1')
        self.assertRaises(NotFound, local_client.get_info,
                          u'/Original Folder 1')

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

        # Check remote folder and its children have not been deleted
        folder_1_remote_info = remote_client.get_info(u'/Original Folder 1')
        self.assertEquals(folder_1_remote_info.name, u'Original Folder 1')

        file_1_1_remote_info = remote_client.get_info(
            u'/Original Folder 1/Original File 1.1.txt')
        self.assertEquals(file_1_1_remote_info.name, u'Original File 1.1.txt')

        folder_1_1_remote_info = remote_client.get_info(
            u'/Original Folder 1/Sub-Folder 1.1')
        self.assertEquals(folder_1_1_remote_info.name, u'Sub-Folder 1.1')

        folder_1_2_remote_info = remote_client.get_info(
            u'/Original Folder 1/Sub-Folder 1.2')
        self.assertEquals(folder_1_2_remote_info.name, u'Sub-Folder 1.2')

        # Check local folder and its children have been re-created
        self.assertTrue(local_client.exists(u'/Original Folder 1'))
        folder_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original Folder 1').one()
        self.assertEquals(folder_1_state.local_name, u'Original Folder 1')
        self.assertEquals(folder_1_state.remote_name, u'Original Folder 1')

        self.assertTrue(
            local_client.exists(u'/Original Folder 1/Original File 1.1.txt'))
        file_1_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original File 1.1.txt').one()
        self.assertEquals(file_1_1_state.local_name, u'Original File 1.1.txt')
        self.assertEquals(file_1_1_state.remote_name, u'Original File 1.1.txt')

        self.assertTrue(
            local_client.exists(u'/Original Folder 1/Sub-Folder 1.1'))
        folder_1_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Sub-Folder 1.1').one()
        self.assertEquals(folder_1_1_state.local_name, u'Sub-Folder 1.1')
        self.assertEquals(folder_1_1_state.remote_name, u'Sub-Folder 1.1')

        self.assertTrue(
            local_client.exists(u'/Original Folder 1/Sub-Folder 1.2'))
        folder_1_2_state = session.query(LastKnownState).filter_by(
            local_name=u'Sub-Folder 1.2').one()
        self.assertEquals(folder_1_2_state.local_name, u'Sub-Folder 1.2')
        self.assertEquals(folder_1_2_state.remote_name, u'Sub-Folder 1.2')
コード例 #34
0
    def test_synchronization_loop_skip_errors(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)
        ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)
        syn = ctl.synchronizer
        expected_folder = os.path.join(self.local_nxdrive_folder_1,
                                       self.workspace_title)

        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(syn.synchronize(), 0)

        # Perform first scan and sync
        self.wait()
        syn.loop(delay=0, max_loops=3)
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(syn.synchronize(), 0)

        # Let's create some document on the client and the server
        local = LocalClient(expected_folder)
        local.make_folder('/', 'Folder 3')
        self.make_server_tree()
        self.wait()

        # Detect the files to synchronize but do not perform the
        # synchronization
        syn.scan_remote(self.local_nxdrive_folder_1)
        syn.scan_local(self.local_nxdrive_folder_1)
        pending = ctl.list_pending()
        self.assertEquals(len(pending), 12)
        self.assertEquals(pending[0].local_name, 'Folder 3')
        self.assertEquals(pending[0].pair_state, 'unknown')
        self.assertEquals(pending[1].remote_name, 'File 5.txt')
        self.assertEquals(pending[1].pair_state, 'remotely_modified')
        self.assertEquals(pending[2].remote_name, 'Folder 1')
        self.assertEquals(pending[2].pair_state, 'remotely_modified')

        # Simulate synchronization errors
        session = ctl.get_session()
        file_5 = session.query(LastKnownState).filter_by(
            remote_name='File 5.txt').one()
        file_5.last_sync_error_date = datetime.utcnow()
        folder_3 = session.query(LastKnownState).filter_by(
            local_name='Folder 3').one()
        folder_3.last_sync_error_date = datetime.utcnow()
        session.commit()

        # Run the full synchronization loop a limited amount of times
        syn.loop(delay=0, max_loops=3)

        # All errors have been skipped, while the remaining docs have
        # been synchronized
        pending = ctl.list_pending()
        self.assertEquals(len(pending), 2)
        self.assertEquals(pending[0].local_name, 'Folder 3')
        self.assertEquals(pending[0].pair_state, 'unknown')
        self.assertEquals(pending[1].remote_name, 'File 5.txt')
        self.assertEquals(pending[1].pair_state, 'remotely_modified')

        # Reduce the skip delay to retry the sync on pairs in error
        syn.error_skip_period = 0.000001
        syn.loop(delay=0, max_loops=3)
        self.assertEquals(ctl.list_pending(), [])
        self.assertEquals(ctl.children_states(expected_folder), [
            (u'File 5.txt', u'synchronized'),
            (u'Folder 1', u'synchronized'),
            (u'Folder 2', u'synchronized'),
            (u'Folder 3', u'synchronized'),
        ])
コード例 #35
0
def setup_temp_folder():
    global lcclient, LOCAL_TEST_FOLDER, TEST_WORKSPACE
    LOCAL_TEST_FOLDER = tempfile.mkdtemp(u'-nuxeo-drive-tests')
    lcclient = LocalClient(LOCAL_TEST_FOLDER)
    TEST_WORKSPACE = lcclient.make_folder(u'/', u'Some Workspace')
    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'))
コード例 #37
0
    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')
コード例 #38
0
    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'),
        ])
コード例 #39
0
    def test_create_content_in_readonly_area(self):
        self.engine_1.start()
        self.wait_sync(wait_for_async=True)

        # Let's create a subfolder of the main readonly folder
        local = LocalClient(self.local_nxdrive_folder_1)
        local.make_folder('/', 'Folder 3')
        local.make_file('/Folder 3', 'File 1.txt', content='Some content.')
        local.make_folder('/Folder 3', 'Sub Folder 1')
        local.make_file('/Folder 3/Sub Folder 1', 'File 2.txt', content='Some other content.')
        self.wait_sync()

        # States have been created for the subfolder and its content,
        # subfolder is marked as unsynchronized
        states = self.engine_1.get_dao().get_states_from_partial_local('/')
        self.assertEquals(len(states), 6)
        sorted_states = sorted(states, key=lambda x: x.local_path)
        self.assertEquals(sorted_states[0].local_name, '')
        self.assertEquals(sorted_states[0].pair_state, 'synchronized')
        self.assertEquals(sorted_states[1].local_name, 'Folder 3')
        self.assertEquals(sorted_states[1].pair_state, 'unsynchronized')
        self.assertEquals(sorted_states[2].local_name, 'File 1.txt')
        self.assertTrue(sorted_states[2].pair_state in ('locally_created', 'unsynchronized'))
        self.assertEquals(sorted_states[3].local_name, 'Sub Folder 1')
        self.assertTrue(sorted_states[3].pair_state in ('locally_created', 'unsynchronized'))
        self.assertEquals(sorted_states[4].local_name, 'File 2.txt')
        self.assertTrue(sorted_states[4].pair_state in ('locally_created', 'unsynchronized'))
        self.assertEquals(sorted_states[5].local_name, self.workspace_title)
        self.assertEquals(sorted_states[5].pair_state, 'synchronized')

        # Let's create a file in the main readonly folder
        local.make_file('/', 'A file in a readonly folder.txt', content='Some Content')
        self.wait_sync()

        # A state has been created, marked as unsynchronized
        # Other states are unchanged
        states = self.engine_1.get_dao().get_states_from_partial_local('/')
        self.assertEquals(len(states), 7)
        sorted_states = sorted(states, key=lambda x: x.local_path)
        self.assertEquals(sorted_states[0].local_name, '')
        self.assertEquals(sorted_states[0].pair_state, 'synchronized')
        self.assertEquals(sorted_states[1].local_name, 'A file in a readonly folder.txt')
        self.assertEquals(sorted_states[1].pair_state, 'unsynchronized')
        self.assertEquals(sorted_states[2].local_name, 'Folder 3')
        self.assertEquals(sorted_states[2].pair_state, 'unsynchronized')
        self.assertEquals(sorted_states[3].local_name, 'File 1.txt')
        self.assertTrue(sorted_states[3].pair_state in ('locally_created', 'unsynchronized'))
        self.assertEquals(sorted_states[4].local_name, 'Sub Folder 1')
        self.assertTrue(sorted_states[4].pair_state in ('locally_created', 'unsynchronized'))
        self.assertEquals(sorted_states[5].local_name, 'File 2.txt')
        self.assertTrue(sorted_states[5].pair_state in ('locally_created', 'unsynchronized'))
        self.assertEquals(sorted_states[6].local_name, self.workspace_title)
        self.assertEquals(sorted_states[6].pair_state, 'synchronized')

        # Let's create a file and a folder in a folder on which the Write
        # permission has been removed. Thanks to NXP-13119, this permission
        # change will be detected server-side, thus fetched by the client
        # in the remote change summary, and the remote_can_create_child flag
        # on which the synchronizer relies to check if creation is allowed
        # will be set to False and no attempt to create the remote file
        # will be made.
        # States will be marked as unsynchronized.

        # Create local folder and synchronize it remotely
        local = self.local_client_1
        local.make_folder(u'/', u'Readonly folder')
        self.wait_sync()

        remote = self.remote_document_client_1
        self.assertTrue(remote.exists(u'/Readonly folder'))

        # Check remote_can_create_child flag in pair state
        readonly_folder_state = self.engine_1.get_dao().get_state_from_local('/' + self.workspace_title
                                                                             + '/Readonly folder')
        self.assertTrue(readonly_folder_state.remote_can_create_child)

        # Wait again for synchronization to detect remote folder creation triggered
        # by last synchronization and make sure we get a clean state at
        # next change summary
        self.wait_sync(wait_for_async=True)
        readonly_folder_state = self.engine_1.get_dao().get_state_from_local('/' + self.workspace_title
                                                                             + '/Readonly folder')
        self.assertTrue(readonly_folder_state.remote_can_create_child)

        # Set remote folder as readonly for test user
        readonly_folder_path = TEST_WORKSPACE_PATH + u'/Readonly folder'
        op_input = "doc:" + readonly_folder_path
        self.root_remote_client.execute("Document.SetACE", op_input=op_input, user="******",
                                        permission="Read")
        self.root_remote_client.block_inheritance(readonly_folder_path, overwrite=False)

        # Wait to make sure permission change is detected.
        self.wait_sync(wait_for_async=True)
        # Re-fetch folder state and check remote_can_create_child flag has been updated
        readonly_folder_state = self.engine_1.get_dao().get_state_from_local('/' + self.workspace_title
                                                                             + '/Readonly folder')
        self.assertFalse(readonly_folder_state.remote_can_create_child)

        # Try to create a local file and folder in the readonly folder,
        # they should not be created remotely and be marked as unsynchronized.
        local.make_file(u'/Readonly folder', u'File in readonly folder', u"File content")
        local.make_folder(u'/Readonly folder', u'Folder in readonly folder')
        self.wait_sync()
        self.assertFalse(remote.exists(u'/Readonly folder/File in readonly folder'))
        self.assertFalse(remote.exists(u'/Readonly folder/Folder in readonly folder'))

        states = self.engine_1.get_dao().get_states_from_partial_local('/' + self.workspace_title + '/Readonly folder')
        self.assertEquals(len(states), 3)
        sorted_states = sorted(states, key=lambda x: x.local_path)
        self.assertEquals(sorted_states[0].local_name, 'Readonly folder')
        self.assertEquals(sorted_states[0].pair_state, 'synchronized')
        self.assertEquals(sorted_states[1].local_name, 'File in readonly folder')
        self.assertEquals(sorted_states[1].pair_state, 'unsynchronized')
        self.assertEquals(sorted_states[2].local_name, 'Folder in readonly folder')
        self.assertEquals(sorted_states[2].pair_state, 'unsynchronized')
コード例 #40
0
    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()
コード例 #41
0
class TestIntegrationLocalMoveAndRename(IntegrationTestCase):

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

        self.sb_1 = self.controller_1.bind_server(
            self.local_nxdrive_folder_1,
            self.nuxeo_url, self.user_1, self.password_1)

        self.controller_1.bind_root(self.local_nxdrive_folder_1,
            self.workspace)

        self.controller_1.synchronizer.update_synchronize_server(self.sb_1)

        self.sync_root_folder_1 = os.path.join(self.local_nxdrive_folder_1,
                                       self.workspace_title)
        self.local_client_1 = LocalClient(self.sync_root_folder_1)

        self.local_client_1.make_file('/', u'Original File 1.txt',
            content=u'Some Content 1'.encode('utf-8'))

        self.local_client_1.make_file('/', u'Original File 2.txt',
            content=u'Some Content 2'.encode('utf-8'))

        self.local_client_1.make_folder(u'/', u'Original Folder 1')
        self.local_client_1.make_folder(
            u'/Original Folder 1', u'Sub-Folder 1.1')
        self.local_client_1.make_folder(
            u'/Original Folder 1', u'Sub-Folder 1.2')
        self.local_client_1.make_file(u'/Original Folder 1',
            u'Original File 1.1.txt',
            content=u'Some Content 1'.encode('utf-8'))  # Same content as OF1

        self.local_client_1.make_folder('/', 'Original Folder 2')
        self.local_client_1.make_file('/Original Folder 2',
            u'Original File 3.txt',
            content=u'Some Content 3'.encode('utf-8'))

        self.controller_1.synchronizer.update_synchronize_server(self.sb_1)

    def test_local_rename_file(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Rename /Original File 1.txt to /Renamed File 1.txt
        original_file_1_uid = remote_client.get_info(
            u'/Original File 1.txt').uid
        local_client.rename(u'/Original File 1.txt', u'Renamed File 1.txt')
        self.assertFalse(local_client.exists(u'/Original File 1.txt'))
        self.assertTrue(local_client.exists(u'/Renamed File 1.txt'))

        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 1)
        self.assertFalse(local_client.exists(u'/Original File 1.txt'))
        self.assertTrue(local_client.exists(u'/Renamed File 1.txt'))
        original_file_1_remote_info = remote_client.get_info(
            original_file_1_uid)
        self.assertEquals(original_file_1_remote_info.name,
            u'Renamed File 1.txt')

        # Rename 'Renamed File 1.txt' to 'Renamed Again File 1.txt'
        # and 'Original File 1.1.txt' to
        # 'Renamed File 1.1.txt' at the same time as they share
        # the same digest but do not live in the same folder
        original_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Original File 1.1.txt').uid
        local_client.rename(
            u'/Original Folder 1/Original File 1.1.txt',
            u'Renamed File 1.1 \xe9.txt')
        self.assertFalse(local_client.exists(
             '/Original Folder 1/Original File 1.1.txt'))
        self.assertTrue(local_client.exists(
            u'/Original Folder 1/Renamed File 1.1 \xe9.txt'))
        local_client.rename('/Renamed File 1.txt', 'Renamed Again File 1.txt')
        self.assertFalse(local_client.exists(u'/Renamed File 1.txt'))
        self.assertTrue(local_client.exists(u'/Renamed Again File 1.txt'))

        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 2)
        self.assertFalse(local_client.exists(u'/Renamed File 1.txt'))
        self.assertTrue(local_client.exists(u'/Renamed Again File 1.txt'))
        self.assertFalse(local_client.exists(
             u'/Original Folder 1/Original File 1.1.txt'))
        self.assertTrue(local_client.exists(
            u'/Original Folder 1/Renamed File 1.1 \xe9.txt'))

        file_1_remote_info = remote_client.get_info(original_file_1_uid)
        self.assertEquals(file_1_remote_info.name,
            u'Renamed Again File 1.txt')

        # User 1 does not have the rights to see the parent container
        # of the test workspace, hence set fetch_parent_uid=False
        parent_of_file_1_remote_info = remote_client.get_info(
            file_1_remote_info.parent_uid, fetch_parent_uid=False)
        self.assertEquals(parent_of_file_1_remote_info.name,
            self.workspace_title)

        file_1_1_remote_info = remote_client.get_info(original_1_1_uid)
        self.assertEquals(file_1_1_remote_info.name,
            u'Renamed File 1.1 \xe9.txt')

        parent_of_file_1_1_remote_info = remote_client.get_info(
            file_1_1_remote_info.parent_uid)
        self.assertEquals(parent_of_file_1_1_remote_info.name,
            u'Original Folder 1')

    def test_local_move_file(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Rename /Original File 1.txt to /Renamed File 1.txt
        original_file_1_uid = remote_client.get_info(
            u'/Original File 1.txt').uid
        local_client.move(u'/Original File 1.txt', u'/Original Folder 1')
        self.assertFalse(local_client.exists(u'/Original File 1.txt'))
        self.assertTrue(local_client.exists(
            u'/Original Folder 1/Original File 1.txt'))

        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 1)
        self.assertFalse(local_client.exists(u'/Original File 1.txt'))
        self.assertTrue(local_client.exists(
            u'/Original Folder 1/Original File 1.txt'))

        file_1_remote_info = remote_client.get_info(original_file_1_uid)
        self.assertEquals(file_1_remote_info.name, u'Original File 1.txt')
        parent_of_file_1_remote_info = remote_client.get_info(
            file_1_remote_info.parent_uid)
        self.assertEquals(parent_of_file_1_remote_info.name,
            u'Original Folder 1')

    def test_local_move_and_rename_file(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Rename /Original File 1.txt to /Renamed File 1.txt
        original_file_1_uid = remote_client.get_info(
            u'/Original File 1.txt').uid

        local_client.rename(u'/Original File 1.txt',
                            u'Renamed File 1 \xe9.txt')
        local_client.move(u'/Renamed File 1 \xe9.txt', u'/Original Folder 1')
        self.assertFalse(local_client.exists(u'/Original File 1.txt'))
        self.assertTrue(local_client.exists(
            u'/Original Folder 1/Renamed File 1 \xe9.txt'))

        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 1)
        self.assertFalse(local_client.exists(u'/Original File 1.txt'))
        self.assertTrue(local_client.exists(
            u'/Original Folder 1/Renamed File 1 \xe9.txt'))

        file_1_remote_info = remote_client.get_info(original_file_1_uid)
        self.assertEquals(file_1_remote_info.name, u'Renamed File 1 \xe9.txt')
        parent_of_file_1_remote_info = remote_client.get_info(
            file_1_remote_info.parent_uid)
        self.assertEquals(parent_of_file_1_remote_info.name,
            u'Original Folder 1')

        # Nothing left to do
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 0)

    def test_local_rename_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Save the uid of some files and folders prior to renaming
        original_folder_1_uid = remote_client.get_info(
            u'/Original Folder 1').uid
        original_file_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Original File 1.1.txt').uid
        original_sub_folder_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Sub-Folder 1.1').uid

        # Rename a non empty folder with some content
        local_client.rename(u'/Original Folder 1', u'Renamed Folder 1 \xe9')
        self.assertFalse(local_client.exists(u'/Original Folder 1'))
        self.assertTrue(local_client.exists(u'/Renamed Folder 1 \xe9'))

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

        # The server folder has been renamed: the uid stays the same
        new_remote_name = remote_client.get_info(original_folder_1_uid).name
        self.assertEquals(new_remote_name, u"Renamed Folder 1 \xe9")

        # The content of the renamed folder is left unchanged
        file_1_1_info = remote_client.get_info(original_file_1_1_uid)
        self.assertEquals(file_1_1_info.name, u"Original File 1.1.txt")
        self.assertEquals(file_1_1_info.parent_uid, original_folder_1_uid)

        sub_folder_1_1_info = remote_client.get_info(
            original_sub_folder_1_1_uid)
        self.assertEquals(sub_folder_1_1_info.name, u"Sub-Folder 1.1")
        self.assertEquals(sub_folder_1_1_info.parent_uid,
            original_folder_1_uid)

        # The more things change, the more they remain the same.
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 0)

    def test_local_move_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Save the uid of some files and folders prior to move
        original_folder_1_uid = remote_client.get_info(
            u'/Original Folder 1').uid
        original_folder_2_uid = remote_client.get_info(
            u'/Original Folder 2').uid
        original_file_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Original File 1.1.txt').uid
        original_sub_folder_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Sub-Folder 1.1').uid

        # Move a non empty folder with some content
        local_client.move(u'/Original Folder 1', u'/Original Folder 2')
        self.assertFalse(local_client.exists(u'/Original Folder 1'))
        self.assertTrue(local_client.exists(
            u'/Original Folder 2/Original Folder 1'))

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

        # The server folder has been moved: the uid stays the same
        remote_folder_info = remote_client.get_info(original_folder_1_uid)

        # The parent folder is not folder 2
        self.assertEquals(remote_folder_info.parent_uid,
            original_folder_2_uid)

        # The content of the renamed folder is left unchanged
        file_1_1_info = remote_client.get_info(original_file_1_1_uid)
        self.assertEquals(file_1_1_info.name, u"Original File 1.1.txt")
        self.assertEquals(file_1_1_info.parent_uid, original_folder_1_uid)

        sub_folder_1_1_info = remote_client.get_info(
            original_sub_folder_1_1_uid)
        self.assertEquals(sub_folder_1_1_info.name, u"Sub-Folder 1.1")
        self.assertEquals(sub_folder_1_1_info.parent_uid,
            original_folder_1_uid)

        # The more things change, the more they remain the same.
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 0)

    def test_concurrent_local_rename_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Save the uid of some files and folders prior to renaming
        folder_1_uid = remote_client.get_info(u'/Original Folder 1').uid
        file_1_1_uid = remote_client.get_info(
            u'/Original Folder 1/Original File 1.1.txt').uid
        folder_2_uid = remote_client.get_info(u'/Original Folder 2').uid
        file_3_uid = remote_client.get_info(
            u'/Original Folder 2/Original File 3.txt').uid

        # Rename a non empty folders concurrently
        local_client.rename(u'/Original Folder 1', u'Renamed Folder 1')
        local_client.rename(u'/Original Folder 2', u'Renamed Folder 2')
        self.assertFalse(local_client.exists(u'/Original Folder 1'))
        self.assertTrue(local_client.exists(u'/Renamed Folder 1'))
        self.assertFalse(local_client.exists(u'/Original Folder 2'))
        self.assertTrue(local_client.exists(u'/Renamed Folder 2'))

        # Synchronize: only the folder renamings are detected: all
        # the descendants are automatically realigned
        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 2)

        # The server folders have been renamed: the uid stays the same
        folder_1_info = remote_client.get_info(folder_1_uid)
        self.assertEquals(folder_1_info.name, u"Renamed Folder 1")

        folder_2_info = remote_client.get_info(folder_2_uid)
        self.assertEquals(folder_2_info.name, u"Renamed Folder 2")

        # The content of the folder has been left unchanged
        file_1_1_info = remote_client.get_info(file_1_1_uid)
        self.assertEquals(file_1_1_info.name, u"Original File 1.1.txt")
        self.assertEquals(file_1_1_info.parent_uid, folder_1_uid)

        file_3_info = remote_client.get_info(file_3_uid)
        self.assertEquals(file_3_info.name, u"Original File 3.txt")
        self.assertEquals(file_3_info.parent_uid, folder_2_uid)

        # The more things change, the more they remain the same.
        time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION)
        self.wait()
        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 0)

    def test_local_rename_sync_root_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        # Use the Administrator to be able to introspect the container of the
        # test workspace.
        remote_client = RemoteDocumentClient(
            self.nuxeo_url, self.admin_user,
            'nxdrive-test-administrator-device',
            self.password, base_folder=self.workspace)

        folder_1_uid = remote_client.get_info(u'/Original Folder 1').uid

        # Create new clients to be able to introspect the test sync root
        toplevel_local_client = LocalClient(self.local_nxdrive_folder_1)

        toplevel_local_client.rename('/' + self.workspace_title,
            'Renamed Nuxeo Drive Test Workspace')
        self.assertEquals(ctl.synchronizer.update_synchronize_server(sb), 1)

        workspace_info = remote_client.get_info(self.workspace)
        self.assertEquals(workspace_info.name,
            u"Renamed Nuxeo Drive Test Workspace")

        folder_1_info = remote_client.get_info(folder_1_uid)
        self.assertEquals(folder_1_info.name, u"Original Folder 1")
        self.assertEquals(folder_1_info.parent_uid, self.workspace)

    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_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_rename_readonly_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1
        session = ctl.get_session()

        # Check local folder
        self.assertTrue(local_client.exists(u'/Original Folder 1'))
        folder_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original Folder 1').one()
        self.assertTrue(folder_1_state.remote_can_rename)

        # Set remote folder as readonly for test user
        folder_1_path = self.TEST_WORKSPACE_PATH + u'/Original Folder 1'
        op_input = "doc:" + folder_1_path
        self.root_remote_client.execute("Document.SetACE",
            input=op_input,
            user="******",
            permission="Write",
            grant="false")

        # Check can_rename flag in pair state
        folder_1_state.refresh_remote(
            client=self.remote_file_system_client_1)
        self.assertFalse(folder_1_state.remote_can_rename)

        # Rename local folder
        local_client.rename(u'/Original Folder 1',
                            u'Renamed Folder 1 \xe9')
        self.assertFalse(local_client.exists(u'/Original Folder 1'))
        self.assertTrue(local_client.exists(u'/Renamed Folder 1 \xe9'))

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

        # Check remote folder has not been renamed
        folder_1_remote_info = remote_client.get_info(
            u'/Original Folder 1')
        self.assertEquals(folder_1_remote_info.name,
            u'Original Folder 1')

        # Check state of local folder and its children
        folder_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Renamed Folder 1 \xe9').one()
        self.assertEquals(folder_1_state.local_name,
                          u'Renamed Folder 1 \xe9')
        self.assertEquals(folder_1_state.remote_name,
                          u'Original Folder 1')

        self.assertTrue(local_client.exists(
            u'/Renamed Folder 1 \xe9/Original File 1.1.txt'))
        file_1_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original File 1.1.txt').one()
        self.assertEquals(file_1_1_state.local_name,
                          u'Original File 1.1.txt')
        self.assertEquals(file_1_1_state.remote_name,
                          u'Original File 1.1.txt')

        self.assertTrue(local_client.exists(
            u'/Renamed Folder 1 \xe9/Sub-Folder 1.1'))
        folder_1_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Sub-Folder 1.1').one()
        self.assertEquals(folder_1_1_state.local_name,
                          u'Sub-Folder 1.1')
        self.assertEquals(folder_1_1_state.remote_name,
                          u'Sub-Folder 1.1')

        self.assertTrue(local_client.exists(
            u'/Renamed Folder 1 \xe9/Sub-Folder 1.2'))
        folder_1_2_state = session.query(LastKnownState).filter_by(
            local_name=u'Sub-Folder 1.2').one()
        self.assertEquals(folder_1_2_state.local_name,
                          u'Sub-Folder 1.2')
        self.assertEquals(folder_1_2_state.remote_name,
                          u'Sub-Folder 1.2')

    def test_local_delete_readonly_folder(self):
        sb, ctl = self.sb_1, self.controller_1
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1
        session = ctl.get_session()

        # Check local folder
        self.assertTrue(local_client.exists(u'/Original Folder 1'))
        folder_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original Folder 1').one()
        self.assertTrue(folder_1_state.remote_can_delete)

        # Set remote folder as readonly for test user
        folder_1_path = self.TEST_WORKSPACE_PATH + u'/Original Folder 1'
        op_input = "doc:" + folder_1_path
        self.root_remote_client.execute("Document.SetACE",
            input=op_input,
            user="******",
            permission="Write",
            grant="false")

        # Check can_delete flag in pair state
        folder_1_state.refresh_remote(
            client=self.remote_file_system_client_1)
        self.assertFalse(folder_1_state.remote_can_delete)

        # Delete local folder
        local_client.delete(u'/Original Folder 1')
        self.assertRaises(NotFound,
                          local_client.get_info, u'/Original Folder 1')

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

        # Check remote folder and its children have not been deleted
        folder_1_remote_info = remote_client.get_info(
            u'/Original Folder 1')
        self.assertEquals(folder_1_remote_info.name,
            u'Original Folder 1')

        file_1_1_remote_info = remote_client.get_info(
            u'/Original Folder 1/Original File 1.1.txt')
        self.assertEquals(file_1_1_remote_info.name,
            u'Original File 1.1.txt')

        folder_1_1_remote_info = remote_client.get_info(
            u'/Original Folder 1/Sub-Folder 1.1')
        self.assertEquals(folder_1_1_remote_info.name,
            u'Sub-Folder 1.1')

        folder_1_2_remote_info = remote_client.get_info(
            u'/Original Folder 1/Sub-Folder 1.2')
        self.assertEquals(folder_1_2_remote_info.name,
            u'Sub-Folder 1.2')

        # Check local folder and its children have been re-created
        self.assertTrue(local_client.exists(u'/Original Folder 1'))
        folder_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original Folder 1').one()
        self.assertEquals(folder_1_state.local_name,
                          u'Original Folder 1')
        self.assertEquals(folder_1_state.remote_name,
                          u'Original Folder 1')

        self.assertTrue(local_client.exists(
            u'/Original Folder 1/Original File 1.1.txt'))
        file_1_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Original File 1.1.txt').one()
        self.assertEquals(file_1_1_state.local_name,
                          u'Original File 1.1.txt')
        self.assertEquals(file_1_1_state.remote_name,
                          u'Original File 1.1.txt')

        self.assertTrue(local_client.exists(
            u'/Original Folder 1/Sub-Folder 1.1'))
        folder_1_1_state = session.query(LastKnownState).filter_by(
            local_name=u'Sub-Folder 1.1').one()
        self.assertEquals(folder_1_1_state.local_name,
                          u'Sub-Folder 1.1')
        self.assertEquals(folder_1_1_state.remote_name,
                          u'Sub-Folder 1.1')

        self.assertTrue(local_client.exists(
            u'/Original Folder 1/Sub-Folder 1.2'))
        folder_1_2_state = session.query(LastKnownState).filter_by(
            local_name=u'Sub-Folder 1.2').one()
        self.assertEquals(folder_1_2_state.local_name,
                          u'Sub-Folder 1.2')
        self.assertEquals(folder_1_2_state.remote_name,
                          u'Sub-Folder 1.2')