blob: 625e6e4776d3669436153f24af0fc146a7038c95 [file] [log] [blame]
#!/usr/bin/env python2
#
# Copyright 2012 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.
from __future__ import print_function
import cPickle as pickle
import inspect
import logging
import os
import signal
import sys
import factory_common # pylint: disable=unused-import
from cros.factory.device import device_utils
from cros.factory.test import session
from cros.factory.test.state import TestState
from cros.factory.test.utils import pytest_utils
from cros.factory.test.utils.pytest_utils import PytestExecutionResult
from cros.factory.testlog import testlog
from cros.factory.utils.arg_utils import Args
from cros.factory.utils import file_utils
from cros.factory.utils import log_utils
from cros.factory.utils import type_utils
# pylint: disable=no-name-in-module
from cros.factory.external.setproctitle import setproctitle
def RunPytest(test_info):
"""Runs a pytest, saving a pickled (status, error_msg) tuple to the
appropriate results file.
Args:
test_info: A PytestInfo object containing information about what to run.
"""
try:
os.setpgrp()
# Register a handler for SIGTERM, so that Python interpreter has
# a chance to do clean up procedures when SIGTERM is received.
def _SIGTERMHandler(signum, frame): # pylint: disable=unused-argument
logging.error('SIGTERM received')
raise type_utils.TestFailure('SIGTERM received')
signal.signal(signal.SIGTERM, _SIGTERMHandler)
test = pytest_utils.LoadPytest(test_info.pytest_name)()
os.environ.update({
session.ENV_TEST_FILE_PATH:
os.path.realpath(inspect.getfile(test.__class__))
})
logging.debug('[%s] Start test case: %s', os.getpid(), test.id())
test.test_info = test_info
if test_info.dut_options:
os.environ.update({
device_utils.ENV_DUT_OPTIONS: str(test_info.dut_options)})
arg_spec = getattr(test, 'ARGS', None)
if arg_spec:
test.args = Args(*arg_spec).Parse(test_info.args)
test_case_result = pytest_utils.RunTestCase(test)
if test_case_result.failure_details:
logging.info('pytest failure:\n%s', test_case_result.DumpStr())
result = PytestExecutionResult.GenerateFromTestResultFailureDetails(
TestState.FAILED, test_case_result.failure_details)
else:
result = PytestExecutionResult(TestState.PASSED)
except Exception:
logging.exception('Unable to run pytest')
result = PytestExecutionResult.GenerateFromException(TestState.FAILED)
file_utils.WriteFile(test_info.results_path, pickle.dumps(result))
def main():
env, info = pickle.load(sys.stdin)
if not env:
sys.exit(0)
os.environ.update(env)
log_utils.InitLogging(info.path)
if testlog.TESTLOG_ENV_VARIABLE_NAME in os.environ:
testlog.Testlog(
stationDeviceId=session.GetDeviceID(),
stationInstallationId=session.GetInstallationID())
else:
# If the testlog.TESTLOG_ENV_VARIABLE_NAME environment variable doesn't
# exist, assume invocation is being called by run_test.py. In this case,
# this is expected behaviour, since run_test.py doesn't save logs.
logging.info('Logging for Testlog is not able to start')
proc_title = os.environ.get('CROS_PROC_TITLE')
if proc_title:
setproctitle(proc_title)
RunPytest(info)
if testlog.TESTLOG_ENV_VARIABLE_NAME in os.environ:
testlog.GetGlobalTestlog().Close()
if __name__ == '__main__':
main()