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'))
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_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()
def test_delete_root_folder(self): raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170") """Check that local delete of root maps to unbind_root on the server""" ctl = self.controller_1 sb = ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url, self.user_1, self.password_1) ctl.bind_root(self.local_nxdrive_folder_1, self.workspace) syn = ctl.synchronizer # Let's synchronize the new root self.assertEquals(syn.update_synchronize_server(sb), 1) self.assertEquals(ctl.list_pending(), []) self.assertEquals(self.get_all_states(), [ (u'/', u'synchronized', u'synchronized'), (u'/Nuxeo Drive Test Workspace', u'synchronized', u'synchronized'), ]) # Refetching the changes in the server audit log does not see any # change self.wait() self.assertEquals(syn.update_synchronize_server(sb), 0) self.assertEquals(ctl.list_pending(), []) # The workspace has been synced local = LocalClient(self.local_nxdrive_folder_1) self.assertTrue(local.exists('/' + self.workspace_title)) # Let's create a subfolder and synchronize it local.make_folder('/' + self.workspace_title, 'Folder 3') self.assertEquals(syn.update_synchronize_server(sb), 1) self.assertEquals(ctl.list_pending(), []) self.assertEquals(self.get_all_states(), [ (u'/', u'synchronized', u'synchronized'), (u'/Nuxeo Drive Test Workspace', u'synchronized', u'synchronized'), (u'/Nuxeo Drive Test Workspace/Folder 3', u'synchronized', u'synchronized'), ]) # Let's delete the root locally local.delete('/' + self.workspace_title) self.assertFalse(local.exists('/' + self.workspace_title)) self.assertEquals(syn.update_synchronize_server(sb), 1) self.assertEquals(self.get_all_states(), [ (u'/', u'synchronized', u'synchronized'), ]) # On the server this has been mapped to a root unregistration: # the workspace is still there self.assertTrue(self.remote_document_client_1.exists('/')) # The subfolder has not been deleted on the server self.assertTrue(self.remote_document_client_1.exists('/Folder 3')) # But the workspace folder is still not there on the client: self.assertFalse(local.exists('/' + self.workspace_title)) self.assertEquals(ctl.list_pending(), []) # Synchronizing later does not refetch the workspace as it's not # mapped as a sync root. self.wait() self.assertEquals(syn.update_synchronize_server(sb), 0) self.assertEquals(self.get_all_states(), [ (u'/', u'synchronized', u'synchronized'), ]) self.assertFalse(local.exists('/' + self.workspace_title)) # We can rebind the root and fetch back its content ctl.bind_root(self.local_nxdrive_folder_1, self.workspace) self.wait() self.wait() syn.loop(delay=0, max_loops=1, no_event_init=True) self.assertEquals(ctl.list_pending(), []) self.assertTrue(local.exists('/' + self.workspace_title)) self.assertTrue(local.exists('/' + self.workspace_title + '/Folder 3')) self.assertEquals(self.get_all_states(), [ (u'/', u'synchronized', u'synchronized'), (u'/Nuxeo Drive Test Workspace', u'synchronized', u'synchronized'), (u'/Nuxeo Drive Test Workspace/Folder 3', u'synchronized', u'synchronized'), ])
def test_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")
def test_synchronize_paged_delete_detection(self): # Initialize a controller with page size = 1 for deleted items # detection query ctl = Controller(self.nxdrive_conf_folder_1, page_size=1) ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url, self.user_1, self.password_1) ctl.bind_root(self.local_nxdrive_folder_1, self.workspace) # Launch first synchronization time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION) self.wait() syn = ctl.synchronizer syn.loop(delay=0.1, max_loops=1) # Get local and remote clients local = LocalClient(os.path.join(self.local_nxdrive_folder_1, self.workspace_title)) remote = self.remote_document_client_1 # Create a remote folder with 2 children then synchronize remote.make_folder('/', 'Remote folder',) remote.make_file('/Remote folder', 'Remote file 1.odt', 'Some content.') remote.make_file('/Remote folder', 'Remote file 2.odt', 'Other content.') time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION) self.wait() syn.loop(delay=0.1, max_loops=1) self.assertTrue(local.exists('/Remote folder')) self.assertTrue(local.exists('/Remote folder/Remote file 1.odt')) self.assertTrue(local.exists('/Remote folder/Remote file 2.odt')) # Delete remote folder then synchronize remote.delete('/Remote folder') time.sleep(self.AUDIT_CHANGE_FINDER_TIME_RESOLUTION) self.wait() syn.loop(delay=0.1, max_loops=1) self.assertFalse(local.exists('/Remote folder')) self.assertFalse(local.exists('/Remote folder/Remote file 1.odt')) self.assertFalse(local.exists('/Remote folder/Remote file 2.odt')) # Create a local folder with 2 children then synchronize local.make_folder('/', 'Local folder') local.make_file('/Local folder', 'Local file 1.odt', 'Some content.') local.make_file('/Local folder', 'Local file 2.odt', 'Other content.') syn.loop(delay=0.1, max_loops=1) self.assertTrue(remote.exists('/Local folder')) self.assertTrue(remote.exists('/Local folder/Local file 1.odt')) self.assertTrue(remote.exists('/Local folder/Local file 2.odt')) # Delete local folder then synchronize time.sleep(self.OS_STAT_MTIME_RESOLUTION) local.delete('/Local folder') syn.loop(delay=0.1, max_loops=1) self.assertFalse(remote.exists('/Local folder')) self.assertFalse(remote.exists('/Local folder/Local file 1.odt')) self.assertFalse(remote.exists('/Local folder/Local file 2.odt')) # Dispose dedicated Controller instantiated for this test ctl.dispose()
def test_delete_local_folder_2_clients(self): raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170") # Define 2 controllers, one for each device ctl1 = self.controller_1 ctl2 = self.controller_2 # Get local clients for each device and remote client local1 = LocalClient(self.local_nxdrive_folder_1) local2 = LocalClient(self.local_nxdrive_folder_2) remote = self.remote_document_client_1 # Bind each device to the server with the same account: # nuxeoDriveTestUser_user_1 and bind test workspace ctl1.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url, self.user_1, self.password_1) ctl2.bind_server(self.local_nxdrive_folder_2, self.nuxeo_url, self.user_1, self.password_1) ctl1.bind_root(self.local_nxdrive_folder_1, self.workspace) # Check synchronization roots for nuxeoDriveTestUser_user_1, # there should be 1, the test workspace sync_roots = remote.get_roots() self.assertEquals(len(sync_roots), 1) self.assertEquals(sync_roots[0].name, self.workspace_title) # Launch first synchronization on both devices self.wait() sync1 = ctl1.synchronizer sync2 = ctl2.synchronizer sync1.loop(delay=0.1, max_loops=1) sync2.loop(delay=0.1, max_loops=1) # Test workspace should be created locally on both devices self.assertTrue(local1.exists('/Nuxeo Drive Test Workspace')) self.assertTrue(local2.exists('/Nuxeo Drive Test Workspace')) # Make nuxeoDriveTestUser_user_1 create a remote folder in the # test workspace and a file inside this folder, # then synchronize both devices test_folder = remote.make_folder(self.workspace, 'Test folder') remote.make_file(test_folder, 'test.odt', 'Some content.') self.wait() sync1.loop(delay=0.1, max_loops=1) sync2.loop(delay=0.1, max_loops=1) # Test folder should be created locally on both devices self.assertTrue(local1.exists( '/Nuxeo Drive Test Workspace/Test folder')) self.assertTrue(local1.exists( '/Nuxeo Drive Test Workspace/Test folder/test.odt')) self.assertTrue(local2.exists( '/Nuxeo Drive Test Workspace/Test folder')) self.assertTrue(local2.exists( '/Nuxeo Drive Test Workspace/Test folder/test.odt')) # Delete Test folder locally on one of the devices local1.delete('/Nuxeo Drive Test Workspace/Test folder') self.assertFalse(local1.exists( '/Nuxeo Drive Test Workspace/Test folder')) # Launch synchronization on both devices in separate threads def sync1_loop(): sync1.loop(delay=1.0, max_loops=3) def sync2_loop(): sync2.loop(delay=1.0, max_loops=3) sync1_thread = Thread(target=sync1_loop) sync2_thread = Thread(target=sync2_loop) sync1_thread.start() sync2_thread.start() # Wait for synchronization threads to complete sync1_thread.join() sync2_thread.join() # Test folder should be deleted on the server and on both devices self.assertFalse(remote.exists(test_folder)) self.assertFalse(local1.exists( '/Nuxeo Drive Test Workspace/Test folder')) self.assertFalse(local2.exists( '/Nuxeo Drive Test Workspace/Test folder'))
def test_delete_local_folder_update_remote_folder_property(self): raise SkipTest("WIP in https://jira.nuxeo.com/browse/NXDRIVE-170") # Get local and remote clients local = LocalClient(self.local_nxdrive_folder_1) remote = self.remote_document_client_1 # Bind server and test workspace for nuxeoDriveTestUser_user_1 ctl = self.controller_1 ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url, self.user_1, self.password_1) ctl.bind_root(self.local_nxdrive_folder_1, self.workspace) # Launch first synchronization self.wait() sync = ctl.synchronizer sync.loop(delay=0.1, max_loops=1) # Test workspace should be created locally self.assertTrue(local.exists('/Nuxeo Drive Test Workspace')) # Create a local folder in the test workspace and a file inside # this folder, then synchronize local.make_folder('/Nuxeo Drive Test Workspace', 'Test folder') local.make_file('/Nuxeo Drive Test Workspace/Test folder', 'test.odt', 'Some content.') sync.loop(delay=0.1, max_loops=1) # Test folder should be created remotely in the test workspace self.assertTrue(remote.exists('/Test folder')) self.assertTrue(remote.exists('/Test folder/test.odt')) # Delete Test folder locally and remotely update one of its properties # concurrently, then synchronize local.delete('/Nuxeo Drive Test Workspace/Test folder') self.assertFalse(local.exists( '/Nuxeo Drive Test Workspace/Test folder')) test_folder_ref = remote._check_ref('/Test folder') # Wait for 1 second to make sure the folder's last modification time # will be different from the pair state's last remote update time time.sleep(REMOTE_MODIFICATION_TIME_RESOLUTION) remote.update(test_folder_ref, properties={'dc:description': 'Some description.'}) test_folder = remote.fetch(test_folder_ref) self.assertEqual(test_folder['properties']['dc:description'], 'Some description.') self.wait() sync.loop(delay=0.1, max_loops=1) # Test folder should be deleted remotely in the test workspace. # Even though fetching the remote changes will send a # 'documentModified' event for Test folder as a result of its # dc:description property update, since the folder will not have been # renamed nor moved since last synchronization, its remote pair state # will not be marked as 'modified', see Model.update_remote(). # Thus the pair state will be ('deleted', 'synchronized'), resolved as # 'locally_deleted'. self.assertFalse(remote.exists('/Test folder')) # Check Test folder has not been re-created locally self.assertFalse(local.exists( '/Nuxeo Drive Test Workspace/Test folder'))
def test_delete_local_folder_2_clients(self): # Define 2 controllers, one for each device ctl1 = self.controller_1 ctl2 = self.controller_2 # Get local clients for each device and remote client local1 = LocalClient(self.local_nxdrive_folder_1) local2 = LocalClient(self.local_nxdrive_folder_2) remote = self.remote_document_client_1 # Bind each device to the server with the same account: # nuxeoDriveTestUser_user_1 and bind test workspace ctl1.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url, self.user_1, self.password_1) ctl2.bind_server(self.local_nxdrive_folder_2, self.nuxeo_url, self.user_1, self.password_1) ctl1.bind_root(self.local_nxdrive_folder_1, self.workspace) # Check synchronization roots for nuxeoDriveTestUser_user_1, # there should be 1, the test workspace sync_roots = remote.get_roots() self.assertEquals(len(sync_roots), 1) self.assertEquals(sync_roots[0].name, self.workspace_title) # Launch first synchronization on both devices self.wait_audit_change_finder_if_needed() self.wait() sync1 = ctl1.synchronizer sync2 = ctl2.synchronizer sync1.loop(delay=0.1, max_loops=1) sync2.loop(delay=0.1, max_loops=1) # Test workspace should be created locally on both devices self.assertTrue(local1.exists('/Nuxeo Drive Test Workspace')) self.assertTrue(local2.exists('/Nuxeo Drive Test Workspace')) # Make nuxeoDriveTestUser_user_1 create a remote folder in the # test workspace and a file inside this folder, # then synchronize both devices test_folder = remote.make_folder(self.workspace, 'Test folder') remote.make_file(test_folder, 'test.odt', 'Some content.') self.wait_audit_change_finder_if_needed() self.wait() sync1.loop(delay=0.1, max_loops=1) sync2.loop(delay=0.1, max_loops=1) # Test folder should be created locally on both devices self.assertTrue(local1.exists( '/Nuxeo Drive Test Workspace/Test folder')) self.assertTrue(local1.exists( '/Nuxeo Drive Test Workspace/Test folder/test.odt')) self.assertTrue(local2.exists( '/Nuxeo Drive Test Workspace/Test folder')) self.assertTrue(local2.exists( '/Nuxeo Drive Test Workspace/Test folder/test.odt')) # Delete Test folder locally on one of the devices local1.delete('/Nuxeo Drive Test Workspace/Test folder') self.assertFalse(local1.exists( '/Nuxeo Drive Test Workspace/Test folder')) # Launch synchronization on both devices in separate threads def sync1_loop(): sync1.loop(delay=1.0, max_loops=3) def sync2_loop(): sync2.loop(delay=1.0, max_loops=3) sync1_thread = Thread(target=sync1_loop) sync2_thread = Thread(target=sync2_loop) sync1_thread.start() sync2_thread.start() # Wait for synchronization threads to complete sync1_thread.join() sync2_thread.join() # Test folder should be deleted on the server and on both devices self.assertFalse(remote.exists(test_folder)) self.assertFalse(local1.exists( '/Nuxeo Drive Test Workspace/Test folder')) self.assertFalse(local2.exists( '/Nuxeo Drive Test Workspace/Test folder'))
def test_delete_local_folder_update_remote_folder_property(self): # Get local and remote clients local = LocalClient(self.local_nxdrive_folder_1) remote = self.remote_document_client_1 # Bind server and test workspace for nuxeoDriveTestUser_user_1 ctl = self.controller_1 ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url, self.user_1, self.password_1) ctl.bind_root(self.local_nxdrive_folder_1, self.workspace) # Launch first synchronization self.wait_audit_change_finder_if_needed() self.wait() sync = ctl.synchronizer sync.loop(delay=0.1, max_loops=1) # Test workspace should be created locally self.assertTrue(local.exists('/Nuxeo Drive Test Workspace')) # Create a local folder in the test workspace and a file inside # this folder, then synchronize local.make_folder('/Nuxeo Drive Test Workspace', 'Test folder') local.make_file('/Nuxeo Drive Test Workspace/Test folder', 'test.odt', 'Some content.') sync.loop(delay=0.1, max_loops=1) # Test folder should be created remotely in the test workspace self.assertTrue(remote.exists('/Test folder')) self.assertTrue(remote.exists('/Test folder/test.odt')) # Delete Test folder locally and remotely update one of its properties # concurrently, then synchronize local.delete('/Nuxeo Drive Test Workspace/Test folder') self.assertFalse(local.exists( '/Nuxeo Drive Test Workspace/Test folder')) test_folder_ref = remote._check_ref('/Test folder') # Wait for 1 second to make sure the folder's last modification time # will be different from the pair state's last remote update time time.sleep(self.REMOTE_MODIFICATION_TIME_RESOLUTION) remote.update(test_folder_ref, properties={'dc:description': 'Some description.'}) test_folder = remote.fetch(test_folder_ref) self.assertEqual(test_folder['properties']['dc:description'], 'Some description.') self.wait_audit_change_finder_if_needed() self.wait() sync.loop(delay=0.1, max_loops=1) # Test folder should be deleted remotely in the test workspace. # Even though fetching the remote changes will send a # 'documentModified' event for Test folder as a result of its # dc:description property update, since the folder will not have been # renamed nor moved since last synchronization, its remote pair state # will not be marked as 'modified', see Model.update_remote(). # Thus the pair state will be ('deleted', 'synchronized'), resolved as # 'locally_deleted'. self.assertFalse(remote.exists('/Test folder')) # Check Test folder has not been re-created locally self.assertFalse(local.exists( '/Nuxeo Drive Test Workspace/Test folder'))
def test_binding_synchronization_empty_start(): 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) # Nothing to synchronize by default assert_equal(ctl.list_pending(), []) assert_equal(ctl.synchronize(), 0) # Let's create some document on the server make_server_tree() # By default nothing is detected assert_equal(ctl.list_pending(), []) # assert_equal(ctl.children_states(expected_folder), []) # Let's scan manually session = ctl.get_session() ctl.scan_remote(expected_folder, session) # Changes on the remote server have been detected... assert_equal(len(ctl.list_pending()), 11) # ...but nothing is yet visible locally as those files don't exist there # yet. # assert_equal(ctl.children_states(expected_folder), []) # Let's perform the synchronization assert_equal(ctl.synchronize(limit=100), 11) # We should now be fully 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")], ) local = LocalClient(expected_folder) assert_equal(local.get_content("/Folder 1/File 1.txt"), "aaa") assert_equal(local.get_content("/Folder 1/Folder 1.1/File 2.txt"), "bbb") assert_equal(local.get_content("/Folder 1/Folder 1.2/File 3.txt"), "ccc") assert_equal(local.get_content("/Folder 2/File 4.txt"), "ddd") assert_equal(local.get_content("/Folder 2/Duplicated File.txt"), "Some content.") assert_equal(local.get_content("/Folder 2/Duplicated File__1.txt"), "Other content.") # 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 do some local and remote changes concurrently local.delete("/File 5.txt") local.update_content("/Folder 1/File 1.txt", "aaaa") remote_client.update_content("/Folder 1/Folder 1.1/File 2.txt", "bbbb") remote_client.delete("/Folder 2") f3 = remote_client.make_folder(TEST_WORKSPACE, "Folder 3") remote_client.make_file(f3, "File 6.txt", content="ffff") local.make_folder("/", "Folder 4") # Rescan ctl.scan_local(expected_folder, session) ctl.scan_remote(expected_folder, session) assert_equal( 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"), ], ) # It is possible to fetch the full children states of the root though: full_states = ctl.children_states(expected_folder, full_states=True) assert_equal(len(full_states), 5) assert_equal(full_states[0][0].remote_name, "Folder 3") assert_equal(full_states[0][1], "children_modified") states = ctl.children_states(expected_folder + "/Folder 1") expected_states = [ (u"/Folder 1/File 1.txt", "locally_modified"), (u"/Folder 1/Folder 1.1", "children_modified"), (u"/Folder 1/Folder 1.2", "synchronized"), ] assert_equal(states, expected_states) states = ctl.children_states(expected_folder + "/Folder 1/Folder 1.1") expected_states = [(u"/Folder 1/Folder 1.1/File 2.txt", u"remotely_modified")] assert_equal(states, expected_states) states = ctl.children_states(expected_folder + "/Folder 2") expected_states = [ (u"/Folder 2/Duplicated File.txt", u"remotely_deleted"), (u"/Folder 2/Duplicated File__1.txt", u"remotely_deleted"), (u"/Folder 2/File 4.txt", u"remotely_deleted"), ] assert_equal(states, expected_states) # Perform synchronization assert_equal(ctl.synchronize(limit=100), 10) # We should now be fully synchronized again assert_equal(len(ctl.list_pending()), 0) assert_equal( 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"/Folder 1/File 1.txt", "synchronized"), (u"/Folder 1/Folder 1.1", "synchronized"), (u"/Folder 1/Folder 1.2", "synchronized"), ] assert_equal(states, expected_states) assert_equal(local.get_content("/Folder 1/File 1.txt"), "aaaa") assert_equal(local.get_content("/Folder 1/Folder 1.1/File 2.txt"), "bbbb") assert_equal(local.get_content("/Folder 3/File 6.txt"), "ffff") assert_equal(remote_client.get_content("/Folder 1/File 1.txt"), "aaaa") assert_equal(remote_client.get_content("/Folder 1/Folder 1.1/File 2.txt"), "bbbb") assert_equal(remote_client.get_content("/Folder 3/File 6.txt"), "ffff") # Rescan: no change to detect we should reach a fixpoint ctl.scan_local(expected_folder, session) ctl.scan_remote(expected_folder, session) assert_equal(len(ctl.list_pending()), 0) assert_equal( 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(1.0) local.update_content("/Folder 1/File 1.txt", "\x80") remote_client.update_content("/Folder 1/Folder 1.1/File 2.txt", "\x80") ctl.scan_local(expected_folder, session) ctl.scan_remote(expected_folder, session) assert_equal(ctl.synchronize(limit=100), 2) assert_equal(remote_client.get_content("/Folder 1/File 1.txt"), "\x80") assert_equal(local.get_content("/Folder 1/Folder 1.1/File 2.txt"), "\x80")
def test_local_scan(): ctl.bind_server(TEST_SYNCED_FOLDER, 'http://example.com/nuxeo', 'username', 'secret') ctl.bind_root(TEST_SYNCED_FOLDER, 'folder_1-nuxeo-ref') ctl.bind_root(TEST_SYNCED_FOLDER, 'folder_2-nuxeo-ref') root_1 = join(TEST_SYNCED_FOLDER, 'Folder 1') root_2 = join(TEST_SYNCED_FOLDER, 'Folder 2') client_1 = LocalClient(root_1) # Folder are registered but empty for now assert_equal(ctl.children_states(root_1), []) assert_equal(ctl.children_states(root_2), []) # Put some content under the first root client_1.make_file('/', 'File 1.txt', content="Initial 'File 1.txt' content") folder_3 = client_1.make_folder('/', 'Folder 3') client_1.make_file(folder_3, 'File 2.txt', content="Initial 'File 2.txt' content") # The states have not been updated assert_equal(ctl.children_states(root_1), []) assert_equal(ctl.children_states(root_2), []) # Scanning the other root will not updated the first root states. session = ctl.get_session() ctl.scan_local(root_2, session) assert_equal(ctl.children_states(root_1), []) # Scanning root_1 will find the changes ctl.scan_local(root_1, session) assert_equal(ctl.children_states(root_1), [ (u'/File 1.txt', u'unknown'), (u'/Folder 3', 'children_modified'), ]) folder_3_abs = os.path.join(root_1, 'Folder 3') assert_equal(ctl.children_states(folder_3_abs), [ (u'/Folder 3/File 2.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 do some changes client_1.delete('/File 1.txt') client_1.make_folder('/Folder 3', 'Folder 3.1') client_1.make_file('/Folder 3', 'File 3.txt', content="Initial 'File 3.txt' content") client_1.update_content('/Folder 3/File 2.txt', "Updated content for 'File 2.txt'") # If we don't do a rescan, the controller is not aware of the changes assert_equal(ctl.children_states(root_1), [ (u'/File 1.txt', u'unknown'), (u'/Folder 3', 'children_modified'), ]) folder_3_abs = os.path.join(root_1, 'Folder 3') assert_equal(ctl.children_states(folder_3_abs), [ (u'/Folder 3/File 2.txt', u'unknown'), ]) # Let's scan again ctl.scan_local(root_1, session) assert_equal(ctl.children_states(root_1), [ (u'/Folder 3', 'children_modified'), ]) assert_equal(ctl.children_states(folder_3_abs), [ (u'/Folder 3/File 2.txt', u'locally_modified'), (u'/Folder 3/File 3.txt', u'unknown'), (u'/Folder 3/Folder 3.1', u'unknown') ]) # Delete the toplevel folder that has not been synchronised to the # server client_1.delete('/Folder 3') ctl.scan_local(root_1, session) assert_equal(ctl.children_states(root_1), []) assert_equal(ctl.children_states(folder_3_abs), [])