Пример #1
0
    def test_invalid_credentials(self):
        # Perform first scan and sync
        self.engine_1.start()
        self.wait_sync(wait_for_async=True)

        # Simulate bad responses
        remote_orig = self.engine_1.remote
        self.engine_1.remote = RemoteTest(
            pytest.nuxeo_url,
            self.user_1,
            "nxdrive-test-administrator-device",
            pytest.version,
            password=self.password_1,
        )
        errors = [
            HTTPError(status=401, message="Mock"),
            HTTPError(status=403, message="Mock"),
        ]
        remote = self.engine_1.remote
        remote.request_token()
        for error in errors:
            remote.make_server_call_raise(error)
            self.wait_sync(wait_for_async=True, fail_if_timeout=False)
            assert self.engine_1.is_offline()

            self.engine_1.set_offline(value=False)
            self.engine_1.set_invalid_credentials(value=False)
            self.engine_1.resume()

        # Re-enable network
        remote.make_server_call_raise(None)
        self.engine_1.remote = remote_orig
Пример #2
0
 def unlock(*_, **__):
     """
     Patch Remote.unlock() so that it raises
     a specific HTTPError.
     """
     err = f"(Mock'ed) Document already locked by {self.user_1}"
     raise HTTPError(status=500, message=err)
Пример #3
0
    def test_local_move_with_remote_error(self):
        local = self.local_1
        remote = self.remote_document_client_1

        # Check local folder
        assert local.exists("/Original Folder 1")

        # Simulate server error
        bad_remote = self.get_bad_remote()
        error = HTTPError(status=500, message="Mock server error")
        bad_remote.make_server_call_raise(error)

        with patch.object(self.engine_1, "remote", new=bad_remote):
            local.rename("/Original Folder 1", "OSErrorTest")
            self.wait_sync(timeout=5, fail_if_timeout=False)
            folder_1 = remote.get_info("/Original Folder 1")
            assert folder_1.name == "Original Folder 1"
            assert local.exists("/OSErrorTest")

        # Set engine online as starting from here the behavior is restored
        self.engine_1.set_offline(value=False)

        self.wait_sync()
        folder_1 = remote.get_info(folder_1.uid)
        assert folder_1.name == "OSErrorTest"
        assert local.exists("/OSErrorTest")
        assert len(local.get_children_info("/OSErrorTest")) == 3
        assert len(remote.get_children_info(folder_1.uid)) == 3
        assert len(local.get_children_info("/")) == 4
        assert len(remote.get_children_info(self.workspace)) == 4
    def test_synchronize_error_remote(self):
        path = Path(f"/{self.workspace_title}") / "test.odt"
        remote = self.remote_document_client_1
        dao = self.engine_1.dao

        bad_remote = self.get_bad_remote()
        error = HTTPError(status=400, message="Mock")
        bad_remote.make_download_raise(error)

        with patch.object(self.engine_1, "remote", new=bad_remote):
            remote.make_file("/", "test.odt", content=b"Some content.")

            self.engine_1.start()
            self.wait_sync(wait_for_async=True)
            self.engine_1.stop()

            pair = dao.get_state_from_local(path)
            assert pair is not None
            assert pair.error_count
            assert pair.pair_state == "remotely_created"

            self.engine_1.start()
            self.wait_sync()
            pair = dao.get_state_from_local(path)
            assert pair.error_count == 4
            assert pair.pair_state == "remotely_created"

        # Requeue errors
        self.engine_1.retry_pair(pair.id)
        self.wait_sync()
        pair = dao.get_state_from_local(path)
        assert not pair.error_count
        assert pair.pair_state == "synchronized"
    def test_416_range_past_eof(self):
        """
        Test wrong bytes range during download.
        """

        remote = self.remote_document_client_1
        local = self.local_1
        engine = self.engine_1

        engine.start()
        self.wait_sync(wait_for_async=True)
        assert local.exists("/")

        remote.make_file("/", "test.bin", content=b"42")

        # Simulate a requested range not satisfiable on file download
        bad_remote = self.get_bad_remote()
        error = HTTPError(status=416,
                          message="Mock Requested Range Not Satisfiable")
        bad_remote.make_download_raise(error)

        with patch.object(self.engine_1, "remote", new=bad_remote):
            self.wait_sync(fail_if_timeout=False)
            # Checks
            assert engine.dao.queue_manager.get_errors_count() == 1

        # Starting here, default behavior is restored
        self.wait_sync()

        # Checks
        assert not engine.dao.get_errors()
        assert local.exists("/test.bin")
