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()
class TestIntegrationReinitDatabase(IntegrationTestCase):

    def setUp(self):
        super(TestIntegrationReinitDatabase, self).setUp()
        self.syn, self.local, self.remote = self.init_default_drive()
        self.ctl = self.controller_1
        # Make a folder and a file
        self.remote.make_folder('/', 'Test folder')
        self.remote.make_file('/Test folder', 'Test.txt',
                              'This is some content')
        self.test_remote_folder_id = self.remote.get_info('/Test folder').uid
        # Wait for synchro
        self._synchronize()
        # Verify that all is synchronize
        self.assertTrue(self.local.exists('/Test folder'),
                        'Local folder should exist')
        self.assertTrue(self.local.exists('/Test folder/Test.txt'),
                        'Local file should exist')
        # Destroy database
        self._reinit_database()

    def tearDown(self):
        # Dispose dedicated Controller instantiated for this test
        # in _reinit_database()
        self.ctl.dispose()

        super(TestIntegrationReinitDatabase, self).tearDown()

    def _check_states(self):
        rows = self.controller_1.get_session().query(LastKnownState).all()
        for row in rows:
            self.assertEquals(row.pair_state, 'synchronized')

    def _reinit_database(self):
        # Close database
        self.ctl.dispose()
        # Destroy configuration folder
        shutil.rmtree(self.nxdrive_conf_folder_1)
        os.mkdir(self.nxdrive_conf_folder_1)
        # Recreate a controller
        self.ctl = Controller(self.nxdrive_conf_folder_1)
        self.ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        self.ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)
        self.syn = self.ctl.synchronizer

    def _synchronize(self, loops=1):
        super(TestIntegrationReinitDatabase, self)._synchronize(self.syn, loops)

    def _check_conflict_locally_handled(self):
        # As a conflict has been raised 2 files should be present locally
        self.assertEqual(len(self.local.get_children_info("/Test folder")), 2)
        self.assertEqual(len(self.remote.get_children_info(
                                            self.test_remote_folder_id)), 1)

    def _check_conflict_locally_and_remotely_handled(self):
        # End the conflict handling by uploading the second local file to
        # the server
        self.assertEqual(len(self.local.get_children_info("/Test folder")), 2)
        self.assertEqual(len(self.remote.get_children_info(
                                            self.test_remote_folder_id,
                                            types=('File', 'Note'))), 2)

    def test_synchronize_folderish_and_same_digest(self):
        # Reload sync
        self._synchronize()
        # Check everything is synchronized
        self._check_states()

    def test_synchronize_remote_change(self):
        # Modify the remote file
        self.remote.update_content('/Test folder/Test.txt',
                                   'Content has changed')
        # Sync
        self._synchronize()
        # Check a conflict is detected and handled locally
        self._check_conflict_locally_handled()
        # Assert content of the original file has changed
        self.assertEquals(self.local.get_content('/Test folder/Test.txt'),
                          'Content has changed',
                          'Local content should be the same as the remote one')
        # Sync again
        self._synchronize(3)
        # Check a conflict is handled locally and remotely
        self._check_conflict_locally_and_remotely_handled()
        # Check everything is synchronized
        self._check_states()

    def test_synchronize_local_change(self):
        # Modify the local file
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        self.local.update_content('/Test folder/Test.txt',
                                   'Content has changed')
        # Sync
        self._synchronize()
        # Check a conflict is detected and handled locally
        self._check_conflict_locally_handled()
        # Assert content of the original file has not changed
        self.assertEquals(self.local.get_content('/Test folder/Test.txt'),
                          'This is some content',
                          'Local content should be the same as the remote one')
        # Sync again
        self._synchronize(3)
        # Check a conflict is handled locally and remotely
        self._check_conflict_locally_and_remotely_handled()
        # Assert content has changed
        self.assertEquals(self.remote.get_content('/Test folder/Test.txt'),
                          'This is some content',
                          'Remote content should not have changed')
        # Check everything is synchronized
        self._check_states()

    def test_synchronize_remote_and_local_change(self):
        # Modify the remote file
        self.remote.update_content('/Test folder/Test.txt',
                                   'Content has remote changed')
        # Modify the local file
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        self.local.update_content('/Test folder/Test.txt',
                                   'Content has local changed')
        # Sync
        self._synchronize()
        # Check a conflict is detected and handled locally
        self._check_conflict_locally_handled()
        # Assert content of the original file has not changed
        self.assertEquals(self.local.get_content('/Test folder/Test.txt'),
                          'Content has remote changed',
                          'Local content should be the same as remote one')
        # Sync again
        self._synchronize(3)
        # Check a conflict is handled locally and remotely
        self._check_conflict_locally_and_remotely_handled()
        # Assert content has changed
        self.assertEquals(self.local.get_content('/Test folder/Test.txt'),
                        'Content has remote changed',
                        'Remote changed content should not have changed again')
        # Check everything is synchronized
        self._check_states()
