toaster: tts fixes
cover toaster: tts fixes
Hi reviewers,
This is a set of fixes for Toaster TTS testing system from Alex.
The patchset has been reviewed by me. Please review and accept.
The following changes since commit bef724057f1ea81571dd3ac5a9cf862f818434b5:
build: Exit scripts with result of last shell function (2015-07-27 16:29:11 +0100)
are available in the git repository at:
git://git.yoctoproject.org/poky-contrib ed/toaster/submit/adamian/20150715_testfixes
http://git.yoctoproject.org/cgit.cgi/poky-contrib/log/?h=ed/toaster/submit/adamian/20150715_testfixes
Alexandru DAMIAN (11):
toaster: tts: fix pylint warnings
toaster: tts: clean up HTML5 compatible url list toaster tests: gitignore and use absolute path for log file
toaster: tts: improve debugging information
toaster: tts: improve logging in urlcheck.py
toaster: tts: fix startup and cleanup for managed mode
toaster: tts: delete pyc files before the tests start
toaster: tts: delete the database only if created
toaster: tts: make sure to import data
toaster: tts: execute tests in numeric order
toaster: toastergui: run pylint on the toaster files
.gitignore | 3 + lib/toaster/contrib/tts/config.py | 37 +++++++----- lib/toaster/contrib/tts/launcher.py | 35 +++++------ lib/toaster/contrib/tts/recv.py | 17 ++++-- lib/toaster/contrib/tts/runner.py | 110 ++++++++++++++++++++-------------- lib/toaster/contrib/tts/scratchpad.py | 20 ------- lib/toaster/contrib/tts/shellutils.py | 64 ++++++++++---------- lib/toaster/contrib/tts/tests.py | 63 ++++++++++--------- lib/toaster/contrib/tts/urlcheck.py | 38 ++++++++---- lib/toaster/contrib/tts/urllist.py | 83 ++++++++++++------------- 10 files changed, 250 insertions(+), 220 deletions(-) delete mode 100644 lib/toaster/contrib/tts/scratchpad.py
--
Regards,
Ed
PATCH 1/11 toaster: tts: fix pylint warnings
From: Alexandru DAMIAN <[email protected]>
This patch brings TTS to the pylint coding standards. Pylint was run with some disables:
disable=logging-too-many-args,line-too-long,missing-docstring
and achieved
Your code has been rated at 10.00/10
There are no functional changes.
--- lib/toaster/contrib/tts/config.py | 37 ++++++++------ lib/toaster/contrib/tts/launcher.py | 35 +++++++------- lib/toaster/contrib/tts/recv.py | 13 +++-- lib/toaster/contrib/tts/runner.py | 87 +++++++++++++++++---------------- lib/toaster/contrib/tts/scratchpad.py | 20 -------- lib/toaster/contrib/tts/shellutils.py | 64 +++++++++++++------------ lib/toaster/contrib/tts/tests.py | 43 ++++++++--------- lib/toaster/contrib/tts/urlcheck.py | 29 ++++++----- lib/toaster/contrib/tts/urllist.py | 90 +++++++++++++++++------------------ 9 files changed, 208 insertions(+), 210 deletions(-) delete mode 100644 lib/toaster/contrib/tts/scratchpad.py
lib/toaster/contrib/tts/config.py +22 -15
@@ -28,42 +28,48 @@ LOGDIR = "log" SETTINGS_FILE = os.path.join(os.path.dirname(__file__), "settings.json") TEST_DIR_NAME = "tts_testdir" +DEBUG = True + OWN_PID = os.getpid() W3C_VALIDATOR = "http://icarus.local/w3c-validator/check?doctype=HTML5&uri=" -#TODO assign port dynamically -TOASTER_PORT=56789 +TOASTER_PORT = 56789 + +TESTDIR = None #we parse the w3c URL to know where to connect import urlparse def get_public_ip(): - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - p = urlparse.urlparse("http://icarus.local/w3c-validator/check?doctype=HTML5&uri=") - s.connect(( p.netloc, 80 if p.port is None else p.port)) - hn = s.getsockname()[0] - s.close() - return hn + temp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + parsed_url = urlparse.urlparse("http://icarus.local/w3c-validator/check?doctype=HTML5&uri=") + temp_socket.connect((parsed_url.netloc, 80 if parsed_url.port is None else parsed_url.port)) + public_ip = temp_socket.getsockname()[0] + temp_socket.close() + return public_ip -TOASTER_BASEURL="http://%s:%d/" % (get_public_ip(), TOASTER_PORT) +TOASTER_BASEURL = "http://%s:%d/" % (get_public_ip(), TOASTER_PORT) OWN_EMAIL_ADDRESS = "Toaster Testing Framework <[email protected]>" REPORT_EMAIL_ADDRESS = "[email protected]" # make sure we have the basic logging infrastructure + +#pylint: disable=invalid-name +# we disable the invalid name because the module-level "logger" is used througout bitbake logger = logging.getLogger("toastertest") -__console = logging.StreamHandler(sys.stdout) -__console.setFormatter(logging.Formatter("%(asctime)s %(levelname)s: %(message)s")) -logger.addHandler(__console) +__console__ = logging.StreamHandler(sys.stdout) +__console__.setFormatter(logging.Formatter("%(asctime)s %(levelname)s: %(message)s")) +logger.addHandler(__console__) logger.setLevel(logging.DEBUG) # singleton file names -LOCKFILE="/tmp/ttf.lock" -BACKLOGFILE=os.path.join(os.path.dirname(__file__), "backlog.txt") +LOCKFILE = "/tmp/ttf.lock" +BACKLOGFILE = os.path.join(os.path.dirname(__file__), "backlog.txt") # task states def enum(*sequential, **named):
@@ -73,7 +79,8 @@ def enum(*sequential, **named): return type('Enum', (), enums) -class TASKS: +class TASKS(object): + #pylint: disable=too-few-public-methods PENDING = "PENDING" INPROGRESS = "INPROGRESS" DONE = "DONE"
lib/toaster/contrib/tts/launcher.py +18 -17
@@ -31,13 +31,11 @@ import smtplib # Import the email modules we'll need from email.mime.text import MIMEText -DEBUG=True - def _take_lockfile(): return shellutils.lockfile(shellutils.mk_lock_filename()) -def read_next_task_by_state(task_state, task_name = None): +def read_next_task_by_state(task_state, task_name=None): if not os.path.exists(os.path.join(os.path.dirname(__file__), config.BACKLOGFILE)): return None os.rename(config.BACKLOGFILE, config.BACKLOGFILE + ".tmp")
@@ -56,28 +54,28 @@ def read_next_task_by_state(task_state, task_name = None): os.remove(config.BACKLOGFILE + ".tmp") return task -def send_report(task_name, plaintext, errtext = None): +def send_report(task_name, plaintext, errtext=None): if errtext is None: msg = MIMEText(plaintext) else: if plaintext is None: - plaintext="" + plaintext = "" msg = MIMEText("--STDOUT dump--\n\n%s\n\n--STDERR dump--\n\n%s" % (plaintext, errtext)) msg['Subject'] = "[review-request] %s - smoke test results" % task_name msg['From'] = config.OWN_EMAIL_ADDRESS msg['To'] = config.REPORT_EMAIL_ADDRESS - s = smtplib.SMTP("localhost") - s.sendmail(config.OWN_EMAIL_ADDRESS, [config.REPORT_EMAIL_ADDRESS], msg.as_string()) - s.quit() + smtp_connection = smtplib.SMTP("localhost") + smtp_connection.sendmail(config.OWN_EMAIL_ADDRESS, [config.REPORT_EMAIL_ADDRESS], msg.as_string()) + smtp_connection.quit() -if __name__ == "__main__": +def main(): # we don't do anything if we have another instance of us running - lf = _take_lockfile() + lock_file = _take_lockfile() - if lf is None: - if DEBUG: + if lock_file is None: + if config.DEBUG: print("Concurrent script in progress, exiting") sys.exit(1)
@@ -88,13 +86,16 @@ if __name__ == "__main__": out = None try: out = shellutils.run_shell_cmd("%s %s" % (os.path.join(os.path.dirname(__file__), "runner.py"), next_task)) - pass - except ShellCmdException as e: - print("Failed while running the test runner: %s", e) - errtext = e.__str__() + except ShellCmdException as exc: + print("Failed while running the test runner: %s", exc) + errtext = exc.__str__() send_report(next_task, out, errtext) read_next_task_by_state(config.TASKS.INPROGRESS, next_task) else: print("No task") - shellutils.unlockfile(lf) + shellutils.unlockfile(lock_file) + + +if __name__ == "__main__": + main()
lib/toaster/contrib/tts/recv.py +9 -4
@@ -26,7 +26,6 @@ from __future__ import print_function import sys, os, config, shellutils -from shellutils import ShellCmdException from email.parser import Parser
@@ -34,9 +33,13 @@ def recv_mail(datastring): headers = Parser().parsestr(datastring) return headers['subject'] +def main(): + lock_file = shellutils.lockfile(shellutils.mk_lock_filename(), retry=True) -if __name__ == "__main__": - lf = shellutils.lockfile(shellutils.mk_lock_filename(), retry = True) + if lock_file is None: + if config.DEBUG: + print("Concurrent script in progress, exiting") + sys.exit(1) subject = recv_mail(sys.stdin.read())
@@ -47,5 +50,7 @@ if __name__ == "__main__": line = "%s|%s\n" % (task_name, config.TASKS.PENDING) fout.write(line) - shellutils.unlockfile(lf) + shellutils.unlockfile(lock_file) +if __name__ == "__main__": + main()
lib/toaster/contrib/tts/runner.py +45 -42
177 lines not on this page · raw message
lib/toaster/contrib/tts/scratchpad.py deleted +0 -20
@@ -1,20 +0,0 @@ -import config - -# Code testing section -def _code_test(): - def callback_writeeventlog(opt, opt_str, value, parser): - if len(parser.rargs) < 1 or parser.rargs[0].startswith("-"): - value = "" - else: - value = parser.rargs[0] - del parser.rargs[0] - - setattr(parser.values, opt.dest, value) - - parser = optparse.OptionParser() - parser.add_option("-w", "--write-log", help = "Writes the event log of the build to a bitbake event json file.", - action = "callback", callback=callback_writeeventlog, dest = "writeeventlog") - - options, targets = parser.parse_args(sys.argv) - - print (options, targets)
lib/toaster/contrib/tts/shellutils.py +33 -31
118 lines not on this page · raw message
lib/toaster/contrib/tts/tests.py +20 -23
83 lines not on this page · raw message
lib/toaster/contrib/tts/urlcheck.py +17 -12
@@ -2,40 +2,45 @@ from __future__ import print_function import sys import httplib2 -import time import config import urllist -# TODO: turn to a test def validate_html5(url): - h = httplib2.Http(".cache") + http_client = httplib2.Http(None) status = "Failed" errors = -1 warnings = -1 - # TODO: the w3c-validator must be a configurable setting urlrequest = config.W3C_VALIDATOR+url + + # pylint: disable=broad-except + # we disable the broad-except because we want to actually catch all possible exceptions try: - resp, content = h.request(urlrequest, "HEAD") + resp, _ = http_client.request(urlrequest, "HEAD") if resp['x-w3c-validator-status'] != "Abort": status = resp['x-w3c-validator-status'] errors = int(resp['x-w3c-validator-errors']) warnings = int(resp['x-w3c-validator-warnings']) - except Exception as e: - config.logger.warn("Failed validation call: %s" % e.__str__()) + except Exception as exc: + config.logger.warn("Failed validation call: %s", exc) return (status, errors, warnings) -if __name__ == "__main__": - print("Testing %s with %s" % (config.TOASTER_BASEURL, config.W3C_VALIDATOR)) - def print_validation(url): - status, errors, warnings = validate_html5(url) - config.logger.error("url %s is %s\terrors %s warnings %s (check at %s)" % (url, status, errors, warnings, config.W3C_VALIDATOR+url)) +def print_validation(url): + status, errors, warnings = validate_html5(url) + config.logger.error("url %s is %s\terrors %s warnings %s (check at %s)", url, status, errors, warnings, config.W3C_VALIDATOR+url) + + +def main(): + print("Testing %s with %s" % (config.TOASTER_BASEURL, config.W3C_VALIDATOR)) if len(sys.argv) > 1: print_validation(sys.argv[1]) else: for url in urllist.URLS: print_validation(config.TOASTER_BASEURL+url) + +if __name__ == "__main__": + main()
lib/toaster/contrib/tts/urllist.py +44 -46
92 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH 2/11 toaster: tts: clean up HTML5 compatible url list
From: Alexandru DAMIAN <[email protected]>
This patch cleans up the list of URLs that are tested for HTML5 compatibility using the w3c-validator. It removes the URLs that are no longer in use, and the AJAX-only URLs that return JSON content.
--- lib/toaster/contrib/tts/urllist.py | 7 ------- 1 file changed, 7 deletions(-)
lib/toaster/contrib/tts/urllist.py +0 -7
@@ -17,7 +17,6 @@ URLS = [ 'toastergui/build/1/package_included_reverse_dependencies/1/1', 'toastergui/build/1/target/1', 'toastergui/build/1/target/1/targetpkg', - 'toastergui/dentries/build/1/target/1', 'toastergui/build/1/target/1/dirinfo', 'toastergui/build/1/target/1/dirinfo_filepath/_/bin/bash', 'toastergui/build/1/configuration',
@@ -28,19 +27,13 @@ URLS = [ 'toastergui/build/1/target/1/packagefile/1', 'toastergui/newproject/', 'toastergui/projects/', - 'toastergui/project/', 'toastergui/project/1', 'toastergui/project/1/configuration', 'toastergui/project/1/builds/', 'toastergui/project/1/layers/', 'toastergui/project/1/layer/1', - 'toastergui/project/1/layer/', 'toastergui/project/1/importlayer', 'toastergui/project/1/targets/', 'toastergui/project/1/machines/', - 'toastergui/xhr_configvaredit/1', - 'toastergui/xhr_importlayer/', - 'toastergui/xhr_updatelayer/', - 'toastergui/project/1/buildrequest/1', 'toastergui/', ]
Signature · 1 line
2.1.4
PATCH 3/11 toaster tests: gitignore and use absolute path for log file
In reply to Ed BartoshFrom: Alexandru DAMIAN <[email protected]>
gitignore the cache directory created by the http client
the log file for tests is already set up as an absolute path, so no need to recompute the path
--- .gitignore | 3 +++ lib/toaster/contrib/tts/recv.py | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-)
.gitignore +3 -0
@@ -12,3 +12,6 @@ venv/ doc/bitbake-user-manual/bitbake-user-manual.html doc/bitbake-user-manual/bitbake-user-manual.pdf doc/bitbake-user-manual/bitbake-user-manual.tgz +lib/toaster/contrib/tts/backlog.txt +lib/toaster/contrib/tts/log/* +lib/toaster/contrib/tts/.cache/*
lib/toaster/contrib/tts/recv.py +2 -2
@@ -25,7 +25,7 @@ # |[full/path]/recv.py from __future__ import print_function -import sys, os, config, shellutils +import sys, config, shellutils from email.parser import Parser
@@ -46,7 +46,7 @@ def main(): subject_parts = subject.split() if "[review-request]" in subject_parts: task_name = subject_parts[subject_parts.index("[review-request]") + 1] - with open(os.path.join(os.path.dirname(__file__), config.BACKLOGFILE), "a") as fout: + with open(config.BACKLOGFILE, "a") as fout: line = "%s|%s\n" % (task_name, config.TASKS.PENDING) fout.write(line)
Signature · 1 line
2.1.4
PATCH 4/11 toaster: tts: improve debugging information
In reply to Ed BartoshFrom: Alexandru DAMIAN <[email protected]>
We add debug information, and exception handling as to make it easy to figure out what is going on when tests fail on automatic start.
--- lib/toaster/contrib/tts/runner.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
lib/toaster/contrib/tts/runner.py +12 -1
@@ -62,7 +62,10 @@ def set_up_test_branch(settings, branch_name): # creates the host dir if os.path.exists(testdir): raise Exception("Test dir '%s'is already there, aborting" % testdir) - os.mkdir(testdir) + + # may raise OSError, is to be handled by the caller + os.makedirs(testdir) + # copies over the .git from the localclone run_shell_cmd("cp -a '%s'/.git '%s'" % (settings['localclone'], testdir))
@@ -171,12 +174,20 @@ def read_settings(): def clean_up(testdir): run_shell_cmd("rm -rf -- '%s'" % testdir) +def dump_info(settings, options, args): + """ detailed information about current run configuration, for debugging purposes. + """ + config.logger.debug("Settings:\n%s\nOptions:\n%s\nArguments:\n%s\n", settings, options, args) + def main(): (options, args) = validate_args() settings = read_settings() need_cleanup = False + # dump debug info + dump_info(settings, options, args) + testdir = None no_failures = 1 try:
Signature · 1 line
2.1.4
PATCH 5/11 toaster: tts: improve logging in urlcheck.py
In reply to Ed BartoshFrom: Alexandru DAMIAN <[email protected]>
This patch improves logging in the urlcheck.py. It allows properly running just HTML5 tests outside the test suite.
--- lib/toaster/contrib/tts/urlcheck.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
lib/toaster/contrib/tts/urlcheck.py +8 -1
@@ -2,11 +2,12 @@ from __future__ import print_function import sys import httplib2 - import config import urllist +config.logger.info("Testing %s with %s", config.TOASTER_BASEURL, config.W3C_VALIDATOR) + def validate_html5(url): http_client = httplib2.Http(None) status = "Failed"
@@ -23,6 +24,12 @@ def validate_html5(url): status = resp['x-w3c-validator-status'] errors = int(resp['x-w3c-validator-errors']) warnings = int(resp['x-w3c-validator-warnings']) + + if status == 'Invalid': + config.logger.warn("Failed %s is %s\terrors %s warnings %s (check at %s)", url, status, errors, warnings, urlrequest) + else: + config.logger.debug("OK! %s", url) + except Exception as exc: config.logger.warn("Failed validation call: %s", exc) return (status, errors, warnings)
Signature · 1 line
2.1.4
PATCH 6/11 toaster: tts: fix startup and cleanup for managed mode
In reply to Ed BartoshFrom: Alexandru DAMIAN <[email protected]>
This patch fixes the toaster startup and database cleanup for managed mode. It is needed because the toaster script thinks it has been called with "source" instead of being executed as independent script if not called through bash.
--- lib/toaster/contrib/tts/runner.py | 1 + lib/toaster/contrib/tts/tests.py | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-)
lib/toaster/contrib/tts/runner.py +1 -0
@@ -122,6 +122,7 @@ def execute_tests(dir_under_test, testname): # we disable the broad-except because we want to actually catch all possible exceptions try: config.logger.debug("Discovered test clases: %s", pprint.pformat(tests)) + unittest.installHandler() suite = unittest.TestSuite() loader = unittest.TestLoader() result = unittest.TestResult()
lib/toaster/contrib/tts/tests.py +4 -3
@@ -76,7 +76,7 @@ class TestHTML5Compliance(unittest.TestCase): setup.expect(r"Enter your option: ") setup.sendline('0') - self.child = pexpect.spawn("%s/bitbake/bin/toaster webport=%d nobrowser" % (config.TESTDIR, config.TOASTER_PORT)) + self.child = pexpect.spawn("bash", ["%s/bitbake/bin/toaster" % config.TESTDIR, "webport=%d" % config.TOASTER_PORT, "nobrowser"], cwd=self.crtdir) self.child.logfile = sys.stdout self.child.expect("Toaster is now running. You can stop it with Ctrl-C")
@@ -101,5 +101,6 @@ class TestHTML5Compliance(unittest.TestCase): self.child.kill(signal.SIGINT) time.sleep(1) os.chdir(self.origdir) -# if os.path.exists(os.path.join(self.crtdir, "toaster.sqlite")): -# os.remove(os.path.join(self.crtdir, "toaster.sqlite")) + toaster_sqlite_path = os.path.join(self.crtdir, "toaster.sqlite") + if os.path.exists(toaster_sqlite_path): + os.remove(toaster_sqlite_path)
Signature · 1 line
2.1.4
PATCH 7/11 toaster: tts: delete pyc files before the tests start
In reply to Ed BartoshFrom: Alexandru DAMIAN <[email protected]>
There may be leftover *.pyc files from previous code runs in the current checkout directory, so we delete everything before starting the tests, to make sure that we actually testing the current checkout.
--- lib/toaster/contrib/tts/runner.py | 4 ++++ 1 file changed, 4 insertions(+)
lib/toaster/contrib/tts/runner.py +4 -0
@@ -200,6 +200,10 @@ def main(): testdir = set_up_test_branch(settings, args[0]) # we expect a branch name as first argument config.TESTDIR = testdir # we let tests know where to run + + # ensure that the test dir only contains no *.pyc leftovers + run_shell_cmd("find '%s' -type f -name *.pyc -exec rm {} \;" % testdir) + no_failures = execute_tests(testdir, options.singletest) except ShellCmdException as exc:
Signature · 1 line
2.1.4
PATCH 8/11 toaster: tts: delete the database only if created
In reply to Ed BartoshFrom: Alexandru DAMIAN <[email protected]>
To allow the tests to run on different databases (in case of manual runs), the HTML5 test will only delete the database file if it was created in the setUp.
--- lib/toaster/contrib/tts/tests.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
lib/toaster/contrib/tts/tests.py +3 -1
@@ -59,8 +59,10 @@ class TestHTML5Compliance(unittest.TestCase): def setUp(self): self.origdir = os.getcwd() self.crtdir = os.path.dirname(config.TESTDIR) + self.cleanup_database = False os.chdir(self.crtdir) if not os.path.exists(os.path.join(self.crtdir, "toaster.sqlite")): + self.cleanup_database = False run_shell_cmd("%s/bitbake/lib/toaster/manage.py syncdb --noinput" % config.TESTDIR) run_shell_cmd("%s/bitbake/lib/toaster/manage.py migrate orm" % config.TESTDIR) run_shell_cmd("%s/bitbake/lib/toaster/manage.py migrate bldcontrol" % config.TESTDIR)
@@ -102,5 +104,5 @@ class TestHTML5Compliance(unittest.TestCase): time.sleep(1) os.chdir(self.origdir) toaster_sqlite_path = os.path.join(self.crtdir, "toaster.sqlite") - if os.path.exists(toaster_sqlite_path): + if self.cleanup_database and os.path.exists(toaster_sqlite_path): os.remove(toaster_sqlite_path)
Signature · 1 line
2.1.4
PATCH 9/11 toaster: tts: make sure to import data
In reply to Ed BartoshFrom: Alexandru DAMIAN <[email protected]>
Importing data from the layer index should be part of the setup because otherwise we have no reliable database configuration.
This patch selects the first option for importing the database configuration file.
--- lib/toaster/contrib/tts/tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
lib/toaster/contrib/tts/tests.py +2 -1
@@ -62,11 +62,12 @@ class TestHTML5Compliance(unittest.TestCase): self.cleanup_database = False os.chdir(self.crtdir) if not os.path.exists(os.path.join(self.crtdir, "toaster.sqlite")): - self.cleanup_database = False + self.cleanup_database = True run_shell_cmd("%s/bitbake/lib/toaster/manage.py syncdb --noinput" % config.TESTDIR) run_shell_cmd("%s/bitbake/lib/toaster/manage.py migrate orm" % config.TESTDIR) run_shell_cmd("%s/bitbake/lib/toaster/manage.py migrate bldcontrol" % config.TESTDIR) run_shell_cmd("%s/bitbake/lib/toaster/manage.py loadconf %s/meta-yocto/conf/toasterconf.json" % (config.TESTDIR, config.TESTDIR)) + run_shell_cmd("%s/bitbake/lib/toaster/manage.py lsupdates" % config.TESTDIR) setup = pexpect.spawn("%s/bitbake/lib/toaster/manage.py checksettings" % config.TESTDIR) setup.logfile = sys.stdout
Signature · 1 line
2.1.4
PATCH 10/11 toaster: tts: execute tests in numeric order
In reply to Ed BartoshFrom: Alexandru DAMIAN <[email protected]>
As the tests are verifying different type of the functionality, it is usually the case that a failing early test will completely make the subsequent tests failing, e.g. if the system cannot start due to a bug, there is little point in testing other functions.
In order to prevent uneeded test runs, and to generate repeatable test patterns, the test cases have now a numeric order in the class name (e.g. Test01XXX). The tests are executed in this order, and the first test failing will stop the test run.
--- lib/toaster/contrib/tts/runner.py | 11 +++++++---- lib/toaster/contrib/tts/tests.py | 6 +++--- 2 files changed, 10 insertions(+), 7 deletions(-)
lib/toaster/contrib/tts/runner.py +7 -4
@@ -31,7 +31,7 @@ from __future__ import print_function import sys, os import unittest, importlib import logging, pprint, json - +import re from shellutils import ShellCmdException, mkdirhier, run_shell_cmd import config
@@ -121,13 +121,16 @@ def execute_tests(dir_under_test, testname): # pylint: disable=broad-except # we disable the broad-except because we want to actually catch all possible exceptions try: + # sorting the tests by the numeric order in the class name + tests = sorted(tests, key=lambda x: int(re.search(r"[0-9]+", x[1]).group(0))) config.logger.debug("Discovered test clases: %s", pprint.pformat(tests)) unittest.installHandler() suite = unittest.TestSuite() loader = unittest.TestLoader() result = unittest.TestResult() - for module_file, name in tests: - suite.addTest(loader.loadTestsFromName("%s.%s" % (module_file, name))) + result.failfast = True + for module_file, test_name in tests: + suite.addTest(loader.loadTestsFromName("%s.%s" % (module_file, test_name))) config.logger.info("Running %d test(s)", suite.countTestCases()) suite.run(result)
@@ -202,7 +205,7 @@ def main(): config.TESTDIR = testdir # we let tests know where to run # ensure that the test dir only contains no *.pyc leftovers - run_shell_cmd("find '%s' -type f -name *.pyc -exec rm {} \;" % testdir) + run_shell_cmd("find '%s' -type f -name *.pyc -exec rm {} \\;" % testdir) no_failures = execute_tests(testdir, options.singletest)
lib/toaster/contrib/tts/tests.py +3 -3
@@ -30,7 +30,7 @@ import config import pexpect import sys, os, signal, time -class TestPyCompilable(unittest.TestCase): +class Test00PyCompilable(unittest.TestCase): ''' Verifies that all Python files are syntactically correct ''' def test_compile_file(self): try:
@@ -38,7 +38,7 @@ class TestPyCompilable(unittest.TestCase): except ShellCmdException as exc: self.fail("Error compiling python files: %s" % (exc)) -class TestPySystemStart(unittest.TestCase): +class Test01PySystemStart(unittest.TestCase): ''' Attempts to start Toaster, verify that it is succesfull, and stop it ''' def setUp(self): run_shell_cmd("bash -c 'rm -f build/*log'")
@@ -55,7 +55,7 @@ class TestPySystemStart(unittest.TestCase): except ShellCmdException as exc: self.fail("Failed starting managed mode: %s" % (exc)) -class TestHTML5Compliance(unittest.TestCase): +class Test02HTML5Compliance(unittest.TestCase): def setUp(self): self.origdir = os.getcwd() self.crtdir = os.path.dirname(config.TESTDIR)
Signature · 1 line
2.1.4
PATCH 11/11 toaster: toastergui: run pylint on the toaster files
In reply to Ed BartoshFrom: Alexandru DAMIAN <[email protected]>
This patch enables pylint running on the toaster files, showing only the errors. This enables spotting common mistakes in the toaster python files.
--- lib/toaster/contrib/tts/tests.py | 6 ++++++ 1 file changed, 6 insertions(+)
lib/toaster/contrib/tts/tests.py +6 -0
@@ -38,6 +38,12 @@ class Test00PyCompilable(unittest.TestCase): except ShellCmdException as exc: self.fail("Error compiling python files: %s" % (exc)) + def test_pylint_file(self): + try: + run_shell_cmd(r"find . -iname \"*\.py\" -type f -print0 | PYTHONPATH=${PYTHONPATH}:. xargs -r -0 -n1 pylint --load-plugins pylint_django -E --reports=n 2>&1", cwd=config.TESTDIR + "/bitbake/lib/toaster") + except ShellCmdException as exc: + self.fail("Pylint fails: %s\n" % exc) + class Test01PySystemStart(unittest.TestCase): ''' Attempts to start Toaster, verify that it is succesfull, and stop it ''' def setUp(self):
Signature · 1 line
2.1.4