Пример #6
0
    def test_synchronize_error_remote(self):
        path = "/" + self.workspace_title + "/test.odt"
        remote = self.remote_document_client_1

        self.engine_1.remote = RemoteTest(
            pytest.nuxeo_url,
            self.user_1,
            "nxdrive-test-administrator-device",
            pytest.version,
            password=self.password_1,
        )
        self.engine_1.remote.make_download_raise(HTTPError(status=400, message="Mock"))
        remote.make_file("/", "test.odt", content=b"Some content.")
        self.engine_1.start()
        self.wait_sync(wait_for_async=True, fail_if_timeout=False)
        self.engine_1.stop()
        pair = self.engine_1.get_dao().get_state_from_local(path)
        assert pair.error_count == 4
        assert pair.pair_state == "remotely_created"
        self.engine_1.start()
        self.wait_sync(fail_if_timeout=False)
        pair = self.engine_1.get_dao().get_state_from_local(path)
        assert pair.error_count == 4
        assert pair.pair_state == "remotely_created"
        self.engine_1.remote.make_download_raise(None)
        # Requeue errors
        self.engine_1.retry_pair(pair.id)
        self.wait_sync(fail_if_timeout=False)
        pair = self.engine_1.get_dao().get_state_from_local(path)
        assert not pair.error_count
        assert pair.pair_state == "synchronized"
Пример #7
0
    def test_direct_edit_max_error(self):
        """
        When uploading changes to the server, recurrent errors can happen.
        The upload must be retried maximum *Options.max_errors* times before being dropped.
        """
        filename = "error.txt"
        doc_id = self.remote.make_file_with_blob("/", filename,
                                                 b"Initial content.")
        local_path = f"/{doc_id}_file-content/{filename}"

        with patch.object(self.manager_1,
                          "open_local_file",
                          new=open_local_file):
            self.direct_edit._prepare_edit(self.nuxeo_url, doc_id)
            self.wait_sync(timeout=2, fail_if_timeout=False)

        # Simulate server error
        bad_remote = self.get_bad_remote()
        bad_remote.make_upload_raise(
            HTTPError(status=404, message="Mock'ed Client Error: Not Found"))

        with patch.object(self.engine_1, "remote", new=bad_remote):
            # Update file content
            self.local.update_content(local_path, b"Updated")
            self.wait_sync(timeout=30)

        # The file should _not_ be updated on the server
        content = self.remote.get_blob(self.remote.get_info(doc_id))
        assert content == b"Initial content."

        # There must be no error has the upload has been dropped.
        assert self.direct_edit._error_queue.empty()

        # Upload errors dict must be empty
        assert not self.direct_edit._upload_errors
Пример #8
0
    def test_synchronization_offline(self):
        # Bound root but nothing is synchronized yet
        local = self.local_1
        assert not local.exists("/")

        # Perform first scan and sync
        self.engine_1.start()
        self.wait_sync(wait_for_async=True)
        assert local.exists("/")
        self.engine_1.stop()

        # Let's create some documents on the client and the server
        local.make_folder("/", "Folder 3")
        self.make_server_tree(deep=False)

        # Find various ways to simulate a network failure
        self.engine_1.remote = RemoteTest(
            pytest.nuxeo_url,
            self.user_1,
            "nxdrive-test-administrator-device",
            pytest.version,
            password=self.password_1,
        )
        errors = [
            ConnectionError("Mock connection error"),
            socket.error("Mock socket error"),
            HTTPError(status=503, message="Mock"),
        ]
        engine_started = False
        for error in errors:
            self.engine_1.remote.make_server_call_raise(error)
            if not engine_started:
                self.engine_1.start()
                engine_started = True

            # Synchronization doesn't occur but does not fail either.
            # - one 'locally_created' error is registered for Folder 3
            # - no states are inserted for the remote documents
            self.wait_sync(wait_for_async=True, fail_if_timeout=False)
            workspace_children = self.engine_1.get_dao().get_states_from_partial_local(
                "/" + self.workspace_title + "/"
            )
            assert len(workspace_children) == 1
            assert workspace_children[0].pair_state != "synchronized"
            assert not self.engine_1.is_offline()

        # Re-enable network
        self.engine_1.remote.make_server_call_raise(None)

        # Verify that everything now gets synchronized
        self.wait_sync(wait_for_async=True)
        assert not self.engine_1.is_offline()
        assert not self.engine_1.get_dao().get_errors(limit=0)
        workspace_children = self.engine_1.get_dao().get_states_from_partial_local(
            "/" + self.workspace_title + "/"
        )
        assert len(workspace_children) == 4
        for state in workspace_children:
            assert state.pair_state == "synchronized"
