Source code for test_actions

"""
unittest.TestCase class providing common functionality for testing actions.
"""
import unittest
import os
import subprocess
import ost

# set verbosity level here, is propagated to all others
ost.PushVerbosityLevel(2)

[docs]class ActionTestCase(unittest.TestCase): """ Class to help developing actions. Comes with a lot of convenience wrappers around what should be tested and serves as a recorder for test calls... just for in two years when you come back to rewrite the whole action... While inheriting this class, :attr:`pm_action` needs to be defined. Otherwise the whole idea does not work. .. attribute:: pm_bin This is the path of the ``pm`` binary. Automatically set by calling :meth:`~ActionTestCase.__init__` inside the initialisation of your class. :type: :class:`str` .. attribute:: pm_action The action to be tested. Needs to be set by your initialisation routine, **after** calling :meth:`~ActionTestCase.__init__` from here. Skip the "pm-" in front of the action name. :type: :class:`str` """ def __init__(self, *args, **kwargs): """ Convenience stuff for action testing. """ # Determining the pm binary to be called. Going hard-coded is a bad # thing. But this is a unit test and we know where we are as all unit # tests are run in "tests/MODULENAME" within build-folder. bld_dir = os.path.abspath(os.path.dirname(os.path.dirname(os.getcwd()))) self.pm_bin = os.path.join(bld_dir, 'stage', 'bin', 'pm') self.pm_action = None unittest.TestCase.__init__(self, *args, **kwargs)
[docs] def RunAction(self, arguments, verbose=False): """ Call an action, return the exit status (``$?`` shell variable). May be set to ``verbose`` to print the actions terminal output. The action to be executed needs to be stored in :attr:`pm_action` first. If in verbose mode, output to :file:`stdout` of the action will be printed first followed by :file:`stderr`. :param arguments: A list of arguments for the call. :type arguments: :class:`list` :param verbose: If ``True``, report output of the action. :type verbose: :class:`bool` :returns: The exit code of the action (:class:`int`). """ if not self.pm_action: raise RuntimeError("A 'pm_action' attribute has to be defined by "+ "each subclass of 'test_actions.ActionTestCase'") # run the action with arguments, wait for the job to finish and capture # output cmd = [self.pm_bin, self.pm_action] + arguments job = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) sout, serr = job.communicate() if verbose: ost.LogScript("stdout of '%s'" % ' '.join(cmd)) ost.LogScript("------") lines = sout.splitlines() for out_l in lines: ost.LogScript(out_l) ost.LogScript("------") ost.LogError("stderr of '%s'" % ' '.join(cmd)) ost.LogError("------") lines = serr.splitlines() for err_l in lines: ost.LogError(err_l) ost.LogError("------") return job.returncode
[docs] def RunExitStatusTest(self, exit_code, arguments, verbose=False): """ Run the action with given arguments and check the exit code. :param exit_code: The expected return code, ``$?`` in a shell. :type exit_code: :class:`int` :param arguments: A list of arguments for the call. :type arguments: :class:`list` :param verbose: If ``True``, report output of the action. :type verbose: :class:`bool` """ exit_code_run = self.RunAction(arguments, verbose=verbose) self.assertEqual(exit_code, exit_code_run, msg="Exit code of '%s' " % ' '.join([self.pm_bin, self.pm_action]+ arguments)+ "is supposed to be '%d' " % exit_code+ "but returned as '%d'." % exit_code_run)
[docs] def testPMExists(self): """ This is an internal test, executed when the source code of the test class is run as unit test. Verifies that :attr:`pm_bin` is an existing file (also complains if a directory is found instead). """ self.assertEqual(os.path.isfile(self.pm_bin), True, msg="Could not find 'pm' bin at '%s', " % self.pm_bin+ "cannot proceed unit tests.")
if __name__ == "__main__": import sys from ost import testutils sys.dont_write_bytecode = True testutils.RunTests() # LocalWords: attr meth ActionTestCase init str stdout stderr param bool