Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .woodpecker/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ when:
path:
<<: *trigger_path
- event: pull_request
branch:
- main
- stable-*
path:
<<: *trigger_path
evaluate: |
Expand Down
3 changes: 3 additions & 0 deletions .woodpecker/cache-pnpm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ when:
<<: *trigger_path
- event: tag
- event: pull_request
branch:
- main
- stable-*
path:
<<: *trigger_path
evaluate: |
Expand Down
3 changes: 3 additions & 0 deletions .woodpecker/cache-python.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ when:
<<: *trigger_path
- event: tag
- event: pull_request
branch:
- main
- stable-*
path:
<<: *trigger_path
evaluate: |
Expand Down
3 changes: 3 additions & 0 deletions .woodpecker/ui-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ when:
- push
- manual
- event: pull_request
branch:
- main
- stable-*
- event: tag
- event: cron
cron: nightly*
Expand Down
3 changes: 2 additions & 1 deletion test/gui/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
shared/scripts/custom_lib
custom_lib/
reports
venv/
8 changes: 8 additions & 0 deletions test/gui/behave.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[behave]
paths=features
default_format = plain
default_tags = not (@skip)
logging_level = WARNING
capture_stderr = false
capture_stdout = false
capture_log = false
43 changes: 43 additions & 0 deletions test/gui/environment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import psutil
import shutil
import os

from helpers.ConfigHelper import init_config
from helpers.api.provisioning import delete_created_users
from helpers.ConfigHelper import set_config, get_config
from helpers.FilesHelper import prefix_path_namespace, cleanup_created_paths
from helpers.SetupClientHelper import app


def before_feature(context, feature):
init_config()


def before_scenario(context, feature):
set_config("currentUserSyncPath", "")


def after_scenario(context, scenario):
# clean up config dir
shutil.rmtree(get_config("clientConfigDir"))
# clean up sync dir
for entry in os.scandir(get_config("clientRootSyncPath")):
try:
if entry.is_file() or entry.is_symlink():
print("Deleting file: " + entry.name)
os.unlink(prefix_path_namespace(entry.path))
elif entry.is_dir():
print("Deleting folder: " + entry.name)
shutil.rmtree(prefix_path_namespace(entry.path))
except OSError as e:
print(f"Failed to delete '{entry.name}'.\nReason: {e}.")
# cleanup paths created outside of the temporary directory during the test
cleanup_created_paths()
delete_created_users()
# quit the application
app().quit()
for process in psutil.process_iter(['pid', 'exe']):
if process.info['exe'] == get_config("app_path"):
print("Closing desktop client...")
psutil.Process(process.info['pid']).kill()
break
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Feature: adding accounts
Then the download everything option should be selected by default for Linux
And the user should be able to choose the local download directory


@smoke
Scenario: Adding normal Account
Given the user has started the client
When the user adds the following account:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
def read_env_file():
envs = {}
script_path = os.path.dirname(os.path.realpath(__file__))
env_path = os.path.abspath(os.path.join(script_path, '..', '..', '..', 'envs.txt'))
env_path = os.path.abspath(os.path.join(script_path, '..', 'envs.txt'))
with open(env_path, 'rt', encoding='UTF-8') as f:
for line in f:
if not line.strip():
Expand Down Expand Up @@ -64,6 +64,7 @@ def get_default_home_dir():

# map environment variables to config keys
CONFIG_ENV_MAP = {
'app_path': 'APP_PATH',
'localBackendUrl': 'BACKEND_HOST',
'maxSyncTimeout': 'MAX_SYNC_TIMEOUT',
'minSyncTimeout': 'MIN_SYNC_TIMEOUT',
Expand All @@ -73,14 +74,17 @@ def get_default_home_dir():
'clientRootSyncPath': 'CLIENT_ROOT_SYNC_PATH',
'tempFolderPath': 'TEMP_FOLDER_PATH',
'guiTestReportDir': 'GUI_TEST_REPORT_DIR',
'record_video_on_failure': 'RECORD_VIDEO_ON_FAILURE'
'record_video_on_failure': 'RECORD_VIDEO_ON_FAILURE',
}