Пример #9
0
def test_crafted_httperror_parse():
    cls = HTTPError()
    exc = cls.parse({
        "message": "oups",
        "stacktrace": "NulPointerException: bla*3"
    })
    assert exc.status == -1
    assert exc.message == "oups"
    assert exc.stacktrace == "NulPointerException: bla*3"
Пример #10
0
    def test_409_conflict(self):
        """
        Test concurrent upload with files having the same first characters.
        """

        remote = self.remote_document_client_1
        local = self.local_1
        engine = self.engine_1

        engine.start()
        self.wait_sync(wait_for_async=True)

        def _raise_for_second_file_only(*args, **kwargs):
            return kwargs.get("filename").endswith("2.txt")

        # Simulate a server conflict on file upload
        engine.remote = RemoteTest(
            pytest.nuxeo_url,
            self.user_1,
            "nxdrive-test-administrator-device",
            pytest.version,
            password=self.password_1,
        )
        error = HTTPError(status=409, message="Mock Conflict")
        engine.remote.make_upload_raise(error)
        engine.remote.raise_on = _raise_for_second_file_only

        # Create 2 files locally
        base = "A" * 40
        file1 = base + "1.txt"
        file2 = base + "2.txt"
        local.make_file("/", file1, content=b"foo")
        local.make_file("/", file2, content=b"bar")

        self.wait_sync(fail_if_timeout=False)

        # Checks
        assert engine.get_dao()._queue_manager.get_errors_count() == 1
        children = remote.get_children_info(self.workspace)
        assert len(children) == 1
        assert children[0].name == file1

        # Re-enable default behavior
        engine.remote.reset_errors()

        self.wait_sync()

        # Checks
        children = remote.get_children_info(self.workspace)
        assert len(children) == 2
        assert children[0].name == file1
        assert children[1].name == file2
    def test_synchronization_give_up(self):
        # Override error threshold to 1 instead of 3
        test_error_threshold = 1
        self.queue_manager_1._error_threshold = test_error_threshold

        # Bound root but nothing is synchronized yet
        local = self.local_1
        dao = self.engine_1.dao
        workspace_path = Path(self.workspace_title)
        assert not local.exists("/")

        # Perform first scan and sync
        self.engine_1.start()
        self.wait_sync(wait_for_async=True)
        assert local.exists("/")
        self.engine_1.stop()

        # Let's create some documents on the client and the server
        local.make_folder("/", "Folder 3")
        self.make_server_tree(deep=False)

        # Simulate a server failure on file download
        bad_remote = self.get_bad_remote()
        error = HTTPError(status=500, message="Mock download error")
        bad_remote.make_download_raise(error)

        # File is not synchronized but synchronization does not fail either,
        # errors are handled and queue manager has given up on them
        with patch.object(self.engine_1, "remote", new=bad_remote):
            self.engine_1.start()
            self.wait_sync(wait_for_async=True, timeout=60)
            states_in_error = dao.get_errors(limit=test_error_threshold)
            assert len(states_in_error) == 1
            children = dao.get_states_from_partial_local(workspace_path)
            assert len(children) == 4
            for state in children:
                if state.folderish:
                    assert state.pair_state == "synchronized"
                else:
                    assert state.pair_state != "synchronized"

        # Reset errors
        for state in states_in_error:
            dao.reset_error(state)

        # Verify that everything now gets synchronized
        self.wait_sync()
        assert not dao.get_errors(limit=test_error_threshold)
        children = dao.get_states_from_partial_local(workspace_path)
        assert len(children) == 4
        for child in children:
            assert child.pair_state == "synchronized"
    def test_synchronization_offline(self):
        # Bound root but nothing is synchronized yet
        local = self.local_1
        dao = self.engine_1.dao
        workspace_path = Path(self.workspace_title)
        assert not local.exists("/")

        # Perform first scan and sync
        self.engine_1.start()
        self.wait_sync(wait_for_async=True)
        assert local.exists("/")
        self.engine_1.stop()

        # Let's create some documents on the client and the server
        local.make_folder("/", "Folder 3")
        self.make_server_tree(deep=False)

        # Find various ways to simulate a network failure
        bad_remote = self.get_bad_remote()
        errors = [
            ConnectionError("Mock connection error"),
            OSError("Mock socket error"),  # Old socket.error
            HTTPError(status=503, message="Mock"),
        ]

        engine_started = False
        with patch.object(self.engine_1, "remote", new=bad_remote):
            for error in errors:
                self.engine_1.remote.make_server_call_raise(error)
                if not engine_started:
                    self.engine_1.start()
                    engine_started = True

                # Synchronization doesn't occur but does not fail either.
                # - one 'locally_created' error is registered for Folder 3
                # - no states are inserted for the remote documents
                self.wait_sync(wait_for_async=True, fail_if_timeout=False)
                children = dao.get_states_from_partial_local(workspace_path)
                assert len(children) == 1
                assert children[0].pair_state != "synchronized"
                assert not self.engine_1.is_offline()

        # Starting here, the network is re-enable
        # Verify that everything now gets synchronized
        self.wait_sync(wait_for_async=True)
        assert not self.engine_1.is_offline()
        assert not dao.get_errors(limit=0)
        children = dao.get_states_from_partial_local(workspace_path)
        assert len(children) == 4
        for state in children:
            assert state.pair_state == "synchronized"
