diff options
Diffstat (limited to 'deprecated/automation/common/command_executer_test.py')
-rwxr-xr-x | deprecated/automation/common/command_executer_test.py | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/deprecated/automation/common/command_executer_test.py b/deprecated/automation/common/command_executer_test.py new file mode 100755 index 00000000..2caaa146 --- /dev/null +++ b/deprecated/automation/common/command_executer_test.py @@ -0,0 +1,210 @@ +#!/usr/bin/python2 +# +# Copyright 2011 Google Inc. All Rights Reserved. +# + +__author__ = 'kbaclawski@google.com (Krystian Baclawski)' + +import cStringIO +import logging +import os +import signal +import socket +import sys +import time +import unittest + + +def AddScriptDirToPath(): + """Required for remote python script execution.""" + path = os.path.abspath(__file__) + + for _ in range(3): + path, _ = os.path.split(path) + + if not path in sys.path: + sys.path.append(path) + + +AddScriptDirToPath() + +from automation.common.command_executer import CommandExecuter + + +class LoggerMock(object): + + def LogCmd(self, cmd, machine='', user=''): + if machine: + logging.info('[%s] Executing: %s', machine, cmd) + else: + logging.info('Executing: %s', cmd) + + def LogError(self, msg): + logging.error(msg) + + def LogWarning(self, msg): + logging.warning(msg) + + def LogOutput(self, msg): + logging.info(msg) + + +class CommandExecuterUnderTest(CommandExecuter): + + def __init__(self): + CommandExecuter.__init__(self, logger_to_set=LoggerMock()) + + # We will record stdout and stderr. + self._stderr = cStringIO.StringIO() + self._stdout = cStringIO.StringIO() + + @property + def stdout(self): + return self._stdout.getvalue() + + @property + def stderr(self): + return self._stderr.getvalue() + + def DataReceivedOnOutput(self, data): + self._stdout.write(data) + + def DataReceivedOnError(self, data): + self._stderr.write(data) + + +class CommandExecuterLocalTests(unittest.TestCase): + HOSTNAME = None + + def setUp(self): + self._executer = CommandExecuterUnderTest() + + def tearDown(self): + pass + + def RunCommand(self, method, **kwargs): + program = os.path.abspath(sys.argv[0]) + + return self._executer.RunCommand('%s runHelper %s' % (program, method), + machine=self.HOSTNAME, + **kwargs) + + def testCommandTimeout(self): + exit_code = self.RunCommand('SleepForMinute', command_timeout=3) + + self.assertTrue(-exit_code in [signal.SIGTERM, signal.SIGKILL], + 'Invalid exit code: %d' % exit_code) + + def testCommandTimeoutIfSigTermIgnored(self): + exit_code = self.RunCommand('IgnoreSigTerm', command_timeout=3) + + self.assertTrue(-exit_code in [signal.SIGTERM, signal.SIGKILL]) + + def testCommandSucceeded(self): + self.assertFalse(self.RunCommand('ReturnTrue')) + + def testCommandFailed(self): + self.assertTrue(self.RunCommand('ReturnFalse')) + + def testStringOnOutputStream(self): + self.assertFalse(self.RunCommand('EchoToOutputStream')) + self.assertEquals(self._executer.stderr, '') + self.assertEquals(self._executer.stdout, 'test') + + def testStringOnErrorStream(self): + self.assertFalse(self.RunCommand('EchoToErrorStream')) + self.assertEquals(self._executer.stderr, 'test') + self.assertEquals(self._executer.stdout, '') + + def testOutputStreamNonInteractive(self): + self.assertFalse( + self.RunCommand('IsOutputStreamInteractive'), + 'stdout stream is a terminal!') + + def testErrorStreamNonInteractive(self): + self.assertFalse( + self.RunCommand('IsErrorStreamInteractive'), + 'stderr stream is a terminal!') + + def testAttemptToRead(self): + self.assertFalse(self.RunCommand('WaitForInput', command_timeout=3)) + + def testInterruptedProcess(self): + self.assertEquals(self.RunCommand('TerminateBySigAbrt'), -signal.SIGABRT) + + +class CommandExecuterRemoteTests(CommandExecuterLocalTests): + HOSTNAME = socket.gethostname() + + def testCommandTimeoutIfSigTermIgnored(self): + exit_code = self.RunCommand('IgnoreSigTerm', command_timeout=6) + + self.assertEquals(exit_code, 255) + + lines = self._executer.stdout.splitlines() + pid = int(lines[0]) + + try: + with open('/proc/%d/cmdline' % pid) as f: + cmdline = f.read() + except IOError: + cmdline = '' + + self.assertFalse('IgnoreSigTerm' in cmdline, 'Process is still alive.') + + +class CommandExecuterTestHelpers(object): + + def SleepForMinute(self): + time.sleep(60) + return 1 + + def ReturnTrue(self): + return 0 + + def ReturnFalse(self): + return 1 + + def EchoToOutputStream(self): + sys.stdout.write('test') + return 0 + + def EchoToErrorStream(self): + sys.stderr.write('test') + return 0 + + def IsOutputStreamInteractive(self): + return sys.stdout.isatty() + + def IsErrorStreamInteractive(self): + return sys.stderr.isatty() + + def IgnoreSigTerm(self): + os.write(1, '%d' % os.getpid()) + signal.signal(signal.SIGTERM, signal.SIG_IGN) + time.sleep(30) + return 0 + + def WaitForInput(self): + try: + # can only read end-of-file marker + return os.read(0, 1) != '' + except OSError: + # that means that stdin descriptor is closed + return 0 + + def TerminateBySigAbrt(self): + os.kill(os.getpid(), signal.SIGABRT) + return 0 + + +if __name__ == '__main__': + FORMAT = '%(asctime)-15s %(levelname)s %(message)s' + logging.basicConfig(format=FORMAT, level=logging.DEBUG) + + if len(sys.argv) > 1: + if sys.argv[1] == 'runHelper': + helpers = CommandExecuterTestHelpers() + sys.exit(getattr(helpers, sys.argv[2])()) + + unittest.main() |