Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/5'
Browse files Browse the repository at this point in the history
  • Loading branch information
TheOneRing committed Jan 11, 2024
2 parents 0960f8e + 484884c commit 5084755
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 55 deletions.
6 changes: 6 additions & 0 deletions changelog/unreleased/11467
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Bugfix: Client stuck in `reconnecting`

Properly handle errors during the update of the server settings.
Due to an unhandled result, the client could get stuck in a `reconnecting` state.

https://github.com/owncloud/client/pull/11467
31 changes: 24 additions & 7 deletions src/gui/connectionvalidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,30 @@ void ConnectionValidator::slotAuthSuccess()
const auto unsupportedServerError = [this] {
_errors.append({tr("The configured server for this client is too old."), tr("Please update to the latest server and restart the client.")});
};
connect(fetchSetting, &FetchServerSettingsJob::unknownServerDetected, unsupportedServerError);
connect(fetchSetting, &FetchServerSettingsJob::unsupportedServerDetected, [unsupportedServerError, this] {
unsupportedServerError();
reportResult(ServerVersionMismatch);
});

connect(fetchSetting, &FetchServerSettingsJob::finishedSignal, this, [this] { reportResult(Connected); });
connect(
fetchSetting, &FetchServerSettingsJob::finishedSignal, this, [fetchSetting, unsupportedServerError, this](FetchServerSettingsJob::Result result) {
switch (result) {
case FetchServerSettingsJob::Result::UnsupportedServer:
unsupportedServerError();
reportResult(ServerVersionMismatch);
break;
case FetchServerSettingsJob::Result::InvalidCredentials:
reportResult(CredentialsWrong);
break;
case FetchServerSettingsJob::Result::TimeOut:
reportResult(Timeout);
break;
case FetchServerSettingsJob::Result::Success:
if (_account->serverSupportLevel() == Account::ServerSupportLevel::Unknown) {
unsupportedServerError();
}
reportResult(Connected);
break;
case FetchServerSettingsJob::Result::Undefined:
reportResult(Undefined);
break;
}
});

fetchSetting->start();
return;
Expand Down
55 changes: 32 additions & 23 deletions src/gui/fetchserversettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,25 @@ void FetchServerSettingsJob::start()
_account->setHttp2Supported(reply->attribute(QNetworkRequest::Http2WasUsedAttribute).toBool());
}
_account->setCapabilities({_account->url(), caps.toVariantMap()});
if (checkServerInfo()) {
auto *userJob = new JsonApiJob(_account, QStringLiteral("ocs/v2.php/cloud/user"), SimpleNetworkJob::UrlQuery{}, QNetworkRequest{}, this);
userJob->setAuthenticationJob(isAuthJob());
userJob->setTimeout(timeoutC);
connect(userJob, &JsonApiJob::finishedSignal, this, [userJob, this] {
// We cannot deal with servers < 10.0.0
switch (_account->serverSupportLevel()) {
case Account::ServerSupportLevel::Unknown:
[[fallthrough]];
case Account::ServerSupportLevel::Supported:
break;
case Account::ServerSupportLevel::Unsupported:
Q_EMIT finishedSignal(Result::UnsupportedServer);
return;
}
auto *userJob = new JsonApiJob(_account, QStringLiteral("ocs/v2.php/cloud/user"), SimpleNetworkJob::UrlQuery{}, QNetworkRequest{}, this);
userJob->setAuthenticationJob(isAuthJob());
userJob->setTimeout(timeoutC);
connect(userJob, &JsonApiJob::finishedSignal, this, [userJob, this] {
if (userJob->timedOut()) {
Q_EMIT finishedSignal(Result::TimeOut);
} else if (userJob->httpStatusCode() == 401) {
Q_EMIT finishedSignal(Result::InvalidCredentials);
} else if (userJob->ocsSuccess()) {
const auto userData = userJob->data().value(QStringLiteral("ocs")).toObject().value(QStringLiteral("data")).toObject();
const QString user = userData.value(QStringLiteral("id")).toString();
if (!user.isEmpty()) {
Expand All @@ -72,9 +86,19 @@ void FetchServerSettingsJob::start()
_account->setDavDisplayName(displayName);
}
runAsyncUpdates();
Q_EMIT finishedSignal();
});
userJob->start();
Q_EMIT finishedSignal(Result::Success);
} else {
Q_EMIT finishedSignal(Result::Undefined);
}
});
userJob->start();
} else {
if (job->timedOut()) {
Q_EMIT finishedSignal(Result::TimeOut);
} else if (job->httpStatusCode() == 401) {
Q_EMIT finishedSignal(Result::InvalidCredentials);
} else {
Q_EMIT finishedSignal(Result::Undefined);
}
}
});
Expand Down Expand Up @@ -103,21 +127,6 @@ void FetchServerSettingsJob::runAsyncUpdates()
jsonJob->start();
}
}
bool FetchServerSettingsJob::checkServerInfo()
{
// We cannot deal with servers < 10.0.0
switch (_account->serverSupportLevel()) {
case Account::ServerSupportLevel::Supported:
break;
case Account::ServerSupportLevel::Unknown:
Q_EMIT unknownServerDetected();
break;
case Account::ServerSupportLevel::Unsupported:
Q_EMIT unsupportedServerDetected();
return false;
}
return true;
}

