| #/usr/bin/env python3.4 |
| # |
| # Copyright (C) 2016 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. |
| """ |
| Test script to automate the Bluetooth Audio Funhaus. |
| """ |
| from acts.keys import Config |
| from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest |
| from acts.test_utils.bt.bt_test_utils import bluetooth_enabled_check |
| from acts.utils import create_dir |
| from acts.utils import exe_cmd |
| from acts.utils import sync_device_time |
| from queue import Empty |
| import json |
| import time |
| import os |
| |
| |
| class BtFunhausTest(BluetoothBaseTest): |
| music_file_to_play = "" |
| device_fails_to_connect_list = [] |
| |
| def __init__(self, controllers): |
| BluetoothBaseTest.__init__(self, controllers) |
| |
| def on_fail(self, test_name, begin_time): |
| self._collect_bluetooth_manager_dumpsys_logs(self.android_devices) |
| super(BluetoothBaseTest, self).on_fail(test_name, begin_time) |
| |
| def setup_class(self): |
| for ad in self.android_devices: |
| sync_device_time(ad) |
| # Disable Bluetooth HCI Snoop Logs for audio tests |
| ad.droid.bluetoothConfigHciSnoopLog(False) |
| if not "bt_config" in self.user_params.keys(): |
| self.log.error("Missing mandatory user config \"bt_config\"!") |
| return False |
| bt_config_map_file = self.user_params["bt_config"] |
| return self._setup_bt_config(bt_config_map_file) |
| |
| def _setup_bt_config(self, bt_config_map_file): |
| bt_config_map = {} |
| bt_conf_path = "/data/misc/bluedroid/bt_config.conf" |
| if not os.path.isfile(bt_config_map_file): |
| bt_config_map_file = os.path.join( |
| self.user_params[Config.key_config_path], bt_config_map_file) |
| if not os.path.isfile(bt_config_map_file): |
| self.log.error("Unable to load bt_config file {}.".format( |
| bt_config_map_file)) |
| return False |
| try: |
| f = open(bt_config_map_file, 'r') |
| bt_config_map = json.load(f) |
| f.close() |
| except FileNotFoundError: |
| self.log.error("File not found: {}.".format(bt_config_map_file)) |
| return False |
| for ad in self.android_devices: |
| serial = ad.serial |
| |
| # Verify serial number in bt_config_map |
| if serial not in bt_config_map.keys(): |
| self.log.error( |
| "Missing android device serial {} in bt_config.".format( |
| serial)) |
| return False |
| # Push the bt_config.conf file to Android device |
| config_path = bt_config_map[serial]["config_path"] |
| if not os.path.isfile(config_path): |
| config_path = os.path.join( |
| self.user_params[Config.key_config_path], config_path) |
| if not os.path.isfile(config_path): |
| self.log.error("Unable to load bt_config file {}.".format( |
| config_path)) |
| return False |
| ad.adb.push("{} {}".format(config_path, bt_conf_path)) |
| |
| # Add music to the Android device |
| music_path_str = "music_path" |
| android_music_path = "/sdcard/Music/" |
| if music_path_str not in self.user_params: |
| self.log.error("Need music for audio testcases...") |
| return False |
| |
| music_path = self.user_params[music_path_str] |
| if not os.path.isdir(music_path): |
| music_path = os.path.join( |
| self.user_params[Config.key_config_path], music_path) |
| if not os.path.isdir(music_path): |
| self.log.error("Unable to find music directory {}.".format( |
| music_path)) |
| return False |
| self._add_music_to_primary_android_device(ad, music_path, |
| android_music_path) |
| ad.reboot() |
| |
| # Verify Bluetooth is enabled |
| if not bluetooth_enabled_check(ad): |
| self.log.error("Failed to toggle on Bluetooth on device {}". |
| format(serial)) |
| return False |
| |
| # Verify Bluetooth device is connected |
| self.log.info( |
| "Waiting up to 10 seconds for device to reconnect...") |
| connected_devices = ad.droid.bluetoothGetConnectedDevices() |
| start_time = time.time() |
| wait_time = 10 |
| result = False |
| while time.time() < start_time + wait_time: |
| connected_devices = ad.droid.bluetoothGetConnectedDevices() |
| if len(connected_devices) > 0: |
| if bt_config_map[serial]["peripheral_info"]["address"] in { |
| d['address'] |
| for d in connected_devices |
| }: |
| result = True |
| break |
| if not result: |
| self.log.error( |
| "Failed to connect to peripheral name: {}, address: {}". |
| format(bt_config_map[serial]["peripheral_info"]["name"], |
| bt_config_map[serial]["peripheral_info"][ |
| "address"])) |
| self.device_fails_to_connect_list.append("{}:{}".format( |
| serial, bt_config_map[serial]["peripheral_info"]["name"])) |
| if len(self.device_fails_to_connect_list) == len(self.android_devices): |
| self.log.error("All devices failed to reconnect.") |
| return False |
| return True |
| |
| def _add_music_to_primary_android_device(self, ad, music_path, |
| android_music_path): |
| for dirname, dirnames, filenames in os.walk(music_path): |
| for filename in filenames: |
| self.music_file_to_play = filename |
| file = os.path.join(dirname, filename) |
| #TODO: Handle file paths with spaces |
| ad.adb.push("{} {}".format(file, android_music_path)) |
| return True |
| |
| def _collect_bluetooth_manager_dumpsys_logs(self, ads): |
| for ad in ads: |
| serial = ad.serial |
| out_name = "{}_{}".format(serial, "bluetooth_dumpsys.txt") |
| dumpsys_path = ''.join((ad.log_path, "/BluetoothDumpsys")) |
| create_dir(dumpsys_path) |
| cmd = ''.join( |
| ("adb -s ", serial, " shell dumpsys bluetooth_manager > ", |
| dumpsys_path, "/", out_name)) |
| exe_cmd(cmd) |
| |
| @BluetoothBaseTest.bt_test_wrap |
| def test_run_bt_audio_12_hours(self): |
| """Test audio quality over 12 hours. |
| |
| This test is designed to run Bluetooth audio for 12 hours |
| and collect relavant logs. If all devices disconnect during |
| the test or Bluetooth is off on all devices, then fail the |
| test. |
| |
| Steps: |
| 1. For each Android device connected run steps 2-5. |
| 2. Open and play media file of music pushed to device |
| 3. Set media to loop indefintely. |
| 4. After 12 hours collect bluetooth_manager dumpsys information |
| 5. Stop media player |
| |
| Expected Result: |
| Audio plays for 12 hours over Bluetooth |
| |
| Returns: |
| Pass if True |
| Fail if False |
| |
| TAGS: Classic, A2DP |
| Priority: 1 |
| """ |
| for ad in self.android_devices: |
| ad.droid.mediaPlayOpen("file:///sdcard/Music/{}".format( |
| self.music_file_to_play)) |
| ad.droid.mediaPlaySetLooping(True) |
| self.log.info("Music is now playing on device {}".format( |
| ad.serial)) |
| |
| sleep_interval = 120 |
| twelve_hours_in_seconds = 43200 |
| twelve_hours_in_seconds = 500 |
| end_time = time.time() + twelve_hours_in_seconds |
| test_result = True |
| bluetooth_off_list = [] |
| device_not_connected_list = [] |
| while time.time() < end_time: |
| for ad in self.android_devices: |
| serial = ad.serial |
| if (not ad.droid.bluetoothCheckState() and |
| serial not in bluetooth_off_list): |
| self.log.error( |
| "Device {}'s Bluetooth state is off.".format(serial)) |
| bluetooth_off_list.append(serial) |
| if (ad.droid.bluetoothGetConnectedDevices() == 0 and |
| serial not in device_not_connected_list): |
| self.log.error( |
| "Device {} not connected to any Bluetooth devices.". |
| format(serial)) |
| device_not_connected_list.append(serial) |
| if len(bluetooth_off_list) == len(self.android_devices): |
| self.log.error( |
| "Bluetooth off on all Android devices. Ending Test") |
| return False |
| if len(device_not_connected_list) == len(self.android_devices): |
| self.log.error( |
| "Every Android device has no device connected.") |
| return False |
| time.sleep(sleep_interval) |
| |
| self._collect_bluetooth_manager_dumpsys_logs(self.android_devices) |
| for ad in self.android_devices: |
| ad.droid.mediaPlayStopAll() |
| if len(device_not_connected_list) > 0 or len(bluetooth_off_list) > 0: |
| self.log.info("Devices reported as not connected: {}".format( |
| device_not_connected_list)) |
| self.log.info("Devices reported with Bluetooth state off: {}". |
| format(bluetooth_off_list)) |
| return False |
| return True |
| |
| def test_setup_fail_if_devices_not_connected(self): |
| """Test for devices connected or not during setup. |
| |
| This test is designed to fail if the number of devices having |
| connection issues at time of setup is greater than 0. This lets |
| the test runner know of the stability of the testbed. |
| |
| Steps: |
| 1. Check lenght of self.device_fails_to_connect_list |
| |
| Expected Result: |
| No device should be in a disconnected state. |
| |
| Returns: |
| Pass if True |
| Fail if False |
| |
| TAGS: None |
| Priority: 1 |
| """ |
| if len(self.device_fails_to_connect_list) > 0: |
| self.log.error("Devices failed to reconnect:\n{}".format( |
| self.device_fails_to_connect_list)) |
| return False |
| return True |