Skip to content

Commit 30d40ff

Browse files
HanaGemelaSalipa-Gurungsaw-jan
authored
[full-ci][gui-tests] Extend oAuth2 scenario (#11067)
* Update test.feature * Update test.feature * add step implementation for oauth2 login * properly wait for AUT context to get removed * login via oauth2 and wait for sync completion * listen sync path if available * fix oauth relogin * refactor --------- Co-authored-by: Salipa-Gurung <salipagurung@gmail.com> Co-authored-by: Saw-jan <saw.jan.grg3e@gmail.com>
1 parent 8eb4b2d commit 30d40ff

10 files changed

Lines changed: 159 additions & 49 deletions

File tree

test/gui/shared/scripts/bdd_hooks.py

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from helpers.StacktraceHelper import getCoredumps, generateStacktrace
2222
from helpers.SyncHelper import closeSocketConnection, clearWaitedAfterSync
2323
from helpers.SpaceHelper import delete_project_spaces
24+
from helpers.SetupClientHelper import wait_until_app_killed
2425
from helpers.ConfigHelper import (
2526
init_config,
2627
get_config,
@@ -116,27 +117,6 @@ def scenarioFailed():
116117
)
117118

118119

119-
def isAppKilled(pid):
120-
if os.path.isdir('/proc/{}'.format(pid)):
121-
# process is still running
122-
# wait 100ms before checking again
123-
snooze(0.1)
124-
return False
125-
return True
126-
127-
128-
def waitUntilAppIsKilled(pid=0):
129-
timeout = get_config('minSyncTimeout') * 1000
130-
killed = waitFor(
131-
lambda: isAppKilled(pid),
132-
timeout,
133-
)
134-
if not killed:
135-
test.log(
136-
"Application was not terminated within {} milliseconds".format(timeout)
137-
)
138-
139-
140120
# runs after every scenario
141121
# Order: 1
142122
# cleanup spaces
@@ -157,7 +137,6 @@ def hook(context):
157137

158138
# capture a screenshot if there is error or test failure in the current scenario execution
159139
if scenarioFailed() and os.getenv('CI'):
160-
161140
import gi
162141

163142
gi.require_version('Gtk', '3.0')
@@ -183,7 +162,7 @@ def hook(context):
183162
# get pid before detaching
184163
pid = ctx.pid
185164
ctx.detach()
186-
waitUntilAppIsKilled(pid)
165+
wait_until_app_killed(pid)
187166

188167
# delete local files/folders
189168
for filename in os.listdir(get_config('clientRootSyncPath')):

test/gui/shared/scripts/helpers/SetupClientHelper.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from urllib.parse import urlparse
2-
import squish
3-
from os import makedirs
2+
import squish, test
3+
from os import makedirs, path
44
from os.path import exists, join
55
from helpers.SpaceHelper import get_space_id
66
from helpers.ConfigHelper import get_config, set_config
@@ -20,7 +20,13 @@ def substituteInLineCodes(value):
2020

2121

2222
def getClientDetails(context):
23-
clientDetails = {'server': '', 'user': '', 'password': '', 'sync_folder': ''}
23+
clientDetails = {
24+
'server': '',
25+
'user': '',
26+
'password': '',
27+
'sync_folder': '',
28+
'oauth': False,
29+
}
2430
for row in context.table[0:]:
2531
row[1] = substituteInLineCodes(row[1])
2632
if row[0] == 'server':
@@ -152,3 +158,24 @@ def setUpClient(username, displayName, space="Personal"):
152158

153159
startClient()
154160
listenSyncStatusForItem(syncPath)
161+
162+
163+
def is_app_killed(pid):
164+
if path.isdir('/proc/{}'.format(pid)):
165+
# process is still running
166+
# wait 100ms before checking again
167+
squish.snooze(0.1)
168+
return False
169+
return True
170+
171+
172+
def wait_until_app_killed(pid=0):
173+
timeout = 5 * 1000
174+
killed = squish.waitFor(
175+
lambda: is_app_killed(pid),
176+
timeout,
177+
)
178+
if not killed:
179+
test.log(
180+
"Application was not terminated within {} milliseconds".format(timeout)
181+
)

test/gui/shared/scripts/helpers/SyncHelper.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@
5151
# default sync patterns for the initial sync (after adding account)
5252
# the pattern can be of TWO types depending on the available resources (files/folders)
5353
'initial': [
54+
# when adding account via New Account wizard
55+
[
56+
SYNC_STATUS['REGISTER'],
57+
SYNC_STATUS['UPDATE'],
58+
SYNC_STATUS['UPDATE'],
59+
SYNC_STATUS['UPDATE'],
60+
],
5461
# when syncing empty account (hidden files are ignored)
5562
[SYNC_STATUS['UPDATE'], SYNC_STATUS['OK']],
5663
# when syncing an account that has some files/folders

test/gui/shared/scripts/pageObjects/AccountConnectionWizard.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
getTempResourcePath,
88
setCurrentUserSyncPath,
99
)
10+
from helpers.SyncHelper import listenSyncStatusForItem
1011
import test
1112

1213

@@ -169,9 +170,11 @@ def acceptCertificate():
169170
)
170171

