blob: 499b2876973834878e900af976c1198f1f4f4162 [file] [log] [blame]
# Copyright 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unittests for the process_util.py module."""
from __future__ import print_function
import os
import signal
from chromite.lib import cros_test_lib
from chromite.lib import process_util
def _SpawnChild(exit_code=None, kill_signal=None):
"""Create a child, have it exit/killed, and return its status."""
assert exit_code is not None or kill_signal is not None
pid = os.fork()
if pid == 0:
# Make sure this child never returns.
while True:
if exit_code is not None:
# pylint: disable=W0212
os._exit(exit_code)
else:
os.kill(os.getpid(), kill_signal)
return os.waitpid(pid, 0)[1]
class GetExitStatusTests(cros_test_lib.TestCase):
"""Tests for GetExitStatus()"""
def testExitNormal(self):
"""Verify normal exits get decoded."""
status = _SpawnChild(exit_code=0)
ret = process_util.GetExitStatus(status)
self.assertEqual(ret, 0)
def testExitError(self):
"""Verify error exits (>0 && <128) get decoded."""
status = _SpawnChild(exit_code=10)
ret = process_util.GetExitStatus(status)
self.assertEqual(ret, 10)
def testExitWeird(self):
"""Verify weird exits (>=128) get decoded."""
status = _SpawnChild(exit_code=150)
ret = process_util.GetExitStatus(status)
self.assertEqual(ret, 150)
def testSIGUSR1(self):
"""Verify normal kill signals get decoded."""
status = _SpawnChild(kill_signal=signal.SIGUSR1)
ret = process_util.GetExitStatus(status)
self.assertEqual(ret, 128 + signal.SIGUSR1)
def testSIGKILL(self):
"""Verify harsh signals get decoded."""
status = _SpawnChild(kill_signal=signal.SIGKILL)
ret = process_util.GetExitStatus(status)
self.assertEqual(ret, 128 + signal.SIGKILL)
class ExitAsStatusTests(cros_test_lib.TestCase):
"""Tests for ExitAsStatus()"""
def _Tester(self, exit_code=None, kill_signal=None):
"""Helper func for testing ExitAsStatus()
Create a child to mimic the grandchild.
Create a grandchild and have it exit/killed.
Assert behavior based on exit/signal behavior.
"""
pid = os.fork()
if pid == 0:
# Let the grandchild exit/kill itself.
# The child should mimic the grandchild.
status = _SpawnChild(exit_code=exit_code, kill_signal=kill_signal)
try:
process_util.ExitAsStatus(status)
except SystemExit as e:
# pylint: disable=W0212
os._exit(e.code)
raise AssertionError('ERROR: should have exited!')
# The parent returns the child's status.
status = os.waitpid(pid, 0)[1]
if exit_code is not None:
self.assertFalse(os.WIFSIGNALED(status))
self.assertTrue(os.WIFEXITED(status))
self.assertEqual(os.WEXITSTATUS(status), exit_code)
else:
self.assertFalse(os.WIFEXITED(status))
self.assertTrue(os.WIFSIGNALED(status))
self.assertEqual(os.WTERMSIG(status), kill_signal)
def testExitNormal(self):
"""Verify normal exits get decoded."""
self._Tester(exit_code=0)
def testExitError(self):
"""Verify error exits (>0 && <128) get decoded."""
self._Tester(exit_code=10)
def testExitWeird(self):
"""Verify weird exits (>=128) get decoded."""
self._Tester(exit_code=150)
def testSIGUSR1(self):
"""Verify normal kill signals get decoded."""
self._Tester(kill_signal=signal.SIGUSR1)
def testSIGKILL(self):
"""Verify harsh signals get decoded."""
self._Tester(kill_signal=signal.SIGKILL)