Ci/74 jenkins file (#118)

* Set up Jenkins file

#74

* Fix Allure trend

* Display resolution changed on CI

* TestRail integration

* Fix test on create community

* Fix wallet tests

* Fix field description in jenkinsfile

* Test name and test scope parameters were split in Jenkinsfile

* Clean up moved in post stage

* Environment variables set up changed in JenkinsFile

* Fix test ID

* Fix warnings in JenkinsFile

* Copy artifacts directory changed

* Fix of two space indentations in Jenkinsfile

* Extra environment variable removed

* Move tests wallet in one folder

---------

Co-authored-by: Valentina Novgorodtceva <valentina@status.im>
This commit is contained in:
Vladimir Druzhinin 2023-09-28 14:44:13 +02:00 committed by GitHub
parent 62a32d9b37
commit fd64142295
28 changed files with 176 additions and 34 deletions

113
test/e2e/ci/Jenkinsfile vendored Normal file
View File

@ -0,0 +1,113 @@
#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.7.13'
pipeline {
agent {
label 'linux && x86_64 && qt-5.15.2'
}
environment {
SQUISH_DIR = "/opt/squish-runner-7.1-20230222-1555"
PYTHONPATH = "${SQUISH_DIR}/lib:${SQUISH_DIR}/lib/python:${PYTHONPATH}"
LD_LIBRARY_PATH = "${SQUISH_DIR}/lib:${SQUISH_DIR}/python3/lib:${LD_LIBRARY_PATH}"
CREDS = credentials('test-rail-api-devops')
TESTRAIL_URL = "https://ethstatus.testrail.net"
}
parameters {
string(
name: 'BRANCH',
description: 'Paste a branch name from test repository.',
defaultValue: 'master'
)
string(
name: 'BUILD',
description: 'Paste a number of PR that you want to test.',
defaultValue: 'PR-'
)
string(
name: 'TEST_NAME',
description: 'Paste test name/part of test name to run specific test',
defaultValue: ''
)
string(
name: 'TEST_SCOPE',
description: 'Paste tag to run specific scope of tests',
defaultValue: ''
)
string(
name: 'TESTRAIL_RUN_ID',
description: 'Test run ID in Test Rail',
defaultValue: ''
)
}
options {
timestamps()
/* Prevent Jenkins jobs from running forever */
timeout(time: 120, unit: 'MINUTES')
/* manage how many builds we keep */
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '30',
artifactNumToKeepStr: '3',
))
}
stages {
stage('Download') {
steps { script {
copyArtifacts(
projectName: "status-desktop/branches/linux/x86_64/package/${params.BUILD}/",
filter: 'pkg/*-x86_64.tar.gz',
selector: lastWithArtifacts(),
target: "${env.WORKSPACE}/tmp"
)
def pkg_path = "${env.WORKSPACE}/${utils.findFile('tmp/pkg/*-x86_64.tar.gz')}"
sh "tar -zxvf '${pkg_path}' -C '${env.WORKSPACE}/tmp'"
def app_dir = "${env.WORKSPACE}/${utils.findFile('tmp/*.AppImage')}"
env.APP_DIR = app_dir
} }
}
stage('Setup') {
steps { script {
sh 'pip3 install --user -r requirements.txt'
} }
}
stage('Test') {
steps { wrap([
$class: 'Xvfb',
autoDisplayName: true,
parallelBuild: false,
screen: '1920x1080x24',
]) { script {
env.TESTRAIL_USR = "${CREDS_USR}"
env.TESTRAIL_PWD = "${CREDS_PSW}"
def cmd = ''
if (params.TEST_NAME != "") {
cmd = cmd + " -k ${params.TEST_NAME}"
}
if (params.TEST_SCOPE != "") {
cmd = cmd + " -m ${params.TEST_SCOPE}"
}
sh "cp -f '${env.WORKSPACE}'/configs/_local.py.ci '${env.WORKSPACE}'/configs/_local.py"
sh "python3 -m pytest ${cmd} --disable-warnings --alluredir=${env.WORKSPACE}/allure-results"
}}}
}
}
post {
always { script {
allure([
jdk: '',
properties: [],
results: [[path: 'allure-results']],
reportBuildPolicy: 'ALWAYS',
])
}}
cleanup { cleanWs() }
}
}

View File

@ -1 +1,2 @@
AUT_PORT = 61500
MLT_AUT_PORT = 61600

View File

@ -1,6 +1,6 @@
import os
TESTRAIL_RUN_ID = os.getenv('TESTRAIL_URL', '').strip()
TESTRAIL_RUN_ID = os.getenv('TESTRAIL_RUN_ID', '').strip()
TESTRAIL_URL = os.getenv('TESTRAIL_URL', None)
TESTRAIL_USER = os.getenv('TESTRAIL_USER', None)
TESTRAIL_USR = os.getenv('TESTRAIL_USR', None)
TESTRAIL_PWD = os.getenv('TESTRAIL_PWD', None)