class TestIntegrationReinitDatabase(IntegrationTestCase):

    def setUp(self):
        super(TestIntegrationReinitDatabase, self).setUp()
        self.syn, self.local, self.remote = self.init_default_drive()
        self.ctl = self.controller_1
        # Make a folder and a file
        self.remote.make_folder('/', 'Test folder')
        self.remote.make_file('/Test folder', 'Test.txt',
                              'This is some content')
        self.test_remote_folder_id = self.remote.get_info('/Test folder').uid
        # Wait for synchro
        self._synchronize()
        # Verify that all is synchronize
        self.assertTrue(self.local.exists('/Test folder'),
                        'Local folder should exist')
        self.assertTrue(self.local.exists('/Test folder/Test.txt'),
                        'Local file should exist')
        # Destroy database
        self._reinit_database()

    def tearDown(self):
        # Dispose dedicated Controller instantiated for this test
        # in _reinit_database()
        self.ctl.dispose()

        super(TestIntegrationReinitDatabase, self).tearDown()

    def _check_states(self):
        rows = self.controller_1.get_session().query(LastKnownState).all()
        for row in rows:
            self.assertEquals(row.pair_state, 'synchronized')

    def _reinit_database(self):
        # Close database
        self.ctl.dispose()
        # Destroy configuration folder
        shutil.rmtree(self.nxdrive_conf_folder_1)
        os.mkdir(self.nxdrive_conf_folder_1)
        # Recreate a controller
        self.ctl = Controller(self.nxdrive_conf_folder_1)
        self.ctl.bind_server(self.local_nxdrive_folder_1, self.nuxeo_url,
                        self.user_1, self.password_1)
        self.ctl.bind_root(self.local_nxdrive_folder_1, self.workspace)
        self.syn = self.ctl.synchronizer

    def _synchronize(self, loops=1):
        super(TestIntegrationReinitDatabase, self)._synchronize(self.syn,
                                                                loops)

    def _check_conflict_locally_handled(self):
        # As a conflict has been raised 2 files should be present locally
        self.assertEqual(len(self.local.get_children_info("/Test folder")), 2)
        self.assertEqual(len(self.remote.get_children_info(
                                            self.test_remote_folder_id)), 1)

    def _check_conflict_locally_and_remotely_handled(self):
        # End the conflict handling by uploading the second local file to
        # the server
        self.assertEqual(len(self.local.get_children_info("/Test folder")), 2)
        self.assertEqual(len(self.remote.get_children_info(
                                            self.test_remote_folder_id,
                                            types=('File', 'Note'))), 2)

    def test_synchronize_folderish_and_same_digest(self):
        # Reload sync
        self._synchronize()
        # Check everything is synchronized
        self._check_states()

    def test_synchronize_remote_change(self):
        # Modify the remote file
        self.remote.update_content('/Test folder/Test.txt',
                                   'Content has changed')
        # Sync
        self._synchronize()
        # Check a conflict is detected and handled locally
        self._check_conflict_locally_handled()
        # Assert content of the original file has changed
        self.assertEquals(self.local.get_content('/Test folder/Test.txt'),
                          'Content has changed',
                          'Local content should be the same as the remote one')
        # Sync again
        self._synchronize(3)
        # Check a conflict is handled locally and remotely
        self._check_conflict_locally_and_remotely_handled()
        # Check everything is synchronized
        self._check_states()

    def test_synchronize_local_change(self):
        # Modify the local file
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        self.local.update_content('/Test folder/Test.txt',
                                   'Content has changed')
        # Sync
        self._synchronize()
        # Check a conflict is detected and handled locally
        self._check_conflict_locally_handled()
        # Assert content of the original file has not changed
        self.assertEquals(self.local.get_content('/Test folder/Test.txt'),
                          'This is some content',
                          'Local content should be the same as the remote one')
        # Sync again
        self._synchronize(3)
        # Check a conflict is handled locally and remotely
        self._check_conflict_locally_and_remotely_handled()
        # Assert content has changed
        self.assertEquals(self.remote.get_content('/Test folder/Test.txt'),
                          'This is some content',
                          'Remote content should not have changed')
        # Check everything is synchronized
        self._check_states()

    def test_synchronize_remote_and_local_change(self):
        # Modify the remote file
        self.remote.update_content('/Test folder/Test.txt',
                                   'Content has remote changed')
        # Modify the local file
        time.sleep(self.OS_STAT_MTIME_RESOLUTION)
        self.local.update_content('/Test folder/Test.txt',
                                   'Content has local changed')
        # Sync
        self._synchronize()
        # Check a conflict is detected and handled locally
        self._check_conflict_locally_handled()
        # Assert content of the original file has not changed
        self.assertEquals(self.local.get_content('/Test folder/Test.txt'),
                          'Content has remote changed',
                          'Local content should be the same as remote one')
        # Sync again
        self._synchronize(3)
        # Check a conflict is handled locally and remotely
        self._check_conflict_locally_and_remotely_handled()
        # Assert content has changed
        self.assertEquals(self.local.get_content('/Test folder/Test.txt'),
                        'Content has remote changed',
                        'Remote changed content should not have changed again')
        # Check everything is synchronized
        self._check_states()