171172
@staticmethod
172-
def addUserCreds(username, password):
173+
def addUserCreds(username, password, oauth=False):
173174
if get_config('ocis'):
174175
AccountConnectionWizard.oidcLogin(username, password)
176+
elif oauth:
177+
AccountConnectionWizard.oauthLogin(username, password)
175178
else:
176179
AccountConnectionWizard.basicLogin(username, password)
177180

@@ -215,17 +218,18 @@ def nextStep():
215218
@staticmethod
216219
def selectSyncFolder(user):
217220
# create sync folder for user
218-
syncPath = createUserSyncPath(user)
221+
sync_path = createUserSyncPath(user)
219222

220223
AccountConnectionWizard.selectAdvancedConfig()
221224
squish.mouseClick(
222225
squish.waitForObject(AccountConnectionWizard.DIRECTORY_NAME_BOX)
223226
)
224227
squish.type(
225228
squish.waitForObject(AccountConnectionWizard.DIRECTORY_NAME_EDIT_BOX),
226-
syncPath,
229+
sync_path,
227230
)
228231
squish.clickButton(squish.waitForObject(AccountConnectionWizard.CHOOSE_BUTTON))
232+
return sync_path
229233

230234
@staticmethod
231235
def set_temp_folder_as_sync_folder(folder_name):
@@ -243,6 +247,7 @@ def set_temp_folder_as_sync_folder(folder_name):
243247
sync_path,
244248
)
245249
setCurrentUserSyncPath(sync_path)
250+
return sync_path
246251

247252
@staticmethod
248253
def addAccount(account_details):
@@ -257,16 +262,23 @@ def addAccountInformation(account_details):
257262
AccountConnectionWizard.acceptCertificate()
258263
if account_details['user']:
259264
AccountConnectionWizard.addUserCreds(
260-
account_details['user'], account_details['password']
265+
account_details['user'],
266+
account_details['password'],
267+
account_details['oauth'],
261268
)
262-
269+
sync_path = ''
263270
if account_details['sync_folder']:
264271
AccountConnectionWizard.selectAdvancedConfig()
265-
AccountConnectionWizard.set_temp_folder_as_sync_folder(
272+
sync_path = AccountConnectionWizard.set_temp_folder_as_sync_folder(
266273
account_details['sync_folder']
267274
)
268275
elif account_details['user']:
269-
AccountConnectionWizard.selectSyncFolder(account_details['user'])
276+
sync_path = AccountConnectionWizard.selectSyncFolder(
277+
account_details['user']
278+
)
279+
if sync_path:
280+
# listen for sync status
281+
listenSyncStatusForItem(sync_path)
270282

271283
@staticmethod
272284
def selectManualSyncFolderOption():

test/gui/shared/scripts/pageObjects/AccountSetting.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ class AccountSetting:
4747
"visible": 1,
4848
"window": names.loginRequiredDialog_OCC_LoginRequiredDialog,
4949
}
50+
ACCOUNT_LOADING = {
51+
"window": names.settings_OCC_SettingsDialog,
52+
"name": "loadingPage",
53+
"type": "QWidget",
54+
"visible": 0,
55+
}
5056

5157
@staticmethod
5258
def accountAction(action):
@@ -131,13 +137,30 @@ def waitUntilAccountIsConnected(displayname, server, timeout=5000):
131137
)
132138