Пример #13
0
    def test_409_conflict(self):
        """
        Test concurrent upload with files having the same first characters.
        """

        remote = self.remote_document_client_1
        local = self.local_1
        engine = self.engine_1

        engine.start()
        self.wait_sync(wait_for_async=True)
        assert local.exists("/")

        def _raise_for_second_file_only(*args, **kwargs):
            return kwargs.get("filename").endswith("2.txt")

        # Simulate a server conflict on file upload
        bad_remote = self.get_bad_remote()
        error = HTTPError(status=409, message="Mock Conflict")
        bad_remote.make_upload_raise(error)
        bad_remote.raise_on = _raise_for_second_file_only

        with patch.object(self.engine_1, "remote", new=bad_remote):
            # Create 2 files locally
            base = "A" * 40
            file1 = base + "1.txt"
            file2 = base + "2.txt"
            local.make_file("/", file1, content=b"foo")
            local.make_file("/", file2, content=b"bar")

            self.wait_sync(fail_if_timeout=False)

            # Checks
            assert engine.dao.queue_manager.get_errors_count() == 1
            children = remote.get_children_info(self.workspace)
            assert len(children) == 1
            assert children[0].name == file1

        # Starting here, default behavior is restored
        self.wait_sync()

        # Checks
        children = remote.get_children_info(self.workspace)
        assert len(children) == 2
        assert children[0].name == file1
        assert children[1].name == file2
Пример #14
0
            def link_blob_to_doc(self, *args, **kwargs):
                # Call the original method to effectively end the upload process
                super().link_blob_to_doc(*args, **kwargs)

                # The file should be present on the server
                # assert self.remote.exists(f"/{file}")

                # There should be 1 upload with DONE transfer status
                uploads = list(dao.get_uploads())
                assert len(uploads) == 1
                upload = uploads[0]
                assert upload.status == TransferStatus.DONE

                # And throw an error
                stack = "The proxy server received an invalid response from an upstream server."
                raise HTTPError(status=502,
                                message="Mocked Proxy Error",
                                stacktrace=stack)
Пример #15
0
    def test_local_move_with_remote_error(self):
        local = self.local_1
        remote = self.remote_document_client_1

        # Check local folder
        assert local.exists("/Original Folder 1")

        # Simulate server error
        self.engine_1.remote = RemoteTest(
            pytest.nuxeo_url,
            self.user_1,
            "nxdrive-test-administrator-device",
            pytest.version,
            password=self.password_1,
        )
        error = HTTPError(status=500, message="Mock server error")
        self.engine_1.remote.make_server_call_raise(error)

        local.rename("/Original Folder 1", "OSErrorTest")
        self.wait_sync(timeout=5, fail_if_timeout=False)
        folder_1 = remote.get_info("/Original Folder 1")
        assert folder_1.name == "Original Folder 1"
        assert local.exists("/OSErrorTest")

        # Remove faulty client and set engine online
        self.engine_1.remote.make_server_call_raise(None)
        self.engine_1.set_offline(value=False)

        self.wait_sync()
        folder_1 = remote.get_info(folder_1.uid)
        assert folder_1.name == "OSErrorTest"
        assert local.exists("/OSErrorTest")
        assert len(local.get_children_info("/OSErrorTest")) == 3
        assert len(remote.get_children_info(folder_1.uid)) == 3
        assert len(local.get_children_info("/")) == 4
        assert len(remote.get_children_info(self.workspace_1)) == 4