DEFAULT_PATH_CONFIG = {
'custom_lib': os.path.abspath('../shared/scripts/custom_lib'),
'custom_lib': os.path.abspath(
os.path.join(os.path.dirname(__file__), 'custom_lib')
),
'home_dir': get_default_home_dir(),
# allow to record first 5 videos
'video_record_limit': 5,
'app_path': None,
}

# default config values
Expand All @@ -98,13 +102,13 @@ def get_default_home_dir():
'guiTestReportDir': os.path.abspath('../reports'),
'record_video_on_failure': False,
'files_for_upload': os.path.join(CURRENT_DIR.parent.parent, 'files-for-upload'),
'syncConnectionName': 'Personal'
'syncConnectionName': 'Personal',
}

# Permission roles mapping
PERMISSION_ROLES = {
'Viewer': 'b1e2218d-eef8-4d4c-b82d-0f1a1b48f3b5',
'Editor': 'fb6c3e19-e378-47e5-b277-9732f9de6e21'
'Editor': 'fb6c3e19-e378-47e5-b277-9732f9de6e21',
}

CONFIG.update(DEFAULT_PATH_CONFIG)
Expand All @@ -130,9 +134,7 @@ def init_config():
# try reading configs from config.ini
try:
script_path = os.path.dirname(os.path.realpath(__file__))
cfg_path = os.path.abspath(
os.path.join(script_path, '..', '..', '..', 'config.ini')
)
cfg_path = os.path.abspath(os.path.join(script_path, '..', 'config.ini'))
read_cfg_file(cfg_path)
except:
pass
Expand Down Expand Up @@ -165,6 +167,9 @@ def init_config():
else:
CONFIG[key] = value.rstrip('/') + '/'

if 'app_path' not in CONFIG or not CONFIG['app_path']:
raise KeyError('APP_PATH must be set in config.ini or environment variables')


def get_config(key):
return CONFIG[key]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
import re
import shutil
from pathlib import Path

from pypdf import PdfReader
from docx import Document
from pptx import Presentation
from openpyxl import load_workbook

from helpers.ConfigHelper import is_windows, get_config


Expand All @@ -16,12 +16,9 @@ def build_conflicted_regex(filename):
namepart = filename.split(".")[0]
extpart = filename.split(".")[1]
# pylint: disable=anomalous-backslash-in-string
return "%s \(conflicted copy \d{4}-\d{2}-\d{2} \d{6}\)\.%s" % (
namepart,
extpart,
)
return rf"{namepart} \(conflicted copy \d{{4}}-\d{{2}}-\d{{2}} \d{{6}}\)\.{extpart}"
# pylint: disable=anomalous-backslash-in-string
return "%s \(conflicted copy \d{4}-\d{2}-\d{2} \d{6}\)" % filename
return rf"{filename} \(conflicted copy \d{{4}}-\d{{2}}-\d{{2}} \d{{6}}\)"


def sanitize_path(path):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
import glob
import shutil
import test
import squish
import squishinfo

from helpers.ConfigHelper import get_config
from helpers.FilesHelper import prefix_path_namespace
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import uuid
import os
import subprocess
import test
import psutil
from urllib.parse import urlparse
from os import makedirs
from os.path import exists, join
import test
import psutil
import squish
import squishinfo
from PySide6.QtCore import QSettings, QUuid, QUrl, QJsonValue
from appium import webdriver
from appium.options.common.base import AppiumOptions

from helpers.SpaceHelper import get_space_id, get_personal_space_id
from helpers.ConfigHelper import get_config, set_config, is_windows
from helpers.SyncHelper import listen_sync_status_for_item
from helpers.api.utils import url_join
from helpers.UserHelper import get_displayname_for_user, get_password_for_user
from helpers.ReportHelper import is_video_enabled
from helpers.api import provisioning


app_driver = None


