diff options
author | saw-jan <saw.jan.grg3e@gmail.com> | 2022-03-25 12:48:36 +0300 |
---|---|---|
committer | Sawjan Gurung <saw.jan.grg3e@gmail.com> | 2022-03-31 09:12:51 +0300 |
commit | 6a106b86246548a78f7842e51ec445c01b8edf17 (patch) | |
tree | 18fcc8d87c04c1c636e70ee72f86c0715fa69b52 /test | |
parent | 06f70b0d53f318b396555f39e5e23ac653cb74c2 (diff) |
save stacktrace of AUT crash to a file
move to helper file
Diffstat (limited to 'test')
-rw-r--r-- | test/gui/shared/scripts/bdd_hooks.py | 15 | ||||
-rw-r--r-- | test/gui/shared/scripts/helpers/SetupClientHelper.py | 66 | ||||
-rw-r--r-- | test/gui/shared/scripts/helpers/StacktraceHelper.py | 68 |
3 files changed, 83 insertions, 66 deletions
diff --git a/test/gui/shared/scripts/bdd_hooks.py b/test/gui/shared/scripts/bdd_hooks.py index f36132868..564ae0863 100644 --- a/test/gui/shared/scripts/bdd_hooks.py +++ b/test/gui/shared/scripts/bdd_hooks.py @@ -19,6 +19,7 @@ import shutil import urllib.request import os import builtins +from helpers.StacktraceHelper import getCoredump, generateStacktrace @OnScenarioStart @@ -64,7 +65,7 @@ def hook(context): for key, value in context.userData.items(): if value == '': context.userData[key] = DEFAULT_CONFIG[key] - elif key == 'maxSyncTimeout': + elif key == 'maxSyncTimeout' or key == 'minSyncTimeout': context.userData[key] = builtins.int(value) elif key == 'clientRootSyncPath': # make sure there is always one trailing slash @@ -93,6 +94,18 @@ def hook(context): @OnScenarioEnd def hook(context): + # search coredumps after every test scenario + # CI pipeline might fail although all tests are passing + coredumps = getCoredump() + if len(coredumps) > 0: + try: + generateStacktrace(context, coredumps) + print("Stacktrace generated.") + except Exception as err: + print(err) + else: + print("No coredump found!") + # capture screenshot if there is error in the scenario execution, and if the test is being run in CI if test.resultCount("errors") > 0 and os.getenv('CI'): import gi diff --git a/test/gui/shared/scripts/helpers/SetupClientHelper.py b/test/gui/shared/scripts/helpers/SetupClientHelper.py index 19d3783dc..fb996d63e 100644 --- a/test/gui/shared/scripts/helpers/SetupClientHelper.py +++ b/test/gui/shared/scripts/helpers/SetupClientHelper.py @@ -1,10 +1,7 @@ from urllib.parse import urlparse import squish -from os import makedirs, environ +from os import makedirs from os.path import exists, join -import test -import subprocess -from configparser import ConfigParser confdir = '/tmp/bdd-tests-owncloud-client/' @@ -78,71 +75,10 @@ def startClient(context): + " --confdir " + confdir ) - squish.installEventHandler("Crash", "crashHandler") squish.snooze(1) -def crashHandler(): - # The core dump is generated in the folder /var/lib/apport/coredump/ - coredumpFolderPath = '/var/lib/apport/coredump/' - cfg = ConfigParser() - - # Select appropriate AUT binary with respect to the test run environment - try: - if environ.get('CI'): - cfg.read('/drone/src/test/gui/drone/server.ini') - - else: - from pathlib import Path - - HOME = str(Path.home()) - cfg.read(HOME + '/.squish/ver1/server.ini') - - except Exception as err: - test.log("the binary path can not be read") - test.log(err) - - owncloudBinary = cfg.get('General', 'AUT/owncloud') - owncloudBinary = owncloudBinary.replace('"', '') + '/owncloud' - - # GUI test stacktrace on crash - test.log("Started printing the GUI test stacktrace of crash") - test.log("############################################################") - test.log("Backtracking...") - test.log("%s" % test.stackTrace()) - test.log("############################################################") - test.log("Finished printing GUI test stacktrace") - - test.log("Started printing the AUT stacktrace of crash") - test.log("############################################################") - ls = subprocess.run( - ['ls', '-t', coredumpFolderPath], stdout=subprocess.PIPE - ).stdout.decode('utf-8') - coredumpFilename = ls.split('\n')[0] - test.log("located latest core dump file: %s" % coredumpFilename) - - if coredumpFilename: - test.log("Backtracking...") - test.log( - "%s" - % subprocess.run( - [ - 'gdb', - owncloudBinary, - coredumpFolderPath + coredumpFilename.strip(), - '-batch', - '-ex', - 'bt full', - ], - stdout=subprocess.PIPE, - ).stdout.decode('utf-8') - ) - - test.log("############################################################") - test.log("Finished printing AUT stacktrace") - - def getPollingInterval(): pollingInterval = '''[ownCloud] remotePollInterval={pollingInterval} diff --git a/test/gui/shared/scripts/helpers/StacktraceHelper.py b/test/gui/shared/scripts/helpers/StacktraceHelper.py new file mode 100644 index 000000000..01133ff2d --- /dev/null +++ b/test/gui/shared/scripts/helpers/StacktraceHelper.py @@ -0,0 +1,68 @@ +import os +import builtins +import subprocess +import glob +import re +from datetime import datetime + + +def getCoredump(): + # read coredump location + with open("/proc/sys/kernel/core_pattern", "r") as f: + coredumpPath = f.read().strip("\n") + + # yields something like: /tmp/core-*-*-*-* + coredumpFilePattern = re.sub(r'%[a-zA-Z]{1}', '*', coredumpPath) + return glob.glob(coredumpFilePattern) + + +def generateStacktrace(context, coredumps): + message = ["###########################################"] + message.append("Scenario: " + context._data["title"]) + + for coredumpFile in coredumps: + message.append(parseStacktrace(coredumpFile)) + + message.append("###########################################") + message.append("") + message = "\n".join(message) + + stacktrace_file = os.environ.get("STACKTRACE_FILE", "../stacktrace") + # save stacktrace to a file + open(stacktrace_file, "a").write(message) + + +def parseStacktrace(coredumpFile): + message = [] + if builtins.bool(coredumpFile): + coredumpFilename = os.path.basename(coredumpFile) + # example coredump file: core-1648445754-1001-11-!drone!src!build-GUI-tests!bin!owncloud + patterns = coredumpFilename.split('-') + appBinary = "-".join(patterns[4:]).replace('!', '/') + + message.append("-------------------------------------------") + message.append("Executable: " + appBinary) + message.append("Timestamp: " + str(datetime.fromtimestamp(float(patterns[1])))) + message.append("Process ID: " + patterns[2]) + message.append("Signal Number: " + patterns[3]) + message.append("-------------------------------------------") + message.append("<<<<< STACKTRACE START >>>>>") + message.append( + subprocess.run( + [ + 'gdb', + appBinary, + coredumpFile, + '-batch', + '-ex', + 'bt full', + ], + stdout=subprocess.PIPE, + ).stdout.decode('utf-8') + ) + message.append("<<<<< STACKTRACE END >>>>>") + + # remove coredump file + os.unlink(coredumpFile) + + return "\n".join(message) |