[bitbake-devel] [[RFC][PATCH] 5/8] toaster/tests: Add helpers.py module.
Aníbal Limón
anibal.limon at linux.intel.com
Tue Feb 23 00:51:55 UTC 2016
The helpers.py module is a utility for clone/setup_venv/start/stop
a toaster instance.
It can be executed in a standalone way or use as utility class.
Signed-off-by: Aníbal Limón <anibal.limon at linux.intel.com>
---
lib/toaster/tests/helpers.py | 178 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 178 insertions(+)
create mode 100755 lib/toaster/tests/helpers.py
diff --git a/lib/toaster/tests/helpers.py b/lib/toaster/tests/helpers.py
new file mode 100755
index 0000000..549358b
--- /dev/null
+++ b/lib/toaster/tests/helpers.py
@@ -0,0 +1,178 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2016 Intel Corporation
+#
+
+import subprocess
+import os
+import shutil
+import signal
+import tempfile
+
+from proc.core import find_processes
+
+TOASTER_TEST_BRANCH = 'toaster_tests'
+VENV_NAME = 'venv'
+SHELL_CMD = os.environ['SHELL'] if 'SHELL' in os.environ else "/bin/bash"
+TOASTER_BUILD_DIR_NAME = 'build'
+
+def _check_output1(*popenargs, **kwargs):
+ """
+ Almost the same as subprocess.check_output but change the stdout from
+ PIPE to tempfile to avoid deadlocks when trying to read the PIPE using
+ communicate(). This scenario can be seen calling toaster_start on failure
+ scenarios.
+
+ This causes a little overhead by the tempfile.
+ """
+
+ f = tempfile.TemporaryFile(mode='rw+')
+ if 'stdout' in kwargs:
+ raise ValueError('stdout argument not allowed, it will be overridden.')
+ process = subprocess.Popen(stdout=f, *popenargs, **kwargs)
+ retcode = process.wait()
+
+ f.flush()
+ os.fsync(f.fileno())
+ f.seek(0, 0)
+ output = f.read()
+ f.close()
+
+ if retcode:
+ cmd = kwargs.get("args")
+ if cmd is None:
+ cmd = popenargs[0]
+ raise subprocess.CalledProcessError(retcode, cmd, output=output)
+ return output
+
+class ToasterHelper(object):
+ def __init__(self, directory, repo, repo_ref='master', port='8000',
+ build_dir=TOASTER_BUILD_DIR_NAME):
+ self.directory = directory
+ self.repo = repo
+ self.repo_ref = repo_ref
+ self.port = port
+ self.build_dir = build_dir
+
+ def _execute_command(self, cmd):
+ return _check_output1([SHELL_CMD, "-c", "cd %s; %s" % \
+ (self.directory, cmd)], stderr=subprocess.STDOUT)
+
+ def _execute_command_oe(self, cmd):
+ return self._execute_command("source oe-init-build-env %s; %s"\
+ % (self.build_dir, cmd))
+
+ def _execute_command_oe_venv(self, cmd):
+ return self._execute_command_oe("source %s/bin/activate; %s"\
+ % (VENV_NAME, cmd))
+
+ def clone(self, rm=False):
+ if os.path.exists(self.directory):
+ if rm:
+ shutil.rmtree(self.directory)
+ else:
+ raise IOError
+
+ subprocess.check_output([SHELL_CMD, "-c", "git clone %s %s" %\
+ (self.repo, self.directory)], stderr=subprocess.STDOUT)
+ self._execute_command("git checkout %s; git branch %s; git checkout %s;"\
+ % (self.repo_ref, TOASTER_TEST_BRANCH, TOASTER_TEST_BRANCH))
+
+ def setup(self):
+ self._execute_command_oe("virtualenv %s" % VENV_NAME)
+ self._execute_command_oe_venv("pip install -r" \
+ " ../bitbake/toaster-requirements.txt")
+ self._execute_command_oe_venv("pip install -r" \
+ " ../bitbake/toaster-tests-requirements.txt")
+
+ def start(self):
+ return self._execute_command_oe_venv("source %s/bitbake/bin/toaster"\
+ " start webport=%s" % (self.directory, self.port))
+
+ def _stop_force(self):
+ """
+ The _stop_force method iterates over the /proc and search for toaster path
+ in the process cmdline then send SIGKILL for every matched process.
+ """
+
+ pids = []
+ for p in find_processes():
+ if len(p.cmdline) > 1 and \
+ os.path.basename(p.cmdline[0]) == 'python' and \
+ p.cmdline[1].startswith(self.directory):
+ pids.append(p.pid)
+
+ for pid in pids:
+ try:
+ os.kill(pid, signal.SIGKILL)
+ except:
+ pass
+
+ return ''
+
+ def stop(self, force=False):
+ """
+ The stop method have force mode because toaster without production
+ setup have known issues when is on load, the server response 503
+ service unavailable.
+ """
+ if force:
+ return self._stop_force()
+ else:
+ return self._execute_command_oe_venv("source %s/bitbake/bin/toaster"\
+ " stop webport=%s" % (self.directory, self.port))
+
+ def get_sqlite_path(self):
+ return os.path.join(self.directory, self.build_dir, 'toaster.sqlite')
+
+ def get_conf_path(self):
+ output = self._execute_command_oe_venv("source %s/bitbake/bin/toaster"\
+ " start webport=%s; echo $TOASTER_CONF;" % \
+ (self.directory, self.port))
+
+ return output.split()[-1]
+
+DEFAULT_WORK_DIRECTORY = '/tmp/toaster'
+DEFAULT_POKY_URL = 'http://git.yoctoproject.org/git/poky.git'
+DEFAULT_POKY_BRANCH = 'master'
+DEFAULT_WEB_PORT = '8000'
+
+if __name__ == "__main__":
+ import argparse
+ import sys
+
+ parser = argparse.ArgumentParser(description='Toaster helper',
+ formatter_class=argparse.RawTextHelpFormatter)
+ parser.add_argument("-a", "--action", choices=['clone', 'setup', 'start', 'stop'],
+ required=True,
+ help="Action to execute can be clone/setup/start/stop")
+ parser.add_argument("-d", "--work-directory", default=DEFAULT_WORK_DIRECTORY,
+ help="Directory for setup toaster, default: %s" % DEFAULT_WORK_DIRECTORY)
+ parser.add_argument("-u", "--url-repository", default=DEFAULT_POKY_URL,
+ help="GIT repository for setup toaster, default %s" % DEFAULT_POKY_URL)
+ parser.add_argument("-r", "--revision", default=DEFAULT_POKY_BRANCH,
+ help="GIT repository revision (branch, tag, hash) for setup toaster" \
+ ", default: %s" % DEFAULT_POKY_BRANCH)
+ parser.add_argument("-p", "--web-port", default=DEFAULT_WEB_PORT,
+ help="Web port for start toaster server, default: %s" % DEFAULT_WEB_PORT)
+ parser.add_argument("-b", "--build-dir", default=TOASTER_BUILD_DIR_NAME,
+ help="Toaster build directory name, default: %s" % TOASTER_BUILD_DIR_NAME)
+
+ args = parser.parse_args()
+
+ try:
+ th = ToasterHelper(args.work_directory, args.url_repository,
+ args.revision, args.web_port, args.build_dir)
+ if args.action == 'stop':
+ th.stop(force=True)
+ else:
+ getattr(th, args.action)()
+ except subprocess.CalledProcessError as e:
+ print e.output
+ raise
+ except IOError as e:
+ if args.action == 'clone':
+ print "ERROR: Directory exists: %s" % args.work_directory
+ raise
+
+ sys.exit(0)
--
2.1.4
More information about the bitbake-devel
mailing list