View File

@ -7,17 +7,17 @@ from PIL import ImageGrab
import configs
import driver
from driver.aut import AUT
from scripts.utils import local_system
from scripts.utils.system_path import SystemPath
from tests.fixtures.path import generate_test_info
from fixtures.path import generate_test_info
_logger = logging.getLogger(__name__)
pytest_plugins = [
'tests.fixtures.aut',
'tests.fixtures.path',
'tests.fixtures.squish',
'tests.fixtures.testrail',
'fixtures.aut',
'fixtures.path',
'fixtures.squish',
'fixtures.testrail',
]
@ -62,5 +62,9 @@ def pytest_exception_interact(node):
body=screenshot.read_bytes(),
attachment_type=allure.attachment_type.PNG)
driver.context.detach()
for port in [configs.squish.AUT_PORT, configs.squish.MLT_AUT_PORT]:
pid = local_system.find_process_by_port(port)
if pid is not None:
local_system.kill_process(pid, verify=True)
except Exception as ex:
_logger.debug(ex)

View File

@ -1,3 +1,4 @@
import logging
from datetime import datetime
import allure
@ -10,6 +11,8 @@ from driver.server import SquishServer
from scripts.utils import system_path, local_system
from scripts.utils.system_path import SystemPath
_logger = logging.getLogger(__name__)
class AUT:
def __init__(
@ -78,12 +81,12 @@ class AUT:
f'-d={self.app_data}'
]
local_system.execute(command)
self.attach()
else:
SquishServer().add_executable_aut(self.aut_id, self.path.parent)
command = [self.aut_id, f'-d={self.app_data}']
self.ctx = squish.startApplication(' '.join(command), configs.timeouts.PROCESS_TIMEOUT_SEC)
self.attach()
self.pid = self.ctx.pid
assert squish.waitFor(lambda: self.ctx.isRunning, configs.timeouts.PROCESS_TIMEOUT_SEC)
return self

View File

@ -10,17 +10,18 @@ _logger = logging.getLogger(__name__)
@allure.step('Attaching to "{0}"')
def attach(aut_name: str, timeout_sec: int = configs.timeouts.PROCESS_TIMEOUT_SEC):
def attach(aut_id: str, timeout_sec: int = configs.timeouts.PROCESS_TIMEOUT_SEC):
started_at = time.monotonic()
_logger.debug(f'Attaching to {aut_id}')
while True:
try:
context = squish.attachToApplication(aut_name)
_logger.info(f'AUT: {aut_name} attached')
context = squish.attachToApplication(aut_id)
_logger.info(f'AUT: {aut_id} attached')
return context
except RuntimeError as err:
_logger.debug(err)
time.sleep(1)
assert time.monotonic() - started_at < timeout_sec, f'Attach error: {aut_name}'
assert time.monotonic() - started_at < timeout_sec, f'Attach error: {aut_id}'
@allure.step('Detaching')

View File

@ -33,8 +33,8 @@ class SquishServer:
def stop(self):
if self.pid is not None:
local_system.kill_process(self.pid)
self.pid = None
local_system.kill_process(self.pid, verify=True)
self.pid = None
# https://doc-snapshots.qt.io/squish/cli-squishserver.html
def configuring(self, action: str, options: typing.Union[int, str, list]):

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -18,4 +18,3 @@ def start_squish_server():
pytest.exit(err)
yield squish_server
squish_server.stop()
squish_server.config.unlink()

View File

@ -22,7 +22,7 @@ def init_testrail_api(request):
_logger.info('TestRail API initializing')
testrail_api = TestRailAPI(
configs.testrail.TESTRAIL_URL,
configs.testrail.TESTRAIL_USER,
configs.testrail.TESTRAIL_USR,
configs.testrail.TESTRAIL_PWD
)
test_case_ids = get_test_ids_in_session(request)

View File

@ -1,3 +1,4 @@
import logging
import typing
import allure
@ -14,6 +15,9 @@ from gui.elements.qt.text_edit import TextEdit
from gui.screens.community import CommunityScreen
_logger = logging.getLogger(__name__)
class CreateCommunitiesBanner(BasePopup):
def __init__(self):
@ -69,11 +73,21 @@ class CreateCommunityPopup(BasePopup):
def logo(self):
return NotImplementedError
def _open_logo_file_dialog(self, attempt: int = 2):
self._add_logo_button.click()
try:
return OpenFileDialog().wait_until_appears().prepare()
except LookupError as err:
if attempt:
_logger.debug(err)
return self._open_logo_file_dialog(attempt-1)
else:
raise
@logo.setter
@allure.step('Set community logo')
def logo(self, kwargs: dict):
self._add_logo_button.click()
OpenFileDialog().wait_until_appears().open_file(kwargs['fp'])
self._open_logo_file_dialog().open_file(kwargs['fp'])
PictureEditPopup().wait_until_appears().make_picture(kwargs.get('zoom', None), kwargs.get('shift', None))
@property