Esempio n. 4
0
class CliHandler(object):
    """Command Line Interface handler: parse options and execute operation"""

    def __init__(self):
        self.parser = make_cli_parser()

    def handle(self, args):
        # use the CLI parser to check that the first args is a valid command
        options = self.parser.parse_args(args)
        if options.debug:
            # Install Post-Mortem debugger hook

            def info(type, value, tb):
                traceback.print_exception(type, value, tb)
                print
                debugger.pm()

            sys.excepthook = info

        filename = options.log_filename
        if filename is None:
            filename = os.path.join(
                options.nxdrive_home, 'logs', 'nxdrive.log')

        configure(
            filename,
            file_level=options.log_level_file,
            console_level=options.log_level_console,
            process_name=options.command,
        )
        self.controller = Controller(options.nxdrive_home)

        handler = getattr(self, options.command, None)
        if handler is None:
            raise NotImplementedError(
                'No handler implemented for command ' + options.command)
        return handler(options)

    def start(self, options=None):
        self.controller.start()
        return 0

    def stop(self, options=None):
        self.controller.stop()
        return 0

    def console(self, options):

        fault_tolerant = not options.stop_on_error
        self.controller.loop(fault_tolerant=fault_tolerant,
                             delay=options.delay)
        return 0

    def status(self, options):
        states = self.controller.status(options.files)
        for filename, status in states:
            print status + '\t' + filename
        return 0

    def bind_server(self, options):
        if options.password is None:
            password = getpass()
        else:
            password = options.password
        self.controller.bind_server(options.local_folder, options.nuxeo_url,
                                    options.username, password)
        for root in options.remote_roots:
            self.controller.bind_root(options.local_folder, root,
                                      repository=options.remote_repo)
        return 0

    def unbind_server(self, options):
        self.controller.unbind_server(options.local_folder)
        return 0

    def bind_root(self, options):
        self.controller.bind_root(options.local_folder, options.remote_root,
                                  repository=options.remote_repo)
        return 0

    def unbind_root(self, options):
        self.controller.unbind_root(options.local_root)
        return 0

    def test(self, options):
        import nose
        # Monkeypatch nose usage message as it's complicated to include
        # the missing text resource in the frozen binary package
        nose.core.TestProgram.usage = lambda cls: ""
        argv = ['']

        if options.with_coverage:
            argv += [
                '--with-coverage',
                '--cover-package=nxdrive',
                '--cover-html',
                '--cover-html-dir=coverage',
            ]

        if options.with_profile:
            argv += [
                '--with-profile',
                '--profile-restrict=nxdrive',
            ]
        # List the test modules explicitly as recursive discovery is broken
        # when the app is frozen.
        argv += [
            "nxdrive.tests.test_controller",
            "nxdrive.tests.test_filesystem_client",
            "nxdrive.tests.test_integration_nuxeo_client",
            "nxdrive.tests.test_integration_synchronization",
        ]
        return 0 if nose.run(argv=argv) else 1