def app():
return app_driver


def substitute_inline_codes(value):
value = value.replace('%local_server%', get_config('localBackendUrl'))
Expand All @@ -32,24 +37,24 @@ def substitute_inline_codes(value):
return value


def get_client_details(context):
def get_client_details(table):
client_details = {
'server': '',
'user': '',
'password': '',
'sync_folder': '',
'oauth': False,
}
for row in context.table[0:]:
row[1] = substitute_inline_codes(row[1])
if row[0] == 'server':
client_details.update({'server': row[1]})
elif row[0] == 'user':
client_details.update({'user': row[1]})
elif row[0] == 'password':
client_details.update({'password': row[1]})
elif row[0] == 'sync_folder':
client_details.update({'sync_folder': row[1]})
for key, value in table.items():
value = substitute_inline_codes(value)
if key == 'server':
client_details.update({'server': value})
elif key == 'user':
client_details.update({'user': value})
elif key == 'password':
client_details.update({'password': value})
elif key == 'sync_folder':
client_details.update({'sync_folder': value})
return client_details


Expand Down Expand Up @@ -103,26 +108,30 @@ def get_current_user_sync_path():


def start_client():
global app_driver
log_command_suffix = ""
logfile = get_config("clientLogFile")
logdir = get_config("clientLogDir") + "/" + squishinfo.testCaseName
logdir = get_config("clientLogDir")
if logfile != "":
log_command_suffix = f' --logfile {logfile}'
elif logdir != "":
log_command_suffix = f' --logdir {logdir}'

squish.startApplication(
'opencloud -s'
+ f' {log_command_suffix}'
+ ' --logdebug'
options = AppiumOptions()
options.set_capability(
'app',
f'{get_config("app_path")} -s {log_command_suffix} --logdebug',
)
options.set_capability(
'appium:environ',
{
'XDG_CONFIG_HOME': '/tmp/opencloudtest/.config',
},
)
app_driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723', options=options
)
if is_video_enabled():
test.startVideoCapture()
else:
test.log(
f'Video recordings reached the maximum limit of {get_config("video_record_limit")}.'
+ 'Skipping video recording...'
)
app_driver.implicitly_wait = 10


def get_polling_interval():
Expand All @@ -134,6 +143,7 @@ def get_polling_interval():
polling_interval = polling_interval.format(**args)
return polling_interval


def generate_account_config(users, space='Personal'):
sync_paths = {}
settings = QSettings(get_config('clientConfigFile'), QSettings.Format.IniFormat)
Expand All @@ -145,7 +155,7 @@ def generate_account_config(users, space='Personal'):
for idx, username in enumerate(users):
users_uuids[username] = QUuid.createUuid()
settings.beginGroup("Accounts")
settings.beginWriteArray(str(idx+1),len(users))
settings.beginWriteArray(str(idx + 1), len(users))

settings.setValue("capabilities", capabilities_variant)
settings.setValue("default_sync_root", create_user_sync_path(username))
Expand All @@ -161,7 +171,7 @@ def generate_account_config(users, space='Personal'):
settings.beginGroup("Folders")
for idx, username in enumerate(users):
sync_path = create_space_path(username, space)
settings.beginWriteArray(str(idx+1),len(users))
settings.beginWriteArray(str(idx + 1), len(users))

if space == 'Personal':
space_id = get_personal_space_id(username)
Expand All @@ -181,17 +191,17 @@ def generate_account_config(users, space='Personal'):
settings.setValue("virtualFilesMode", 'cfapi')
else:
settings.setValue("virtualFilesMode", 'off')
settings.setValue("journalPath",".sync_journal.db")
settings.setValue("journalPath", ".sync_journal.db")
settings.endArray()
settings.setValue("size", len(users))
sync_paths.update({username: sync_path})

settings.endGroup()


settings.sync()
return sync_paths


def setup_client(username, space='Personal'):
set_config('syncConnectionName', space)
sync_paths = generate_account_config([username], space)
Expand Down
Loading
Loading