View File

@ -21,7 +21,7 @@ GENERATED_PAGES_LIMIT = 20
class AccountPopup(BasePopup):
def __init__(self):
super(AccountPopup, self).__init__()
self._scroll = Scroll('scrollView_StatusScrollView')
self._scroll = Scroll('o_Flickable')
self._name_text_edit = TextEdit('mainWallet_AddEditAccountPopup_AccountName')
self._emoji_button = Button('mainWallet_AddEditAccountPopup_AccountEmojiPopupButton')
self._color_radiobutton = QObject('color_StatusColorRadioButton')
@ -108,7 +108,7 @@ class AccountPopup(BasePopup):
self._address_combobox_button.click()
GeneratedAddressesList().wait_until_appears().select(index)
if value != constants.wallet.DerivationPath.ETHEREUM.value:
self._scroll.vertical_down_to(self._non_eth_checkbox)
self._scroll.vertical_scroll_to(self._non_eth_checkbox)
self._non_eth_checkbox.set(True)
else:
self._derivation_path_text_edit.type_text(str(index))

View File

@ -2,6 +2,7 @@ import logging
import allure
import configs
import driver
from gui.elements.qt.object import QObject
@ -47,3 +48,8 @@ class Window(QObject):
@allure.step("Hide {0}")
def hide(self):
driver.waitForObjectExists(self.real_name).setVisible(False)
def wait_until_appears(self, timeout_msec: int = configs.timeouts.UI_LOAD_TIMEOUT_MSEC):
super().wait_until_appears(timeout_msec)
_logger.info(f'Window {getattr(self.object, "title", "")} appears')
return self

View File

@ -6,3 +6,4 @@ addopts = --disable-warnings
markers =
smoke: Smoke tests
self: Framework self-tests

View File

@ -108,8 +108,8 @@ def test_generate_new_keys(main_window, keys_screen, user_name: str, password, u
)
@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/703039', 'Import: 12 word seed phrase')
@pytest.mark.case(703039)
@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/703040', 'Import: 12 word seed phrase')
@pytest.mark.case(703040)
@pytest.mark.parametrize('user_account', [constants.user.user_account_two])
def test_import_seed_phrase(aut: AUT, keys_screen, main_window, user_account):
with step('Open import seed phrase view and enter seed phrase'):

View File

@ -1,12 +1,14 @@
import logging
import allure
import driver
import pytest
from allure_commons._allure import step
_logger = logging.getLogger(__name__)
pytestmark = allure.suite("Self")
def test_start_aut():
driver.context.detach()
@pytest.mark.self
def test_start_aut(main_window):
with step("Verify: 'main_window' fixture launched test app and prepared main window"):
assert main_window.exists

View File

@ -8,12 +8,8 @@ import constants
import driver
from gui.components.signing_phrase_popup import SigningPhrasePopup
from gui.components.wallet.authenticate_popup import AuthenticatePopup
from gui.components.wallet.testnet_mode_banner import TestnetModeBanner
from gui.components.wallet.wallet_toast_message import WalletToastMessage
from gui.main_window import MainWindow
from gui.screens.settings import KeycardSettingsView
from scripts.tools import image
pytestmark = allure.suite("Wallet")

View File

@ -7,14 +7,16 @@ from allure import step
import configs
import constants
import driver
from constants.wallet import WalletNetworkSettings
from gui.components.signing_phrase_popup import SigningPhrasePopup
from gui.components.wallet.authenticate_popup import AuthenticatePopup
from gui.components.wallet.testnet_mode_banner import TestnetModeBanner
from gui.components.wallet.wallet_toast_message import WalletToastMessage
from constants.wallet import WalletNetworkSettings
from gui.main_window import MainWindow
from scripts.tools import image
pytestmark = allure.suite("Wallet")
@allure.testcase('https://ethstatus.testrail.net/index.php?/cases/view/703505', 'Network: Testnet switching')
@pytest.mark.case(703505)
@ -200,7 +202,7 @@ def test_change_account_order_not_possible(main_screen: MainWindow, default_name
assert account_order.accounts[0].name == default_name
with step('Back button is present and text on top is correct'):
assert account_order.text_labels_from_edit_account_order_settings[0] == text_on_top
assert account_order.account_recommendations[0] == text_on_top
assert account_order.is_back_button_present() is True