blob: 899df006a6fe94077a047ad4f7cc6a6b21a6290c [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 2021 - 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 traceback
import os
import logging
from functools import wraps
from grpc import RpcError
from mobly import signals
from mobly.base_test import BaseTestClass
from mobly.controllers.android_device_lib.adb import AdbError
from mobly.controllers import android_device
from mobly.controllers.android_device import MOBLY_CONTROLLER_CONFIG_NAME as ANDROID_DEVICE_COFNIG_NAME
from blueberry.utils.mobly_sl4a_utils import setup_sl4a
from blueberry.utils.mobly_sl4a_utils import teardown_sl4a
from blueberry.tests.gd.cert.context import get_current_context
from blueberry.tests.gd.cert.gd_device import MOBLY_CONTROLLER_CONFIG_NAME as GD_DEVICE_CONFIG_NAME
from blueberry.tests.gd_sl4a.lib.ble_lib import enable_bluetooth, disable_bluetooth, BleLib
from blueberry.facade import rootservice_pb2 as facade_rootservice
from blueberry.tests.gd.cert import gd_device
class GdSl4aBaseTestClass(BaseTestClass):
SUBPROCESS_WAIT_TIMEOUT_SECONDS = 10
def setup_class(self, 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[GD_DEVICE_CONFIG_NAME]:
config['verbose_mode'] = self.verbose_mode
self.cert_module = cert_module
# Parse and construct GD device objects
self.gd_devices = self.register_controller(gd_device, required=True)
self.cert = self.gd_devices[0]
# Parse and construct Android device objects
self.android_devices = self.register_controller(android_device, required=True)
server_port = int(self.controller_configs[ANDROID_DEVICE_COFNIG_NAME][0]['server_port'])
forwarded_port = int(self.controller_configs[ANDROID_DEVICE_COFNIG_NAME][0]['forwarded_port'])
self.dut = self.android_devices[0]
setup_sl4a(self.dut, server_port, forwarded_port)
# Enable full btsnoop log
self.dut.adb.root()
self.dut.adb.shell("setprop persist.bluetooth.btsnooplogmode full")
getprop_result = self.dut.adb.shell("getprop persist.bluetooth.btsnooplogmode") == "full"
if not getprop_result:
self.dut.log.warning("Failed to enable Bluetooth Hci Snoop Logging.")
self.ble = BleLib(dut=self.dut)
def teardown_class(self):
teardown_sl4a(self.dut)
def setup_test(self):
self.cert.rootservice.StartStack(
facade_rootservice.StartStackRequest(
module_under_test=facade_rootservice.BluetoothModule.Value(self.cert_module),))
self.cert.wait_channel_ready()
self.timer_list = []
self.dut.ed.clear_all_events()
self.dut.sl4a.setScreenTimeout(500)
self.dut.sl4a.wakeUpNow()
# Always start tests with Bluetooth enabled and BLE disabled.
self.dut.sl4a.bluetoothDisableBLE()
disable_bluetooth(self.dut.sl4a, self.dut.ed)
# Enable full verbose logging for Bluetooth
self.dut.adb.shell("device_config put bluetooth INIT_logging_debug_enabled_for_all true")
# Then enable Bluetooth
enable_bluetooth(self.dut.sl4a, self.dut.ed)
self.dut.sl4a.bluetoothDisableBLE()
return True
def teardown_test(self):
# Make sure BLE is disabled and Bluetooth is disabled after test
self.dut.sl4a.bluetoothDisableBLE()
disable_bluetooth(self.dut.sl4a, self.dut.ed)
self.cert.rootservice.StopStack(facade_rootservice.StopStackRequest())
# TODO: split cert logcat logs into individual tests
current_test_dir = get_current_context().get_full_output_path()
# Pull DUT logs
self.pull_dut_logs(current_test_dir)
# Pull CERT logs
self.cert.pull_logs(current_test_dir)
def pull_dut_logs(self, base_dir):
try:
self.dut.adb.pull([
"/data/misc/bluetooth/logs/btsnoop_hci.log",
os.path.join(base_dir, "DUT_%s_btsnoop_hci.log" % self.dut.serial)
])
self.dut.adb.pull([
"/data/misc/bluedroid/bt_config.conf",
os.path.join(base_dir, "DUT_%s_bt_config.conf" % self.dut.serial)
])
self.dut.adb.pull([
"/data/misc/bluedroid/bt_config.bak",
os.path.join(base_dir, "DUT_%s_bt_config.bak" % self.dut.serial)
])
except AdbError as error:
logging.warning("Failed to pull logs from DUT: " + str(error))
def __getattribute__(self, name):
attr = super().__getattribute__(name)
if not callable(attr) or not GdSl4aBaseTestClass.__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" % (exception_info))
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 GdSl4aBaseTestClass.__ENTRY_METHODS