Пример #16
0
 def upload_part(*args, **kwargs):
     raise HTTPError(409, "Conflict", "Mock'ed error")
Пример #17
0
 def link_blob_to_doc(self, *args, **kwargs):
     """Throw an network error."""
     raise HTTPError(status=504, message="Mocked Gateway timeout")
Пример #18
0
 def bad_request(*args, **kwargs):
     raise HTTPError(500, "Server Error", "Mock'ed error")
Пример #19
0
def test_crafted_httperror():
    exc = HTTPError()
    assert exc.status == -1
    assert exc.message is None
    assert exc.stacktrace is None
Пример #20
0
def test_crafted_httperror_with_message():
    exc = HTTPError(message="oups")
    assert exc.status == -1
    assert exc.message == "oups"
    assert exc.stacktrace is None
Пример #21
0
def test_crafted_httperror_with_message_and_stacktrace():
    exc = HTTPError(message="oups", stacktrace="NulPointerException: bla*3")
    assert exc.status == -1
    assert exc.message == "oups"
    assert exc.stacktrace == "NulPointerException: bla*3"
Пример #22
0
 def get(*args, **kwargs):
     """Mimic the error message when a converter is not available."""
     raise HTTPError(message=f"{converter} is not available")
Пример #23
0
 def upload(*_, **__):
     """Mocked remote.upload method that raises a HTTPError 413"""
     raise HTTPError(
         status=413,
         message="Mock'ed Client Error: Request Entity Too Large")
Пример #24
0
    def test_synchronization_give_up(self):
        # Override error threshold to 1 instead of 3
        test_error_threshold = 1
        self.queue_manager_1._error_threshold = test_error_threshold

        # Bound root but nothing is synchronized yet
        local = self.local_1
        assert not local.exists("/")

        # Perform first scan and sync
        self.engine_1.start()
        self.wait_sync(wait_for_async=True)
        assert local.exists("/")
        self.engine_1.stop()

        # Let's create some documents on the client and the server
        local.make_folder("/", "Folder 3")
        self.make_server_tree(deep=False)

        # Simulate a server failure on file download
        self.engine_1.remote = RemoteTest(
            pytest.nuxeo_url,
            self.user_1,
            "nxdrive-test-administrator-device",
            pytest.version,
            password=self.password_1,
        )
        error = HTTPError(status=500, message="Mock download error")
        self.engine_1.remote.make_download_raise(error)

        # File is not synchronized but synchronization does not fail either,
        # errors are handled and queue manager has given up on them
        self.engine_1.start()
        self.wait_sync(wait_for_async=True, timeout=60)
        states_in_error = self.engine_1.get_dao().get_errors(limit=test_error_threshold)
        assert len(states_in_error) == 1
        workspace_children = self.engine_1.get_dao().get_states_from_partial_local(
            "/" + self.workspace_title + "/"
        )
        assert len(workspace_children) == 4
        for state in workspace_children:
            if state.folderish:
                assert state.pair_state == "synchronized"
            else:
                assert state.pair_state != "synchronized"

        # Remove faulty client and reset errors
        self.engine_1.remote.make_download_raise(None)
        for state in states_in_error:
            self.engine_1.get_dao().reset_error(state)

        # Verify that everything now gets synchronized
        self.wait_sync()
        states_in_error = self.engine_1.get_dao().get_errors(limit=test_error_threshold)
        assert not states_in_error
        workspace_children = self.engine_1.get_dao().get_states_from_partial_local(
            "/" + self.workspace_title + "/"
        )
        assert len(workspace_children) == 4
        for state in workspace_children:
            assert state.pair_state == "synchronized"
Пример #25
0
 def put_object(*args, **kwargs):
     raise HTTPError(409, "Conflict", "Mock'ed error")