Funhaus runner code
Bug: b/30896601
Bug: b/30896407
Bug: b/30896220
Bug: b/30895491
Bug: b/30789415
Change-Id: I489f57cd88239a33248e8e3840c4eee7fcee89df
(cherry picked from commit 479c689656fb0cea7b88f53e13dd34548988b513)
diff --git a/acts/tests/google/bt/audio_lab/BtFunhausTest.py b/acts/tests/google/bt/audio_lab/BtFunhausTest.py
new file mode 100644
index 0000000..61be777
--- /dev/null
+++ b/acts/tests/google/bt/audio_lab/BtFunhausTest.py
@@ -0,0 +1,264 @@
+#/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
\ No newline at end of file