diff --git a/test/gui/shared/scripts/helpers/SetupClientHelper.py b/test/gui/shared/scripts/helpers/SetupClientHelper.py index cec39052449..b26d91141b1 100644 --- a/test/gui/shared/scripts/helpers/SetupClientHelper.py +++ b/test/gui/shared/scripts/helpers/SetupClientHelper.py @@ -1,5 +1,6 @@ import squish, test import psutil +import uuid from urllib.parse import urlparse from os import makedirs from os.path import exists, join @@ -7,6 +8,7 @@ from helpers.ConfigHelper import get_config, set_config, isWindows from helpers.SyncHelper import listenSyncStatusForItem from helpers.api.utils import url_join +from helpers.UserHelper import getDisplaynameForUser def substituteInLineCodes(value): @@ -100,71 +102,86 @@ def startClient(): def getPollingInterval(): - pollingInterval = '''[ownCloud] - remotePollInterval={pollingInterval} - ''' + pollingInterval = ''' +[ownCloud] +remotePollInterval={pollingInterval} +''' args = {'pollingInterval': 5000} pollingInterval = pollingInterval.format(**args) return pollingInterval -def setUpClient(username, displayName, space="Personal"): - userSetting = ''' - [Accounts] - 0/Folders/1/davUrl={url} - 0/Folders/1/ignoreHiddenFiles=true - 0/Folders/1/localPath={client_sync_path} - 0/Folders/1/displayString={displayString} - 0/Folders/1/paused=false - 0/Folders/1/targetPath=/ - 0/Folders/1/version=2 - 0/Folders/1/virtualFilesMode={vfs} - 0/dav_user={davUserName} - 0/display-name={displayUserName} - 0/http_CredentialVersion=1 - 0/http_oauth={oauth} - 0/http_user={davUserName} - 0/url={local_server} - 0/user={displayUserFirstName} - 0/version=1 - 0/supportsSpaces={supportsSpaces} - version=2 - ''' - - userSetting = userSetting + getPollingInterval() - - syncPath = createUserSyncPath(username) - dav_endpoint = url_join("remote.php/dav/files", username) - - server_url = get_config('localBackendUrl') - is_ocis = get_config('ocis') - if is_ocis: - set_config('syncConnectionName', space) - syncPath = createSpacePath(space) - if space == "Personal": - space = displayName - dav_endpoint = url_join("dav/spaces", get_space_id(space, username)) - - args = { - 'url': url_join(server_url, dav_endpoint, ''), - 'displayString': get_config('syncConnectionName'), - 'displayUserName': displayName, - 'davUserName': username if is_ocis else username.lower(), - 'displayUserFirstName': displayName.split()[0], - 'client_sync_path': syncPath, - 'local_server': server_url, - 'oauth': 'true' if is_ocis else 'false', - 'vfs': 'wincfapi' if isWindows() else 'off', - 'supportsSpaces': 'true' if is_ocis else 'false', - } - userSetting = userSetting.format(**args) - - configFile = open(get_config('clientConfigFile'), "w") - configFile.write(userSetting) - configFile.close() - +def generate_account_config(users, space="Personal"): + sync_paths = [] + user_setting = '' + for idx, username in enumerate(users): + user_setting += ''' +{user_index}/Folders/{uuid_v4}/davUrl={url} +{user_index}/Folders/{uuid_v4}/ignoreHiddenFiles=true +{user_index}/Folders/{uuid_v4}/localPath={client_sync_path} +{user_index}/Folders/{uuid_v4}/displayString={displayString} +{user_index}/Folders/{uuid_v4}/paused=false +{user_index}/Folders/{uuid_v4}/targetPath=/ +{user_index}/Folders/{uuid_v4}/version=13 +{user_index}/Folders/{uuid_v4}/virtualFilesMode=off +{user_index}/dav_user={davUserName} +{user_index}/display-name={displayUserName} +{user_index}/http_CredentialVersion=1 +{user_index}/http_oauth={oauth} +{user_index}/http_user={davUserName} +{user_index}/url={local_server} +{user_index}/user={displayUserFirstName} +{user_index}/supportsSpaces={supportsSpaces} +{user_index}/version=13 +''' + if not idx: + user_setting = "[Accounts]" + user_setting + + sync_path = createUserSyncPath(username) + dav_endpoint = url_join("remote.php/dav/files", username) + + server_url = get_config('localBackendUrl') + is_ocis = get_config('ocis') + if is_ocis: + set_config('syncConnectionName', space) + sync_path = createSpacePath(space) + space_name = space + if space == "Personal": + space_name = getDisplaynameForUser(username) + dav_endpoint = url_join("dav/spaces", get_space_id(space_name, username)) + + args = { + 'url': url_join(server_url, dav_endpoint, ''), + 'displayString': get_config('syncConnectionName'), + 'displayUserName': getDisplaynameForUser(username), + 'davUserName': username if is_ocis else username.lower(), + 'displayUserFirstName': getDisplaynameForUser(username).split()[0], + 'client_sync_path': sync_path, + 'local_server': server_url, + 'oauth': 'true' if is_ocis else 'false', + 'vfs': 'wincfapi' if isWindows() else 'off', + 'supportsSpaces': 'true' if is_ocis else 'false', + 'user_index': idx, + 'uuid_v4': generate_UUIDV4(), + } + user_setting = user_setting.format(**args) + sync_paths.append(sync_path) + # append extra configs + user_setting += "version=13" + user_setting = user_setting + getPollingInterval() + + config_file = open(get_config('clientConfigFile'), "a+", encoding="utf-8") + config_file.write(user_setting) + config_file.close() + + return sync_paths + + +def setUpClient(username, space="Personal"): + sync_paths = generate_account_config([username], space) startClient() - listenSyncStatusForItem(syncPath) + for sync_path in sync_paths: + listenSyncStatusForItem(sync_path) def is_app_killed(pid): @@ -185,3 +202,7 @@ def wait_until_app_killed(pid=0): test.log( "Application was not terminated within {} milliseconds".format(timeout) ) + + +def generate_UUIDV4(): + return str(uuid.uuid4()) diff --git a/test/gui/shared/scripts/pageObjects/EnterPassword.py b/test/gui/shared/scripts/pageObjects/EnterPassword.py index 98c7bdd3802..01752cd3704 100644 --- a/test/gui/shared/scripts/pageObjects/EnterPassword.py +++ b/test/gui/shared/scripts/pageObjects/EnterPassword.py @@ -1,79 +1,115 @@ -import names import squish from helpers.WebUIHelper import authorize_via_webui from helpers.ConfigHelper import get_config -from pageObjects.AccountConnectionWizard import AccountConnectionWizard +from helpers.UserHelper import getPasswordForUser class EnterPassword: + LOGIN_DIALOG = { + "name": "LoginRequiredDialog", + "type": "OCC::LoginRequiredDialog", + "visible": 1, + } + LOGIN_USER_LABEL = { + "name": "topLabel", + "type": "QLabel", + "visible": 1, + "window": LOGIN_DIALOG, + } + USERNAME_BOX = { + "name": "usernameLineEdit", + "type": "QLineEdit", + "visible": 1, + "window": LOGIN_DIALOG, + } PASSWORD_BOX = { - "container": names.loginRequiredDialog_contentWidget_QStackedWidget, "name": "passwordLineEdit", "type": "QLineEdit", "visible": 1, + "window": LOGIN_DIALOG, } LOGIN_BUTTON = { "text": "Log in", "type": "QPushButton", "visible": 1, - "window": names.stack_stackedWidget_QStackedWidget, + "window": LOGIN_DIALOG, } LOGOUT_BUTTON = { "text": "Log out", "type": "QPushButton", "visible": 1, - "window": names.stack_stackedWidget_QStackedWidget, + "window": LOGIN_DIALOG, } COPY_URL_TO_CLIPBOARD_BUTTON = { - "container": names.loginRequiredDialog_contentWidget_QStackedWidget, "name": "copyUrlToClipboardButton", "type": "QPushButton", "visible": 1, + "window": LOGIN_DIALOG, + } + TLS_CERT_WINDOW = { + "name": "OCC__TlsErrorDialog", + "type": "OCC::TlsErrorDialog", + "visible": 1, + } + ACCEPT_CERTIFICATE_YES = { + "text": "Yes", + "type": "QPushButton", + "visible": 1, + "window": TLS_CERT_WINDOW, } - @staticmethod - def enterPassword(password): - squish.waitForObject( - EnterPassword.PASSWORD_BOX, get_config('maxSyncTimeout') * 1000 - ) - squish.type(squish.waitForObject(EnterPassword.PASSWORD_BOX), password) - squish.clickButton(squish.waitForObject(EnterPassword.LOGIN_BUTTON)) + def __init__(self, occurrence=1): + if occurrence > 1 and not get_config('ocis'): + self.LOGIN_DIALOG.update({"occurrence": occurrence}) + elif occurrence > 1 and get_config('ocis'): + self.TLS_CERT_WINDOW.update({"occurrence": occurrence}) - @staticmethod - def oidcReLogin(username, password): + def get_username(self): + # Parse username from following label: + # Please enter your password to log in to the account Alice Hansen@localhost. + # The account Alice Hansen@localhost:9200 is currently logged out. + label = str(squish.waitForObjectExists(self.LOGIN_USER_LABEL).text) + label = label.split("@", maxsplit=1)[0].split(" ") + label.reverse() + return label[1].capitalize() + + def enterPassword(self, password): + squish.waitForObject(self.PASSWORD_BOX, get_config('maxSyncTimeout') * 1000) + squish.type(squish.waitForObject(self.PASSWORD_BOX), password) + squish.clickButton(squish.waitForObject(self.LOGIN_BUTTON)) + + def oidcReLogin(self, username, password): # wait 500ms for copy button to fully load squish.snooze(1 / 2) - squish.clickButton( - squish.waitForObject(EnterPassword.COPY_URL_TO_CLIPBOARD_BUTTON) - ) + squish.clickButton(squish.waitForObject(self.COPY_URL_TO_CLIPBOARD_BUTTON)) authorize_via_webui(username, password) - @staticmethod - def oauthReLogin(username, password): + def oauthReLogin(self, username, password): # wait 500ms for copy button to fully load squish.snooze(1 / 2) - squish.clickButton( - squish.waitForObject(EnterPassword.COPY_URL_TO_CLIPBOARD_BUTTON) - ) + squish.clickButton(squish.waitForObject(self.COPY_URL_TO_CLIPBOARD_BUTTON)) authorize_via_webui(username, password, "oauth") - @staticmethod - def reLogin(username, password, oauth=False): + def reLogin(self, username, password, oauth=False): if get_config('ocis'): - EnterPassword.oidcReLogin(username, password) + self.oidcReLogin(username, password) elif oauth: - EnterPassword.oauthReLogin(username, password) + self.oauthReLogin(username, password) else: - EnterPassword.enterPassword(password) + self.enterPassword(password) + + def loginAfterSetup(self, username=None, password=None): + if not username: + username = self.get_username() + password = getPasswordForUser(username) - @staticmethod - def loginAfterSetup(username, password): if get_config('ocis'): - AccountConnectionWizard.acceptCertificate() - EnterPassword.oidcReLogin(username, password) + self.oidcReLogin(username, password) else: - EnterPassword.enterPassword(password) + self.enterPassword(password) + + def logout(self): + squish.clickButton(squish.waitForObject(self.LOGOUT_BUTTON)) - @staticmethod - def logout(): - squish.clickButton(squish.waitForObject(EnterPassword.LOGOUT_BUTTON)) + def accept_certificate(self): + squish.clickButton(squish.waitForObject(self.ACCEPT_CERTIFICATE_YES)) diff --git a/test/gui/shared/steps/account_context.py b/test/gui/shared/steps/account_context.py index 709514a8e38..9be55dc56f6 100644 --- a/test/gui/shared/steps/account_context.py +++ b/test/gui/shared/steps/account_context.py @@ -4,27 +4,19 @@ from pageObjects.Toolbar import Toolbar from pageObjects.AccountSetting import AccountSetting -from helpers.SetupClientHelper import substituteInLineCodes, getClientDetails +from helpers.SetupClientHelper import ( + setUpClient, + startClient, + substituteInLineCodes, + getClientDetails, + generate_account_config, + getResourcePath, +) from helpers.UserHelper import getDisplaynameForUser, getPasswordForUser -from helpers.SetupClientHelper import setUpClient, startClient -from helpers.SyncHelper import waitForInitialSyncToComplete -from helpers.SetupClientHelper import getResourcePath +from helpers.SyncHelper import waitForInitialSyncToComplete, listenSyncStatusForItem from helpers.ConfigHelper import get_config, isWindows, isLinux -@Given(r'the user has added (the first|another) account with', regexp=True) -def step(context, accountType): - if accountType == 'another': - Toolbar.openNewAccountSetup() - account_details = getClientDetails(context) - AccountConnectionWizard.addAccount(account_details) - space = "" - if get_config("ocis"): - space = "Personal" - # wait for files to sync - waitForInitialSyncToComplete(getResourcePath('/', account_details["user"], space)) - - @When('the user adds the following wrong user credentials:') def step(context): account_details = getClientDetails(context) @@ -61,14 +53,40 @@ def step(context, displayname, host): @Given('user "|any|" has set up a client with default settings') def step(context, username): password = getPasswordForUser(username) - displayName = getDisplaynameForUser(username) - setUpClient(username, displayName) - EnterPassword.loginAfterSetup(username, password) + setUpClient(username) + enter_password = EnterPassword() + if get_config('ocis'): + enter_password.accept_certificate() + + enter_password.loginAfterSetup(username, password) # wait for files to sync waitForInitialSyncToComplete(getResourcePath('/', username)) +@Given('the user has set up the following accounts with default settings:') +def step(context): + users = [] + for row in context.table: + users.append(row[0]) + sync_paths = generate_account_config(users) + startClient() + if get_config('ocis'): + # accept certificate for each user + for idx, _ in enumerate(users): + enter_password = EnterPassword(len(users) - idx) + enter_password.accept_certificate() + + for idx, sync_path in enumerate(sync_paths): + listenSyncStatusForItem(sync_path) + # login from last dialog + account_idx = len(sync_paths) - idx + enter_password = EnterPassword(account_idx) + enter_password.loginAfterSetup() + # wait for files to sync + waitForInitialSyncToComplete(sync_path) + + @Given('the user has started the client') def step(context): startClient() @@ -127,7 +145,8 @@ def step(context, username): def step(context, username): AccountSetting.login() password = getPasswordForUser(username) - EnterPassword.reLogin(username, password) + enter_password = EnterPassword() + enter_password.reLogin(username, password) # wait for files to sync waitForInitialSyncToComplete(getResourcePath('/', username)) @@ -150,7 +169,8 @@ def step(context, username): @When('user "|any|" enters the password "|any|"') def step(context, username, password): - EnterPassword.reLogin(username, password) + enter_password = EnterPassword() + enter_password.reLogin(username, password) @Then('user "|any|" should be connect to the client-UI') @@ -279,7 +299,8 @@ def step(context): @When('user "|any|" logs out from the login required dialog') def step(context, username): - EnterPassword.logout() + enter_password = EnterPassword() + enter_password.logout() @When("the user quits the client") diff --git a/test/gui/shared/steps/spaces_context.py b/test/gui/shared/steps/spaces_context.py index fd73fcfa915..5dd20c36bc2 100644 --- a/test/gui/shared/steps/spaces_context.py +++ b/test/gui/shared/steps/spaces_context.py @@ -38,9 +38,9 @@ def step(context, user, space_name, role): @Given('user "|any|" has set up a client with space "|any|"') def step(context, user, space_name): password = getPasswordForUser(user) - displayName = getDisplaynameForUser(user) - setUpClient(user, displayName, space_name) - EnterPassword.loginAfterSetup(user, password) + setUpClient(user, space_name) + enter_password = EnterPassword() + enter_password.loginAfterSetup(user, password) # wait for files to sync waitForInitialSyncToComplete(getResourcePath('/', user, space_name)) diff --git a/test/gui/tst_removeAccountConnection/test.feature b/test/gui/tst_removeAccountConnection/test.feature index 4ff3da9181d..d1503f0224d 100644 --- a/test/gui/tst_removeAccountConnection/test.feature +++ b/test/gui/tst_removeAccountConnection/test.feature @@ -8,11 +8,9 @@ Feature: remove account connection Scenario: remove an account connection Given user "Alice" has been created on the server with default attributes and without skeleton files And user "Brian" has been created on the server with default attributes and without skeleton files - And user "Alice" has set up a client with default settings - And the user has added another account with - | server | %local_server% | - | user | Brian | - | password | AaBb2Cc3Dd4 | + And the user has set up the following accounts with default settings: + | Alice | + | Brian | When the user removes the connection for user "Brian" and host %local_server_hostname% Then the account with displayname "Brian Murphy" and host "%local_server_hostname%" should not be displayed But the account with displayname "Alice Hansen" and host "%local_server_hostname%" should be displayed