bool FetchServerSettingsJob::isAuthJob() const
{
Expand Down
17 changes: 3 additions & 14 deletions src/gui/fetchserversettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,21 @@ class FetchServerSettingsJob : public QObject
{
Q_OBJECT
public:
enum class Result { Success, TimeOut, InvalidCredentials, UnsupportedServer, Undefined };
Q_ENUM(Result);
FetchServerSettingsJob(const AccountPtr &account, QObject *parent);

void start();

Q_SIGNALS:
/***
* The version of the server is unsupported
*/
void unsupportedServerDetected();

/***
* We failed to detect the server version
*/
void unknownServerDetected();

void finishedSignal();
void finishedSignal(Result);

private:
void runAsyncUpdates();

bool checkServerInfo();

// returns whether the started jobs should be excluded from the retry queue
bool isAuthJob() const;


const AccountPtr _account;
};

Expand Down
4 changes: 4 additions & 0 deletions test/gui/shared/scripts/helpers/FilesHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,7 @@ def get_file_size_on_disk(resource_path):
raise Exception(
"'get_file_size_on_disk' function is only supported for Windows OS."
)


def get_file_size(resource_path):
return os.stat(resource_path).st_size
45 changes: 45 additions & 0 deletions test/gui/shared/scripts/pageObjects/SyncConnection.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import names
import squish
import object

from helpers.ConfigHelper import get_config

Expand All @@ -22,6 +23,12 @@ class SyncConnection:
"visible": 1,
"window": names.disable_virtual_file_support_QMessageBox,
}
SELECTIVE_SYNC_APPLY_BUTTON = {
"container": names.settings_stack_QStackedWidget,
"name": "selectiveSyncApply",
"type": "QPushButton",
"visible": 1,
}

@staticmethod
def openMenu():
Expand Down Expand Up @@ -62,3 +69,41 @@ def disableVFS():
@staticmethod
def hasMenuItem(item):
return squish.waitForObjectItem(SyncConnection.MENU, item)

@staticmethod
def menu_item_exists(menuItem):
obj = SyncConnection.MENU.copy()
obj.update({"type": "QAction", "text": menuItem})
return object.exists(obj)

@staticmethod
def choose_what_to_sync():
SyncConnection.openMenu()
SyncConnection.performAction("Choose what to sync")

