From 7bbb882ffa6d9cd911699c2b66fc0fc466f8b9cc Mon Sep 17 00:00:00 2001 From: Churikova Tetiana Date: Mon, 24 Jan 2022 12:40:02 +0100 Subject: [PATCH] e2e: shared steps for session --- test/appium/support/base_test_report.py | 23 +++++++++++---- test/appium/support/github_report.py | 23 ++++++++++----- test/appium/support/test_data.py | 8 ++++-- test/appium/support/testrail_report.py | 20 +++++++++---- test/appium/tests/base_test_case.py | 38 +++++++++++++++++++++---- 5 files changed, 85 insertions(+), 27 deletions(-) diff --git a/test/appium/support/base_test_report.py b/test/appium/support/base_test_report.py index cd44ad32b5..8451637948 100644 --- a/test/appium/support/base_test_report.py +++ b/test/appium/support/base_test_report.py @@ -28,8 +28,7 @@ class BaseTestReport: file_name = "%s.json" % test_name return os.path.join(self.TEST_REPORT_DIR, file_name) - def save_test(self, test, geth: dict): - file_path = self.get_test_report_file_path(test.name) + def save_geth(self, geth: dict): geth_paths = {} for log in geth.keys(): geth_path = os.path.join(self.TEST_REPORT_DIR, log) @@ -37,6 +36,14 @@ class BaseTestReport: result.write(geth[log]) result.close() geth_paths[log] = geth_path + return geth_paths + + def save_test(self, test, geth: dict = None): + if geth: + geth_paths = self.save_geth(geth) + else: + geth_paths = test.geth_paths + file_path = self.get_test_report_file_path(test.name) test_dict = { 'testrail_case_id': test.testrail_case_id, 'name': test.name, @@ -58,7 +65,8 @@ class BaseTestReport: testruns.append(SingleTestData.TestRunData( steps=testrun_data['steps'], jobs=testrun_data['jobs'], - error=testrun_data['error'])) + error=testrun_data['error'], + first_commands=testrun_data['first_commands'])) tests.append(SingleTestData(name=test_data['name'], geth_paths=test_data['geth_paths'], testruns=testruns, @@ -85,9 +93,12 @@ class BaseTestReport: return hmac.new(bytes(self.sauce_username + ":" + self.sauce_access_key, 'latin-1'), bytes(job_id, 'latin-1'), md5).hexdigest() - def get_sauce_job_url(self, job_id): + def get_sauce_job_url(self, job_id, first_command=0): token = self.get_sauce_token(job_id) - return 'https://saucelabs.com/jobs/%s?auth=%s' % (job_id, token) + url = 'https://saucelabs.com/jobs/%s?auth=%s' % (job_id, token) + if first_command > 0: + url += "#%s" % first_command + return url @staticmethod def get_jenkins_link_to_rerun_e2e(branch_name="develop", pr_id="", apk_name="", tr_case_ids=""): @@ -107,4 +118,4 @@ class BaseTestReport: @staticmethod def is_test_successful(test): # Test passed if last testrun has passed - return test.testruns[-1].error is None + return test.testruns[-1].error is None \ No newline at end of file diff --git a/test/appium/support/github_report.py b/test/appium/support/github_report.py index 713223b90f..538a496574 100644 --- a/test/appium/support/github_report.py +++ b/test/appium/support/github_report.py @@ -2,6 +2,7 @@ import os from support.base_test_report import BaseTestReport from support.testrail_report import TestrailReport + class GithubHtmlReport(BaseTestReport): TEST_REPORT_DIR = "%s/../report" % os.path.dirname(os.path.abspath(__file__)) @@ -52,7 +53,9 @@ class GithubHtmlReport(BaseTestReport): pr_id = pytest_config_global['pr_number'] apk_name = pytest_config_global['apk'] tr_case_ids = self.list_of_failed_testrail_ids(self.get_failed_tests()) - html += "
  • Rerun tests
  • " % self.get_jenkins_link_to_rerun_e2e(pr_id=pr_id, apk_name=apk_name, tr_case_ids=tr_case_ids) + html += "
  • Rerun tests
  • " % self.get_jenkins_link_to_rerun_e2e(pr_id=pr_id, + apk_name=apk_name, + tr_case_ids=tr_case_ids) html += "
    " html += "" @@ -73,7 +76,8 @@ class GithubHtmlReport(BaseTestReport): def build_test_row_html(self, index, test, run_id): test_rail_link = TestrailReport().get_test_result_link(run_id, test.testrail_case_id) if test_rail_link: - html = "" % (index + 1, test_rail_link, test.name, test.testrail_case_id) + html = "" % ( + index + 1, test_rail_link, test.name, test.testrail_case_id) else: html = "" % (index + 1, test.name) html += "" return html - def build_device_sessions_html(self, jobs, test_run): + def build_device_sessions_html(self, test_run): html = "Device sessions" html += "

    " - return html + return html \ No newline at end of file diff --git a/test/appium/support/test_data.py b/test/appium/support/test_data.py index 1e7cf2db07..ae56616981 100644 --- a/test/appium/support/test_data.py +++ b/test/appium/support/test_data.py @@ -1,3 +1,4 @@ +from typing import Dict class SingleTestData(object): @@ -8,13 +9,14 @@ class SingleTestData(object): self.geth_paths = geth_paths class TestRunData(object): - def __init__(self, steps, jobs, error): + def __init__(self, steps, jobs, error, first_commands: Dict[str, int]): self.steps = steps self.jobs = jobs self.error = error + self.first_commands = first_commands def create_new_testrun(self): - self.testruns.append(SingleTestData.TestRunData(list(), dict(), None)) + self.testruns.append(SingleTestData.TestRunData(list(), dict(), None, dict())) class TestSuiteData(object): @@ -30,4 +32,4 @@ class TestSuiteData(object): else: test = SingleTestData(test_name, list(), testrail_case_id, list()) self.tests.append(test) - self.current_test = test + self.current_test = test \ No newline at end of file diff --git a/test/appium/support/testrail_report.py b/test/appium/support/testrail_report.py index 09cfb08f1c..4948831239 100644 --- a/test/appium/support/testrail_report.py +++ b/test/appium/support/testrail_report.py @@ -130,7 +130,11 @@ class TestrailReport(BaseTestReport): for step in last_testrun.steps: test_steps += step + "\n" for i, device in enumerate(last_testrun.jobs): - devices += "# [Device %d](%s) \n" % (i + 1, self.get_sauce_job_url(device)) + if last_testrun.first_commands: + devices += "# [Device %d](%s) \n" % ( + i + 1, self.get_sauce_job_url(job_id=device, first_command=last_testrun.first_commands[device])) + else: + devices += "# [Device %d](%s) \n" % (i + 1, self.get_sauce_job_url(job_id=device)) data = {'status_id': self.outcomes['undefined_fail'] if last_testrun.error else self.outcomes['passed'], 'comment': '%s' % ('# Error: \n %s \n' % emoji.demojize( last_testrun.error)) + devices + test_steps if last_testrun.error @@ -166,13 +170,17 @@ class TestrailReport(BaseTestReport): ids_failed_test.append(test.testrail_case_id) case_title = '\n' case_title += '-------\n' - case_title += "## %s) ID %s: [%s](%s) \n" % (i + 1, test.testrail_case_id, test.name, test_rail_link) + case_title += "## %s) ID %s: [%s](%s) \n" % ( + i + 1, test.testrail_case_id, test.name, test_rail_link) error = "```%s```\n" % last_testrun.error[:255] for job_id, f in last_testrun.jobs.items(): + if last_testrun.first_commands: + job_url = self.get_sauce_job_url(job_id=job_id, + first_command=last_testrun.first_commands[job_id]) + else: + job_url = self.get_sauce_job_url(job_id=job_id) case_info = "Logs for device %d: [steps](%s), [failure screenshot](%s)" \ - % (f, - self.get_sauce_job_url(job_id), - self.get_sauce_final_screenshot_url(job_id)) + % (f, job_url, self.get_sauce_final_screenshot_url(job_id)) description += case_title + error + case_info description_title += '## Failed tests: %s \n' % ','.join(map(str, ids_failed_test)) @@ -196,4 +204,4 @@ class TestrailReport(BaseTestReport): test_id = self.get('get_results_for_case/%s/%s' % (test_run_id, test_case_id))['results'][0]['test_id'] return '%stests/view/%s' % (self.url, test_id) except KeyError: - return None + return None \ No newline at end of file diff --git a/test/appium/tests/base_test_case.py b/test/appium/tests/base_test_case.py index 2556371c11..7a8c7d3a2c 100644 --- a/test/appium/tests/base_test_case.py +++ b/test/appium/tests/base_test_case.py @@ -4,13 +4,18 @@ import re import subprocess import sys from abc import ABCMeta, abstractmethod +from http.client import RemoteDisconnected from os import environ import pytest +import requests from appium import webdriver from appium.webdriver.common.mobileby import MobileBy +from sauceclient import SauceException from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import WebDriverException +from selenium.webdriver.support.wait import WebDriverWait + from tests import transl from support.api.network_api import NetworkApi @@ -19,8 +24,9 @@ from tests import test_suite_data, start_threads, appium_container, pytest_confi import base64 from re import findall -sauce_username = environ.get('SAUCE_USERNAME') +from tests.conftest import sauce +sauce_username = environ.get('SAUCE_USERNAME') sauce_access_key = environ.get('SAUCE_ACCESS_KEY') @@ -334,6 +340,8 @@ class LocalSharedMultipleDeviceTestCase(AbstractTestCase): class SauceSharedMultipleDeviceTestCase(AbstractTestCase): def setup_method(self, method): + for _, driver in self.drivers.items(): + driver.execute_script("sauce:context=Started %s" % method.__name__) jobs = test_suite_data.current_test.testruns[-1].jobs if not jobs: for index, driver in self.drivers.items(): @@ -354,16 +362,36 @@ class SauceSharedMultipleDeviceTestCase(AbstractTestCase): pass finally: geth = {geth_names[i]: geth_contents[i] for i in range(len(geth_names))} - self.github_report.save_test(test_suite_data.current_test, geth) + test_suite_data.current_test.geth_paths = self.github_report.save_geth(geth) @classmethod def teardown_class(cls): - for driver in cls.drivers: + requests_session = requests.Session() + requests_session.auth = (sauce_username, sauce_access_key) + for _, driver in cls.drivers.items(): + session_id = driver.session_id try: - cls.drivers[driver].quit() + sauce.jobs.update_job(job_id=session_id, name=cls.__name__) + except (RemoteDisconnected, SauceException): + pass + try: + driver.quit() except WebDriverException: pass + url = sauce.jobs.get_job_asset_url(job_id=session_id, filename="log.json") + WebDriverWait(driver, 60, 2).until(lambda _: requests_session.get(url).status_code == 200) + commands = requests_session.get(url).json() + for command in commands: + try: + if command['message'].startswith("Started "): + for test in test_suite_data.tests: + if command['message'] == "Started %s" % test.name: + test.testruns[-1].first_commands[session_id] = commands.index(command) + 1 + except KeyError: + continue cls.loop.close() + for test in test_suite_data.tests: + cls.github_report.save_test(test) if pytest_config_global['env'] == 'local': @@ -380,4 +408,4 @@ class NoDeviceTestCase(AbstractTestCase): pass def teardown_method(self, method): - self.github_report.save_test(test_suite_data.current_test) + self.github_report.save_test(test_suite_data.current_test) \ No newline at end of file
    %s. %s, id: %s
    %s. %s, id: %s
    %d. %s (TestRail link is not found)
    " @@ -92,20 +96,25 @@ class GithubHtmlReport(BaseTestReport): html += "%s" % last_testrun.error[:255] html += "

    " if last_testrun.jobs: - html += self.build_device_sessions_html(last_testrun.jobs, last_testrun) + html += self.build_device_sessions_html(last_testrun) html += "