blob: 6ed7f7d5b3defbc1d36b55365e5e1d9be4550a0b [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 2019 - The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import importlib
import logging
import os
import signal
import subprocess
import traceback
from functools import wraps
from grpc import RpcError
from acts import asserts, signals
from acts.context import get_current_context
from acts.base_test import BaseTestClass
from cert.async_subprocess_logger import AsyncSubprocessLogger
from cert.os_utils import get_gd_root
from cert.os_utils import read_crash_snippet_and_log_tail
from cert.os_utils import is_subprocess_alive
from cert.os_utils import make_ports_available
from cert.os_utils import TerminalColor
from cert.gd_device import MOBLY_CONTROLLER_CONFIG_NAME as CONTROLLER_CONFIG_NAME
from facade import rootservice_pb2 as facade_rootservice
from cert.gd_base_test_lib import setup_class_core
from cert.gd_base_test_lib import teardown_class_core
from cert.gd_base_test_lib import setup_test_core
from cert.gd_base_test_lib import teardown_test_core
from cert.gd_base_test_lib import dump_crashes_core
class GdBaseTestClass(BaseTestClass):
SUBPROCESS_WAIT_TIMEOUT_SECONDS = 10
def setup_class(self, dut_module, cert_module):
self.log_path_base = get_current_context().get_full_output_path()
self.verbose_mode = bool(self.user_params.get('verbose_mode', False))
for config in self.controller_configs[CONTROLLER_CONFIG_NAME]:
config['verbose_mode'] = self.verbose_mode
self.info = setup_class_core(
dut_module=dut_module,
cert_module=cert_module,
verbose_mode=self.verbose_mode,
log_path_base=self.log_path_base,
controller_configs=self.controller_configs)
self.dut_module = self.info['dut_module']
self.cert_module = self.info['cert_module']
self.rootcanal_running = self.info['rootcanal_running']
self.rootcanal_logpath = self.info['rootcanal_logpath']
self.rootcanal_process = self.info['rootcanal_process']
self.rootcanal_logger = self.info['rootcanal_logger']
if 'rootcanal' in self.controller_configs:
asserts.assert_true(self.info['rootcanal_exist'],
"Root canal does not exist at %s" % self.info['rootcanal'])
asserts.assert_true(self.info['make_rootcanal_ports_available'],
"Failed to make root canal ports available")
self.log.debug("Running %s" % " ".join(self.info['rootcanal_cmd']))
asserts.assert_true(
self.info['is_rootcanal_process_started'],
msg="Cannot start root-canal at " + str(self.info['rootcanal']))
asserts.assert_true(self.info['is_subprocess_alive'], msg="root-canal stopped immediately after running")
self.controller_configs = self.info['controller_configs']
# Parse and construct GD device objects
self.register_controller(importlib.import_module('cert.gd_device'), builtin=True)
self.dut = self.gd_devices[1]
self.cert = self.gd_devices[0]
def teardown_class(self):
teardown_class_core(
rootcanal_running=self.rootcanal_running,
rootcanal_process=self.rootcanal_process,
rootcanal_logger=self.rootcanal_logger,
subprocess_wait_timeout_seconds=self.SUBPROCESS_WAIT_TIMEOUT_SECONDS)
def setup_test(self):
setup_test_core(dut=self.dut, cert=self.cert, dut_module=self.dut_module, cert_module=self.cert_module)
def teardown_test(self):
teardown_test_core(cert=self.cert, dut=self.dut)
def __getattribute__(self, name):
attr = super().__getattribute__(name)
if not callable(attr) or not GdBaseTestClass.__is_entry_function(name):
return attr
@wraps(attr)
def __wrapped(*args, **kwargs):
try:
return attr(*args, **kwargs)
except RpcError as e:
exception_info = "".join(traceback.format_exception(e.__class__, e, e.__traceback__))
raise signals.TestFailure(
"RpcError during test\n\nRpcError:\n\n%s\n%s" % (exception_info, self.__dump_crashes()))
return __wrapped
__ENTRY_METHODS = {"setup_class", "teardown_class", "setup_test", "teardown_test"}
@staticmethod
def __is_entry_function(name):
return name.startswith("test_") or name in GdBaseTestClass.__ENTRY_METHODS
def __dump_crashes(self):
"""
return: formatted stack traces if found, or last few lines of log
"""
crash_detail = dump_crashes_core(
dut=self.dut,
cert=self.cert,
rootcanal_running=self.rootcanal_running,
rootcanal_process=self.rootcanal_process,
rootcanal_logpath=self.rootcanal_logpath)
return crash_detail