@staticmethod
def unselect_folder_in_selective_sync(folder_name):
sync_folders = object.children(
squish.waitForObject(SyncConnection.FOLDER_SYNC_CONNECTION)
)
for sync_folder in sync_folders:
# TODO: allow selective sync in other sync folders as well
if hasattr(sync_folder, "text") and sync_folder.text == "Personal":
items = object.children(sync_folder)
for item in items:
if hasattr(item, "text") and item.text:
# remove item size suffix
# example: folder1 (13 B) => folder1
item_name = item.text.rsplit(" ", 2)[0]
if item_name == folder_name:
squish.mouseClick(
item,
9,
9,
squish.Qt.NoModifier,
squish.Qt.LeftButton,
)
break
squish.clickButton(
squish.waitForObject(SyncConnection.SELECTIVE_SYNC_APPLY_BUTTON)
)
17 changes: 16 additions & 1 deletion test/gui/shared/steps/sync_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from pageObjects.Activity import Activity
from pageObjects.Settings import Settings

from helpers.SetupClientHelper import getResourcePath
from helpers.ConfigHelper import get_config, isWindows
from helpers.SyncHelper import (
waitForFileOrFolderToSync,
Expand Down Expand Up @@ -61,6 +60,16 @@ def step(context, item):
SyncConnection.hasMenuItem(item)


@Then('the "|any|" button should not be available')
def step(context, item):
SyncConnection.openMenu()
test.compare(
SyncConnection.menu_item_exists(item),
False,
f'Menu item "{item}" does not exist.',
)


@When("the user disables virtual file support")
def step(context):
SyncConnection.disableVFS()
Expand Down Expand Up @@ -200,3 +209,9 @@ def step(context, action):
if isWindows():
action = action.rstrip("s")
SyncConnectionWizard.enableOrDisableVfsSupport(action)


@When('user unselects a folder "|any|" in selective sync')
def step(context, folder_name):
SyncConnection.choose_what_to_sync()
SyncConnection.unselect_folder_in_selective_sync(folder_name)
4 changes: 2 additions & 2 deletions test/gui/shared/steps/vfs_context.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from helpers.FilesHelper import get_file_size_on_disk
from helpers.FilesHelper import get_file_size_on_disk, get_file_size


@Then('the placeholder of file "|any|" should exist on the file system')
Expand All @@ -14,7 +14,7 @@ def step(context, file_name):
def step(context, file_name):
resource_path = getResourcePath(file_name)
size_on_disk = get_file_size_on_disk(resource_path)
file_size = os.stat(resource_path).st_size
file_size = get_file_size(resource_path)
test.compare(
size_on_disk,
file_size,
Expand Down
20 changes: 12 additions & 8 deletions test/gui/tst_vfs/test.feature
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,24 @@ Feature: Enable/disable virtual file support
And user "Alice" has uploaded file with content "ownCloud" to "testFile.txt" in the server
And user "Alice" has created folder "folder1" in the server
And user "Alice" has uploaded file with content "some contents" to "folder1/lorem.txt" in the server
And user "Alice" has created folder "folder2" in the server
And user "Alice" has uploaded file with content "content" to "folder2/lorem.txt" in the server
And user "Alice" has set up a client with default settings
Then the placeholder of file "testFile.txt" should exist on the file system
And the placeholder of file "folder1/lorem.txt" should exist on the file system
And the placeholder of file "folder2/lorem.txt" should exist on the file system
And the "Choose what to sync" button should not be available
When the user disables virtual file support
Then the "Enable virtual file support..." button should be available
And the file "testFile.txt" should be downloaded
And the file "folder1/lorem.txt" should be downloaded
And the file "testFile.txt" should exist on the file system with the following content
"""
ownCloud
"""
And the file "folder1/lorem.txt" should exist on the file system with the following content
"""
some contents
"""
And the file "folder2/lorem.txt" should be downloaded
When user unselects a folder "folder1" in selective sync
And the user waits for the files to sync
Then the folder "folder1" should not exist on the file system
And the file "folder2/lorem.txt" should exist on the file system
When the user enables virtual file support
Then the "Disable virtual file support..." button should be available
And the placeholder of file "folder1/lorem.txt" should exist on the file system
And the file "testFile.txt" should be downloaded
And the file "folder2/lorem.txt" should be downloaded

0 comments on commit 5084755

Please sign in to comment.