133139
if not result:
134-
raise Exception(
140+
raise TimeoutError(
135141
"Timeout waiting for the account to be connected for "
136142
+ str(timeout)
137143
+ " milliseconds"
138144
)
139145
return result
140146

147+
@staticmethod
148+
def wait_until_sync_folder_is_configured(timeout=5000):
149+
result = squish.waitFor(
150+
lambda: not squish.waitForObjectExists(
151+
AccountSetting.ACCOUNT_LOADING
152+
).visible,
153+
timeout,
154+
)
155+
156+
if not result:
157+
raise TimeoutError(
158+
"Timeout waiting for sync folder to be connected for "
159+
+ str(timeout)
160+
+ " milliseconds"
161+
)
162+
return result
163+
141164
@staticmethod
142165
def confirmRemoveAllFiles():
143166
squish.clickButton(squish.waitForObject(AccountSetting.REMOVE_ALL_FILES))

test/gui/shared/scripts/pageObjects/EnterPassword.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,20 @@ def oidcReLogin(username, password):
4444
authorize_via_webui(username, password)
4545

4646
@staticmethod
47-
def reLogin(username, password):
47+
def oauthReLogin(username, password):
48+
# wait 500ms for copy button to fully load
49+
squish.snooze(1 / 2)
50+
squish.clickButton(
51+
squish.waitForObject(EnterPassword.COPY_URL_TO_CLIPBOARD_BUTTON)
52+
)
53+
authorize_via_webui(username, password, "oauth")
54+
55+
@staticmethod
56+
def reLogin(username, password, oauth=False):
4857
if get_config('ocis'):
4958
EnterPassword.oidcReLogin(username, password)
59+
elif oauth:
60+
EnterPassword.oauthReLogin(username, password)
5061
else:
5162
EnterPassword.enterPassword(password)
5263

test/gui/shared/scripts/pageObjects/Toolbar.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
import squish
2+
from helpers.SetupClientHelper import wait_until_app_killed
23

34

45
class Toolbar:
6+
QUIT_CONFIRMATION_DIALOG = {
7+
"type": "QMessageBox",
8+
"unnamed": 1,
9+
"visible": 1,
10+
"windowTitle": "Quit ownCloud",
11+
}
12+
CONFIRM_QUIT_BUTTON = {
13+
"text": "Yes",
14+
"type": "QPushButton",
15+
"unnamed": 1,
16+
"visible": 1,
17+
"window": QUIT_CONFIRMATION_DIALOG,
18+
}
19+
520
@staticmethod
621
def getItemSelector(item_name):
722
return {
@@ -35,3 +50,14 @@ def getDisplayedAccountText(displayname, host):
3550
@staticmethod
3651
def open_settings_tab():
3752
squish.clickButton(squish.waitForObject(Toolbar.getItemSelector("Settings")))
53+
54+
@staticmethod
55+
def quit_owncloud():
56+
squish.clickButton(
57+
squish.waitForObject(Toolbar.getItemSelector("Quit ownCloud"))
58+
)
59+
squish.clickButton(squish.waitForObject(Toolbar.CONFIRM_QUIT_BUTTON))
60+
for ctx in squish.applicationContextList():
61+
pid = ctx.pid
62+
ctx.detach()
63+
wait_until_app_killed(pid)

test/gui/shared/steps/account_context.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ def step(context):
6565
startClient()
6666

6767

68+
@When('the user starts the client')
69+
def step(context):
70+
startClient()
71+
72+
6873
@When('the user opens the add-account dialog')
6974
def step(context):
7075
Toolbar.openNewAccountSetup()
@@ -74,6 +79,8 @@ def step(context):
7479
def step(context):
7580
account_details = getClientDetails(context)
7681
AccountConnectionWizard.addAccount(account_details)
82+
# wait for files to sync
83+
waitForInitialSyncToComplete(getResourcePath('/', account_details["user"]))
7784

7885

7986
@Given('the user has entered the following account information:')
@@ -117,6 +124,16 @@ def step(context, username):
117124
waitForInitialSyncToComplete(getResourcePath('/', username))
118125

119126

127+
@When('user "|any|" logs in to the client-UI with oauth2')
128+
def step(context, username):
129+
AccountSetting.login()
130+
password = getPasswordForUser(username)
131+
EnterPassword.reLogin(username, password, True)
132+
133+
# wait for files to sync
134+
waitForInitialSyncToComplete(getResourcePath('/', username))
135+
136+
120137
@When('user "|any|" opens login dialog')
121138
def step(context, username):
122139
AccountSetting.login()
@@ -131,11 +148,8 @@ def step(context, username, password):
131148
def step(context, username):
132149
displayname = getDisplaynameForUser(username)
133150
server = get_config('localBackendUrl')
134-
test.compare(
135-
AccountSetting.waitUntilAccountIsConnected(displayname, server),
136-
True,
137-
"User '%s' is connected" % username,
138-
)
151+
AccountSetting.waitUntilAccountIsConnected(displayname, server)
152+
AccountSetting.wait_until_sync_folder_is_configured()
139153

140154

141155
@When('the user removes the connection for user "|any|" and host |any|')
@@ -230,14 +244,13 @@ def step(context):
230244
test.compare(True, AccountSetting.isLogDialogVisible(), "Log dialog is opened")
231245

232246

233-
@When('the user adds the following account with oauth2 enabled:')
247+
@When('the user adds the following oauth2 account:')
234248
def step(context):
235249
account_details = getClientDetails(context)
236-
AccountConnectionWizard.addServer(account_details['server'])
237-
AccountConnectionWizard.oauthLogin(
238-
account_details['user'], account_details['password']
239-
)
240-
AccountConnectionWizard.nextStep()
250+
account_details.update({'oauth': True})
251+
AccountConnectionWizard.addAccount(account_details)
252+
# wait for files to sync
253+
waitForInitialSyncToComplete(getResourcePath('/', account_details["user"]))
241254

242255

243256
@When('the user cancels the sync connection wizard')
@@ -253,3 +266,8 @@ def step(context):
253266
@When('user "|any|" logs out from the login required dialog')
254267
def step(context, username):
255268
AccountSetting.logoutFromLoginRequiredDialog()
269+
270+
271+
@When("the user quits the client")
272+
def step(context):
273+
Toolbar.quit_owncloud()

test/gui/shared/steps/spaces_context.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,5 @@ def step(context, user, file_name, space_name, content):
5858
regexp=True,
5959
)
6060
def step(context, user, space_name, resource_name):
61-
print(user, space_name, resource_name)
6261
exists = resource_exists(space_name, resource_name, user)
6362
test.compare(exists, True, "Resource exists")

0 commit comments

Comments
 (0)