Merge "Catch more exception in monsoon.py" am: af568482b8 am: fddaa3d01f am: 964fd8594c
am: 65b1ecfab9
Change-Id: I2d4378c388684c9ca9fb8af2c8db810b116bf9cf
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index a07b050..70ccbf0 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,5 +1,6 @@
[Hook Scripts]
acts_base_class_test = ./acts/framework/tests/acts_base_class_test.py
+acts_libs_ota_tests = ./acts/framework/tests/libs/ota/unittest_bundle.py
acts_adb_test = ./acts/framework/tests/acts_adb_test.py
acts_android_device_test = ./acts/framework/tests/acts_android_device_test.py
acts_asserts_test = ./acts/framework/tests/acts_asserts_test.py
@@ -15,10 +16,10 @@
acts_import_test_utils_test = ./acts/framework/tests/acts_import_test_utils_test.py
acts_import_unit_test = ./acts/framework/tests/acts_import_unit_test.py
acts_relay_controller_test = ./acts/framework/tests/acts_relay_controller_test.py
-commit_message_hook = ./tools/commit_message_check.py
+test_runner_test = ./acts/framework/tests/test_runner_test.py
+keyword_check = ./tools/keyword_check.py
yapf_hook = ./tools/yapf_checker.py
-commit_message_check = ./tools/commit_message_check.py
-lab_test = ./tools/lab/test_main.py
+lab_test = ./tools/lab/lab_upload_hooks.py
[Builtin Hooks]
commit_msg_bug_field = true
diff --git a/acts/README.md b/acts/README.md
index caa2f0c..a4e9950 100644
--- a/acts/README.md
+++ b/acts/README.md
@@ -75,7 +75,8 @@
On Ubuntu, sudo apt-get install python3.4 python3-setuptools
2. Run "python3.4 setup.py install" with elevated permissions
3. To verify ACTS is ready to go, at the location for README, and run:
- cd tests/ && act.py -c acts_sanity_test_config.json -tc IntegrationTest
+ cd framework/tests/ \
+ && act.py -c acts_sanity_test_config.json -tc IntegrationTest
After installation, `act.py` will be in usr/bin and can be called as command
line utilities. Components in ACTS are importable under the package "acts."
@@ -92,7 +93,7 @@
Above, the command `act.py -c acts_sanity_test_config.json -tc IntegrationTest`
was run to verify ACTS was properly set up.
Below are the components of that command:
-- `acts.py`: is the script that runs the test
+- `act.py`: is the script that runs the test
- -c acts_sanity_test_config: is the flag and name of the configuration file
to be used in the test
- -tc IntegrationTest: is the name of the test case
diff --git a/acts/framework/acts/base_test.py b/acts/framework/acts/base_test.py
index 7be85a9..f66058a 100755
--- a/acts/framework/acts/base_test.py
+++ b/acts/framework/acts/base_test.py
@@ -13,20 +13,17 @@
# 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 logging
import os
-import time
import traceback
from acts import asserts
-from acts import keys
from acts import logger
from acts import records
from acts import signals
from acts import tracelogger
from acts import utils
-from acts.test_utils.tel.tel_test_utils import run_multithread_func
+from concurrent.futures import ThreadPoolExecutor
# Macro strings for test result reporting
TEST_CASE_TOKEN = "[Test Case]"
@@ -179,9 +176,15 @@
self.current_test_name = test_name
try:
# Write test start token to adb log if android device is attached.
- for ad in self.android_devices:
- ad.droid.logV("%s BEGIN %s" % (TEST_CASE_TOKEN, test_name))
- except:
+ if hasattr(self, 'android_devices'):
+ for ad in self.android_devices:
+ if not ad.skip_sl4a:
+ ad.droid.logV("%s BEGIN %s" % (TEST_CASE_TOKEN,
+ test_name))
+ except Exception as e:
+ self.log.warning(
+ 'Unable to send BEGIN log command to all devices.')
+ self.log.warning('Error: %s' % e)
pass
return self.setup_test()
@@ -195,6 +198,7 @@
Implementation is optional.
"""
+ return True
def _teardown_test(self, test_name):
"""Proxy function to guarantee the base implementation of teardown_test
@@ -229,7 +233,7 @@
if record.details:
self.log.error(record.details)
self.log.info(RESULT_LINE_TEMPLATE, record.test_name, record.result)
- self.on_fail(record.test_name, record.log_begin_time)
+ self.on_fail(record.test_name, record.begin_time)
def on_fail(self, test_name, begin_time):
"""A function that is executed upon a test case failure.
@@ -253,7 +257,7 @@
if msg:
self.log.info(msg)
self.log.info(RESULT_LINE_TEMPLATE, record.test_name, record.result)
- self.on_pass(record.test_name, record.log_begin_time)
+ self.on_pass(record.test_name, record.begin_time)
def on_pass(self, test_name, begin_time):
"""A function that is executed upon a test case passing.
@@ -275,7 +279,7 @@
"""
self.log.info(RESULT_LINE_TEMPLATE, record.test_name, record.result)
self.log.info("Reason to skip: %s", record.details)
- self.on_skip(record.test_name, record.log_begin_time)
+ self.on_skip(record.test_name, record.begin_time)
def on_skip(self, test_name, begin_time):
"""A function that is executed upon a test case being skipped.
@@ -297,7 +301,7 @@
"""
self.log.info(RESULT_LINE_TEMPLATE, record.test_name, record.result)
self.log.info("Reason to block: %s", record.details)
- self.on_blocked(record.test_name, record.log_begin_time)
+ self.on_blocked(record.test_name, record.begin_time)
def on_blocked(self, test_name, begin_time):
"""A function that is executed upon a test begin skipped.
@@ -316,7 +320,7 @@
case.
"""
self.log.exception(record.details)
- self.on_exception(record.test_name, record.log_begin_time)
+ self.on_exception(record.test_name, record.begin_time)
def on_exception(self, test_name, begin_time):
"""A function that is executed upon an unhandled exception from a test
@@ -368,7 +372,8 @@
is_generate_trigger = False
tr_record = records.TestResultRecord(test_name, self.TAG)
tr_record.test_begin()
- self.begin_time = tr_record.log_begin_time
+ self.begin_time = int(tr_record.begin_time)
+ self.log_begin_time = tr_record.log_begin_time
self.test_name = tr_record.test_name
self.log.info("%s %s", TEST_CASE_TOKEN, test_name)
verdict = None
@@ -425,15 +430,11 @@
self._exec_procedure_func(self._on_exception, tr_record)
self._exec_procedure_func(self._on_fail, tr_record)
else:
- # Keep supporting return False for now.
- # TODO(angli): Deprecate return False support.
if verdict or (verdict is None):
# Test passed.
tr_record.test_pass()
self._exec_procedure_func(self._on_pass, tr_record)
return
- # Test failed because it didn't return True.
- # This should be removed eventually.
tr_record.test_fail()
self._exec_procedure_func(self._on_fail, tr_record)
finally:
@@ -679,17 +680,36 @@
user.
"""
- def _ad_take_reports(self, ad, test_name, begin_time):
+ def _ad_take_bugreport(self, ad, test_name, begin_time):
+ for i in range(3):
+ try:
+ ad.take_bug_report(test_name, begin_time)
+ return True
+ except Exception as e:
+ ad.log.error("bugreport attempt %s error: %s", i + 1, e)
+
+ def _ad_take_extra_logs(self, ad, test_name, begin_time):
+ result = True
+ if getattr(ad, "qxdm_log", False):
+ # Gather qxdm log modified 3 minutes earlier than test start time
+ if begin_time:
+ qxdm_begin_time = begin_time - 1000 * 60 * 3
+ else:
+ qxdm_begin_time = None
+ try:
+ ad.get_qxdm_logs(test_name, qxdm_begin_time)
+ except Exception as e:
+ ad.log.error("Failed to get QXDM log for %s with error %s",
+ test_name, e)
+ result = False
+
try:
- ad.take_bug_report(test_name, begin_time)
- bugreport_path = os.path.join(ad.log_path, test_name)
- utils.create_dir(bugreport_path)
- ad.check_crash_report(test_name, begin_time, True)
- if getattr(ad, "qxdm_log", False):
- ad.get_qxdm_logs()
+ ad.check_crash_report(test_name, begin_time, log_crash_report=True)
except Exception as e:
- ad.log.error("Failed to take a bug report for %s with error %s",
+ ad.log.error("Failed to check crash report for %s with error %s",
test_name, e)
+ result = False
+ return result
def _skip_bug_report(self):
"""A function to check whether we should skip creating a bug report."""
@@ -720,25 +740,29 @@
if self._skip_bug_report():
return
- tasks = [(self._ad_take_reports, (ad, test_name, begin_time))
- for ad in self.android_devices]
- run_multithread_func(self.log, tasks)
+ executor = ThreadPoolExecutor(max_workers=10)
+ for ad in getattr(self, 'android_devices', []):
+ executor.submit(self._ad_take_bugreport, ad, test_name, begin_time)
+ executor.submit(self._ad_take_extra_logs, ad, test_name,
+ begin_time)
+ executor.shutdown()
def _reboot_device(self, ad):
ad.log.info("Rebooting device.")
ad = ad.reboot()
def _cleanup_logger_sessions(self):
- for (logger, session) in self.logger_sessions:
- self.log.info("Resetting a diagnostic session %s, %s", logger,
+ for (mylogger, session) in self.logger_sessions:
+ self.log.info("Resetting a diagnostic session %s, %s", mylogger,
session)
- logger.reset()
+ mylogger.reset()
self.logger_sessions = []
def _pull_diag_logs(self, test_name, begin_time):
- for (logger, session) in self.logger_sessions:
- self.log.info("Pulling diagnostic session %s", logger)
- logger.stop(session)
- diag_path = os.path.join(self.log_path, begin_time)
+ for (mylogger, session) in self.logger_sessions:
+ self.log.info("Pulling diagnostic session %s", mylogger)
+ mylogger.stop(session)
+ diag_path = os.path.join(
+ self.log_path, logger.epoch_to_log_line_timestamp(begin_time))
utils.create_dir(diag_path)
- logger.pull(session, diag_path)
+ mylogger.pull(session, diag_path)
diff --git a/acts/framework/acts/bin/act.py b/acts/framework/acts/bin/act.py
index 2e533cd..f784d01 100755
--- a/acts/framework/acts/bin/act.py
+++ b/acts/framework/acts/bin/act.py
@@ -18,7 +18,6 @@
import argparse
import multiprocessing
-import os
import signal
import sys
import traceback
@@ -91,8 +90,8 @@
Each test run will be in its own process.
Args:
- parsed_config: A list of dicts, each is a set of configs for one
- test_runner.TestRunner.
+ parsed_configs: A list of dicts, each is a set of configs for one
+ test_runner.TestRunner.
test_identifiers: A list of tuples, each identifies what test case to
run on what test class.
repeat: Number of times to iterate the specified tests.
@@ -145,11 +144,6 @@
"""This is a sample implementation of a cli entry point for ACTS test
execution.
- Alternatively, you could directly invoke an ACTS test script:
-
- python3 MyTest.py -c my_config.json
-
- See acts.test_runner.main for more details.
Or you could implement your own cli entry point using acts.config_parser
functions and acts.test_runner.execute_one_test_class.
"""
@@ -227,7 +221,7 @@
'-r',
'--random',
action="store_true",
- help=("If set, tests will be executed in random order."))
+ help="If set, tests will be executed in random order.")
parser.add_argument(
'-ti',
'--test_case_iterations',
diff --git a/acts/framework/acts/config_parser.py b/acts/framework/acts/config_parser.py
index 176e7c3..ac6380e 100755
--- a/acts/framework/acts/config_parser.py
+++ b/acts/framework/acts/config_parser.py
@@ -100,6 +100,8 @@
Args:
testbed_configs: A list of testbed configuration json objects.
+ config_path : The path to the config file, which can be used to
+ generate absolute paths from relative paths in configs.
Raises:
If any part of the configuration is invalid, ActsConfigError is raised.
@@ -110,13 +112,6 @@
_validate_testbed_name(name)
-def _verify_test_class_name(test_cls_name):
- if not test_cls_name.endswith("Test"):
- raise ActsConfigError(
- ("Requested test class '%s' does not follow the test class naming "
- "convention *Test.") % test_cls_name)
-
-
def gen_term_signal_handler(test_runners):
def termination_sig_handler(signal_num, frame):
print('Received sigterm %s.' % signal_num)
@@ -149,14 +144,12 @@
if len(tokens) == 1:
# This should be considered a test class name
test_cls_name = tokens[0]
- _verify_test_class_name(test_cls_name)
- return (test_cls_name, None)
+ return test_cls_name, None
elif len(tokens) == 2:
# This should be considered a test class name followed by
# a list of test case names.
test_cls_name, test_case_names = tokens
clean_names = []
- _verify_test_class_name(test_cls_name)
for elem in test_case_names.split(','):
test_case_name = elem.strip()
if not test_case_name.startswith("test_"):
@@ -166,7 +159,7 @@
"naming convention test_*.") % (test_case_name,
test_cls_name))
clean_names.append(test_case_name)
- return (test_cls_name, clean_names)
+ return test_cls_name, clean_names
def parse_test_list(test_list):
@@ -186,7 +179,7 @@
Args:
test_identifiers: A list of test classes/cases.
- random_iterations: The range of random iterations for each case.
+ test_case_iterations: The range of random iterations for each case.
Returns:
A list of randomized test cases.
"""
@@ -223,7 +216,7 @@
override_test_args=None,
override_random=None,
override_test_case_iterations=None):
- """Processes the test configuration file provied by user.
+ """Processes the test configuration file provided by the user.
Loads the configuration file into a json object, unpacks each testbed
config into its own json object, and validate the configuration in the
@@ -280,18 +273,19 @@
'if you have the correct testbed names.' % name)
testbeds = tbs
- if (not keys.Config.key_log_path.value in configs
+ if (keys.Config.key_log_path.value not in configs
and _ENV_ACTS_LOGPATH in os.environ):
print('Using environment log path: %s' %
(os.environ[_ENV_ACTS_LOGPATH]))
configs[keys.Config.key_log_path.value] = os.environ[_ENV_ACTS_LOGPATH]
- if (not keys.Config.key_test_paths.value in configs
+ if (keys.Config.key_test_paths.value not in configs
and _ENV_ACTS_TESTPATHS in os.environ):
print('Using environment test paths: %s' %
(os.environ[_ENV_ACTS_TESTPATHS]))
configs[keys.Config.key_test_paths.value] = os.environ[
_ENV_ACTS_TESTPATHS].split(_PATH_SEPARATOR)
+ # Add the global paths to the global config.
k_log_path = keys.Config.key_log_path.value
configs[k_log_path] = utils.abs_path(configs[k_log_path])
diff --git a/acts/framework/acts/controllers/access_point.py b/acts/framework/acts/controllers/access_point.py
index 4b7919f..231ce00 100755
--- a/acts/framework/acts/controllers/access_point.py
+++ b/acts/framework/acts/controllers/access_point.py
@@ -96,7 +96,7 @@
Attributes:
ssh: The ssh connection to this ap.
- ssh_settings: The ssh settings being used by the ssh conneciton.
+ ssh_settings: The ssh settings being used by the ssh connection.
dhcp_settings: The dhcp server settings being used.
"""
@@ -174,7 +174,7 @@
Args:
hostapd_config: hostapd_config.HostapdConfig, The configurations
to use when starting up the ap.
- additional_parameters: A dicitonary of parameters that can sent
+ additional_parameters: A dictionary of parameters that can sent
directly into the hostapd config file. This
can be used for debugging and or adding one
off parameters into the config.
@@ -321,7 +321,7 @@
"""
if identifier not in list(self._aps.keys()):
- raise ValueError('Invalid identifer %s given' % identifier)
+ raise ValueError('Invalid identifier %s given' % identifier)
instance = self._aps.get(identifier)
@@ -351,7 +351,7 @@
"""Called to take down the entire access point.
When called will stop all aps running on this host, shutdown the dhcp
- server, and stop the ssh conneciton.
+ server, and stop the ssh connection.
"""
if self._aps:
diff --git a/acts/framework/acts/controllers/adb.py b/acts/framework/acts/controllers/adb.py
index 3461071..562cbb8 100644
--- a/acts/framework/acts/controllers/adb.py
+++ b/acts/framework/acts/controllers/adb.py
@@ -163,8 +163,8 @@
result = job.run(cmd, ignore_status=True, timeout=timeout)
ret, out, err = result.exit_status, result.stdout, result.stderr
- logging.debug("cmd: %s, stdout: %s, stderr: %s, ret: %s", cmd, out,
- err, ret)
+ if DEVICE_OFFLINE_REGEX.match(err):
+ raise AdbError(cmd=cmd, stdout=out, stderr=err, ret_code=ret)
if "Result: Parcel" in out:
return parsing_parcel_output(out)
if ignore_status:
@@ -178,14 +178,14 @@
return self._exec_cmd(' '.join((self.adb_str, name, arg_str)),
**kwargs)
- def _exec_cmd_nb(self, cmd):
+ def _exec_cmd_nb(self, cmd, **kwargs):
"""Executes adb commands in a new shell, non blocking.
Args:
cmds: A string that is the adb command to execute.
"""
- job.run_async(cmd)
+ return job.run_async(cmd, **kwargs)
def _exec_adb_cmd_nb(self, name, arg_str, **kwargs):
return self._exec_cmd_nb(' '.join((self.adb_str, name, arg_str)),
diff --git a/acts/framework/acts/controllers/android_device.py b/acts/framework/acts/controllers/android_device.py
index f388c29..6439267 100755
--- a/acts/framework/acts/controllers/android_device.py
+++ b/acts/framework/acts/controllers/android_device.py
@@ -18,10 +18,11 @@
from builtins import open
from datetime import datetime
+import collections
import logging
+import math
import os
import re
-import shellescape
import socket
import time
@@ -46,7 +47,9 @@
CRASH_REPORT_PATHS = ("/data/tombstones/", "/data/vendor/ramdump/",
"/data/ramdump/", "/data/vendor/ssrdump",
"/data/vendor/ramdump/bluetooth")
-CRASH_REPORT_SKIPS = ("RAMDUMP_RESERVED", "RAMDUMP_STATUS", "bluetooth")
+CRASH_REPORT_SKIPS = ("RAMDUMP_RESERVED", "RAMDUMP_STATUS", "RAMDUMP_OUTPUT",
+ "bluetooth")
+DEFAULT_QXDM_LOG_PATH = "/data/vendor/radio/diag_logs"
BUG_REPORT_TIMEOUT = 1800
PULL_TIMEOUT = 300
PORT_RETRY_COUNT = 3
@@ -340,7 +343,6 @@
test_name: Name of the test case that triggered this bug report.
begin_time: Logline format timestamp taken when the test started.
"""
- begin_time = acts_logger.normalize_log_line_timestamp(begin_time)
def take_br(test_name, begin_time, ad):
ad.take_bug_report(test_name, begin_time)
@@ -391,6 +393,7 @@
self._ssh_connection = ssh_connection
self.skip_sl4a = False
self.crash_report = None
+ self.data_accounting = collections.defaultdict(int)
self._sl4a_manager = sl4a_manager.Sl4aManager(self.adb)
def clean_up(self):
@@ -413,13 +416,13 @@
skip_sl4a: Does not attempt to start SL4A if True.
skip_setup_wizard: Whether or not to skip the setup wizard.
"""
+ if skip_setup_wizard:
+ self.exit_setup_wizard()
try:
self.start_adb_logcat()
except:
self.log.exception("Failed to start adb logcat!")
raise
- if skip_setup_wizard:
- self.exit_setup_wizard()
if not skip_sl4a:
try:
droid, ed = self.get_droid()
@@ -658,9 +661,11 @@
"""
return self._sl4a_manager.sessions[droid.uid].get_event_dispatcher()
- def _is_timestamp_in_range(self, target, begin_time, end_time):
- low = acts_logger.logline_timestamp_comparator(begin_time, target) <= 0
- high = acts_logger.logline_timestamp_comparator(end_time, target) >= 0
+ def _is_timestamp_in_range(self, target, log_begin_time, log_end_time):
+ low = acts_logger.logline_timestamp_comparator(log_begin_time,
+ target) <= 0
+ high = acts_logger.logline_timestamp_comparator(log_end_time,
+ target) >= 0
return low and high
def cat_adb_log(self, tag, begin_time):
@@ -669,20 +674,20 @@
Args:
tag: An identifier of the time period, usualy the name of a test.
- begin_time: Logline format timestamp of the beginning of the time
- period.
+ begin_time: Epoch time of the beginning of the time period.
"""
+ log_begin_time = acts_logger.epoch_to_log_line_timestamp(begin_time)
if not self.adb_logcat_file_path:
raise AndroidDeviceError(
("Attempting to cat adb log when none has"
" been collected on Android device %s.") % self.serial)
- end_time = acts_logger.get_log_line_timestamp()
+ log_end_time = acts_logger.get_log_line_timestamp()
self.log.debug("Extracting adb log from logcat.")
adb_excerpt_path = os.path.join(self.log_path, "AdbLogExcerpts")
utils.create_dir(adb_excerpt_path)
f_name = os.path.basename(self.adb_logcat_file_path)
out_name = f_name.replace("adblog,", "").replace(".txt", "")
- out_name = ",{},{}.txt".format(begin_time, out_name)
+ out_name = ",{},{}.txt".format(log_begin_time, out_name)
tag_len = utils.MAX_FILENAME_LEN - len(out_name)
tag = tag[:tag_len]
out_name = tag + out_name
@@ -702,8 +707,8 @@
line_time = line[:acts_logger.log_line_timestamp_len]
if not acts_logger.is_valid_logline_timestamp(line_time):
continue
- if self._is_timestamp_in_range(line_time, begin_time,
- end_time):
+ if self._is_timestamp_in_range(line_time, log_begin_time,
+ log_end_time):
in_range = True
if not line.endswith('\n'):
line += '\n'
@@ -854,7 +859,7 @@
Args:
test_name: Name of the test case that triggered this bug report.
- begin_time: Logline format timestamp taken when the test started.
+ begin_time: Epoch time when the test started.
"""
self.adb.wait_for_device(timeout=WAIT_FOR_DEVICE_TIMEOUT)
new_br = True
@@ -868,8 +873,10 @@
new_br = False
br_path = os.path.join(self.log_path, test_name)
utils.create_dir(br_path)
+ time_stamp = acts_logger.normalize_log_line_timestamp(
+ acts_logger.epoch_to_log_line_timestamp(begin_time))
out_name = "AndroidDevice%s_%s" % (
- self.serial, begin_time.replace(" ", "_").replace(":", "-"))
+ self.serial, time_stamp.replace(" ", "_").replace(":", "-"))
out_name = "%s.zip" % out_name if new_br else "%s.txt" % out_name
full_out_path = os.path.join(br_path, out_name)
# in case device restarted, wait for adb interface to return
@@ -889,19 +896,27 @@
full_out_path)
self.adb.wait_for_device(timeout=WAIT_FOR_DEVICE_TIMEOUT)
- def get_file_names(self, directory):
+ def get_file_names(self,
+ directory,
+ begin_time=None,
+ skip_files=[],
+ match_string=None):
"""Get files names with provided directory."""
- # -1 (the number one) prints one file per line.
- out = self.adb.shell(
- "ls -1 %s" % directory, ignore_status=True)
- if "Permission denied" in out:
- self.root_adb()
- out = self.adb.shell(
- "ls -1 %s" % directory, ignore_status=True)
- if out and "No such" not in out:
- return out.split('\n')
- else:
+ cmd = "find %s -type f" % directory
+ if begin_time:
+ current_time = utils.get_current_epoch_time()
+ seconds = int(math.ceil((current_time - begin_time) / 1000.0))
+ cmd = "%s -mtime -%ss" % (cmd, seconds)
+ if match_string:
+ cmd = "%s -iname %s" % (cmd, match_string)
+ for skip_file in skip_files:
+ cmd = "%s ! -iname %s" % (cmd, skip_file)
+ out = self.adb.shell(cmd, ignore_status=True)
+ if not out or "No such" in out or "Permission denied" in out:
return []
+ files = out.split("\n")
+ self.log.debug("Find files in directory %s: %s", directory, files)
+ return files
def pull_files(self, files, remote_path=None):
"""Pull files from devies."""
@@ -917,22 +932,20 @@
log_crash_report=False):
"""check crash report on the device."""
crash_reports = []
- if begin_time:
- begin_time = "%s-%s" % (datetime.now().year, begin_time)
- begin_time = datetime.strptime(begin_time, "%Y-%m-%d %H:%M:%S.%f")
for crash_path in CRASH_REPORT_PATHS:
- for report in self.get_file_names(crash_path):
- if report in CRASH_REPORT_SKIPS:
- continue
- file_path = os.path.join(crash_path, report)
- if begin_time:
- file_time = self.adb.shell('stat -c "%%y" %s' % file_path)
- file_time = datetime.strptime(file_time[:-3],
- "%Y-%m-%d %H:%M:%S.%f")
- if begin_time < file_time:
- crash_reports.append(file_path)
- else:
- crash_reports.append(file_path)
+ crashes = self.get_file_names(
+ crash_path,
+ skip_files=CRASH_REPORT_SKIPS,
+ begin_time=begin_time)
+ if crash_path == "/data/tombstones/" and crashes:
+ tombstones = crashes[:]
+ for tombstone in tombstones:
+ if self.adb.shell(
+ 'cat %s | grep "crash_dump failed to dump process"'
+ % tombstone):
+ crashes.remove(tombstone)
+ if crashes:
+ crash_reports.extend(crashes)
if crash_reports and log_crash_report:
test_name = test_name or time.strftime("%Y-%m-%d-%Y-%H-%M-%S")
crash_log_path = os.path.join(self.log_path, test_name,
@@ -941,7 +954,7 @@
self.pull_files(crash_reports, crash_log_path)
return crash_reports
- def get_qxdm_logs(self):
+ def get_qxdm_logs(self, test_name="", begin_time=None):
"""Get qxdm logs."""
# Sleep 10 seconds for the buffered log to be written in qxdm log file
time.sleep(10)
@@ -949,12 +962,23 @@
qxdm_logs = self.get_file_names(
log_path, begin_time=begin_time, match_string="*.qmdl")
if qxdm_logs:
- qxdm_path = os.path.join(self.log_path, "QXDM_Logs")
- utils.create_dir(qxdm_path)
- self.pull_files(qxdm_logs, qxdm_path)
+ qxdm_log_path = os.path.join(self.log_path, test_name,
+ "QXDM_%s" % self.serial)
+ utils.create_dir(qxdm_log_path)
+ self.log.info("Pull QXDM Log %s to %s", qxdm_logs, qxdm_log_path)
+ self.pull_files(qxdm_logs, qxdm_log_path)
+ else:
+ self.log.error("Didn't find QXDM logs in %s." % log_path)
+ if "Verizon" in self.adb.getprop("gsm.sim.operator.alpha"):
+ omadm_log_path = os.path.join(self.log_path, test_name,
+ "OMADM_%s" % self.serial)
+ utils.create_dir(omadm_log_path)
+ self.log.info("Pull OMADM Log")
self.adb.pull(
- "/firmware/image/qdsp6m.qdb %s" % qxdm_path,
- timeout=PULL_TIMEOUT, ignore_status=True)
+ "/data/data/com.android.omadm.service/files/dm/log/ %s" %
+ omadm_log_path,
+ timeout=PULL_TIMEOUT,
+ ignore_status=True)
def start_new_session(self, max_connections=None, server_port=None):
"""Start a new session in sl4a.
@@ -982,6 +1006,28 @@
"""
self._sl4a_manager.terminate_all_sessions()
+ def run_iperf_client_nb(self,
+ server_host,
+ extra_args="",
+ timeout=IPERF_TIMEOUT,
+ log_file_path=None):
+ """Start iperf client on the device asynchronously.
+
+ Return status as true if iperf client start successfully.
+ And data flow information as results.
+
+ Args:
+ server_host: Address of the iperf server.
+ extra_args: A string representing extra arguments for iperf client,
+ e.g. "-i 1 -t 30".
+ log_file_path: The complete file path to log the results.
+
+ """
+ cmd = "iperf3 -c {} {}".format(server_host, extra_args)
+ if log_file_path:
+ cmd += " --logfile {} &".format(log_file_path)
+ self.adb.shell_nb(cmd)
+
def run_iperf_client(self,
server_host,
extra_args="",
@@ -1069,11 +1115,14 @@
self.adb.reboot()
self.wait_for_boot_completion()
self.root_adb()
- if stop_at_lock_screen and self.is_screen_lock_enabled():
+ if stop_at_lock_screen:
return
+ if not self.ensure_screen_on():
+ self.log.error("User window cannot come up")
+ raise AndroidDeviceError("User window cannot come up")
self.start_services(self.skip_sl4a)
- def search_logcat(self, matching_string):
+ def search_logcat(self, matching_string, begin_time=None):
"""Search logcat message with given string.
Args:
@@ -1093,7 +1142,8 @@
begin_time)
cmd_option = '%s -t "%s"' % (cmd_option, log_begin_time)
out = self.adb.logcat(
- '-b all -d | grep "%s"' % matching_string, ignore_status=True)
+ '%s | grep "%s"' % (cmd_option, matching_string),
+ ignore_status=True)
if not out: return []
result = []
logs = re.findall(r'(\S+\s\S+)(.*%s.*)' % re.escape(matching_string),
@@ -1294,6 +1344,16 @@
self.adb.shell(
"am start -n com.google.android.setupwizard/.SetupWizardExitActivity"
)
+ #Wait up to 5 seconds for user_setup_complete to be updated
+ for _ in range(5):
+ if self.is_user_setup_complete():
+ return
+ time.sleep(1)
+ #If fail to exit setup wizard, set local.prop and reboot
+ if not self.is_user_setup_complete():
+ self.adb.shell("echo ro.test_harness=1 > /data/local.prop")
+ self.adb.shell("chmod 644 /data/local.prop")
+ self.reboot(stop_at_lock_screen=True)
class AndroidDeviceLoggerAdapter(logging.LoggerAdapter):
diff --git a/acts/framework/acts/controllers/anritsu_lib/_anritsu_utils.py b/acts/framework/acts/controllers/anritsu_lib/_anritsu_utils.py
index 8e5445a..0da016f 100644
--- a/acts/framework/acts/controllers/anritsu_lib/_anritsu_utils.py
+++ b/acts/framework/acts/controllers/anritsu_lib/_anritsu_utils.py
@@ -1,4 +1,4 @@
-#/usr/bin/env python3.4
+#!/usr/bin/env python3.4
#
# Copyright 2016 - The Android Open Source Project
#
@@ -13,10 +13,10 @@
# 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.
-
"""
Utility functions for for Anritsu Signalling Tester.
"""
+# yapf: disable
OPERATION_COMPLETE = 1
NO_ERROR = 0
@@ -229,3 +229,4 @@
def __str__(self):
return self._error_message
+# yapf: enable
diff --git a/acts/framework/acts/controllers/anritsu_lib/cell_configurations.py b/acts/framework/acts/controllers/anritsu_lib/cell_configurations.py
index f82c6bd..d3369bf 100644
--- a/acts/framework/acts/controllers/anritsu_lib/cell_configurations.py
+++ b/acts/framework/acts/controllers/anritsu_lib/cell_configurations.py
@@ -1,4 +1,4 @@
-#/usr/bin/env python3.4
+#!/usr/bin/env python3.4
#
# Copyright 2016 - The Android Open Source Project
#
diff --git a/acts/framework/acts/controllers/anritsu_lib/md8475a.py b/acts/framework/acts/controllers/anritsu_lib/md8475a.py
index 5b7f0e3..a6c0e13 100644
--- a/acts/framework/acts/controllers/anritsu_lib/md8475a.py
+++ b/acts/framework/acts/controllers/anritsu_lib/md8475a.py
@@ -1,4 +1,4 @@
-#/usr/bin/env python3.4
+#!/usr/bin/env python3.4
#
# Copyright 2016 - The Android Open Source Project
#
@@ -54,6 +54,23 @@
IDENTITY_REQ_DATA_LEN = 24
SEQ_LOG_MESSAGE_START_INDEX = 60
+WCDMA_BANDS = {
+ "I": "1",
+ "II": "2",
+ "III": "3",
+ "IV": "4",
+ "V": "5",
+ "VI": "6",
+ "VII": "7",
+ "VIII": "8",
+ "IX": "9",
+ "X": "10",
+ "XI": "11",
+ "XII": "12",
+ "XIII": "13",
+ "XIV": "14"
+}
+
def create(configs, logger):
objs = []
@@ -651,6 +668,8 @@
# this is needed before Sync command is supported in 6.40a
if self.send_query("IMSVNSTAT? 1") == "RUNNING":
self.send_command("IMSSTOPVN 1")
+ if self.send_query("IMSVNSTAT? 2") == "RUNNING":
+ self.send_command("IMSSTOPVN 2")
stat = self.send_query("STAT?")
# Stop simulation if its is RUNNING
if stat == "RUNNING":
@@ -710,8 +729,19 @@
error = int(
self.send_query("SIMMODEL %s;ERROR?" % sim_model,
COMMAND_COMPLETE_WAIT_TIME))
- if error:
- return False
+ if error: # Try again if first set SIMMODEL fails
+ time.sleep(3)
+ if "WLAN" in sim_model:
+ new_sim_model = sim_model[:-5]
+ error = int(
+ self.send_query("SIMMODEL %s;ERROR?" % new_sim_model,
+ COMMAND_COMPLETE_WAIT_TIME))
+ time.sleep(3)
+ error = int(
+ self.send_query("SIMMODEL %s;ERROR?" % sim_model,
+ COMMAND_COMPLETE_WAIT_TIME))
+ if error:
+ return False
# Reset every time after SIMMODEL is set because SIMMODEL will load
# some of the contents from previous parameter files.
self.reset()
@@ -865,6 +895,34 @@
bts_number, rat_info = self.send_query("CAMPINGCELL?").split(",")
return bts_number, rat_info
+ def get_supported_bands(self, rat):
+ """ Gets the supported bands from UE capability information
+
+ Args:
+ rat: LTE or WCDMA
+
+ Returns:
+ returns a list of bnads
+ """
+ cmd = "UEINFO? "
+ if rat == "LTE":
+ cmd += "L"
+ elif rat == "WCDMA":
+ cmd += "W"
+ else:
+ raise ValueError('The rat argument needs to be "LTE" or "WCDMA"')
+ cmd += "_SupportedBand"
+ result = self.send_query(cmd).split(",")
+ if result == "NONE":
+ return None
+ if rat == "WCDMA":
+ bands = []
+ for band in result:
+ bands.append(WCDMA_BANDS[band])
+ return bands
+ else:
+ return result
+
def start_testcase(self):
""" Starts a test case on Anritsu
@@ -1506,8 +1564,14 @@
Returns:
None
"""
- cmd = "OLVL {},{}".format(level, self._bts_number)
- self._anritsu.send_command(cmd)
+ counter = 1
+ while float(level) != float(self.output_level):
+ if counter > 3:
+ raise AnritsuError("Fail to set output level in 3 tries!")
+ cmd = "OLVL {},{}".format(level, self._bts_number)
+ self._anritsu.send_command(cmd)
+ counter += 1
+ time.sleep(1)
@property
def input_level(self):
@@ -1532,8 +1596,14 @@
Returns:
None
"""
- cmd = "RFLVL {},{}".format(level, self._bts_number)
- self._anritsu.send_command(cmd)
+ counter = 1
+ while float(level) != float(self.input_level):
+ if counter > 3:
+ raise AnritsuError("Fail to set intput level in 3 tries!")
+ cmd = "RFLVL {},{}".format(level, self._bts_number)
+ self._anritsu.send_command(cmd)
+ counter += 1
+ time.sleep(1)
@property
def band(self):
@@ -2468,6 +2538,38 @@
self._anritsu.send_command(cmd)
@property
+ def lte_scheduling_mode(self):
+ """ Gets the Scheduling mode of the LTE cell
+
+ Args:
+ None
+
+ Returns:
+ Scheduling mode
+ """
+ cmd = "SCHEDULEMODE? " + self._bts_number
+ return self._anritsu.send_query(cmd)
+
+ @lte_scheduling_mode.setter
+ def lte_scheduling_mode(self, mode):
+ """ Sets the Scheduling mode of the LTE cell
+
+ Args:
+ mode: STATIC (default) or DYNAMIC
+
+ Returns:
+ None
+ """
+ counter = 1
+ while mode != self.lte_scheduling_mode:
+ if counter > 3:
+ raise AnritsuError("Fail to set scheduling mode in 3 tries!")
+ cmd = "SCHEDULEMODE {},{}".format(mode, self._bts_number)
+ self._anritsu.send_command(cmd)
+ counter += 1
+ time.sleep(1)
+
+ @property
def lte_mcs_dl(self):
""" Gets the Modulation and Coding scheme (DL) of the LTE cell
@@ -3420,6 +3522,58 @@
cmd = "PDNVNID {},{}".format(self._pdn_number, vnid)
self._anritsu.send_command(cmd)
+ @property
+ def pdn_apn_name(self):
+ """ Get PDN APN NAME
+
+ Args:
+ None
+
+ Returns:
+ PDN APN NAME
+ """
+ cmd = "PDNCHECKAPN? " + self._pdn_number
+ return self._anritsu.send_query(cmd)
+
+ @pdn_apn_name.setter
+ def pdn_apn_name(self, name):
+ """ Set PDN APN NAME
+
+ Args:
+ name: fast.t-mobile.com, ims
+
+ Returns:
+ None
+ """
+ cmd = "PDNCHECKAPN {},{}".format(self._pdn_number, name)
+ self._anritsu.send_command(cmd)
+
+ @property
+ def pdn_qci(self):
+ """ Get PDN QCI Value
+
+ Args:
+ None
+
+ Returns:
+ PDN QCI Value
+ """
+ cmd = "PDNQCIDEFAULT? " + self._pdn_number
+ return self._anritsu.send_query(cmd)
+
+ @pdn_qci.setter
+ def pdn_qci(self, qci_value):
+ """ Set PDN QCI Value
+
+ Args:
+ qci_value: 5, 9
+
+ Returns:
+ None
+ """
+ cmd = "PDNQCIDEFAULT {},{}".format(self._pdn_number, qci_value)
+ self._anritsu.send_command(cmd)
+
class _TriggerMessage(object):
'''Class to interact with trigger message handling supported by MD8475 '''
@@ -3555,6 +3709,32 @@
self._anritsu.send_command(cmd)
@property
+ def imscscf_iptype(self):
+ """ Gets CSCF IP Type
+
+ Args:
+ None
+
+ Returns:
+ CSCF IP Type
+ """
+ cmd = "IMSCSCFIPTYPE? " + self._vnid
+ return self._anritsu.send_query(cmd)
+
+ @imscscf_iptype.setter
+ def imscscf_iptype(self, iptype):
+ """ Set CSCF IP Type
+
+ Args:
+ iptype: IPV4, IPV6, IPV4V6
+
+ Returns:
+ None
+ """
+ cmd = "IMSCSCFIPTYPE {},{}".format(self._vnid, iptype)
+ self._anritsu.send_command(cmd)
+
+ @property
def cscf_monitoring_ua(self):
""" Get CSCF Monitoring UA URI
@@ -3581,6 +3761,146 @@
self._anritsu.send_command(cmd)
@property
+ def cscf_host_name(self):
+ """ Get CSCF Host Name
+
+ Args:
+ None
+
+ Returns:
+ CSCF Host Name
+ """
+ cmd = "IMSCSCFNAME? " + self._vnid
+ return self._anritsu.send_query(cmd)
+
+ @cscf_host_name.setter
+ def cscf_host_name(self, host_name):
+ """ Set CSCF Host Name
+
+ Args:
+ host_name: CSCF Host Name
+
+ Returns:
+ None
+ """
+ cmd = "IMSCSCFNAME {},{}".format(self._vnid, host_name)
+ self._anritsu.send_command(cmd)
+
+ @property
+ def cscf_ims_authentication(self):
+ """ Get CSCF IMS Auth Value
+
+ Args:
+ None
+
+ Returns:
+ CSCF IMS Auth
+ """
+ cmd = "IMSCSCFAUTH? " + self._vnid
+ return self._anritsu.send_query(cmd)
+
+ @cscf_ims_authentication.setter
+ def cscf_ims_authentication(self, on_off):
+ """ Set CSCF IMS Auth Value
+
+ Args:
+ on_off: CSCF IMS Auth ENABLE/DISABLE
+
+ Returns:
+ None
+ """
+ cmd = "IMSCSCFAUTH {},{}".format(self._vnid, on_off)
+ self._anritsu.send_command(cmd)
+
+ @property
+ def cscf_virtual_ua(self):
+ """ Get CSCF Virtual UA URI
+
+ Args:
+ None
+
+ Returns:
+ CSCF Virtual UA URI
+ """
+ cmd = "IMSCSCFVUAURI? " + self._vnid
+ return self._anritsu.send_query(cmd)
+
+ @cscf_virtual_ua.setter
+ def cscf_virtual_ua(self, ua_uri):
+ """ Set CSCF Virtual UA URI
+
+ Args:
+ ua_uri: CSCF Virtual UA URI
+
+ Returns:
+ None
+ """
+ cmd = "IMSCSCFVUAURI {},{}".format(self._vnid, ua_uri)
+ self._anritsu.send_command(cmd)
+
+ @property
+ def tmo_cscf_userslist_add(self):
+ """ Get CSCF USERLIST
+
+ Args:
+ None
+
+ Returns:
+ CSCF USERLIST
+ """
+ cmd = "IMSCSCFUSERSLIST? " + self._vnid
+ return self._anritsu.send_query(cmd)
+
+ @tmo_cscf_userslist_add.setter
+ def tmo_cscf_userslist_add(self, username):
+ """ Set CSCF USER to USERLIST
+ This is needed if IMS AUTH is enabled
+
+ Args:
+ username: CSCF Username
+
+ Returns:
+ None
+ """
+ cmd = "IMSCSCFUSERSLISTADD {},{},00112233445566778899AABBCCDDEEFF,TS34108,AKAV1_MD5,\
+ OPC,00000000000000000000000000000000,8000,TRUE,FALSE,0123456789ABCDEF0123456789ABCDEF,\
+ 54CDFEAB9889000001326754CDFEAB98,6754CDFEAB9889BAEFDC457623100132,\
+ 326754CDFEAB9889BAEFDC4576231001,TRUE,TRUE,TRUE".format(
+ self._vnid, username)
+ self._anritsu.send_command(cmd)
+
+ @property
+ def vzw_cscf_userslist_add(self):
+ """ Get CSCF USERLIST
+
+ Args:
+ None
+
+ Returns:
+ CSCF USERLIST
+ """
+ cmd = "IMSCSCFUSERSLIST? " + self._vnid
+ return self._anritsu.send_query(cmd)
+
+ @vzw_cscf_userslist_add.setter
+ def vzw_cscf_userslist_add(self, username):
+ """ Set CSCF USER to USERLIST
+ This is needed if IMS AUTH is enabled
+
+ Args:
+ username: CSCF Username
+
+ Returns:
+ None
+ """
+ cmd = "IMSCSCFUSERSLISTADD {},{},465B5CE8B199B49FAA5F0A2EE238A6BC,MILENAGE,AKAV1_MD5,\
+ OP,5F1D289C5D354D0A140C2548F5F3E3BA,8000,TRUE,FALSE,0123456789ABCDEF0123456789ABCDEF,\
+ 54CDFEAB9889000001326754CDFEAB98,6754CDFEAB9889BAEFDC457623100132,\
+ 326754CDFEAB9889BAEFDC4576231001,TRUE,TRUE,TRUE".format(
+ self._vnid, username)
+ self._anritsu.send_command(cmd)
+
+ @property
def dns(self):
""" Gets DNS Enable status
@@ -3635,6 +3955,32 @@
self._anritsu.send_command(cmd)
@property
+ def ndp_prefix(self):
+ """ Gets NDP IPv6 Prefix
+
+ Args:
+ None
+
+ Returns:
+ NDP IPv6 Prefix
+ """
+ cmd = "IMSNDPPREFIX? " + self._vnid
+ return self._anritsu.send_query(cmd)
+
+ @ndp_prefix.setter
+ def ndp_prefix(self, prefix_addr):
+ """ Set NDP IPv6 Prefix
+
+ Args:
+ prefix_addr: NDP IPV6 Prefix Addr
+
+ Returns:
+ None
+ """
+ cmd = "IMSNDPPREFIX {},{},64".format(self._vnid, prefix_addr)
+ self._anritsu.send_command(cmd)
+
+ @property
def psap(self):
""" Gets PSAP Enable status
diff --git a/acts/framework/acts/controllers/anritsu_lib/mg3710a.py b/acts/framework/acts/controllers/anritsu_lib/mg3710a.py
index f112dbf..9c6cf46 100644
--- a/acts/framework/acts/controllers/anritsu_lib/mg3710a.py
+++ b/acts/framework/acts/controllers/anritsu_lib/mg3710a.py
@@ -1,4 +1,4 @@
-#/usr/bin/env python3.4
+#!/usr/bin/env python3.4
#
# Copyright 2016 - The Android Open Source Project
#
@@ -695,8 +695,8 @@
Returns:
frequency offset
"""
- return self.send_query("SOUR{}:RAD:ARB:WM{}:FREQ:OFFS?".format(sg,
- a_or_b))
+ return self.send_query(
+ "SOUR{}:RAD:ARB:WM{}:FREQ:OFFS?".format(sg, a_or_b))
def set_arb_freq_offset_aorb(self, a_or_b, offset, sg=1):
""" Sets the frequency offset of Pattern A/Pattern B based on Baseband
diff --git a/acts/framework/acts/controllers/ap_lib/dhcp_server.py b/acts/framework/acts/controllers/ap_lib/dhcp_server.py
index 6d81360..19d6d73 100644
--- a/acts/framework/acts/controllers/ap_lib/dhcp_server.py
+++ b/acts/framework/acts/controllers/ap_lib/dhcp_server.py
@@ -29,7 +29,7 @@
class DhcpServer(object):
"""Manages the dhcp server program.
- Only one of these can run in an enviroment at a time.
+ Only one of these can run in an environment at a time.
Attributes:
config: The dhcp server configuration that is being used.
@@ -76,8 +76,9 @@
self._shell.delete_file(self._log_file)
self._shell.touch_file(self._lease_file)
- dhcpd_command = '%s -cf "%s" -lf %s -f""' % (
- self.PROGRAM_FILE, self._config_file, self._lease_file)
+ dhcpd_command = '%s -cf "%s" -lf %s -f""' % (self.PROGRAM_FILE,
+ self._config_file,
+ self._lease_file)
base_command = 'cd "%s"; %s' % (self._working_dir, dhcpd_command)
job_str = '%s > "%s" 2>&1' % (base_command, self._log_file)
self._runner.run_async(job_str)
@@ -96,7 +97,7 @@
def is_alive(self):
"""
Returns:
- True if the deamon is running.
+ True if the daemon is running.
"""
return self._shell.is_alive(self._identifier)
diff --git a/acts/framework/acts/controllers/ap_lib/hostapd.py b/acts/framework/acts/controllers/ap_lib/hostapd.py
index 9f78d79..e28e8e5 100644
--- a/acts/framework/acts/controllers/ap_lib/hostapd.py
+++ b/acts/framework/acts/controllers/ap_lib/hostapd.py
@@ -61,7 +61,7 @@
Args:
config: Configs to start the hostapd with.
timeout: Time to wait for DHCP server to come up.
- additional_parameters: A dicitonary of parameters that can sent
+ additional_parameters: A dictionary of parameters that can sent
directly into the hostapd config file. This
can be used for debugging and or adding one
off parameters into the config.
@@ -69,7 +69,7 @@
Returns:
True if the daemon could be started. Note that the daemon can still
start and not work. Invalid configurations can take a long amount
- of time to be produced, and because the daemon runs indefinetly
+ of time to be produced, and because the daemon runs indefinitely
it's impossible to wait on. If you need to check if configs are ok
then periodic checks to is_running and logs should be used.
"""
@@ -103,7 +103,7 @@
def is_alive(self):
"""
Returns:
- True if the deamon is running.
+ True if the daemon is running.
"""
return self._shell.is_alive(self._identifier)
@@ -166,8 +166,8 @@
if bad_config:
raise Error('Interface failed to start', self)
- bad_config = self._shell.search_file("Interface %s wasn't started" %
- self._interface, self._log_file)
+ bad_config = self._shell.search_file(
+ "Interface %s wasn't started" % self._interface, self._log_file)
if bad_config:
raise Error('Interface failed to start', self)
diff --git a/acts/framework/acts/controllers/chameleon_controller.py b/acts/framework/acts/controllers/chameleon_controller.py
new file mode 100644
index 0000000..e4b50e7
--- /dev/null
+++ b/acts/framework/acts/controllers/chameleon_controller.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2017 - 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 logging
+import time
+import xmlrpc.client
+from subprocess import call
+
+from acts import signals
+
+ACTS_CONTROLLER_CONFIG_NAME = "ChameleonDevice"
+ACTS_CONTROLLER_REFERENCE_NAME = "chameleon_devices"
+
+CHAMELEON_DEVICE_EMPTY_CONFIG_MSG = "Configuration is empty, abort!"
+CHAMELEON_DEVICE_NOT_LIST_CONFIG_MSG = "Configuration should be a list, abort!"
+
+audio_bus_endpoints = {
+ 'CROS_HEADPHONE': 'Cros device headphone',
+ 'CROS_EXTERNAL_MICROPHONE': 'Cros device external microphone',
+ 'PERIPHERAL_MICROPHONE': 'Peripheral microphone',
+ 'PERIPHERAL_SPEAKER': 'Peripheral speaker',
+ 'FPGA_LINEOUT': 'Chameleon FPGA line-out',
+ 'FPGA_LINEIN': 'Chameleon FPGA line-in',
+ 'BLUETOOTH_OUTPUT': 'Bluetooth module output',
+ 'BLUETOOTH_INPUT': 'Bluetooth module input'
+}
+
+
+class ChameleonDeviceError(signals.ControllerError):
+ pass
+
+
+def create(configs):
+ if not configs:
+ raise ChameleonDeviceError(CHAMELEON_DEVICE_EMPTY_CONFIG_MSG)
+ elif not isinstance(configs, list):
+ raise ChameleonDeviceError(CHAMELEON_DEVICE_NOT_LIST_CONFIG_MSG)
+ elif isinstance(configs[0], str):
+ # Configs is a list of IP addresses
+ chameleons = get_instances(configs)
+ return chameleons
+
+
+def destroy(chameleons):
+ for chameleon in chameleons:
+ del chameleon
+
+
+def get_info(chameleons):
+ """Get information on a list of ChameleonDevice objects.
+
+ Args:
+ ads: A list of ChameleonDevice objects.
+
+ Returns:
+ A list of dict, each representing info for ChameleonDevice objects.
+ """
+ device_info = []
+ for chameleon in chameleons:
+ info = {"address": chameleon.address, "port": chameleon.port}
+ device_info.append(info)
+ return device_info
+
+
+def get_instances(ips):
+ """Create ChameleonDevice instances from a list of IPs.
+
+ Args:
+ ips: A list of Chameleon IPs.
+
+ Returns:
+ A list of ChameleonDevice objects.
+ """
+ return [ChameleonDevice(ip) for ip in ips]
+
+
+class ChameleonDevice:
+ """Class representing a Chameleon device.
+
+ Each object of this class represents one Chameleon device in ACTS.
+
+ Attributes:
+ address: The full address to contact the Chameleon device at
+ client: The ServiceProxy of the XMLRPC client.
+ log: A logger object.
+ port: The TCP port number of the Chameleon device.
+ """
+
+ def __init__(self, ip="", port=9992):
+ self.ip = ip
+ self.log = logging.getLogger()
+ self.port = port
+ self.address = "http://{}:{}".format(ip, self.port)
+ try:
+ self.client = xmlrpc.client.ServerProxy(
+ self.address, allow_none=True, verbose=False)
+ except ConnectionRefusedError as err:
+ self.log.exception(
+ "Failed to connect to Chameleon Device at: {}".format(
+ self.address))
+ self.client.Reset()
+
+ def pull_file(self, chameleon_location, destination):
+ """Pulls a file from the Chameleon device. Usually the raw audio file.
+
+ Args:
+ chameleon_location: The path to the file on the Chameleon device
+ destination: The destination to where to pull it locally.
+ """
+ # TODO: (tturney) implement
+ self.log.error("Definition not yet implemented")
+
+ def start_capturing_audio(self, port_id, has_file=True):
+ """Starts capturing audio.
+
+ Args:
+ port_id: The ID of the audio input port.
+ has_file: True for saving audio data to file. False otherwise.
+ """
+ self.client.StartCapturingAudio(port_id, has_file)
+
+ def stop_capturing_audio(self, port_id):
+ """Stops capturing audio.
+
+ Args:
+ port_id: The ID of the audio input port.
+ Returns:
+ List contain the location of the recorded audio and a dictionary
+ of values relating to the raw audio including: file_type, channel,
+ sample_format, and rate.
+ """
+ return self.client.StopCapturingAudio(port_id)
+
+ def audio_board_connect(self, bus_number, endpoint):
+ """Connects an endpoint to an audio bus.
+
+ Args:
+ bus_number: 1 or 2 for audio bus 1 or bus 2.
+ endpoint: An endpoint defined in audio_bus_endpoints.
+ """
+ self.client.AudioBoardConnect(bus_number, endpoint)
+
+ def audio_board_disconnect(self, bus_number, endpoint):
+ """Connects an endpoint to an audio bus.
+
+ Args:
+ bus_number: 1 or 2 for audio bus 1 or bus 2.
+ endpoint: An endpoint defined in audio_bus_endpoints.
+ """
+ self.client.AudioBoardDisconnect(bus_number, endpoint)
+
+ def audio_board_disable_bluetooth(self):
+ """Disables Bluetooth module on audio board."""
+ self.client.AudioBoardDisableBluetooth()
+
+ def audio_board_clear_routes(self, bus_number):
+ """Clears routes on an audio bus.
+
+ Args:
+ bus_number: 1 or 2 for audio bus 1 or bus 2.
+ """
+ self.client.AudioBoardClearRoutes(bus_number)
+
+ def scp(self, source, destination):
+ """Copies files from the Chameleon device to the host machine.
+
+ Args:
+ source: The file path on the Chameleon board.
+ dest: The file path on the host machine.
+ """
+ cmd = "scp root@{}:/{} {}".format(self.ip, source, destination)
+ try:
+ call(cmd.split(" "))
+ except FileNotFoundError as err:
+ self.log.exception("File not found {}".format(source))
diff --git a/acts/framework/acts/controllers/iperf_client.py b/acts/framework/acts/controllers/iperf_client.py
new file mode 100644
index 0000000..2ba3919
--- /dev/null
+++ b/acts/framework/acts/controllers/iperf_client.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2017 - 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.
+"""
+Starts iperf client on host machine.
+"""
+from acts import utils
+import os
+import subprocess
+
+
+class IPerfClient():
+ """Class that handles iperf3 client operations."""
+
+ def __init__(self, port, ip_address, log_path):
+ self.port = port
+ self.log_path = os.path.join(log_path, "iPerf{}".format(self.port))
+ self.iperf_cmd = "iperf3 -c {} -i1".format(ip_address)
+ self.iperf_process = None
+ self.log_files = []
+ self.started = False
+
+ def start(self, extra_args="", tag=""):
+ """Starts iperf client on specified port on host machine.
+
+ Args:
+ extra_args: A string representing extra arguments to start iperf
+ client with.
+ tag: Appended to log file name to identify logs from different
+ iperf runs.
+
+ Returns:
+ full_out_path: Iperf result path.
+ """
+ if self.started:
+ return
+ utils.create_dir(self.log_path)
+ if tag:
+ tag = tag + ','
+ out_file_name = "IPerfClient,{},{}{}.log".format(
+ self.port, tag, len(self.log_files))
+ full_out_path = os.path.join(self.log_path, out_file_name)
+ cmd = "{} {}".format(self.iperf_cmd, extra_args)
+ cmd = cmd.split()
+ with open(full_out_path, "w") as f:
+ subprocess.call(cmd, stdout=f)
+ self.log_files.append(full_out_path)
+ self.started = True
+ return full_out_path
diff --git a/acts/framework/acts/controllers/monsoon.py b/acts/framework/acts/controllers/monsoon.py
index d91f644..17e8017 100644
--- a/acts/framework/acts/controllers/monsoon.py
+++ b/acts/framework/acts/controllers/monsoon.py
@@ -302,7 +302,7 @@
while 1: # loop until we get data or a timeout
_bytes = self._ReadPacket()
if not _bytes:
- return None
+ raise MonsoonError("Data collection failed due to empty data")
if len(_bytes) < 4 + 8 + 1 or _bytes[0] < 0x20 or _bytes[0] > 0x2F:
logging.warning("Wanted data, dropped type=0x%02x, len=%d",
_bytes[0], len(_bytes))
diff --git a/acts/framework/acts/controllers/native.py b/acts/framework/acts/controllers/native.py
index 86b8523..aa70f85 100644
--- a/acts/framework/acts/controllers/native.py
+++ b/acts/framework/acts/controllers/native.py
@@ -1,4 +1,4 @@
-#/usr/bin/env python3.4
+#!/usr/bin/env python3.4
#
# Copyright (C) 2009 Google Inc.
#
diff --git a/acts/framework/acts/controllers/relay_lib/dongles.py b/acts/framework/acts/controllers/relay_lib/dongles.py
index 518caad..34ab1c4 100644
--- a/acts/framework/acts/controllers/relay_lib/dongles.py
+++ b/acts/framework/acts/controllers/relay_lib/dongles.py
@@ -23,7 +23,7 @@
# Necessary timeout inbetween commands
CMD_TIMEOUT = 1.2
# Pairing mode activation wait time
-PAIRING_MODE_WAIT_TIME = 6
+PAIRING_MODE_WAIT_TIME = 4.5
SINGLE_ACTION_SHORT_WAIT_TIME = 0.6
SINGLE_ACTION_LONG_WAIT_TIME = 2.0
MISSING_RELAY_MSG = 'Relay config for Three button "%s" missing relay "%s".'
diff --git a/acts/framework/acts/controllers/relay_lib/fugu_remote.py b/acts/framework/acts/controllers/relay_lib/fugu_remote.py
index 4a9a4e7..92316b1 100644
--- a/acts/framework/acts/controllers/relay_lib/fugu_remote.py
+++ b/acts/framework/acts/controllers/relay_lib/fugu_remote.py
@@ -68,23 +68,23 @@
Holds down the 'Home' and 'Back' buttons for a little over 5 seconds.
"""
with SynchronizeRelays():
- self.relays[Buttons.HOME.value].set_nc()
- self.relays[Buttons.BACK.value].set_nc()
+ self.hold_down(Buttons.HOME.value)
+ self.hold_down(Buttons.BACK.value)
time.sleep(PAIRING_MODE_WAIT_TIME)
with SynchronizeRelays():
- self.relays[Buttons.HOME.value].set_no()
- self.relays[Buttons.BACK.value].set_no()
+ self.release(Buttons.HOME.value)
+ self.release(Buttons.BACK.value)
def press_play_pause(self):
"""Briefly presses the Play/Pause button."""
- self.relays[Buttons.PLAY_PAUSE.value].set_nc_for()
+ self.press(Buttons.PLAY_PAUSE.value)
def press_home(self):
"""Briefly presses the Home button."""
- self.relays[Buttons.HOME.value].set_nc_for()
+ self.press(Buttons.HOME.value)
def press_back(self):
"""Briefly presses the Back button."""
- self.relays[Buttons.BACK.value].set_nc_for()
+ self.press(Buttons.BACK.value)
diff --git a/acts/framework/acts/controllers/relay_lib/i6s_headset.py b/acts/framework/acts/controllers/relay_lib/i6s_headset.py
new file mode 100644
index 0000000..c1d3dc6
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/i6s_headset.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+#
+# Copyright 2017 - 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 enum
+
+from acts.controllers.relay_lib.errors import RelayConfigError
+from acts.controllers.relay_lib.generic_relay_device import GenericRelayDevice
+from acts.controllers.relay_lib.helpers import validate_key
+
+PAIRING_MODE_WAIT_TIME = 3
+WAIT_TIME = 0.1
+MISSING_RELAY_MSG = 'Relay config for i6s Headset "%s" missing relay "%s".'
+
+
+class Buttons(enum.Enum):
+ Power = "Power"
+ Answer_Call = "Answer"
+ Initiate_Call = "Call"
+ Next = 'Next'
+ Previous = "Previous"
+ Play_pause = 'Play_pause'
+ Pair = "Pair"
+ Volume_up = "Volume_up"
+ Volume_down = "Volume_down"
+
+
+class I6sHeadset(GenericRelayDevice):
+
+ def __init__(self, config, relay_rig):
+ GenericRelayDevice.__init__(self, config, relay_rig)
+ self.mac_address = validate_key('mac_address', config, str,
+ 'I6sHeadset')
+ for button in Buttons:
+ self.ensure_config_contains_relay(button.value)
+
+ def setup(self):
+ GenericRelayDevice.setup(self)
+
+ def clean_up(self):
+ """Turns off headset."""
+ self.relays[Buttons.Pair.value].set_no_for(PAIRING_MODE_WAIT_TIME)
+
+ def ensure_config_contains_relay(self, relay_name):
+ """
+ Throws an error if the relay does not exist.
+
+ Args:
+ relay_name:relay_name to be checked.
+ """
+ if relay_name not in self.relays:
+ raise RelayConfigError(MISSING_RELAY_MSG % (self.name, relay_name))
+
+ def pairing_mode(self):
+ """Sets relay in paring mode."""
+ self.relays[Buttons.Pair.value].set_no_for(PAIRING_MODE_WAIT_TIME)
+
+ def power_on(self):
+ """Power on relay."""
+ self.relays[Buttons.Power.value].set_no_for(WAIT_TIME)
+
+ def play_pause(self):
+ """
+ Sets relay to
+ Play state : if there is no A2DP_streaming.
+ Pause state : if there is A2DP_streaming.
+ """
+ self.relays[Buttons.Play_pause.value].set_no_for(WAIT_TIME)
+
+ def skip_next(self):
+ """Skips to next song from relay_device."""
+ self.relays[Buttons.Next.value].set_no_for(WAIT_TIME)
+
+ def skip_previous(self):
+ """Skips to previous song from relay_device."""
+ self.relays[Buttons.Previous.value].set_no_for(WAIT_TIME)
+
+ def volume_up(self):
+ """Increases volume from relay_device."""
+ self.relays[Buttons.Volume_up.value].set_no_for(WAIT_TIME)
+
+ def volume_down(self):
+ """Decreases volume from relay_device."""
+ self.relays[Buttons.Volume_down.value].set_no_for(WAIT_TIME)
+
+ def initiate_call_from_hf(self):
+ """Initiate call from relay device."""
+ for i in range(0, 2):
+ self.relays[Buttons.Initiate_Call.value].set_no_for(WAIT_TIME)
+ return True
+
+ def accept_call(self):
+ """Accepts call from relay device."""
+ self.relays[Buttons.Answer_Call.value].set_no_for(WAIT_TIME)
+ return True
diff --git a/acts/framework/acts/controllers/relay_lib/logitech_headset.py b/acts/framework/acts/controllers/relay_lib/logitech_headset.py
new file mode 100644
index 0000000..fadbc2c
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/logitech_headset.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+#
+# Copyright 2018 - 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.
+"""
+Device Details:
+https://www.logitech.com/en-in/product/bluetooth-audio-adapter#specification-tabular
+"""
+import enum
+from acts.controllers.relay_lib.errors import RelayConfigError
+from acts.controllers.relay_lib.generic_relay_device import GenericRelayDevice
+from acts.controllers.relay_lib.helpers import validate_key
+
+PAIRING_MODE_WAIT_TIME = 5
+WAIT_TIME = 0.1
+MISSING_RELAY_MSG = 'Relay config for logitech Headset "%s" missing relay "%s".'
+
+
+class Buttons(enum.Enum):
+ Power = "Power"
+ Pair = "Pair"
+
+
+class LogitechAudioReceiver(GenericRelayDevice):
+ def __init__(self, config, relay_rig):
+ GenericRelayDevice.__init__(self, config, relay_rig)
+ self.mac_address = validate_key('mac_address', config, str,
+ 'LogitechAudioReceiver')
+ for button in Buttons:
+ self.ensure_config_contains_relay(button.value)
+
+ def setup(self):
+ GenericRelayDevice.setup(self)
+
+ def clean_up(self):
+ """Sets all relays to their default state (off)."""
+ GenericRelayDevice.clean_up(self)
+
+ def ensure_config_contains_relay(self, relay_name):
+ """
+ Throws an error if the relay does not exist.
+
+ Args:
+ relay_name:relay_name to be checked.
+ """
+ if relay_name not in self.relays:
+ raise RelayConfigError(MISSING_RELAY_MSG % (self.name, relay_name))
+
+ def power_on(self):
+ """Power on relay."""
+ self.relays[Buttons.Power.value].set_nc()
+
+ def pairing_mode(self):
+ """Sets relay in paring mode."""
+ self.relays[Buttons.Pair.value].set_nc()
diff --git a/acts/framework/acts/controllers/relay_lib/rdl_relay_board.py b/acts/framework/acts/controllers/relay_lib/rdl_relay_board.py
new file mode 100644
index 0000000..ad2acf0
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/rdl_relay_board.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+#
+# Copyright 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.
+
+from acts.controllers.relay_lib.relay import RelayState
+from acts.controllers.relay_lib.usb_relay_board_base import UsbRelayBoardBase
+from pylibftdi import BitBangDevice
+
+
+class RdlRelayBoard(UsbRelayBoardBase):
+ def set(self, relay_position, value):
+ """Returns the current status of the passed in relay.
+
+ Args:
+ relay_position: Relay position.
+ value: Turn_on or Turn_off the relay for the given relay_position.
+ """
+ with BitBangDevice(self.device) as bb:
+ if value == RelayState.NO:
+ bb.port |= self.address[relay_position]
+ else:
+ bb.port &= ~(self.address[relay_position])
+ self.status_dict[relay_position] = value
diff --git a/acts/framework/acts/controllers/relay_lib/relay_rig.py b/acts/framework/acts/controllers/relay_lib/relay_rig.py
index 3f4ca05..3f55940 100644
--- a/acts/framework/acts/controllers/relay_lib/relay_rig.py
+++ b/acts/framework/acts/controllers/relay_lib/relay_rig.py
@@ -15,9 +15,13 @@
# limitations under the License.
from acts.controllers.relay_lib.errors import RelayConfigError
from acts.controllers.relay_lib.helpers import validate_key
+from acts.controllers.relay_lib.rdl_relay_board import RdlRelayBoard
from acts.controllers.relay_lib.sain_smart_board import SainSmartBoard
+from acts.controllers.relay_lib.sain_smart_8_channel_usb_relay_board import SainSmart8ChannelUsbRelayBoard
from acts.controllers.relay_lib.generic_relay_device import GenericRelayDevice
from acts.controllers.relay_lib.fugu_remote import FuguRemote
+from acts.controllers.relay_lib.i6s_headset import I6sHeadset
+from acts.controllers.relay_lib.logitech_headset import LogitechAudioReceiver
from acts.controllers.relay_lib.sony_xb2_speaker import SonyXB2Speaker
from acts.controllers.relay_lib.ak_xb10_speaker import AkXB10Speaker
from acts.controllers.relay_lib.dongles import SingleButtonDongle
@@ -45,13 +49,20 @@
# A dict of lambdas that instantiate relay board upon invocation.
# The key is the class type name, the value is the lambda.
_board_constructors = {
- 'SainSmartBoard': lambda x: SainSmartBoard(x),
+ 'SainSmartBoard':
+ lambda x: SainSmartBoard(x),
+ 'RdlRelayBoard':
+ lambda x: RdlRelayBoard(x),
+ 'SainSmart8ChannelUsbRelayBoard':
+ lambda x: SainSmart8ChannelUsbRelayBoard(x),
}
# Similar to the dict above, except for devices.
_device_constructors = {
'GenericRelayDevice': lambda x, rig: GenericRelayDevice(x, rig),
'FuguRemote': lambda x, rig: FuguRemote(x, rig),
+ 'I6sHeadset': lambda x, rig: I6sHeadset(x, rig),
+ "LogitechAudioReceiver" :lambda x, rig: LogitechAudioReceiver(x, rig),
'SonyXB2Speaker': lambda x, rig: SonyXB2Speaker(x, rig),
'AkXB10Speaker': lambda x, rig: AkXB10Speaker(x, rig),
'SingleButtonDongle': lambda x, rig: SingleButtonDongle(x, rig),
diff --git a/acts/framework/acts/controllers/relay_lib/sain_smart_8_channel_usb_relay_board.py b/acts/framework/acts/controllers/relay_lib/sain_smart_8_channel_usb_relay_board.py
new file mode 100644
index 0000000..5cc5f6f
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/sain_smart_8_channel_usb_relay_board.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+#
+# Copyright 2018 - 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.
+
+from acts.controllers.relay_lib.relay import RelayState
+from acts.controllers.relay_lib.usb_relay_board_base import UsbRelayBoardBase
+from pylibftdi import BitBangDevice
+""" This library is to control the sainsmart board.
+
+Device:
+ https://www.sainsmart.com/products/8-channel-12v-usb-relay-module
+
+Additional setup steps:
+Change out pip/pip3 and python2.7/3.4 based on python version
+1. pip install pylibftdi
+2. pip install usblib1
+3. sudo apt-get install libftdi-dev
+4. Make this file /etc/udev/rules.d/99-libftdi.rules with root and add the lines below:
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", GROUP="dialout", MODE="0660"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", GROUP="dialout", MODE="0660"
+5. Connect USB relay to computer and power board with necessary connectors
+6. Verify device is found by: python -m pylibftdi.examples.list_devices
+6a. Example output: FTDI:FT245R USB FIFO:A9079L5D
+7. The FIFO value is going to be your device name in the config
+8. Your config should look something like this (note FIFO name is used here):
+
+{
+ "_description": "This is an example skeleton of a ficticious relay.",
+ "testbed": [{
+ "_description": "A testbed with one relay",
+ "name": "relay_test",
+ "RelayDevice": {
+ "boards": [{
+ "type": "SainSmart8ChannelUsbRelayBoard",
+ "name": "ttyUSB0",
+ "device": "A9079L5D"
+ }],
+ "devices": [{
+ "type": "SingleButtonDongle",
+ "name": "aukey",
+ "mac_address": "e9:08:ef:2b:47:a1",
+ "relays": {
+ "Action": "ttyUSB0/1"
+ }
+
+ }]
+ }
+ }],
+ "logpath": "/tmp/logs",
+ "testpaths": ["../tests"]
+}
+"""
+
+
+class SainSmart8ChannelUsbRelayBoard(UsbRelayBoardBase):
+ def set(self, relay_position, value):
+ """Returns the current status of the passed in relay.
+
+ Note that this board acts in reverse of normal relays.
+ EG: NO = NC and NC = NO
+
+ Args:
+ relay_position: Relay position.
+ value: Turn_on or Turn_off the relay for the given relay_position.
+ """
+ with BitBangDevice(self.device) as bb:
+ if value == RelayState.NO:
+ bb.port &= ~(self.address[relay_position])
+ else:
+ bb.port |= self.address[relay_position]
+ self.status_dict[relay_position] = value
diff --git a/acts/framework/acts/controllers/relay_lib/sain_smart_board.py b/acts/framework/acts/controllers/relay_lib/sain_smart_board.py
index 2d27816..a341c03 100644
--- a/acts/framework/acts/controllers/relay_lib/sain_smart_board.py
+++ b/acts/framework/acts/controllers/relay_lib/sain_smart_board.py
@@ -92,6 +92,13 @@
def _sync_status_dict(self):
"""Returns a dictionary of relays and there current state."""
result = self._load_page(self.HIDDEN_STATUS_PAGE)
+ if 'TUX' not in result:
+ raise RelayDeviceConnectionError(
+ 'Sainsmart board with URL %s has not completed initialization '
+ 'after its IP was set, and must be power-cycled to prevent '
+ 'random disconnections. After power-cycling, make sure %s/%s '
+ 'has TUX appear in its output.' %
+ (self.base_url, self.base_url, self.HIDDEN_STATUS_PAGE))
status_string = re.search(r'">([01]*)TUX', result).group(1)
self.status_dict = dict()
diff --git a/acts/framework/acts/controllers/relay_lib/usb_relay_board_base.py b/acts/framework/acts/controllers/relay_lib/usb_relay_board_base.py
new file mode 100644
index 0000000..bfecaf2
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/usb_relay_board_base.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+#
+# Copyright 2018 - 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.
+
+from acts.controllers.relay_lib.relay import RelayState
+from acts.controllers.relay_lib.relay_board import RelayBoard
+from pylibftdi import BitBangDevice
+
+
+class UsbRelayBoardBase(RelayBoard):
+
+ VALID_RELAY_POSITIONS = [1, 2, 3, 4, 5, 6, 7, 8]
+ NUM_RELAYS = 8
+
+ def __init__(self, config):
+ self.status_dict = dict()
+ self.device = config["device"]
+ super(UsbRelayBoardBase, self).__init__(config)
+ self.address = {
+ 1: 0x1,
+ 2: 0x2,
+ 3: 0x4,
+ 4: 0x8,
+ 5: 0x10,
+ 6: 0x20,
+ 7: 0x40,
+ 8: 0x80,
+ "select_all": 0xFF
+ }
+
+ def get_relay_position_list(self):
+ return self.VALID_RELAY_POSITIONS
+
+ def test_bit(self, int_type, offset):
+ """Function to get status for the given relay position.
+
+ Args:
+ int_type: Port value for given relay.
+ offset: offset for given Relay_position.
+
+ Returns:
+ returns current status for given relay_position.
+ """
+ mask = 1 << offset
+ return (int_type & mask)
+
+ def _get_relay_state(self, data, relay):
+ """Function to get status for the given relay position.
+
+ Args:
+ data: Port value for given relay.
+ relay: Relay_position.
+
+ Returns:
+ returns current status for given relay_position.
+ """
+ if relay == 1:
+ return self.test_bit(data, 1)
+ if relay == 2:
+ return self.test_bit(data, 3)
+ if relay == 3:
+ return self.test_bit(data, 5)
+ if relay == 4:
+ return self.test_bit(data, 7)
+ if relay == 5:
+ return self.test_bit(data, 2)
+ if relay == 6:
+ return self.test_bit(data, 4)
+ if relay == 7:
+ return self.test_bit(data, 6)
+ if relay == 8:
+ return self.test_bit(data, 8)
+
+ def get_relay_status(self, relay_position):
+ """Get relay status for the given relay position.
+
+ Args:
+ relay_position: Status for given Relay position.
+
+ Returns:
+ returns current status for given relay_position.
+ """
+ with BitBangDevice(self.device) as bb:
+ self.status_dict[relay_position] = self._get_relay_state(
+ bb.port, relay_position)
+ return self.status_dict[relay_position]
+
+ def set(self, relay_position, value):
+ """Returns the current status of the passed in relay.
+
+ Args:
+ relay_position: Relay position.
+ value: Turn_on or Turn_off the relay for the given relay_position.
+ """
+ raise NotImplementedError
diff --git a/acts/framework/acts/controllers/sniffer_lib/local/tcpdump.py b/acts/framework/acts/controllers/sniffer_lib/local/tcpdump.py
index a633c3d..a464e8e 100644
--- a/acts/framework/acts/controllers/sniffer_lib/local/tcpdump.py
+++ b/acts/framework/acts/controllers/sniffer_lib/local/tcpdump.py
@@ -18,6 +18,7 @@
from acts.controllers import sniffer
from acts.controllers.sniffer_lib.local import local_base
+
class Sniffer(local_base.SnifferLocalBase):
"""This class defines a sniffer which uses tcpdump as its back-end
"""
@@ -27,12 +28,13 @@
"""
self._executable_path = None
- super().__init__(config_path, logger, base_configs=base_configs)
+ super(local_base.SnifferLocalBase).__init__(
+ config_path, logger, base_configs=base_configs)
self._executable_path = shutil.which("tcpdump")
if self._executable_path is None:
raise sniffer.SnifferError(
- "Cannot find a path to the 'tcpdump' executable")
+ "Cannot find a path to the 'tcpdump' executable")
def get_descriptor(self):
"""See base class documentation
@@ -44,7 +46,9 @@
"""
return "tcpdump"
- def _get_command_line(self, additional_args=None, duration=None,
+ def _get_command_line(self,
+ additional_args=None,
+ duration=None,
packet_count=None):
cmd = "{} -i {} -w {}".format(self._executable_path, self._interface,
self._temp_capture_file_path)
diff --git a/acts/framework/acts/controllers/utils_lib/commands/shell.py b/acts/framework/acts/controllers/utils_lib/commands/shell.py
index eee65e1..ac232da 100644
--- a/acts/framework/acts/controllers/utils_lib/commands/shell.py
+++ b/acts/framework/acts/controllers/utils_lib/commands/shell.py
@@ -130,8 +130,8 @@
True if the string or pattern was found, False otherwise.
"""
try:
- self.run('grep %s %s' %
- (shellescape.quote(search_string), file_name))
+ self.run('grep %s %s' % (shellescape.quote(search_string),
+ file_name))
return True
except job.Error:
return False
@@ -195,7 +195,7 @@
that match the identifier until either all are dead or the timeout
finishes.
- Programs are guranteed to be killed after running this command.
+ Programs are guaranteed to be killed after running this command.
Args:
identifier: A string used to identify the program.
@@ -230,7 +230,7 @@
Args:
pid: The process id of the program to kill.
- sig: The singal to send.
+ sig: The signal to send.
Raises:
job.Error: Raised when the signal fail to reach
diff --git a/acts/framework/acts/controllers/utils_lib/ssh/connection.py b/acts/framework/acts/controllers/utils_lib/ssh/connection.py
index 9d238da..962c0db 100644
--- a/acts/framework/acts/controllers/utils_lib/ssh/connection.py
+++ b/acts/framework/acts/controllers/utils_lib/ssh/connection.py
@@ -28,11 +28,11 @@
class Error(Exception):
- """An error occured during an ssh operation."""
+ """An error occurred during an ssh operation."""
class CommandError(Exception):
- """An error occured with the command.
+ """An error occurred with the command.
Attributes:
result: The results of the ssh command that had the error.
@@ -46,8 +46,9 @@
self.result = result
def __str__(self):
- return 'cmd: %s\nstdout: %s\nstderr: %s' % (
- self.result.command, self.result.stdout, self.result.stderr)
+ return 'cmd: %s\nstdout: %s\nstderr: %s' % (self.result.command,
+ self.result.stdout,
+ self.result.stderr)
_Tunnel = collections.namedtuple('_Tunnel',
@@ -71,7 +72,7 @@
def __init__(self, settings):
"""
Args:
- settings: The ssh settings to use for this conneciton.
+ settings: The ssh settings to use for this connection.
formatter: The object that will handle formatting ssh command
for use with the background job.
"""
@@ -88,11 +89,12 @@
def setup_master_ssh(self, timeout_seconds=5):
"""Sets up the master ssh connection.
- Sets up the inital master ssh connection if it has not already been
+ Sets up the initial master ssh connection if it has not already been
started.
Args:
- timeout_seconds: The time to wait for the master ssh connection to be made.
+ timeout_seconds: The time to wait for the master ssh connection to
+ be made.
Raises:
Error: When setting up the master ssh connection fails.
@@ -159,7 +161,7 @@
ignore_status: bool True to ignore the exit code of the remote
subprocess. Note that if you do ignore status codes,
you should handle non-zero exit codes explicitly.
- env: dict enviroment variables to setup on the remote host.
+ env: dict environment variables to setup on the remote host.
io_encoding: str unicode encoding of command output.
Returns:
@@ -191,9 +193,8 @@
dns_retry_count = 2
while True:
- result = job.run(terminal_command,
- ignore_status=True,
- timeout=timeout)
+ result = job.run(
+ terminal_command, ignore_status=True, timeout=timeout)
output = result.stdout
# Check for a connected message to prevent false negatives.
@@ -261,7 +262,7 @@
Args:
command: The command to execute over ssh. Can be either a string
or a list.
- env: A dictonary of enviroment variables to setup on the remote
+ env: A dictonary of environment variables to setup on the remote
host.
Returns:
diff --git a/acts/framework/acts/keys.py b/acts/framework/acts/keys.py
index 695f8e4..083d44c 100644
--- a/acts/framework/acts/keys.py
+++ b/acts/framework/acts/keys.py
@@ -37,6 +37,7 @@
key_test_case_iterations = "test_case_iterations"
# Config names for controllers packaged in ACTS.
key_android_device = "AndroidDevice"
+ key_chameleon_device = "ChameleonDevice"
key_native_android_device = "NativeAndroidDevice"
key_relay_device = "RelayDevice"
key_access_point = "AccessPoint"
@@ -54,6 +55,7 @@
# module name of controllers packaged in ACTS.
m_key_monsoon = "monsoon"
m_key_android_device = "android_device"
+ m_key_chameleon_device = "chameleon_controller"
m_key_native_android_device = "native_android_device"
m_key_relay_device = "relay_device_controller"
m_key_access_point = "access_point"
@@ -68,9 +70,16 @@
# Controller names packaged with ACTS.
builtin_controller_names = [
- key_android_device, key_native_android_device, key_relay_device,
- key_access_point, key_attenuator, key_iperf_server, key_packet_sender,
- key_monsoon, key_sniffer
+ key_android_device,
+ key_native_android_device,
+ key_relay_device,
+ key_access_point,
+ key_attenuator,
+ key_iperf_server,
+ key_packet_sender,
+ key_monsoon,
+ key_sniffer,
+ key_chameleon_device,
]
# Keys that are file or folder paths.
diff --git a/acts/framework/acts/libs/ota/ota_runners/ota_runner.py b/acts/framework/acts/libs/ota/ota_runners/ota_runner.py
index 45bc4c6..7e1c4ca 100644
--- a/acts/framework/acts/libs/ota/ota_runners/ota_runner.py
+++ b/acts/framework/acts/libs/ota/ota_runners/ota_runner.py
@@ -50,12 +50,13 @@
self.android_device.root_adb()
log.info('Root complete.')
if self.android_device.skip_sl4a:
- self.android_device.log.info("Skipping SL4A install.")
+ self.android_device.log.info('Skipping SL4A install.')
else:
for _ in range(3):
- self.android_device.log.info("Re-installing SL4A.")
+ self.android_device.log.info('Re-installing SL4A from "%s".',
+ self.get_sl4a_apk())
self.android_device.adb.install(
- "-r -g %s" % self.get_sl4a_apk(), ignore_status=True)
+ '-r -g %s' % self.get_sl4a_apk(), ignore_status=True)
time.sleep(SL4A_SERVICE_SETUP_TIME)
if self.android_device.is_sl4a_installed():
break
diff --git a/acts/framework/acts/libs/proc/job.py b/acts/framework/acts/libs/proc/job.py
index 84c4993..472e86b 100644
--- a/acts/framework/acts/libs/proc/job.py
+++ b/acts/framework/acts/libs/proc/job.py
@@ -192,10 +192,13 @@
A subprocess.Popen object representing the created subprocess.
"""
- return subprocess.Popen(
+ proc = subprocess.Popen(
command,
env=env,
- close_fds=True,
+ preexec_fn=os.setpgrp,
shell=not isinstance(command, list),
stdout=DEVNULL,
stderr=subprocess.STDOUT)
+ logging.debug("command %s started with pid %s", command, proc.pid)
+ return proc
+
diff --git a/acts/framework/acts/records.py b/acts/framework/acts/records.py
index a36ccb3..7cf94d8 100644
--- a/acts/framework/acts/records.py
+++ b/acts/framework/acts/records.py
@@ -175,10 +175,10 @@
return "%s %s %s" % (t, self.test_name, self.result)
def to_dict(self):
- """Gets a dictionary representating the content of this class.
+ """Gets a dictionary representing the content of this class.
Returns:
- A dictionary representating the content of this class.
+ A dictionary representing the content of this class.
"""
d = {}
d[TestResultEnums.RECORD_NAME] = self.test_name
diff --git a/acts/framework/acts/test_runner.py b/acts/framework/acts/test_runner.py
index 70b3400..fdb9099 100644
--- a/acts/framework/acts/test_runner.py
+++ b/acts/framework/acts/test_runner.py
@@ -18,10 +18,10 @@
standard_library.install_aliases()
-import argparse
import copy
import importlib
import inspect
+import fnmatch
import logging
import os
import pkgutil
@@ -36,81 +36,10 @@
from acts import utils
-def main():
- """Execute the test class in a test module.
-
- This is the default entry point for running a test script file directly.
- In this case, only one test class in a test script is allowed.
-
- To make your test script executable, add the following to your file:
-
- from acts import test_runner
- ...
- if __name__ == "__main__":
- test_runner.main()
-
- If you want to implement your own cli entry point, you could use function
- execute_one_test_class(test_class, test_config, test_identifier)
- """
- # Parse cli args.
- parser = argparse.ArgumentParser(description="ACTS Test Executable.")
- parser.add_argument(
- '-c',
- '--config',
- nargs=1,
- type=str,
- required=True,
- metavar="<PATH>",
- help="Path to the test configuration file.")
- parser.add_argument(
- '--test_case',
- nargs='+',
- type=str,
- metavar="[test_a test_b...]",
- help="A list of test case names in the test script.")
- parser.add_argument(
- '-tb',
- '--test_bed',
- nargs='+',
- type=str,
- metavar="[<TEST BED NAME1> <TEST BED NAME2> ...]",
- help="Specify which test beds to run tests on.")
- args = parser.parse_args(sys.argv[1:])
- # Load test config file.
- test_configs = config_parser.load_test_config_file(args.config[0],
- args.test_bed)
- # Find the test class in the test script.
- test_class = _find_test_class()
- test_class_name = test_class.__name__
- # Parse test case specifiers if exist.
- test_case_names = None
- if args.test_case:
- test_case_names = args.test_case
- test_identifier = [(test_class_name, test_case_names)]
- # Execute the test class with configs.
- ok = True
- for config in test_configs:
- try:
- result = execute_one_test_class(test_class, config,
- test_identifier)
- if not result:
- logging.error(
- 'Results for config %s have returned empty.' % config)
- ok = result and ok
- except signals.TestAbortAll:
- pass
- except:
- logging.exception("Error occurred when executing test bed %s",
- config[keys.Config.key_testbed.value])
- ok = False
- if not ok:
- sys.exit(1)
-
-
def _find_test_class():
"""Finds the test class in a test script.
- Walk through module memebers and find the subclass of BaseTestClass. Only
+ Walk through module members and find the subclass of BaseTestClass. Only
one subclass is allowed in a test script.
Returns:
@@ -133,7 +62,7 @@
"""Executes one specific test class.
You could call this function in your own cli test entry point if you choose
- not to use act.py or test_runner.main.
+ not to use act.py.
Args:
test_class: A subclass of acts.base_test.BaseTestClass that has the test
@@ -178,7 +107,8 @@
self.controller_registry: A dictionary that holds the controller
objects used in a test run.
self.test_classes: A dictionary where we can look up the test classes
- by name to instantiate.
+ by name to instantiate. Supports unix shell style
+ wildcards.
self.run_list: A list of tuples specifying what tests to run.
self.results: The test result object used to record the results of
this test run.
@@ -537,9 +467,8 @@
ValueError is raised if the requested test class could not be found
in the test_paths directories.
"""
- try:
- test_cls = self.test_classes[test_cls_name]
- except KeyError:
+ matches = fnmatch.filter(self.test_classes.keys(), test_cls_name)
+ if not matches:
self.log.info(
"Cannot find test class %s or classes matching pattern, "
"skipping for now." % test_cls_name)
@@ -547,22 +476,29 @@
record.test_skip(signals.TestSkip("Test class does not exist."))
self.results.add_record(record)
return
- if self.test_configs.get(keys.Config.key_random.value) or (
- "Preflight" in test_cls_name) or "Postflight" in test_cls_name:
- test_case_iterations = 1
- else:
- test_case_iterations = self.test_configs.get(
- keys.Config.key_test_case_iterations.value, 1)
+ if matches != [test_cls_name]:
+ self.log.info("Found classes matching pattern %s: %s",
+ test_cls_name, matches)
- with test_cls(self.test_run_info) as test_cls_instance:
- try:
- cls_result = test_cls_instance.run(test_cases,
- test_case_iterations)
- self.results += cls_result
- self._write_results_json_str()
- except signals.TestAbortAll as e:
- self.results += e.results
- raise e
+ for test_cls_name_match in matches:
+ test_cls = self.test_classes[test_cls_name_match]
+ if self.test_configs.get(keys.Config.key_random.value) or (
+ "Preflight" in test_cls_name_match) or (
+ "Postflight" in test_cls_name_match):
+ test_case_iterations = 1
+ else:
+ test_case_iterations = self.test_configs.get(
+ keys.Config.key_test_case_iterations.value, 1)
+
+ with test_cls(self.test_run_info) as test_cls_instance:
+ try:
+ cls_result = test_cls_instance.run(test_cases,
+ test_case_iterations)
+ self.results += cls_result
+ self._write_results_json_str()
+ except signals.TestAbortAll as e:
+ self.results += e.results
+ raise e
def run(self, test_class=None):
"""Executes test cases.
@@ -593,6 +529,7 @@
for test_cls_name, test_case_names in self.run_list:
if not self.running:
break
+
if test_case_names:
self.log.debug("Executing test cases %s in test class %s.",
test_case_names, test_cls_name)
diff --git a/acts/framework/acts/test_utils/audio_analysis_lib/__init__.py b/acts/framework/acts/test_utils/audio_analysis_lib/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/acts/framework/acts/test_utils/audio_analysis_lib/__init__.py
diff --git a/acts/framework/acts/test_utils/audio_analysis_lib/audio_analysis.py b/acts/framework/acts/test_utils/audio_analysis_lib/audio_analysis.py
new file mode 100644
index 0000000..8450601
--- /dev/null
+++ b/acts/framework/acts/test_utils/audio_analysis_lib/audio_analysis.py
@@ -0,0 +1,436 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2017 - 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.
+"""This module provides utilities to do audio data analysis."""
+
+import logging
+import numpy
+import operator
+
+# The default block size of pattern matching.
+ANOMALY_DETECTION_BLOCK_SIZE = 120
+
+# Only peaks with coefficient greater than 0.01 of the first peak should be
+# considered. Note that this correspond to -40dB in the spectrum.
+DEFAULT_MIN_PEAK_RATIO = 0.01
+
+# The minimum RMS value of meaningful audio data.
+MEANINGFUL_RMS_THRESHOLD = 0.001
+
+# The minimal signal norm value.
+_MINIMUM_SIGNAL_NORM = 0.001
+
+# The default pattern mathing threshold. By experiment, this threshold
+# can tolerate normal noise of 0.3 amplitude when sine wave signal
+# amplitude is 1.
+PATTERN_MATCHING_THRESHOLD = 0.85
+
+# Window size for peak detection.
+PEAK_WINDOW_SIZE_HZ = 20
+
+
+class RMSTooSmallError(Exception):
+ """Error when signal RMS is too small."""
+ pass
+
+
+class EmptyDataError(Exception):
+ """Error when signal is empty."""
+ pass
+
+
+def normalize_signal(signal, saturate_value):
+ """Normalizes the signal with respect to the saturate value.
+
+ Args:
+ signal: A list for one-channel PCM data.
+ saturate_value: The maximum value that the PCM data might be.
+
+ Returns:
+ A numpy array containing normalized signal. The normalized signal has
+ value -1 and 1 when it saturates.
+
+ """
+ signal = numpy.array(signal)
+ return signal / float(saturate_value)
+
+
+def spectral_analysis(signal,
+ rate,
+ min_peak_ratio=DEFAULT_MIN_PEAK_RATIO,
+ peak_window_size_hz=PEAK_WINDOW_SIZE_HZ):
+ """Gets the dominant frequencies by spectral analysis.
+
+ Args:
+ signal: A list of numbers for one-channel PCM data. This should be
+ normalized to [-1, 1] so the function can check if signal RMS
+ is too small to be meaningful.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+ min_peak_ratio: The minimum peak_i/peak_0 ratio such that the
+ peaks other than the greatest one should be
+ considered.
+ This is to ignore peaks that are too small compared
+ to the first peak peak_0.
+ peak_window_size_hz: The window size in Hz to find the peaks.
+ The minimum differences between found peaks will
+ be half of this value.
+
+ Returns:
+ A list of tuples:
+ [(peak_frequency_0, peak_coefficient_0),
+ (peak_frequency_1, peak_coefficient_1),
+ (peak_frequency_2, peak_coefficient_2), ...]
+ where the tuples are sorted by coefficients. The last
+ peak_coefficient will be no less than peak_coefficient *
+ min_peak_ratio. If RMS is less than MEANINGFUL_RMS_THRESHOLD,
+ returns [(0, 0)].
+
+ """
+ # Checks the signal is meaningful.
+ if len(signal) == 0:
+ raise EmptyDataError('Signal data is empty')
+
+ signal_rms = numpy.linalg.norm(signal) / numpy.sqrt(len(signal))
+ logging.debug('signal RMS = %s', signal_rms)
+
+ # If RMS is too small, set dominant frequency and coefficient to 0.
+ if signal_rms < MEANINGFUL_RMS_THRESHOLD:
+ logging.warning(
+ 'RMS %s is too small to be meaningful. Set frequency to 0.',
+ signal_rms)
+ return [(0, 0)]
+
+ logging.debug('Doing spectral analysis ...')
+
+ # First, pass signal through a window function to mitigate spectral leakage.
+ y_conv_w = signal * numpy.hanning(len(signal))
+
+ length = len(y_conv_w)
+
+ # x_f is the frequency in Hz, y_f is the transformed coefficient.
+ x_f = _rfft_freq(length, rate)
+ y_f = 2.0 / length * numpy.fft.rfft(y_conv_w)
+
+ # y_f is complex so consider its absolute value for magnitude.
+ abs_y_f = numpy.abs(y_f)
+ threshold = max(abs_y_f) * min_peak_ratio
+
+ # Suppresses all coefficients that are below threshold.
+ for i in range(len(abs_y_f)):
+ if abs_y_f[i] < threshold:
+ abs_y_f[i] = 0
+
+ # Gets the peak detection window size in indice.
+ # x_f[1] is the frequency difference per index.
+ peak_window_size = int(peak_window_size_hz / x_f[1])
+
+ # Detects peaks.
+ peaks = peak_detection(abs_y_f, peak_window_size)
+
+ # Transform back the peak location from index to frequency.
+ results = []
+ for index, value in peaks:
+ results.append((x_f[int(index)], value))
+ return results
+
+
+def _rfft_freq(length, rate):
+ """Gets the frequency at each index of real FFT.
+
+ Args:
+ length: The window length of FFT.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+
+ Returns:
+ A numpy array containing frequency corresponding to numpy.fft.rfft
+ result at each index.
+
+ """
+ # The difference in Hz between each index.
+ val = rate / float(length)
+ # Only care half of frequencies for FFT on real signal.
+ result_length = length // 2 + 1
+ return numpy.linspace(0, (result_length - 1) * val, result_length)
+
+
+def peak_detection(array, window_size):
+ """Detects peaks in an array.
+
+ A point (i, array[i]) is a peak if array[i] is the maximum among
+ array[i - half_window_size] to array[i + half_window_size].
+ If array[i - half_window_size] to array[i + half_window_size] are all equal,
+ then there is no peak in this window.
+ Note that we only consider peak with value greater than 0.
+
+ Args:
+ array: The input array to detect peaks in. Array is a list of
+ absolute values of the magnitude of transformed coefficient.
+
+ window_size: The window to detect peaks.
+
+ Returns:
+ A list of tuples:
+ [(peak_index_1, peak_value_1), (peak_index_2, peak_value_2), ...]
+ where the tuples are sorted by peak values.
+
+ """
+ half_window_size = window_size / 2
+ length = len(array)
+
+ def mid_is_peak(array, mid, left, right):
+ """Checks if value at mid is the largest among left to right in array.
+
+ Args:
+ array: A list of numbers.
+ mid: The mid index.
+ left: The left index.
+ rigth: The right index.
+
+ Returns:
+ A tuple (is_peak, next_candidate)
+ is_peak is True if array[index] is the maximum among numbers
+ in array between index [left, right] inclusively.
+ next_candidate is the index of next candidate for peak if
+ is_peak is False. It is the index of maximum value in
+ [mid + 1, right]. If is_peak is True, next_candidate is
+ right + 1.
+
+ """
+ value_mid = array[int(mid)]
+ is_peak = True
+ next_peak_candidate_index = None
+
+ # Check the left half window.
+ for index in range(int(left), int(mid)):
+ if array[index] >= value_mid:
+ is_peak = False
+ break
+
+ # Mid is at the end of array.
+ if mid == right:
+ return is_peak, right + 1
+
+ # Check the right half window and also record next candidate.
+ # Favor the larger index for next_peak_candidate_index.
+ for index in range(int(right), int(mid), -1):
+ if (next_peak_candidate_index is None or
+ array[index] > array[next_peak_candidate_index]):
+ next_peak_candidate_index = index
+
+ if array[next_peak_candidate_index] >= value_mid:
+ is_peak = False
+
+ if is_peak:
+ next_peak_candidate_index = right + 1
+
+ return is_peak, next_peak_candidate_index
+
+ results = []
+ mid = 0
+ next_candidate_idx = None
+ while mid < length:
+ left = max(0, mid - half_window_size)
+ right = min(length - 1, mid + half_window_size)
+
+ # Only consider value greater than 0.
+ if array[int(mid)] == 0:
+ mid = mid + 1
+ continue
+
+ is_peak, next_candidate_idx = mid_is_peak(array, mid, left, right)
+
+ if is_peak:
+ results.append((mid, array[int(mid)]))
+
+ # Use the next candidate found in [mid + 1, right], or right + 1.
+ mid = next_candidate_idx
+
+ # Sort the peaks by values.
+ return sorted(results, key=lambda x: x[1], reverse=True)
+
+
+def anomaly_detection(signal,
+ rate,
+ freq,
+ block_size=ANOMALY_DETECTION_BLOCK_SIZE,
+ threshold=PATTERN_MATCHING_THRESHOLD):
+ """Detects anomaly in a sine wave signal.
+
+ This method detects anomaly in a sine wave signal by matching
+ patterns of each block.
+ For each moving window of block in the test signal, checks if there
+ is any block in golden signal that is similar to this block of test signal.
+ If there is such a block in golden signal, then this block of test
+ signal is matched and there is no anomaly in this block of test signal.
+ If there is any block in test signal that is not matched, then this block
+ covers an anomaly.
+ The block of test signal starts from index 0, and proceeds in steps of
+ half block size. The overlapping of test signal blocks makes sure there must
+ be at least one block covering the transition from sine wave to anomaly.
+
+ Args:
+ signal: A 1-D array-like object for 1-channel PCM data.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+ freq: The expected frequency of signal.
+ block_size: The block size in samples to detect anomaly.
+ threshold: The threshold of correlation index to be judge as matched.
+
+ Returns:
+ A list containing detected anomaly time in seconds.
+
+ """
+ if len(signal) == 0:
+ raise EmptyDataError('Signal data is empty')
+
+ golden_y = _generate_golden_pattern(rate, freq, block_size)
+
+ results = []
+
+ for start in range(0, len(signal), int(block_size / 2)):
+ end = start + block_size
+ test_signal = signal[start:end]
+ matched = _moving_pattern_matching(golden_y, test_signal, threshold)
+ if not matched:
+ results.append(start)
+
+ results = [float(x) / rate for x in results]
+
+ return results
+
+
+def _generate_golden_pattern(rate, freq, block_size):
+ """Generates a golden pattern of certain frequency.
+
+ The golden pattern must cover all the possibilities of waveforms in a
+ block. So, we need a golden pattern covering 1 period + 1 block size,
+ such that the test block can start anywhere in a period, and extends
+ a block size.
+
+ |period |1 bk|
+ | | |
+ . . . .
+ . . . .
+ . . .
+
+ Args:
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+ freq: The frequency of golden pattern.
+ block_size: The block size in samples to detect anomaly.
+
+ Returns:
+ A 1-D array for golden pattern.
+
+ """
+ samples_in_a_period = int(rate / freq) + 1
+ samples_in_golden_pattern = samples_in_a_period + block_size
+ golden_x = numpy.linspace(0.0, (samples_in_golden_pattern - 1) * 1.0 /
+ rate, samples_in_golden_pattern)
+ golden_y = numpy.sin(freq * 2.0 * numpy.pi * golden_x)
+ return golden_y
+
+
+def _moving_pattern_matching(golden_signal, test_signal, threshold):
+ """Checks if test_signal is similar to any block of golden_signal.
+
+ Compares test signal with each block of golden signal by correlation
+ index. If there is any block of golden signal that is similar to
+ test signal, then it is matched.
+
+ Args:
+ golden_signal: A 1-D array for golden signal.
+ test_signal: A 1-D array for test signal.
+ threshold: The threshold of correlation index to be judge as matched.
+
+ Returns:
+ True if there is a match. False otherwise.
+
+ ValueError: if test signal is longer than golden signal.
+
+ """
+ if len(golden_signal) < len(test_signal):
+ raise ValueError('Test signal is longer than golden signal')
+
+ block_length = len(test_signal)
+ number_of_movings = len(golden_signal) - block_length + 1
+ correlation_indices = []
+ for moving_index in range(number_of_movings):
+ # Cuts one block of golden signal from start index.
+ # The block length is the same as test signal.
+ start = moving_index
+ end = start + block_length
+ golden_signal_block = golden_signal[start:end]
+ try:
+ correlation_index = _get_correlation_index(golden_signal_block,
+ test_signal)
+ except TestSignalNormTooSmallError:
+ logging.info(
+ 'Caught one block of test signal that has no meaningful norm')
+ return False
+ correlation_indices.append(correlation_index)
+
+ # Checks if the maximum correlation index is high enough.
+ max_corr = max(correlation_indices)
+ if max_corr < threshold:
+ logging.debug('Got one unmatched block with max_corr: %s', max_corr)
+ return False
+ return True
+
+
+class GoldenSignalNormTooSmallError(Exception):
+ """Exception when golden signal norm is too small."""
+ pass
+
+
+class TestSignalNormTooSmallError(Exception):
+ """Exception when test signal norm is too small."""
+ pass
+
+
+def _get_correlation_index(golden_signal, test_signal):
+ """Computes correlation index of two signal of same length.
+
+ Args:
+ golden_signal: An 1-D array-like object.
+ test_signal: An 1-D array-like object.
+
+ Raises:
+ ValueError: if two signal have different lengths.
+ GoldenSignalNormTooSmallError: if golden signal norm is too small
+ TestSignalNormTooSmallError: if test signal norm is too small.
+
+ Returns:
+ The correlation index.
+ """
+ if len(golden_signal) != len(test_signal):
+ raise ValueError('Only accepts signal of same length: %s, %s' %
+ (len(golden_signal), len(test_signal)))
+
+ norm_golden = numpy.linalg.norm(golden_signal)
+ norm_test = numpy.linalg.norm(test_signal)
+ if norm_golden <= _MINIMUM_SIGNAL_NORM:
+ raise GoldenSignalNormTooSmallError(
+ 'No meaningful data as norm is too small.')
+ if norm_test <= _MINIMUM_SIGNAL_NORM:
+ raise TestSignalNormTooSmallError(
+ 'No meaningful data as norm is too small.')
+
+ # The 'valid' cross correlation result of two signals of same length will
+ # contain only one number.
+ correlation = numpy.correlate(golden_signal, test_signal, 'valid')[0]
+ return correlation / (norm_golden * norm_test)
diff --git a/acts/framework/acts/test_utils/audio_analysis_lib/audio_data.py b/acts/framework/acts/test_utils/audio_analysis_lib/audio_data.py
new file mode 100644
index 0000000..b123025
--- /dev/null
+++ b/acts/framework/acts/test_utils/audio_analysis_lib/audio_data.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2017 - 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.
+"""This module provides abstraction of audio data."""
+
+import contextlib
+import copy
+import numpy
+import struct
+from io import StringIO
+"""The dict containing information on how to parse sample from raw data.
+
+Keys: The sample format as in aplay command.
+Values: A dict containing:
+ message: Human-readable sample format.
+ dtype_str: Data type used in numpy dtype. Check
+ https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html
+ for supported data type.
+ size_bytes: Number of bytes for one sample.
+"""
+SAMPLE_FORMATS = dict(
+ S32_LE=dict(
+ message='Signed 32-bit integer, little-endian',
+ dtype_str='<i',
+ size_bytes=4),
+ S16_LE=dict(
+ message='Signed 16-bit integer, little-endian',
+ dtype_str='<i',
+ size_bytes=2))
+
+
+def get_maximum_value_from_sample_format(sample_format):
+ """Gets the maximum value from sample format.
+
+ Args:
+ sample_format: A key in SAMPLE_FORMAT.
+
+ Returns:The maximum value the sample can hold + 1.
+
+ """
+ size_bits = SAMPLE_FORMATS[sample_format]['size_bytes'] * 8
+ return 1 << (size_bits - 1)
+
+
+class AudioRawDataError(Exception):
+ """Error in AudioRawData."""
+ pass
+
+
+class AudioRawData(object):
+ """The abstraction of audio raw data.
+
+ @property channel: The number of channels.
+ @property channel_data: A list of lists containing samples in each channel.
+ E.g., The third sample in the second channel is
+ channel_data[1][2].
+ @property sample_format: The sample format which should be one of the keys
+ in audio_data.SAMPLE_FORMATS.
+ """
+
+ def __init__(self, binary, channel, sample_format):
+ """Initializes an AudioRawData.
+
+ Args:
+ binary: A string containing binary data. If binary is not None,
+ The samples in binary will be parsed and be filled into
+ channel_data.
+ channel: The number of channels.
+ sample_format: One of the keys in audio_data.SAMPLE_FORMATS.
+ """
+ self.channel = channel
+ self.channel_data = [[] for _ in range(self.channel)]
+ self.sample_format = sample_format
+ if binary:
+ self.read_binary(binary)
+
+ def read_binary(self, binary):
+ """Reads samples from binary and fills channel_data.
+
+ Reads samples of fixed width from binary string into a numpy array
+ and shapes them into each channel.
+
+ Args:
+ binary: A string containing binary data.
+ """
+ sample_format_dict = SAMPLE_FORMATS[self.sample_format]
+
+ # The data type used in numpy fromstring function. For example,
+ # <i4 for 32-bit signed int.
+ np_dtype = '%s%d' % (sample_format_dict['dtype_str'],
+ sample_format_dict['size_bytes'])
+
+ # Reads data from a string into 1-D array.
+ np_array = numpy.fromstring(binary, dtype=np_dtype)
+
+ n_frames = len(np_array) / self.channel
+ # Reshape np_array into an array of shape (n_frames, channel).
+ np_array = np_array.reshape(int(n_frames), self.channel)
+ # Transpose np_arrya so it becomes of shape (channel, n_frames).
+ self.channel_data = np_array.transpose()
diff --git a/acts/framework/acts/test_utils/audio_analysis_lib/audio_quality_measurement.py b/acts/framework/acts/test_utils/audio_analysis_lib/audio_quality_measurement.py
new file mode 100644
index 0000000..4087fe4
--- /dev/null
+++ b/acts/framework/acts/test_utils/audio_analysis_lib/audio_quality_measurement.py
@@ -0,0 +1,929 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2017 - 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.
+"""This module provides utilities to detect some artifacts and measure the
+ quality of audio."""
+
+import logging
+import math
+import numpy
+
+import acts.test_utils.audio_analysis_lib.audio_analysis as audio_analysis
+
+# The input signal should be one sine wave with fixed frequency which
+# can have silence before and/or after sine wave.
+# For example:
+# silence sine wave silence
+# -----------|VVVVVVVVVVVVV|-----------
+# (a) (b) (c)
+# This module detects these artifacts:
+# 1. Detect noise in (a) and (c).
+# 2. Detect delay in (b).
+# 3. Detect burst in (b).
+# Assume the transitions between (a)(b) and (b)(c) are smooth and
+# amplitude increases/decreases linearly.
+# This module will detect artifacts in the sine wave.
+# This module also estimates the equivalent noise level by teager operator.
+# This module also detects volume changes in the sine wave. However, volume
+# changes may be affected by delay or burst.
+# Some artifacts may cause each other.
+
+# In this module, amplitude and frequency are derived from Hilbert transform.
+# Both amplitude and frequency are a function of time.
+
+# To detect each artifact, each point will be compared with
+# average amplitude of its block. The block size will be 1.5 ms.
+# Using average amplitude can mitigate the error caused by
+# Hilbert transform and noise.
+# In some case, for more accuracy, the block size may be modified
+# to other values.
+DEFAULT_BLOCK_SIZE_SECS = 0.0015
+
+# If the difference between average frequency of this block and
+# dominant frequency of full signal is less than 0.5 times of
+# dominant frequency, this block is considered to be within the
+# sine wave. In most cases, if there is no sine wave(only noise),
+# average frequency will be much greater than 5 times of
+# dominant frequency.
+# Also, for delay during playback, the frequency will be about 0
+# in perfect situation or much greater than 5 times of dominant
+# frequency if it's noised.
+DEFAULT_FREQUENCY_ERROR = 0.5
+
+# If the amplitude of some sample is less than 0.6 times of the
+# average amplitude of its left/right block, it will be considered
+# as a delay during playing.
+DEFAULT_DELAY_AMPLITUDE_THRESHOLD = 0.6
+
+# If the average amplitude of the block before or after playing
+# is more than 0.5 times to the average amplitude of the wave,
+# it will be considered as a noise artifact.
+DEFAULT_NOISE_AMPLITUDE_THRESHOLD = 0.5
+
+# In the sine wave, if the amplitude is more than 1.4 times of
+# its left side and its right side, it will be considered as
+# a burst.
+DEFAULT_BURST_AMPLITUDE_THRESHOLD = 1.4
+
+# When detecting burst, if the amplitude is lower than 0.5 times
+# average amplitude, we ignore it.
+DEFAULT_BURST_TOO_SMALL = 0.5
+
+# For a signal which is the combination of sine wave with fixed frequency f and
+# amplitude 1 and standard noise with amplitude k, the average teager value is
+# nearly linear to the noise level k.
+# Given frequency f, we simulate a sine wave with default noise level and
+# calculate its average teager value. Then, we can estimate the equivalent
+# noise level of input signal by the average teager value of input signal.
+DEFAULT_STANDARD_NOISE = 0.005
+
+# For delay, burst, volume increasing/decreasing, if two delay(
+# burst, volume increasing/decreasing) happen within
+# DEFAULT_SAME_EVENT_SECS seconds, we consider they are the
+# same event.
+DEFAULT_SAME_EVENT_SECS = 0.001
+
+# When detecting increasing/decreasing volume of signal, if the amplitude
+# is lower than 0.1 times average amplitude, we ignore it.
+DEFAULT_VOLUME_CHANGE_TOO_SMALL = 0.1
+
+# If average amplitude of right block is less/more than average
+# amplitude of left block times DEFAULT_VOLUME_CHANGE_AMPLITUDE, it will be
+# considered as decreasing/increasing on volume.
+DEFAULT_VOLUME_CHANGE_AMPLITUDE = 0.1
+
+# If the increasing/decreasing volume event is too close to the start or the end
+# of sine wave, we consider its volume change as part of rising/falling phase in
+# the start/end.
+NEAR_START_OR_END_SECS = 0.01
+
+# After applying Hilbert transform, the resulting amplitude and frequency may be
+# extremely large in the start and/or the end part. Thus, we will append zeros
+# before and after the whole wave for 0.1 secs.
+APPEND_ZEROS_SECS = 0.1
+
+# If the noise event is too close to the start or the end of the data, we
+# consider its noise as part of artifacts caused by edge effect of Hilbert
+# transform.
+# For example, originally, the data duration is 10 seconds.
+# We append 0.1 seconds of zeros in the beginning and the end of the data, so
+# the data becomes 10.2 seocnds long.
+# Then, we apply Hilbert transform to 10.2 seconds of data.
+# Near 0.1 seconds and 10.1 seconds, there will be edge effect of Hilbert
+# transform. We do not want these be treated as noise.
+# If NEAR_DATA_START_OR_END_SECS is set to 0.01, then the noise happened
+# at [0, 0.11] and [10.09, 10.1] will be ignored.
+NEAR_DATA_START_OR_END_SECS = 0.01
+
+# If the noise event is too close to the start or the end of the sine wave in
+# the data, we consider its noise as part of artifacts caused by edge effect of
+# Hilbert transform.
+# A |-------------|vvvvvvvvvvvvvvvvvvvvvvv|-------------|
+# B |ooooooooo| d | | d |ooooooooo|
+#
+# A is full signal. It contains a sine wave and silence before and after sine
+# wave.
+# In B, |oooo| shows the parts that we are going to check for noise before/after
+# sine wave. | d | is determined by NEAR_SINE_START_OR_END_SECS.
+NEAR_SINE_START_OR_END_SECS = 0.01
+
+
+class SineWaveNotFound(Exception):
+ """Error when there's no sine wave found in the signal"""
+ pass
+
+
+def hilbert(x):
+ """Hilbert transform copied from scipy.
+
+ More information can be found here:
+ http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.hilbert.html
+
+ Args:
+ x: Real signal data to transform.
+
+ Returns:
+ Analytic signal of x, we can further extract amplitude and
+ frequency from it.
+
+ """
+ x = numpy.asarray(x)
+ if numpy.iscomplexobj(x):
+ raise ValueError("x must be real.")
+ axis = -1
+ N = x.shape[axis]
+ if N <= 0:
+ raise ValueError("N must be positive.")
+
+ Xf = numpy.fft.fft(x, N, axis=axis)
+ h = numpy.zeros(N)
+ if N % 2 == 0:
+ h[0] = h[N // 2] = 1
+ h[1:N // 2] = 2
+ else:
+ h[0] = 1
+ h[1:(N + 1) // 2] = 2
+
+ if len(x.shape) > 1:
+ ind = [newaxis] * x.ndim
+ ind[axis] = slice(None)
+ h = h[ind]
+ x = numpy.fft.ifft(Xf * h, axis=axis)
+ return x
+
+
+def noised_sine_wave(frequency, rate, noise_level):
+ """Generates a sine wave of 2 second with specified noise level.
+
+ Args:
+ frequency: Frequency of sine wave.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+ noise_level: Required noise level.
+
+ Returns:
+ A sine wave with specified noise level.
+
+ """
+ wave = []
+ for index in range(0, rate * 2):
+ sample = 2.0 * math.pi * frequency * float(index) / float(rate)
+ sine_wave = math.sin(sample)
+ noise = noise_level * numpy.random.standard_normal()
+ wave.append(sine_wave + noise)
+ return wave
+
+
+def average_teager_value(wave, amplitude):
+ """Computes the normalized average teager value.
+
+ After averaging the teager value, we will normalize the value by
+ dividing square of amplitude.
+
+ Args:
+ wave: Wave to apply teager operator.
+ amplitude: Average amplitude of given wave.
+
+ Returns:
+ Average teager value.
+
+ """
+ teager_value, length = 0, len(wave)
+ for i in range(1, length - 1):
+ ith_teager_value = abs(wave[i] * wave[i] - wave[i - 1] * wave[i + 1])
+ ith_teager_value *= max(1, abs(wave[i]))
+ teager_value += ith_teager_value
+ teager_value = (float(teager_value) / length) / (amplitude**2)
+ return teager_value
+
+
+def noise_level(amplitude, frequency, rate, teager_value_of_input):
+ """Computes the noise level compared with standard_noise.
+
+ For a signal which is the combination of sine wave with fixed frequency f
+ and amplitude 1 and standard noise with amplitude k, the average teager
+ value is nearly linear to the noise level k.
+ Thus, we can compute the average teager value of a sine wave with
+ standard_noise. Then, we can estimate the noise level of given input.
+
+ Args:
+ amplitude: Amplitude of input audio.
+ frequency: Dominant frequency of input audio.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+ teager_value_of_input: Average teager value of input audio.
+
+ Returns:
+ A float value denotes the audio is equivalent to have how many times of
+ noise compared with its amplitude.For example, 0.02 denotes that the
+ wave has a noise which has standard distribution with standard
+ deviation being 0.02 times the amplitude of the wave.
+
+ """
+ standard_noise = DEFAULT_STANDARD_NOISE
+
+ # Generates the standard sine wave with stdandard_noise level of noise.
+ standard_wave = noised_sine_wave(frequency, rate, standard_noise)
+
+ # Calculates the average teager value.
+ teager_value_of_std_wave = average_teager_value(standard_wave, amplitude)
+
+ return (teager_value_of_input / teager_value_of_std_wave) * standard_noise
+
+
+def error(f1, f2):
+ """Calculates the relative error between f1 and f2.
+
+ Args:
+ f1: Exact value.
+ f2: Test value.
+
+ Returns:
+ Relative error between f1 and f2.
+
+ """
+ return abs(float(f1) - float(f2)) / float(f1)
+
+
+def hilbert_analysis(signal, rate, block_size):
+ """Finds amplitude and frequency of each time of signal by Hilbert transform.
+
+ Args:
+ signal: The wave to analyze.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+ block_size: The size of block to transform.
+
+ Returns:
+ A tuple of list: (amplitude, frequency) composed of amplitude and
+ frequency of each time.
+
+ """
+ # To apply Hilbert transform, the wave will be transformed
+ # segment by segment. For each segment, its size will be
+ # block_size and we will only take middle part of it.
+ # Thus, each segment looks like: |-----|=====|=====|-----|.
+ # "=...=" part will be taken while "-...-" part will be ignored.
+ #
+ # The whole size of taken part will be half of block_size
+ # which will be hilbert_block.
+ # The size of each ignored part will be half of hilbert_block
+ # which will be half_hilbert_block.
+ hilbert_block = block_size // 2
+ half_hilbert_block = hilbert_block // 2
+ # As mentioned above, for each block, we will only take middle
+ # part of it. Thus, the whole transformation will be completed as:
+ # |=====|=====|-----| |-----|=====|=====|-----|
+ # |-----|=====|=====|-----| |-----|=====|=====|
+ # |-----|=====|=====|-----|
+ # Specially, beginning and ending part may not have ignored part.
+ length = len(signal)
+ result = []
+ for left_border in range(0, length, hilbert_block):
+ right_border = min(length, left_border + hilbert_block)
+ temp_left_border = max(0, left_border - half_hilbert_block)
+ temp_right_border = min(length, right_border + half_hilbert_block)
+ temp = hilbert(signal[temp_left_border:temp_right_border])
+ for index in range(left_border, right_border):
+ result.append(temp[index - temp_left_border])
+ result = numpy.asarray(result)
+ amplitude = numpy.abs(result)
+ phase = numpy.unwrap(numpy.angle(result))
+ frequency = numpy.diff(phase) / (2.0 * numpy.pi) * rate
+ #frequency.append(frequency[len(frequency)-1])
+ frequecny = numpy.append(frequency, frequency[len(frequency) - 1])
+ return (amplitude, frequency)
+
+
+def find_block_average_value(arr, side_block_size, block_size):
+ """For each index, finds average value of its block, left block, right block.
+
+ It will find average value for each index in the range.
+
+ For each index, the range of its block is
+ [max(0, index - block_size / 2), min(length - 1, index + block_size / 2)]
+ For each index, the range of its left block is
+ [max(0, index - size_block_size), index]
+ For each index, the range of its right block is
+ [index, min(length - 1, index + side_block_size)]
+
+ Args:
+ arr: The array to be computed.
+ side_block_size: the size of the left_block and right_block.
+ block_size: the size of the block.
+
+ Returns:
+ A tuple of lists: (left_block_average_array,
+ right_block_average_array,
+ block_average_array)
+ """
+ length = len(arr)
+ left_border, right_border = 0, 1
+ left_block_sum = arr[0]
+ right_block_sum = arr[0]
+ left_average_array = numpy.zeros(length)
+ right_average_array = numpy.zeros(length)
+ block_average_array = numpy.zeros(length)
+ for index in range(0, length):
+ while left_border < index - side_block_size:
+ left_block_sum -= arr[left_border]
+ left_border += 1
+ while right_border < min(length, index + side_block_size):
+ right_block_sum += arr[right_border]
+ right_border += 1
+
+ left_average_value = float(left_block_sum) / (index - left_border + 1)
+ right_average_value = float(right_block_sum) / (right_border - index)
+ left_average_array[index] = left_average_value
+ right_average_array[index] = right_average_value
+
+ if index + 1 < length:
+ left_block_sum += arr[index + 1]
+ right_block_sum -= arr[index]
+ left_border, right_border = 0, 1
+ block_sum = 0
+ for index in range(0, length):
+ while left_border < index - block_size / 2:
+ block_sum -= arr[left_border]
+ left_border += 1
+ while right_border < min(length, index + block_size / 2):
+ block_sum += arr[right_border]
+ right_border += 1
+
+ average_value = float(block_sum) / (right_border - left_border)
+ block_average_array[index] = average_value
+ return (left_average_array, right_average_array, block_average_array)
+
+
+def find_start_end_index(dominant_frequency, block_frequency_delta, block_size,
+ frequency_error_threshold):
+ """Finds start and end index of sine wave.
+
+ For each block with size of block_size, we check that whether its frequency
+ is close enough to the dominant_frequency. If yes, we will consider this
+ block to be within the sine wave.
+ Then, it will return the start and end index of sine wave indicating that
+ sine wave is between [start_index, end_index)
+ It's okay if the whole signal only contains sine wave.
+
+ Args:
+ dominant_frequency: Dominant frequency of signal.
+ block_frequency_delta: Average absolute difference between dominant
+ frequency and frequency of each block. For
+ each index, its block is
+ [max(0, index - block_size / 2),
+ min(length - 1, index + block_size / 2)]
+ block_size: Block size in samples.
+
+ Returns:
+ A tuple composed of (start_index, end_index)
+
+ """
+ length = len(block_frequency_delta)
+
+ # Finds the start/end time index of playing based on dominant frequency
+ start_index, end_index = length - 1, 0
+ for index in range(0, length):
+ left_border = max(0, index - block_size / 2)
+ right_border = min(length - 1, index + block_size / 2)
+ frequency_error = block_frequency_delta[index] / dominant_frequency
+ if frequency_error < frequency_error_threshold:
+ start_index = min(start_index, left_border)
+ end_index = max(end_index, right_border + 1)
+ return (start_index, end_index)
+
+
+def noise_detection(start_index, end_index, block_amplitude, average_amplitude,
+ rate, noise_amplitude_threshold):
+ """Detects noise before/after sine wave.
+
+ If average amplitude of some sample's block before start of wave or after
+ end of wave is more than average_amplitude times noise_amplitude_threshold,
+ it will be considered as a noise.
+
+ Args:
+ start_index: Start index of sine wave.
+ end_index: End index of sine wave.
+ block_amplitude: An array for average amplitude of each block, where
+ amplitude is computed from Hilbert transform.
+ average_amplitude: Average amplitude of sine wave.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+ noise_amplitude_threshold: If the average amplitude of a block is
+ higher than average amplitude of the wave times
+ noise_amplitude_threshold, it will be considered as
+ noise before/after playback.
+
+ Returns:
+ A tuple of lists indicating the time that noise happens:
+ (noise_before_playing, noise_after_playing).
+
+ """
+ length = len(block_amplitude)
+ amplitude_threshold = average_amplitude * noise_amplitude_threshold
+ same_event_samples = rate * DEFAULT_SAME_EVENT_SECS
+
+ # Detects noise before playing.
+ noise_time_point = []
+ last_noise_end_time_point = []
+ previous_noise_index = None
+ times = 0
+ for index in range(0, length):
+ # Ignore noise too close to the beginning or the end of sine wave.
+ # Check the docstring of NEAR_SINE_START_OR_END_SECS.
+ if ((start_index - rate * NEAR_SINE_START_OR_END_SECS) <= index and
+ (index < end_index + rate * NEAR_SINE_START_OR_END_SECS)):
+ continue
+
+ # Ignore noise too close to the beginning or the end of original data.
+ # Check the docstring of NEAR_DATA_START_OR_END_SECS.
+ if (float(index) / rate <=
+ NEAR_DATA_START_OR_END_SECS + APPEND_ZEROS_SECS):
+ continue
+ if (float(length - index) / rate <=
+ NEAR_DATA_START_OR_END_SECS + APPEND_ZEROS_SECS):
+ continue
+ if block_amplitude[index] > amplitude_threshold:
+ same_event = False
+ if previous_noise_index:
+ same_event = (index - previous_noise_index
+ ) < same_event_samples
+ if not same_event:
+ index_start_sec = float(index) / rate - APPEND_ZEROS_SECS
+ index_end_sec = float(index + 1) / rate - APPEND_ZEROS_SECS
+ noise_time_point.append(index_start_sec)
+ last_noise_end_time_point.append(index_end_sec)
+ times += 1
+ index_end_sec = float(index + 1) / rate - APPEND_ZEROS_SECS
+ last_noise_end_time_point[times - 1] = index_end_sec
+ previous_noise_index = index
+
+ noise_before_playing, noise_after_playing = [], []
+ for i in range(times):
+ duration = last_noise_end_time_point[i] - noise_time_point[i]
+ if noise_time_point[i] < float(start_index) / rate - APPEND_ZEROS_SECS:
+ noise_before_playing.append((noise_time_point[i], duration))
+ else:
+ noise_after_playing.append((noise_time_point[i], duration))
+
+ return (noise_before_playing, noise_after_playing)
+
+
+def delay_detection(start_index, end_index, block_amplitude, average_amplitude,
+ dominant_frequency, rate, left_block_amplitude,
+ right_block_amplitude, block_frequency_delta,
+ delay_amplitude_threshold, frequency_error_threshold):
+ """Detects delay during playing.
+
+ For each sample, we will check whether the average amplitude of its block
+ is less than average amplitude of its left block and its right block times
+ delay_amplitude_threshold. Also, we will check whether the frequency of
+ its block is far from the dominant frequency.
+ If at least one constraint fulfilled, it will be considered as a delay.
+
+ Args:
+ start_index: Start index of sine wave.
+ end_index: End index of sine wave.
+ block_amplitude: An array for average amplitude of each block, where
+ amplitude is computed from Hilbert transform.
+ average_amplitude: Average amplitude of sine wave.
+ dominant_frequency: Dominant frequency of signal.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+ left_block_amplitude: Average amplitude of left block of each index.
+ Ref to find_block_average_value function.
+ right_block_amplitude: Average amplitude of right block of each index.
+ Ref to find_block_average_value function.
+ block_frequency_delta: Average absolute difference frequency to
+ dominant frequency of block of each index.
+ Ref to find_block_average_value function.
+ delay_amplitude_threshold: If the average amplitude of a block is
+ lower than average amplitude of the wave times
+ delay_amplitude_threshold, it will be considered
+ as delay.
+ frequency_error_threshold: Ref to DEFAULT_FREQUENCY_ERROR
+
+ Returns:
+ List of delay occurrence:
+ [(time_1, duration_1), (time_2, duration_2), ...],
+ where time and duration are in seconds.
+
+ """
+ delay_time_points = []
+ last_delay_end_time_points = []
+ previous_delay_index = None
+ times = 0
+ same_event_samples = rate * DEFAULT_SAME_EVENT_SECS
+ start_time = float(start_index) / rate - APPEND_ZEROS_SECS
+ end_time = float(end_index) / rate - APPEND_ZEROS_SECS
+ for index in range(int(start_index), int(end_index)):
+ if block_amplitude[
+ index] > average_amplitude * delay_amplitude_threshold:
+ continue
+ now_time = float(index) / rate - APPEND_ZEROS_SECS
+ if abs(now_time - start_time) < NEAR_START_OR_END_SECS:
+ continue
+ if abs(now_time - end_time) < NEAR_START_OR_END_SECS:
+ continue
+ # If amplitude less than its left/right side and small enough,
+ # it will be considered as a delay.
+ amp_threshold = average_amplitude * delay_amplitude_threshold
+ left_threshold = delay_amplitude_threshold * left_block_amplitude[
+ index]
+ amp_threshold = min(amp_threshold, left_threshold)
+ right_threshold = delay_amplitude_threshold * right_block_amplitude[
+ index]
+ amp_threshold = min(amp_threshold, right_threshold)
+
+ frequency_error = block_frequency_delta[index] / dominant_frequency
+
+ amplitude_too_small = block_amplitude[index] < amp_threshold
+ frequency_not_match = frequency_error > frequency_error_threshold
+
+ if amplitude_too_small or frequency_not_match:
+ same_event = False
+ if previous_delay_index:
+ same_event = (index - previous_delay_index
+ ) < same_event_samples
+ if not same_event:
+ index_start_sec = float(index) / rate - APPEND_ZEROS_SECS
+ index_end_sec = float(index + 1) / rate - APPEND_ZEROS_SECS
+ delay_time_points.append(index_start_sec)
+ last_delay_end_time_points.append(index_end_sec)
+ times += 1
+ previous_delay_index = index
+ index_end_sec = float(index + 1) / rate - APPEND_ZEROS_SECS
+ last_delay_end_time_points[times - 1] = index_end_sec
+
+ delay_list = []
+ for i in range(len(delay_time_points)):
+ duration = last_delay_end_time_points[i] - delay_time_points[i]
+ delay_list.append((delay_time_points[i], duration))
+ return delay_list
+
+
+def burst_detection(start_index, end_index, block_amplitude, average_amplitude,
+ dominant_frequency, rate, left_block_amplitude,
+ right_block_amplitude, block_frequency_delta,
+ burst_amplitude_threshold, frequency_error_threshold):
+ """Detects burst during playing.
+
+ For each sample, we will check whether the average amplitude of its block is
+ more than average amplitude of its left block and its right block times
+ burst_amplitude_threshold. Also, we will check whether the frequency of
+ its block is not compatible to the dominant frequency.
+ If at least one constraint fulfilled, it will be considered as a burst.
+
+ Args:
+ start_index: Start index of sine wave.
+ end_index: End index of sine wave.
+ block_amplitude: An array for average amplitude of each block, where
+ amplitude is computed from Hilbert transform.
+ average_amplitude: Average amplitude of sine wave.
+ dominant_frequency: Dominant frequency of signal.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+ left_block_amplitude: Average amplitude of left block of each index.
+ Ref to find_block_average_value function.
+ right_block_amplitude: Average amplitude of right block of each index.
+ Ref to find_block_average_value function.
+ block_frequency_delta: Average absolute difference frequency to
+ dominant frequency of block of each index.
+ burst_amplitude_threshold: If the amplitude is higher than average
+ amplitude of its left block and its right block
+ times burst_amplitude_threshold. It will be
+ considered as a burst.
+ frequency_error_threshold: Ref to DEFAULT_FREQUENCY_ERROR
+
+ Returns:
+ List of burst occurence: [time_1, time_2, ...],
+ where time is in seconds.
+
+ """
+ burst_time_points = []
+ previous_burst_index = None
+ same_event_samples = rate * DEFAULT_SAME_EVENT_SECS
+ for index in range(int(start_index), int(end_index)):
+ # If amplitude higher than its left/right side and large enough,
+ # it will be considered as a burst.
+ if block_amplitude[
+ index] <= average_amplitude * DEFAULT_BURST_TOO_SMALL:
+ continue
+ if abs(index - start_index) < rate * NEAR_START_OR_END_SECS:
+ continue
+ if abs(index - end_index) < rate * NEAR_START_OR_END_SECS:
+ continue
+ amp_threshold = average_amplitude * DEFAULT_BURST_TOO_SMALL
+ left_threshold = burst_amplitude_threshold * left_block_amplitude[
+ index]
+ amp_threshold = max(amp_threshold, left_threshold)
+ right_threshold = burst_amplitude_threshold * right_block_amplitude[
+ index]
+ amp_threshold = max(amp_threshold, right_threshold)
+
+ frequency_error = block_frequency_delta[index] / dominant_frequency
+
+ amplitude_too_large = block_amplitude[index] > amp_threshold
+ frequency_not_match = frequency_error > frequency_error_threshold
+
+ if amplitude_too_large or frequency_not_match:
+ same_event = False
+ if previous_burst_index:
+ same_event = index - previous_burst_index < same_event_samples
+ if not same_event:
+ burst_time_points.append(
+ float(index) / rate - APPEND_ZEROS_SECS)
+ previous_burst_index = index
+
+ return burst_time_points
+
+
+def changing_volume_detection(start_index, end_index, average_amplitude, rate,
+ left_block_amplitude, right_block_amplitude,
+ volume_changing_amplitude_threshold):
+ """Finds volume changing during playback.
+
+ For each index, we will compare average amplitude of its left block and its
+ right block. If average amplitude of right block is more than average
+ amplitude of left block times (1 + DEFAULT_VOLUME_CHANGE_AMPLITUDE), it will
+ be considered as an increasing volume. If the one of right block is less
+ than that of left block times (1 - DEFAULT_VOLUME_CHANGE_AMPLITUDE), it will
+ be considered as a decreasing volume.
+
+ Args:
+ start_index: Start index of sine wave.
+ end_index: End index of sine wave.
+ average_amplitude: Average amplitude of sine wave.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+ left_block_amplitude: Average amplitude of left block of each index.
+ Ref to find_block_average_value function.
+ right_block_amplitude: Average amplitude of right block of each index.
+ Ref to find_block_average_value function.
+ volume_changing_amplitude_threshold: If the average amplitude of right
+ block is higher or lower than
+ that of left one times this
+ value, it will be considered as
+ a volume change.
+ Also refer to
+ DEFAULT_VOLUME_CHANGE_AMPLITUDE
+
+ Returns:
+ List of volume changing composed of 1 for increasing and -1 for
+ decreasing.
+
+ """
+ length = len(left_block_amplitude)
+
+ # Detects rising and/or falling volume.
+ previous_rising_index, previous_falling_index = None, None
+ changing_time = []
+ changing_events = []
+ amplitude_threshold = average_amplitude * DEFAULT_VOLUME_CHANGE_TOO_SMALL
+ same_event_samples = rate * DEFAULT_SAME_EVENT_SECS
+ for index in range(int(start_index), int(end_index)):
+ # Skips if amplitude is too small.
+ if left_block_amplitude[index] < amplitude_threshold:
+ continue
+ if right_block_amplitude[index] < amplitude_threshold:
+ continue
+ # Skips if changing is from start or end time
+ if float(abs(start_index - index)) / rate < NEAR_START_OR_END_SECS:
+ continue
+ if float(abs(end_index - index)) / rate < NEAR_START_OR_END_SECS:
+ continue
+
+ delta_margin = volume_changing_amplitude_threshold
+ if left_block_amplitude[index] > 0:
+ delta_margin *= left_block_amplitude[index]
+
+ increasing_threshold = left_block_amplitude[index] + delta_margin
+ decreasing_threshold = left_block_amplitude[index] - delta_margin
+
+ if right_block_amplitude[index] > increasing_threshold:
+ same_event = False
+ if previous_rising_index:
+ same_event = index - previous_rising_index < same_event_samples
+ if not same_event:
+ changing_time.append(float(index) / rate - APPEND_ZEROS_SECS)
+ changing_events.append(+1)
+ previous_rising_index = index
+ if right_block_amplitude[index] < decreasing_threshold:
+ same_event = False
+ if previous_falling_index:
+ same_event = index - previous_falling_index < same_event_samples
+ if not same_event:
+ changing_time.append(float(index) / rate - APPEND_ZEROS_SECS)
+ changing_events.append(-1)
+ previous_falling_index = index
+
+ # Combines consecutive increasing/decreasing event.
+ combined_changing_events, prev = [], 0
+ for i in range(len(changing_events)):
+ if changing_events[i] == prev:
+ continue
+ combined_changing_events.append((changing_time[i], changing_events[i]))
+ prev = changing_events[i]
+ return combined_changing_events
+
+
+def quality_measurement(
+ signal,
+ rate,
+ dominant_frequency=None,
+ block_size_secs=DEFAULT_BLOCK_SIZE_SECS,
+ frequency_error_threshold=DEFAULT_FREQUENCY_ERROR,
+ delay_amplitude_threshold=DEFAULT_DELAY_AMPLITUDE_THRESHOLD,
+ noise_amplitude_threshold=DEFAULT_NOISE_AMPLITUDE_THRESHOLD,
+ burst_amplitude_threshold=DEFAULT_BURST_AMPLITUDE_THRESHOLD,
+ volume_changing_amplitude_threshold=DEFAULT_VOLUME_CHANGE_AMPLITUDE):
+ """Detects several artifacts and estimates the noise level.
+
+ This method detects artifact before playing, after playing, and delay
+ during playing. Also, it estimates the noise level of the signal.
+ To avoid the influence of noise, it calculates amplitude and frequency
+ block by block.
+
+ Args:
+ signal: A list of numbers for one-channel PCM data. The data should
+ be normalized to [-1,1].
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+ dominant_frequency: Dominant frequency of signal. Set None to
+ recalculate the frequency in this function.
+ block_size_secs: Block size in seconds. The measurement will be done
+ block-by-block using average amplitude and frequency
+ in each block to avoid noise.
+ frequency_error_threshold: Ref to DEFAULT_FREQUENCY_ERROR.
+ delay_amplitude_threshold: If the average amplitude of a block is
+ lower than average amplitude of the wave
+ times delay_amplitude_threshold, it will
+ be considered as delay.
+ Also refer to delay_detection and
+ DEFAULT_DELAY_AMPLITUDE_THRESHOLD.
+ noise_amplitude_threshold: If the average amplitude of a block is
+ higher than average amplitude of the wave
+ times noise_amplitude_threshold, it will
+ be considered as noise before/after
+ playback.
+ Also refer to noise_detection and
+ DEFAULT_NOISE_AMPLITUDE_THRESHOLD.
+ burst_amplitude_threshold: If the average amplitude of a block is
+ higher than average amplitude of its left
+ block and its right block times
+ burst_amplitude_threshold. It will be
+ considered as a burst.
+ Also refer to burst_detection and
+ DEFAULT_BURST_AMPLITUDE_THRESHOLD.
+ volume_changing_amplitude_threshold: If the average amplitude of right
+ block is higher or lower than
+ that of left one times this
+ value, it will be considered as
+ a volume change.
+ Also refer to
+ changing_volume_detection and
+ DEFAULT_VOLUME_CHANGE_AMPLITUDE
+
+ Returns:
+ A dictoinary of detection/estimation:
+ {'artifacts':
+ {'noise_before_playback':
+ [(time_1, duration_1), (time_2, duration_2), ...],
+ 'noise_after_playback':
+ [(time_1, duration_1), (time_2, duration_2), ...],
+ 'delay_during_playback':
+ [(time_1, duration_1), (time_2, duration_2), ...],
+ 'burst_during_playback':
+ [time_1, time_2, ...]
+ },
+ 'volume_changes':
+ [(time_1, flag_1), (time_2, flag_2), ...],
+ 'equivalent_noise_level': level
+ }
+ where durations and time points are in seconds. And,
+ equivalence_noise_level is the quotient of noise and wave which
+ refers to DEFAULT_STANDARD_NOISE. volume_changes is a list of
+ tuples containing time stamps and decreasing/increasing flags for
+ volume change events.
+
+ """
+ # Calculates the block size, from seconds to samples.
+ block_size = int(block_size_secs * rate)
+
+ signal = numpy.concatenate(
+ (numpy.zeros(int(rate * APPEND_ZEROS_SECS)), signal,
+ numpy.zeros(int(rate * APPEND_ZEROS_SECS))))
+ signal = numpy.array(signal, dtype=float)
+ length = len(signal)
+
+ # Calculates the amplitude and frequency.
+ amplitude, frequency = hilbert_analysis(signal, rate, block_size)
+
+ # Finds the dominant frequency.
+ if not dominant_frequency:
+ dominant_frequency = audio_analysis.spectral_analysis(signal,
+ rate)[0][0]
+
+ # Finds the array which contains absolute difference between dominant
+ # frequency and frequency at each time point.
+ frequency_delta = abs(frequency - dominant_frequency)
+
+ # Computes average amplitude of each type of block
+ res = find_block_average_value(amplitude, block_size * 2, block_size)
+ left_block_amplitude, right_block_amplitude, block_amplitude = res
+
+ # Computes average absolute difference of frequency and dominant frequency
+ # of the block of each index
+ _, _, block_frequency_delta = find_block_average_value(
+ frequency_delta, block_size * 2, block_size)
+
+ # Finds start and end index of sine wave.
+ start_index, end_index = find_start_end_index(
+ dominant_frequency, block_frequency_delta, block_size,
+ frequency_error_threshold)
+
+ if start_index > end_index:
+ raise SineWaveNotFound('No sine wave found in signal')
+
+ logging.debug('Found sine wave: start: %s, end: %s',
+ float(start_index) / rate - APPEND_ZEROS_SECS,
+ float(end_index) / rate - APPEND_ZEROS_SECS)
+
+ sum_of_amplitude = float(sum(amplitude[int(start_index):int(end_index)]))
+ # Finds average amplitude of sine wave.
+ average_amplitude = sum_of_amplitude / (end_index - start_index)
+
+ # Finds noise before and/or after playback.
+ noise_before_playing, noise_after_playing = noise_detection(
+ start_index, end_index, block_amplitude, average_amplitude, rate,
+ noise_amplitude_threshold)
+
+ # Finds delay during playback.
+ delays = delay_detection(start_index, end_index, block_amplitude,
+ average_amplitude, dominant_frequency, rate,
+ left_block_amplitude, right_block_amplitude,
+ block_frequency_delta, delay_amplitude_threshold,
+ frequency_error_threshold)
+
+ # Finds burst during playback.
+ burst_time_points = burst_detection(
+ start_index, end_index, block_amplitude, average_amplitude,
+ dominant_frequency, rate, left_block_amplitude, right_block_amplitude,
+ block_frequency_delta, burst_amplitude_threshold,
+ frequency_error_threshold)
+
+ # Finds volume changing during playback.
+ volume_changes = changing_volume_detection(
+ start_index, end_index, average_amplitude, rate, left_block_amplitude,
+ right_block_amplitude, volume_changing_amplitude_threshold)
+
+ # Calculates the average teager value.
+ teager_value = average_teager_value(
+ signal[int(start_index):int(end_index)], average_amplitude)
+
+ # Finds out the noise level.
+ noise = noise_level(average_amplitude, dominant_frequency, rate,
+ teager_value)
+
+ return {
+ 'artifacts': {
+ 'noise_before_playback': noise_before_playing,
+ 'noise_after_playback': noise_after_playing,
+ 'delay_during_playback': delays,
+ 'burst_during_playback': burst_time_points
+ },
+ 'volume_changes': volume_changes,
+ 'equivalent_noise_level': noise
+ }
diff --git a/acts/framework/acts/test_utils/audio_analysis_lib/check_quality.py b/acts/framework/acts/test_utils/audio_analysis_lib/check_quality.py
new file mode 100644
index 0000000..15ff09e
--- /dev/null
+++ b/acts/framework/acts/test_utils/audio_analysis_lib/check_quality.py
@@ -0,0 +1,555 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2017 - 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.
+"""Audio Analysis tool to analyze wave file and detect artifacts."""
+
+import argparse
+import collections
+import json
+import logging
+import math
+import numpy
+import os
+import pprint
+import subprocess
+import tempfile
+import wave
+
+import acts.test_utils.audio_analysis_lib.audio_analysis as audio_analysis
+import acts.test_utils.audio_analysis_lib.audio_data as audio_data
+import acts.test_utils.audio_analysis_lib.audio_quality_measurement as \
+ audio_quality_measurement
+
+# Holder for quality parameters used in audio_quality_measurement module.
+QualityParams = collections.namedtuple('QualityParams', [
+ 'block_size_secs', 'frequency_error_threshold',
+ 'delay_amplitude_threshold', 'noise_amplitude_threshold',
+ 'burst_amplitude_threshold'
+])
+
+DEFAULT_QUALITY_BLOCK_SIZE_SECS = 0.0015
+DEFAULT_BURST_AMPLITUDE_THRESHOLD = 1.4
+DEFAULT_DELAY_AMPLITUDE_THRESHOLD = 0.6
+DEFAULT_FREQUENCY_ERROR_THRESHOLD = 0.5
+DEFAULT_NOISE_AMPLITUDE_THRESHOLD = 0.5
+
+
+class WaveFileException(Exception):
+ """Error in WaveFile."""
+ pass
+
+
+class WaveFormatExtensibleException(Exception):
+ """Wave file is in WAVE_FORMAT_EXTENSIBLE format which is not supported."""
+ pass
+
+
+class WaveFile(object):
+ """Class which handles wave file reading.
+
+ Properties:
+ raw_data: audio_data.AudioRawData object for data in wave file.
+ rate: sampling rate.
+
+ """
+
+ def __init__(self, filename):
+ """Inits a wave file.
+
+ Args:
+ filename: file name of the wave file.
+
+ """
+ self.raw_data = None
+ self.rate = None
+
+ self._wave_reader = None
+ self._n_channels = None
+ self._sample_width_bits = None
+ self._n_frames = None
+ self._binary = None
+
+ try:
+ self._read_wave_file(filename)
+ except WaveFormatExtensibleException:
+ logging.warning(
+ 'WAVE_FORMAT_EXTENSIBLE is not supproted. '
+ 'Try command "sox in.wav -t wavpcm out.wav" to convert '
+ 'the file to WAVE_FORMAT_PCM format.')
+ self._convert_and_read_wav_file(filename)
+
+ def _convert_and_read_wav_file(self, filename):
+ """Converts the wav file and read it.
+
+ Converts the file into WAVE_FORMAT_PCM format using sox command and
+ reads its content.
+
+ Args:
+ filename: The wave file to be read.
+
+ Raises:
+ RuntimeError: sox is not installed.
+
+ """
+ # Checks if sox is installed.
+ try:
+ subprocess.check_output(['sox', '--version'])
+ except:
+ raise RuntimeError('sox command is not installed. '
+ 'Try sudo apt-get install sox')
+
+ with tempfile.NamedTemporaryFile(suffix='.wav') as converted_file:
+ command = ['sox', filename, '-t', 'wavpcm', converted_file.name]
+ logging.debug('Convert the file using sox: %s', command)
+ subprocess.check_call(command)
+ self._read_wave_file(converted_file.name)
+
+ def _read_wave_file(self, filename):
+ """Reads wave file header and samples.
+
+ Args:
+ filename: The wave file to be read.
+
+ @raises WaveFormatExtensibleException: Wave file is in
+ WAVE_FORMAT_EXTENSIBLE format.
+ @raises WaveFileException: Wave file format is not supported.
+
+ """
+ try:
+ self._wave_reader = wave.open(filename, 'r')
+ self._read_wave_header()
+ self._read_wave_binary()
+ except wave.Error as e:
+ if 'unknown format: 65534' in str(e):
+ raise WaveFormatExtensibleException()
+ else:
+ logging.exception('Unsupported wave format')
+ raise WaveFileException()
+ finally:
+ if self._wave_reader:
+ self._wave_reader.close()
+
+ def _read_wave_header(self):
+ """Reads wave file header.
+
+ @raises WaveFileException: wave file is compressed.
+
+ """
+ # Header is a tuple of
+ # (nchannels, sampwidth, framerate, nframes, comptype, compname).
+ header = self._wave_reader.getparams()
+ logging.debug('Wave header: %s', header)
+
+ self._n_channels = header[0]
+ self._sample_width_bits = header[1] * 8
+ self.rate = header[2]
+ self._n_frames = header[3]
+ comptype = header[4]
+ compname = header[5]
+
+ if comptype != 'NONE' or compname != 'not compressed':
+ raise WaveFileException('Can not support compressed wav file.')
+
+ def _read_wave_binary(self):
+ """Reads in samples in wave file."""
+ self._binary = self._wave_reader.readframes(self._n_frames)
+ format_str = 'S%d_LE' % self._sample_width_bits
+ self.raw_data = audio_data.AudioRawData(
+ binary=self._binary,
+ channel=self._n_channels,
+ sample_format=format_str)
+
+
+class QualityCheckerError(Exception):
+ """Error in QualityChecker."""
+ pass
+
+
+class CompareFailure(QualityCheckerError):
+ """Exception when frequency comparison fails."""
+ pass
+
+
+class QualityFailure(QualityCheckerError):
+ """Exception when quality check fails."""
+ pass
+
+
+class QualityChecker(object):
+ """Quality checker controls the flow of checking quality of raw data."""
+
+ def __init__(self, raw_data, rate):
+ """Inits a quality checker.
+
+ Args:
+ raw_data: An audio_data.AudioRawData object.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+
+ """
+ self._raw_data = raw_data
+ self._rate = rate
+ self._spectrals = []
+ self._quality_result = []
+
+ def do_spectral_analysis(self, ignore_high_freq, check_quality,
+ quality_params):
+ """Gets the spectral_analysis result.
+
+ Args:
+ ignore_high_freq: Ignore high frequencies above this threshold.
+ check_quality: Check quality of each channel.
+ quality_params: A QualityParams object for quality measurement.
+
+ """
+ self.has_data()
+ for channel_idx in range(self._raw_data.channel):
+ signal = self._raw_data.channel_data[channel_idx]
+ max_abs = max(numpy.abs(signal))
+ logging.debug('Channel %d max abs signal: %f', channel_idx,
+ max_abs)
+ if max_abs == 0:
+ logging.info('No data on channel %d, skip this channel',
+ channel_idx)
+ continue
+
+ saturate_value = audio_data.get_maximum_value_from_sample_format(
+ self._raw_data.sample_format)
+ normalized_signal = audio_analysis.normalize_signal(
+ signal, saturate_value)
+ logging.debug('saturate_value: %f', saturate_value)
+ logging.debug('max signal after normalized: %f',
+ max(normalized_signal))
+ spectral = audio_analysis.spectral_analysis(
+ normalized_signal, self._rate)
+
+ logging.debug('Channel %d spectral:\n%s', channel_idx,
+ pprint.pformat(spectral))
+
+ # Ignore high frequencies above the threshold.
+ spectral = [(f, c) for (f, c) in spectral if f < ignore_high_freq]
+
+ logging.info('Channel %d spectral after ignoring high frequencies '
+ 'above %f:\n%s', channel_idx, ignore_high_freq,
+ pprint.pformat(spectral))
+
+ try:
+ if check_quality:
+ quality = audio_quality_measurement.quality_measurement(
+ signal=normalized_signal,
+ rate=self._rate,
+ dominant_frequency=spectral[0][0],
+ block_size_secs=quality_params.block_size_secs,
+ frequency_error_threshold=quality_params.
+ frequency_error_threshold,
+ delay_amplitude_threshold=quality_params.
+ delay_amplitude_threshold,
+ noise_amplitude_threshold=quality_params.
+ noise_amplitude_threshold,
+ burst_amplitude_threshold=quality_params.
+ burst_amplitude_threshold)
+
+ logging.debug('Channel %d quality:\n%s', channel_idx,
+ pprint.pformat(quality))
+ self._quality_result.append(quality)
+ self._spectrals.append(spectral)
+ except Exception as error:
+ logging.warning(
+ "Failed to analyze channel {} with error: {}".format(
+ channel_idx, error))
+
+ def has_data(self):
+ """Checks if data has been set.
+
+ Raises:
+ QualityCheckerError: if data or rate is not set yet.
+
+ """
+ if not self._raw_data or not self._rate:
+ raise QualityCheckerError('Data and rate is not set yet')
+
+ def check_freqs(self, expected_freqs, freq_threshold):
+ """Checks the dominant frequencies in the channels.
+
+ Args:
+ expected_freq: A list of frequencies. If frequency is 0, it
+ means this channel should be ignored.
+ freq_threshold: The difference threshold to compare two
+ frequencies.
+
+ """
+ logging.debug('expected_freqs: %s', expected_freqs)
+ for idx, expected_freq in enumerate(expected_freqs):
+ if expected_freq == 0:
+ continue
+ if not self._spectrals[idx]:
+ raise CompareFailure(
+ 'Failed at channel %d: no dominant frequency' % idx)
+ dominant_freq = self._spectrals[idx][0][0]
+ if abs(dominant_freq - expected_freq) > freq_threshold:
+ raise CompareFailure(
+ 'Failed at channel %d: %f is too far away from %f' %
+ (idx, dominant_freq, expected_freq))
+
+ def check_quality(self):
+ """Checks the quality measurement results on each channel.
+
+ Raises:
+ QualityFailure when there is artifact.
+
+ """
+ error_msgs = []
+
+ for idx, quality_res in enumerate(self._quality_result):
+ artifacts = quality_res['artifacts']
+ if artifacts['noise_before_playback']:
+ error_msgs.append('Found noise before playback: %s' %
+ (artifacts['noise_before_playback']))
+ if artifacts['noise_after_playback']:
+ error_msgs.append('Found noise after playback: %s' %
+ (artifacts['noise_after_playback']))
+ if artifacts['delay_during_playback']:
+ error_msgs.append('Found delay during playback: %s' %
+ (artifacts['delay_during_playback']))
+ if artifacts['burst_during_playback']:
+ error_msgs.append('Found burst during playback: %s' %
+ (artifacts['burst_during_playback']))
+ if error_msgs:
+ raise QualityFailure('Found bad quality: %s',
+ '\n'.join(error_msgs))
+
+ def dump(self, output_file):
+ """Dumps the result into a file in json format.
+
+ Args:
+ output_file: A file path to dump spectral and quality
+ measurement result of each channel.
+
+ """
+ dump_dict = {
+ 'spectrals': self._spectrals,
+ 'quality_result': self._quality_result
+ }
+ with open(output_file, 'w') as f:
+ json.dump(dump_dict, f)
+
+ def has_data(self):
+ """Checks if data has been set.
+
+ Raises:
+ QualityCheckerError: if data or rate is not set yet.
+
+ """
+ if not self._raw_data or not self._rate:
+ raise QualityCheckerError('Data and rate is not set yet')
+
+ def check_freqs(self, expected_freqs, freq_threshold):
+ """Checks the dominant frequencies in the channels.
+
+ Args:
+ expected_freq: A list of frequencies. If frequency is 0, it
+ means this channel should be ignored.
+ freq_threshold: The difference threshold to compare two
+ frequencies.
+
+ """
+ logging.debug('expected_freqs: %s', expected_freqs)
+ for idx, expected_freq in enumerate(expected_freqs):
+ if expected_freq == 0:
+ continue
+ if not self._spectrals[idx]:
+ raise CompareFailure(
+ 'Failed at channel %d: no dominant frequency' % idx)
+ dominant_freq = self._spectrals[idx][0][0]
+ if abs(dominant_freq - expected_freq) > freq_threshold:
+ raise CompareFailure(
+ 'Failed at channel %d: %f is too far away from %f' %
+ (idx, dominant_freq, expected_freq))
+
+ def check_quality(self):
+ """Checks the quality measurement results on each channel.
+
+ Raises:
+ QualityFailure when there is artifact.
+
+ """
+ error_msgs = []
+
+ for idx, quality_res in enumerate(self._quality_result):
+ artifacts = quality_res['artifacts']
+ if artifacts['noise_before_playback']:
+ error_msgs.append('Found noise before playback: %s' %
+ (artifacts['noise_before_playback']))
+ if artifacts['noise_after_playback']:
+ error_msgs.append('Found noise after playback: %s' %
+ (artifacts['noise_after_playback']))
+ if artifacts['delay_during_playback']:
+ error_msgs.append('Found delay during playback: %s' %
+ (artifacts['delay_during_playback']))
+ if artifacts['burst_during_playback']:
+ error_msgs.append('Found burst during playback: %s' %
+ (artifacts['burst_during_playback']))
+ if error_msgs:
+ raise QualityFailure('Found bad quality: %s',
+ '\n'.join(error_msgs))
+
+ def dump(self, output_file):
+ """Dumps the result into a file in json format.
+
+ Args:
+ output_file: A file path to dump spectral and quality
+ measurement result of each channel.
+
+ """
+ dump_dict = {
+ 'spectrals': self._spectrals,
+ 'quality_result': self._quality_result
+ }
+ with open(output_file, 'w') as f:
+ json.dump(dump_dict, f)
+
+
+class CheckQualityError(Exception):
+ """Error in check_quality main function."""
+ pass
+
+
+def read_audio_file(filename, channel, bit_width, rate):
+ """Reads audio file.
+
+ Args:
+ filename: The wav or raw file to check.
+ channel: For raw file. Number of channels.
+ bit_width: For raw file. Bit width of a sample.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+
+
+ Returns:
+ A tuple (raw_data, rate) where raw_data is audio_data.AudioRawData, rate
+ is sampling rate.
+
+ """
+ if filename.endswith('.wav'):
+ wavefile = WaveFile(filename)
+ raw_data = wavefile.raw_data
+ rate = wavefile.rate
+ elif filename.endswith('.raw'):
+ binary = None
+ with open(filename, 'rb') as f:
+ binary = f.read()
+ raw_data = audio_data.AudioRawData(
+ binary=binary, channel=channel, sample_format='S%d_LE' % bit_width)
+ else:
+ raise CheckQualityError(
+ 'File format for %s is not supported' % filename)
+
+ return raw_data, rate
+
+
+def get_quality_params(
+ quality_block_size_secs, quality_frequency_error_threshold,
+ quality_delay_amplitude_threshold, quality_noise_amplitude_threshold,
+ quality_burst_amplitude_threshold):
+ """Gets quality parameters in arguments.
+
+ Args:
+ quality_block_size_secs: Input block size in seconds.
+ quality_frequency_error_threshold: Input the frequency error
+ threshold.
+ quality_delay_amplitude_threshold: Input the delay aplitutde
+ threshold.
+ quality_noise_amplitude_threshold: Input the noise aplitutde
+ threshold.
+ quality_burst_amplitude_threshold: Input the burst aplitutde
+ threshold.
+
+ Returns:
+ A QualityParams object.
+
+ """
+ quality_params = QualityParams(
+ block_size_secs=quality_block_size_secs,
+ frequency_error_threshold=quality_frequency_error_threshold,
+ delay_amplitude_threshold=quality_delay_amplitude_threshold,
+ noise_amplitude_threshold=quality_noise_amplitude_threshold,
+ burst_amplitude_threshold=quality_burst_amplitude_threshold)
+
+ return quality_params
+
+
+def quality_analysis(
+ filename,
+ output_file,
+ bit_width,
+ rate,
+ channel,
+ freqs=None,
+ freq_threshold=5,
+ ignore_high_freq=5000,
+ spectral_only=False,
+ quality_block_size_secs=DEFAULT_QUALITY_BLOCK_SIZE_SECS,
+ quality_burst_amplitude_threshold=DEFAULT_BURST_AMPLITUDE_THRESHOLD,
+ quality_delay_amplitude_threshold=DEFAULT_DELAY_AMPLITUDE_THRESHOLD,
+ quality_frequency_error_threshold=DEFAULT_FREQUENCY_ERROR_THRESHOLD,
+ quality_noise_amplitude_threshold=DEFAULT_NOISE_AMPLITUDE_THRESHOLD,
+):
+ """ Runs various functions to measure audio quality base on user input.
+
+ Args:
+ filename: The wav or raw file to check.
+ output_file: Output file to dump analysis result in JSON format.
+ bit_width: For raw file. Bit width of a sample.
+ rate: Sampling rate in samples per second. Example inputs: 44100,
+ 48000
+ channel: For raw file. Number of channels.
+ freqs: Expected frequencies in the channels.
+ freq_threshold: Frequency difference threshold in Hz.
+ ignore_high_freq: Frequency threshold in Hz to be ignored for high
+ frequency. Default is 5KHz
+ spectral_only: Only do spectral analysis on each channel.
+ quality_block_size_secs: Input block size in seconds.
+ quality_frequency_error_threshold: Input the frequency error
+ threshold.
+ quality_delay_amplitude_threshold: Input the delay aplitutde
+ threshold.
+ quality_noise_amplitude_threshold: Input the noise aplitutde
+ threshold.
+ quality_burst_amplitude_threshold: Input the burst aplitutde
+ threshold.
+ """
+ format = '%(asctime)-15s:%(levelname)s:%(pathname)s:%(lineno)d: %(message)s'
+ logging.basicConfig(format=format, level=logging.INFO)
+ raw_data, rate = read_audio_file(filename, channel, bit_width, rate)
+
+ checker = QualityChecker(raw_data, rate)
+
+ quality_params = get_quality_params(
+ quality_block_size_secs, quality_frequency_error_threshold,
+ quality_delay_amplitude_threshold, quality_noise_amplitude_threshold,
+ quality_burst_amplitude_threshold)
+
+ checker.do_spectral_analysis(
+ ignore_high_freq=ignore_high_freq,
+ check_quality=(not spectral_only),
+ quality_params=quality_params)
+
+ checker.dump(output_file)
+
+ if freqs:
+ checker.check_freqs(freqs, freq_threshold)
+
+ if not spectral_only:
+ checker.check_quality()
diff --git a/acts/framework/acts/test_utils/bt/BtFunhausBaseTest.py b/acts/framework/acts/test_utils/bt/BtFunhausBaseTest.py
index 5fb302a..7d0085b 100644
--- a/acts/framework/acts/test_utils/bt/BtFunhausBaseTest.py
+++ b/acts/framework/acts/test_utils/bt/BtFunhausBaseTest.py
@@ -43,8 +43,46 @@
def __init__(self, controllers):
BtMetricsBaseTest.__init__(self, controllers)
self.ad = self.android_devices[0]
+ self.dongle = self.relay_devices[0]
+
+ def _pair_devices(self):
+ self.ad.droid.bluetoothStartPairingHelper(False)
+ self.dongle.enter_pairing_mode()
+
+ self.ad.droid.bluetoothBond(self.dongle.mac_address)
+
+ end_time = time.time() + 20
+ self.ad.log.info("Verifying devices are bonded")
+ while time.time() < end_time:
+ bonded_devices = self.ad.droid.bluetoothGetBondedDevices()
+
+ for d in bonded_devices:
+ if d['address'] == self.dongle.mac_address:
+ self.ad.log.info("Successfully bonded to device.")
+ self.log.info("Bonded devices:\n{}".format(bonded_devices))
+ return True
+ self.ad.log.info("Failed to bond devices.")
+ return False
+
+ def setup_test(self):
+ super(BtFunhausBaseTest, self).setup_test()
+ self.dongle.setup()
+ tries = 5
+ # Since we are not concerned with pairing in this test, try 5 times.
+ while tries > 0:
+ if self._pair_devices():
+ return True
+ else:
+ tries -= 1
+ return False
+
+ def teardown_test(self):
+ super(BtFunhausBaseTest, self).teardown_test()
+ self.dongle.clean_up()
+ return True
def on_fail(self, test_name, begin_time):
+ self.dongle.clean_up()
self._collect_bluetooth_manager_dumpsys_logs(self.android_devices)
super(BtFunhausBaseTest, self).on_fail(test_name, begin_time)
@@ -80,8 +118,8 @@
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))
+ self.log.error(
+ "Unable to find music directory {}.".format(music_path))
return False
if type(music_path) is list:
for item in music_path:
@@ -144,7 +182,7 @@
while time.time() < end_time:
if not self.ad.droid.bluetoothCheckState():
self.ad.log.error("Device {}'s Bluetooth state is off.".format(
- serial))
+ self.ad.serial))
return False
if self.ad.droid.bluetoothGetConnectedDevices() == 0:
self.ad.log.error(
diff --git a/acts/framework/acts/test_utils/bt/BtMetricsBaseTest.py b/acts/framework/acts/test_utils/bt/BtMetricsBaseTest.py
index 3964ca4..3528447 100644
--- a/acts/framework/acts/test_utils/bt/BtMetricsBaseTest.py
+++ b/acts/framework/acts/test_utils/bt/BtMetricsBaseTest.py
@@ -28,7 +28,6 @@
def __init__(self, controllers):
BluetoothBaseTest.__init__(self, controllers)
self.bluetooth_proto_path = None
- self.dongle = self.relay_devices[0]
self.ad = self.android_devices[0]
def setup_class(self):
@@ -46,8 +45,8 @@
except Exception:
self.log.error("File not found.")
if not os.path.isfile(self.bluetooth_proto_path):
- self.log.error("Unable to find Bluetooth proto {}."
- .format(self.bluetooth_proto_path))
+ self.log.error("Unable to find Bluetooth proto {}.".format(
+ self.bluetooth_proto_path))
return False
for ad in self.android_devices:
ad.metrics_path = os.path.join(ad.log_path, "BluetoothMetrics")
@@ -70,40 +69,8 @@
# Clear all metrics
for ad in self.android_devices:
get_bluetooth_metrics(ad, ad.bluetooth_proto_module)
- self.dongle.setup()
- tries = 5
- # Since we are not concerned with pairing in this test, try 5 times.
- while tries > 0:
- if self._pair_devices():
- return True
- else:
- tries -= 1
- return False
-
- def teardown_test(self):
- super(BtMetricsBaseTest, self).teardown_test()
- self.dongle.clean_up()
return True
- def _pair_devices(self):
- self.ad.droid.bluetoothStartPairingHelper(False)
- self.dongle.enter_pairing_mode()
-
- self.ad.droid.bluetoothBond(self.dongle.mac_address)
-
- end_time = time.time() + 20
- self.ad.log.info("Verifying devices are bonded")
- while time.time() < end_time:
- bonded_devices = self.ad.droid.bluetoothGetBondedDevices()
-
- for d in bonded_devices:
- if d['address'] == self.dongle.mac_address:
- self.ad.log.info("Successfully bonded to device.")
- self.log.info("Bonded devices:\n{}".format(bonded_devices))
- return True
- self.ad.log.info("Failed to bond devices.")
- return False
-
def collect_bluetooth_manager_metrics_logs(self, ads):
"""
Collect Bluetooth metrics logs, save an ascii log to disk and return
diff --git a/acts/tests/google/bt/pts/ble_lib.py b/acts/framework/acts/test_utils/bt/ble_lib.py
similarity index 91%
rename from acts/tests/google/bt/pts/ble_lib.py
rename to acts/framework/acts/test_utils/bt/ble_lib.py
index f8ff402..379f182 100644
--- a/acts/tests/google/bt/pts/ble_lib.py
+++ b/acts/framework/acts/test_utils/bt/ble_lib.py
@@ -76,22 +76,25 @@
self.dut.droid.bleStartBleAdvertising(
advertise_callback, advertise_data, advertise_settings)
if self._verify_ble_adv_started(advertise_callback):
- self.log.info("Tracking Callback ID: {}".format(
- advertise_callback))
+ self.log.info(
+ "Tracking Callback ID: {}".format(advertise_callback))
self.advertisement_list.append(advertise_callback)
self.log.info(self.advertisement_list)
def start_connectable_advertisement_set(self, line):
"""Start Connectable Advertisement Set"""
adv_callback = self.dut.droid.bleAdvSetGenCallback()
- adv_data = {"includeDeviceName": True, }
- self.dut.droid.bleAdvSetStartAdvertisingSet({
- "connectable": True,
- "legacyMode": False,
- "primaryPhy": "PHY_LE_1M",
- "secondaryPhy": "PHY_LE_1M",
- "interval": 320
- }, adv_data, None, None, None, 0, 0, adv_callback)
+ adv_data = {
+ "includeDeviceName": True,
+ }
+ self.dut.droid.bleAdvSetStartAdvertisingSet(
+ {
+ "connectable": True,
+ "legacyMode": False,
+ "primaryPhy": "PHY_LE_1M",
+ "secondaryPhy": "PHY_LE_1M",
+ "interval": 320
+ }, adv_data, None, None, None, 0, 0, adv_callback)
evt = self.dut.ed.pop_event(
advertising_set_started.format(adv_callback), self.default_timeout)
set_id = evt['data']['setId']
@@ -151,8 +154,8 @@
self.dut.droid.bleStartBleAdvertising(
advertise_callback, advertise_data, advertise_settings)
if self._verify_ble_adv_started(advertise_callback):
- self.log.info("Tracking Callback ID: {}".format(
- advertise_callback))
+ self.log.info(
+ "Tracking Callback ID: {}".format(advertise_callback))
self.advertisement_list.append(advertise_callback)
self.log.info(self.advertisement_list)
diff --git a/acts/framework/acts/test_utils/bt/bt_coc_test_utils.py b/acts/framework/acts/test_utils/bt/bt_coc_test_utils.py
new file mode 100644
index 0000000..db2aed6
--- /dev/null
+++ b/acts/framework/acts/test_utils/bt/bt_coc_test_utils.py
@@ -0,0 +1,253 @@
+#/usr/bin/env python3.4
+#
+# Copyright 2018 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 logging
+import time
+from acts import utils
+
+from acts.test_utils.bt.bt_constants import bt_default_timeout
+from acts.test_utils.bt.bt_constants import default_bluetooth_socket_timeout_ms
+from acts.test_utils.bt.bt_constants import default_le_data_length
+from acts.test_utils.bt.bt_constants import gatt_phy
+from acts.test_utils.bt.bt_constants import gatt_transport
+from acts.test_utils.bt.bt_constants import l2cap_coc_header_size
+from acts.test_utils.bt.bt_constants import le_connection_interval_time_step
+from acts.test_utils.bt.bt_constants import le_default_supervision_timeout
+from acts.test_utils.bt.bt_test_utils import get_mac_address_of_generic_advertisement
+from acts.test_utils.bt.bt_gatt_utils import setup_gatt_connection
+from acts.test_utils.bt.bt_gatt_utils import disconnect_gatt_connection
+
+log = logging
+
+
+class BtCoCTestUtilsError(Exception):
+ pass
+
+
+def do_multi_connection_throughput(client_ad, list_server_ad,
+ list_client_conn_id, num_iterations,
+ number_buffers, buffer_size):
+ """Throughput measurements from one client to one-or-many servers.
+
+ Args:
+ client_ad: the Android device to perform the write.
+ list_server_ad: the list of Android server devices connected to this client.
+ list_client_conn_id: list of client connection IDs
+ num_iterations: the number of test repetitions.
+ number_buffers: the total number of data buffers to transmit per test.
+ buffer_size: the number of bytes per L2CAP data buffer.
+
+ Returns:
+ Throughput in terms of bytes per second, 0 if test failed.
+ """
+
+ total_num_bytes = 0
+ start_write_time = time.perf_counter()
+ client_ad.log.info(
+ "do_multi_connection_throughput: Before write. Start Time={:f}, "
+ "num_iterations={}, number_buffers={}, buffer_size={}, "
+ "number_buffers*buffer_size={}, num_servers={}".format(
+ start_write_time, num_iterations, number_buffers, buffer_size,
+ number_buffers * buffer_size, len(list_server_ad)))
+
+ if (len(list_server_ad) != len(list_client_conn_id)):
+ client_ad.log.error("do_multi_connection_throughput: invalid "
+ "parameters. Num of list_server_ad({}) != "
+ "list_client_conn({})".format(
+ len(list_server_ad), len(list_client_conn_id)))
+ return 0
+
+ try:
+ for _, client_conn_id in enumerate(list_client_conn_id):
+ client_ad.log.info("do_multi_connection_throughput: "
+ "client_conn_id={}".format(client_conn_id))
+ # Plumb the tx data queue with the first set of data buffers.
+ client_ad.droid.bluetoothConnectionThroughputSend(
+ number_buffers, buffer_size, client_conn_id)
+ except Exception as err:
+ client_ad.log.error("Failed to write data: {}".format(err))
+ return 0
+
+ # Each Loop iteration will write and read one set of buffers.
+ for _ in range(0, (num_iterations - 1)):
+ try:
+ for _, client_conn_id in enumerate(list_client_conn_id):
+ client_ad.droid.bluetoothConnectionThroughputSend(
+ number_buffers, buffer_size, client_conn_id)
+ except Exception as err:
+ client_ad.log.error("Failed to write data: {}".format(err))
+ return 0
+
+ for _, server_ad in enumerate(list_server_ad):
+ try:
+ server_ad.droid.bluetoothConnectionThroughputRead(
+ number_buffers, buffer_size)
+ total_num_bytes += number_buffers * buffer_size
+ except Exception as err:
+ server_ad.log.error("Failed to read data: {}".format(err))
+ return 0
+
+ for _, server_ad in enumerate(list_server_ad):
+ try:
+ server_ad.droid.bluetoothConnectionThroughputRead(
+ number_buffers, buffer_size)
+ total_num_bytes += number_buffers * buffer_size
+ except Exception as err:
+ server_ad.log.error("Failed to read data: {}".format(err))
+ return 0
+
+ end_read_time = time.perf_counter()
+
+ test_time = (end_read_time - start_write_time)
+ if (test_time == 0):
+ client_ad.log.error("Buffer transmits cannot take zero time")
+ return 0
+ data_rate = (1.000 * total_num_bytes) / test_time
+ log.info(
+ "Calculated using total write and read times: total_num_bytes={}, "
+ "test_time={}, data rate={:08.0f} bytes/sec, {:08.0f} bits/sec".format(
+ total_num_bytes, test_time, data_rate, (data_rate * 8)))
+ return data_rate
+
+
+def orchestrate_coc_connection(
+ client_ad,
+ server_ad,
+ is_ble,
+ secured_conn=False,
+ le_connection_interval=0,
+ le_tx_data_length=default_le_data_length,
+ accept_timeout_ms=default_bluetooth_socket_timeout_ms):
+ """Sets up the CoC connection between two Android devices.
+
+ Args:
+ client_ad: the Android device performing the connection.
+ server_ad: the Android device accepting the connection.
+ is_ble: using LE transport.
+ secured_conn: using secured connection
+ le_connection_interval: LE Connection interval. 0 means use default.
+ le_tx_data_length: LE Data Length used by BT Controller to transmit.
+ accept_timeout_ms: timeout while waiting for incoming connection.
+ Returns:
+ True if connection was successful or false if unsuccessful,
+ client connection ID,
+ and server connection ID
+ """
+ server_ad.droid.bluetoothStartPairingHelper()
+ client_ad.droid.bluetoothStartPairingHelper()
+
+ adv_callback = None
+ mac_address = None
+ if is_ble:
+ try:
+ # This will start advertising and scanning. Will fail if it could
+ # not find the advertisements from server_ad
+ client_ad.log.info(
+ "Orchestrate_coc_connection: Start BLE advertisement and"
+ "scanning. Secured Connection={}".format(secured_conn))
+ mac_address, adv_callback = (
+ get_mac_address_of_generic_advertisement(client_ad, server_ad))
+ except BtTestUtilsError as err:
+ raise BtCoCTestUtilsError(
+ "Orchestrate_coc_connection: Error in getting mac address: {}".
+ format(err))
+ else:
+ mac_address = server_ad.droid.bluetoothGetLocalAddress()
+ adv_callback = None
+
+ # Adjust the Connection Interval (if necessary)
+ bluetooth_gatt_1 = -1
+ gatt_callback_1 = -1
+ if (le_connection_interval != 0) and is_ble:
+ client_ad.log.info(
+ "Adjusting connection interval={}".format(le_connection_interval))
+ try:
+ bluetooth_gatt_1, gatt_callback_1 = setup_gatt_connection(
+ client_ad,
+ mac_address,
+ False,
+ transport=gatt_transport['le'],
+ opportunistic=False)
+ except GattTestUtilsError as err:
+ client_ad.log.error(err)
+ return False, None, None
+ client_ad.log.info("setup_gatt_connection returns success")
+ minInterval = le_connection_interval / le_connection_interval_time_step
+ maxInterval = le_connection_interval / le_connection_interval_time_step
+ return_status = client_ad.droid.gattClientRequestLeConnectionParameters(
+ bluetooth_gatt_1, minInterval, maxInterval, 0,
+ le_default_supervision_timeout)
+ if not return_status:
+ client_ad.log.error(
+ "gattClientRequestLeConnectionParameters returns failure")
+ return False, None, None
+ client_ad.log.info(
+ "gattClientRequestLeConnectionParameters returns success. Interval={}"
+ .format(minInterval))
+ # For now, we will only test with 1 Mbit Phy.
+ # TODO: Add explicit tests with 2 MBit Phy.
+ client_ad.droid.gattClientSetPreferredPhy(
+ bluetooth_gatt_1, gatt_phy['1m'], gatt_phy['1m'], 0)
+
+ server_ad.droid.bluetoothSocketConnBeginAcceptThreadPsm(
+ accept_timeout_ms, is_ble, secured_conn)
+
+ psm_value = server_ad.droid.bluetoothSocketConnGetPsm()
+ client_ad.log.info("Assigned PSM value={}".format(psm_value))
+
+ client_ad.droid.bluetoothSocketConnBeginConnectThreadPsm(
+ mac_address, is_ble, psm_value, secured_conn)
+
+ if (le_tx_data_length != default_le_data_length) and is_ble:
+ client_ad.log.info("orchestrate_coc_connection: call "
+ "bluetoothSocketRequestMaximumTxDataLength")
+ client_ad.droid.bluetoothSocketRequestMaximumTxDataLength()
+
+ end_time = time.time() + bt_default_timeout
+ test_result = False
+ while time.time() < end_time:
+ if len(server_ad.droid.bluetoothSocketConnActiveConnections()) > 0:
+ server_ad.log.info("CoC Server Connection Active")
+ if len(client_ad.droid.bluetoothSocketConnActiveConnections()) > 0:
+ client_ad.log.info("CoC Client Connection Active")
+ test_result = True
+ break
+ time.sleep(1)
+ if not test_result:
+ client_ad.log.error("Failed to establish an CoC connection")
+ return False, None
+
+ if len(client_ad.droid.bluetoothSocketConnActiveConnections()) > 0:
+ server_ad.log.info(
+ "CoC client_ad Connection Active, num=%d",
+ len(client_ad.droid.bluetoothSocketConnActiveConnections()))
+ else:
+ server_ad.log.info("Error CoC client_ad Connection Inactive")
+ client_ad.log.info("Error CoC client_ad Connection Inactive")
+
+ # Get the conn_id
+ client_conn_id = client_ad.droid.bluetoothGetLastConnId()
+ server_conn_id = server_ad.droid.bluetoothGetLastConnId()
+ client_ad.log.info(
+ "orchestrate_coc_connection: client conn id={}, server conn id={}".
+ format(client_conn_id, server_conn_id))
+
+ if (le_connection_interval != 0) and is_ble:
+ disconnect_gatt_connection(client_ad, bluetooth_gatt_1,
+ gatt_callback_1)
+ client_ad.droid.gattClientClose(bluetooth_gatt_1)
+
+ return True, client_conn_id, server_conn_id
diff --git a/acts/framework/acts/test_utils/bt/bt_constants.py b/acts/framework/acts/test_utils/bt/bt_constants.py
index 7a55aa4..0d9c5f0 100644
--- a/acts/framework/acts/test_utils/bt/bt_constants.py
+++ b/acts/framework/acts/test_utils/bt/bt_constants.py
@@ -18,10 +18,21 @@
bt_default_timeout = 15
default_rfcomm_timeout_ms = 10000
+default_bluetooth_socket_timeout_ms = 10000
pan_connect_timeout = 5
bt_discovery_timeout = 3
small_timeout = 0.0001
+# LE specifications related constants
+le_connection_interval_time_step = 1.25
+le_default_supervision_timeout = 2000
+default_le_data_length = 23
+
+# Headers of LE L2CAP Connection-oriented Channels. See section 3.4, Vol 3, Part A, Version 5.0.
+l2cap_header_size = 4
+l2cap_coc_sdu_length_field_size = 2
+l2cap_coc_header_size = l2cap_header_size + l2cap_coc_sdu_length_field_size
+
java_integer = {"min": -2147483648, "max": 2147483647}
btsnoop_log_path_on_device = "/data/misc/bluetooth/logs/btsnoop_hci.log"
@@ -72,6 +83,9 @@
rfcomm_secure_uuid = "fa87c0d0-afac-11de-8a39-0800200c9a66"
rfcomm_insecure_uuid = "8ce255c0-200a-11e0-ac64-0800200c9a66"
+# bluetooth socket connection test uuid
+bluetooth_socket_conn_test_uuid = "12345678-1234-5678-9abc-123456789abc"
+
# Bluetooth Adapter Scan Mode Types
bt_scan_mode_types = {
"state_off": -1,
@@ -159,6 +173,20 @@
"undefined": -1
}
+# Bluetooth HID constants.
+hid_connection_timeout = 5
+
+# Bluetooth HID EventFacade constants.
+hid_on_set_report_event = "onSetReport"
+hid_on_get_report_event = "onGetReport"
+hid_on_set_protocol_event = "onSetProtocol"
+hid_on_intr_data_event = "onInterruptData"
+hid_on_virtual_cable_unplug_event = "onVirtualCableUnplug"
+hid_id_keyboard = 1
+hid_id_mouse = 2
+hid_default_event_timeout = 15
+hid_default_set_report_payload = "Haha"
+
### Bluetooth Constants End ###
### Bluetooth Low Energy Constants Begin ###
@@ -238,28 +266,40 @@
gatt_cb_err = {
"char_write_req_err":
"Characteristic Write Request event not found. Expected {}",
- "char_write_err": "Characteristic Write event not found. Expected {}",
+ "char_write_err":
+ "Characteristic Write event not found. Expected {}",
"desc_write_req_err":
"Descriptor Write Request event not found. Expected {}",
- "desc_write_err": "Descriptor Write event not found. Expected {}",
- "char_read_err": "Characteristic Read event not found. Expected {}",
- "char_read_req_err": "Characteristic Read Request not found. Expected {}",
- "desc_read_err": "Descriptor Read event not found. Expected {}",
+ "desc_write_err":
+ "Descriptor Write event not found. Expected {}",
+ "char_read_err":
+ "Characteristic Read event not found. Expected {}",
+ "char_read_req_err":
+ "Characteristic Read Request not found. Expected {}",
+ "desc_read_err":
+ "Descriptor Read event not found. Expected {}",
"desc_read_req_err":
"Descriptor Read Request event not found. Expected {}",
- "rd_remote_rssi_err": "Read Remote RSSI event not found. Expected {}",
+ "rd_remote_rssi_err":
+ "Read Remote RSSI event not found. Expected {}",
"gatt_serv_disc_err":
"GATT Services Discovered event not found. Expected {}",
- "serv_added_err": "Service Added event not found. Expected {}",
- "mtu_changed_err": "MTU Changed event not found. Expected {}",
- "mtu_serv_changed_err": "MTU Server Changed event not found. Expected {}",
+ "serv_added_err":
+ "Service Added event not found. Expected {}",
+ "mtu_changed_err":
+ "MTU Changed event not found. Expected {}",
+ "mtu_serv_changed_err":
+ "MTU Server Changed event not found. Expected {}",
"gatt_conn_changed_err":
"GATT Connection Changed event not found. Expected {}",
"char_change_err":
"GATT Characteristic Changed event not fond. Expected {}",
- "phy_read_err": "Phy Read event not fond. Expected {}",
- "phy_update_err": "Phy Update event not fond. Expected {}",
- "exec_write_err": "GATT Execute Write event not found. Expected {}"
+ "phy_read_err":
+ "Phy Read event not fond. Expected {}",
+ "phy_update_err":
+ "Phy Update event not fond. Expected {}",
+ "exec_write_err":
+ "GATT Execute Write event not found. Expected {}"
}
# GATT callback strings as defined in GattClientFacade.java and
@@ -511,3 +551,32 @@
}
### Bluetooth GATT Constants End ###
+
+### Chameleon Constants Begin ###
+
+# Chameleon audio bits per sample.
+audio_bits_per_sample_16 = 16
+audio_bits_per_sample_24 = 24
+audio_bits_per_sample_32 = 32
+
+# Chameleon audio sample rates.
+audio_sample_rate_44100 = 44100
+audio_sample_rate_48000 = 48000
+audio_sample_rate_88200 = 88200
+audio_sample_rate_96000 = 96000
+
+# Chameleon audio channel modes.
+audio_channel_mode_mono = 1
+audio_channel_mode_stereo = 2
+audio_channel_mode_8 = 8
+
+# Chameleon time delays.
+delay_after_binding_seconds = 0.5
+delay_before_record_seconds = 0.5
+silence_wait_seconds = 5
+
+# Chameleon bus endpoints.
+fpga_linein_bus_endpoint = 'Chameleon FPGA line-in'
+headphone_bus_endpoint = 'Cros device headphone'
+
+### Chameleon Constants End ###
diff --git a/acts/framework/acts/test_utils/bt/bt_gatt_utils.py b/acts/framework/acts/test_utils/bt/bt_gatt_utils.py
index 3f80d68..1e4d5b9 100644
--- a/acts/framework/acts/test_utils/bt/bt_gatt_utils.py
+++ b/acts/framework/acts/test_utils/bt/bt_gatt_utils.py
@@ -61,9 +61,9 @@
cen_ad.droid.gattClientClose(bluetooth_gatt)
except Exception:
self.log.debug("Failed to close gatt client.")
- raise GattTestUtilsError(
- "Could not establish a connection to "
- "peripheral. Expected event: {}".format(expected_event))
+ raise GattTestUtilsError("Could not establish a connection to "
+ "peripheral. Event Details: {}".format(
+ pprint.pformat(event)))
return bluetooth_gatt, gatt_callback
diff --git a/acts/framework/acts/test_utils/bt/bt_metrics_utils.py b/acts/framework/acts/test_utils/bt/bt_metrics_utils.py
index ba9a1b6..3ed6f11 100644
--- a/acts/framework/acts/test_utils/bt/bt_metrics_utils.py
+++ b/acts/framework/acts/test_utils/bt/bt_metrics_utils.py
@@ -31,9 +31,5 @@
proto_native_str_64 = \
ad.adb.shell("/system/bin/dumpsys bluetooth_manager --proto-bin")
proto_native_str = base64.b64decode(proto_native_str_64)
- proto_java_str_64 = \
- ad.adb.shell("/system/bin/dumpsys bluetooth_manager --proto-java-bin")
- proto_java_str = base64.b64decode(proto_java_str_64)
bluetooth_log.MergeFromString(proto_native_str)
- bluetooth_log.MergeFromString(proto_java_str)
return bluetooth_log
diff --git a/acts/framework/acts/test_utils/bt/bt_test_utils.py b/acts/framework/acts/test_utils/bt/bt_test_utils.py
index 5658408..f51e476 100644
--- a/acts/framework/acts/test_utils/bt/bt_test_utils.py
+++ b/acts/framework/acts/test_utils/bt/bt_test_utils.py
@@ -57,12 +57,14 @@
from acts.test_utils.bt.bt_constants import btsnoop_last_log_path_on_device
from acts.test_utils.bt.bt_constants import btsnoop_log_path_on_device
from acts.test_utils.bt.bt_constants import default_rfcomm_timeout_ms
+from acts.test_utils.bt.bt_constants import default_bluetooth_socket_timeout_ms
from acts.test_utils.bt.bt_constants import mtu_changed
from acts.test_utils.bt.bt_constants import pairing_variant_passkey_confirmation
from acts.test_utils.bt.bt_constants import pan_connect_timeout
from acts.test_utils.bt.bt_constants import small_timeout
from acts.test_utils.bt.bt_constants import scan_result
from acts.test_utils.bt.bt_constants import scan_failed
+from acts.test_utils.bt.bt_constants import hid_id_keyboard
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
from acts.test_utils.tel.tel_test_utils import verify_http_connection
from acts.utils import exe_cmd
@@ -103,8 +105,8 @@
event = scn_ad.ed.pop_event(
scan_result.format(scan_callback), bt_default_timeout)
except Empty as error:
- raise BtTestUtilsError("Failed to find scan event: {}".format(
- error))
+ raise BtTestUtilsError(
+ "Failed to find scan event: {}".format(error))
address = event['data']['Result']['deviceInfo']['address']
if address not in address_list:
address_list.append(address)
@@ -141,8 +143,8 @@
adv_ad.log.info("Advertisement {} started.".format(i + 1))
except Empty as error:
adv_ad.log.error("Advertisement {} failed to start.".format(i + 1))
- raise BtTestUtilsError("Test failed with Empty error: {}".format(
- error))
+ raise BtTestUtilsError(
+ "Test failed with Empty error: {}".format(error))
return advertise_callback_list
@@ -229,7 +231,7 @@
d = a.droid
# TODO: Create specific RPC command to instantiate
# BluetoothConnectionFacade. This is just a workaround.
- d.bluetoothStartConnectionStateChangeMonitor("");
+ d.bluetoothStartConnectionStateChangeMonitor("")
setup_result = d.bluetoothSetLocalName(generate_id_by_size(4))
if not setup_result:
a.log.error("Failed to set device name.")
@@ -356,8 +358,8 @@
small_timeout)
if evt[0]["name"] == adv_succ.format(advertise_callback):
advertisement_count += 1
- android_device.log.info("Advertisement {} started.".format(
- advertisement_count))
+ android_device.log.info(
+ "Advertisement {} started.".format(advertisement_count))
else:
error = evt[0]["data"]["Error"]
if error == "ADVERTISE_FAILED_TOO_MANY_ADVERTISERS":
@@ -405,8 +407,9 @@
max_tries = 3
#Retry to calculate max advertisements
while max_advertisements == -1 and max_tries > 0:
- a.log.info("Attempts left to determine max advertisements: {}".
- format(max_tries))
+ a.log.info(
+ "Attempts left to determine max advertisements: {}".format(
+ max_tries))
max_advertisements = determine_max_advertisements(a)
max_tries -= 1
advertisements_to_devices[model] = max_advertisements
@@ -508,8 +511,8 @@
event = scan_ad.ed.pop_event(
"BleScan{}onScanResults".format(scan_callback), bt_default_timeout)
except Empty as err:
- raise BtTestUtilsError("Scanner did not find advertisement {}".format(
- err))
+ raise BtTestUtilsError(
+ "Scanner did not find advertisement {}".format(err))
mac_address = event['data']['Result']['deviceInfo']['address']
scan_ad.droid.bleStopBleScan(scan_callback)
return mac_address, advertise_callback
@@ -647,8 +650,7 @@
"""Sets the priority of said profile(s) on host_ad for client_ad"""
for profile in profiles:
host_ad.log.info("Profile {} on {} for {} set to priority {}".format(
- profile,
- host_ad.droid.bluetoothGetLocalName(),
+ profile, host_ad.droid.bluetoothGetLocalName(),
client_ad.droid.bluetoothGetLocalAddress(), priority.value))
if bt_profile_constants['a2dp_sink'] == profile:
host_ad.droid.bluetoothA2dpSinkSetPriority(
@@ -712,8 +714,8 @@
timeout=bt_default_timeout)
pri_variant = pri_pairing_req["data"]["PairingVariant"]
pri_pin = pri_pairing_req["data"]["Pin"]
- pri_ad.log.info("Primary device received Pin: {}, Variant: {}"
- .format(pri_pin, pri_variant))
+ pri_ad.log.info("Primary device received Pin: {}, Variant: {}".format(
+ pri_pin, pri_variant))
sec_pairing_req = sec_ad.ed.pop_event(
event_name="BluetoothActionPairingRequest",
timeout=bt_default_timeout)
@@ -723,8 +725,8 @@
.format(sec_pin, sec_variant))
except Empty as err:
log.error("Wait for pin error: {}".format(err))
- log.error("Pairing request state, Primary: {}, Secondary: {}"
- .format(pri_pairing_req, sec_pairing_req))
+ log.error("Pairing request state, Primary: {}, Secondary: {}".format(
+ pri_pairing_req, sec_pairing_req))
return False
if pri_variant == sec_variant == pairing_variant_passkey_confirmation:
confirmation = pri_pin == sec_pin
@@ -842,34 +844,34 @@
# Now try to connect them, the following call will try to initiate all
# connections.
- pri_ad.droid.bluetoothConnectBonded(sec_ad.droid.bluetoothGetLocalAddress(
- ))
+ pri_ad.droid.bluetoothConnectBonded(
+ sec_ad.droid.bluetoothGetLocalAddress())
end_time = time.time() + 10
profile_connected = set()
sec_addr = sec_ad.droid.bluetoothGetLocalAddress()
pri_ad.log.info("Profiles to be connected {}".format(profiles_set))
# First use APIs to check profile connection state
- while (time.time() < end_time and
- not profile_connected.issuperset(profiles_set)):
- if (bt_profile_constants['headset_client'] not in profile_connected and
- bt_profile_constants['headset_client'] in profiles_set):
+ while (time.time() < end_time
+ and not profile_connected.issuperset(profiles_set)):
+ if (bt_profile_constants['headset_client'] not in profile_connected
+ and bt_profile_constants['headset_client'] in profiles_set):
if is_hfp_client_device_connected(pri_ad, sec_addr):
profile_connected.add(bt_profile_constants['headset_client'])
- if (bt_profile_constants['a2dp'] not in profile_connected and
- bt_profile_constants['a2dp'] in profiles_set):
+ if (bt_profile_constants['a2dp'] not in profile_connected
+ and bt_profile_constants['a2dp'] in profiles_set):
if is_a2dp_src_device_connected(pri_ad, sec_addr):
profile_connected.add(bt_profile_constants['a2dp'])
- if (bt_profile_constants['a2dp_sink'] not in profile_connected and
- bt_profile_constants['a2dp_sink'] in profiles_set):
+ if (bt_profile_constants['a2dp_sink'] not in profile_connected
+ and bt_profile_constants['a2dp_sink'] in profiles_set):
if is_a2dp_snk_device_connected(pri_ad, sec_addr):
profile_connected.add(bt_profile_constants['a2dp_sink'])
- if (bt_profile_constants['map_mce'] not in profile_connected and
- bt_profile_constants['map_mce'] in profiles_set):
+ if (bt_profile_constants['map_mce'] not in profile_connected
+ and bt_profile_constants['map_mce'] in profiles_set):
if is_map_mce_device_connected(pri_ad, sec_addr):
profile_connected.add(bt_profile_constants['map_mce'])
- if (bt_profile_constants['map'] not in profile_connected and
- bt_profile_constants['map'] in profiles_set):
+ if (bt_profile_constants['map'] not in profile_connected
+ and bt_profile_constants['map'] in profiles_set):
if is_map_mse_device_connected(pri_ad, sec_addr):
profile_connected.add(bt_profile_constants['map'])
time.sleep(0.1)
@@ -892,8 +894,8 @@
if state == bt_profile_states['connected'] and \
device_addr == sec_ad.droid.bluetoothGetLocalAddress():
profile_connected.add(profile)
- pri_ad.log.info("Profiles connected until now {}".format(
- profile_connected))
+ pri_ad.log.info(
+ "Profiles connected until now {}".format(profile_connected))
# Failure happens inside the while loop. If we came here then we already
# connected.
return True
@@ -951,8 +953,8 @@
if state == bt_profile_states['disconnected'] and \
device_addr == sec_ad.droid.bluetoothGetLocalAddress():
profile_disconnected.add(profile)
- pri_ad.log.info("Profiles disconnected so far {}".format(
- profile_disconnected))
+ pri_ad.log.info(
+ "Profiles disconnected so far {}".format(profile_disconnected))
return True
@@ -998,8 +1000,8 @@
snoop_path + '/' + out_name, ".btsnoop_hci.log.last"))
exe_cmd(cmd)
except Exception as err:
- testcase.log.info("File does not exist {}".format(
- btsnoop_last_log_path_on_device))
+ testcase.log.info(
+ "File does not exist {}".format(btsnoop_last_log_path_on_device))
def kill_bluetooth_process(ad):
@@ -1026,32 +1028,50 @@
Returns:
True if connection was successful, false if unsuccessful.
"""
+ result = orchestrate_bluetooth_socket_connection(
+ client_ad, server_ad, accept_timeout_ms,
+ (bt_rfcomm_uuids['default_uuid'] if uuid is None else uuid))
+
+ return result
+
+
+def orchestrate_bluetooth_socket_connection(
+ client_ad,
+ server_ad,
+ accept_timeout_ms=default_bluetooth_socket_timeout_ms,
+ uuid=None):
+ """Sets up the Bluetooth Socket connection between two Android devices.
+
+ Args:
+ client_ad: the Android device performing the connection.
+ server_ad: the Android device accepting the connection.
+ Returns:
+ True if connection was successful, false if unsuccessful.
+ """
server_ad.droid.bluetoothStartPairingHelper()
client_ad.droid.bluetoothStartPairingHelper()
- if not uuid:
- server_ad.droid.bluetoothRfcommBeginAcceptThread(
- bt_rfcomm_uuids['default_uuid'], accept_timeout_ms)
- client_ad.droid.bluetoothRfcommBeginConnectThread(
- server_ad.droid.bluetoothGetLocalAddress(),
- bt_rfcomm_uuids['default_uuid'])
- else:
- server_ad.droid.bluetoothRfcommBeginAcceptThread(uuid,
- accept_timeout_ms)
- client_ad.droid.bluetoothRfcommBeginConnectThread(
- server_ad.droid.bluetoothGetLocalAddress(), uuid)
+
+ server_ad.droid.bluetoothSocketConnBeginAcceptThreadUuid(
+ (bluetooth_socket_conn_test_uuid
+ if uuid is None else uuid), accept_timeout_ms)
+ client_ad.droid.bluetoothSocketConnBeginConnectThreadUuid(
+ server_ad.droid.bluetoothGetLocalAddress(),
+ (bluetooth_socket_conn_test_uuid if uuid is None else uuid))
+
end_time = time.time() + bt_default_timeout
result = False
test_result = True
while time.time() < end_time:
- if len(client_ad.droid.bluetoothRfcommActiveConnections()) > 0:
+ if len(client_ad.droid.bluetoothSocketConnActiveConnections()) > 0:
test_result = True
- client_ad.log.info("RFCOMM Client Connection Active")
+ client_ad.log.info("Bluetooth socket Client Connection Active")
break
else:
test_result = False
time.sleep(1)
if not test_result:
- client_ad.log.error("Failed to establish an RFCOMM connection")
+ client_ad.log.error(
+ "Failed to establish a Bluetooth socket connection")
return False
return True
@@ -1071,19 +1091,19 @@
client_ad.log.info("Write message.")
try:
if binary:
- client_ad.droid.bluetoothRfcommWriteBinary(msg)
+ client_ad.droid.bluetoothSocketConnWriteBinary(msg)
else:
- client_ad.droid.bluetoothRfcommWrite(msg)
+ client_ad.droid.bluetoothSocketConnWrite(msg)
except Exception as err:
client_ad.log.error("Failed to write data: {}".format(err))
return False
server_ad.log.info("Read message.")
try:
if binary:
- read_msg = server_ad.droid.bluetoothRfcommReadBinary().rstrip(
+ read_msg = server_ad.droid.bluetoothSocketConnReadBinary().rstrip(
"\r\n")
else:
- read_msg = server_ad.droid.bluetoothRfcommRead()
+ read_msg = server_ad.droid.bluetoothSocketConnRead()
except Exception as err:
server_ad.log.error("Failed to read data: {}".format(err))
return False
@@ -1127,13 +1147,13 @@
false if unsuccessful.
"""
test_result = True
- if len(server_ad.droid.bluetoothRfcommActiveConnections()) == 0:
+ if len(server_ad.droid.bluetoothSocketConnActiveConnections()) == 0:
if log:
- server_ad.log.error("No rfcomm connections found on server.")
+ server_ad.log.error("No socket connections found on server.")
test_result = False
- if len(client_ad.droid.bluetoothRfcommActiveConnections()) == 0:
+ if len(client_ad.droid.bluetoothSocketConnActiveConnections()) == 0:
if log:
- client_ad.log.error("No rfcomm connections found on client.")
+ client_ad.log.error("No socket connections found on client.")
test_result = False
return test_result
@@ -1260,3 +1280,33 @@
return True
return False
+
+def hid_keyboard_report(key, modifier="00"):
+ """Get the HID keyboard report for the given key
+
+ Args:
+ key: the key we want
+ modifier: HID keyboard modifier bytes
+ Returns:
+ The byte array for the HID report.
+ """
+ return str(
+ bytearray.fromhex(" ".join(
+ [modifier, "00", key, "00", "00", "00", "00", "00"])), "utf-8")
+
+
+def hid_device_send_key_data_report(host_id, device_ad, key, interval=1):
+ """Send a HID report simulating a 1-second keyboard press from host_ad to
+ device_ad
+
+ Args:
+ host_id: the Bluetooth MAC address or name of the HID host
+ device_ad: HID device
+ key: the key we want to send
+ interval: the interval between key press and key release
+ """
+ device_ad.droid.bluetoothHidDeviceSendReport(host_id, hid_id_keyboard,
+ hid_keyboard_report(key))
+ time.sleep(interval)
+ device_ad.droid.bluetoothHidDeviceSendReport(host_id, hid_id_keyboard,
+ hid_keyboard_report("00"))
diff --git a/acts/framework/acts/test_utils/bt/bta_lib.py b/acts/framework/acts/test_utils/bt/bta_lib.py
new file mode 100644
index 0000000..f75ff6b
--- /dev/null
+++ b/acts/framework/acts/test_utils/bt/bta_lib.py
@@ -0,0 +1,110 @@
+#/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.
+"""
+Bluetooth adapter libraries
+"""
+
+from acts.test_utils.bt.bt_constants import bt_scan_mode_types
+from acts.test_utils.bt.bt_test_utils import set_bt_scan_mode
+
+import pprint
+
+
+class BtaLib():
+ def __init__(self, log, mac_addr, dut):
+ self.advertisement_list = []
+ self.dut = dut
+ self.log = log
+ self.mac_addr = mac_addr
+
+ def set_scan_mode(self, scan_mode):
+ """Set the Scan mode of the Bluetooth Adapter"""
+ for mode in bt_scan_mode_types:
+ if scan_mode == mode.name:
+ set_bt_scan_mode(self.dut, mode.value)
+ return
+
+ def set_device_name(self, line):
+ """Set Bluetooth Adapter Name"""
+ self.dut.droid.bluetoothSetLocalName(line)
+
+ def enable(self):
+ """Enable Bluetooth Adapter"""
+ self.dut.droid.bluetoothToggleState(True)
+
+ def disable(self):
+ """Disable Bluetooth Adapter"""
+ self.dut.droid.bluetoothToggleState(False)
+
+ def init_bond(self):
+ """Initiate bond to PTS device"""
+ self.dut.droid.bluetoothDiscoverAndBond(self.mac_addr)
+
+ def start_discovery(self):
+ """Start BR/EDR Discovery"""
+ self.dut.droid.bluetoothStartDiscovery()
+
+ def stop_discovery(self):
+ """Stop BR/EDR Discovery"""
+ self.dut.droid.bluetoothCancelDiscovery()
+
+ def get_discovered_devices(self):
+ """Get Discovered Br/EDR Devices"""
+ if self.dut.droid.bluetoothIsDiscovering():
+ self.dut.droid.bluetoothCancelDiscovery()
+ self.log.info(
+ pprint.pformat(self.dut.droid.bluetoothGetDiscoveredDevices()))
+
+ def bond(self):
+ """Bond to PTS device"""
+ self.dut.droid.bluetoothBond(self.mac_addr)
+
+ def disconnect(self):
+ """BTA disconnect"""
+ self.dut.droid.bluetoothDisconnectConnected(self.mac_addr)
+
+ def unbond(self):
+ """Unbond from PTS device"""
+ self.dut.droid.bluetoothUnbond(self.mac_addr)
+
+ def start_pairing_helper(self, line):
+ """Start or stop Bluetooth Pairing Helper"""
+ if line:
+ self.dut.droid.bluetoothStartPairingHelper(bool(line))
+ else:
+ self.dut.droid.bluetoothStartPairingHelper()
+
+ def push_pairing_pin(self, line):
+ """Push pairing pin to the Android Device"""
+ self.dut.droid.eventPost("BluetoothActionPairingRequestUserConfirm",
+ line)
+
+ def get_pairing_pin(self):
+ """Get pairing PIN"""
+ self.log.info(
+ self.dut.ed.pop_event("BluetoothActionPairingRequest", 1))
+
+ def fetch_uuids_with_sdp(self):
+ """BTA fetch UUIDS with SDP"""
+ self.log.info(self.dut.droid.bluetoothFetchUuidsWithSdp(self.mac_addr))
+
+ def connect_profiles(self):
+ """Connect available profiles"""
+ self.dut.droid.bluetoothConnectBonded(self.mac_addr)
+
+ def tts_speak(self):
+ """Open audio channel by speaking characters"""
+ self.dut.droid.ttsSpeak(self.mac_addr)
diff --git a/acts/tests/google/bt/pts/config_lib.py b/acts/framework/acts/test_utils/bt/config_lib.py
similarity index 100%
rename from acts/tests/google/bt/pts/config_lib.py
rename to acts/framework/acts/test_utils/bt/config_lib.py
diff --git a/acts/tests/google/bt/pts/configs/bt_stack.conf b/acts/framework/acts/test_utils/bt/configs/bt_stack.conf
similarity index 100%
rename from acts/tests/google/bt/pts/configs/bt_stack.conf
rename to acts/framework/acts/test_utils/bt/configs/bt_stack.conf
diff --git a/acts/tests/google/bt/pts/configs/dis_mitm_bt_stack.conf b/acts/framework/acts/test_utils/bt/configs/dis_mitm_bt_stack.conf
similarity index 100%
rename from acts/tests/google/bt/pts/configs/dis_mitm_bt_stack.conf
rename to acts/framework/acts/test_utils/bt/configs/dis_mitm_bt_stack.conf
diff --git a/acts/tests/google/bt/pts/configs/non_bond_bt_stack.conf b/acts/framework/acts/test_utils/bt/configs/non_bond_bt_stack.conf
similarity index 100%
rename from acts/tests/google/bt/pts/configs/non_bond_bt_stack.conf
rename to acts/framework/acts/test_utils/bt/configs/non_bond_bt_stack.conf
diff --git a/acts/tests/google/bt/pts/gatt_test_database.py b/acts/framework/acts/test_utils/bt/gatt_test_database.py
similarity index 100%
rename from acts/tests/google/bt/pts/gatt_test_database.py
rename to acts/framework/acts/test_utils/bt/gatt_test_database.py
diff --git a/acts/tests/google/bt/pts/gattc_lib.py b/acts/framework/acts/test_utils/bt/gattc_lib.py
similarity index 94%
rename from acts/tests/google/bt/pts/gattc_lib.py
rename to acts/framework/acts/test_utils/bt/gattc_lib.py
index 4bcb0f4..4dfc076 100644
--- a/acts/tests/google/bt/pts/gattc_lib.py
+++ b/acts/framework/acts/test_utils/bt/gattc_lib.py
@@ -130,6 +130,19 @@
self.bluetooth_gatt, self.discovered_services_index,
int(instance_id, 16), write_value)
+ def write_char_by_instance_id_value(self, line):
+ """GATT Client Write to Characteristic by instance ID"""
+ args = line.split()
+ if len(args) != 2:
+ self.log.info("2 Arguments required: [InstanceId] [Size]")
+ return
+ instance_id = args[0]
+ write_value = args[1]
+ self._setup_discovered_services_index()
+ self.dut.droid.gattClientWriteCharacteristicByInstanceId(
+ self.bluetooth_gatt, self.discovered_services_index,
+ int(instance_id, 16), [int(write_value)])
+
def mod_write_char_by_instance_id(self, line):
"""GATT Client Write to Char that doesn't have write permission"""
args = line.split()
@@ -393,8 +406,9 @@
self.bluetooth_gatt,
self.discovered_services_index, i, j, k)
except Exception as err:
- self.log.info("Failed to read to descriptor: {}".
- format(descriptor_uuids[k]))
+ self.log.info(
+ "Failed to read to descriptor: {}".format(
+ descriptor_uuids[k]))
def write_all_char(self, line):
"""Write to every Characteristic on the GATT server"""
@@ -423,8 +437,9 @@
j)
time.sleep(1)
except Exception as err:
- self.log.info("Failed to write to characteristic: {}".
- format(characteristic_uuids[j]))
+ self.log.info(
+ "Failed to write to characteristic: {}".format(
+ characteristic_uuids[j]))
def write_all_desc(self, line):
""" Write to every Descriptor on the GATT server """
@@ -460,8 +475,9 @@
self.bluetooth_gatt,
self.discovered_services_index, i, j, k)
except Exception as err:
- self.log.info("Failed to write to descriptor: {}".
- format(descriptor_uuids[k]))
+ self.log.info(
+ "Failed to write to descriptor: {}".format(
+ descriptor_uuids[k]))
def discover_service_by_uuid(self, line):
""" Discover service by UUID """
diff --git a/acts/tests/google/bt/pts/gatts_lib.py b/acts/framework/acts/test_utils/bt/gatts_lib.py
similarity index 90%
rename from acts/tests/google/bt/pts/gatts_lib.py
rename to acts/framework/acts/test_utils/bt/gatts_lib.py
index 45a7a8d..c341d1a 100644
--- a/acts/tests/google/bt/pts/gatts_lib.py
+++ b/acts/framework/acts/test_utils/bt/gatts_lib.py
@@ -28,8 +28,8 @@
from acts.test_utils.bt.bt_constants import gatt_server_responses
from acts.test_utils.bt.bt_constants import gatt_service_types
from acts.test_utils.bt.bt_constants import small_timeout
+from acts.test_utils.bt.gatt_test_database import STRING_512BYTES
-from gatt_test_database import STRING_512BYTES
from acts.utils import exe_cmd
from math import ceil
@@ -57,14 +57,19 @@
"""From the GATT Client, discover services and list all services,
chars and descriptors.
"""
- self.log.info("Listing Characteristics")
+ self.log.info("Service List:")
+ for service in self.dut.droid.gattGetServiceUuidList(self.gatt_server):
+ self.dut.log.info("GATT Server service uuid: {}".format(service))
+ self.log.info("Characteristics List:")
for characteristic in self.characteristic_list:
instance_id = self.dut.droid.gattServerGetCharacteristicInstanceId(
characteristic)
uuid = self.dut.droid.gattServerGetCharacteristicUuid(
characteristic)
- self.dut.log.info("GATT Server characteristic handle uuid: {} {}".
- format(hex(instance_id), uuid))
+ self.dut.log.info(
+ "GATT Server characteristic handle uuid: {} {}".format(
+ hex(instance_id), uuid))
+ # TODO: add getting insance ids and uuids from each descriptor.
def open(self):
"""Open an empty GATT Server instance"""
@@ -84,8 +89,8 @@
for btgs in self.gatt_server_list:
self.dut.droid.gattServerClose(btgs)
except Exception as err:
- self.log.error("Failed to close Bluetooth GATT Servers: {}".format(
- err))
+ self.log.error(
+ "Failed to close Bluetooth GATT Servers: {}".format(err))
self.characteristic_list = []
self.descriptor_list = []
self.gatt_server_list = []
@@ -128,8 +133,8 @@
self.log.debug("Found event: {}.".format(event))
request_id = event['data']['requestId']
if event['name'] == execute_write:
- if ('execute' in event['data'] and
- event['data']['execute'] == True):
+ if ('execute' in event['data']
+ and event['data']['execute'] == True):
for key in self.write_mapping:
value = self.write_mapping[key]
self.log.info("Writing key, value: {}, {}".format(
@@ -145,12 +150,12 @@
offset = event['data']['offset']
instance_id = event['data']['instanceId']
if (event['name'] == desc_write or event['name'] == char_write):
- if ('preparedWrite' in event['data'] and
- event['data']['preparedWrite'] == True):
+ if ('preparedWrite' in event['data']
+ and event['data']['preparedWrite'] == True):
value = event['data']['value']
if instance_id in self.write_mapping.keys():
- self.write_mapping[instance_id] = self.write_mapping[
- instance_id] + value
+ self.write_mapping[
+ instance_id] = self.write_mapping[instance_id] + value
self.log.info(
"New Prepared Write Value for {}: {}".format(
instance_id, self.write_mapping[instance_id]))
@@ -183,8 +188,8 @@
self.gatt_server, 0, request_id, status, offset, data)
def _setup_service(self, serv):
- service = self.dut.droid.gattServerCreateService(serv['uuid'],
- serv['type'])
+ service = self.dut.droid.gattServerCreateService(
+ serv['uuid'], serv['type'])
if 'handles' in serv:
self.dut.droid.gattServerServiceSetHandlesToReserve(
service, serv['handles'])
@@ -224,8 +229,8 @@
descriptor = self.dut.droid.gattServerCreateBluetoothGattDescriptor(
desc['uuid'], desc['permissions'])
if 'value' in desc:
- self.dut.droid.gattServerDescriptorSetByteValue(descriptor,
- desc['value'])
+ self.dut.droid.gattServerDescriptorSetByteValue(
+ descriptor, desc['value'])
if 'instance_id' in desc:
self.dut.droid.gattServerDescriptorSetInstanceId(
descriptor, desc['instance_id'])
@@ -268,7 +273,7 @@
self.gatt_server_callback)
char_write = gatt_event['char_write']['evt'].format(
self.gatt_server_callback)
- execute_write = gatt_event['char_exec_write']['evt'].format(
+ execute_write = gatt_event['exec_write']['evt'].format(
self.gatt_server_callback)
regex = "({}|{}|{}|{}|{})".format(desc_read, desc_write, char_read,
char_write, execute_write)
@@ -327,8 +332,8 @@
self.log.info(event)
request_id = event['data']['requestId']
if event['name'] == execute_write:
- if ('execute' in event['data'] and
- event['data']['execute'] == True):
+ if ('execute' in event['data']
+ and event['data']['execute'] == True):
for key in self.write_mapping:
value = self.write_mapping[key]
self.log.debug("Writing key, value: {}, {}".format(
@@ -341,15 +346,14 @@
continue
offset = event['data']['offset']
instance_id = event['data']['instanceId']
- if (event['name'] == desc_write or
- event['name'] == char_write):
- if ('preparedWrite' in event['data'] and
- event['data']['preparedWrite'] == True):
+ if (event['name'] == desc_write
+ or event['name'] == char_write):
+ if ('preparedWrite' in event['data']
+ and event['data']['preparedWrite'] == True):
value = event['data']['value']
if instance_id in self.write_mapping:
self.write_mapping[
- instance_id] = self.write_mapping[
- instance_id] + value
+ instance_id] = self.write_mapping[instance_id] + value
else:
self.write_mapping[instance_id] = value
else:
diff --git a/acts/tests/google/bt/pts/rfcomm_lib.py b/acts/framework/acts/test_utils/bt/rfcomm_lib.py
similarity index 90%
rename from acts/tests/google/bt/pts/rfcomm_lib.py
rename to acts/framework/acts/test_utils/bt/rfcomm_lib.py
index 257c929..49b35b6 100644
--- a/acts/tests/google/bt/pts/rfcomm_lib.py
+++ b/acts/framework/acts/test_utils/bt/rfcomm_lib.py
@@ -36,8 +36,8 @@
if len(line) > 0:
uuid = line
if uuid:
- self.dut.droid.bluetoothRfcommBeginConnectThread(self.mac_addr,
- uuid)
+ self.dut.droid.bluetoothRfcommBeginConnectThread(
+ self.mac_addr, uuid)
else:
self.dut.droid.bluetoothRfcommBeginConnectThread(self.mac_addr)
@@ -69,8 +69,8 @@
if uuid:
self.dut.droid.bluetoothRfcommBeginAcceptThread(uuid)
else:
- self.dut.droid.bluetoothRfcommBeginAcceptThread(bt_rfcomm_uuids[
- 'base_uuid'])
+ self.dut.droid.bluetoothRfcommBeginAcceptThread(
+ bt_rfcomm_uuids['base_uuid'])
def stop(self):
"""Stop RFCOMM Connection"""
diff --git a/acts/framework/acts/test_utils/coex/CoexBaseTest.py b/acts/framework/acts/test_utils/coex/CoexBaseTest.py
new file mode 100644
index 0000000..e2c5372
--- /dev/null
+++ b/acts/framework/acts/test_utils/coex/CoexBaseTest.py
@@ -0,0 +1,321 @@
+#/usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 os
+import threading
+import time
+
+from acts.base_test import BaseTestClass
+from acts.controllers.iperf_client import IPerfClient
+from acts.test_utils.bt.bt_test_utils import disable_bluetooth
+from acts.test_utils.bt.bt_test_utils import enable_bluetooth
+from acts.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
+from acts.test_utils.bt.bt_test_utils import take_btsnoop_logs
+from acts.test_utils.coex.coex_test_utils import configure_and_start_ap
+from acts.test_utils.coex.coex_test_utils import iperf_result
+from acts.test_utils.coex.coex_test_utils import get_phone_ip
+from acts.test_utils.coex.coex_test_utils import wifi_connection_check
+from acts.test_utils.coex.coex_test_utils import xlsheet
+from acts.test_utils.wifi.wifi_test_utils import reset_wifi
+from acts.test_utils.wifi.wifi_test_utils import wifi_connect
+from acts.test_utils.wifi.wifi_test_utils import wifi_test_device_init
+from acts.test_utils.wifi.wifi_test_utils import wifi_toggle_state
+from acts.utils import create_dir
+from acts.utils import start_standing_subprocess
+from acts.utils import stop_standing_subprocess
+
+TEST_CASE_TOKEN = "[Test Case]"
+RESULT_LINE_TEMPLATE = TEST_CASE_TOKEN + " %s %s"
+IPERF_SERVER_WAIT_TIME = 5
+
+
+class CoexBaseTest(BaseTestClass):
+
+ def __init__(self, controllers):
+ BaseTestClass.__init__(self, controllers)
+ self.pri_ad = self.android_devices[0]
+ if len(self.android_devices) == 2:
+ self.sec_ad = self.android_devices[1]
+ elif len(self.android_devices) == 3:
+ self.third_ad = self.android_devices[2]
+
+ def setup_class(self):
+ self.tag = 0
+ self.iperf_result = {}
+ self.thread_list = []
+ if not setup_multiple_devices_for_bt_test(self.android_devices):
+ self.log.error("Failed to setup devices for bluetooth test")
+ return False
+ req_params = ["network", "iperf"]
+ self.unpack_userparams(req_params)
+ if "RelayDevice" in self.user_params:
+ self.audio_receiver = self.relay_devices[0]
+ else:
+ self.log.warning("Missing Relay config file.")
+ if "music_file" in self.user_params:
+ self.push_music_to_android_device(self.pri_ad)
+ self.path = self.pri_ad.log_path
+ if "AccessPoints" in self.user_params:
+ self.ap = self.access_points[0]
+ configure_and_start_ap(self.ap, self.network)
+ wifi_test_device_init(self.pri_ad)
+ wifi_connect(self.pri_ad, self.network)
+
+ def setup_test(self):
+ self.received = []
+ for a in self.android_devices:
+ a.ed.clear_all_events()
+ if not wifi_connection_check(self.pri_ad, self.network["SSID"]):
+ self.log.error("Wifi connection does not exist")
+ return False
+ if not enable_bluetooth(self.pri_ad.droid, self.pri_ad.ed):
+ self.log.error("Failed to enable bluetooth")
+ return False
+
+ def teardown_test(self):
+ if not disable_bluetooth(self.pri_ad.droid):
+ self.log.info("Failed to disable bluetooth")
+ return False
+ self.teardown_thread()
+
+ def teardown_class(self):
+ if "AccessPoints" in self.user_params:
+ self.ap.close()
+ reset_wifi(self.pri_ad)
+ wifi_toggle_state(self.pri_ad, False)
+ json_result = self.results.json_str()
+ xlsheet(self.pri_ad, json_result)
+
+ def start_iperf_server_on_shell(self, server_port):
+ """Starts iperf server on android device with specified.
+
+ Args:
+ server_port: Port in which server should be started.
+ """
+ log_path = os.path.join(self.pri_ad.log_path, "iPerf{}".format(
+ server_port))
+ iperf_server = "iperf3 -s -p {} -J".format(server_port)
+ log_files = []
+ create_dir(log_path)
+ out_file_name = "IPerfServer,{},{},{}.log".format(
+ server_port, self.tag, log_files)
+ self.tag = self.tag + 1
+ full_out_path = os.path.join(log_path, out_file_name)
+ cmd = "adb -s {} shell {} > {}".format(
+ self.pri_ad.serial, iperf_server, full_out_path)
+ self.iperf_process.append(start_standing_subprocess(cmd))
+ log_files.append(full_out_path)
+ time.sleep(IPERF_SERVER_WAIT_TIME)
+
+ def stop_iperf_server_on_shell(self):
+ """Stops all the instances of iperf server on shell."""
+ try:
+ for process in self.iperf_process:
+ stop_standing_subprocess(process)
+ except Exception:
+ self.log.info("Iperf server already killed")
+
+ def run_iperf_and_get_result(self):
+ """Frames iperf command based on test and starts iperf client on
+ host machine.
+ """
+ self.flag_list = []
+ self.iperf_process = []
+ test_params = self.current_test_name.split("_")
+
+ self.protocol = test_params[-2:-1]
+ self.stream = test_params[-1:]
+
+ if self.protocol[0] == "tcp":
+ self.iperf_args = "-t {} -p {} {} -J".format(
+ self.iperf["duration"], self.iperf["port_1"],
+ self.iperf["tcp_window_size"])
+ else:
+ self.iperf_args = ("-t {} -p {} -u {} --get-server-output -J"
+ .format(self.iperf["duration"],
+ self.iperf["port_1"],
+ self.iperf["udp_bandwidth"]))
+
+ if self.stream[0] == "ul":
+ self.iperf_args += " -R"
+
+ if self.protocol[0] == "tcp" and self.stream[0] == "bidirectional":
+ self.bidirectional_args = "-t {} -p {} {} -R -J".format(
+ self.iperf["duration"], self.iperf["port_2"],
+ self.iperf["tcp_window_size"])
+ else:
+ self.bidirectional_args = ("-t {} -p {} -u {} --get-server-output"
+ " -J".format(self.iperf["duration"],
+ self.iperf["port_2"],
+ self.iperf["udp_bandwidth"]
+ ))
+
+ if self.stream[0] == "bidirectional":
+ self.start_iperf_server_on_shell(self.iperf["port_2"])
+ self.start_iperf_server_on_shell(self.iperf["port_1"])
+
+ if self.stream[0] == "bidirectional":
+ args = [
+ lambda: self.run_iperf(self.iperf_args, self.iperf["port_1"]),
+ lambda: self.run_iperf(self.bidirectional_args,
+ self.iperf["port_2"])
+ ]
+ self.run_thread(args)
+ else:
+ args = [
+ lambda: self.run_iperf(self.iperf_args, self.iperf["port_1"])
+ ]
+ self.run_thread(args)
+
+ def run_iperf(self, iperf_args, server_port):
+ """Gets android device ip and start iperf client from host machine to
+ that ip and parses the iperf result.
+
+ Args:
+ iperf_args: Iperf parameters to run traffic.
+ server_port: Iperf port to start client.
+ """
+ ip = get_phone_ip(self.pri_ad)
+ iperf_client = IPerfClient(server_port, ip, self.pri_ad.log_path)
+ result = iperf_client.start(iperf_args)
+ try:
+ sent, received = iperf_result(result, self.stream)
+ self.received.append(str(round(received, 2)) + "Mb/s")
+ self.log.info("Sent: {} Mb/s, Received: {} Mb/s".format(
+ sent, received))
+ self.flag_list.append(True)
+
+ except TypeError:
+ self.log.error("Iperf failed/stopped.")
+ self.flag_list.append(False)
+ self.received.append("Iperf Failed")
+
+ self.iperf_result[self.current_test_name] = self.received
+
+ def on_fail(self, record, test_name, begin_time):
+ self.log.info(
+ "Test {} failed, Fetching Btsnoop logs and bugreport".format(
+ test_name))
+ take_btsnoop_logs(self.android_devices, self, test_name)
+ self._take_bug_report(test_name, begin_time)
+ record.extras = self.received
+
+ def _on_fail(self, record):
+ """Proxy function to guarantee the base implementation of on_fail is
+ called.
+
+ Args:
+ record: The records.TestResultRecord object for the failed test
+ case.
+ """
+ if record.details:
+ self.log.error(record.details)
+ self.log.info(RESULT_LINE_TEMPLATE, record.test_name, record.result)
+ self.on_fail(record, record.test_name, record.log_begin_time)
+
+ def _on_pass(self, record):
+ """Proxy function to guarantee the base implementation of on_pass is
+ called.
+
+ Args:
+ record: The records.TestResultRecord object for the passed test
+ case.
+ """
+ msg = record.details
+ if msg:
+ self.log.info(msg)
+ self.log.info(RESULT_LINE_TEMPLATE, record.test_name, record.result)
+ record.extras = self.received
+
+ def run_thread(self, kwargs):
+ """Convenience function to start thread.
+
+ Args:
+ kwargs: Function object to start in thread.
+ """
+ for function in kwargs:
+ self.thread = threading.Thread(target=function)
+ self.thread_list.append(self.thread)
+ self.thread.start()
+
+ def teardown_result(self):
+ """Convenience function to join thread and fetch iperf result."""
+ for thread_id in self.thread_list:
+ if thread_id.is_alive():
+ thread_id.join()
+ self.stop_iperf_server_on_shell()
+ if False in self.flag_list:
+ return False
+ return True
+
+ def teardown_thread(self):
+ """Convenience function to join thread."""
+ for thread_id in self.thread_list:
+ if thread_id.is_alive():
+ thread_id.join()
+ self.stop_iperf_server_on_shell()
+
+ def push_music_to_android_device(self, ad):
+ """Add music to Android device as specified by the test config
+
+ Args:
+ ad: Android device
+
+ Returns:
+ True on success, False on failure
+ """
+ self.log.info("Pushing music to the Android device")
+ music_path_str = "music_file"
+ 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 type(music_path) is list:
+ self.log.info("Media ready to push as is.")
+ if type(music_path) is list:
+ for item in music_path:
+ self.music_file_to_play = item
+ ad.adb.push("{} {}".format(item, android_music_path))
+ return True
+
+ def avrcp_actions(self):
+ """Performs avrcp controls like volume up, volume down, skip next and
+ skip previous.
+
+ Returns: True if successful, otherwise False.
+ """
+ #TODO: Validate the success state of functionalities performed.
+ self.audio_receiver.volume_up()
+ time.sleep(2)
+ self.audio_receiver.volume_down()
+ time.sleep(2)
+ self.audio_receiver.skip_next()
+ time.sleep(2)
+ self.audio_receiver.skip_previous()
+ time.sleep(2)
+ return True
+
+ def change_volume(self):
+ """Changes volume with HFP call.
+
+ Returns: True if successful, otherwise False.
+ """
+ self.audio_receiver.volume_up()
+ time.sleep(2)
+ self.audio_receiver.volume_down()
+ time.sleep(2)
+ return True
diff --git a/acts/framework/acts/test_utils/coex/bluez_test_utils.py b/acts/framework/acts/test_utils/coex/bluez_test_utils.py
new file mode 100644
index 0000000..5a49a77
--- /dev/null
+++ b/acts/framework/acts/test_utils/coex/bluez_test_utils.py
@@ -0,0 +1,513 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 dbus
+import dbus.mainloop.glib
+import dbus.service
+import logging
+import time
+
+from acts.test_utils.coex.coex_constants import ADAPTER_INTERFACE
+from acts.test_utils.coex.coex_constants import CALL_MANAGER
+from acts.test_utils.coex.coex_constants import DBUS_INTERFACE
+from acts.test_utils.coex.coex_constants import DEVICE_INTERFACE
+from acts.test_utils.coex.coex_constants import DISCOVERY_TIME
+from acts.test_utils.coex.coex_constants import MEDIA_CONTROL_INTERACE
+from acts.test_utils.coex.coex_constants import MEDIA_PLAY_INTERFACE
+from acts.test_utils.coex.coex_constants import OBJECT_MANGER
+from acts.test_utils.coex.coex_constants import OFONO_MANAGER
+from acts.test_utils.coex.coex_constants import PROPERTIES
+from acts.test_utils.coex.coex_constants import PROPERTIES_CHANGED
+from acts.test_utils.coex.coex_constants import SERVICE_NAME
+from acts.test_utils.coex.coex_constants import VOICE_CALL
+from acts.test_utils.coex.coex_constants import WAIT_TIME
+from gi.repository import GObject
+
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+class BluezUtils():
+
+ def __init__(self):
+ devices = {}
+ self.device_interface = False
+ self.mainloop = 0
+ self.property_changed = False
+ self.bd_address = None
+ self.bus = dbus.SystemBus()
+ self.bus.add_signal_receiver(self.properties_changed,
+ dbus_interface=DBUS_INTERFACE,
+ signal_name=PROPERTIES_CHANGED,
+ arg0=DEVICE_INTERFACE,
+ path_keyword="path")
+ self.om = dbus.Interface(
+ self.bus.get_object(SERVICE_NAME, "/"), OBJECT_MANGER)
+ objects = self.om.GetManagedObjects()
+ for path, interfaces in objects.items():
+ if ADAPTER_INTERFACE in interfaces:
+ devices[path] = interfaces[ADAPTER_INTERFACE]
+ self.adapter = self.find_adapter(0)
+
+ def register_signal(self):
+ """Start signal_dispatcher"""
+ self.mainloop = GObject.MainLoop()
+ self.mainloop.run()
+
+ def unregister_signal(self):
+ """Stops signal_dispatcher"""
+ self.mainloop.quit()
+
+ def get_properties(self,props, path, check):
+ """Return's status for parameter check .
+
+ Args:
+ props:dbus interface
+ path:path for getting status
+ check:String for which status need to be checked
+ """
+ return props.Get(path,check)
+
+ def properties_changed(self, interface, changed, invalidated, path):
+ """
+ Function to be executed when specified signal is caught
+ """
+ if path == "/org/bluez/hci0/dev_" + (self.bd_address).replace(":", "_"):
+ self.unregister_signal()
+ return
+
+ def get_managed_objects(self):
+ """Gets the instance of all the objects in dbus.
+
+ Returns:
+ Dictionary containing path and interface of
+ all the instance in dbus.
+ """
+ manager = dbus.Interface(
+ self.bus.get_object(SERVICE_NAME, "/"), OBJECT_MANGER)
+ return manager.GetManagedObjects()
+
+ def find_adapter(self, pattern=None):
+ """Gets the adapter interface with specified pattern in dbus.
+
+ Args:
+ pattern: Adapter name pattern to be found out.
+
+ Returns:
+ Adapter interface with specified pattern.
+ """
+ return self.find_adapter_in_objects(self.get_managed_objects(), pattern)
+
+ def find_adapter_in_objects(self, objects, pattern=None):
+ """Gets the adapter interface with specified pattern in dbus.
+
+ Args:
+ objects: Dictionary containing path and interface of
+ all the instance in dbus.
+ pattern: Adapter name pattern to be found out.
+
+ Returns:
+ Adapter interface if successful else raises an exception.
+ """
+ for path, ifaces in objects.items():
+ adapter = ifaces.get(ADAPTER_INTERFACE)
+ if adapter is None:
+ continue
+ if not pattern or pattern == adapter["Address"] or \
+ path.endswith(pattern):
+ adapter_obj = self.bus.get_object(SERVICE_NAME, path)
+ return dbus.Interface(adapter_obj, ADAPTER_INTERFACE)
+ raise Exception("Bluetooth adapter not found")
+
+ def find_device_in_objects(self,
+ objects,
+ device_address,
+ adapter_pattern=None):
+ """Gets the device interface in objects with specified device
+ address and pattern.
+
+ Args:
+ objects: Dictionary containing path and interface of
+ all the instance in dbus.
+ device_address: Bluetooth interface MAC address of the device
+ which is to be found out.
+ adapter_pattern: Adapter name pattern to be found out.
+
+ Returns:
+ Device interface if successful else raises an exception.
+ """
+ path_prefix = ""
+ if adapter_pattern:
+ adapter = self.find_adapter_in_objects(objects, adapter_pattern)
+ path_prefix = adapter.object_path
+ for path, ifaces in objects.items():
+ device = ifaces.get(DEVICE_INTERFACE)
+ if device is None:
+ continue
+ if (device["Address"] == device_address and
+ path.startswith(path_prefix)):
+ device_obj = self.bus.get_object(SERVICE_NAME, path)
+ return dbus.Interface(device_obj, DEVICE_INTERFACE)
+ raise Exception("Bluetooth device not found")
+
+ def get_bluetooth_adapter_address(self):
+ """Gets the bluetooth adapter address.
+
+ Returns:
+ Address of bluetooth adapter.
+ """
+ path = self.adapter.object_path
+ props = dbus.Interface(
+ self.bus.get_object(SERVICE_NAME, path), PROPERTIES)
+ address = props.Get(ADAPTER_INTERFACE, "Address")
+ return address
+
+ def find_device(self, device_address):
+ """Discovers the DUT and returns its dbus interface.
+
+ Args:
+ Device_address: Bluetooth interface MAC address of the device.
+
+ Returns:
+ Dbus interface of the device.
+ """
+ addr = "dev_" + str(device_address).replace(":", "_")
+ device_path = "org/bluez/hci0/" + addr
+ self.adapter.StartDiscovery()
+ time.sleep(DISCOVERY_TIME)
+ objects = self.om.GetManagedObjects()
+ for path, interfaces in objects.items():
+ if device_path in path:
+ obj = self.bus.get_object(SERVICE_NAME, path)
+ self.device_interface = dbus.Interface(obj, DEVICE_INTERFACE)
+ self.adapter.StopDiscovery()
+ if not self.device_interface:
+ self.adapter.StopDiscovery()
+ return False
+ return True
+
+ def media_control_iface(self, device_address):
+ """Gets the dbus media control interface for the device
+ and returns it.
+
+ Args:
+ device_address: Bluetooth interface MAC address of the device.
+
+ Returns:
+ Dbus media control interface of the device.
+ """
+ control_iface = dbus.Interface(
+ self.bus.get_object(SERVICE_NAME, '/org/bluez/hci0/dev_' +
+ device_address.replace(":", "_")),
+ MEDIA_CONTROL_INTERACE)
+ return control_iface
+
+ def get_a2dp_interface(self, device_address):
+ """Gets the dbus media interface for the device.
+
+ Args:
+ device_address: Bluetooth interface MAC address of the device.
+
+ Returns:
+ Dbus media interface of the device.
+ """
+ a2dp_interface = dbus.Interface(
+ self.bus.get_object(
+ SERVICE_NAME, '/org/bluez/hci0/dev_' +
+ device_address.replace(":", "_") + '/player0'),
+ MEDIA_PLAY_INTERFACE)
+ return a2dp_interface
+
+ def ofo_iface(self):
+ """Gets dbus hfp interface for the device.
+
+ Returns:
+ Dbus hfp interface of the device.
+ """
+ manager = dbus.Interface(
+ self.bus.get_object('org.ofono', '/'), OFONO_MANAGER)
+ modems = manager.GetModems()
+ return modems
+
+ def call_manager(self, path):
+ """Gets Ofono(HFP) interface for the device.
+
+ Args:
+ path: Ofono interface path of the device.
+
+ Returns:
+ Ofono interface for the device.
+ """
+ vcm = dbus.Interface(
+ self.bus.get_object('org.ofono', path), CALL_MANAGER)
+ return vcm
+
+ def answer_call_interface(self, path):
+ """Gets the voice call interface for the device.
+
+ Args
+ path: Voice call path of the device.
+
+ Returns:
+ Interface for the voice call.
+ """
+ call = dbus.Interface(
+ self.bus.get_object('org.ofono', path), VOICE_CALL)
+ return call
+
+ def pair_bluetooth_device(self):
+ """Pairs the bluez machine with DUT.
+
+ Returns:
+ True if pairing is successful else False.
+ """
+ self.device_interface.Pair()
+ path = self.device_interface.object_path
+ props = dbus.Interface(
+ self.bus.get_object(SERVICE_NAME, path), PROPERTIES)
+ paired = self.get_properties(props, DEVICE_INTERFACE, "Paired")
+ return paired
+
+ def connect_bluetooth_device(self, *args):
+ """Connects the bluez machine to DUT with the specified
+ profile.
+
+ Args:
+ uuid: Profile UUID which is to be connected.
+
+ Returns:
+ True if connection is successful else False.
+ """
+
+ self.register_signal()
+ for uuid in args:
+ self.device_interface.ConnectProfile(uuid)
+ path = self.device_interface.object_path
+ props = dbus.Interface(
+ self.bus.get_object(SERVICE_NAME, path), PROPERTIES)
+ connect = self.get_properties(props, DEVICE_INTERFACE, "Connected")
+ return connect
+
+ def disconnect_bluetooth_profile(self, uuid, pri_ad):
+ """Disconnects the DUT for the specified profile.
+
+ Args:
+ uuid: Profile UUID which is to be disconnected.
+ pri_ad: An android device object.
+
+ Returns:
+ True if disconnection of profile is successful else False.
+ """
+
+ self.register_signal()
+ self.device_interface.DisconnectProfile(uuid)
+ time.sleep(6)
+ connected_devices = pri_ad.droid.bluetoothGetConnectedDevices()
+ if len(connected_devices) > 0:
+ return False
+ return True
+
+ def play_media(self, address):
+ """Initiate media play for the specified device.
+
+ Args:
+ address: Bluetooth interface MAC address of the device.
+
+ Returns:
+ "playing" if successful else "stopped" or "paused".
+ """
+ self.register_signal()
+ a2dp = self.media_control_iface(address)
+ time.sleep(WAIT_TIME)
+ a2dp.Play()
+ play_pause = self.get_a2dp_interface(address)
+ path = play_pause.object_path
+ time.sleep(WAIT_TIME)
+ props = dbus.Interface(
+ self.bus.get_object(SERVICE_NAME, path), PROPERTIES)
+ status = self.get_properties(props, MEDIA_PLAY_INTERFACE, "Status")
+ return status
+
+ def pause_media(self, address):
+ """Pauses the media palyer for the specified device.
+
+ Args:
+ address: Bluetooth interface MAC address of the device.
+
+ Return:
+ "paused" or "stopped" if successful else "playing".
+ """
+ self.register_signal()
+ a2dp = self.get_a2dp_interface(address)
+ time.sleep(WAIT_TIME)
+ a2dp.Pause()
+ path = a2dp.object_path
+ props = dbus.Interface(
+ self.bus.get_object(SERVICE_NAME, path), PROPERTIES)
+ status = self.get_properties(props, MEDIA_PLAY_INTERFACE, "Status")
+ return status
+
+ def remove_bluetooth_device(self, address):
+ """Removes the device from the paired list.
+
+ Args:
+ address: Bluetooth interface MAC address of the device.
+
+ Returns:
+ True if removing of device is successful else False.
+ """
+ managed_objects = self.get_managed_objects()
+ adapter = self.find_adapter_in_objects(managed_objects)
+ try:
+ dev = self.find_device_in_objects(managed_objects, address)
+ path = dev.object_path
+ except:
+ return False
+
+ adapter.RemoveDevice(path)
+ return True
+
+ def stop_media(self, address):
+ """Stops the media player for the specified device.
+
+ Args:
+ address: Bluetooth interface MAC address of the device.
+
+ Returns:
+ "paused" or "stopped" if successful else "playing".
+ """
+ self.register_signal()
+ a2dp = self.get_a2dp_interface(address)
+ time.sleep(WAIT_TIME)
+ a2dp.Stop()
+ path = a2dp.object_path
+ props = dbus.Interface(
+ self.bus.get_object(SERVICE_NAME, path), PROPERTIES)
+ status = self.get_properties(props, MEDIA_PLAY_INTERFACE, "Status")
+ return status
+
+ def skip_next(self, address):
+ """Skips to Next track in media player.
+
+ Args:
+ address: Bluetooth interface MAC address of the device.
+
+ Returns:
+ True if the media track change is successful else False.
+ """
+ self.register_signal()
+ a2dp = self.get_a2dp_interface(address)
+ time.sleep(WAIT_TIME)
+ path = a2dp.object_path
+ props = dbus.Interface(
+ self.bus.get_object(SERVICE_NAME, path), PROPERTIES)
+ track = self.get_properties(props, MEDIA_PLAY_INTERFACE, "Track")
+ Title = track['Title']
+ a2dp.Next()
+ time.sleep(WAIT_TIME)
+ track = self.get_properties(props, MEDIA_PLAY_INTERFACE, "Track")
+ if Title == track['Title']:
+ return False
+ return True
+
+ def skip_previous(self, address):
+ """Skips to previous track in media player.
+
+ Args:
+ address: Buetooth interface MAC address of the device.
+
+ Returns:
+ True if media track change is successful else False.
+ """
+ a2dp = self.get_a2dp_interface(address)
+ time.sleep(WAIT_TIME)
+ path = a2dp.object_path
+ props = dbus.Interface(
+ self.bus.get_object(SERVICE_NAME, path), PROPERTIES)
+ track = self.get_properties(props, MEDIA_PLAY_INTERFACE, "Track")
+ Title = track['Title']
+ a2dp.Previous()
+ a2dp.Previous()
+ time.sleep(WAIT_TIME)
+ track = self.get_properties(props,MEDIA_PLAY_INTERFACE, "Track")
+ if Title == track['Title']:
+ return False
+ return True
+
+ def avrcp_actions(self, address):
+ """Performs AVRCP actions for the device
+
+ Args:
+ address: Bluetooth interface MAC address of the device.
+
+ Returns:
+ True if avrcp actions are performed else False.
+ """
+ if not self.skip_next(address):
+ logging.info("skip Next failed")
+ return False
+ time.sleep(WAIT_TIME)
+
+ if not self.skip_previous(address):
+ logging.info("skip previous failed")
+ return False
+ time.sleep(WAIT_TIME)
+ return True
+
+ def initiate_and_disconnect_call_from_hf(self, phone_no, duration):
+ """Initiates the call from bluez for the specified phone number.
+
+ Args:
+ phone_no: Phone number to which the call should be made.
+ duration: Time till which the call should be active.
+
+ Returns:
+ True if the call is initiated and disconnected else False.
+ """
+ modems = self.ofo_iface()
+ modem = modems[0][0]
+ hide_callerid = "default"
+ vcm = self.call_manager(modem)
+ time.sleep(WAIT_TIME)
+ path = vcm.Dial(phone_no, hide_callerid)
+ if 'voicecall' not in path:
+ return False
+ time.sleep(duration)
+ vcm.HangupAll()
+ return True
+
+ def answer_call(self, duration):
+ """Answers the incoming call from bluez.
+
+ Args:
+ duration: Time till which the call should be active.
+
+ Returns:
+ True if call is answered else False.
+ """
+ modems = self.ofo_iface()
+ for path, properties in modems:
+ if CALL_MANAGER not in properties["Interfaces"]:
+ continue
+ mgr = self.call_manager(path)
+ calls = mgr.GetCalls()
+ for path, properties in calls:
+ state = properties["State"]
+ if state != "incoming":
+ continue
+ call = self.answer_call_interface(path)
+ call.Answer()
+ time.sleep(duration)
+ call.Hangup()
+ return True
diff --git a/acts/framework/acts/test_utils/coex/coex_constants.py b/acts/framework/acts/test_utils/coex/coex_constants.py
new file mode 100644
index 0000000..22f478a
--- /dev/null
+++ b/acts/framework/acts/test_utils/coex/coex_constants.py
@@ -0,0 +1,41 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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.
+
+AUDIO_ROUTE_SPEAKER = "SPEAKER"
+AUDIO_ROUTE_BLUETOOTH = "BLUETOOTH"
+
+CALL_WAIT_TIME = 10
+DISCOVERY_TIME = 13
+WAIT_TIME = 3
+
+OBJECT_MANGER = "org.freedesktop.DBus.ObjectManager"
+PROPERTIES = "org.freedesktop.DBus.Properties"
+PROPERTIES_CHANGED = "PropertiesChanged"
+SERVICE_NAME = "org.bluez"
+CALL_MANAGER = "org.ofono.VoiceCallManager"
+VOICE_CALL = "org.ofono.VoiceCall"
+OFONO_MANAGER = "org.ofono.Manager"
+
+ADAPTER_INTERFACE = SERVICE_NAME + ".Adapter1"
+DBUS_INTERFACE = "org.freedesktop.DBus.Properties"
+DEVICE_INTERFACE = SERVICE_NAME + ".Device1"
+MEDIA_CONTROL_INTERACE = SERVICE_NAME +".MediaControl1"
+MEDIA_PLAY_INTERFACE = SERVICE_NAME + ".MediaPlayer1"
+
+bluetooth_profiles = {
+ "A2DP_SRC": "0000110a-0000-1000-8000-00805f9b34fb",
+ "HFP_AG": "0000111f-0000-1000-8000-00805f9b34fb"
+}
diff --git a/acts/framework/acts/test_utils/coex/coex_test_utils.py b/acts/framework/acts/test_utils/coex/coex_test_utils.py
new file mode 100644
index 0000000..6a290f6
--- /dev/null
+++ b/acts/framework/acts/test_utils/coex/coex_test_utils.py
@@ -0,0 +1,908 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 json
+import logging
+import math
+import os
+import pandas
+import re
+import subprocess
+import time
+
+from acts.controllers.ap_lib import hostapd_config
+from acts.controllers.ap_lib import hostapd_constants
+from acts.controllers.ap_lib import hostapd_security
+from acts.test_utils.bt.bt_constants import \
+ bluetooth_profile_connection_state_changed
+from acts.test_utils.bt.bt_constants import bt_default_timeout
+from acts.test_utils.bt.bt_constants import bt_profile_constants
+from acts.test_utils.bt.bt_constants import bt_profile_states
+from acts.test_utils.bt.bt_constants import bt_scan_mode_types
+from acts.test_utils.bt.bt_gatt_utils import GattTestUtilsError
+from acts.test_utils.bt.bt_gatt_utils import orchestrate_gatt_connection
+from acts.test_utils.bt.bt_test_utils import disable_bluetooth
+from acts.test_utils.bt.bt_test_utils import enable_bluetooth
+from acts.test_utils.bt.bt_test_utils import is_a2dp_src_device_connected
+from acts.test_utils.bt.bt_test_utils import is_a2dp_snk_device_connected
+from acts.test_utils.bt.bt_test_utils import is_hfp_client_device_connected
+from acts.test_utils.bt.bt_test_utils import is_map_mce_device_connected
+from acts.test_utils.bt.bt_test_utils import is_map_mse_device_connected
+from acts.test_utils.car.car_telecom_utils import wait_for_active
+from acts.test_utils.car.car_telecom_utils import wait_for_dialing
+from acts.test_utils.car.car_telecom_utils import wait_for_not_in_call
+from acts.test_utils.car.car_telecom_utils import wait_for_ringing
+from acts.test_utils.tel.tel_test_utils import get_phone_number
+from acts.test_utils.tel.tel_test_utils import hangup_call
+from acts.test_utils.tel.tel_test_utils import initiate_call
+from acts.test_utils.tel.tel_test_utils import run_multithread_func
+from acts.test_utils.tel.tel_test_utils import setup_droid_properties
+from acts.test_utils.tel.tel_test_utils import wait_and_answer_call
+from acts.test_utils.wifi.wifi_test_utils import reset_wifi
+from acts.test_utils.wifi.wifi_test_utils import wifi_connect
+from acts.test_utils.wifi.wifi_test_utils import wifi_test_device_init
+from acts.test_utils.wifi.wifi_test_utils import wifi_toggle_state
+from acts.utils import exe_cmd, create_dir
+
+THROUGHPUT_THRESHOLD = 100
+AP_START_TIME = 10
+DISCOVERY_TIME = 10
+BLUETOOTH_WAIT_TIME = 2
+
+
+def a2dp_dumpsys_parser(file_path):
+ """Convenience function to parse a2dp dumpsys logs.
+
+ Args:
+ file_path: Path of dumpsys logs.
+
+ Returns:
+ True if parsing is successful, False otherwise.
+ """
+ a2dp_dumpsys_info = []
+ with open(file_path) as dumpsys_file:
+ for line in dumpsys_file:
+ if "A2DP State:" in line:
+ a2dp_dumpsys_info.append(line)
+ elif "Counts (max dropped)" not in line and len(
+ a2dp_dumpsys_info) > 0:
+ a2dp_dumpsys_info.append(line)
+ elif "Counts (max dropped)" in line:
+ a2dp_dumpsys_info = ''.join(a2dp_dumpsys_info)
+ logging.info(a2dp_dumpsys_info)
+ return True
+ logging.error("failed to get A2DP state")
+ return False
+
+
+def connect_ble(pri_ad, sec_ad):
+ """Connect BLE device from DUT.
+
+ Args:
+ pri_ad: An android device object.
+ sec_ad: An android device object.
+
+ Returns:
+ True if successful, otherwise False.
+ """
+ adv_instances = []
+ gatt_server_list = []
+ bluetooth_gatt_list = []
+ pri_ad.droid.bluetoothEnableBLE()
+ gatt_server_cb = sec_ad.droid.gattServerCreateGattServerCallback()
+ gatt_server = sec_ad.droid.gattServerOpenGattServer(gatt_server_cb)
+ gatt_server_list.append(gatt_server)
+ try:
+ bluetooth_gatt, gatt_callback, adv_callback = (
+ orchestrate_gatt_connection(pri_ad, sec_ad))
+ bluetooth_gatt_list.append(bluetooth_gatt)
+ except GattTestUtilsError as err:
+ logging.error(err)
+ return False
+ adv_instances.append(adv_callback)
+ connected_devices = sec_ad.droid.gattServerGetConnectedDevices(gatt_server)
+ logging.debug("Connected device = {}".format(connected_devices))
+ return True
+
+
+def collect_bluetooth_manager_dumpsys_logs(pri_ad):
+ """Collect "adb shell dumpsys bluetooth_manager" logs.
+
+ Args:
+ pri_ad : An android device.
+
+ Returns:
+ True if dumpsys is successful, False otherwise.
+ """
+ out_file = "{}_{}".format(pri_ad.serial, "bluetooth_dumpsys.txt")
+ dumpsys_path = ''.join((pri_ad.log_path, "/BluetoothDumpsys"))
+ create_dir(dumpsys_path)
+ cmd = ''.join("adb -s {} shell dumpsys bluetooth_manager > {}/{}".format(
+ pri_ad.serial, dumpsys_path, out_file))
+ exe_cmd(cmd)
+ file_path = "{}/{}".format(dumpsys_path, out_file)
+ if not a2dp_dumpsys_parser(file_path):
+ logging.error("Could not parse dumpsys logs")
+ return False
+ return True
+
+
+def configure_and_start_ap(ap, network):
+ """Configure hostapd parameters and starts access point.
+
+ Args:
+ ap: An access point object.
+ network: A dictionary with wifi network details.
+ """
+ hostapd_sec = hostapd_security.Security(
+ security_mode=network["security"], password=network["password"])
+
+ config = hostapd_config.HostapdConfig(
+ n_capabilities=[hostapd_constants.N_CAPABILITY_HT40_MINUS],
+ mode=hostapd_constants.MODE_11N_PURE,
+ channel=network["channel"],
+ ssid=network["SSID"],
+ security=hostapd_sec)
+ ap.start_ap(config)
+ time.sleep(AP_START_TIME)
+
+
+def connect_dev_to_headset(pri_droid, dev_to_connect, profiles_set):
+ supported_profiles = bt_profile_constants.values()
+ for profile in profiles_set:
+ if profile not in supported_profiles:
+ pri_droid.log.info("Profile {} is not supported list {}".format(
+ profile, supported_profiles))
+ return False
+
+ paired = False
+ for paired_device in pri_droid.droid.bluetoothGetBondedDevices():
+ if paired_device['address'] == \
+ dev_to_connect:
+ paired = True
+ break
+
+ if not paired:
+ pri_droid.log.info("{} not paired to {}".format(
+ pri_droid.droid.getBuildSerial(), dev_to_connect))
+ return False
+
+ pri_droid.droid.bluetoothConnectBonded(dev_to_connect)
+
+ end_time = time.time() + 10
+ profile_connected = set()
+ sec_addr = dev_to_connect
+ logging.info("Profiles to be connected {}".format(profiles_set))
+
+ while (time.time() < end_time and
+ not profile_connected.issuperset(profiles_set)):
+ if (bt_profile_constants['headset_client'] not in profile_connected and
+ bt_profile_constants['headset_client'] in profiles_set):
+ if is_hfp_client_device_connected(pri_droid, sec_addr):
+ profile_connected.add(bt_profile_constants['headset_client'])
+ if (bt_profile_constants['headset'] not in profile_connected and
+ bt_profile_constants['headset'] in profiles_set):
+ profile_connected.add(bt_profile_constants['headset'])
+ if (bt_profile_constants['a2dp'] not in profile_connected and
+ bt_profile_constants['a2dp'] in profiles_set):
+ if is_a2dp_src_device_connected(pri_droid, sec_addr):
+ profile_connected.add(bt_profile_constants['a2dp'])
+ if (bt_profile_constants['a2dp_sink'] not in profile_connected and
+ bt_profile_constants['a2dp_sink'] in profiles_set):
+ if is_a2dp_snk_device_connected(pri_droid, sec_addr):
+ profile_connected.add(bt_profile_constants['a2dp_sink'])
+ if (bt_profile_constants['map_mce'] not in profile_connected and
+ bt_profile_constants['map_mce'] in profiles_set):
+ if is_map_mce_device_connected(pri_droid, sec_addr):
+ profile_connected.add(bt_profile_constants['map_mce'])
+ if (bt_profile_constants['map'] not in profile_connected and
+ bt_profile_constants['map'] in profiles_set):
+ if is_map_mse_device_connected(pri_droid, sec_addr):
+ profile_connected.add(bt_profile_constants['map'])
+ time.sleep(0.1)
+
+ while not profile_connected.issuperset(profiles_set):
+ try:
+ time.sleep(10)
+ profile_event = pri_droid.ed.pop_event(
+ bluetooth_profile_connection_state_changed,
+ bt_default_timeout + 10)
+ logging.info("Got event {}".format(profile_event))
+ except Exception:
+ logging.error("Did not get {} profiles left {}".format(
+ bluetooth_profile_connection_state_changed, profile_connected))
+ return False
+ profile = profile_event['data']['profile']
+ state = profile_event['data']['state']
+ device_addr = profile_event['data']['addr']
+ if state == bt_profile_states['connected'] and \
+ device_addr == dev_to_connect:
+ profile_connected.add(profile)
+ logging.info("Profiles connected until now {}".format(
+ profile_connected))
+ return True
+
+
+def device_discoverable(pri_ad, sec_ad):
+ """Verifies whether the device is discoverable or not.
+
+ Args:
+ pri_ad: An primary android device object.
+ sec_ad: An secondary android device object.
+
+ Returns:
+ True if the device found, False otherwise.
+ """
+ pri_ad.droid.bluetoothMakeDiscoverable()
+ scan_mode = pri_ad.droid.bluetoothGetScanMode()
+ if scan_mode == bt_scan_mode_types['connectable_discoverable']:
+ logging.info("Primary device scan mode is "
+ "SCAN_MODE_CONNECTABLE_DISCOVERABLE.")
+ else:
+ logging.info("Primary device scan mode is not "
+ "SCAN_MODE_CONNECTABLE_DISCOVERABLE.")
+ return False
+ if sec_ad.droid.bluetoothStartDiscovery():
+ time.sleep(DISCOVERY_TIME)
+ droid_name = pri_ad.droid.bluetoothGetLocalName()
+ get_discovered_devices = sec_ad.droid.bluetoothGetDiscoveredDevices()
+ find_flag = False
+
+ if get_discovered_devices:
+ for device in get_discovered_devices:
+ if 'name' in device and device['name'] == droid_name:
+ logging.info("Primary device is in the discovery "
+ "list of secondary device.")
+ find_flag = True
+ break
+ else:
+ logging.info("Secondary device get all the discovered devices "
+ "list is empty")
+ return False
+ else:
+ logging.info("Secondary device start discovery process error.")
+ return False
+ if not find_flag:
+ return False
+ return True
+
+
+def disconnect_headset_from_dev(pri_ad, sec_ad, profiles_list):
+ """
+ Disconnect primary from secondary on a specific set of profiles
+ Args:
+ pri_ad - Primary android_device initiating disconnection
+ sec_ad - Secondary android droid (sl4a interface to keep the
+ method signature the same connect_pri_to_sec above)
+ profiles_list - List of profiles we want to disconnect from
+
+ Returns:
+ True on Success
+ False on Failure
+ """
+ supported_profiles = bt_profile_constants.values()
+ for profile in profiles_list:
+ if profile not in supported_profiles:
+ pri_ad.log.info("Profile {} is not in supported list {}".format(
+ profile, supported_profiles))
+ return False
+
+ pri_ad.log.info(pri_ad.droid.bluetoothGetBondedDevices())
+
+ try:
+ pri_ad.droid.bluetoothDisconnectConnectedProfile(sec_ad, profiles_list)
+ except Exception as err:
+ pri_ad.log.error(
+ "Exception while trying to disconnect profile(s) {}: {}".format(
+ profiles_list, err))
+ return False
+
+ profile_disconnected = set()
+ pri_ad.log.info("Disconnecting from profiles: {}".format(profiles_list))
+
+ while not profile_disconnected.issuperset(profiles_list):
+ try:
+ profile_event = pri_ad.ed.pop_event(
+ bluetooth_profile_connection_state_changed, bt_default_timeout)
+ pri_ad.log.info("Got event {}".format(profile_event))
+ except Exception:
+ pri_ad.log.error("Did not disconnect from Profiles")
+ return False
+
+ profile = profile_event['data']['profile']
+ state = profile_event['data']['state']
+ device_addr = profile_event['data']['addr']
+
+ if state == bt_profile_states['disconnected'] and \
+ device_addr == sec_ad:
+ profile_disconnected.add(profile)
+ pri_ad.log.info("Profiles disconnected so far {}".format(
+ profile_disconnected))
+
+ return True
+
+
+def initiate_disconnect_from_hf(audio_receiver, pri_ad, sec_ad, duration):
+ """Initiates call and disconnect call on primary device.
+ Steps:
+ 1. Initiate call from HF.
+ 2. Wait for dialing state at DUT and wait for ringing at secondary device.
+ 3. Accepts call from secondary device.
+ 4. Wait for call active state at primary and secondary device.
+ 5. Sleeps until given duration.
+ 6. Disconnect call from primary device.
+ 7. Wait for call is not present state.
+
+ Args:
+ pri_ad: An android device to disconnect call.
+ sec_ad: An android device accepting call.
+ duration: Duration of call in seconds.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ audio_receiver.initiate_call_from_hf()
+ time.sleep(2)
+ flag = True
+ flag &= wait_for_dialing(logging, pri_ad)
+ flag &= wait_for_ringing(logging, sec_ad)
+ if not flag:
+ logging.error("Outgoing call did not get established")
+ return False
+
+ if not wait_and_answer_call(logging, sec_ad):
+ logging.error("Failed to answer call in second device.")
+ return False
+ if not wait_for_active(logging, pri_ad):
+ logging.error("AG not in Active state.")
+ return False
+ if not wait_for_active(logging, sec_ad):
+ logging.error("RE not in Active state.")
+ return False
+ time.sleep(duration)
+ if not hangup_call(logging, pri_ad):
+ logging.error("Failed to hangup call.")
+ return False
+ flag = True
+ flag &= wait_for_not_in_call(logging, pri_ad)
+ flag &= wait_for_not_in_call(logging, sec_ad)
+ return flag
+
+
+def initiate_disconnect_call_dut(pri_ad, sec_ad, duration, callee_number):
+ """Initiates call and disconnect call on primary device.
+ Steps:
+ 1. Initiate call from DUT.
+ 2. Wait for dialing state at DUT and wait for ringing at secondary device.
+ 3. Accepts call from secondary device.
+ 4. Wait for call active state at primary and secondary device.
+ 5. Sleeps until given duration.
+ 6. Disconnect call from primary device.
+ 7. Wait for call is not present state.
+
+ Args:
+ pri_ad: An android device to disconnect call.
+ sec_ad: An android device accepting call.
+ duration: Duration of call in seconds.
+ callee_number: Secondary device's phone number.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ if not initiate_call(logging, pri_ad, callee_number):
+ logging.error("Failed to initiate call")
+ return False
+ time.sleep(2)
+
+ flag = True
+ flag &= wait_for_dialing(logging, pri_ad)
+ flag &= wait_for_ringing(logging, sec_ad)
+ if not flag:
+ logging.error("Outgoing call did not get established")
+ return False
+
+ if not wait_and_answer_call(logging, sec_ad):
+ logging.error("Failed to answer call in second device.")
+ return False
+ # Wait for AG, RE to go into an Active state.
+ if not wait_for_active(logging, pri_ad):
+ logging.error("AG not in Active state.")
+ return False
+ if not wait_for_active(logging, sec_ad):
+ logging.error("RE not in Active state.")
+ return False
+ time.sleep(duration)
+ if not hangup_call(logging, pri_ad):
+ logging.error("Failed to hangup call.")
+ return False
+ flag = True
+ flag &= wait_for_not_in_call(logging, pri_ad)
+ flag &= wait_for_not_in_call(logging, sec_ad)
+
+ return flag
+
+
+def iperf_result(result, stream):
+ """Accepts the iperf result in json format and parse the output to
+ get throughput value.
+
+ Args:
+ result: contains the logs of iperf in json format.
+ stream: string to indicate uplink/downlink traffic.
+
+ Returns:
+ tx_rate: Data sent from client.
+ rx_rate: Data received from client.
+ """
+ try:
+ with open(result, 'r') as iperf_data:
+ time.sleep(1)
+ json_data = json.load(iperf_data)
+ except ValueError:
+ with open(result, 'r') as iperf_data:
+ # Possibly a result from interrupted iperf run, skip first line
+ # and try again.
+ time.sleep(1)
+ lines = iperf_data.readlines()[1:]
+ json_data = json.loads(''.join(lines))
+
+ if "error" in json_data:
+ logging.error(json_data["error"])
+ return False
+
+ protocol = json_data["start"]["test_start"]["protocol"]
+ if protocol == "UDP":
+ if "intervals" in json_data.keys():
+ interval = [
+ interval["sum"]["bits_per_second"] / 1e6
+ for interval in json_data["intervals"]
+ ]
+ tx_rate = math.fsum(interval) / len(interval)
+ else:
+ logging.error("Unable to retrive client results")
+ return False
+ if "server_output_json" in json_data.keys():
+ interval = [
+ interval["sum"]["bits_per_second"] / 1e6
+ for interval in json_data["server_output_json"]["intervals"]
+ ]
+ rx_rate = math.fsum(interval) / len(interval)
+ else:
+ logging.info("unable to retrive server results")
+ return False
+ if not stream == "ul":
+ return tx_rate, rx_rate
+ return rx_rate, tx_rate
+
+ elif protocol == "TCP":
+ tx_rate = json_data['end']['sum_sent']['bits_per_second']
+ rx_rate = json_data['end']['sum_received']['bits_per_second']
+ return tx_rate / 1e6, rx_rate / 1e6
+ else:
+ return False
+
+
+def is_a2dp_connected(pri_ad, headset_mac_address):
+ """Convenience Function to see if the 2 devices are connected on A2DP.
+
+ Args:
+ pri_ad : An android device.
+ headset_mac_address : Mac address of headset.
+
+ Returns:
+ True:If A2DP connection exists, False otherwise.
+ """
+ devices = pri_ad.droid.bluetoothA2dpGetConnectedDevices()
+ for device in devices:
+ logging.debug("A2dp Connected device {}".format(device["name"]))
+ if device["address"] == headset_mac_address:
+ return True
+ return False
+
+
+def media_stream_check(pri_ad, duration, headset_mac_address):
+ """Checks whether A2DP connecion is active or not for given duration of
+ time.
+
+ Args:
+ pri_ad : An android device.
+ duration : No of seconds to check if a2dp streaming is alive.
+ headset_mac_address : Headset mac address.
+
+ Returns:
+ True: If A2dp connection is active for entire duration.
+ False: If A2dp connection is not active.
+ """
+ while time.time() < duration:
+ if not is_a2dp_connected(pri_ad, headset_mac_address):
+ logging.error("A2dp connection not active at {}".format(
+ pri_ad.droid.getBuildSerial()))
+ return False
+ time.sleep(1)
+ return True
+
+
+def multithread_func(log, tasks):
+ """Multi-thread function wrapper.
+
+ Args:
+ log: log object.
+ tasks: tasks to be executed in parallel.
+
+ Returns:
+ List of results of tasks
+ """
+ results = run_multithread_func(log, tasks)
+ for res in results:
+ if not res:
+ return False
+ return True
+
+
+def music_play_and_check(pri_ad, headset_mac_address, music_to_play, duration):
+ """Starts playing media and checks if media plays for n seconds.
+
+ Steps:
+ 1. Starts media player on android device.
+ 2. Checks if music streaming is ongoing for n seconds.
+ 3. Stops media player.
+ 4. Collect dumpsys logs.
+
+ Args:
+ pri_ad: An android device.
+ headset_mac_address: Mac address of third party headset.
+ music_to_play: Indicates the music file to play.
+ duration: Time in secs to indicate music time to play.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ if not start_media_play(pri_ad, music_to_play):
+ logging.error("Start media play failed.")
+ return False
+ stream_time = time.time() + duration
+ if not media_stream_check(pri_ad, stream_time, headset_mac_address):
+ logging.error("A2DP Connection check failed.")
+ pri_ad.droid.mediaPlayStop()
+ return False
+ pri_ad.droid.mediaPlayStop()
+ if not collect_bluetooth_manager_dumpsys_logs(pri_ad):
+ return False
+ return True
+
+
+def music_play_and_check_via_app(pri_ad, headset_mac_address):
+ """Starts google music player and check for A2DP connection.
+
+ Steps:
+ 1. Starts Google music player on android device.
+ 2. Checks for A2DP connection.
+
+ Args:
+ pri_ad: An android device.
+ headset_mac_address: Mac address of third party headset.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ pri_ad.adb.shell("am start com.google.android.music")
+ time.sleep(3)
+ pri_ad.adb.shell("input keyevent 85")
+
+ if not is_a2dp_connected(pri_ad, headset_mac_address):
+ logging.error("A2dp connection not active at {}".format(
+ pri_ad.droid.getBuildSerial()))
+ return False
+ return True
+
+
+def get_phone_ip(ad):
+ """Get the WiFi IP address of the phone.
+
+ Args:
+ ad: the android device under test
+
+ Returns:
+ Ip address of the phone for WiFi, as a string
+ """
+ return ad.droid.connectivityGetIPv4Addresses('wlan0')[0]
+
+
+def pair_dev_to_headset(pri_ad, dev_to_pair):
+
+ bonded_devices = pri_ad.droid.bluetoothGetBondedDevices()
+ for d in bonded_devices:
+ if d['address'] == dev_to_pair:
+ pri_ad.log.info("Successfully bonded to device".format(
+ dev_to_pair))
+ return True
+ pri_ad.droid.bluetoothStartDiscovery()
+ time.sleep(10)
+ pri_ad.droid.bluetoothCancelDiscovery()
+ logging.info("disovered devices = {}".format(
+ pri_ad.droid.bluetoothGetDiscoveredDevices()))
+ for device in pri_ad.droid.bluetoothGetDiscoveredDevices():
+ if device['address'] == dev_to_pair:
+
+ result = pri_ad.droid.bluetoothDiscoverAndBond(dev_to_pair)
+ pri_ad.log.info(result)
+ end_time = time.time() + bt_default_timeout
+ pri_ad.log.info("Verifying devices are bonded")
+ time.sleep(5)
+ while time.time() < end_time:
+ bonded_devices = pri_ad.droid.bluetoothGetBondedDevices()
+ bonded = False
+ for d in bonded_devices:
+ if d['address'] == dev_to_pair:
+ pri_ad.log.info("Successfully bonded to device".format(
+ dev_to_pair))
+ return True
+ pri_ad.log.info("Failed to bond devices.")
+ return False
+
+def pair_and_connect_headset(pri_ad, headset_mac_address, profile_to_connect):
+ """Pair and connect android device with third party headset.
+
+ Args:
+ pri_ad: An android device.
+ headset_mac_address: Mac address of third party headset.
+ profile_to_connect: Profile to be connected with headset.
+
+ Returns:
+ True if pair and connect to headset successful, False otherwise.
+ """
+ if not pair_dev_to_headset(pri_ad, headset_mac_address):
+ logging.error("Could not pair to headset.")
+ return False
+ # Wait until pairing gets over.
+ time.sleep(2)
+ if not connect_dev_to_headset(pri_ad, headset_mac_address,
+ profile_to_connect):
+ logging.error("Could not connect to headset.")
+ return False
+ return True
+
+
+def perform_classic_discovery(pri_ad):
+ """Convenience function to start and stop device discovery.
+
+ Args:
+ pri_ad: An android device.
+
+ Returns:
+ True start and stop discovery is successful, False otherwise.
+ """
+ if not pri_ad.droid.bluetoothStartDiscovery():
+ logging.info("Failed to start inquiry")
+ return False
+ time.sleep(DISCOVERY_TIME)
+ if not pri_ad.droid.bluetoothCancelDiscovery():
+ logging.info("Failed to cancel inquiry")
+ return False
+ logging.info("Discovered device list {}".format(
+ pri_ad.droid.bluetoothGetDiscoveredDevices()))
+ return True
+
+
+def connect_wlan_profile(pri_ad, network):
+ """Disconnect and Connect to AP.
+
+ Args:
+ pri_ad: An android device.
+ network: Network to which AP to be connected.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ reset_wifi(pri_ad)
+ wifi_toggle_state(pri_ad, False)
+ wifi_test_device_init(pri_ad)
+ wifi_connect(pri_ad, network)
+ if not wifi_connection_check(pri_ad, network["SSID"]):
+ logging.error("Wifi connection does not exist.")
+ return False
+ return True
+
+
+def toggle_bluetooth(pri_ad, iterations):
+ """Toggles bluetooth on/off for N iterations.
+
+ Args:
+ pri_ad: An android device object.
+ iterations: Number of iterations to run.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ for i in range(iterations):
+ logging.info("Bluetooth Turn on/off iteration : {}".format(i))
+ if not enable_bluetooth(pri_ad.droid, pri_ad.ed):
+ logging.error("Failed to enable bluetooth")
+ return False
+ time.sleep(BLUETOOTH_WAIT_TIME)
+ if not disable_bluetooth(pri_ad.droid):
+ logging.error("Failed to turn off bluetooth")
+ return False
+ time.sleep(BLUETOOTH_WAIT_TIME)
+ return True
+
+
+def toggle_screen_state(pri_ad, iterations):
+ """Toggles the screen state to on or off..
+
+ Args:
+ pri_ad: Android device.
+ iterations: Number of times screen on/off should be performed.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ for i in range(iterations):
+ if not pri_ad.ensure_screen_on():
+ logging.error("User window cannot come up")
+ return False
+ if not pri_ad.go_to_sleep():
+ logging.info("Screen off")
+ return True
+
+
+def setup_tel_config(pri_ad, sec_ad, sim_conf_file):
+ """Sets tel properties for primary device and secondary devices
+
+ Args:
+ pri_ad: An android device object.
+ sec_ad: An android device object.
+ sim_conf_file: Sim card map.
+
+ Returns:
+ pri_ad_num: Phone number of primary device.
+ sec_ad_num: Phone number of secondary device.
+ """
+ setup_droid_properties(logging, pri_ad, sim_conf_file)
+ pri_ad_num = get_phone_number(logging, pri_ad)
+ setup_droid_properties(logging, sec_ad, sim_conf_file)
+ sec_ad_num = get_phone_number(logging, sec_ad)
+ return pri_ad_num, sec_ad_num
+
+
+def start_fping(pri_ad, duration):
+ """Starts fping to ping for DUT's ip address.
+
+ Steps:
+ 1. Run fping command to check DUT's IP is alive or not.
+
+ Args:
+ pri_ad: An android device object.
+ duration: Duration of fping in seconds.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ out_file_name = "{}".format("fping.txt")
+ full_out_path = os.path.join(pri_ad.log_path, out_file_name)
+ cmd = "fping {} -D -c {}".format(get_phone_ip(pri_ad), duration)
+ cmd = cmd.split()
+ with open(full_out_path, "w") as f:
+ subprocess.call(cmd, stdout=f)
+ f = open(full_out_path, "r")
+ for lines in f:
+ l = re.split("[:/=]", lines)
+ if l[len(l) - 1] != "0%":
+ logging.error("Packet drop observed")
+ return False
+ return True
+
+
+def start_media_play(pri_ad, music_file_to_play):
+ """Starts media player on device.
+
+ Args:
+ pri_ad : An android device.
+ music_file_to_play : An audio file to play.
+
+ Returns:
+ True:If media player start music, False otherwise.
+ """
+ if not pri_ad.droid.mediaPlayOpen("file:///sdcard/Music/{}"
+ .format(music_file_to_play)):
+ logging.error("Failed to play music")
+ return False
+
+ pri_ad.droid.mediaPlaySetLooping(True)
+ logging.info("Music is now playing on device {}".format(pri_ad.serial))
+ return True
+
+
+def throughput_pass_fail_check(throughput):
+ """Method to check if the throughput is above the defined
+ threshold.
+
+ Args:
+ throughput: Throughput value of test run.
+
+ Returns:
+ Pass if throughput is above threshold.
+ Fail if throughput is below threshold and Iperf Failed.
+ Empty if Iperf value is not present.
+ """
+ iperf_result_list = []
+ if len(throughput) != 0:
+ for i in range(len(throughput)):
+ if throughput[i] != 'Iperf Failed':
+ if float(throughput[i].split('Mb/s')[0]) > \
+ THROUGHPUT_THRESHOLD:
+ iperf_result_list.append("PASS")
+ else:
+ iperf_result_list.append("FAIL")
+ elif throughput[i] == 'Iperf Failed':
+ iperf_result_list.append("FAIL")
+ return "FAIL" if "FAIL" or "Iperf Failed" in iperf_result_list \
+ else "PASS"
+ else:
+ return " "
+
+
+def wifi_connection_check(pri_ad, ssid):
+ """Function to check existence of wifi connection.
+
+ Args:
+ pri_ad : An android device.
+ ssid : wifi ssid to check.
+
+ Returns:
+ True if wifi connection exists, False otherwise.
+ """
+ wifi_info = pri_ad.droid.wifiGetConnectionInfo()
+ if (wifi_info["SSID"] == ssid and
+ wifi_info["supplicant_state"] == "completed"):
+ return True
+ logging.error("Wifi Connection check failed : {}".format(wifi_info))
+ return False
+
+
+def xlsheet(pri_ad, test_result):
+ """Parses the output and writes in spreadsheet.
+
+ Args:
+ pri_ad: An android device.
+ test_result: final output of testrun.
+ """
+ test_result = json.loads(test_result)
+ file_name = '/'.join((pri_ad.log_path,
+ test_result["Results"][0]["Test Class"] + ".xlsx"))
+ result = [(i["Test Name"], i["Result"], ' '.join(i["Extras"]),
+ throughput_pass_fail_check(i["Extras"]))
+ for i in test_result["Results"]]
+
+ try:
+ data_obj = pandas.DataFrame(
+ result,
+ columns=[
+ "Test Name", "Result", "Iperf Throughput", "Throughput Result"
+ ])
+ except Exception as err:
+ logging.info("Error in writing into xlsheet {}".format(err))
+ return False
+
+ writer = pandas.ExcelWriter(file_name, engine='xlsxwriter')
+ data_obj.to_excel(writer, sheet_name='Sheet1')
+ workbook = writer.book
+ for column in (1, 4):
+ writer.sheets['Sheet1'].set_column(column, column, 40)
+ workbook.add_format({
+ 'bold': True,
+ 'text_wrap': True,
+ })
diff --git a/acts/framework/acts/test_utils/net/connectivity_const.py b/acts/framework/acts/test_utils/net/connectivity_const.py
index 89bdb2c..59c8d47 100644
--- a/acts/framework/acts/test_utils/net/connectivity_const.py
+++ b/acts/framework/acts/test_utils/net/connectivity_const.py
@@ -53,6 +53,10 @@
# This is a random value as of now
VPN_TIMEOUT = 15
+# Connectiivty Manager constants
+TYPE_MOBILE = 0
+TYPE_WIFI = 1
+
# Constants for VpnProfile
class VpnProfile(object):
""" This class contains all the possible
diff --git a/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py b/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py
index e8e6ad1..b300492 100644
--- a/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py
+++ b/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py
@@ -17,42 +17,47 @@
Base Class for Defining Common Telephony Test Functionality
"""
+import logging
import os
-import time
-import inspect
+import re
+import shutil
import traceback
import acts.controllers.diag_logger
+from acts import asserts
+from acts import logger as acts_logger
from acts.base_test import BaseTestClass
+from acts.controllers.android_device import DEFAULT_QXDM_LOG_PATH
from acts.keys import Config
from acts.signals import TestSignal
from acts.signals import TestAbortClass
from acts.signals import TestAbortAll
+from acts.signals import TestBlocked
+from acts import records
from acts import utils
from acts.test_utils.tel.tel_subscription_utils import \
initial_set_up_for_subid_infomation
from acts.test_utils.tel.tel_test_utils import abort_all_tests
-from acts.test_utils.tel.tel_test_utils import check_qxdm_logger_always_on
-from acts.test_utils.tel.tel_test_utils import is_sim_locked
from acts.test_utils.tel.tel_test_utils import ensure_phones_default_state
from acts.test_utils.tel.tel_test_utils import ensure_phones_idle
from acts.test_utils.tel.tel_test_utils import print_radio_info
-from acts.test_utils.tel.tel_test_utils import refresh_droid_config
+from acts.test_utils.tel.tel_test_utils import reboot_device
+from acts.test_utils.tel.tel_test_utils import refresh_sl4a_session
+from acts.test_utils.tel.tel_test_utils import run_multithread_func
from acts.test_utils.tel.tel_test_utils import setup_droid_properties
from acts.test_utils.tel.tel_test_utils import set_phone_screen_on
from acts.test_utils.tel.tel_test_utils import set_phone_silent_mode
-from acts.test_utils.tel.tel_test_utils import set_qxdm_logger_always_on
+from acts.test_utils.tel.tel_test_utils import set_qxdm_logger_command
+from acts.test_utils.tel.tel_test_utils import start_qxdm_loggers
+from acts.test_utils.tel.tel_test_utils import stop_qxdm_loggers
from acts.test_utils.tel.tel_test_utils import unlock_sim
from acts.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_BACKGROUND
from acts.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_FOREGROUND
from acts.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_RINGING
from acts.test_utils.tel.tel_defines import WIFI_VERBOSE_LOGGING_ENABLED
from acts.test_utils.tel.tel_defines import WIFI_VERBOSE_LOGGING_DISABLED
-from acts.utils import force_airplane_mode
-
-QXDM_LOG_PATH = "/data/vendor/radio/diag_logs/logs/"
class TelephonyBaseTest(BaseTestClass):
@@ -61,21 +66,42 @@
BaseTestClass.__init__(self, controllers)
self.logger_sessions = []
+ self.log_path = getattr(logging, "log_path", None)
+ self.qxdm_log = self.user_params.get("qxdm_log", True)
+ qxdm_log_mask_cfg = self.user_params.get("qxdm_log_mask_cfg", None)
+ if isinstance(qxdm_log_mask_cfg, list):
+ qxdm_log_mask_cfg = qxdm_log_mask_cfg[0]
+ if qxdm_log_mask_cfg and "dev/null" in qxdm_log_mask_cfg:
+ qxdm_log_mask_cfg = None
+ stop_qxdm_loggers(self.log, self.android_devices)
for ad in self.android_devices:
- ad.qxdm_log = True
- if getattr(ad, "qxdm_always_on", False):
- #this is only supported on 2017 devices
- ad.log.info("qxdm_always_on is set in config file")
- mask = getattr(ad, "qxdm_mask", "Radio-general.cfg")
- if not check_qxdm_logger_always_on(ad, mask):
- ad.log.info("qxdm always on is not set, turn it on")
- set_qxdm_logger_always_on(ad, mask)
- else:
- ad.log.info("qxdm always on is already set")
+ if not hasattr(ad, "init_log_path"):
+ ad.init_log_path = ad.log_path
+ ad.log_path = self.log_path
print_radio_info(ad)
if not unlock_sim(ad):
abort_all_tests(ad.log, "unable to unlock SIM")
+ ad.wakeup_screen()
+ ad.adb.shell("input keyevent 82")
+ ad.qxdm_log = getattr(ad, "qxdm_log", self.qxdm_log)
+ if ad.qxdm_log:
+ qxdm_log_mask = getattr(ad, "qxdm_log_mask", None)
+ if qxdm_log_mask_cfg:
+ qxdm_mask_path = DEFAULT_QXDM_LOG_PATH
+ ad.adb.shell("mkdir %s" % qxdm_mask_path)
+ ad.log.info("Push %s to %s", qxdm_log_mask_cfg,
+ qxdm_mask_path)
+ ad.adb.push("%s %s" % (qxdm_log_mask_cfg, qxdm_mask_path))
+ mask_file_name = os.path.split(qxdm_log_mask_cfg)[-1]
+ qxdm_log_mask = os.path.join(qxdm_mask_path,
+ mask_file_name)
+ set_qxdm_logger_command(ad, mask=qxdm_log_mask)
+ ad.adb.pull(
+ "/firmware/image/qdsp6m.qdb %s" % ad.init_log_path,
+ ignore_status=True)
+ start_qxdm_loggers(self.log, self.android_devices,
+ utils.get_current_epoch_time())
self.skip_reset_between_cases = self.user_params.get(
"skip_reset_between_cases", True)
@@ -85,59 +111,54 @@
def tel_test_wrap(fn):
def _safe_wrap_test_case(self, *args, **kwargs):
test_id = "%s:%s:%s" % (self.__class__.__name__, self.test_name,
- self.begin_time.replace(' ', '-'))
+ self.log_begin_time.replace(' ', '-'))
self.test_id = test_id
- log_string = "[Test ID] %s" % test_id
- self.log.info(log_string)
- no_crash = True
- try:
- for ad in self.android_devices:
- if getattr(ad, "droid"):
- ad.droid.logI("Started %s" % log_string)
- # TODO: b/19002120 start QXDM Logging
- result = fn(self, *args, **kwargs)
- for ad in self.android_devices:
- if getattr(ad, "droid"):
- ad.droid.logI("Finished %s" % log_string)
- new_crash = ad.check_crash_report(self.test_name,
- self.begin_time, result)
- if self.user_params.get("check_crash", True) and new_crash:
- ad.log.error("Find new crash reports %s", new_crash)
- no_crash = False
- if not result and self.user_params.get("telephony_auto_rerun"):
+ self.result_detail = ""
+ tries = 2 if self.user_params.get("telephony_auto_rerun") else 1
+ for i in range(tries):
+ result = True
+ log_string = "[Test ID] %s" % test_id
+ if i > 1:
+ log_string = "[Rerun]%s" % log_string
self.teardown_test()
- # re-run only once, if re-run pass, mark as pass
- log_string = "[Rerun Test ID] %s. 1st run failed." % test_id
- self.log.info(log_string)
self.setup_test()
- for ad in self.android_devices:
- if getattr(ad, "droid"):
- ad.droid.logI("Rerun Started %s" % log_string)
+ self.log.info(log_string)
+ for ad in self.android_devices:
+ ad.log_path = self.log_path
+ try:
+ ad.droid.logI("Started %s" % log_string)
+ except Exception as e:
+ ad.log.warning(e)
+ refresh_sl4a_session(ad)
+ try:
result = fn(self, *args, **kwargs)
- if result is True:
- self.log.info("Rerun passed.")
- elif result is False:
- self.log.info("Rerun failed.")
- else:
- # In the event that we have a non-bool or null
- # retval, we want to clearly distinguish this in the
- # logs from an explicit failure, though the test will
- # still be considered a failure for reporting purposes.
- self.log.info("Rerun indeterminate.")
- result = False
- return result and no_crash
- except (TestSignal, TestAbortClass, TestAbortAll):
- raise
- except Exception as e:
- self.log.error(str(e))
- return False
- finally:
- # TODO: b/19002120 stop QXDM Logging
+ except (TestSignal, TestAbortClass, TestAbortAll) as signal:
+ if self.result_detail:
+ signal.details = self.result_detail
+ raise
+ except Exception as e:
+ self.log.error(traceback.format_exc())
+ asserts.fail(self.result_detail)
for ad in self.android_devices:
try:
- ad.adb.wait_for_device()
+ ad.droid.logI("Finished %s" % log_string)
except Exception as e:
- self.log.error(str(e))
+ ad.log.warning(e)
+ refresh_sl4a_session(ad)
+ if result: break
+ if self.user_params.get("check_crash", True):
+ new_crash = ad.check_crash_report(self.test_name,
+ self.begin_time, True)
+ if new_crash:
+ msg = "Find new crash reports %s" % new_crash
+ ad.log.error(msg)
+ self.result_detail = "%s %s %s" % (self.result_detail,
+ ad.serial, msg)
+ result = False
+ if result:
+ asserts.explicit_pass(self.result_detail)
+ else:
+ asserts.fail(self.result_detail)
return _safe_wrap_test_case
@@ -244,30 +265,38 @@
return True
def teardown_class(self):
+ stop_qxdm_loggers(self.log, self.android_devices)
+ ensure_phones_default_state(self.log, self.android_devices)
try:
for ad in self.android_devices:
ad.droid.disableDevicePassword()
if "enable_wifi_verbose_logging" in self.user_params:
ad.droid.wifiEnableVerboseLogging(
WIFI_VERBOSE_LOGGING_DISABLED)
+ if hasattr(ad, "init_log_path"):
+ ad.log_path = ad.init_log_path
return True
except Exception as e:
self.log.error("Failure with %s", e)
def setup_test(self):
+ for ad in self.android_devices:
+ ad.ed.clear_all_events()
+ output = ad.adb.logcat("-t 1")
+ match = re.search(r"\d+-\d+\s\d+:\d+:\d+.\d+", output)
+ if match:
+ ad.test_log_begin_time = match.group(0)
+ if getattr(self, "qxdm_log", True):
+ start_qxdm_loggers(self.log, self.android_devices, self.begin_time)
if getattr(self, "diag_logger", None):
for logger in self.diag_logger:
self.log.info("Starting a diagnostic session %s", logger)
self.logger_sessions.append((logger, logger.start()))
-
if self.skip_reset_between_cases:
ensure_phones_idle(self.log, self.android_devices)
else:
ensure_phones_default_state(self.log, self.android_devices)
- def teardown_test(self):
- return True
-
def on_exception(self, test_name, begin_time):
self._pull_diag_logs(test_name, begin_time)
self._take_bug_report(test_name, begin_time)
@@ -278,6 +307,80 @@
self._take_bug_report(test_name, begin_time)
self._cleanup_logger_sessions()
+ def on_blocked(self, test_name, begin_time):
+ self.on_fail(test_name, begin_time)
+
+ def _ad_take_extra_logs(self, ad, test_name, begin_time):
+ extra_qxdm_logs_in_seconds = self.user_params.get(
+ "extra_qxdm_logs_in_seconds", 60 * 3)
+ result = True
+ if getattr(ad, "qxdm_log", True):
+ # Gather qxdm log modified 3 minutes earlier than test start time
+ if begin_time:
+ qxdm_begin_time = begin_time - 1000 * extra_qxdm_logs_in_seconds
+ else:
+ qxdm_begin_time = None
+ try:
+ ad.get_qxdm_logs(test_name, qxdm_begin_time)
+ except Exception as e:
+ ad.log.error("Failed to get QXDM log for %s with error %s",
+ test_name, e)
+ result = False
+
+ try:
+ ad.check_crash_report(test_name, begin_time, log_crash_report=True)
+ except Exception as e:
+ ad.log.error("Failed to check crash report for %s with error %s",
+ test_name, e)
+ result = False
+
+ log_begin_time = getattr(ad, "test_log_begin_time", None)\
+ or acts_logger.epoch_to_log_line_timestamp(begin_time - 1000 * 60)
+ log_path = os.path.join(self.log_path, test_name,
+ "%s_%s.logcat" % (ad.serial, begin_time))
+ try:
+ ad.adb.logcat(
+ 'b all -d -v year -t "%s" > %s' % (log_begin_time, log_path),
+ timeout=120)
+ except Exception as e:
+ ad.log.error("Failed to get logcat with error %s", e)
+ result = False
+ return result
+
+ def _take_bug_report(self, test_name, begin_time):
+ if self._skip_bug_report():
+ return
+ dev_num = getattr(self, "number_of_devices", None) or len(
+ self.android_devices)
+ tasks = [(self._ad_take_bugreport, (ad, test_name, begin_time))
+ for ad in self.android_devices[:dev_num]]
+ tasks.extend([(self._ad_take_extra_logs, (ad, test_name, begin_time))
+ for ad in self.android_devices[:dev_num]])
+ run_multithread_func(self.log, tasks)
+ for ad in self.android_devices[:dev_num]:
+ if getattr(ad, "reboot_to_recover", False):
+ reboot_device(ad)
+ ad.reboot_to_recover = False
+ if not self.user_params.get("zip_log", False): return
+ src_dir = os.path.join(self.log_path, test_name)
+ file_name = "%s_%s" % (src_dir, begin_time)
+ self.log.info("Zip folder %s to %s.zip", src_dir, file_name)
+ shutil.make_archive(file_name, "zip", src_dir)
+ shutil.rmtree(src_dir)
+
+ def _block_all_test_cases(self, tests):
+ """Over-write _block_all_test_case in BaseTestClass."""
+ for (i, (test_name, test_func)) in enumerate(tests):
+ signal = TestBlocked("Failed class setup")
+ record = records.TestResultRecord(test_name, self.TAG)
+ record.test_begin()
+ # mark all test cases as FAIL
+ record.test_fail(signal)
+ self.results.add_record(record)
+ # only gather bug report for the first test case
+ if i == 0:
+ self.on_fail(test_name, record.begin_time)
+
def on_pass(self, test_name, begin_time):
self._cleanup_logger_sessions()
diff --git a/acts/framework/acts/test_utils/tel/TelephonyLabPowerTest.py b/acts/framework/acts/test_utils/tel/TelephonyLabPowerTest.py
new file mode 100644
index 0000000..501f385
--- /dev/null
+++ b/acts/framework/acts/test_utils/tel/TelephonyLabPowerTest.py
@@ -0,0 +1,200 @@
+#/usr/bin/env python3.4
+#
+# Copyright 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.
+"""
+Sanity tests for voice tests in telephony
+"""
+import time, os
+
+from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError
+from acts.controllers.anritsu_lib.md8475a import MD8475A
+from acts.controllers.anritsu_lib.md8475a import BtsBandwidth
+from acts.test_utils.tel.anritsu_utils import set_system_model_lte
+from acts.test_utils.tel.anritsu_utils import set_usim_parameters
+from acts.test_utils.tel.tel_defines import RAT_FAMILY_LTE
+from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_CDMA_EVDO
+from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA
+from acts.test_utils.tel.tel_test_utils import ensure_network_rat
+from acts.test_utils.tel.tel_test_utils import set_phone_screen_on
+from acts.test_utils.tel.tel_test_utils import toggle_volte
+from acts.test_utils.tel.tel_voice_utils import phone_idle_volte
+from acts.test_utils.tel.tel_voice_utils import phone_setup_volte
+from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts.utils import create_dir
+from acts.utils import disable_doze
+from acts.utils import set_adaptive_brightness
+from acts.utils import set_ambient_display
+from acts.utils import set_auto_rotate
+from acts.utils import set_location_service
+
+DEFAULT_CALL_NUMBER = "+11234567891"
+
+# Monsoon output Voltage in V
+MONSOON_OUTPUT_VOLTAGE = 4.2
+# Monsoon output max current in A
+MONSOON_MAX_CURRENT = 7.8
+
+# Sampling rate in Hz
+ACTIVE_CALL_TEST_SAMPLING_RATE = 100
+# Sample duration in seconds
+ACTIVE_CALL_TEST_SAMPLE_TIME = 10
+# Offset time in seconds
+ACTIVE_CALL_TEST_OFFSET_TIME = 10
+
+
+class TelephonyLabPowerTest(TelephonyBaseTest):
+ def __init__(self, controllers):
+ TelephonyBaseTest.__init__(self, controllers)
+ self.ad = self.android_devices[0]
+ self.ad.sim_card = getattr(self.ad, "sim_card", None)
+ self.md8475a_ip_address = self.user_params[
+ "anritsu_md8475a_ip_address"]
+ self.wlan_option = self.user_params.get("anritsu_wlan_option", False)
+
+ def _configure_dut(self):
+ try:
+ self.log.info("Rebooting DUT")
+ self.ad.reboot()
+ self.log.info("DUT rebooted")
+ set_adaptive_brightness(self.ad, False)
+ set_ambient_display(self.ad, False)
+ set_auto_rotate(self.ad, False)
+ set_location_service(self.ad, False)
+ # This is not needed for AOSP build
+ disable_doze(self.ad)
+ set_phone_screen_on(self.log, self.ad, 15)
+ self.ad.droid.telephonyFactoryReset()
+ except Exception as e:
+ self.ad.log.error(e)
+ return False
+ return True
+
+ def _configure_dut_network_mode_for_data_volte(self):
+ self._configure_dut()
+ try:
+ # TODO do what is needed to verify connected for LTE data transfer
+ self.log.info("setting back to LTE")
+ self.ad.droid.telephonySetPreferredNetworkTypesForSubscription(
+ "NETWORK_MODE_LTE_CDMA_EVDO",
+ self.ad.droid.subscriptionGetDefaultSubId())
+ self.ad.adb.shell(
+ "setprop net.lte.ims.volte.provisioned 1", ignore_status=True)
+ except Exception as e:
+ self.ad.log.error(e)
+ return False
+ return True
+
+ def _configure_simulation(self):
+ try:
+ self.anritsu = MD8475A(self.md8475a_ip_address, self.log,
+ self.wlan_option)
+ [lte_bts] = set_system_model_lte(self.anritsu, self.user_params,
+ self.ad.sim_card)
+ self.bts = lte_bts
+ lte_bts.bandwidth = BtsBandwidth.LTE_BANDWIDTH_10MHz
+ set_usim_parameters(self.anritsu, self.ad.sim_card)
+ self.anritsu.start_simulation()
+ self.anritsu.send_command("IMSSTARTVN 1")
+ except AnritsuError:
+ self.log.error("Error in connecting to Anritsu Simulator")
+ return False
+ return True
+
+ def _dut_setup_data_volte(self, ad):
+ ad.droid.telephonyToggleDataConnection(True)
+ toggle_volte(self.log, ad, True)
+ return ensure_network_rat(
+ self.log,
+ ad,
+ NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA,
+ RAT_FAMILY_LTE,
+ toggle_apm_after_setting=True)
+
+ def setup_class(self):
+ # Monsoon setup
+ self.log.info("Starting Monsoon setup")
+ self.mon = self.monsoons[0]
+ self.mon.set_voltage(MONSOON_OUTPUT_VOLTAGE)
+ self.mon.set_max_current(MONSOON_MAX_CURRENT)
+ self.mon.dut = self.ad = self.android_devices[0]
+ self.monsoon_log_path = os.path.join(self.log_path, "MonsoonLog")
+ create_dir(self.monsoon_log_path)
+ self.log.info("Conffiguring MD8475A network simulator")
+ self._configure_simulation()
+ self.log.info("Setting DUT's network mode for data and volte")
+ self._configure_dut_network_mode_for_data_volte()
+ self.log.info("Enabling DUT for data and VoLTE")
+ if not self._dut_setup_data_volte(self.ad):
+ self.log.error("phone_setup_volte failed.")
+ self.log.info("Waiting for DUT to register on MD8475A")
+ self.anritsu.wait_for_registration_state()
+ self.log.info("Waiting for DUT to register with IMS server")
+ if not phone_idle_volte(self.log, self.ad):
+ self.log.error("phone_idle_volte failed.")
+
+ def setup_test(self):
+ self.log.info("Bypassing empty setup_test() in TelephonyLabPowerTest")
+
+ def teardown_class(self):
+ self.log.info("Stopping Simulation and disconnect MD8475A")
+ self.anritsu.stop_simulation()
+ self.anritsu.disconnect()
+ return True
+
+ def _save_logs_for_power_test(self, monsoon_result, bug_report):
+ if monsoon_result and "monsoon_log_for_power_test" in self.user_params:
+ monsoon_result.save_to_text_file(
+ [monsoon_result],
+ os.path.join(self.monsoon_log_path, self.test_id))
+ if bug_report and "bug_report_for_power_test" in self.user_params:
+ self.android_devices[0].take_bug_report(self.test_name,
+ self.begin_time)
+
+ def power_test(self,
+ olvl,
+ rflvl,
+ sch_mode="DYNAMIC",
+ sample_rate=ACTIVE_CALL_TEST_SAMPLING_RATE,
+ sample_time=ACTIVE_CALL_TEST_SAMPLE_TIME,
+ offset_time=ACTIVE_CALL_TEST_OFFSET_TIME):
+ """ Set Output(DL)/InputDL(UL) power and scheduling mode of BTS,
+ and samping parameters of Monsoon
+ Args: ovlv: Output (DL) level in dBm
+ rflvl: Input (UL) level in dBm
+ sch_mode: Scheduling mode, either "STATIC" or "DYNAMIC"
+ sample_rate: Sampling rate in Hz
+ sample_time: Sample duration in seconds
+ offset_time: Offset time in seconds
+ Return: True if no exception
+ """
+ self.bts.output_level = olvl
+ self.bts.input_level = rflvl
+ self.bts.lte_scheduling_mode = sch_mode
+ bug_report = True
+ average_current = 0
+ result = None
+ self.log.info("Test %s" % self.test_name)
+ try:
+ result = self.mon.measure_power(sample_rate, sample_time,
+ self.test_id, offset_time)
+ average_current = result.average_current
+ self._save_logs_for_power_test(result, bug_report)
+ self.log.info("{} Result: {} mA".format(self.test_id,
+ average_current))
+ except Exception as e:
+ self.log.error("Exception during power consumption measurement: " +
+ str(e))
+ return False
+ return True
diff --git a/acts/framework/acts/test_utils/tel/anritsu_utils.py b/acts/framework/acts/test_utils/tel/anritsu_utils.py
index 1755198..73ab66b 100644
--- a/acts/framework/acts/test_utils/tel/anritsu_utils.py
+++ b/acts/framework/acts/test_utils/tel/anritsu_utils.py
@@ -78,8 +78,8 @@
TEST_PLMN_1X_NAME = "MD8475A_1X"
TEST_PLMN_1_MCC = "001"
TEST_PLMN_1_MNC = "01"
-DEFAULT_MCC = "001"
-DEFAULT_MNC = "01"
+DEFAULT_MCC = "310"
+DEFAULT_MNC = "260"
DEFAULT_RAC = 1
DEFAULT_LAC = 1
VzW_MCC = "311"
@@ -103,11 +103,13 @@
UE_IPV4_ADDR_2 = "192.168.1.11"
UE_IPV4_ADDR_3 = "192.168.1.21"
UE_IPV6_ADDR_1 = "2001:0:0:1::1"
-UE_IPV6_ADDR_2 = "2001:0:0:1::11"
-UE_IPV6_ADDR_3 = "2001:0:0:1::21"
-DNS_IPV4_ADDR = "192.168.1.2"
+UE_IPV6_ADDR_2 = "2001:0:0:2::1"
+UE_IPV6_ADDR_3 = "2001:0:0:3::1"
+DNS_IPV4_ADDR = "192.168.1.12"
CSCF_IPV4_ADDR = "192.168.1.2"
CSCF_IPV6_ADDR = "2001:0:0:1::2"
+CSCF_IPV6_ADDR_2 = "2001:0:0:2::2"
+CSCF_IPV6_ADDR_3 = "2001:0:0:3::2"
# GSM BAND constants
GSM_BAND_GSM450 = "GSM450"
@@ -126,9 +128,9 @@
WCDMA_BAND_2 = 2
# Default Cell Parameters
-DEFAULT_OUTPUT_LEVEL = -30
-# apply to LTE & WCDMA only to reduce UE transmit power if path loss
-DEFAULT_INPUT_LEVEL = -10
+DEFAULT_OUTPUT_LEVEL = -20
+DEFAULT_1X_OUTPUT_LEVEL = -35
+DEFAULT_INPUT_LEVEL = 0
DEFAULT_LTE_BAND = [2, 4]
DEFAULT_WCDMA_BAND = 1
DEFAULT_WCDMA_PACKET_RATE = BtsPacketRate.WCDMA_DLHSAUTO_REL7_ULHSAUTO
@@ -140,8 +142,8 @@
DEFAULT_EVDO_BAND = 0
DEFAULT_EVDO_CH = 356
DEFAULT_EVDO_SECTOR_ID = "00000000,00000000,00000000,00000000"
-VzW_CDMA1x_BAND = 0
-VzW_CDMA1x_CH = 384
+VzW_CDMA1x_BAND = 1
+VzW_CDMA1x_CH = 150
VzW_CDMA1X_SID = 26
VzW_CDMA1X_NID = 65535
VzW_EVDO_BAND = 0
@@ -210,7 +212,12 @@
DEFAULT_VNID = 1
NDP_NIC_NAME = '"Intel(R) 82577LM Gigabit Network Connection"'
CSCF_Monitoring_UA_URI = '"sip:+11234567890@test.3gpp.com"'
-TMO_CSCF_Monitoring_UA_URI = '"sip:310260123456789@msg.lab.t-mobile.com"'
+TMO_CSCF_Monitoring_UA_URI = '"sip:001010123456789@msg.lab.t-mobile.com"'
+CSCF_Virtual_UA_URI = '"sip:+11234567891@test.3gpp.com"'
+TMO_CSCF_Virtual_UA_URI = '"sip:0123456789@ims.mnc01.mcc001.3gppnetwork.org"'
+CSCF_HOSTNAME = '"ims.mnc01.mcc001.3gppnetwork.org"'
+TMO_USERLIST_NAME = "310260123456789@msg.lab.t-mobile.com"
+VZW_USERLIST_NAME = "001010123456789@test.3gpp.com"
#Cell Numbers
CELL_1 = 1
@@ -358,6 +365,7 @@
bts.rac = get_gsm_rac(user_params, cell_no)
bts.lac = get_gsm_lac(user_params, cell_no)
bts.output_level = DEFAULT_OUTPUT_LEVEL
+ bts.input_level = DEFAULT_INPUT_LEVEL
def _init_1x_bts(bts, user_params, cell_no, sim_card):
@@ -378,8 +386,7 @@
bts.dl_channel = get_1x_channel(user_params, cell_no, sim_card)
bts.sector1_sid = get_1x_sid(user_params, cell_no, sim_card)
bts.sector1_nid = get_1x_nid(user_params, cell_no, sim_card)
- bts.output_level = DEFAULT_OUTPUT_LEVEL
- bts.input_level = DEFAULT_INPUT_LEVEL
+ bts.output_level = DEFAULT_1X_OUTPUT_LEVEL
def _init_evdo_bts(bts, user_params, cell_no, sim_card):
@@ -398,10 +405,15 @@
bts.band = get_evdo_band(user_params, cell_no, sim_card)
bts.dl_channel = get_evdo_channel(user_params, cell_no, sim_card)
bts.evdo_sid = get_evdo_sid(user_params, cell_no, sim_card)
- bts.output_level = DEFAULT_OUTPUT_LEVEL
+ bts.output_level = DEFAULT_1X_OUTPUT_LEVEL
-def _init_PDN(anritsu_handle, pdn, ipv4, ipv6, ims_binding):
+def _init_PDN(anritsu_handle,
+ pdn,
+ ipv4,
+ ipv6,
+ ims_binding,
+ vnid_number=DEFAULT_VNID):
""" initializes the PDN parameters
All PDN parameters should be set here
@@ -420,14 +432,19 @@
pdn.ue_address_ipv6 = ipv6
if ims_binding:
pdn.pdn_ims = Switch.ENABLE
- pdn.pdn_vnid = DEFAULT_VNID
+ pdn.pdn_vnid = vnid_number
else:
pdn.primary_dns_address_ipv4 = DNS_IPV4_ADDR
pdn.secondary_dns_address_ipv4 = DNS_IPV4_ADDR
pdn.cscf_address_ipv4 = CSCF_IPV4_ADDR
-def _init_IMS(anritsu_handle, vnid, sim_card=None):
+def _init_IMS(anritsu_handle,
+ vnid,
+ sim_card=None,
+ ipv6_address=CSCF_IPV6_ADDR,
+ ip_type="IPV4V6",
+ auth=False):
""" initializes the IMS VNID parameters
All IMS parameters should be set here
@@ -440,11 +457,26 @@
"""
# vnid.sync = Switch.ENABLE # supported in 6.40a release
vnid.cscf_address_ipv4 = CSCF_IPV4_ADDR
- vnid.cscf_address_ipv6 = CSCF_IPV6_ADDR
+ vnid.cscf_address_ipv6 = ipv6_address
+ vnid.imscscf_iptype = ip_type
vnid.dns = Switch.DISABLE
vnid.ndp_nic = NDP_NIC_NAME
+ vnid.ndp_prefix = ipv6_address
if sim_card == P0135Ax:
vnid.cscf_monitoring_ua = TMO_CSCF_Monitoring_UA_URI
+ vnid.cscf_virtual_ua = TMO_CSCF_Virtual_UA_URI
+ vnid.cscf_host_name = CSCF_HOSTNAME
+ vnid.cscf_ims_authentication = "DISABLE"
+ if auth:
+ vnid.cscf_ims_authentication = "ENABLE"
+ vnid.tmo_cscf_userslist_add = TMO_USERLIST_NAME
+ elif sim_card == VzW12349:
+ vnid.cscf_monitoring_ua = CSCF_Monitoring_UA_URI
+ vnid.cscf_virtual_ua = CSCF_Virtual_UA_URI
+ vnid.cscf_ims_authentication = "DISABLE"
+ if auth:
+ vnid.cscf_ims_authentication = "ENABLE"
+ vnid.vzw_cscf_userslist_add = VZW_USERLIST_NAME
else:
vnid.cscf_monitoring_ua = CSCF_Monitoring_UA_URI
vnid.psap = Switch.ENABLE
@@ -475,7 +507,31 @@
_init_PDN(anritsu_handle, pdn2, UE_IPV4_ADDR_2, UE_IPV6_ADDR_2, False)
_init_PDN(anritsu_handle, pdn3, UE_IPV4_ADDR_3, UE_IPV6_ADDR_3, True)
vnid1 = anritsu_handle.get_IMS(DEFAULT_VNID)
- _init_IMS(anritsu_handle, vnid1, sim_card)
+ if sim_card == P0135Ax:
+ vnid2 = anritsu_handle.get_IMS(2)
+ vnid3 = anritsu_handle.get_IMS(3)
+ _init_IMS(
+ anritsu_handle,
+ vnid1,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR,
+ auth=True)
+ _init_IMS(
+ anritsu_handle,
+ vnid2,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR_2,
+ ip_type="IPV6")
+ _init_IMS(
+ anritsu_handle,
+ vnid3,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR_3,
+ ip_type="IPV6")
+ elif sim_card == VzW12349:
+ _init_IMS(anritsu_handle, vnid1, sim_card, auth=True)
+ else:
+ _init_IMS(anritsu_handle, vnid1, sim_card)
return [lte1_bts, lte2_bts]
@@ -526,7 +582,31 @@
_init_PDN(anritsu_handle, pdn2, UE_IPV4_ADDR_2, UE_IPV6_ADDR_2, False)
_init_PDN(anritsu_handle, pdn3, UE_IPV4_ADDR_3, UE_IPV6_ADDR_3, True)
vnid1 = anritsu_handle.get_IMS(DEFAULT_VNID)
- _init_IMS(anritsu_handle, vnid1, sim_card)
+ if sim_card == P0135Ax:
+ vnid2 = anritsu_handle.get_IMS(2)
+ vnid3 = anritsu_handle.get_IMS(3)
+ _init_IMS(
+ anritsu_handle,
+ vnid1,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR,
+ auth=True)
+ _init_IMS(
+ anritsu_handle,
+ vnid2,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR_2,
+ ip_type="IPV6")
+ _init_IMS(
+ anritsu_handle,
+ vnid3,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR_3,
+ ip_type="IPV6")
+ elif sim_card == VzW12349:
+ _init_IMS(anritsu_handle, vnid1, sim_card, auth=True)
+ else:
+ _init_IMS(anritsu_handle, vnid1, sim_card)
return [lte_bts, wcdma_bts]
@@ -554,7 +634,31 @@
_init_PDN(anritsu_handle, pdn2, UE_IPV4_ADDR_2, UE_IPV6_ADDR_2, False)
_init_PDN(anritsu_handle, pdn3, UE_IPV4_ADDR_3, UE_IPV6_ADDR_3, True)
vnid1 = anritsu_handle.get_IMS(DEFAULT_VNID)
- _init_IMS(anritsu_handle, vnid1, sim_card)
+ if sim_card == P0135Ax:
+ vnid2 = anritsu_handle.get_IMS(2)
+ vnid3 = anritsu_handle.get_IMS(3)
+ _init_IMS(
+ anritsu_handle,
+ vnid1,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR,
+ auth=True)
+ _init_IMS(
+ anritsu_handle,
+ vnid2,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR_2,
+ ip_type="IPV6")
+ _init_IMS(
+ anritsu_handle,
+ vnid3,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR_3,
+ ip_type="IPV6")
+ elif sim_card == VzW12349:
+ _init_IMS(anritsu_handle, vnid1, sim_card, auth=True)
+ else:
+ _init_IMS(anritsu_handle, vnid1, sim_card)
return [lte_bts, gsm_bts]
@@ -583,7 +687,31 @@
_init_PDN(anritsu_handle, pdn2, UE_IPV4_ADDR_2, UE_IPV6_ADDR_2, False)
_init_PDN(anritsu_handle, pdn3, UE_IPV4_ADDR_3, UE_IPV6_ADDR_3, True)
vnid1 = anritsu_handle.get_IMS(DEFAULT_VNID)
- _init_IMS(anritsu_handle, vnid1, sim_card)
+ if sim_card == P0135Ax:
+ vnid2 = anritsu_handle.get_IMS(2)
+ vnid3 = anritsu_handle.get_IMS(3)
+ _init_IMS(
+ anritsu_handle,
+ vnid1,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR,
+ auth=True)
+ _init_IMS(
+ anritsu_handle,
+ vnid2,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR_2,
+ ip_type="IPV6")
+ _init_IMS(
+ anritsu_handle,
+ vnid3,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR_3,
+ ip_type="IPV6")
+ elif sim_card == VzW12349:
+ _init_IMS(anritsu_handle, vnid1, sim_card, auth=True)
+ else:
+ _init_IMS(anritsu_handle, vnid1, sim_card)
return [lte_bts, cdma1x_bts]
@@ -611,7 +739,31 @@
_init_PDN(anritsu_handle, pdn2, UE_IPV4_ADDR_2, UE_IPV6_ADDR_2, False)
_init_PDN(anritsu_handle, pdn3, UE_IPV4_ADDR_3, UE_IPV6_ADDR_3, True)
vnid1 = anritsu_handle.get_IMS(DEFAULT_VNID)
- _init_IMS(anritsu_handle, vnid1)
+ if sim_card == P0135Ax:
+ vnid2 = anritsu_handle.get_IMS(2)
+ vnid3 = anritsu_handle.get_IMS(3)
+ _init_IMS(
+ anritsu_handle,
+ vnid1,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR,
+ auth=True)
+ _init_IMS(
+ anritsu_handle,
+ vnid2,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR_2,
+ ip_type="IPV6")
+ _init_IMS(
+ anritsu_handle,
+ vnid3,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR_3,
+ ip_type="IPV6")
+ elif sim_card == VzW12349:
+ _init_IMS(anritsu_handle, vnid1, sim_card, auth=True)
+ else:
+ _init_IMS(anritsu_handle, vnid1, sim_card)
return [lte_bts, evdo_bts]
@@ -681,7 +833,31 @@
_init_PDN(anritsu_handle, pdn2, UE_IPV4_ADDR_2, UE_IPV6_ADDR_2, False)
_init_PDN(anritsu_handle, pdn3, UE_IPV4_ADDR_3, UE_IPV6_ADDR_3, True)
vnid1 = anritsu_handle.get_IMS(DEFAULT_VNID)
- _init_IMS(anritsu_handle, vnid1, sim_card)
+ if sim_card == P0135Ax:
+ vnid2 = anritsu_handle.get_IMS(2)
+ vnid3 = anritsu_handle.get_IMS(3)
+ _init_IMS(
+ anritsu_handle,
+ vnid1,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR,
+ auth=True)
+ _init_IMS(
+ anritsu_handle,
+ vnid2,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR_2,
+ ip_type="IPV6")
+ _init_IMS(
+ anritsu_handle,
+ vnid3,
+ sim_card,
+ ipv6_address=CSCF_IPV6_ADDR_3,
+ ip_type="IPV6")
+ elif sim_card == VzW12349:
+ _init_IMS(anritsu_handle, vnid1, sim_card, auth=True)
+ else:
+ _init_IMS(anritsu_handle, vnid1, sim_card)
return [lte_bts]
@@ -928,9 +1104,9 @@
def handover_tc(log,
anritsu_handle,
wait_time=0,
- timeout=60,
s_bts=BtsNumber.BTS1,
- t_bts=BtsNumber.BTS2):
+ t_bts=BtsNumber.BTS2,
+ timeout=60):
""" Setup and perform a handover test case in MD8475A
Args:
@@ -943,6 +1119,7 @@
True for success False for failure
"""
log.info("Starting HO test case procedure")
+ log.info("Serving BTS = {}, Target BTS = {}".format(s_bts, t_bts))
time.sleep(wait_time)
ho_tc = anritsu_handle.get_AnritsuTestCases()
ho_tc.procedure = TestProcedure.PROCEDURE_HO
@@ -2124,3 +2301,22 @@
except KeyError:
csfb_type = CsfbType.CSFB_TYPE_REDIRECTION
return csfb_type
+
+
+def set_post_sim_params(anritsu_handle, user_params, sim_card):
+ if sim_card == P0135Ax:
+ anritsu_handle.send_command("PDNCHECKAPN 1,ims")
+ anritsu_handle.send_command("PDNCHECKAPN 2,fast.t-mobile.com")
+ anritsu_handle.send_command("PDNIMS 1,ENABLE")
+ anritsu_handle.send_command("PDNVNID 1,1")
+ anritsu_handle.send_command("PDNIMS 2,ENABLE")
+ anritsu_handle.send_command("PDNVNID 2,2")
+ anritsu_handle.send_command("PDNIMS 3,ENABLE")
+ anritsu_handle.send_command("PDNVNID 3,1")
+ if sim_card == VzW12349:
+ anritsu_handle.send_command("PDNCHECKAPN 1,IMS")
+ anritsu_handle.send_command("PDNCHECKAPN 2,VZWINTERNET")
+ anritsu_handle.send_command("PDNIMS 1,ENABLE")
+ anritsu_handle.send_command("PDNVNID 1,1")
+ anritsu_handle.send_command("PDNIMS 3,ENABLE")
+ anritsu_handle.send_command("PDNVNID 3,1")
diff --git a/acts/framework/acts/test_utils/tel/tel_defines.py b/acts/framework/acts/test_utils/tel/tel_defines.py
index 5863e81..ffc7348 100644
--- a/acts/framework/acts/test_utils/tel/tel_defines.py
+++ b/acts/framework/acts/test_utils/tel/tel_defines.py
@@ -18,7 +18,7 @@
# TIMERS
###############################################
# Max time to wait for phone data/network connection state update
-MAX_WAIT_TIME_CONNECTION_STATE_UPDATE = 20
+MAX_WAIT_TIME_CONNECTION_STATE_UPDATE = 60
# Max time to wait for network reselection
MAX_WAIT_TIME_NW_SELECTION = 180
@@ -29,6 +29,9 @@
# Wait time between state check retry
WAIT_TIME_BETWEEN_STATE_CHECK = 5
+# Max wait time for state change
+MAX_WAIT_TIME_FOR_STATE_CHANGE = 60
+
# Max time to wait after caller make a call and before
# callee start ringing
MAX_WAIT_TIME_CALLEE_RINGING = 90
@@ -39,6 +42,9 @@
"+850", "+81"
]
+# default pin/password
+DEFAULT_DEVICE_PASSWORD = "1111"
+
# Wait time after enterring puk code
WAIT_TIME_SUPPLY_PUK_CODE = 30
@@ -94,7 +100,7 @@
MAX_WAIT_TIME_USER_PLANE_DATA = 20
# Max time to wait for tethering entitlement check
-MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK = 15
+MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK = 60
# Max time to wait for voice mail count report correct result.
MAX_WAIT_TIME_VOICE_MAIL_COUNT = 90
@@ -250,6 +256,7 @@
CARRIER_ORG = 'org'
CARRIER_TEL = 'tel'
CARRIER_TSA = 'tsa'
+CARRIER_USCC = 'uscc'
RAT_FAMILY_CDMA = 'cdma'
RAT_FAMILY_CDMA2000 = 'cdma2000'
@@ -423,6 +430,11 @@
PHONE_TYPE_CDMA = "CDMA"
PHONE_TYPE_SIP = "SIP"
+# Constant for SIM Power State
+CARD_POWER_DOWN = 0
+CARD_POWER_UP = 1
+CARD_POWER_UP_PASS_THROUGH = 2
+
# Constant for SIM State
SIM_STATE_READY = "READY"
SIM_STATE_UNKNOWN = "UNKNOWN"
@@ -433,6 +445,7 @@
SIM_STATE_NOT_READY = "NOT_READY"
SIM_STATE_PERM_DISABLED = "PERM_DISABLED"
SIM_STATE_CARD_IO_ERROR = "CARD_IO_ERROR"
+SIM_STATE_LOADED = "LOADED"
# Constant for Data Connection State
DATA_STATE_CONNECTED = "CONNECTED"
@@ -445,6 +458,10 @@
DATA_ROAMING_ENABLE = 1
DATA_ROAMING_DISABLE = 0
+# Constant for ConnectivityManager Data Connection
+TYPE_MOBILE = 0
+TYPE_WIFI = 1
+
# Constant for Telephony Manager Call State
TELEPHONY_STATE_RINGING = "RINGING"
TELEPHONY_STATE_IDLE = "IDLE"
@@ -464,6 +481,15 @@
SERVICE_STATE_POWER_OFF = "POWER_OFF"
SERVICE_STATE_UNKNOWN = "UNKNOWN"
+# Service State Mapping
+SERVICE_STATE_MAPPING = {
+ "-1": SERVICE_STATE_UNKNOWN,
+ "0": SERVICE_STATE_IN_SERVICE,
+ "1": SERVICE_STATE_OUT_OF_SERVICE,
+ "2": SERVICE_STATE_EMERGENCY_ONLY,
+ "3": SERVICE_STATE_POWER_OFF
+}
+
# Constant for VoLTE Hand-over Service State
VOLTE_SERVICE_STATE_HANDOVER_STARTED = "STARTED"
VOLTE_SERVICE_STATE_HANDOVER_COMPLETED = "COMPLETED"
diff --git a/acts/framework/acts/test_utils/tel/tel_lookup_tables.py b/acts/framework/acts/test_utils/tel/tel_lookup_tables.py
index b07d310..e554b00 100644
--- a/acts/framework/acts/test_utils/tel/tel_lookup_tables.py
+++ b/acts/framework/acts/test_utils/tel/tel_lookup_tables.py
@@ -25,7 +25,7 @@
return _TelTables.technology_tbl[rat_type]['generation']
-def network_preference_for_generaton(generation, operator, phone_type=None):
+def network_preference_for_generation(generation, operator, phone_type=None):
if not phone_type:
return _TelTables.operator_network_tbl[operator][generation][
'network_preference']
@@ -223,6 +223,9 @@
'23432': tel_defines.CARRIER_EEUK, #Virgin Mobile (MVNO)
'23415': tel_defines.CARRIER_VFUK,
+ #USCC
+ '311580': tel_defines.CARRIER_USCC,
+
#Vodafone (Germany)
'26202': tel_defines.CARRIER_GMBH,
'26204': tel_defines.CARRIER_GMBH,
@@ -651,6 +654,11 @@
tel_defines.CAPABILITY_PHONE, tel_defines.CAPABILITY_OMADM,
tel_defines.CAPABILITY_VOLTE, tel_defines.CAPABILITY_WFC,
tel_defines.CAPABILITY_VT
+ ],
+ "default": [
+ tel_defines.CAPABILITY_PHONE, tel_defines.CAPABILITY_OMADM,
+ tel_defines.CAPABILITY_VOLTE, tel_defines.CAPABILITY_WFC,
+ tel_defines.CAPABILITY_VT
]
}
@@ -670,5 +678,6 @@
tel_defines.CAPABILITY_PHONE, tel_defines.CAPABILITY_VOLTE,
tel_defines.CAPABILITY_WFC
],
- tel_defines.CARRIER_VFUK: [tel_defines.CAPABILITY_PHONE]
+ tel_defines.CARRIER_VFUK: [tel_defines.CAPABILITY_PHONE],
+ "default": [tel_defines.CAPABILITY_PHONE]
}
diff --git a/acts/framework/acts/test_utils/tel/tel_test_utils.py b/acts/framework/acts/test_utils/tel/tel_test_utils.py
index f7bbe07..9459d4d 100644
--- a/acts/framework/acts/test_utils/tel/tel_test_utils.py
+++ b/acts/framework/acts/test_utils/tel/tel_test_utils.py
@@ -25,11 +25,16 @@
import urllib.parse
import time
+from acts import utils
from queue import Empty
from acts.asserts import abort_all
from acts.controllers.adb import AdbError
+from acts.controllers.android_device import DEFAULT_QXDM_LOG_PATH
+from acts.controllers.android_device import SL4A_APK_NAME
from acts.controllers.sl4a_lib.event_dispatcher import EventDispatcher
from acts.test_utils.tel.tel_defines import AOSP_PREFIX
+from acts.test_utils.tel.tel_defines import CARD_POWER_DOWN
+from acts.test_utils.tel.tel_defines import CARD_POWER_UP
from acts.test_utils.tel.tel_defines import CARRIER_UNKNOWN
from acts.test_utils.tel.tel_defines import COUNTRY_CODE_LIST
from acts.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
@@ -77,11 +82,14 @@
from acts.test_utils.tel.tel_defines import RAT_UNKNOWN
from acts.test_utils.tel.tel_defines import SERVICE_STATE_EMERGENCY_ONLY
from acts.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
+from acts.test_utils.tel.tel_defines import SERVICE_STATE_MAPPING
from acts.test_utils.tel.tel_defines import SERVICE_STATE_OUT_OF_SERVICE
from acts.test_utils.tel.tel_defines import SERVICE_STATE_POWER_OFF
+from acts.test_utils.tel.tel_defines import SIM_STATE_LOADED
+from acts.test_utils.tel.tel_defines import SIM_STATE_NOT_READY
from acts.test_utils.tel.tel_defines import SIM_STATE_PIN_REQUIRED
from acts.test_utils.tel.tel_defines import SIM_STATE_READY
-from acts.test_utils.tel.tel_defines import WAIT_TIME_SUPPLY_PUK_CODE
+from acts.test_utils.tel.tel_defines import SIM_STATE_UNKNOWN
from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_IDLE
from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_OFFHOOK
from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_RINGING
@@ -89,12 +97,15 @@
from acts.test_utils.tel.tel_defines import WAIT_TIME_1XRTT_VOICE_ATTACH
from acts.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
+from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
from acts.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_DATA_SUB_ID
from acts.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
from acts.test_utils.tel.tel_defines import WAIT_TIME_LEAVE_VOICE_MAIL
from acts.test_utils.tel.tel_defines import WAIT_TIME_REJECT_CALL
from acts.test_utils.tel.tel_defines import WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE
from acts.test_utils.tel.tel_defines import WFC_MODE_DISABLED
+from acts.test_utils.tel.tel_defines import TYPE_MOBILE
+from acts.test_utils.tel.tel_defines import TYPE_WIFI
from acts.test_utils.tel.tel_defines import EventCallStateChanged
from acts.test_utils.tel.tel_defines import EventConnectivityChanged
from acts.test_utils.tel.tel_defines import EventDataConnectionStateChanged
@@ -119,7 +130,7 @@
from acts.test_utils.tel.tel_lookup_tables import get_voice_mail_check_number
from acts.test_utils.tel.tel_lookup_tables import get_voice_mail_delete_digit
from acts.test_utils.tel.tel_lookup_tables import \
- network_preference_for_generaton
+ network_preference_for_generation
from acts.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id
from acts.test_utils.tel.tel_lookup_tables import \
rat_families_for_network_preference
@@ -146,6 +157,7 @@
from acts.logger import epoch_to_log_line_timestamp
from acts.logger import normalize_log_line_timestamp
from acts.utils import get_current_epoch_time
+from acts.utils import exe_cmd
WIFI_SSID_KEY = wifi_test_utils.WifiEnums.SSID_KEY
WIFI_PWD_KEY = wifi_test_utils.WifiEnums.PWD_KEY
@@ -247,41 +259,45 @@
log.warning("Failed to load %s!", sim_filename)
if not ad.cfg["subscription"]:
abort_all_tests(ad.log, "No Valid SIMs found in device")
- result = False
+ result = True
+ active_sub_id = get_outgoing_voice_sub_id(ad)
for sub_id, sub_info in ad.cfg["subscription"].items():
sub_info["operator"] = get_operator_name(log, ad, sub_id)
iccid = sub_info["iccid"]
if not iccid:
ad.log.warn("Unable to find ICC-ID for SIM")
continue
- if not sub_info["phone_num"]:
- if iccid in sim_data and sim_data[iccid].get("phone_num"):
- sub_info["phone_num"] = sim_data[iccid]["phone_num"]
- ad.phone_number = sub_info["phone_num"]
- result = True
- else:
- phone_number = get_phone_number_by_secret_code(
- ad, sub_info["sim_operator_name"])
- if phone_number:
+ if sub_info.get("phone_num"):
+ if getattr(ad, "phone_number", None) and check_phone_number_match(
+ sub_info["phone_num"], ad.phone_number):
+ sub_info["phone_num"] = ad.phone_number
+ elif iccid and iccid in sim_data and sim_data[iccid].get(
+ "phone_num"):
+ if check_phone_number_match(sim_data[iccid]["phone_num"],
+ sub_info["phone_num"]):
sub_info["phone_num"] = sim_data[iccid]["phone_num"]
- ad.phone_number = sub_info["phone_num"]
- result = True
else:
- ad.log.error(
- "Unable to retrieve phone number for sub %s iccid %s"
- " from device or testbed config or sim_file %s",
- sim_filename, sub_id, iccid)
- else:
- result = True
- if sim_data.get(iccid) and sim_data[iccid].get("phone_num"):
- if not check_phone_number_match(sub_info["phone_num"],
- sim_data[iccid]["phone_num"]):
ad.log.warning(
- "ICCID %s phone number is %s in %s, does not match "
- "the number %s retrieved from the phone", iccid,
- sim_data[iccid]["phone_num"], sim_filename,
+ "phone_num %s in sim card data file for iccid %s"
+ " do not match phone_num %s in droid subscription",
+ sim_data[iccid]["phone_num"], iccid,
sub_info["phone_num"])
- sub_info["phone_num"] = sim_data[iccid]["phone_num"]
+ elif iccid and iccid in sim_data and sim_data[iccid].get("phone_num"):
+ sub_info["phone_num"] = sim_data[iccid]["phone_num"]
+ elif sub_id == active_sub_id:
+ phone_number = get_phone_number_by_secret_code(
+ ad, sub_info["sim_operator_name"])
+ if phone_number:
+ sub_info["phone_num"] = phone_number
+ elif getattr(ad, "phone_num", None):
+ sub_info["phone_num"] = ad.phone_number
+ if (not sub_info.get("phone_num")) and sub_id == active_sub_id:
+ ad.log.info("sub_id %s sub_info = %s", sub_id, sub_info)
+ ad.log.error(
+ "Unable to retrieve phone number for sub %s with iccid"
+ " %s from device or testbed config or sim card file %s",
+ sub_id, iccid, sim_filename)
+ result = False
if not hasattr(
ad, 'roaming'
) and sub_info["sim_plmn"] != sub_info["network_plmn"] and (
@@ -309,20 +325,23 @@
Returns:
None
"""
- cfg = {"subscription": {}}
+ if hasattr(ad, 'cfg'):
+ cfg = ad.cfg.copy()
+ else:
+ cfg = {"subscription": {}}
droid = ad.droid
sub_info_list = droid.subscriptionGetAllSubInfoList()
for sub_info in sub_info_list:
sub_id = sub_info["subscriptionId"]
sim_slot = sub_info["simSlotIndex"]
if sim_slot != INVALID_SIM_SLOT_INDEX:
- sim_serial = droid.telephonyGetSimSerialNumberForSubscription(
- sub_id)
- if not sim_serial:
- ad.log.error("Unable to find ICC-ID for SIM in slot %s",
- sim_slot)
sim_record = {}
- sim_record["iccid"] = sim_serial
+ if sub_info.get("iccId"):
+ sim_record["iccid"] = sub_info["iccId"]
+ else:
+ sim_record[
+ "iccid"] = droid.telephonyGetSimSerialNumberForSubscription(
+ sub_id)
sim_record["sim_slot"] = sim_slot
try:
sim_record[
@@ -330,9 +349,14 @@
sub_id)
except:
sim_record["phone_type"] = droid.telephonyGetPhoneType()
+ if sub_info.get("mcc"):
+ sim_record["mcc"] = sub_info["mcc"]
+ if sub_info.get("mnc"):
+ sim_record["mnc"] = sub_info["mnc"]
sim_record[
"sim_plmn"] = droid.telephonyGetSimOperatorForSubscription(
sub_id)
+ sim_record["display_name"] = sub_info["displayName"]
sim_record[
"sim_operator_name"] = droid.telephonyGetSimOperatorNameForSubscription(
sub_id)
@@ -348,13 +372,18 @@
sim_record[
"sim_country"] = droid.telephonyGetSimCountryIsoForSubscription(
sub_id)
- phone_number = droid.telephonyGetLine1NumberForSubscription(sub_id)
- if not phone_number and getattr(ad, "phone_number", None):
- phone_number = ad.phone_number
- sim_record["phone_num"] = phone_number_formatter(phone_number)
+ if sub_info.get("number"):
+ sim_record["phone_num"] = sub_info["number"]
+ else:
+ sim_record["phone_num"] = phone_number_formatter(
+ droid.telephonyGetLine1NumberForSubscription(sub_id))
sim_record[
"phone_tag"] = droid.telephonyGetLine1AlphaTagForSubscription(
sub_id)
+ if (not sim_record["phone_num"]
+ ) and cfg["subscription"].get(sub_id):
+ sim_record["phone_num"] = cfg["subscription"][sub_id][
+ "phone_num"]
cfg['subscription'][sub_id] = sim_record
ad.log.debug("SubId %s SIM record: %s", sub_id, sim_record)
setattr(ad, 'cfg', cfg)
@@ -470,6 +499,12 @@
return signal_strength
+def get_wifi_signal_strength(ad):
+ signal_strength = ad.droid.wifiGetConnectionInfo()['rssi']
+ ad.log.info("WiFi Signal Strength is %s" % signal_strength)
+ return signal_strength
+
+
def is_expected_event(event_to_check, events_list):
""" check whether event is present in the event list
@@ -506,6 +541,31 @@
return True
+def is_sim_ready_by_adb(log, ad):
+ state = ad.adb.getprop("gsm.sim.state")
+ return state == SIM_STATE_READY or state == SIM_STATE_LOADED
+
+
+def wait_for_sim_ready_by_adb(log, ad, wait_time=90):
+ return _wait_for_droid_in_state(log, ad, wait_time, is_sim_ready_by_adb)
+
+
+def get_service_state_by_adb(log, ad):
+ output = ad.adb.shell("dumpsys telephony.registry | grep mServiceState")
+ if "mVoiceRegState" in output:
+ result = re.search(r"mVoiceRegState=(\S+)\((\S+)\)", output)
+ if result:
+ ad.log.info("mVoiceRegState is %s %s", result.group(1),
+ result.group(2))
+ return result.group(2)
+ else:
+ result = re.search(r"mServiceState=(\S+)", output)
+ if result:
+ ad.log.info("mServiceState=%s %s", result.group(1),
+ SERVICE_STATE_MAPPING[result.group(1)])
+ return SERVICE_STATE_MAPPING[result.group(1)]
+
+
def _is_expecting_event(event_recv_list):
""" check for more event is expected in event list
@@ -780,7 +840,7 @@
False: for errors
"""
if not event_tracking_started:
- ad.ed.clear_all_events()
+ ad.ed.clear_events(EventCallStateChanged)
ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
event_ringing = None
for i in range(retries):
@@ -794,7 +854,7 @@
ad.log.info("callee in ringing state")
break
if i == retries - 1:
- ad.log.error(
+ ad.log.info(
"callee didn't receive ring event or got into ringing state")
return False
if not event_tracking_started:
@@ -835,7 +895,7 @@
False: if call offhook event is not received.
"""
if not event_tracking_started:
- ad.ed.clear_all_events()
+ ad.ed.clear_events(EventCallStateChanged)
ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
try:
ad.ed.wait_for_event(
@@ -881,7 +941,7 @@
True: if incoming call is received and answered successfully.
False: for errors
"""
- ad.ed.clear_all_events()
+ ad.ed.clear_events(EventCallStateChanged)
ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
try:
if not _wait_for_droid_in_state(
@@ -939,9 +999,10 @@
True: if incoming call is received and reject successfully.
False: for errors
"""
- return wait_and_reject_call_for_subscription(
- log, ad,
- get_incoming_voice_sub_id(ad), incoming_number, delay_reject, reject)
+ return wait_and_reject_call_for_subscription(log, ad,
+ get_incoming_voice_sub_id(ad),
+ incoming_number, delay_reject,
+ reject)
def wait_and_reject_call_for_subscription(log,
@@ -972,7 +1033,7 @@
ad.log.error("Could not reject a call: phone never rang.")
return False
- ad.ed.clear_all_events()
+ ad.ed.clear_events(EventCallStateChanged)
ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
if reject is True:
# Delay between ringing and reject.
@@ -1021,7 +1082,7 @@
# short circuit in case no calls are active
if not ad.droid.telecomIsInCall():
return True
- ad.ed.clear_all_events()
+ ad.ed.clear_events(EventCallStateChanged)
ad.droid.telephonyStartTrackingCallState()
ad.log.info("Hangup call.")
ad.droid.telecomEndCall()
@@ -1039,7 +1100,7 @@
return False
finally:
ad.droid.telephonyStopTrackingCallStateChange()
- return True
+ return not ad.droid.telecomIsInCall()
def disconnect_call_by_id(log, ad, call_id):
@@ -1110,8 +1171,7 @@
number1 = phone_number_formatter(number1)
number2 = phone_number_formatter(number2)
# Handle extra country code attachment when matching phone number
- if number1.replace("+", "") in number2 or number2.replace("+",
- "") in number1:
+ if number1[-7:] in number2 or number2[-7:] in number1:
return True
else:
logging.info("phone number1 %s and number2 %s does not match" %
@@ -1137,7 +1197,7 @@
Returns:
result: if phone call is placed successfully.
"""
- ad.ed.clear_all_events()
+ ad.ed.clear_events(EventCallStateChanged)
sub_id = get_outgoing_voice_sub_id(ad)
ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
@@ -1157,16 +1217,18 @@
for i in range(checking_retries):
if (ad.droid.telecomIsInCall() and
ad.droid.telephonyGetCallState() == TELEPHONY_STATE_OFFHOOK
- and
- ad.droid.telecomGetCallState() == TELEPHONY_STATE_OFFHOOK
- ) or wait_for_call_offhook_event(log, ad, sub_id, True,
- checking_interval):
+ and ad.droid.telecomGetCallState() ==
+ TELEPHONY_STATE_OFFHOOK) or wait_for_call_offhook_event(
+ log, ad, sub_id, True, checking_interval):
return True
ad.log.info(
"Make call to %s fail. telecomIsInCall:%s, Telecom State:%s,"
- " Telephony State:%s", callee_number,
- ad.droid.telecomIsInCall(),
+ " Telephony State:%s", callee_number, ad.droid.telecomIsInCall(),
ad.droid.telephonyGetCallState(), ad.droid.telecomGetCallState())
+ reasons = ad.search_logcat(
+ "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause")
+ if reasons:
+ ad.log.info(reasons[-1]["log_message"])
return False
finally:
ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
@@ -1240,6 +1302,7 @@
try:
# Make a Call
ad.wakeup_screen()
+ ad.send_keycode("MENU")
ad.log.info("Call %s", callee_number)
ad.adb.shell("am start -a com.android.phone.EmergencyDialer.DIAL")
ad.adb.shell(
@@ -1263,7 +1326,7 @@
ad.log.error("initiate emergency call failed with error %s", e)
-def hung_up_call_by_adb(ad):
+def hangup_call_by_adb(ad):
"""Make emergency call by EmergencyDialer.
Args:
@@ -1432,7 +1495,7 @@
# ensure that all internal states are updated in telecom
time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- ad_callee.ed.clear_all_events()
+ ad_callee.ed.ad.ed.clear_events(EventCallStateChanged)
if verify_caller_func and not verify_caller_func(log, ad_caller):
raise _CallSequenceException("Caller not in correct state!")
@@ -1543,8 +1606,8 @@
# wait for telephonyGetVoiceMailCount to update correct result
remaining_time = MAX_WAIT_TIME_VOICE_MAIL_COUNT
- while ((remaining_time > 0) and
- (ad.droid.telephonyGetVoiceMailCount() != 0)):
+ while ((remaining_time > 0)
+ and (ad.droid.telephonyGetVoiceMailCount() != 0)):
time.sleep(1)
remaining_time -= 1
current_voice_mail_count = ad.droid.telephonyGetVoiceMailCount()
@@ -1645,7 +1708,7 @@
"""
CHECK_INTERVAL = 5
- result = True
+ begin_time = get_current_epoch_time()
caller_number = ad_caller.cfg['subscription'][subid_caller]['phone_num']
callee_number = ad_callee.cfg['subscription'][subid_callee]['phone_num']
@@ -1655,8 +1718,10 @@
if not verify_callee_func:
verify_callee_func = is_phone_in_call
result = True
- ad_caller.log.info("Call from %s to %s with duration %s", caller_number,
- callee_number, wait_time_in_call)
+ msg = "Call from %s to %s" % (caller_number, callee_number)
+ if ad_hangup:
+ msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
+ ad_caller.log.info(msg)
try:
if not initiate_call(
@@ -1665,7 +1730,6 @@
callee_number,
wait_time_betwn_call_initcheck=extra_sleep):
ad_caller.log.error("Initiate call failed.")
- result = False
return False
else:
ad_caller.log.info("Caller initate call successfully")
@@ -1677,11 +1741,17 @@
caller=ad_caller,
incall_ui_display=incall_ui_display):
ad_callee.log.error("Answer call fail.")
- result = False
return False
else:
ad_callee.log.info("Callee answered the call successfully")
+ for ad in (ad_caller, ad_callee):
+ if not wait_for_in_call_active(ad):
+ result = False
+ if not ad.droid.telecomCallGetAudioState():
+ ad.log.error("Audio is not in call state")
+ result = False
+
elapsed_time = 0
while (elapsed_time < wait_time_in_call):
CHECK_INTERVAL = min(CHECK_INTERVAL,
@@ -1690,29 +1760,33 @@
elapsed_time += CHECK_INTERVAL
time_message = "at <%s>/<%s> second." % (elapsed_time,
wait_time_in_call)
- if not verify_caller_func(log, ad_caller):
- ad_caller.log.error("Caller is NOT in correct %s state at %s",
- verify_caller_func.__name__, time_message)
- result = False
- else:
- ad_caller.log.info("Caller is in correct %s state at %s",
- verify_caller_func.__name__, time_message)
- if not verify_callee_func(log, ad_callee):
- ad_callee.log.error("Callee is NOT in correct %s state at %s",
- verify_callee_func.__name__, time_message)
- result = False
- else:
- ad_callee.log.info("Callee is in correct %s state at %s",
- verify_callee_func.__name__, time_message)
- if not result:
- return result
- return result
- finally:
- if result and ad_hangup and not hangup_call(log, ad_hangup):
+ for ad, call_func in [(ad_caller, verify_caller_func),
+ (ad_callee, verify_callee_func)]:
+ if not call_func(log, ad):
+ ad.log.error("NOT in correct %s state at %s",
+ call_func.__name__, time_message)
+ result = False
+ else:
+ ad.log.info("In correct %s state at %s",
+ call_func.__name__, time_message)
+ if not ad.droid.telecomCallGetAudioState():
+ ad.log.error("Audio is not in call state at %s",
+ time_message)
+ result = False
+ if not result:
+ break
+ if ad_hangup and not hangup_call(log, ad_hangup):
ad_hangup.log.info("Failed to hang up the call")
result = False
+ return result
+ finally:
if not result:
for ad in [ad_caller, ad_callee]:
+ reasons = ad.search_logcat(
+ "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause",
+ begin_time)
+ if reasons:
+ ad.log.info(reasons[-1]["log_message"])
try:
if ad.droid.telecomIsInCall():
ad.droid.telecomEndCall()
@@ -1745,14 +1819,14 @@
if not formatter:
return input_string
# Remove "1" or "+1"from front
- if (len(input_string) == PHONE_NUMBER_STRING_FORMAT_11_DIGIT and
- input_string[0] == "1"):
+ if (len(input_string) == PHONE_NUMBER_STRING_FORMAT_11_DIGIT
+ and input_string[0] == "1"):
input_string = input_string[1:]
- elif (len(input_string) == PHONE_NUMBER_STRING_FORMAT_12_DIGIT and
- input_string[0:2] == "+1"):
+ elif (len(input_string) == PHONE_NUMBER_STRING_FORMAT_12_DIGIT
+ and input_string[0:2] == "+1"):
input_string = input_string[2:]
- elif (len(input_string) == PHONE_NUMBER_STRING_FORMAT_7_DIGIT and
- formatter == PHONE_NUMBER_STRING_FORMAT_7_DIGIT):
+ elif (len(input_string) == PHONE_NUMBER_STRING_FORMAT_7_DIGIT
+ and formatter == PHONE_NUMBER_STRING_FORMAT_7_DIGIT):
return input_string
elif len(input_string) != PHONE_NUMBER_STRING_FORMAT_10_DIGIT:
return None
@@ -1787,9 +1861,10 @@
def verify_http_connection(log,
ad,
- url="http://www.google.com/",
+ url="www.google.com",
retry=5,
- retry_interval=15):
+ retry_interval=15,
+ expected_state=True):
"""Make ping request and return status.
Args:
@@ -1800,23 +1875,26 @@
"""
for i in range(0, retry + 1):
-
- try:
- http_response = ad.droid.httpPing(url)
- except:
- http_response = None
-
+ # b/18899134 httpPing will hang
+ #try:
+ # http_response = ad.droid.httpPing(url)
+ #except:
+ # http_response = None
# If httpPing failed, it may return {} (if phone just turn off APM) or
# None (regular fail)
- # So here use "if http_response" to see if it pass or fail
- if http_response:
- ad.log.info("Verify Internet succeeded")
+ state = ad.droid.pingHost(url)
+ ad.log.info("Connection to %s is %s", url, state)
+ if expected_state == state:
+ ad.log.info("Verify Internet connection state is %s succeeded",
+ str(expected_state))
return True
- else:
- if i < retry:
- time.sleep(retry_interval)
- ad.log.info("Verify Internet retry failed after %s second",
- i * retry_interval)
+ if i < retry:
+ ad.log.info(
+ "Verify Internet connection state=%s failed. Try again",
+ str(expected_state))
+ time.sleep(retry_interval)
+ ad.log.info("Verify Internet state=%s failed after %s second",
+ expected_state, i * retry_interval)
return False
@@ -1875,7 +1953,6 @@
# files available for download on the same website:
# 1GB.zip, 512MB.zip, 200MB.zip, 50MB.zip, 20MB.zip, 10MB.zip, 5MB.zip
# download file by adb command, as phone call will use sl4a
- url = "http://146.148.91.8/download/" + file_name + ".zip"
file_map_dict = {
'5MB': 5000000,
'10MB': 10000000,
@@ -1891,12 +1968,10 @@
return False
timeout = min(max(file_size / 100000, 600), 3600)
output_path = "/sdcard/Download/" + file_name + ".zip"
- if not ad.curl_capable:
- return (http_file_download_by_chrome, (ad, url, file_size, True,
- timeout))
- else:
- return (http_file_download_by_curl, (ad, url, output_path, file_size,
- True, timeout))
+ url = "http://ipv4.download.thinkbroadband.com/" + file_name + ".zip"
+ #url = "http://146.148.91.8/download/" + file_name + ".zip"
+ return (http_file_download_by_sl4a, (ad, url, output_path, file_size, True,
+ timeout))
def active_file_download_test(log, ad, file_name="5MB"):
@@ -1914,9 +1989,12 @@
"""
for i in range(retries):
ad.log.info("Verify internet connection - attempt %d", i + 1)
- result = adb_shell_ping(ad, count=5, timeout=60, loss_tolerance=40)
- if result:
- return True
+ dest_to_ping = ["www.google.com", "www.amazon.com", "54.230.144.105"]
+ for dest in dest_to_ping:
+ result = adb_shell_ping(
+ ad, count=5, timeout=60, loss_tolerance=40, dest_ip=dest)
+ if result:
+ return True
return False
@@ -1929,7 +2007,9 @@
limit_rate=None,
omit=10,
ipv6=False,
- rate_dict=None):
+ rate_dict=None,
+ blocking=True,
+ log_file_path=None):
"""Iperf test by adb.
Args:
@@ -1947,7 +2027,16 @@
if ipv6: iperf_option += " -6"
if reverse: iperf_option += " -R"
try:
+ if log_file_path:
+ ad.adb.shell("rm %s" % log_file_path, ignore_status=True)
ad.log.info("Running adb iperf test with server %s", iperf_server)
+ if not blocking:
+ ad.run_iperf_client_nb(
+ iperf_server,
+ iperf_option,
+ timeout=timeout + 60,
+ log_file_path=log_file_path)
+ return True
result, data = ad.run_iperf_client(
iperf_server, iperf_option, timeout=timeout + 60)
ad.log.info("Iperf test result with server %s is %s", iperf_server,
@@ -2000,13 +2089,56 @@
if retry:
curl_cmd += " --retry %s" % retry
curl_cmd += " --url %s > %s" % (url, file_path)
+ accounting_apk = "com.android.server.telecom" #"com.quicinc.cne.CNEService"
+ result = True
+ begin_time = int(time.time() * 1000 - 2 * 60 * 60 * 1000)
+ end_time = int(time.time() * 1000 + 2 * 60 * 60 * 1000)
try:
+ data_accounting = {
+ "mobile_rx_bytes":
+ ad.droid.getMobileRxBytes(),
+ "subscriber_mobile_data_usage":
+ get_mobile_data_usage(ad, None, None, begin_time, end_time),
+ "curl_mobile_data_usage":
+ get_mobile_data_usage(ad, None, accounting_apk, begin_time,
+ end_time)
+ }
+ ad.log.info("Before downloading: %s", data_accounting)
ad.log.info("Download %s to %s by adb shell command %s", url,
file_path, curl_cmd)
ad.adb.shell(curl_cmd, timeout=timeout)
if _check_file_existance(ad, file_path, expected_file_size):
ad.log.info("%s is downloaded to %s successfully", url, file_path)
- return True
+ new_data_accounting = {
+ "mobile_rx_bytes":
+ ad.droid.getMobileRxBytes(),
+ "subscriber_mobile_data_usage":
+ get_mobile_data_usage(ad, None, None, begin_time, end_time),
+ "curl_mobile_data_usage":
+ get_mobile_data_usage(ad, None, accounting_apk, begin_time,
+ end_time)
+ }
+ ad.log.info("After downloading: %s", new_data_accounting)
+ accounting_diff = {
+ key: value - data_accounting[key]
+ for key, value in new_data_accounting.items()
+ }
+ ad.log.info("Data accounting difference: %s", accounting_diff)
+ if getattr(ad, "on_mobile_data", False):
+ for key, value in accounting_diff.items():
+ if value < expected_file_size:
+ ad.log.warning("%s diff is %s less than %s", key,
+ value, expected_file_size)
+ ad.data_accounting["%s_failure" % key] += 1
+ else:
+ for key, value in accounting_diff.items():
+ if value >= expected_file_size:
+ ad.log.error("%s diff is %s. File download is "
+ "consuming mobile data", key, value)
+ result = False
+ ad.log.info("data_accounting_failure: %s", dict(
+ ad.data_accounting))
+ return result
else:
ad.log.warning("Fail to download %s", url)
return False
@@ -2039,30 +2171,72 @@
check.
timeout: timeout for file download to complete.
"""
+ chrome_apk = "com.android.chrome"
file_directory, file_name = _generate_file_directory_and_file_name(
url, "/sdcard/Download/")
file_path = os.path.join(file_directory, file_name)
# Remove pre-existing file
- ad.force_stop_apk("com.android.chrome")
+ ad.force_stop_apk(chrome_apk)
file_to_be_delete = os.path.join(file_directory, "*%s*" % file_name)
ad.adb.shell("rm -f %s" % file_to_be_delete)
ad.adb.shell("rm -rf /sdcard/Download/.*")
ad.adb.shell("rm -f /sdcard/Download/.*")
- total_rx_bytes_before = ad.droid.getTotalRxBytes()
- mobile_rx_bytes_before = ad.droid.getMobileRxBytes()
- subscriber_mobile_data_usage_before = get_mobile_data_usage(ad)
+ begin_time = int(time.time() * 1000 - 2 * 60 * 60 * 1000)
+ end_time = int(time.time() * 1000 + 2 * 60 * 60 * 1000)
+ data_accounting = {
+ "total_rx_bytes":
+ ad.droid.getTotalRxBytes(),
+ "mobile_rx_bytes":
+ ad.droid.getMobileRxBytes(),
+ "subscriber_mobile_data_usage":
+ get_mobile_data_usage(ad, None, None, begin_time, end_time),
+ "chrome_mobile_data_usage":
+ get_mobile_data_usage(ad, None, chrome_apk, begin_time, end_time)
+ }
+ ad.log.info("Before downloading: %s", data_accounting)
ad.ensure_screen_on()
ad.log.info("Download %s with timeout %s", url, timeout)
open_url_by_adb(ad, url)
elapse_time = 0
+ result = True
while elapse_time < timeout:
time.sleep(30)
if _check_file_existance(ad, file_path, expected_file_size):
ad.log.info("%s is downloaded successfully", url)
if remove_file_after_check:
ad.log.info("Remove the downloaded file %s", file_path)
- ad.adb.shell("rm %s" % file_path, ignore_status=True)
- return True
+ ad.adb.shell("rm -f %s" % file_to_be_delete)
+ ad.adb.shell("rm -rf /sdcard/Download/.*")
+ ad.adb.shell("rm -f /sdcard/Download/.*")
+ #time.sleep(30)
+ new_data_accounting = {
+ "mobile_rx_bytes":
+ ad.droid.getMobileRxBytes(),
+ "subscriber_mobile_data_usage":
+ get_mobile_data_usage(ad, None, None, begin_time, end_time),
+ "chrome_mobile_data_usage":
+ get_mobile_data_usage(ad, None, chrome_apk, begin_time,
+ end_time)
+ }
+ ad.log.info("After downloading: %s", new_data_accounting)
+ accounting_diff = {
+ key: value - data_accounting[key]
+ for key, value in new_data_accounting.items()
+ }
+ ad.log.info("Data accounting difference: %s", accounting_diff)
+ if getattr(ad, "on_mobile_data", False):
+ for key, value in accounting_diff.items():
+ if value < expected_file_size:
+ ad.log.warning("%s diff is %s less than %s", key,
+ value, expected_file_size)
+ ad.data_accounting["%s_failure" % key] += 1
+ else:
+ for key, value in accounting_diff.items():
+ if value >= expected_file_size:
+ ad.log.error("%s diff is %s. File download is "
+ "consuming mobile data", key, value)
+ result = False
+ return result
elif _check_file_existance(ad, "%s.crdownload" % file_path):
ad.log.info("Chrome is downloading %s", url)
elif elapse_time < 60:
@@ -2072,15 +2246,15 @@
ad.log.error("Unable to download file from %s", url)
break
elapse_time += 30
- ad.log.error("Fail to download file from %s", url)
+ ad.log.warning("Fail to download file from %s", url)
ad.force_stop_apk("com.android.chrome")
- ad.adb.shell("rm %s" % file_path, ignore_status=True)
- ad.adb.shell("rm %s.crdownload" % file_path, ignore_status=True)
+ ad.adb.shell("rm -f %s" % file_to_be_delete)
+ ad.adb.shell("rm -rf /sdcard/Download/.*")
+ ad.adb.shell("rm -f /sdcard/Download/.*")
return False
-def http_file_download_by_sl4a(log,
- ad,
+def http_file_download_by_sl4a(ad,
url,
out_path=None,
expected_file_size=None,
@@ -2089,7 +2263,6 @@
"""Download http file by sl4a RPC call.
Args:
- log: log object
ad: Android Device Object.
url: The url that file to be downloaded from".
out_path: Optional. Where to download file to.
@@ -2103,13 +2276,72 @@
file_folder, file_name = _generate_file_directory_and_file_name(
url, out_path)
file_path = os.path.join(file_folder, file_name)
+ ad.adb.shell("rm -f %s" % file_path)
+ accounting_apk = SL4A_APK_NAME
+ result = True
+ begin_time = int(time.time() * 1000 - 2 * 60 * 60 * 1000)
+ end_time = int(time.time() * 1000 + 2 * 60 * 60 * 1000)
try:
+ if not getattr(ad, "downloading_droid", None):
+ ad.downloading_droid, ad.downloading_ed = ad.get_droid()
+ ad.downloading_ed.start()
+ else:
+ try:
+ if not ad.downloading_droid.is_live:
+ ad.downloading_droid, ad.downloading_ed = ad.get_droid()
+ ad.downloading_ed.start()
+ except Exception as e:
+ ad.log.info(e)
+ ad.downloading_droid, ad.downloading_ed = ad.get_droid()
+ ad.downloading_ed.start()
+ data_accounting = {
+ "mobile_rx_bytes":
+ ad.droid.getMobileRxBytes(),
+ "subscriber_mobile_data_usage":
+ get_mobile_data_usage(ad, None, None, begin_time, end_time),
+ "sl4a_mobile_data_usage":
+ get_mobile_data_usage(ad, None, accounting_apk, begin_time,
+ end_time)
+ }
+ ad.log.info("Before downloading: %s", data_accounting)
ad.log.info("Download file from %s to %s by sl4a RPC call", url,
file_path)
- ad.droid.httpDownloadFile(url, file_path, timeout=timeout)
+ try:
+ ad.downloading_droid.httpDownloadFile(
+ url, file_path, timeout=timeout)
+ except Exception as e:
+ ad.log.warning("SL4A file download error: %s", e)
+ return False
if _check_file_existance(ad, file_path, expected_file_size):
ad.log.info("%s is downloaded successfully", url)
- return True
+ new_data_accounting = {
+ "mobile_rx_bytes":
+ ad.droid.getMobileRxBytes(),
+ "subscriber_mobile_data_usage":
+ get_mobile_data_usage(ad, None, None, begin_time, end_time),
+ "sl4a_mobile_data_usage":
+ get_mobile_data_usage(ad, None, accounting_apk, begin_time,
+ end_time)
+ }
+ ad.log.info("After downloading: %s", new_data_accounting)
+ accounting_diff = {
+ key: value - data_accounting[key]
+ for key, value in new_data_accounting.items()
+ }
+ ad.log.info("Data accounting difference: %s", accounting_diff)
+ if getattr(ad, "on_mobile_data", False):
+ for key, value in accounting_diff.items():
+ if value < expected_file_size:
+ ad.log.warning("%s diff is %s less than %s", key,
+ value, expected_file_size)
+ ad.data_accounting["%s_failure"] += 1
+ else:
+ for key, value in accounting_diff.items():
+ if value >= expected_file_size:
+ ad.log.error("%s diff is %s. File download is "
+ "consuming mobile data", key, value)
+ result = False
+ return result
else:
ad.log.warning("Fail to download %s", url)
return False
@@ -2122,13 +2354,80 @@
ad.adb.shell("rm %s" % file_path, ignore_status=True)
-def trigger_modem_crash(log, ad, timeout=10):
+def get_mobile_data_usage(ad,
+ subscriber_id=None,
+ apk=None,
+ begin_time=None,
+ end_time=None):
+ if not subscriber_id:
+ subscriber_id = ad.droid.telephonyGetSubscriberId()
+ if begin_time is None:
+ begin_time = 0
+ if end_time is None:
+ end_time = int(time.time() * 1000 + 2 * 60 * 60 * 1000)
+ if apk:
+ uid = ad.get_apk_uid(apk)
+ try:
+ usage = ad.droid.connectivityQueryDetailsForUid(
+ TYPE_MOBILE, subscriber_id, begin_time, end_time, uid)
+ except Exception:
+ usage = ad.droid.cconnectivityQueryDetailsForUid(
+ subscriber_id, begin_time, end_time, uid)
+ ad.log.debug("The mobile data usage for apk %s is %s", apk, usage)
+ else:
+ try:
+ usage = ad.droid.connectivityQuerySummaryForDevice(
+ TYPE_MOBILE, subscriber_id, begin_time, end_time)
+ except Exception:
+ usage = ad.droid.connectivityQuerySummaryForDevice(
+ subscriber_id, begin_time, end_time)
+ ad.log.debug("The mobile data usage for subscriber is %s", usage)
+ return usage
+
+
+def set_mobile_data_usage_limit(ad, limit, subscriber_id=None):
+ if not subscriber_id:
+ subscriber_id = ad.droid.telephonyGetSubscriberId()
+ ad.log.info("Set subscriber mobile data usage limit to %s", limit)
+ ad.droid.connectivitySetDataUsageLimit(subscriber_id, str(limit))
+
+
+def remove_mobile_data_usage_limit(ad, subscriber_id=None):
+ if not subscriber_id:
+ subscriber_id = ad.droid.telephonyGetSubscriberId()
+ ad.log.info("Remove subscriber mobile data usage limit")
+ ad.droid.connectivitySetDataUsageLimit(subscriber_id, "-1")
+
+
+def trigger_modem_crash(ad, timeout=120):
cmd = "echo restart > /sys/kernel/debug/msm_subsys/modem"
- ad.log.info("Triggering Modem Crash using adb command %s", cmd)
- ad.adb.shell(cmd, timeout=timeout)
+ ad.log.info("Triggering Modem Crash from kernel using adb command %s", cmd)
+ ad.adb.shell(cmd)
+ time.sleep(timeout)
return True
+def trigger_modem_crash_by_modem(ad, timeout=120):
+ begin_time = get_current_epoch_time()
+ ad.adb.shell(
+ "setprop persist.sys.modem.diag.mdlog false", ignore_status=True)
+ stop_qxdm_logger(ad)
+ cmd = ('am instrument -w -e request "4b 25 03 00" '
+ '"com.google.mdstest/com.google.mdstest.instrument.'
+ 'ModemCommandInstrumentation"')
+ ad.log.info("Crash modem by %s", cmd)
+ ad.adb.shell(cmd, ignore_status=True)
+ time.sleep(timeout) # sleep time for sl4a stability
+ reasons = ad.search_logcat("modem subsystem failure reason", begin_time)
+ if reasons:
+ ad.log.info("Modem crash is triggered successfully")
+ ad.log.info(reasons[-1]["log_message"])
+ return True
+ else:
+ ad.log.info("Modem crash is not triggered successfully")
+ return False
+
+
def _connection_state_change(_event, target_state, connection_type):
if connection_type:
if 'TypeName' not in _event['data']:
@@ -2148,7 +2447,7 @@
def wait_for_cell_data_connection(
- log, ad, state, timeout_value=EventDispatcher.DEFAULT_TIMEOUT):
+ log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
"""Wait for data connection status to be expected value for default
data subscription.
@@ -2162,7 +2461,7 @@
If True, it will wait for status to be DATA_STATE_CONNECTED.
If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
timeout_value: wait for cell data timeout value.
- This is optional, default value is EventDispatcher.DEFAULT_TIMEOUT
+ This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
Returns:
True if success.
@@ -2185,7 +2484,11 @@
def wait_for_cell_data_connection_for_subscription(
- log, ad, sub_id, state, timeout_value=EventDispatcher.DEFAULT_TIMEOUT):
+ log,
+ ad,
+ sub_id,
+ state,
+ timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
"""Wait for data connection status to be expected value for specified
subscrption id.
@@ -2200,7 +2503,7 @@
If True, it will wait for status to be DATA_STATE_CONNECTED.
If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
timeout_value: wait for cell data timeout value.
- This is optional, default value is EventDispatcher.DEFAULT_TIMEOUT
+ This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
Returns:
True if success.
@@ -2214,7 +2517,7 @@
data_state = ad.droid.telephonyGetDataConnectionState()
if not state and ad.droid.telephonyGetDataConnectionState() == state_str:
return True
- ad.ed.clear_all_events()
+ ad.ed.clear_events(EventDataConnectionStateChanged)
ad.droid.telephonyStartTrackingDataConnectionStateChangeForSubscription(
sub_id)
ad.droid.connectivityStartTrackingConnectivityStateChange()
@@ -2247,8 +2550,7 @@
# The bug is tracked here: b/22612607
# So we use _is_network_connected_state_match.
- if _wait_for_droid_in_state(log, ad,
- MAX_WAIT_TIME_CONNECTION_STATE_UPDATE,
+ if _wait_for_droid_in_state(log, ad, timeout_value,
_is_network_connected_state_match, state):
return _wait_for_nw_data_connection(
log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
@@ -2261,7 +2563,7 @@
def wait_for_wifi_data_connection(
- log, ad, state, timeout_value=EventDispatcher.DEFAULT_TIMEOUT):
+ log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
"""Wait for data connection status to be expected value and connection is by WiFi.
Args:
@@ -2271,7 +2573,7 @@
If True, it will wait for status to be DATA_STATE_CONNECTED.
If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
timeout_value: wait for network data timeout value.
- This is optional, default value is EventDispatcher.DEFAULT_TIMEOUT
+ This is optional, default value is MAX_WAIT_TIME_NW_SELECTION
Returns:
True if success.
@@ -2282,10 +2584,8 @@
log, ad, state, NETWORK_CONNECTION_TYPE_WIFI, timeout_value)
-def wait_for_data_connection(log,
- ad,
- state,
- timeout_value=EventDispatcher.DEFAULT_TIMEOUT):
+def wait_for_data_connection(
+ log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
"""Wait for data connection status to be expected value.
Wait for the data connection status to be DATA_STATE_CONNECTED
@@ -2298,7 +2598,7 @@
If True, it will wait for status to be DATA_STATE_CONNECTED.
If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
timeout_value: wait for network data timeout value.
- This is optional, default value is EventDispatcher.DEFAULT_TIMEOUT
+ This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
Returns:
True if success.
@@ -2312,7 +2612,7 @@
ad,
is_connected,
connection_type=None,
- timeout_value=EventDispatcher.DEFAULT_TIMEOUT):
+ timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
"""Wait for data connection status to be expected value.
Wait for the data connection status to be DATA_STATE_CONNECTED
@@ -2327,13 +2627,13 @@
connection_type: expected connection type.
This is optional, if it is None, then any connection type will return True.
timeout_value: wait for network data timeout value.
- This is optional, default value is EventDispatcher.DEFAULT_TIMEOUT
+ This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
Returns:
True if success.
False if failed.
"""
- ad.ed.clear_all_events()
+ ad.ed.clear_events(EventConnectivityChanged)
ad.droid.connectivityStartTrackingConnectivityStateChange()
try:
cur_data_connection_state = ad.droid.connectivityNetworkIsConnected()
@@ -2368,9 +2668,9 @@
# data connection state.
# Otherwise, the network state will not be correct.
# The bug is tracked here: b/20921915
- if _wait_for_droid_in_state(
- log, ad, MAX_WAIT_TIME_CONNECTION_STATE_UPDATE,
- _is_network_connected_state_match, is_connected):
+ if _wait_for_droid_in_state(log, ad, timeout_value,
+ _is_network_connected_state_match,
+ is_connected):
current_type = get_internet_connection_type(log, ad)
ad.log.info("current data connection type: %s", current_type)
if not connection_type:
@@ -2514,9 +2814,8 @@
Raises:
TelTestUtilsError if platform does not support VoLTE.
"""
- return toggle_volte_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad),
- new_state)
+ return toggle_volte_for_subscription(
+ log, ad, get_outgoing_voice_sub_id(ad), new_state)
def toggle_volte_for_subscription(log, ad, sub_id, new_state=None):
@@ -2651,7 +2950,11 @@
log: log object.
ad: android device.
"""
- return ad.droid.telecomIsInCall()
+ try:
+ return ad.droid.telecomIsInCall()
+ except:
+ return "mCallState=2" in ad.adb.shell(
+ "dumpsys telephony.registry | grep mCallState")
def is_phone_not_in_call(log, ad):
@@ -2686,6 +2989,40 @@
return _wait_for_droid_in_state(log, ad, max_time, is_phone_in_call)
+def is_phone_in_call_active(ad, call_id=None):
+ """Return True if phone in active call.
+
+ Args:
+ log: log object.
+ ad: android device.
+ call_id: the call id
+ """
+ if not call_id:
+ call_id = ad.droid.telecomCallGetCallIds()[0]
+ call_state = ad.droid.telecomCallGetCallState(call_id)
+ ad.log.info("%s state is %s", call_id, call_state)
+ return call_state == "ACTIVE"
+
+
+def wait_for_in_call_active(ad, timeout=5, interval=1, call_id=None):
+ """Wait for call reach active state.
+
+ Args:
+ log: log object.
+ ad: android device.
+ call_id: the call id
+ """
+ if not call_id:
+ call_id = ad.droid.telecomCallGetCallIds()[0]
+ args = [ad, call_id]
+ if not wait_for_state(is_phone_in_call_active, True, timeout, interval,
+ *args):
+ ad.log.error("Call did not reach ACTIVE state")
+ return False
+ else:
+ return True
+
+
def wait_for_telecom_ringing(log, ad, max_time=MAX_WAIT_TIME_TELECOM_RINGING):
"""Wait for android to be in telecom ringing state.
@@ -2850,17 +3187,18 @@
Return True if VoLTE feature bit is True and IMS registered.
Return False if VoLTE feature bit is False or IMS not registered.
"""
+ result = True
if not ad.droid.telephonyIsVolteAvailable():
ad.log.info("IsVolteCallingAvailble is False")
- return False
+ result = False
else:
ad.log.info("IsVolteCallingAvailble is True")
- if not is_ims_registered(log, ad):
- ad.log.info("VoLTE is Available, but IMS is not registered.")
- return False
- else:
- ad.log.info("IMS is registered")
- return True
+ if not is_ims_registered(log, ad):
+ ad.log.info("IMS is not registered.")
+ result = False
+ else:
+ ad.log.info("IMS is registered")
+ return result
def is_video_enabled(log, ad):
@@ -3087,9 +3425,8 @@
Return True if 'text' equals to event['data']['Text']
and phone number match.
"""
- return (
- check_phone_number_match(event['data']['Sender'], phonenumber_tx) and
- event['data']['Text'] == text)
+ return (check_phone_number_match(event['data']['Sender'], phonenumber_tx)
+ and event['data']['Text'] == text)
def is_sms_partial_match(event, phonenumber_tx, text):
@@ -3105,12 +3442,15 @@
Return True if 'text' starts with event['data']['Text']
and phone number match.
"""
- return (
- check_phone_number_match(event['data']['Sender'], phonenumber_tx) and
- text.startswith(event['data']['Text']))
+ return (check_phone_number_match(event['data']['Sender'], phonenumber_tx)
+ and text.startswith(event['data']['Text']))
-def sms_send_receive_verify(log, ad_tx, ad_rx, array_message):
+def sms_send_receive_verify(log,
+ ad_tx,
+ ad_rx,
+ array_message,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
"""Send SMS, receive SMS, and verify content and sender's number.
Send (several) SMS from droid_tx to droid_rx.
@@ -3126,14 +3466,16 @@
subid_tx = get_outgoing_message_sub_id(ad_tx)
subid_rx = get_incoming_message_sub_id(ad_rx)
return sms_send_receive_verify_for_subscription(
- log, ad_tx, ad_rx, subid_tx, subid_rx, array_message)
+ log, ad_tx, ad_rx, subid_tx, subid_rx, array_message, max_wait_time)
def wait_for_matching_sms(log,
ad_rx,
phonenumber_tx,
text,
- allow_multi_part_long_sms=True):
+ allow_multi_part_long_sms=True,
+ begin_time=None,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
"""Wait for matching incoming SMS.
Args:
@@ -3149,25 +3491,31 @@
"""
if not allow_multi_part_long_sms:
try:
- ad_rx.ed.wait_for_event(EventSmsReceived, is_sms_match,
- MAX_WAIT_TIME_SMS_RECEIVE, phonenumber_tx,
- text)
+ ad_rx.messaging_ed.wait_for_event(EventSmsReceived, is_sms_match,
+ max_wait_time, phonenumber_tx,
+ text)
return True
except Empty:
ad_rx.log.error("No matched SMS received event.")
+ if begin_time:
+ if sms_mms_receive_logcat_check(ad_rx, "sms", begin_time):
+ ad_rx.log.info("Receivd SMS message is seen in logcat")
return False
else:
try:
received_sms = ''
while (text != ''):
- event = ad_rx.ed.wait_for_event(
- EventSmsReceived, is_sms_partial_match,
- MAX_WAIT_TIME_SMS_RECEIVE, phonenumber_tx, text)
+ event = ad_rx.messaging_ed.wait_for_event(
+ EventSmsReceived, is_sms_partial_match, max_wait_time,
+ phonenumber_tx, text)
text = text[len(event['data']['Text']):]
received_sms += event['data']['Text']
return True
except Empty:
ad_rx.log.error("No matched SMS received event.")
+ if begin_time:
+ if sms_mms_receive_logcat_check(ad_rx, "sms", begin_time):
+ ad_rx.log.info("Receivd SMS message is seen in logcat")
if received_sms != '':
ad_rx.log.error("Only received partial matched SMS: %s",
received_sms)
@@ -3191,7 +3539,12 @@
return True
-def wait_for_matching_mms(log, ad_rx, phonenumber_tx, text):
+def wait_for_matching_mms(log,
+ ad_rx,
+ phonenumber_tx,
+ text,
+ begin_time=None,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
"""Wait for matching incoming SMS.
Args:
@@ -3207,17 +3560,25 @@
"""
try:
#TODO: add mms matching after mms message parser is added in sl4a. b/34276948
- ad_rx.ed.wait_for_event(EventMmsDownloaded, is_mms_match,
- MAX_WAIT_TIME_SMS_RECEIVE, phonenumber_tx,
- text)
+ ad_rx.messaging_ed.wait_for_event(EventMmsDownloaded, is_mms_match,
+ max_wait_time, phonenumber_tx, text)
return True
except Empty:
ad_rx.log.warning("No matched MMS downloaded event.")
+ if begin_time:
+ if sms_mms_receive_logcat_check(ad_rx, "mms", begin_time):
+ return True
return False
-def sms_send_receive_verify_for_subscription(log, ad_tx, ad_rx, subid_tx,
- subid_rx, array_message):
+def sms_send_receive_verify_for_subscription(
+ log,
+ ad_tx,
+ ad_rx,
+ subid_tx,
+ subid_rx,
+ array_message,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
"""Send SMS, receive SMS, and verify content and sender's number.
Send (several) SMS from droid_tx to droid_rx.
@@ -3232,43 +3593,70 @@
subid_rx: Receiver's subsciption ID to be used for SMS
array_message: the array of message to send/receive
"""
-
phonenumber_tx = ad_tx.cfg['subscription'][subid_tx]['phone_num']
phonenumber_rx = ad_rx.cfg['subscription'][subid_rx]['phone_num']
+
+ for ad in (ad_tx, ad_rx):
+ if not getattr(ad, "messaging_droid", None):
+ ad.messaging_droid, ad.messaging_ed = ad.get_droid()
+ ad.messaging_ed.start()
+ else:
+ try:
+ if not ad.messaging_droid.is_live:
+ ad.messaging_droid, ad.messaging_ed = ad.get_droid()
+ ad.messaging_ed.start()
+ except Exception as e:
+ ad.log.info(e)
+ ad.messaging_droid, ad.messaging_ed = ad.get_droid()
+ ad.messaging_ed.start()
+
for text in array_message:
+ # set begin_time 300ms before current time to system time discrepency
+ begin_time = get_current_epoch_time() - 300
length = len(text)
ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
phonenumber_tx, phonenumber_rx, length, text)
- result = False
- ad_rx.ed.clear_all_events()
- ad_rx.droid.smsStartTrackingIncomingSmsMessage()
- time.sleep(0.1) #sleep 100ms after starting event tracking
try:
- ad_tx.droid.smsSendTextMessage(phonenumber_rx, text, True)
-
+ ad_rx.messaging_ed.clear_events(EventSmsReceived)
+ ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
+ ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
+ time.sleep(0.1) #sleep 100ms after starting event tracking
+ ad_tx.messaging_droid.smsSendTextMessage(phonenumber_rx, text,
+ True)
try:
- ad_tx.ed.pop_event(EventSmsSentSuccess,
- MAX_WAIT_TIME_SMS_SENT_SUCCESS)
+ ad_tx.messaging_ed.pop_event(EventSmsSentSuccess,
+ max_wait_time)
except Empty:
ad_tx.log.error("No sent_success event for SMS of length %s.",
length)
- return False
+ # check log message as a work around for the missing sl4a
+ # event dispatcher event
+ if not sms_mms_send_logcat_check(ad_tx, "sms", begin_time):
+ return False
if not wait_for_matching_sms(
log,
ad_rx,
phonenumber_tx,
text,
- allow_multi_part_long_sms=True):
+ allow_multi_part_long_sms=True,
+ begin_time=begin_time):
ad_rx.log.error("No matching received SMS of length %s.",
length)
return False
+ except Exception as e:
+ log.error("Exception error %s", e)
+ raise
finally:
- ad_rx.droid.smsStopTrackingIncomingSmsMessage()
+ ad_rx.messaging_droid.smsStopTrackingIncomingSmsMessage()
return True
-def mms_send_receive_verify(log, ad_tx, ad_rx, array_message):
+def mms_send_receive_verify(log,
+ ad_tx,
+ ad_rx,
+ array_message,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
"""Send MMS, receive MMS, and verify content and sender's number.
Send (several) MMS from droid_tx to droid_rx.
@@ -3282,14 +3670,57 @@
array_message: the array of message to send/receive
"""
return mms_send_receive_verify_for_subscription(
- log, ad_tx, ad_rx,
- get_outgoing_message_sub_id(ad_tx),
- get_incoming_message_sub_id(ad_rx), array_message)
+ log, ad_tx, ad_rx, get_outgoing_message_sub_id(ad_tx),
+ get_incoming_message_sub_id(ad_rx), array_message, max_wait_time)
+
+
+def sms_mms_send_logcat_check(ad, type, begin_time):
+ type = type.upper()
+ log_results = ad.search_logcat(
+ "%s Message sent successfully" % type, begin_time=begin_time)
+ if log_results:
+ ad.log.info("Found SL4A %s sent succeessful log message" % type)
+ return True
+ else:
+ log_results = ad.search_logcat(
+ "ProcessSentMessageAction: Done sending %s message" % type,
+ begin_time=begin_time)
+ if log_results:
+ for log_result in log_results:
+ if "status is SUCCEEDED" in log_result["log_message"]:
+ ad.log.info(
+ "Found BugleDataModel %s send succeed log message" %
+ type)
+ return True
+ return False
+
+
+def sms_mms_receive_logcat_check(ad, type, begin_time):
+ type = type.upper()
+ log_results = ad.search_logcat(
+ "New %s Received" % type, begin_time=begin_time) or \
+ ad.search_logcat("New %s Downloaded" % type, begin_time=begin_time)
+ if log_results:
+ ad.log.info("Found SL4A %s received log message" % type)
+ return True
+ else:
+ log_results = ad.search_logcat(
+ "Received %s message" % type, begin_time=begin_time)
+ if log_results:
+ ad.log.info("Found %s received log message" % type)
+ return True
+ return False
#TODO: add mms matching after mms message parser is added in sl4a. b/34276948
-def mms_send_receive_verify_for_subscription(log, ad_tx, ad_rx, subid_tx,
- subid_rx, array_payload):
+def mms_send_receive_verify_for_subscription(
+ log,
+ ad_tx,
+ ad_rx,
+ subid_tx,
+ subid_rx,
+ array_payload,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
"""Send MMS, receive MMS, and verify content and sender's number.
Send (several) MMS from droid_tx to droid_rx.
@@ -3307,31 +3738,50 @@
phonenumber_tx = ad_tx.cfg['subscription'][subid_tx]['phone_num']
phonenumber_rx = ad_rx.cfg['subscription'][subid_rx]['phone_num']
+
+ for ad in (ad_rx, ad_tx):
+ if "Permissive" not in ad.adb.shell("su root getenforce"):
+ ad.adb.shell("su root setenforce 0")
+ if not getattr(ad, "messaging_droid", None):
+ ad.messaging_droid, ad.messaging_ed = ad.get_droid()
+ ad.messaging_ed.start()
+
for subject, message, filename in array_payload:
+ begin_time = get_current_epoch_time()
+ ad_tx.messaging_ed.clear_events(EventMmsSentSuccess)
+ ad_rx.messaging_ed.clear_events(EventMmsDownloaded)
+ ad_rx.messaging_droid.smsStartTrackingIncomingMmsMessage()
ad_tx.log.info(
"Sending MMS from %s to %s, subject: %s, message: %s, file: %s.",
phonenumber_tx, phonenumber_rx, subject, message, filename)
- result = False
- ad_rx.ed.clear_all_events()
- ad_rx.droid.smsStartTrackingIncomingMmsMessage()
try:
- ad_tx.droid.smsSendMultimediaMessage(
+ ad_tx.messaging_droid.smsSendMultimediaMessage(
phonenumber_rx, subject, message, phonenumber_tx, filename)
try:
- ad_tx.ed.pop_event(EventMmsSentSuccess,
- MAX_WAIT_TIME_SMS_SENT_SUCCESS)
+ ad_tx.messaging_ed.pop_event(EventMmsSentSuccess,
+ max_wait_time)
except Empty:
ad_tx.log.warning("No sent_success event.")
- return False
+ # check log message as a work around for the missing sl4a
+ # event dispatcher event
+ if not sms_mms_send_logcat_check(ad_tx, "mms", begin_time):
+ return False
- if not wait_for_matching_mms(log, ad_rx, phonenumber_tx, message):
+ if not wait_for_matching_mms(
+ log, ad_rx, phonenumber_tx, message,
+ begin_time=begin_time):
return False
+ except Exception as e:
+ log.error("Exception error %s", e)
+ raise
finally:
ad_rx.droid.smsStopTrackingIncomingMmsMessage()
return True
-def mms_receive_verify_after_call_hangup(log, ad_tx, ad_rx, array_message):
+def mms_receive_verify_after_call_hangup(
+ log, ad_tx, ad_rx, array_message,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
"""Verify the suspanded MMS during call will send out after call release.
Hangup call from droid_tx to droid_rx.
@@ -3345,14 +3795,19 @@
array_message: the array of message to send/receive
"""
return mms_receive_verify_after_call_hangup_for_subscription(
- log, ad_tx, ad_rx,
- get_outgoing_message_sub_id(ad_tx),
- get_incoming_message_sub_id(ad_rx), array_message)
+ log, ad_tx, ad_rx, get_outgoing_message_sub_id(ad_tx),
+ get_incoming_message_sub_id(ad_rx), array_message, max_wait_time)
#TODO: add mms matching after mms message parser is added in sl4a. b/34276948
def mms_receive_verify_after_call_hangup_for_subscription(
- log, ad_tx, ad_rx, subid_tx, subid_rx, array_payload):
+ log,
+ ad_tx,
+ ad_rx,
+ subid_tx,
+ subid_rx,
+ array_payload,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
"""Verify the suspanded MMS during call will send out after call release.
Hangup call from droid_tx to droid_rx.
@@ -3370,24 +3825,30 @@
phonenumber_tx = ad_tx.cfg['subscription'][subid_tx]['phone_num']
phonenumber_rx = ad_rx.cfg['subscription'][subid_rx]['phone_num']
+ for ad in (ad_tx, ad_rx):
+ if not getattr(ad, "messaging_droid", None):
+ ad.messaging_droid, ad.messaging_ed = ad.get_droid()
+ ad.messaging_ed.start()
for subject, message, filename in array_payload:
+ begin_time = get_current_epoch_time()
ad_rx.log.info(
"Waiting MMS from %s to %s, subject: %s, message: %s, file: %s.",
phonenumber_tx, phonenumber_rx, subject, message, filename)
- result = False
- ad_rx.ed.clear_all_events()
- ad_rx.droid.smsStartTrackingIncomingMmsMessage()
+ ad_rx.messaging_droid.smsStartTrackingIncomingMmsMessage()
time.sleep(5)
try:
hangup_call(log, ad_tx)
hangup_call(log, ad_rx)
try:
- ad_tx.ed.pop_event(EventMmsSentSuccess,
- MAX_WAIT_TIME_SMS_SENT_SUCCESS)
+ ad_tx.messaging_ed.pop_event(EventMmsSentSuccess,
+ max_wait_time)
except Empty:
log.warning("No sent_success event.")
-
- if not wait_for_matching_mms(log, ad_rx, phonenumber_tx, message):
+ if not sms_mms_send_logcat_check(ad_tx, "mms", begin_time):
+ return False
+ if not wait_for_matching_mms(
+ log, ad_rx, phonenumber_tx, message,
+ begin_time=begin_time):
return False
finally:
ad_rx.droid.smsStopTrackingIncomingMmsMessage()
@@ -3404,9 +3865,8 @@
"""Ensure ad's current network is in expected rat_family.
"""
return ensure_network_rat_for_subscription(
- log, ad,
- ad.droid.subscriptionGetDefaultSubId(), network_preference, rat_family,
- voice_or_data, max_wait_time, toggle_apm_after_setting)
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
+ rat_family, voice_or_data, max_wait_time, toggle_apm_after_setting)
def ensure_network_rat_for_subscription(
@@ -3464,8 +3924,7 @@
"""Ensure that current rat is within the device's preferred network rats.
"""
return ensure_network_preference_for_subscription(
- log, ad,
- ad.droid.subscriptionGetDefaultSubId(), network_preference,
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
voice_or_data, max_wait_time, toggle_apm_after_setting)
@@ -3525,9 +3984,8 @@
Wait for ad in expected network type.
"""
return ensure_network_generation_for_subscription(
- log, ad,
- ad.droid.subscriptionGetDefaultSubId(), generation, max_wait_time,
- voice_or_data, toggle_apm_after_setting)
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), generation,
+ max_wait_time, voice_or_data, toggle_apm_after_setting)
def ensure_network_generation_for_subscription(
@@ -3548,16 +4006,13 @@
"RAT network type voice: %s, data: %s",
ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id))
- if is_droid_in_network_generation_for_subscription(
- log, ad, sub_id, generation, voice_or_data):
- return True
try:
ad.log.info("Finding the network preference for generation %s for "
"operator %s phone type %s", generation,
ad.cfg["subscription"][sub_id]["operator"],
ad.cfg["subscription"][sub_id]["phone_type"])
- network_preference = network_preference_for_generaton(
+ network_preference = network_preference_for_generation(
generation, ad.cfg["subscription"][sub_id]["operator"],
ad.cfg["subscription"][sub_id]["phone_type"])
ad.log.info("Network preference for %s is %s", generation,
@@ -3574,14 +4029,29 @@
current_network_preference = \
ad.droid.telephonyGetPreferredNetworkTypesForSubscription(
sub_id)
-
- if (current_network_preference is not network_preference and
- not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
- network_preference, sub_id)):
- ad.log.error(
- "Network preference is %s. Set Preferred Networks to %s failed.",
- current_network_preference, network_preference)
- return False
+ for _ in range(3):
+ if current_network_preference == network_preference:
+ break
+ if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
+ network_preference, sub_id):
+ ad.log.info(
+ "Network preference is %s. Set Preferred Networks to %s failed.",
+ current_network_preference, network_preference)
+ reasons = ad.search_logcat(
+ "REQUEST_SET_PREFERRED_NETWORK_TYPE error")
+ if reasons:
+ reason_log = reasons[-1]["log_message"]
+ ad.log.info(reason_log)
+ if "DEVICE_IN_USE" in reason_log:
+ time.sleep(5)
+ else:
+ ad.log.error("Failed to set Preferred Networks to %s",
+ network_preference)
+ return False
+ else:
+ ad.log.error("Failed to set Preferred Networks to %s",
+ network_preference)
+ return False
if is_droid_in_network_generation_for_subscription(
log, ad, sub_id, generation, voice_or_data):
@@ -3607,7 +4077,8 @@
rat_generation_from_rat(
ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
sub_id)))
-
+ if not result:
+ ad.log.info("singal strength = %s", get_telephony_signal_strength(ad))
return result
@@ -3617,9 +4088,8 @@
max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
voice_or_data=None):
return wait_for_network_rat_for_subscription(
- log, ad,
- ad.droid.subscriptionGetDefaultSubId(), rat_family, max_wait_time,
- voice_or_data)
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
+ max_wait_time, voice_or_data)
def wait_for_network_rat_for_subscription(
@@ -3640,9 +4110,8 @@
max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
voice_or_data=None):
return wait_for_not_network_rat_for_subscription(
- log, ad,
- ad.droid.subscriptionGetDefaultSubId(), rat_family, max_wait_time,
- voice_or_data)
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
+ max_wait_time, voice_or_data)
def wait_for_not_network_rat_for_subscription(
@@ -3664,8 +4133,7 @@
max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
voice_or_data=None):
return wait_for_preferred_network_for_subscription(
- log, ad,
- ad.droid.subscriptionGetDefaultSubId(), network_preference,
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
max_wait_time, voice_or_data)
@@ -3689,9 +4157,8 @@
max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
voice_or_data=None):
return wait_for_network_generation_for_subscription(
- log, ad,
- ad.droid.subscriptionGetDefaultSubId(), generation, max_wait_time,
- voice_or_data)
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), generation,
+ max_wait_time, voice_or_data)
def wait_for_network_generation_for_subscription(
@@ -3709,8 +4176,8 @@
def is_droid_in_rat_family(log, ad, rat_family, voice_or_data=None):
return is_droid_in_rat_family_for_subscription(
- log, ad,
- ad.droid.subscriptionGetDefaultSubId(), rat_family, voice_or_data)
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
+ voice_or_data)
def is_droid_in_rat_family_for_subscription(log,
@@ -3724,8 +4191,8 @@
def is_droid_in_rat_familiy_list(log, ad, rat_family_list, voice_or_data=None):
return is_droid_in_rat_family_list_for_subscription(
- log, ad,
- ad.droid.subscriptionGetDefaultSubId(), rat_family_list, voice_or_data)
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family_list,
+ voice_or_data)
def is_droid_in_rat_family_list_for_subscription(log,
@@ -3796,8 +4263,8 @@
return True
else:
ad.log.info("%s network rat %s is %s, does not meet expected %s",
- service, nw_rat,
- rat_generation_from_rat(nw_rat), nw_gen)
+ service, nw_rat, rat_generation_from_rat(nw_rat),
+ nw_gen)
return False
return False
@@ -3928,7 +4395,7 @@
while duration < MAX_WAIT_TIME_NW_SELECTION:
subInfo = ad.droid.subscriptionGetAllSubInfoList()
if subInfo and len(subInfo) >= 1:
- ad.log.info("Find valid subcription %s", subInfo)
+ ad.log.debug("Find valid subcription %s", subInfo)
break
else:
ad.log.info("Did not find a valid subscription")
@@ -3973,6 +4440,7 @@
data_roaming = getattr(ad, 'roaming', False)
if get_cell_data_roaming_state_by_adb(ad) != data_roaming:
set_cell_data_roaming_state_by_adb(ad, data_roaming)
+ remove_mobile_data_usage_limit(ad)
if not wait_for_not_network_rat(
log, ad, RAT_FAMILY_WLAN, voice_or_data=NETWORK_SERVICE_DATA):
ad.log.error("%s still in %s", NETWORK_SERVICE_DATA,
@@ -4028,10 +4496,12 @@
wifi_info = ad.droid.wifiGetConnectionInfo()
if wifi_info["supplicant_state"] == "completed" and wifi_info["SSID"] == wifi_ssid:
ad.log.info("Wifi is connected to %s", wifi_ssid)
+ ad.on_mobile_data = False
return True
else:
ad.log.info("Wifi is not connected to %s", wifi_ssid)
ad.log.debug("Wifi connection_info=%s", wifi_info)
+ ad.on_mobile_data = True
return False
@@ -4085,6 +4555,7 @@
boolean success (True) or failure (False)
"""
if not ad.droid.wifiGetConfiguredNetworks():
+ ad.on_mobile_data = True
return True
try:
old_state = ad.droid.wifiCheckState()
@@ -4093,6 +4564,7 @@
except Exception as e:
log.error("forget_all_wifi_networks with exception: %s", e)
return False
+ ad.on_mobile_data = True
return True
@@ -4127,6 +4599,7 @@
"""
ad.droid.wifiFactoryReset()
ad.droid.wifiToggleState(False)
+ ad.on_mobile_data = True
def wifi_toggle_state(log, ad, state, retries=3):
@@ -4142,6 +4615,7 @@
"""
for i in range(retries):
if wifi_test_utils.wifi_toggle_state(ad, state, assert_on_fail=False):
+ ad.on_mobile_data = not state
return True
time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
return False
@@ -4199,7 +4673,7 @@
try:
if current_preference not in get_allowable_network_preference(
sub_info["operator"], sub_info["phone_type"]):
- network_preference = network_preference_for_generaton(
+ network_preference = network_preference_for_generation(
GEN_4G, sub_info["operator"], sub_info["phone_type"])
ad.droid.telephonySetPreferredNetworkTypesForSubscription(
network_preference, sub_id)
@@ -4222,6 +4696,25 @@
return func(*params)
+def run_multithread_func_async(log, task):
+ """Starts a multi-threaded function asynchronously.
+
+ Args:
+ log: log object.
+ task: a task to be executed in parallel.
+
+ Returns:
+ Future object representing the execution of the task.
+ """
+ executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
+ try:
+ future_object = executor.submit(task_wrapper, task)
+ except Exception as e:
+ log.error("Exception error %s", e)
+ raise
+ return future_object
+
+
def run_multithread_func(log, tasks):
"""Run multi-thread functions and return results.
@@ -4232,18 +4725,20 @@
Returns:
results for tasks.
"""
- MAX_NUMBER_OF_WORKERS = 5
+ MAX_NUMBER_OF_WORKERS = 10
number_of_workers = min(MAX_NUMBER_OF_WORKERS, len(tasks))
executor = concurrent.futures.ThreadPoolExecutor(
max_workers=number_of_workers)
+ if not log: log = logging
try:
results = list(executor.map(task_wrapper, tasks))
except Exception as e:
log.error("Exception error %s", e)
raise
executor.shutdown()
- log.info("multithread_func %s result: %s",
- [task[0].__name__ for task in tasks], results)
+ if log:
+ log.info("multithread_func %s result: %s",
+ [task[0].__name__ for task in tasks], results)
return results
@@ -4322,17 +4817,6 @@
out = ad.adb.shell("settings list system | grep volume")
for attr in re.findall(r"(volume_.*)=\d+", out):
ad.adb.shell("settings put system %s 0" % attr)
- try:
- if not ad.droid.telecomIsInCall():
- ad.droid.telecomCallNumber(STORY_LINE)
- for _ in range(10):
- ad.send_keycode("VOLUME_DOWN")
- time.sleep(1)
- ad.droid.telecomEndCall()
- time.sleep(1)
- except Exception as e:
- ad.log.info("fail to turn down voice call volume %s", e)
-
return silent_mode == ad.droid.checkRingerSilentMode()
@@ -4607,32 +5091,166 @@
return None
-def set_qxdm_logger_always_on(ad, mask_file="Radio-general.cfg"):
+def find_qxdm_log_mask(ad, mask="default.cfg"):
+ """Find QXDM logger mask."""
+ if "/" not in mask:
+ # Call nexuslogger to generate log mask
+ start_nexuslogger(ad)
+ # Find the log mask path
+ for path in (DEFAULT_QXDM_LOG_PATH, "/data/diag_logs",
+ "/vendor/etc/mdlog/"):
+ out = ad.adb.shell(
+ "find %s -type f -iname %s" % (path, mask), ignore_status=True)
+ if out and "No such" not in out and "Permission denied" not in out:
+ if path.startswith("/vendor/"):
+ ad.qxdm_log_path = DEFAULT_QXDM_LOG_PATH
+ else:
+ ad.qxdm_log_path = path
+ return out.split("\n")[0]
+ if mask in ad.adb.shell("ls /vendor/etc/mdlog/"):
+ ad.qxdm_log_path = DEFAULT_QXDM_LOG_PATH
+ return "%s/%s" % ("/vendor/etc/mdlog/", mask)
+ else:
+ out = ad.adb.shell("ls %s" % mask, ignore_status=True)
+ if out and "No such" not in out:
+ ad.qxdm_log_path = "/data/vendor/radio/diag_logs"
+ return mask
+ ad.log.warning("Could NOT find QXDM logger mask path for %s", mask)
+
+
+def set_qxdm_logger_command(ad, mask=None):
"""Set QXDM logger always on.
Args:
ad: android device object.
"""
- ad.adb.shell("setprop persist.sys.modem.diag.mdlog true")
- ad.adb.shell("setprop persist.radio.smlog_switch false")
- ad.adb.shell('echo "diag_mdlog -f /data/vendor/radio/diag_logs/cfg/%s'
- ' -o /data/vendor/radio/diag_logs/logs -s 500 -n 10 -b -c > '
- '/data/vendor/radio/diag_logs/diag.conf"' % mask_file)
- ad.reboot()
+ ## Neet to check if log mask will be generated without starting nexus logger
+ masks = []
+ mask_path = None
+ if mask:
+ masks = [mask]
+ masks.extend(["QC_Default.cfg", "default.cfg"])
+ for mask in masks:
+ mask_path = find_qxdm_log_mask(ad, mask)
+ if mask_path: break
+ if not mask_path:
+ ad.log.error("Cannot find QXDM mask %s", mask)
+ ad.qxdm_logger_command = None
+ return False
+ else:
+ ad.log.info("Use QXDM log mask %s", mask_path)
+ ad.log.debug("qxdm_log_path = %s", ad.qxdm_log_path)
+ output_path = os.path.join(ad.qxdm_log_path, "logs")
+ ad.qxdm_logger_command = ("diag_mdlog -f %s -o %s -s 50 -c" %
+ (mask_path, output_path))
+ conf_path = os.path.join(ad.qxdm_log_path, "diag.conf")
+ # Enable qxdm always on so that after device reboot, qxdm will be
+ # turned on automatically
+ ad.adb.shell('echo "%s" > %s' % (ad.qxdm_logger_command, conf_path))
+ ad.adb.shell(
+ "setprop persist.sys.modem.diag.mdlog true", ignore_status=True)
+ return True
-def check_qxdm_logger_always_on(ad, mask_file="Radio-general.cfg"):
+def stop_qxdm_logger(ad):
+ """Stop QXDM logger."""
+ for cmd in ("diag_mdlog -k", "killall diag_mdlog"):
+ output = ad.adb.shell("ps -ef | grep mdlog") or ""
+ if "diag_mdlog" not in output:
+ break
+ ad.log.debug("Kill the existing qxdm process")
+ ad.adb.shell(cmd, ignore_status=True)
+ time.sleep(5)
+
+
+def start_qxdm_logger(ad, begin_time=None):
+ """Start QXDM logger."""
+ if not getattr(ad, "qxdm_log", True): return
+ # Delete existing QXDM logs 5 minutes earlier than the begin_time
+ if getattr(ad, "qxdm_log_path", None):
+ seconds = None
+ if begin_time:
+ current_time = get_current_epoch_time()
+ seconds = int((current_time - begin_time) / 1000.0) + 10 * 60
+ elif len(ad.get_file_names(ad.qxdm_log_path)) > 50:
+ seconds = 900
+ if seconds:
+ ad.adb.shell(
+ "find %s -type f -iname *.qmdl -not -mtime -%ss -delete" %
+ (ad.qxdm_log_path, seconds))
+ if getattr(ad, "qxdm_logger_command", None):
+ output = ad.adb.shell("ps -ef | grep mdlog") or ""
+ if ad.qxdm_logger_command not in output:
+ ad.log.debug("QXDM logging command %s is not running",
+ ad.qxdm_logger_command)
+ if "diag_mdlog" in output:
+ # Kill the existing diag_mdlog process
+ # Only one diag_mdlog process can be run
+ stop_qxdm_logger(ad)
+ ad.log.info("Start QXDM logger")
+ ad.adb.shell_nb(ad.qxdm_logger_command)
+ elif not ad.get_file_names(ad.qxdm_log_path, 60):
+ ad.log.debug("Existing diag_mdlog is not generating logs")
+ stop_qxdm_logger(ad)
+ ad.adb.shell_nb(ad.qxdm_logger_command)
+ return True
+
+
+def start_qxdm_loggers(log, ads, begin_time=None):
+ tasks = [(start_qxdm_logger, [ad, begin_time]) for ad in ads
+ if getattr(ad, "qxdm_log", True)]
+ if tasks: run_multithread_func(log, tasks)
+
+
+def stop_qxdm_loggers(log, ads):
+ tasks = [(stop_qxdm_logger, [ad]) for ad in ads]
+ run_multithread_func(log, tasks)
+
+
+def start_nexuslogger(ad):
+ """Start Nexus/Pixel Logger Apk."""
+ qxdm_logger_apk = None
+ for apk, activity in (("com.android.nexuslogger", ".MainActivity"),
+ ("com.android.pixellogger",
+ ".ui.main.MainActivity")):
+ if ad.is_apk_installed(apk):
+ qxdm_logger_apk = apk
+ break
+ if not qxdm_logger_apk: return
+ if ad.is_apk_running(qxdm_logger_apk):
+ if "granted=true" in ad.adb.shell(
+ "dumpsys package %s | grep WRITE_EXTERN" % qxdm_logger_apk):
+ return True
+ else:
+ ad.log.info("Kill %s" % qxdm_logger_apk)
+ ad.force_stop_apk(qxdm_logger_apk)
+ time.sleep(5)
+ for perm in ("READ", "WRITE"):
+ ad.adb.shell("pm grant %s android.permission.%s_EXTERNAL_STORAGE" %
+ (qxdm_logger_apk, perm))
+ time.sleep(2)
+ for i in range(3):
+ ad.log.info("Start %s Attempt %d" % (qxdm_logger_apk, i + 1))
+ ad.adb.shell("am start -n %s/%s" % (qxdm_logger_apk, activity))
+ time.sleep(5)
+ if ad.is_apk_running(qxdm_logger_apk):
+ ad.send_keycode("HOME")
+ return True
+ return False
+
+
+def check_qxdm_logger_mask(ad, mask_file="QC_Default.cfg"):
"""Check if QXDM logger always on is set.
Args:
ad: android device object.
"""
- if ad.adb.shell("getprop persist.sys.modem.diag.mdlog") != 'true':
- return False
- if ad.adb.shell("getprop persist.radio.smlog_switch") != 'false':
- return False
+ output = ad.adb.shell(
+ "ls /data/vendor/radio/diag_logs/", ignore_status=True)
+ if not output or "No such" in output:
+ return True
if mask_file not in ad.adb.shell(
"cat /data/vendor/radio/diag_logs/diag.conf", ignore_status=True):
return False
@@ -4648,7 +5266,16 @@
"""
ad.log.debug("Ensuring no tcpdump is running in background")
- ad.adb.shell("killall -9 tcpdump")
+ try:
+ ad.adb.shell("killall -9 tcpdump")
+ except AdbError:
+ ad.log.warn("Killing existing tcpdump processes failed")
+ out = ad.adb.shell("ls -l /sdcard/tcpdump/")
+ if "No such file" in out or not out:
+ ad.adb.shell("mkdir /sdcard/tcpdump")
+ else:
+ ad.adb.shell("rm -rf /sdcard/tcpdump/*", ignore_status=True)
+
begin_time = epoch_to_log_line_timestamp(get_current_epoch_time())
begin_time = normalize_log_line_timestamp(begin_time)
@@ -4663,11 +5290,10 @@
cmd = "adb -s {} shell tcpdump -i any -s0 -n -p udp port 500 or \
udp port 4500 -w {}".format(ad.serial, file_name)
ad.log.debug("%s" % cmd)
- tcpdump_pid = start_standing_subprocess(cmd, 5)
- return (tcpdump_pid, file_name)
+ return start_standing_subprocess(cmd, 5)
-def stop_adb_tcpdump(ad, tcpdump_pid, tcpdump_file, pull_tcpdump=False):
+def stop_adb_tcpdump(ad, proc=None, pull_tcpdump=False, test_name=""):
"""Stops tcpdump on any iface
Pulls the tcpdump file in the tcpdump dir
@@ -4677,13 +5303,18 @@
tcpdump_file: filename needed to pull out
"""
- ad.log.debug("Stopping and pulling tcpdump if failed")
- stop_standing_subprocess(tcpdump_pid)
+ ad.log.info("Stopping and pulling tcpdump if any")
+ try:
+ if proc is not None:
+ stop_standing_subprocess(proc)
+ except Exception as e:
+ ad.log.warning(e)
if pull_tcpdump:
- tcpdump_path = os.path.join(ad.log_path, "tcpdump")
- create_dir(tcpdump_path)
- ad.adb.pull("{} {}".format(tcpdump_file, tcpdump_path))
- ad.adb.shell("rm -rf {}".format(tcpdump_file))
+ log_path = os.path.join(ad.log_path, test_name,
+ "TCPDUMP_%s" % ad.serial)
+ utils.create_dir(log_path)
+ ad.adb.pull("/sdcard/tcpdump/. %s" % log_path)
+ ad.adb.shell("rm -rf /sdcard/tcpdump/*", ignore_status=True)
return True
@@ -4697,7 +5328,7 @@
"""
status = True
# Pull sl4a apk from device
- out = ad.adb.shell("pm path com.googlecode.android_scripting")
+ out = ad.adb.shell("pm path %s" % SL4A_APK_NAME)
result = re.search(r"package:(.*)", out)
if not result:
ad.log.error("Couldn't find sl4a apk")
@@ -4714,6 +5345,7 @@
except Exception as e:
ad.log.error(e)
status = False
+ time.sleep(30) #sleep time after fastboot wipe
for _ in range(2):
try:
ad.log.info("Reboot in fastboot")
@@ -4723,8 +5355,6 @@
except Exception as e:
ad.log.error("Exception error %s", e)
ad.root_adb()
- if not ad.ensure_screen_on():
- ad.log.error("User window cannot come up")
if result:
# Try to reinstall for three times as the device might not be
# ready to apk install shortly after boot complete.
@@ -4732,12 +5362,41 @@
if ad.is_sl4a_installed():
break
ad.log.info("Re-install sl4a")
- ad.adb.install("-r /tmp/base.apk")
+ ad.adb.install("-r /tmp/base.apk", ignore_status=True)
time.sleep(10)
- ad.start_services(ad.skip_sl4a, skip_setup_wizard=skip_setup_wizard)
+ try:
+ ad.start_adb_logcat()
+ except:
+ ad.log.exception("Failed to start adb logcat!")
+ if skip_setup_wizard:
+ ad.exit_setup_wizard()
+ if ad.skip_sl4a: return status
+ bring_up_sl4a(ad)
+
return status
+def bring_up_sl4a(ad, attemps=3):
+ for i in range(attemps):
+ try:
+ droid, ed = ad.get_droid()
+ ed.start()
+ ad.log.info("Broght up new sl4a session")
+ except Exception as e:
+ if i < attemps - 1:
+ ad.log.info(e)
+ time.sleep(10)
+ else:
+ ad.log.error(e)
+ raise
+
+
+def reboot_device(ad):
+ ad.reboot()
+ ad.ensure_screen_on()
+ unlock_sim(ad)
+
+
def unlocking_device(ad, device_password=None):
"""First unlock device attempt, required after reboot"""
ad.unlock_screen(device_password)
@@ -4763,8 +5422,7 @@
ad.terminate_all_sessions()
ad.ensure_screen_on()
ad.log.info("Open new sl4a connection")
- droid, ed = ad.get_droid()
- ed.start()
+ bring_up_sl4a(ad)
def reset_device_password(ad, device_password=None):
@@ -4772,8 +5430,17 @@
unlock_sim(ad)
screen_lock = ad.is_screen_lock_enabled()
if device_password:
- refresh_sl4a_session(ad)
- ad.droid.setDevicePassword(device_password)
+ try:
+ refresh_sl4a_session(ad)
+ ad.droid.setDevicePassword(device_password)
+ except Exception as e:
+ ad.log.warning("setDevicePassword failed with %s", e)
+ try:
+ ad.droid.setDevicePassword(device_password, "1111")
+ except Exception as e:
+ ad.log.warning(
+ "setDevicePassword providing previous password error: %s",
+ e)
time.sleep(2)
if screen_lock:
# existing password changed
@@ -4791,8 +5458,14 @@
# need to disable the password and log in on the first time
# with unlocking with a swipe
ad.log.info("Disable device password")
+ ad.unlock_screen(password="1111")
refresh_sl4a_session(ad)
- ad.droid.disableDevicePassword()
+ ad.ensure_screen_on()
+ try:
+ ad.droid.disableDevicePassword()
+ except Exception as e:
+ ad.log.warning("disableDevicePassword failed with %s", e)
+ fastboot_wipe(ad)
time.sleep(2)
ad.adb.wait_for_device(timeout=180)
refresh_sl4a_session(ad)
@@ -4800,11 +5473,16 @@
ad.start_adb_logcat()
-def is_sim_locked(ad):
+def get_sim_state(ad):
try:
- return ad.droid.telephonyGetSimState() == SIM_STATE_PIN_REQUIRED
+ state = ad.droid.telephonyGetSimState()
except:
- return ad.adb.getprop("gsm.sim.state") == SIM_STATE_PIN_REQUIRED
+ state = ad.adb.getprop("gsm.sim.state")
+ return state
+
+
+def is_sim_locked(ad):
+ return get_sim_state(ad) == SIM_STATE_PIN_REQUIRED
def unlock_sim(ad):
@@ -4815,14 +5493,16 @@
# "puk_pin": "1234"}]
if not is_sim_locked(ad):
return True
+ else:
+ ad.is_sim_locked = True
puk_pin = getattr(ad, "puk_pin", "1111")
try:
if not hasattr(ad, 'puk'):
ad.log.info("Enter SIM pin code")
- result = ad.droid.telephonySupplyPin(puk_pin)
+ ad.droid.telephonySupplyPin(puk_pin)
else:
ad.log.info("Enter PUK code and pin")
- result = ad.droid.telephonySupplyPuk(ad.puk, puk_pin)
+ ad.droid.telephonySupplyPuk(ad.puk, puk_pin)
except:
# if sl4a is not available, use adb command
ad.unlock_screen(puk_pin)
@@ -4896,7 +5576,6 @@
ad.fastboot.flash("radio %s" % file_path, timeout=300)
except Exception as e:
ad.log.error(e)
- status = False
for _ in range(2):
try:
ad.log.info("Reboot in fastboot")
@@ -4909,10 +5588,143 @@
if not ad.ensure_screen_on():
ad.log.error("User window cannot come up")
ad.start_services(ad.skip_sl4a, skip_setup_wizard=skip_setup_wizard)
+ unlock_sim(ad)
+
+
+def set_preferred_apn_by_adb(ad, pref_apn_name):
+ """Select Pref APN
+ Set Preferred APN on UI using content query/insert
+ It needs apn name as arg, and it will match with plmn id
+ """
+ try:
+ plmn_id = get_plmn_by_adb(ad)
+ out = ad.adb.shell("content query --uri content://telephony/carriers "
+ "--where \"apn='%s' and numeric='%s'\"" %
+ (pref_apn_name, plmn_id))
+ if "No result found" in out:
+ ad.log.warning("Cannot find APN %s on device", pref_apn_name)
+ return False
+ else:
+ apn_id = re.search(r'_id=(\d+)', out).group(1)
+ ad.log.info("APN ID is %s", apn_id)
+ ad.adb.shell("content insert --uri content:"
+ "//telephony/carriers/preferapn --bind apn_id:i:%s" %
+ (apn_id))
+ out = ad.adb.shell("content query --uri "
+ "content://telephony/carriers/preferapn")
+ if "No result found" in out:
+ ad.log.error("Failed to set prefer APN %s", pref_apn_name)
+ return False
+ elif apn_id == re.search(r'_id=(\d+)', out).group(1):
+ ad.log.info("Preferred APN set to %s", pref_apn_name)
+ return True
+ except Exception as e:
+ ad.log.error("Exception while setting pref apn %s", e)
+ return True
+
+
+def check_apm_mode_on_by_serial(ad, serial_id):
+ try:
+ apm_check_cmd = "|".join(("adb -s %s shell dumpsys wifi" % serial_id,
+ "grep -i airplanemodeon", "cut -f2 -d ' '"))
+ output = exe_cmd(apm_check_cmd)
+ if output.decode("utf-8").split("\n")[0] == "true":
+ return True
+ else:
+ return False
+ except Exception as e:
+ ad.log.warning("Exception during check apm mode on %s", e)
+ return True
+
+
+def set_apm_mode_on_by_serial(ad, serial_id):
+ try:
+ cmd1 = "adb -s %s shell settings put global airplane_mode_on 1" % serial_id
+ cmd2 = "adb -s %s shell am broadcast -a android.intent.action.AIRPLANE_MODE" % serial_id
+ exe_cmd(cmd1)
+ exe_cmd(cmd2)
+ except Exception as e:
+ ad.log.warning("Exception during set apm mode on %s", e)
+ return True
def print_radio_info(ad, extra_msg=""):
for prop in ("gsm.version.baseband", "persist.radio.ver_info",
- "persist.radio.cnv.ver_info", "persist.radio.ci_status"):
+ "persist.radio.cnv.ver_info"):
output = ad.adb.getprop(prop)
- if output: ad.log.info("%s%s = %s", extra_msg, prop, output)
+ ad.log.info("%s%s = %s", extra_msg, prop, output)
+
+
+def wait_for_state(state_check_func,
+ state,
+ max_wait_time=MAX_WAIT_TIME_FOR_STATE_CHANGE,
+ checking_interval=WAIT_TIME_BETWEEN_STATE_CHECK,
+ *args,
+ **kwargs):
+ while max_wait_time >= 0:
+ if state_check_func(*args, **kwargs) == state:
+ return True
+ time.sleep(checking_interval)
+ max_wait_time -= checking_interval
+ return False
+
+
+def power_off_sim(ad, sim_slot_id=None):
+ try:
+ if sim_slot_id is None:
+ ad.droid.telephonySetSimPowerState(CARD_POWER_DOWN)
+ verify_func = ad.droid.telephonyGetSimState
+ verify_args = []
+ else:
+ ad.droid.telephonySetSimStateForSlotId(sim_slot_id,
+ CARD_POWER_DOWN)
+ verify_func = ad.droid.telephonyGetSimStateForSlotId
+ verify_args = [sim_slot_id]
+ except Exception as e:
+ ad.log.error(e)
+ return False
+ if wait_for_state(verify_func, SIM_STATE_UNKNOWN,
+ MAX_WAIT_TIME_FOR_STATE_CHANGE,
+ WAIT_TIME_BETWEEN_STATE_CHECK, *verify_args):
+ ad.log.info("SIM slot is powered off, SIM state is UNKNOWN")
+ return True
+ else:
+ ad.log.info("SIM state = %s", verify_func(*verify_args))
+ ad.log.warning("Fail to power off SIM slot")
+ return False
+
+
+def power_on_sim(ad, sim_slot_id=None):
+ try:
+ if sim_slot_id is None:
+ ad.droid.telephonySetSimPowerState(CARD_POWER_UP)
+ verify_func = ad.droid.telephonyGetSimState
+ verify_args = []
+ else:
+ ad.droid.telephonySetSimStateForSlotId(sim_slot_id, CARD_POWER_UP)
+ verify_func = ad.droid.telephonyGetSimStateForSlotId
+ verify_args = [sim_slot_id]
+ except Exception as e:
+ ad.log.error(e)
+ return False
+ if wait_for_state(verify_func, SIM_STATE_READY,
+ MAX_WAIT_TIME_FOR_STATE_CHANGE,
+ WAIT_TIME_BETWEEN_STATE_CHECK, *verify_args):
+ ad.log.info("SIM slot is powered on, SIM state is READY")
+ return True
+ elif verify_func(*verify_args) == SIM_STATE_PIN_REQUIRED:
+ ad.log.info("SIM is pin locked")
+ return True
+ else:
+ ad.log.error("Fail to power on SIM slot")
+ return False
+
+
+def log_screen_shot(ad, test_name):
+ file_name = "/sdcard/Pictures/screencap_%s.png" % (
+ utils.get_current_epoch_time())
+ screen_shot_path = os.path.join(ad.log_path, test_name,
+ "Screenshot_%s" % ad.serial)
+ utils.create_dir(screen_shot_path)
+ ad.adb.shell("screencap -p %s" % file_name)
+ ad.adb.pull("%s %s" % (file_name, screen_shot_path))
diff --git a/acts/framework/acts/test_utils/tel/tel_video_utils.py b/acts/framework/acts/test_utils/tel/tel_video_utils.py
index 48ab6ee..c96f490 100644
--- a/acts/framework/acts/test_utils/tel/tel_video_utils.py
+++ b/acts/framework/acts/test_utils/tel/tel_video_utils.py
@@ -30,6 +30,10 @@
from acts.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
from acts.test_utils.tel.tel_defines import GEN_4G
+from acts.test_utils.tel.tel_defines import RAT_1XRTT
+from acts.test_utils.tel.tel_defines import RAT_IWLAN
+from acts.test_utils.tel.tel_defines import RAT_LTE
+from acts.test_utils.tel.tel_defines import RAT_UMTS
from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_OFFHOOK
from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_RINGING
from acts.test_utils.tel.tel_defines import VT_STATE_AUDIO_ONLY
@@ -66,6 +70,8 @@
from acts.test_utils.tel.tel_test_utils import wait_for_ringing_call
from acts.test_utils.tel.tel_test_utils import wait_for_telecom_ringing
from acts.test_utils.tel.tel_test_utils import wait_for_video_enabled
+from acts.test_utils.tel.tel_test_utils import get_network_rat
+from acts.test_utils.tel.tel_test_utils import is_wfc_enabled
from acts.test_utils.tel.tel_voice_utils import is_call_hd
@@ -107,8 +113,8 @@
toggle_airplane_mode(log, ad, False)
if not set_wfc_mode(log, ad, wfc_mode):
- log.error(
- "{} WFC mode failed to be set to {}.".format(ad.serial, wfc_mode))
+ log.error("{} WFC mode failed to be set to {}.".format(
+ ad.serial, wfc_mode))
return False
toggle_volte(log, ad, True)
@@ -151,8 +157,9 @@
return False
if not wait_for_video_enabled(log, ad, MAX_WAIT_TIME_VOLTE_ENABLED):
- log.error("{} failed to <report video calling enabled> within {}s.".
- format(ad.serial, MAX_WAIT_TIME_VOLTE_ENABLED))
+ log.error(
+ "{} failed to <report video calling enabled> within {}s.".format(
+ ad.serial, MAX_WAIT_TIME_VOLTE_ENABLED))
return False
return True
@@ -191,8 +198,8 @@
"""
if video_state is None:
- log.info(
- "Verify if {}(subid {}) in video call.".format(ad.serial, sub_id))
+ log.info("Verify if {}(subid {}) in video call.".format(
+ ad.serial, sub_id))
if not ad.droid.telecomIsInCall():
log.error("{} not in call.".format(ad.serial))
return False
@@ -219,6 +226,58 @@
return False
+def is_phone_in_call_viwifi_for_subscription(log, ad, sub_id,
+ video_state=None):
+ """Return if ad (for sub_id) is in a viwifi call (in expected video state).
+ Args:
+ log: log object.
+ ad: android device object
+ sub_id: device sub_id
+ video_state: Expected Video call state.
+ This is optional, if it's None,
+ then TX_ENABLED/RX_ENABLED/BIDIRECTIONAL video call state will
+ return True.
+
+ Returns:
+ True if ad is in a video call (in expected video state).
+ """
+
+ if video_state is None:
+ log.info("Verify if {}(subid {}) in video call.".format(
+ ad.serial, sub_id))
+ if not ad.droid.telecomIsInCall():
+ log.error("{} not in call.".format(ad.serial))
+ return False
+ nw_type = get_network_rat(log, ad, NETWORK_SERVICE_DATA)
+ if nw_type != RAT_IWLAN:
+ ad.log.error("Data rat on: %s. Expected: iwlan", nw_type)
+ return False
+ if not is_wfc_enabled(log, ad):
+ ad.log.error("WiFi Calling feature bit is False.")
+ return False
+ call_list = ad.droid.telecomCallGetCallIds()
+ for call in call_list:
+ state = ad.droid.telecomCallVideoGetState(call)
+ if video_state is None:
+ if {
+ VT_STATE_AUDIO_ONLY: False,
+ VT_STATE_TX_ENABLED: True,
+ VT_STATE_TX_PAUSED: True,
+ VT_STATE_RX_ENABLED: True,
+ VT_STATE_RX_PAUSED: True,
+ VT_STATE_BIDIRECTIONAL: True,
+ VT_STATE_BIDIRECTIONAL_PAUSED: True,
+ VT_STATE_STATE_INVALID: False
+ }[state]:
+ return True
+ else:
+ if state == video_state:
+ return True
+ ad.log.info("Non-Video-State: %s", state)
+ ad.log.error("Phone not in video call. Call list: %s", call_list)
+ return False
+
+
def is_phone_in_call_video_bidirectional(log, ad):
"""Return if phone in bi-directional video call.
@@ -250,6 +309,36 @@
VT_STATE_BIDIRECTIONAL)
+def is_phone_in_call_viwifi_bidirectional(log, ad):
+ """Return if phone in bi-directional viwifi call.
+
+ Args:
+ log: log object.
+ ad: android device object
+
+ Returns:
+ True if phone in bi-directional viwifi call.
+ """
+ return is_phone_in_call_viwifi_bidirectional_for_subscription(
+ log, ad, get_outgoing_voice_sub_id(ad))
+
+
+def is_phone_in_call_viwifi_bidirectional_for_subscription(log, ad, sub_id):
+ """Return if phone in bi-directional viwifi call for subscription id.
+
+ Args:
+ log: log object.
+ ad: android device object
+ sub_id: subscription id.
+
+ Returns:
+ True if phone in bi-directional viwifi call.
+ """
+ ad.log.info("Verify if subid %s in bi-directional video call.", sub_id)
+ return is_phone_in_call_viwifi_for_subscription(log, ad, sub_id,
+ VT_STATE_BIDIRECTIONAL)
+
+
def is_phone_in_call_video_tx_enabled(log, ad):
"""Return if phone in tx_enabled video call.
@@ -337,8 +426,8 @@
Returns:
True if phone in hd voice call.
"""
- log.info(
- "Verify if {}(subid {}) in hd voice call.".format(ad.serial, sub_id))
+ log.info("Verify if {}(subid {}) in hd voice call.".format(
+ ad.serial, sub_id))
if not ad.droid.telecomIsInCall():
log.error("{} not in call.".format(ad.serial))
return False
@@ -398,8 +487,7 @@
False: for errors
"""
return wait_and_answer_video_call_for_subscription(
- log, ad,
- get_outgoing_voice_sub_id(ad), incoming_number, video_state,
+ log, ad, get_outgoing_voice_sub_id(ad), incoming_number, video_state,
incall_ui_display)
@@ -430,8 +518,9 @@
"""
if not wait_for_ringing_call(log, ad, incoming_number):
- log.error("Video call could not be established: <{}> never rang.".
- format(ad.serial))
+ log.error(
+ "Video call could not be established: <{}> never rang.".format(
+ ad.serial))
return False
ad.ed.clear_all_events()
@@ -505,8 +594,7 @@
"""
return video_call_setup_teardown_for_subscription(
- log, ad_caller, ad_callee,
- get_outgoing_voice_sub_id(ad_caller),
+ log, ad_caller, ad_callee, get_outgoing_voice_sub_id(ad_caller),
get_incoming_voice_sub_id(ad_callee), ad_hangup, video_state,
verify_caller_func, verify_callee_func, wait_time_in_call,
incall_ui_display)
@@ -614,8 +702,8 @@
callee_state_result = verify_callee_func(log, ad_callee)
if not callee_state_result:
raise _CallSequenceException(
- "Callee not in correct state at <{}>/<{}> seconds"
- .format(elapsed_time, wait_time_in_call))
+ "Callee not in correct state at <{}>/<{}> seconds".format(
+ elapsed_time, wait_time_in_call))
if not verify_caller_func:
caller_state_result = ad_caller.droid.telecomIsInCall()
@@ -623,8 +711,8 @@
caller_state_result = verify_caller_func(log, ad_caller)
if not caller_state_result:
raise _CallSequenceException(
- "Caller not in correct state at <{}>/<{}> seconds"
- .format(elapsed_time, wait_time_in_call))
+ "Caller not in correct state at <{}>/<{}> seconds".format(
+ elapsed_time, wait_time_in_call))
if not ad_hangup:
return True
@@ -672,8 +760,7 @@
"""
return video_call_setup_for_subscription(
- log, ad_caller, ad_callee,
- get_outgoing_voice_sub_id(ad_caller),
+ log, ad_caller, ad_callee, get_outgoing_voice_sub_id(ad_caller),
get_incoming_voice_sub_id(ad_callee), video_state, incall_ui_display)
@@ -784,8 +871,8 @@
cur_video_state = ad_requester.droid.telecomCallVideoGetState(
call_id_requester)
- log.info("State change request from {} to {} requested"
- .format(cur_video_state, video_state_request))
+ log.info("State change request from {} to {} requested".format(
+ cur_video_state, video_state_request))
if cur_video_state == video_state_request:
return True
@@ -811,8 +898,8 @@
ad_responder.droid.telecomCallVideoStopListeningForEvent(
call_id_responder, EVENT_VIDEO_SESSION_MODIFY_REQUEST_RECEIVED)
- if (verify_func_between_request_and_response and
- not verify_func_between_request_and_response()):
+ if (verify_func_between_request_and_response
+ and not verify_func_between_request_and_response()):
log.error("verify_func_between_request_and_response failed.")
return False
@@ -916,12 +1003,12 @@
current_video_state_requester = ad_requester.droid.telecomCallVideoGetState(
call_id_requester)
if video_state_request is None:
- if (current_video_state_requester == VT_STATE_BIDIRECTIONAL or
- current_video_state_requester ==
+ if (current_video_state_requester == VT_STATE_BIDIRECTIONAL
+ or current_video_state_requester ==
VT_STATE_BIDIRECTIONAL_PAUSED):
video_state_request = VT_STATE_RX_ENABLED
- elif (current_video_state_requester == VT_STATE_TX_ENABLED or
- current_video_state_requester == VT_STATE_TX_PAUSED):
+ elif (current_video_state_requester == VT_STATE_TX_ENABLED
+ or current_video_state_requester == VT_STATE_TX_PAUSED):
video_state_request = VT_STATE_AUDIO_ONLY
else:
log.error("Can Not Downgrade. ad: {}, current state {}".format(
@@ -966,10 +1053,11 @@
return False
if (expected_video_state_responder !=
ad_responder.droid.telecomCallVideoGetState(call_id_responder)):
- log.error("responder not in correct state. expected:{}, current:{}".
- format(expected_video_state_responder,
- ad_responder.droid.telecomCallVideoGetState(
- call_id_responder)))
+ log.error(
+ "responder not in correct state. expected:{}, current:{}".format(
+ expected_video_state_responder,
+ ad_responder.droid.telecomCallVideoGetState(
+ call_id_responder)))
return False
return True
diff --git a/acts/framework/acts/test_utils/tel/tel_voice_utils.py b/acts/framework/acts/test_utils/tel/tel_voice_utils.py
index cf155ae..8afd6c8 100644
--- a/acts/framework/acts/test_utils/tel/tel_voice_utils.py
+++ b/acts/framework/acts/test_utils/tel/tel_voice_utils.py
@@ -64,6 +64,7 @@
from acts.test_utils.tel.tel_test_utils import \
reset_preferred_network_type_to_allowable_range
from acts.test_utils.tel.tel_test_utils import set_wfc_mode
+from acts.test_utils.tel.tel_test_utils import set_wifi_to_default
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts.test_utils.tel.tel_test_utils import toggle_volte
from acts.test_utils.tel.tel_test_utils import toggle_volte_for_subscription
@@ -435,6 +436,7 @@
True if success, False if fail.
"""
toggle_airplane_mode(log, ad, False, strict_checking=False)
+ set_wifi_to_default(log, ad)
if not set_wfc_mode(log, ad, WFC_MODE_DISABLED):
ad.log.error("Disable WFC failed.")
return False
@@ -771,6 +773,7 @@
def phone_setup_rat_for_subscription(log, ad, sub_id, network_preference,
rat_family):
toggle_airplane_mode(log, ad, False, strict_checking=False)
+ set_wifi_to_default(log, ad)
if not set_wfc_mode(log, ad, WFC_MODE_DISABLED):
ad.log.error("Disable WFC failed.")
return False
@@ -978,6 +981,7 @@
return wait_for_network_generation_for_subscription(
log, ad, sub_id, GEN_2G, voice_or_data=NETWORK_SERVICE_VOICE)
+
def get_current_voice_rat(log, ad):
"""Return current Voice RAT
@@ -987,6 +991,7 @@
return get_current_voice_rat_for_subscription(
log, ad, get_outgoing_voice_sub_id(ad))
+
def get_current_voice_rat_for_subscription(log, ad, sub_id):
"""Return current Voice RAT for subscription id.
@@ -995,7 +1000,8 @@
sub_id: subscription id.
"""
return get_network_rat_for_subscription(log, ad, sub_id,
- NETWORK_SERVICE_VOICE)
+ NETWORK_SERVICE_VOICE)
+
def is_phone_in_call_volte(log, ad):
"""Return if phone is in VoLTE call.
diff --git a/acts/framework/acts/test_utils/wifi/WifiBaseTest.py b/acts/framework/acts/test_utils/wifi/WifiBaseTest.py
index a048906..bd62853 100755
--- a/acts/framework/acts/test_utils/wifi/WifiBaseTest.py
+++ b/acts/framework/acts/test_utils/wifi/WifiBaseTest.py
@@ -37,12 +37,13 @@
class WifiBaseTest(BaseTestClass):
def __init__(self, controllers):
BaseTestClass.__init__(self, controllers)
- if self.attenuators:
+ if hasattr(self, 'attenuators'):
for attenuator in self.attenuators:
attenuator.set_atten(0)
def get_wpa2_network(
self,
+ hidden=False,
ap_count=1,
ssid_length_2g=hostapd_constants.AP_SSID_LENGTH_2G,
ssid_length_5g=hostapd_constants.AP_SSID_LENGTH_5G,
@@ -74,17 +75,33 @@
ref_5g_ssid = '5g_%s' % utils.rand_ascii_str(ssid_length_5g)
ref_5g_passphrase = utils.rand_ascii_str(passphrase_length_5g)
- network_dict_2g = {
- "SSID": ref_2g_ssid,
- "security": ref_2g_security,
- "password": ref_2g_passphrase
- }
+ if hidden:
+ network_dict_2g = {
+ "SSID": ref_2g_ssid,
+ "security": ref_2g_security,
+ "password": ref_2g_passphrase,
+ "hiddenSSID": true
+ }
- network_dict_5g = {
- "SSID": ref_5g_ssid,
- "security": ref_5g_security,
- "password": ref_5g_passphrase
- }
+ network_dict_5g = {
+ "SSID": ref_5g_ssid,
+ "security": ref_5g_security,
+ "password": ref_5g_passphrase,
+ "hiddenSSID": true
+ }
+ else:
+ network_dict_2g = {
+ "SSID": ref_2g_ssid,
+ "security": ref_2g_security,
+ "password": ref_2g_passphrase
+ }
+
+ network_dict_5g = {
+ "SSID": ref_5g_ssid,
+ "security": ref_5g_security,
+ "password": ref_5g_passphrase
+ }
+
ap = 0
for ap in range(ap_count):
self.user_params["reference_networks"].append({
@@ -97,6 +114,7 @@
return {"2g": network_dict_2g, "5g": network_dict_5g}
def get_open_network(self,
+ hidden=False,
ap_count=1,
ssid_length_2g=hostapd_constants.AP_SSID_LENGTH_2G,
ssid_length_5g=hostapd_constants.AP_SSID_LENGTH_5G):
@@ -116,8 +134,29 @@
self.user_params["open_network"] = []
open_2g_ssid = '2g_%s' % utils.rand_ascii_str(ssid_length_2g)
open_5g_ssid = '5g_%s' % utils.rand_ascii_str(ssid_length_5g)
- network_dict_2g = {"SSID": open_2g_ssid, "security": 'none'}
- network_dict_5g = {"SSID": open_5g_ssid, "security": 'none'}
+ if hidden:
+ network_dict_2g = {
+ "SSID": open_2g_ssid,
+ "security": 'none',
+ "hiddenSSID": true
+ }
+
+ network_dict_5g = {
+ "SSID": open_5g_ssid,
+ "security": 'none',
+ "hiddenSSID": true
+ }
+ else:
+ network_dict_2g = {
+ "SSID": open_2g_ssid,
+ "security": 'none'
+ }
+
+ network_dict_5g = {
+ "SSID": open_5g_ssid,
+ "security": 'none'
+ }
+
ap = 0
for ap in range(ap_count):
self.user_params["open_network"].append({
@@ -166,6 +205,7 @@
ap_passphrase_length_2g=hostapd_constants.AP_PASSPHRASE_LENGTH_2G,
ap_ssid_length_5g=hostapd_constants.AP_SSID_LENGTH_5G,
ap_passphrase_length_5g=hostapd_constants.AP_PASSPHRASE_LENGTH_5G,
+ hidden=False,
ap_count=1):
asserts.assert_true(
len(self.user_params["AccessPoint"]) == 2,
@@ -214,7 +254,16 @@
# build config based on the bss_Settings alone.
hostapd_config_settings = network_list.pop(0)
for network in network_list:
- if "password" in network:
+ if "password" in network and "hiddenSSID" in network:
+ bss_settings.append(
+ hostapd_bss_settings.BssSettings(
+ name=network["SSID"],
+ ssid=network["SSID"],
+ hidden=True,
+ security=hostapd_security.Security(
+ security_mode=network["security"],
+ password=network["password"])))
+ elif "password" in network and not "hiddenSSID" in network:
bss_settings.append(
hostapd_bss_settings.BssSettings(
name=network["SSID"],
@@ -222,10 +271,17 @@
security=hostapd_security.Security(
security_mode=network["security"],
password=network["password"])))
- else:
+ elif not "password" in network and "hiddenSSID" in network:
bss_settings.append(
hostapd_bss_settings.BssSettings(
- name=network["SSID"], ssid=network["SSID"]))
+ name=network["SSID"],
+ ssid=network["SSID"],
+ hidden=True))
+ elif not "password" in network and not "hiddenSSID" in network:
+ bss_settings.append(
+ hostapd_bss_settings.BssSettings(
+ name=network["SSID"],
+ ssid=network["SSID"]))
if "password" in hostapd_config_settings:
config = hostapd_ap_preset.create_ap_preset(
channel=ap_settings["channel"],
diff --git a/acts/framework/acts/test_utils/wifi/aware/aware_const.py b/acts/framework/acts/test_utils/wifi/aware/aware_const.py
index a7574a4..e94c9bb 100644
--- a/acts/framework/acts/test_utils/wifi/aware/aware_const.py
+++ b/acts/framework/acts/test_utils/wifi/aware/aware_const.py
@@ -90,7 +90,7 @@
# WifiAwareDiscoverySessionCallback events keys
SESSION_CB_KEY_CB_ID = "callbackId"
-SESSION_CB_KEY_SESSION_ID = "sessionId"
+SESSION_CB_KEY_SESSION_ID = "discoverySessionId"
SESSION_CB_KEY_REASON = "reason"
SESSION_CB_KEY_PEER_ID = "peerId"
SESSION_CB_KEY_SERVICE_SPECIFIC_INFO = "serviceSpecificInfo"
diff --git a/acts/framework/acts/test_utils/wifi/wifi_test_utils.py b/acts/framework/acts/test_utils/wifi/wifi_test_utils.py
index 0b96a77..f48ec92 100755
--- a/acts/framework/acts/test_utils/wifi/wifi_test_utils.py
+++ b/acts/framework/acts/test_utils/wifi/wifi_test_utils.py
@@ -754,7 +754,6 @@
"""
ad.droid.wifiStartTrackingTetherStateChange()
ad.droid.connectivityStopTethering(tel_defines.TETHERING_WIFI)
- ad.droid.wifiSetApEnabled(False, None)
try:
ad.ed.pop_event("WifiManagerApDisabled", 30)
ad.ed.wait_for_event("TetherStateChanged",
diff --git a/acts/framework/acts/utils.py b/acts/framework/acts/utils.py
index 62c5d58..2447548 100755
--- a/acts/framework/acts/utils.py
+++ b/acts/framework/acts/utils.py
@@ -728,6 +728,16 @@
1 if new_state else 0))
+def set_regulatory_domain(ad, domain):
+ """Set the Wi-Fi regulatory domain
+
+ Args:
+ ad: android device object.
+ domain: regulatory domain
+ """
+ ad.adb.shell("iw reg set %s" % domain)
+
+
def bypass_setup_wizard(ad, bypass_wait_time=3):
"""Bypass the setup wizard on an input Android device
diff --git a/acts/framework/setup.py b/acts/framework/setup.py
index 48c71bb..654ba5f 100755
--- a/acts/framework/setup.py
+++ b/acts/framework/setup.py
@@ -17,7 +17,6 @@
from distutils import cmd
from distutils import log
import os
-import pip
import shutil
import setuptools
from setuptools.command import test
@@ -29,11 +28,13 @@
# mock-1.0.1 is the last version compatible with setuptools <17.1,
# which is what comes with Ubuntu 14.04 LTS.
'mock<=1.0.1',
+ 'numpy',
'pyserial',
'shellescape',
'protobuf',
'roman',
'scapy-python3',
+ 'pylibftdi',
]
if sys.version_info < (3, ):
@@ -122,7 +123,7 @@
def run(self):
"""Entry point for the uninstaller."""
# Remove the working directory from the python path. This ensures that
- # Source code is not accidently tarageted.
+ # Source code is not accidentally targeted.
our_dir = os.path.abspath(os.path.dirname(__file__))
if our_dir in sys.path:
sys.path.remove(our_dir)
@@ -167,6 +168,13 @@
},
url="http://www.android.com/")
+ if {'-u', '--uninstall', 'uninstall'}.intersection(sys.argv):
+ act_path = '/usr/local/bin/act.py'
+ if os.path.islink(act_path):
+ os.unlink(act_path)
+ elif os.path.exists(act_path):
+ os.remove(act_path)
+
if __name__ == '__main__':
main()
diff --git a/acts/framework/tests/AttenuatorSanityTest.py b/acts/framework/tests/AttenuatorSanityTest.py
index b2f5f47..7f86ef9 100644
--- a/acts/framework/tests/AttenuatorSanityTest.py
+++ b/acts/framework/tests/AttenuatorSanityTest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright (C) 2016 The Android Open Source Project
#
diff --git a/acts/framework/tests/IntegrationTest.py b/acts/framework/tests/IntegrationTest.py
index c8bdf2f..3cb34b7 100755
--- a/acts/framework/tests/IntegrationTest.py
+++ b/acts/framework/tests/IntegrationTest.py
@@ -31,7 +31,3 @@
self.log.info("This is a bare minimal test to make sure the basic ACTS"
"test flow works.")
asserts.explicit_pass("Hello World")
-
-
-if __name__ == "__main__":
- test_runner.main()
diff --git a/acts/framework/tests/Sl4aSanityTest.py b/acts/framework/tests/Sl4aSanityTest.py
index c3671a3..a88272f 100644
--- a/acts/framework/tests/Sl4aSanityTest.py
+++ b/acts/framework/tests/Sl4aSanityTest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright (C) 2016 The Android Open Source Project
#
diff --git a/acts/framework/tests/SnifferSanityTest.py b/acts/framework/tests/SnifferSanityTest.py
index fa9ed8b..0787873 100644
--- a/acts/framework/tests/SnifferSanityTest.py
+++ b/acts/framework/tests/SnifferSanityTest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright (C) 2016 The Android Open Source Project
#
diff --git a/acts/framework/tests/acts_adb_test.py b/acts/framework/tests/acts_adb_test.py
index b56ef8b..5e0544a 100755
--- a/acts/framework/tests/acts_adb_test.py
+++ b/acts/framework/tests/acts_adb_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2017 - The Android Open Source Project
#
diff --git a/acts/framework/tests/acts_android_device_test.py b/acts/framework/tests/acts_android_device_test.py
index 02aa485..b2cb0b5 100755
--- a/acts/framework/tests/acts_android_device_test.py
+++ b/acts/framework/tests/acts_android_device_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
@@ -26,13 +26,16 @@
# Mock log path for a test run.
MOCK_LOG_PATH = "/tmp/logs/MockTest/xx-xx-xx_xx-xx-xx/"
+
# Mock start and end time of the adb cat.
MOCK_ADB_LOGCAT_BEGIN_TIME = "1970-01-02 21:03:20.123"
MOCK_ADB_LOGCAT_END_TIME = "1970-01-02 21:22:02.000"
MOCK_ADB_EPOCH_BEGIN_TIME = 191000123
MOCK_SERIAL = 1
-MOCK_BUILD_ID = "ABC1.123456.007"
+MOCK_RELEASE_BUILD_ID = "ABC1.123456.007"
+MOCK_DEV_BUILD_ID = "ABC-MR1"
+MOCK_NYC_BUILD_ID = "N4F27P"
def get_mock_ads(num):
@@ -60,13 +63,20 @@
return [ad.serial for ad in get_mock_ads(5)]
-class MockAdbProxy():
+class MockAdbProxy(object):
"""Mock class that swaps out calls to adb with mock calls."""
- def __init__(self, serial, fail_br=False, fail_br_before_N=False):
+ def __init__(self,
+ serial,
+ fail_br=False,
+ fail_br_before_N=False,
+ build_id=MOCK_RELEASE_BUILD_ID):
self.serial = serial
self.fail_br = fail_br
self.fail_br_before_N = fail_br_before_N
+ self.return_value = None
+ self.return_multiple = False
+ self.build_id = build_id
def shell(self, params, ignore_status=False, timeout=60):
if params == "id -u":
@@ -79,10 +89,15 @@
if self.fail_br_before_N:
return "/system/bin/sh: bugreportz: not found"
return "1.1"
+ else:
+ if self.return_multiple:
+ return self.return_value.pop(0)
+ else:
+ return self.return_value
def getprop(self, params):
if params == "ro.build.id":
- return MOCK_BUILD_ID
+ return self.build_id
elif params == "ro.build.version.incremental":
return "123456789"
elif params == "ro.build.type":
@@ -98,7 +113,9 @@
def bugreport(self, params, timeout=android_device.BUG_REPORT_TIMEOUT):
expected = os.path.join(
logging.log_path, "AndroidDevice%s" % self.serial,
- "test_something", "AndroidDevice%s_sometime" % self.serial)
+ "test_something", "AndroidDevice%s_%s" %
+ (self.serial,
+ logger.normalize_log_line_timestamp(MOCK_ADB_LOGCAT_BEGIN_TIME)))
assert expected in params, "Expected '%s', got '%s'." % (expected,
params)
@@ -228,25 +245,28 @@
# These tests mock out any interaction with the OS and real android device
# in AndroidDeivce.
- @mock.patch('acts.controllers.adb.AdbProxy', return_value=MockAdbProxy(1))
+ @mock.patch(
+ 'acts.controllers.adb.AdbProxy',
+ return_value=MockAdbProxy(MOCK_SERIAL))
@mock.patch(
'acts.controllers.fastboot.FastbootProxy',
- return_value=MockFastbootProxy(1))
+ return_value=MockFastbootProxy(MOCK_SERIAL))
def test_AndroidDevice_instantiation(self, MockFastboot, MockAdbProxy):
"""Verifies the AndroidDevice object's basic attributes are correctly
set after instantiation.
"""
- mock_serial = 1
- ad = android_device.AndroidDevice(serial=mock_serial)
+ ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
self.assertEqual(ad.serial, 1)
self.assertEqual(ad.model, "fakemodel")
self.assertIsNone(ad.adb_logcat_process)
self.assertIsNone(ad.adb_logcat_file_path)
expected_lp = os.path.join(logging.log_path,
- "AndroidDevice%s" % mock_serial)
+ "AndroidDevice%s" % MOCK_SERIAL)
self.assertEqual(ad.log_path, expected_lp)
- @mock.patch('acts.controllers.adb.AdbProxy', return_value=MockAdbProxy(1))
+ @mock.patch(
+ 'acts.controllers.adb.AdbProxy',
+ return_value=MockAdbProxy(MOCK_SERIAL))
@mock.patch(
'acts.controllers.fastboot.FastbootProxy',
return_value=MockFastbootProxy(MOCK_SERIAL))
@@ -260,11 +280,14 @@
self.assertEqual(build_info["build_id"], "ABC1.123456.007")
self.assertEqual(build_info["build_type"], "userdebug")
- @mock.patch('acts.controllers.adb.AdbProxy', return_value=MockAdbProxy(1))
+ @mock.patch(
+ 'acts.controllers.adb.AdbProxy',
+ return_value=MockAdbProxy(MOCK_SERIAL, build_id=MOCK_DEV_BUILD_ID))
@mock.patch(
'acts.controllers.fastboot.FastbootProxy',
return_value=MockFastbootProxy(MOCK_SERIAL))
- def test_AndroidDevice_build_info_dev(self, MockFastboot, MockAdbProxy):
+ def test_AndroidDevice_build_info_release(self, MockFastboot,
+ MockAdbProxy):
"""Verifies the AndroidDevice object's basic attributes are correctly
set after instantiation.
"""
@@ -283,6 +306,36 @@
@mock.patch(
'acts.controllers.fastboot.FastbootProxy',
return_value=MockFastbootProxy(MOCK_SERIAL))
+ def test_AndroidDevice_build_info_dev(self, MockFastboot, MockAdbProxy):
+ """Verifies the AndroidDevice object's basic attributes are correctly
+ set after instantiation.
+ """
+ ad = android_device.AndroidDevice(serial=1)
+ build_info = ad.build_info
+ self.assertEqual(build_info["build_id"], "123456789")
+ self.assertEqual(build_info["build_type"], "userdebug")
+
+ @mock.patch(
+ 'acts.controllers.adb.AdbProxy',
+ return_value=MockAdbProxy(MOCK_SERIAL, build_id=MOCK_NYC_BUILD_ID))
+ @mock.patch(
+ 'acts.controllers.fastboot.FastbootProxy',
+ return_value=MockFastbootProxy(MOCK_SERIAL))
+ def test_AndroidDevice_build_info_nyc(self, MockFastboot, MockAdbProxy):
+ """Verifies the AndroidDevice object's build id is set correctly for
+ NYC releases.
+ """
+ ad = android_device.AndroidDevice(serial=1)
+ build_info = ad.build_info
+ self.assertEqual(build_info["build_id"], MOCK_NYC_BUILD_ID)
+
+ @mock.patch(
+ 'acts.controllers.adb.AdbProxy',
+ return_value=MockAdbProxy(MOCK_SERIAL))
+ @mock.patch(
+ 'acts.controllers.fastboot.FastbootProxy',
+ return_value=MockFastbootProxy(MOCK_SERIAL))
+
@mock.patch('acts.utils.create_dir')
@mock.patch('acts.utils.exe_cmd')
def test_AndroidDevice_take_bug_report(self, exe_mock, create_dir_mock,
@@ -290,19 +343,18 @@
"""Verifies AndroidDevice.take_bug_report calls the correct adb command
and writes the bugreport file to the correct path.
"""
- mock_serial = 1
- ad = android_device.AndroidDevice(serial=mock_serial)
- ad.take_bug_report("test_something", "sometime")
+ ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
+ ad.take_bug_report("test_something", 234325.32)
expected_path = os.path.join(
logging.log_path, "AndroidDevice%s" % ad.serial, "test_something")
create_dir_mock.assert_called_with(expected_path)
@mock.patch(
'acts.controllers.adb.AdbProxy',
- return_value=MockAdbProxy(1, fail_br=True))
+ return_value=MockAdbProxy(MOCK_SERIAL, fail_br=True))
@mock.patch(
'acts.controllers.fastboot.FastbootProxy',
- return_value=MockFastbootProxy(1))
+ return_value=MockFastbootProxy(MOCK_SERIAL))
@mock.patch('acts.utils.create_dir')
@mock.patch('acts.utils.exe_cmd')
def test_AndroidDevice_take_bug_report_fail(
@@ -310,19 +362,18 @@
"""Verifies AndroidDevice.take_bug_report writes out the correct message
when taking bugreport fails.
"""
- mock_serial = 1
- ad = android_device.AndroidDevice(serial=mock_serial)
+ ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
expected_msg = "Failed to take bugreport on 1: OMG I died!"
with self.assertRaisesRegex(android_device.AndroidDeviceError,
expected_msg):
- ad.take_bug_report("test_something", "sometime")
+ ad.take_bug_report("test_something", 4346343.23)
@mock.patch(
'acts.controllers.adb.AdbProxy',
- return_value=MockAdbProxy(1, fail_br_before_N=True))
+ return_value=MockAdbProxy(MOCK_SERIAL, fail_br_before_N=True))
@mock.patch(
'acts.controllers.fastboot.FastbootProxy',
- return_value=MockFastbootProxy(1))
+ return_value=MockFastbootProxy(MOCK_SERIAL))
@mock.patch('acts.utils.create_dir')
@mock.patch('acts.utils.exe_cmd')
def test_AndroidDevice_take_bug_report_fallback(
@@ -330,17 +381,18 @@
"""Verifies AndroidDevice.take_bug_report falls back to traditional
bugreport on builds that do not have bugreportz.
"""
- mock_serial = 1
- ad = android_device.AndroidDevice(serial=mock_serial)
- ad.take_bug_report("test_something", "sometime")
+ ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
+ ad.take_bug_report("test_something", MOCK_ADB_EPOCH_BEGIN_TIME)
expected_path = os.path.join(
logging.log_path, "AndroidDevice%s" % ad.serial, "test_something")
create_dir_mock.assert_called_with(expected_path)
- @mock.patch('acts.controllers.adb.AdbProxy', return_value=MockAdbProxy(1))
+ @mock.patch(
+ 'acts.controllers.adb.AdbProxy',
+ return_value=MockAdbProxy(MOCK_SERIAL))
@mock.patch(
'acts.controllers.fastboot.FastbootProxy',
- return_value=MockFastbootProxy(1))
+ return_value=MockFastbootProxy(MOCK_SERIAL))
@mock.patch('acts.utils.create_dir')
@mock.patch('acts.utils.start_standing_subprocess', return_value="process")
@mock.patch('acts.utils.stop_standing_subprocess')
@@ -352,8 +404,7 @@
object, including various function calls and the expected behaviors of
the calls.
"""
- mock_serial = 1
- ad = android_device.AndroidDevice(serial=mock_serial)
+ ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
expected_msg = ("Android device .* does not have an ongoing adb logcat"
" collection.")
# Expect error if stop is called before start.
@@ -383,10 +434,12 @@
self.assertIsNone(ad.adb_logcat_process)
self.assertEqual(ad.adb_logcat_file_path, expected_log_path)
- @mock.patch('acts.controllers.adb.AdbProxy', return_value=MockAdbProxy(1))
+ @mock.patch(
+ 'acts.controllers.adb.AdbProxy',
+ return_value=MockAdbProxy(MOCK_SERIAL))
@mock.patch(
'acts.controllers.fastboot.FastbootProxy',
- return_value=MockFastbootProxy(1))
+ return_value=MockFastbootProxy(MOCK_SERIAL))
@mock.patch('acts.utils.create_dir')
@mock.patch('acts.utils.start_standing_subprocess', return_value="process")
@mock.patch('acts.utils.stop_standing_subprocess')
@@ -398,8 +451,7 @@
object, including various function calls and the expected behaviors of
the calls.
"""
- mock_serial = 1
- ad = android_device.AndroidDevice(serial=mock_serial)
+ ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
ad.adb_logcat_param = "-b radio"
expected_msg = ("Android device .* does not have an ongoing adb logcat"
" collection.")
@@ -418,6 +470,7 @@
start_proc_mock.assert_called_with(adb_cmd % (ad.serial,
expected_log_path))
self.assertEqual(ad.adb_logcat_file_path, expected_log_path)
+
@mock.patch(
'acts.controllers.adb.AdbProxy',
return_value=MockAdbProxy(MOCK_SERIAL))
diff --git a/acts/framework/tests/acts_asserts_test.py b/acts/framework/tests/acts_asserts_test.py
index dbf39d9..da8d4c7 100755
--- a/acts/framework/tests/acts_asserts_test.py
+++ b/acts/framework/tests/acts_asserts_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
diff --git a/acts/framework/tests/acts_base_class_test.py b/acts/framework/tests/acts_base_class_test.py
index 7ee3e85..d4ae599 100755
--- a/acts/framework/tests/acts_base_class_test.py
+++ b/acts/framework/tests/acts_base_class_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
@@ -54,9 +54,9 @@
class MockBaseTest(base_test.BaseTestClass):
def test_func(self):
asserts.assert_true(
- self.current_test_name == "test_func",
- ("Got "
- "unexpected test name %s.") % self.current_test_name)
+ self.current_test_name == "test_func",
+ ("Got "
+ "unexpected test name %s.") % self.current_test_name)
bt_cls = MockBaseTest(self.mock_test_cls_configs)
bt_cls.run(test_names=["test_func"])
diff --git a/acts/framework/tests/acts_host_utils_test.py b/acts/framework/tests/acts_host_utils_test.py
index e75d27a..f13d328 100755
--- a/acts/framework/tests/acts_host_utils_test.py
+++ b/acts/framework/tests/acts_host_utils_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
@@ -14,7 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import mock
import socket
import unittest
@@ -26,19 +25,6 @@
under acts.controllers.adb.
"""
- def test_is_port_available_positive(self):
- # Unfortunately, we cannot do this test reliably for SOCK_STREAM
- # because the kernel allow this socket to linger about for some
- # small amount of time. We're not using SO_REUSEADDR because we
- # are working around behavior on darwin where binding to localhost
- # on some port and then binding again to the wildcard address
- # with SO_REUSEADDR seems to be allowed.
- test_s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- test_s.bind(('localhost', 0))
- port = test_s.getsockname()[1]
- test_s.close()
- self.assertTrue(host_utils.is_port_available(port))
-
def test_detects_udp_port_in_use(self):
test_s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
test_s.bind(('localhost', 0))
diff --git a/acts/framework/tests/acts_import_test_utils_test.py b/acts/framework/tests/acts_import_test_utils_test.py
index 2171b38..a0a66fd 100755
--- a/acts/framework/tests/acts_import_test_utils_test.py
+++ b/acts/framework/tests/acts_import_test_utils_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
diff --git a/acts/framework/tests/acts_import_unit_test.py b/acts/framework/tests/acts_import_unit_test.py
index 5f0b20c..eb78c9f 100755
--- a/acts/framework/tests/acts_import_unit_test.py
+++ b/acts/framework/tests/acts_import_unit_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
@@ -19,7 +19,7 @@
import sys
import uuid
-if sys.version_info < (3,):
+if sys.version_info < (3, ):
import warnings
with warnings.catch_warnings():
@@ -51,8 +51,9 @@
'acts/controllers/native.py',
'acts/controllers/native_android_device.py',
'acts/test_utils/wifi/wifi_power_test_utils.py',
- 'acts/framework/acts/controllers/packet_sender.py',
+ 'acts/controllers/packet_sender.py',
'acts/test_utils/wifi/wifi_retail_ap.py',
+ 'acts/test_utils/bt/bt_power_test_utils.py',
]
diff --git a/acts/framework/tests/acts_job_test.py b/acts/framework/tests/acts_job_test.py
index f93bf3d..a86ca91 100755
--- a/acts/framework/tests/acts_job_test.py
+++ b/acts/framework/tests/acts_job_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
# Copyright 2016 - The Android Open Source Project
#
diff --git a/acts/framework/tests/acts_logger_test.py b/acts/framework/tests/acts_logger_test.py
index dd18ae7..e804e45 100755
--- a/acts/framework/tests/acts_logger_test.py
+++ b/acts/framework/tests/acts_logger_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
diff --git a/acts/framework/tests/acts_records_test.py b/acts/framework/tests/acts_records_test.py
index cbf6561..ee59258 100755
--- a/acts/framework/tests/acts_records_test.py
+++ b/acts/framework/tests/acts_records_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
@@ -49,7 +49,7 @@
d[records.TestResultEnums.RECORD_BEGIN_TIME] = record.begin_time
d[records.TestResultEnums.RECORD_END_TIME] = record.end_time
d[records.TestResultEnums.
- RECORD_LOG_BEGIN_TIME] = record.log_begin_time
+ RECORD_LOG_BEGIN_TIME] = record.log_begin_time
d[records.TestResultEnums.RECORD_LOG_END_TIME] = record.log_end_time
d[records.TestResultEnums.RECORD_UID] = None
d[records.TestResultEnums.RECORD_CLASS] = None
diff --git a/acts/framework/tests/acts_relay_controller_test.py b/acts/framework/tests/acts_relay_controller_test.py
index 2676bff..8e21fe0 100755
--- a/acts/framework/tests/acts_relay_controller_test.py
+++ b/acts/framework/tests/acts_relay_controller_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
@@ -40,6 +40,7 @@
RelayDevice = relay_device.RelayDevice
RelayRig = relay_rig.RelayRig
SainSmartBoard = sain_smart_board.SainSmartBoard
+RelayDeviceConnectionError = errors.RelayDeviceConnectionError
class MockBoard(RelayBoard):
@@ -324,6 +325,18 @@
self.ss_board.set(self.r0.position, RelayState.NO)
self.assertNotEqual(os.stat(self.test_dir[7:] + '00').st_atime, 0)
+ def test_connection_error_no_tux(self):
+ default_status_msg = self.STATUS_MSG
+ self.STATUS_MSG = self.STATUS_MSG.replace('TUX', '')
+ try:
+ self._set_status_page('1111111111111111')
+ self.ss_board.get_relay_status(0)
+ except RelayDeviceConnectionError:
+ self.STATUS_MSG = default_status_msg
+ return
+
+ self.fail('Should have thrown an error without TUX appearing.')
+
class ActsRelayRigTest(unittest.TestCase):
def setUp(self):
@@ -700,7 +713,7 @@
})
self.mock_board = self.mock_rig.boards['MockBoard']
self.fugu_config = {
- 'type': 'GenericRelayDevice',
+ 'type': 'FuguRemote',
'name': 'UniqueDeviceName',
'mac_address': '00:00:00:00:00:00',
'relays': {
diff --git a/acts/framework/tests/acts_test_runner_test.py b/acts/framework/tests/acts_test_runner_test.py
index 451ee98..5b21ea9 100755
--- a/acts/framework/tests/acts_test_runner_test.py
+++ b/acts/framework/tests/acts_test_runner_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
@@ -209,7 +209,11 @@
@mock.patch(
'acts.controllers.android_device.AndroidDevice.ensure_screen_on',
return_value=True)
- def test_run_two_test_classes(self, mock_ensure_screen_on, mock_get_all,
+ @mock.patch(
+ 'acts.controllers.android_device.AndroidDevice.exit_setup_wizard',
+ return_value=True)
+ def test_run_two_test_classes(self, mock_exit_setup_wizard,
+ mock_ensure_screen_on, mock_get_all,
mock_list_adb, mock_fastboot, mock_adb):
"""Verifies that runing more than one test class in one test run works
proerly.
diff --git a/acts/framework/tests/acts_test_ssh.py b/acts/framework/tests/acts_test_ssh.py
index eb4efe7..c6f1250 100755
--- a/acts/framework/tests/acts_test_ssh.py
+++ b/acts/framework/tests/acts_test_ssh.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
# Copyright 2016 - The Android Open Source Project
#
diff --git a/acts/framework/tests/acts_unittest_suite.py b/acts/framework/tests/acts_unittest_suite.py
index 3b68d08..a4f1c94 100755
--- a/acts/framework/tests/acts_unittest_suite.py
+++ b/acts/framework/tests/acts_unittest_suite.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
diff --git a/acts/framework/tests/acts_utils_test.py b/acts/framework/tests/acts_utils_test.py
index fd7b083..5114e2a 100755
--- a/acts/framework/tests/acts_utils_test.py
+++ b/acts/framework/tests/acts_utils_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
diff --git a/acts/framework/tests/audio_analysis_unittest.py b/acts/framework/tests/audio_analysis_unittest.py
new file mode 100644
index 0000000..d90b822
--- /dev/null
+++ b/acts/framework/tests/audio_analysis_unittest.py
@@ -0,0 +1,358 @@
+#!/usr/bin/env python3
+#
+# Copyright 2017 - 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 logging
+import numpy
+import os
+import unittest
+
+import acts.test_utils.audio_analysis_lib.audio_analysis as audio_analysis
+import acts.test_utils.audio_analysis_lib.audio_data as audio_data
+
+
+class SpectralAnalysisTest(unittest.TestCase):
+ def setUp(self):
+ """Uses the same seed to generate noise for each test."""
+ numpy.random.seed(0)
+
+ def dummy_peak_detection(self, array, window_size):
+ """Detects peaks in an array in simple way.
+
+ A point (i, array[i]) is a peak if array[i] is the maximum among
+ array[i - half_window_size] to array[i + half_window_size].
+ If array[i - half_window_size] to array[i + half_window_size] are all
+ equal, then there is no peak in this window.
+
+ Args:
+ array: The input array to detect peaks in. Array is a list of
+ absolute values of the magnitude of transformed coefficient.
+ window_size: The window to detect peaks.
+
+ Returns:
+ A list of tuples:
+ [(peak_index_1, peak_value_1), (peak_index_2, peak_value_2),
+ ...]
+ where the tuples are sorted by peak values.
+
+ """
+ half_window_size = window_size / 2
+ length = len(array)
+
+ def mid_is_peak(array, mid, left, right):
+ """Checks if value at mid is the largest among left to right.
+
+ Args:
+ array: A list of numbers.
+ mid: The mid index.
+ left: The left index.
+ rigth: The right index.
+
+ Returns:
+ True if array[index] is the maximum among numbers in array
+ between index [left, right] inclusively.
+
+ """
+ value_mid = array[int(mid)]
+ for index in range(int(left), int(right) + 1):
+ if index == mid:
+ continue
+ if array[index] >= value_mid:
+ return False
+ return True
+
+ results = []
+ for mid in range(length):
+ left = max(0, mid - half_window_size)
+ right = min(length - 1, mid + half_window_size)
+ if mid_is_peak(array, mid, left, right):
+ results.append((mid, array[int(mid)]))
+
+ # Sort the peaks by values.
+ return sorted(results, key=lambda x: x[1], reverse=True)
+
+ def testPeakDetection(self):
+ array = [0, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 5, 3, 2, 1, 1, 1, 1, 1]
+ result = audio_analysis.peak_detection(array, 4)
+ golden_answer = [(12, 5), (4, 4)]
+ self.assertEqual(result, golden_answer)
+
+ def testPeakDetectionLarge(self):
+ array = numpy.random.uniform(0, 1, 1000000)
+ window_size = 100
+ logging.debug('Test large array using dummy peak detection')
+ dummy_answer = self.dummy_peak_detection(array, window_size)
+ logging.debug('Test large array using improved peak detection')
+ improved_answer = audio_analysis.peak_detection(array, window_size)
+ logging.debug('Compare the result')
+ self.assertEqual(dummy_answer, improved_answer)
+
+ def testSpectralAnalysis(self):
+ rate = 48000
+ length_in_secs = 0.5
+ freq_1 = 490.0
+ freq_2 = 60.0
+ coeff_1 = 1
+ coeff_2 = 0.3
+ samples = length_in_secs * rate
+ noise = numpy.random.standard_normal(int(samples)) * 0.005
+ x = numpy.linspace(0.0, (samples - 1) * 1.0 / rate, samples)
+ y = (coeff_1 * numpy.sin(freq_1 * 2.0 * numpy.pi * x) + coeff_2 *
+ numpy.sin(freq_2 * 2.0 * numpy.pi * x)) + noise
+ results = audio_analysis.spectral_analysis(y, rate)
+ # Results should contains
+ # [(490, 1*k), (60, 0.3*k), (0, 0.1*k)] where 490Hz is the dominant
+ # frequency with coefficient 1, 60Hz is the second dominant frequency
+ # with coefficient 0.3, 0Hz is from Gaussian noise with coefficient
+ # around 0.1. The k constant is resulted from window function.
+ logging.debug('Results: %s', results)
+ self.assertTrue(abs(results[0][0] - freq_1) < 1)
+ self.assertTrue(abs(results[1][0] - freq_2) < 1)
+ self.assertTrue(
+ abs(results[0][1] / results[1][1] - coeff_1 / coeff_2) < 0.01)
+
+ def testSpectralAnalysisRealData(self):
+ """This unittest checks the spectral analysis works on real data."""
+ file_path = os.path.join(
+ os.path.dirname(__file__), 'test_data', '1k_2k.raw')
+ binary = open(file_path, 'rb').read()
+ data = audio_data.AudioRawData(binary, 2, 'S32_LE')
+ saturate_value = audio_data.get_maximum_value_from_sample_format(
+ 'S32_LE')
+ golden_frequency = [1000, 2000]
+ for channel in [0, 1]:
+ normalized_signal = audio_analysis.normalize_signal(
+ data.channel_data[channel], saturate_value)
+ spectral = audio_analysis.spectral_analysis(normalized_signal,
+ 48000, 0.02)
+ logging.debug('channel %s: %s', channel, spectral)
+ self.assertTrue(
+ abs(spectral[0][0] - golden_frequency[channel]) < 5,
+ 'Dominant frequency is not correct')
+
+ def testNotMeaningfulData(self):
+ """Checks that sepectral analysis handles un-meaningful data."""
+ rate = 48000
+ length_in_secs = 0.5
+ samples = length_in_secs * rate
+ noise_amplitude = audio_analysis.MEANINGFUL_RMS_THRESHOLD * 0.5
+ noise = numpy.random.standard_normal(int(samples)) * noise_amplitude
+ results = audio_analysis.spectral_analysis(noise, rate)
+ self.assertEqual([(0, 0)], results)
+
+ def testEmptyData(self):
+ """Checks that sepectral analysis rejects empty data."""
+ with self.assertRaises(audio_analysis.EmptyDataError):
+ results = audio_analysis.spectral_analysis([], 100)
+
+
+class NormalizeTest(unittest.TestCase):
+ def testNormalize(self):
+ y = [1, 2, 3, 4, 5]
+ normalized_y = audio_analysis.normalize_signal(y, 10)
+ expected = numpy.array([0.1, 0.2, 0.3, 0.4, 0.5])
+ for i in range(len(y)):
+ self.assertEqual(expected[i], normalized_y[i])
+
+
+class AnomalyTest(unittest.TestCase):
+ def setUp(self):
+ """Creates a test signal of sine wave."""
+ # Use the same seed for each test case.
+ numpy.random.seed(0)
+
+ self.block_size = 120
+ self.rate = 48000
+ self.freq = 440
+ length_in_secs = 0.25
+ self.samples = length_in_secs * self.rate
+ x = numpy.linspace(0.0, (self.samples - 1) * 1.0 / self.rate,
+ self.samples)
+ self.y = numpy.sin(self.freq * 2.0 * numpy.pi * x)
+
+ def add_noise(self):
+ """Add noise to the test signal."""
+ noise_amplitude = 0.3
+ noise = numpy.random.standard_normal(len(self.y)) * noise_amplitude
+ self.y = self.y + noise
+
+ def insert_anomaly(self):
+ """Inserts an anomaly to the test signal.
+
+ The anomaly self.anomaly_samples should be created before calling this
+ method.
+
+ """
+ self.anomaly_start_secs = 0.1
+ self.y = numpy.insert(self.y,
+ int(self.anomaly_start_secs * self.rate),
+ self.anomaly_samples)
+
+ def generate_skip_anomaly(self):
+ """Skips a section of test signal."""
+ self.anomaly_start_secs = 0.1
+ self.anomaly_duration_secs = 0.005
+ anomaly_append_secs = self.anomaly_start_secs + self.anomaly_duration_secs
+ anomaly_start_index = self.anomaly_start_secs * self.rate
+ anomaly_append_index = anomaly_append_secs * self.rate
+ self.y = numpy.append(self.y[:int(anomaly_start_index)],
+ self.y[int(anomaly_append_index):])
+
+ def create_constant_anomaly(self, amplitude):
+ """Creates an anomaly of constant samples.
+
+ Args:
+ amplitude: The amplitude of the constant samples.
+
+ """
+ self.anomaly_duration_secs = 0.005
+ self.anomaly_samples = ([amplitude] *
+ int(self.anomaly_duration_secs * self.rate))
+
+ def run_analysis(self):
+ """Runs the anomaly detection."""
+ self.results = audio_analysis.anomaly_detection(
+ self.y, self.rate, self.freq, self.block_size)
+ logging.debug('Results: %s', self.results)
+
+ def check_no_anomaly(self):
+ """Verifies that there is no anomaly in detection result."""
+ self.run_analysis()
+ self.assertFalse(self.results)
+
+ def check_anomaly(self):
+ """Verifies that there is anomaly in detection result.
+
+ The detection result should contain anomaly time stamps that are
+ close to where anomaly was inserted. There can be multiple anomalies
+ since the detection depends on the block size.
+
+ """
+ self.run_analysis()
+ self.assertTrue(self.results)
+ # Anomaly can be detected as long as the detection window of block size
+ # overlaps with anomaly.
+ expected_detected_range_secs = (
+ self.anomaly_start_secs - float(self.block_size) / self.rate,
+ self.anomaly_start_secs + self.anomaly_duration_secs)
+ for detected_secs in self.results:
+ self.assertTrue(detected_secs <= expected_detected_range_secs[1])
+ self.assertTrue(detected_secs >= expected_detected_range_secs[0])
+
+ def testGoodSignal(self):
+ """Sine wave signal with no noise or anomaly."""
+ self.check_no_anomaly()
+
+ def testGoodSignalNoise(self):
+ """Sine wave signal with noise."""
+ self.add_noise()
+ self.check_no_anomaly()
+
+ def testZeroAnomaly(self):
+ """Sine wave signal with no noise but with anomaly.
+
+ This test case simulates underrun in digital data where there will be
+ one block of samples with 0 amplitude.
+
+ """
+ self.create_constant_anomaly(0)
+ self.insert_anomaly()
+ self.check_anomaly()
+
+ def testZeroAnomalyNoise(self):
+ """Sine wave signal with noise and anomaly.
+
+ This test case simulates underrun in analog data where there will be
+ one block of samples with amplitudes close to 0.
+
+ """
+ self.create_constant_anomaly(0)
+ self.insert_anomaly()
+ self.add_noise()
+ self.check_anomaly()
+
+ def testLowConstantAnomaly(self):
+ """Sine wave signal with low constant anomaly.
+
+ The anomaly is one block of constant values.
+
+ """
+ self.create_constant_anomaly(0.05)
+ self.insert_anomaly()
+ self.check_anomaly()
+
+ def testLowConstantAnomalyNoise(self):
+ """Sine wave signal with low constant anomaly and noise.
+
+ The anomaly is one block of constant values.
+
+ """
+ self.create_constant_anomaly(0.05)
+ self.insert_anomaly()
+ self.add_noise()
+ self.check_anomaly()
+
+ def testHighConstantAnomaly(self):
+ """Sine wave signal with high constant anomaly.
+
+ The anomaly is one block of constant values.
+
+ """
+ self.create_constant_anomaly(2)
+ self.insert_anomaly()
+ self.check_anomaly()
+
+ def testHighConstantAnomalyNoise(self):
+ """Sine wave signal with high constant anomaly and noise.
+
+ The anomaly is one block of constant values.
+
+ """
+ self.create_constant_anomaly(2)
+ self.insert_anomaly()
+ self.add_noise()
+ self.check_anomaly()
+
+ def testSkippedAnomaly(self):
+ """Sine wave signal with skipped anomaly.
+
+ The anomaly simulates the symptom where a block is skipped.
+
+ """
+ self.generate_skip_anomaly()
+ self.check_anomaly()
+
+ def testSkippedAnomalyNoise(self):
+ """Sine wave signal with skipped anomaly with noise.
+
+ The anomaly simulates the symptom where a block is skipped.
+
+ """
+ self.generate_skip_anomaly()
+ self.add_noise()
+ self.check_anomaly()
+
+ def testEmptyData(self):
+ """Checks that anomaly detection rejects empty data."""
+ self.y = []
+ with self.assertRaises(audio_analysis.EmptyDataError):
+ self.check_anomaly()
+
+
+if __name__ == '__main__':
+ logging.basicConfig(
+ level=logging.DEBUG,
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ unittest.main()
diff --git a/acts/framework/tests/audio_quality_measurement_unittest.py b/acts/framework/tests/audio_quality_measurement_unittest.py
new file mode 100644
index 0000000..0166ce9
--- /dev/null
+++ b/acts/framework/tests/audio_quality_measurement_unittest.py
@@ -0,0 +1,268 @@
+#!/usr/bin/env python3
+#
+# Copyright 2017 - 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 logging
+import math
+import numpy
+import unittest
+
+import acts.test_utils.audio_analysis_lib.audio_data as audio_data
+import acts.test_utils.audio_analysis_lib.audio_analysis as audio_analysis
+import acts.test_utils.audio_analysis_lib.audio_quality_measurement as \
+ audio_quality_measurement
+
+
+class NoiseLevelTest(unittest.TestCase):
+ def setUp(self):
+ """Uses the same seed to generate noise for each test."""
+ numpy.random.seed(0)
+
+ def testNoiseLevel(self):
+ # Generates the standard sin wave with standard_noise portion of noise.
+ rate = 48000
+ length_in_secs = 2
+ frequency = 440
+ amplitude = 1
+ standard_noise = 0.05
+
+ wave = []
+ for index in range(0, rate * length_in_secs):
+ phase = 2.0 * math.pi * frequency * float(index) / float(rate)
+ sine_wave = math.sin(phase)
+ noise = standard_noise * numpy.random.standard_normal()
+ wave.append(float(amplitude) * (sine_wave + noise))
+
+ # Calculates the average value after applying teager operator.
+ teager_value_of_wave, length = 0, len(wave)
+ for i in range(1, length - 1):
+ ith_teager_value = abs(wave[i] * wave[i] - wave[i - 1] * wave[i +
+ 1])
+ ith_teager_value *= max(1, abs(wave[i]))
+ teager_value_of_wave += ith_teager_value
+ teager_value_of_wave /= float(length * (amplitude**2))
+
+ noise = audio_quality_measurement.noise_level(
+ amplitude, frequency, rate, teager_value_of_wave)
+
+ self.assertTrue(abs(noise - standard_noise) < 0.01)
+
+
+class ErrorTest(unittest.TestCase):
+ def testError(self):
+ value1 = [0.2, 0.4, 0.1, 0.01, 0.01, 0.01]
+ value2 = [0.3, 0.3, 0.08, 0.0095, 0.0098, 0.0099]
+ error = [0.5, 0.25, 0.2, 0.05, 0.02, 0.01]
+ for i in range(len(value1)):
+ ret = audio_quality_measurement.error(value1[i], value2[i])
+ self.assertTrue(abs(ret - error[i]) < 0.001)
+
+
+class QualityMeasurementTest(unittest.TestCase):
+ def setUp(self):
+ """Creates a test signal of sine wave."""
+ numpy.random.seed(0)
+
+ self.rate = 48000
+ self.freq = 440
+ self.amplitude = 1
+ length_in_secs = 2
+ self.samples = length_in_secs * self.rate
+ self.y = []
+ for index in range(self.samples):
+ phase = 2.0 * math.pi * self.freq * float(index) / float(self.rate)
+ sine_wave = math.sin(phase)
+ self.y.append(float(self.amplitude) * sine_wave)
+
+ def add_noise(self):
+ """Adds noise to the test signal."""
+ noise_amplitude = 0.01 * self.amplitude
+ for index in range(self.samples):
+ noise = noise_amplitude * numpy.random.standard_normal()
+ self.y[index] += noise
+
+ def generate_delay(self):
+ """Generates some delays during playing."""
+ self.delay_start_time = [0.200, 0.375, 0.513, 0.814, 1.000, 1.300]
+ self.delay_end_time = [0.201, 0.377, 0.516, 0.824, 1.100, 1.600]
+
+ for i in range(len(self.delay_start_time)):
+ start_index = int(self.delay_start_time[i] * self.rate)
+ end_index = int(self.delay_end_time[i] * self.rate)
+ for j in range(start_index, end_index):
+ self.y[j] = 0
+
+ def generate_artifacts_before_playback(self):
+ """Generates artifacts before playing."""
+ silence_before_playback_end_time = 0.2
+ end_index = int(silence_before_playback_end_time * self.rate)
+ for i in range(0, end_index):
+ self.y[i] = 0
+ noise_start_index = int(0.1 * self.rate)
+ noise_end_index = int(0.1005 * self.rate)
+ for i in range(noise_start_index, noise_end_index):
+ self.y[i] = 3 * self.amplitude
+
+ def generate_artifacts_after_playback(self):
+ """Generates artifacts after playing."""
+ silence_after_playback_start_time = int(1.9 * self.rate)
+ noise_start_index = int(1.95 * self.rate)
+ noise_end_index = int((1.95 + 0.02) * self.rate)
+
+ for i in range(silence_after_playback_start_time, self.samples):
+ self.y[i] = 0
+ for i in range(noise_start_index, noise_end_index):
+ self.y[i] = self.amplitude
+
+ def generate_burst_during_playback(self):
+ """Generates bursts during playing."""
+ self.burst_start_time = [0.300, 0.475, 0.613, 0.814, 1.300]
+ self.burst_end_time = [0.301, 0.476, 0.614, 0.815, 1.301]
+
+ for i in range(len(self.burst_start_time)):
+ start_index = int(self.burst_start_time[i] * self.rate)
+ end_index = int(self.burst_end_time[i] * self.rate)
+ for j in range(start_index, end_index):
+ self.y[j] = self.amplitude * (3 + numpy.random.uniform(-1, 1))
+
+ def generate_volume_changing(self):
+ "Generates volume changing during playing."
+ start_time = [0.300, 1.400]
+ end_time = [0.600, 1.700]
+ for i in range(len(start_time)):
+ start_index = int(start_time[i] * self.rate)
+ end_index = int(end_time[i] * self.rate)
+ for j in range(start_index, end_index):
+ self.y[j] *= 1.4
+ self.volume_changing = [+1, -1, +1, -1]
+ self.volume_changing_time = [0.3, 0.6, 1.4, 1.7]
+
+ def testGoodSignal(self):
+ """Sine wave signal with no noise or artifacts."""
+ result = audio_quality_measurement.quality_measurement(self.y,
+ self.rate)
+ self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
+ self.assertTrue(len(result['volume_changes']) == 0)
+ self.assertTrue(result['equivalent_noise_level'] < 0.005)
+
+ def testGoodSignalNoise(self):
+ """Sine wave signal with noise."""
+ self.add_noise()
+ result = audio_quality_measurement.quality_measurement(self.y,
+ self.rate)
+ self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
+ self.assertTrue(len(result['volume_changes']) == 0)
+ self.assertTrue(0.009 < result['equivalent_noise_level'] and
+ result['equivalent_noise_level'] < 0.011)
+
+ def testDelay(self):
+ """Sine wave with delay during playing."""
+ self.generate_delay()
+ result = audio_quality_measurement.quality_measurement(self.y,
+ self.rate)
+ self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
+ self.assertTrue(
+ len(result['volume_changes']) == 2 * len(self.delay_start_time))
+ self.assertTrue(result['equivalent_noise_level'] < 0.005)
+
+ self.assertTrue(
+ len(result['artifacts']['delay_during_playback']) ==
+ len(self.delay_start_time))
+ for i in range(len(result['artifacts']['delay_during_playback'])):
+ delta = abs(result['artifacts']['delay_during_playback'][i][0] -
+ self.delay_start_time[i])
+ self.assertTrue(delta < 0.001)
+ duration = self.delay_end_time[i] - self.delay_start_time[i]
+ delta = abs(result['artifacts']['delay_during_playback'][i][1] -
+ duration)
+ self.assertTrue(delta < 0.001)
+
+ def testArtifactsBeforePlayback(self):
+ """Sine wave with artifacts before playback."""
+ self.generate_artifacts_before_playback()
+ result = audio_quality_measurement.quality_measurement(self.y,
+ self.rate)
+ self.assertTrue(len(result['artifacts']['noise_before_playback']) == 1)
+ delta = abs(result['artifacts']['noise_before_playback'][0][0] - 0.1)
+ self.assertTrue(delta < 0.01)
+ delta = abs(result['artifacts']['noise_before_playback'][0][1] - 0.005)
+ self.assertTrue(delta < 0.004)
+ self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
+ self.assertTrue(len(result['volume_changes']) == 0)
+ self.assertTrue(result['equivalent_noise_level'] < 0.005)
+
+ def testArtifactsAfterPlayback(self):
+ """Sine wave with artifacts after playback."""
+ self.generate_artifacts_after_playback()
+ result = audio_quality_measurement.quality_measurement(self.y,
+ self.rate)
+ self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['noise_after_playback']) == 1)
+ delta = abs(result['artifacts']['noise_after_playback'][0][0] - 1.95)
+ self.assertTrue(delta < 0.01)
+ delta = abs(result['artifacts']['noise_after_playback'][0][1] - 0.02)
+ self.assertTrue(delta < 0.001)
+ self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
+ self.assertTrue(len(result['volume_changes']) == 0)
+ self.assertTrue(result['equivalent_noise_level'] < 0.005)
+
+ def testBurstDuringPlayback(self):
+ """Sine wave with burst during playback."""
+ self.generate_burst_during_playback()
+ result = audio_quality_measurement.quality_measurement(self.y,
+ self.rate)
+ self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['burst_during_playback']) == 5)
+ self.assertTrue(len(result['volume_changes']) == 10)
+ self.assertTrue(result['equivalent_noise_level'] > 0.02)
+ for i in range(len(result['artifacts']['burst_during_playback'])):
+ delta = abs(self.burst_start_time[i] - result['artifacts'][
+ 'burst_during_playback'][i])
+ self.assertTrue(delta < 0.002)
+
+ def testVolumeChanging(self):
+ """Sine wave with volume changing during playback."""
+ self.generate_volume_changing()
+ result = audio_quality_measurement.quality_measurement(self.y,
+ self.rate)
+ self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
+ self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
+ self.assertTrue(result['equivalent_noise_level'] < 0.005)
+ self.assertTrue(
+ len(result['volume_changes']) == len(self.volume_changing))
+ for i in range(len(self.volume_changing)):
+ self.assertTrue(
+ abs(self.volume_changing_time[i] - result['volume_changes'][i][
+ 0]) < 0.01)
+ self.assertTrue(
+ self.volume_changing[i] == result['volume_changes'][i][1])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/acts/framework/tests/controllers/__init__.py b/acts/framework/tests/controllers/__init__.py
index 9727988..9006087 100644
--- a/acts/framework/tests/controllers/__init__.py
+++ b/acts/framework/tests/controllers/__init__.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2018 - The Android Open Source Project
#
diff --git a/acts/framework/tests/controllers/sl4a_lib/__init__.py b/acts/framework/tests/controllers/sl4a_lib/__init__.py
index 9727988..9006087 100644
--- a/acts/framework/tests/controllers/sl4a_lib/__init__.py
+++ b/acts/framework/tests/controllers/sl4a_lib/__init__.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2018 - The Android Open Source Project
#
diff --git a/acts/framework/tests/controllers/sl4a_lib/rpc_client_test.py b/acts/framework/tests/controllers/sl4a_lib/rpc_client_test.py
index dbaa2ab..a663ab3 100644
--- a/acts/framework/tests/controllers/sl4a_lib/rpc_client_test.py
+++ b/acts/framework/tests/controllers/sl4a_lib/rpc_client_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2018 - The Android Open Source Project
#
diff --git a/acts/framework/tests/controllers/sl4a_lib/rpc_connection_test.py b/acts/framework/tests/controllers/sl4a_lib/rpc_connection_test.py
index ce1d1a6..0190702 100755
--- a/acts/framework/tests/controllers/sl4a_lib/rpc_connection_test.py
+++ b/acts/framework/tests/controllers/sl4a_lib/rpc_connection_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
diff --git a/acts/framework/tests/controllers/sl4a_lib/sl4a_manager_test.py b/acts/framework/tests/controllers/sl4a_lib/sl4a_manager_test.py
index ded5f65..378eeae 100644
--- a/acts/framework/tests/controllers/sl4a_lib/sl4a_manager_test.py
+++ b/acts/framework/tests/controllers/sl4a_lib/sl4a_manager_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2018 - The Android Open Source Project
#
diff --git a/acts/framework/tests/controllers/sl4a_lib/sl4a_session_test.py b/acts/framework/tests/controllers/sl4a_lib/sl4a_session_test.py
index d16fb99..f056d2a 100644
--- a/acts/framework/tests/controllers/sl4a_lib/sl4a_session_test.py
+++ b/acts/framework/tests/controllers/sl4a_lib/sl4a_session_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2018 - The Android Open Source Project
#
diff --git a/acts/framework/tests/controllers/sl4a_lib/test_suite.py b/acts/framework/tests/controllers/sl4a_lib/test_suite.py
index add8d6c..3f87225 100755
--- a/acts/framework/tests/controllers/sl4a_lib/test_suite.py
+++ b/acts/framework/tests/controllers/sl4a_lib/test_suite.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2018 - The Android Open Source Project
#
@@ -13,21 +13,6 @@
# 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.
-#!/usr/bin/env python3.4
-#
-# Copyright 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.
import sys
import unittest
diff --git a/acts/framework/tests/libs/__init__.py b/acts/framework/tests/libs/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/acts/framework/tests/libs/__init__.py
diff --git a/acts/framework/tests/libs/ota/__init__.py b/acts/framework/tests/libs/ota/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/acts/framework/tests/libs/ota/__init__.py
diff --git a/acts/framework/tests/libs/ota/ota_runners/__init__.py b/acts/framework/tests/libs/ota/ota_runners/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/acts/framework/tests/libs/ota/ota_runners/__init__.py
diff --git a/acts/framework/tests/libs/ota/ota_runners/ota_runner_factory_test.py b/acts/framework/tests/libs/ota/ota_runners/ota_runner_factory_test.py
new file mode 100644
index 0000000..042f226
--- /dev/null
+++ b/acts/framework/tests/libs/ota/ota_runners/ota_runner_factory_test.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python3
+#
+# Copyright 2017 - 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 unittest
+
+import logging
+import mock
+
+from acts.controllers import android_device
+from acts.libs.ota.ota_runners import ota_runner
+from acts.libs.ota.ota_runners import ota_runner_factory
+from acts import config_parser
+
+
+class OtaRunnerFactoryTests(unittest.TestCase):
+ """Tests all of the functions in the ota_runner_factory module."""
+
+ def setUp(self):
+ self.device = mock.MagicMock()
+ self.device.serial = 'fake_serial'
+
+ def test_get_ota_value_from_config_no_map_key_missing(self):
+ acts_config = {}
+ with self.assertRaises(config_parser.ActsConfigError):
+ ota_runner_factory.get_ota_value_from_config(
+ acts_config, 'ota_tool', self.device)
+
+ def test_get_ota_value_from_config_with_map_key_missing(self):
+ acts_config = {'ota_map': {'fake_serial': 'MockOtaTool'}}
+ with self.assertRaises(config_parser.ActsConfigError):
+ ota_runner_factory.get_ota_value_from_config(
+ acts_config, 'ota_tool', self.device)
+
+ def test_get_ota_value_from_config_with_map_key_found(self):
+ expected_value = '/path/to/tool'
+ acts_config = {
+ 'ota_map': {
+ 'fake_serial': 'MockOtaTool'
+ },
+ 'ota_tool_MockOtaTool': expected_value
+ }
+ ret = ota_runner_factory.get_ota_value_from_config(
+ acts_config, 'ota_tool', self.device)
+ self.assertEqual(expected_value, ret)
+
+ def test_create_from_configs_raise_when_non_default_tool_path_missing(
+ self):
+ acts_config = {
+ 'ota_tool': 'FakeTool',
+ }
+ try:
+ ota_runner_factory.create_from_configs(acts_config, self.device)
+ except config_parser.ActsConfigError:
+ return
+ self.fail('create_from_configs did not throw an error when a tool was'
+ 'specified without a tool path.')
+
+ def test_create_from_configs_without_map_makes_proper_calls(self):
+ acts_config = {
+ 'ota_package': 'jkl;',
+ 'ota_sl4a': 'qaz',
+ 'ota_tool': 'FakeTool',
+ 'FakeTool': 'qwerty'
+ }
+ function_path = 'acts.libs.ota.ota_runners.ota_runner_factory.create'
+ with mock.patch(function_path) as mocked_function:
+ ota_runner_factory.create_from_configs(acts_config, self.device)
+ mocked_function.assert_called_with('jkl;', 'qaz', self.device,
+ 'FakeTool', 'qwerty')
+
+ def test_create_from_configs_with_map_makes_proper_calls(self):
+ acts_config = {
+ 'ota_map': {
+ 'fake_serial': "hardwareA"
+ },
+ 'ota_package_hardwareA': 'jkl;',
+ 'ota_sl4a_hardwareA': 'qaz',
+ 'ota_tool_hardwareA': 'FakeTool',
+ 'FakeTool': 'qwerty'
+ }
+ function_path = 'acts.libs.ota.ota_runners.ota_runner_factory.create'
+ with mock.patch(function_path) as mocked_function:
+ ota_runner_factory.create_from_configs(acts_config, self.device)
+ mocked_function.assert_called_with('jkl;', 'qaz', self.device,
+ 'FakeTool', 'qwerty')
+
+ def test_create_raise_on_ota_pkg_and_sl4a_fields_have_different_types(
+ self):
+ with mock.patch('acts.libs.ota.ota_tools.ota_tool_factory.create'):
+ with self.assertRaises(TypeError):
+ ota_runner_factory.create('ota_package', ['ota_sl4a'],
+ self.device)
+
+ def test_create_raise_on_ota_package_not_a_list_or_string(self):
+ with mock.patch('acts.libs.ota.ota_tools.ota_tool_factory.create'):
+ with self.assertRaises(TypeError):
+ ota_runner_factory.create({
+ 'ota': 'pkg'
+ }, {'ota': 'sl4a'}, self.device)
+
+ def test_create_returns_single_ota_runner_on_ota_package_being_a_str(self):
+ with mock.patch('acts.libs.ota.ota_tools.ota_tool_factory.create'):
+ ret = ota_runner_factory.create('', '', self.device)
+ self.assertEqual(type(ret), ota_runner.SingleUseOtaRunner)
+
+ def test_create_returns_multi_ota_runner_on_ota_package_being_a_list(self):
+ with mock.patch('acts.libs.ota.ota_tools.ota_tool_factory.create'):
+ ret = ota_runner_factory.create([], [], self.device)
+ self.assertEqual(type(ret), ota_runner.MultiUseOtaRunner)
+
+ def test_create_returns_bound_ota_runner_on_second_request(self):
+ with mock.patch('acts.libs.ota.ota_tools.ota_tool_factory.create'):
+ first_return = ota_runner_factory.create([], [], self.device)
+ logging.disable(logging.WARNING)
+ second_return = ota_runner_factory.create([], [], self.device)
+ logging.disable(logging.NOTSET)
+ self.assertEqual(first_return, second_return)
+
+ def test_create_returns_different_ota_runner_on_second_request(self):
+ with mock.patch('acts.libs.ota.ota_tools.ota_tool_factory.create'):
+ first_return = ota_runner_factory.create(
+ [], [], self.device, use_cached_runners=False)
+ second_return = ota_runner_factory.create(
+ [], [], self.device, use_cached_runners=False)
+ self.assertNotEqual(first_return, second_return)
diff --git a/acts/framework/tests/libs/ota/ota_runners/ota_runner_test.py b/acts/framework/tests/libs/ota/ota_runners/ota_runner_test.py
new file mode 100644
index 0000000..7acd6d6
--- /dev/null
+++ b/acts/framework/tests/libs/ota/ota_runners/ota_runner_test.py
@@ -0,0 +1,223 @@
+#!/usr/bin/env python3
+#
+# Copyright 2017 - 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 unittest
+import mock
+
+from acts.libs.ota.ota_tools import ota_tool
+from acts.libs.ota.ota_runners import ota_runner
+from acts.controllers import android_device
+
+
+class MockOtaTool(ota_tool.OtaTool):
+ def __init__(self, command):
+ super(MockOtaTool, self).__init__(command)
+ self.update_call_count = 0
+ self.cleanup_call_count = 0
+
+ def update(self, unused):
+ self.update_call_count += 1
+
+ def cleanup(self, unused):
+ self.cleanup_call_count += 1
+
+ def reset_count(self):
+ self.update_call_count = 0
+ self.cleanup_call_count = 0
+
+ def assert_calls_equal(self, test, number_of_expected_calls):
+ test.assertEqual(number_of_expected_calls, self.update_call_count)
+ test.assertEqual(number_of_expected_calls, self.cleanup_call_count)
+
+
+class OtaRunnerImpl(ota_runner.OtaRunner):
+ """Sets properties to return an empty string to allow OtaRunner tests."""
+
+ def get_sl4a_apk(self):
+ return ''
+
+ def get_ota_package(self):
+ return ''
+
+
+class OtaRunnerTest(unittest.TestCase):
+ """Tests the OtaRunner class."""
+
+ def setUp(self):
+ self.prev_sl4a_service_setup_time = ota_runner.SL4A_SERVICE_SETUP_TIME
+ ota_runner.SL4A_SERVICE_SETUP_TIME = 0
+
+ def tearDown(self):
+ ota_runner.SL4A_SERVICE_SETUP_TIME = self.prev_sl4a_service_setup_time
+
+ def test_update(self):
+ device = mock.MagicMock()
+ tool = MockOtaTool('mock_command')
+ runner = OtaRunnerImpl(tool, device)
+ runner.android_device.adb.getprop = mock.Mock(side_effect=['a', 'b'])
+ runner._update()
+ device.stop_services.assert_called()
+ device.wait_for_boot_completion.assert_called()
+ device.start_services.assert_called()
+ device.adb.install.assert_called()
+ tool.assert_calls_equal(self, 1)
+
+ def test_update_fail_on_no_change_to_build(self):
+ device = mock.MagicMock()
+ tool = MockOtaTool('mock_command')
+ runner = OtaRunnerImpl(tool, device)
+ runner.android_device.adb.getprop = mock.Mock(side_effect=['a', 'a'])
+ try:
+ runner._update()
+ self.fail('Matching build fingerprints did not throw an error!')
+ except ota_runner.OtaError:
+ pass
+
+ def test_init(self):
+ device = mock.MagicMock()
+ tool = MockOtaTool('mock_command')
+ runner = ota_runner.OtaRunner(tool, device)
+
+ self.assertEqual(runner.ota_tool, tool)
+ self.assertEqual(runner.android_device, device)
+ self.assertEqual(runner.serial, device.serial)
+
+
+class SingleUseOtaRunnerTest(unittest.TestCase):
+ """Tests the SingleUseOtaRunner class."""
+
+ def setUp(self):
+ self.device = mock.MagicMock()
+ self.tool = MockOtaTool('mock_command')
+
+ def test_update_first_update_runs(self):
+ runner = ota_runner.SingleUseOtaRunner(self.tool, self.device, '', '')
+ try:
+ with mock.patch.object(ota_runner.OtaRunner, '_update'):
+ runner.update()
+ except ota_runner.OtaError:
+ self.fail('SingleUseOtaRunner threw an exception on the first '
+ 'update call.')
+
+ def test_update_second_update_raises_error(self):
+ runner = ota_runner.SingleUseOtaRunner(self.tool, self.device, '', '')
+ with mock.patch.object(ota_runner.OtaRunner, '_update'):
+ runner.update()
+ try:
+ runner.update()
+ except ota_runner.OtaError:
+ return
+ self.fail('SingleUseOtaRunner did not throw an exception on the second'
+ 'update call.')
+
+ def test_can_update_no_updates_called(self):
+ runner = ota_runner.SingleUseOtaRunner(self.tool, self.device, '', '')
+ self.assertEqual(True, runner.can_update())
+
+ def test_can_update_has_updated_already(self):
+ runner = ota_runner.SingleUseOtaRunner(self.tool, self.device, '', '')
+ with mock.patch.object(ota_runner.OtaRunner, '_update'):
+ runner.update()
+ self.assertEqual(False, runner.can_update())
+
+ def test_get_ota_package(self):
+ runner = ota_runner.SingleUseOtaRunner(self.tool, self.device, 'a',
+ 'b')
+ self.assertEqual(runner.get_ota_package(), 'a')
+
+ def test_get_sl4a_apk(self):
+ runner = ota_runner.SingleUseOtaRunner(self.tool, self.device, 'a',
+ 'b')
+ self.assertEqual(runner.get_sl4a_apk(), 'b')
+
+
+class MultiUseOtaRunnerTest(unittest.TestCase):
+ """Tests the MultiUseOtaRunner class."""
+
+ def setUp(self):
+ self.device = mock.MagicMock()
+ self.tool = MockOtaTool('mock_command')
+
+ def test_update_first_update_runs(self):
+ runner = ota_runner.MultiUseOtaRunner(self.tool, self.device, [''],
+ [''])
+ try:
+ with mock.patch.object(ota_runner.OtaRunner, '_update'):
+ runner.update()
+ except ota_runner.OtaError:
+ self.fail('MultiUseOtaRunner threw an exception on the first '
+ 'update call.')
+
+ def test_update_multiple_updates_run(self):
+ runner = ota_runner.MultiUseOtaRunner(self.tool, self.device,
+ ['first_pkg', 'second_pkg'],
+ ['first_apk', 'second_apk'])
+ with mock.patch.object(ota_runner.OtaRunner, '_update'):
+ runner.update()
+ try:
+ runner.update()
+ except ota_runner.OtaError:
+ self.fail('MultiUseOtaRunner threw an exception before '
+ 'running out of update packages.')
+
+ def test_update_too_many_update_calls_raises_error(self):
+ runner = ota_runner.MultiUseOtaRunner(self.tool, self.device,
+ ['first_pkg', 'second_pkg'],
+ ['first_apk', 'second_apk'])
+ with mock.patch.object(ota_runner.OtaRunner, '_update'):
+ runner.update()
+ runner.update()
+ try:
+ runner.update()
+ except ota_runner.OtaError:
+ return
+ self.fail('MultiUseOtaRunner did not throw an exception after running '
+ 'out of update packages.')
+
+ def test_can_update_no_updates_called(self):
+ runner = ota_runner.MultiUseOtaRunner(self.tool, self.device,
+ ['first_pkg', 'second_pkg'],
+ ['first_apk', 'second_apk'])
+ self.assertEqual(True, runner.can_update())
+
+ def test_can_update_has_more_updates_left(self):
+ runner = ota_runner.MultiUseOtaRunner(self.tool, self.device,
+ ['first_pkg', 'second_pkg'],
+ ['first_apk', 'second_apk'])
+ with mock.patch.object(ota_runner.OtaRunner, '_update'):
+ runner.update()
+ self.assertEqual(True, runner.can_update())
+
+ def test_can_update_ran_out_of_updates(self):
+ runner = ota_runner.MultiUseOtaRunner(self.tool, self.device,
+ ['first_pkg', 'second_pkg'],
+ ['first_apk', 'second_apk'])
+ with mock.patch.object(ota_runner.OtaRunner, '_update'):
+ runner.update()
+ runner.update()
+ self.assertEqual(False, runner.can_update())
+
+ def test_get_ota_package(self):
+ runner = ota_runner.MultiUseOtaRunner(self.tool, self.device,
+ ['first_pkg', 'second_pkg'],
+ ['first_apk', 'second_apk'])
+ self.assertEqual(runner.get_ota_package(), 'first_pkg')
+
+ def test_get_sl4a_apk(self):
+ runner = ota_runner.MultiUseOtaRunner(self.tool, self.device,
+ ['first_pkg', 'second_pkg'],
+ ['first_apk', 'second_apk'])
+ self.assertEqual(runner.get_sl4a_apk(), 'first_apk')
diff --git a/acts/framework/tests/libs/ota/ota_tools/__init__.py b/acts/framework/tests/libs/ota/ota_tools/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/acts/framework/tests/libs/ota/ota_tools/__init__.py
diff --git a/acts/framework/tests/libs/ota/ota_tools/adb_sideload_ota_tool_test.py b/acts/framework/tests/libs/ota/ota_tools/adb_sideload_ota_tool_test.py
new file mode 100644
index 0000000..05c8aaf
--- /dev/null
+++ b/acts/framework/tests/libs/ota/ota_tools/adb_sideload_ota_tool_test.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+#
+# Copyright 2017 - 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 mock
+import unittest
+from acts.controllers import android_device
+from acts.libs.ota.ota_runners import ota_runner
+from acts.libs.ota.ota_tools import ota_tool
+from acts.libs.ota.ota_tools import adb_sideload_ota_tool
+
+
+def get_mock_android_device(serial='', ssh_connection=None):
+ """Returns a mocked AndroidDevice with a mocked adb/fastboot."""
+ with mock.patch('acts.controllers.adb.AdbProxy') as adb_proxy, (
+ mock.patch('acts.controllers.fastboot.FastbootProxy')) as fb_proxy:
+ fb_proxy.return_value.devices.return_value = ""
+ ret = mock.Mock(
+ android_device.AndroidDevice(
+ serial=serial, ssh_connection=ssh_connection))
+ fb_proxy.reset_mock()
+ return ret
+
+
+class AdbSideloadOtaToolTest(unittest.TestCase):
+ """Tests the OtaTool class."""
+
+ def test_init(self):
+ expected_value = 'commmand string'
+ self.assertEqual(
+ ota_tool.OtaTool(expected_value).command, expected_value)
+
+ def setUp(self):
+ self.sl4a_service_setup_time = ota_runner.SL4A_SERVICE_SETUP_TIME
+ ota_runner.SL4A_SERVICE_SETUP_TIME = 0
+
+ def tearDown(self):
+ ota_runner.SL4A_SERVICE_SETUP_TIME = self.sl4a_service_setup_time
+
+ @staticmethod
+ def test_start():
+ # This test could have a bunch of verify statements,
+ # but its probably not worth it.
+ device = get_mock_android_device()
+ tool = adb_sideload_ota_tool.AdbSideloadOtaTool('')
+ runner = ota_runner.SingleUseOtaRunner(tool, device, '', '')
+ runner.android_device.adb.getprop = mock.Mock(side_effect=['a', 'b'])
+ runner.update()
diff --git a/acts/framework/tests/libs/ota/ota_tools/ota_tool_factory_test.py b/acts/framework/tests/libs/ota/ota_tools/ota_tool_factory_test.py
new file mode 100644
index 0000000..9e15177
--- /dev/null
+++ b/acts/framework/tests/libs/ota/ota_tools/ota_tool_factory_test.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+#
+# Copyright 2017 - 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 unittest
+from acts.libs.ota.ota_tools import ota_tool_factory
+
+
+class MockOtaTool(object):
+ def __init__(self, command):
+ self.command = command
+
+
+class OtaToolFactoryTests(unittest.TestCase):
+ def setUp(self):
+ ota_tool_factory._constructed_tools = {}
+
+ def test_create_constructor_exists(self):
+ ota_tool_factory._CONSTRUCTORS = {
+ MockOtaTool.__name__: lambda command: MockOtaTool(command),
+ }
+ ret = ota_tool_factory.create(MockOtaTool.__name__, 'command')
+ self.assertEqual(type(ret), MockOtaTool)
+ self.assertTrue(ret in ota_tool_factory._constructed_tools.values())
+
+ def test_create_not_in_constructors(self):
+ ota_tool_factory._CONSTRUCTORS = {}
+ with self.assertRaises(KeyError):
+ ota_tool_factory.create(MockOtaTool.__name__, 'command')
+
+ def test_create_returns_cached_tool(self):
+ ota_tool_factory._CONSTRUCTORS = {
+ MockOtaTool.__name__: lambda command: MockOtaTool(command),
+ }
+ ret_a = ota_tool_factory.create(MockOtaTool.__name__, 'command')
+ ret_b = ota_tool_factory.create(MockOtaTool.__name__, 'command')
+ self.assertEqual(ret_a, ret_b)
diff --git a/acts/framework/tests/libs/ota/ota_tools/ota_tool_test.py b/acts/framework/tests/libs/ota/ota_tools/ota_tool_test.py
new file mode 100644
index 0000000..73ee599
--- /dev/null
+++ b/acts/framework/tests/libs/ota/ota_tools/ota_tool_test.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+#
+# Copyright 2017 - 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 unittest
+from acts.libs.ota.ota_tools import ota_tool
+
+
+class OtaToolTests(unittest.TestCase):
+ """Tests the OtaTool class."""
+
+ def test_init(self):
+ expected_value = 'commmand string'
+ self.assertEqual(
+ ota_tool.OtaTool(expected_value).command, expected_value)
+
+ def test_start_throws_error_on_unimplemented(self):
+ obj = 'some object'
+ with self.assertRaises(NotImplementedError):
+ ota_tool.OtaTool('').update(obj)
+
+ def test_end_is_not_abstract(self):
+ obj = 'some object'
+ try:
+ ota_tool.OtaTool('').cleanup(obj)
+ except:
+ self.fail('End is not required and should be a virtual function.')
diff --git a/acts/framework/tests/libs/ota/ota_tools/update_device_ota_tool_test.py b/acts/framework/tests/libs/ota/ota_tools/update_device_ota_tool_test.py
new file mode 100644
index 0000000..b541f43
--- /dev/null
+++ b/acts/framework/tests/libs/ota/ota_tools/update_device_ota_tool_test.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+#
+# Copyright 2017 - 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 mock
+import unittest
+from acts.controllers import android_device
+from acts.libs.ota.ota_runners import ota_runner
+from acts.libs.ota.ota_tools import update_device_ota_tool
+
+
+def get_mock_android_device(serial='', ssh_connection=None):
+ """Returns a mocked AndroidDevice with a mocked adb/fastboot."""
+ with mock.patch('acts.controllers.adb.AdbProxy') as adb_proxy, (
+ mock.patch('acts.controllers.fastboot.FastbootProxy')) as fb_proxy:
+ fb_proxy.return_value.devices.return_value = ""
+ ret = mock.Mock(
+ android_device.AndroidDevice(
+ serial=serial, ssh_connection=ssh_connection))
+ fb_proxy.reset_mock()
+ return ret
+
+
+class UpdateDeviceOtaToolTest(unittest.TestCase):
+ """Tests for UpdateDeviceOtaTool."""
+
+ def setUp(self):
+ self.sl4a_service_setup_time = ota_runner.SL4A_SERVICE_SETUP_TIME
+ ota_runner.SL4A_SERVICE_SETUP_TIME = 0
+
+ def tearDown(self):
+ ota_runner.SL4A_SERVICE_SETUP_TIME = self.sl4a_service_setup_time
+
+ def test_update(self):
+ with mock.patch('tempfile.mkdtemp') as mkdtemp, (
+ mock.patch('shutil.rmtree')) as rmtree, (
+ mock.patch('acts.utils.unzip_maintain_permissions')):
+ mkdtemp.return_value = ''
+ rmtree.return_value = ''
+ device = get_mock_android_device()
+ tool = update_device_ota_tool.UpdateDeviceOtaTool('')
+ runner = mock.Mock(
+ ota_runner.SingleUseOtaRunner(tool, device, '', ''))
+ runner.return_value.android_device = device
+ with mock.patch('acts.libs.proc.job.run'):
+ tool.update(runner)
+ del tool
+
+ def test_del(self):
+ with mock.patch('tempfile.mkdtemp') as mkdtemp, (
+ mock.patch('shutil.rmtree')) as rmtree, (
+ mock.patch('acts.utils.unzip_maintain_permissions')):
+ mkdtemp.return_value = ''
+ rmtree.return_value = ''
+ tool = update_device_ota_tool.UpdateDeviceOtaTool('')
+ del tool
+ self.assertTrue(mkdtemp.called)
+ self.assertTrue(rmtree.called)
diff --git a/acts/framework/tests/libs/ota/ota_updater_test.py b/acts/framework/tests/libs/ota/ota_updater_test.py
new file mode 100644
index 0000000..fff4136
--- /dev/null
+++ b/acts/framework/tests/libs/ota/ota_updater_test.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+#
+# Copyright 2017 - 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 mock
+import unittest
+from acts.libs.ota import ota_updater
+from acts.libs.ota.ota_runners import ota_runner
+
+
+class MockAndroidDevice(object):
+ def __init__(self, serial):
+ self.serial = serial
+
+
+class MockOtaRunner(object):
+ def __init__(self):
+ self.call_count = 0
+ self.should_fail = False
+ self.can_update_value = 'CAN_UPDATE_CALLED'
+
+ def set_failure(self, should_fail=True):
+ self.should_fail = should_fail
+
+ def update(self):
+ self.call_count += 1
+ if self.should_fail:
+ raise ota_runner.OtaError
+
+ def can_update(self):
+ return self.can_update_value
+
+
+class OtaUpdaterTests(unittest.TestCase):
+ """Tests the methods in the ota_updater module."""
+
+ def test_initialize(self):
+ user_params = {'a': 1, 'b': 2, 'c': 3}
+ android_devices = ['x', 'y', 'z']
+ with mock.patch('acts.libs.ota.ota_runners.ota_runner_factory.'
+ 'create_from_configs') as fn:
+ ota_updater.initialize(user_params, android_devices)
+ for i in range(len(android_devices)):
+ fn.assert_has_call(mock.call(user_params, android_devices[i]))
+ self.assertSetEqual(
+ set(android_devices), set(ota_updater.ota_runners.keys()))
+
+ def test_check_initialization_is_initialized(self):
+ device = MockAndroidDevice('serial')
+ ota_updater.ota_runners = {
+ device: ota_runner.OtaRunner('tool', device)
+ }
+ try:
+ ota_updater._check_initialization(device)
+ except ota_runner.OtaError:
+ self.fail('_check_initialization raised for initialized runner!')
+
+ def test_check_initialization_is_not_initialized(self):
+ device = MockAndroidDevice('serial')
+ ota_updater.ota_runners = {}
+ with self.assertRaises(KeyError):
+ ota_updater._check_initialization(device)
+
+ def test_update_do_not_ignore_failures_and_failures_occur(self):
+ device = MockAndroidDevice('serial')
+ runner = MockOtaRunner()
+ runner.set_failure(True)
+ ota_updater.ota_runners = {device: runner}
+ with self.assertRaises(ota_runner.OtaError):
+ ota_updater.update(device)
+
+ def test_update_ignore_failures_and_failures_occur(self):
+ device = MockAndroidDevice('serial')
+ runner = MockOtaRunner()
+ runner.set_failure(True)
+ ota_updater.ota_runners = {device: runner}
+ try:
+ ota_updater.update(device, ignore_update_errors=True)
+ except ota_runner.OtaError:
+ self.fail('OtaError was raised when errors are to be ignored!')
+
+ def test_can_update(self):
+ device = MockAndroidDevice('serial')
+ runner = MockOtaRunner()
+ ota_updater.ota_runners = {device: runner}
+ self.assertEqual(ota_updater.can_update(device), 'CAN_UPDATE_CALLED')
diff --git a/acts/framework/tests/libs/ota/unittest_bundle.py b/acts/framework/tests/libs/ota/unittest_bundle.py
new file mode 100755
index 0000000..e0019f1
--- /dev/null
+++ b/acts/framework/tests/libs/ota/unittest_bundle.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python3
+#
+# Copyright 2017 - 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 sys
+import unittest
+
+
+def main():
+ suite = unittest.TestLoader().discover(
+ start_dir='./acts/framework/tests/libs/ota', pattern='*_test.py')
+ return suite
+
+
+if __name__ == "__main__":
+ test_suite = main()
+ runner = unittest.TextTestRunner()
+ test_run = runner.run(test_suite)
+ sys.exit(not test_run.wasSuccessful())
diff --git a/acts/framework/tests/mock_controller.py b/acts/framework/tests/mock_controller.py
index a3893fd..65b2673 100644
--- a/acts/framework/tests/mock_controller.py
+++ b/acts/framework/tests/mock_controller.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3.4
+#!/usr/bin/env python3
#
# Copyright 2016 - The Android Open Source Project
#
diff --git a/acts/framework/tests/test_data/1k_2k.raw b/acts/framework/tests/test_data/1k_2k.raw
new file mode 100644
index 0000000..42e7ab9
--- /dev/null
+++ b/acts/framework/tests/test_data/1k_2k.raw
Binary files differ
diff --git a/acts/framework/tests/test_runner_test.py b/acts/framework/tests/test_runner_test.py
new file mode 100755
index 0000000..65f50c9
--- /dev/null
+++ b/acts/framework/tests/test_runner_test.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+#
+# Copyright 2017 - 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.
+
+from mock import Mock
+import unittest
+import tempfile
+
+from acts import keys
+from acts import test_runner
+
+import mock_controller
+
+
+class TestRunnerTest(unittest.TestCase):
+ def setUp(self):
+ self.tmp_dir = tempfile.mkdtemp()
+ self.base_mock_test_config = {
+ "testbed": {
+ "name": "SampleTestBed",
+ },
+ "logpath": self.tmp_dir,
+ "cli_args": None,
+ "testpaths": ["./"],
+ "icecream": 42,
+ "extra_param": "haha"
+ }
+
+ def create_mock_context(self):
+ context = Mock()
+ context.__exit__ = Mock()
+ context.__enter__ = Mock()
+ return context
+
+ def create_test_classes(self, class_names):
+ return {
+ class_name: Mock(return_value=self.create_mock_context())
+ for class_name in class_names
+ }
+
+ def test_class_name_pattern_single(self):
+ class_names = ['test_class_1', 'test_class_2']
+ pattern = 'test*1'
+ tr = test_runner.TestRunner(self.base_mock_test_config, [(pattern,
+ None)])
+
+ test_classes = self.create_test_classes(class_names)
+ tr.import_test_modules = Mock(return_value=test_classes)
+ tr.run()
+ self.assertTrue(test_classes[class_names[0]].called)
+ self.assertFalse(test_classes[class_names[1]].called)
+
+ def test_class_name_pattern_multi(self):
+ class_names = ['test_class_1', 'test_class_2', 'other_name']
+ pattern = 'test_class*'
+ tr = test_runner.TestRunner(self.base_mock_test_config, [(pattern,
+ None)])
+
+ test_classes = self.create_test_classes(class_names)
+ tr.import_test_modules = Mock(return_value=test_classes)
+ tr.run()
+ self.assertTrue(test_classes[class_names[0]].called)
+ self.assertTrue(test_classes[class_names[1]].called)
+ self.assertFalse(test_classes[class_names[2]].called)
+
+ def test_class_name_pattern_question_mark(self):
+ class_names = ['test_class_1', 'test_class_12']
+ pattern = 'test_class_?'
+ tr = test_runner.TestRunner(self.base_mock_test_config, [(pattern,
+ None)])
+
+ test_classes = self.create_test_classes(class_names)
+ tr.import_test_modules = Mock(return_value=test_classes)
+ tr.run()
+ self.assertTrue(test_classes[class_names[0]].called)
+ self.assertFalse(test_classes[class_names[1]].called)
+
+ def test_class_name_pattern_char_seq(self):
+ class_names = ['test_class_1', 'test_class_2', 'test_class_3']
+ pattern = 'test_class_[1357]'
+ tr = test_runner.TestRunner(self.base_mock_test_config, [(pattern,
+ None)])
+
+ test_classes = self.create_test_classes(class_names)
+ tr.import_test_modules = Mock(return_value=test_classes)
+ tr.run()
+ self.assertTrue(test_classes[class_names[0]].called)
+ self.assertFalse(test_classes[class_names[1]].called)
+ self.assertTrue(test_classes[class_names[2]].called)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/acts/tests/google/ble/concurrency/ConcurrentGattConnectTest.py b/acts/tests/google/ble/concurrency/ConcurrentGattConnectTest.py
new file mode 100644
index 0000000..c319a23
--- /dev/null
+++ b/acts/tests/google/ble/concurrency/ConcurrentGattConnectTest.py
@@ -0,0 +1,145 @@
+#/usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 for concurrent Gatt connections.
+Testbed assumes 6 Android devices. One will be the central and the rest
+peripherals.
+"""
+
+from queue import Empty
+import time
+from acts.test_utils.bt.bt_gatt_utils import setup_gatt_connection
+from acts.test_utils.bt.bt_constants import ble_scan_settings_modes
+from acts.test_utils.bt.bt_constants import ble_advertise_settings_modes
+from acts.test_utils.bt.bt_constants import bt_profile_constants
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
+
+
+class ConcurrentGattConnectTest(BluetoothBaseTest):
+ bt_default_timeout = 10
+ max_connections = 5
+
+ def __init__(self, controllers):
+ BluetoothBaseTest.__init__(self, controllers)
+ self.pri_dut = self.android_devices[0]
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='6638282c-69b5-4237-9f0d-18e131424a9f')
+ def test_concurrent_gatt_connections(self):
+ """Test max concurrent GATT connections
+
+ Connect to all peripherals.
+
+ Steps:
+ 1. Scan
+ 2. Save addresses
+ 3. Connect all addresses of the peripherals
+
+ Expected Result:
+ All connections successful.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: Bluetooth, GATT
+ Priority: 2
+ """
+ # Create 4 advertisements from different android devices
+ # List of tuples (android_device, advertise_callback)
+ advertise_callbacks = []
+ # List of tuples (android_deivce, gatt_server_callback)
+ gatt_server_callbacks = []
+ # List of tubles (android_device, gatt_server)
+ gatt_servers = []
+ advertisement_names = []
+ for i in range(1, self.max_connections + 1):
+ # Set device name
+ ad = self.android_devices[i]
+ name = "test_adv_{}".format(i)
+ advertisement_names.append(name)
+ ad.droid.bluetoothSetLocalName(name)
+
+ # Setup and start advertisements
+ ad.droid.bleSetAdvertiseDataIncludeDeviceName(True)
+ ad.droid.bleSetAdvertiseSettingsAdvertiseMode(
+ ble_advertise_settings_modes['low_latency'])
+ advertise_data = ad.droid.bleBuildAdvertiseData()
+ advertise_settings = ad.droid.bleBuildAdvertiseSettings()
+ advertise_callback = ad.droid.bleGenBleAdvertiseCallback()
+ ad.droid.bleStartBleAdvertising(advertise_callback, advertise_data,
+ advertise_settings)
+ advertise_callbacks.append((ad, advertise_callback))
+ # Setup generic Gatt server
+ gatt_server_callback = ad.droid.gattServerCreateGattServerCallback(
+ )
+ gatt_server_callbacks.append((ad, gatt_server_callback))
+ gatt_server = ad.droid.gattServerOpenGattServer(
+ gatt_server_callback)
+ gatt_servers.append((ad, gatt_server))
+
+ # From central device, scan for all appropriate addresses by name
+ filter_list = self.pri_dut.droid.bleGenFilterList()
+ self.pri_dut.droid.bleSetScanSettingsScanMode(
+ ble_scan_settings_modes['low_latency'])
+ scan_settings = self.pri_dut.droid.bleBuildScanSetting()
+ scan_callback = self.pri_dut.droid.bleGenScanCallback()
+ for name in advertisement_names:
+ self.pri_dut.droid.bleSetScanFilterDeviceName(name)
+ self.pri_dut.droid.bleBuildScanFilter(filter_list)
+ self.pri_dut.droid.bleStartBleScan(filter_list, scan_settings,
+ scan_callback)
+ address_list = []
+ scan_timeout = 20
+ end_time = time.time() + scan_timeout
+ while time.time() < end_time and len(address_list) < len(
+ self.android_devices) - 1:
+ try:
+ event = self.pri_dut.ed.pop_event(
+ "BleScan{}onScanResults".format(scan_callback),
+ self.bt_default_timeout)
+ mac_address = event['data']['Result']['deviceInfo']['address']
+ if mac_address not in address_list:
+ self.log.info(
+ "Found new mac address: {}".format(mac_address))
+ address_list.append(mac_address)
+ except Empty as err:
+ self.log.error("Failed to find any scan results.")
+ return False
+ if len(address_list) < self.max_connections:
+ self.log.error("Could not find all necessary advertisements.")
+ return False
+
+ # Connect to all addresses
+ for address in address_list:
+ try:
+ autoconnect = False
+ bluetooth_gatt, gatt_callback = setup_gatt_connection(
+ self.pri_dut, address, autoconnect)
+ self.log.info("Successfully connected to {}".format(address))
+ except Exception as err:
+ self.log.error(
+ "Failed to establish connection to {}".format(address))
+ return False
+ if (len(
+ self.pri_dut.droid.bluetoothGetConnectedLeDevices(
+ bt_profile_constants['gatt_server'])) !=
+ self.max_connections):
+ self.log.error("Did not reach max connection count.")
+ return False
+
+ return True
diff --git a/acts/tests/google/ble/conn_oriented_chan/BleCoc2ConnTest.py b/acts/tests/google/ble/conn_oriented_chan/BleCoc2ConnTest.py
new file mode 100644
index 0000000..ed7bff5
--- /dev/null
+++ b/acts/tests/google/ble/conn_oriented_chan/BleCoc2ConnTest.py
@@ -0,0 +1,477 @@
+#/usr/bin/env python3.4
+#
+# Copyright 2017 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 execute Bluetooth Connection-orient Channel (CoC) functionality for
+2 connections test cases. This test was designed to be run in a shield box.
+"""
+
+import threading
+import time
+
+from queue import Empty
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
+from acts.test_utils.bt.bt_coc_test_utils import orchestrate_coc_connection
+from acts.test_utils.bt.bt_coc_test_utils import do_multi_connection_throughput
+from acts.test_utils.bt.bt_constants import default_le_data_length
+from acts.test_utils.bt.bt_constants import l2cap_coc_header_size
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.bt.bt_test_utils import kill_bluetooth_process
+from acts.test_utils.bt.bt_test_utils import reset_bluetooth
+from acts.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
+from acts.test_utils.bt.bt_test_utils import take_btsnoop_logs
+from acts.test_utils.bt.bt_test_utils import write_read_verify_data
+from acts.test_utils.bt.bt_test_utils import verify_server_and_client_connected
+
+
+class BleCoc2ConnTest(BluetoothBaseTest):
+ def __init__(self, controllers):
+ BluetoothBaseTest.__init__(self, controllers)
+ self.client_ad = self.android_devices[0]
+ self.server_ad = self.android_devices[1]
+ # Note that some tests required a third device.
+ if len(self.android_devices) > 2:
+ self.server2_ad = self.android_devices[2]
+
+ def setup_class(self):
+ return setup_multiple_devices_for_bt_test(self.android_devices)
+
+ def teardown_test(self):
+ self.client_ad.droid.bluetoothSocketConnStop()
+ self.server_ad.droid.bluetoothSocketConnStop()
+
+ def _run_coc_connection_throughput_2_conn(
+ self,
+ is_secured,
+ buffer_size,
+ le_connection_interval=0,
+ le_tx_data_length=default_le_data_length):
+
+ # The num_iterations is that number of repetitions of each
+ # set of buffers r/w.
+ # number_buffers is the total number of data buffers to transmit per
+ # set of buffers r/w.
+ # buffer_size is the number of bytes per L2CAP data buffer.
+ num_iterations = 10
+ number_buffers = 100
+ # Note: A 117 octets buffer size would fix nicely to a 123 bytes Data Length
+ buffer_size = 117
+
+ # Make sure at least 3 phones are setup
+ if len(self.android_devices) <= 2:
+ self.log.info("test_coc_connection_throughput_2_conn: "
+ "Error: 3rd phone not configured in file")
+ return False
+
+ self.log.info(
+ "_run_coc_connection_throughput_2_conn: is_secured={}, Interval={}, buffer_size={}, "
+ "le_tx_data_length={}".format(is_secured, le_connection_interval,
+ buffer_size, le_tx_data_length))
+ status, client_conn_id1, server_conn_id1 = orchestrate_coc_connection(
+ self.client_ad, self.server_ad, True, is_secured,
+ le_connection_interval, le_tx_data_length)
+ if not status:
+ return False
+
+ status, client_conn_id2, server_conn_id2 = orchestrate_coc_connection(
+ self.client_ad, self.server2_ad, True, is_secured,
+ le_connection_interval, le_tx_data_length)
+ if not status:
+ return False
+
+ list_server_ad = [self.server_ad, self.server2_ad]
+ list_client_conn_id = [client_conn_id1, client_conn_id2]
+ data_rate = do_multi_connection_throughput(
+ self.client_ad, list_server_ad, list_client_conn_id,
+ num_iterations, number_buffers, buffer_size)
+ if data_rate <= 0:
+ return False
+
+ self.log.info(
+ "test_coc_connection_throughput_2_conn: throughput=%d bytes per "
+ "sec", data_rate)
+
+ self.client_ad.droid.bluetoothSocketConnStop(client_conn_id1)
+ self.client_ad.droid.bluetoothSocketConnStop(client_conn_id2)
+ self.server_ad.droid.bluetoothSocketConnStop(server_conn_id1)
+ self.server2_ad.droid.bluetoothSocketConnStop(server_conn_id2)
+ return True
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='27226006-b725-4312-920e-6193cf0539d4')
+ def test_coc_insecured_connection_throughput_2_conn(self):
+ """Test LE CoC data throughput on two insecured connections
+
+ Test Data Throughput of 2 L2CAP CoC insecured connections.
+ 3 phones are required.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish a L2CAP CoC connection from the client to the server#1 AD.
+ The connection is insecured.
+ 3. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 4. Establish a L2CAP CoC connection from the client to the server#2 AD.
+ The connection is insecured.
+ 5. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 6. Write data from the client to both server#1 and server#2.
+ 7. Verify data matches from client and server
+
+ Expected Result:
+ L2CAP CoC connections are established and data written correctly to both servers.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 2
+ """
+
+ # Note: A 117 octets buffer size would fix nicely to a 123 bytes Data Length
+ status = self._run_coc_connection_throughput_2_conn(False, 117)
+ return status
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='1a5fb032-8a27-42f1-933f-3e39311c09a6')
+ def test_coc_secured_connection_throughput_2_conn(self):
+ """Test LE CoC data throughput on two secured connections
+
+ Test Data Throughput of 2 L2CAP CoC secured connections.
+ 3 phones are required.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish a L2CAP CoC connection from the client to the server#1 AD.
+ The connection is secured.
+ 3. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 4. Establish a L2CAP CoC connection from the client to the server#2 AD.
+ The connection is secured.
+ 5. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 6. Write data from the client to both server#1 and server#2.
+ 7. Verify data matches from client and server
+
+ Expected Result:
+ L2CAP CoC connections are established and data written correctly to both servers.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 2
+ """
+
+ # Note: A 117 octets buffer size would fix nicely to a 123 bytes Data Length
+ status = self._run_coc_connection_throughput_2_conn(True, 117)
+ return status
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='b198f8cc-26af-44bd-bb4d-7dc8f8645617')
+ def test_coc_connection_throughput_2_conn_NOSEC_10CI_60SIZE(self):
+ """Test LE CoC data throughput with 10msec CI and 60bytes buffer size.
+
+ Test data throughput of 2 L2CAP CoC insecured connections with 20msec connection interval
+ and 60 bytes buffer size. 3 phones are required.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish a L2CAP CoC connection from the client to the server#1 AD.
+ The connection is insecured.
+ 3. Set the connection interval to 20 msec and buffer size to 60 bytes.
+ 4. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 5. Establish a L2CAP CoC connection from the client to the server#2 AD.
+ The connection is insecured.
+ 6. Set the connection interval to 20 msec and buffer size to 60 bytes.
+ 7. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 8. Write data from the client to both server#1 and server#2.
+ 9. Verify data matches from client and server
+
+ Expected Result:
+ L2CAP CoC connections are established and data written correctly to both servers.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 1
+ """
+
+ is_secured = False
+ le_connection_interval = 10
+ buffer_size = 60
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ status = self._run_coc_connection_throughput_2_conn(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+ return status
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='12dc2a6c-8283-4617-a911-42335dd693a8')
+ def test_coc_connection_throughput_2_conn_NOSEC_10CI_80SIZE(self):
+ """Test LE CoC data throughput with 10msec CI and 80bytes buffer size.
+
+ Test data throughput of 2 L2CAP CoC insecured connections with 20msec connection interval
+ and 80 bytes buffer size. 3 phones are required.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish a L2CAP CoC connection from the client to the server#1 AD.
+ The connection is insecured.
+ 3. Set the connection interval to 20 msec and buffer size to 80 bytes.
+ 4. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 5. Establish a L2CAP CoC connection from the client to the server#2 AD.
+ The connection is insecured.
+ 6. Set the connection interval to 20 msec and buffer size to 80 bytes.
+ 7. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 8. Write data from the client to both server#1 and server#2.
+ 9. Verify data matches from client and server
+
+ Expected Result:
+ L2CAP CoC connections are established and data written correctly to both servers.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 1
+ """
+
+ is_secured = False
+ le_connection_interval = 10
+ buffer_size = 80
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ status = self._run_coc_connection_throughput_2_conn(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+ return status
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='4730df05-3909-4adf-a365-7f0c3258c402')
+ def test_coc_connection_throughput_2_conn_NOSEC_10CI_120SIZE(self):
+ """Test LE CoC data throughput with 10msec CI and 120bytes buffer size.
+
+ Test data throughput of 2 L2CAP CoC insecured connections with 20msec connection interval
+ and 120 bytes buffer size. 3 phones are required.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish a L2CAP CoC connection from the client to the server#1 AD.
+ The connection is insecured.
+ 3. Set the connection interval to 20 msec and buffer size to 120 bytes.
+ 4. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 5. Establish a L2CAP CoC connection from the client to the server#2 AD.
+ The connection is insecured.
+ 6. Set the connection interval to 20 msec and buffer size to 120 bytes.
+ 7. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 8. Write data from the client to both server#1 and server#2.
+ 9. Verify data matches from client and server
+
+ Expected Result:
+ L2CAP CoC connections are established and data written correctly to both servers.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 1
+ """
+
+ is_secured = False
+ le_connection_interval = 10
+ buffer_size = 120
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ status = self._run_coc_connection_throughput_2_conn(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+ return status
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='471a8748-b0a5-4be5-9322-7c75e2b5d048')
+ def test_coc_connection_throughput_2_conn_NOSEC_15CI_120SIZE(self):
+ """Test LE CoC data throughput with 15msec CI and 120bytes buffer size.
+
+ Test data throughput of 2 L2CAP CoC insecured connections with 15msec connection interval
+ and 120 bytes buffer size. 3 phones are required.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish a L2CAP CoC connection from the client to the server#1 AD.
+ The connection is insecured.
+ 3. Set the connection interval to 15 msec and buffer size to 120 bytes.
+ 4. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 5. Establish a L2CAP CoC connection from the client to the server#2 AD.
+ The connection is insecured.
+ 6. Set the connection interval to 15 msec and buffer size to 120 bytes.
+ 7. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 8. Write data from the client to both server#1 and server#2.
+ 9. Verify data matches from client and server
+
+ Expected Result:
+ L2CAP CoC connections are established and data written correctly to both servers.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 1
+ """
+
+ is_secured = False
+ le_connection_interval = 15
+ buffer_size = 120
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ status = self._run_coc_connection_throughput_2_conn(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+ return status
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='053e59c2-f312-4bec-beaf-9e4efdce063a')
+ def test_coc_connection_throughput_2_conn_NOSEC_15CI_180SIZE(self):
+ """Test LE CoC data throughput with 15msec CI and 180bytes buffer size.
+
+ Test data throughput of 2 L2CAP CoC insecured connections with 15msec connection interval
+ and 120 bytes buffer size. 3 phones are required.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish a L2CAP CoC connection from the client to the server#1 AD.
+ The connection is insecured.
+ 3. Set the connection interval to 15 msec and buffer size to 180 bytes.
+ 4. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 5. Establish a L2CAP CoC connection from the client to the server#2 AD.
+ The connection is insecured.
+ 6. Set the connection interval to 15 msec and buffer size to 180 bytes.
+ 7. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 8. Write data from the client to both server#1 and server#2.
+ 9. Verify data matches from client and server
+
+ Expected Result:
+ L2CAP CoC connections are established and data written correctly to both servers.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 1
+ """
+
+ is_secured = False
+ le_connection_interval = 15
+ buffer_size = 180
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ status = self._run_coc_connection_throughput_2_conn(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+ return status
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='2b43caa6-76b3-48c5-b342-32ebb31ac52c')
+ def test_coc_connection_throughput_2_conn_NOSEC_20CI_240SIZE(self):
+ """Test LE CoC data throughput with 20msec CI and 240bytes buffer size.
+
+ Test data throughput of 2 L2CAP CoC insecured connections with 20msec connection interval
+ and 240 bytes buffer size. 3 phones are required.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish a L2CAP CoC connection from the client to the server#1 AD.
+ The connection is insecured.
+ 3. Set the connection interval to 20 msec and buffer size to 240 bytes.
+ 4. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 5. Establish a L2CAP CoC connection from the client to the server#2 AD.
+ The connection is insecured.
+ 6. Set the connection interval to 20 msec and buffer size to 240 bytes.
+ 7. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 8. Write data from the client to both server#1 and server#2.
+ 9. Verify data matches from client and server
+
+ Expected Result:
+ L2CAP CoC connections are established and data written correctly to both servers.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 1
+ """
+
+ is_secured = False
+ le_connection_interval = 20
+ buffer_size = 240
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ status = self._run_coc_connection_throughput_2_conn(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+ return status
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='f630df02-3fd6-4aa0-bc15-06837b705e97')
+ def test_coc_connection_throughput_2_conn_NOSEC_30CI_240SIZE(self):
+ """Test LE CoC data throughput with 30msec CI and 240bytes buffer size.
+
+ Test data throughput of 2 L2CAP CoC insecured connections with 20msec connection interval
+ and 240 bytes buffer size. 3 phones are required.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish a L2CAP CoC connection from the client to the server#1 AD.
+ The connection is insecured.
+ 3. Set the connection interval to 30 msec and buffer size to 240 bytes.
+ 4. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 5. Establish a L2CAP CoC connection from the client to the server#2 AD.
+ The connection is insecured.
+ 6. Set the connection interval to 30 msec and buffer size to 240 bytes.
+ 7. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 8. Write data from the client to both server#1 and server#2.
+ 9. Verify data matches from client and server
+
+ Expected Result:
+ L2CAP CoC connections are established and data written correctly to both servers.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 2
+ """
+
+ is_secured = False
+ le_connection_interval = 30
+ buffer_size = 240
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ status = self._run_coc_connection_throughput_2_conn(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+ return status
diff --git a/acts/tests/google/ble/conn_oriented_chan/BleCocTest.py b/acts/tests/google/ble/conn_oriented_chan/BleCocTest.py
new file mode 100644
index 0000000..1c2e7e3
--- /dev/null
+++ b/acts/tests/google/ble/conn_oriented_chan/BleCocTest.py
@@ -0,0 +1,581 @@
+#/usr/bin/env python3.4
+#
+# Copyright 2017 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 execute Bluetooth Connection-orient Channel (CoC) functionality
+test cases. This test was designed to be run in a shield box.
+"""
+
+import threading
+import time
+
+from queue import Empty
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
+from acts.test_utils.bt.bt_coc_test_utils import orchestrate_coc_connection
+from acts.test_utils.bt.bt_coc_test_utils import do_multi_connection_throughput
+from acts.test_utils.bt.bt_constants import default_le_data_length
+from acts.test_utils.bt.bt_constants import l2cap_coc_header_size
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.bt.bt_test_utils import kill_bluetooth_process
+from acts.test_utils.bt.bt_test_utils import reset_bluetooth
+from acts.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
+from acts.test_utils.bt.bt_test_utils import take_btsnoop_logs
+from acts.test_utils.bt.bt_test_utils import write_read_verify_data
+from acts.test_utils.bt.bt_test_utils import verify_server_and_client_connected
+
+
+class BleCocTest(BluetoothBaseTest):
+ message = (
+ "Space: the final frontier. These are the voyages of "
+ "the starship Enterprise. Its continuing mission: to explore "
+ "strange new worlds, to seek out new life and new civilizations,"
+ " to boldly go where no man has gone before.")
+
+ def __init__(self, controllers):
+ BluetoothBaseTest.__init__(self, controllers)
+ self.client_ad = self.android_devices[0]
+ self.server_ad = self.android_devices[1]
+ # Note that some tests required a third device.
+ if len(self.android_devices) > 2:
+ self.server2_ad = self.android_devices[2]
+
+ def setup_class(self):
+ return setup_multiple_devices_for_bt_test(self.android_devices)
+
+ def teardown_test(self):
+ self.client_ad.droid.bluetoothSocketConnStop()
+ self.server_ad.droid.bluetoothSocketConnStop()
+
+ def _run_coc_connection_throughput(
+ self,
+ is_secured,
+ buffer_size,
+ le_connection_interval=0,
+ le_tx_data_length=default_le_data_length):
+
+ # The num_iterations is that number of repetitions of each
+ # set of buffers r/w.
+ # number_buffers is the total number of data buffers to transmit per
+ # set of buffers r/w.
+ # buffer_size is the number of bytes per L2CAP data buffer.
+ number_buffers = 100
+ num_iterations = 10
+
+ self.log.info(
+ "_run_coc_connection_throughput: calling "
+ "orchestrate_coc_connection. is_secured={}, Connection Interval={}msec, "
+ "buffer_size={}bytes".format(is_secured, le_connection_interval,
+ buffer_size))
+ status, client_conn_id, server_conn_id = orchestrate_coc_connection(
+ self.client_ad, self.server_ad, True, is_secured,
+ le_connection_interval, le_tx_data_length)
+ if not status:
+ return False
+
+ list_server_ad = [self.server_ad]
+ list_client_conn_id = [client_conn_id]
+ data_rate = do_multi_connection_throughput(
+ self.client_ad, list_server_ad, list_client_conn_id,
+ num_iterations, number_buffers, buffer_size)
+ if data_rate <= 0:
+ return False
+ self.log.info(
+ "_run_coc_connection_throughput: throughput=%d bytes per sec",
+ data_rate)
+
+ return True
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='b6989966-c504-4934-bcd7-57fb4f7fde9c')
+ def test_coc_secured_connection(self):
+ """Test Bluetooth LE CoC secured connection
+
+ Test LE CoC though establishing a basic connection with security.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish an LE CoC Secured connection from the client to the server AD.
+ 3. Verify that the LE CoC connection is active from both the client and
+ server.
+ Expected Result:
+ LE CoC connection is established then disconnected succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 1
+ """
+ is_secured = True
+ self.log.info(
+ "_test_coc_secured_connection: calling orchestrate_coc_connection but "
+ "isBle=1 and securedConn={}".format(is_secured))
+ status, client_conn_id, server_conn_id = orchestrate_coc_connection(
+ self.client_ad, self.server_ad, True, is_secured)
+ if not status:
+ return False
+
+ return True
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='6587792c-78fb-469f-9084-772c249f97de')
+ def test_coc_insecured_connection(self):
+ """Test Bluetooth LE CoC insecured connection
+
+ Test LE CoC though establishing a basic connection with no security.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish an LE CoC Secured connection from the client to the server AD.
+ 3. Verify that the LE CoC connection is active from both the client and
+ server.
+ Expected Result:
+ LE CoC connection is established then disconnected succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 1
+ """
+ is_secured = False
+ self.log.info(
+ "test_coc_insecured_connection: calling orchestrate_coc_connection but "
+ "isBle=1 and securedConn={}".format(is_secured))
+ status, client_conn_id, server_conn_id = orchestrate_coc_connection(
+ self.client_ad, self.server_ad, True, is_secured)
+ if not status:
+ return False
+
+ return True
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='32a7b02e-f2b5-4193-b414-36c8815ac407')
+ def test_coc_secured_connection_write_ascii(self):
+ """Test LE CoC secured connection writing and reading ascii data
+
+ Test LE CoC though establishing a secured connection and reading and writing ascii data.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish an LE CoC connection from the client to the server AD. The security of
+ connection is TRUE.
+ 3. Verify that the LE CoC connection is active from both the client and
+ server.
+ 4. Write data from the client and read received data from the server.
+ 5. Verify data matches from client and server
+ 6. Disconnect the LE CoC connection.
+
+ Expected Result:
+ LE CoC connection is established then disconnected succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 1
+ """
+ is_secured = True
+ self.log.info(
+ "test_coc_secured_connection_write_ascii: calling "
+ "orchestrate_coc_connection. is_secured={}".format(is_secured))
+ status, client_conn_id, server_conn_id = orchestrate_coc_connection(
+ self.client_ad, self.server_ad, True, is_secured)
+ if not status:
+ return False
+ if not write_read_verify_data(self.client_ad, self.server_ad,
+ self.message, False):
+ return False
+ if not verify_server_and_client_connected(self.client_ad,
+ self.server_ad):
+ return False
+
+ return True
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='12537d27-79c9-40a0-8bdb-d023b0e36b58')
+ def test_coc_insecured_connection_write_ascii(self):
+ """Test LE CoC insecured connection writing and reading ascii data
+
+ Test LE CoC though establishing a connection.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish an LE CoC connection from the client to the server AD. The security of
+ connection is FALSE.
+ 3. Verify that the LE CoC connection is active from both the client and
+ server.
+ 4. Write data from the client and read received data from the server.
+ 5. Verify data matches from client and server
+ 6. Disconnect the LE CoC connection.
+
+ Expected Result:
+ LE CoC connection is established then disconnected succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 1
+ """
+ is_secured = False
+ self.log.info(
+ "test_coc_secured_connection_write_ascii: calling "
+ "orchestrate_coc_connection. is_secured={}".format(is_secured))
+ status, client_conn_id, server_conn_id = orchestrate_coc_connection(
+ self.client_ad, self.server_ad, True, is_secured)
+ if not status:
+ return False
+ if not write_read_verify_data(self.client_ad, self.server_ad,
+ self.message, False):
+ return False
+ if not verify_server_and_client_connected(self.client_ad,
+ self.server_ad):
+ return False
+
+ return True
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='214037f4-f0d1-47db-86a7-5230c71bdcac')
+ def test_coc_secured_connection_throughput(self):
+ """Test LE CoC writing and measured data throughput with security
+
+ Test CoC thoughput by establishing a secured connection and sending data.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish a L2CAP CoC connection from the client to the server AD.
+ 3. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 4. Write data from the client to server.
+ 5. Verify data matches from client and server
+ 6. Disconnect the L2CAP CoC connections.
+
+ Expected Result:
+ CoC connection is established then disconnected succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 1
+ """
+
+ is_secured = True
+ # Note: A 117 octets buffer size would fix nicely to a 123 bytes Data Length
+ return self._run_coc_connection_throughput(is_secured, 117)
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='6dc019bb-c3bf-4c98-978e-e2c5755058d7')
+ def test_coc_insecured_connection_throughput(self):
+ """Test LE CoC writing and measured data throughput without security.
+
+ Test CoC thoughput by establishing an insecured connection and sending data.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Establish a L2CAP CoC connection from the client to the server AD.
+ 3. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 4. Write data from the client to server.
+ 5. Verify data matches from client and server
+ 6. Disconnect the L2CAP CoC connections.
+
+ Expected Result:
+ CoC connection is established then disconnected succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 1
+ """
+
+ is_secured = False
+ # Note: A 117 octets buffer size would fix nicely to a 123 bytes Data Length
+ return self._run_coc_connection_throughput(is_secured, 117)
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='0af94805-1550-426c-bfdd-191b8b3a4c12')
+ def test_coc_connection_throughput_NOSEC_10CI_60SIZE(self):
+ """Test LE CoC data throughput with 10msec CI and 60bytes buffer size.
+
+ Test CoC thoughput by establishing a connection and sending data with 10msec
+ Connection Interval and 60 bytes data buffer size.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Change the Connection Interval to 10msec.
+ 3. Change Payload Buffer Size to 60 bytes.
+ 4. Establish a L2CAP CoC connection from the client to the server AD.
+ 5. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 6. Write data from the client to server.
+ 7. Verify data matches from client and server
+ 8. Disconnect the L2CAP CoC connections.
+
+ Expected Result:
+ CoC connection is established, check transmitted data contents, then disconnected
+ succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 2
+ """
+
+ is_secured = False
+ le_connection_interval = 10
+ buffer_size = 60
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ return self._run_coc_connection_throughput(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='c32dac07-623a-4fdd-96c6-387a76afb2af')
+ def test_coc_connection_throughput_NOSEC_10CI_80SIZE(self):
+ """Test LE CoC data throughput with 10msec CI and 80bytes buffer size.
+
+ Test CoC thoughput by establishing a connection and sending data with 10msec
+ Connection Interval and 80 bytes data buffer size.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Change the Connection Interval to 10msec.
+ 3. Change Payload Buffer Size to 80 bytes.
+ 4. Establish a L2CAP CoC connection from the client to the server AD.
+ 5. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 6. Write data from the client to server.
+ 7. Verify data matches from client and server
+ 8. Disconnect the L2CAP CoC connections.
+
+ Expected Result:
+ CoC connection is established, check transmitted data contents, then disconnected
+ succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 2
+ """
+
+ is_secured = False
+ le_connection_interval = 10
+ buffer_size = 80
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ return self._run_coc_connection_throughput(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='45d1b0c1-73b6-483f-ac6b-c3cec805da32')
+ def test_coc_connection_throughput_NOSEC_10CI_120SIZE(self):
+ """Test LE CoC data throughput with 10msec CI and 120bytes buffer size.
+
+ Test CoC thoughput by establishing a connection and sending data with 10msec
+ Connection Interval and 120 bytes data buffer size.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Change the Connection Interval to 10msec.
+ 3. Change Payload Buffer Size to 120 bytes.
+ 4. Establish a L2CAP CoC connection from the client to the server AD.
+ 5. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 6. Write data from the client to server.
+ 7. Verify data matches from client and server
+ 8. Disconnect the L2CAP CoC connections.
+
+ Expected Result:
+ CoC connection is established, check transmitted data contents, then disconnected
+ succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 2
+ """
+
+ is_secured = False
+ le_connection_interval = 10
+ buffer_size = 120
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ return self._run_coc_connection_throughput(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='85f07f07-1017-42db-b38d-df0bf2fce804')
+ def test_coc_connection_throughput_NOSEC_15CI_120SIZE(self):
+ """Test LE CoC data throughput with 15msec CI and 120bytes buffer size.
+
+ Test CoC thoughput by establishing a connection and sending data with 15msec
+ Connection Interval and 120 bytes data buffer size.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Change the Connection Interval to 15msec.
+ 3. Change Payload Buffer Size to 120 bytes.
+ 4. Establish a L2CAP CoC connection from the client to the server AD.
+ 5. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 6. Write data from the client to server.
+ 7. Verify data matches from client and server
+ 8. Disconnect the L2CAP CoC connections.
+
+ Expected Result:
+ CoC connection is established, check transmitted data contents, then disconnected
+ succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 2
+ """
+
+ is_secured = False
+ le_connection_interval = 15
+ buffer_size = 120
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ return self._run_coc_connection_throughput(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='4d3d4a06-7bbb-4a8c-9016-f326560cebb0')
+ def test_coc_connection_throughput_NOSEC_15CI_180SIZE(self):
+ """Test LE CoC data throughput with 15msec CI and 180bytes buffer size.
+
+ Test CoC thoughput by establishing a connection and sending data with 15msec
+ Connection Interval and 180 bytes data buffer size.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Change the Connection Interval to 15msec.
+ 3. Change Payload Buffer Size to 180 bytes.
+ 4. Establish a L2CAP CoC connection from the client to the server AD.
+ 5. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 6. Write data from the client to server.
+ 7. Verify data matches from client and server
+ 8. Disconnect the L2CAP CoC connections.
+
+ Expected Result:
+ CoC connection is established, check transmitted data contents, then disconnected
+ succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 2
+ """
+
+ is_secured = False
+ le_connection_interval = 15
+ buffer_size = 180
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ return self._run_coc_connection_throughput(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='124d85ba-41e6-4ab7-a017-99a88db7524a')
+ def test_coc_connection_throughput_NOSEC_20CI_240SIZE(self):
+ """Test LE CoC data throughput with 20msec CI and 240bytes buffer size.
+
+ Test CoC thoughput by establishing a connection and sending data with 20msec
+ Connection Interval and 240 bytes data buffer size.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Change the Connection Interval to 20msec.
+ 3. Change Payload Buffer Size to 240 bytes.
+ 4. Establish a L2CAP CoC connection from the client to the server AD.
+ 5. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 6. Write data from the client to server.
+ 7. Verify data matches from client and server
+ 8. Disconnect the L2CAP CoC connections.
+
+ Expected Result:
+ CoC connection is established, check transmitted data contents, then disconnected
+ succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 2
+ """
+
+ is_secured = False
+ le_connection_interval = 20
+ buffer_size = 240
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ return self._run_coc_connection_throughput(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='218932bc-ebb0-4c2b-96ad-220c600b50b1')
+ def test_coc_connection_throughput_NOSEC_30CI_240SIZE(self):
+ """Test LE CoC data throughput with 30msec CI and 240bytes buffer size.
+
+ Test CoC thoughput by establishing a connection and sending data with 30msec
+ Connection Interval and 240 bytes data buffer size.
+
+ Steps:
+ 1. Get the mac address of the server device.
+ 2. Change the Connection Interval to 30msec.
+ 3. Change Payload Buffer Size to 240 bytes.
+ 4. Establish a L2CAP CoC connection from the client to the server AD.
+ 5. Verify that the L2CAP CoC connection is active from both the client
+ and server.
+ 6. Write data from the client to server.
+ 7. Verify data matches from client and server
+ 8. Disconnect the L2CAP CoC connections.
+
+ Expected Result:
+ CoC connection is established, check transmitted data contents, then disconnected
+ succcessfully.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: BLE, CoC
+ Priority: 2
+ """
+
+ is_secured = False
+ le_connection_interval = 30
+ buffer_size = 240
+ le_tx_data_length = buffer_size + l2cap_coc_header_size
+ return self._run_coc_connection_throughput(
+ is_secured, buffer_size, le_connection_interval, le_tx_data_length)
diff --git a/acts/tests/google/ble/examples/BleExamplesTest.py b/acts/tests/google/ble/examples/BleExamplesTest.py
index 6056086..2c2174b 100644
--- a/acts/tests/google/ble/examples/BleExamplesTest.py
+++ b/acts/tests/google/ble/examples/BleExamplesTest.py
@@ -19,7 +19,7 @@
import pprint
-from acts.controllers import android_devices
+from acts.controllers import android_device
from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
from acts.test_utils.bt.bt_constants import adv_succ
from acts.test_utils.bt.bt_constants import scan_result
diff --git a/acts/tests/google/ble/examples/GattServerExampleTest.py b/acts/tests/google/ble/examples/GattServerExampleTest.py
new file mode 100644
index 0000000..cfdd052
--- /dev/null
+++ b/acts/tests/google/ble/examples/GattServerExampleTest.py
@@ -0,0 +1,67 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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.
+
+from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
+from acts.test_utils.bt.bt_constants import gatt_characteristic
+from acts.test_utils.bt.bt_constants import gatt_descriptor
+from acts.test_utils.bt.bt_constants import gatt_service_types
+from acts.test_utils.bt.bt_constants import gatt_characteristic_value_format
+from acts.test_utils.bt.bt_constants import gatt_char_desc_uuids
+from acts.test_utils.bt.gatts_lib import GattServerLib
+
+service_uuid = '0000a00a-0000-1000-8000-00805f9b34fb'
+characteristic_uuid = 'aa7edd5a-4d1d-4f0e-883a-d145616a1630'
+descriptor_uuid = gatt_char_desc_uuids['client_char_cfg']
+
+gatt_server_read_descriptor_sample = {
+ 'services': [{
+ 'uuid':
+ service_uuid,
+ 'type':
+ gatt_service_types['primary'],
+ 'characteristics': [{
+ 'uuid':
+ characteristic_uuid,
+ 'properties':
+ gatt_characteristic['property_read'],
+ 'permissions':
+ gatt_characteristic['permission_read'],
+ 'instance_id':
+ 0x002a,
+ 'value_type':
+ gatt_characteristic_value_format['string'],
+ 'value':
+ 'Test Database',
+ 'descriptors': [{
+ 'uuid': descriptor_uuid,
+ 'permissions': gatt_descriptor['permission_read'],
+ }]
+ }]
+ }]
+}
+
+
+class GattServerExampleTest(BluetoothBaseTest):
+ def __init__(self, controllers):
+ BluetoothBaseTest.__init__(self, controllers)
+ self.dut = self.android_devices[0]
+
+ @BluetoothBaseTest.bt_test_wrap
+ def test_create_gatt_server_db_example(self):
+ gatts = GattServerLib(log=self.log, mac_addr=None, dut=self.dut)
+ gatts.setup_gatts_db(database=gatt_server_read_descriptor_sample)
+ self.log.info(gatts.list_all_uuids())
+ return True
diff --git a/acts/tests/google/ble/gatt/GattConnectTest.py b/acts/tests/google/ble/gatt/GattConnectTest.py
index 667611d..07c8e1b 100644
--- a/acts/tests/google/ble/gatt/GattConnectTest.py
+++ b/acts/tests/google/ble/gatt/GattConnectTest.py
@@ -23,15 +23,20 @@
from acts.test_decorators import test_tracker_info
from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
+from acts.test_utils.bt.bt_constants import ble_advertise_settings_modes
+from acts.test_utils.bt.bt_constants import ble_scan_settings_modes
+from acts.test_utils.bt.bt_constants import ble_scan_settings_match_nums
from acts.test_utils.bt.bt_constants import bt_profile_constants
from acts.test_utils.bt.bt_constants import gatt_characteristic
from acts.test_utils.bt.bt_constants import gatt_descriptor
from acts.test_utils.bt.bt_constants import gatt_service_types
from acts.test_utils.bt.bt_constants import gatt_cb_err
from acts.test_utils.bt.bt_constants import gatt_cb_strings
+from acts.test_utils.bt.bt_constants import gatt_connection_state
from acts.test_utils.bt.bt_constants import gatt_mtu_size
from acts.test_utils.bt.bt_constants import gatt_phy_mask
from acts.test_utils.bt.bt_constants import gatt_transport
+from acts.test_utils.bt.bt_constants import scan_result
from acts.test_utils.bt.bt_gatt_utils import GattTestUtilsError
from acts.test_utils.bt.bt_gatt_utils import disconnect_gatt_connection
from acts.test_utils.bt.bt_gatt_utils import wait_for_gatt_disconnect_event
@@ -43,6 +48,8 @@
from acts.test_utils.bt.bt_test_utils import get_mac_address_of_generic_advertisement
from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+PHYSICAL_DISCONNECT_TIMEOUT = 5
+
class GattConnectTest(BluetoothBaseTest):
adv_instances = []
@@ -61,6 +68,12 @@
bluetooth_gatt_list = []
self.gatt_server_list = []
self.adv_instances = []
+ # Ensure there is ample time for a physical disconnect in between
+ # testcases.
+ self.log.info(
+ "Waiting for {} seconds for physical GATT disconnections".format(
+ PHYSICAL_DISCONNECT_TIMEOUT))
+ time.sleep(PHYSICAL_DISCONNECT_TIMEOUT)
def teardown_test(self):
for bluetooth_gatt in self.bluetooth_gatt_list:
@@ -989,3 +1002,151 @@
self.adv_instances.append(adv_callback)
return self._orchestrate_gatt_disconnection(bluetooth_gatt,
gatt_callback)
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='a0a37ca6-9fa8-4d35-9fdb-0e25b4b8a363')
+ def test_gatt_connect_second_adv_after_canceling_first_adv(self):
+ """Test GATT connection to peripherals second advertising address.
+
+ The the ability of cancelling GATT connections and trying to reconnect
+ to the same device via a different address.
+
+ Steps:
+ 1. A starts advertising
+ 2. B starts scanning and finds A's mac address
+ 3. Stop advertisement from step 1. Start a new advertisement on A and
+ find the new new mac address, B knows of both old and new address.
+ 4. B1 sends connect request to old address of A
+ 5. B1 cancel connect attempt after 10 seconds
+ 6. B1 sends connect request to new address of A
+ 7. Verify B1 establish connection to A in less than 10 seconds
+
+ Expected Result:
+ Verify that a connection was established only on the second
+ advertisement's mac address.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: LE, Advertising, Scanning, GATT
+ Priority: 3
+ """
+ autoconnect = False
+ transport = gatt_transport['auto']
+ opportunistic = False
+ # Setup a basic Gatt server on the peripheral
+ gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback()
+ gatt_server = self.per_ad.droid.gattServerOpenGattServer(
+ gatt_server_cb)
+
+ # Set advertisement settings to include local name in advertisement
+ # and set the advertising mode to low_latency.
+ self.per_ad.droid.bleSetAdvertiseSettingsIsConnectable(True)
+ self.per_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True)
+ self.per_ad.droid.bleSetAdvertiseSettingsAdvertiseMode(
+ ble_advertise_settings_modes['low_latency'])
+
+ # Setup necessary advertisement objects.
+ advertise_data = self.per_ad.droid.bleBuildAdvertiseData()
+ advertise_settings = self.per_ad.droid.bleBuildAdvertiseSettings()
+ advertise_callback = self.per_ad.droid.bleGenBleAdvertiseCallback()
+
+ # Step 1: Start advertisement
+ self.per_ad.droid.bleStartBleAdvertising(
+ advertise_callback, advertise_data, advertise_settings)
+
+ # Setup scan settings for low_latency scanning and to include the local name
+ # of the advertisement started in step 1.
+ filter_list = self.cen_ad.droid.bleGenFilterList()
+ self.cen_ad.droid.bleSetScanSettingsNumOfMatches(
+ ble_scan_settings_match_nums['one'])
+ self.cen_ad.droid.bleSetScanFilterDeviceName(
+ self.per_ad.droid.bluetoothGetLocalName())
+ self.cen_ad.droid.bleBuildScanFilter(filter_list)
+ self.cen_ad.droid.bleSetScanSettingsScanMode(ble_scan_settings_modes[
+ 'low_latency'])
+
+ # Setup necessary scan objects.
+ scan_settings = self.cen_ad.droid.bleBuildScanSetting()
+ scan_callback = self.cen_ad.droid.bleGenScanCallback()
+
+ # Step 2: Start scanning on central Android device and find peripheral
+ # address.
+ self.cen_ad.droid.bleStartBleScan(filter_list, scan_settings,
+ scan_callback)
+ expected_event_name = scan_result.format(scan_callback)
+ try:
+ mac_address_pre_restart = self.cen_ad.ed.pop_event(
+ expected_event_name, self.default_timeout)['data']['Result'][
+ 'deviceInfo']['address']
+ self.log.info(
+ "Peripheral advertisement found with mac address: {}".format(
+ mac_address_pre_restart))
+ except Empty:
+ self.log.info("Peripheral advertisement not found")
+ test_result = False
+
+ # Step 3: Restart peripheral advertising such that a new mac address is
+ # created.
+ self.per_ad.droid.bleStopBleAdvertising(advertise_callback)
+ self.per_ad.droid.bleStartBleAdvertising(
+ advertise_callback, advertise_data, advertise_settings)
+
+ try:
+ mac_address_post_restart = self.cen_ad.ed.pop_event(
+ expected_event_name, self.default_timeout)['data']['Result'][
+ 'deviceInfo']['address']
+ self.log.info(
+ "Peripheral advertisement found with mac address: {}".format(
+ mac_address_post_restart))
+ except Empty:
+ self.log.info("Peripheral advertisement not found")
+ test_result = False
+
+ # Steps 4: Try to connect to the first mac address
+ gatt_callback = self.cen_ad.droid.gattCreateGattCallback()
+ self.log.info("Gatt Connect to mac address {}.".format(
+ mac_address_pre_restart))
+ bluetooth_gatt = self.cen_ad.droid.gattClientConnectGatt(
+ gatt_callback, mac_address_pre_restart, autoconnect, transport,
+ opportunistic, gatt_phy_mask['1m_mask'])
+ self.bluetooth_gatt_list.append(bluetooth_gatt)
+ expected_event = gatt_cb_strings['gatt_conn_change'].format(
+ gatt_callback)
+ try:
+ event = self.cen_ad.ed.pop_event(expected_event,
+ self.default_timeout)
+ self.log.error(
+ "Connection callback updated unexpectedly: {}".format(event))
+ return False
+ except Empty:
+ self.log.info("No connection update as expected.")
+
+ # Step 5: Cancel connection request.
+ self.cen_ad.droid.gattClientDisconnect(bluetooth_gatt)
+
+ # Step 6: Connect to second mac address.
+ self.log.info("Gatt Connect to mac address {}.".format(
+ mac_address_post_restart))
+ bluetooth_gatt = self.cen_ad.droid.gattClientConnectGatt(
+ gatt_callback, mac_address_post_restart, autoconnect, transport,
+ opportunistic, gatt_phy_mask['1m_mask'])
+ self.bluetooth_gatt_list.append(bluetooth_gatt)
+ expected_event = gatt_cb_strings['gatt_conn_change'].format(
+ gatt_callback)
+
+ # Step 7: Verify connection was setup successfully.
+ try:
+ event = self.cen_ad.ed.pop_event(expected_event,
+ self.default_timeout)
+ self.log.info(
+ "Connection callback updated successfully: {}".format(event))
+ if event['data']['State'] != gatt_connection_state['connected']:
+ self.log.error(
+ "Could not establish a connection to the peripheral.")
+ return False
+ except Empty:
+ self.log.error("No connection update was found.")
+ return False
+ return self.cen_ad.droid.gattClientDisconnect(bluetooth_gatt)
\ No newline at end of file
diff --git a/acts/tests/google/bt/RfcommTest.py b/acts/tests/google/bt/RfcommTest.py
index cdd53ee..846827b 100644
--- a/acts/tests/google/bt/RfcommTest.py
+++ b/acts/tests/google/bt/RfcommTest.py
@@ -55,23 +55,11 @@
def setup_class(self):
return setup_multiple_devices_for_bt_test(self.android_devices)
- def setup_test(self):
- for a in self.android_devices:
- if not clear_bonded_devices(a):
- return False
- for a in self.android_devices:
- a.ed.clear_all_events()
- return True
-
def teardown_test(self):
self.client_ad.droid.bluetoothRfcommCloseClientSocket()
self.server_ad.droid.bluetoothRfcommCloseServerSocket()
return True
- def on_fail(self, test_name, begin_time):
- take_btsnoop_logs(self.android_devices, self, test_name)
- reset_bluetooth(self.android_devices)
-
def teardown_test(self):
if verify_server_and_client_connected(
self.client_ad, self.server_ad, log=False):
@@ -263,8 +251,8 @@
TAGS: Classic, RFCOMM
Priority: 3
"""
- return self._test_rfcomm_connection_with_uuid(bt_rfcomm_uuids[
- 'base_uuid'])
+ return self._test_rfcomm_connection_with_uuid(
+ bt_rfcomm_uuids['base_uuid'])
@BluetoothBaseTest.bt_test_wrap
@test_tracker_info(uuid='42c8d861-48b3-423b-ae8c-df140ebaad9d')
@@ -339,8 +327,8 @@
TAGS: Classic, RFCOMM
Priority: 3
"""
- return self._test_rfcomm_connection_with_uuid(bt_rfcomm_uuids[
- 'rfcomm'])
+ return self._test_rfcomm_connection_with_uuid(
+ bt_rfcomm_uuids['rfcomm'])
@BluetoothBaseTest.bt_test_wrap
@test_tracker_info(uuid='e3c05357-99ec-4819-86e4-1363e3359317')
@@ -390,8 +378,8 @@
TAGS: Classic, RFCOMM
Priority: 3
"""
- return self._test_rfcomm_connection_with_uuid(bt_rfcomm_uuids[
- 'tcs_bin'])
+ return self._test_rfcomm_connection_with_uuid(
+ bt_rfcomm_uuids['tcs_bin'])
@BluetoothBaseTest.bt_test_wrap
@test_tracker_info(uuid='ea1cfc32-d3f0-4420-a8e5-793c6ddf5820')
@@ -416,8 +404,8 @@
TAGS: Classic, RFCOMM
Priority: 3
"""
- return self._test_rfcomm_connection_with_uuid(bt_rfcomm_uuids[
- 'tcs_at'])
+ return self._test_rfcomm_connection_with_uuid(
+ bt_rfcomm_uuids['tcs_at'])
@BluetoothBaseTest.bt_test_wrap
@test_tracker_info(uuid='5b0d5608-38a5-48f7-b3e5-dc52a4a681dd')
@@ -667,8 +655,8 @@
TAGS: Classic, RFCOMM
Priority: 3
"""
- return self._test_rfcomm_connection_with_uuid(bt_rfcomm_uuids[
- 'hardcopy_control_channel'])
+ return self._test_rfcomm_connection_with_uuid(
+ bt_rfcomm_uuids['hardcopy_control_channel'])
@BluetoothBaseTest.bt_test_wrap
@test_tracker_info(uuid='1ae6ca34-87ab-48ad-8da8-98c997538af4')
@@ -693,8 +681,8 @@
TAGS: Classic, RFCOMM
Priority: 3
"""
- return self._test_rfcomm_connection_with_uuid(bt_rfcomm_uuids[
- 'hardcopy_data_channel'])
+ return self._test_rfcomm_connection_with_uuid(
+ bt_rfcomm_uuids['hardcopy_data_channel'])
@BluetoothBaseTest.bt_test_wrap
@test_tracker_info(uuid='d18ed311-a533-4306-944a-6f0f95eac141')
@@ -719,8 +707,8 @@
TAGS: Classic, RFCOMM
Priority: 3
"""
- return self._test_rfcomm_connection_with_uuid(bt_rfcomm_uuids[
- 'hardcopy_notification'])
+ return self._test_rfcomm_connection_with_uuid(
+ bt_rfcomm_uuids['hardcopy_notification'])
@BluetoothBaseTest.bt_test_wrap
@test_tracker_info(uuid='ab0af819-7d26-451d-8275-1119ee3c8df8')
@@ -820,8 +808,8 @@
TAGS: Classic, RFCOMM
Priority: 3
"""
- return self._test_rfcomm_connection_with_uuid(bt_rfcomm_uuids[
- 'mcap_control_channel'])
+ return self._test_rfcomm_connection_with_uuid(
+ bt_rfcomm_uuids['mcap_control_channel'])
@BluetoothBaseTest.bt_test_wrap
@test_tracker_info(uuid='ba3ab84c-bc61-442c-944c-af4fbca157f1')
@@ -846,8 +834,8 @@
TAGS: Classic, RFCOMM
Priority: 3
"""
- return self._test_rfcomm_connection_with_uuid(bt_rfcomm_uuids[
- 'mcap_data_channel'])
+ return self._test_rfcomm_connection_with_uuid(
+ bt_rfcomm_uuids['mcap_data_channel'])
@BluetoothBaseTest.bt_test_wrap
@test_tracker_info(uuid='d6c7523d-9247-480e-8154-edd51ae1be50')
diff --git a/acts/tests/google/bt/audio_lab/BtChameleonTest.py b/acts/tests/google/bt/audio_lab/BtChameleonTest.py
new file mode 100644
index 0000000..f600acd
--- /dev/null
+++ b/acts/tests/google/bt/audio_lab/BtChameleonTest.py
@@ -0,0 +1,223 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2017 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 testing and analysis.
+
+Quick way to generate necessary audio files:
+sudo apt-get install sox
+sox -b 16 -r 48000 -c 2 -n audio_file_2k1k_10_sec.wav synth 10 sine 2000 sine 3000
+sox -b 16 -r 48000 -c 2 -n audio_file_2k1k_300_sec.wav synth 300 sine 2000 sine 3000
+
+"""
+import os
+import subprocess
+import time
+
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.audio_analysis_lib.check_quality import quality_analysis
+from acts.test_utils.bt.BtFunhausBaseTest import BtFunhausBaseTest
+from acts.test_utils.bt.bt_constants import audio_bits_per_sample_32
+from acts.test_utils.bt.bt_constants import audio_channel_mode_8
+from acts.test_utils.bt.bt_constants import audio_sample_rate_48000
+from acts.test_utils.bt.bt_constants import delay_after_binding_seconds
+from acts.test_utils.bt.bt_constants import delay_before_record_seconds
+from acts.test_utils.bt.bt_constants import fpga_linein_bus_endpoint
+from acts.test_utils.bt.bt_constants import headphone_bus_endpoint
+from acts.test_utils.bt.bt_constants import silence_wait_seconds
+
+from acts import utils
+
+
+class BtChameleonTest(BtFunhausBaseTest):
+
+ audio_file_2k1k_10_sec = "audio_file_2k1k_10_sec.wav"
+ audio_file_2k1k_300_sec = "audio_file_2k1k_300_sec.wav"
+ android_sdcard_music_path = "/sdcard/Music"
+
+ def __init__(self, controllers):
+ BtFunhausBaseTest.__init__(self, controllers)
+ self.chameleon = self.chameleon_devices[0]
+ self.dut = self.android_devices[0]
+ self.raw_audio_dest = "{}/{}".format(self.android_devices[0].log_path,
+ "Chameleon_audio")
+ utils.create_dir(self.raw_audio_dest)
+ self.chameleon.audio_board_connect(1, headphone_bus_endpoint)
+ self.chameleon.audio_board_connect(1, fpga_linein_bus_endpoint)
+ time.sleep(delay_after_binding_seconds)
+
+ def _orchestrate_audio_quality_test(self, output_file_prefix_name,
+ bits_per_sample, rate, record_seconds,
+ channel, audio_to_play):
+ audio_analysis_filename = "{}_audio_analysis.txt".format(
+ output_file_prefix_name)
+ bluetooth_bind_time_seconds = 5
+ port_id = 6
+ has_file = True
+ # Additional sleep to allow full connection of Bluetooth device
+ # from test setup.
+ time.sleep(bluetooth_bind_time_seconds)
+ self.chameleon.start_capturing_audio(port_id, has_file)
+ time.sleep(delay_before_record_seconds)
+ self.dut.droid.mediaPlayOpen("file://{}".format(audio_to_play))
+ time.sleep(record_seconds + silence_wait_seconds)
+ raw_audio_info = self.chameleon_devices[0].stop_capturing_audio(
+ port_id)
+ self.ad.droid.mediaPlayStopAll()
+ raw_audio_path = raw_audio_info[0]
+ dest_file_path = "{}/{}_recording.raw".format(self.raw_audio_dest,
+ output_file_prefix_name)
+ self.chameleon.scp(raw_audio_path, dest_file_path)
+ self._collect_bluetooth_manager_dumpsys_logs(self.android_devices)
+ self.collect_bluetooth_manager_metrics_logs(self.android_devices)
+ analysis_path = "{}/{}".format(self.raw_audio_dest,
+ audio_analysis_filename)
+ try:
+ quality_analysis(
+ filename=dest_file_path,
+ output_file=analysis_path,
+ bit_width=bits_per_sample,
+ rate=rate,
+ channel=channel,
+ spectral_only=False)
+ except Exception as err:
+ self.log.exception("Failed to analyze raw audio: {}".format(err))
+ return False
+ # TODO: Log results to proto
+ return True
+
+ @test_tracker_info(uuid='b808fed6-5cb0-4e40-9522-c0f410cd77e8')
+ def test_run_bt_audio_quality_2k1k_10_sec_sine_wave(self):
+ """Measure audio quality over Bluetooth by playing a 1k2k sine wave.
+
+ Play a sine wave and measure the analysis of 1kHz and 2kHz on two
+ different channels for 10 seconds:
+ 1. Delays during playback.
+ 2. Noise before playback.
+ 3. Noise after playback.
+ 4. Bursts during playback.
+ 5. Volume changes.
+
+ Steps:
+ 1. Connect Chameleon headphone audio bus endpoint.
+ 2. Connect FPGA line-in bus endpoint.
+ 3. Clear audio routes on the Chameleon device.
+ 4. Start capturing audio on the Chameleon device.
+ 5. Start playing the sine wave on the Android device.
+ 6. Record for record_seconds + silence_wait_seconds.
+ 7. Stop recording audio on the Chameleon device.
+ 8. Stop playing audio on the Android Device.
+ 9. Pull raw recorded audio from the Chameleon device.
+ 10. Analyze raw audio and log results.
+
+
+ Expected Result:
+ Audio is recorded and processed successfully.
+
+ Returns:
+ True if Pass
+ False if Fail
+
+ TAGS: Classic, A2DP, Chameleon
+ Priority: 2
+ """
+ sox_call = "{}{}".format("sox -b 16 -r 48000 -c 2 -n {}".format(
+ self.audio_file_2k1k_10_sec), " synth 10 sine 2000 sine 3000")
+ subprocess.call(sox_call, shell=True)
+ sox_audio_path = "{}/{}".format(
+ os.path.dirname(os.path.realpath(self.audio_file_2k1k_10_sec)),
+ self.audio_file_2k1k_10_sec)
+ sox_audio_path = os.path.join(
+ os.path.dirname(os.path.realpath(self.audio_file_2k1k_10_sec)),
+ self.audio_file_2k1k_10_sec)
+ self.dut.adb.push("{} {}".format(sox_audio_path,
+ self.android_sdcard_music_path))
+ output_file_prefix_name = "{}_{}".format("test_2k1k_10_sec",
+ time.time())
+ bits_per_sample = audio_bits_per_sample_32
+ rate = audio_sample_rate_48000
+ record_seconds = 10 # The length in seconds for how long to record
+ channel = audio_channel_mode_8
+ audio_to_play = "{}/{}".format(self.android_sdcard_music_path,
+ self.audio_file_2k1k_10_sec)
+ audio_to_play = os.path.join(self.android_sdcard_music_path,
+ self.audio_file_2k1k_10_sec)
+ return self._orchestrate_audio_quality_test(
+ output_file_prefix_name=output_file_prefix_name,
+ bits_per_sample=bits_per_sample,
+ rate=rate,
+ record_seconds=record_seconds,
+ channel=channel,
+ audio_to_play=audio_to_play)
+
+ @test_tracker_info(uuid='7e971cef-6637-4198-929a-7ecc712121d7')
+ def test_run_bt_audio_quality_2k1k_300_sec_sine_wave(self):
+ """Measure audio quality over Bluetooth by playing a 1k2k sine wave.
+
+ Play a sine wave and measure the analysis of 1kHz and 2kHz on two
+ different channels for 300 seconds:
+ 1. Delays during playback.
+ 2. Noise before playback.
+ 3. Noise after playback.
+ 4. Bursts during playback.
+ 5. Volume changes.
+
+ Steps:
+ 1. Connect Chameleon headphone audio bus endpoint.
+ 2. Connect FPGA line-in bus endpoint.
+ 3. Clear audio routes on the Chameleon device.
+ 4. Start capturing audio on the Chameleon device.
+ 5. Start playing the sine wave on the Android device.
+ 6. Record for record_seconds + silence_wait_seconds.
+ 7. Stop recording audio on the Chameleon device.
+ 8. Stop playing audio on the Android Device.
+ 9. Pull raw recorded audio from the Chameleon device.
+ 10. Analyze raw audio and log results.
+
+
+ Expected Result:
+ Audio is recorded and processed successfully.
+
+ Returns:
+ True if Pass
+ False if Fail
+
+ TAGS: Classic, A2DP, Chameleon
+ Priority: 2
+ """
+ sox_call = "{}{}".format("sox -b 16 -r 48000 -c 2 -n {}".format(
+ self.audio_file_2k1k_300_sec), " synth 300 sine 2000 sine 3000")
+ subprocess.call(sox_call, shell=True)
+ sox_audio_path = os.path.join(
+ os.path.dirname(os.path.realpath(self.audio_file_2k1k_300_sec)),
+ self.audio_file_2k1k_300_sec)
+ self.dut.adb.push("{} {}".format(sox_audio_path,
+ self.android_sdcard_music_path))
+ output_file_prefix_name = "{}_{}".format("test_2k1k_300_sec.wav",
+ time.time())
+ bits_per_sample = audio_bits_per_sample_32
+ rate = audio_sample_rate_48000
+ record_seconds = 300 # The length in seconds for how long to record
+ channel = audio_channel_mode_8
+ audio_to_play = os.path.join(self.android_sdcard_music_path,
+ self.audio_file_2k1k_300_sec)
+
+ return self._orchestrate_audio_quality_test(
+ output_file_prefix_name=output_file_prefix_name,
+ bits_per_sample=bits_per_sample,
+ rate=rate,
+ record_seconds=record_seconds,
+ channel=channel,
+ audio_to_play=audio_to_play)
diff --git a/acts/tests/google/bt/audio_lab/BtFunhausTest.py b/acts/tests/google/bt/audio_lab/BtFunhausTest.py
index 2e697af..705900b 100644
--- a/acts/tests/google/bt/audio_lab/BtFunhausTest.py
+++ b/acts/tests/google/bt/audio_lab/BtFunhausTest.py
@@ -34,14 +34,14 @@
"""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
+ and collect relevant 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.
+ 3. Set media to loop indefinitely.
4. After 12 hours collect bluetooth_manager dumpsys information
5. Stop media player
diff --git a/acts/tests/google/bt/car_bt/BtCarHfpTest.py b/acts/tests/google/bt/car_bt/BtCarHfpTest.py
index 3bdfc56..b883753 100644
--- a/acts/tests/google/bt/car_bt/BtCarHfpTest.py
+++ b/acts/tests/google/bt/car_bt/BtCarHfpTest.py
@@ -30,6 +30,8 @@
BLUETOOTH_PKG_NAME = "com.android.bluetooth"
CALL_TYPE_OUTGOING = "CALL_TYPE_OUTGOING"
CALL_TYPE_INCOMING = "CALL_TYPE_INCOMING"
+AUDIO_STATE_DISCONNECTED = 0
+AUDIO_STATE_ROUTED = 2
SHORT_TIMEOUT = 5
@@ -212,6 +214,59 @@
"""
return self.dial_a_hangup_b(self.re, self.re, self.ag_phone_number)
+ def test_bluetooth_voice_recognition_assistant(self):
+ """
+ Tests if we can initate a remote Voice Recognition session.
+
+ Precondition:
+ 1. Devices are connected.
+
+ Steps:
+ 1. Verify that audio isn't routed between the HF and AG.
+ 2. From the HF send a BVRA command.
+ 3. Verify that audio is routed from the HF to AG.
+ 4. From the HF send a BVRA command to stop the session.
+ 5. Verify that audio is no longer routed from the HF to AG.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ Priority: 0
+ """
+ audio_state = self.hf.droid.bluetoothHfpClientGetAudioState(
+ self.ag.droid.bluetoothGetLocalAddress())
+ if (audio_state != AUDIO_STATE_DISCONNECTED):
+ self.log.info(
+ "Audio connected before test started, current state {}.".
+ format(str(audio_state)))
+ return False
+ bvra_started = self.hf.droid.bluetoothHfpClientStartVoiceRecognition(
+ self.ag.droid.bluetoothGetLocalAddress())
+ if (bvra_started != True):
+ self.log.info("BVRA Failed to start.")
+ return False
+ time.sleep(SHORT_TIMEOUT)
+ audio_state = self.hf.droid.bluetoothHfpClientGetAudioState(
+ self.ag.droid.bluetoothGetLocalAddress())
+ if (audio_state != AUDIO_STATE_ROUTED):
+ self.log.info("Audio didn't route, current state {}.".format(
+ str(audio_state)))
+ return False
+ bvra_stopped = self.hf.droid.bluetoothHfpClientStopVoiceRecognition(
+ self.ag.droid.bluetoothGetLocalAddress())
+ if (bvra_stopped != True):
+ self.log.info("BVRA Failed to stop.")
+ return False
+ time.sleep(SHORT_TIMEOUT)
+ audio_state = self.hf.droid.bluetoothHfpClientGetAudioState(
+ self.ag.droid.bluetoothGetLocalAddress())
+ if (audio_state != AUDIO_STATE_DISCONNECTED):
+ self.log.info("Audio didn't cleanup, current state {}.".format(
+ str(audio_state)))
+ return False
+ return True
+
def dial_a_hangup_b(self, caller, callee, ph=""):
"""
a, b and c can be either of AG, HF or Remote.
diff --git a/acts/tests/google/bt/hid/HidDeviceTest.py b/acts/tests/google/bt/hid/HidDeviceTest.py
new file mode 100644
index 0000000..1016855
--- /dev/null
+++ b/acts/tests/google/bt/hid/HidDeviceTest.py
@@ -0,0 +1,325 @@
+#!/usr/bin/env python3.4
+#
+# Copyright (C) 2017 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.
+"""
+Bluetooth HID Device Test.
+"""
+
+from acts.base_test import BaseTestClass
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
+from acts.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.bt.bt_test_utils import pair_pri_to_sec
+from acts.test_utils.bt.bt_test_utils import hid_keyboard_report
+from acts.test_utils.bt.bt_test_utils import hid_device_send_key_data_report
+from acts.test_utils.bt.bt_constants import hid_connection_timeout
+from acts.test_utils.bt import bt_constants
+import time
+
+
+class HidDeviceTest(BluetoothBaseTest):
+ tests = None
+ default_timeout = 10
+
+ def __init__(self, controllers):
+ BaseTestClass.__init__(self, controllers)
+ self.host_ad = self.android_devices[0]
+ self.device_ad = self.android_devices[1]
+
+ def setup_test(self):
+ for a in self.android_devices:
+ if not clear_bonded_devices(a):
+ return False
+ for a in self.android_devices:
+ a.ed.clear_all_events()
+
+ i = 0
+ while not self.device_ad.droid.bluetoothHidDeviceIsReady():
+ time.sleep(1)
+ i += 1
+ self.log.info("BluetoothHidDevice NOT Ready")
+ if i == 10:
+ return False
+
+ if not self.device_ad.droid.bluetoothHidDeviceRegisterApp():
+ self.log.error("Device: registration failed")
+ return False
+
+ self.log.info("Device: registration done")
+ return True
+
+ def teardown_test(self):
+ self.log.info("Device: unregister")
+ self.device_ad.droid.bluetoothHidDeviceUnregisterApp()
+ time.sleep(2)
+ return True
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='047afb31-96c5-4a56-acb5-2b216037f35d')
+ def test_hid(self):
+ """Test HID Host and Device basic functionality
+
+ Test the HID Device framework app registration; test HID Host sending
+ report through HID control channel and interrupt channel.
+
+ Steps:
+ 1. Bluetooth HID device registers the Bluetooth input device service.
+ 2. Get the MAC address of the HID host and HID device.
+ 3. Establish HID profile connection from the HID host to the HID device.
+ 4. HID host sends set_report, get_report, set_protocol, send_data to
+ the HID device, and check if the HID device receives them.
+ 5. HID device sends data report, report_error, reply_report commands to
+ the HID host, and check if the HID host receives them.
+
+ Expected Result:
+ HID profile connection is successfully established; all commands and
+ data reports are correctly handled.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: Classic, HID
+ Priority: 1
+ """
+
+ test_result = True
+
+ pair_pri_to_sec(self.host_ad, self.device_ad, attempts=3)
+
+ self.log.info("Device bonded: {}".format(
+ self.device_ad.droid.bluetoothGetBondedDevices()))
+ self.log.info("Host bonded: {}".format(
+ self.host_ad.droid.bluetoothGetBondedDevices()))
+
+ host_id = self.host_ad.droid.bluetoothGetLocalAddress()
+ device_id = self.device_ad.droid.bluetoothGetLocalAddress()
+
+ self.host_ad.droid.bluetoothConnectBonded(device_id)
+
+ time.sleep(hid_connection_timeout)
+ self.log.info("Device: connected: {}".format(
+ self.device_ad.droid.bluetoothHidDeviceGetConnectedDevices()))
+
+ self.log.info("Host: set report")
+ self.host_ad.droid.bluetoothHidSetReport(
+ device_id, 1, bt_constants.hid_default_set_report_payload)
+
+ try:
+ hid_device_callback = self.device_ad.ed.pop_event(
+ bt_constants.hid_on_set_report_event,
+ bt_constants.hid_default_event_timeout)
+ except Empty as err:
+ self.log.error("Callback not received: {}".format(err))
+ test_result = False
+
+ self.log.info("Host: get report")
+ self.host_ad.droid.bluetoothHidGetReport(device_id, 1, 1, 1024)
+
+ try:
+ hid_device_callback = self.device_ad.ed.pop_event(
+ bt_constants.hid_on_get_report_event,
+ bt_constants.hid_default_event_timeout)
+ except Empty as err:
+ self.log.error("Callback not received: {}".format(err))
+ test_result = False
+
+ self.log.info("Host: set_protocol")
+ self.host_ad.droid.bluetoothHidSetProtocolMode(device_id, 1)
+
+ try:
+ hid_device_callback = self.device_ad.ed.pop_event(
+ bt_constants.hid_on_set_protocol_event,
+ bt_constants.hid_default_event_timeout)
+ except Empty as err:
+ self.log.error("Callback not received: {}".format(err))
+ test_result = False
+
+ self.log.info("Host: send data")
+ self.host_ad.droid.bluetoothHidSendData(device_id, "It's a report")
+
+ try:
+ hid_device_callback = self.device_ad.ed.pop_event(
+ bt_constants.hid_on_intr_data_event,
+ bt_constants.hid_default_event_timeout)
+ except Empty as err:
+ self.log.error("Callback not received: {}".format(err))
+ test_result = False
+
+ self.log.info("Device: send data report through interrupt channel")
+ hid_device_send_key_data_report(host_id, self.device_ad, "04")
+ hid_device_send_key_data_report(host_id, self.device_ad, "05")
+
+ self.log.info("Device: report error")
+ self.device_ad.droid.bluetoothHidDeviceReportError(host_id, 1)
+
+ self.log.info("Device: reply report")
+ self.device_ad.droid.bluetoothHidDeviceReplyReport(
+ host_id, 1, 1, hid_keyboard_report("04"))
+
+ self.log.info("Device bonded: {}".format(
+ self.device_ad.droid.bluetoothGetBondedDevices()))
+ self.log.info("Host bonded: {}".format(
+ self.host_ad.droid.bluetoothGetBondedDevices()))
+
+ return test_result
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='5ddc3eb1-2b8d-43b5-bdc4-ba577d90481d')
+ def test_hid_host_unplug(self):
+ """Test HID Host Virtual_cable_unplug
+
+ Test the HID host and HID device handle Virtual_cable_unplug correctly
+
+ Steps:
+ 1. Bluetooth HID device registers the Bluetooth input device service.
+ 2. Get the MAC address of the HID host and HID device.
+ 3. Establish HID profile connection from the HID host to the HID device.
+ 4. HID host sends virtual_cable_unplug command to the HID device.
+
+ Expected Result:
+ HID profile connection is successfully established; After the HID host
+ sends virtual_cable_unplug command to the HID device, both disconnect
+ each other, but not unpair.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: Classic, HID
+ Priority: 2
+ """
+
+ test_result = True
+ pair_pri_to_sec(self.host_ad, self.device_ad, attempts=3)
+
+ self.log.info("Device bonded: {}".format(
+ self.device_ad.droid.bluetoothGetBondedDevices()))
+ self.log.info("Host bonded: {}".format(
+ self.host_ad.droid.bluetoothGetBondedDevices()))
+
+ host_id = self.host_ad.droid.bluetoothGetLocalAddress()
+ device_id = self.device_ad.droid.bluetoothGetLocalAddress()
+
+ self.host_ad.droid.bluetoothConnectBonded(device_id)
+
+ time.sleep(hid_connection_timeout)
+ self.log.info("Device connected: {}".format(
+ self.device_ad.droid.bluetoothHidDeviceGetConnectedDevices()))
+
+ self.log.info("Device: send data report through interrupt channel")
+ hid_device_send_key_data_report(host_id, self.device_ad, "04")
+ hid_device_send_key_data_report(host_id, self.device_ad, "05")
+
+ self.log.info("Host: virtual unplug")
+ self.host_ad.droid.bluetoothHidVirtualUnplug(device_id)
+
+ try:
+ hid_device_callback = self.device_ad.ed.pop_event(
+ bt_constants.hid_on_virtual_cable_unplug_event,
+ bt_constants.hid_default_event_timeout)
+ except Empty as err:
+ self.log.error("Callback not received: {}".format(err))
+ test_result = False
+
+ self.log.info("Device bonded: {}".format(
+ self.device_ad.droid.bluetoothGetBondedDevices()))
+ self.log.info("Host bonded: {}".format(
+ self.host_ad.droid.bluetoothGetBondedDevices()))
+
+ if not self.device_ad.droid.bluetoothGetBondedDevices():
+ self.log.error("HID device unbonded host on virtual_cable_unplug")
+ test_result = False
+
+ if not self.host_ad.droid.bluetoothGetBondedDevices():
+ self.log.error("HID host unbonded device on virtual_cable_unplug")
+ test_result = False
+
+ return test_result
+
+ @BluetoothBaseTest.bt_test_wrap
+ @test_tracker_info(uuid='5315ccc2-0869-4b63-9b02-6ea349acabc8')
+ def test_hid_device_unplug(self):
+ """Test HID Device Virtual_cable_unplug
+
+ Test the HID host and HID device handle Virtual_cable_unplug correctly
+
+ Steps:
+ 1. Bluetooth HID device registers the Bluetooth input device service.
+ 2. Get the MAC address of the HID host and HID device.
+ 3. Establish HID profile connection from the HID host to the HID device.
+ 4. HID device sends virtual_cable_unplug command to the HID host.
+
+ Expected Result:
+ HID profile connection is successfully established; After the HID device
+ sends virtual_cable_unplug command to the HID host, both disconnect
+ each other, but not unpair.
+
+ Returns:
+ Pass if True
+ Fail if False
+
+ TAGS: Classic, HID
+ Priority: 2
+ """
+
+ test_result = True
+
+ pair_pri_to_sec(self.host_ad, self.device_ad, attempts=3)
+
+ self.log.info("Device bonded: {}".format(
+ self.device_ad.droid.bluetoothGetBondedDevices()))
+ self.log.info("Host bonded: {}".format(
+ self.host_ad.droid.bluetoothGetBondedDevices()))
+
+ host_id = self.host_ad.droid.bluetoothGetLocalAddress()
+ device_id = self.device_ad.droid.bluetoothGetLocalAddress()
+
+ self.host_ad.droid.bluetoothConnectBonded(device_id)
+
+ time.sleep(hid_connection_timeout)
+ self.log.info("Device connected: {}".format(
+ self.device_ad.droid.bluetoothHidDeviceGetConnectedDevices()))
+
+ self.log.info("Device: send data report through interrupt channel")
+ hid_device_send_key_data_report(host_id, self.device_ad, "04")
+ hid_device_send_key_data_report(host_id, self.device_ad, "05")
+
+ self.log.info("Device: virtual unplug")
+ self.device_ad.droid.bluetoothHidDeviceVirtualUnplug(host_id)
+
+ try:
+ hid_device_callback = self.device_ad.ed.pop_event(
+ bt_constants.hid_on_virtual_cable_unplug_event,
+ bt_constants.hid_default_event_timeout)
+ except Empty as err:
+ self.log.error("Callback not received: {}".format(err))
+ test_result = False
+
+ self.log.info("Device bonded: {}".format(
+ self.device_ad.droid.bluetoothGetBondedDevices()))
+ self.log.info("Host bonded: {}".format(
+ self.host_ad.droid.bluetoothGetBondedDevices()))
+
+ if not self.device_ad.droid.bluetoothGetBondedDevices():
+ self.log.error("HID device unbonded host on virtual_cable_unplug")
+ test_result = False
+
+ if not self.host_ad.droid.bluetoothGetBondedDevices():
+ self.log.error("HID host unbonded device on virtual_cable_unplug")
+ test_result = False
+
+ return test_result
diff --git a/acts/tests/google/bt/pts/BtCmdLineTest.py b/acts/tests/google/bt/pts/BtCmdLineTest.py
index 5091db3..b276274 100644
--- a/acts/tests/google/bt/pts/BtCmdLineTest.py
+++ b/acts/tests/google/bt/pts/BtCmdLineTest.py
@@ -37,10 +37,11 @@
def __init__(self, controllers):
BluetoothBaseTest.__init__(self, controllers)
if not "target_mac_address" in self.user_params.keys():
- self.log.error(
- "Missing mandatory user config \"target_mac_address\"!")
- return False
- self.target_mac_address = self.user_params["target_mac_address"].upper()
+ self.log.warning("Missing user config \"target_mac_address\"!")
+ self.target_mac_address = ""
+ else:
+ self.target_mac_address = self.user_params[
+ "target_mac_address"].upper()
self.android_devices[0].droid.bluetoothSetLocalName("CMD LINE Test")
if len(self.android_devices) > 1:
@@ -77,8 +78,8 @@
for filename in filenames:
file = os.path.join(dirname, filename)
#TODO: Handle file paths with spaces
- self.android_devices[0].adb.push(
- "{} {}".format(file, android_music_path))
+ self.android_devices[0].adb.push("{} {}".format(
+ file, android_music_path))
def setup_class(self):
return True
diff --git a/acts/tests/google/bt/pts/cmd_input.py b/acts/tests/google/bt/pts/cmd_input.py
index e97b1a4..3ef2cb5 100644
--- a/acts/tests/google/bt/pts/cmd_input.py
+++ b/acts/tests/google/bt/pts/cmd_input.py
@@ -16,18 +16,18 @@
"""
Python script for wrappers to various libraries.
"""
-from acts.test_utils.bt.BtEnum import BluetoothScanModeType
-from acts.test_utils.bt.GattEnum import GattServerResponses
-from ble_lib import BleLib
-from bta_lib import BtaLib
-from config_lib import ConfigLib
-from gattc_lib import GattClientLib
-from gatts_lib import GattServerLib
-from rfcomm_lib import RfcommLib
+from acts.test_utils.bt.bt_constants import bt_scan_mode_types
+from acts.test_utils.bt.bt_constants import gatt_server_responses
+import acts.test_utils.bt.gatt_test_database as gatt_test_database
+from acts.test_utils.bt.ble_lib import BleLib
+from acts.test_utils.bt.bta_lib import BtaLib
+from acts.test_utils.bt.config_lib import ConfigLib
+from acts.test_utils.bt.gattc_lib import GattClientLib
+from acts.test_utils.bt.gatts_lib import GattServerLib
+from acts.test_utils.bt.rfcomm_lib import RfcommLib
import time
import cmd
-import gatt_test_database
"""Various Global Strings"""
CMD_LOG = "CMD {} result: {}"
FAILURE = "CMD {} threw exception: {}"
@@ -173,6 +173,14 @@
except Exception as err:
self.log.info(FAILURE.format(cmd, err))
+ def do_gattc_write_char_by_instance_id_value(self, line):
+ """GATT Client Write to Characteristic by instance ID"""
+ cmd = "GATT Client write to Characteristic by instance ID"
+ try:
+ self.gattc_lib.write_char_by_instance_id_value(line)
+ except Exception as err:
+ self.log.info(FAILURE.format(cmd, err))
+
def do_gattc_mod_write_char_by_instance_id(self, line):
"""GATT Client Write to Char that doesn't have write permission"""
cmd = "GATT Client Write to Char that doesn't have write permission"
@@ -369,8 +377,8 @@
def complete_gatts_setup_database(self, text, line, begidx, endidx):
if not text:
- completions = list(gatt_test_database.GATT_SERVER_DB_MAPPING.keys(
- ))[:]
+ completions = list(
+ gatt_test_database.GATT_SERVER_DB_MAPPING.keys())[:]
else:
completions = [
s for s in gatt_test_database.GATT_SERVER_DB_MAPPING.keys()
@@ -381,10 +389,10 @@
def complete_gatts_send_response(self, text, line, begidx, endidx):
"""GATT Server database name completion"""
if not text:
- completions = list(GattServerResponses.keys())[:]
+ completions = list(gatt_server_responses.keys())[:]
else:
completions = [
- s for s in GattServerResponses.keys() if s.startswith(text)
+ s for s in gatt_server_responses.keys() if s.startswith(text)
]
return completions
@@ -392,10 +400,10 @@
endidx):
"""GATT Server database name completion"""
if not text:
- completions = list(GattServerResponses.keys())[:]
+ completions = list(gatt_server_responses.keys())[:]
else:
completions = [
- s for s in GattServerResponses.keys() if s.startswith(text)
+ s for s in gatt_server_responses.keys() if s.startswith(text)
]
return completions
@@ -403,10 +411,10 @@
endidx):
"""GATT Server database name completion"""
if not text:
- completions = list(GattServerResponses.keys())[:]
+ completions = list(gatt_server_responses.keys())[:]
else:
completions = [
- s for s in GattServerResponses.keys() if s.startswith(text)
+ s for s in gatt_server_responses.keys() if s.startswith(text)
]
return completions
@@ -633,7 +641,7 @@
return completions
def complete_bta_set_scan_mode(self, text, line, begidx, endidx):
- completions = [e.name for e in BluetoothScanModeType]
+ completions = [e.name for e in bt_scan_mode_types]
if not text:
completions = completions[:]
else:
@@ -916,8 +924,9 @@
self.mac_addr):
self.log.info(
FAILURE.format(
- cmd, "bluetoothHspDisconnectAudio returned false for "
- + self.mac_addr))
+ cmd,
+ "bluetoothHspDisconnectAudio returned false for " +
+ self.mac_addr))
except Exception as err:
self.log.info(FAILURE.format(cmd, err))
@@ -949,8 +958,7 @@
"""Get HID Report"""
cmd = "Get HID Report"
try:
- self.pri_dut.droid.bluetoothHidGetReport(self.mac_addr, "1", "1",
- 1024)
+ self.pri_dut.droid.bluetoothHidGetReport(self.mac_addr, 1, 1, 1024)
except Exception as err:
self.log.info(FAILURE.format(cmd, err))
@@ -958,8 +966,7 @@
"""Get HID Report"""
cmd = "Get HID Report"
try:
- self.pri_dut.droid.bluetoothHidSetReport(self.mac_addr, "1",
- "Test")
+ self.pri_dut.droid.bluetoothHidSetReport(self.mac_addr, 1, "Test")
except Exception as err:
self.log.info(FAILURE.format(cmd, err))
diff --git a/acts/tests/google/bt/pts/instructions/GAP_PTS_INSTRUCTIONS b/acts/tests/google/bt/pts/instructions/GAP_PTS_INSTRUCTIONS
index 47da157..e18d9c1 100644
--- a/acts/tests/google/bt/pts/instructions/GAP_PTS_INSTRUCTIONS
+++ b/acts/tests/google/bt/pts/instructions/GAP_PTS_INSTRUCTIONS
@@ -187,7 +187,7 @@
gattc_disconnect
Note: Run the test a first time and it will fail. Change the address to
-be the peer address in the PTS logs that start with:
+be the peer address in the PTS logs that start with:
SEC_LE?SEC_LE_REMOTE_CSRK_REQUEST_IND=PDU
peerAddr: 'xxxxxxxxxxxx'O
TC_BOND_NBON_BV_01_C
diff --git a/acts/tests/google/coex/functionality_tests/CoexBasicFunctionalityTest.py b/acts/tests/google/coex/functionality_tests/CoexBasicFunctionalityTest.py
new file mode 100644
index 0000000..87aa828
--- /dev/null
+++ b/acts/tests/google/coex/functionality_tests/CoexBasicFunctionalityTest.py
@@ -0,0 +1,267 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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.
+
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_test_utils import perform_classic_discovery
+from acts.test_utils.coex.coex_test_utils import toggle_bluetooth
+from acts.test_utils.coex.coex_test_utils import start_fping
+
+
+class CoexBasicFunctionalityTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["iterations"]
+ self.unpack_userparams(req_params)
+
+ def toogle_bluetooth_with_iperf(self):
+ """Wrapper function to start iperf traffic and toggling bluetooth."""
+ self.run_iperf_and_get_result()
+ if not toggle_bluetooth(self.pri_ad, self.iterations):
+ return False
+ return self.teardown_result()
+
+ def start_discovery_with_iperf(self):
+ """Wrapper function to starts iperf traffic and bluetooth discovery,
+ gets all the devices discovered, stops discovery.
+ """
+ self.run_iperf_and_get_result()
+ for i in range(self.iterations):
+ self.log.info("Bluetooth inquiry iteration : {}".format(i))
+ if not perform_classic_discovery(self.pri_ad):
+ return False
+ return self.teardown_result()
+
+ def test_toogle_bluetooth_with_tcp_ul(self):
+ """Starts TCP-uplink traffic, when toggling bluetooth.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device when toggling bluetooth.
+
+ Steps:
+ 1. Start TCP-uplink traffic at background.
+ 2. Enable bluetooth.
+ 3. Disable bluetooth.
+ 4. Repeat steps 3 and 4 for n iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_001
+ """
+ if not self.toogle_bluetooth_with_iperf():
+ return False
+ return True
+
+ def test_toogle_bluetooth_with_tcp_dl(self):
+ """Starts TCP-downlink traffic, when toggling bluetooth.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device when toggling bluetooth.
+
+ Steps:
+ 1. Start TCP-downlink traffic at background.
+ 2. Enable bluetooth.
+ 3. Disable bluetooth.
+ 4. Repeat steps 3 and 4 for n iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_002
+ """
+ if not self.toogle_bluetooth_with_iperf():
+ return False
+ return True
+
+ def test_toogle_bluetooth_with_udp_ul(self):
+ """Starts UDP-uplink traffic, when toggling bluetooth.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device when toggling bluetooth.
+
+ Steps:
+ 1. Start UDP-uplink traffic at background.
+ 2. Enable bluetooth.
+ 3. Disable bluetooth.
+ 4. Repeat steps 3 and 4 for n iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_003
+ """
+ if not self.toogle_bluetooth_with_iperf():
+ return False
+ return True
+
+ def test_toogle_bluetooth_with_udp_dl(self):
+ """Starts UDP-downlink traffic, when toggling bluetooth.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device when toggling bluetooth.
+
+ Steps:
+ 1. Start UDP-downlink traffic at background.
+ 2. Enable bluetooth.
+ 3. Disable bluetooth.
+ 4. Repeat steps 3 and 4 for n iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_004
+ """
+ if not self.toogle_bluetooth_with_iperf():
+ return False
+ return True
+
+ def test_bluetooth_discovery_with_tcp_ul(self):
+ """Starts TCP-uplink traffic, along with bluetooth discovery.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device test the functional behaviour of bluetooth discovery.
+
+ Steps:
+ 1. Run TCP-uplink traffic at background.
+ 2. Enable bluetooth
+ 3. Start bluetooth discovery.
+ 4. List all discovered devices.
+ 5. Repeat step 3 and 4 for n iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_005
+ """
+ if not self.start_discovery_with_iperf():
+ return False
+ return True
+
+ def test_bluetooth_discovery_with_tcp_dl(self):
+ """Starts TCP-downlink traffic, along with bluetooth discovery.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device test the functional behaviour of bluetooth discovery.
+
+ Steps:
+ 1. Run TCP-downlink traffic at background.
+ 2. Enable bluetooth
+ 3. Start bluetooth discovery.
+ 4. List all discovered devices.
+ 5. Repeat step 3 and 4 for n iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_006
+ """
+ if not self.start_discovery_with_iperf():
+ return False
+ return True
+
+ def test_bluetooth_discovery_with_udp_ul(self):
+ """Starts UDP-uplink traffic, along with bluetooth discovery.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device test the functional behaviour of bluetooth discovery.
+
+ Steps:
+ 1. Run UDP-uplink traffic at background.
+ 2. Enable bluetooth
+ 3. Start bluetooth discovery.
+ 4. List all discovered devices.
+ 5. Repeat step 3 and 4 for n iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_007
+ """
+ if not self.start_discovery_with_iperf():
+ return False
+ return True
+
+ def test_bluetooth_discovery_with_udp_dl(self):
+ """Starts UDP-downlink traffic, along with bluetooth discovery.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the functional behaviour of bluetooth discovery.
+
+ Steps:
+ 1. Run UDP-downlink traffic at background.
+ 2. Enable bluetooth.
+ 3. Start bluetooth discovery.
+ 4. List all discovered devices.
+ 5. Repeat step 3 and 4 for n iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_008
+ """
+ if not self.start_discovery_with_iperf():
+ return False
+ return True
+
+ def test_toogle_bluetooth_with_fping(self):
+ """Starts fping, while toggling bluetooth.
+
+ This test is to start fping between host machine and android device
+ while toggling bluetooth.
+
+ Steps:
+ 1. Start fping on background.
+ 2. Enable bluetooth.
+ 3. Disable bluetooth.
+ 4. Repeat steps 3 and 4 for n iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_070
+ """
+ args = [lambda: start_fping(self.pri_ad, self.iperf["duration"])]
+ self.run_thread(args)
+ if not self.toogle_bluetooth_with_iperf():
+ return False
+ return self.teardown_thread()
+
+ def test_bluetooth_discovery_with_fping(self):
+ """Starts fping, along with bluetooth discovery.
+
+ This test is to start fping between host machine and android device
+ and test functional behaviour of bluetooth discovery.
+
+ Steps:
+ 1. Start fping on background.
+ 2. Enable bluetooth.
+ 3. Start bluetooth discovery.
+ 4. Repeat step 3 for n iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_071
+ """
+ args = [lambda: start_fping(self.pri_ad, self.iperf["duration"])]
+ self.run_thread(args)
+ if not self.start_discovery_with_iperf():
+ return False
+ return self.teardown_thread()
diff --git a/acts/tests/google/coex/functionality_tests/CoexBtMultiProfileFunctionalityTest.py b/acts/tests/google/coex/functionality_tests/CoexBtMultiProfileFunctionalityTest.py
new file mode 100644
index 0000000..c5861af
--- /dev/null
+++ b/acts/tests/google/coex/functionality_tests/CoexBtMultiProfileFunctionalityTest.py
@@ -0,0 +1,231 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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.
+
+from acts.test_utils.bt import BtEnum
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_test_utils import connect_ble
+from acts.test_utils.coex.coex_test_utils import initiate_disconnect_from_hf
+from acts.test_utils.coex.coex_test_utils import multithread_func
+from acts.test_utils.coex.coex_test_utils import music_play_and_check_via_app
+from acts.test_utils.coex.coex_test_utils import pair_and_connect_headset
+from acts.test_utils.coex.coex_test_utils import setup_tel_config
+
+
+class CoexBtMultiProfileFunctionalityTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["sim_conf_file", "music_play_time"]
+ self.unpack_userparams(req_params)
+ self.ag_phone_number, self.re_phone_number = setup_tel_config(
+ self.pri_ad, self.sec_ad, self.sim_conf_file)
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.audio_receiver.pairing_mode()
+ if not pair_and_connect_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ set([BtEnum.BluetoothProfile.HEADSET.value]) and
+ set([BtEnum.BluetoothProfile.A2DP.value])):
+ self.log.error("Failed to pair and connect to headset")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.audio_receiver.clean_up()
+
+ def start_media_streaming_initiate_hfp_call_with_iperf(self):
+ """Start media streaming and initiate call from hf to check
+ SCO connection along with iperf.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ self.run_iperf_and_get_result()
+ if not music_play_and_check_via_app(
+ self.pri_ad, self.audio_receiver.mac_address):
+ self.log.error("Failed to stream music file")
+ return False
+ if not initiate_disconnect_from_hf(
+ self.audio_receiver, self.pri_ad, self.sec_ad,
+ self.iperf["duration"]):
+ self.log.error("Failed to initiate/hung up call")
+ return False
+ return self.teardown_result()
+
+ def ble_with_multiprofile_connection(self):
+ """Wrapper function to check ble connection alongwith a2dp streaming
+ and hfp call connection with iperf.
+ """
+ if not connect_ble(self.pri_ad, self.sec_ad):
+ self.log.error("Failed to connect BLE device")
+ return False
+ if not music_play_and_check_via_app(
+ self.pri_ad, self.audio_receiver.mac_address):
+ self.log.error("Failed to stream music file")
+ return False
+ self.run_iperf_and_get_result()
+ tasks = [(initiate_disconnect_from_hf,
+ (self.audio_receiver, self.pri_ad, self.sec_ad,
+ self.iperf["duration"]))]
+ if not multithread_func(self.log, tasks):
+ return False
+ return self.teardown_result()
+
+ def test_a2dp_streaming_hfp_call_with_tcp_ul(self):
+ """Starts TCP-uplink traffic with media streaming and HFP call.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the functional behaviour of media streaming
+ via A2DP and initiating a call when media streaming is ongoing to
+ check HFP.
+
+ Steps:
+ 1. Start TCP-uplink traffic.
+ 1. Enable bluetooth.
+ 2. Start media streaming to A2DP headset.
+ 4. Initiate a call from headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_066
+ """
+ if not self.start_media_streaming_initiate_hfp_call_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_hfp_call_with_tcp_dl(self):
+ """Starts TCP-downlink traffic with media streaming and HFP call.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the functional behaviour of media streaming
+ via A2DP and initiating a call when media streaming is ongoing to
+ check HFP.
+
+ Steps:
+ 1. Start TCP-downlink traffic.
+ 1. Enable bluetooth.
+ 2. Start media streaming to A2DP headset.
+ 4. Initiate a call from headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_067
+ """
+ if not self.start_media_streaming_initiate_hfp_call_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_hfp_call_with_udp_ul(self):
+ """Starts UDP-uplink traffic with media streaming and HFP call.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the functional behaviour of media streaming
+ via A2DP and initiating a call when media streaming is ongoing to
+ check HFP.
+
+ Steps:
+ 1. Start UDP-uplink traffic.
+ 1. Enable bluetooth.
+ 2. Start media streaming to A2DP headset.
+ 4. Initiate a call from headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_068
+ """
+ if not self.start_media_streaming_initiate_hfp_call_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_hfp_call_with_udp_dl(self):
+ """Starts UDP-downlink traffic with media streaming and HFP call.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the functional behaviour of media streaming
+ via A2DP and initiating a call when media streaming is ongoing to
+ check HFP.
+
+ Steps:
+ 1. Start UDP-downlink traffic.
+ 1. Enable bluetooth.
+ 2. Start media streaming to A2DP headset.
+ 4. Initiate a call from headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_069
+ """
+ if not self.start_media_streaming_initiate_hfp_call_with_iperf():
+ return False
+ return True
+
+ def test_ble_connection_a2dp_streaming_hfp_call_with_tcp_ul(self):
+ """Starts TCP-uplink traffic while connecting to BLE device,
+ A2DP streaming and HFP call.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the functional behaviour of BLE connection,
+ media streaming via A2DP and HFP call connection.
+
+ Steps:
+ 1. Enable Bluetooth.
+ 2. Connect to BLE device.
+ 3. Start media streaming to A2DP headset.
+ 4. Start TCP-uplink traffic.
+ 5. Initiate HFP call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_082
+ """
+ if not self.ble_with_multiprofile_connection():
+ return True
+ return False
+
+ def test_ble_connection_a2dp_streaming_hfp_call_with_tcp_dl(self):
+ """Starts TCP-downlink traffic while connecting to BLE device,
+ A2DP streaming and HFP call.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the functional behaviour of BLE connection,
+ media streaming via A2DP and HFP call connection.
+
+ Steps:
+ 1. Enable Bluetooth.
+ 2. Connect to BLE device.
+ 3. Start media streaming to A2DP headset.
+ 4. Start TCP-uplink traffic.
+ 5. Initiate HFP call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_083.
+ """
+ if not self.ble_with_multiprofile_connection():
+ return True
+ return False
diff --git a/acts/tests/google/coex/functionality_tests/WlanWithA2dpFunctionalityTest.py b/acts/tests/google/coex/functionality_tests/WlanWithA2dpFunctionalityTest.py
new file mode 100644
index 0000000..28361c5
--- /dev/null
+++ b/acts/tests/google/coex/functionality_tests/WlanWithA2dpFunctionalityTest.py
@@ -0,0 +1,819 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 time
+
+from acts.test_utils.bt import BtEnum
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_test_utils import connect_dev_to_headset
+from acts.test_utils.coex.coex_test_utils import connect_ble
+from acts.test_utils.coex.coex_test_utils import disconnect_headset_from_dev
+from acts.test_utils.coex.coex_test_utils import multithread_func
+from acts.test_utils.coex.coex_test_utils import music_play_and_check
+from acts.test_utils.coex.coex_test_utils import pair_and_connect_headset
+from acts.test_utils.coex.coex_test_utils import perform_classic_discovery
+from acts.test_utils.coex.coex_test_utils import toggle_screen_state
+from acts.test_utils.coex.coex_test_utils import start_fping
+
+BLUETOOTH_WAIT_TIME = 2
+
+
+class WlanWithA2dpFunctionalityTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["iterations"]
+ self.unpack_userparams(req_params)
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.audio_receiver.power_on()
+ self.audio_receiver.pairing_mode()
+ if not pair_and_connect_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ set([BtEnum.BluetoothProfile.A2DP.value])):
+ self.log.error("Failed to pair and connect to headset")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.audio_receiver.clean_up()
+
+ def connect_disconnect_a2dp_headset(self):
+ """Connects and disconnect a2dp profile on headset for multiple
+ iterations.
+
+ Steps:
+ 1.Connect a2dp profile on headset.
+ 2.Disconnect a2dp profile on headset.
+ 3.Repeat step 1 and 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ for i in range(0, self.iterations):
+ self.log.info("A2DP connect/disconnect Iteration {}".format(i))
+ if not connect_dev_to_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ set([BtEnum.BluetoothProfile.A2DP.value])):
+ self.log.error("Failed to connect headset.")
+ return False
+
+ if not disconnect_headset_from_dev(
+ self.pri_ad, self.audio_receiver.mac_address,
+ [BtEnum.BluetoothProfile.A2DP.value]):
+ self.log.error("Failed to disconnect headset.")
+ return False
+ return True
+
+ def connect_disconnect_headset(self):
+ """Initiates connection to paired headset and disconnects headset.
+
+ Returns:
+ True if successful False otherwise.
+ """
+ for i in range(0, self.iterations):
+ self.pri_ad.droid.bluetoothConnectBonded(
+ self.audio_receiver.mac_address)
+ time.sleep(BLUETOOTH_WAIT_TIME)
+ if not self.pri_ad.droid.bluetoothIsDeviceConnected(
+ self.audio_receiver.mac_address):
+ return False
+ self.pri_ad.droid.bluetoothDisconnectConnected(
+ self.audio_receiver.mac_address)
+ return True
+
+ def perform_classic_discovery_with_iperf(self):
+ """Wrapper function to start iperf traffic and classic discovery"""
+ self.run_iperf_and_get_result()
+ if not perform_classic_discovery(self.pri_ad):
+ return False
+ return self.teardown_result()
+
+ def connect_disconnect_a2dp_headset_with_iperf(self):
+ """Wrapper function to start iperf traffic and connect/disconnect
+ to headset for N iterations.
+ """
+ self.run_iperf_and_get_result()
+ if not self.connect_disconnect_a2dp_headset():
+ return False
+ return self.teardown_result()
+
+ def music_streaming_bluetooth_discovery_with_iperf(self):
+ """Wrapper function to start iperf traffic, music streaming and
+ classic discovery.
+ """
+ self.run_iperf_and_get_result()
+ tasks = [(music_play_and_check,
+ (self.pri_ad, self.audio_receiver.mac_address,
+ self.music_file_to_play, self.iperf["duration"])),
+ (perform_classic_discovery, (self.pri_ad,))]
+ if not multithread_func(self.log, tasks):
+ return False
+ return self.teardown_result()
+
+ def music_streaming_with_iperf(self):
+ """Wrapper function to start iperf traffic and music streaming."""
+ self.run_iperf_and_get_result()
+ if not music_play_and_check(
+ self.pri_ad, self.audio_receiver.mac_address,
+ self.music_file_to_play, self.iperf["duration"]):
+ return False
+ return self.teardown_result()
+
+ def music_streaming_avrcp_controls_with_iperf(self):
+ """Wrapper function to start iperf traffic, music streaming and avrcp
+ controls.
+ """
+ self.run_iperf_and_get_result()
+ tasks = [(music_play_and_check,
+ (self.pri_ad, self.audio_receiver.mac_address,
+ self.music_file_to_play, self.iperf["duration"])),
+ (self.avrcp_actions, ())]
+ if not multithread_func(self.log, tasks):
+ return False
+ return self.teardown_result()
+
+ def music_streaming_discovery_avrcp_controls_with_iperf(self):
+ """Wrapper function to start iperf traffic, music streaming, bluetooth
+ discovery and avrcp controls.
+ """
+ self.run_iperf_and_get_result()
+ tasks = [(music_play_and_check,
+ (self.pri_ad, self.audio_receiver.mac_address,
+ self.music_file_to_play, self.iperf["duration"])),
+ (perform_classic_discovery, (self.pri_ad,)),
+ (self.avrcp_actions, ())]
+ if not multithread_func(self.log, tasks):
+ return False
+ return self.teardown_result()
+
+ def music_streaming_ble_connection_with_iperf(self):
+ """Wrapper function to start iperf traffic, music streaming and ble
+ connection.
+ """
+ self.run_iperf_and_get_result()
+ tasks = [(music_play_and_check,
+ (self.pri_ad, self.audio_receiver.mac_address,
+ self.music_file_to_play, self.iperf["duration"])),
+ (connect_ble, (self.pri_ad, self.sec_ad))]
+ if not multithread_func(self.log, tasks):
+ return False
+ return self.teardown_result()
+
+ def test_inquiry_after_headset_connection_with_tcp_ul(self):
+ """Starts TCP-uplink traffic, start inquiry after bluetooth connection.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test functional behaviour of bluetooth discovery
+ after connecting to headset.
+
+ Steps:
+ 1. Run TCP-uplink traffic.
+ 2. Start bluetooth discovery when headset is connected.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_009
+ """
+ if not self.perform_classic_discovery_with_iperf():
+ return False
+ return True
+
+ def test_inquiry_after_headset_connection_with_tcp_dl(self):
+ """Starts TCP-downlink traffic, start inquiry after bluetooth connection.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test functional behaviour of bluetooth discovery
+ after connecting to headset.
+
+ Steps:
+ 1. Run TCP-downlink traffic.
+ 2. Start bluetooth discovery when headset is connected.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_010
+ """
+ if not self.perform_classic_discovery_with_iperf():
+ return False
+ return True
+
+ def test_inquiry_after_headset_connection_with_udp_ul(self):
+ """Starts UDP-uplink traffic, start inquiry after bluetooth connection.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test functional behaviour of bluetooth discovery
+ after connecting to headset.
+
+ Steps:
+ 1. Run UDP-uplink traffic.
+ 2. Start bluetooth discovery when headset is connected.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_011
+ """
+ if not self.perform_classic_discovery_with_iperf():
+ return False
+ return True
+
+ def test_inquiry_after_headset_connection_with_udp_dl(self):
+ """Starts UDP-downlink traffic, start inquiry after bluetooth connection.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test functional behaviour of bluetooth discovery
+ after connecting to headset.
+
+ Steps:
+ 1. Run UDP-downlink traffic.
+ 2. Start bluetooth discovery when headset is connected.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_012
+ """
+ if not self.perform_classic_discovery_with_iperf():
+ return False
+ return True
+
+ def test_connect_disconnect_a2dp_headset_with_tcp_ul(self):
+ """Starts TCP-uplink traffic and connect/disconnect a2dp headset.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test functional behaviour of connection and
+ disconnection to a2dp headset.
+
+ Steps:
+ 1. Run TCP-uplink traffic.
+ 2. Connect and disconnect A2DP headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_013
+ """
+ if not self.connect_disconnect_a2dp_headset_with_iperf():
+ return False
+ return True
+
+ def test_connect_disconnect_a2dp_headset_with_tcp_dl(self):
+ """Starts TCP-downlink traffic and connect/disconnect a2dp headset.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test functional behaviour of connection and
+ disconnection to a2dp headset.
+
+ Steps:
+ 1. Run TCP-downlink traffic.
+ 2. Connect and disconnect A2DP headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_014
+ """
+ if not self.connect_disconnect_a2dp_headset_with_iperf():
+ return False
+ return True
+
+ def test_connect_disconnect_a2dp_headset_with_udp_ul(self):
+ """Starts UDP-uplink traffic and connect/disconnect a2dp headset.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test functional behaviour of connection and
+ disconnection to a2dp headset.
+
+ Steps:
+ 1. Run UDP-uplink traffic.
+ 2. Connect and disconnect A2DP headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_015
+ """
+ if not self.connect_disconnect_a2dp_headset_with_iperf():
+ return False
+ return True
+
+ def test_connect_disconnect_a2dp_headset_with_udp_dl(self):
+ """Starts UDP-downlink traffic and connect/disconnect a2dp headset.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test functional behaviour of connection and
+ disconnection to a2dp headset.
+
+ Steps:
+ 1. Run UDP-downlink traffic.
+ 2. Connect and disconnect A2DP headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_016
+ """
+ if not self.connect_disconnect_a2dp_headset_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_bluetooth_discovery_with_tcp_ul(self):
+ """Starts TCP-uplink traffic, with music streaming to a2dp headset and
+ bluetooth discovery.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test functional behaviour of a2dp music streaming
+ and bluetooth discovery.
+
+ Steps:
+ 1. Run TCP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Start bluetooth discovery on android device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_017
+ """
+ if not self.music_streaming_bluetooth_discovery_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_bluetooth_discovery_with_tcp_dl(self):
+ """Starts TCP-downlink traffic, with music streaming to a2dp headset
+ and bluetooth discovery.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test functional behaviour of a2dp music streaming
+ and bluetooth discovery.
+
+ Steps:
+ 1. Run TCP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Start bluetooth discovery on android device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_018
+ """
+ if not self.music_streaming_bluetooth_discovery_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_bluetooth_discovery_with_udp_ul(self):
+ """Starts UDP-uplink traffic, with music streaming to a2dp headset and
+ bluetooth discovery.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test functional behaviour of a2dp music streaming
+ and bluetooth discovery.
+
+ Steps:
+ 1. Run UDP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Start bluetooth discovery on android device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_019
+ """
+ if not self.music_streaming_bluetooth_discovery_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_bluetooth_discovery_with_udp_dl(self):
+ """Starts UDP-downlink traffic, with music streaming to a2dp headset
+ and bluetooth discovery.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test functional behaviour of a2dp music streaming
+ and bluetooth discovery.
+
+ Steps:
+ 1. Run UDP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Start bluetooth discovery on android device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_020
+ """
+ if not self.music_streaming_bluetooth_discovery_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_with_tcp_ul(self):
+ """Starts TCP-uplink traffic with music streaming to a2dp headset.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming.
+
+ Steps:
+ 1. Run TCP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_021
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_with_tcp_dl(self):
+ """Starts TCP-downlink traffic with music streaming to a2dp headset.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming.
+
+ Steps:
+ 1. Run TCP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_022
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_with_udp_ul(self):
+ """Starts UDP-uplink traffic with music streaming to a2dp headset.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming.
+
+ Steps:
+ 1. Run UDP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_023
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_with_udp_dl(self):
+ """Starts UDP-downlink traffic with music streaming to a2dp headset.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming.
+
+ Steps:
+ 1. Run UDP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_024
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_avrcp_controls_with_tcp_ul(self):
+ """Starts TCP-uplink traffic with music streaming and avrcp controls.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming and avrcp controls.
+
+ 1. Run TCP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_025
+ """
+ if not self.music_streaming_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_avrcp_controls_with_tcp_dl(self):
+ """Starts TCP-downlink traffic with music streaming and avrcp controls.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming and avrcp controls.
+
+ 1. Run TCP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_026
+ """
+ if not self.music_streaming_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_avrcp_controls_with_udp_ul(self):
+ """Starts UDP-uplink traffic with music streaming and avrcp controls.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming and avrcp controls.
+
+ 1. Run UDP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_027
+ """
+ if not self.music_streaming_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_avrcp_controls_with_udp_dl(self):
+ """Starts UDP-downlink traffic with music streaming and avrcp controls.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming and avrcp controls.
+
+ 1. Run UDP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_028
+ """
+ if not self.music_streaming_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_avrcp_controls_bluetooth_discovery_tcp_ul(self):
+ """Starts TCP-uplink traffic with music streaming, avrcp controls and
+ bluetooth discovery.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming, avrcp controls and bluetooth discovery.
+
+ 1. Run TCP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+ 4. Start bluetooth discovery.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_029
+ """
+ if not self.music_streaming_discovery_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_avrcp_controls_bluetooth_discovery_tcp_dl(self):
+ """Starts TCP-downlink traffic with music streaming, avrcp controls and
+ bluetooth discovery.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming, avrcp controls and bluetooth discovery.
+
+ 1. Run TCP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+ 4. Start bluetooth discovery.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_030
+ """
+ if not self.music_streaming_discovery_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_avrcp_controls_bluetooth_discovery_udp_ul(self):
+ """Starts UDP-uplink traffic with music streaming, avrcp controls and
+ bluetooth discovery.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming, avrcp controls and bluetooth discovery.
+
+ 1. Run UDP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+ 4. Start bluetooth discovery.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_031
+ """
+ if not self.music_streaming_discovery_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_avrcp_controls_bluetooth_discovery_udp_dl(self):
+ """Starts UDP-downlink traffic with music streaming, avrcp controls and
+ bluetooth discovery.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming, avrcp controls and bluetooth discovery.
+
+ 1. Run UDP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+ 4. Start bluetooth discovery.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_032
+ """
+ if not self.music_streaming_discovery_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_connect_disconnect_headset_with_fping(self):
+ """Starts fping, along with connection and disconnection of headset.
+
+ This test is to start fping between host machine and android device
+ with connection and disconnection of paired headset.
+
+ Steps:
+ 1. Start fping.
+ 2. Enable bluetooth
+ 3. Connect bluetooth headset.
+ 4. Disconnect bluetooth headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_076
+ """
+ args = [lambda: start_fping(self.pri_ad, self.iperf["duration"])]
+ self.run_thread(args)
+ if not self.connect_disconnect_headset():
+ return False
+ return self.teardown_thread()
+
+ def test_a2dp_streaming_with_fping(self):
+ """Starts fping along with a2dp streaming.
+
+ This test is to start fping between host machine and android device
+ and test the functional behaviour of music streaming to a2dp headset.
+
+ Steps:
+ 1. Start fping.
+ 1. Start media play on android device and check for music streaming.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_077
+ """
+ args = [lambda: start_fping(self.pri_ad, self.iperf["duration"])]
+ self.run_thread(args)
+ if not music_play_and_check(
+ self.pri_ad, self.audio_receiver.mac_address,
+ self.music_file_to_play, self.iperf["duration"]):
+ return False
+ return self.teardown_thread()
+
+ def test_connect_disconnect_headset_toggle_screen_state_with_fping(self):
+ """Starts fping along with connection and disconnection of the headset.
+
+ This test is to start fping between host machine and android device
+ and test the functional behaviour of connection and disconnection of
+ the paired headset when screen is off and on.
+
+ Steps:
+ 1. Start fping.
+ 2. Connect bluetooth headset.
+ 4. Disconnect bluetooth headset.
+ 5. Screen on/off.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_079
+ """
+ tasks = [(start_fping, (self.pri_ad, self.iperf["duration"])),
+ (self.connect_disconnect_headset, ()),
+ (toggle_screen_state, (self.pri_ad, self.iterations))]
+ if not multithread_func(self.log, tasks):
+ return False
+ return self.teardown_thread()
+
+ def test_a2dp_streaming_toggle_screen_state_with_fping(self):
+ """Starts fping along with a2dp streaming.
+
+ This test is to start fping with traffic between host machine and
+ android device and test the functional behaviour of a2dp streaming when
+ screen turned on or off.
+
+ Steps:
+ 1. Start fping.
+ 2. Start media play on android device and check for music streaming.
+ 3. Start screen on/off of android device multiple times.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_080
+ """
+ tasks = [(start_fping, (self.pri_ad, self.iperf["duration"])),
+ (music_play_and_check,
+ (self.pri_ad, self.audio_receiver.mac_address,
+ self.music_file_to_play, self.iperf["duration"])),
+ (toggle_screen_state, (self.pri_ad, self.iterations))]
+ if not multithread_func(self.log, tasks):
+ return False
+ return self.teardown_thread()
+
+ def test_a2dp_streaming_ble_connection_with_tcp_ul(self):
+ """Starts TCP-uplink traffic with a2dp streaming and ble connection.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the functional behaviour of ble connection
+ and a2dp streaming.
+
+ Steps:
+ 1. Start TCP-uplink traffic.
+ 2. Start media play on android device and check for music streaming.
+ 3. Initiate ble connection to android device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_084
+ """
+ if not self.music_streaming_ble_connection_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_ble_connection_with_tcp_dl(self):
+ """Starts TCP-downlink traffic with a2dp streaming and ble connection.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the functional behaviour of ble connection
+ and a2dp streaming.
+
+ Steps:
+ 1. Start TCP-downlink traffic.
+ 2. Start media play on android device and check for music streaming.
+ 3. Initiate ble connection to android device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_085
+ """
+ if not self.music_streaming_ble_connection_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/functionality_tests/WlanWithHfpFunctionalityTest.py b/acts/tests/google/coex/functionality_tests/WlanWithHfpFunctionalityTest.py
new file mode 100644
index 0000000..983d4c1
--- /dev/null
+++ b/acts/tests/google/coex/functionality_tests/WlanWithHfpFunctionalityTest.py
@@ -0,0 +1,695 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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.
+
+from acts.test_utils.bt import BtEnum
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_test_utils import connect_dev_to_headset
+from acts.test_utils.coex.coex_test_utils import initiate_disconnect_from_hf
+from acts.test_utils.coex.coex_test_utils import initiate_disconnect_call_dut
+from acts.test_utils.coex.coex_test_utils import multithread_func
+from acts.test_utils.coex.coex_test_utils import pair_and_connect_headset
+from acts.test_utils.coex.coex_test_utils import perform_classic_discovery
+from acts.test_utils.coex.coex_test_utils import connect_wlan_profile
+from acts.test_utils.coex.coex_test_utils import toggle_screen_state
+from acts.test_utils.coex.coex_test_utils import setup_tel_config
+from acts.test_utils.coex.coex_test_utils import start_fping
+from acts.test_utils.tel.tel_test_utils import hangup_call
+from acts.test_utils.tel.tel_test_utils import initiate_call
+
+BLUETOOTH_WAIT_TIME = 2
+
+
+class WlanWithHfpFunctionalityTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["sim_conf_file"]
+ self.unpack_userparams(req_params)
+ self.ag_phone_number, self.re_phone_number = setup_tel_config(
+ self.pri_ad, self.sec_ad, self.sim_conf_file)
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.audio_receiver.pairing_mode()
+ if not pair_and_connect_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ set([BtEnum.BluetoothProfile.HEADSET.value])):
+ self.log.error("Failed to pair and connect to headset.")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.audio_receiver.clean_up()
+
+ def call_from_sec_ad_to_pri_ad(self):
+ """Initiates the call from secondary device and accepts the call
+ from HF.
+
+ Steps:
+ 1. Initiate call from secondary device to primary device.
+ 2. Accept the call from HF.
+ 3. Hangup the call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ if not initiate_call(self.log, self.sec_ad, self.ag_phone_number):
+ self.log.error("Failed to initiate call")
+ return False
+ if not self.audio_receiver.accept_call():
+ self.log.error("Failed to answer call from HF.")
+ return False
+ if not hangup_call(self.log, self.pri_ad):
+ self.log.error("Failed to hangup call.")
+ return False
+ return False
+
+ def connect_to_headset_when_turned_off_with_iperf(self):
+ """Wrapper function to start iperf and test connection to headset
+ when it is turned off.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ self.run_iperf_and_get_result()
+ self.audio_receiver.clean_up()
+ if not connect_dev_to_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ set([BtEnum.BluetoothProfile.HEADSET.value])):
+ self.log.error("Failed to connect to headset.")
+ return True
+ return False
+
+ def check_headset_reconnection_with_iperf(self):
+ """Wrapper function to start iperf and check behaviour of hfp
+ reconnection."""
+ self.run_iperf_and_get_result()
+ self.audio_receiver.clean_up()
+ self.audio_receiver.power_on()
+ if not self.pri_ad.droid.bluetoothIsDeviceConnected(
+ self.audio_receiver.mac_address):
+ self.log.error("Device not found in connected list")
+ return False
+ return self.teardown_result()
+
+ def initiate_call_from_hf_with_iperf(self):
+ """Wrapper function to start iperf and initiate call"""
+ self.run_iperf_and_get_result()
+ if not initiate_disconnect_from_hf(
+ self.audio_receiver, self.pri_ad, self.sec_ad,
+ self.iperf["duration"]):
+ return False
+ return self.teardown_result()
+
+ def initiate_call_from_hf_bt_discovery_with_iperf(self):
+ """Wrapper function to start iperf, initiate call and perform classic
+ discovery.
+ """
+ self.run_iperf_and_get_result()
+ tasks = [(initiate_disconnect_from_hf, (
+ self.audio_receiver, self.pri_ad, self.sec_ad,
+ self.iperf["duration"])),
+ (perform_classic_discovery, (self.pri_ad,))]
+ if not multithread_func(self.log, tasks):
+ return False
+ return self.teardown_result()
+
+ def initiate_call_associate_ap_with_iperf(self):
+ """Wrapper function to initiate call from primary device and associate
+ with access point and start iperf traffic."""
+ args = [
+ lambda: initiate_disconnect_call_dut(
+ self.pri_ad, self.sec_ad, self.iperf["duration"],
+ self.re_phone_number)
+ ]
+ self.run_thread(args)
+ if not connect_wlan_profile(self.pri_ad, self.network):
+ return False
+ self.run_iperf_and_get_result()
+ return self.teardown_result()
+
+ def test_hfp_call_with_tcp_ul(self):
+ """Starts TCP-uplink traffic with hfp connection.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the functional behaviour of hfp connection
+ and call.
+
+ Steps:.
+ 1. Start TCP-uplink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_042
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_hfp_call_with_tcp_dl(self):
+ """Starts TCP-downlink traffic with hfp connection.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the functional behaviour of hfp connection
+ and call.
+
+ Steps:.
+ 1. Start TCP-downlink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_043
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_hfp_call_with_udp_ul(self):
+ """Starts UDP-uplink traffic with hfp connection.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the functional behaviour of hfp connection
+ and call.
+
+ Steps:.
+ 1. Start UDP-uplink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_044
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_hfp_call_with_udp_dl(self):
+ """Starts UDP-downlink traffic with hfp connection.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the functional behaviour of hfp connection
+ and call.
+
+ Steps:.
+ 1. Start UDP-downlink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_045
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_hfp_call_bluetooth_discovery_with_tcp_ul(self):
+ """Starts TCP-uplink traffic with hfp connection and bluetooth
+ discovery.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the functional behaviour of hfp connection
+ and call and bluetooth discovery.
+
+ Steps:.
+ 1. Start TCP-uplink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+ 3. Start bluetooth discovery.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_046
+ """
+ if not self.initiate_call_from_hf_bt_discovery_with_iperf():
+ return False
+ return True
+
+ def test_hfp_call_bluetooth_discovery_with_tcp_dl(self):
+ """Starts TCP-downlink traffic with hfp connection and bluetooth
+ discovery.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the functional behaviour of hfp connection
+ and call and bluetooth discovery.
+
+ Steps:.
+ 1. Start TCP-downlink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+ 3. Start bluetooth discovery.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_047
+ """
+ if not self.initiate_call_from_hf_bt_discovery_with_iperf():
+ return False
+ return True
+
+ def test_hfp_call_bluetooth_discovery_with_udp_ul(self):
+ """Starts UDP-uplink traffic with hfp connection and bluetooth
+ discovery.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the functional behaviour of hfp connection
+ and call and bluetooth discovery.
+
+ Steps:.
+ 1. Start UDP-uplink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+ 3. Start bluetooth discovery.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_048
+ """
+ if not self.initiate_call_from_hf_bt_discovery_with_iperf():
+ return False
+ return True
+
+ def test_hfp_call_bluetooth_discovery_with_udp_dl(self):
+ """Starts UDP-downlink traffic with hfp connection and bluetooth
+ discovery.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the functional behaviour of hfp connection
+ and call and bluetooth discovery.
+
+ Steps:.
+ 1. Start UDP-downlink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+ 3. Start bluetooth discovery.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_049
+ """
+ if not self.initiate_call_from_hf_bt_discovery_with_iperf():
+ return False
+ return True
+
+ def test_hfp_call_and_associate_ap_with_tcp_ul(self):
+ """Starts TCP-uplink traffic with hfp call.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test functional behaviour of hfp call connection
+ while associating with AP.
+
+ Steps:
+ 1. Initiate call from HF and disconnect call from primary device.
+ 2. Associate with AP.
+ 3. Start TCP-uplink traffic.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_050
+ """
+ if not self.initiate_call_associate_ap_with_iperf():
+ return False
+ return True
+
+ def test_hfp_call_and_associate_ap_with_tcp_dl(self):
+ """Starts TCP-downlink traffic with hfp call.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test functional behaviour of hfp call connection
+ while associating with AP.
+
+ Steps:
+ 1. Initiate call from HF and disconnect call from primary device.
+ 2. Associate with AP.
+ 3. Start TCP-downlink traffic.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_051
+ """
+ if not self.initiate_call_associate_ap_with_iperf():
+ return False
+ return True
+
+ def test_hfp_call_and_associate_ap_with_udp_ul(self):
+ """Starts UDP-uplink traffic with hfp call.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test functional behaviour of hfp call connection
+ while associating with AP.
+
+ Steps:
+ 1. Initiate call from HF and disconnect call from primary device.
+ 2. Associate with AP.
+ 3. Start UDP-uplink traffic.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_052
+ """
+ if not self.initiate_call_associate_ap_with_iperf():
+ return False
+ return True
+
+ def test_hfp_call_and_associate_ap_with_udp_dl(self):
+ """Starts UDP-downlink traffic with hfp call.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test functional behaviour of hfp call connection
+ while associating with AP.
+
+ Steps:
+ 1. Initiate call from HF and disconnect call from primary device.
+ 2. Associate with AP.
+ 3. Start UDP-downlink traffic.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_053
+ """
+ if not self.initiate_call_associate_ap_with_iperf():
+ return False
+ return True
+
+ def test_hfp_redial_with_tcp_ul(self):
+ """Starts TCP-uplink traffic with hfp connection.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device with hfp connection.
+
+ Steps:
+ 1. Start TCP-uplink traffic.
+ 2. Initiate call from HF(last dialed number) and disconnect call
+ from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_054
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_hfp_redial_with_tcp_dl(self):
+ """Starts TCP-downlink traffic with hfp connection.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device with hfp connection.
+
+ Steps:
+ 1. Start TCP-downlink traffic.
+ 2. Initiate call from HF(last dialed number) and disconnect call
+ from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_055
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_hfp_redial_with_udp_ul(self):
+ """Starts UDP-uplink traffic with hfp connection.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device with hfp connection.
+
+ Steps:
+ 1. Start UDP-uplink traffic.
+ 2. Initiate call from HF(last dialed number) and disconnect call
+ from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_056
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_hfp_redial_with_udp_dl(self):
+ """Starts UDP-downlink traffic with hfp connection.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device with hfp connection.
+
+ Steps:
+ 1. Start UDP-downlink traffic.
+ 2. Initiate call from HF(last dialed number) and disconnect call
+ from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_057
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_hfp_reconnection_with_tcp_ul(self):
+ """Starts TCP-uplink traffic with hfp reconnection.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the functional behaviour of hfp reconnection.
+
+ Steps:.
+ 1. Start TCP-uplink traffic.
+ 2. Connect HF to DUT.
+ 3. Disconnect HF from DUT.
+ 4. Switch off the headset and turn ON HF to reconnect.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_062
+ """
+ if not self.check_headset_reconnection_with_iperf():
+ return False
+ return True
+
+ def test_hfp_reconnection_with_tcp_dl(self):
+ """Starts TCP-downlink traffic with hfp reconnection.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the functional behaviour of hfp reconnection.
+
+ Steps:.
+ 1. Start TCP-downlink traffic.
+ 2. Connect HF to DUT.
+ 3. Disconnect HF from DUT.
+ 4. Switch off the headset and turn ON HF to reconnect.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_063
+ """
+ if not self.check_headset_reconnection_with_iperf():
+ return False
+ return True
+
+ def test_hfp_reconnection_with_udp_ul(self):
+ """Starts UDP-uplink traffic with hfp reconnection.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the functional behaviour of hfp reconnection.
+
+ Steps:.
+ 1. Start UDP-uplink traffic.
+ 2. Connect HF to DUT.
+ 3. Disconnect HF from DUT.
+ 4. Switch off the headset and turn ON HF to reconnect.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_064
+ """
+ if not self.check_headset_reconnection_with_iperf():
+ return False
+ return True
+
+ def test_hfp_reconnection_with_udp_dl(self):
+ """Starts UDP-downlink traffic with hfp reconnection.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the functional behaviour of hfp reconnection.
+
+ Steps:.
+ 1. Start UDP-downlink traffic.
+ 2. Connect HF to DUT.
+ 3. Disconnect HF from DUT.
+ 4. Switch off the headset and turn ON HF to reconnect.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_065
+ """
+ if not self.check_headset_reconnection_with_iperf():
+ return False
+ return True
+
+ def test_hfp_connection_when_hf_turned_off_with_tcp_ul(self):
+ """Starts TCP-uplink traffic with hfp connection.
+
+ This test is to start TCP-Uplink traffic between host machine and
+ android device and test the functional behaviour of hfp connection
+ when device is off.
+
+ Steps:
+ 1. Start TCP-uplink traffic.
+ 2. Make sure headset is turned off.
+ 3. Initiate hfp connection to headset from DUT.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_072
+ """
+ if not self.connect_to_headset_when_turned_off_with_iperf():
+ return False
+ return self.teardown_result()
+
+ def test_hfp_connection_when_hf_turned_off_with_tcp_dl(self):
+ """Starts TCP-downlink traffic with hfp connection.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the functional behaviour of hfp connection
+ when device is off.
+
+ Steps:
+ 1. Start TCP-downlink traffic.
+ 2. Make sure headset is turned off.
+ 3. Initiate hfp connection to headset from DUT.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_073
+ """
+ if not self.connect_to_headset_when_turned_off_with_iperf():
+ return False
+ return self.teardown_result()
+
+ def test_hfp_connection_when_hf_turned_off_with_udp_ul(self):
+ """Starts UDP-uplink traffic with hfp connection.
+
+ This test is to start UDP-Uplink traffic between host machine and
+ android device and test the functional behaviour of hfp connection
+ when device is off.
+
+ Steps:
+ 1. Start UDP-uplink traffic.
+ 2. Make sure headset is turned off.
+ 3. Initiate hfp connection to headset from DUT.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_074
+ """
+ if not self.connect_to_headset_when_turned_off_with_iperf():
+ return False
+ return self.teardown_result()
+
+ def test_hfp_connection_when_hf_turned_off_with_udp_dl(self):
+ """Starts UDP-downlink traffic with hfp connection.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the functional behaviour of hfp connection
+ when device is off.
+
+ Steps:
+ 1. Start UDP-downlink traffic.
+ 2. Make sure headset is turned off.
+ 3. Initiate hfp connection to headset from DUT.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_075
+ """
+ if not self.connect_to_headset_when_turned_off_with_iperf():
+ return False
+ return self.teardown_result()
+
+ def test_hfp_call_with_fping(self):
+ """Starts fping with hfp call connection.
+
+ This test is to start fping between host machine and android device
+ and test the functional behaviour of hfp call.
+
+ Steps:
+ 1. Start fping from AP backend to android device.
+ 1. Initiate call from headset to secondary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_078
+ """
+ args = [lambda: start_fping(self.pri_ad, self.iperf["duration"])]
+ self.run_thread(args)
+ if not initiate_disconnect_from_hf(
+ self.audio_receiver,self.pri_ad, self.sec_ad,
+ self.iperf["duration"]):
+ return False
+ return self.teardown_thread()
+
+ def test_hfp_call_toggle_screen_state_with_fping(self):
+ """Starts fping with hfp call connection.
+
+ This test is to start fping between host machine and android device
+ and test the functional behaviour of hfp call when toggling the
+ screen state.
+
+ Steps:
+ 1. Start fping from AP backend.
+ 1. Initiate call from primary device headset to secondary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_081
+ """
+ tasks = [(start_fping, (self.pri_ad, self.iperf["duration"])),
+ (initiate_disconnect_from_hf, (
+ self.audio_receiver, self.pri_ad, self.sec_ad,
+ self.iperf["duration"])),
+ (toggle_screen_state, (self.pri_ad, self.iterations))]
+ if not multithread_func(self.log, tasks):
+ return False
+ return True
diff --git a/acts/tests/google/coex/performance_tests/CoexBasicPerformanceTest.py b/acts/tests/google/coex/performance_tests/CoexBasicPerformanceTest.py
new file mode 100644
index 0000000..98603d2
--- /dev/null
+++ b/acts/tests/google/coex/performance_tests/CoexBasicPerformanceTest.py
@@ -0,0 +1,164 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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.
+
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_test_utils import perform_classic_discovery
+
+
+class CoexBasicPerformanceTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def run_iperf_and_perform_discovery(self):
+ """Starts iperf client on host machine and bluetooth discovery
+ simultaneously.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ self.run_iperf_and_get_result()
+ if not perform_classic_discovery(self.pri_ad):
+ return False
+ return self.teardown_result()
+
+ def test_performance_with_bt_on_tcp_ul(self):
+ """Check throughput when bluetooth on.
+
+ This test is to start TCP-Uplink traffic between host machine and
+ android device and check the throughput when bluetooth is on.
+
+ Steps:
+ 1. Start TCP-uplink traffic when bluetooth is on.
+
+ Test Id: Bt_CoEx_kpi_005
+ """
+ self.run_iperf_and_get_result()
+ self.teardown_result()
+
+ def test_performance_with_bt_on_tcp_dl(self):
+ """Check throughput when bluetooth on.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and check the throughput when bluetooth is on.
+
+ Steps:
+ 1. Start TCP-downlink traffic when bluetooth is on.
+
+ Test Id: Bt_CoEx_kpi_006
+ """
+ self.run_iperf_and_get_result()
+ self.teardown_result()
+
+ def test_performance_with_bt_on_udp_ul(self):
+ """Check throughput when bluetooth on.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and check the throughput when bluetooth is on.
+
+ Steps:
+ 1. Start UDP-uplink traffic when bluetooth is on.
+
+ Test Id: Bt_CoEx_kpi_007
+ """
+ self.run_iperf_and_get_result()
+ self.teardown_result()
+
+ def test_performance_with_bt_on_udp_dl(self):
+ """Check throughput when bluetooth on.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and check the throughput when bluetooth is on.
+
+ Steps:
+ 1. Start UDP-downlink traffic when bluetooth is on.
+
+ Test Id: Bt_CoEx_kpi_008
+ """
+ self.run_iperf_and_get_result()
+ self.teardown_result()
+
+ def test_performance_with_bluetooth_discovery_tcp_ul(self):
+ """Check throughput when bluetooth discovery is ongoing.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and bluetooth discovery and checks throughput.
+
+ Steps:
+ 1. Start TCP-uplink traffic and bluetooth discovery parallelly.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_kpi_009
+ """
+ if not self.run_iperf_and_perform_discovery():
+ return False
+ return True
+
+ def test_performance_with_bluetooth_discovery_tcp_dl(self):
+ """Check throughput when bluetooth discovery is ongoing.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and bluetooth discovery and checks throughput.
+
+ Steps:
+ 1. Start TCP-downlink traffic and bluetooth discovery parallelly.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_kpi_010
+ """
+ if not self.run_iperf_and_perform_discovery():
+ return False
+ return True
+
+ def test_performance_with_bluetooth_discovery_udp_ul(self):
+ """Check throughput when bluetooth discovery is ongoing.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and bluetooth discovery and checks throughput.
+
+ Steps:
+ 1. Start UDP-uplink traffic and bluetooth discovery parallelly.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_kpi_011
+ """
+ if not self.run_iperf_and_perform_discovery():
+ return False
+ return True
+
+ def test_performance_with_bluetooth_discovery_udp_dl(self):
+ """Check throughput when bluetooth discovery is ongoing.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and bluetooth discovery and checks throughput.
+
+ Steps:
+ 1. Start UDP-downlink traffic and bluetooth discovery parallelly.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_kpi_012
+ """
+ if not self.run_iperf_and_perform_discovery():
+ return False
+ return True
diff --git a/acts/tests/google/coex/performance_tests/CoexBtMultiProfilePerformanceTest.py b/acts/tests/google/coex/performance_tests/CoexBtMultiProfilePerformanceTest.py
new file mode 100644
index 0000000..7616b7a
--- /dev/null
+++ b/acts/tests/google/coex/performance_tests/CoexBtMultiProfilePerformanceTest.py
@@ -0,0 +1,197 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 time
+
+from acts.test_utils.bt import BtEnum
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.car.tel_telecom_utils import wait_for_dialing
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_test_utils import connect_dev_to_headset
+from acts.test_utils.coex.coex_test_utils import music_play_and_check_via_app
+from acts.test_utils.coex.coex_test_utils import pair_and_connect_headset
+from acts.test_utils.coex.coex_test_utils import setup_tel_config
+from acts.test_utils.coex.coex_test_utils import connect_wlan_profile
+from acts.test_utils.tel.tel_test_utils import hangup_call
+from acts.test_utils.tel.tel_test_utils import initiate_call
+from acts.test_utils.tel.tel_test_utils import wait_and_answer_call
+
+
+class CoexBtMultiProfilePerformanceTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["sim_conf_file", "music_play_time"]
+ self.unpack_userparams(req_params)
+ self.ag_phone_number, self.re_phone_number = setup_tel_config(
+ self.pri_ad, self.sec_ad, self.sim_conf_file)
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.audio_receiver.pairing_mode()
+ if not pair_and_connect_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ set([BtEnum.BluetoothProfile.HEADSET.value]) and
+ set([BtEnum.BluetoothProfile.A2DP.value])):
+ self.log.error("Failed to pair and connect to headset")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.audio_receiver.clean_up()
+
+ def initiate_call_when_a2dp_streaming_on(self):
+ """Initiates HFP call, then check for call is present or not.
+
+ Disconnect a2dp profile and then connect HFP profile and
+ answer the call from reference device.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ if not initiate_call(self.log, self.pri_ad, self.re_phone_number):
+ self.log.error("Failed to initiate call")
+ return False
+ if wait_for_dialing(self.log, self.pri_ad):
+ self.pri_ad.droid.bluetoothDisconnectConnectedProfile(
+ self.audio_receiver.mac_address,
+ [BtEnum.BluetoothProfile.A2DP.value])
+ if not connect_dev_to_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ [BtEnum.BluetoothProfile.HEADSET.value]):
+ return False
+ if not wait_and_answer_call(self.log, self.sec_ad):
+ self.log.error("Failed to answer call in second device")
+ return False
+ time.sleep(self.iperf["duration"])
+ if not hangup_call(self.log, self.pri_ad):
+ self.log.error("Failed to hangup call")
+ return False
+ return True
+
+ def play_music_and_connect_wifi(self):
+ """Perform a2dp music streaming and scan and connect to wifi
+ network
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ if not music_play_and_check_via_app(
+ self.pri_ad, self.audio_receiver.mac_address):
+ self.log.error("Failed to stream music file")
+ return False
+ if not connect_wlan_profile(self.pri_ad, self.network):
+ return False
+ return True
+
+ def initiate_call_when_a2dp_streaming_with_iperf(self):
+ """Wrapper function to initiate call when a2dp streaming and starts
+ iperf.
+ """
+ if not self.play_music_and_connect_wifi():
+ return False
+ self.run_iperf_and_get_result()
+ if not self.initiate_call_when_a2dp_streaming_on():
+ return False
+ return self.teardown_result()
+
+ def test_performance_a2dp_streaming_hfp_call_tcp_ul(self):
+ """Check performance when a2dp streaming and hfp call..
+
+ This test is to check wifi performance when a2dp streaming and
+ hfp call performed sequentially with TCP-uplink traffic.
+
+ Steps:
+ 1.Enable bluetooth.
+ 2.Start a2dp streaming.
+ 3.Run TCP-uplink traffic.
+ 4.Initiate hfp call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_041
+ """
+ if not self.initiate_call_when_a2dp_streaming_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_hfp_call_tcp_dl(self):
+ """Check performance when a2dp streaming and hfp call..
+
+ This test is to check wifi performance when a2dp streaming and
+ hfp call performed sequentially with TCP-downlink traffic.
+
+ Steps:
+ 1.Enable bluetooth.
+ 2.Start a2dp streaming.
+ 3.Run TCP-downlink traffic.
+ 4.Initiate hfp call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_042
+ """
+ if not self.initiate_call_when_a2dp_streaming_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_hfp_call_udp_ul(self):
+ """Check performance when a2dp streaming and hfp call..
+
+ This test is to check wifi performance when a2dp streaming and
+ hfp call performed sequentially with UDP-uplink traffic.
+
+ Steps:
+ 1.Enable bluetooth.
+ 2.Start a2dp streaming.
+ 3.Run UDP-uplink traffic.
+ 4.Initiate hfp call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_043
+ """
+ if not self.initiate_call_when_a2dp_streaming_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_hfp_call_udp_dl(self):
+ """Check performance when a2dp streaming and hfp call..
+
+ This test is to check wifi performance when a2dp streaming and
+ hfp call performed sequentially with UDP-uplink traffic.
+
+ Steps:
+ 1.Enable bluetooth.
+ 2.Start a2dp streaming.
+ 3.Run UDP-uplink traffic.
+ 4.Initiate hfp call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_044
+ """
+ if not self.initiate_call_when_a2dp_streaming_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/performance_tests/WlanStandalonePerformanceTest.py b/acts/tests/google/coex/performance_tests/WlanStandalonePerformanceTest.py
new file mode 100644
index 0000000..c962efd
--- /dev/null
+++ b/acts/tests/google/coex/performance_tests/WlanStandalonePerformanceTest.py
@@ -0,0 +1,86 @@
+#/usr/bin/env python3.4
+#
+# Copyright (C) 2018 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.
+
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.bt.bt_test_utils import disable_bluetooth
+
+
+class WlanStandalonePerformanceTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ if not disable_bluetooth(self.pri_ad.droid):
+ self.log.info("Failed to disable bluetooth")
+ return False
+
+ def test_performance_wlan_standalone_tcp_ul(self):
+ """Check throughout for wlan standalone.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device for wlan-standalone.
+
+ Steps:
+ 1. Start TCP-uplink traffic.
+
+ Test Id: Bt_CoEx_kpi_001
+ """
+ self.run_iperf_and_get_result()
+ return self.teardown_result()
+
+ def test_performance_wlan_standalone_tcp_dl(self):
+ """Check throughout for wlan standalone.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device for wlan-standalone.
+
+ Steps:
+ 1. Start TCP-downlink traffic.
+
+ Test Id: Bt_CoEx_kpi_002
+ """
+ self.run_iperf_and_get_result()
+ return self.teardown_result()
+
+ def test_performance_wlan_standalone_udp_ul(self):
+ """Check throughout for wlan standalone.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device for wlan-standalone.
+
+ Steps:
+ 1. Start UDP-uplink traffic.
+
+ Test Id: Bt_CoEx_kpi_003
+ """
+ self.run_iperf_and_get_result()
+ return self.teardown_result()
+
+ def test_performance_wlan_standalone_udp_dl(self):
+ """Check throughout for wlan standalone.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device for wlan-standalone.
+
+ Steps:
+ 1. Start UDP-downlink traffic.
+
+ Test Id: Bt_CoEx_kpi_004
+ """
+ self.run_iperf_and_get_result()
+ return self.teardown_result()
diff --git a/acts/tests/google/coex/performance_tests/WlanWithA2dpPerformanceTest.py b/acts/tests/google/coex/performance_tests/WlanWithA2dpPerformanceTest.py
new file mode 100644
index 0000000..99e8361
--- /dev/null
+++ b/acts/tests/google/coex/performance_tests/WlanWithA2dpPerformanceTest.py
@@ -0,0 +1,315 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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.
+
+from acts.test_utils.bt import BtEnum
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_test_utils import music_play_and_check
+from acts.test_utils.coex.coex_test_utils import multithread_func
+from acts.test_utils.coex.coex_test_utils import pair_and_connect_headset
+from acts.test_utils.coex.coex_test_utils import perform_classic_discovery
+
+
+class WlanWithA2dpPerformanceTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+ self.tests = ("test_performance_a2dp_streaming_tcp_ul",)
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.audio_receiver.pairing_mode()
+ if not pair_and_connect_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ set([BtEnum.BluetoothProfile.A2DP.value])):
+ self.log.error("Failed to pair and connect to headset")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.audio_receiver.clean_up()
+
+ def initiate_music_streaming_to_headset_with_iperf(self):
+ """Initiate music streaming to headset and start iperf traffic."""
+ self.run_iperf_and_get_result()
+ if not music_play_and_check(
+ self.pri_ad, self.audio_receiver.mac_address,
+ self.music_file_to_play, self.iperf["duration"]):
+ return False
+ return self.teardown_result()
+
+ def perform_discovery_with_iperf(self):
+ """Starts iperf traffic based on test and perform bluetooth classic
+ discovery.
+ """
+ self.run_iperf_and_get_result()
+ if not perform_classic_discovery(self.pri_ad):
+ return False
+ return self.teardown_result()
+
+ def music_streaming_and_avrcp_controls_with_iperf(self):
+ """Starts iperf traffic based on test and initiate music streaming and
+ check for avrcp controls.
+ """
+ self.run_iperf_and_get_result()
+ tasks = [(music_play_and_check,
+ (self.pri_ad, self.audio_receiver.mac_address,
+ self.music_file_to_play, self.iperf["duration"])),
+ (self.avrcp_actions, ())]
+ if not multithread_func(self.log, tasks):
+ return False
+ return self.teardown_result()
+
+ def test_performance_a2dp_streaming_tcp_ul(self):
+ """Performance test to check throughput when streaming music.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the performance when music streamed to a2dp
+ headset.
+
+ Steps:
+ 1. Start TCP-uplink traffic.
+ 2. Start music streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_013
+ """
+ if not self.initiate_music_streaming_to_headset_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_tcp_dl(self):
+ """Performance test to check throughput when streaming music.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the performance when music streamed to a2dp
+ headset.
+
+ Steps:
+ 1. Start TCP-downlink traffic.
+ 2. Start music streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_014
+ """
+ if not self.initiate_music_streaming_to_headset_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_udp_ul(self):
+ """Performance test to check throughput when streaming music.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the performance when music streamed to a2dp
+ headset.
+
+ Steps:
+ 1. Start UDP-uplink traffic.
+ 2. Start music streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_015
+ """
+ if not self.initiate_music_streaming_to_headset_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_udp_dl(self):
+ """Performance test to check throughput when streaming music.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the performance when music streamed to a2dp
+ headset.
+
+ Steps:
+ 1. Start UDP-downlink traffic.
+ 2. Start music streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_016
+ """
+ if not self.initiate_music_streaming_to_headset_with_iperf():
+ return False
+ return True
+
+ def test_performance_inquiry_after_headset_connection_with_tcp_ul(self):
+ """Performance test to check throughput when bluetooth discovery.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the performance when bluetooth discovery is
+ performed after connecting to headset.
+
+ Steps:
+ 1. Run TCP-uplink traffic.
+ 2. Start bluetooth discovery when headset is connected.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_029
+ """
+ if not self.perform_discovery_with_iperf():
+ return False
+ return True
+
+ def test_performance_inquiry_after_headset_connection_with_tcp_dl(self):
+ """Performance test to check throughput when bluetooth discovery.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the performance when bluetooth discovery is
+ performed after connecting to headset.
+
+ Steps:
+ 1. Run TCP-downlink traffic.
+ 2. Start bluetooth discovery when headset is connected.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_030
+ """
+ if not self.perform_discovery_with_iperf():
+ return False
+ return True
+
+ def test_performance_inquiry_after_headset_connection_with_udp_ul(self):
+ """Performance test to check throughput when bluetooth discovery.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the performance when bluetooth discovery is
+ performed after connecting to headset.
+
+ Steps:
+ 1. Run UDP-uplink traffic.
+ 2. Start bluetooth discovery when headset is connected.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_031
+ """
+ if not self.perform_discovery_with_iperf():
+ return False
+ return True
+
+ def test_performance_inquiry_after_headset_connection_with_udp_dl(self):
+ """Performance test to check throughput when bluetooth discovery.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the performance when bluetooth discovery is
+ performed after connecting to headset.
+
+ Steps:
+ 1. Run UDP-downlink traffic.
+ 2. Start bluetooth discovery when headset is connected.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_032
+ """
+ if not self.perform_discovery_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_avrcp_controls_with_tcp_ul(self):
+ """Performance test to check throughput when music streaming.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the wlan throughput when perfroming a2dp music
+ streaming and avrcp controls.
+
+ 1. Start TCP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_033
+ """
+ if not self.music_streaming_and_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_avrcp_controls_with_tcp_dl(self):
+ """Performance test to check throughput when music streaming.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the wlan throughput when perfroming a2dp music
+ streaming and avrcp controls.
+
+ 1. Start TCP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_034
+ """
+ if not self.music_streaming_and_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_avrcp_controls_with_udp_ul(self):
+ """Performance test to check throughput when music streaming.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the wlan throughput when perfroming a2dp music
+ streaming and avrcp controls.
+
+ 1. Start UDP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_035
+ """
+ if not self.music_streaming_and_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_avrcp_controls_with_udp_dl(self):
+ """Performance test to check throughput when music streaming.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the wlan throughput when perfroming a2dp music
+ streaming and avrcp controls.
+
+ 1. Start UDP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_036
+ """
+ if not self.music_streaming_and_avrcp_controls_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/performance_tests/WlanWithBlePerformanceTest.py b/acts/tests/google/coex/performance_tests/WlanWithBlePerformanceTest.py
new file mode 100644
index 0000000..12dfc13
--- /dev/null
+++ b/acts/tests/google/coex/performance_tests/WlanWithBlePerformanceTest.py
@@ -0,0 +1,300 @@
+#/usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 time
+
+from acts.test_utils.bt.bt_gatt_utils import close_gatt_client
+from acts.test_utils.bt.bt_gatt_utils import disconnect_gatt_connection
+from acts.test_utils.bt.bt_gatt_utils import GattTestUtilsError
+from acts.test_utils.bt.bt_gatt_utils import orchestrate_gatt_connection
+from acts.test_utils.bt.bt_test_utils import generate_ble_scan_objects
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+
+
+class WlanWithBlePerformanceTest(CoexBaseTest):
+ default_timeout = 10
+ adv_instances = []
+ bluetooth_gatt_list = []
+ gatt_server_list = []
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.pri_ad.droid.bluetoothDisableBLE()
+ self.gatt_server_list = []
+ self.adv_instances = []
+
+ def teardown_test(self):
+ CoexBaseTest.teardown_test(self)
+ for bluetooth_gatt in self.bluetooth_gatt_list:
+ self.pri_ad.droid.gattClientClose(bluetooth_gatt)
+ for gatt_server in self.gatt_server_list:
+ self.sec_ad.droid.gattServerClose(gatt_server)
+ for adv in self.adv_instances:
+ self.sec_ad.droid.bleStopBleAdvertising(adv)
+ return True
+
+ def _orchestrate_gatt_disconnection(self, bluetooth_gatt, gatt_callback):
+ """Disconnect gatt connection between two devices.
+
+ Args:
+ bluetooth_gatt: Index of the BluetoothGatt object
+ gatt_callback: Index of gatt callback object.
+
+ Steps:
+ 1. Disconnect gatt connection.
+ 2. Close bluetooth gatt object.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ self.log.info("Disconnecting from peripheral device.")
+ try:
+ disconnect_gatt_connection(self.pri_ad, bluetooth_gatt,
+ gatt_callback)
+ close_gatt_client(self.pri_ad, bluetooth_gatt)
+ if bluetooth_gatt in self.bluetooth_gatt_list:
+ self.bluetooth_gatt_list.remove(bluetooth_gatt)
+ except GattTestUtilsError as err:
+ self.log.error(err)
+ return False
+ return True
+
+ def ble_start_stop_scan(self):
+ """Convenience method to start BLE scan and stop BLE scan.
+
+ Steps:
+ 1. Enable ble.
+ 2. Create LE scan objects.
+ 3. Start scan.
+ 4. Stop scan.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ self.pri_ad.droid.bluetoothEnableBLE()
+ filter_list, scan_settings, scan_callback = generate_ble_scan_objects(
+ self.pri_ad.droid)
+ self.pri_ad.droid.bleStartBleScan(filter_list, scan_settings,
+ scan_callback)
+ time.sleep(self.iperf["duration"])
+ try:
+ self.pri_ad.droid.bleStopBleScan(scan_callback)
+ except Exception as err:
+ self.log.error(str(err))
+ return False
+ return True
+
+ def initiate_ble_gatt_connection(self):
+ """Creates gatt connection and disconnect gatt connection.
+
+ Steps:
+ 1. Initializes gatt objects.
+ 2. Start a generic advertisement.
+ 3. Start a generic scanner.
+ 4. Find the advertisement and extract the mac address.
+ 5. Stop the first scanner.
+ 6. Create a GATT connection between the scanner and advertiser.
+ 7. Disconnect the GATT connection.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ self.pri_ad.droid.bluetoothEnableBLE()
+ gatt_server_cb = self.sec_ad.droid.gattServerCreateGattServerCallback()
+ gatt_server = self.sec_ad.droid.gattServerOpenGattServer(gatt_server_cb)
+ self.gatt_server_list.append(gatt_server)
+ try:
+ bluetooth_gatt, gatt_callback, adv_callback = (
+ orchestrate_gatt_connection(self.pri_ad, self.sec_ad))
+ self.bluetooth_gatt_list.append(bluetooth_gatt)
+ time.sleep(self.iperf["duration"])
+ except GattTestUtilsError as err:
+ self.log.error(err)
+ return False
+ self.adv_instances.append(adv_callback)
+ return self._orchestrate_gatt_disconnection(bluetooth_gatt,
+ gatt_callback)
+
+ def ble_start_stop_scan_with_iperf(self):
+ self.run_iperf_and_get_result()
+ if not self.ble_start_stop_scan():
+ return False
+ return self.teardown_result()
+
+ def ble_gatt_connection_with_iperf(self):
+ self.run_iperf_and_get_result()
+ if not self.initiate_ble_gatt_connection():
+ return False
+ return self.teardown_result()
+
+ def test_performance_ble_scan_tcp_ul(self):
+ """Test performance with ble scan.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the wlan throughput when performing ble scan.
+
+ Steps:
+ 1. Start TCP-uplink traffic.
+ 2. Start and stop BLE scan.
+
+ Returns:
+ True if pass, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_021
+ """
+ if not self.ble_start_stop_scan_with_iperf():
+ return False
+ return True
+
+ def test_performance_ble_scan_tcp_dl(self):
+ """Test performance with ble scan.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the wlan throughput when performing ble scan.
+
+ Steps:
+ 1. Start TCP-downlink traffic.
+ 2. Start and stop BLE scan.
+
+ Returns:
+ True if pass, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_022
+ """
+ if not self.ble_start_stop_scan_with_iperf():
+ return False
+ return True
+
+ def test_performance_ble_scan_udp_ul(self):
+ """Test performance with ble scan.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the wlan throughput when performing ble scan.
+
+ Steps:
+ 1. Start UDP-uplink traffic.
+ 2. Start and stop BLE scan.
+
+ Returns:
+ True if pass, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_023
+ """
+ if not self.ble_start_stop_scan_with_iperf():
+ return False
+ return True
+
+ def test_performance_ble_scan_udp_dl(self):
+ """Test performance with ble scan.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the wlan throughput when performing ble scan.
+
+ Steps:
+ 1. Start UDP-uplink traffic.
+ 2. Start and stop BLE scan.
+
+ Returns:
+ True if pass, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_024
+ """
+ if not self.ble_start_stop_scan_with_iperf():
+ return False
+ return True
+
+ def test_performance_ble_connect_tcp_ul(self):
+ """Test performance with ble gatt connection.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the wlan throughput when ble gatt connection
+ is established.
+
+ Steps:
+ 1. Start TCP-uplink traffic.
+ 2. Initiate gatt connection.
+
+ Returns:
+ True if pass, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_025
+ """
+ if not self.ble_gatt_connection_with_iperf():
+ return False
+ return True
+
+ def test_performance_ble_connect_tcp_dl(self):
+ """Test performance with ble gatt connection.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the wlan throughput when ble gatt connection
+ is established.
+
+ Steps:
+ 1. Start TCP-downlink traffic.
+ 2. Initiate gatt connection.
+
+ Returns:
+ True if pass, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_026
+ """
+ if not self.ble_gatt_connection_with_iperf():
+ return False
+ return True
+
+ def test_performance_ble_connect_udp_ul(self):
+ """Test performance with ble gatt connection.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the wlan throughput when ble gatt connection
+ is established.
+
+ Steps:
+ 1. Start UDP-uplink traffic.
+ 2. Initiate gatt connection.
+
+ Returns:
+ True if pass, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_027
+ """
+ if not self.ble_gatt_connection_with_iperf():
+ return False
+ return True
+
+ def test_performance_ble_connect_udp_dl(self):
+ """Test performance with ble gatt connection.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the wlan throughput when ble gatt connection
+ is established.
+
+ Steps:
+ 1. Start UDP-downlink traffic.
+ 2. Initiate gatt connection.
+
+ Returns:
+ True if pass, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_028
+ """
+ if not self.ble_gatt_connection_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/performance_tests/WlanWithHfpPerformanceTest.py b/acts/tests/google/coex/performance_tests/WlanWithHfpPerformanceTest.py
new file mode 100644
index 0000000..781f272
--- /dev/null
+++ b/acts/tests/google/coex/performance_tests/WlanWithHfpPerformanceTest.py
@@ -0,0 +1,259 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 time
+
+from acts.test_utils.bt import BtEnum
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_test_utils import multithread_func
+from acts.test_utils.coex.coex_test_utils import initiate_disconnect_from_hf
+from acts.test_utils.coex.coex_test_utils import pair_and_connect_headset
+from acts.test_utils.coex.coex_test_utils import setup_tel_config
+from acts.test_utils.tel.tel_test_utils import hangup_call
+from acts.test_utils.tel.tel_test_utils import initiate_call
+
+
+class WlanWithHfpPerformanceTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["sim_conf_file"]
+ self.unpack_userparams(req_params)
+ self.ag_phone_number, self.re_phone_number = setup_tel_config(
+ self.pri_ad, self.sec_ad, self.sim_conf_file)
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.audio_receiver.pairing_mode()
+ if not pair_and_connect_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ set([BtEnum.BluetoothProfile.HEADSET.value])):
+ self.log.error("Failed to pair and connect to headset")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.audio_receiver.clean_up()
+
+ def call_from_sec_ad_to_pri_ad(self):
+ """Initiates the call from secondary device and accepts the call
+ from HF connected to primary device.
+
+ Steps:
+ 1. Initiate call from secondary device to primary device.
+ 2. Accept the call from HF.
+ 3. Hangup the call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ if not initiate_call(self.log, self.sec_ad, self.ag_phone_number):
+ self.log.error("Failed to initiate call")
+ return False
+ time.sleep(5) # Wait until initiate call.
+ if not self.audio_receiver.accept_call():
+ self.log.error("Failed to answer call from HF.")
+ return False
+ time.sleep(self.iperf["duration"])
+ if not hangup_call(self.log, self.pri_ad):
+ self.log.error("Failed to hangup call.")
+ return False
+ return False
+
+ def initiate_call_from_hf_with_iperf(self):
+ """Wrapper function to start iperf and initiate call."""
+ self.run_iperf_and_get_result()
+ if not initiate_disconnect_from_hf(
+ self.audio_receiver, self.pri_ad, self.sec_ad,
+ self.iperf["duration"]):
+ return False
+ return self.teardown_result()
+
+ def initiate_call_and_change_volume_with_iperf(self):
+ """Wrapper function to start iperf and initiate call and check avrcp
+ controls.
+ """
+ self.run_iperf_and_get_result()
+ tasks = [(self.call_from_sec_ad_to_pri_ad, ()),
+ (self.change_volume, ())]
+ if not multithread_func(self.log, tasks):
+ return False
+ return self.teardown_result()
+
+ def test_performance_hfp_call_tcp_ul(self):
+ """Test performance with hfp connection.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and check throughput when hfp connection
+ and call is active.
+
+ Steps:.
+ 1. Start TCP-uplink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_017
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_tcp_dl(self):
+ """Test performance with hfp connection.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and check throughput when hfp connection
+ and call is active.
+
+ Steps:.
+ 1. Start TCP-downlink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_018
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_udp_ul(self):
+ """Test performance with hfp connection.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and check throughput when hfp connection
+ and call is active.
+
+ Steps:.
+ 1. Start UDP-uplink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_019
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_udp_dl(self):
+ """Test performance with hfp connection.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and check throughput when hfp connection
+ and call is active.
+
+ Steps:.
+ 1. Start UDP-downlink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_020
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_volume_check_tcp_ul(self):
+ """Test performance with hfp connection and perform volume actions.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and check throughput when hfp connection and perform
+ volume change when call is active.
+
+ Steps:.
+ 1. Start TCP-uplink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_037
+ """
+ if not self.initiate_call_and_change_volume_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_volume_check_tcp_dl(self):
+ """Test performance with hfp connection and perform volume actions.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and check throughput when hfp connection and perform
+ volume change when call is active.
+
+ Steps:.
+ 1. Start TCP-downlink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_038
+ """
+ if not self.initiate_call_and_change_volume_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_volume_check_udp_ul(self):
+ """Test performance with hfp connection and perform volume actions.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and check throughput when hfp connection and perform
+ volume change when call is active.
+
+ Steps:.
+ 1. Start UDP-uplink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_039
+ """
+ if not self.initiate_call_and_change_volume_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_volume_check_udp_dl(self):
+ """Test performance with hfp connection and perform volume actions.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and check throughput when hfp connection and perform
+ volume change when call is active.
+
+ Steps:.
+ 1. Start UDP-downlink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_040
+ """
+ if not self.initiate_call_and_change_volume_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/slave_role/functionality_tests/WlanWithA2dpFunctionalitySlaveTest.py b/acts/tests/google/coex/slave_role/functionality_tests/WlanWithA2dpFunctionalitySlaveTest.py
new file mode 100644
index 0000000..7e4c1ca
--- /dev/null
+++ b/acts/tests/google/coex/slave_role/functionality_tests/WlanWithA2dpFunctionalitySlaveTest.py
@@ -0,0 +1,265 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 time
+
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.bluez_test_utils import BluezUtils
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_constants import bluetooth_profiles
+from acts.test_utils.coex.coex_constants import WAIT_TIME
+from acts.test_utils.coex.coex_test_utils import music_play_and_check
+from acts.test_utils.coex.coex_test_utils import connect_wlan_profile
+
+
+class WlanWithA2dpFunctionalitySlaveTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["iterations"]
+ self.unpack_userparams(req_params)
+ self.device_id = str(self.pri_ad.droid.bluetoothGetLocalAddress())
+ self.dbus = BluezUtils()
+ self.adapter_mac_address = self.dbus.get_bluetooth_adapter_address()
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.pri_ad.droid.bluetoothMakeDiscoverable()
+ if not self.dbus.find_device(self.device_id):
+ self.log.info("Device is not discoverable")
+ return False
+ self.pri_ad.droid.bluetoothStartPairingHelper(True)
+ if not self.dbus.pair_bluetooth_device():
+ self.log.info("Pairing failed")
+ return False
+ if not self.dbus.connect_bluetooth_device(
+ bluetooth_profiles["A2DP_SRC"]):
+ self.log.info("Connection Failed")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.dbus.remove_bluetooth_device(self.device_id)
+
+ def connect_disconnect_a2dp_headset(self):
+ """Connect and disconnect a2dp profile from headset."""
+ for i in range(self.iterations):
+ if not self.dbus.disconnect_bluetooth_profile(
+ bluetooth_profiles["A2DP_SRC"], self.pri_ad):
+ self.log.info("Disconnection Failed")
+ return False
+ time.sleep(WAIT_TIME)
+ if not self.dbus.connect_bluetooth_device(
+ bluetooth_profiles["A2DP_SRC"]):
+ self.log.info("Connection Failed")
+ return False
+ return True
+
+ def connect_disconnect_a2dp_headset_with_iperf(self):
+ """Wrapper function to start iperf traffic and connect/disconnect
+ to headset for N iterations.
+ """
+ self.run_iperf_and_get_result()
+ if not self.connect_disconnect_a2dp_headset():
+ return False
+ return self.teardown_result()
+
+ def music_streaming_with_iperf(self):
+ """Wrapper function to start iperf traffic, music streaming
+ to headset and associate with access point for N iterations.
+ """
+ args = [
+ lambda: music_play_and_check(
+ self.pri_ad, self.audio_receiver.mac_address,
+ self.music_file_to_play, self.iperf["duration"])
+ ]
+ self.run_thread(args)
+ if not connect_wlan_profile(self.pri_ad, self.network):
+ return False
+ self.run_iperf_and_get_result()
+ return self.teardown_result()
+
+ def test_connect_disconnect_a2dp_headset_slave_role_with_tcp_ul(self):
+ """Starts TCP-uplink traffic and connect/disconnect a2dp headset.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test functional behaviour of connection and
+ disconnection to a2dp headset when android device as a slave.
+
+ Steps:
+ 1. Run TCP-uplink traffic.
+ 2. Initiate connection from a2dp headset(bluez).
+ 2. Connect and disconnect A2DP headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_034
+ """
+ if not self.connect_disconnect_a2dp_headset_with_iperf():
+ return False
+ return True
+
+ def test_connect_disconnect_a2dp_headset_slave_role_with_tcp_dl(self):
+ """Starts TCP-downlink traffic and connect/disconnect a2dp headset.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test functional behaviour of connection and
+ disconnection to a2dp headset when android device as a slave.
+
+ Steps:
+ 1. Run TCP-downlink traffic.
+ 2. Initiate connection from a2dp headset(bluez).
+ 2. Connect and disconnect a2dp headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_035
+ """
+ if not self.connect_disconnect_a2dp_headset_with_iperf():
+ return False
+ return True
+
+ def test_connect_disconnect_a2dp_headset_slave_role_with_udp_ul(self):
+ """Starts UDP-uplink traffic and connect/disconnect a2dp headset.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test functional behaviour of connection and
+ disconnection to a2dp headset when android device as a slave.
+
+ Steps:
+ 1. Run UDP-uplink traffic.
+ 2. Initiate connection from a2dp headset(bluez).
+ 2. Connect and disconnect a2dp headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_036
+ """
+ if not self.connect_disconnect_a2dp_headset_with_iperf():
+ return False
+ return True
+
+ def test_connect_disconnect_a2dp_headset_slave_role_with_udp_dl(self):
+ """Starts UDP-downlink traffic and connect/disconnect a2dp headset.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test functional behaviour of connection and
+ disconnection to a2dp headset when android device as a slave.
+
+ Steps:
+ 1. Run UDP-downlink traffic.
+ 2. Initiate connection from a2dp headset(bluez).
+ 2. Connect and disconnect a2dp headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_037
+ """
+ if not self.connect_disconnect_a2dp_headset_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_slave_role_with_tcp_ul(self):
+ """Starts TCP-uplink traffic with music streaming to a2dp headset.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming when device acts as a slave.
+
+ Steps:
+ 1. Run TCP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_038
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_slave_role_with_tcp_dl(self):
+ """Starts TCP-downlink traffic with music streaming to a2dp headset.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming when device acts as a slave.
+
+ Steps:
+ 1. Run TCP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_039
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_slave_role_with_udp_ul(self):
+ """Starts UDP-uplink traffic with music streaming to a2dp headset.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming when device acts as a slave.
+
+ Steps:
+ 1. Run UDP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_040
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_a2dp_streaming_slave_role_with_udp_dl(self):
+ """Starts UDP-downlink traffic with music streaming to a2dp headset.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the functional behaviour of a2dp music
+ streaming when device acts as a slave.
+
+ Steps:
+ 1. Run UDP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_041
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/slave_role/functionality_tests/WlanWithHfpFunctionalitySlaveTest.py b/acts/tests/google/coex/slave_role/functionality_tests/WlanWithHfpFunctionalitySlaveTest.py
new file mode 100644
index 0000000..5781eae
--- /dev/null
+++ b/acts/tests/google/coex/slave_role/functionality_tests/WlanWithHfpFunctionalitySlaveTest.py
@@ -0,0 +1,167 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 time
+
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.bluez_test_utils import BluezUtils
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_constants import WAIT_TIME
+from acts.test_utils.coex.coex_constants import bluetooth_profiles
+
+
+class WlanWithHfpFunctionalitySlaveTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["iterations"]
+ self.unpack_userparams(req_params)
+ self.device_id = str(self.pri_ad.droid.bluetoothGetLocalAddress())
+ self.dbus = BluezUtils()
+ self.adapter_mac_address = self.dbus.get_bluetooth_adapter_address()
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.pri_ad.droid.bluetoothMakeDiscoverable()
+ if not self.dbus.find_device(self.device_id):
+ self.log.info("Device is not discoverable")
+ return False
+ self.pri_ad.droid.bluetoothStartPairingHelper(True)
+ if not self.dbus.pair_bluetooth_device():
+ self.log.info("Pairing failed")
+ return False
+ if not self.dbus.connect_bluetooth_device(bluetooth_profiles["HFP_AG"]):
+ self.log.info("Connection Failed")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.dbus.remove_bluetooth_device(self.device_id)
+
+ def connect_disconnect_hfp_headset(self):
+ """Connect and disconnect headset for multiple iterations."""
+ for i in range(self.iterations):
+ if not self.dbus.disconnect_bluetooth_profile(
+ bluetooth_profiles["HFP_AG"], self.pri_ad):
+ self.log.info("Disconnection Failed")
+ return False
+ time.sleep(WAIT_TIME)
+ if not self.dbus.connect_bluetooth_device(
+ bluetooth_profiles["HFP_AG"]):
+ self.log.info("Connection Failed")
+ return False
+ return True
+
+ def connect_disconnect_hfp_headset_with_iperf(self):
+ """Wrapper function to start iperf traffic and connect/disconnect
+ to headset for N iterations.
+ """
+ self.run_iperf_and_get_result()
+ if not self.connect_disconnect_hfp_headset():
+ return False
+ return self.teardown_result()
+
+ def test_connect_disconnect_hfp_headset_slave_role_with_tcp_ul(self):
+ """Starts TCP-uplink traffic and connect/disconnect hfp headset.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test functional behaviour of connection and
+ disconnection to hfp headset when android device as a slave.
+
+ Steps:
+ 1. Run TCP-uplink traffic.
+ 2. Initiate connection from hfp headset(bluez).
+ 2. Connect and disconnect hfp headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_058
+ """
+ if not self.connect_disconnect_hfp_headset_with_iperf():
+ return False
+ return True
+
+ def test_connect_disconnect_hfp_headset_slave_role_with_tcp_dl(self):
+ """Starts TCP-downlink traffic and connect/disconnect hfp headset.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test functional behaviour of connection and
+ disconnection to hfp headset when android device as a slave.
+
+ Steps:
+ 1. Run TCP-downlink traffic.
+ 2. Initiate connection from hfp headset(bluez).
+ 2. Connect and disconnect hfp headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_059
+ """
+ if not self.connect_disconnect_hfp_headset_with_iperf():
+ return False
+ return True
+
+ def test_connect_disconnect_hfp_headset_slave_role_with_udp_ul(self):
+ """Starts UDP-uplink traffic and connect/disconnect hfp headset.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test functional behaviour of connection and
+ disconnection to hfp headset when android device as a slave.
+
+ Steps:
+ 1. Run UDP-uplink traffic.
+ 2. Initiate connection from hfp headset(bluez).
+ 2. Connect and disconnect hfp headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_060
+ """
+ if not self.connect_disconnect_hfp_headset_with_iperf():
+ return False
+ return True
+
+ def test_connect_disconnect_hfp_headset_slave_role_with_udp_dl(self):
+ """Starts UDP-downlink traffic and connect/disconnect hfp headset.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test functional behaviour of connection and
+ disconnection to hfp headset when android device as a slave.
+
+ Steps:
+ 1. Run UDP-downlink traffic.
+ 2. Initiate connection from hfp headset(bluez).
+ 2. Connect and disconnect hfp headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_061
+ """
+ if not self.connect_disconnect_hfp_headset_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/slave_role/performance_tests/CoexBtMultiProfilePerformanceSlaveTest.py b/acts/tests/google/coex/slave_role/performance_tests/CoexBtMultiProfilePerformanceSlaveTest.py
new file mode 100644
index 0000000..68b7ab4
--- /dev/null
+++ b/acts/tests/google/coex/slave_role/performance_tests/CoexBtMultiProfilePerformanceSlaveTest.py
@@ -0,0 +1,186 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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.
+
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.bluez_test_utils import BluezUtils
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_constants import bluetooth_profiles
+from acts.test_utils.coex.coex_test_utils import music_play_and_check_via_app
+from acts.test_utils.coex.coex_test_utils import initiate_disconnect_call_dut
+from acts.test_utils.coex.coex_test_utils import connect_wlan_profile
+from acts.test_utils.coex.coex_test_utils import setup_tel_config
+
+
+class CoexBtMultiProfilePerformanceSlaveTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["sim_conf_file"]
+ self.unpack_userparams(req_params)
+ self.ag_phone_number, self.re_phone_number = setup_tel_config(
+ self.pri_ad, self.sec_ad, self.sim_conf_file)
+ self.device_id = str(self.pri_ad.droid.bluetoothGetLocalAddress())
+ self.dbus = BluezUtils()
+ self.adapter_mac_address = self.dbus.get_bluetooth_adapter_address()
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.pri_ad.droid.bluetoothMakeDiscoverable()
+ if not self.dbus.find_device(self.device_id):
+ self.log.error("Device is not discoverable")
+ return False
+ self.pri_ad.droid.bluetoothStartPairingHelper(True)
+ if not self.dbus.pair_bluetooth_device():
+ self.log.error("Pairing failed")
+ return False
+ if not self.dbus.connect_bluetooth_device(
+ bluetooth_profiles["HFP_AG"], bluetooth_profiles["A2DP_SRC"]):
+ self.log.error("Connection Failed")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.dbus.remove_bluetooth_device(self.device_id)
+
+ def initiate_call_when_a2dp_streaming_on(self):
+ """Initiates HFP call, then check for call is present or not.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ if not initiate_disconnect_call_dut(
+ self.pri_ad, self.sec_ad, self.iperf["duration"],
+ self.re_phone_number):
+ return False
+ return True
+
+ def play_music_and_connect_wifi(self):
+ """Perform A2DP music streaming and scan and connect to wifi
+ network
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ if not music_play_and_check_via_app(
+ self.pri_ad, self.adapter_mac_address):
+ self.log.error("Failed to stream music file")
+ return False
+ if not connect_wlan_profile(self.pri_ad, self.network):
+ return False
+ return True
+
+ def initiate_call_when_a2dp_streaming_with_iperf(self):
+ """Wrapper function to initiate call when a2dp streaming and starts
+ iperf.
+ """
+ if not self.play_music_and_connect_wifi():
+ return False
+ self.run_iperf_and_get_result()
+ if not self.initiate_call_when_a2dp_streaming_on():
+ return False
+ return self.teardown_result()
+
+ def test_performance_a2dp_streaming_hfp_call_tcp_ul(self):
+ """Check performance when a2dp streaming and hfp call..
+
+ This test is to check wifi performance when a2dp streaming and
+ hfp call performed sequentially with TCP-uplink traffic. Android
+ device is in slave role.
+
+ Steps:
+ 1.Enable bluetooth.
+ 2.Start a2dp streaming.
+ 3.Run TCP-uplink traffic.
+ 4.Initiate hfp call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_061
+ """
+ if not self.initiate_call_when_a2dp_streaming_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_hfp_call_tcp_dl(self):
+ """Check performance when a2dp streaming and hfp call..
+
+ This test is to check wifi performance when a2dp streaming and
+ hfp call performed sequentially with TCP-downlink traffic. Android
+ device is in slave role.
+
+ Steps:
+ 1.Enable bluetooth.
+ 2.Start a2dp streaming.
+ 3.Run TCP-downlink traffic.
+ 4.Initiate hfp call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_062
+ """
+ if not self.initiate_call_when_a2dp_streaming_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_hfp_call_udp_ul(self):
+ """Check performance when a2dp streaming and hfp call..
+
+ This test is to check wifi performance when a2dp streaming and
+ hfp call performed sequentially with UDP-uplink traffic. Android
+ device is in slave role.
+
+ Steps:
+ 1.Enable bluetooth.
+ 2.Start a2dp streaming.
+ 3.Run UDP-uplink traffic.
+ 4.Initiate hfp call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_063
+ """
+ if not self.initiate_call_when_a2dp_streaming_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_hfp_call_udp_dl(self):
+ """Check performance when a2dp streaming and hfp call..
+
+ This test is to check wifi performance when a2dp streaming and
+ hfp call performed sequentially with UDP-downlink traffic. Android
+ device is in slave role.
+
+ Steps:
+ 1.Enable bluetooth.
+ 2.Start a2dp streaming.
+ 3.Run UDP-downlink traffic.
+ 4.Initiate hfp call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Kpi_064
+ """
+ if not self.initiate_call_when_a2dp_streaming_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/slave_role/performance_tests/WlanWithA2dpPerformanceSlaveTest.py b/acts/tests/google/coex/slave_role/performance_tests/WlanWithA2dpPerformanceSlaveTest.py
new file mode 100644
index 0000000..bf9bff1
--- /dev/null
+++ b/acts/tests/google/coex/slave_role/performance_tests/WlanWithA2dpPerformanceSlaveTest.py
@@ -0,0 +1,238 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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.
+
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.bluez_test_utils import BluezUtils
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_constants import bluetooth_profiles
+from acts.test_utils.coex.coex_test_utils import music_play_and_check
+from acts.test_utils.coex.coex_test_utils import multithread_func
+
+
+class WlanWithA2dpPerformanceSlaveTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ self.device_id = str(self.pri_ad.droid.bluetoothGetLocalAddress())
+ self.dbus = BluezUtils()
+ self.adapter_mac_address = self.dbus.get_bluetooth_adapter_address()
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.pri_ad.droid.bluetoothMakeDiscoverable()
+ if not self.dbus.find_device(self.device_id):
+ self.log.info("Device is not discoverable")
+ return False
+ self.pri_ad.droid.bluetoothStartPairingHelper(True)
+ if not self.dbus.pair_bluetooth_device():
+ self.log.info("Pairing failed")
+ return False
+ if not self.dbus.connect_bluetooth_device(
+ bluetooth_profiles["A2DP_SRC"]):
+ self.log.info("Connection Failed")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.dbus.remove_bluetooth_device(self.device_id)
+
+ def music_streaming_with_iperf(self):
+ """Wrapper function to start iperf traffic, music streaming
+ to headset and associate with access point for N iterations.
+ """
+ self.run_iperf_and_get_result()
+ if not music_play_and_check(
+ self.pri_ad, self.adapter_mac_address, self.music_file_to_play,
+ self.iperf["duration"]):
+ return False
+ return self.teardown_result()
+
+ def music_streaming_avrcp_controls_with_iperf(self):
+ """Wrapper function to start iperf traffic, music streaming and avrcp
+ controls.
+ """
+ self.run_iperf_and_get_result()
+ tasks = [(music_play_and_check,
+ (self.pri_ad, self.adapter_mac_address,
+ self.music_file_to_play, self.iperf["duration"])),
+ (self.dbus.avrcp_actions, (self.device_id,))]
+ if not multithread_func(self.log, tasks):
+ return False
+ return self.teardown_result()
+
+ def test_performance_a2dp_streaming_slave_role_with_tcp_ul(self):
+ """Starts TCP-uplink traffic with music streaming to a2dp headset.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the performance of a2dp music
+ streaming and wifi throughput when device acts as a slave.
+
+ Steps:
+ 1. Run TCP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_045
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_slave_role_with_tcp_dl(self):
+ """Starts TCP-downlink traffic with music streaming to a2dp headset.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the performance of a2dp music
+ streaming and wifi throughput when device acts as a slave.
+
+ Steps:
+ 1. Run TCP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_046
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_slave_role_with_udp_ul(self):
+ """Starts UDP-uplink traffic with music streaming to a2dp headset.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the performance of a2dp music
+ streaming and wifi throughput when device acts as a slave.
+
+ Steps:
+ 1. Run UDP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_047
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_slave_role_with_udp_dl(self):
+ """Starts UDP-downlink traffic with music streaming to a2dp headset.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the performance of a2dp music
+ streaming and wifi throughput when device acts as a slave.
+
+ Steps:
+ 1. Run UDP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_048
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_avrcp_controls_slave_role_tcp_ul(self):
+ """Starts TCP-uplink traffic with music streaming and avrcp controls.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the performance of a2dp music streaming and
+ avrcp controls when device is in slave role.
+
+ 1. Run TCP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_049
+ """
+ if not self.music_streaming_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_avrcp_controls_slave_role_tcp_dl(self):
+ """Starts TCP-downlink traffic with music streaming and avrcp controls.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the performance of a2dp music streaming and
+ avrcp controls when device is in slave role.
+
+ 1. Run TCP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_050
+ """
+ if not self.music_streaming_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_avrcp_controls_slave_role_udp_ul(self):
+ """Starts UDP-uplink traffic with music streaming and avrcp controls.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the performance of a2dp music streaming and
+ avrcp controls when device is in slave role.
+
+ 1. Run UDP-uplink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_051
+ """
+ if not self.music_streaming_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_performance_a2dp_streaming_avrcp_controls_slave_role_udp_dl(self):
+ """Starts UDP-downlink traffic with music streaming and avrcp controls.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the performance of a2dp music streaming and
+ avrcp controls when device is in slave role.
+
+ 1. Run UDP-downlink traffic.
+ 2. Start media streaming to a2dp headset.
+ 3. Check all avrcp related controls.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_052
+ """
+ if not self.music_streaming_avrcp_controls_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/slave_role/performance_tests/WlanWithHFPPerformanceSlaveTest.py b/acts/tests/google/coex/slave_role/performance_tests/WlanWithHFPPerformanceSlaveTest.py
new file mode 100644
index 0000000..1ff111f
--- /dev/null
+++ b/acts/tests/google/coex/slave_role/performance_tests/WlanWithHFPPerformanceSlaveTest.py
@@ -0,0 +1,246 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 time
+
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.bluez_test_utils import BluezUtils
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_constants import bluetooth_profiles
+from acts.test_utils.coex.coex_constants import CALL_WAIT_TIME
+from acts.test_utils.coex.coex_test_utils import multithread_func
+from acts.test_utils.coex.coex_test_utils import setup_tel_config
+from acts.test_utils.tel.tel_test_utils import initiate_call
+
+
+class WlanWithHFPPerformanceSlaveTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["sim_conf_file"]
+ self.unpack_userparams(req_params)
+ self.ag_phone_number, self.re_phone_number = setup_tel_config(
+ self.pri_ad, self.sec_ad, self.sim_conf_file)
+ self.device_id = str(self.pri_ad.droid.bluetoothGetLocalAddress())
+ self.dbus = BluezUtils()
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.pri_ad.droid.bluetoothMakeDiscoverable()
+ if not self.dbus.find_device(self.device_id):
+ self.log.info("Device is not discoverable")
+ return False
+ self.pri_ad.droid.bluetoothStartPairingHelper(True)
+ if not self.dbus.pair_bluetooth_device():
+ self.log.info("Pairing failed")
+ return False
+ if not self.dbus.connect_bluetooth_device(
+ bluetooth_profiles["HFP_AG"], bluetooth_profiles["A2DP_SRC"]):
+ self.log.info("Connection failed")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.dbus.remove_bluetooth_device(self.device_id)
+
+ def initiate_call_from_hf_with_iperf(self):
+ """Wrapper function to start iperf and initiate call"""
+ self.run_iperf_and_get_result()
+ if not self.dbus.initiate_and_disconnect_call_from_hf(
+ self.re_phone_number, self.iperf["duration"]):
+ return False
+ return self.teardown_result()
+
+ def initiate_call_avrcp_controls_with_iperf(self):
+ """Wrapper function to start iperf, initiate call from hf and answer
+ call from secondary device.
+ """
+ initiate_call(self.log, self.sec_ad, self.ag_phone_number)
+ time.sleep(CALL_WAIT_TIME)
+ self.run_iperf_and_get_result()
+ tasks = [(self.dbus.answer_call, (self.iperf["duration"],)),
+ (self.dbus.avrcp_actions, (self.device_id,))]
+ if not multithread_func(self.log, tasks):
+ return False
+ return self.teardown_result()
+
+ def test_performance_hfp_call_slave_role_tcp_ul(self):
+ """Starts TCP-uplink traffic with hfp connection.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the performance hfp connection
+ call and wifi throughput when device is in slave role.
+
+ Steps:.
+ 1. Start TCP-uplink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_053
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_slave_role_tcp_dl(self):
+ """Starts TCP-downlink traffic with hfp connection.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the performance hfp connection
+ call and wifi throughput when device is in slave role.
+
+ Steps:.
+ 1. Start TCP-downlink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_054
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_slave_role_udp_ul(self):
+ """Starts UDP-uplink traffic with hfp connection.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the performance hfp connection
+ call and wifi throughput when device is in slave role.
+
+ Steps:.
+ 1. Start UDP-uplink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_055
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_slave_role_udp_dl(self):
+ """Starts UDP-downlink traffic with hfp connection.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the performance hfp connection
+ call and wifi throughput when device is in slave role.
+
+ Steps:
+ 1. Start UDP-downlink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_056
+ """
+ if not self.initiate_call_from_hf_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_avrcp_controls_slave_role_tcp_ul(self):
+ """Starts TCP-uplink traffic with hfp connection and check volume.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the performance hfp connection,
+ call, volume change and wifi throughput when device is in slave role.
+
+ Steps:.
+ 1. Start TCP-uplink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+ 3. Change call volume when device is in call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_057
+ """
+ if not self.initiate_call_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_avrcp_controls_slave_role_tcp_dl(self):
+ """Starts TCP-downlink traffic with hfp connection and check volume.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the performance hfp connection,
+ call, volume change and wifi throughput when device is in slave role.
+
+ Steps:.
+ 1. Start TCP-downlink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+ 3. Change call volume when device is in call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_058
+ """
+ if not self.initiate_call_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_avrcp_controls_slave_role_udp_ul(self):
+ """Starts UDP-uplink traffic with hfp connection and check volume.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the performance hfp connection,
+ call, volume change and wifi throughput when device is in slave role.
+
+ Steps:.
+ 1. Start UDP-uplink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+ 3. Change call volume when device is in call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_059
+ """
+ if not self.initiate_call_avrcp_controls_with_iperf():
+ return False
+ return True
+
+ def test_performance_hfp_call_avrcp_controls_slave_role_udp_dl(self):
+ """Starts UDP-downlink traffic with hfp connection and check volume.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the performance hfp connection,
+ call, volume change and wifi throughput when device is in slave role.
+
+ Steps:.
+ 1. Start UDP-downlink traffic.
+ 2. Initiate call from HF and disconnect call from primary device.
+ 3. Change call volume when device is in call.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_060
+ """
+ if not self.initiate_call_avrcp_controls_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/stress_tests/CoexA2dpStressTest.py b/acts/tests/google/coex/stress_tests/CoexA2dpStressTest.py
new file mode 100644
index 0000000..51e4407
--- /dev/null
+++ b/acts/tests/google/coex/stress_tests/CoexA2dpStressTest.py
@@ -0,0 +1,443 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 time
+
+from acts.test_utils.bt import BtEnum
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_test_utils import connect_dev_to_headset
+from acts.test_utils.coex.coex_test_utils import disconnect_headset_from_dev
+from acts.test_utils.coex.coex_test_utils import music_play_and_check
+from acts.test_utils.coex.coex_test_utils import pair_and_connect_headset
+
+
+class CoexA2dpStressTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["iterations"]
+ self.unpack_userparams(req_params)
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.audio_receiver.pairing_mode()
+ if not pair_and_connect_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ set([BtEnum.BluetoothProfile.A2DP.value])):
+ self.log.error("Failed to pair and connect to headset")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.audio_receiver.clean_up()
+
+ def connect_disconnect_headset(self):
+ """Initiates connection to paired headset and disconnects headset.
+
+ Returns:
+ True if successful False otherwise.
+ """
+ for i in range(self.iterations):
+ self.log.info("Headset connect/disconnect iteration={}".format(i))
+ self.pri_ad.droid.bluetoothConnectBonded(
+ self.audio_receiver.mac_address)
+ time.sleep(2)
+ self.pri_ad.droid.bluetoothDisconnectConnected(
+ self.audio_receiver.mac_address)
+ return True
+
+ def connect_disconnect_a2dp_headset(self):
+ """Connect and disconnect a2dp profile on headset for multiple
+ iterations.
+
+ Steps:
+ 1.Connect a2dp profile on headset.
+ 2.Disconnect a2dp profile on headset.
+ 3.Repeat step 1 and 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ for i in range(self.iterations):
+ if not connect_dev_to_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ {BtEnum.BluetoothProfile.A2DP.value}):
+ self.log.error("Failure to connect A2dp headset.")
+ return False
+
+ if not disconnect_headset_from_dev(
+ self.pri_ad, self.audio_receiver.mac_address,
+ [BtEnum.BluetoothProfile.A2DP.value]):
+ self.log.error("Could not disconnect {}".format(
+ self.audio_receiver.mac_address))
+ return False
+ return True
+
+ def connect_disconnect_headset_with_iperf(self):
+ """Wrapper function to start iperf traffic and connect/disconnect
+ to headset for N iterations.
+ """
+ self.run_iperf_and_get_result()
+ if not self.connect_disconnect_headset():
+ return False
+ return self.teardown_result()
+
+ def connect_disconnect_a2dp_headset_with_iperf(self):
+ """Wrapper function to start iperf traffic and connect/disconnect
+ to a2dp headset for N iterations.
+ """
+ self.run_iperf_and_get_result()
+ if not self.connect_disconnect_a2dp_headset():
+ return False
+ return self.teardown_result()
+
+ def music_streaming_with_iperf(self):
+ """Wrapper function to start iperf traffic and music streaming."""
+ self.run_iperf_and_get_result()
+ if not music_play_and_check(
+ self.pri_ad, self.audio_receiver.mac_address,
+ self.music_file_to_play, self.iperf["duration"]):
+ return False
+ return self.teardown_result()
+
+ def test_stress_connect_disconnect_headset_with_tcp_ul(self):
+ """Stress test for connect/disconnect headset.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset.
+
+ Steps:
+ 1. Run TCP-uplink traffic.
+ 2. Connect and disconnect headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_013
+ """
+ if not self.connect_disconnect_headset_with_iperf():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_headset_with_tcp_dl(self):
+ """Stress test for connect/disconnect headset.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset.
+
+ Steps:
+ 1. Run TCP-downlink traffic.
+ 2. Connect and disconnect headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_014
+ """
+ if not self.connect_disconnect_headset_with_iperf():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_headset_with_udp_ul(self):
+ """Stress test for connect/disconnect headset.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset.
+
+ Steps:
+ 1. Run UDP-uplink traffic.
+ 2. Connect and disconnect headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_015
+ """
+ if not self.connect_disconnect_headset_with_iperf():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_headset_with_udp_dl(self):
+ """Stress test for connect/disconnect headset.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset.
+
+ Steps:
+ 1. Run UDP-downlink traffic.
+ 2. Connect and disconnect headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_016
+ """
+ if not self.connect_disconnect_headset_with_iperf():
+ return False
+ return True
+
+ def test_stress_a2dp_long_duration_with_tcp_ul(self):
+ """Stress test to stream music to headset continuously for 12 hours.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the integrity of audio streaming for 12 hours.
+
+ Steps:
+ 1. Start TCP uplink traffic.
+ 2. Start music streaming to headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_017
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_stress_a2dp_long_duration_with_tcp_dl(self):
+ """Stress test to stream music to headset continuously for 12 hours.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the integrity of audio streaming for 12 hours.
+
+ Steps:
+ 1. Start TCP downlink traffic.
+ 2. Start music streaming to headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_018
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_stress_a2dp_long_duration_with_udp_ul(self):
+ """Stress test to stream music to headset continuously for 12 hours.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the integrity of audio streaming for 12 hours.
+
+ Steps:
+ 1. Start UDP uplink traffic.
+ 2. Start music streaming to headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_019
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_stress_a2dp_long_duration_with_udp_dl(self):
+ """Stress test to stream music to headset continuously for 12 hours.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the integrity of audio streaming for 12 hours.
+
+ Steps:
+ 1. Start UDP downlink traffic.
+ 2. Start music streaming to headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_020
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_a2dp_profile_with_tcp_ul(self):
+ """Stress test for connect/disconnect a2dp headset.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset with a2dp profile.
+
+ Steps:
+ 1. Run TCP-uplink traffic.
+ 2. Connect and disconnect headset with a2dp profile.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_029
+ """
+ if not self.connect_disconnect_a2dp_headset_with_iperf():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_a2dp_profile_with_tcp_dl(self):
+ """Stress test for connect/disconnect a2dp headset.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset with a2dp profile.
+
+ Steps:
+ 1. Run TCP-downlink traffic.
+ 2. Connect and disconnect headset with a2dp profile.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_030
+ """
+ if not self.connect_disconnect_a2dp_headset_with_iperf():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_a2dp_profile_with_udp_ul(self):
+ """Stress test for connect/disconnect a2dp headset.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset with a2dp profile.
+
+ Steps:
+ 1. Run UDP-uplink traffic.
+ 2. Connect and disconnect headset with a2dp profile.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_031
+ """
+ if not self.connect_disconnect_a2dp_headset_with_iperf():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_a2dp_profile_with_udp_dl(self):
+ """Stress test for connect/disconnect a2dp headset.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset with a2dp profile.
+
+ Steps:
+ 1. Run UDP-downlink traffic.
+ 2. Connect and disconnect headset with a2dp profile.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_032
+ """
+ if not self.connect_disconnect_a2dp_headset_with_iperf():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_headset_with_tcp_bidirectional(self):
+ """Stress test for connect/disconnect headset.
+
+ This test starts TCP-bidirectional traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset.
+
+ Steps:
+ 1. Run TCP-bidirectional traffic.
+ 2. Connect and disconnect headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_057
+ """
+ if not self.connect_disconnect_headset_with_iperf():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_headset_with_udp_bidirectional(self):
+ """Stress test for connect/disconnect headset.
+
+ This test starts UDP-bidirectional traffic between host machin and
+ android device and test the integrity of connection and disconnection
+ to headset.
+
+ Steps:
+ 1. Run UDP-bidirectional traffic.
+ 2. Connect and disconnect headset.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_058
+ """
+ if not self.connect_disconnect_headset_with_iperf():
+ return False
+ return True
+
+ def test_stress_a2dp_long_duration_with_tcp_bidirectional(self):
+ """Stress test to stream music to headset continuously for 12 hours.
+
+ This test starts TCP-bidirectional traffic between host machin and
+ android device and test the integrity of audio streaming for 12 hours.
+
+ Steps:
+ 1. Start TCP bidirectional traffic.
+ 2. Start music streaming to headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_065
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
+
+ def test_stress_a2dp_long_duration_with_udp_bidirectional(self):
+ """Stress test to stream music to headset continuously for 12 hours.
+
+ This test starts UDP-bidirectional traffic between host machin and
+ android device and test the integrity of audio streaming for 12 hours.
+
+ Steps:
+ 1. Start UDP bidirectional traffic.
+ 2. Start music streaming to headset.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_066
+ """
+ if not self.music_streaming_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/stress_tests/CoexBasicStressTest.py b/acts/tests/google/coex/stress_tests/CoexBasicStressTest.py
new file mode 100644
index 0000000..bc87b80
--- /dev/null
+++ b/acts/tests/google/coex/stress_tests/CoexBasicStressTest.py
@@ -0,0 +1,447 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 time
+
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_test_utils import toggle_bluetooth
+from acts.test_utils.coex.coex_test_utils import device_discoverable
+
+
+class CoexBasicStressTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["iterations"]
+ self.unpack_userparams(req_params)
+
+ def start_stop_classic_discovery_with_iperf(self):
+ """Starts and stop bluetooth discovery for 1000 iterations.
+
+ Steps:
+ 1. Start Discovery on Primary device.
+ 2. Stop Discovery on Secondary device.
+ 3. Repeat step 1 and 2.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ self.run_iperf_and_get_result()
+ for i in range(self.iterations):
+ self.log.info("Inquiry iteration {}".format(i))
+ if not self.pri_ad.droid.bluetoothStartDiscovery():
+ self.log.error("Bluetooth discovery failed.")
+ return False
+ time.sleep(2)
+ if not self.pri_ad.droid.bluetoothCancelDiscovery():
+ self.log.error("Bluetooth cancel discovery failed.")
+ return False
+ return self.teardown_result()
+
+ def check_device_discoverability_with_iperf(self):
+ """Checks if primary device is visible from secondary device.
+
+ Steps:
+ 1. Start discovery on primary device.
+ 2. Discover primary device from Secondary device.
+ 3. Repeat step 1 and 2.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ self.run_iperf_and_get_result()
+ for i in range(self.iterations):
+ self.log.info("Discovery iteration = {}".format(i))
+ if not device_discoverable(self.pri_ad, self.sec_ad):
+ self.log.error("Primary device could not be discovered.")
+ return False
+ return self.teardown_result()
+
+ def toogle_bluetooth_with_iperf(self):
+ """Wrapper function to start iperf traffic and toggling bluetooth."""
+ self.run_iperf_and_get_result()
+ if not toggle_bluetooth(self.pri_ad, self.iterations):
+ return False
+ return self.teardown_result()
+
+ def test_stress_toggle_bluetooth_with_tcp_ul(self):
+ """Stress test toggling bluetooth on and off.
+
+ This test is to start TCP-uplink traffic between host machine
+ and android device and test the integrity of toggling bluetooth
+ on and off.
+
+ Steps:
+ 1. Starts TCP-uplink traffic.
+ 2. Toggle bluetooth state on and off for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_001
+ """
+ if not self.toogle_bluetooth_with_iperf():
+ return False
+ return True
+
+ def test_stress_toggle_bluetooth_with_tcp_dl(self):
+ """Stress test toggling bluetooth on and off.
+
+ This test is to start TCP-downlink traffic between host machine
+ and android device and test the integrity of toggling bluetooth
+ on and off.
+
+ Steps:
+ 1. Starts TCP-downlink traffic.
+ 2. Toggle bluetooth state on and off for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_002
+ """
+ if not self.toogle_bluetooth_with_iperf():
+ return False
+ return True
+
+ def test_stress_toggle_bluetooth_with_udp_ul(self):
+ """Stress test toggling bluetooth on and off.
+
+ This test is to start UDP-uplink traffic between host machine
+ and android device and test the integrity of toggling bluetooth
+ on and off.
+
+ Steps:
+ 1. Starts UDP-uplink traffic.
+ 2. Toggle bluetooth state on and off for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_003
+ """
+ if not self.toogle_bluetooth_with_iperf():
+ return False
+ return True
+
+ def test_stress_toggle_bluetooth_with_udp_dl(self):
+ """Stress test toggling bluetooth on and off.
+
+ This test is to start UDP-downlink traffic between host machine
+ and android device and test the integrity of toggling bluetooth
+ on and off.
+
+ Steps:
+ 1. Starts UDP-downlink traffic.
+ 2. Toggle bluetooth state on and off for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_004
+ """
+ if not self.toogle_bluetooth_with_iperf():
+ return False
+ return True
+
+ def test_stress_bluetooth_discovery_with_tcp_ul(self):
+ """Stress test on bluetooth discovery.
+
+ This test is to start TCP-uplink traffic between host machine
+ and android device and test the integrity of start and stop discovery.
+
+ Steps:
+ 1. Starts TCP-uplink traffic.
+ 2. Performs start and stop discovery in quick succession.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_005
+ """
+ if not self.start_stop_classic_discovery_with_iperf():
+ return False
+ return True
+
+ def test_stress_bluetooth_discovery_with_tcp_dl(self):
+ """Stress test on bluetooth discovery.
+
+ This test is to start TCP-downlink traffic between host machine
+ and android device and test the integrity of start and stop discovery.
+
+ Steps:
+ 1. Starts TCP-downlink traffic.
+ 2. Performs start and stop discovery in quick succession.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_006
+ """
+ if not self.start_stop_classic_discovery_with_iperf():
+ return False
+ return True
+
+ def test_stress_bluetooth_discovery_with_udp_ul(self):
+ """Stress test on bluetooth discovery.
+
+ This test is to start UDP-uplink traffic between host machine
+ and android device and test the integrity of start and stop discovery.
+
+ Steps:
+ 1. Starts UDP-uplink traffic.
+ 2. Performs start and stop discovery in quick succession.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_007
+ """
+ if not self.start_stop_classic_discovery_with_iperf():
+ return False
+ return True
+
+ def test_stress_bluetooth_discovery_with_udp_dl(self):
+ """Stress test on bluetooth discovery.
+
+ This test is to start UDP-downlink traffic between host machine
+ and android device and test the integrity of start and stop discovery.
+
+ Steps:
+ 1. Starts UDP-downlink traffic.
+ 2. Performs start and stop discovery in quick succession.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_008
+ """
+ if not self.start_stop_classic_discovery_with_iperf():
+ return False
+ return True
+
+ def test_stress_primary_device_visibility_with_tcp_ul(self):
+ """Stress test on device visibility from secondary device.
+
+ This test is to start TCP-uplink traffic between host machine
+ and android device and stress test on device discoverability from
+ secondary device
+
+ Steps:
+ 1. Start TCP-uplink traffic.
+ 2. Make primary device visible.
+ 3. Check if primary device name is visible from secondary device.
+ 4. Repeat step 2 and 3 for n iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_009
+ """
+ if not self.check_device_discoverability_with_iperf():
+ return False
+ return True
+
+ def test_stress_primary_device_visibility_with_tcp_dl(self):
+ """Stress test on device visibility from secondary device.
+
+ This test is to start TCP-downlink traffic between host machine
+ and android device and stress test on device discoverability from
+ secondary device
+
+ Steps:
+ 1. Start TCP-downlink traffic.
+ 2. Make primary device visible.
+ 3. Check if primary device name is visible from secondary device.
+ 4. Repeat step 2 and 3 for n iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_010
+ """
+ if not self.check_device_discoverability_with_iperf():
+ return False
+ return True
+
+ def test_stress_primary_device_visibility_with_udp_ul(self):
+ """Stress test on device visibility from secondary device.
+
+ This test is to start UDP-uplink traffic between host machine
+ and android device and stress test on device discoverability from
+ secondary device
+
+ Steps:
+ 1. Start UDP-uplink traffic.
+ 2. Make primary device visible.
+ 3. Check if primary device name is visible from secondary device.
+ 4. Repeat step 2 and 3 for n iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_011
+ """
+ if not self.check_device_discoverability_with_iperf():
+ return False
+ return True
+
+ def test_stress_primary_device_visibility_with_udp_dl(self):
+ """Stress test on device visibility from secondary device.
+
+ This test is to start UDP-downlink traffic between host machine
+ and android device and stress test on device discoverability from
+ secondary device
+
+ Steps:
+ 1. Start UDP-downlink traffic.
+ 2. Make primary device visible.
+ 3. Check if primary device name is visible from secondary device.
+ 4. Repeat step 2 and 3 for n iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_012
+ """
+ if not self.check_device_discoverability_with_iperf():
+ return False
+ return True
+
+ def test_stress_toggle_bluetooth_with_tcp_bidirectional(self):
+ """Stress test toggling bluetooth on and off.
+
+ This test is to start TCP-bidirectional traffic between host machine
+ and android device and test the integrity of toggling bluetooth
+ on and off.
+
+ Steps:
+ 1. Starts TCP-bidirectional traffic.
+ 2. Toggle bluetooth state on and off for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_051
+ """
+ if not self.toogle_bluetooth_with_iperf():
+ return False
+ return True
+
+ def test_stress_toggle_bluetooth_with_udp_bidirectional(self):
+ """Stress test toggling bluetooth on and off.
+
+ This test is to start UDP-bidirectional traffic between host machine
+ and android device and test the integrity of toggling bluetooth
+ on and off.
+
+ Steps:
+ 1. Starts TCP-bidirectional traffic.
+ 2. Toggle bluetooth state on and off for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_052
+ """
+ if not self.toogle_bluetooth_with_iperf():
+ return False
+ return True
+
+ def test_stress_bluetooth_discovery_with_tcp_bidirectional(self):
+ """Stress test on bluetooth discovery.
+
+ This test is to start TCP-bidirectional traffic between host machine
+ and android device and test the integrity of start and stop discovery.
+
+ Steps:
+ 1. Starts TCP-bidirectional traffic.
+ 2. Performs start and stop discovery in quick succession.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_053
+ """
+ if not self.start_stop_classic_discovery_with_iperf():
+ return False
+ return True
+
+ def test_stress_bluetooth_discovery_with_udp_bidirectional(self):
+ """Stress test on bluetooth discovery.
+
+ This test is to start UDP-bidirectional traffic between host machine
+ and android device and test the integrity of start and stop discovery.
+
+ Steps:
+ 1. Start wlan traffic with UDP-bidirectional.
+ 2. Start bluetooth discovery for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_054
+ """
+ if not self.start_stop_classic_discovery_with_iperf():
+ return False
+ return True
+
+ def test_stress_primary_device_visiblity_tcp_bidirectional(self):
+ """Stress test on device visibility from secondary device.
+
+ This test is to start TCP-bidirectional traffic between host machine
+ and android device and stress test on device discoverability from
+ secondary device
+
+ Steps:
+ 1. Start TCP-bidirectional traffic.
+ 2. Make primary device visible.
+ 3. Check if primary device name is visible from secondary device.
+ 4. Repeat step 2 and 3 for n iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_055
+ """
+ if not self.check_device_discoverability_with_iperf():
+ return False
+ return True
+
+ def test_stress_primary_device_visiblity_udp_bidirectional(self):
+ """Stress test on device visibility from secondary device.
+
+ This test is to start UDP-bidirectional traffic between host machine
+ and android device and stress test on device discoverability from
+ secondary device
+
+ Steps:
+ 1. Start UDP-bidirectional traffic.
+ 2. Make primary device visible.
+ 3. Check if primary device name is visible from secondary device.
+ 4. Repeat step 2 and 3 for n iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_056
+ """
+ if not self.check_device_discoverability_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/stress_tests/CoexBtMultiProfileStressTest.py b/acts/tests/google/coex/stress_tests/CoexBtMultiProfileStressTest.py
new file mode 100644
index 0000000..8c770e8
--- /dev/null
+++ b/acts/tests/google/coex/stress_tests/CoexBtMultiProfileStressTest.py
@@ -0,0 +1,180 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 time
+
+from acts.test_utils.bt import BtEnum
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_test_utils import disconnect_headset_from_dev
+from acts.test_utils.coex.coex_test_utils import pair_and_connect_headset
+
+
+class CoexBtMultiProfileStressTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ self.receiver = self.relay_devices[1]
+ req_params = ["iterations"]
+ self.unpack_userparams(req_params)
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.audio_receiver.pairing_mode()
+ self.receiver.setup()
+ self.receiver.power_on()
+ self.receiver.pairing_mode()
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.audio_receiver.clean_up()
+ self.receiver.clean_up()
+
+ def initiate_classic_connection_to_multiple_devices(self):
+ """Initiates multiple BR/EDR connections.
+
+ Steps:
+ 1. Initiate A2DP Connection.
+ 2. Initiate HFP Connection.
+ 3. Disconnect A2DP Connection.
+ 4. Disconnect HFP Connection.
+ 5. Repeat step 1 to 4.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ for i in range(self.iterations):
+ if not pair_and_connect_headset(
+ self.pri_ad, self.receiver.mac_address,
+ {BtEnum.BluetoothProfile.A2DP.value}):
+ self.log.error("Failed to connect A2DP Profile.")
+ return False
+ time.sleep(2)
+
+ if not pair_and_connect_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ {BtEnum.BluetoothProfile.HEADSET.value}):
+ self.log.error("Failed to connect HEADSET profile.")
+ return False
+ time.sleep(2)
+
+ if not disconnect_headset_from_dev(
+ self.pri_ad, self.receiver.mac_address,
+ [BtEnum.BluetoothProfile.A2DP.value]):
+ self.log.error("Could not disconnect {}".format(
+ self.receiver.mac_address))
+ return False
+
+ if not disconnect_headset_from_dev(
+ self.pri_ad, self.audio_receiver.mac_address,
+ [BtEnum.BluetoothProfile.HEADSET.value]):
+ self.log.error("Could not disconnect {}".format(
+ self.audio_receiver.mac_address))
+ return False
+ return True
+
+ def initiate_classic_connection_with_iperf(self):
+ """Wrapper function to initiate bluetooth classic connection to
+ multiple devices.
+ """
+ self.run_iperf_and_get_result()
+ if not self.initiate_classic_connection_to_multiple_devices():
+ return False
+ return self.teardown_result()
+
+ def test_stress_multiple_connection_with_tcp_ul(self):
+ """ Connects multiple headsets with wlan traffic over TCP-uplink.
+
+ This test is to perform connect and disconnect with A2DP and HFP
+ profiles on two different bluetooth devices.
+
+ Steps:
+ 1. Run wlan traffic over TCP-uplink.
+ 2. Initiate connect and disconnect to multiple profiles from primary
+ device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_037
+ """
+ if not self.initiate_classic_connection_with_iperf():
+ return False
+ return True
+
+ def test_stress_multiple_connection_with_tcp_dl(self):
+ """ Connects multiple headsets with wlan traffic over TCP-downlink.
+
+ This test is to perform connect and disconnect with A2DP and HFP
+ profiles on two different bluetooth devices.
+
+ Steps:
+ 1. Run wlan traffic over TCP-downlink.
+ 2. Initiate connect and disconnect to multiple profiles from primary
+ device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_038
+ """
+ if not self.initiate_classic_connection_with_iperf():
+ return False
+ return True
+
+ def test_stress_multiple_connection_with_udp_ul(self):
+ """ Connects multiple headsets with wlan traffic over UDP-uplink.
+
+ This test is to perform connect and disconnect with A2DP and HFP
+ profiles on two different bluetooth devices.
+
+ Steps:
+ 1. Run wlan traffic over UDP-uplink.
+ 2. Initiate connect and disconnect to multiple profiles from primary
+ device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_039
+ """
+ if not self.initiate_classic_connection_with_iperf():
+ return False
+ return True
+
+ def test_stress_multiple_connection_with_udp_dl(self):
+ """ Connects multiple headsets with wlan traffic over UDP-downlink.
+
+ This test is to perform connect and disconnect with A2DP and HFP
+ profiles.
+
+ Steps:
+ 1. Run wlan traffic over UDP-downlink.
+ 2. Initiate connect and disconnect to multiple profiles from primary
+ device.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_040
+ """
+ if not self.initiate_classic_connection_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/coex/stress_tests/CoexHfpStressTest.py b/acts/tests/google/coex/stress_tests/CoexHfpStressTest.py
new file mode 100644
index 0000000..390cba1
--- /dev/null
+++ b/acts/tests/google/coex/stress_tests/CoexHfpStressTest.py
@@ -0,0 +1,636 @@
+# /usr/bin/env python3.4
+#
+# Copyright (C) 2018 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 time
+
+from acts.test_utils.bt import BtEnum
+from acts.test_utils.bt.bt_test_utils import clear_bonded_devices
+from acts.test_utils.coex.CoexBaseTest import CoexBaseTest
+from acts.test_utils.coex.coex_test_utils import connect_dev_to_headset
+from acts.test_utils.coex.coex_test_utils import disconnect_headset_from_dev
+from acts.test_utils.coex.coex_constants import AUDIO_ROUTE_BLUETOOTH
+from acts.test_utils.coex.coex_constants import AUDIO_ROUTE_SPEAKER
+from acts.test_utils.coex.coex_test_utils import initiate_disconnect_from_hf
+from acts.test_utils.coex.coex_test_utils import pair_and_connect_headset
+from acts.test_utils.tel.tel_test_utils import hangup_call
+from acts.test_utils.tel.tel_voice_utils import set_audio_route
+
+
+class CoexHfpStressTest(CoexBaseTest):
+
+ def __init__(self, controllers):
+ CoexBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ CoexBaseTest.setup_class(self)
+ req_params = ["iterations"]
+ self.unpack_userparams(req_params)
+
+ def setup_test(self):
+ CoexBaseTest.setup_test(self)
+ self.audio_receiver.pairing_mode()
+ if not pair_and_connect_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ set([BtEnum.BluetoothProfile.HEADSET.value])):
+ self.log.error("Failed to pair and connect to headset")
+ return False
+
+ def teardown_test(self):
+ clear_bonded_devices(self.pri_ad)
+ CoexBaseTest.teardown_test(self)
+ self.audio_receiver.clean_up()
+
+ def connect_disconnect_hfp_headset(self):
+ """Connect and disconnect hfp profile on headset for multiple
+ iterations.
+
+ Steps:
+ 1.Connect hfp profile on headset.
+ 2.Disconnect hfp profile on headset.
+ 3.Repeat step 1 and 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ for i in range(self.iterations):
+ if not connect_dev_to_headset(
+ self.pri_ad, self.audio_receiver.mac_address,
+ {BtEnum.BluetoothProfile.HEADSET.value}):
+ self.log.error("Failure to connect HFP headset.")
+ return False
+
+ if not disconnect_headset_from_dev(
+ self.pri_ad, self.audio_receiver.mac_address,
+ {BtEnum.BluetoothProfile.HEADSET.value}):
+ self.log.error("Could not disconnect {}".format(
+ self.audio_receiver.mac_address))
+ return False
+ return True
+
+ def initiate_call_from_hf_disconnect_from_ag(self):
+ """Initiates call from HF and disconnect call from ag for multiple
+ iterations.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ for i in range(self.iterations):
+ if not self.audio_receiver.initiate_call_from_hf():
+ self.log.error("Failed to initiate call.")
+ return False
+ time.sleep(5)
+ if not hangup_call(self.log, self.pri_ad):
+ self.log.error("Failed to hang up the call.")
+ return False
+ return True
+
+ def route_audio_from_hf_to_speaker(self):
+ """Route audio from HF to primary device inbuilt speakers and
+ vice_versa.
+
+ Steps:
+ 1. Initiate call from HF.
+ 2. Toggle audio from HF to speaker and vice-versa from N iterations.
+ 3. Hangup call from primary device.
+
+ Returns:
+ True if successful, False otherwise.
+ """
+ if not self.audio_receiver.initiate_call_from_hf():
+ self.log.error("Failed to initiate call.")
+ return False
+ for i in range(self.iterations):
+ self.log.info("DUT speaker iteration = {}".format(i))
+ if not set_audio_route(self.log, self.pri_ad, AUDIO_ROUTE_SPEAKER):
+ self.log.error("Failed switching to primary device speaker.")
+ hangup_call(self.log, self.pri_ad)
+ return False
+ time.sleep(2)
+ if not set_audio_route(self.log, self.pri_ad,
+ AUDIO_ROUTE_BLUETOOTH):
+ self.log.error("Failed switching to bluetooth headset.")
+ hangup_call(self.log, self.pri_ad)
+ return False
+ if not hangup_call(self.log, self.pri_ad):
+ self.log.error("Failed to hang up the call.")
+ return False
+ return True
+
+ def connect_disconnect_hfp_headset_with_iperf(self):
+ """Wrapper function to start iperf traffic and connect/disconnect
+ to a2dp headset for N iterations.
+ """
+ self.run_iperf_and_get_result()
+ if not self.connect_disconnect_hfp_headset():
+ return False
+ return self.teardown_result()
+
+ def hfp_long_duration_with_iperf(self):
+ """Wrapper function to start iperf traffic and initiate hfp call."""
+ self.run_iperf_and_get_result()
+ if not initiate_disconnect_from_hf(
+ self.audio_receiver, self.pri_ad, self.sec_ad,
+ self.iperf["duration"]):
+ return False
+ return self.teardown_result()
+
+ def initiate_call_multiple_times_with_iperf(self):
+ """Wrapper function to start iperf traffic and initiate call and
+ disconnect call simultaneously.
+ """
+ self.run_iperf_and_get_result()
+ if not self.initiate_call_from_hf_disconnect_from_ag():
+ return False
+ return self.teardown_result()
+
+ def route_audio_from_hf_to_speaker_with_iperf(self):
+ """Wrapper function to start iperf traffic and route audio from
+ headset to speaker.
+ """
+ self.run_iperf_and_get_result()
+ if not self.route_audio_from_hf_to_speaker():
+ return False
+ return self.teardown_result()
+
+ def test_stress_hfp_long_duration_with_tcp_ul(self):
+ """Stress test on hfp call continuously for 12 hours.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the integrity of hfp connection for 12 hours.
+
+ Steps:
+ 1. Start TCP-uplink traffic.
+ 2. Initiate call.
+ 3. Verify call status.
+ 4. Disconnect call.
+ 5. Repeat steps 2 to 4 for N iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_021
+ """
+ if not self.hfp_long_duration_with_iperf():
+ return False
+ return True
+
+ def test_stress_hfp_long_duration_with_tcp_dl(self):
+ """Stress test on hfp call continuously for 12 hours.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the integrity of hfp connection for 12 hours.
+
+ Steps:
+ 1. Start TCP-downlink traffic.
+ 2. Initiate call.
+ 3. Verify call status.
+ 4. Disconnect call.
+ 5. Repeat steps 2 to 4 for N iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_022
+ """
+ if not self.hfp_long_duration_with_iperf():
+ return False
+ return True
+
+ def test_stress_hfp_long_duration_with_udp_ul(self):
+ """Stress test on hfp call continuously for 12 hours.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the integrity of hfp connection for 12 hours.
+
+ Steps:
+ 1. Start UDP-uplink traffic.
+ 2. Initiate call.
+ 3. Verify call status.
+ 4. Disconnect call.
+ 5. Repeat steps 2 to 4 for N iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_023
+ """
+ if not self.hfp_long_duration_with_iperf():
+ return False
+ return True
+
+ def test_stress_hfp_long_duration_with_udp_dl(self):
+ """Stress test on hfp call continuously for 12 hours.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the integrity of hfp connection for 12 hours.
+
+ Steps:
+ 1. Start UDP-downlink traffic.
+ 2. Initiate call.
+ 3. Verify call status.
+ 4. Disconnect call.
+ 5. Repeat steps 2 to 4 for N iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_024
+ """
+ if not self.hfp_long_duration_with_iperf():
+ return False
+ return True
+
+ def test_stress_hfp_call_multiple_times_with_tcp_ul(self):
+ """Stress test for initiate and disconnect hfp call.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the integrity of hfp call.
+
+ Steps:
+ 1. Start TCP-uplink traffic.
+ 2. Initiate call from HF
+ 3. Verify status of call
+ 4. Disconnect from AG.
+ 5. Repeat steps 2 to 4 for N iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_025
+ """
+ if not self.initiate_call_multiple_times_with_iperf():
+ return False
+ return True
+
+ def test_stress_hfp_call_multiple_times_with_tcp_dl(self):
+ """Stress test for initiate and disconnect hfp call.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the integrity of hfp call.
+
+ Steps:
+ 1. Start TCP-downlink traffic.
+ 2. Initiate call from HF
+ 3. Verify status of call
+ 4. Disconnect from AG.
+ 5. Repeat steps 2 to 4 for N iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_026
+ """
+ if not self.initiate_call_multiple_times_with_iperf():
+ return False
+ return True
+
+ def test_stress_hfp_call_multiple_times_with_udp_ul(self):
+ """Stress test for initiate and disconnect hfp call.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the integrity of hfp call.
+
+ Steps:
+ 1. Start UDP-uplink traffic.
+ 2. Initiate call from HF
+ 3. Verify status of call
+ 4. Disconnect from AG.
+ 5. Repeat steps 2 to 4 for N iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_027
+ """
+ if not self.initiate_call_multiple_times_with_iperf():
+ return False
+ return True
+
+ def test_stress_hfp_call_multiple_times_with_udp_dl(self):
+ """Stress test for initiate and disconnect hfp call.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the integrity of hfp call.
+
+ Steps:
+ 1. Start UDP-downlink traffic.
+ 2. Initiate call from HF
+ 3. Verify status of call
+ 4. Disconnect from AG.
+ 5. Repeat steps 2 to 4 for N iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_028
+ """
+ if not self.initiate_call_multiple_times_with_iperf():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_hfp_profile_with_tcp_ul(self):
+ """Stress test for connect/disconnect hfp headset.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset with hfp profile.
+
+ Steps:
+ 1. Run TCP-uplink traffic.
+ 2. Connect and disconnect headset with hfp profile.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_033
+ """
+ if not self.connect_disconnect_hfp_headset():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_hfp_profile_with_tcp_dl(self):
+ """Stress test for connect/disconnect hfp headset.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset with hfp profile.
+
+ Steps:
+ 1. Run TCP-downlink traffic.
+ 2. Connect and disconnect headset with hfp profile.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_034
+ """
+ if not self.connect_disconnect_hfp_headset():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_hfp_profile_with_udp_ul(self):
+ """Stress test for connect/disconnect hfp headset.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset with hfp profile.
+
+ Steps:
+ 1. Run UDP-uplink traffic.
+ 2. Connect and disconnect headset with hfp profile.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_035
+ """
+ if not self.connect_disconnect_hfp_headset():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_hfp_profile_with_udp_dl(self):
+ """Stress test for connect/disconnect hfp headset.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset with hfp profile.
+
+ Steps:
+ 1. Run UDP-downlink traffic.
+ 2. Connect and disconnect headset with hfp profile.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_036
+ """
+ if not self.connect_disconnect_hfp_headset():
+ return False
+ return True
+
+ def test_stress_audio_routing_with_tcp_ul(self):
+ """Stress to route audio from HF to primary device speaker.
+
+ This test is to start TCP-uplink traffic between host machine and
+ android device and test the integrity of audio routing between
+ bluetooth headset and android device inbuilt speaker.
+
+ Steps:
+ 1. Starts TCP-uplink traffic.
+ 2. Route audio from hf to speaker and vice-versa.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_037
+ """
+ if not self.route_audio_from_hf_to_speaker_with_iperf():
+ return False
+ return True
+
+ def test_stress_audio_routing_with_tcp_dl(self):
+ """Stress to route audio from HF to primary device speaker.
+
+ This test is to start TCP-downlink traffic between host machine and
+ android device and test the integrity of audio routing between
+ bluetooth headset and android device inbuilt speaker.
+
+ Steps:
+ 1. Starts TCP-downlink traffic.
+ 2. Route audio from hf to speaker and vice-versa.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_038
+ """
+ if not self.route_audio_from_hf_to_speaker_with_iperf():
+ return False
+ return True
+
+ def test_stress_audio_routing_with_udp_ul(self):
+ """Stress to route audio from HF to primary device speaker.
+
+ This test is to start UDP-uplink traffic between host machine and
+ android device and test the integrity of audio routing between
+ bluetooth headset and android device inbuilt speaker.
+
+ Steps:
+ 1. Starts UDP-uplink traffic.
+ 2. Route audio from hf to speaker and vice-versa.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_039
+ """
+ if not self.route_audio_from_hf_to_speaker_with_iperf():
+ return False
+ return True
+
+ def test_stress_audio_routing_with_udp_dl(self):
+ """Stress to route audio from HF to primary device speaker.
+
+ This test is to start UDP-downlink traffic between host machine and
+ android device and test the integrity of audio routing between
+ bluetooth headset and android device inbuilt speaker.
+
+ Steps:
+ 1. Starts UDP-downlink traffic.
+ 2. Route audio from hf to speaker and vice-versa.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_040
+ """
+ if not self.route_audio_from_hf_to_speaker_with_iperf():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_hfp_with_tcp_bidirectional(self):
+ """Stress test for connect/disconnect headset.
+
+ This test is to start TCP-bidirectional traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset with hfp profile.
+
+ Steps:
+ 1. Run TCP-bidirectional traffic.
+ 2. Connect and disconnect headset with hfp profile.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_067
+ """
+ if not self.connect_disconnect_hfp_headset():
+ return False
+ return True
+
+ def test_stress_connect_disconnect_hfp_with_udp_bidirectional(self):
+ """Stress test for connect/disconnect headset.
+
+ This test is to start UDP-bidirectional traffic between host machine and
+ android device and test the integrity of connection and disconnection
+ to headset with hfp profile.
+
+ Steps:
+ 1. Run UDP-bidirectional traffic.
+ 2. Connect and disconnect headset with hfp profile.
+ 3. Repeat step 2 for N iterations.
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_068
+ """
+ if not self.connect_disconnect_hfp_headset():
+ return False
+ return True
+
+ def test_stress_hfp_long_duration_with_tcp_bidirectional(self):
+ """Stress test on hfp call continuously for 12 hours.
+
+ This test is to start TCP-bidirectional traffic between host machine and
+ android device and test the integrity of hfp connection for 12 hours.
+
+ Steps:
+ 1. Start TCP-bidirectional traffic.
+ 2. Initiate call.
+ 3. Verify call status.
+ 4. Disconnect call.
+ 5. Repeat steps 2 to 4 for N iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_069
+ """
+ if not self.hfp_long_duration_with_iperf():
+ return False
+ return True
+
+ def test_stress_hfp_long_duration_with_udp_bidirectional(self):
+ """Stress test on hfp call continuously for 12 hours.
+
+ This test is to start UDP-bidirectional traffic between host machine and
+ android device and test the integrity of hfp connection for 12 hours.
+
+ Steps:
+ 1. Start UDP-bidirectional traffic.
+ 2. Initiate call.
+ 3. Verify call status.
+ 4. Disconnect call.
+ 5. Repeat steps 2 to 4 for N iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_070
+ """
+ if not self.hfp_long_duration_with_iperf():
+ return False
+ return True
+
+ def test_stress_hfp_call_multiple_times_with_tcp_bidirectional(self):
+ """Stress test for initiate and disconnect hfp call.
+
+ This test is to start TCP-bidirectional traffic between host machine and
+ android device and test the integrity of hfp call.
+
+ Steps:
+ 1. Start TCP-bidirectional traffic.
+ 2. Initiate call from HF
+ 3. Verify status of call
+ 4. Disconnect from AG.
+ 5. Repeat steps 2 to 4 for N iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_071
+ """
+ if not self.initiate_call_multiple_times_with_iperf():
+ return False
+ return True
+
+ def test_stress_hfp_call_multiple_times_with_udp_bidirectional(self):
+ """Stress test for initiate and disconnect hfp call.
+
+ This test is to start UDP-bidirectional traffic between host machine and
+ android device and test the integrity of hfp call.
+
+ Steps:
+ 1. Start UDP-bidirectional traffic.
+ 2. Initiate call from HF
+ 3. Verify status of call
+ 4. Disconnect from AG.
+ 5. Repeat steps 2 to 4 for N iterations
+
+ Returns:
+ True if successful, False otherwise.
+
+ Test Id: Bt_CoEx_Stress_072
+ """
+ if not self.initiate_call_multiple_times_with_iperf():
+ return False
+ return True
diff --git a/acts/tests/google/net/DataUsageTest.py b/acts/tests/google/net/DataUsageTest.py
new file mode 100644
index 0000000..0e636ac
--- /dev/null
+++ b/acts/tests/google/net/DataUsageTest.py
@@ -0,0 +1,390 @@
+#
+# Copyright 2018 - 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 time
+
+from acts import asserts
+from acts import base_test
+from acts.controllers import adb
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.net import connectivity_const as cconst
+from acts.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
+from acts.test_utils.tel.tel_test_utils import http_file_download_by_chrome
+from acts.test_utils.tel.tel_test_utils import verify_http_connection
+from acts.test_utils.tel import tel_test_utils as ttutils
+from acts.test_utils.wifi import wifi_test_utils as wutils
+
+conn_test_class = "com.android.tests.connectivity.uid.ConnectivityTestActivity"
+android_os_class = "com.quicinc.cne.CNEService.CNEServiceApp"
+instr_cmd = "am instrument -w -e command grant-all \
+ com.android.permissionutils/.PermissionInstrumentation"
+
+HOUR_IN_MILLIS = 1000 * 60 * 60
+BYTE_TO_MB_ANDROID = 1000.0 * 1000.0
+BYTE_TO_MB = 1024.0 * 1024.0
+DOWNLOAD_PATH = "/sdcard/download/"
+DATA_USG_ERR = 2.2
+DATA_ERR = 0.2
+TIMEOUT = 2 * 60
+INC_DATA = 10
+
+
+class DataUsageTest(base_test.BaseTestClass):
+ """ Data usage tests """
+
+ def __init__(self, controllers):
+ base_test.BaseTestClass.__init__(self, controllers)
+ self.tests = ("test_mobile_data_usage_downlink",
+ "test_wifi_data_usage_downlink",
+ "test_wifi_tethering_mobile_data_usage_downlink",
+ "test_data_usage_limit_downlink",
+ "test_wifi_tethering_data_usage_limit_downlink",)
+
+ def setup_class(self):
+ """ Setup devices for tests and unpack params """
+ self.dut = self.android_devices[0]
+ self.tethered_devices = self.android_devices[1:]
+ wutils.reset_wifi(self.dut)
+ self.dut.droid.telephonyToggleDataConnection(True)
+ wait_for_cell_data_connection(self.log, self.dut, True)
+ asserts.assert_true(
+ verify_http_connection(self.log, self.dut),
+ "HTTP verification failed on cell data connection")
+
+ # unpack user params
+ req_params = ("wifi_network", "download_file", "file_size", "network")
+ self.unpack_userparams(req_params)
+ self.file_path = DOWNLOAD_PATH + self.download_file.split('/')[-1]
+ self.file_size = int(self.file_size)
+ self.sub_id = str(self.dut.droid.telephonyGetSubscriberId())
+ self.android_os_uid = self.dut.droid.getUidForPackage(android_os_class)
+ self.conn_test_uid = self.dut.droid.getUidForPackage(conn_test_class)
+ for ad in self.android_devices:
+ try:
+ ad.adb.shell(instr_cmd)
+ except adb.AdbError:
+ self.log.warn("adb cmd %s failed on %s" % (instr_cmd, ad.serial))
+
+ # Set chrome browser start with no-first-run verification
+ # Give permission to read from and write to storage
+ commands = ["pm grant com.android.chrome "
+ "android.permission.READ_EXTERNAL_STORAGE",
+ "pm grant com.android.chrome "
+ "android.permission.WRITE_EXTERNAL_STORAGE",
+ "rm /data/local/chrome-command-line",
+ "am set-debug-app --persistent com.android.chrome",
+ 'echo "chrome --no-default-browser-check --no-first-run '
+ '--disable-fre" > /data/local/tmp/chrome-command-line']
+ for cmd in commands:
+ for dut in self.android_devices:
+ try:
+ dut.adb.shell(cmd)
+ except adb.AdbError:
+ self.log.warn("adb command %s failed on %s" % (cmd, dut.serial))
+
+ def teardown_class(self):
+ """ Reset devices """
+ wutils.reset_wifi(self.dut)
+
+ """ Helper functions """
+
+ def _download_data_through_app(self, ad):
+ """ Download data through app on DUT
+
+ Args:
+ 1. ad - DUT to download the file on
+
+ Returns:
+ True - if file download is successful
+ False - if file download is not successful
+ """
+ intent = self.dut.droid.createIntentForClassName(conn_test_class)
+ json_obj = {"url": self.download_file}
+ ad.droid.launchForResultWithIntent(intent, json_obj)
+ download_status = False
+ end_time = time.time() + TIMEOUT
+ while time.time() < end_time:
+ download_status = ttutils._check_file_existance(
+ ad, self.file_path, self.file_size * BYTE_TO_MB)
+ if download_status:
+ self.log.info("Delete file: %s", self.file_path)
+ ad.adb.shell("rm %s" % self.file_path, ignore_status=True)
+ break
+ time.sleep(8) # wait to check again if download is complete
+ return download_status
+
+ def _get_data_usage(self, ad, conn_type):
+ """ Get data usage
+
+ Args:
+ 1. ad - DUT to get data usage from
+ 2. conn_type - MOBILE/WIFI data usage
+
+ Returns:
+ Tuple of Android Os app, Conn UID app, Total data usages
+ """
+ aos = self._get_data_usage_for_uid_rx(ad, conn_type, self.android_os_uid)
+ app = self._get_data_usage_for_uid_rx(ad, conn_type, self.conn_test_uid)
+ tot = self._get_data_usage_for_device_rx(ad, conn_type)
+ self.log.info("Android Os data usage: %s" % aos)
+ self.log.info("Conn UID Test data usage: %s" % app)
+ self.log.info("Total data usage: %s" % tot)
+ return (aos, app, tot)
+
+ def _get_total_data_usage_for_device(self, conn_type):
+ """ Get total data usage in MB for device
+
+ Args:
+ 1. conn_type - MOBILE/WIFI data usage
+
+ Returns:
+ Data usage in MB
+ """
+ end_time = int(time.time() * 1000) + 2 * HOUR_IN_MILLIS
+ data_usage = self.dut.droid.connectivityQuerySummaryForDevice(
+ conn_type, self.sub_id, 0, end_time)
+ data_usage /= BYTE_TO_MB_ANDROID
+ self.log.info("Total data usage is: %s" % data_usage)
+ return data_usage
+
+ def _get_data_usage_for_uid_rx(self, ad, conn_type, uid):
+ """ Get data usage for UID in Rx Bytes
+
+ Args:
+ 1. ad - DUT to get data usage from
+ 2. conn_type - MOBILE/WIFI data usage
+ 3. uid - UID of the app
+
+ Returns:
+ Data usage in MB
+ """
+ subscriber_id = ad.droid.telephonyGetSubscriberId()
+ end_time = int(time.time() * 1000) + 2 * HOUR_IN_MILLIS
+ data_usage = ad.droid.connectivityQueryDetailsForUidRxBytes(
+ conn_type, subscriber_id, 0, end_time, uid)
+ return data_usage/BYTE_TO_MB_ANDROID
+
+ def _get_data_usage_for_device_rx(self, ad, conn_type):
+ """ Get total data usage in rx bytes for device
+
+ Args:
+ 1. ad - DUT to get data usage from
+ 2. conn_type - MOBILE/WIFI data usage
+
+ Returns:
+ Data usage in MB
+ """
+ subscriber_id = ad.droid.telephonyGetSubscriberId()
+ end_time = int(time.time() * 1000) + 2 * HOUR_IN_MILLIS
+ data_usage = ad.droid.connectivityQuerySummaryForDeviceRxBytes(
+ conn_type, subscriber_id, 0, end_time)
+ return data_usage/BYTE_TO_MB_ANDROID
+
+ """ Test Cases """
+
+ @test_tracker_info(uuid="b2d9b36c-3a1c-47ca-a9c1-755450abb20c")
+ def test_mobile_data_usage_downlink(self):
+ """ Verify mobile data usage
+
+ Steps:
+ 1. Get the current data usage of ConnUIDTest and Android OS apps
+ 2. DUT is on LTE data
+ 3. Download file of size xMB through ConnUIDTest app
+ 4. Verify that data usage of Android OS app did not change
+ 5. Verify that data usage of ConnUIDTest app increased by ~xMB
+ 6. Verify that data usage of device also increased by ~xMB
+ """
+ # disable wifi
+ wutils.wifi_toggle_state(self.dut, False)
+
+ # get pre mobile data usage
+ (aos_pre, app_pre, total_pre) = self._get_data_usage(self.dut,
+ cconst.TYPE_MOBILE)
+
+ # download file through app
+ self._download_data_through_app(self.dut)
+
+ # get new mobile data usage
+ (aos_pst, app_pst, total_pst) = self._get_data_usage(self.dut,
+ cconst.TYPE_MOBILE)
+
+ # verify data usage
+ aos_diff = aos_pst - aos_pre
+ app_diff = app_pst - app_pre
+ total_diff = total_pst - total_pre
+ self.log.info("Data usage of Android os increased by %s" % aos_diff)
+ self.log.info("Data usage of ConnUID app increased by %s" % app_diff)
+ self.log.info("Data usage on the device increased by %s" % total_diff)
+ return (aos_diff < DATA_ERR) and \
+ (self.file_size < app_diff < self.file_size + DATA_USG_ERR) and \
+ (self.file_size < total_diff < self.file_size + DATA_USG_ERR)
+
+ @test_tracker_info(uuid="72ddb42a-5942-4a6a-8b20-2181c41b2765")
+ def test_wifi_data_usage_downlink(self):
+ """ Verify wifi data usage
+
+ Steps:
+ 1. Get the current data usage of ConnUIDTest and Android OS apps
+ 2. DUT is on LTE data
+ 3. Download file of size xMB through ConnUIDTest app
+ 4. Verify that data usage of Android OS app did not change
+ 5. Verify that data usage of ConnUIDTest app increased by ~xMB
+ 6. Verify that data usage of device also increased by ~xMB
+ """
+ # connect to wifi network
+ wutils.wifi_connect(self.dut, self.wifi_network)
+
+ # get pre wifi data usage
+ (aos_pre, app_pre, total_pre) = self._get_data_usage(self.dut,
+ cconst.TYPE_WIFI)
+
+ # download file through app
+ self._download_data_through_app(self.dut)
+
+ # get new mobile data usage
+ (aos_pst, app_pst, total_pst) = self._get_data_usage(self.dut,
+ cconst.TYPE_WIFI)
+
+ # verify data usage
+ aos_diff = aos_pst - aos_pre
+ app_diff = app_pst - app_pre
+ total_diff = total_pst - total_pre
+ self.log.info("Data usage of Android os increased by %s" % aos_diff)
+ self.log.info("Data usage of ConnUID app increased by %s" % app_diff)
+ self.log.info("Data usage on the device increased by %s" % total_diff)
+ return (aos_diff < DATA_ERR) and \
+ (self.file_size < app_diff < self.file_size + DATA_USG_ERR) and \
+ (self.file_size < total_diff < self.file_size + DATA_USG_ERR)
+
+ @test_tracker_info(uuid="fe1390e5-635c-49a9-b050-032e66f52f40")
+ def test_wifi_tethering_mobile_data_usage_downlink(self):
+ """ Verify mobile data usage with tethered device
+
+ Steps:
+ 1. Start wifi hotspot and connect tethered device to it
+ 2. Get the data usage on hotspot device
+ 3. Download data on tethered device
+ 4. Get the new data usage on hotspot device
+ 5. Verify that hotspot device's data usage increased by downloaded file size
+ """
+ # connect device to wifi hotspot
+ ad = self.tethered_devices[0]
+ wutils.start_wifi_tethering(self.dut,
+ self.network[wutils.WifiEnums.SSID_KEY],
+ self.network[wutils.WifiEnums.PWD_KEY],
+ ttutils.WIFI_CONFIG_APBAND_2G)
+ wutils.wifi_connect(ad, self.network)
+
+ # get pre mobile data usage
+ (aos_pre, app_pre, total_pre) = self._get_data_usage(self.dut,
+ cconst.TYPE_MOBILE)
+
+ # download file through app
+ self._download_data_through_app(ad)
+
+ # get new mobile data usage
+ (aos_pst, app_pst, total_pst) = self._get_data_usage(self.dut,
+ cconst.TYPE_MOBILE)
+
+ # stop wifi hotspot
+ wutils.stop_wifi_tethering(self.dut)
+
+ # verify data usage
+ aos_diff = aos_pst - aos_pre
+ app_diff = app_pst - app_pre
+ total_diff = total_pst - total_pre
+ self.log.info("Data usage of Android os increased by %s" % aos_diff)
+ self.log.info("Data usage of ConnUID app increased by %s" % app_diff)
+ self.log.info("Data usage on the device increased by %s" % total_diff)
+ return (aos_diff < DATA_ERR) and (app_diff < DATA_ERR) and \
+ (self.file_size < total_diff < self.file_size + DATA_USG_ERR)
+
+ @test_tracker_info(uuid="ac4750fd-20d9-451d-a85b-79fdbaa7da97")
+ def test_data_usage_limit_downlink(self):
+ """ Verify connectivity when data usage limit reached
+
+ Steps:
+ 1. Set the data usage limit to current data usage + 10MB
+ 2. Download 20MB data
+ 3. File download stops and data limit reached
+ 4. Device should lose internet connectivity
+ 5. Verify data usage limit
+ """
+ # get pre mobile data usage
+ total_pre = self._get_total_data_usage_for_device(cconst.TYPE_MOBILE)
+
+ # set data usage limit to current usage limit + 10MB
+ self.log.info("Setting data usage limit to %sMB" % (total_pre + INC_DATA))
+ self.dut.droid.connectivitySetDataUsageLimit(
+ self.sub_id, str(int((total_pre + INC_DATA) * BYTE_TO_MB_ANDROID)))
+
+ # download file through app
+ http_file_download_by_chrome(
+ self.dut, self.download_file, self.file_size, timeout=120)
+ total_pst = self._get_total_data_usage_for_device(cconst.TYPE_MOBILE)
+
+ # verify data usage
+ connectivity_status = wutils.validate_connection(self.dut)
+ self.dut.droid.connectivityFactoryResetNetworkPolicies(self.sub_id)
+ self.log.info("Expected data usage: %s" % (total_pre + INC_DATA))
+ self.log.info("Actual data usage: %s" % total_pst)
+ asserts.assert_true(
+ not connectivity_status,
+ "Device has internet connectivity after reaching data limit")
+ return total_pst - total_pre - INC_DATA < DATA_USG_ERR
+
+ @test_tracker_info(uuid="7c9ab330-9645-4030-bb1e-dcce126944a2")
+ def test_wifi_tethering_data_usage_limit_downlink(self):
+ """ Verify connectivity when data usage limit reached
+
+ Steps:
+ 1. Set the data usage limit to current data usage + 10MB
+ 2. Start wifi tethering and connect a dut to the SSID
+ 3. Download 20MB data on tethered device
+ 4. File download stops and data limit reached
+ 5. Verify data usage limit
+ """
+ # connect device to wifi hotspot
+ ad = self.tethered_devices[0]
+ wutils.toggle_wifi_off_and_on(self.dut)
+ wutils.start_wifi_tethering(self.dut,
+ self.network[wutils.WifiEnums.SSID_KEY],
+ self.network[wutils.WifiEnums.PWD_KEY],
+ ttutils.WIFI_CONFIG_APBAND_2G)
+ wutils.wifi_connect(ad, self.network)
+
+ # get pre mobile data usage
+ total_pre = self._get_total_data_usage_for_device(cconst.TYPE_MOBILE)
+
+ # set data usage limit to current usage limit + 10MB
+ self.log.info("Setting data usage limit to %sMB" % (total_pre + INC_DATA))
+ self.dut.droid.connectivitySetDataUsageLimit(
+ self.sub_id, str(int((total_pre + INC_DATA) * BYTE_TO_MB_ANDROID)))
+
+ # download file from tethered device
+ http_file_download_by_chrome(
+ ad, self.download_file, self.file_size, timeout=120)
+ total_pst = self._get_total_data_usage_for_device(cconst.TYPE_MOBILE)
+
+ # verify data usage
+ connectivity_status = wutils.validate_connection(ad)
+ self.dut.droid.connectivityFactoryResetNetworkPolicies(self.sub_id)
+ wutils.stop_wifi_tethering(self.dut)
+ self.log.info("Expected data usage: %s" % (total_pre + INC_DATA))
+ self.log.info("Actual data usage: %s" % total_pst)
+ asserts.assert_true(
+ not connectivity_status,
+ "Device has internet connectivity after reaching data limit")
+ return total_pst - total_pre - INC_DATA < DATA_USG_ERR
diff --git a/acts/tests/google/nfc/NfcBasicFunctionalityTest.py b/acts/tests/google/nfc/NfcBasicFunctionalityTest.py
index 8715fdf..5d531d1 100644
--- a/acts/tests/google/nfc/NfcBasicFunctionalityTest.py
+++ b/acts/tests/google/nfc/NfcBasicFunctionalityTest.py
@@ -23,30 +23,46 @@
class NfcBasicFunctionalityTest(BaseTestClass):
nfc_on_event = "NfcStateOn"
nfc_off_event = "NfcStateOff"
- timeout = 1
+ timeout = 5
def setup_class(self):
self.dut = self.android_devices[0]
+ self._ensure_nfc_enabled(self.dut)
self.dut.droid.nfcStartTrackingStateChange()
+ self.dut.adb.shell("setprop nfc.app_log_level 255")
+ self.dut.adb.shell("setprop nfc.enable_protocol_log 255")
+ self.dut.adb.shell("setprop nfc.nxp_log_level_global 5")
+ self.dut.adb.shell("setprop nfc.nxp_log_level_extns 5")
+ self.dut.adb.shell("setprop nfc.nxp_log_level_hal 5")
+ self.dut.adb.shell("setprop nfc.nxp_log_level_nci 5")
+ self.dut.adb.shell("setprop nfc.nxp_log_level_tml 5")
+ self.dut.adb.shell("setprop nfc.nxp_log_level_dnld 5")
+ self._ensure_nfc_disabled(self.dut)
return True
def _ensure_nfc_enabled(self, dut):
end_time = time.time() + 10
- while (not dut.droid.nfcIsEnabled() and end_time > time.time()):
+ while end_time > time.time():
try:
- dut.ed.pop_event(nfc_on_event, self.timeout)
+ dut.ed.pop_event(self.nfc_on_event, self.timeout)
+ self.log.info("Event {} found".format(self.nfc_on_event))
+ return True
except Exception as err:
- self.log.debug("Event not yet found")
- return dut.droid.nfcIsEnabled()
+ self.log.debug(
+ "Event {} not yet found".format(self.nfc_on_event))
+ return False
def _ensure_nfc_disabled(self, dut):
end_time = time.time() + 10
- while (dut.droid.nfcIsEnabled() and end_time > time.time()):
+ while end_time > time.time():
try:
- dut.ed.pop_event(nfc_off_event, self.timeout)
+ dut.ed.pop_event(self.nfc_off_event, self.timeout)
+ self.log.info("Event {} found".format(self.nfc_off_event))
+ return True
except Exception as err:
- self.log.debug("Event not yet found")
- return not dut.droid.nfcIsEnabled()
+ self.log.debug(
+ "Event {} not yet found".format(self.nfc_off_event))
+ return False
def setup_test(self):
# Every test starts with the assumption that NFC is enabled
@@ -59,6 +75,9 @@
return False
return True
+ def on_fail(self, test_name, begin_time):
+ self.dut.take_bug_report(test_name, begin_time)
+
@test_tracker_info(uuid='d57fcdd8-c56c-4ab0-81fb-e2218b100de9')
def test_nfc_toggle_state_100_iterations(self):
"""Test toggling NFC state 100 times.
diff --git a/acts/tests/google/tel/lab/TelLabCmasTest.py b/acts/tests/google/tel/lab/TelLabCmasTest.py
index 9ac76fc..0da53f1 100644
--- a/acts/tests/google/tel/lab/TelLabCmasTest.py
+++ b/acts/tests/google/tel/lab/TelLabCmasTest.py
@@ -44,6 +44,7 @@
from acts.test_utils.tel.anritsu_utils import set_system_model_gsm
from acts.test_utils.tel.anritsu_utils import set_system_model_wcdma
from acts.test_utils.tel.anritsu_utils import set_usim_parameters
+from acts.test_utils.tel.anritsu_utils import set_post_sim_params
from acts.test_utils.tel.tel_defines import NETWORK_MODE_CDMA
from acts.test_utils.tel.tel_defines import NETWORK_MODE_GSM_ONLY
from acts.test_utils.tel.tel_defines import NETWORK_MODE_GSM_UMTS
@@ -59,6 +60,7 @@
from acts.test_utils.tel.tel_test_utils import ensure_network_rat
from acts.test_utils.tel.tel_test_utils import ensure_phones_idle
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.test_decorators import test_tracker_info
@@ -88,10 +90,11 @@
return True
def setup_test(self):
+ if getattr(self, "qxdm_log", True):
+ start_qxdm_loggers(self.log, self.android_devices)
ensure_phones_idle(self.log, self.android_devices)
toggle_airplane_mode(self.log, self.ad, True)
- self.ad.adb.shell("setprop net.lte.ims.volte.provisioned 1",
- ignore_status=True)
+ self.ad.adb.shell("logcat -c -b all", ignore_status=True)
return True
def teardown_test(self):
@@ -118,6 +121,9 @@
[self.bts1] = set_simulation_func(self.anritsu, self.user_params,
self.ad.sim_card)
set_usim_parameters(self.anritsu, self.ad.sim_card)
+ if rat == RAT_LTE:
+ set_post_sim_params(self.anritsu, self.user_params,
+ self.ad.sim_card)
self.anritsu.start_simulation()
if rat == RAT_LTE:
@@ -134,6 +140,7 @@
preferred_network_setting = NETWORK_MODE_GSM_ONLY
rat_family = RAT_FAMILY_GSM
elif rat == RAT_1XRTT:
+ self.ad.droid.telephonyToggleDataConnection(False)
preferred_network_setting = NETWORK_MODE_CDMA
rat_family = RAT_FAMILY_CDMA2000
else:
@@ -157,8 +164,14 @@
self.log, self.ad, self.anritsu,
next(TelLabCmasTest.SERIAL_NO), message_id,
warning_message):
- self.log.error("Phone {} Failed to receive CMAS message"
- .format(self.ad.serial))
+ self.log.warning("Phone {} Failed to receive CMAS message"
+ .format(self.ad.serial))
+ # Another check of logcat before confirming failure
+ if self.ad.search_logcat(warning_message):
+ self.ad.log.info(
+ "Confirmed from Logcat - User received %s",
+ warning_message)
+ return True
return False
else:
if not cmas_receive_verify_message_cdma1x(
@@ -166,8 +179,13 @@
next(TelLabCmasTest.SERIAL_NO), message_id,
warning_message, c2k_response_type, c2k_severity,
c2k_urgency, c2k_certainty):
- self.log.error("Phone {} Failed to receive CMAS message"
- .format(self.ad.serial))
+ self.log.warning("Phone {} Failed to receive CMAS message"
+ .format(self.ad.serial))
+ if self.ad.search_logcat(warning_message):
+ self.ad.log.info(
+ "Confirmed from Logcat - User received %s",
+ warning_message)
+ return True
return False
except AnritsuError as e:
self.log.error("Error in connection with Anritsu Simulator: " +
diff --git a/acts/tests/google/tel/lab/TelLabDataRoamingTest.py b/acts/tests/google/tel/lab/TelLabDataRoamingTest.py
index 59d0964..71c5ed5 100644
--- a/acts/tests/google/tel/lab/TelLabDataRoamingTest.py
+++ b/acts/tests/google/tel/lab/TelLabDataRoamingTest.py
@@ -18,6 +18,7 @@
"""
import time
+from acts.test_decorators import test_tracker_info
from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError
from acts.controllers.anritsu_lib.md8475a import MD8475A
from acts.controllers.anritsu_lib.md8475a import BtsServiceState
@@ -25,12 +26,15 @@
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.test_utils.tel.anritsu_utils import set_system_model_lte_wcdma
from acts.test_utils.tel.anritsu_utils import set_usim_parameters
+from acts.test_utils.tel.anritsu_utils import set_post_sim_params
from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
from acts.test_utils.tel.tel_defines import RAT_FAMILY_LTE
from acts.test_utils.tel.tel_test_utils import ensure_network_rat
from acts.test_utils.tel.tel_test_utils import ensure_phones_idle
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts.test_utils.tel.tel_test_utils import toggle_cell_data_roaming
+from acts.test_utils.tel.tel_test_utils import set_preferred_apn_by_adb
+from acts.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts.utils import adb_shell_ping
PING_DURATION = 5 # Number of packets to ping
@@ -46,6 +50,8 @@
self.md8475a_ip_address = self.user_params[
"anritsu_md8475a_ip_address"]
self.wlan_option = self.user_params.get("anritsu_wlan_option", False)
+ if self.ad.sim_card == "VzW12349":
+ set_preferred_apn_by_adb(self.ad, "VZWINTERNET")
def setup_class(self):
try:
@@ -57,10 +63,12 @@
return True
def setup_test(self):
+ if getattr(self, "qxdm_log", True):
+ start_qxdm_loggers(self.log, self.android_devices)
ensure_phones_idle(self.log, self.android_devices)
toggle_airplane_mode(self.log, self.ad, True)
- self.ad.adb.shell("setprop net.lte.ims.volte.provisioned 1",
- ignore_status=True)
+ self.ad.adb.shell(
+ "setprop net.lte.ims.volte.provisioned 1", ignore_status=True)
return True
def teardown_test(self):
@@ -73,39 +81,62 @@
self.anritsu.disconnect()
return True
- def LTE_WCDMA_data_roaming(self, mcc, mnc):
+ def phone_setup_data_roaming(self):
+ return ensure_network_rat(
+ self.log,
+ self.ad,
+ NETWORK_MODE_LTE_GSM_WCDMA,
+ RAT_FAMILY_LTE,
+ toggle_apm_after_setting=True)
+
+ def LTE_WCDMA_data_roaming(self, mcc, mnc, lte_band, wcdma_band):
try:
[self.bts1, self.bts2] = set_system_model_lte_wcdma(
self.anritsu, self.user_params, self.ad.sim_card)
set_usim_parameters(self.anritsu, self.ad.sim_card)
+ set_post_sim_params(self.anritsu, self.user_params,
+ self.ad.sim_card)
self.bts1.mcc = mcc
self.bts1.mnc = mnc
self.bts2.mcc = mcc
self.bts2.mnc = mnc
- self.bts2.packet_rate = BtsPacketRate.WCDMA_DLHSAUTO_REL7_ULHSAUTO
+ self.bts1.band = lte_band
+ self.bts2.band = wcdma_band
+ self.bts2.packet_rate = BtsPacketRate.WCDMA_DLHSAUTO_REL8_ULHSAUTO
self.anritsu.start_simulation()
self.bts2.service_state = BtsServiceState.SERVICE_STATE_OUT
self.log.info("Toggle Mobile Data On")
self.ad.droid.telephonyToggleDataConnection(True)
- if not ensure_network_rat(
- self.log,
- self.ad,
- NETWORK_MODE_LTE_GSM_WCDMA,
- RAT_FAMILY_LTE,
- toggle_apm_after_setting=True):
- self.log.error(
- "Failed to set rat family {}, preferred network:{}".format(
- RAT_FAMILY_LTE, NETWORK_MODE_LTE_GSM_WCDMA))
- return False
+
+ if not self.phone_setup_data_roaming():
+ self.log.warning("phone_setup_func failed. Rebooting UE")
+ self.ad.reboot()
+ time.sleep(30)
+ if self.ad.sim_card == "VzW12349":
+ set_preferred_apn_by_adb(self.ad, "VZWINTERNET")
+ if not self.phone_setup_data_roaming():
+ self.log.error(
+ "Failed to set rat family {}, preferred network:{}".
+ format(RAT_FAMILY_LTE, NETWORK_MODE_LTE_GSM_WCDMA))
+ return False
+
toggle_cell_data_roaming(self.ad, True)
self.anritsu.wait_for_registration_state(1) # for BTS1 LTE
time.sleep(TIME_TO_WAIT_BEFORE_PING)
- if not adb_shell_ping(self.ad, PING_DURATION, PING_TARGET):
- self.log.error(
- "Test Fail: Phone {} can not ping {} with Data Roaming On"
- .format(self.ad.serial, PING_TARGET))
- return False
+ for i in range(3):
+ self.ad.log.info("Verify internet connection - attempt %d",
+ i + 1)
+ result = adb_shell_ping(self.ad, PING_DURATION, PING_TARGET)
+ if result:
+ self.ad.log.info("PING SUCCESS")
+ break
+ elif i == 2:
+ self.log.error(
+ "Test Fail: Phone {} can not ping {} with Data Roaming On"
+ .format(self.ad.serial, PING_TARGET))
+ return False
+
toggle_cell_data_roaming(self.ad, False)
time.sleep(TIME_TO_WAIT_BEFORE_PING)
if adb_shell_ping(self.ad, PING_DURATION, PING_TARGET):
@@ -124,11 +155,19 @@
self.anritsu.wait_for_registration_state(2) # for BTS2 WCDMA
time.sleep(TIME_TO_WAIT_BEFORE_PING)
- if not adb_shell_ping(self.ad, PING_DURATION, PING_TARGET):
- self.log.error(
- "Test Fail: Phone {} can not ping {} with Data Roaming On"
- .format(self.ad.serial, PING_TARGET))
- return False
+ for i in range(3):
+ self.ad.log.info("Verify internet connection - attempt %d",
+ i + 1)
+ result = adb_shell_ping(self.ad, PING_DURATION, PING_TARGET)
+ if result:
+ self.ad.log.info("PING SUCCESS")
+ break
+ elif i == 2:
+ self.log.error(
+ "Test Fail: Phone {} can not ping {} with Data Roaming On"
+ .format(self.ad.serial, PING_TARGET))
+ return False
+
toggle_cell_data_roaming(self.ad, False)
time.sleep(TIME_TO_WAIT_BEFORE_PING)
if adb_shell_ping(self.ad, PING_DURATION, PING_TARGET):
@@ -148,6 +187,7 @@
""" Tests Begin """
+ @test_tracker_info(uuid="46d49bff-9671-4ab0-a90d-b49d870af6f0")
@TelephonyBaseTest.tel_test_wrap
def test_data_roaming_optus(self):
"""Data roaming test for Optus LTE and WCDMA networks
@@ -171,8 +211,10 @@
Returns:
True if pass; False if fail
"""
- return self.LTE_WCDMA_data_roaming("505", "90F")
+ return self.LTE_WCDMA_data_roaming(
+ mcc="505", mnc="02F", lte_band="3", wcdma_band="1")
+ @test_tracker_info(uuid="68a6313c-d95a-4cae-8e35-2fdf3c94df56")
@TelephonyBaseTest.tel_test_wrap
def test_data_roaming_telus(self):
"""Data roaming test for Telus LTE and WCDMA networks
@@ -196,8 +238,10 @@
Returns:
True if pass; False if fail
"""
- return self.LTE_WCDMA_data_roaming("302", "86F")
+ return self.LTE_WCDMA_data_roaming(
+ mcc="302", mnc="220", lte_band="4", wcdma_band="2")
+ @test_tracker_info(uuid="16de850a-6511-42d4-8d8f-d800477aba6b")
@TelephonyBaseTest.tel_test_wrap
def test_data_roaming_vodafone(self):
"""Data roaming test for Vodafone LTE and WCDMA networks
@@ -221,8 +265,10 @@
Returns:
True if pass; False if fail
"""
- return self.LTE_WCDMA_data_roaming("234", "15F")
+ return self.LTE_WCDMA_data_roaming(
+ mcc="234", mnc="15F", lte_band="20", wcdma_band="1")
+ @test_tracker_info(uuid="e9050f3d-b53c-4a87-9363-b88a842a3479")
@TelephonyBaseTest.tel_test_wrap
def test_data_roaming_o2(self):
"""Data roaming test for O2 LTE and WCDMA networks
@@ -246,8 +292,10 @@
Returns:
True if pass; False if fail
"""
- return self.LTE_WCDMA_data_roaming("234", "02F")
+ return self.LTE_WCDMA_data_roaming(
+ mcc="234", mnc="02F", lte_band="20", wcdma_band="1")
+ @test_tracker_info(uuid="a3f56da1-6a51-45b0-8016-3a492661e1f4")
@TelephonyBaseTest.tel_test_wrap
def test_data_roaming_orange(self):
"""Data roaming test for Orange LTE and WCDMA networks
@@ -271,8 +319,10 @@
Returns:
True if pass; False if fail
"""
- return self.LTE_WCDMA_data_roaming("234", "33F")
+ return self.LTE_WCDMA_data_roaming(
+ mcc="234", mnc="33F", lte_band="20", wcdma_band="1")
+ @test_tracker_info(uuid="dcde16c1-730c-41ee-ad29-286f4962c66f")
@TelephonyBaseTest.tel_test_wrap
def test_data_roaming_idea(self):
"""Data roaming test for Idea LTE and WCDMA networks
@@ -296,6 +346,7 @@
Returns:
True if pass; False if fail
"""
- return self.LTE_WCDMA_data_roaming("404", "24F")
+ return self.LTE_WCDMA_data_roaming(
+ mcc="404", mnc="24F", lte_band="3", wcdma_band="1")
""" Tests End """
diff --git a/acts/tests/google/tel/lab/TelLabDataTest.py b/acts/tests/google/tel/lab/TelLabDataTest.py
index ee7d24c..abb2002 100644
--- a/acts/tests/google/tel/lab/TelLabDataTest.py
+++ b/acts/tests/google/tel/lab/TelLabDataTest.py
@@ -22,6 +22,7 @@
import logging
import os
+from acts.test_decorators import test_tracker_info
from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError
from acts.controllers.anritsu_lib.md8475a import MD8475A
from acts.controllers.anritsu_lib.md8475a import BtsBandwidth
@@ -35,12 +36,14 @@
from acts.test_utils.tel.anritsu_utils import sms_mo_send
from acts.test_utils.tel.anritsu_utils import sms_mt_receive_verify
from acts.test_utils.tel.anritsu_utils import set_usim_parameters
+from acts.test_utils.tel.anritsu_utils import set_post_sim_params
from acts.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
from acts.test_utils.tel.tel_defines import DIRECTION_MOBILE_TERMINATED
from acts.test_utils.tel.tel_defines import NETWORK_MODE_CDMA
from acts.test_utils.tel.tel_defines import NETWORK_MODE_GSM_ONLY
from acts.test_utils.tel.tel_defines import NETWORK_MODE_GSM_UMTS
from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
+from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_CDMA_EVDO
from acts.test_utils.tel.tel_defines import RAT_1XRTT
from acts.test_utils.tel.tel_defines import RAT_GSM
from acts.test_utils.tel.tel_defines import RAT_LTE
@@ -56,6 +59,7 @@
from acts.test_utils.tel.tel_test_utils import ensure_network_generation
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts.test_utils.tel.tel_test_utils import iperf_test_by_adb
+from acts.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.utils import adb_shell_ping
from acts.utils import rand_ascii_str
@@ -64,6 +68,7 @@
DEFAULT_PING_DURATION = 30
+
class TelLabDataTest(TelephonyBaseTest):
SETTLING_TIME = 30
SERIAL_NO = cb_serial_number()
@@ -97,10 +102,10 @@
return True
def setup_test(self):
+ if getattr(self, "qxdm_log", True):
+ start_qxdm_loggers(self.log, self.android_devices)
ensure_phones_idle(self.log, self.android_devices)
toggle_airplane_mode(self.log, self.ad, True)
- self.ad.adb.shell(
- "setprop net.lte.ims.volte.provisioned 1", ignore_status=True)
return True
def teardown_test(self):
@@ -118,6 +123,8 @@
[self.bts1] = set_simulation_func(self.anritsu, self.user_params,
self.ad.sim_card)
set_usim_parameters(self.anritsu, self.ad.sim_card)
+ set_post_sim_params(self.anritsu, self.user_params,
+ self.ad.sim_card)
if self.lte_bandwidth == 20:
self.bts1.bandwidth = BtsBandwidth.LTE_BANDWIDTH_20MHz
elif self.lte_bandwidth == 15:
@@ -130,7 +137,7 @@
self.anritsu.start_simulation()
if rat == RAT_LTE:
- preferred_network_setting = NETWORK_MODE_LTE_GSM_WCDMA
+ preferred_network_setting = NETWORK_MODE_LTE_CDMA_EVDO
rat_family = RAT_FAMILY_LTE
elif rat == RAT_WCDMA:
preferred_network_setting = NETWORK_MODE_GSM_UMTS
@@ -158,10 +165,6 @@
self.anritsu.wait_for_registration_state()
time.sleep(self.SETTLING_TIME)
- if not ensure_network_generation(self.log, self.ad, GEN_4G,
- NETWORK_SERVICE_DATA):
- self.log.error("Device not in 4G Connected Mode.")
- return False
# Fetch IP address of the host machine
cmd = "|".join(("ifconfig", "grep eth0 -A1", "grep inet",
@@ -198,7 +201,7 @@
else:
self.log.error("iperf failed to Destination.")
self.log.info("Iteration %d Failed", iteration)
- if float(current_power) < -55.0 :
+ if float(current_power) < -55.0:
return True
else:
return False
@@ -226,6 +229,7 @@
""" Tests Begin """
+ @test_tracker_info(uuid="df40279a-46dc-40ee-9205-bce2d0fba7e8")
@TelephonyBaseTest.tel_test_wrap
def test_lte_pings_iperf(self):
""" Test Pings functionality on LTE
diff --git a/acts/tests/google/tel/lab/TelLabEmergencyCallTest.py b/acts/tests/google/tel/lab/TelLabEmergencyCallTest.py
index 2a3a3d8..c46ddd8 100644
--- a/acts/tests/google/tel/lab/TelLabEmergencyCallTest.py
+++ b/acts/tests/google/tel/lab/TelLabEmergencyCallTest.py
@@ -36,6 +36,7 @@
from acts.test_utils.tel.anritsu_utils import set_system_model_lte_gsm
from acts.test_utils.tel.anritsu_utils import set_system_model_wcdma
from acts.test_utils.tel.anritsu_utils import set_usim_parameters
+from acts.test_utils.tel.anritsu_utils import set_post_sim_params
from acts.test_utils.tel.tel_defines import CALL_TEARDOWN_PHONE
from acts.test_utils.tel.tel_defines import DEFAULT_EMERGENCY_CALL_NUMBER
from acts.test_utils.tel.tel_defines import EMERGENCY_CALL_NUMBERS
@@ -57,16 +58,22 @@
from acts.test_utils.tel.tel_test_utils import ensure_phones_idle
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
from acts.test_utils.tel.tel_test_utils import toggle_volte
+from acts.test_utils.tel.tel_test_utils import check_apm_mode_on_by_serial
+from acts.test_utils.tel.tel_test_utils import set_apm_mode_on_by_serial
+from acts.test_utils.tel.tel_test_utils import set_preferred_apn_by_adb
+from acts.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts.test_utils.tel.tel_voice_utils import phone_idle_volte
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.test_decorators import test_tracker_info
+from acts.utils import exe_cmd
+
class TelLabEmergencyCallTest(TelephonyBaseTest):
def __init__(self, controllers):
TelephonyBaseTest.__init__(self, controllers)
try:
- self.stress_test_number = int(self.user_params[
- "stress_test_number"])
+ self.stress_test_number = int(
+ self.user_params["stress_test_number"])
self.log.info("Executing {} calls per test in stress test mode".
format(self.stress_test_number))
except KeyError:
@@ -91,6 +98,25 @@
self.log.warning("Unknown Emergency Number {}".format(
self.emergency_call_number))
+ # Check for all adb devices on the linux machine, and set APM ON
+ cmd = "|".join(("adb devices", "grep -i device$", "cut -f1"))
+ output = exe_cmd(cmd)
+ list_of_devices = output.decode("utf-8").split("\n")
+ if len(list_of_devices) > 1:
+ for i in range(len(list_of_devices) - 1):
+ self.log.info("Serial %s", list_of_devices[i])
+ if check_apm_mode_on_by_serial(self.ad, list_of_devices[i]):
+ self.log.info("Device is already in APM ON")
+ else:
+ self.log.info("Device is not in APM, turning it ON")
+ set_apm_mode_on_by_serial(self.ad, list_of_devices[i])
+ if check_apm_mode_on_by_serial(self.ad,
+ list_of_devices[i]):
+ self.log.info("Device is now in APM ON")
+
+ if self.ad.sim_card == "VzW12349":
+ set_preferred_apn_by_adb(self.ad, "VZWINTERNET")
+
def setup_class(self):
try:
self.anritsu = MD8475A(self.md8475a_ip_address, self.log,
@@ -101,10 +127,15 @@
return True
def setup_test(self):
+ if getattr(self, "qxdm_log", True):
+ start_qxdm_loggers(self.log, self.android_devices)
ensure_phone_default_state(self.log, self.ad, check_subscription=False)
toggle_airplane_mode_by_adb(self.log, self.ad, True)
- self.ad.adb.shell("setprop net.lte.ims.volte.provisioned 1",
- ignore_status=True)
+ try:
+ if self.ad.sim_card == "VzW12349":
+ self.ad.droid.imsSetVolteProvisioning(True)
+ except Exception as e:
+ self.ad.log.error(e)
# get a handle to virtual phone
self.virtualPhoneHandle = self.anritsu.get_VirtualPhone()
return True
@@ -135,6 +166,9 @@
set_simulation_func(self.anritsu, self.user_params,
self.ad.sim_card)
set_usim_parameters(self.anritsu, self.ad.sim_card)
+ if is_ims_call or srvcc or csfb_type:
+ set_post_sim_params(self.anritsu, self.user_params,
+ self.ad.sim_card)
self.virtualPhoneHandle.auto_answer = (VirtualPhoneAutoAnswer.ON,
2)
if csfb_type:
@@ -168,12 +202,16 @@
elif srvcc == "InCall":
self.anritsu.start_simulation()
self.anritsu.send_command("IMSSTARTVN 1")
+ self.anritsu.send_command("IMSSTARTVN 2")
+ self.anritsu.send_command("IMSSTARTVN 3")
check_ims_reg = True
check_ims_calling = True
else:
self.anritsu.start_simulation()
- if is_ims_call:
+ if is_ims_call or csfb_type:
self.anritsu.send_command("IMSSTARTVN 1")
+ self.anritsu.send_command("IMSSTARTVN 2")
+ self.anritsu.send_command("IMSSTARTVN 3")
iterations = 1
if self.stress_test_number > 0:
@@ -181,8 +219,8 @@
successes = 0
for i in range(1, iterations + 1):
if self.stress_test_number:
- self.log.info("Running iteration {} of {}".format(
- i, iterations))
+ self.log.info(
+ "Running iteration {} of {}".format(i, iterations))
# FIXME: There's no good reason why this must be true;
# I can only assume this was done to work around a problem
self.ad.droid.telephonyToggleDataConnection(False)
@@ -191,13 +229,21 @@
sim_model = (self.anritsu.get_simulation_model()).split(",")
no_of_bts = len(sim_model)
for i in range(2, no_of_bts + 1):
- self.anritsu.send_command("OUTOFSERVICE OUT,BTS{}".format(
- i))
+ self.anritsu.send_command(
+ "OUTOFSERVICE OUT,BTS{}".format(i))
if phone_setup_func is not None:
if not phone_setup_func(self.ad):
- self.log.error("phone_setup_func failed.")
- continue
+ self.log.warning(
+ "phone_setup_func failed. Rebooting UE")
+ self.ad.reboot()
+ time.sleep(30)
+ if self.ad.sim_card == "VzW12349":
+ set_preferred_apn_by_adb(self.ad, "VZWINTERNET")
+ if not phone_setup_func(self.ad):
+ self.log.error("phone_setup_func failed.")
+ continue
+
if is_wait_for_registration:
self.anritsu.wait_for_registration_state()
@@ -207,8 +253,8 @@
continue
for i in range(2, no_of_bts + 1):
- self.anritsu.send_command("OUTOFSERVICE IN,BTS{}".format(
- i))
+ self.anritsu.send_command(
+ "OUTOFSERVICE IN,BTS{}".format(i))
time.sleep(WAIT_TIME_ANRITSU_REG_AND_CALL)
if srlte_csfb or srvcc:
@@ -249,6 +295,7 @@
return True
def _phone_setup_lte_wcdma(self, ad):
+ toggle_volte(self.log, ad, False)
return ensure_network_rat(
self.log,
ad,
@@ -313,17 +360,17 @@
@test_tracker_info(uuid="f5c93228-3b43-48a3-b509-796d41625171")
@TelephonyBaseTest.tel_test_wrap
def test_emergency_call_lte_wcdma_csfb_redirection(self):
- """ Test Emergency call functionality on LTE (CSFB to WCDMA).
+ """ Test Emergency call functionality on LTE.
CSFB type is REDIRECTION
Steps:
1. Setup CallBox on LTE and WCDMA network, make sure DUT register on LTE network.
- 2. Make an emergency call to 911. Make sure DUT CSFB to WCDMA.
+ 2. Make an emergency call to 911. Make sure DUT does not CSFB to WCDMA.
3. Make sure Anritsu receives the call and accept.
4. Tear down the call.
Expected Results:
- 2. Emergency call succeed. DUT CSFB to WCDMA.
+ 2. Emergency call succeed. DUT does not CSFB to WCDMA.
3. Anritsu can accept the call.
4. Tear down call succeed.
@@ -334,22 +381,23 @@
set_system_model_lte_wcdma,
self._phone_setup_lte_wcdma,
emergency_number=self.emergency_call_number,
- csfb_type=CsfbType.CSFB_TYPE_REDIRECTION)
+ csfb_type=CsfbType.CSFB_TYPE_REDIRECTION,
+ is_ims_call=True)
@test_tracker_info(uuid="8deb6b21-2cb0-4241-bcad-6cd62a340b07")
@TelephonyBaseTest.tel_test_wrap
def test_emergency_call_lte_wcdma_csfb_handover(self):
- """ Test Emergency call functionality on LTE (CSFB to WCDMA).
+ """ Test Emergency call functionality on LTE.
CSFB type is HANDOVER
Steps:
1. Setup CallBox on LTE and WCDMA network, make sure DUT register on LTE network.
- 2. Make an emergency call to 911. Make sure DUT CSFB to WCDMA.
+ 2. Make an emergency call to 911. Make sure DUT does not CSFB to WCDMA.
3. Make sure Anritsu receives the call and accept.
4. Tear down the call.
Expected Results:
- 2. Emergency call succeed. DUT CSFB to WCDMA.
+ 2. Emergency call succeed. DUT does not CSFB to WCDMA.
3. Anritsu can accept the call.
4. Tear down call succeed.
@@ -360,7 +408,8 @@
set_system_model_lte_wcdma,
self._phone_setup_lte_wcdma,
emergency_number=self.emergency_call_number,
- csfb_type=CsfbType.CSFB_TYPE_HANDOVER)
+ csfb_type=CsfbType.CSFB_TYPE_HANDOVER,
+ is_ims_call=True)
@test_tracker_info(uuid="52b6b783-de77-497d-87e0-63c930e6c9bb")
@TelephonyBaseTest.tel_test_wrap
diff --git a/acts/tests/google/tel/lab/TelLabEtwsTest.py b/acts/tests/google/tel/lab/TelLabEtwsTest.py
index 3c469b4..0576c9b 100644
--- a/acts/tests/google/tel/lab/TelLabEtwsTest.py
+++ b/acts/tests/google/tel/lab/TelLabEtwsTest.py
@@ -30,6 +30,7 @@
from acts.test_utils.tel.anritsu_utils import set_system_model_lte
from acts.test_utils.tel.anritsu_utils import set_system_model_wcdma
from acts.test_utils.tel.anritsu_utils import set_usim_parameters
+from acts.test_utils.tel.anritsu_utils import set_post_sim_params
from acts.test_utils.tel.tel_defines import NETWORK_MODE_CDMA
from acts.test_utils.tel.tel_defines import NETWORK_MODE_GSM_ONLY
from acts.test_utils.tel.tel_defines import NETWORK_MODE_GSM_UMTS
@@ -45,6 +46,7 @@
from acts.test_utils.tel.tel_test_utils import ensure_network_rat
from acts.test_utils.tel.tel_test_utils import ensure_phones_idle
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.test_decorators import test_tracker_info
@@ -76,10 +78,10 @@
return True
def setup_test(self):
+ if getattr(self, "qxdm_log", True):
+ start_qxdm_loggers(self.log, self.android_devices)
ensure_phones_idle(self.log, self.android_devices)
toggle_airplane_mode(self.log, self.ad, True)
- self.ad.adb.shell("setprop net.lte.ims.volte.provisioned 1",
- ignore_status=True)
return True
def teardown_test(self):
@@ -97,6 +99,9 @@
[self.bts1] = set_simulation_func(self.anritsu, self.user_params,
self.ad.sim_card)
set_usim_parameters(self.anritsu, self.ad.sim_card)
+ if rat == RAT_LTE:
+ set_post_sim_params(self.anritsu, self.user_params,
+ self.ad.sim_card)
self.anritsu.start_simulation()
if rat == RAT_LTE:
diff --git a/acts/tests/google/tel/lab/TelLabMobilityTest.py b/acts/tests/google/tel/lab/TelLabMobilityTest.py
index 8ce7b7e..12e570b 100644
--- a/acts/tests/google/tel/lab/TelLabMobilityTest.py
+++ b/acts/tests/google/tel/lab/TelLabMobilityTest.py
@@ -18,6 +18,7 @@
"""
import time
+from acts.test_decorators import test_tracker_info
from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError
from acts.controllers.anritsu_lib.md8475a import MD8475A
from acts.controllers.anritsu_lib.md8475a import BtsNumber
@@ -31,6 +32,7 @@
from acts.test_utils.tel.anritsu_utils import set_system_model_lte_1x
from acts.test_utils.tel.anritsu_utils import set_system_model_lte_evdo
from acts.test_utils.tel.anritsu_utils import set_usim_parameters
+from acts.test_utils.tel.anritsu_utils import set_post_sim_params
from acts.test_utils.tel.tel_defines import CALL_TEARDOWN_PHONE
from acts.test_utils.tel.tel_defines import RAT_FAMILY_CDMA2000
from acts.test_utils.tel.tel_defines import RAT_FAMILY_GSM
@@ -51,6 +53,8 @@
from acts.test_utils.tel.tel_test_utils import toggle_volte
from acts.test_utils.tel.tel_test_utils import run_multithread_func
from acts.test_utils.tel.tel_test_utils import iperf_test_by_adb
+from acts.test_utils.tel.tel_test_utils import set_preferred_apn_by_adb
+from acts.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts.test_utils.tel.tel_voice_utils import phone_idle_volte
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.utils import adb_shell_ping
@@ -58,7 +62,7 @@
from acts.controllers import iperf_server
from acts.utils import exe_cmd
-DEFAULT_CALL_NUMBER = "0123456789"
+DEFAULT_CALL_NUMBER = "+11234567891"
DEFAULT_PING_DURATION = 5
WAITTIME_BEFORE_HANDOVER = 20
WAITTIME_AFTER_HANDOVER = 20
@@ -77,6 +81,8 @@
self.ip_server = self.iperf_servers[0]
self.port_num = self.ip_server.port
self.log.info("Iperf Port is %s", self.port_num)
+ if self.ad.sim_card == "VzW12349":
+ set_preferred_apn_by_adb(self.ad, "VZWINTERNET")
def setup_class(self):
try:
@@ -89,6 +95,8 @@
def setup_test(self):
try:
+ if getattr(self, "qxdm_log", True):
+ start_qxdm_loggers(self.log, self.android_devices)
self.ad.droid.telephonyFactoryReset()
except Exception as e:
self.ad.log.error(e)
@@ -115,7 +123,7 @@
phone_idle_func_after_registration=None,
volte=True,
iperf=True,
- all_bands=True,
+ all_bands=False,
is_wait_for_registration=True,
voice_number=DEFAULT_CALL_NUMBER,
teardown_side=CALL_TEARDOWN_PHONE,
@@ -124,91 +132,108 @@
bts = set_simulation_func(self.anritsu, self.user_params,
self.ad.sim_card)
set_usim_parameters(self.anritsu, self.ad.sim_card)
-
+ set_post_sim_params(self.anritsu, self.user_params,
+ self.ad.sim_card)
self.anritsu.start_simulation()
self.anritsu.send_command("IMSSTARTVN 1")
-
- self.ad.droid.telephonyToggleDataConnection(False)
-
+ self.anritsu.send_command("IMSSTARTVN 2")
+ self.anritsu.send_command("IMSSTARTVN 3")
# turn off all other BTS to ensure UE registers on BTS1
- sim_model = (self.anritsu.get_simulation_model()).split(",")
- no_of_bts = len(sim_model)
+ simmodel = self.anritsu.get_simulation_model().split(',')
+ no_of_bts = len(simmodel)
for i in range(2, no_of_bts + 1):
self.anritsu.send_command("OUTOFSERVICE OUT,BTS{}".format(i))
if phone_setup_func is not None:
if not phone_setup_func(self.ad):
- self.log.error("phone_setup_func failed.")
-
+ self.log.warning("phone_setup_func failed. Rebooting UE")
+ self.ad.reboot()
+ time.sleep(30)
+ if self.ad.sim_card == "VzW12349":
+ set_preferred_apn_by_adb(self.ad, "VZWINTERNET")
+ if not phone_setup_func(self.ad):
+ self.log.error("phone_setup_func failed.")
if is_wait_for_registration:
self.anritsu.wait_for_registration_state()
-
if phone_idle_func_after_registration:
if not phone_idle_func_after_registration(self.log, self.ad):
self.log.error("phone_idle_func failed.")
-
for i in range(2, no_of_bts + 1):
self.anritsu.send_command("OUTOFSERVICE IN,BTS{}".format(i))
-
time.sleep(WAIT_TIME_ANRITSU_REG_AND_CALL)
-
- if iperf:
+ if iperf: # setup iPerf server
server_ip = self.iperf_setup()
if not server_ip:
self.log.error("iperf server can not be reached by ping")
return False
-
- if volte:
+ if volte: # make a VoLTE MO call
if not make_ims_call(self.log, self.ad, self.anritsu,
voice_number):
self.log.error("Phone {} Failed to make volte call to {}"
.format(self.ad.serial, voice_number))
return False
+ if all_bands and (simmodel[1] == "WCDMA"):
+ band = []
+ for rat in simmodel[:2]:
+ band.append(self.anritsu.get_supported_bands(rat))
+ self.log.info("UE reported LTE bands are {}".format(band[0]))
+ self.log.info("UE reported WCDMA bands are {}".format(band[1]))
+ current_lte_band = bts[0].band
+ # move current LTE band to the last in the list
+ band[0].remove(current_lte_band)
+ band[0].append(current_lte_band)
+ n = max(len(band[0]), len(band[1]))
+ else:
+ n = 1 # n is the number of LTE->WCDMA->LTE handovers
- if not iperf: # VoLTE only
- result = handover_tc(self.log, self.anritsu,
- WAITTIME_BEFORE_HANDOVER, BtsNumber.BTS1,
- BtsNumber.BTS2)
- time.sleep(WAITTIME_AFTER_HANDOVER)
- else: # with iPerf
- iperf_task = (self._iperf_task, (
- server_ip,
- WAITTIME_BEFORE_HANDOVER + WAITTIME_AFTER_HANDOVER - 10))
- ho_task = (handover_tc,
- (self.log, self.anritsu, WAITTIME_BEFORE_HANDOVER,
- BtsNumber.BTS1, BtsNumber.BTS2))
- result = run_multithread_func(self.log, [ho_task, iperf_task])
- if not result[1]:
- self.log.error("iPerf failed.")
- return False
+ for i in range(n):
+ if all_bands:
+ bts[1].band = band[1][i % len(band[1])]
+ if not iperf: # VoLTE only
+ result = handover_tc(self.log, self.anritsu,
+ WAITTIME_BEFORE_HANDOVER,
+ BtsNumber.BTS1, BtsNumber.BTS2)
+ time.sleep(WAITTIME_AFTER_HANDOVER)
+ else: # with iPerf
+ iperf_task = (self._iperf_task,
+ (server_ip, WAITTIME_BEFORE_HANDOVER +
+ WAITTIME_AFTER_HANDOVER - 10))
+ ho_task = (handover_tc, (self.log, self.anritsu,
+ WAITTIME_BEFORE_HANDOVER,
+ BtsNumber.BTS1, BtsNumber.BTS2))
+ result = run_multithread_func(self.log,
+ [ho_task, iperf_task])
+ if not result[1]:
+ self.log.error("iPerf failed.")
+ return False
- self.log.info("handover test case result code {}.".format(result[
- 0]))
+ self.log.info(
+ "handover test case result code {}.".format(result[0]))
+ if volte:
+ # check if the phone stay in call
+ if not self.ad.droid.telecomIsInCall():
+ self.log.error("Call is already ended in the phone.")
+ return False
- if volte:
- # check if the phone stay in call
- if not self.ad.droid.telecomIsInCall():
- self.log.error("Call is already ended in the phone.")
- return False
-
- if not tear_down_call(self.log, self.ad, self.anritsu):
- self.log.error("Phone {} Failed to tear down"
- .format(self.ad.serial, voice_number))
- return False
-
- simmodel = self.anritsu.get_simulation_model().split(',')
- if simmodel[1] == "WCDMA" and iperf:
- iperf_task = (self._iperf_task, (
- server_ip,
- WAITTIME_BEFORE_HANDOVER + WAITTIME_AFTER_HANDOVER - 10))
- ho_task = (handover_tc,
- (self.log, self.anritsu, WAITTIME_BEFORE_HANDOVER,
- BtsNumber.BTS2, BtsNumber.BTS1))
- result = run_multithread_func(self.log, [ho_task, iperf_task])
- if not result[1]:
- self.log.error("iPerf failed.")
- return False
- self.log.info("handover test case result code {}.".format(
- result[0]))
+ if not tear_down_call(self.log, self.ad, self.anritsu):
+ self.log.error("Phone {} Failed to tear down"
+ .format(self.ad.serial, voice_number))
+ return False
+ if simmodel[1] == "WCDMA" and iperf:
+ if all_bands:
+ bts[0].band = band[0][i % len(band[0])]
+ iperf_task = (self._iperf_task,
+ (server_ip, WAITTIME_BEFORE_HANDOVER +
+ WAITTIME_AFTER_HANDOVER - 10))
+ ho_task = (handover_tc, (self.log, self.anritsu,
+ WAITTIME_BEFORE_HANDOVER,
+ BtsNumber.BTS2, BtsNumber.BTS1))
+ result = run_multithread_func(self.log,
+ [ho_task, iperf_task])
+ if not result[1]:
+ self.log.error("iPerf failed.")
+ return False
+ self.log.info(
+ "handover test case result code {}.".format(result[0]))
except AnritsuError as e:
self.log.error("Error in connection with Anritsu Simulator: " +
@@ -313,6 +338,7 @@
""" Tests Begin """
+ @test_tracker_info(uuid="bd014822-2c09-4503-9e01-594513ea6808")
@TelephonyBaseTest.tel_test_wrap
def test_volte_iperf_handover(self):
""" Test VoLTE to VoLTE Inter-Freq handover with iPerf data
@@ -340,6 +366,7 @@
volte=True,
iperf=True)
+ @test_tracker_info(uuid="a5a15947-40eb-4a70-b652-0b52a548c3c1")
@TelephonyBaseTest.tel_test_wrap
def test_volte_handover(self):
""" Test VoLTE to VoLTE Inter-Freq handover without iPerf data
@@ -365,6 +392,7 @@
volte=True,
iperf=False)
+ @test_tracker_info(uuid="382521d9-d991-49bc-8347-2e766ec0db74")
@TelephonyBaseTest.tel_test_wrap
def test_iperf_handover(self):
""" Test Inter-Freq handover with iPerf data
@@ -389,22 +417,24 @@
volte=False,
iperf=True)
+ @test_tracker_info(uuid="d255a58b-8697-4d0a-9bc0-1e7ffa4cccaf")
@TelephonyBaseTest.tel_test_wrap
def test_volte_iperf_handover_wcdma(self):
- """ Test VoLTE to VoLTE Inter-Freq handover with iPerf data
+ """ Test VoLTE to WCDMA to LTE handover with iPerf data
Steps:
- 1. Setup CallBox for 2 LTE cells with 2 different bands.
+ 1. Setup CallBox for LTE and WCDMA simulation.
2. Turn on DUT and enable VoLTE. Make an voice call to DEFAULT_CALL_NUMBER.
3. Check if VoLTE voice call connected successfully.
4. Start iPerf data transfer
- 5. Handover the call to BTS2 and check if the call is still up.
+ 5. SRVCC to WCDMA and check if the call is still up.
6. Check iPerf data throughput
7. Tear down the call.
+ 8. Handover back to LTE with iPerf
Expected Results:
1. VoLTE Voice call is made successfully.
2. After handover, the call is not dropped.
- 3. Tear down call succeed.
+ 3. iPerf continue after handover
Returns:
True if pass; False if fail
@@ -416,11 +446,12 @@
volte=True,
iperf=True)
+ @test_tracker_info(uuid="28bc2e85-602e-4143-afe7-6dd442bef5c8")
@TelephonyBaseTest.tel_test_wrap
def test_volte_handover_wcdma(self):
- """ Test VoLTE to VoLTE Inter-Freq handover with iPerf data
+ """ Test VoLTE to WCDMA handover (SRVCC)
Steps:
- 1. Setup CallBox for 2 LTE cells with 2 different bands.
+ 1. Setup CallBox for LTE and WCDMA simulation.
2. Turn on DUT and enable VoLTE. Make an voice call to DEFAULT_CALL_NUMBER.
3. Check if VoLTE voice call connected successfully.
4. Start iPerf data transfer
@@ -443,22 +474,24 @@
volte=True,
iperf=False)
+ @test_tracker_info(uuid="3ef15650-8e44-4b75-b809-8d7dec5a41e3")
@TelephonyBaseTest.tel_test_wrap
def test_iperf_handover_wcdma(self):
- """ Test VoLTE to VoLTE Inter-Freq handover with iPerf data
+ """ Test LTE to WCDMA to LTE handovers with iPerf data
Steps:
- 1. Setup CallBox for 2 LTE cells with 2 different bands.
- 2. Turn on DUT and enable VoLTE. Make an voice call to DEFAULT_CALL_NUMBER.
- 3. Check if VoLTE voice call connected successfully.
- 4. Start iPerf data transfer
- 5. Handover the call to BTS2 and check if the call is still up.
- 6. Check iPerf data throughput
- 7. Tear down the call.
+ 1. Setup CallBox for LTE and WCDMA simulation.
+ 2. Turn on DUT and register on LTE BTS.
+ 3. Start iPerf data transfer
+ 4. Handover to WCDMA.
+ 5. Stop and check iPerf data throughput
+ 6. Start iPerf data transfer
+ 7. Handover to WCDMA.
+ 8. Stop and check iPerf data throughput
+
Expected Results:
- 1. VoLTE Voice call is made successfully.
- 2. After handover, the call is not dropped.
- 3. Tear down call succeed.
+ 1. Each handover is successful
+ 2. After each handover, the iPerf continues successfully.
Returns:
True if pass; False if fail
@@ -470,4 +503,38 @@
volte=False,
iperf=True)
+ @test_tracker_info(uuid="2bfad82d-1797-474b-9bf7-c14602b061cd")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_iperf_handover_wcdma_all_bands(self):
+ """ Test LTE->WCDMA->LTE handovers through all bands UE supports with iPerf data
+ Steps:
+ 1. Setup CallBox for LTE and WCDMA simulation.
+ 2. Turn on DUT and register on LTE BTS.
+ 3. Query MD8475A for UE supported bands contained in UE Capability Information
+ 4. Set target WCDMA band with first band in WCDMA supported band list
+ 5. Start iPerf data transfer
+ 6. Handover to WCDMA.
+ 7. Stop and check iPerf data throughput
+ 8. Set target LTE band with first band in LTE supported band list
+ 9. Start iPerf data transfer
+ 10. Handover to LTE.
+ 11. Stop and check iPerf data throughput
+ 12. Repeat step 4-11 with second WCDMA/LTE bands in supported band lists
+ 13. Repeat step 12 until all bands are tested. Reuse the begining of the shorter list to match the longer list.
+
+ Expected Results:
+ 1. Each handover is successful
+ 2. After each handover, the iPerf continues successfully.
+
+ Returns:
+ True if pass; False if fail
+ """
+ return self.active_handover(
+ set_system_model_lte_wcdma,
+ self._phone_setup_volte,
+ phone_idle_volte,
+ volte=False,
+ iperf=True,
+ all_bands=True)
+
""" Tests End """
diff --git a/acts/tests/google/tel/lab/TelLabNeighborCellTest.py b/acts/tests/google/tel/lab/TelLabNeighborCellTest.py
index c616777..0a2cf8e 100644
--- a/acts/tests/google/tel/lab/TelLabNeighborCellTest.py
+++ b/acts/tests/google/tel/lab/TelLabNeighborCellTest.py
@@ -19,6 +19,7 @@
import math
import time
+from acts.test_decorators import test_tracker_info
from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError
from acts.controllers.anritsu_lib.md8475a import CTCHSetup
from acts.controllers.anritsu_lib.md8475a import BtsBandwidth
@@ -593,6 +594,7 @@
""" Tests Begin """
+ @test_tracker_info(uuid="17a42861-abb5-480b-9139-89219fa304b2")
@TelephonyBaseTest.tel_test_wrap
def test_2lte_intra_freq_ncell_away_close(self):
""" Test phone moving away from Neighbor Intra Freq cell then
@@ -639,6 +641,7 @@
return self.lte_intra_freq_ncell(self.ad, pcid, init_pwr, power_seq)
+ @test_tracker_info(uuid="117f404b-fb78-474a-86ba-209e6a54c9a8")
@TelephonyBaseTest.tel_test_wrap
def test_2lte_intra_freq_scell_away_close(self):
""" Test phone moving away from serving cell then close back while
@@ -686,8 +689,9 @@
return self.lte_intra_freq_ncell(self.ad, pcid, init_pwr, power_seq)
+ @test_tracker_info(uuid="d1eec95f-40e9-4099-a669-9a88e56049ca")
@TelephonyBaseTest.tel_test_wrap
- def test_2lte_intra_freq_ncell_away_close(self):
+ def test_2lte_intra_freq_ncell_away_close_2(self):
""" Test phone moving away from serving cell and close to neighbor
Intra Freq cell, then back and forth
@@ -719,6 +723,7 @@
return self.lte_intra_freq_ncell(self.ad, pcid, init_pwr, power_seq)
+ @test_tracker_info(uuid="c642a85b-4970-429c-81c4-f635392879be")
@TelephonyBaseTest.tel_test_wrap
def test_2lte_intra_freq_2cell_synced(self):
""" Test phone moving away and back to both serving cell and neighbor
@@ -751,6 +756,7 @@
return self.lte_intra_freq_ncell(self.ad, pcid, init_pwr, power_seq)
+ @test_tracker_info(uuid="9144fab6-c7e1-4de2-a01d-7a15c117ec70")
@TelephonyBaseTest.tel_test_wrap
def test_3lte_intra_freq_scell_reversed(self):
""" Test phone moving away and back between 2 neighbor cells while maintain
@@ -786,6 +792,7 @@
return self.lte_intra_freq_ncell(self.ad, pcid, init_pwr, power_seq)
+ @test_tracker_info(uuid="7bfbea72-e6fa-45ae-bf7e-b9b42063abe7")
@TelephonyBaseTest.tel_test_wrap
def test_3lte_intra_freq_3cell_synced(self):
""" Test phone moving away and back to both serving cell and neighbor
@@ -818,6 +825,7 @@
return self.lte_intra_freq_ncell(self.ad, pcid, init_pwr, power_seq)
+ @test_tracker_info(uuid="b4577ae1-6435-4a15-9449-e02013dfb032")
@TelephonyBaseTest.tel_test_wrap
def test_ncells_intra_lte_0_cells(self):
""" Test Number of neighbor cells reported by Phone when no neighbor
@@ -870,6 +878,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="fe2cc07b-9676-41ab-b7ff-112d3ef84980")
@TelephonyBaseTest.tel_test_wrap
def test_ncells_intra_lte_1_cells(self):
""" Test Number of neighbor cells reported by Phone when one neighbor
@@ -945,6 +954,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="8abc7903-4ea7-407a-946b-455d7f767c3e")
@TelephonyBaseTest.tel_test_wrap
def test_ncells_intra_lte_2_cells(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -1031,6 +1041,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="623b3d16-bc48-4353-abc3-054ca6351a97")
@TelephonyBaseTest.tel_test_wrap
def test_ncells_intra_lte_3_cells(self):
""" Test Number of neighbor cells reported by Phone when three neighbor
@@ -1131,6 +1142,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="3e094e3d-e7b7-447a-9a7a-8060c5b17e88")
@TelephonyBaseTest.tel_test_wrap
def test_ncells_intra_lte_4_cells(self):
""" Test Number of neighbor cells reported by Phone when four neighbor
@@ -1250,6 +1262,7 @@
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="7e9a9c30-9284-4440-b85e-f94b83e0373f")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_lte_intrafreq_0_tmo(self):
""" Test Number of neighbor cells reported by Phone when no neighbor
@@ -1303,6 +1316,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="13bd7000-5a45-43f5-9e54-001e0aa09262")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_lte_intrafreq_1_tmo(self):
""" Test Number of neighbor cells reported by Phone when one neighbor
@@ -1377,6 +1391,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="5dca3a16-73a0-448a-a35d-22ebd253a570")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_lte_intrafreq_2_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -1471,6 +1486,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="860152de-8aa0-422e-b5b0-28bf244076f4")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_lte_intrafreq_3_tmo(self):
""" Test Number of neighbor cells reported by Phone when three neighbor
@@ -1583,6 +1599,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="8c5b63ba-1322-47b6-adce-5224cbc0995a")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_lte_interfreq_1_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -1661,6 +1678,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="97853501-a328-4706-bb3f-c5e708b1ccb8")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_lte_interfreq_2_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -1759,6 +1777,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="74bd528c-e1c5-476d-9ee0-ebfc7bbc5de1")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_lte_interband_2_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -1856,6 +1875,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="6289e3e4-9316-4b82-bd0b-dde53f26da0d")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_lte_interrat_1_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -1933,6 +1953,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="9be4e4a8-f79a-4283-9a85-371a9bddfa5d")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_lte_interrat_2_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -2029,6 +2050,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="14db7a3d-b18b-4b87-9d84-fb0c00d3971e")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_wcdma_intrafreq_0_tmo(self):
""" Test Number of neighbor cells reported by Phone when no neighbor
@@ -2081,6 +2103,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="1a227d1e-9991-4646-b51a-8156f24485da")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_wcdma_intrafreq_1_tmo(self):
""" Test Number of neighbor cells reported by Phone when one neighbor
@@ -2156,6 +2179,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="170689a0-0db1-4a14-8b87-5a1b6c9b8581")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_wcdma_intrafreq_2_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -2250,6 +2274,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="3ec77512-4d5b-40c9-b733-cf358f999e15")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_wcdma_intrafreq_3_tmo(self):
""" Test Number of neighbor cells reported by Phone when three neighbor
@@ -2364,6 +2389,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="6f39e4a5-81da-4f47-8022-f22d82ff6f31")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_wcdma_interfreq_1_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -2442,6 +2468,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="992d9ffb-2538-447b-b7e8-f40061063686")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_wcdma_interfreq_2_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -2537,6 +2564,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="60cb8c15-3cb3-4ead-9e59-a8aee819e9ef")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_wcdma_interband_2_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -2633,6 +2661,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="daa29f27-f67b-47ee-9a30-1c9572eedf2f")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_wcdma_interrat_1_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -2723,6 +2752,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="08e5d666-fae6-48a3-b03b-de7b7b3f5982")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_wcdma_interrat_2_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -2819,6 +2849,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="bebbe764-4c8c-4aaf-81b9-c61509a9695e")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_gsm_intrafreq_0_tmo(self):
""" Test Number of neighbor cells reported by Phone when no neighbor
@@ -2869,6 +2900,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="861dd399-d6f6-4e9f-9e8d-0718966ea45a")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_gsm_intrafreq_1_tmo(self):
""" Test Number of neighbor cells reported by Phone when one neighbor
@@ -2943,6 +2975,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="58627a33-45bd-436d-85b2-1ca711f56794")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_gsm_intrafreq_2_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -3035,6 +3068,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="3ff3439a-2e45-470a-a2d6-c63e37379f19")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_gsm_intrafreq_3_tmo(self):
""" Test Number of neighbor cells reported by Phone when three neighbor
@@ -3145,6 +3179,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="0cac1370-144e-40a4-b6bc-66691926f898")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_gsm_interfreq_1_tmo(self):
""" Test Number of neighbor cells reported by Phone when one neighbor
@@ -3220,6 +3255,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="5f0367dd-08b5-4871-a784-51a0f76e229b")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_gsm_interfreq_2_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -3313,6 +3349,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="b195153f-f6a0-4ec4-bb53-29c30ec0a034")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_gsm_interband_2_tmo(self):
""" Test Number of neighbor cells reported by Phone when two neighbor
@@ -3404,6 +3441,7 @@
time.sleep(self._SETTLING_TIME)
return self._verify_cell_info(self.ad, expected_cell_info_stats)
+ @test_tracker_info(uuid="209f62c1-7950-447c-9101-abe930da20ba")
@TelephonyBaseTest.tel_test_wrap
def test_neighbor_cell_reporting_gsm_interrat_2_tmo(self):
""" Test Number of neighbor cells reported by Phone when no neighbor
diff --git a/acts/tests/google/tel/lab/TelLabPowerDataTest.py b/acts/tests/google/tel/lab/TelLabPowerDataTest.py
new file mode 100644
index 0000000..9ebd85a
--- /dev/null
+++ b/acts/tests/google/tel/lab/TelLabPowerDataTest.py
@@ -0,0 +1,244 @@
+#/usr/bin/env python3.4
+#
+# Copyright 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.
+"""
+Sanity tests for voice tests in telephony
+"""
+import time, os
+
+from acts.test_utils.tel.anritsu_utils import make_ims_call
+from acts.test_utils.tel.anritsu_utils import tear_down_call
+from acts.test_utils.tel.tel_test_utils import iperf_test_by_adb
+from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts.test_utils.tel.TelephonyLabPowerTest import TelephonyLabPowerTest
+from acts.utils import adb_shell_ping
+from acts.controllers import iperf_server
+from acts.utils import exe_cmd
+import json
+
+DEFAULT_PING_DURATION = 10
+IPERF_DURATION = 30
+IPERF_LOG_FILE_PATH = "/sdcard/iperf.txt"
+
+DEFAULT_CALL_NUMBER = "+11234567891"
+WAIT_TIME_VOLTE = 5
+
+
+class TelLabPowerDataTest(TelephonyLabPowerTest):
+ # TODO Keep if we want to add more in here for this class.
+ def __init__(self, controllers):
+ TelephonyLabPowerTest.__init__(self, controllers)
+ self.ip_server = self.iperf_servers[0]
+ self.port_num = self.ip_server.port
+ self.log.info("Iperf Port is %s", self.port_num)
+ self.log.info("End of __init__ class of TelLabPowerDataTest")
+
+ # May not need
+ def teardown_class(self):
+ # Always take down the simulation
+ TelephonyLabPowerTest.teardown_class(self)
+
+ def iperf_setup(self):
+ # Fetch IP address of the host machine
+ cmd = "|".join(("ifconfig", "grep eth0 -A1", "grep inet",
+ "cut -d ':' -f2", "cut -d ' ' -f 1"))
+ destination_ip = exe_cmd(cmd)
+ destination_ip = (destination_ip.decode("utf-8")).split("\n")[0]
+ self.log.info("Dest IP is %s", destination_ip)
+ time.sleep(1)
+ if not adb_shell_ping(
+ self.ad, DEFAULT_PING_DURATION, destination_ip,
+ loss_tolerance=95):
+ self.log.error("Pings failed to Destination.")
+ return False
+
+ return destination_ip
+
+ def _iperf_task(self, destination_ip, duration):
+ self.log.info("Starting iPerf task")
+ self.ip_server.start()
+ tput_dict = {"Uplink": 0, "Downlink": 0}
+ if iperf_test_by_adb(
+ self.log,
+ self.ad,
+ destination_ip,
+ self.port_num,
+ True, # reverse
+ duration,
+ rate_dict=tput_dict,
+ blocking=False,
+ log_file_path=IPERF_LOG_FILE_PATH):
+ return True
+ else:
+ self.log.error("iperf failed to Destination.")
+ self.ip_server.stop()
+ return False
+
+ def power_iperf_test(self, olvl, rflvl, sch_mode="DYNAMIC", volte=False):
+ if volte:
+ # make a VoLTE MO call
+ self.log.info("DEFAULT_CALL_NUMBER = " + DEFAULT_CALL_NUMBER)
+ if not make_ims_call(self.log, self.ad, self.anritsu,
+ DEFAULT_CALL_NUMBER):
+ self.log.error("Phone {} Failed to make volte call to {}"
+ .format(self.ad.serial, DEFAULT_CALL_NUMBER))
+ return False
+ self.log.info("wait for %d seconds" % WAIT_TIME_VOLTE)
+ time.sleep(WAIT_TIME_VOLTE)
+
+ server_ip = self.iperf_setup()
+ if not server_ip:
+ self.log.error("iperf server can not be reached by ping")
+ return False
+
+ self._iperf_task(server_ip, IPERF_DURATION)
+ self.log.info("Wait for 10 secconds before power measurement")
+ time.sleep(10)
+ self.power_test(olvl, rflvl, sch_mode)
+
+ result = self.ad.adb.shell("cat {}".format(IPERF_LOG_FILE_PATH))
+ if result is not None:
+ data_json = json.loads(''.join(result))
+ rx_rate = data_json['end']['sum_received']['bits_per_second']
+ xfer_time = data_json['end']['sum_received']['seconds']
+ self.ad.log.info('iPerf3 transfer time was %ssecs', xfer_time)
+ self.ad.log.info('iPerf3 download speed is %sbps', rx_rate)
+
+ if volte:
+ # check if the phone is still in call, then tear it down
+ if not self.ad.droid.telecomIsInCall():
+ self.log.error("Call is already ended in the phone.")
+ return False
+ if not tear_down_call(self.log, self.ad, self.anritsu):
+ self.log.error("Phone {} Failed to tear down VoLTE call"
+ .format(self.ad.serial))
+ return False
+
+ return True
+
+ """ Tests Begin """
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_data_power_n30_n30(self):
+ """ Test power consumption for iPerf data @ DL/UL -30/-30dBm
+ Steps:
+ 1. Assume UE already in Communication mode.
+ 2. Initiate iPerf data transfer.
+ 3. Set DL/UL power and Dynamic scheduling.
+ 4. Measure power consumption.
+
+ Expected Results:
+ 1. power consumption measurement is successful
+ 2. measurement results is saved accordingly
+
+ Returns:
+ True if pass; False if fail
+ """
+ return self.power_iperf_test(-30, -30)
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_data_power_n50_n10(self):
+ """ Test power consumption for iPerf data @ DL/UL -50/-10dBm
+ Steps:
+ 1. Assume UE already in Communication mode.
+ 2. Initiate iPerf data transfer.
+ 3. Set DL/UL power and Dynamic scheduling.
+ 4. Measure power consumption.
+
+ Expected Results:
+ 1. power consumption measurement is successful
+ 2. measurement results is saved accordingly
+
+ Returns:
+ True if pass; False if fail
+ """
+ return self.power_iperf_test(-50, -10)
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_data_power_n70_10(self):
+ """ Test power consumption for iPerf data @ DL/UL -70/+10dBm
+ Steps:
+ 1. Assume UE already in Communication mode.
+ 2. Initiate iPerf data transfer.
+ 3. Set DL/UL power and Dynamic scheduling.
+ 4. Measure power consumption.
+
+ Expected Results:
+ 1. power consumption measurement is successful
+ 2. measurement results is saved accordingly
+
+ Returns:
+ True if pass; False if fail
+ """
+ return self.power_iperf_test(-70, 10)
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_data_volte_power_n30_n30(self):
+ """ Test power consumption for iPerf data and volte @ DL/UL -30/-30dBm
+ Steps:
+ 1. Assume UE already in Communication mode.
+ 2. Make MO VoLTE call.
+ 3. Initiate iPerf data transfer.
+ 4. Set DL/UL power and Dynamic scheduling.
+ 5. Measure power consumption.
+
+ Expected Results:
+ 1. power consumption measurement is successful
+ 2. measurement results is saved accordingly
+
+ Returns:
+ True if pass; False if fail
+ """
+ return self.power_iperf_test(-30, -30, volte=True)
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_data_volte_power_n50_n10(self):
+ """ Test power consumption for iPerf data and volte @ DL/UL -50/-10dBm
+ Steps:
+ 1. Assume UE already in Communication mode.
+ 2. Make MO VoLTE call.
+ 3. Initiate iPerf data transfer.
+ 4. Set DL/UL power and Dynamic scheduling.
+ 5. Measure power consumption.
+
+ Expected Results:
+ 1. power consumption measurement is successful
+ 2. measurement results is saved accordingly
+
+ Returns:
+ True if pass; False if fail
+ """
+ return self.power_iperf_test(-50, -10, volte=True)
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_data_volte_power_n70_10(self):
+ """ Test power consumption for iPerf data and volte @ DL/UL -70/+10dBm
+ Steps:
+ 1. Assume UE already in Communication mode.
+ 2. Make MO VoLTE call.
+ 3. Initiate iPerf data transfer.
+ 4. Set DL/UL power and Dynamic scheduling.
+ 5. Measure power consumption.
+
+ Expected Results:
+ 1. power consumption measurement is successful
+ 2. measurement results is saved accordingly
+
+ Returns:
+ True if pass; False if fail
+ """
+ return self.power_iperf_test(-70, 10, volte=True)
+
+ """ Tests End """
diff --git a/acts/tests/google/tel/lab/TelLabPowerVoLTETest.py b/acts/tests/google/tel/lab/TelLabPowerVoLTETest.py
new file mode 100644
index 0000000..2b88059
--- /dev/null
+++ b/acts/tests/google/tel/lab/TelLabPowerVoLTETest.py
@@ -0,0 +1,121 @@
+#/usr/bin/env python3.4
+#
+# Copyright 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.
+"""
+Sanity tests for voice tests in telephony
+"""
+import time
+
+from acts.test_utils.tel.anritsu_utils import make_ims_call
+from acts.test_utils.tel.anritsu_utils import tear_down_call
+from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts.test_utils.tel.TelephonyLabPowerTest import TelephonyLabPowerTest
+
+DEFAULT_CALL_NUMBER = "+11234567891"
+WAIT_TIME_VOLTE = 5
+
+
+class TelLabPowerVoLTETest(TelephonyLabPowerTest):
+
+ # TODO Keep if we want to add more in here for this class.
+ def __init__(self, controllers):
+ TelephonyLabPowerTest.__init__(self, controllers)
+
+ def setup_class(self):
+ self.log.info("entering setup_class TelLabPowerVoLTETest")
+ TelephonyLabPowerTest.setup_class(self)
+ self.log.info("Making MO VoLTE call")
+ # make a VoLTE MO call
+ self.log.info("DEFAULT_CALL_NUMBER = " + DEFAULT_CALL_NUMBER)
+ if not make_ims_call(self.log, self.ad, self.anritsu,
+ DEFAULT_CALL_NUMBER):
+ self.log.error("Phone {} Failed to make volte call to {}"
+ .format(self.ad.serial, DEFAULT_CALL_NUMBER))
+ return False
+ self.log.info("wait for %d seconds" % WAIT_TIME_VOLTE)
+ time.sleep(WAIT_TIME_VOLTE)
+ return True
+
+ def teardown_test(self):
+ # check if the phone stay in call
+ if not self.ad.droid.telecomIsInCall():
+ self.log.error("Call is already ended in the phone.")
+ return False
+ self.log.info("End of teardown_test()")
+ return True
+
+ def teardown_class(self):
+ if not tear_down_call(self.log, self.ad, self.anritsu):
+ self.log.error("Phone {} Failed to tear down"
+ .format(self.ad.serial))
+ return False
+ # Always take down the simulation
+ TelephonyLabPowerTest.teardown_class(self)
+ return True
+
+ """ Tests Begin """
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_volte_power_n40_n20(self):
+ """ Measure power consumption of a VoLTE call with DL/UL -40/-20dBm
+ Steps:
+ 1. Assume a VoLTE call is already in place by Setup_Class.
+ 2. Set DL/UL power and Dynamic scheduling
+ 3. Measure power consumption.
+
+ Expected Results:
+ 1. power consumption measurement is successful
+ 2. measurement results is saved accordingly
+
+ Returns:
+ True if pass; False if fail
+ """
+ return self.power_test(-40, -20)
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_volte_power_n60_0(self):
+ """ Measure power consumption of a VoLTE call with DL/UL -60/0dBm
+ Steps:
+ 1. Assume a VoLTE call is already in place by Setup_Class.
+ 2. Set DL/UL power and Dynamic scheduling
+ 3. Measure power consumption.
+
+ Expected Results:
+ 1. power consumption measurement is successful
+ 2. measurement results is saved accordingly
+
+ Returns:
+ True if pass; False if fail
+ """
+ return self.power_test(-60, 0)
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_volte_power_n80_20(self):
+ """ Measure power consumption of a VoLTE call with DL/UL -80/+20dBm
+ Steps:
+ 1. Assume a VoLTE call is already in place by Setup_Class.
+ 2. Set DL/UL power and Dynamic scheduling
+ 3. Measure power consumption.
+
+ Expected Results:
+ 1. power consumption measurement is successful
+ 2. measurement results is saved accordingly
+
+ Returns:
+ True if pass; False if fail
+ """
+ return self.power_test(-80, 20)
+
+ """ Tests End """
diff --git a/acts/tests/google/tel/lab/TelLabVoiceTest.py b/acts/tests/google/tel/lab/TelLabVoiceTest.py
index 92af3c5..24b91f9 100644
--- a/acts/tests/google/tel/lab/TelLabVoiceTest.py
+++ b/acts/tests/google/tel/lab/TelLabVoiceTest.py
@@ -18,6 +18,7 @@
"""
import time
+from acts.test_decorators import test_tracker_info
from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError
from acts.controllers.anritsu_lib.md8475a import CsfbType
from acts.controllers.anritsu_lib.md8475a import MD8475A
@@ -36,6 +37,7 @@
from acts.test_utils.tel.anritsu_utils import set_system_model_lte_gsm
from acts.test_utils.tel.anritsu_utils import set_system_model_wcdma
from acts.test_utils.tel.anritsu_utils import set_usim_parameters
+from acts.test_utils.tel.anritsu_utils import set_post_sim_params
from acts.test_utils.tel.tel_defines import CALL_TEARDOWN_PHONE
from acts.test_utils.tel.tel_defines import RAT_FAMILY_CDMA2000
from acts.test_utils.tel.tel_defines import RAT_FAMILY_GSM
@@ -54,6 +56,8 @@
from acts.test_utils.tel.tel_test_utils import ensure_phones_idle
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
from acts.test_utils.tel.tel_test_utils import toggle_volte
+from acts.test_utils.tel.tel_test_utils import set_preferred_apn_by_adb
+from acts.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts.test_utils.tel.tel_voice_utils import phone_idle_volte
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
@@ -64,8 +68,8 @@
def __init__(self, controllers):
TelephonyBaseTest.__init__(self, controllers)
try:
- self.stress_test_number = int(self.user_params[
- "stress_test_number"])
+ self.stress_test_number = int(
+ self.user_params["stress_test_number"])
self.log.info("Executing {} calls per test in stress test mode".
format(self.stress_test_number))
except KeyError:
@@ -86,6 +90,9 @@
self.log.info("Using provided voice call number: {}".format(
self.voice_call_number))
+ if self.ad.sim_card == "VzW12349":
+ set_preferred_apn_by_adb(self.ad, "VZWINTERNET")
+
def setup_class(self):
try:
self.anritsu = MD8475A(self.md8475a_ip_address, self.log,
@@ -97,12 +104,14 @@
def setup_test(self):
try:
+ if getattr(self, "qxdm_log", True):
+ start_qxdm_loggers(self.log, self.android_devices)
self.ad.droid.telephonyFactoryReset()
+ if self.ad.sim_card == "VzW12349":
+ self.ad.droid.imsSetVolteProvisioning(True)
except Exception as e:
self.ad.log.error(e)
toggle_airplane_mode_by_adb(self.log, self.ad, True)
- self.ad.adb.shell("setprop net.lte.ims.volte.provisioned 1",
- ignore_status=True)
# get a handle to virtual phone
self.virtualPhoneHandle = self.anritsu.get_VirtualPhone()
return True
@@ -133,6 +142,9 @@
set_simulation_func(self.anritsu, self.user_params,
self.ad.sim_card)
set_usim_parameters(self.anritsu, self.ad.sim_card)
+ if is_ims_call or srvcc or csfb_type:
+ set_post_sim_params(self.anritsu, self.user_params,
+ self.ad.sim_card)
self.virtualPhoneHandle.auto_answer = (VirtualPhoneAutoAnswer.ON,
2)
if srvcc != None:
@@ -140,12 +152,16 @@
self.anritsu.send_command("IMSCSCFAUTOANSWER 1,DISABLE")
self.anritsu.start_simulation()
self.anritsu.send_command("IMSSTARTVN 1")
+ self.anritsu.send_command("IMSSTARTVN 2")
+ self.anritsu.send_command("IMSSTARTVN 3")
check_ims_reg = True
check_ims_calling = True
else:
self.anritsu.start_simulation()
- if is_ims_call:
+ if is_ims_call or csfb_type:
self.anritsu.send_command("IMSSTARTVN 1")
+ self.anritsu.send_command("IMSSTARTVN 2")
+ self.anritsu.send_command("IMSSTARTVN 3")
iterations = 1
if self.stress_test_number > 0:
@@ -153,8 +169,8 @@
successes = 0
for i in range(1, iterations + 1):
if self.stress_test_number:
- self.log.info("Running iteration {} of {}".format(
- i, iterations))
+ self.log.info(
+ "Running iteration {} of {}".format(i, iterations))
# FIXME: There's no good reason why this must be true;
# I can only assume this was done to work around a problem
self.ad.droid.telephonyToggleDataConnection(False)
@@ -163,13 +179,21 @@
sim_model = (self.anritsu.get_simulation_model()).split(",")
no_of_bts = len(sim_model)
for i in range(2, no_of_bts + 1):
- self.anritsu.send_command("OUTOFSERVICE OUT,BTS{}".format(
- i))
+ self.anritsu.send_command(
+ "OUTOFSERVICE OUT,BTS{}".format(i))
if phone_setup_func is not None:
if not phone_setup_func(self.ad):
- self.log.error("phone_setup_func failed.")
- continue
+ self.log.warning(
+ "phone_setup_func failed. Rebooting UE")
+ self.ad.reboot()
+ time.sleep(30)
+ if self.ad.sim_card == "VzW12349":
+ set_preferred_apn_by_adb(self.ad, "VZWINTERNET")
+ if not phone_setup_func(self.ad):
+ self.log.error("phone_setup_func failed.")
+ continue
+
if is_wait_for_registration:
self.anritsu.wait_for_registration_state()
@@ -179,8 +203,8 @@
continue
for i in range(2, no_of_bts + 1):
- self.anritsu.send_command("OUTOFSERVICE IN,BTS{}".format(
- i))
+ self.anritsu.send_command(
+ "OUTOFSERVICE IN,BTS{}".format(i))
time.sleep(WAIT_TIME_ANRITSU_REG_AND_CALL)
if srvcc:
@@ -225,6 +249,7 @@
return True
def _phone_setup_lte_wcdma(self, ad):
+ toggle_volte(self.log, ad, False)
return ensure_network_rat(
self.log,
ad,
@@ -283,6 +308,7 @@
""" Tests Begin """
+ @test_tracker_info(uuid="56c42e16-3936-4c51-8b8b-4866f54cc0bc")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_lte_wcdma_csfb_redirection(self):
""" Test Voice call functionality on LTE (CSFB to WCDMA).
@@ -308,6 +334,7 @@
voice_number=self.voice_call_number,
csfb_type=CsfbType.CSFB_TYPE_REDIRECTION)
+ @test_tracker_info(uuid="dcc1428f-9b7d-4064-8313-f1f5e428e0c7")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_lte_wcdma_csfb_handover(self):
""" Test Voice call functionality on LTE (CSFB to WCDMA).
@@ -333,6 +360,7 @@
voice_number=self.voice_call_number,
csfb_type=CsfbType.CSFB_TYPE_HANDOVER)
+ @test_tracker_info(uuid="e250b134-d5e9-48ca-b224-eb0e07648275")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_lte_1x_csfb(self):
""" Test Voice call functionality on LTE (CSFB to 1x).
@@ -356,6 +384,7 @@
self._phone_setup_lte_1x,
voice_number=self.voice_call_number)
+ @test_tracker_info(uuid="fcbe0f5d-51c2-46c8-8ff3-2daa1d91b936")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_wcdma(self):
""" Test Voice call functionality on WCDMA
@@ -379,6 +408,7 @@
self._phone_setup_wcdma,
voice_number=self.voice_call_number)
+ @test_tracker_info(uuid="077f851b-2c8e-4b1d-adc2-0326d3346157")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_gsm(self):
""" Test Voice call functionality on GSM
@@ -402,6 +432,7 @@
self._phone_setup_gsm,
voice_number=self.voice_call_number)
+ @test_tracker_info(uuid="80376fb3-44fc-43b7-be99-2ccd3bd2913e")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_1x(self):
""" Test Voice call functionality on CDMA 1X
@@ -425,6 +456,7 @@
self._phone_setup_1x,
voice_number=self.voice_call_number)
+ @test_tracker_info(uuid="1f8ae218-042d-4114-9fc7-4401a503b3b4")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_1x_evdo(self):
""" Test Voice call functionality on CDMA 1X with EVDO
@@ -448,6 +480,7 @@
self._phone_setup_1x,
voice_number=self.voice_call_number)
+ @test_tracker_info(uuid="7641ffc0-c1b3-42b8-92d6-00ae53719f8d")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_volte_wcdma_srvcc(self):
""" Test Voice call functionality,
@@ -475,6 +508,7 @@
voice_number=self.voice_call_number,
wait_time_in_call=WAIT_TIME_IN_CALL_FOR_IMS)
+ @test_tracker_info(uuid="0d63e797-b4bc-4094-98c3-70060e5ea91b")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_volte_gsm_srvcc(self):
""" Test Voice call functionality,
@@ -502,6 +536,7 @@
voice_number=self.voice_call_number,
wait_time_in_call=WAIT_TIME_IN_CALL_FOR_IMS)
+ @test_tracker_info(uuid="f73f6cc0-79c8-47b3-9867-ea7390dfee41")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_volte_wcdma_asrvcc(self):
""" Test Voice call functionality,
@@ -528,6 +563,7 @@
srvcc="Alert",
voice_number=self.voice_call_number)
+ @test_tracker_info(uuid="823e8e10-58bd-476d-ba4b-ec436ac424fb")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_volte_gsm_asrvcc(self):
""" Test Voice call functionality,
@@ -555,6 +591,7 @@
voice_number=self.voice_call_number,
wait_time_in_call=WAIT_TIME_IN_CALL_FOR_IMS)
+ @test_tracker_info(uuid="cd066cb1-6d12-4e29-90b9-f44054f00a00")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_volte_wcdma_asrvcc_mt(self):
""" Test Voice call functionality,
@@ -582,6 +619,7 @@
mo=False,
voice_number=self.voice_call_number)
+ @test_tracker_info(uuid="b23ebec3-7e5c-4aca-a749-e34307c56d58")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_volte_gsm_asrvcc_mt(self):
""" Test Voice call functionality,
@@ -610,6 +648,7 @@
voice_number=self.voice_call_number,
wait_time_in_call=WAIT_TIME_IN_CALL_FOR_IMS)
+ @test_tracker_info(uuid="b81b3a0e-a7e3-4b30-889f-7c015bdc6980")
@TelephonyBaseTest.tel_test_wrap
def test_voice_call_volte(self):
""" Test Voice call functionality on VoLTE
diff --git a/acts/tests/google/tel/live/TelLiveDataTest.py b/acts/tests/google/tel/live/TelLiveDataTest.py
index b199dd9..c0034c0 100644
--- a/acts/tests/google/tel/live/TelLiveDataTest.py
+++ b/acts/tests/google/tel/live/TelLiveDataTest.py
@@ -26,6 +26,9 @@
from queue import Empty
from acts.test_utils.tel.tel_subscription_utils import \
get_subid_from_slot_index
+from acts.test_utils.bt.bt_test_utils import bluetooth_enabled_check
+from acts.test_utils.bt.bt_test_utils import disable_bluetooth
+from acts.test_utils.bt.bt_test_utils import pair_pri_to_sec
from acts.test_utils.tel.tel_subscription_utils import set_subid_for_data
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
@@ -60,6 +63,8 @@
from acts.test_utils.tel.tel_data_utils import wifi_tethering_cleanup
from acts.test_utils.tel.tel_data_utils import wifi_tethering_setup_teardown
from acts.test_utils.tel.tel_test_utils import active_file_download_test
+from acts.test_utils.tel.tel_test_utils import start_adb_tcpdump
+from acts.test_utils.tel.tel_test_utils import stop_adb_tcpdump
from acts.test_utils.tel.tel_test_utils import call_setup_teardown
from acts.test_utils.tel.tel_test_utils import check_is_wifi_connected
from acts.test_utils.tel.tel_test_utils import ensure_phones_default_state
@@ -68,15 +73,19 @@
from acts.test_utils.tel.tel_test_utils import \
ensure_network_generation_for_subscription
from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected
+from acts.test_utils.tel.tel_test_utils import get_mobile_data_usage
from acts.test_utils.tel.tel_test_utils import get_slot_index_from_subid
from acts.test_utils.tel.tel_test_utils import get_network_rat_for_subscription
from acts.test_utils.tel.tel_test_utils import hangup_call
from acts.test_utils.tel.tel_test_utils import multithread_func
+from acts.test_utils.tel.tel_test_utils import remove_mobile_data_usage_limit
from acts.test_utils.tel.tel_test_utils import set_call_state_listen_level
+from acts.test_utils.tel.tel_test_utils import set_mobile_data_usage_limit
from acts.test_utils.tel.tel_test_utils import setup_sim
from acts.test_utils.tel.tel_test_utils import stop_wifi_tethering
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts.test_utils.tel.tel_test_utils import toggle_volte
+from acts.test_utils.tel.tel_test_utils import verify_http_connection
from acts.test_utils.tel.tel_test_utils import verify_internet_connection
from acts.test_utils.tel.tel_test_utils import verify_incall_state
from acts.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
@@ -87,6 +96,7 @@
wait_for_data_attach_for_subscription
from acts.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
from acts.test_utils.tel.tel_test_utils import wifi_reset
+from acts.test_utils.tel.tel_test_utils import wait_for_state
from acts.test_utils.tel.tel_test_utils import wifi_toggle_state
from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
@@ -101,6 +111,7 @@
from acts.utils import disable_doze
from acts.utils import enable_doze
from acts.utils import rand_ascii_str
+from acts.utils import adb_shell_ping
class TelLiveDataTest(TelephonyBaseTest):
@@ -109,11 +120,35 @@
self.stress_test_number = self.get_stress_test_number()
self.wifi_network_ssid = self.user_params.get(
- "wifi_network_ssid") or self.user_params.get("wifi_network_ssid_2g")
+ "wifi_network_ssid") or self.user_params.get(
+ "wifi_network_ssid_2g")
self.wifi_network_pass = self.user_params.get(
- "wifi_network_pass") or self.user_params.get("wifi_network_pass_2g")
- self.provider = self.android_devices[-1]
- self.clients = self.android_devices[:-1]
+ "wifi_network_pass") or self.user_params.get(
+ "wifi_network_pass_2g")
+ self.provider = self.android_devices[0]
+ self.clients = self.android_devices[1:]
+
+ def setup_test(self):
+ TelephonyBaseTest.setup_test(self)
+ self.number_of_devices = 1
+ try:
+ self.tcpdump_proc = [None, None]
+ self.tcpdump_proc[0] = start_adb_tcpdump(
+ self.android_devices[0], self.test_name, mask="all")
+ except Exception as e:
+ self.log.warning("Failed to start tcpdump collection", e)
+ pass
+
+ def on_fail(self, test_name, begin_time):
+ self.log.info("Inside Teardown Test")
+ TelephonyBaseTest.on_fail(self, test_name, begin_time)
+ try:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(self.android_devices[0], self.tcpdump_proc[0],
+ True, self.test_name)
+ except Exception as e:
+ self.log.warning("Failed to stop tcpdump collection", e)
+ pass
@test_tracker_info(uuid="1b0354f3-8668-4a28-90a5-3b3d2b2756d3")
@TelephonyBaseTest.tel_test_wrap
@@ -276,10 +311,10 @@
True stress pass rate is higher than MINIMUM_SUCCESS_RATE.
False otherwise.
"""
- ads = self.android_devices
MINIMUM_SUCCESS_RATE = .95
success_count = 0
fail_count = 0
+ self.number_of_devices = 2
for i in range(1, self.stress_test_number + 1):
@@ -370,6 +405,7 @@
class _LocalException(Exception):
pass
+ self.number_of_devices = 2
ad_list = [self.android_devices[0], self.android_devices[1]]
ensure_phones_idle(self.log, ad_list)
@@ -392,12 +428,17 @@
wifi_toggle_state(self.log, self.android_devices[0], False)
self.android_devices[0].droid.telephonyToggleDataConnection(True)
if (not wait_for_cell_data_connection(self.log,
- self.android_devices[0], True) or
- not verify_internet_connection(self.log,
- self.android_devices[0])):
+ self.android_devices[0], True)
+ or not verify_internet_connection(self.log,
+ self.android_devices[0])):
self.log.error("Data not available on cell")
return False
+ self.log.info(
+ "b/69431819, sending data to increase NW threshold limit")
+ adb_shell_ping(
+ self.android_devices[0], count=30, timeout=60, loss_tolerance=100)
+
try:
self.log.info("Step2 Initiate call and accept.")
if call_direction == DIRECTION_MOBILE_ORIGINATED:
@@ -414,8 +455,8 @@
if simultaneous_voice_data:
self.log.info("Step3 Verify internet.")
time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- if not verify_internet_connection(self.log,
- self.android_devices[0]):
+ if not verify_internet_connection(
+ self.log, self.android_devices[0], retries=3):
raise _LocalException("Internet Inaccessible when Enabled")
self.log.info("Step4 Turn off data and verify not connected.")
@@ -435,8 +476,8 @@
if not wait_for_cell_data_connection(
self.log, self.android_devices[0], True):
raise _LocalException("Failed to Re-Enable Cellular Data")
- if not verify_internet_connection(self.log,
- self.android_devices[0]):
+ if not verify_internet_connection(
+ self.log, self.android_devices[0], retries=3):
raise _LocalException("Internet Inaccessible when Enabled")
else:
self.log.info("Step3 Verify no Internet and skip step 4-5.")
@@ -445,15 +486,15 @@
raise _LocalException("Internet Accessible.")
self.log.info("Step6 Verify phones still in call and Hang up.")
- if not verify_incall_state(self.log, [
- self.android_devices[0], self.android_devices[1]
- ], True):
+ if not verify_incall_state(
+ self.log,
+ [self.android_devices[0], self.android_devices[1]], True):
return False
if not hangup_call(self.log, self.android_devices[0]):
self.log.error("Failed to hang up call")
return False
- if not verify_internet_connection(self.log,
- self.android_devices[0]):
+ if not verify_internet_connection(
+ self.log, self.android_devices[0], retries=3):
raise _LocalException("Internet Inaccessible when Enabled")
except _LocalException as e:
@@ -603,7 +644,6 @@
True stress pass rate is higher than MINIMUM_SUCCESS_RATE.
False otherwise.
"""
- ads = self.android_devices
MINIMUM_SUCCESS_RATE = .95
success_count = 0
fail_count = 0
@@ -611,7 +651,7 @@
for i in range(1, self.stress_test_number + 1):
ensure_phones_default_state(
- self.log, [self.android_devices[0], self.android_devices[1]])
+ self.log, [self.android_devices[0]])
wifi_reset(self.log, self.android_devices[0])
wifi_toggle_state(self.log, self.android_devices[0], False)
@@ -646,15 +686,15 @@
True stress pass rate is higher than MINIMUM_SUCCESS_RATE.
False otherwise.
"""
- ads = self.android_devices
MINIMUM_SUCCESS_RATE = .95
success_count = 0
fail_count = 0
+ self.number_of_devices = 1
for i in range(1, self.stress_test_number + 1):
ensure_phones_default_state(
- self.log, [self.android_devices[0], self.android_devices[1]])
+ self.log, [self.android_devices[0]])
wifi_reset(self.log, self.android_devices[0])
wifi_toggle_state(self.log, self.android_devices[0], False)
@@ -689,38 +729,511 @@
True if success.
False if failed.
"""
+ self.number_of_devices = None
ensure_phones_idle(self.log, self.android_devices)
+ wifi_toggle_state(self.log, self.provider, False)
if network_generation:
if not ensure_network_generation(
self.log, self.provider, network_generation,
MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
- self.provider.log.error("Device failed to connect to %s.",
+ self.provider.log.error("Provider failed to connect to %s.",
network_generation)
return False
- self.log.info("Airplane Off, Wifi Off, Data On.")
+ self.provider.log.info(
+ "Set provider Airplane Off, Wifi Off, Bluetooth Off, Data On.")
toggle_airplane_mode(self.log, self.provider, False)
- wifi_toggle_state(self.log, self.provider, False)
self.provider.droid.telephonyToggleDataConnection(True)
- for ad in self.clients:
- ad.droid.telephonyToggleDataConnection(False)
+ self.provider.log.info("Provider disable wifi")
+ wifi_toggle_state(self.log, self.provider, False)
+ # Turn off active SoftAP if any.
+ if self.provider.droid.wifiIsApEnabled():
+ self.provider.log.info("Disable provider wifi tethering")
+ stop_wifi_tethering(self.log, self.provider)
+ self.provider.log.info("Provider disable bluetooth")
+ disable_bluetooth(self.provider.droid)
+ for ad in self.clients:
+ ad.log.info(
+ "Set client Airplane Off, Wifi Off, Bluetooth Off, Data Off.")
+ toggle_airplane_mode(self.log, ad, False)
+ ad.log.info("Client disable data")
+ ad.droid.telephonyToggleDataConnection(False)
+ ad.log.info("Client disable bluetooth")
+ disable_bluetooth(ad.droid)
+ ad.log.info("Client disable wifi")
+ wifi_toggle_state(self.log, ad, False)
if not wait_for_cell_data_connection(self.log, self.provider, True):
self.provider.log.error(
"Provider failed to enable data connection.")
return False
self.log.info("Verify internet")
- if not verify_internet_connection(self.log, self.provider):
- self.provider.log.error("Data not available on cell.")
+ if not self._test_internet_connection(
+ client_status=False, provider_status=True):
+ self.log.error("Internet connection check failed before tethering")
return False
- # Turn off active SoftAP if any.
- if self.provider.droid.wifiIsApEnabled():
- stop_wifi_tethering(self.log, self.provider)
-
return True
+ def _enable_bluetooth_tethering_connection(self, provider, clients):
+ for ad in [self.provider] + self.clients:
+ if not bluetooth_enabled_check(ad):
+ ad.log.info("Bluetooth is not enabled")
+ return False
+ else:
+ ad.log.info("Bluetooth is enabled")
+
+ for client in self.clients:
+ if not (pair_pri_to_sec(self.provider, client)):
+ client.log.error("Client failed to pair with provider")
+ return False
+ else:
+ client.log.info("Client paired with provider")
+ self.provider.log.info("Provider enabling bluetooth tethering")
+ try:
+ provider.droid.bluetoothPanSetBluetoothTethering(True)
+ except Exception as e:
+ provider.log.error(
+ "Faile to enable provider Bluetooth tethering with %s", e)
+ return False
+
+ if wait_for_state(provider.droid.bluetoothPanIsTetheringOn, True):
+ provider.log.info("Provider Bluetooth tethering is enabled.")
+ else:
+ provider.log.error(
+ "Failed to enable provider Bluetooth tethering.")
+ provider.log.error("bluetoothPanIsTetheringOn = %s",
+ provider.droid.bluetoothPanIsTetheringOn())
+ return False
+ time.sleep(5)
+ for client in clients:
+ client.droid.bluetoothConnectBonded(
+ provider.droid.bluetoothGetLocalAddress())
+ time.sleep(20)
+ return True
+
+ def _test_internet_connection(self,
+ client_status=True,
+ provider_status=True):
+ client_retry = 10 if client_status else 1
+ for client in self.clients:
+ if not verify_http_connection(
+ self.log,
+ client,
+ retry=client_retry,
+ expected_state=client_status):
+ client.log.error("client internet connection state is not %s",
+ client_status)
+ return False
+ else:
+ client.log.info("client internet connection state is %s",
+ client_status)
+ if not verify_http_connection(
+ self.log, self.provider, retry=3,
+ expected_state=provider_status):
+ self.provider.log.error(
+ "provider internet connection is not %s" % provider_status)
+ return False
+ else:
+ self.provider.log.info(
+ "provider internet connection is %s" % provider_status)
+ return True
+
+ def _verify_bluetooth_tethering_connection(self,
+ change_rat=None,
+ toggle_data=False,
+ toggle_tethering=False,
+ voice_call=False,
+ toggle_bluetooth=True):
+ """Setups up a bluetooth tethering conenction between two android devices.
+
+ Returns:
+ True if PAN connection and verification is successful,
+ false if unsuccessful.
+ """
+ if not self._enable_bluetooth_tethering_connection(
+ self.provider, self.clients):
+ return False
+ if not self._test_internet_connection():
+ self.log.error("Internet connection check failed")
+ return False
+ if voice_call:
+ self.log.info("====== Voice call test =====")
+ for caller, callee in [(self.provider, self.clients[0]),
+ (self.clients[0], self.provider)]:
+ if not call_setup_teardown(
+ self.log, caller, callee, ad_hangup=None):
+ self.log.error("Setup Call Failed.")
+ hangup_call(self.log, caller)
+ return False
+ self.log.info("Verify data.")
+ if not verify_http_connection(
+ self.log, self.clients[0], retry=0):
+ self.clients[0].log.warning(
+ "client internet connection state is not on")
+ else:
+ self.clients[0].log.info(
+ "client internet connection state is on")
+ hangup_call(self.log, caller)
+ if not verify_http_connection(
+ self.log, self.clients[0], retry=0):
+ self.clients[0].log.warning(
+ "client internet connection state is not on")
+ return False
+ else:
+ self.clients[0].log.info(
+ "client internet connection state is on")
+ if toggle_tethering:
+ self.log.info("====== Toggling provider bluetooth tethering =====")
+ self.provider.log.info("Disable bluetooth tethering")
+ self.provider.droid.bluetoothPanSetBluetoothTethering(False)
+ if not self._test_internet_connection(False, True):
+ self.log.error(
+ "Internet connection check failed after disable tethering")
+ return False
+ self.provider.log.info("Enable bluetooth tethering")
+ if not self._enable_bluetooth_tethering_connection(
+ self.provider, self.clients):
+ self.provider.log.error(
+ "Fail to re-enable bluetooth tethering")
+ return False
+ if not self._test_internet_connection(True, True):
+ self.log.error(
+ "Internet connection check failed after enable tethering")
+ return False
+ if toggle_bluetooth:
+ self.log.info("====== Toggling provider bluetooth =====")
+ self.provider.log.info("Disable provider bluetooth")
+ disable_bluetooth(self.provider.droid)
+ if not self._test_internet_connection(False, True):
+ self.log.error(
+ "Internet connection check failed after disable bluetooth")
+ return False
+ if not self._enable_bluetooth_tethering_connection(
+ self.provider, self.clients):
+ self.provider.log.error(
+ "Fail to re-enable bluetooth tethering")
+ return False
+ if not self._test_internet_connection(True, True):
+ self.log.error(
+ "Internet connection check failed after enable bluetooth")
+ return False
+ if toggle_data:
+ self.log.info("===== Toggling provider data connection =====")
+ self.provider.log.info("Disable provider data connection")
+ self.provider.droid.telephonyToggleDataConnection(False)
+
+ if not self._test_internet_connection(False, False):
+ return False
+ self.provider.log.info("Enable provider data connection")
+ self.provider.droid.telephonyToggleDataConnection(True)
+ if not wait_for_cell_data_connection(self.log, self.provider,
+ True):
+ self.provider.log.error(
+ "Provider failed to enable data connection.")
+ return False
+ if not self._test_internet_connection(True, True):
+ self.log.error(
+ "Internet connection check failed after enable data")
+ return False
+ if change_rat:
+ self.log.info("===== Change provider RAT to %s =====", change_rat)
+ if not ensure_network_generation(
+ self.log,
+ self.provider,
+ change_rat,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ toggle_apm_after_setting=False):
+ self.provider.log.error("Provider failed to reselect to %s.",
+ change_rat)
+ return False
+ if not self._test_internet_connection(True, True):
+ self.log.error(
+ "Internet connection check failed after RAT change to %s",
+ change_rat)
+ return False
+ return True
+
+ @test_tracker_info(uuid="2d945656-22f7-4610-9a84-40ce04d603a4")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tethering_4g_to_bluetooth(self):
+ """Bluetooth Tethering test: LTE to Bluetooth Tethering
+
+ 1. DUT in LTE mode, idle.
+ 2. DUT start Bluetooth Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Toggle provider bluetooth connection
+ 6. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not self._test_setup_tethering(RAT_4G):
+ self.log.error("Verify 4G Internet access failed.")
+ return False
+
+ return self._verify_bluetooth_tethering_connection()
+
+ @test_tracker_info(uuid="8d2ae56b-c2c1-4c32-9b8e-5044007b5b90")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tethering_4g_to_bluetooth_with_voice_call(self):
+ """Bluetooth Tethering test: LTE to Bluetooth Tethering
+
+ 1. DUT in LTE mode, idle.
+ 2. DUT start Bluetooth Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Verify provider and client are able to make or receive phone call
+ 6. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not self._test_setup_tethering(RAT_4G):
+ self.log.error("Verify 4G Internet access failed.")
+ return False
+
+ return self._verify_bluetooth_tethering_connection(
+ toggle_tethering=False, toggle_bluetooth=False, voice_call=True)
+
+ @test_tracker_info(uuid="b4617727-fa83-4451-89d7-7e574c0a0938")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tethering_4g_to_bluetooth_toggle_data(self):
+ """Bluetooth Tethering test: LTE to Bluetooth Tethering
+
+ 1. DUT in LTE mode, idle.
+ 2. DUT start Bluetooth Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Toggle provider data connection
+ 6. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not self._test_setup_tethering(RAT_4G):
+ self.log.error("Verify 4G Internet access failed.")
+ return False
+
+ return self._verify_bluetooth_tethering_connection(
+ toggle_tethering=False, toggle_bluetooth=False, toggle_data=True)
+
+ @test_tracker_info(uuid="6a0f6001-609d-41f2-ad09-c8ae19f73ac8")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tethering_4g_to_bluetooth_toggle_tethering(self):
+ """Bluetooth Tethering test: LTE to Bluetooth Tethering
+
+ 1. DUT in LTE mode, idle.
+ 2. DUT start Bluetooth Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Toggle provider bluetooth tethering
+ 6. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not self._test_setup_tethering(RAT_4G):
+ self.log.error("Verify 4G Internet access failed.")
+ return False
+
+ return self._verify_bluetooth_tethering_connection(
+ toggle_tethering=True, toggle_bluetooth=False, toggle_data=False)
+
+ @test_tracker_info(uuid="b1abc1ac-8018-4956-a17e-bf2ceaf264ea")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tethering_3g_to_bluetooth(self):
+ """Bluetooth Tethering test: 3G to Bluetoothing Tethering
+
+ 1. DUT in 3G mode, idle.
+ 2. DUT start bluetooth Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Toggle provider bluetooth connection
+ 6. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not self._test_setup_tethering(RAT_3G):
+ self.log.error("Verify 3G Internet access failed.")
+ return False
+
+ return self._verify_bluetooth_tethering_connection()
+
+ @test_tracker_info(uuid="69793745-0c49-4cef-9879-d372e3a3f4c7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tethering_3g_to_bluetooth_with_voice_call(self):
+ """Bluetooth Tethering test: 3G to Bluetooth Tethering
+
+ 1. DUT in 3G mode, idle.
+ 2. DUT start Bluetooth Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Verify provider and client are able to make or receive phone call
+ 6. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not self._test_setup_tethering(RAT_3G):
+ self.log.error("Verify 3G Internet access failed.")
+ return False
+
+ return self._verify_bluetooth_tethering_connection(
+ toggle_tethering=False, toggle_bluetooth=False, voice_call=True)
+
+ @test_tracker_info(uuid="4275ee69-dfdf-4f47-82c5-4224fceee761")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tethering_3g_to_bluetooth_toggle_data(self):
+ """Bluetooth Tethering test: 3G to Bluetoothing Tethering
+
+ 1. DUT in 3G mode, idle.
+ 2. DUT start bluetooth Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Toggle provider data connection
+ 6. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not self._test_setup_tethering(RAT_3G):
+ self.log.error("Verify 3G Internet access failed.")
+ return False
+
+ return self._verify_bluetooth_tethering_connection(
+ toggle_tethering=False, toggle_bluetooth=False, toggle_data=True)
+
+ @test_tracker_info(uuid="db0e0f27-1a4f-4301-832d-b66415e289f3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tethering_2g_to_bluetooth(self):
+ """Bluetooth Tethering test: 2G to Bluetooth Tethering
+
+ 1. DUT in 2G mode, idle.
+ 2. DUT start bluetooth Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Toggle provider bluetooth connection
+ 6. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not self._test_setup_tethering(RAT_2G):
+ self.log.error("Verify 3G Internet access failed.")
+ return False
+
+ return self._verify_bluetooth_tethering_connection()
+
+ @test_tracker_info(uuid="584e9fa5-a38e-47cd-aa33-fcf8d72c423e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tethering_2g_to_bluetooth_with_voice_call(self):
+ """Bluetooth Tethering test: 2G to Bluetooth Tethering
+
+ 1. DUT in 2G mode, idle.
+ 2. DUT start Bluetooth Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Verify provider and client are able to make or receive phone call
+ 6. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not self._test_setup_tethering(RAT_2G):
+ self.log.error("Verify 2G Internet access failed.")
+ return False
+
+ return self._verify_bluetooth_tethering_connection(
+ toggle_tethering=False, toggle_bluetooth=False, voice_call=True)
+
+ @test_tracker_info(uuid="be3e74f9-3dc8-4b72-8a33-32bff0868a44")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tethering_2g_to_bluetooth_toggle_data(self):
+ """Bluetooth Tethering test: 2G to Bluetooth Tethering
+
+ 1. DUT in 2G mode, idle.
+ 2. DUT start Bluetooth Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Toggle provider data connection
+ 6. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not self._test_setup_tethering(RAT_2G):
+ self.log.error("Verify 4G Internet access failed.")
+ return False
+
+ return self._verify_bluetooth_tethering_connection(
+ toggle_tethering=False, toggle_bluetooth=False, toggle_data=True)
+
+ @test_tracker_info(uuid="4a106549-0bfa-4c8f-8e66-edec93fabadf")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tethering_rat_from_4g_to_3g_bluetooth(self):
+ """Bluetooth Tethering test: 2G to Bluetooth Tethering
+
+ 1. DUT in 4G mode, idle.
+ 2. DUT start bluetooth Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Change provider RAT to 3G
+ 6. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not self._test_setup_tethering(RAT_4G):
+ self.log.error("Verify 3G Internet access failed.")
+ return False
+
+ return self._verify_bluetooth_tethering_connection(
+ toggle_tethering=False,
+ toggle_bluetooth=False,
+ toggle_data=False,
+ change_rat=RAT_3G)
+
+ @test_tracker_info(uuid="eaa5b61b-f054-437f-ae82-8d80f6487785")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tethering_rat_from_4g_to_2g_bluetooth(self):
+ """Bluetooth Tethering test: 2G to Bluetooth Tethering
+
+ 1. DUT in 4G mode, idle.
+ 2. DUT start bluetooth Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Change provider RAT to 2G
+ 6. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not self._test_setup_tethering(RAT_4G):
+ self.log.error("Verify 3G Internet access failed.")
+ return False
+
+ return self._verify_bluetooth_tethering_connection(
+ toggle_tethering=False,
+ toggle_bluetooth=False,
+ toggle_data=False,
+ change_rat=RAT_2G)
+
@test_tracker_info(uuid="912a11a3-14b3-4928-885f-cea69f14a571")
@TelephonyBaseTest.tel_test_wrap
def test_tethering_4g_to_2gwifi(self):
@@ -735,14 +1248,13 @@
True if success.
False if failed.
"""
- ads = self.android_devices
if not self._test_setup_tethering(RAT_4G):
self.log.error("Verify 4G Internet access failed.")
return False
return wifi_tethering_setup_teardown(
self.log,
- self.provider, [self.clients[0]],
+ self.provider, self.clients,
ap_band=WIFI_CONFIG_APBAND_2G,
check_interval=10,
check_iteration=10)
@@ -761,17 +1273,32 @@
True if success.
False if failed.
"""
- ads = self.android_devices
- if not self._test_setup_tethering(RAT_4G):
- self.log.error("Verify 4G Internet access failed.")
- return False
+ num = len(self.android_devices)
+ for idx, ad in enumerate(self.android_devices):
+ self.provider = self.android_devices[idx]
+ self.clients = self.android_devices[:idx] + self.android_devices[
+ idx+1:]
+ if not self._test_setup_tethering(RAT_4G):
+ ad.log.error("Verify 4G Internet access failed.")
+ continue
- return wifi_tethering_setup_teardown(
- self.log,
- self.provider, [self.clients[0]],
- ap_band=WIFI_CONFIG_APBAND_5G,
- check_interval=10,
- check_iteration=10)
+ if not self.provider.droid.carrierConfigIsTetheringModeAllowed(
+ TETHERING_MODE_WIFI, MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK):
+ ad.log.info("Tethering is not entitled")
+ continue
+
+ if wifi_tethering_setup_teardown(self.log, self.provider,
+ [self.clients[0]],
+ ap_band=WIFI_CONFIG_APBAND_5G,
+ check_interval=10,
+ check_iteration=10):
+ self.android_devices = [self.provider] + self.clients
+ return True
+ elif idx == num - 1:
+ self.log.error("Tethering is not working on all devices")
+ return False
+ self.log.error("Faile to enable tethering on all devices")
+ return False
@test_tracker_info(uuid="59be8d68-f05b-4448-8584-de971174fd81")
@TelephonyBaseTest.tel_test_wrap
@@ -787,14 +1314,13 @@
True if success.
False if failed.
"""
- ads = self.android_devices
if not self._test_setup_tethering(RAT_3G):
self.log.error("Verify 3G Internet access failed.")
return False
return wifi_tethering_setup_teardown(
self.log,
- self.provider, [self.clients[0]],
+ self.provider, self.clients,
ap_band=WIFI_CONFIG_APBAND_2G,
check_interval=10,
check_iteration=10)
@@ -813,45 +1339,17 @@
True if success.
False if failed.
"""
- ads = self.android_devices
if not self._test_setup_tethering(RAT_3G):
self.log.error("Verify 3G Internet access failed.")
return False
return wifi_tethering_setup_teardown(
self.log,
- self.provider, [self.clients[0]],
+ self.provider, self.clients,
ap_band=WIFI_CONFIG_APBAND_5G,
check_interval=10,
check_iteration=10)
- @test_tracker_info(uuid="f8c4e3d8-b0e5-40ac-a31e-5ae5705a42c6")
- @TelephonyBaseTest.tel_test_wrap
- def test_tethering_4g_to_2gwifi_2clients(self):
- """WiFi Tethering test: LTE to WiFI 2.4G Tethering, with multiple clients
-
- 1. DUT in 3G mode, idle.
- 2. DUT start 5G WiFi Tethering
- 3. PhoneB and PhoneC disable data, connect to DUT's softAP
- 4. Verify Internet access on DUT and PhoneB PhoneC
-
- Returns:
- True if success.
- False if failed.
- """
- ads = self.android_devices
- if not self._test_setup_tethering(RAT_4G):
- self.log.error("Verify 4G Internet access failed.")
- return False
-
- return wifi_tethering_setup_teardown(
- self.log,
- self.provider,
- self.clients,
- ap_band=WIFI_CONFIG_APBAND_2G,
- check_interval=10,
- check_iteration=10)
-
@test_tracker_info(uuid="89fe6321-4c0d-40c0-89b2-54008ecca68f")
@TelephonyBaseTest.tel_test_wrap
def test_tethering_2g_to_2gwifi(self):
@@ -937,8 +1435,8 @@
self.log.error("WiFi Tethering failed.")
return False
- if (not wait_for_wifi_data_connection(self.log, self.provider, True) or
- not verify_internet_connection(self.log, self.provider)):
+ if (not wait_for_wifi_data_connection(self.log, self.provider, True)
+ or not verify_internet_connection(self.log, self.provider)):
self.log.error("Provider data did not return to Wifi")
return False
return True
@@ -1009,8 +1507,10 @@
self.provider.log.error("Provider WiFi tethering stopped.")
return False
- if not check_is_wifi_connected(self.log, self.clients[0], ssid) or (
- not verify_internet_connection(self.log, self.clients[0])):
+ if not check_is_wifi_connected(
+ self.log, self.clients[0],
+ ssid) or (not verify_internet_connection(
+ self.log, self.clients[0])):
self.clients[0].log.error(
"Client wifi connection check failed!")
return False
@@ -1228,8 +1728,8 @@
Returns:
True if entitlement check returns True.
"""
- if (not wait_for_cell_data_connection(self.log, self.provider, True) or
- not verify_internet_connection(self.log, self.provider)):
+ if (not wait_for_cell_data_connection(self.log, self.provider, True)
+ or not verify_internet_connection(self.log, self.provider)):
self.log.error("Failed cell data call for entitlement check.")
return False
@@ -1257,8 +1757,7 @@
for i in range(1, self.stress_test_number + 1):
- ensure_phones_default_state(self.log,
- [self.provider, self.clients[0]])
+ ensure_phones_default_state(self.log, self.android_devices)
if self.test_tethering_4g_to_2gwifi():
success_count += 1
@@ -1299,7 +1798,7 @@
return wifi_tethering_setup_teardown(
self.log,
- self.provider, [self.clients[0]],
+ self.provider, self.clients,
ap_band=WIFI_CONFIG_APBAND_2G,
check_interval=10,
check_iteration=10,
@@ -1328,7 +1827,7 @@
return wifi_tethering_setup_teardown(
self.log,
- self.provider, [self.clients[0]],
+ self.provider, self.clients,
ap_band=WIFI_CONFIG_APBAND_2G,
check_interval=10,
check_iteration=10,
@@ -1352,6 +1851,7 @@
True if no error happen, otherwise False.
"""
result = True
+ self.number_of_devices = 2
# Turn off active SoftAP if any.
if ad_host.droid.wifiIsApEnabled():
stop_wifi_tethering(self.log, ad_host)
@@ -1366,8 +1866,8 @@
self.log.error("Client connect to WiFi failed.")
result = False
if not wifi_reset(self.log, ad_client):
- self.log.error(
- "Reset client WiFi failed. {}".format(ad_client.serial))
+ self.log.error("Reset client WiFi failed. {}".format(
+ ad_client.serial))
result = False
if not stop_wifi_tethering(self.log, ad_host):
self.log.error("Stop WiFi tethering failed.")
@@ -1442,7 +1942,6 @@
fail_list = {}
for password in password_list:
- result = True
ssid = rand_ascii_str(8)
self.log.info("SSID: <{}>, Password: <{}>".format(ssid, password))
if not self._test_start_wifi_tethering_connect_teardown(
@@ -1458,6 +1957,7 @@
def _test_tethering_wifi_and_voice_call(self, provider_data_rat,
provider_setup_func,
provider_in_call_check_func):
+ self.number_of_devices = 2
if not self._test_setup_tethering(provider_data_rat):
self.log.error("Verify 4G Internet access failed.")
return False
@@ -1635,8 +2135,8 @@
self.provider.log.info("Reboot provider")
self.provider.reboot()
- time.sleep(WAIT_TIME_AFTER_REBOOT +
- WAIT_TIME_TETHERING_AFTER_REBOOT)
+ time.sleep(
+ WAIT_TIME_AFTER_REBOOT + WAIT_TIME_TETHERING_AFTER_REBOOT)
self.log.info("After reboot check if tethering stopped.")
if self.provider.droid.wifiIsApEnabled():
@@ -1674,8 +2174,8 @@
self.log.info("Make sure DUT can connect to live network by WIFI")
if ((not ensure_wifi_connected(self.log, self.provider,
self.wifi_network_ssid,
- self.wifi_network_pass)) or
- (not verify_internet_connection(self.log, self.provider))):
+ self.wifi_network_pass))
+ or (not verify_internet_connection(self.log, self.provider))):
self.log.error("WiFi connect fail.")
return False
@@ -1743,8 +2243,8 @@
self.log.info("Make sure DUT can connect to live network by WIFI")
if ((not ensure_wifi_connected(self.log, self.provider,
self.wifi_network_ssid,
- self.wifi_network_pass)) or
- (not verify_internet_connection(self.log, self.provider))):
+ self.wifi_network_pass))
+ or (not verify_internet_connection(self.log, self.provider))):
self.log.error("WiFi connect fail.")
return False
@@ -1958,9 +2458,8 @@
ad = self.android_devices[0]
if not ensure_network_generation_for_subscription(
- self.log, ad,
- ad.droid.subscriptionGetDefaultDataSubId(), GEN_4G,
- MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
+ self.log, ad, ad.droid.subscriptionGetDefaultDataSubId(),
+ GEN_4G, MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
self.log.error("Device {} failed to reselect in {}s.".format(
ad.serial, MAX_WAIT_TIME_NW_SELECTION))
return False
@@ -1988,9 +2487,8 @@
ad = self.android_devices[0]
if not ensure_network_generation_for_subscription(
- self.log, ad,
- ad.droid.subscriptionGetDefaultDataSubId(), GEN_3G,
- MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
+ self.log, ad, ad.droid.subscriptionGetDefaultDataSubId(),
+ GEN_3G, MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
self.log.error("Device {} failed to reselect in {}s.".format(
ad.serial, MAX_WAIT_TIME_NW_SELECTION))
return False
@@ -2017,9 +2515,8 @@
"""
ad = self.android_devices[0]
if not ensure_network_generation_for_subscription(
- self.log, ad,
- ad.droid.subscriptionGetDefaultDataSubId(), GEN_2G,
- MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
+ self.log, ad, ad.droid.subscriptionGetDefaultDataSubId(),
+ GEN_2G, MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
self.log.error("Device {} failed to reselect in {}s.".format(
ad.serial, MAX_WAIT_TIME_NW_SELECTION))
return False
@@ -2278,8 +2775,8 @@
self.wifi_network_pass):
self.log.error("WiFi connect fail.")
return False
- if (not wait_for_wifi_data_connection(self.log, ad, True) or
- not verify_internet_connection(self.log, ad)):
+ if (not wait_for_wifi_data_connection(self.log, ad, True)
+ or not verify_internet_connection(self.log, ad)):
self.log.error("Data is not on WiFi")
return False
@@ -2310,15 +2807,13 @@
ad = self.android_devices[0]
# Install App and Push config
self.log.info("Pushing embms config and apk to the Android device.")
- embms_path_str = "embms_path"
android_embms_path = "/sdcard/mobitv"
- if embms_path_str not in self.user_params:
- self.log.error("Need vzwdca for embms test in config file")
- return False
- embms_path = self.user_params[embms_path_str]
+ embms_path = self.user_params.get("embms_path", "embms_path")
+ if isinstance(embms_path, list):
+ embms_path = embms_path[0]
ad.adb.shell("mkdir /sdcard/mobitv")
dcafile = os.path.join(embms_path, "dca.config")
- apkfile = os.path.join(embms_path, "VzwDCA-v3035.apk")
+ apkfile = os.path.join(embms_path, "VzwDCA.apk")
ad.adb.push("%s %s" % (dcafile, android_embms_path))
ad.adb.install("%s" % apkfile)
@@ -2487,7 +2982,7 @@
Steps:
1. Download a file random picked.
- 2. Device sleep for sometime and Repeat 1 .
+ 2. Device sleep for sometime and Repeat 1.
Expected Results:
Total download failure rate is less than 10%.
@@ -2497,4 +2992,48 @@
False if failed.
"""
return self.file_download_stress()
+
+ @test_tracker_info(uuid="c9970955-123b-467c-afbb-95ec8f99e9b7")
+ def test_file_download_with_mobile_data_usage_limit_set(self):
+ """ Steps:
+ 1. Set the data usage limit to current data usage + 9MB
+ 2. Download 5MB file from internet.
+ 3. The first file download should succeed
+ 4. The second file download should fail
+ """
+ dut = self.android_devices[0]
+ ensure_phones_default_state(self.log, [dut])
+ subscriber_id = dut.droid.telephonyGetSubscriberId()
+ old_data_usage = get_mobile_data_usage(dut, subscriber_id)
+
+ # set data usage limit to current usage limit + 10MB
+ data_limit = old_data_usage + 9 * 1000 * 1000
+ set_mobile_data_usage_limit(dut, data_limit, subscriber_id)
+
+ # download file - size 5MB twice
+ try:
+ for _ in range(2):
+ if not active_file_download_test(self.log, dut, "5MB"):
+ if get_mobile_data_usage(
+ dut, subscriber_id) + 5 * 1000 * 1000 < data_limit:
+ dut.log.error(
+ "Fail to download file when mobile data usage is"
+ " below data usage limit")
+ return False
+ else:
+ dut.log.info(
+ "Download fails as expected due to data limit reached"
+ )
+ else:
+ if get_mobile_data_usage(dut, subscriber_id) < data_limit:
+ dut.log.info(
+ "Download file succeed when mobile data usage is"
+ " below data usage limit")
+ else:
+ dut.log.error(
+ "Download should fail due to data limit reached")
+ return False
+ return True
+ finally:
+ remove_mobile_data_usage_limit(dut, subscriber_id)
""" Tests End """
diff --git a/acts/tests/google/tel/live/TelLiveEmergencyTest.py b/acts/tests/google/tel/live/TelLiveEmergencyTest.py
new file mode 100644
index 0000000..28dd15d
--- /dev/null
+++ b/acts/tests/google/tel/live/TelLiveEmergencyTest.py
@@ -0,0 +1,289 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2017 - Google
+#
+# 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 for Telephony Pre Check In Sanity
+"""
+
+import time
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts.test_utils.tel.tel_defines import DEFAULT_DEVICE_PASSWORD
+from acts.test_utils.tel.tel_test_utils import abort_all_tests
+from acts.test_utils.tel.tel_test_utils import dumpsys_telecom_call_info
+from acts.test_utils.tel.tel_test_utils import get_service_state_by_adb
+from acts.test_utils.tel.tel_test_utils import fastboot_wipe
+from acts.test_utils.tel.tel_test_utils import hangup_call_by_adb
+from acts.test_utils.tel.tel_test_utils import initiate_call
+from acts.test_utils.tel.tel_test_utils import initiate_emergency_dialer_call_by_adb
+from acts.test_utils.tel.tel_test_utils import reset_device_password
+from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
+from acts.test_utils.tel.tel_test_utils import unlock_sim
+from acts.test_utils.tel.tel_test_utils import wait_for_sim_ready_by_adb
+
+
+class TelLiveEmergencyTest(TelephonyBaseTest):
+ def __init__(self, controllers):
+ TelephonyBaseTest.__init__(self, controllers)
+
+ self.dut = self.android_devices[0]
+ self.number_of_devices = 1
+ fake_number = self.user_params.get("fake_emergency_number", "800")
+ self.fake_emergency_number = fake_number.strip("+").replace("-", "")
+ self.wifi_network_ssid = self.user_params.get(
+ "wifi_network_ssid") or self.user_params.get(
+ "wifi_network_ssid_2g")
+ self.wifi_network_pass = self.user_params.get(
+ "wifi_network_pass") or self.user_params.get(
+ "wifi_network_pass_2g")
+
+ def setup_test(self):
+ if not unlock_sim(self.dut):
+ abort_all_tests(self.dut.log, "unable to unlock SIM")
+ self.expected_call_result = True
+
+ def teardown_test(self):
+ self.dut.ensure_screen_on()
+ reset_device_password(self.dut, None)
+
+ def change_emergency_number_list(self):
+ for _ in range(5):
+ existing = self.dut.adb.getprop("ril.ecclist")
+ self.dut.log.info("Existing ril.ecclist is: %s", existing)
+ if self.fake_emergency_number in existing:
+ return True
+ emergency_numbers = "%s,%s" % (existing,
+ self.fake_emergency_number)
+ cmd = "setprop ril.ecclist %s" % emergency_numbers
+ self.dut.log.info(cmd)
+ self.dut.adb.shell(cmd)
+ # After some system events, ril.ecclist might change
+ # wait sometime for it to settle
+ time.sleep(10)
+ if self.fake_emergency_number in existing:
+ return True
+ return False
+
+ def change_qcril_emergency_source_mcc_table(self):
+ # This will add the fake number into emergency number list for a mcc
+ # in qcril. Please note, the fake number will be send as an emergency
+ # number by modem and reach the real 911 by this
+ qcril_database_path = self.dut.adb.shell("find /data -iname qcril.db")
+ if not qcril_database_path: return
+ mcc = self.dut.droid.telephonyGetNetworkOperator()
+ mcc = mcc[:3]
+ self.dut.log.info("Add %s mcc %s in qcril_emergency_source_mcc_table")
+ self.dut.adb.shell(
+ "sqlite3 %s \"INSERT INTO qcril_emergency_source_mcc_table VALUES('%s','%s','','')\""
+ % (qcril_database_path, mcc, self.fake_emergency_number))
+
+ def fake_emergency_call_test(self, by_emergency_dialer=True, attemps=3):
+ self.dut.log.info("ServiceState is in %s",
+ get_service_state_by_adb(self.log, self.dut))
+ if by_emergency_dialer:
+ dialing_func = initiate_emergency_dialer_call_by_adb
+ callee = self.fake_emergency_number
+ else:
+ dialing_func = initiate_call
+ # Initiate_call method has to have "+" in front
+ # otherwise the number will be in dialer without dial out
+ # with sl4a fascade. Need further investigation
+ callee = "+%s" % self.fake_emergency_number
+ for i in range(attemps):
+ result = True
+ if not self.change_emergency_number_list():
+ self.dut.log.error("Unable to add number to ril.ecclist")
+ return False
+ time.sleep(1)
+ call_numbers = len(dumpsys_telecom_call_info(self.dut))
+ dial_result = dialing_func(self.log, self.dut, callee)
+ hangup_call_by_adb(self.dut)
+ self.dut.send_keycode("BACK")
+ self.dut.send_keycode("BACK")
+ calls_info = dumpsys_telecom_call_info(self.dut)
+ if len(calls_info) <= call_numbers:
+ self.dut.log.error("New call is not in sysdump telecom")
+ result = False
+ else:
+ self.dut.log.info("New call info = %s", calls_info[-1])
+
+ if dial_result == self.expected_call_result:
+ self.dut.log.info("Call to %s returns %s as expected", callee,
+ self.expected_call_result)
+ else:
+ self.dut.log.info("Call to %s returns %s", callee,
+ not self.expected_call_result)
+ result = False
+ if result:
+ return True
+ ecclist = self.dut.adb.getprop("ril.ecclist")
+ self.dut.log.info("ril.ecclist = %s", ecclist)
+ if self.fake_emergency_number in ecclist:
+ if i == attemps - 1:
+ self.dut.log.error("%s is in ril-ecclist, but call failed",
+ self.fake_emergency_number)
+ else:
+ self.dut.log.warning(
+ "%s is in ril-ecclist, but call failed, try again",
+ self.fake_emergency_number)
+ else:
+ if i == attemps - 1:
+ self.dut.log.error("Fail to write %s to ril-ecclist",
+ self.fake_emergency_number)
+ else:
+ self.dut.log.info("%s is not in ril-ecclist",
+ self.fake_emergency_number)
+ self.dut.log.info("fake_emergency_call_test result is %s", result)
+ import pdb
+ pdb.set_trace()
+ return result
+
+ """ Tests Begin """
+
+ @test_tracker_info(uuid="fe75ba2c-e4ea-4fc1-881b-97e7a9a7f48e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_fake_emergency_call_by_emergency_dialer(self):
+ """Test emergency call with emergency dialer in user account.
+
+ Add system emergency number list with storyline number.
+ Use the emergency dialer to call storyline.
+ Verify DUT has in call activity.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return self.fake_emergency_call_test()
+
+ @test_tracker_info(uuid="8a0978a8-d93e-4f6a-99fe-d0e28bf1be2a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_fake_emergency_call_by_dialer(self):
+ """Test emergency call with dialer.
+
+ Add system emergency number list with storyline number.
+ Call storyline by dialer.
+ Verify DUT has in call activity.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return self.fake_emergency_call_test(by_emergency_dialer=False)
+
+ @test_tracker_info(uuid="2e6fcc75-ff9e-47b1-9ae8-ed6f9966d0f5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_fake_emergency_call_in_apm(self):
+ """Test emergency call with emergency dialer in airplane mode.
+
+ Enable airplane mode.
+ Add system emergency number list with storyline number.
+ Use the emergency dialer to call storyline.
+ Verify DUT has in call activity.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ try:
+ toggle_airplane_mode_by_adb(self.log, self.dut, True)
+ if self.fake_emergency_call_test():
+ return True
+ else:
+ return False
+ finally:
+ toggle_airplane_mode_by_adb(self.log, self.dut, False)
+
+ @test_tracker_info(uuid="469bfa60-6e8f-4159-af1f-ab6244073079")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_fake_emergency_call_in_screen_lock(self):
+ """Test emergency call with emergency dialer in screen lock phase.
+
+ Enable device password and then reboot upto password query window.
+ Add system emergency number list with storyline.
+ Use the emergency dialer to call storyline.
+ Verify DUT has in call activity.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ toggle_airplane_mode_by_adb(self.log, self.dut, False)
+ reset_device_password(self.dut, DEFAULT_DEVICE_PASSWORD)
+ if not wait_for_sim_ready_by_adb(self.log, self.dut):
+ self.dut.log.error("SIM is not ready")
+ return False
+ self.dut.reboot(stop_at_lock_screen=True)
+ if self.fake_emergency_call_test():
+ return True
+ else:
+ return False
+
+ @test_tracker_info(uuid="17401c57-0dc2-49b5-b954-a94dbb2d5ad0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_fake_emergency_call_in_screen_lock_apm(self):
+ """Test emergency call with emergency dialer in screen lock phase.
+
+ Enable device password and then reboot upto password query window.
+ Add system emergency number list with storyline.
+ Use the emergency dialer to call storyline.
+ Verify DUT has in call activity.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ try:
+ toggle_airplane_mode_by_adb(self.log, self.dut, True)
+ reset_device_password(self.dut, DEFAULT_DEVICE_PASSWORD)
+ self.dut.reboot(stop_at_lock_screen=True)
+ if not wait_for_sim_ready_by_adb(self.log, self.dut):
+ self.dut.log.error("SIM is not ready")
+ return False
+ if self.fake_emergency_call_test():
+ return True
+ else:
+ return False
+ finally:
+ toggle_airplane_mode_by_adb(self.log, self.dut, False)
+
+ @test_tracker_info(uuid="ccea13ae-6951-4790-a5f7-b5b7a2451c6c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_fake_emergency_call_in_setupwizard(self):
+ """Test emergency call with emergency dialer in setupwizard.
+
+ Wipe the device and then reboot upto setupwizard.
+ Add system emergency number list with storyline number.
+ Use the emergency dialer to call storyline.
+ Verify DUT has in call activity.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ try:
+ if not fastboot_wipe(self.dut, skip_setup_wizard=False):
+ return False
+ if not wait_for_sim_ready_by_adb(self.log, self.dut):
+ self.dut.log.error("SIM is not ready")
+ return False
+ if self.fake_emergency_call_test():
+ return True
+ else:
+ return False
+ finally:
+ self.dut.exit_setup_wizard()
+
+
+""" Tests End """
diff --git a/acts/tests/google/tel/live/TelLiveLockedSimTest.py b/acts/tests/google/tel/live/TelLiveLockedSimTest.py
new file mode 100644
index 0000000..b44fd95
--- /dev/null
+++ b/acts/tests/google/tel/live/TelLiveLockedSimTest.py
@@ -0,0 +1,223 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2017 - Google
+#
+# 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 for Telephony Locked SIM Emergency Call Test
+"""
+
+import time
+from acts.base_test import BaseTestClass
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts.test_utils.tel.tel_defines import DEFAULT_DEVICE_PASSWORD
+from acts.test_utils.tel.tel_test_utils import abort_all_tests
+from acts.test_utils.tel.tel_test_utils import fastboot_wipe
+from acts.test_utils.tel.tel_test_utils import is_sim_locked
+from acts.test_utils.tel.tel_test_utils import is_sim_ready_by_adb
+from acts.test_utils.tel.tel_test_utils import reset_device_password
+from acts.test_utils.tel.tel_test_utils import refresh_sl4a_session
+from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
+from acts.test_utils.tel.tel_test_utils import unlocking_device
+from acts.test_utils.tel.tel_test_utils import unlock_sim
+from acts.test_utils.tel.tel_test_utils import STORY_LINE
+from TelLiveEmergencyTest import TelLiveEmergencyTest
+
+EXPECTED_CALL_TEST_RESULT = False
+
+
+class TelLiveLockedSimTest(TelLiveEmergencyTest):
+ def __init__(self, controllers):
+ BaseTestClass.__init__(self, controllers)
+ self.logger_sessions = []
+ fake_number = self.user_params.get("fake_emergency_number", STORY_LINE)
+ self.fake_emergency_number = fake_number.strip("+").replace("-", "")
+ for ad in self.android_devices:
+ if not is_sim_locked(ad):
+ ad.log.info("SIM is not locked")
+ else:
+ ad.log.info("SIM is locked")
+ self.dut = ad
+ return
+ #if there is no locked SIM, reboot the device and check again
+ for ad in self.android_devices:
+ reset_device_password(ad, None)
+ ad.reboot(stop_at_lock_screen=True)
+ for _ in range(10):
+ if is_sim_ready_by_adb(self.log, ad):
+ ad.log.info("SIM is not locked")
+ break
+ elif is_sim_locked(ad):
+ ad.log.info("SIM is locked")
+ self.dut = ad
+ ad.ensure_screen_on()
+ ad.start_services(ad.skip_sl4a)
+ return
+ else:
+ time.sleep(5)
+ self.log.error("There is no locked SIM in this testbed")
+ abort_all_tests(self.log, "There is no locked SIM")
+
+ def setup_class(self):
+ self.android_devices = [self.dut]
+ pass
+
+ def setup_test(self):
+ self.expected_call_result = False
+ unlocking_device(self.dut)
+ refresh_sl4a_session(self.dut)
+ unlock_sim(self.dut)
+
+ """ Tests Begin """
+
+ @test_tracker_info(uuid="fd7fb69c-6fd4-4874-a4ca-769353b9db25")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_fake_emergency_call_by_emergency_dialer(self):
+ """Test emergency call with emergency dialer in user account.
+
+ Enable SIM lock on the SIM. Reboot device to SIM pin request page.
+ Add storyline number to system emergency number list.
+ Use the emergency dialer to call "611".
+ Verify DUT has in call activity.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ self.expected_call_result = True
+ toggle_airplane_mode_by_adb(self.log, self.dut, False)
+ return self.fake_emergency_call_test()
+
+ @test_tracker_info(uuid="669cf1d9-9513-4f90-b0fd-2f0e8f1cc941")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_fake_emergency_call_by_dialer(self):
+ """Test emergency call with dialer.
+
+ Enable SIM lock on the SIM. Reboot device to SIM pin request page.
+ Add system emergency number list with storyline number.
+ Call storyline by dialer.
+ Verify DUT has in call activity.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ self.expected_call_result = True
+ toggle_airplane_mode_by_adb(self.log, self.dut, False)
+ return self.fake_emergency_call_test(by_emergency_dialer=True)
+
+ @test_tracker_info(uuid="1990f166-66a7-4092-b448-c179a9194371")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_fake_emergency_call_in_apm(self):
+ """Test emergency call with emergency dialer in airplane mode.
+
+ Enable airplane mode.
+ Enable SIM lock on the SIM. Reboot device to SIM pin request page.
+ Add system emergency number list with storyline number.
+ Use the emergency dialer to call storyline.
+ Verify DUT has in call activity.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ self.expected_call_result = True
+ try:
+ toggle_airplane_mode_by_adb(self.log, self.dut, True)
+ if self.fake_emergency_call_test():
+ return True
+ else:
+ return False
+ finally:
+ toggle_airplane_mode_by_adb(self.log, self.dut, False)
+
+ @test_tracker_info(uuid="7ffdad34-b8fb-41b0-b0fd-2def5adc67bc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_fake_emergency_call_in_screen_lock(self):
+ """Test emergency call with emergency dialer in screen lock phase.
+
+ Enable SIM lock on the SIM.
+ Enable device password and then reboot upto password and pin query stage.
+ Add system emergency number list with storyline number.
+ Use the emergency dialer to call storyline.
+ Verify DUT has in call activity.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ self.dut.log.info("Turn off airplane mode")
+ toggle_airplane_mode_by_adb(self.log, self.dut, False)
+ self.dut.log.info("Set screen lock pin")
+ reset_device_password(self.dut, DEFAULT_DEVICE_PASSWORD)
+ self.dut.log.info("Reboot device to screen lock screen")
+ self.dut.reboot(stop_at_lock_screen=True)
+ if self.fake_emergency_call_test():
+ return True
+ else:
+ return False
+
+ @test_tracker_info(uuid="12dc1eb6-50ed-4ad9-b195-5d96c6b6952e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_fake_emergency_call_in_screen_lock_apm(self):
+ """Test emergency call with emergency dialer in screen lock phase.
+
+ Enable device password and airplane mode
+ Enable SIM lock on the SIM.
+ Reboot upto pin query window.
+ Add system emergency number list with story line.
+ Use the emergency dialer to call story line.
+ Verify DUT has in call activity.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ toggle_airplane_mode_by_adb(self.log, self.dut, True)
+ self.dut.log.info("Set screen lock pin")
+ reset_device_password(self.dut, DEFAULT_DEVICE_PASSWORD)
+ self.dut.log.info("Reboot device to screen lock screen")
+ self.dut.reboot(stop_at_lock_screen=True)
+ if self.fake_emergency_call_test():
+ return True
+ else:
+ return False
+
+ @test_tracker_info(uuid="1e01927a-a077-466d-8bf8-52dca87ab87c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_fake_emergency_call_in_setupwizard(self):
+ """Test emergency call with emergency dialer in setupwizard.
+
+ Enable SIM lock on the SIM.
+ Wipe the device and then reboot upto setupwizard.
+ Add system emergency number list with story line.
+ Use the emergency dialer to call story line.
+ Verify DUT has in call activity.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ try:
+ if not fastboot_wipe(self.dut, skip_setup_wizard=False):
+ return False
+ if self.fake_emergency_call_test():
+ return True
+ else:
+ return False
+ finally:
+ self.dut.exit_setup_wizard()
+
+
+""" Tests End """
diff --git a/acts/tests/google/tel/live/TelLiveMobilityStressTest.py b/acts/tests/google/tel/live/TelLiveMobilityStressTest.py
index 16d4d95..2120c04 100644
--- a/acts/tests/google/tel/live/TelLiveMobilityStressTest.py
+++ b/acts/tests/google/tel/live/TelLiveMobilityStressTest.py
@@ -20,6 +20,7 @@
import collections
import random
import time
+from acts.asserts import explicit_pass
from acts.asserts import fail
from acts.test_decorators import test_tracker_info
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
@@ -44,6 +45,7 @@
from acts.test_utils.tel.tel_test_utils import run_multithread_func
from acts.test_utils.tel.tel_test_utils import set_wfc_mode
from acts.test_utils.tel.tel_test_utils import sms_send_receive_verify
+from acts.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts.test_utils.tel.tel_test_utils import mms_send_receive_verify
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
@@ -100,6 +102,9 @@
return True
+ def on_fail(self, test_name, begin_time):
+ pass
+
def _setup_volte_wfc_wifi_preferred(self):
return self._wfc_phone_setup(
False, WFC_MODE_WIFI_PREFERRED, volte_mode=True)
@@ -136,13 +141,20 @@
0: sms_send_receive_verify,
1: mms_send_receive_verify
}
- self.result_info["Total %s" % message_type_map[selection]] += 1
+ message_type = message_type_map[selection]
+ self.result_info["Total %s" % message_type] += 1
+ begin_time = get_current_epoch_time()
+ start_qxdm_loggers(self.log, self.android_devices)
if not message_func_map[selection](self.log, ads[0], ads[1],
message_content_map[selection]):
- self.log.error("%s of length %s from %s to %s fails",
- message_type_map[selection], length, ads[0].serial,
- ads[1].serial)
- self.result_info["%s failure" % message_type_map[selection]] += 1
+ self.log.error("%s of length %s from %s to %s fails", message_type,
+ length, ads[0].serial, ads[1].serial)
+ self.result_info["%s failure" % message_type] += 1
+ if message_type == "SMS" or self.result_info["%s failure" %
+ message_type] == 1:
+ self._take_bug_report("%s_%s_failure" % (self.test_name,
+ message_type),
+ begin_time)
return False
else:
self.log.info("%s of length %s from %s to %s succeed",
@@ -152,6 +164,8 @@
def _make_phone_call(self, ads):
self.result_info["Total Calls"] += 1
+ begin_time = get_current_epoch_time()
+ start_qxdm_loggers(self.log, self.android_devices)
if not call_setup_teardown(
self.log,
ads[0],
@@ -162,6 +176,8 @@
self.max_phone_call_duration)):
self.log.error("Call setup and teardown failed.")
self.result_info["Call Failure"] += 1
+ self._take_bug_report("%s_call_failure" % self.test_name,
+ begin_time)
return False
self.log.info("Call setup and teardown succeed.")
return True
@@ -171,8 +187,7 @@
while time.time() < self.finishing_time:
self.dut.log.info(dict(self.result_info))
try:
- begin_time = epoch_to_log_line_timestamp(
- get_current_epoch_time())
+ begin_time = get_current_epoch_time()
time.sleep(self.crash_check_interval)
crash_report = self.dut.check_crash_report(
"checking_crash", begin_time, True)
@@ -185,16 +200,14 @@
self.log.error("Exception error %s", str(e))
self.result_info["Exception Errors"] += 1
if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
+ return False
except Exception as e:
- self.finishing_time = time.time()
- raise
+ return False
self.dut.log.info("Crashes found: %s", failure)
if failure:
- return "%s crashes" % failure
+ return False
else:
- return ""
+ return True
def environment_change_4g_wifi(self):
#block cell 3G, WIFI 2G
@@ -274,24 +287,23 @@
self.log, self.helper))
if not self._make_phone_call(ads):
failure += 1
- self._take_bug_report("%s_call_failure" % self.test_name,
- time.strftime("%m-%d-%Y-%H-%M-%S"))
self.dut.droid.goToSleepNow()
time.sleep(random.randrange(0, self.max_sleep_time))
- except IGNORE_EXCEPTION as e:
+ except IGNORE_EXCEPTIONS as e:
self.log.error("Exception error %s", str(e))
self.result_info["Exception Errors"] += 1
if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
+ self.log.error("Too many exception errors %s",
+ IGNORE_EXCEPTIONS)
+ return False
except Exception as e:
- self.finishing_time = time.time()
- raise
+ self.log.error(e)
+ return False
self.dut.log.info("Call test failure: %s/%s", failure, total_count)
if failure:
- return "Call test failure: %s/%s" % (failure, total_count)
+ return False
else:
- return ""
+ return True
def message_test(self):
failure = 0
@@ -303,25 +315,24 @@
total_count += 1
if not self._send_message(ads):
failure += 1
- #self._take_bug_report("%s_messaging_failure" % self.test_name,
- # time.strftime("%m-%d-%Y-%H-%M-%S"))
self.dut.droid.goToSleepNow()
time.sleep(random.randrange(0, self.max_sleep_time))
- except IGNORE_EXCEPTION as e:
+ except IGNORE_EXCEPTIONS as e:
self.log.error("Exception error %s", str(e))
self.result_info["Exception Errors"] += 1
if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
+ self.log.error("Too many exception errors %s",
+ IGNORE_EXCEPTIONS)
+ return False
except Exception as e:
- self.finishing_time = time.time()
- raise
+ self.log.error(e)
+ return False
self.dut.log.info("Messaging test failure: %s/%s", failure,
total_count)
if failure / total_count > 0.1:
- return "Messaging test failure: %s/%s" % (failure, total_count)
+ return False
else:
- return ""
+ return True
def data_test(self):
failure = 0
@@ -331,6 +342,8 @@
file_names = ["5MB", "10MB", "20MB", "50MB", "200MB"]
while time.time() < self.finishing_time:
total_count += 1
+ begin_time = get_current_epoch_time()
+ start_qxdm_loggers(self.log, self.android_devices)
try:
self.dut.log.info(dict(self.result_info))
self.result_info["Total file download"] += 1
@@ -338,28 +351,30 @@
file_name = file_names[selection]
if not active_file_download_test(self.log, self.dut,
file_name):
- self.result_info["%s file download failure" %
- file_name] += 1
- #self._take_bug_report("%s_download_failure" % self.test_name,
- # time.strftime("%m-%d-%Y-%H-%M-%S"))
+ self.result_info["File download failure"] += 1
failure += 1
- self.dut.droid.goToSleepNow()
- time.sleep(random.randrange(0, self.max_sleep_time))
- except IGNORE_EXCEPTION as e:
+ if self.result_info["File download failure"] == 1:
+ self._take_bug_report(
+ "%s_file_download_failure" % self.test_name,
+ begin_time)
+ self.dut.droid.goToSleepNow()
+ time.sleep(random.randrange(0, self.max_sleep_time))
+ except IGNORE_EXCEPTIONS as e:
self.log.error("Exception error %s", str(e))
self.result_info["Exception Errors"] += 1
if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
+ self.log.error("Too many exception error %s",
+ IGNORE_EXCEPTIONS)
+ return False
except Exception as e:
- self.finishing_time = time.time()
- raise
+ self.log.error(e)
+ return False
self.dut.log.info("File download test failure: %s/%s", failure,
total_count)
if failure / total_count > 0.1:
- return "File download test failure: %s/%s" % (failure, total_count)
+ return False
else:
- return ""
+ return True
def parallel_tests(self, change_env_func, setup_func=None):
if setup_func and not setup_func():
@@ -370,12 +385,12 @@
results = run_multithread_func(self.log, [(self.call_test, []), (
self.message_test, []), (self.data_test, []), (
self.crash_check_test, []), (change_env_func, [])])
- self.log.info(dict(self.result_info))
- error_message = " ".join(results).strip()
- if error_message:
- self.log.error(error_message)
- fail(error_message)
- return True
+ result_message = "%s" % dict(self.result_info)
+ self.log.info(result_message)
+ if all(results):
+ explicit_pass(result_message)
+ else:
+ fail(result_message)
""" Tests Begin """
diff --git a/acts/tests/google/tel/live/TelLiveNoSimTest.py b/acts/tests/google/tel/live/TelLiveNoSimTest.py
index f886e61..87b204a 100644
--- a/acts/tests/google/tel/live/TelLiveNoSimTest.py
+++ b/acts/tests/google/tel/live/TelLiveNoSimTest.py
@@ -17,64 +17,29 @@
Test Script for Telephony Pre Check In Sanity
"""
-import time
-import os
from acts.test_decorators import test_tracker_info
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts.test_utils.tel.tel_test_utils import dumpsys_telecom_call_info
-from acts.test_utils.tel.tel_test_utils import hung_up_call_by_adb
-from acts.test_utils.tel.tel_test_utils import initiate_call
-from acts.test_utils.tel.tel_test_utils import initiate_emergency_dialer_call_by_adb
+from acts.test_utils.tel.tel_defines import DEFAULT_DEVICE_PASSWORD
+from acts.test_utils.tel.tel_defines import SIM_STATE_ABSENT
+from acts.test_utils.tel.tel_test_utils import fastboot_wipe
+from acts.test_utils.tel.tel_test_utils import reset_device_password
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
-from acts.test_utils.tel.tel_test_utils import STORY_LINE
+from TelLiveEmergencyTest import TelLiveEmergencyTest
-class TelLiveNoSimTest(TelephonyBaseTest):
+class TelLiveNoSimTest(TelLiveEmergencyTest):
def setup_class(self):
- self.wifi_network_ssid = self.user_params.get(
- "wifi_network_ssid") or self.user_params.get("wifi_network_ssid_2g")
- self.wifi_network_pass = self.user_params.get(
- "wifi_network_pass") or self.user_params.get("wifi_network_pass_2g")
- self.dut = self.android_devices[0]
- self.fake_emergency_number = self.user_params.get(
- "fake_emergency_number", STORY_LINE.strip("+"))
-
- def teardown_class(self):
- super(TelephonyBaseTest, self).teardown_class()
- #reboot to load default emergency number list ril.ecclist
- self.dut.reboot()
+ for ad in self.android_devices:
+ if ad.adb.getprop("gsm.sim.state") == SIM_STATE_ABSENT:
+ ad.log.info("Device has no SIM in it, set as DUT")
+ self.dut = ad
+ return True
+ self.log.error("No device meets no SIM requirement")
+ return False
def setup_test(self):
- if not self.dut.skip_sl4a and not getattr(self.dut, "droid"):
- self.dut.start_services()
-
- def change_emergency_number_list(self):
- existing = self.dut.adb.shell("getprop ril.ecclist")
- if self.fake_emergency_number in existing: return
- emergency_numbers = "%s,%s" % (existing, self.fake_emergency_number)
- self.dut.log.info("Change emergency numbes to %s", emergency_numbers)
- self.dut.adb.shell("setprop ril.ecclist %s" % emergency_numbers)
-
- def fake_emergency_call_test(self, by_emergency_dialer=True):
- self.change_emergency_number_list()
- time.sleep(1)
- call_numbers = len(dumpsys_telecom_call_info(self.dut))
- if by_emergency_dialer:
- dialing_func = initiate_emergency_dialer_call_by_adb
- else:
- dialing_func = initiate_call
- if dialing_func(
- self.log, self.dut, self.fake_emergency_number, timeout=10):
- hung_up_call_by_adb(self.dut)
- self.dut.log.error(
- "calling to the fake emergency number should fail")
- calls_info = dumpsys_telecom_call_info(self.dut)
- if len(calls_info) <= call_numbers:
- self.dut.log.error("New call is not in sysdump telecom")
- return False
- else:
- self.dut.log.info("New call info = %s", calls_info[call_numbers])
- return True
+ self.expected_call_result = False
+ self.android_devices = [self.dut]
""" Tests Begin """
@@ -83,14 +48,15 @@
def test_fake_emergency_call_by_emergency_dialer(self):
"""Test emergency call with emergency dialer in user account.
- Change system emergency number list to "611".
- Use the emergency dialer to call "611".
+ Add storyline number to system emergency number list.
+ Use the emergency dialer to call storyline.
Verify DUT has in call activity.
Returns:
True if success.
False if failed.
"""
+ toggle_airplane_mode_by_adb(self.log, self.dut, False)
return self.fake_emergency_call_test()
@test_tracker_info(uuid="cdf7ddad-480f-4757-83bd-a74321b799f7")
@@ -98,14 +64,15 @@
def test_fake_emergency_call_by_dialer(self):
"""Test emergency call with dialer.
- Change system emergency number list to "611".
- Call "611" by dialer.
+ Add storyline number to system emergency number list.
+ Call storyline by dialer.
Verify DUT has in call activity.
Returns:
True if success.
False if failed.
"""
+ toggle_airplane_mode_by_adb(self.log, self.dut, False)
return self.fake_emergency_call_test(by_emergency_dialer=False)
@test_tracker_info(uuid="e147960a-4227-41e2-bd06-65001ad5e0cd")
@@ -114,8 +81,8 @@
"""Test emergency call with emergency dialer in airplane mode.
Enable airplane mode.
- Change system emergency number list to "611".
- Use the emergency dialer to call "611".
+ Add storyline number to system emergency number list.
+ Use the emergency dialer to call storyline.
Verify DUT has in call activity.
Returns:
@@ -137,29 +104,21 @@
"""Test emergency call with emergency dialer in screen lock phase.
Enable device password and then reboot upto password query window.
- Change system emergency number list to "611".
- Use the emergency dialer to call "611".
+ Add storyline number to system emergency number list.
+ Use the emergency dialer to call storyline.
Verify DUT has in call activity.
Returns:
True if success.
False if failed.
"""
- try:
- if not self.dut.device_password and getattr(self.dut, "droid"):
- self.dut.droid.setDevicePassword("1111")
- self.dut.reboot(stop_at_lock_screen=True)
- if self.fake_emergency_call_test():
- return True
- else:
- return False
- finally:
- if not self.dut.ensure_screen_on():
- self.dut.log.error("User screen cannot come up")
- return False
- self.dut.start_services(self.dut.skip_sl4a)
- if not self.dut.device_password:
- self.dut.droid.disableDevicePassword()
+ toggle_airplane_mode_by_adb(self.log, self.dut, False)
+ reset_device_password(self.dut, DEFAULT_DEVICE_PASSWORD)
+ self.dut.reboot(stop_at_lock_screen=True)
+ if self.fake_emergency_call_test():
+ return True
+ else:
+ return False
@test_tracker_info(uuid="1ef97f8a-eb3d-45b7-b947-ac409bb70587")
@TelephonyBaseTest.tel_test_wrap
@@ -167,8 +126,8 @@
"""Test emergency call with emergency dialer in screen lock phase.
Enable device password and then reboot upto password query window.
- Change system emergency number list to "611".
- Use the emergency dialer to call "611".
+ Add storyline number to system emergency number list.
+ Use the emergency dialer to call storyline.
Verify DUT has in call activity.
Returns:
@@ -177,8 +136,7 @@
"""
try:
toggle_airplane_mode_by_adb(self.log, self.dut, True)
- if not self.dut.device_password and getattr(self.dut, "droid"):
- self.dut.droid.setDevicePassword("1111")
+ reset_device_password(self.dut, DEFAULT_DEVICE_PASSWORD)
self.dut.reboot(stop_at_lock_screen=True)
if self.fake_emergency_call_test():
return True
@@ -186,12 +144,6 @@
return False
finally:
toggle_airplane_mode_by_adb(self.log, self.dut, False)
- if not self.dut.ensure_screen_on():
- self.dut.log.error("User screen cannot come up")
- return False
- self.dut.start_services(self.dut.skip_sl4a)
- if not self.dut.device_password:
- self.dut.droid.disableDevicePassword()
@test_tracker_info(uuid="50f8b3d9-b126-4419-b5e5-b37b850deb8e")
@TelephonyBaseTest.tel_test_wrap
@@ -199,8 +151,8 @@
"""Test emergency call with emergency dialer in setupwizard.
Wipe the device and then reboot upto setupwizard.
- Change system emergency number list to "611".
- Use the emergency dialer to call "611".
+ Add storyline number to system emergency number list.
+ Use the emergency dialer to call storyline.
Verify DUT has in call activity.
Returns:
@@ -208,16 +160,14 @@
False if failed.
"""
try:
- self.dut.fastboot_wipe()
+ if not fastboot_wipe(self.dut, skip_setup_wizard=False):
+ return False
if self.fake_emergency_call_test():
return True
else:
return False
finally:
- self.dut.ensure_screen_on()
self.dut.exit_setup_wizard()
- if self.dut.device_password:
- self.dut.droid.setDevicePassword(self.dut.device_password)
""" Tests End """
diff --git a/acts/tests/google/tel/live/TelLivePostflightTest.py b/acts/tests/google/tel/live/TelLivePostflightTest.py
index 85f4bcd..34b30ea 100644
--- a/acts/tests/google/tel/live/TelLivePostflightTest.py
+++ b/acts/tests/google/tel/live/TelLivePostflightTest.py
@@ -18,26 +18,48 @@
"""
import os
from acts import utils
+from acts.asserts import fail
+from acts.base_test import BaseTestClass
from acts.test_decorators import test_tracker_info
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts.asserts import fail
class TelLivePostflightTest(TelephonyBaseTest):
+ def __init__(self, controllers):
+ BaseTestClass.__init__(self, controllers)
+
+ def setup_class(self):
+ pass
+
+ def teardown_class(self):
+ pass
+
+ def setup_test(self):
+ pass
+
+ def on_pass(self, *arg):
+ pass
+
+ def on_fail(self, *arg):
+ pass
+
@test_tracker_info(uuid="ba6e260e-d2e1-4c01-9d51-ef2df1591039")
@TelephonyBaseTest.tel_test_wrap
def test_check_crash(self):
msg = ""
for ad in self.android_devices:
- post_crash = ad.check_crash_report(self.test_id, None, False)
+ post_crash = ad.check_crash_report(self.test_id)
pre_crash = getattr(ad, "crash_report_preflight", [])
crash_diff = list(set(post_crash).difference(set(pre_crash)))
if crash_diff:
- msg += "%s find new crash reports %s" % (ad.serial, crash_diff)
+ msg += "%s find new crash reports %s " % (ad.serial,
+ crash_diff)
ad.log.error("Find new crash reports %s", crash_diff)
- crash_path = os.path.join(ad.log_path, self.test_id, "Crashes")
+ crash_path = os.path.join(ad.log_path, self.test_name,
+ "Crashes")
utils.create_dir(crash_path)
ad.pull_files(crash_diff, crash_path)
+ self._ad_take_bugreport(ad, self.test_name, self.begin_time)
if msg:
fail(msg)
return True
@@ -50,15 +72,26 @@
tombstones = ad.get_file_names("/data/tombstones/")
if not tombstones: continue
for tombstone in tombstones:
- ts_path = os.path.join("/data/tombstones/", tombstone)
- if ad.adb.shell("cat %s | grep pid | grep dialer" % ts_path):
- message = "%s dialer crash: %s " % (ad.serial, ts_path)
+ if ad.adb.shell("cat %s | grep pid | grep dialer" % tombstone):
+ message = "%s dialer crash: %s " % (ad.serial, tombstone)
ad.log.error(message)
msg += message
- crash_path = os.path.join(ad.log_path, self.test_id,
+ crash_path = os.path.join(ad.log_path, self.test_name,
"Crashes")
utils.create_dir(crash_path)
- ad.pull_files([], crash_path)
+ ad.pull_files([tombstone], crash_path)
+ if msg:
+ fail(msg)
+ return True
+
+ @test_tracker_info(uuid="707d4a33-2e21-40ea-bd27-d15f4e3ff0f0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_check_data_accounting_failures(self):
+ msg = ""
+ for ad in self.android_devices:
+ ad.log.info("data_accounting_errors: %s", dict(ad.data_accounting))
+ if any(ad.data_accounting.values()):
+ msg += "%s %s" % (ad.serial, dict(ad.data_accounting))
if msg:
fail(msg)
return True
diff --git a/acts/tests/google/tel/live/TelLivePreflightTest.py b/acts/tests/google/tel/live/TelLivePreflightTest.py
index adb1379..916ef9b 100644
--- a/acts/tests/google/tel/live/TelLivePreflightTest.py
+++ b/acts/tests/google/tel/live/TelLivePreflightTest.py
@@ -20,6 +20,10 @@
import time
from queue import Empty
+from acts import signals
+from acts import utils
+from acts.controllers.android_device import get_info
+from acts.libs.ota import ota_updater
from acts.test_decorators import test_tracker_info
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.test_utils.tel.tel_defines import AOSP_PREFIX
@@ -42,10 +46,13 @@
from acts.test_utils.tel.tel_test_utils import ensure_phone_subscription
from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected
from acts.test_utils.tel.tel_test_utils import get_operator_name
+from acts.test_utils.tel.tel_test_utils import is_sim_locked
+from acts.test_utils.tel.tel_test_utils import run_multithread_func
from acts.test_utils.tel.tel_test_utils import setup_droid_properties
from acts.test_utils.tel.tel_test_utils import set_phone_screen_on
from acts.test_utils.tel.tel_test_utils import set_phone_silent_mode
-from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
+from acts.test_utils.tel.tel_test_utils import unlock_sim
from acts.test_utils.tel.tel_test_utils import verify_http_connection
from acts.test_utils.tel.tel_test_utils import wait_for_voice_attach_for_subscription
from acts.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
@@ -60,11 +67,19 @@
TelephonyBaseTest.__init__(self, controllers)
self.wifi_network_ssid = self.user_params.get(
- "wifi_network_ssid") or self.user_params.get("wifi_network_ssid_2g")
+ "wifi_network_ssid") or self.user_params.get(
+ "wifi_network_ssid_2g") or self.user_params.get(
+ "wifi_network_ssid_5g")
self.wifi_network_pass = self.user_params.get(
- "wifi_network_pass") or self.user_params.get("wifi_network_pass_2g")
+ "wifi_network_pass") or self.user_params.get(
+ "wifi_network_pass_2g") or self.user_params.get(
+ "wifi_network_ssid_5g")
def setup_class(self):
+ for ad in self.android_devices:
+ toggle_airplane_mode_by_adb(self.log, ad, False)
+
+ def teardown_class(self):
pass
def setup_test(self):
@@ -72,6 +87,48 @@
""" Tests Begin """
+ @test_tracker_info(uuid="cb897221-99e1-4697-927e-02d92d969440")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_ota_upgrade(self):
+ ota_package = self.user_params.get("ota_package")
+ if isinstance(ota_package, list):
+ ota_package = ota_package[0]
+ if ota_package and "dev/null" not in ota_package:
+ self.log.info("Upgrade with ota_package %s", ota_package)
+ self.log.info("Before OTA upgrade: %s",
+ get_info(self.android_devices))
+ else:
+ raise signals.TestSkip("No ota_package is defined")
+ ota_util = self.user_params.get("ota_util")
+ if isinstance(ota_util, list):
+ ota_util = ota_util[0]
+ if ota_util:
+ if "update_engine_client.zip" in ota_util:
+ self.user_params["UpdateDeviceOtaTool"] = ota_util
+ self.user_params["ota_tool"] = "UpdateDeviceOtaTool"
+ else:
+ self.user_params["AdbSideloadOtaTool"] = ota_util
+ self.user_params["ota_tool"] = "AdbSideloadOtaTool"
+ self.log.info("OTA upgrade with %s by %s", ota_package,
+ self.user_params["ota_tool"])
+ ota_updater.initialize(self.user_params, self.android_devices)
+ tasks = [(ota_updater.update, [ad]) for ad in self.android_devices]
+ try:
+ run_multithread_func(self.log, tasks)
+ except Exception as err:
+ abort_all_tests(self.log, "Unable to do ota upgrade: %s" % err)
+ device_info = get_info(self.android_devices)
+ self.log.info("After OTA upgrade: %s", device_info)
+ self.results.add_controller_info("AndroidDevice", device_info)
+ for ad in self.android_devices:
+ if is_sim_locked(ad):
+ ad.log.info("After OTA, SIM keeps the locked state")
+ elif getattr(ad, "is_sim_locked", False):
+ ad.log.error("After OTA, SIM loses the locked state")
+ if not unlock_sim(ad):
+ abort_all_tests(ad.log, "unable to unlock SIM")
+ return True
+
@test_tracker_info(uuid="8390a2eb-a744-4cda-bade-f94a2cc83f02")
@TelephonyBaseTest.tel_test_wrap
def test_check_environment(self):
@@ -104,11 +161,19 @@
@test_tracker_info(uuid="1070b160-902b-43bf-92a0-92cc2d05bb13")
@TelephonyBaseTest.tel_test_wrap
def test_check_crash(self):
+ result = True
+ begin_time = None
for ad in self.android_devices:
+ output = ad.adb.shell("cat /proc/uptime")
+ epoch_up_time = utils.get_current_epoch_time() - 1000 * float(
+ output.split(" ")[0])
ad.crash_report_preflight = ad.check_crash_report(
- self.test_id, None, True)
+ self.test_name,
+ begin_time=epoch_up_time,
+ log_crash_report=True)
if ad.crash_report_preflight:
msg = "Find crash reports %s before test starts" % (
ad.crash_report_preflight)
ad.log.warn(msg)
- return True
+ result = False
+ return result
diff --git a/acts/tests/google/tel/live/TelLiveProjectFiTest.py b/acts/tests/google/tel/live/TelLiveProjectFiTest.py
new file mode 100644
index 0000000..4b4873f
--- /dev/null
+++ b/acts/tests/google/tel/live/TelLiveProjectFiTest.py
@@ -0,0 +1,579 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2017 - Google
+#
+# 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 for Project Fi Setting
+"""
+
+import time
+
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts.test_utils.tel.tel_defines import CARRIER_SPT
+from acts.test_utils.tel.tel_defines import CARRIER_TMO
+from acts.test_utils.tel.tel_defines import CARRIER_USCC
+from acts.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id
+from acts.test_utils.tel.tel_test_utils import abort_all_tests
+from acts.test_utils.tel.tel_test_utils import ensure_phone_subscription
+from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected
+from acts.test_utils.tel.tel_test_utils import is_sim_ready
+from acts.test_utils.tel.tel_test_utils import log_screen_shot
+from acts.test_utils.tel.tel_test_utils import multithread_func
+from acts.test_utils.tel.tel_test_utils import refresh_droid_config
+from acts.test_utils.tel.tel_test_utils import send_dialer_secret_code
+from acts.test_utils.tel.tel_test_utils import wait_for_state
+
+CARRIER_AUTO = "auto"
+
+_CARRIER_DIALER_CODE_LOOKUP = {
+ CARRIER_AUTO: '342886',
+ CARRIER_SPT: '34777',
+ CARRIER_TMO: '34866',
+ CARRIER_USCC: '34872'
+}
+
+_SWITCHING_PREF_FILE = (
+ '/data/data/com.google.android.apps.tycho/shared_prefs/switching.xml')
+
+_INTENT_FLAGS = int(0x00008000 | 0x10000000 | 0x00080000 | 0x00020000)
+_TYCHO_PKG = 'com.google.android.apps.tycho'
+_MAX_WAIT_TIME = 600
+
+
+class TychoClassId(object):
+ """Tycho Activity/Service Classnames."""
+ # Activities
+ CARRIER_SETUP = 'CarrierSetupEntryPointTrampoline'
+ INIT_ACTIVITY = 'InitActivity'
+ # Services
+ SYNC_SERVICE = 'services.SyncService'
+ ACTIVATE_SUPER_NETWORK_SERVICE = 'services.SuperNetworkConfigurationService'
+
+
+class ActionTypeId(object):
+ """Andorid Action Type to trigger events."""
+ MAIN = 'android.intent.action.MAIN'
+ MASTER_CLEAR_NOTIFICATION = 'android.intent.action.MASTER_CLEAR_NOTIFICATION'
+ TYCHO_ACTIVATE_SUPER_NETWORK = (
+ 'com.google.android.apps.tycho.ActionType.ACTIVATE_SUPER_NETWORK')
+
+
+class TelLiveProjectFiTest(TelephonyBaseTest):
+ def setup_class(self):
+ self.wifi_network_ssid = self.user_params.get(
+ "wifi_network_ssid") or self.user_params.get(
+ "wifi_network_ssid_2g") or self.user_params.get(
+ "wifi_network_ssid_5g")
+ self.wifi_network_pass = self.user_params.get(
+ "wifi_network_pass") or self.user_params.get(
+ "wifi_network_pass_2g") or self.user_params.get(
+ "wifi_network_ssid_5g")
+
+ def _add_google_account(self, ad, retries=3):
+ for _ in range(3):
+ ad.ensure_screen_on()
+ output = ad.adb.shell(
+ 'am instrument -w -e account "%s@gmail.com" -e password '
+ '"%s" -e sync true -e wait-for-checkin false '
+ 'com.google.android.tradefed.account/.AddAccount' %
+ (ad.user_account, ad.user_password))
+ if "result=SUCCESS" in output:
+ ad.log.info("google account is added successfully")
+ return True
+ ad.log.error("Fail to add google account due to %s", output)
+ return False
+
+ def _remove_google_account(self, ad, retries=3):
+ if not ad.is_apk_installed("com.google.android.tradefed.account"
+ ) and self.user_params.get("account_util"):
+ account_util = self.user_params["account_util"]
+ if isinstance(account_util, list):
+ account_util = account_util[0]
+ ad.log.info("Install account_util %s", account_util)
+ ad.ensure_screen_on()
+ ad.adb.install("-r %s" % account_util, timeout=180)
+ if not ad.is_apk_installed("com.google.android.tradefed.account"):
+ ad.log.error(
+ "com.google.android.tradefed.account is not installed")
+ return False
+ for _ in range(3):
+ ad.ensure_screen_on()
+ output = ad.adb.shell(
+ 'am instrument -w '
+ 'com.google.android.tradefed.account/.RemoveAccounts')
+ if "result=SUCCESS" in output:
+ ad.log.info("google account is removed successfully")
+ return True
+ ad.log.error("Fail to remove google account due to %s", output)
+ return False
+
+ def _install_account_util(self, ad):
+ account_util = self.user_params["account_util"]
+ if isinstance(account_util, list):
+ account_util = account_util[0]
+ ad.log.info("Install account_util %s", account_util)
+ ad.ensure_screen_on()
+ ad.adb.install("-r %s" % account_util, timeout=180)
+ time.sleep(3)
+ if not ad.is_apk_installed("com.google.android.tradefed.account"):
+ ad.log.info("com.google.android.tradefed.account is not installed")
+ return False
+ return True
+
+ def _account_registration(self, ad):
+ if hasattr(ad, "user_account"):
+ ad.exit_setup_wizard()
+ if not ad.is_apk_installed("com.google.android.tradefed.account"
+ ) and self.user_params.get(
+ "account_util"):
+ for _ in range(2):
+ if self._install_account_util(ad):
+ break
+ else:
+ ad.log.error(
+ "Fail to install com.google.android.tradefed.account")
+ return False
+ ad.force_stop_apk(_TYCHO_PKG)
+ if not ensure_wifi_connected(self.log, ad, self.wifi_network_ssid,
+ self.wifi_network_pass):
+ ad.log.error("Failed to connect to wifi")
+ return False
+ ad.log.info("Add google account")
+ if not self._add_google_account(ad):
+ ad.log.error("Failed to add google account")
+ return False
+ ad.adb.shell(
+ 'am instrument -w -e account "%s@gmail.com" -e password '
+ '"%s" -e sync true -e wait-for-checkin false '
+ 'com.google.android.tradefed.account/.AddAccount' %
+ (ad.user_account, ad.user_password))
+ ad.log.info("Enable and activate tycho apk")
+ ad.adb.shell('pm enable %s' % _TYCHO_PKG)
+ self.activate_fi_account(ad)
+ if not self.check_project_fi_activated(ad):
+ ad.log.error("Fail to activate Fi account")
+ return False
+ elif "Fi Network" in ad.adb.getprop("gsm.sim.operator.alpha"):
+ ad.log.error("Google account is not provided for Fi Network")
+ return False
+ if not ensure_phone_subscription(self.log, ad):
+ ad.log.error("Unable to find a valid subscription!")
+ return False
+ refresh_droid_config(self.log, ad)
+ return True
+
+ def start_service(self, ad, package, service_id, extras, action_type):
+ """Starts the specified service.
+
+ Args:
+ ad: (android_device.AndroidDevice) device to start activity on
+ package: (str) the package to start the service from
+ service_id: (str) service to start
+ extras: (dict) extras needed to specify with the activity id
+ action_type: The action type id to create the intent
+ """
+ ad.log.info('Starting service %s/.%s.', package, service_id)
+ intent = ad.droid.makeIntent(action_type, None, None, extras, [
+ 'android.intent.category.DEFAULT'
+ ], package, package + '.' + service_id, _INTENT_FLAGS)
+ ad.droid.startServiceIntent(intent)
+
+ def start_activity(self, ad, package, activity_id, extras=None):
+ """Starts the specified activity.
+
+ Args:
+ ad: (android_device.AndroidDevice) device to start activity on
+ package: (str) the package to start
+ activity_id: (str) activity to start
+ extras: (dict) extras needed to specify with the activity id
+ """
+ ad.log.info('Starting activity %s/.%s.', package, activity_id)
+ intent = ad.droid.makeIntent(ActionTypeId.MAIN, None, None, extras, [
+ 'android.intent.category.LAUNCHER'
+ ], package, package + '.' + activity_id, _INTENT_FLAGS)
+ ad.droid.startActivityIntent(intent, False)
+
+ def activate_fi_account(self, ad):
+ """Start Tycho InitActivity.
+
+ For in-app Tycho activition (post-SUW tests), Tycho does not
+ automatically trigger OMADM process. This method is used to start
+ Tycho InitActivity before launching super network activation.
+
+ The device will finally stay on Sprint network if everything goes well.
+
+ Args:
+ ad: Android device need to start Tycho InitActivity.
+ """
+ extra = {'in_setup_wizard': False, 'force_show_account_chooser': False}
+ self.start_activity(ad, _TYCHO_PKG, TychoClassId.INIT_ACTIVITY, extra)
+ for _ in range(30):
+ ad.send_keycode("WAKEUP")
+ time.sleep(1)
+ current_window = ad.get_my_current_focus_window()
+ log_screen_shot(ad, self.test_name)
+ if 'SwitchConfirmDialogActivity' in current_window:
+ ad.log.info("In Switch Confirmation Dialog")
+ if ad.adb.getprop("ro.build.version.release")[0] not in ("8", "O"):
+ ad.send_keycode("TAB")
+ ad.send_keycode("TAB")
+ ad.send_keycode("ENTER")
+ time.sleep(10)
+ elif 'tycho.InitActivity' in current_window:
+ ad.log.info("In Tycho InitActivity")
+ ad.send_keycode("TAB")
+ ad.send_keycode("TAB")
+ ad.send_keycode("ENTER")
+ time.sleep(10)
+
+ elif 'tycho.AccountChooserActivity' in current_window:
+ ad.send_keycode("ENTER")
+ else:
+ ad.log.info("Finished activation process")
+ return
+
+ def check_project_fi_activated(self, ad):
+ for _ in range(20):
+ if is_sim_ready(self.log, ad) and (
+ ad.droid.telephonyGetSimOperatorName() == "Fi Network"):
+ ad.log.info("SIM state is READY, SIM operator is Fi")
+ return True
+ time.sleep(5)
+
+ def start_tycho_activation(self, ad):
+ """Start the Tycho client and register to cellular network.
+
+ Starts Tycho within SUW:
+ - Tycho is expected to follow the in-SUW work flow:
+ - Tycho will perform TychoInit, handshake to server,
+ account configuration, etc
+ - If successful, Tycho will trigger a switch to Sprint Network
+ - If successful, Tycho will start OMA-DM activation sessions
+
+ The device will finally stay on Sprint network if everything goes well.
+
+ Args:
+ ad: Android device need to start Tycho activation.
+ """
+ extra = {'device_setup': True, 'has_account': True}
+ self.start_activity(ad, _TYCHO_PKG, TychoClassId.CARRIER_SETUP, extra)
+
+ def start_super_network_activation(self, ad):
+ """Start the Super-Network activation.
+
+ For in-app Tycho activition (post-SUW tests), this method starts
+ super-network activation after Tycho is initialized.
+
+ The device will finally stay on Sprint network if everything goes well.
+
+ Args:
+ ad: Android device need to start Tycho super network activation.
+ """
+ extra = {'in_setup_wizard': False, 'is_interactive': True}
+ self.start_service(ad, _TYCHO_PKG,
+ TychoClassId.ACTIVATE_SUPER_NETWORK_SERVICE, extra,
+ ActionTypeId.TYCHO_ACTIVATE_SUPER_NETWORK)
+
+ def get_active_carrier(self, ad):
+ """Gets the active carrier profile value from the device.
+
+ Args:
+ ad: An AndroidDevice Object.
+
+ Returns:
+ (string) A key from the CARRIER_TO_MCC_MNC map representing the
+ active carrier.
+
+ Raises:
+ KeyError: when an mcc_mnc code reported by the device is not a
+ recognized Fi partner carrier.
+ """
+ mcc_mnc = ad.droid.telephonyGetSimOperator()
+ if not mcc_mnc:
+ return "UNKNOWN"
+ try:
+ return operator_name_from_plmn_id(mcc_mnc)
+ except KeyError:
+ ad.log.error('Unknown Mobile Country Code/Mobile Network Code %s',
+ mcc_mnc)
+ raise
+
+ def switch_sim(self, ad):
+ """Requests switch between physical sim and esim.
+
+ Args:
+ ad: An AndroidDevice Object.
+ timeout: (optional -- integer) the number of seconds in which a
+ switch should be completed.
+
+ Raises:
+ Error: whenever a device is not set to the desired carrier within
+ the timeout window.
+ """
+ old_sim_operator = ad.droid.telephonyGetSimOperatorName()
+ ad.log.info("Before SIM switch, SIM operator = %s", old_sim_operator)
+ send_dialer_secret_code(ad, "794824746")
+ time.sleep(10)
+ new_sim_operator = ad.droid.telephonyGetSimOperatorName()
+ ad.log.info("After SIM switch, SIM operator = %s", new_sim_operator)
+ refresh_droid_config(self.log, ad)
+ return old_sim_operator != new_sim_operator
+
+ def set_active_carrier(self,
+ ad,
+ carrier,
+ timeout=_MAX_WAIT_TIME,
+ check_interval=10):
+ """Requests an active carrier to be set on the device sim.
+
+ If switching to a different carrier, after the switch is completed
+ auto-switching will be disabled. To re-enable, call enable_auto_switching.
+
+ Args:
+ ad: An AndroidDevice Object.
+ carrier: (carrier_constants.Carrier) Which carrier to switch to.
+ timeout: (optional -- integer) the number of seconds in which a
+ switch should be completed.
+
+ Raises:
+ Error: whenever a device is not set to the desired carrier within
+ the timeout window.
+ """
+ # If there's no need to switch, then don't.
+ max_time = timeout
+ while max_time >= 0:
+ if self.is_ready_to_make_carrier_switch(ad):
+ break
+ time.sleep(check_interval)
+ max_time -= check_interval
+ else:
+ ad.log.error("Device stays in carrier switch lock state")
+ return False
+ if carrier == CARRIER_AUTO:
+ send_dialer_secret_code(ad, _CARRIER_DIALER_CODE_LOOKUP[carrier])
+ return True
+ old_carrier = self.get_active_carrier(ad)
+ if carrier == old_carrier:
+ ad.log.info('Already on %s, so no need to switch', carrier)
+ return True
+
+ # Start switch on device, using events to verify that the switch starts.
+ ad.log.info('Initiating unsolicited switch from %s to %s.',
+ old_carrier, carrier)
+ send_dialer_secret_code(ad, _CARRIER_DIALER_CODE_LOOKUP[carrier])
+ return self.wait_for_carrier_switch_completed(
+ ad, carrier, timeout=timeout, check_interval=check_interval)
+
+ def is_switching_silent(self, ad):
+ """Checks if Tycho switching controller is in silent mode.
+
+ Note that silent mode is a sign of airplane mode, not of a switching lock.
+
+ Args: ad: An AndroidDevice Object.
+
+ Returns:
+ A Boolean True if the preferences file reports True, False otherwise.
+ """
+ return "isInSilentMode\" value=\"true" in ad.adb.shell(
+ "cat %s | grep isInSilentMode" % _SWITCHING_PREF_FILE,
+ ignore_status=True)
+
+ def is_switching_locked(self, ad):
+ """Checks if Tycho switching controller is locked.
+
+ Args: ad: An AndroidDevice Object.
+
+ Returns:
+ A Boolean True if the switching controller is locked for any reason,
+ False otherwise.
+ """
+ return "switchingInProgress\" value=\"true" in ad.adb.shell(
+ "cat %s | grep switchingInProgress" % _SWITCHING_PREF_FILE)
+
+ def is_ready_to_make_carrier_switch(self, ad):
+ """Checks if device is ready to make carrier switch.
+
+ Args:
+ ad: An AndroidDevice Object.
+
+ Returns:
+ A Boolean True if it is ready to make switch, False otherwise.
+ """
+ # Check Tycho switching controller states.
+ if self.is_switching_silent(ad):
+ ad.log.info(
+ "Cannot make carrier switch: SwitchingController is in silent "
+ "mode!")
+ return False
+ if self.is_switching_locked(ad):
+ ad.log.info(
+ "Cannot make carrier switch: SwitchingController is locked!")
+ return False
+ if self.is_carrier_switch_in_progress(ad):
+ ad.log.info("Cannot make carrier switch: Switch in progress!")
+ return False
+ return True
+
+ def is_carrier_switch_in_progress(self, ad):
+ """Checks if Tycho says that a switch is currently in progress.
+
+ Args:
+ ad: An AndroidDevice Object.
+
+ Returns:
+ A Boolean True if the preferences file reports True, False otherwise.
+ """
+ switching_preferences = ad.adb.shell("cat %s" % _SWITCHING_PREF_FILE)
+ return 'InProgress\" value=\"true' in switching_preferences
+
+ def check_network_carrier(self, ad, carrier):
+ current_carrier = self.get_active_carrier(ad)
+ ad.log.info("Current network carrier is %s", current_carrier)
+ is_in_switch = self.is_carrier_switch_in_progress(ad)
+ ad.log.info("Device in carrier switch progress mode")
+ return current_carrier == carrier and is_in_switch
+
+ def wait_for_carrier_switch_completed(self,
+ ad,
+ carrier,
+ timeout=_MAX_WAIT_TIME,
+ check_interval=10):
+ """Wait for carrier switch to complete.
+
+ This function waits for a carrier switch to complete by monitoring the
+ Tycho switching controller preference file.
+
+ Args:
+ ad: An Android device object.
+ carrier: The target carrier network to switch to.
+ timeout: (integer) Time wait for switch to complete.
+
+ Return:
+ True or False for successful/unsuccessful switch.
+ """
+ check_args = [ad, carrier]
+ if wait_for_state(self.check_network_carrier, True, check_interval,
+ timeout, *check_args):
+ ad.log.info("Switched to %s successfully", carrier)
+ ad.send_keycode("ENTER")
+ return True
+ else:
+ ad.log.error("Carrier is %s. Fail to switch to %s",
+ self.get_active_carrier(ad), carrier)
+ return False
+
+ def operator_network_switch(self, ad, carrier):
+ if ad.droid.telephonyGetSimOperatorName() == "Fi Network":
+ for i in range(3):
+ if self.set_active_carrier(ad, carrier):
+ break
+ elif i == 2:
+ ad.log.error("Failed to switch to %s", carrier)
+ return False
+ if not ensure_phone_subscription(self.log, ad):
+ ad.log.error("Unable to find a valid subscription!")
+ return False
+ refresh_droid_config(self.log, ad)
+ return True
+
+ def network_switch_test(self, carrier):
+ tasks = [(self.operator_network_switch, [ad, carrier])
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ abort_all_tests(self.log,
+ "Unable to switch to network %s" % carrier)
+ return True
+
+ """ Tests Begin """
+
+ @test_tracker_info(uuid="4d92318e-4980-471a-882b-3136c5dda384")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_project_fi_account_activation(self):
+ """Test activate Fi account.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ tasks = [(self._account_registration, [ad])
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ abort_all_tests(self.log, "Unable to activate Fi account!")
+ return True
+
+ @test_tracker_info(uuid="6bfbcc1d-e318-4964-bf36-5b82f086860d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_switch_to_tmobile_network(self):
+ """Test switch to tmobile network.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return self.network_switch_test(CARRIER_TMO)
+
+ @test_tracker_info(uuid="4f27944d-f3c5-423d-b0c5-5c66dbb98376")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_switch_to_sprint_network(self):
+ """Test switch to tmobile network.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return self.network_switch_test(CARRIER_SPT)
+
+ @test_tracker_info(uuid="5f30c9bd-b79e-4805-aa46-7855ed9023f0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_switch_to_uscc_network(self):
+ """Test switch to tmobile network.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return self.network_switch_test(CARRIER_USCC)
+
+ @test_tracker_info(uuid="0b062751-d59d-420e-941e-3ffa02aea0d5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_switch_to_auto_network(self):
+ """Test switch to auto network selection.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return self.network_switch_test(CARRIER_AUTO)
+
+ @test_tracker_info(uuid="13c5f080-69bf-42fd-86ed-c67b1984c347")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_switch_between_sim(self):
+ """Test switch between physical sim and esim.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ for ad in self.android_devices:
+ self.switch_sim(ad)
+
+ @test_tracker_info(uuid="")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_remove_google_account(self):
+ for ad in self.android_devices:
+ self._remove_google_account(ad)
+
+
+""" Tests End """
diff --git a/acts/tests/google/tel/live/TelLiveRebootStressTest.py b/acts/tests/google/tel/live/TelLiveRebootStressTest.py
index bcdbe66..4e8dd4e 100644
--- a/acts/tests/google/tel/live/TelLiveRebootStressTest.py
+++ b/acts/tests/google/tel/live/TelLiveRebootStressTest.py
@@ -19,67 +19,59 @@
import collections
import time
+
+from acts import signals
from acts.test_decorators import test_tracker_info
from acts.controllers.sl4a_lib.sl4a_types import Sl4aNetworkInfo
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.test_utils.tel.tel_data_utils import wifi_tethering_setup_teardown
-from acts.test_utils.tel.tel_defines import AOSP_PREFIX
from acts.test_utils.tel.tel_defines import CAPABILITY_VOLTE
from acts.test_utils.tel.tel_defines import CAPABILITY_VT
from acts.test_utils.tel.tel_defines import CAPABILITY_WFC
from acts.test_utils.tel.tel_defines import CAPABILITY_OMADM
-from acts.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_PROVISIONING
from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK
from acts.test_utils.tel.tel_defines import TETHERING_MODE_WIFI
from acts.test_utils.tel.tel_defines import WAIT_TIME_AFTER_REBOOT
from acts.test_utils.tel.tel_defines import WAIT_TIME_AFTER_CRASH
-from acts.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
-from acts.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
-from acts.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL_FOR_IMS
-from acts.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
-from acts.test_utils.tel.tel_defines import WFC_MODE_DISABLED
-from acts.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
from acts.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
-from acts.test_utils.tel.tel_subscription_utils import \
- get_incoming_voice_sub_id
-from acts.test_utils.tel.tel_subscription_utils import \
- get_outgoing_voice_sub_id
from acts.test_utils.tel.tel_lookup_tables import device_capabilities
from acts.test_utils.tel.tel_lookup_tables import operator_capabilities
from acts.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected
+from acts.test_utils.tel.tel_test_utils import ensure_phone_subscription
from acts.test_utils.tel.tel_test_utils import get_model_name
from acts.test_utils.tel.tel_test_utils import get_operator_name
-from acts.test_utils.tel.tel_test_utils import multithread_func
+from acts.test_utils.tel.tel_test_utils import get_outgoing_voice_sub_id
+from acts.test_utils.tel.tel_test_utils import get_slot_index_from_subid
+from acts.test_utils.tel.tel_test_utils import is_sim_locked
+from acts.test_utils.tel.tel_test_utils import power_off_sim
+from acts.test_utils.tel.tel_test_utils import power_on_sim
+from acts.test_utils.tel.tel_test_utils import reboot_device
from acts.test_utils.tel.tel_test_utils import sms_send_receive_verify
+from acts.test_utils.tel.tel_test_utils import mms_send_receive_verify
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
from acts.test_utils.tel.tel_test_utils import verify_http_connection
+from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
from acts.test_utils.tel.tel_test_utils import trigger_modem_crash
-from acts.test_utils.tel.tel_test_utils import initiate_call
-from acts.test_utils.tel.tel_test_utils import wait_and_answer_call
+from acts.test_utils.tel.tel_test_utils import trigger_modem_crash_by_modem
+from acts.test_utils.tel.tel_test_utils import unlock_sim
+from acts.test_utils.tel.tel_test_utils import wait_for_state
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
-from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
from acts.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
from acts.test_utils.tel.tel_voice_utils import phone_setup_csfb
from acts.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts.test_utils.tel.tel_voice_utils import \
- phone_setup_iwlan_cellular_preferred
from acts.test_utils.tel.tel_voice_utils import phone_setup_voice_general
from acts.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts.test_utils.tel.tel_voice_utils import phone_idle_3g
-from acts.test_utils.tel.tel_voice_utils import phone_idle_csfb
-from acts.test_utils.tel.tel_voice_utils import phone_idle_iwlan
-from acts.test_utils.tel.tel_voice_utils import phone_idle_volte
from acts.test_utils.tel.tel_video_utils import video_call_setup_teardown
from acts.test_utils.tel.tel_video_utils import phone_setup_video
from acts.test_utils.tel.tel_video_utils import \
is_phone_in_call_video_bidirectional
+from acts.utils import get_current_epoch_time
from acts.utils import rand_ascii_str
@@ -100,38 +92,100 @@
self.android_devices) > 1 else None
self.dut_model = get_model_name(self.dut)
self.dut_operator = get_operator_name(self.log, self.dut)
+ self.dut_capabilities = set(
+ device_capabilities.get(
+ self.dut_model, device_capabilities["default"])) & set(
+ operator_capabilities.get(
+ self.dut_operator, operator_capabilities["default"]))
+ self.user_params["check_crash"] = False
+ self.skip_reset_between_cases = False
- def _check_provisioning(self):
- if (CAPABILITY_OMADM in device_capabilities[self.dut_model] and
- CAPABILITY_OMADM in operator_capabilities[self.dut_operator]):
- self.log.info("Check Provisioning bit")
- if not self.dut.droid.imsIsVolteProvisionedOnDevice():
- self.log.error("{}: VoLTE Not Provisioned on the Platform".
- format(self.dut.serial))
- return False
- return True
+ def setup_class(self):
+ TelephonyBaseTest.setup_class(self)
+ methods = [("check_subscription",
+ self._check_subscription), ("check_data",
+ self._check_data),
+ ("check_call_setup_teardown",
+ self._check_call_setup_teardown), ("check_sms",
+ self._check_sms),
+ ("check_mms", self._check_mms), ("check_lte_data",
+ self._check_lte_data),
+ ("check_volte",
+ self._check_volte), ("check_vt",
+ self._check_vt), ("check_wfc",
+ self._check_wfc),
+ ("check_3g", self._check_3g), ("check_tethering",
+ self._check_tethering)]
+ self.testing_methods = []
+ for name, func in methods:
+ check_result = func()
+ self.dut.log.info("%s is %s before tests start", name,
+ check_result)
+ if check_result:
+ self.testing_methods.append((name, func))
+ self.log.info("Working features: %s", self.testing_methods)
+
+ def feature_validator(self, **kwargs):
+ failed_tests = []
+ for name, func in self.testing_methods:
+ if kwargs.get(name, True):
+ if not func():
+ self.log.error("%s failed", name)
+ failed_tests.append(name)
+ else:
+ self.log.info("%s succeeded", name)
+ if failed_tests:
+ self.log.error("%s failed", failed_tests)
+ return failed_tests
+
+ def _check_subscription(self):
+ if not ensure_phone_subscription(self.log, self.dut):
+ self.dut.log.error("Subscription check failed")
+ return False
+ else:
+ return True
def _check_provision(self):
- elapsed_time = 0
- while (elapsed_time < MAX_WAIT_TIME_PROVISIONING):
- if self._check_provisioning():
- return True
+ if CAPABILITY_OMADM in self.dut_capabilities:
+ if not wait_for_state(self.dut.droid.imsIsVolteProvisionedOnDevice,
+ True):
+ self.log.error("VoLTE provisioning check fails.")
+ return False
else:
- time.sleep(CHECK_INTERVAL)
- elapsed_time += CHECK_INTERVAL
- self.log.error("Provisioning fail.")
+ return True
return False
def _clear_provisioning(self):
- if (CAPABILITY_OMADM in device_capabilities[self.dut_model] and
- CAPABILITY_OMADM in operator_capabilities[self.dut_operator]):
+ if CAPABILITY_OMADM in self.dut_capabilities:
self.log.info("Clear Provisioning bit")
self.dut.droid.imsSetVolteProvisioning(False)
return True
def _check_call_setup_teardown(self):
- if not call_setup_teardown(self.log, self.dut, self.ad_reference):
- self.log.error("Phone Call Failed.")
+ if not call_setup_teardown(self.log, self.dut, self.ad_reference,
+ self.dut):
+ self.log.error("Phone call test failed.")
+ return False
+ return True
+
+ def _check_sms(self):
+ if not sms_send_receive_verify(self.log, self.dut, self.ad_reference,
+ [rand_ascii_str(180)]):
+ self.log.error("SMS test failed")
+ return False
+ return True
+
+ def _check_mms(self):
+ message_array = [("Test Message", rand_ascii_str(180), None)]
+ if not mms_send_receive_verify(self.log, self.dut, self.ad_reference,
+ message_array):
+ self.log.error("MMS test failed")
+ return False
+ return True
+
+ def _check_data(self):
+ if not verify_http_connection(self.log, self.dut):
+ self.log.error("Data connection is not available.")
return False
return True
@@ -153,7 +207,7 @@
return True
def _check_volte(self):
- if (CAPABILITY_VOLTE in operator_capabilities[self.dut_operator]):
+ if CAPABILITY_VOLTE in self.dut_capabilities:
self.log.info("Check VoLTE")
if not phone_setup_volte(self.log, self.dut):
self.log.error("Failed to setup VoLTE.")
@@ -171,10 +225,10 @@
return True
def _check_vt(self):
- if (CAPABILITY_VT in operator_capabilities[self.dut_operator]):
+ if CAPABILITY_VT in self.dut_capabilities:
self.log.info("Check VT")
if not phone_setup_video(self.log, self.dut):
- self.log.error("Failed to setup VT.")
+ self.dut.log.error("Failed to setup VT.")
return False
time.sleep(5)
if not video_call_setup_teardown(
@@ -190,7 +244,7 @@
return True
def _check_wfc(self):
- if (CAPABILITY_WFC in operator_capabilities[self.dut_operator]):
+ if CAPABILITY_WFC in self.dut_capabilities:
self.log.info("Check WFC")
if not phone_setup_iwlan(
self.log, self.dut, True, WFC_MODE_WIFI_PREFERRED,
@@ -228,17 +282,25 @@
def _check_tethering(self):
self.log.info("Check tethering")
- if not self.dut.droid.carrierConfigIsTetheringModeAllowed(
- TETHERING_MODE_WIFI,
- MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK):
- self.log.error("Tethering Entitlement check failed.")
- return False
+ for i in range(3):
+ try:
+ if not self.dut.droid.carrierConfigIsTetheringModeAllowed(
+ TETHERING_MODE_WIFI,
+ MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK):
+ self.log.error("Tethering Entitlement check failed.")
+ if i == 2: return False
+ time.sleep(10)
+ except Exception as e:
+ if i == 2:
+ self.dut.log.error(e)
+ return False
+ time.sleep(10)
if not wifi_tethering_setup_teardown(
self.log,
self.dut, [self.ad_reference],
check_interval=5,
check_iteration=1):
- self.log.error("Tethering Failed.")
+ self.log.error("Tethering check failed.")
return False
return True
@@ -266,7 +328,7 @@
return False
return True
- def _telephony_monitor_test(self):
+ def _telephony_monitor_test(self, negative_test=False):
"""
Steps -
1. Reboot the phone
@@ -284,57 +346,110 @@
Returns:
True is pass, False if fail.
"""
- # Reboot
+ self.number_of_devices = 2
ads = self.android_devices
+ # Ensure apk is running/not running
+ monitor_apk = None
+ for apk in ("com.google.telephonymonitor",
+ "com.google.android.connectivitymonitor"):
+ if ads[0].is_apk_installed(apk):
+ ads[0].log.info("apk %s is installed", apk)
+ monitor_apk = apk
+ break
+ if not monitor_apk:
+ ads[0].log.info(
+ "ConnectivityMonitor|TelephonyMonitor is not installed")
+ return False
+
ads[0].adb.shell(
"am start -n com.android.settings/.DevelopmentSettings",
ignore_status=True)
- ads[0].log.info("reboot!")
- ads[0].reboot()
- ads[0].log.info("wait %d secs for radio up." % WAIT_TIME_AFTER_REBOOT)
- time.sleep(WAIT_TIME_AFTER_REBOOT)
+ cmd = "setprop persist.radio.enable_tel_mon user_enabled"
+ ads[0].log.info(cmd)
+ ads[0].adb.shell(cmd)
- # Ensure apk is running
- if not ads[0].is_apk_running("com.google.telephonymonitor"):
- ads[0].log.info("TelephonyMonitor is not running, start it now")
- ads[0].adb.shell(
- 'am broadcast -a '
- 'com.google.gservices.intent.action.GSERVICES_OVERRIDE -e '
- '"ce.telephony_monitor_enable" "true"')
+ if not ads[0].is_apk_running(monitor_apk):
+ ads[0].log.info("%s is not running", monitor_apk)
+ # Reboot
+ ads = self.android_devices
+ ads[0].log.info("reboot to bring up %s", monitor_apk)
+ reboot_device(ads[0])
+ for i in range(30):
+ if ads[0].is_apk_running(monitor_apk):
+ ads[0].log.info("%s is running after reboot", monitor_apk)
+ break
+ elif i == 19:
+ ads[0].log.error("%s is not running after reboot",
+ monitor_apk)
+ return False
+ else:
+ ads[0].log.info(
+ "%s is not running after reboot. Wait and check again",
+ monitor_apk)
+ time.sleep(30)
- # Setup Phone Call
- caller_number = ads[0].cfg['subscription'][get_outgoing_voice_sub_id(
- ads[0])]['phone_num']
- callee_number = ads[1].cfg['subscription'][get_incoming_voice_sub_id(
- ads[1])]['phone_num']
- tasks = [(phone_setup_voice_general, (self.log, ads[0])),
- (phone_setup_voice_general, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
+ ads[0].adb.shell(
+ "am start -n com.android.settings/.DevelopmentSettings",
+ ignore_status=True)
+ monitor_setting = ads[0].adb.getprop("persist.radio.enable_tel_mon")
+ ads[0].log.info("radio.enable_tel_mon setting is %s", monitor_setting)
+ expected_monitor_setting = "disabled" if negative_test else "user_enabled"
+ cmd = "setprop persist.radio.enable_tel_mon %s" % (
+ expected_monitor_setting)
+ if monitor_setting != expected_monitor_setting:
+ ads[0].log.info(cmd)
+ ads[0].adb.shell(cmd)
- if not initiate_call(ads[0].log, ads[0], callee_number):
- ads[0].log.error("Phone was unable to initate a call")
- return False
- if not wait_and_answer_call(self.log, ads[1], caller_number):
- ads[0].log.error("wait_and_answer_call failed")
+ if not call_setup_teardown(
+ self.log, ads[0], ads[1], ad_hangup=None,
+ wait_time_in_call=10):
+ self.log.error("Call setup failed")
return False
# Modem SSR
time.sleep(5)
- ads[1].log.info("Triggering ModemSSR")
- ads[1].adb.shell(
- "echo restart > /sys/kernel/debug/msm_subsys/modem",
- ignore_status=True)
- time.sleep(60)
-
- # Parse logcat for UI notification
- if ads[0].search_logcat("Bugreport notification title Call Drop:"):
- ads[0].log.info("User got the Call Drop Notification")
+ ads[0].log.info("Triggering ModemSSR")
+ if (not ads[0].is_apk_installed("com.google.mdstest")
+ ) or ads[0].adb.getprop("ro.build.version.release")[0] in (
+ "8", "O", "7", "N") or self.dut.model in ("angler", "bullhead",
+ "sailfish",
+ "marlin"):
+ trigger_modem_crash(self.dut)
else:
- ads[0].log.error("User didn't get Call Drop Notification in 1 min")
- return False
- return True
+ trigger_modem_crash_by_modem(self.dut)
+
+ try:
+ if ads[0].droid.telecomIsInCall():
+ ads[0].log.info("Still in call after call drop trigger event")
+ return False
+ else:
+ reasons = self.dut.search_logcat(
+ "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause")
+ if reasons:
+ ads[0].log.info(reasons[-1]["log_message"])
+ except Exception as e:
+ ads[0].log.error(e)
+ # Parse logcat for UI notification
+ result = True
+ if not negative_test:
+ if ads[0].search_logcat("Bugreport notification title Call Drop:"):
+ ads[0].log.info(
+ "User got Call Drop Notification with TelephonyMonitor on")
+ else:
+ ads[0].log.error(
+ "User didn't get Call Drop Notify with TelephonyMonitor on"
+ )
+ result = False
+ else:
+ if ads[0].search_logcat("Bugreport notification title Call Drop:"):
+ ads[0].log.error("User got the Call Drop Notification with "
+ "TelephonyMonitor/ConnectivityMonitor off")
+ result = False
+ else:
+ ads[0].log.info("User still get Call Drop Notify with "
+ "TelephonyMonitor/ConnectivityMonitor off")
+ reboot_device(ads[0])
+ return result
def _reboot_stress_test(self, **kwargs):
"""Reboot Reliability Test
@@ -356,62 +471,63 @@
Returns:
True is pass, False if fail.
"""
- CHECK_INTERVAL = 10
-
+ self.number_of_devices = 2
toggle_airplane_mode(self.log, self.dut, False)
phone_setup_voice_general(self.log, self.ad_reference)
fail_count = collections.defaultdict(int)
test_result = True
- test_method_mapping = {
- "check_provision": self._check_provision,
- "check_call_setup_teardown": self._check_call_setup_teardown,
- "check_lte_data": self._check_lte_data,
- "check_volte": self._check_volte,
- "check_wfc": self._check_wfc,
- "check_3g": self._check_3g,
- "check_tethering": self._check_tethering,
- "check_data_roaming": self._check_data_roaming_status,
- "clear_provision": self._clear_provisioning
- }
- for kwarg in kwargs:
- if kwarg not in test_method_mapping:
- self.log.error("method %s is not supported" % method)
-
- required_methods = []
- for method in test_method_mapping.keys():
- if method in kwargs: required_methods.append(method)
for i in range(1, self.stress_test_number + 1):
- self.log.info("Reboot Stress Test {} Iteration: <{}> / <{}>".
- format(self.test_name, i, self.stress_test_number))
-
- self.log.info("{} reboot!".format(self.dut.serial))
- self.dut.reboot()
+ self.log.info("Reboot Stress Test %s Iteration: <%s> / <%s>",
+ self.test_name, i, self.stress_test_number)
+ begin_time = get_current_epoch_time()
+ self.dut.log.info("Reboot")
+ reboot_device(self.dut)
self.log.info("{} wait {}s for radio up.".format(
self.dut.serial, WAIT_TIME_AFTER_REBOOT))
time.sleep(WAIT_TIME_AFTER_REBOOT)
- iteration_result = "pass"
- for check in required_methods:
- if not test_method_mapping[check]():
- fail_count[check] += 1
- iteration_result = "fail"
- self.log.info("Reboot Stress Test {} Iteration: <{}> / <{}> {}".
- format(self.test_name, i, self.stress_test_number,
- iteration_result))
+ failed_tests = self.feature_validator(**kwargs)
+ for test in failed_tests:
+ fail_count[test] += 1
- # TODO: Check if crash happens.
+ crash_report = self.dut.check_crash_report(
+ "%s_%s" % (self.test_name, i),
+ begin_time,
+ log_crash_report=True)
+ if crash_report:
+ fail_count["crashes"] += 1
+ if failed_tests or crash_report:
+ self.log.error(
+ "Reboot Stress Test Iteration <%s> / <%s> FAIL",
+ i,
+ self.stress_test_number,
+ )
+ self._take_bug_report("%s_%s" % (self.test_name, i),
+ begin_time)
+ else:
+ self.log.info(
+ "Reboot Stress Test Iteration <%s> / <%s> PASS",
+ i,
+ self.stress_test_number,
+ )
+ self.log.info("Total failure count: %s", list(fail_count))
for failure, count in fail_count.items():
if count:
- self.log.error("{} {} failures in {} iterations".format(
- count, failure, self.stress_test_number))
+ self.log.error("%s %s failures in %s iterations", count,
+ failure, self.stress_test_number)
test_result = False
return test_result
- def _crash_recovery_test(self, **kwargs):
+ def _crash_recovery_test(self, process="modem", **kwargs):
"""Crash Recovery Test
Arguments:
+ process: the process to be killed. For example:
+ "rild", "netmgrd", "com.android.phone", "imsqmidaemon",
+ "imsdatadaemon", "ims_rtp_daemon",
+ "com.android.ims.rcsservice", "system_server", "cnd",
+ "modem"
check_lte_data: whether to check the LTE data.
check_volte: whether to check Voice over LTE.
check_vt: whether to check VT
@@ -423,73 +539,77 @@
Returns:
True is pass, False if fail.
"""
- CHECK_INTERVAL = 10
+ self.number_of_devices = 2
- toggle_airplane_mode(self.log, self.dut, False)
- phone_setup_voice_general(self.log, self.ad_reference)
- fail_count = collections.defaultdict(int)
- test_result = True
- test_method_mapping = {
- "check_provision": self._check_provision,
- "check_call_setup_teardown": self._check_call_setup_teardown,
- "check_lte_data": self._check_lte_data,
- "check_volte": self._check_volte,
- "check_vt": self._check_vt,
- "check_wfc": self._check_wfc,
- "check_3g": self._check_3g,
- "check_tethering": self._check_tethering,
- "check_data_roaming": self._check_data_roaming_status,
- "clear_provision": self._clear_provisioning
- }
- for kwarg in kwargs:
- if kwarg not in test_method_mapping:
- self.log.error("method %s is not supported" % method)
+ if process == "modem":
+ self.user_params["check_crash"] = False
+ self.dut.log.info("Crash modem from kernal")
+ trigger_modem_crash(self.dut)
+ elif process == "modem-crash":
+ self.user_params["check_crash"] = False
+ self.dut.log.info("Crash modem from modem")
+ trigger_modem_crash_by_modem(self.dut)
+ elif process == "sim":
+ self.user_params["check_crash"] = True
+ sub_id = get_outgoing_voice_sub_id(self.dut)
+ slot_index = get_slot_index_from_subid(self.log, self.dut, sub_id)
+ if not power_off_sim(self.dut, slot_index):
+ self.dut.log.warning("Fail to power off SIM")
+ raise signals.TestSkip("Power cycle SIM not working")
+ if not power_on_sim(self.dut, slot_index):
+ self.dut.log.error("Fail to power on SIM slot")
+ setattr(self.dut, "reboot_to_recover", True)
+ return False
+ else:
+ self.dut.log.info("Crash recover test by killing process <%s>",
+ process)
+ process_pid = self.dut.adb.shell("pidof %s" % process)
+ self.dut.log.info("Pid of %s is %s", process, process_pid)
+ if not process_pid:
+ self.dut.log.error("Process %s not running", process)
+ return False
+ if process in ("netd", "system_server"):
+ self.dut.stop_services()
+ self.dut.adb.shell("kill -9 %s" % process_pid, ignore_status=True)
+ self.dut.log.info("Wait %s sec for process %s come up.",
+ WAIT_TIME_AFTER_CRASH, process)
+ time.sleep(WAIT_TIME_AFTER_CRASH)
+ if process in ("netd", "system_server"):
+ self.dut.ensure_screen_on()
+ try:
+ self.dut.start_services(self.dut.skip_sl4a)
+ except Exception as e:
+ self.dut.log.warning(e)
+ process_pid_new = self.dut.adb.shell("pidof %s" % process)
+ if process_pid == process_pid_new:
+ self.dut.log.error(
+ "Process %s has the same pid: old:%s new:%s", process,
+ process_pid, process_pid_new)
+ try:
+ self.dut.droid.logI("Start testing after restarting %s" % process)
+ except Exception:
+ self.dut.ensure_screen_on()
+ self.dut.start_services(self.dut.skip_sl4a)
+ if is_sim_locked(self.dut):
+ unlock_sim(self.dut)
- required_methods = []
- for method in test_method_mapping.keys():
- if method in kwargs: required_methods.append(method)
-
- process_list = ("rild", "netmgrd", "com.android.phone", "imsqmidaemon",
- "imsdatadaemon", "ims_rtp_daemon", "netd",
- "com.android.ims.rcsservice", "system_server", "cnd",
- "modem")
- for service in process_list:
- iteration_result = "pass"
- self.log.info("Crash Recover Test for Process <%s>" % service)
- self.log.info("%s kill Process %s" % (self.dut.serial, service))
- if service == "modem":
- trigger_modem_crash(self.log, self.dut)
- time.sleep(WAIT_TIME_AFTER_CRASH * 2)
- else:
- process_pid = self.dut.adb.shell("pidof %s" % service)
- self.log.info("%s is the pidof %s" % (process_pid, service))
- if not process_pid:
- self.dut.log.error("Process %s not running" % service)
- iteration_result = "fail"
- if service == "netd" or service == "system_server":
- self.dut.stop_services()
- self.dut.adb.shell(
- "kill -9 %s" % process_pid, ignore_status=True)
- self.log.info("%s wait %d sec for radio up." %
- (self.dut.serial, WAIT_TIME_AFTER_CRASH))
- time.sleep(WAIT_TIME_AFTER_CRASH)
- if service == "netd" or service == "system_server":
- self.dut.start_services()
- process_pid_new = self.dut.adb.shell("pidof %s" % service)
- if process_pid == process_pid_new:
- self.log.error("kill failed old:%s new:%s" %
- (process_pid, process_pid_new))
- for check in required_methods:
- if not test_method_mapping[check]():
- fail_count[check] += 1
- iteration_result = "fail"
- self.log.info("Crash Recover Test for Process <%s> %s" %
- (service, iteration_result))
- for failure, count in fail_count.items():
- if count:
- self.log.error("%d %s failures" % (count, failure))
- test_result = False
- return test_result
+ begin_time = get_current_epoch_time()
+ failed_tests = self.feature_validator(**kwargs)
+ crash_report = self.dut.check_crash_report(
+ self.test_name, begin_time, log_crash_report=True)
+ if crash_report:
+ fail_count["crashes"] += 1
+ if failed_tests or crash_report:
+ if failed_tests:
+ self.dut.log.error("%s failed after %s restart", failed_tests,
+ process)
+ setattr(self.dut, "reboot_to_recover", True)
+ if crash_report:
+ self.dut.log.error("Crash %s found after %s restart",
+ crash_report, process)
+ return False
+ else:
+ return True
def _telephony_bootup_time_test(self, **kwargs):
"""Telephony Bootup Perf Test
@@ -505,6 +625,7 @@
Returns:
True is pass, False if fail.
"""
+ self.number_of_devices = 1
ad = self.dut
toggle_airplane_mode(self.log, ad, False)
if not phone_setup_volte(self.log, ad):
@@ -518,7 +639,7 @@
ad.log.info("Telephony Bootup Time Test %s Iteration: %d / %d",
self.test_name, i, self.stress_test_number)
ad.log.info("reboot!")
- ad.reboot()
+ reboot_device(ad)
iteration_result = "pass"
time.sleep(30)
@@ -626,47 +747,9 @@
check_data_roaming=False,
clear_provision=True)
- @test_tracker_info(uuid="39a822e5-0360-44ce-97c7-f75468eba8d7")
- @TelephonyBaseTest.tel_test_wrap
- def test_reboot_stress_without_clear_provisioning(self):
- """Reboot Reliability Test without Clear Provisioning
-
- Steps:
- 1. Reboot DUT.
- 2. Check Provisioning bit (if support provisioning)
- 3. Wait for DUT to camp on LTE, Verify Data.
- 4. Enable VoLTE, check IMS registration. Wait for DUT report VoLTE
- enabled, make VoLTE call. And verify VoLTE SMS.
- (if support VoLTE)
- 5. Connect WiFi, enable WiFi Calling, wait for DUT report WiFi
- Calling enabled and make a WFC call and verify SMS.
- Disconnect WiFi. (if support WFC)
- 6. Wait for DUT to camp on 3G, Verify Data.
- 7. Make CS call and verify SMS.
- 8. Verify Tethering Entitlement Check and Verify WiFi Tethering.
- 9. Check crashes.
- 10. Repeat Step 1~9 for N times.
-
- Expected Results:
- No crash happens in stress test.
-
- Returns:
- True is pass, False if fail.
- """
- return self._reboot_stress_test(
- check_provision=True,
- check_call_setup_teardown=True,
- check_lte_data=True,
- check_volte=True,
- check_wfc=True,
- check_3g=True,
- check_tethering=True,
- check_data_roaming=False,
- clear_provision=False)
-
@test_tracker_info(uuid="8b0e2c06-02bf-40fd-a374-08860e482757")
@TelephonyBaseTest.tel_test_wrap
- def test_reboot_stress_check_phone_call_only(self):
+ def test_reboot_stress(self):
"""Reboot Reliability Test
Steps:
@@ -682,31 +765,10 @@
Returns:
True is pass, False if fail.
"""
- return self._stress_test(
- check_provision=True, check_call_setup_teardown=True)
+ return self._reboot_stress_test()
- @test_tracker_info(uuid="6c243b53-379a-4cda-9848-84fcec4019bd")
- @TelephonyBaseTest.tel_test_wrap
- def test_reboot_stress_data_roaming(self):
- """Reboot Reliability Test
-
- Steps:
- 1. Reboot DUT.
- 8. Check the data connection
- 9. Check crashes.
- 10. Repeat Step 1~9 for N times. (before reboot, clear Provisioning
- bit if provisioning is supported)
-
- Expected Results:
- No crash happens in stress test.
-
- Returns:
- True is pass, False if fail.
- """
- return self._reboot_stress_test(check_data_roaming=True)
-
- @TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="109d59ff-a488-4a68-87fd-2d8d0c035326")
+ @TelephonyBaseTest.tel_test_wrap
def test_bootup_optimized_stress(self):
"""Bootup Optimized Reliability Test
@@ -735,13 +797,13 @@
"""
return self._telephony_bootup_time_test()
- @TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="08752fac-dbdb-4d5b-91f6-4ffc3a3ac6d6")
- def test_crash_recovery_functional(self):
+ @TelephonyBaseTest.tel_test_wrap
+ def test_crash_recovery_modem(self):
"""Crash Recovery Test
Steps:
- 1. Crash multiple daemons/processes
+ 1. Crash modem
2. Post crash recovery, verify Voice, Data, SMS, VoLTE, VT
Expected Results:
@@ -750,11 +812,203 @@
Returns:
True is pass, False if fail.
"""
- return self._crash_recovery_test(
- check_lte_data=True, check_volte=True, check_vt=True)
+ return self._crash_recovery_test(process="modem")
+ @test_tracker_info(uuid="ce5f4d63-7f3d-48b7-831d-2c1d5db60733")
@TelephonyBaseTest.tel_test_wrap
+ def test_crash_recovery_crash_modem_from_modem(self):
+ """Crash Recovery Test
+
+ Steps:
+ 1. Crash modem
+ 2. Post crash recovery, verify Voice, Data, SMS, VoLTE, VT
+
+ Expected Results:
+ No crash happens in functional test, features work fine.
+
+ Returns:
+ True is pass, False if fail.
+ """
+ if (not self.dut.is_apk_installed("com.google.mdstest")) or (
+ self.dut.adb.getprop("ro.build.version.release")[0] in
+ ("8", "O", "7", "N")) or self.dut.model in ("angler", "bullhead",
+ "sailfish", "marlin"):
+ raise signals.TestSkip(
+ "com.google.mdstest not installed or supported")
+ return self._crash_recovery_test(process="modem-crash")
+
+ @test_tracker_info(uuid="489284e8-77c9-4961-97c8-b6f1a833ff90")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_crash_recovery_rild(self):
+ """Crash Recovery Test
+
+ Steps:
+ 1. Crash rild
+ 2. Post crash recovery, verify Voice, Data, SMS, VoLTE, VT
+
+ Expected Results:
+ No crash happens in functional test, features work fine.
+
+ Returns:
+ True is pass, False if fail.
+ """
+ return self._crash_recovery_test(process="rild")
+
+ @test_tracker_info(uuid="e1b34b2c-99e6-4966-a11c-88cedc953b47")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_crash_recovery_netmgrd(self):
+ """Crash Recovery Test
+
+ Steps:
+ 1. Crash netmgrd
+ 2. Post crash recovery, verify Voice, Data, SMS, VoLTE, VT
+
+ Expected Results:
+ No crash happens in functional test, features work fine.
+
+ Returns:
+ True is pass, False if fail.
+ """
+ return self._crash_recovery_test(process="netmgrd")
+
+ @test_tracker_info(uuid="fa34f994-bc49-4444-9187-87691c94b4f4")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_crash_recovery_phone(self):
+ """Crash Recovery Test
+
+ Steps:
+ 1. Crash com.android.phone
+ 2. Post crash recovery, verify Voice, Data, SMS, VoLTE, VT
+
+ Expected Results:
+ No crash happens in functional test, features work fine.
+
+ Returns:
+ True is pass, False if fail.
+ """
+ return self._crash_recovery_test(process="com.android.phone")
+
+ @test_tracker_info(uuid="6f5a24bb-3cf3-4362-9675-36a6be90282f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_crash_recovery_imsqmidaemon(self):
+ """Crash Recovery Test
+
+ Steps:
+ 1. Crash imsqmidaemon
+ 2. Post crash recovery, verify Voice, Data, SMS, VoLTE, VT
+
+ Expected Results:
+ No crash happens in functional test, features work fine.
+
+ Returns:
+ True is pass, False if fail.
+ """
+ return self._crash_recovery_test(process="imsqmidaemon")
+
+ @test_tracker_info(uuid="7a8dc971-054b-47e7-9e57-3bb7b39937d3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_crash_recovery_imsdatadaemon(self):
+ """Crash Recovery Test
+
+ Steps:
+ 1. Crash imsdatadaemon
+ 2. Post crash recovery, verify Voice, Data, SMS, VoLTE, VT
+
+ Expected Results:
+ No crash happens in functional test, features work fine.
+
+ Returns:
+ True is pass, False if fail.
+ """
+ return self._crash_recovery_test(process="imsdatadaemon")
+
+ @test_tracker_info(uuid="350ca58c-01f2-4a61-baff-530b8b24f1f6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_crash_recovery_ims_rtp_daemon(self):
+ """Crash Recovery Test
+
+ Steps:
+ 1. Crash imsdatadaemon
+ 2. Post crash recovery, verify Voice, Data, SMS, VoLTE, VT
+
+ Expected Results:
+ No crash happens in functional test, features work fine.
+
+ Returns:
+ True is pass, False if fail.
+ """
+ return self._crash_recovery_test(process="ims_rtp_daemon")
+
+ @test_tracker_info(uuid="af78f33a-2b50-4c55-a302-3701b655c557")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_crash_recovery_ims_rcsservice(self):
+ """Crash Recovery Test
+
+ Steps:
+ 1. Crash imsdatadaemon
+ 2. Post crash recovery, verify Voice, Data, SMS, VoLTE, VT
+
+ Expected Results:
+ No crash happens in functional test, features work fine.
+
+ Returns:
+ True is pass, False if fail.
+ """
+ return self._crash_recovery_test(process="com.android.ims.rcsservice")
+
+ @test_tracker_info(uuid="8119aeef-84ba-415c-88ea-6eba35bd91fd")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_crash_recovery_system_server(self):
+ """Crash Recovery Test
+
+ Steps:
+ 1. Crash system_server
+ 2. Post crash recovery, verify Voice, Data, SMS, VoLTE, VT
+
+ Expected Results:
+ No crash happens in functional test, features work fine.
+
+ Returns:
+ True is pass, False if fail.
+ """
+ return self._crash_recovery_test(process="system_server")
+
+ @test_tracker_info(uuid="c3891aca-9e1a-4e37-9f2f-23f12ef0a86f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_crash_recovery_cnd(self):
+ """Crash Recovery Test
+
+ Steps:
+ 1. Crash cnd
+ 2. Post crash recovery, verify Voice, Data, SMS, VoLTE, VT
+
+ Expected Results:
+ No crash happens in functional test, features work fine.
+
+ Returns:
+ True is pass, False if fail.
+ """
+ return self._crash_recovery_test(process="cnd")
+
+ @test_tracker_info(uuid="c1b661b9-d5cf-4a22-90a9-3fd55ddc2f3f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_sim_slot_power_cycle(self):
+ """SIM slot power cycle Test
+
+ Steps:
+ 1. Power cycle SIM slot to simulate SIM resit
+ 2. Post power cycle SIM, verify Voice, Data, SMS, VoLTE, VT
+
+ Expected Results:
+ No crash happens in functional test, features work fine.
+
+ Returns:
+ True is pass, False if fail.
+ """
+ return self._crash_recovery_test(process="sim")
+
@test_tracker_info(uuid="b6d2fccd-5dfd-4637-aa3b-257837bfba54")
+ @TelephonyBaseTest.tel_test_wrap
def test_telephonymonitor_functional(self):
"""Telephony Monitor Functional Test
@@ -771,5 +1025,23 @@
"""
return self._telephony_monitor_test()
+ @test_tracker_info(uuid="f048189b-e4bb-46f7-b150-37acf020af6e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_telephonymonitor_negative(self):
+ """Telephony Monitor Functional Test
+
+ Steps:
+ 1. Verify Telephony Monitor functionality is working or not
+ 2. Force Trigger a call drop : media timeout and ensure it is
+ not notified by Telephony Monitor
+
+ Expected Results:
+ feature work fine, and does not report to User about Call Drop
+
+ Returns:
+ True is pass, False if fail.
+ """
+ return self._telephony_monitor_test(negative_test=True)
+
""" Tests End """
diff --git a/acts/tests/google/tel/live/TelLiveSettingsTest.py b/acts/tests/google/tel/live/TelLiveSettingsTest.py
index 59d84c6..4a41f9a 100644
--- a/acts/tests/google/tel/live/TelLiveSettingsTest.py
+++ b/acts/tests/google/tel/live/TelLiveSettingsTest.py
@@ -17,7 +17,15 @@
Test Script for Telephony Settings
"""
+import os
import time
+
+from acts import signals
+from acts.keys import Config
+from acts.utils import create_dir
+from acts.utils import unzip_maintain_permissions
+from acts.utils import get_current_epoch_time
+from acts.utils import exe_cmd
from acts.test_decorators import test_tracker_info
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_WIFI_CONNECTION
@@ -31,12 +39,24 @@
from acts.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
from acts.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts.test_utils.tel.tel_test_utils import call_setup_teardown
+from acts.test_utils.tel.tel_test_utils import ensure_phone_subscription
from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected
+from acts.test_utils.tel.tel_test_utils import flash_radio
+from acts.test_utils.tel.tel_test_utils import get_outgoing_voice_sub_id
+from acts.test_utils.tel.tel_test_utils import get_slot_index_from_subid
from acts.test_utils.tel.tel_test_utils import is_droid_in_rat_family
+from acts.test_utils.tel.tel_test_utils import is_sim_locked
from acts.test_utils.tel.tel_test_utils import is_wfc_enabled
+from acts.test_utils.tel.tel_test_utils import multithread_func
+from acts.test_utils.tel.tel_test_utils import power_off_sim
+from acts.test_utils.tel.tel_test_utils import power_on_sim
+from acts.test_utils.tel.tel_test_utils import print_radio_info
+from acts.test_utils.tel.tel_test_utils import set_qxdm_logger_command
from acts.test_utils.tel.tel_test_utils import set_wfc_mode
+from acts.test_utils.tel.tel_test_utils import system_file_push
from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
from acts.test_utils.tel.tel_test_utils import toggle_volte
+from acts.test_utils.tel.tel_test_utils import unlock_sim
from acts.test_utils.tel.tel_test_utils import verify_http_connection
from acts.test_utils.tel.tel_test_utils import wait_for_ims_registered
from acts.test_utils.tel.tel_test_utils import wait_for_network_rat
@@ -47,6 +67,7 @@
from acts.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
from acts.test_utils.tel.tel_test_utils import wifi_reset
from acts.test_utils.tel.tel_test_utils import wifi_toggle_state
+from acts.test_utils.tel.tel_test_utils import set_wifi_to_default
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
from acts.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
from acts.test_utils.tel.tel_voice_utils import phone_setup_csfb
@@ -54,6 +75,7 @@
from acts.test_utils.tel.tel_voice_utils import phone_setup_volte
from acts.test_utils.tel.tel_voice_utils import phone_idle_iwlan
from acts.test_utils.tel.tel_voice_utils import phone_idle_volte
+from acts.utils import set_mobile_data_always_on
class TelLiveSettingsTest(TelephonyBaseTest):
@@ -71,7 +93,7 @@
self.wifi_network_pass = self.user_params["wifi_network_pass"]
except KeyError:
self.wifi_network_pass = None
-
+ self.number_of_devices = 1
self.stress_test_number = self.get_stress_test_number()
def _wifi_connected_enable_wfc_teardown_wfc(
@@ -207,8 +229,8 @@
if is_wfc_available_after_turn_off_apm and is_wfc_not_available:
self.log.error("WFC is not available.")
return False
- elif (not is_wfc_available_after_turn_off_apm and
- not is_wfc_not_available):
+ elif (not is_wfc_available_after_turn_off_apm
+ and not is_wfc_not_available):
self.log.error("WFC is available.")
return False
return True
@@ -286,7 +308,7 @@
3. DUT WiFi Calling feature bit return True, network rat is iwlan.
4. DUT WiFi Calling feature bit return False, network rat is not iwlan.
"""
-
+ set_wifi_to_default(self.log, self.ad)
if not phone_setup_voice_3g(self.log, self.ad):
self.log.error("Failed to setup 3G")
return False
@@ -389,7 +411,7 @@
3. DUT WiFi Calling feature bit return True, network rat is iwlan.
4. DUT WiFi Calling feature bit return False, network rat is not iwlan.
"""
-
+ set_wifi_to_default(self.log, self.ad)
if not phone_setup_voice_3g(self.log, self.ad):
self.log.error("Failed to setup 3G")
return False
@@ -539,6 +561,7 @@
2. DUT WiFi Calling feature bit return True, network rat is iwlan.
4. DUT WiFI Calling feature bit return False, network rat is not iwlan.
"""
+ set_wifi_to_default(self.log, self.ad)
if not phone_setup_voice_3g(self.log, self.ad):
self.log.error("Failed to setup 3G.")
return False
@@ -640,6 +663,7 @@
2. DUT WiFi Calling feature bit return False, network rat is not iwlan.
4. DUT WiFI Calling feature bit return True, network rat is iwlan.
"""
+ set_wifi_to_default(self.log, self.ad)
if not phone_setup_voice_3g(self.log, self.ad):
self.log.error("Failed to setup 3G.")
return False
@@ -1047,8 +1071,8 @@
result = False
return result
- @TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="135301ea-6d00-4233-98fd-cda706d61eb2")
+ @TelephonyBaseTest.tel_test_wrap
def test_ims_factory_reset_to_volte_on_wfc_off(self):
"""Test VOLTE is enabled WFC is disabled after ims factory reset.
@@ -1079,8 +1103,8 @@
if not self.verify_volte_on_wfc_off(): result = False
return result
- @TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="5318bf7a-4210-4b49-b361-9539d28f3e38")
+ @TelephonyBaseTest.tel_test_wrap
def test_ims_factory_reset_to_volte_off_wfc_off(self):
"""Test VOLTE is enabled WFC is disabled after ims factory reset.
@@ -1111,8 +1135,8 @@
if not self.verify_volte_off_wfc_off(): result = False
return result
- @TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="c6149bd6-7080-453d-af37-1f9bd350a764")
+ @TelephonyBaseTest.tel_test_wrap
def test_telephony_factory_reset(self):
"""Test VOLTE is enabled WFC is disabled after telephony factory reset.
@@ -1129,8 +1153,8 @@
self.ad.droid.telephonyFactoryReset()
return self.verify_default_telephony_setting()
- @TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="ce60740f-4d8e-4013-a7cf-65589e8a0893")
+ @TelephonyBaseTest.tel_test_wrap
def test_factory_reset_by_wipe_to_volte_on_wfc_off(self):
"""Verify the network setting after factory reset by wipe.
@@ -1149,13 +1173,13 @@
set_wfc_mode(self.log, self.ad, WFC_MODE_WIFI_PREFERRED)
self.revert_default_telephony_setting()
self.ad.log.info("Wipe in fastboot")
- self.ad.fastboot_wipe()
+ fastboot_wipe(self.ad)
result = self.verify_volte_on_wfc_off()
if not self.verify_default_telephony_setting(): result = False
return result
- @TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="44e9291e-949b-4db1-a209-c6d41552ec27")
+ @TelephonyBaseTest.tel_test_wrap
def test_factory_reset_by_wipe_to_volte_off_wfc_off(self):
"""Verify the network setting after factory reset by wipe.
@@ -1174,7 +1198,300 @@
set_wfc_mode(self.log, self.ad, WFC_MODE_WIFI_PREFERRED)
self.revert_default_telephony_setting()
self.ad.log.info("Wipe in fastboot")
- self.ad.fastboot_wipe()
+ fastboot_wipe(self.ad)
result = self.verify_volte_off_wfc_off()
if not self.verify_default_telephony_setting(): result = False
return result
+
+ @test_tracker_info(uuid="64deba57-c1c2-422f-b771-639c95edfbc0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_disable_mobile_data_always_on(self):
+ """Verify mobile_data_always_on can be disabled.
+
+ Steps:
+ 1. Disable mobile_data_always_on by adb.
+ 2. Verify the mobile data_always_on state.
+
+ Expected Results: mobile_data_always_on return 0.
+ """
+ self.ad.log.info("Disable mobile_data_always_on")
+ set_mobile_data_always_on(self.ad, False)
+ time.sleep(1)
+ return self.ad.adb.shell(
+ "settings get global mobile_data_always_on") == "0"
+
+ @test_tracker_info(uuid="56ddcd5a-92b0-46c7-9c2b-d743794efb7c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_enable_mobile_data_always_on(self):
+ """Verify mobile_data_always_on can be enabled.
+
+ Steps:
+ 1. Enable mobile_data_always_on by adb.
+ 2. Verify the mobile data_always_on state.
+
+ Expected Results: mobile_data_always_on return 1.
+ """
+ self.ad.log.info("Enable mobile_data_always_on")
+ set_mobile_data_always_on(self.ad, True)
+ time.sleep(1)
+ return "1" in self.ad.adb.shell(
+ "settings get global mobile_data_always_on")
+
+ @test_tracker_info(uuid="c2cc5b66-40af-4ba6-81cb-6c44ae34cbbb")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_push_new_radio_or_mbn(self):
+ """Verify new mdn and radio can be push to device.
+
+ Steps:
+ 1. If new radio path is given, flash new radio on the device.
+ 2. Verify the radio version.
+ 3. If new mbn path is given, push new mbn to device.
+ 4. Verify the installed mbn version.
+
+ Expected Results:
+ radio and mbn can be pushed to device and mbn.ver is available.
+ """
+ result = True
+ paths = {}
+ for path_key, dst_name in zip(["radio_image", "mbn_path"],
+ ["radio.img", "mcfg_sw"]):
+ path = self.user_params.get(path_key)
+ if not path:
+ continue
+ elif isinstance(path, list):
+ if not path[0]:
+ continue
+ path = path[0]
+ if "dev/null" in path:
+ continue
+ if not os.path.exists(path):
+ self.log.error("path %s does not exist", path)
+ self.log.info(self.user_params)
+ path = os.path.join(self.user_params[Config.key_config_path],
+ path)
+ if not os.path.exists(path):
+ self.log.error("path %s does not exist", path)
+ continue
+
+ self.log.info("%s path = %s", path_key, path)
+ if "zip" in path:
+ self.log.info("Unzip %s", path)
+ file_path, file_name = os.path.split(path)
+ dest_path = os.path.join(file_path, dst_name)
+ os.system("rm -rf %s" % dest_path)
+ unzip_maintain_permissions(path, file_path)
+ path = dest_path
+ os.system("chmod -R 777 %s" % path)
+ paths[path_key] = path
+ if not paths:
+ self.log.info("No radio_path or mbn_path is provided")
+ raise signals.TestSkip("No radio_path or mbn_path is provided")
+ self.log.info("paths = %s", paths)
+ for ad in self.android_devices:
+ if paths.get("radio_image"):
+ print_radio_info(ad, "Before flash radio, ")
+ flash_radio(ad, paths["radio_image"])
+ print_radio_info(ad, "After flash radio, ")
+ if not paths.get("mbn_path") or "mbn" not in ad.adb.shell(
+ "ls /vendor"):
+ ad.log.info("No need to push mbn files")
+ continue
+ push_result = True
+ try:
+ mbn_ver = ad.adb.shell(
+ "cat /vendor/mbn/mcfg/configs/mcfg_sw/mbn.ver")
+ if mbn_ver:
+ ad.log.info("Before push mbn, mbn.ver = %s", mbn_ver)
+ else:
+ ad.log.info(
+ "There is no mbn.ver before push, unmatching device")
+ continue
+ except:
+ ad.log.info(
+ "There is no mbn.ver before push, unmatching device")
+ continue
+ print_radio_info(ad, "Before push mbn, ")
+ for i in range(2):
+ if not system_file_push(ad, paths["mbn_path"],
+ "/vendor/mbn/mcfg/configs/"):
+ if i == 1:
+ ad.log.error("Failed to push mbn file")
+ push_result = False
+ else:
+ ad.log.info("The mbn file is pushed to device")
+ break
+ if not push_result:
+ result = False
+ continue
+ print_radio_info(ad, "After push mbn, ")
+ try:
+ new_mbn_ver = ad.adb.shell(
+ "cat /vendor/mbn/mcfg/configs/mcfg_sw/mbn.ver")
+ if new_mbn_ver:
+ ad.log.info("new mcfg_sw mbn.ver = %s", new_mbn_ver)
+ if new_mbn_ver == mbn_ver:
+ ad.log.error(
+ "mbn.ver is the same before and after push")
+ result = False
+ else:
+ ad.log.error("Unable to get new mbn.ver")
+ result = False
+ except Exception as e:
+ ad.log.error("cat mbn.ver with error %s", e)
+ result = False
+ return result
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_set_qxdm_log_mask_ims(self):
+ """Set the QXDM Log mask to IMS_DS_CNE_LnX_Golden.cfg"""
+ tasks = [(set_qxdm_logger_command, [ad, "IMS_DS_CNE_LnX_Golden.cfg"])
+ for ad in self.android_devices]
+ return multithread_func(self.log, tasks)
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_set_qxdm_log_mask_qc_default(self):
+ """Set the QXDM Log mask to QC_Default.cfg"""
+ tasks = [(set_qxdm_logger_command, [ad, " QC_Default.cfg"])
+ for ad in self.android_devices]
+ return multithread_func(self.log, tasks)
+
+ @test_tracker_info(uuid="e2734d66-6111-4e76-aa7b-d3b4cbcde4f1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_check_carrier_id(self):
+ """Verify mobile_data_always_on can be enabled.
+
+ Steps:
+ 1. Enable mobile_data_always_on by adb.
+ 2. Verify the mobile data_always_on state.
+
+ Expected Results: mobile_data_always_on return 1.
+ """
+ result = True
+ if self.ad.adb.getprop("ro.build.version.release")[0] in ("8", "O",
+ "7", "N"):
+ raise signals.TestSkip("Not supported in this build")
+ old_carrier_id = self.ad.droid.telephonyGetSubscriptionCarrierId()
+ old_carrier_name = self.ad.droid.telephonyGetSubscriptionCarrierName()
+ self.result_detail = "carrier_id = %s, carrier_name = %s" % (
+ old_carrier_id, old_carrier_name)
+ self.ad.log.info(self.result_detail)
+ sub_id = get_outgoing_voice_sub_id(self.ad)
+ slot_index = get_slot_index_from_subid(self.log, self.ad, sub_id)
+ if power_off_sim(self.ad, slot_index):
+ for i in range(3):
+ carrier_id = self.ad.droid.telephonyGetSubscriptionCarrierId()
+ carrier_name = self.ad.droid.telephonyGetSubscriptionCarrierName(
+ )
+ msg = "After SIM power down, carrier_id = %s(expecting -1), " \
+ "carrier_name = %s(expecting None)" % (carrier_id, carrier_name)
+ if carrier_id != -1 or carrier_name:
+ if i == 2:
+ self.ad.log.error(msg)
+ self.result_detail = "%s %s" % (self.result_detail,
+ msg)
+ result = False
+ else:
+ time.sleep(5)
+ else:
+ self.ad.log.info(msg)
+ break
+ else:
+ if self.ad.model in ("taimen", "walleye"):
+ msg = "Power off SIM slot is not working"
+ self.ad.log.error(msg)
+ result = False
+ else:
+ msg = "Power off SIM slot is not supported"
+ self.ad.log.warning(msg)
+ self.result_detail = "%s %s" % (self.result_detail, msg)
+
+ if not power_on_sim(self.ad, slot_index):
+ self.ad.log.error("Fail to power up SIM")
+ result = False
+ setattr(self.ad, "reboot_to_recover", True)
+ else:
+ if is_sim_locked(self.ad):
+ self.ad.log.info("Sim is locked")
+ carrier_id = self.ad.droid.telephonyGetSubscriptionCarrierId()
+ carrier_name = self.ad.droid.telephonyGetSubscriptionCarrierName(
+ )
+ msg = "In locked SIM, carrier_id = %s(expecting -1), " \
+ "carrier_name = %s(expecting None)" % (carrier_id, carrier_name)
+ if carrier_id != -1 or carrier_name:
+ self.ad.log.error(msg)
+ self.result_detail = "%s %s" % (self.result_detail, msg)
+ result = False
+ else:
+ self.ad.log.info(msg)
+ unlock_sim(self.ad)
+ elif getattr(self.ad, "is_sim_locked", False):
+ self.ad.log.error(
+ "After SIM slot power cycle, SIM in not in locked state")
+ return False
+
+ if not ensure_phone_subscription(self.log, self.ad):
+ self.ad.log.error("Unable to find a valid subscription!")
+ result = False
+ new_carrier_id = self.ad.droid.telephonyGetSubscriptionCarrierId()
+ new_carrier_name = self.ad.droid.telephonyGetSubscriptionCarrierName(
+ )
+ msg = "After SIM power up, new_carrier_id = %s, " \
+ "new_carrier_name = %s" % (new_carrier_id, new_carrier_name)
+ if old_carrier_id != new_carrier_id or (old_carrier_name !=
+ new_carrier_name):
+ self.ad.log.error(msg)
+ self.result_detail = "%s %s" % (self.result_detail, msg)
+ result = False
+ else:
+ self.ad.log.info(msg)
+ return result
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_modem_power_anomaly_file_existence(self):
+ """Verify if the power anomaly file exists
+
+ 1. Collect Bugreport
+ 2. unzip bugreport
+ 3. remane the .bin file to .tar
+ 4. unzip dumpstate.tar
+ 5. Verify if the file exists
+
+ """
+ ad = self.android_devices[0]
+ begin_time = get_current_epoch_time()
+ for i in range(3):
+ try:
+ bugreport_path = os.path.join(ad.log_path, self.test_name)
+ create_dir(bugreport_path)
+ ad.take_bug_report(self.test_name, begin_time)
+ break
+ except Exception as e:
+ ad.log.error("bugreport attempt %s error: %s", i + 1, e)
+ ad.log.info("Bugreport Path is %s" % bugreport_path)
+ try:
+ list_of_files = os.listdir(bugreport_path)
+ ad.log.info(list_of_files)
+ for filename in list_of_files:
+ if ".zip" in filename:
+ ad.log.info(filename)
+ file_path = os.path.join(bugreport_path, filename)
+ ad.log.info(file_path)
+ unzip_maintain_permissions(file_path, bugreport_path)
+ dumpstate_path = os.path.join(bugreport_path,
+ "dumpstate_board.bin")
+ if os.path.isfile(dumpstate_path):
+ os.rename(dumpstate_path,
+ bugreport_path + "/dumpstate_board.tar")
+ os.chmod(bugreport_path + "/dumpstate_board.tar", 0o777)
+ current_dir = os.getcwd()
+ os.chdir(bugreport_path)
+ exe_cmd("tar -xvf %s" %
+ (bugreport_path + "/dumpstate_board.tar"))
+ os.chdir(current_dir)
+ if os.path.isfile(bugreport_path + "/power_anomaly_data.txt"):
+ ad.log.info("Modem Power Anomaly File Exists!!")
+ return True
+ return False
+ except Exception as e:
+ ad.log.error(e)
+ return False
diff --git a/acts/tests/google/tel/live/TelLiveSinglePhoneStressTest.py b/acts/tests/google/tel/live/TelLiveSinglePhoneStressTest.py
deleted file mode 100644
index 2541ca6..0000000
--- a/acts/tests/google/tel/live/TelLiveSinglePhoneStressTest.py
+++ /dev/null
@@ -1,504 +0,0 @@
-#!/usr/bin/env python3.4
-#
-# Copyright 2017 - Google
-#
-# 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 for Telephony Stress Call Test
-"""
-
-import collections
-import random
-import time
-
-from acts.asserts import fail
-from acts.test_decorators import test_tracker_info
-from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_ONLY
-from acts.test_utils.tel.tel_defines import NETWORK_MODE_WCDMA_ONLY
-from acts.test_utils.tel.tel_defines import NETWORK_MODE_GLOBAL
-from acts.test_utils.tel.tel_defines import NETWORK_MODE_CDMA
-from acts.test_utils.tel.tel_defines import NETWORK_MODE_GSM_ONLY
-from acts.test_utils.tel.tel_defines import NETWORK_MODE_TDSCDMA_GSM_WCDMA
-from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA
-from acts.test_utils.tel.tel_defines import WAIT_TIME_AFTER_MODE_CHANGE
-from acts.test_utils.tel.tel_test_utils import active_file_download_test
-from acts.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts.test_utils.tel.tel_test_utils import ensure_phone_default_state
-from acts.test_utils.tel.tel_test_utils import ensure_phone_subscription
-from acts.test_utils.tel.tel_test_utils import ensure_phone_idle
-from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts.test_utils.tel.tel_test_utils import hangup_call
-from acts.test_utils.tel.tel_test_utils import initiate_call
-from acts.test_utils.tel.tel_test_utils import is_phone_in_call
-from acts.test_utils.tel.tel_test_utils import run_multithread_func
-from acts.test_utils.tel.tel_test_utils import set_wfc_mode
-from acts.test_utils.tel.tel_test_utils import sms_send_receive_verify
-from acts.test_utils.tel.tel_test_utils import mms_send_receive_verify
-from acts.test_utils.tel.tel_test_utils import verify_incall_state
-from acts.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
-from acts.test_utils.tel.tel_test_utils import start_adb_tcpdump
-from acts.test_utils.tel.tel_test_utils import stop_adb_tcpdump
-from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
-from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
-from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
-from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
-from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts.test_utils.tel.tel_voice_utils import get_current_voice_rat
-from acts.logger import epoch_to_log_line_timestamp
-from acts.utils import get_current_epoch_time
-from acts.utils import rand_ascii_str
-
-import socket
-from acts.controllers.sl4a_client import Sl4aProtocolError
-
-IGNORE_EXCEPTIONS = (BrokenPipeError, Sl4aProtocolError)
-EXCEPTION_TOLERANCE = 20
-
-
-class TelLiveSinglePhoneStressTest(TelephonyBaseTest):
- def setup_class(self):
- super(TelLiveSinglePhoneStressTest, self).setup_class()
- self.dut = self.android_devices[0]
- self.call_server_number = self.user_params.get("call_server_number",
- "7124325335")
- self.user_params["telephony_auto_rerun"] = False
- self.wifi_network_ssid = self.user_params.get(
- "wifi_network_ssid") or self.user_params.get(
- "wifi_network_ssid_2g")
- self.wifi_network_pass = self.user_params.get(
- "wifi_network_pass") or self.user_params.get(
- "wifi_network_pass_2g")
- self.max_phone_call_duration = int(
- self.user_params.get("max_phone_call_duration", 3600))
- self.max_sleep_time = int(self.user_params.get("max_sleep_time", 1200))
- self.max_run_time = int(self.user_params.get("max_run_time", 18000))
- self.max_sms_length = int(self.user_params.get("max_sms_length", 1000))
- self.max_mms_length = int(self.user_params.get("max_mms_length", 160))
- self.min_sms_length = int(self.user_params.get("min_sms_length", 1))
- self.min_mms_length = int(self.user_params.get("min_mms_length", 1))
- self.min_phone_call_duration = int(
- self.user_params.get("min_phone_call_duration", 10))
- self.crash_check_interval = int(
- self.user_params.get("crash_check_interval", 300))
-
- return True
-
- def _setup_wfc(self):
- if not ensure_wifi_connected(
- self.log,
- self.dut,
- self.wifi_network_ssid,
- self.wifi_network_pass,
- retry=3):
- self.dut.log.error("Phone Wifi connection fails.")
- return False
- self.dut.log.info("Phone WIFI is connected successfully.")
- if not set_wfc_mode(self.log, self.dut, WFC_MODE_WIFI_PREFERRED):
- self.dut.log.error("Phone failed to enable Wifi-Calling.")
- return False
- self.dut.log.info("Phone is set in Wifi-Calling successfully.")
- if not phone_idle_iwlan(self.log, self.dut):
- self.dut.log.error("Phone is not in WFC enabled state.")
- return False
- self.dut.log.info("Phone is in WFC enabled state.")
- return True
-
- def _setup_lte_volte_enabled(self):
- if not phone_setup_volte(self.log, self.dut):
- self.dut.log.error("Phone failed to enable VoLTE.")
- return False
- self.dut.log.info("Phone VOLTE is enabled successfully.")
- return True
-
- def _setup_lte_volte_disabled(self):
- if not phone_setup_csfb(self.log, self.dut):
- self.dut.log.error("Phone failed to setup CSFB.")
- return False
- self.dut.log.info("Phone VOLTE is disabled successfully.")
- return True
-
- def _setup_3g(self):
- if not phone_setup_voice_3g(self.log, self.dut):
- self.dut.log.error("Phone failed to setup 3g.")
- return False
- self.dut.log.info("Phone RAT 3G is enabled successfully.")
- return True
-
- def _setup_2g(self):
- if not phone_setup_voice_2g(self.log, self.dut):
- self.dut.log.error("Phone failed to setup 2g.")
- return False
- self.dut.log.info("RAT 2G is enabled successfully.")
- return True
-
- def crash_check_test(self):
- failure = 0
- while time.time() < self.finishing_time:
- self.dut.log.info(dict(self.result_info))
- try:
- begin_time = epoch_to_log_line_timestamp(
- get_current_epoch_time())
- time.sleep(self.crash_check_interval)
- crash_report = self.dut.check_crash_report("checking_crash",
- begin_time, True)
- if crash_report:
- self.dut.log.error("Find new crash reports %s",
- crash_report)
- failure += 1
- self.result_info["Crashes"] += 1
- except IGNORE_EXCEPTIONS as e:
- self.log.error("Exception error %s", str(e))
- self.result_info["Exception Errors"] += 1
- if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
- except Exception as e:
- self.finishing_time = time.time()
- raise
- self.dut.log.info("Crashes found: %s", failure)
- if failure:
- return "%s crashes" % failure
- else:
- return ""
-
- def call_test(self):
- failure = 0
- total_count = 0
- while time.time() < self.finishing_time:
- total_count += 1
- try:
- self.dut.log.info(dict(self.result_info))
- self.result_info["Total Calls"] += 1
- duration = random.randrange(self.min_phone_call_duration,
- self.max_phone_call_duration)
- # Current Voice RAT
- self.dut.log.info("Current Voice RAT is %s",
- get_current_voice_rat(self.log, self.dut))
- self.dut.log.info("Make call to %s with call duration %s",
- self.call_server_number, duration)
- if not initiate_call(self.log, self.dut,
- self.call_server_number):
- self.dut.log.error("Initiate phone call to %s failed.",
- self.call_server_number)
- self.result_info["Call initiation failure"] += 1
- failure += 1
- self._take_bug_report("%s_call_initiation_failure" %
- self.test_name,
- time.strftime("%m-%d-%Y-%H-%M-%S"))
- continue
- elapse_time = 0
- interval = min(60, duration)
- while elapse_time < duration:
- interval = min(duration - elapse_time, interval)
- time.sleep(interval)
- elapse_time += interval
- if not is_phone_in_call(self.log, self.dut):
- self.dut.log.error("Call droped.")
- self.result_info["Call drop"] += 1
- failure += 1
- self._take_bug_report(
- "%s_call_drop" % self.test_name,
- time.strftime("%m-%d-%Y-%H-%M-%S"))
- break
- else:
- self.dut.log.info("DUT is in call")
- else:
- hangup_call(self.log, self.dut)
- self.dut.log.info("Call test succeed.")
- ensure_phone_idle(self.log, self.dut)
- self.dut.droid.goToSleepNow()
- time.sleep(random.randrange(0, self.max_sleep_time))
- except IGNORE_EXCEPTIONS as e:
- self.log.error("Exception error %s", str(e))
- self.result_info["Exception Errors"] += 1
- if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
- except Exception as e:
- self.finishing_time = time.time()
- raise
- self.dut.log.info("Call test failure: %s/%s", failure, total_count)
- if failure:
- return "Call test failure: %s/%s" % (failure, total_count)
- else:
- return ""
-
- def volte_modechange_volte_test(self):
- failure = 0
- total_count = 0
- sub_id = self.dut.droid.subscriptionGetDefaultSubId()
- while time.time() < self.finishing_time:
- total_count += 1
- try:
- self.dut.log.info(dict(self.result_info))
- self.result_info["Total Calls"] += 1
- duration = random.randrange(self.min_phone_call_duration,
- self.max_phone_call_duration)
- # Current Voice RAT
- self.dut.log.info("Current Voice RAT is %s",
- get_current_voice_rat(self.log, self.dut))
- self.dut.log.info("Make call to %s with call duration %s",
- self.call_server_number, duration)
- if not initiate_call(self.log, self.dut,
- self.call_server_number):
- self.dut.log.error("Initiate phone call to %s failed.",
- self.call_server_number)
- self.result_info["Call initiation failure"] += 1
- failure += 1
- self._take_bug_report("%s_call_initiation_failure" %
- self.test_name,
- time.strftime("%m-%d-%Y-%H-%M-%S"))
- continue
- elapse_time = 0
- interval = min(5, duration)
- while elapse_time < duration:
- interval = min(duration - elapse_time, interval)
- time.sleep(interval)
- elapse_time += interval
- if not is_phone_in_call_volte(self.log, self.dut):
- self.dut.log.error("Call not VoLTE")
- self.result_info["Call not VoLTE"] += 1
- failure += 1
- self._take_bug_report(
- "%s_not_in_volte" % self.test_name,
- time.strftime("%m-%d-%Y-%H-%M-%S"))
- break
- else:
- self.dut.log.info("DUT is in VoLTE call")
- else:
- hangup_call(self.log, self.dut)
- self.dut.log.info("VoLTE test succeed.")
-
- # ModePref change to non-LTE
- network_preference_list = [
- NETWORK_MODE_TDSCDMA_GSM_WCDMA,
- NETWORK_MODE_WCDMA_ONLY, NETWORK_MODE_GLOBAL,
- NETWORK_MODE_CDMA, NETWORK_MODE_GSM_ONLY
- ]
- network_preference = random.choice(network_preference_list)
- set_preferred_network_mode_pref(self.dut.log, self.dut,
- sub_id, network_preference)
- time.sleep(WAIT_TIME_AFTER_MODE_CHANGE)
- self.dut.log.info(
- "Current Voice RAT is %s",
- get_current_voice_rat(self.log, self.dut))
-
- # ModePref change back to with LTE
- set_preferred_network_mode_pref(
- self.dut.log, self.dut, sub_id,
- NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA)
- time.sleep(WAIT_TIME_AFTER_MODE_CHANGE)
-
- except IGNORE_EXCEPTIONS as e:
- self.log.error("Exception error %s", str(e))
- self.result_info["Exception Errors"] += 1
- if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
- except Exception as e:
- self.finishing_time = time.time()
- raise
- self.dut.log.info("VoLTE test failure: %s/%s", failure,
- total_count)
- if failure:
- return "VoLTE test failure: %s/%s" % (failure, total_count)
- else:
- return ""
-
- def message_test(self):
- failure = 0
- total_count = 0
- message_type_map = {0: "SMS", 1: "MMS"}
- max_length_map = {0: self.max_sms_length, 1: self.max_mms_length}
- min_length_map = {0: self.min_sms_length, 1: self.min_mms_length}
- message_func_map = {
- 0: sms_send_receive_verify,
- 1: mms_send_receive_verify
- }
- while time.time() < self.finishing_time:
- try:
- self.dut.log.info(dict(self.result_info))
- total_count += 1
- selection = random.randrange(0, 2)
- message_type = message_type_map[selection]
- self.result_info["Total %s" % message_type] += 1
- length = random.randrange(min_length_map[selection],
- max_length_map[selection] + 1)
- text = rand_ascii_str(length)
- message_content_map = {
- 0: [text],
- 1: [("Mms Message", text, None)]
- }
- if not message_func_map[selection](
- self.log, self.dut, self.dut,
- message_content_map[selection]):
- self.log.error("%s of length %s from self to self fails",
- message_type, length)
- self.result_info["%s failure" % message_type] += 1
- #self._take_bug_report("%s_messaging_failure" % self.test_name,
- # time.strftime("%m-%d-%Y-%H-%M-%S"))
- failure += 1
- else:
- self.dut.log.info(
- "%s of length %s from self to self succeed",
- message_type, length)
- self.dut.droid.goToSleepNow()
- time.sleep(random.randrange(0, self.max_sleep_time))
- except IGNORE_EXCEPTIONS as e:
- self.log.error("Exception error %s", str(e))
- self.result_info["Exception Errors"] += 1
- if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
- except Exception as e:
- self.finishing_time = time.time()
- raise
- self.dut.log.info("Messaging test failure: %s/%s", failure,
- total_count)
- if failure / total_count > 0.1:
- return "Messaging test failure: %s/%s" % (failure, total_count)
- else:
- return ""
-
- def data_test(self):
- failure = 0
- total_count = 0
- tcpdump_pid = None
- #file_names = ["5MB", "10MB", "20MB", "50MB", "200MB", "512MB", "1GB"]
- file_names = ["5MB", "10MB", "20MB", "50MB", "200MB", "512MB"]
- while time.time() < self.finishing_time:
- total_count += 1
- pull_tcpdump = False
- try:
- self.dut.log.info(dict(self.result_info))
- self.result_info["Total file download"] += 1
- selection = random.randrange(0, len(file_names))
- file_name = file_names[selection]
- (tcpdump_pid, tcpdump_file) = \
- start_adb_tcpdump(self.dut, self.test_name, mask="all")
- if not active_file_download_test(self.log, self.dut,
- file_name):
- self.result_info["%s file download failure" %
- file_name] += 1
- failure += 1
- pull_tcpdump = True
- self._take_bug_report("%s_download_failure" %
- self.test_name,
- time.strftime("%m-%d-%Y-%H-%M-%S"))
- self.dut.droid.goToSleepNow()
- time.sleep(random.randrange(0, self.max_sleep_time))
- except IGNORE_EXCEPTIONS as e:
- self.log.error("Exception error %s", str(e))
- self.result_info["Exception Errors"] += 1
- if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
- except Exception as e:
- self.finishing_time = time.time()
- raise
- finally:
- if tcpdump_pid is not None:
- stop_adb_tcpdump(self.dut, tcpdump_pid, tcpdump_file,
- pull_tcpdump)
- self.dut.log.info("File download test failure: %s/%s", failure,
- total_count)
- if failure / total_count > 0.1:
- return "File download test failure: %s/%s" % (failure, total_count)
- else:
- return ""
-
- def parallel_tests(self, setup_func=None):
- if setup_func and not setup_func():
- self.log.error("Test setup %s failed", setup_func.__name__)
- return False
- self.result_info = collections.defaultdict(int)
- self.finishing_time = time.time() + self.max_run_time
- results = run_multithread_func(self.log, [(self.call_test, []), (
- self.message_test, []), (self.data_test, []),
- (self.crash_check_test, [])])
- self.log.info(dict(self.result_info))
- error_message = " ".join(results).strip()
- if error_message:
- self.log.error(error_message)
- fail(error_message)
- return True
-
- def parallel_volte_tests(self, setup_func=None):
- if setup_func and not setup_func():
- self.log.error("Test setup %s failed", setup_func.__name__)
- return False
- self.result_info = collections.defaultdict(int)
- self.finishing_time = time.time() + self.max_run_time
- results = run_multithread_func(
- self.log, [(self.volte_modechange_volte_test, []),
- (self.message_test, []), (self.crash_check_test, [])])
- self.log.info(dict(self.result_info))
- error_message = " ".join(results).strip()
- if error_message:
- self.log.error(error_message)
- fail(error_message)
- return True
-
- """ Tests Begin """
-
- @test_tracker_info(uuid="d035e5b9-476a-4e3d-b4e9-6fd86c51a68d")
- @TelephonyBaseTest.tel_test_wrap
- def test_default_parallel_stress(self):
- """ Default state stress test"""
- return self.parallel_tests()
-
- @test_tracker_info(uuid="c21e1f17-3282-4f0b-b527-19f048798098")
- @TelephonyBaseTest.tel_test_wrap
- def test_lte_volte_parallel_stress(self):
- """ VoLTE on stress test"""
- return self.parallel_tests(setup_func=self._setup_lte_volte_enabled)
-
- @test_tracker_info(uuid="a317c23a-41e0-4ef8-af67-661451cfefcf")
- @TelephonyBaseTest.tel_test_wrap
- def test_csfb_parallel_stress(self):
- """ LTE non-VoLTE stress test"""
- return self.parallel_tests(setup_func=self._setup_lte_volte_disabled)
-
- @test_tracker_info(uuid="fdb791bf-c414-4333-9fa3-cc18c9b3b234")
- @TelephonyBaseTest.tel_test_wrap
- def test_wfc_parallel_stress(self):
- """ Wifi calling on stress test"""
- return self.parallel_tests(setup_func=self._setup_wfc)
-
- @test_tracker_info(uuid="4566eef6-55de-4ac8-87ee-58f2ef41a3e8")
- @TelephonyBaseTest.tel_test_wrap
- def test_3g_parallel_stress(self):
- """ 3G stress test"""
- return self.parallel_tests(setup_func=self._setup_3g)
-
- @test_tracker_info(uuid="f34f1a31-3948-4675-8698-372a83b8088d")
- @TelephonyBaseTest.tel_test_wrap
- def test_call_2g_parallel_stress(self):
- """ 2G call stress test"""
- return self.parallel_tests(setup_func=self._setup_2g)
-
- @test_tracker_info(uuid="af580fca-fea6-4ca5-b981-b8c710302d37")
- @TelephonyBaseTest.tel_test_wrap
- def test_volte_modeprefchange_parallel_stress(self):
- """ VoLTE Mode Pref call stress test"""
- return self.parallel_volte_tests(
- setup_func=self._setup_lte_volte_enabled)
-
- """ Tests End """
diff --git a/acts/tests/google/tel/live/TelLiveSmsTest.py b/acts/tests/google/tel/live/TelLiveSmsTest.py
index 9b4e874..c100379 100644
--- a/acts/tests/google/tel/live/TelLiveSmsTest.py
+++ b/acts/tests/google/tel/live/TelLiveSmsTest.py
@@ -35,10 +35,13 @@
from acts.test_utils.tel.tel_test_utils import ensure_network_generation
from acts.test_utils.tel.tel_test_utils import ensure_phones_idle
from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected
+from acts.test_utils.tel.tel_test_utils import get_mobile_data_usage
+from acts.test_utils.tel.tel_test_utils import remove_mobile_data_usage_limit
from acts.test_utils.tel.tel_test_utils import mms_send_receive_verify
from acts.test_utils.tel.tel_test_utils import mms_receive_verify_after_call_hangup
from acts.test_utils.tel.tel_test_utils import multithread_func
from acts.test_utils.tel.tel_test_utils import set_call_state_listen_level
+from acts.test_utils.tel.tel_test_utils import set_mobile_data_usage_limit
from acts.test_utils.tel.tel_test_utils import setup_sim
from acts.test_utils.tel.tel_test_utils import sms_send_receive_verify
from acts.test_utils.tel.tel_video_utils import phone_setup_video
@@ -77,10 +80,8 @@
# use the second one as sms/mms help device, use the third one
# as the active call help device.
self.caller = self.android_devices[0]
- if len(self.android_devices) > 2:
- self.callee = self.android_devices[2]
- else:
- self.callee = self.android_devices[1]
+ self.callee = self.android_devices[1]
+ self.number_of_devices = 2
self.message_lengths = (50, 160, 180)
def setup_class(self):
@@ -469,6 +470,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_test_mo(ads)
@@ -492,7 +494,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
-
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_test_mt(ads)
@test_tracker_info(uuid="bb8e1a06-a4b5-4f9b-9ab2-408ace9a1deb")
@@ -515,6 +517,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mo(ads)
@@ -538,7 +541,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
-
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mt(ads)
@test_tracker_info(uuid="2c229a4b-c954-4ba3-94ba-178dc7784d03")
@@ -561,6 +564,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_test_mo(ads)
@@ -584,6 +588,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_test_mt(ads)
@@ -607,6 +612,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mo(ads)
@@ -630,6 +636,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mt(ads)
@@ -654,6 +661,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
@@ -680,6 +688,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
@@ -706,7 +715,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
-
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_test_mo(ads)
@test_tracker_info(uuid="2186e152-bf83-4d6e-93eb-b4bf9ae2d76e")
@@ -730,6 +739,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_test_mt(ads)
@@ -754,6 +764,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mo(ads)
@@ -778,6 +789,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mt(ads)
@@ -805,6 +817,7 @@
return False
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mo(ads)
@@ -832,6 +845,7 @@
return False
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mt(ads)
@@ -850,13 +864,14 @@
"""
ads = self.android_devices
- if (not phone_setup_data_general(self.log, ads[1]) and
- not phone_setup_voice_general(self.log, ads[1])):
+ if (not phone_setup_data_general(self.log, ads[1])
+ and not phone_setup_voice_general(self.log, ads[1])):
self.log.error("Failed to setup PhoneB.")
return False
if not ensure_network_generation(self.log, ads[0], GEN_4G):
self.log.error("DUT Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_test_mo(ads)
@@ -876,13 +891,14 @@
ads = self.android_devices
- if (not phone_setup_data_general(self.log, ads[1]) and
- not phone_setup_voice_general(self.log, ads[1])):
+ if (not phone_setup_data_general(self.log, ads[1])
+ and not phone_setup_voice_general(self.log, ads[1])):
self.log.error("Failed to setup PhoneB.")
return False
if not ensure_network_generation(self.log, ads[0], GEN_4G):
self.log.error("DUT Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_test_mt(ads)
@@ -907,6 +923,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mo(ads)
@@ -931,6 +948,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mt(ads)
@@ -956,6 +974,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
return self._mms_test_mo(ads)
@@ -982,6 +1001,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
@@ -1006,7 +1026,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
-
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
self.log.info("Begin In Call SMS Test.")
if not call_setup_teardown(
self.log,
@@ -1042,7 +1062,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
-
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
self.log.info("Begin In Call SMS Test.")
if not call_setup_teardown(
self.log,
@@ -1078,7 +1098,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
-
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
self.log.info("Begin In Call SMS Test.")
if not call_setup_teardown(
self.log,
@@ -1114,7 +1134,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
-
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
self.log.info("Begin In Call MMS Test.")
if not call_setup_teardown(
self.log,
@@ -1151,7 +1171,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
-
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
self.log.info("Begin In Call SMS Test.")
@@ -1190,7 +1210,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
-
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
self.log.info("Begin In Call MMS Test.")
@@ -1232,6 +1252,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mo_sms_in_3g_call(ads)
@@ -1258,6 +1279,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mt_sms_in_3g_call(ads)
@@ -1284,6 +1306,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mo_mms_in_3g_call(ads)
@@ -1310,6 +1333,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mt_mms_in_3g_call(ads)
@@ -1337,6 +1361,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
@@ -1366,7 +1391,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
-
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
return self._mt_mms_in_3g_call(ads, wifi=True)
@@ -1394,6 +1419,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mo_sms_in_csfb_call(ads)
@@ -1420,6 +1446,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mt_sms_in_csfb_call(ads)
@@ -1446,6 +1473,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mo_mms_in_csfb_call(ads)
@@ -1472,6 +1500,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mt_mms_in_csfb_call(ads)
@@ -1499,6 +1528,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
@@ -1528,6 +1558,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
@@ -1556,6 +1587,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mo_sms_in_1x_call(ads)
@@ -1582,6 +1614,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mt_sms_in_1x_call(ads)
@@ -1609,6 +1642,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mo_mms_in_1x_call(ads)
@@ -1635,6 +1669,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mt_mms_in_1x_call(ads)
@@ -1662,6 +1697,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
@@ -1690,6 +1726,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
@@ -1718,6 +1755,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mo_sms_in_1x_call(ads)
@@ -1744,6 +1782,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mt_sms_in_1x_call(ads)
@@ -1770,6 +1809,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mo_mms_in_1x_call(ads)
@@ -1796,6 +1836,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mt_mms_in_1x_call(ads)
@@ -1822,6 +1863,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
@@ -1850,6 +1892,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
@@ -1878,6 +1921,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_test_mo(ads)
@@ -1904,6 +1948,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_test_mt(ads)
@@ -1930,6 +1975,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mo(ads)
@@ -1956,6 +2002,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mt(ads)
@@ -1974,12 +2021,14 @@
ads = self.android_devices
phone_setup_voice_general(self.log, ads[0])
- tasks = [(ensure_wifi_connected, (
- self.log, ads[0], self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_voice_general, (self.log, ads[1]))]
+ tasks = [(ensure_wifi_connected,
+ (self.log, ads[0], self.wifi_network_ssid,
+ self.wifi_network_pass)), (phone_setup_voice_general,
+ (self.log, ads[1]))]
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_test_mo(ads)
@@ -1998,12 +2047,14 @@
ads = self.android_devices
phone_setup_voice_general(self.log, ads[0])
- tasks = [(ensure_wifi_connected, (
- self.log, ads[0], self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_voice_general, (self.log, ads[1]))]
+ tasks = [(ensure_wifi_connected,
+ (self.log, ads[0], self.wifi_network_ssid,
+ self.wifi_network_pass)), (phone_setup_voice_general,
+ (self.log, ads[1]))]
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_test_mt(ads)
@@ -2022,12 +2073,14 @@
ads = self.android_devices
phone_setup_voice_general(self.log, ads[0])
- tasks = [(ensure_wifi_connected, (
- self.log, ads[0], self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_voice_general, (self.log, ads[1]))]
+ tasks = [(ensure_wifi_connected,
+ (self.log, ads[0], self.wifi_network_ssid,
+ self.wifi_network_pass)), (phone_setup_voice_general,
+ (self.log, ads[1]))]
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mo(ads)
@@ -2046,12 +2099,14 @@
ads = self.android_devices
phone_setup_voice_general(self.log, ads[0])
- tasks = [(ensure_wifi_connected, (
- self.log, ads[0], self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_voice_general, (self.log, ads[1]))]
+ tasks = [(ensure_wifi_connected,
+ (self.log, ads[0], self.wifi_network_ssid,
+ self.wifi_network_pass)), (phone_setup_voice_general,
+ (self.log, ads[1]))]
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mms_test_mt(ads)
@@ -2079,6 +2134,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
self.log.info("Begin In Call SMS Test.")
if not call_setup_teardown(
@@ -2116,6 +2172,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
self.log.info("Begin In Call SMS Test.")
if not call_setup_teardown(
@@ -2153,6 +2210,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
self.log.info("Begin In Call MMS Test.")
if not call_setup_teardown(
@@ -2190,6 +2248,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
self.log.info("Begin In Call MMS Test.")
if not call_setup_teardown(
@@ -2222,6 +2281,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
if not video_call_setup_teardown(
self.log,
@@ -2255,6 +2315,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
if not video_call_setup_teardown(
self.log,
@@ -2288,6 +2349,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
if not video_call_setup_teardown(
self.log,
@@ -2321,6 +2383,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
if not video_call_setup_teardown(
self.log,
@@ -2358,6 +2421,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
self.log.info("Begin In Call SMS Test.")
if not call_setup_teardown(
@@ -2398,6 +2462,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
self.log.info("Begin In Call SMS Test.")
if not call_setup_teardown(
@@ -2438,6 +2503,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mo_mms_in_2g_call(ads)
@@ -2464,6 +2530,7 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._mt_mms_in_2g_call(ads)
@@ -2490,10 +2557,11 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
- return self._mo_mms_in_2g_call(ads, wifi=True)
+ return self._mo_mms_in_2g_call(ads)
@test_tracker_info(uuid="060def89-01bd-4b44-a49b-a4536fe39165")
@TelephonyBaseTest.tel_test_wrap
@@ -2518,7 +2586,128 @@
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
self.wifi_network_pass)
- return self._mt_mms_in_2g_call(ads, wifi=True)
+ return self._mt_mms_in_2g_call(ads)
+
+ @test_tracker_info(uuid="7de95a56-8055-4c0c-9438-f249403c6078")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_sms_mo_general_after_mobile_data_usage_limit_reached(self):
+ """Test SMS send after mobile data usage limit is reached.
+
+ Airplane mode is off.
+ Set the data limit to the current usage
+ Send SMS from PhoneA to PhoneB.
+ Verify received message on PhoneB is correct.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ ads = self.android_devices
+ try:
+ subscriber_id = ads[0].droid.telephonyGetSubscriberId()
+ data_usage = get_mobile_data_usage(ads[0], subscriber_id)
+ set_mobile_data_usage_limit(ads[0], data_usage, subscriber_id)
+
+ tasks = [(phone_setup_voice_general, (self.log, ads[0])),
+ (phone_setup_voice_general, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ return self._sms_test_mo(ads)
+ finally:
+ remove_mobile_data_usage_limit(ads[0], subscriber_id)
+
+ @test_tracker_info(uuid="df56687f-0932-4b13-952c-ae0ce30b1d7a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_sms_mt_general_after_mobile_data_usage_limit_reached(self):
+ """Test SMS receive after mobile data usage limit is reached.
+
+ Airplane mode is off.
+ Set the data limit to the current usage
+ Send SMS from PhoneB to PhoneA.
+ Verify received message on PhoneA is correct.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ ads = self.android_devices
+ try:
+ subscriber_id = ads[0].droid.telephonyGetSubscriberId()
+ data_usage = get_mobile_data_usage(ads[0], subscriber_id)
+ set_mobile_data_usage_limit(ads[0], data_usage, subscriber_id)
+
+ tasks = [(phone_setup_voice_general, (self.log, ads[0])),
+ (phone_setup_voice_general, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ return self._sms_test_mt(ads)
+ finally:
+ remove_mobile_data_usage_limit(ads[0], subscriber_id)
+
+ @test_tracker_info(uuid="131f98c6-3b56-44df-b5e7-66f33e2cf117")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_mms_mo_general_after_mobile_data_usage_limit_reached(self):
+ """Test MMS send after mobile data usage limit is reached.
+
+ Airplane mode is off.
+ Set the data limit to the current usage
+ Send MMS from PhoneA to PhoneB.
+ Verify MMS cannot be send.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ ads = self.android_devices
+ try:
+ subscriber_id = ads[0].droid.telephonyGetSubscriberId()
+ data_usage = get_mobile_data_usage(ads[0], subscriber_id)
+ set_mobile_data_usage_limit(ads[0], data_usage, subscriber_id)
+
+ tasks = [(phone_setup_voice_general, (self.log, ads[0])),
+ (phone_setup_voice_general, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ return not self._mms_test_mo(ads)
+ finally:
+ remove_mobile_data_usage_limit(ads[0], subscriber_id)
+
+ @test_tracker_info(uuid="051e259f-0cb9-417d-9a68-8e8a4266fca1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_mms_mt_general_after_mobile_data_usage_limit_reached(self):
+ """Test MMS receive after mobile data usage limit is reached.
+
+ Airplane mode is off.
+ Set the data limit to the current usage
+ Send MMS from PhoneB to PhoneA.
+ Verify MMS cannot be received.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ ads = self.android_devices
+ try:
+ subscriber_id = ads[0].droid.telephonyGetSubscriberId()
+ data_usage = get_mobile_data_usage(ads[0], subscriber_id)
+ set_mobile_data_usage_limit(ads[0], data_usage, subscriber_id)
+
+ tasks = [(phone_setup_voice_general, (self.log, ads[0])),
+ (phone_setup_voice_general, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ return not self._mms_test_mt(ads)
+ finally:
+ remove_mobile_data_usage_limit(ads[0], subscriber_id)
diff --git a/acts/tests/google/tel/live/TelLiveStressCallTest.py b/acts/tests/google/tel/live/TelLiveStressCallTest.py
index 42f85a9..ebbea5f 100644
--- a/acts/tests/google/tel/live/TelLiveStressCallTest.py
+++ b/acts/tests/google/tel/live/TelLiveStressCallTest.py
@@ -24,15 +24,16 @@
from acts.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
from acts.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts.test_utils.tel.tel_test_utils import ensure_phone_default_state
from acts.test_utils.tel.tel_test_utils import ensure_phone_subscription
from acts.test_utils.tel.tel_test_utils import ensure_phones_idle
from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected
from acts.test_utils.tel.tel_test_utils import hangup_call
from acts.test_utils.tel.tel_test_utils import set_wfc_mode
from acts.test_utils.tel.tel_test_utils import sms_send_receive_verify
+from acts.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts.test_utils.tel.tel_test_utils import verify_incall_state
from acts.test_utils.tel.tel_test_utils import multithread_func
+from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
@@ -48,6 +49,8 @@
from acts.test_utils.tel.tel_video_utils import video_call_setup
from acts.test_utils.tel.tel_video_utils import \
is_phone_in_call_video_bidirectional
+from acts.logger import epoch_to_log_line_timestamp
+from acts.utils import get_current_epoch_time
from acts.utils import rand_ascii_str
@@ -56,13 +59,12 @@
super(TelLiveStressCallTest, self).setup_class()
self.caller = self.android_devices[0]
self.callee = self.android_devices[1]
+ self.number_of_devices = 2
self.user_params["telephony_auto_rerun"] = False
self.wifi_network_ssid = self.user_params.get(
- "wifi_network_ssid") or self.user_params.get(
- "wifi_network_ssid_2g")
+ "wifi_network_ssid") or self.user_params.get("wifi_network_ssid_2g")
self.wifi_network_pass = self.user_params.get(
- "wifi_network_pass") or self.user_params.get(
- "wifi_network_pass_2g")
+ "wifi_network_pass") or self.user_params.get("wifi_network_pass_2g")
self.phone_call_iteration = int(
self.user_params.get("phone_call_iteration", 500))
self.phone_call_duration = int(
@@ -72,6 +74,9 @@
return True
+ def on_fail(self, test_name, begin_time):
+ pass
+
def _setup_wfc(self):
for ad in self.android_devices:
if not ensure_wifi_connected(
@@ -93,6 +98,28 @@
ad.log.info("Phone is in WFC enabled state.")
return True
+ def _setup_wfc_apm(self):
+ for ad in self.android_devices:
+ toggle_airplane_mode(ad.log, ad, True)
+ if not ensure_wifi_connected(
+ ad.log,
+ ad,
+ self.wifi_network_ssid,
+ self.wifi_network_pass,
+ retries=3):
+ ad.log.error("Phone Wifi connection fails.")
+ return False
+ ad.log.info("Phone WIFI is connected successfully.")
+ if not set_wfc_mode(self.log, ad, WFC_MODE_WIFI_PREFERRED):
+ ad.log.error("Phone failed to enable Wifi-Calling.")
+ return False
+ ad.log.info("Phone is set in Wifi-Calling successfully.")
+ if not phone_idle_iwlan(self.log, ad):
+ ad.log.error("Phone is not in WFC enabled state.")
+ return False
+ ad.log.info("Phone is in WFC enabled state.")
+ return True
+
def _setup_vt(self):
ads = self.android_devices
tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
@@ -170,6 +197,7 @@
for i in range(1, self.phone_call_iteration + 1):
msg = "Stress Call Test %s Iteration: <%s> / <%s>" % (
self.test_name, i, self.phone_call_iteration)
+ begin_time = get_current_epoch_time()
self.log.info(msg)
iteration_result = True
ensure_phones_idle(self.log, self.android_devices)
@@ -179,16 +207,26 @@
iteration_result = False
self.log.error("%s call dialing failure.", msg)
else:
- if network_check_func and not network_check_func(self.log,
- self.caller):
+ if network_check_func and not network_check_func(
+ self.log, self.caller):
fail_count["caller_network_check"] += 1
+ reasons = self.caller.search_logcat(
+ "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause",
+ begin_time)
+ if reasons:
+ self.caller.log.info(reasons[-1]["log_message"])
iteration_result = False
self.log.error("%s network check %s failure.", msg,
network_check_func.__name__)
- if network_check_func and not network_check_func(self.log,
- self.callee):
+ if network_check_func and not network_check_func(
+ self.log, self.callee):
fail_count["callee_network_check"] += 1
+ reasons = self.callee.search_logcat(
+ "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause",
+ begin_time)
+ if reasons:
+ self.callee.log.info(reasons[-1]["log_message"])
iteration_result = False
self.log.error("%s network check failure.", msg)
@@ -208,8 +246,9 @@
self.log.info("%s %s", msg, iteration_result)
if not iteration_result:
- self._take_bug_report("%s_%s" % (self.test_name, i),
- self.begin_time)
+ self._take_bug_report("%s_CallNo_%s" % (self.test_name, i),
+ begin_time)
+ start_qxdm_loggers(self.log, self.android_devices)
if self.sleep_time_between_test_iterations:
self.caller.droid.goToSleepNow()
@@ -317,7 +356,7 @@
""" Wifi calling call stress test
Steps:
- 1. Make Sure PhoneA and PhoneB in Wifi Calling mode.
+ 1. Make Sure PhoneA and PhoneB in WFC On + Wifi Connected
2. Call from PhoneA to PhoneB, hang up on PhoneA.
3, Repeat 2 around N times based on the config setup
@@ -333,6 +372,28 @@
setup_func=self._setup_wfc,
network_check_func=is_phone_in_call_iwlan)
+ @test_tracker_info(uuid="be45c620-b45b-4a06-8424-b17d744d0735")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_wifi_calling_stress_apm(self):
+ """ Wifi calling in AirPlaneMode call stress test
+
+ Steps:
+ 1. Make Sure PhoneA and PhoneB in WFC On + APM ON + Wifi Connected
+ 2. Call from PhoneA to PhoneB, hang up on PhoneA.
+ 3, Repeat 2 around N times based on the config setup
+
+ Expected Results:
+ 1, Verify phone is at IDLE state
+ 2, Verify the phone is at ACTIVE, if it is in dialing, then we retry
+ 3, Verify the phone is IDLE after hung up
+
+ Returns:
+ True if pass; False if fail.
+ """
+ return self.stress_test(
+ setup_func=self._setup_wfc_apm,
+ network_check_func=is_phone_in_call_iwlan)
+
@test_tracker_info(uuid="8af0454b-b4db-46d8-b5cc-e13ec5bc59ab")
@TelephonyBaseTest.tel_test_wrap
def test_call_3g_stress(self):
diff --git a/acts/tests/google/tel/live/TelLiveStressTest.py b/acts/tests/google/tel/live/TelLiveStressTest.py
index 6cb0bca..6456cd8 100644
--- a/acts/tests/google/tel/live/TelLiveStressTest.py
+++ b/acts/tests/google/tel/live/TelLiveStressTest.py
@@ -18,13 +18,16 @@
"""
import collections
+import json
+import os
import random
import time
+
+from acts import utils
from acts.asserts import fail
from acts.test_decorators import test_tracker_info
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_ONLY
+from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
from acts.test_utils.tel.tel_defines import NETWORK_MODE_WCDMA_ONLY
from acts.test_utils.tel.tel_defines import NETWORK_MODE_GLOBAL
from acts.test_utils.tel.tel_defines import NETWORK_MODE_CDMA
@@ -32,46 +35,54 @@
from acts.test_utils.tel.tel_defines import NETWORK_MODE_TDSCDMA_GSM_WCDMA
from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA
from acts.test_utils.tel.tel_defines import WAIT_TIME_AFTER_MODE_CHANGE
+from acts.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts.test_utils.tel.tel_test_utils import active_file_download_test
+from acts.test_utils.tel.tel_test_utils import is_phone_in_call
from acts.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts.test_utils.tel.tel_test_utils import ensure_phone_default_state
-from acts.test_utils.tel.tel_test_utils import ensure_phone_subscription
-from acts.test_utils.tel.tel_test_utils import ensure_phones_idle
from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected
from acts.test_utils.tel.tel_test_utils import hangup_call
+from acts.test_utils.tel.tel_test_utils import hangup_call_by_adb
+from acts.test_utils.tel.tel_test_utils import initiate_call
from acts.test_utils.tel.tel_test_utils import run_multithread_func
from acts.test_utils.tel.tel_test_utils import set_wfc_mode
from acts.test_utils.tel.tel_test_utils import sms_send_receive_verify
+from acts.test_utils.tel.tel_test_utils import start_adb_tcpdump
+from acts.test_utils.tel.tel_test_utils import stop_adb_tcpdump
+from acts.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts.test_utils.tel.tel_test_utils import mms_send_receive_verify
-from acts.test_utils.tel.tel_test_utils import verify_incall_state
from acts.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
+from acts.test_utils.tel.tel_test_utils import wait_for_in_call_active
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
from acts.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts.test_utils.tel.tel_voice_utils import phone_setup_iwlan
from acts.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
from acts.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
from acts.test_utils.tel.tel_voice_utils import phone_setup_volte
from acts.test_utils.tel.tel_voice_utils import phone_idle_iwlan
from acts.test_utils.tel.tel_voice_utils import get_current_voice_rat
-from acts.logger import epoch_to_log_line_timestamp
from acts.utils import get_current_epoch_time
from acts.utils import rand_ascii_str
-from acts.controllers.sl4a_lib.rpc_client import Sl4aProtocolError
-
-IGNORE_EXCEPTIONS = (BrokenPipeError, Sl4aProtocolError)
-EXCEPTION_TOLERANCE = 20
+EXCEPTION_TOLERANCE = 5
class TelLiveStressTest(TelephonyBaseTest):
def setup_class(self):
super(TelLiveStressTest, self).setup_class()
self.dut = self.android_devices[0]
- self.helper = self.android_devices[1]
+ self.single_phone_test = self.user_params.get("single_phone_test",
+ False)
+ if len(self.android_devices) == 1:
+ self.single_phone_test = True
+ if self.single_phone_test:
+ self.android_devices = self.android_devices[:1]
+ self.call_server_number = self.user_params.get(
+ "call_server_number", "+17124325335")
+ else:
+ self.android_devices = self.android_devices[:2]
self.user_params["telephony_auto_rerun"] = False
self.wifi_network_ssid = self.user_params.get(
"wifi_network_ssid") or self.user_params.get(
@@ -83,8 +94,9 @@
self.user_params.get("phone_call_iteration", 500))
self.max_phone_call_duration = int(
self.user_params.get("max_phone_call_duration", 600))
+ self.min_sleep_time = int(self.user_params.get("min_sleep_time", 10))
self.max_sleep_time = int(self.user_params.get("max_sleep_time", 120))
- self.max_run_time = int(self.user_params.get("max_run_time", 18000))
+ self.max_run_time = int(self.user_params.get("max_run_time", 14400))
self.max_sms_length = int(self.user_params.get("max_sms_length", 1000))
self.max_mms_length = int(self.user_params.get("max_mms_length", 160))
self.min_sms_length = int(self.user_params.get("min_sms_length", 1))
@@ -96,6 +108,14 @@
return True
+ def setup_test(self):
+ super(TelLiveStressTest, self).setup_test()
+ self.result_info = collections.defaultdict(int)
+ self._init_perf_json()
+
+ def on_fail(self, test_name, begin_time):
+ pass
+
def _setup_wfc(self):
for ad in self.android_devices:
if not ensure_wifi_connected(
@@ -149,275 +169,408 @@
ad.log.info("RAT 2G is enabled successfully.")
return True
- def _send_message(self, ads):
+ def _send_message(self, max_wait_time=2 * MAX_WAIT_TIME_SMS_RECEIVE):
+ if self.single_phone_test:
+ ads = [self.dut, self.dut]
+ else:
+ ads = self.android_devices[:]
+ random.shuffle(ads)
selection = random.randrange(0, 2)
message_type_map = {0: "SMS", 1: "MMS"}
max_length_map = {0: self.max_sms_length, 1: self.max_mms_length}
min_length_map = {0: self.min_sms_length, 1: self.min_mms_length}
length = random.randrange(min_length_map[selection],
max_length_map[selection] + 1)
- text = rand_ascii_str(length)
- message_content_map = {0: [text], 1: [("Mms Message", text, None)]}
message_func_map = {
0: sms_send_receive_verify,
1: mms_send_receive_verify
}
- self.result_info["Total %s" % message_type_map[selection]] += 1
+ message_type = message_type_map[selection]
+ the_number = self.result_info["%s Total" % message_type] + 1
+ begin_time = get_current_epoch_time()
+ start_qxdm_loggers(self.log, self.android_devices)
+ log_msg = "The %s-th %s test: of length %s from %s to %s" % (
+ the_number, message_type, length, ads[0].serial, ads[1].serial)
+ self.log.info(log_msg)
+ for ad in self.android_devices:
+ for i in range(3):
+ try:
+ ad.droid.logI(log_msg)
+ break
+ except Exception as e:
+ if i == 2:
+ ad.log.info("SL4A error: %s", e)
+ raise
+ else:
+ time.sleep(5)
+ text = "%s: " % log_msg
+ text_length = len(text)
+ if length < text_length:
+ text = text[:length]
+ else:
+ text += rand_ascii_str(length - text_length)
+ message_content_map = {0: [text], 1: [(log_msg, text, None)]}
+ incall_non_ims = False
+ for ad in self.android_devices:
+ if ad.droid.telecomIsInCall() and (
+ not ad.droid.telephonyIsImsRegistered()):
+ incall_non_ims = True
+ break
+
if not message_func_map[selection](self.log, ads[0], ads[1],
- message_content_map[selection]):
- self.log.error("%s of length %s from %s to %s fails",
- message_type_map[selection], length, ads[0].serial,
- ads[1].serial)
- self.result_info["%s failure" % message_type_map[selection]] += 1
+ message_content_map[selection],
+ max_wait_time):
+ self.result_info["%s Total" % message_type] += 1
+ if message_type == "SMS":
+ self.log.error("%s fails", log_msg)
+ self.result_info["%s Failure" % message_type] += 1
+ self._take_bug_report("%s_%s_No_%s_failure" %
+ (self.test_name, message_type,
+ the_number), begin_time)
+ else:
+ if incall_non_ims:
+ self.log.info(
+ "Device not in IMS, MMS in call is not support")
+ self.result_info["Expected In-call MMS failure"] += 1
+ return True
+ else:
+ self.log.error("%s fails", log_msg)
+ self.result_info["MMS failure"] += 1
+ if self.result_info["MMS failure"] == 1:
+ self._take_bug_report("%s_%s_No_%s_failure" %
+ (self.test_name, message_type,
+ the_number), begin_time)
return False
else:
- self.log.info("%s of length %s from %s to %s succeed",
- message_type_map[selection], length, ads[0].serial,
- ads[1].serial)
+ self.result_info["%s Total" % message_type] += 1
+ self.log.info("%s succeed", log_msg)
+ self.result_info["%s Success" % message_type] += 1
return True
- def _make_phone_call(self, ads):
- self.result_info["Total Calls"] += 1
- if not call_setup_teardown(
+ def _make_phone_call(self, call_verification_func=None):
+ ads = self.android_devices[:]
+ if not self.single_phone_test:
+ random.shuffle(ads)
+ for ad in ads:
+ hangup_call_by_adb(ad)
+ the_number = self.result_info["Call Total"] + 1
+ duration = random.randrange(self.min_phone_call_duration,
+ self.max_phone_call_duration)
+ result = True
+ if self.single_phone_test:
+ log_msg = "The %s-th phone call test for %ssec duration" % (
+ the_number, duration)
+ else:
+ log_msg = "The %s-th phone call test from %s to %s for %ssec" % (
+ the_number, ads[0].serial, ads[1].serial, duration)
+ self.log.info(log_msg)
+ for ad in ads:
+ ad.droid.logI(log_msg)
+ begin_time = get_current_epoch_time()
+ start_qxdm_loggers(self.log, self.android_devices, begin_time)
+ if self.single_phone_test:
+ call_setup_result = initiate_call(
self.log,
- ads[0],
- ads[1],
- ad_hangup=ads[random.randrange(0, 2)],
- wait_time_in_call=random.randrange(
- self.min_phone_call_duration,
- self.max_phone_call_duration)):
- self.log.error("Call setup and teardown failed.")
- self.result_info["Call Failure"] += 1
- return False
- self.log.info("Call setup and teardown succeed.")
- return True
+ self.dut,
+ self.call_server_number,
+ wait_time_betwn_call_initcheck=5) and wait_for_in_call_active(
+ self.dut, 60, 3)
+ else:
+ call_setup_result = call_setup_teardown(
+ self.log, ads[0], ads[1], ad_hangup=None, wait_time_in_call=0)
+ if not call_setup_result:
+ self.log.error("%s: Setup Call failed.", log_msg)
+ self.result_info["Call Setup Failure"] += 1
+ failure_reason = "setup"
+ result = False
+ else:
+ elapsed_time = 0
+ check_interval = 5
+ while (elapsed_time < duration):
+ check_interval = min(check_interval, duration - elapsed_time)
+ time.sleep(check_interval)
+ elapsed_time += check_interval
+ time_message = "at <%s>/<%s> second." % (elapsed_time,
+ duration)
+ for ad in ads:
+ if not call_verification_func(self.log, ad):
+ ad.log.error("Call is NOT in correct %s state at %s",
+ call_verification_func.__name__,
+ time_message)
+ self.result_info["Call Maintenance Failure"] += 1
+ failure_reason = "maintenance"
+ reasons = ad.search_logcat(
+ "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause",
+ begin_time)
+ if reasons:
+ ad.log.info(reasons[-1]["log_message"])
+ hangup_call(self.log, ads[0])
+ result = False
+ else:
+ ad.log.info("Call is in correct %s state at %s",
+ call_verification_func.__name__,
+ time_message)
+ if not result:
+ break
+ if not hangup_call(self.log, ads[0]):
+ time.sleep(10)
+ for ad in ads:
+ if ad.droid.telecomIsInCall():
+ ad.log.error("Still in call after hungup")
+ self.result_info["Call Teardown Failure"] += 1
+ failure_reason = "teardown"
+ result = False
+ self.result_info["Call Total"] += 1
+ if not result:
+ self.log.info("%s test failed", log_msg)
+ test_name = "%s_call_No_%s_%s_failure" % (self.test_name,
+ the_number,
+ failure_reason)
+ for ad in ads:
+ log_path = os.path.join(self.log_path, test_name,
+ "%s_binder" % ad.serial)
+ utils.create_dir(log_path)
+ ad.adb.pull("/sys/kernel/debug/binder %s" % log_path)
+ self._take_bug_report(test_name, begin_time)
+ else:
+ self.log.info("%s test succeed", log_msg)
+ self.result_info["Call Success"] += 1
+ if self.result_info["Call Total"] % 50 == 0:
+ test_name = "%s_call_No_%s_success_binder_logs" % (
+ self.test_name, the_number)
+ for ad in ads:
+ log_path = os.path.join(self.log_path, test_name,
+ "%s_binder" % ad.serial)
+ utils.create_dir(log_path)
+ ad.adb.pull("/sys/kernel/debug/binder %s" % log_path)
+ return result
- def _make_volte_call(self, ads):
- self.result_info["Total Calls"] += 1
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=ads[0],
- verify_caller_func=is_phone_in_call_volte,
- verify_callee_func=None,
- wait_time_in_call=random.randrange(
- self.min_phone_call_duration,
- self.max_phone_call_duration)):
- self.log.error("Call setup and teardown failed.")
- self.result_info["Call Failure"] += 1
+ def _prefnetwork_mode_change(self, sub_id):
+ # ModePref change to non-LTE
+ begin_time = get_current_epoch_time()
+ start_qxdm_loggers(self.log, self.android_devices)
+ network_preference_list = [
+ NETWORK_MODE_TDSCDMA_GSM_WCDMA, NETWORK_MODE_WCDMA_ONLY,
+ NETWORK_MODE_GLOBAL, NETWORK_MODE_CDMA, NETWORK_MODE_GSM_ONLY
+ ]
+ network_preference = random.choice(network_preference_list)
+ set_preferred_network_mode_pref(self.log, self.dut, sub_id,
+ network_preference)
+ time.sleep(WAIT_TIME_AFTER_MODE_CHANGE)
+ self.dut.log.info("Current Voice RAT is %s",
+ get_current_voice_rat(self.log, self.dut))
+
+ # ModePref change back to with LTE
+ set_preferred_network_mode_pref(self.log, self.dut, sub_id,
+ NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA)
+ time.sleep(WAIT_TIME_AFTER_MODE_CHANGE)
+ rat = get_current_voice_rat(self.log, self.dut)
+ self.dut.log.info("Current Voice RAT is %s", rat)
+ self.result_info["RAT Change Total"] += 1
+ if rat != "LTE":
+ self.result_info["RAT Change Failure"] += 1
+ self._take_bug_report("%s_rat_change_failure" % self.test_name,
+ begin_time)
return False
- self.log.info("Call setup and teardown succeed.")
- return True
+ else:
+ self.result_info["RAT Change Success"] += 1
+ return True
+
+ def _get_result_message(self):
+ msg_list = [
+ "%s: %s" % (count, self.result_info[count])
+ for count in sorted(self.result_info.keys())
+ ]
+ return ", ".join(msg_list)
+
+ def _write_perf_json(self):
+ json_str = json.dumps(self.perf_data, indent=4, sort_keys=True)
+ with open(self.perf_file, 'w') as f:
+ f.write(json_str)
+
+ def _init_perf_json(self):
+ self.perf_file = os.path.join(self.log_path, "%s_perf_data_%s.json" %
+ (self.test_name, self.begin_time))
+ self.perf_data = self.android_devices[0].build_info.copy()
+ self.perf_data["model"] = self.android_devices[0].model
+ self._write_perf_json()
+
+ def _update_perf_json(self):
+ for result_key, result_value in self.result_info.items():
+ self.perf_data[result_key] = result_value
+ self._write_perf_json()
def crash_check_test(self):
failure = 0
while time.time() < self.finishing_time:
- self.dut.log.info(dict(self.result_info))
try:
- begin_time = epoch_to_log_line_timestamp(
- get_current_epoch_time())
+ self.log.info(dict(self.result_info))
+ self._update_perf_json()
+ begin_time = get_current_epoch_time()
time.sleep(self.crash_check_interval)
- crash_report = self.dut.check_crash_report("checking_crash",
- begin_time, True)
- if crash_report:
- self.dut.log.error("Find new crash reports %s",
- crash_report)
- failure += 1
- self.result_info["Crashes"] += 1
- except IGNORE_EXCEPTIONS as e:
+ for ad in self.android_devices:
+ crash_report = ad.check_crash_report(
+ "checking_crash", begin_time, log_crash_report=True)
+ if crash_report:
+ ad.log.error("Find new crash reports %s", crash_report)
+ failure += 1
+ self.result_info["Crashes"] += 1
+ except Exception as e:
self.log.error("Exception error %s", str(e))
self.result_info["Exception Errors"] += 1
- if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
- except Exception as e:
- self.finishing_time = time.time()
- raise
- self.dut.log.info("Crashes found: %s", failure)
+ self.log.info("Crashes found: %s", failure)
+ if self.result_info["Exception Errors"] >= EXCEPTION_TOLERANCE:
+ self.log.error("Too many exception errors, quit test")
+ return False
if failure:
- return "%s crashes" % failure
+ return False
else:
- return ""
+ return True
- def call_test(self):
- failure = 0
- total_count = 0
+ def call_test(self, call_verification_func=None):
while time.time() < self.finishing_time:
try:
- ads = [self.dut, self.helper]
- random.shuffle(ads)
- total_count += 1
- if not self._make_phone_call(ads):
- failure += 1
- self._take_bug_report("%s_call_failure" % self.test_name,
- time.strftime("%m-%d-%Y-%H-%M-%S"))
- self.dut.droid.goToSleepNow()
- time.sleep(random.randrange(0, self.max_sleep_time))
- except IGNORE_EXCEPTIONS as e:
+ self._make_phone_call(call_verification_func)
+ except Exception as e:
self.log.error("Exception error %s", str(e))
self.result_info["Exception Errors"] += 1
- if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
- except Exception as e:
- self.finishing_time = time.time()
- raise
- self.dut.log.info("Call test failure: %s/%s", failure, total_count)
- if failure:
- return "Call test failure: %s/%s" % (failure, total_count)
+ if self.result_info["Exception Errors"] >= EXCEPTION_TOLERANCE:
+ self.log.error("Too many exception errors, quit test")
+ return False
+ self.log.info("%s", dict(self.result_info))
+ time.sleep(
+ random.randrange(self.min_sleep_time, self.max_sleep_time))
+ if any([
+ self.result_info["Call Setup Failure"],
+ self.result_info["Call Maintenance Failure"],
+ self.result_info["Call Teardown Failure"]
+ ]):
+ return False
else:
- return ""
+ return True
+
+ def message_test(self, max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
+ while time.time() < self.finishing_time:
+ try:
+ self._send_message(max_wait_time=max_wait_time)
+ except Exception as e:
+ self.log.error("Exception error %s", str(e))
+ self.result_info["Exception Errors"] += 1
+ self.log.info(dict(self.result_info))
+ if self.result_info["Exception Errors"] >= EXCEPTION_TOLERANCE:
+ self.log.error("Too many exception errors, quit test")
+ return False
+ time.sleep(
+ random.randrange(self.min_sleep_time, self.max_sleep_time))
+ if self.result_info["SMS Failure"] or (
+ self.result_info["MMS Failure"] / self.result_info["MMS Total"]
+ > 0.3):
+ return False
+ else:
+ return True
+
+ def _data_download(self):
+ #file_names = ["5MB", "10MB", "20MB", "50MB", "200MB", "512MB", "1GB"]
+ file_names = ["5MB", "10MB", "20MB", "50MB", "200MB"]
+ begin_time = get_current_epoch_time()
+ start_qxdm_loggers(self.log, self.android_devices)
+ self.tcpdump_proc = None
+ self.dut.log.info(dict(self.result_info))
+ selection = random.randrange(0, len(file_names))
+ file_name = file_names[selection]
+ if self.result_info["File Download Failure"] < 1:
+ self.tcpdump_proc = start_adb_tcpdump(
+ self.dut, "%s_file_download" % self.test_name, mask="all")
+ self.result_info["File Download Total"] += 1
+ if not active_file_download_test(self.log, self.dut, file_name):
+ self.result_info["File Download Failure"] += 1
+ if self.result_info["File Download Failure"] == 1:
+ if self.tcpdump_proc is not None:
+ stop_adb_tcpdump(
+ self.dut, self.tcpdump_proc, True,
+ "%s_file_download_failure" % self.test_name)
+ self._take_bug_report(
+ "%s_file_download_failure" % self.test_name,
+ begin_time)
+ return False
+ else:
+ self.result_info["File Download Success"] += 1
+ if self.tcpdump_proc is not None:
+ stop_adb_tcpdump(self.dut, self.tcpdump_proc, False)
+ return True
+
+ def data_test(self):
+ while time.time() < self.finishing_time:
+ try:
+ self._data_download()
+ except Exception as e:
+ self.log.error("Exception error %s", str(e))
+ self.result_info["Exception Errors"] += 1
+ self.log.info("%s", dict(self.result_info))
+ if self.result_info["Exception Errors"] >= EXCEPTION_TOLERANCE:
+ self.log.error("Too many exception errors, quit test")
+ return False
+ time.sleep(
+ random.randrange(self.min_sleep_time, self.max_sleep_time))
+ if self.result_info["File Download Failure"] / self.result_info["File Download Total"] > 0.1:
+ return False
+ else:
+ return True
+
+ def parallel_tests(self, setup_func=None, call_verification_func=None):
+ self.log.info(self._get_result_message())
+ if setup_func and not setup_func():
+ msg = "Test setup %s failed" % setup_func.__name__
+ self.log.error(msg)
+ fail(msg)
+ if not call_verification_func:
+ call_verification_func = is_phone_in_call
+ self.finishing_time = time.time() + self.max_run_time
+ results = run_multithread_func(
+ self.log, [(self.call_test, [call_verification_func]),
+ (self.message_test, []), (self.data_test, []),
+ (self.crash_check_test, [])])
+ result_message = self._get_result_message()
+ self.log.info(result_message)
+ self._update_perf_json()
+ self.result_detail = result_message
+ return all(results)
def volte_modechange_volte_test(self):
- failure = 0
- total_count = 0
sub_id = self.dut.droid.subscriptionGetDefaultSubId()
while time.time() < self.finishing_time:
try:
- ads = [self.dut, self.helper]
- total_count += 1
- if not self._make_volte_call(ads):
- failure += 1
- self._take_bug_report("%s_call_failure" % self.test_name,
- time.strftime("%m-%d-%Y-%H-%M-%S"))
-
- # ModePref change to non-LTE
- network_preference_list = [
- NETWORK_MODE_TDSCDMA_GSM_WCDMA, NETWORK_MODE_WCDMA_ONLY,
- NETWORK_MODE_GLOBAL, NETWORK_MODE_CDMA,
- NETWORK_MODE_GSM_ONLY
- ]
- network_preference = random.choice(network_preference_list)
- set_preferred_network_mode_pref(ads[0].log, ads[0], sub_id,
- network_preference)
- time.sleep(WAIT_TIME_AFTER_MODE_CHANGE)
- self.dut.log.info("Current Voice RAT is %s",
- get_current_voice_rat(self.log, self.dut))
-
- # ModePref change back to with LTE
- set_preferred_network_mode_pref(
- ads[0].log, ads[0], sub_id,
- NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA)
- time.sleep(WAIT_TIME_AFTER_MODE_CHANGE)
- self.dut.log.info("Current Voice RAT is %s",
- get_current_voice_rat(self.log, self.dut))
-
- except IGNORE_EXCEPTIONS as e:
+ run_multithread_func(
+ self.log,
+ [(self._data_download, []),
+ (self._make_phone_call, [is_phone_in_call_volte]),
+ (self._send_message, [])])
+ self._prefnetwork_mode_change(sub_id)
+ except Exception as e:
self.log.error("Exception error %s", str(e))
self.result_info["Exception Errors"] += 1
- if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
- except Exception as e:
- self.finishing_time = time.time()
- raise
- self.dut.log.info("VoLTE test failure: %s/%s", failure,
- total_count)
- if failure:
- return "VoLTE test failure: %s/%s" % (failure, total_count)
+ self.log.info(dict(self.result_info))
+ if self.result_info["Exception Errors"] >= EXCEPTION_TOLERANCE:
+ self.log.error("Too many exception errors, quit test")
+ return False
+ if self.result_info["Call Failure"] or self.result_info["RAT Change Failure"] or self.result_info["SMS Failure"]:
+ return False
else:
- return ""
+ return True
- def message_test(self):
- failure = 0
- total_count = 0
- while time.time() < self.finishing_time:
- try:
- ads = [self.dut, self.helper]
- random.shuffle(ads)
- total_count += 1
- if not self._send_message(ads):
- failure += 1
- #self._take_bug_report("%s_messaging_failure" % self.test_name,
- # time.strftime("%m-%d-%Y-%H-%M-%S"))
- self.dut.droid.goToSleepNow()
- time.sleep(random.randrange(0, self.max_sleep_time))
- except IGNORE_EXCEPTIONS as e:
- self.log.error("Exception error %s", str(e))
- self.result_info["Exception Errors"] += 1
- if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise
- except Exception as e:
- self.finishing_time = time.time()
- raise
- self.dut.log.info("Messaging test failure: %s/%s", failure,
- total_count)
- if failure / total_count > 0.1:
- return "Messaging test failure: %s/%s" % (failure, total_count)
- else:
- return ""
-
- def data_test(self):
- failure = 0
- total_count = 0
- #file_names = ["5MB", "10MB", "20MB", "50MB", "200MB", "512MB", "1GB"]
- file_names = ["5MB", "10MB", "20MB", "50MB", "200MB", "512MB"]
- while time.time() < self.finishing_time:
- try:
- self.dut.log.info(dict(self.result_info))
- self.result_info["Total file download"] += 1
- selection = random.randrange(0, len(file_names))
- file_name = file_names[selection]
- total_count += 1
- if not active_file_download_test(self.log, self.dut,
- file_name):
- self.result_info["%s file download failure" %
- file_name] += 1
- failure += 1
- #self._take_bug_report("%s_download_failure" % self.test_name,
- # time.strftime("%m-%d-%Y-%H-%M-%S"))
- self.dut.droid.goToSleepNow()
- time.sleep(random.randrange(0, self.max_sleep_time))
- except IGNORE_EXCEPTIONS as e:
- self.log.error("Exception error %s", str(e))
- self.result_info["Exception Errors"] += 1
- if self.result_info["Exception Errors"] > EXCEPTION_TOLERANCE:
- self.finishing_time = time.time()
- raise "Too many %s errors" % IGNORE_EXCEPTIONS
- except Exception as e:
- self.log.error(e)
- self.finishing_time = time.time()
- raise
- self.dut.log.info("File download test failure: %s/%s", failure,
- total_count)
- if failure / total_count > 0.1:
- return "File download test failure: %s/%s" % (failure, total_count)
- else:
- return ""
-
- def parallel_tests(self, setup_func=None):
+ def parallel_with_network_change_tests(self, setup_func=None):
if setup_func and not setup_func():
self.log.error("Test setup %s failed", setup_func.__name__)
return False
- self.result_info = collections.defaultdict(int)
self.finishing_time = time.time() + self.max_run_time
- results = run_multithread_func(self.log, [(self.call_test, []), (
- self.message_test, []), (self.data_test, []),
- (self.crash_check_test, [])])
- self.log.info(dict(self.result_info))
- error_message = " ".join(results).strip()
- if error_message:
- self.log.error(error_message)
- fail(error_message)
- return True
-
- def parallel_volte_tests(self, setup_func=None):
- if setup_func and not setup_func():
- self.log.error("Test setup %s failed", setup_func.__name__)
- return False
- self.result_info = collections.defaultdict(int)
- self.finishing_time = time.time() + self.max_run_time
- results = run_multithread_func(
- self.log, [(self.volte_modechange_volte_test, []),
- (self.message_test, []), (self.crash_check_test, [])])
- self.log.info(dict(self.result_info))
- error_message = " ".join(results).strip()
- if error_message:
- self.log.error(error_message)
- fail(error_message)
- return True
+ results = run_multithread_func(self.log,
+ [(self.volte_modechange_volte_test, []),
+ (self.crash_check_test, [])])
+ result_message = self._get_result_message()
+ self.log.info(result_message)
+ self._update_perf_json()
+ self.result_detail = result_message
+ return all(results)
""" Tests Begin """
@@ -431,37 +584,47 @@
@TelephonyBaseTest.tel_test_wrap
def test_lte_volte_parallel_stress(self):
""" VoLTE on stress test"""
- return self.parallel_tests(setup_func=self._setup_lte_volte_enabled)
+ return self.parallel_tests(
+ setup_func=self._setup_lte_volte_enabled,
+ call_verification_func=is_phone_in_call_volte)
@test_tracker_info(uuid="a317c23a-41e0-4ef8-af67-661451cfefcf")
@TelephonyBaseTest.tel_test_wrap
def test_csfb_parallel_stress(self):
""" LTE non-VoLTE stress test"""
- return self.parallel_tests(setup_func=self._setup_lte_volte_disabled)
+ return self.parallel_tests(
+ setup_func=self._setup_lte_volte_disabled,
+ call_verification_func=is_phone_in_call_csfb)
@test_tracker_info(uuid="fdb791bf-c414-4333-9fa3-cc18c9b3b234")
@TelephonyBaseTest.tel_test_wrap
def test_wfc_parallel_stress(self):
""" Wifi calling on stress test"""
- return self.parallel_tests(setup_func=self._setup_wfc)
+ return self.parallel_tests(
+ setup_func=self._setup_wfc,
+ call_verification_func=is_phone_in_call_iwlan)
@test_tracker_info(uuid="4566eef6-55de-4ac8-87ee-58f2ef41a3e8")
@TelephonyBaseTest.tel_test_wrap
def test_3g_parallel_stress(self):
""" 3G stress test"""
- return self.parallel_tests(setup_func=self._setup_3g)
+ return self.parallel_tests(
+ setup_func=self._setup_3g,
+ call_verification_func=is_phone_in_call_3g)
@test_tracker_info(uuid="f34f1a31-3948-4675-8698-372a83b8088d")
@TelephonyBaseTest.tel_test_wrap
def test_call_2g_parallel_stress(self):
""" 2G call stress test"""
- return self.parallel_tests(setup_func=self._setup_2g)
+ return self.parallel_tests(
+ setup_func=self._setup_2g,
+ call_verification_func=is_phone_in_call_2g)
@test_tracker_info(uuid="af580fca-fea6-4ca5-b981-b8c710302d37")
@TelephonyBaseTest.tel_test_wrap
def test_volte_modeprefchange_parallel_stress(self):
""" VoLTE Mode Pref call stress test"""
- return self.parallel_volte_tests(
+ return self.parallel_with_network_change_tests(
setup_func=self._setup_lte_volte_enabled)
""" Tests End """
diff --git a/acts/tests/google/tel/live/TelLiveVideoDataTest.py b/acts/tests/google/tel/live/TelLiveVideoDataTest.py
index 095215c..f28c7ed 100644
--- a/acts/tests/google/tel/live/TelLiveVideoDataTest.py
+++ b/acts/tests/google/tel/live/TelLiveVideoDataTest.py
@@ -33,6 +33,7 @@
self.stress_test_number = self.get_stress_test_number()
self.wifi_network_ssid = self.user_params["wifi_network_ssid"]
+ self.number_of_devices = 2
try:
self.wifi_network_pass = self.user_params["wifi_network_pass"]
diff --git a/acts/tests/google/tel/live/TelLiveVideoTest.py b/acts/tests/google/tel/live/TelLiveVideoTest.py
index 367c484..53b626e 100644
--- a/acts/tests/google/tel/live/TelLiveVideoTest.py
+++ b/acts/tests/google/tel/live/TelLiveVideoTest.py
@@ -98,6 +98,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.number_of_devices = 2
tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
(self.log, ads[1]))]
if not multithread_func(self.log, tasks):
@@ -117,7 +118,7 @@
return True
- @test_tracker_info(uuid="345e6ae9-4e9f-45e6-86a1-b661a84b6293")
+ @test_tracker_info(uuid="8abebda7-6646-4180-a37d-2f0acca63b64")
@TelephonyBaseTest.tel_test_wrap
def test_call_video_to_video_long(self):
""" Test VT<->VT call functionality.
@@ -133,6 +134,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.number_of_devices = 2
tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
(self.log, ads[1]))]
if not multithread_func(self.log, tasks):
@@ -167,6 +169,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.number_of_devices = 2
tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
(self.log, ads[1]))]
if not multithread_func(self.log, tasks):
@@ -202,6 +205,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.number_of_devices = 2
tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
(self.log, ads[1]))]
if not multithread_func(self.log, tasks):
@@ -247,6 +251,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.number_of_devices = 2
tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
(self.log, ads[1]))]
if not multithread_func(self.log, tasks):
@@ -294,6 +299,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.number_of_devices = 2
tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
(self.log, ads[1]))]
if not multithread_func(self.log, tasks):
@@ -351,6 +357,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.number_of_devices = 2
tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
(self.log, ads[1]))]
if not multithread_func(self.log, tasks):
@@ -451,6 +458,7 @@
"""
ads = self.android_devices
+ self.number_of_devices = 2
tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
(self.log, ads[1]))]
if not multithread_func(self.log, tasks):
@@ -484,6 +492,7 @@
"""
ads = self.android_devices
+ self.number_of_devices = 2
tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
(self.log, ads[1]))]
if not multithread_func(self.log, tasks):
@@ -608,8 +617,8 @@
call_id_requester, EVENT_VIDEO_SESSION_EVENT)
ad_responder.droid.telecomCallVideoStartListeningForEvent(
call_id_responder, EVENT_VIDEO_SESSION_EVENT)
- self.log.info(
- "Put In-Call UI on {} to background.".format(ad_requester.serial))
+ self.log.info("Put In-Call UI on {} to background.".format(
+ ad_requester.serial))
ad_requester.droid.showHomeScreen()
try:
event_on_responder = ad_responder.ed.pop_event(
@@ -647,8 +656,8 @@
VT_STATE_BIDIRECTIONAL_PAUSED, CALL_STATE_ACTIVE):
return False
- self.log.info(
- "Put In-Call UI on {} to foreground.".format(ad_requester.serial))
+ self.log.info("Put In-Call UI on {} to foreground.".format(
+ ad_requester.serial))
ad_requester.droid.telecomCallVideoStartListeningForEvent(
call_id_requester, EVENT_VIDEO_SESSION_EVENT)
ad_responder.droid.telecomCallVideoStartListeningForEvent(
@@ -696,6 +705,7 @@
@TelephonyBaseTest.tel_test_wrap
def test_call_video_to_video_mo_to_backgroundpause_foregroundresume(self):
ads = self.android_devices
+ self.number_of_devices = 2
tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
(self.log, ads[1]))]
if not multithread_func(self.log, tasks):
@@ -722,6 +732,7 @@
@TelephonyBaseTest.tel_test_wrap
def test_call_video_to_video_mt_to_backgroundpause_foregroundresume(self):
ads = self.android_devices
+ self.number_of_devices = 2
tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
(self.log, ads[1]))]
if not multithread_func(self.log, tasks):
@@ -752,6 +763,7 @@
Hangup on PhoneC.
Verify all phones not in call.
"""
+ self.number_of_devices = 3
if not hangup_call(self.log, ads[1]):
return False
time.sleep(WAIT_TIME_IN_CALL)
@@ -774,6 +786,7 @@
Accept the call on Phone_C
Verify both calls remain active.
"""
+ self.number_of_devices = 3
# This test case is not supported by VZW.
ads = self.android_devices
tasks = [(phone_setup_video, (self.log, ads[0])),
@@ -845,6 +858,7 @@
Accept the call on Phone_A
Verify both calls remain active.
"""
+ self.number_of_devices = 3
ads = self.android_devices
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_video, (self.log, ads[1])), (phone_setup_volte,
@@ -918,6 +932,7 @@
"""
# This test case is not supported by VZW.
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_volte, (self.log, ads[1])), (phone_setup_video,
(self.log, ads[2]))]
@@ -993,6 +1008,7 @@
# TODO (b/21437650):
# Test will fail. After established 2nd call ~15s, Phone C will drop call.
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_volte, (self.log, ads[1])), (phone_setup_video,
(self.log, ads[2]))]
@@ -1070,6 +1086,7 @@
End Voice call on PhoneA.
"""
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_video, (self.log, ads[1])), (phone_setup_volte,
(self.log, ads[2]))]
@@ -1181,6 +1198,7 @@
"""
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_video, (self.log, ads[1])), (phone_setup_volte,
(self.log, ads[2]))]
@@ -1269,8 +1287,8 @@
# Audio will goto earpiece in here
for ad in [ads[0], ads[1]]:
if get_audio_route(self.log, ad) != AUDIO_ROUTE_EARPIECE:
- self.log.error(
- "{} Audio is not on EARPIECE.".format(ad.serial))
+ self.log.error("{} Audio is not on EARPIECE.".format(
+ ad.serial))
# TODO: b/26337892 Define expected audio route behavior.
time.sleep(WAIT_TIME_IN_CALL)
@@ -1298,8 +1316,8 @@
# Audio will goto earpiece in here
for ad in [ads[0], ads[1]]:
if get_audio_route(self.log, ad) != AUDIO_ROUTE_EARPIECE:
- self.log.error(
- "{} Audio is not on EARPIECE.".format(ad.serial))
+ self.log.error("{} Audio is not on EARPIECE.".format(
+ ad.serial))
# TODO: b/26337892 Define expected audio route behavior.
time.sleep(WAIT_TIME_IN_CALL)
@@ -1327,6 +1345,7 @@
"""
# This test case is not supported by VZW.
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_video, (self.log, ads[1])), (phone_setup_video,
(self.log, ads[2]))]
@@ -1401,6 +1420,7 @@
# TODO: b/21437650 Test will fail. After established 2nd call ~15s,
# Phone C will drop call.
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_video, (self.log, ads[1])), (phone_setup_video,
(self.log, ads[2]))]
@@ -1487,6 +1507,7 @@
# TODO: b/21437650 Test will fail. After established 2nd call ~15s,
# Phone C will drop call.
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_video, (self.log, ads[1])), (phone_setup_video,
(self.log, ads[2]))]
@@ -1570,6 +1591,7 @@
"""
# This test case is not supported by VZW.
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_video, (self.log, ads[1])), (phone_setup_video,
(self.log, ads[2]))]
@@ -1647,6 +1669,7 @@
True if succeed;
False if failed.
"""
+ self.number_of_devices = 3
self.log.info(
"Merge - Step1: Merge to Conf Call and verify Conf Call.")
ads[0].droid.telecomCallJoinCallsInConf(call_ab_id, call_ac_id)
@@ -1670,9 +1693,10 @@
# Check if Conf Call is currently active
if ads[0].droid.telecomCallGetCallState(
call_conf_id) != CALL_STATE_ACTIVE:
- self.log.error("Call_id:{}, state:{}, expected: STATE_ACTIVE".
- format(call_conf_id, ads[
- 0].droid.telecomCallGetCallState(call_conf_id)))
+ self.log.error(
+ "Call_id:{}, state:{}, expected: STATE_ACTIVE".format(
+ call_conf_id,
+ ads[0].droid.telecomCallGetCallState(call_conf_id)))
return False
self.log.info(
@@ -1688,8 +1712,8 @@
if not verify_incall_state(self.log, [ads[1]], False):
return False
- if not (hangup_call(self.log, ads[2]) and
- hangup_call(self.log, ads[0])):
+ if not (hangup_call(self.log, ads[2])
+ and hangup_call(self.log, ads[0])):
self.log.error("Failed to clean up remaining calls")
return False
return True
@@ -1709,6 +1733,7 @@
call_id for conference
"""
+ self.number_of_devices = 2
self.log.info("Step4: Merge to Conf Call and verify Conf Call.")
ads[0].droid.telecomCallJoinCallsInConf(call_ab_id, call_ac_id)
time.sleep(WAIT_TIME_IN_CALL)
@@ -1731,14 +1756,14 @@
if (CALL_PROPERTY_CONFERENCE not in ads[0]
.droid.telecomCallGetProperties(call_conf_id)):
- self.log.error("Conf call id properties wrong: {}".format(ads[
- 0].droid.telecomCallGetProperties(call_conf_id)))
+ self.log.error("Conf call id properties wrong: {}".format(
+ ads[0].droid.telecomCallGetProperties(call_conf_id)))
return False
if (CALL_CAPABILITY_MANAGE_CONFERENCE not in ads[0]
.droid.telecomCallGetCapabilities(call_conf_id)):
- self.log.error("Conf call id capabilities wrong: {}".format(ads[
- 0].droid.telecomCallGetCapabilities(call_conf_id)))
+ self.log.error("Conf call id capabilities wrong: {}".format(
+ ads[0].droid.telecomCallGetCapabilities(call_conf_id)))
return False
if (call_ab_id in calls) or (call_ac_id in calls):
@@ -1752,9 +1777,10 @@
# Check if Conf Call is currently active
if ads[0].droid.telecomCallGetCallState(
call_conf_id) != CALL_STATE_ACTIVE:
- self.log.error("Call_id:{}, state:{}, expected: STATE_ACTIVE".
- format(call_conf_id, ads[
- 0].droid.telecomCallGetCallState(call_conf_id)))
+ self.log.error(
+ "Call_id:{}, state:{}, expected: STATE_ACTIVE".format(
+ call_conf_id,
+ ads[0].droid.telecomCallGetCallState(call_conf_id)))
return False
if not hangup_call(self.log, ads[1]):
@@ -1768,8 +1794,8 @@
if not verify_incall_state(self.log, [ads[1]], False):
return False
- if not (hangup_call(self.log, ads[2]) and
- hangup_call(self.log, ads[0])):
+ if not (hangup_call(self.log, ads[2])
+ and hangup_call(self.log, ads[0])):
self.log.error("Failed to clean up remaining calls")
return False
@@ -1815,6 +1841,7 @@
self, use_cep=False):
# This test case is not supported by VZW.
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_volte, (self.log, ads[1])), (phone_setup_video,
(self.log, ads[2]))]
@@ -1911,6 +1938,7 @@
def _test_call_volte_add_mt_video_accept_as_voice_merge_drop(
self, use_cep=False):
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_volte, (self.log, ads[1])), (phone_setup_video,
(self.log, ads[2]))]
@@ -2010,6 +2038,7 @@
def _test_call_video_add_mo_voice_swap_downgrade_merge_drop(self, use_cep):
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_video, (self.log, ads[1])), (phone_setup_volte,
(self.log, ads[2]))]
@@ -2089,10 +2118,10 @@
return False
self.log.info("Step5: Disable camera on PhoneA and PhoneB.")
- if not video_call_downgrade(
- self.log, ads[0], call_id_video_ab, ads[1],
- get_call_id_in_video_state(self.log, ads[1],
- VT_STATE_BIDIRECTIONAL)):
+ if not video_call_downgrade(self.log, ads[0], call_id_video_ab, ads[1],
+ get_call_id_in_video_state(
+ self.log, ads[1],
+ VT_STATE_BIDIRECTIONAL)):
self.log.error("Failed to disable video on PhoneA.")
return False
if not video_call_downgrade(self.log, ads[1],
@@ -2159,9 +2188,10 @@
return self._test_call_video_add_mt_voice_swap_downgrade_merge_drop(
True)
- def _test_call_video_add_mt_voice_swap_downgrade_merge_drop(self,
- use_cep=False):
+ def _test_call_video_add_mt_voice_swap_downgrade_merge_drop(
+ self, use_cep=False):
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_video, (self.log, ads[1])), (phone_setup_volte,
(self.log, ads[2]))]
@@ -2242,10 +2272,10 @@
return False
self.log.info("Step5: Disable camera on PhoneA and PhoneB.")
- if not video_call_downgrade(
- self.log, ads[0], call_id_video_ab, ads[1],
- get_call_id_in_video_state(self.log, ads[1],
- VT_STATE_BIDIRECTIONAL)):
+ if not video_call_downgrade(self.log, ads[0], call_id_video_ab, ads[1],
+ get_call_id_in_video_state(
+ self.log, ads[1],
+ VT_STATE_BIDIRECTIONAL)):
self.log.error("Failed to disable video on PhoneA.")
return False
if not video_call_downgrade(self.log, ads[1],
@@ -2310,6 +2340,7 @@
def _test_call_volte_add_mo_video_downgrade_merge_drop(self, use_cep):
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_volte, (self.log, ads[1])), (phone_setup_video,
(self.log, ads[2]))]
@@ -2371,10 +2402,10 @@
return False
self.log.info("Step4: Disable camera on PhoneA and PhoneC.")
- if not video_call_downgrade(
- self.log, ads[0], call_id_video_ac, ads[2],
- get_call_id_in_video_state(self.log, ads[2],
- VT_STATE_BIDIRECTIONAL)):
+ if not video_call_downgrade(self.log, ads[0], call_id_video_ac, ads[2],
+ get_call_id_in_video_state(
+ self.log, ads[2],
+ VT_STATE_BIDIRECTIONAL)):
self.log.error("Failed to disable video on PhoneA.")
return False
if not video_call_downgrade(self.log, ads[2],
@@ -2441,6 +2472,7 @@
# TODO: b/21437650 Test will fail. After established 2nd call ~15s,
# Phone C will drop call.
ads = self.android_devices
+ self.number_of_devices = 3
tasks = [(phone_setup_video, (self.log, ads[0])),
(phone_setup_volte, (self.log, ads[1])), (phone_setup_video,
(self.log, ads[2]))]
@@ -2502,10 +2534,10 @@
return False
self.log.info("Step4: Disable camera on PhoneA and PhoneC.")
- if not video_call_downgrade(
- self.log, ads[0], call_id_video_ac, ads[2],
- get_call_id_in_video_state(self.log, ads[2],
- VT_STATE_BIDIRECTIONAL)):
+ if not video_call_downgrade(self.log, ads[0], call_id_video_ac, ads[2],
+ get_call_id_in_video_state(
+ self.log, ads[2],
+ VT_STATE_BIDIRECTIONAL)):
self.log.error("Failed to disable video on PhoneA.")
return False
if not video_call_downgrade(self.log, ads[2],
@@ -2564,8 +2596,8 @@
if wait_for_video_enabled(self.log, ads[0],
MAX_WAIT_TIME_VOLTE_ENABLED):
self.log.error(
- "{} failed to <report vt enabled false> for {}s."
- .format(ads[0].serial, MAX_WAIT_TIME_VOLTE_ENABLED))
+ "{} failed to <report vt enabled false> for {}s.".format(
+ ads[0].serial, MAX_WAIT_TIME_VOLTE_ENABLED))
return False
self.log.info(
"Step4 Attempt to make VT call, verify call is AUDIO_ONLY.")
diff --git a/acts/tests/google/tel/live/TelLiveVoiceTest.py b/acts/tests/google/tel/live/TelLiveVoiceTest.py
index 4740a47..1d04c6a 100644
--- a/acts/tests/google/tel/live/TelLiveVoiceTest.py
+++ b/acts/tests/google/tel/live/TelLiveVoiceTest.py
@@ -18,20 +18,13 @@
"""
import time
-import os
+
+from acts import signals
from acts.test_decorators import test_tracker_info
-from acts.test_utils.tel.tel_subscription_utils import \
- get_subid_from_slot_index
-from acts.test_utils.tel.tel_subscription_utils import set_subid_for_data
-from acts.test_utils.tel.tel_subscription_utils import \
- set_subid_for_message
-from acts.test_utils.tel.tel_subscription_utils import \
- set_subid_for_outgoing_call
from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
from acts.test_utils.tel.tel_defines import DIRECTION_MOBILE_TERMINATED
from acts.test_utils.tel.tel_defines import GEN_2G
-from acts.test_utils.tel.tel_defines import GEN_3G
from acts.test_utils.tel.tel_defines import GEN_4G
from acts.test_utils.tel.tel_defines import CALL_STATE_ACTIVE
from acts.test_utils.tel.tel_defines import CALL_STATE_HOLDING
@@ -40,14 +33,9 @@
from acts.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts.test_utils.tel.tel_defines import PHONE_TYPE_CDMA
from acts.test_utils.tel.tel_defines import PHONE_TYPE_GSM
-from acts.test_utils.tel.tel_defines import RAT_3G
-from acts.test_utils.tel.tel_defines import RAT_FAMILY_WLAN
-from acts.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
-from acts.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_DATA_SUB_ID
from acts.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
from acts.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL_FOR_IMS
from acts.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
-from acts.test_utils.tel.tel_defines import WFC_MODE_DISABLED
from acts.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
from acts.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts.test_utils.tel.tel_subscription_utils import \
@@ -57,31 +45,25 @@
from acts.test_utils.tel.tel_test_utils import call_setup_teardown
from acts.test_utils.tel.tel_test_utils import \
call_voicemail_erase_all_pending_voicemail
-from acts.test_utils.tel.tel_test_utils import \
- ensure_network_generation_for_subscription
from acts.test_utils.tel.tel_test_utils import active_file_download_task
from acts.utils import adb_shell_ping
-from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected
from acts.test_utils.tel.tel_test_utils import ensure_network_generation
+from acts.test_utils.tel.tel_test_utils import get_mobile_data_usage
from acts.test_utils.tel.tel_test_utils import get_phone_number
from acts.test_utils.tel.tel_test_utils import hangup_call
from acts.test_utils.tel.tel_test_utils import initiate_call
-from acts.test_utils.tel.tel_test_utils import is_droid_in_rat_family
from acts.test_utils.tel.tel_test_utils import multithread_func
from acts.test_utils.tel.tel_test_utils import num_active_calls
from acts.test_utils.tel.tel_test_utils import phone_number_formatter
+from acts.test_utils.tel.tel_test_utils import remove_mobile_data_usage_limit
from acts.test_utils.tel.tel_test_utils import run_multithread_func
-from acts.test_utils.tel.tel_test_utils import set_call_state_listen_level
+from acts.test_utils.tel.tel_test_utils import set_mobile_data_usage_limit
from acts.test_utils.tel.tel_test_utils import set_phone_number
-from acts.test_utils.tel.tel_test_utils import set_wfc_mode
-from acts.test_utils.tel.tel_test_utils import setup_sim
-from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts.test_utils.tel.tel_test_utils import verify_http_connection
from acts.test_utils.tel.tel_test_utils import verify_incall_state
from acts.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
from acts.test_utils.tel.tel_test_utils import wait_for_ringing_call
-from acts.test_utils.tel.tel_test_utils import wait_for_not_network_rat
-from acts.test_utils.tel.tel_test_utils import wifi_toggle_state
+from acts.test_utils.tel.tel_test_utils import wait_for_state
from acts.test_utils.tel.tel_test_utils import start_adb_tcpdump
from acts.test_utils.tel.tel_test_utils import stop_adb_tcpdump
from acts.test_utils.tel.tel_test_utils import set_wifi_to_default
@@ -124,11 +106,13 @@
self.long_duration_call_total_duration = self.user_params.get(
"long_duration_call_total_duration",
DEFAULT_LONG_DURATION_CALL_TOTAL_DURATION)
+ self.tcpdump_proc = [None, None]
+ self.number_of_devices = 2
""" Tests Begin """
@TelephonyBaseTest.tel_test_wrap
- @test_tracker_info(uuid="8036004e-e42e-441f-b32d-96069be71ec2")
+ @test_tracker_info(uuid="fca3f9e1-447a-416f-9a9c-50b7161981bf")
def test_call_mo_voice_general(self):
""" General voice to voice call.
@@ -152,7 +136,7 @@
None, None)
@TelephonyBaseTest.tel_test_wrap
- @test_tracker_info(uuid="448e1597-c28f-4e1d-88fd-3158e6b7c630")
+ @test_tracker_info(uuid="69faeb84-3830-47c0-ad80-dc657381a83b")
def test_call_mt_voice_general(self):
""" General voice to voice call.
@@ -213,6 +197,9 @@
Returns:
True if pass; False if fail.
"""
+ if self.android_devices[0].droid.telephonyGetSimCountryIso() == "ca":
+ raise signals.TestSkip("7 digit dialing not supported")
+
ads = self.android_devices
tasks = [(phone_setup_volte, (self.log, ads[0])), (phone_setup_volte,
@@ -246,6 +233,9 @@
Returns:
True if pass; False if fail.
"""
+ if self.android_devices[0].droid.telephonyGetSimCountryIso() == "ca":
+ raise signals.TestSkip("10 digit dialing not supported")
+
ads = self.android_devices
tasks = [(phone_setup_volte, (self.log, ads[0])), (phone_setup_volte,
@@ -583,41 +573,49 @@
Returns:
True if pass; False if fail.
"""
+ result = True
try:
- (tcpdump_pid, tcpdump_file) = \
- start_adb_tcpdump(ads[0], self.test_name)
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ self.tcpdump_proc[1] = start_adb_tcpdump(ads[1], self.test_name)
tasks = [(phone_setup_iwlan, (self.log, ads[0], apm_mode, wfc_mode,
wifi_ssid, wifi_pwd)),
(phone_setup_iwlan, (self.log, ads[1], apm_mode, wfc_mode,
wifi_ssid, wifi_pwd))]
if not multithread_func(self.log, tasks):
self.log.error("Phone Failed to Set Up Properly.")
+ result = False
return False
ad_ping = ads[0]
- call_task = (two_phone_call_short_seq, (
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
- ads[1], phone_idle_iwlan, is_phone_in_call_iwlan, None,
- WAIT_TIME_IN_CALL_FOR_IMS))
+ call_task = (two_phone_call_short_seq,
+ (self.log, ads[0], phone_idle_iwlan,
+ is_phone_in_call_iwlan, ads[1], phone_idle_iwlan,
+ is_phone_in_call_iwlan, None,
+ WAIT_TIME_IN_CALL_FOR_IMS))
ping_task = (adb_shell_ping, (ad_ping, DEFAULT_PING_DURATION))
results = run_multithread_func(self.log, [ping_task, call_task])
if not results[1]:
self.log.error("Call setup failed in active ICMP transfer.")
- return False
if results[0]:
self.log.info(
"ICMP transfer succeeded with parallel phone call.")
- return True
else:
self.log.error(
"ICMP transfer failed with parallel phone call.")
- return False
+ result = all(results)
+ return result
finally:
- if tcpdump_pid is not None:
- stop_adb_tcpdump(ads[0], tcpdump_pid, tcpdump_file)
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
+ if self.tcpdump_proc[1] is not None:
+ stop_adb_tcpdump(ads[1], self.tcpdump_proc[1], not result,
+ self.test_name)
+ self.tcpdump_proc[1] = None
@test_tracker_info(uuid="a4a043c0-f4ba-4405-9262-42c752cc4487")
@TelephonyBaseTest.tel_test_wrap
@@ -667,18 +665,35 @@
True if pass; False if fail.
"""
ads = [self.android_devices[0], self.android_devices[1]]
- tasks = [(phone_setup_iwlan_cellular_preferred, (
- self.log, ads[0], self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_iwlan_cellular_preferred,
- (self.log, ads[1], self.wifi_network_ssid,
- self.wifi_network_pass))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ self.tcpdump_proc[1] = start_adb_tcpdump(ads[1], self.test_name)
+ tasks = [(phone_setup_iwlan_cellular_preferred,
+ (self.log, ads[0], self.wifi_network_ssid,
+ self.wifi_network_pass)),
+ (phone_setup_iwlan_cellular_preferred,
+ (self.log, ads[1], self.wifi_network_ssid,
+ self.wifi_network_pass))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return False
- return two_phone_call_short_seq(
- self.log, ads[0], None, is_phone_in_call_not_iwlan, ads[1], None,
- is_phone_in_call_not_iwlan, None, WAIT_TIME_IN_CALL_FOR_IMS)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], None, is_phone_in_call_not_iwlan, ads[1],
+ None, is_phone_in_call_not_iwlan, None,
+ WAIT_TIME_IN_CALL_FOR_IMS)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
+ if self.tcpdump_proc[1] is not None:
+ stop_adb_tcpdump(ads[1], self.tcpdump_proc[1], not result,
+ self.test_name)
+ self.tcpdump_proc[1] = None
@test_tracker_info(uuid="0d63c250-d9e7-490c-8c48-0a6afbad5f88")
@TelephonyBaseTest.tel_test_wrap
@@ -745,19 +760,28 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], False, WFC_MODE_WIFI_ONLY,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_volte, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return result
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], False, WFC_MODE_WIFI_ONLY,
- self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_volte, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
-
- return two_phone_call_short_seq(
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
- phone_idle_volte, is_phone_in_call_volte, None,
- WAIT_TIME_IN_CALL_FOR_IMS)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_volte, is_phone_in_call_volte, None,
+ WAIT_TIME_IN_CALL_FOR_IMS)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
@test_tracker_info(uuid="6e0630a9-63b2-4ea1-8ec9-6560f001905c")
@TelephonyBaseTest.tel_test_wrap
@@ -773,19 +797,28 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], False, WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_volte, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return result
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], False, WFC_MODE_WIFI_PREFERRED,
- self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_volte, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
-
- return two_phone_call_short_seq(
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
- phone_idle_volte, is_phone_in_call_volte, None,
- WAIT_TIME_IN_CALL_FOR_IMS)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_volte, is_phone_in_call_volte, None,
+ WAIT_TIME_IN_CALL_FOR_IMS)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
@test_tracker_info(uuid="51077985-2229-491f-9a54-1ff53871758c")
@TelephonyBaseTest.tel_test_wrap
@@ -801,19 +834,28 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], True, WFC_MODE_WIFI_ONLY,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_volte, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return result
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], True, WFC_MODE_WIFI_ONLY,
- self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_volte, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
-
- return two_phone_call_short_seq(
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
- phone_idle_volte, is_phone_in_call_volte, None,
- WAIT_TIME_IN_CALL_FOR_IMS)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_volte, is_phone_in_call_volte, None,
+ WAIT_TIME_IN_CALL_FOR_IMS)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
@test_tracker_info(uuid="fff9edcd-1ace-4f2d-a09b-06f3eea56cca")
@TelephonyBaseTest.tel_test_wrap
@@ -829,19 +871,28 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], True, WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_volte, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return result
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], True, WFC_MODE_WIFI_PREFERRED,
- self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_volte, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
-
- return two_phone_call_short_seq(
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
- phone_idle_volte, is_phone_in_call_volte, None,
- WAIT_TIME_IN_CALL_FOR_IMS)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_volte, is_phone_in_call_volte, None,
+ WAIT_TIME_IN_CALL_FOR_IMS)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
@test_tracker_info(uuid="8591554e-4e38-406c-97bf-8921d5329c47")
@TelephonyBaseTest.tel_test_wrap
@@ -857,19 +908,29 @@
True if pass; False if fail.
"""
ads = self.android_devices
- # Turn OFF WiFi for Phone B
- set_wifi_to_default(self.log, ads[1])
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], False, WFC_MODE_WIFI_ONLY,
- self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_csfb, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ # Turn OFF WiFi for Phone B
+ set_wifi_to_default(self.log, ads[1])
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], False, WFC_MODE_WIFI_ONLY,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_csfb, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return result
- return two_phone_call_short_seq(
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
- phone_idle_csfb, is_phone_in_call_csfb, None)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_csfb, is_phone_in_call_csfb, None)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
@test_tracker_info(uuid="9711888d-5b1e-4d05-86e9-98f94f46098b")
@TelephonyBaseTest.tel_test_wrap
@@ -885,19 +946,29 @@
True if pass; False if fail.
"""
ads = self.android_devices
- # Turn OFF WiFi for Phone B
- set_wifi_to_default(self.log, ads[1])
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], False, WFC_MODE_WIFI_PREFERRED,
- self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_csfb, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ # Turn OFF WiFi for Phone B
+ set_wifi_to_default(self.log, ads[1])
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], False, WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_csfb, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return result
- return two_phone_call_short_seq(
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
- phone_idle_csfb, is_phone_in_call_csfb, None)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_csfb, is_phone_in_call_csfb, None)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
@test_tracker_info(uuid="902c96a4-858f-43ff-bd56-6d7d27004320")
@TelephonyBaseTest.tel_test_wrap
@@ -913,19 +984,29 @@
True if pass; False if fail.
"""
ads = self.android_devices
- # Turn OFF WiFi for Phone B
- set_wifi_to_default(self.log, ads[1])
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], True, WFC_MODE_WIFI_ONLY,
- self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_csfb, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ # Turn OFF WiFi for Phone B
+ set_wifi_to_default(self.log, ads[1])
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], True, WFC_MODE_WIFI_ONLY,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_csfb, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return result
- return two_phone_call_short_seq(
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
- phone_idle_csfb, is_phone_in_call_csfb, None)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_csfb, is_phone_in_call_csfb, None)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
@test_tracker_info(uuid="362a5396-ebda-4706-a73a-d805e5028fd7")
@TelephonyBaseTest.tel_test_wrap
@@ -941,19 +1022,29 @@
True if pass; False if fail.
"""
ads = self.android_devices
- # Turn OFF WiFi for Phone B
- set_wifi_to_default(self.log, ads[1])
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], True, WFC_MODE_WIFI_PREFERRED,
- self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_csfb, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ # Turn OFF WiFi for Phone B
+ set_wifi_to_default(self.log, ads[1])
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], True, WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_csfb, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return result
- return two_phone_call_short_seq(
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
- phone_idle_csfb, is_phone_in_call_csfb, None)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_csfb, is_phone_in_call_csfb, None)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
@test_tracker_info(uuid="647bb859-46bc-4e3e-b6ab-7944d3bbcc26")
@TelephonyBaseTest.tel_test_wrap
@@ -969,19 +1060,29 @@
True if pass; False if fail.
"""
ads = self.android_devices
- # Turn OFF WiFi for Phone B
- set_wifi_to_default(self.log, ads[1])
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], False, WFC_MODE_WIFI_ONLY,
- self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_voice_3g, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ # Turn OFF WiFi for Phone B
+ set_wifi_to_default(self.log, ads[1])
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], False, WFC_MODE_WIFI_ONLY,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_voice_3g, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return result
- return two_phone_call_short_seq(
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
- phone_idle_3g, is_phone_in_call_3g, None)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_3g, is_phone_in_call_3g, None)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
@test_tracker_info(uuid="3688ea1f-a52d-4a35-9df4-d5ed0985e49b")
@TelephonyBaseTest.tel_test_wrap
@@ -997,19 +1098,29 @@
True if pass; False if fail.
"""
ads = self.android_devices
- # Turn OFF WiFi for Phone B
- set_wifi_to_default(self.log, ads[1])
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], False, WFC_MODE_WIFI_PREFERRED,
- self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_voice_3g, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ # Turn OFF WiFi for Phone B
+ set_wifi_to_default(self.log, ads[1])
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], False, WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_voice_3g, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return result
- return two_phone_call_short_seq(
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
- phone_idle_3g, is_phone_in_call_3g, None)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_3g, is_phone_in_call_3g, None)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
@test_tracker_info(uuid="f4efc821-fbaf-4ec2-b89b-5a47354344f0")
@TelephonyBaseTest.tel_test_wrap
@@ -1025,19 +1136,29 @@
True if pass; False if fail.
"""
ads = self.android_devices
- # Turn OFF WiFi for Phone B
- set_wifi_to_default(self.log, ads[1])
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], True, WFC_MODE_WIFI_ONLY,
- self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_voice_3g, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ # Turn OFF WiFi for Phone B
+ set_wifi_to_default(self.log, ads[1])
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], True, WFC_MODE_WIFI_ONLY,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_voice_3g, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return False
- return two_phone_call_short_seq(
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
- phone_idle_3g, is_phone_in_call_3g, None)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_3g, is_phone_in_call_3g, None)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
@test_tracker_info(uuid="2b1345b7-3b62-44bd-91ad-9c5a4925b0e1")
@TelephonyBaseTest.tel_test_wrap
@@ -1053,19 +1174,29 @@
True if pass; False if fail.
"""
ads = self.android_devices
- # Turn OFF WiFi for Phone B
- set_wifi_to_default(self.log, ads[1])
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], True, WFC_MODE_WIFI_PREFERRED,
- self.wifi_network_ssid, self.wifi_network_pass)),
- (phone_setup_voice_3g, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
+ result = True
+ try:
+ self.tcpdump_proc[0] = start_adb_tcpdump(ads[0], self.test_name)
+ # Turn OFF WiFi for Phone B
+ set_wifi_to_default(self.log, ads[1])
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], True, WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_voice_3g, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ return False
- return two_phone_call_short_seq(
- self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
- phone_idle_3g, is_phone_in_call_3g, None)
+ result = two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_3g, is_phone_in_call_3g, None)
+ return result
+ finally:
+ if self.tcpdump_proc[0] is not None:
+ stop_adb_tcpdump(ads[0], self.tcpdump_proc[0], not result,
+ self.test_name)
+ self.tcpdump_proc[0] = None
@test_tracker_info(uuid="7b3fea22-114a-442e-aa12-dde3b6001681")
@TelephonyBaseTest.tel_test_wrap
@@ -1179,7 +1310,7 @@
phone_idle_iwlan, is_phone_in_call_iwlan, None,
WAIT_TIME_IN_CALL_FOR_IMS)
- @test_tracker_info(uuid="7049de19-3abf-48df-868f-18d0af829393")
+ @test_tracker_info(uuid="a7293d6c-0fdb-4842-984a-e4c6395fd41d")
@TelephonyBaseTest.tel_test_wrap
def test_call_epdg_to_epdg_long_wfc_wifi_preferred(self):
""" WiFi Preferred, WiFi calling to WiFi Calling test
@@ -1243,7 +1374,7 @@
phone_idle_iwlan, is_phone_in_call_iwlan, None,
WAIT_TIME_IN_CALL_FOR_IMS)
- @test_tracker_info(uuid="2b926e4a-f493-41fa-98af-20d25ec132bb")
+ @test_tracker_info(uuid="3c751d79-7159-4407-a63c-96f835dd6cb0")
@TelephonyBaseTest.tel_test_wrap
def test_call_epdg_to_epdg_long_apm_wfc_wifi_preferred(self):
""" Airplane + WiFi Preferred, WiFi calling to WiFi Calling test
@@ -1275,7 +1406,7 @@
phone_idle_iwlan, is_phone_in_call_iwlan, None,
WAIT_TIME_IN_CALL_FOR_IMS)
- @test_tracker_info(uuid="30d5d573-043f-4d8b-98e0-e7f7bc9b8d6f")
+ @test_tracker_info(uuid="9deab765-e2da-4826-bae8-ba8755551a1b")
@TelephonyBaseTest.tel_test_wrap
def test_call_csfb_3g_to_csfb_3g_long(self):
""" CSFB 3G to CSFB 3G call test
@@ -1380,8 +1511,8 @@
self.log.info("Final Count - Success: {}, Failure: {} - {}%".format(
success_count, fail_count,
str(100 * success_count / (success_count + fail_count))))
- if success_count / (success_count + fail_count
- ) >= MINIMUM_SUCCESS_RATE:
+ if success_count / (
+ success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
return True
else:
return False
@@ -1439,8 +1570,8 @@
self.log.info("Final Count - Success: {}, Failure: {} - {}%".format(
success_count, fail_count,
str(100 * success_count / (success_count + fail_count))))
- if success_count / (success_count + fail_count
- ) >= MINIMUM_SUCCESS_RATE:
+ if success_count / (
+ success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
return True
else:
return False
@@ -1498,8 +1629,8 @@
self.log.info("Final Count - Success: {}, Failure: {} - {}%".format(
success_count, fail_count,
str(100 * success_count / (success_count + fail_count))))
- if success_count / (success_count + fail_count
- ) >= MINIMUM_SUCCESS_RATE:
+ if success_count / (
+ success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
return True
else:
return False
@@ -1557,8 +1688,8 @@
self.log.info("Final Count - Success: {}, Failure: {} - {}%".format(
success_count, fail_count,
str(100 * success_count / (success_count + fail_count))))
- if success_count / (success_count + fail_count
- ) >= MINIMUM_SUCCESS_RATE:
+ if success_count / (
+ success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
return True
else:
return False
@@ -1616,8 +1747,8 @@
self.log.info("Final Count - Success: {}, Failure: {} - {}%".format(
success_count, fail_count,
str(100 * success_count / (success_count + fail_count))))
- if success_count / (success_count + fail_count
- ) >= MINIMUM_SUCCESS_RATE:
+ if success_count / (
+ success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
return True
else:
return False
@@ -1669,8 +1800,8 @@
self.log.info("Final Count - Success: {}, Failure: {}".format(
success_count, fail_count))
- if success_count / (success_count + fail_count
- ) >= MINIMUM_SUCCESS_RATE:
+ if success_count / (
+ success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
return True
else:
return False
@@ -1722,8 +1853,8 @@
self.log.info("Final Count - Success: {}, Failure: {}".format(
success_count, fail_count))
- if success_count / (success_count + fail_count
- ) >= MINIMUM_SUCCESS_RATE:
+ if success_count / (
+ success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
return True
else:
return False
@@ -1810,8 +1941,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MO Call Hold/Unhold Test.")
@@ -1855,8 +1986,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MO Call Hold/Unhold Test.")
@@ -1900,8 +2031,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MO Call Hold/Unhold Test.")
@@ -1945,8 +2076,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MO Call Hold/Unhold Test.")
@@ -1990,8 +2121,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MT Call Hold/Unhold Test.")
@@ -2035,8 +2166,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MT Call Hold/Unhold Test.")
@@ -2080,8 +2211,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MT Call Hold/Unhold Test.")
@@ -2125,8 +2256,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MT Call Hold/Unhold Test.")
@@ -2168,8 +2299,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MO Call Hold/Unhold Test.")
@@ -2211,8 +2342,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MT Call Hold/Unhold Test.")
@@ -2258,8 +2389,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MO Call Hold/Unhold Test.")
@@ -2305,8 +2436,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MT Call Hold/Unhold Test.")
@@ -2352,8 +2483,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MO Call Hold/Unhold Test.")
@@ -2399,8 +2530,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MT Call Hold/Unhold Test.")
@@ -2645,7 +2776,7 @@
self.log, ads[0], phone_idle_2g, is_phone_in_call_2g, ads[1],
phone_idle_2g, is_phone_in_call_2g, None)
- @test_tracker_info(uuid="6e24e64f-aa0e-4101-89ed-4cc30c738c7e")
+ @test_tracker_info(uuid="947f3178-735b-4ac2-877c-a06a94972457")
@TelephonyBaseTest.tel_test_wrap
def test_call_2g_to_2g_long(self):
""" Test 2g<->2g call functionality.
@@ -2698,8 +2829,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MO Call Hold/Unhold Test.")
@@ -2744,8 +2875,8 @@
ads[0].droid.telecomCallClearCallList()
if num_active_calls(self.log, ads[0]) != 0:
- self.log.error("Phone {} Call List is not empty."
- .format(ads[0].serial))
+ self.log.error("Phone {} Call List is not empty.".format(
+ ads[0].serial))
return False
self.log.info("Begin MT Call Hold/Unhold Test.")
@@ -2886,13 +3017,13 @@
ad_caller.droid.telecomCallClearCallList()
if num_active_calls(self.log, ad_caller) != 0:
- self.log.error(
- "Phone {} has ongoing calls.".format(ad_caller.serial))
+ self.log.error("Phone {} has ongoing calls.".format(
+ ad_caller.serial))
return False
if not initiate_call(self.log, ad_caller, callee_number):
- self.log.error(
- "Phone was {} unable to initate a call".format(ads[0].serial))
+ self.log.error("Phone was {} unable to initate a call".format(
+ ads[0].serial))
return False
if not wait_for_ringing_call(self.log, ad_callee, caller_number):
@@ -2962,7 +3093,7 @@
caller_verifier, callee_verifier,
wait_time_in_call):
#wait time for active data transfer
- time.sleep(10)
+ time.sleep(5)
return call_setup_teardown(log, ad_caller, ad_callee, ad_hangup,
caller_verifier, callee_verifier,
wait_time_in_call)
@@ -2975,9 +3106,6 @@
MAX_WAIT_TIME_NW_SELECTION)
return False
- #toggle_airplane_mode(self.log, self.android_devices[0], False)
- #wifi_toggle_state(self.log, self.android_devices[0], False)
-
self.android_devices[0].droid.telephonyToggleDataConnection(True)
if not wait_for_cell_data_connection(
self.log, self.android_devices[0], True):
@@ -2996,10 +3124,23 @@
ad_callee = self.android_devices[0]
ad_download = self.android_devices[0]
+ ad_download.ensure_screen_on()
+ ad_download.adb.shell('am start -a android.intent.action.VIEW -d '
+ '"https://www.youtube.com/watch?v=VHF-XK0Vg1s"')
+ if wait_for_state(ad_download.droid.audioIsMusicActive, True, 15, 1):
+ ad_download.log.info("Before call, audio is in MUSIC_state")
+ else:
+ ad_download.log.warning("Before call, audio is not in MUSIC state")
call_task = (_call_setup_teardown, (self.log, ad_caller, ad_callee,
- ad_caller, None, None, 60))
+ ad_caller, None, None, 30))
download_task = active_file_download_task(self.log, ad_download)
results = run_multithread_func(self.log, [download_task, call_task])
+ if wait_for_state(ad_download.droid.audioIsMusicActive, True, 15, 1):
+ ad_download.log.info("After call hangup, audio is back to music")
+ else:
+ ad_download.log.warning(
+ "After call hang up, audio is not back to music")
+ ad_download.force_stop_apk("com.google.android.youtube")
if not results[1]:
self.log.error("Call setup failed in active data transfer.")
return False
@@ -3009,8 +3150,9 @@
elif not allow_data_transfer_interruption:
self.log.error("Data transfer failed with parallel phone call.")
return False
- ad_download.log.info("Retry data transfer after call hung up")
- return download_task[0](*download_task[1])
+ else:
+ ad_download.log.info("Retry data transfer after call hung up")
+ return download_task[0](*download_task[1])
@test_tracker_info(uuid="aa40e7e1-e64a-480b-86e4-db2242449555")
@TelephonyBaseTest.tel_test_wrap
@@ -3354,5 +3496,441 @@
return self._test_call_setup_in_active_data_transfer(
None, DIRECTION_MOBILE_TERMINATED)
+ def _test_call_setup_in_active_youtube_video(
+ self,
+ nw_gen=None,
+ call_direction=DIRECTION_MOBILE_ORIGINATED,
+ allow_data_transfer_interruption=False):
+ """Test call can be established during active data connection.
+
+ Turn off airplane mode, disable WiFi, enable Cellular Data.
+ Make sure phone in <nw_gen>.
+ Starting playing youtube video.
+ Initiate a voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if nw_gen:
+ if not ensure_network_generation(
+ self.log, self.android_devices[0], nw_gen,
+ MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
+ self.log.error("Device failed to reselect in %s.",
+ MAX_WAIT_TIME_NW_SELECTION)
+ return False
+ else:
+ ensure_phones_default_state(self.log, self.android_devices)
+ self.android_devices[0].droid.telephonyToggleDataConnection(True)
+ if not wait_for_cell_data_connection(self.log, self.android_devices[0],
+ True):
+ self.log.error("Data connection is not on cell")
+ return False
+
+ if not verify_http_connection(self.log, self.android_devices[0]):
+ self.log.error("HTTP connection is not available")
+ return False
+
+ if call_direction == DIRECTION_MOBILE_ORIGINATED:
+ ad_caller = self.android_devices[0]
+ ad_callee = self.android_devices[1]
+ else:
+ ad_caller = self.android_devices[1]
+ ad_callee = self.android_devices[0]
+ ad_download = self.android_devices[0]
+
+ ad_download.log.info("Open an youtube video")
+ ad_download.ensure_screen_on()
+ ad_download.adb.shell('am start -a android.intent.action.VIEW -d '
+ '"https://www.youtube.com/watch?v=VHF-XK0Vg1s"')
+ if wait_for_state(ad_download.droid.audioIsMusicActive, True, 15, 1):
+ ad_download.log.info("Before call, audio is in MUSIC_state")
+ else:
+ ad_download.log.warning("Before call, audio is not in MUSIC state")
+
+ if not call_setup_teardown(self.log, ad_caller, ad_callee, ad_caller,
+ None, None, 30):
+ self.log.error("Call setup failed in active youtube video")
+ result = False
+ else:
+ self.log.info("Call setup succeed in active youtube video")
+ result = True
+
+ if wait_for_state(ad_download.droid.audioIsMusicActive, True, 15, 1):
+ ad_download.log.info("After call hangup, audio is back to music")
+ else:
+ ad_download.log.warning(
+ "After call hang up, audio is not back to music")
+ ad_download.force_stop_apk("com.google.android.youtube")
+ return result
+
+ @test_tracker_info(uuid="1dc9f03f-1b6c-4c17-993b-3acafdc26ea3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mo_voice_general_in_active_youtube_video(self):
+ """Test call can be established during active youtube video.
+
+ Turn off airplane mode, disable WiFi, enable Cellular Data.
+ Make sure phone in <nw_gen>.
+ Starting an youtube video.
+ Initiate a MO voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return self._test_call_setup_in_active_youtube_video(
+ None, DIRECTION_MOBILE_ORIGINATED)
+
+ @test_tracker_info(uuid="32bc8fab-a0b9-4d47-8afb-940d1fdcde02")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mt_voice_general_in_active_youtube_video(self):
+ """Test call can be established during active youtube video.
+
+ Turn off airplane mode, disable WiFi, enable Cellular Data.
+ Make sure phone in <nw_gen>.
+ Starting an youtube video.
+ Initiate a MT voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return self._test_call_setup_in_active_youtube_video(
+ None, DIRECTION_MOBILE_TERMINATED)
+
+ @test_tracker_info(uuid="72204212-e0c8-4447-be3f-ae23b2a63a1c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mo_voice_volte_in_active_youtube_video(self):
+ """Test call can be established during active youtube video.
+
+ Turn off airplane mode, disable WiFi, enable Cellular Data.
+ Make sure phone in <nw_gen>.
+ Starting an youtube video.
+ Initiate a MO voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not phone_setup_volte(self.log, self.android_devices[0]):
+ self.android_devices[0].log.error("Failed to setup VoLTE")
+ return False
+ return self._test_call_setup_in_active_youtube_video(
+ GEN_4G, DIRECTION_MOBILE_ORIGINATED)
+
+ @test_tracker_info(uuid="84cd3ab9-a2b2-4ef9-b531-ee6201bec128")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mt_voice_volte_in_active_youtube_video(self):
+ """Test call can be established during active youtube video.
+
+ Turn off airplane mode, disable WiFi, enable Cellular Data.
+ Make sure phone in <nw_gen>.
+ Starting an youtube video.
+ Initiate a MT voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not phone_setup_volte(self.log, self.android_devices[0]):
+ self.android_devices[0].log.error("Failed to setup VoLTE")
+ return False
+ return self._test_call_setup_in_active_youtube_video(
+ GEN_4G, DIRECTION_MOBILE_TERMINATED)
+
+ @test_tracker_info(uuid="a8dca8d3-c44c-40a6-be56-931b4be5499b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mo_voice_csfb_in_active_youtube_video(self):
+ """Test call can be established during active youbube video.
+
+ Turn off airplane mode, disable WiFi, enable Cellular Data.
+ Make sure phone in <nw_gen>.
+ Starting an youtube video.
+ Initiate a MO voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not phone_setup_csfb(self.log, self.android_devices[0]):
+ self.android_devices[0].log.error("Failed to setup VoLTE")
+ return False
+ return self._test_call_setup_in_active_youtube_video(
+ GEN_4G,
+ DIRECTION_MOBILE_ORIGINATED,
+ allow_data_transfer_interruption=True)
+
+ @test_tracker_info(uuid="d11f7263-f51d-4ea3-916a-0df4f52023ce")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mt_voice_csfb_in_active_youtube_video(self):
+ """Test call can be established during active youtube video.
+
+ Turn off airplane mode, disable WiFi, enable Cellular Data.
+ Make sure phone in <nw_gen>.
+ Starting an youtube video.
+ Initiate a MT voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not phone_setup_csfb(self.log, self.android_devices[0]):
+ self.android_devices[0].log.error("Failed to setup VoLTE")
+ return False
+ return self._test_call_setup_in_active_youtube_video(
+ GEN_4G,
+ DIRECTION_MOBILE_TERMINATED,
+ allow_data_transfer_interruption=True)
+
+ @test_tracker_info(uuid="676378b4-94b7-4ad7-8242-7ccd2bf1efba")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mo_voice_3g_in_active_youtube_video(self):
+ """Test call can be established during active youtube video.
+
+ Turn off airplane mode, disable WiFi, enable Cellular Data.
+ Make sure phone in <nw_gen>.
+ Starting an youtube video.
+ Initiate a MO voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not phone_setup_voice_3g(self.log, self.android_devices[0]):
+ self.android_devices[0].log.error("Failed to setup 3G")
+ return False
+ return self._test_call_setup_in_active_youtube_video(
+ GEN_3G,
+ DIRECTION_MOBILE_ORIGINATED,
+ allow_data_transfer_interruption=True)
+
+ @test_tracker_info(uuid="6216fc6d-2aa2-4eb9-90e2-5791cb31c12e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mt_voice_3g_in_active_youtube_video(self):
+ """Test call can be established during active youtube video.
+
+ Turn off airplane mode, disable WiFi, enable Cellular Data.
+ Make sure phone in <nw_gen>.
+ Starting youtube video.
+ Initiate a MT voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not phone_setup_voice_3g(self.log, self.android_devices[0]):
+ self.android_devices[0].log.error("Failed to setup 3G")
+ return False
+ return self._test_call_setup_in_active_youtube_video(
+ GEN_3G,
+ DIRECTION_MOBILE_TERMINATED,
+ allow_data_transfer_interruption=True)
+
+ @test_tracker_info(uuid="58ec9783-6f8e-49f6-8dae-9dd33108b6f9")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mo_voice_2g_in_active_youtube_video(self):
+ """Test call can be established during active youtube video.
+
+ Turn off airplane mode, disable WiFi, enable Cellular Data.
+ Make sure phone in <nw_gen>.
+ Starting youtube video.
+ Initiate a MO voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not phone_setup_voice_2g(self.log, self.android_devices[0]):
+ self.android_devices[0].log.error("Failed to setup voice in 2G")
+ return False
+ return self._test_call_setup_in_active_youtube_video(
+ GEN_2G,
+ DIRECTION_MOBILE_ORIGINATED,
+ allow_data_transfer_interruption=True)
+
+ @test_tracker_info(uuid="e8ba7c0c-48a3-4fc6-aa34-a2e1c570521a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mt_voice_2g_in_active_youtube_video(self):
+ """Test call can be established during active youtube video.
+
+ Turn off airplane mode, disable WiFi, enable Cellular Data.
+ Make sure phone in <nw_gen>.
+ Starting an youtube video.
+ Initiate a MT voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not phone_setup_voice_2g(self.log, self.android_devices[0]):
+ self.android_devices[0].log.error("Failed to setup voice in 2G")
+ return False
+ return self._test_call_setup_in_active_youtube_video(
+ GEN_2G,
+ DIRECTION_MOBILE_TERMINATED,
+ allow_data_transfer_interruption=True)
+
+ @test_tracker_info(uuid="eb8971c1-b34a-430f-98df-0d4554c7ab12")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mo_voice_wifi_wfc_in_active_youtube_video(self):
+ """Test call can be established during active youtube video.
+
+ Turn off airplane mode, turn on wfc and wifi.
+ Starting youtube video.
+ Initiate a MO voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not phone_setup_iwlan(self.log, self.android_devices[0], False,
+ WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass):
+ self.android_devices[0].log.error(
+ "Failed to setup IWLAN with NON-APM WIFI WFC on")
+ return False
+ return self._test_call_setup_in_active_youtube_video(
+ None, DIRECTION_MOBILE_ORIGINATED)
+
+ @test_tracker_info(uuid="275a93d6-1f39-40c8-893f-ff77afd09e54")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mt_voice_wifi_wfc_in_active_youtube_video(self):
+ """Test call can be established during active youtube_video.
+
+ Turn off airplane mode, turn on wfc and wifi.
+ Starting an youtube video.
+ Initiate a MT voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not phone_setup_iwlan(self.log, self.android_devices[0], False,
+ WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass):
+ self.android_devices[0].log.error(
+ "Failed to setup iwlan with APM off and WIFI and WFC on")
+ return False
+ return self._test_call_setup_in_active_youtube_video(
+ None, DIRECTION_MOBILE_TERMINATED)
+
+ @test_tracker_info(uuid="ea087709-d4df-4223-b80c-1b33bacbd5a2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mo_voice_apm_wifi_wfc_in_active_youtube_video(self):
+ """Test call can be established during active youtube video.
+
+ Turn on wifi-calling, airplane mode and wifi.
+ Starting an youtube video.
+ Initiate a MO voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not phone_setup_iwlan(self.log, self.android_devices[0], True,
+ WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass):
+ self.android_devices[0].log.error(
+ "Failed to setup iwlan with APM, WIFI and WFC on")
+ return False
+ return self._test_call_setup_in_active_youtube_video(
+ None, DIRECTION_MOBILE_ORIGINATED)
+
+ @test_tracker_info(uuid="44cc14e0-60c7-4fdb-ad26-31fdc4e52aaf")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_mt_voice_apm_wifi_wfc_in_active_youtube_video(self):
+ """Test call can be established during active youtube video.
+
+ Turn on wifi-calling, airplane mode and wifi.
+ Starting youtube video.
+ Initiate a MT voice call. Verify call can be established.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not phone_setup_iwlan(self.log, self.android_devices[0], True,
+ WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass):
+ self.android_devices[0].log.error(
+ "Failed to setup iwlan with APM, WIFI and WFC on")
+ return False
+ return self._test_call_setup_in_active_youtube_video(
+ None, DIRECTION_MOBILE_TERMINATED)
+
+ @test_tracker_info(uuid="f367de12-1fd8-488d-816f-091deaacb791")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_wfc_wifi_preferred_after_mobile_data_usage_limit_reached(
+ self):
+ """ WiFi Preferred, WiFi calling test after data limit reached
+
+ 1. Set the data limit to the current usage
+ 2. Setup PhoneA WFC mode: WIFI_PREFERRED.
+ 3. Make Sure PhoneB is in 3G mode.
+ 4. Call from PhoneA to PhoneB, accept on PhoneB, hang up on PhoneA.
+ 5. Call from PhoneA to PhoneB, accept on PhoneB, hang up on PhoneB.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ ads = self.android_devices
+ try:
+ subscriber_id = ads[0].droid.telephonyGetSubscriberId()
+ data_usage = get_mobile_data_usage(ads[0], subscriber_id)
+ set_mobile_data_usage_limit(ads[0], data_usage, subscriber_id)
+
+ # Turn OFF WiFi for Phone B
+ set_wifi_to_default(self.log, ads[1])
+ tasks = [(phone_setup_iwlan,
+ (self.log, ads[0], False, WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_voice_3g, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan,
+ ads[1], phone_idle_3g, is_phone_in_call_3g, None)
+ finally:
+ remove_mobile_data_usage_limit(ads[0], subscriber_id)
+
+ @test_tracker_info(uuid="af943c7f-2b42-408f-b8a3-2d360a7483f7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_volte_after_mobile_data_usage_limit_reached(self):
+ """ VoLTE to VoLTE call test after mobile data usage limit reached
+
+ 1. Set the data limit to the current usage
+ 2. Make Sure PhoneA is in LTE mode (with VoLTE).
+ 3. Make Sure PhoneB is in LTE mode (with VoLTE).
+ 4. Call from PhoneA to PhoneB, accept on PhoneB, hang up on PhoneA.
+ 5. Call from PhoneA to PhoneB, accept on PhoneB, hang up on PhoneB.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ ads = self.android_devices
+ try:
+ subscriber_id = ads[0].droid.telephonyGetSubscriberId()
+ data_usage = get_mobile_data_usage(ads[0], subscriber_id)
+ set_mobile_data_usage_limit(ads[0], data_usage, subscriber_id)
+
+ tasks = [(phone_setup_volte, (self.log, ads[0])),
+ (phone_setup_volte, (self.log, ads[1]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return two_phone_call_short_seq(
+ self.log, ads[0], phone_idle_volte, is_phone_in_call_volte,
+ ads[1], phone_idle_volte, is_phone_in_call_volte, None,
+ WAIT_TIME_IN_CALL_FOR_IMS)
+ finally:
+ remove_mobile_data_usage_limit(ads[0], subscriber_id)
+
""" Tests End """
diff --git a/acts/tests/google/tel/live/TelWifiDataTest.py b/acts/tests/google/tel/live/TelWifiDataTest.py
index 4ee1f2e..c30afb0 100644
--- a/acts/tests/google/tel/live/TelWifiDataTest.py
+++ b/acts/tests/google/tel/live/TelWifiDataTest.py
@@ -30,6 +30,8 @@
from acts.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
from acts.test_utils.tel.tel_test_utils import run_multithread_func
from acts.test_utils.tel.tel_test_utils import active_file_download_test
+from acts.test_utils.tel.tel_test_utils import get_telephony_signal_strength
+from acts.test_utils.tel.tel_test_utils import get_wifi_signal_strength
from acts.utils import adb_shell_ping
# Attenuator name
@@ -79,15 +81,16 @@
Make sure DUT get Cell Data coverage (LTE)
Make sure DUT WiFi is connected
"""
- toggle_airplane_mode(self.log, self.android_devices[0], False)
- if not ensure_network_generation(self.log, self.android_devices[0],
+ ad = self.android_devices[0]
+ toggle_airplane_mode(self.log, ad, False)
+ if not ensure_network_generation(self.log, ad,
GEN_4G, NETWORK_SERVICE_DATA):
return False
- if not ensure_wifi_connected(self.log, self.android_devices[0],
+ if not ensure_wifi_connected(self.log, ad,
self.live_network_ssid,
self.live_network_pwd):
- ad.log.error("%s connect WiFI failed")
+ ad.log.error("connect WiFi failed")
return False
return True
@@ -152,6 +155,8 @@
irat_wait_time) or
not verify_http_connection(self.log, ad)):
ad.log.error("Data not on WiFi")
+ get_telephony_signal_strength(ad)
+ get_wifi_signal_strength(ad)
return False
ad.log.info("Triggering WiFi to Cellular IRAT")
@@ -160,6 +165,8 @@
irat_wait_time) or
not verify_http_connection(self.log, ad)):
ad.log.error("Data not on Cell")
+ get_telephony_signal_strength(ad)
+ get_wifi_signal_strength(ad)
return False
return True
@@ -256,17 +263,29 @@
self._atten_setup_wifi_cell()
if (not wait_for_wifi_data_connection(self.log, ad, True)):
ad.log.error("Data not on WiFi")
+ get_telephony_signal_strength(ad)
+ get_wifi_signal_strength(ad)
break
+
+ ad.on_mobile_data = False
if not active_file_download_test(self.log, ad):
ad.log.error("HTTP file download failed on WiFi")
+ get_telephony_signal_strength(ad)
+ get_wifi_signal_strength(ad)
break
self._atten_setup_cell_only()
if (not wait_for_cell_data_connection(self.log, ad, True)):
ad.log.error("Data not on Cell")
+ get_telephony_signal_strength(ad)
+ get_wifi_signal_strength(ad)
break
+
+ ad.on_mobile_data = True
if not active_file_download_test(self.log, ad):
ad.log.error("HTTP file download failed on cell")
+ get_telephony_signal_strength(ad)
+ get_wifi_signal_strength(ad)
break
self.log.info(">----Iteration : %d/%d succeed.----<",
@@ -319,13 +338,18 @@
if (not wait_for_wifi_data_connection(self.log, ad, True) or
not verify_http_connection(self.log, ad)):
ad.log.error("Data not on WiFi")
+ get_telephony_signal_strength(ad)
+ get_wifi_signal_strength(ad)
break
self._atten_setup_cell_only()
if (not wait_for_cell_data_connection(self.log, ad, True) or
not verify_http_connection(self.log, ad)):
ad.log.error("Data not on Cell")
+ get_telephony_signal_strength(ad)
+ get_wifi_signal_strength(ad)
break
+
self.log.info(">----Iteration : %d/%d succeed.----<",
current_iteration, total_iteration)
current_iteration += 1
@@ -360,9 +384,14 @@
if (not wait_for_wifi_data_connection(self.log, ad, True) or
not verify_http_connection(self.log, ad)):
ad.log.error("Data not on WiFi")
+ get_telephony_signal_strength(ad)
+ get_wifi_signal_strength(ad)
return False
+ ad.on_mobile_data = False
if not active_file_download_test(self.log, ad, "10MB"):
ad.log.error("HTTP file download failed on WiFi")
+ get_telephony_signal_strength(ad)
+ get_wifi_signal_strength(ad)
return False
return True
@@ -390,9 +419,14 @@
if (not wait_for_cell_data_connection(self.log, ad, True) or
not verify_http_connection(self.log, ad)):
ad.log.error("Data not on LTE")
+ get_telephony_signal_strength(ad)
+ get_wifi_signal_strength(ad)
return False
- if not active_file_download_test(self.log, ad, "1GB"):
+ ad.on_mobile_data = True
+ if not active_file_download_test(self.log, ad, "512MB"):
ad.log.error("HTTP file download failed on LTE")
+ get_telephony_signal_strength(ad)
+ get_wifi_signal_strength(ad)
return False
return True
diff --git a/acts/tests/google/tel/live/TelWifiVideoTest.py b/acts/tests/google/tel/live/TelWifiVideoTest.py
new file mode 100644
index 0000000..a2293da
--- /dev/null
+++ b/acts/tests/google/tel/live/TelWifiVideoTest.py
@@ -0,0 +1,173 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2018 - Google
+#
+# 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 for ViWiFi live call test
+"""
+
+import time
+from queue import Empty
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts.test_utils.tel.tel_defines import AUDIO_ROUTE_EARPIECE
+from acts.test_utils.tel.tel_defines import AUDIO_ROUTE_SPEAKER
+from acts.test_utils.tel.tel_defines import CALL_STATE_ACTIVE
+from acts.test_utils.tel.tel_defines import CALL_STATE_HOLDING
+from acts.test_utils.tel.tel_defines import CALL_CAPABILITY_MANAGE_CONFERENCE
+from acts.test_utils.tel.tel_defines import CALL_CAPABILITY_MERGE_CONFERENCE
+from acts.test_utils.tel.tel_defines import CALL_CAPABILITY_SWAP_CONFERENCE
+from acts.test_utils.tel.tel_defines import CALL_PROPERTY_CONFERENCE
+from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_VIDEO_SESSION_EVENT
+from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOLTE_ENABLED
+from acts.test_utils.tel.tel_defines import VT_STATE_AUDIO_ONLY
+from acts.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
+from acts.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL_PAUSED
+from acts.test_utils.tel.tel_defines import VT_VIDEO_QUALITY_DEFAULT
+from acts.test_utils.tel.tel_defines import VT_STATE_RX_ENABLED
+from acts.test_utils.tel.tel_defines import VT_STATE_TX_ENABLED
+from acts.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
+from acts.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
+from acts.test_utils.tel.tel_defines import EVENT_VIDEO_SESSION_EVENT
+from acts.test_utils.tel.tel_defines import EventTelecomVideoCallSessionEvent
+from acts.test_utils.tel.tel_defines import SESSION_EVENT_RX_PAUSE
+from acts.test_utils.tel.tel_defines import SESSION_EVENT_RX_RESUME
+from acts.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts.test_utils.tel.tel_test_utils import call_setup_teardown
+from acts.test_utils.tel.tel_test_utils import disconnect_call_by_id
+from acts.test_utils.tel.tel_test_utils import hangup_call
+from acts.test_utils.tel.tel_test_utils import multithread_func
+from acts.test_utils.tel.tel_test_utils import num_active_calls
+from acts.test_utils.tel.tel_test_utils import verify_http_connection
+from acts.test_utils.tel.tel_test_utils import verify_incall_state
+from acts.test_utils.tel.tel_test_utils import wait_for_video_enabled
+from acts.test_utils.tel.tel_video_utils import get_call_id_in_video_state
+from acts.test_utils.tel.tel_video_utils import \
+ is_phone_in_call_video_bidirectional
+from acts.test_utils.tel.tel_video_utils import \
+ is_phone_in_call_viwifi_bidirectional
+from acts.test_utils.tel.tel_video_utils import is_phone_in_call_voice_hd
+from acts.test_utils.tel.tel_video_utils import phone_setup_video
+from acts.test_utils.tel.tel_video_utils import \
+ verify_video_call_in_expected_state
+from acts.test_utils.tel.tel_video_utils import video_call_downgrade
+from acts.test_utils.tel.tel_video_utils import video_call_modify_video
+from acts.test_utils.tel.tel_video_utils import video_call_setup_teardown
+from acts.test_utils.tel.tel_voice_utils import get_audio_route
+from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
+from acts.test_utils.tel.tel_voice_utils import phone_setup_volte
+from acts.test_utils.tel.tel_voice_utils import set_audio_route
+from acts.test_utils.tel.tel_voice_utils import get_cep_conference_call_id
+from acts.test_utils.tel.tel_voice_utils import phone_setup_iwlan
+
+DEFAULT_LONG_DURATION_CALL_TOTAL_DURATION = 1 * 60 * 60 # default 1 hour
+
+
+class TelWifiVideoTest(TelephonyBaseTest):
+ def __init__(self, controllers):
+ TelephonyBaseTest.__init__(self, controllers)
+
+ self.stress_test_number = self.get_stress_test_number()
+ self.wifi_network_ssid = self.user_params.get("wifi_network_ssid")
+ self.wifi_network_pass = self.user_params.get("wifi_network_pass")
+
+ self.long_duration_call_total_duration = self.user_params.get(
+ "long_duration_call_total_duration",
+ DEFAULT_LONG_DURATION_CALL_TOTAL_DURATION)
+
+ """ Tests Begin """
+
+ @test_tracker_info(uuid="375e9b88-8d8e-45fe-8502-e4da4147682d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_video_to_video_wifi_preferred(self):
+ """ Test ViWifi<->ViWifi call functionality.
+
+ Make Sure PhoneA is in iWLAN mode (with Video Calling).
+ Make Sure PhoneB is in iWLAN mode (with Video Calling).
+ Connect to Wifi
+ Call from PhoneA to PhoneB as Bi-Directional Video,
+ Accept on PhoneB as video call, hang up on PhoneA.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ ads = self.android_devices
+ tasks = [
+ (phone_setup_iwlan,
+ (self.log, ads[0], False, WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_iwlan,
+ (self.log, ads[1], False, WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ ]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ if not video_call_setup_teardown(
+ self.log,
+ ads[0],
+ ads[1],
+ ads[0],
+ video_state=VT_STATE_BIDIRECTIONAL,
+ verify_caller_func=is_phone_in_call_viwifi_bidirectional,
+ verify_callee_func=is_phone_in_call_viwifi_bidirectional):
+ self.log.error("Failed to setup+teardown a call")
+ return False
+
+ return True
+
+ @test_tracker_info(uuid="0c6782b4-fa81-4c18-a7bf-9f0f5cc05d6d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_call_video_to_video_wifi_preferred_apm(self):
+ """ Test ViWifi<->ViWifi call functionality in APM Mode.
+
+ Make Sure PhoneA is in iWLAN mode (with Video Calling).
+ Make Sure PhoneB is in iWLAN mode (with Video Calling).
+ Turn on APM Mode
+ Connect to Wifi
+ Call from PhoneA to PhoneB as Bi-Directional Video,
+ Accept on PhoneB as video call, hang up on PhoneA.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ ads = self.android_devices
+ tasks = [
+ (phone_setup_iwlan,
+ (self.log, ads[0], True, WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ (phone_setup_iwlan,
+ (self.log, ads[1], True, WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid, self.wifi_network_pass)),
+ ]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ if not video_call_setup_teardown(
+ self.log,
+ ads[0],
+ ads[1],
+ ads[0],
+ video_state=VT_STATE_BIDIRECTIONAL,
+ verify_caller_func=is_phone_in_call_viwifi_bidirectional,
+ verify_callee_func=is_phone_in_call_viwifi_bidirectional):
+ self.log.error("Failed to setup+teardown a call")
+ return False
+
+ return True
+
+
+""" Tests End """
diff --git a/acts/tests/google/tel/live/TelWifiVoiceTest.py b/acts/tests/google/tel/live/TelWifiVoiceTest.py
index 4b8af08..21c37f3 100755
--- a/acts/tests/google/tel/live/TelWifiVoiceTest.py
+++ b/acts/tests/google/tel/live/TelWifiVoiceTest.py
@@ -75,6 +75,8 @@
from acts.test_utils.tel.tel_test_utils import wait_for_wfc_enabled
from acts.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
from acts.test_utils.tel.tel_test_utils import verify_http_connection
+from acts.test_utils.tel.tel_test_utils import get_telephony_signal_strength
+from acts.test_utils.tel.tel_test_utils import get_wifi_signal_strength
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
from acts.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
@@ -346,11 +348,15 @@
self.log.info(
"Expected exception happened: <{}>, return True.".format(
e))
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
return True
else:
self.log.info(
"Unexpected exception happened: <{}>, return False.".
format(e))
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
return False
finally:
ensure_phones_default_state(self.log, [ads[0], ads[1]])
@@ -455,7 +461,7 @@
def _wfc_phone_setup_cellular_absent(self, wfc_mode):
is_exception_happened = False
- time.sleep(60)
+ time.sleep(90)
try:
if not toggle_airplane_mode(self.log, self.android_devices[0],
False):
@@ -2559,6 +2565,7 @@
# ensure cellular rat, wfc mode, wifi associated
toggle_airplane_mode(self.log, self.android_devices[0], False)
toggle_volte(self.log, self.android_devices[0], True)
+
if not ensure_network_generation(
self.log,
self.android_devices[0],
@@ -2566,25 +2573,35 @@
voice_or_data=NETWORK_SERVICE_DATA):
self.log.error("_rove_out_test: {} failed to be in rat: {}".format(
self.android_devices[0].serial, cellular_rat))
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
return False
+
if not set_wfc_mode(self.log, self.android_devices[0], wfc_mode):
self.log.error("{} set WFC mode failed.".format(
self.android_devices[0].serial))
return False
+
if not ensure_wifi_connected(self.log, self.android_devices[0],
self.live_network_ssid,
self.live_network_pwd):
self.log.error("{} connect WiFI failed, expected succeed".format(
self.android_devices[0].serial))
return False
+
if (not wait_for_wifi_data_connection(self.log,
self.android_devices[0], True) or
not verify_http_connection(self.log, self.android_devices[0])):
self.log.error("No Data on Wifi")
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
return False
+
if not self._phone_idle_iwlan():
self.log.error("Phone failed to report iwlan in {}dBm.".format(
WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_INITIAL_STATE))
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
return False
# set up wifi to WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_NOT_ROVE_OUT in 10 seconds
@@ -2598,10 +2615,15 @@
self.android_devices[0], True) or
not verify_http_connection(self.log, self.android_devices[0])):
self.log.error("No Data on Wifi")
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
return False
+
if self._phone_wait_for_not_wfc() or not self._phone_idle_iwlan():
self.log.error("Phone should not rove-out in {}dBm.".format(
WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_NOT_ROVE_OUT))
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
return False
# set up wifi to WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_ROVE_OUT in 10 seconds
@@ -2615,12 +2637,17 @@
self.android_devices[0], True) or
not verify_http_connection(self.log, self.android_devices[0])):
self.log.error("No Data on Wifi")
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
return False
if not self._phone_wait_for_not_wfc() or self._phone_idle_iwlan():
self.log.error("Phone should rove-out in {}dBm.".format(
WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_ROVE_OUT))
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
return False
+
# make a call.
if wfc_mode == WFC_MODE_WIFI_ONLY:
return self._wfc_call_sequence(
@@ -3126,8 +3153,13 @@
self.wifi_rssi_with_no_atten, MIN_RSSI_RESERVED_VALUE, 2, 1)
# Make sure phone hand-out, not drop call
if not self._phone_wait_for_not_wfc():
- self.log.error("Phone should hand out.")
+ self.log.error("Phone should hand out to LTE.")
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
return False
+ self.log.info("iWLAN to LTE switch happened at below Signal Strengths")
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
if not self._is_phone_in_call_volte():
self.log.error("Phone should be in volte call.")
return False
@@ -3402,7 +3434,12 @@
# Make sure phone hand-out to iWLAN, not drop call
if not self._phone_wait_for_wfc():
self.log.error("Phone should hand out to iWLAN.")
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
return False
+ self.log.info("LTE to iWLAN switch happened at below Signal Strengths")
+ get_telephony_signal_strength(self.android_devices[0])
+ get_wifi_signal_strength(self.android_devices[0])
time.sleep(30)
if not self._is_phone_in_call_iwlan():
self.log.error("Phone should be in iWLAN call.")
diff --git a/acts/tests/google/tel/live/TelephonyConnectivitySanityTest.py b/acts/tests/google/tel/live/TelephonyConnectivitySanityTest.py
deleted file mode 100644
index 762117c..0000000
--- a/acts/tests/google/tel/live/TelephonyConnectivitySanityTest.py
+++ /dev/null
@@ -1,546 +0,0 @@
-#/usr/bin/env python3.4
-#
-# Copyright 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.
-"""
-Sanity tests for connectivity tests in telephony
-"""
-
-import time
-
-from acts.controllers.anritsu_lib.md8475a import BtsServiceState
-from acts.controllers.anritsu_lib.md8475a import BtsTechnology
-from acts.controllers.anritsu_lib.md8475a import MD8475A
-from acts.controllers.anritsu_lib.md8475a import ProcessingStatus
-from acts.controllers.anritsu_lib.md8475a import TriggerMessageIDs
-from acts.controllers.anritsu_lib.md8475a import TriggerMessageReply
-from acts.test_utils.tel import tel_test_utils
-from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-
-
-class TelephonyConnectivitySanityTest(TelephonyBaseTest):
- def __init__(self, controllers):
- TelephonyBaseTest.__init__(self, controllers)
- self.anritsu = MD8475A(tel_test_utils.MD8475A_IP_ADDRESS)
-
- def setup_test(self):
- self.lte_bts, self.wcdma_bts = tel_test_utils.set_system_model(
- self.anritsu, "LTE_WCDMA")
- tel_test_utils.init_phone(self.droid, self.ed)
- self.droid.telephonyStartTrackingServiceStateChange()
- self.droid.telephonyStartTrackingDataConnectionStateChange()
- self.log.info("Starting Simulation")
- self.anritsu.start_simulation()
- return True
-
- def teardown_test(self):
- self.droid.telephonyStopTrackingServiceStateChange()
- self.droid.telephonyStopTrackingDataConnectionStateChange()
- self.log.info("Stopping Simulation")
- self.anritsu.stop_simulation()
- # turn off modem
- tel_test_utils.turn_off_modem(self.droid)
-
- def teardown_class(self):
- self.anritsu.disconnect()
-
- """ Tests Begin """
-
- @TelephonyBaseTest.tel_test_wrap
- def test_network_registration(self):
- '''
- Test ID: TEL-CO-01
- Checks the Network service state after bootup. Verifies the
- network registration
-
- Steps
- -----
- 1. The device is in airplane mode
- 2. Turn off the airplane mode (This simulates the Boot up for modem)
- 3. check for the service state. expecting IN SERVICE
- '''
- test_status = "failed"
- # turn on modem to start registration
- tel_test_utils.turn_on_modem(self.droid)
- self.log.info("Waiting for Network registration")
- test_status, event = tel_test_utils.wait_for_network_registration(
- self.ed, self.anritsu, self.log)
-
- if test_status == "passed":
- self.log.info(
- "TEL-CO-01:Network registration verification: Passed")
- return True
- else:
- self.log.info(
- "TEL-CO-01:Network registration verification: Failed")
- return False
-
- @TelephonyBaseTest.tel_test_wrap
- def test_network_params_verification(self):
- '''
- Test ID: TEL-CO-02
- verifies the network registration parameters
-
- Steps
- -----
- 1. The device is in airplane mode
- 2. Turn off the airplane mode (This simulates the Boot up for modem)
- 3. check for the service state. expecting IN SERVICE
- 4. verifies the values for different parameters
- '''
- test_status = "failed"
- # turn on modem to start registration
- tel_test_utils.turn_on_modem(self.droid)
- self.log.info("Waiting for Network registration")
- test_status, event = tel_test_utils.wait_for_network_registration(
- self.ed, self.anritsu, self.log)
-
- if test_status == "passed":
- self.log.info("Verifying the NW Service Parameters")
- expected_voice_nwtype = None
- operator_name = None
- mcc = None
- mnc = None
-
- bts_number, rat_info = self.anritsu.get_camping_cell()
- if rat_info == BtsTechnology.WCDMA.value:
- expected_voice_nwtype = "UMTS"
- operator_name = tel_test_utils.WCDMA_NW_NAME
- mcc = tel_test_utils.NW_MCC
- mnc = tel_test_utils.NW_MNC
- elif rat_info == BtsTechnology.LTE.value:
- expected_voice_nwtype = "LTE"
- operator_name = tel_test_utils.LTE_NW_NAME
- mcc = tel_test_utils.NW_MCC
- mnc = tel_test_utils.NW_MNC
-
- self.log.info("VoiceNwState :{}".format(event['data'][
- 'VoiceRegState']))
- self.log.info("VoiceNetworkType :{}".format(event['data'][
- 'VoiceNetworkType']))
- self.log.info("DataRegState :{}".format(event['data'][
- 'DataRegState']))
- self.log.info("DataNetworkType :{}".format(event['data'][
- 'DataNetworkType']))
- self.log.info("OperatorName :{}".format(event['data'][
- 'OperatorName']))
- self.log.info("OperatorId :{}".format(event['data']['OperatorId']))
- self.log.info("Roaming :{}".format(event['data']['Roaming']))
-
- if event['data']['VoiceNetworkType'] != expected_voice_nwtype:
- test_status = "failed"
- self.log.info("Error:Expected NW Type is not received")
- if event['data']['OperatorId'][:3] != mcc:
- test_status = "failed"
- self.log.info("Error:Expected MNC is not received")
- if event['data']['OperatorId'][3:] != mnc:
- test_status = "failed"
- self.log.info("Error:Expected MCC is not received")
-
- # proceed with next step only if previous step is success
- if test_status == "passed":
- self.log.info("Waiting for data state: DATA_CONNECTED")
- test_status, event = tel_test_utils.wait_for_data_state(
- self.ed, self.log, "DATA_CONNECTED", 120)
-
- if test_status == "passed":
- self.log.info("TEL-CO-02: Network registration parameters"
- " verification: Passed")
- return True
- else:
- self.log.info("TEL-CO-02: Network registration parameters"
- " verification: Failed")
- return False
-
- @TelephonyBaseTest.tel_test_wrap
- def test_network_deregistration(self):
- '''
- Test ID: TEL-CO-03
- verifies the network de registration
-
- Steps
- -----
- 1. The device is in airplane mode
- 2. Turn off the airplane mode (This simulates the Boot up for modem)
- 3. check for the service state. expecting IN SERVICE
- 4. Turn on Airplane mode (This simulates network de registration)
- 5. check for the service state. expecting POWER_OFF
- '''
- test_status = "failed"
- # turn on modem to start registration
- tel_test_utils.turn_on_modem(self.droid)
- self.log.info("Waiting for Network registration")
- test_status, event = tel_test_utils.wait_for_network_registration(
- self.ed, self.anritsu, self.log)
-
- # proceed with next step only if previous step is success
- if test_status == "passed":
- test_status = "failed"
- self.ed.clear_all_events()
- self.log.info("Making device to detach from network")
- self.droid.connectivityToggleAirplaneMode(True)
- self.log.info("Waiting for service state: POWER_OFF")
- test_status, event = tel_test_utils.wait_for_network_state(
- self.ed, self.log, "POWER_OFF", 60)
-
- if test_status == "passed":
- self.log.info("TEL-CO-03: Network de-registration"
- " verification: Passed")
- return True
- else:
- self.log.info("TEL-CO-03: Network de-registration"
- " verification: Failed")
- return False
-
- @TelephonyBaseTest.tel_test_wrap
- def test_network_out_of_service(self):
- '''
- Test ID: TEL-CO-04
- verifies the network out of state
-
- Steps
- -----
- 1. The device is in airplane mode
- 2. Turn off the airplane mode (This simulates the Boot up for modem)
- 3. check for the service state. expecting IN SERVICE
- 4. Make network out of service
- 5. check for the service state. expecting OUT_OF_SERVICE
- '''
-
- test_status = "failed"
- # turn on modem to start registration
- tel_test_utils.turn_on_modem(self.droid)
- self.log.info("Waiting for Network registration")
- test_status, event = tel_test_utils.wait_for_network_registration(
- self.ed, self.anritsu, self.log)
-
- # proceed with next step only if previous step is success
- if test_status == "passed":
- test_status = "failed"
- self.ed.clear_all_events()
- # This sleep is required.Sometimes Anritsu box doesn't behave as
- # expected in executing the commands send to it without this delay.
- # May be it is in state transition.so the test doesn't proceed.
- # hence introduced this delay.
- time.sleep(5)
- bts_number, rat_info = self.anritsu.get_camping_cell()
- self.log.info("Making the attached NW as OUT_OF_STATE")
- if rat_info == BtsTechnology.LTE.value:
- self.lte_bts.service_state = BtsServiceState.SERVICE_STATE_OUT
- else:
- self.wcdma_bts.service_state = BtsServiceState.SERVICE_STATE_OUT
- self.log.info("Waiting for service state: OUT_OF_SERVICE")
- test_status, event = tel_test_utils.wait_for_network_state(
- self.ed, self.log, "OUT_OF_SERVICE", 90)
-
- if test_status == "passed":
- self.log.info("TEL-CO-04: Network out-of-service"
- " verification: Passed")
- return True
- else:
- self.log.info("TEL-CO-04: Network out-of-service"
- " verification: Failed")
- return False
-
- @TelephonyBaseTest.tel_test_wrap
- def test_network_return_inservice(self):
- '''
- Test ID: TEL-CO-06
- verifies the network returns to IN_SERVICE from OUT_OF_SERVICE
-
- Steps
- -----
- 1. The device is in airplane mode
- 2. Turn off the airplane mode (This simulates the Boot up for modem)
- 3. check for the service state. expecting IN SERVICE
- 4. Make the network out of service
- 5. check for the service state. expecting OUT_OF_SERVICE
- 6. Bring back the device to IN_SERVICE
- 7. check for the service state. expecting IN_SERVICE
- '''
- test_status = "failed"
- # turn on modem to start registration
- tel_test_utils.turn_on_modem(self.droid)
- self.log.info("Waiting for Network registration")
- test_status, event = tel_test_utils.wait_for_network_registration(
- self.ed, self.anritsu, self.log)
- self.log.info("Waiting for data state: DATA_CONNECTED")
- test_status, event = tel_test_utils.wait_for_data_state(
- self.ed, self.log, "DATA_CONNECTED", 120)
-
- # proceed with next step only if previous step is success
- if test_status == "passed":
- test_status = "failed"
- self.ed.clear_all_events()
- # This sleep is required.Sometimes Anritsu box doesn't behave as
- # expected in executing the commands send to it without this delay.
- # May be it is in state transition.so the test doesn't proceed.
- # hence introduced this delay.
- time.sleep(5)
- bts_number, rat_info = self.anritsu.get_camping_cell()
- self.log.info("Making the attached NW as OUT_OF_STATE")
- if rat_info == BtsTechnology.LTE.value:
- self.lte_bts.service_state = BtsServiceState.SERVICE_STATE_OUT
- else:
- self.wcdma_bts.service_state = BtsServiceState.SERVICE_STATE_OUT
- self.log.info("Waiting for service state: OUT_OF_SERVICE")
- test_status, event = tel_test_utils.wait_for_network_state(
- self.ed, self.log, "OUT_OF_SERVICE", 120)
-
- # proceed with next step only if previous step is success
- if test_status == "passed":
- test_status = "failed"
- self.log.info("Waiting for Network registration")
- test_status, event = tel_test_utils.wait_for_network_registration(
- self.ed, self.anritsu, self.log)
- self.log.info("Waiting for data state: DATA_CONNECTED")
- test_status, event = tel_test_utils.wait_for_data_state(
- self.ed, self.log, "DATA_CONNECTED", 120)
-
- # proceed with next step only if previous step is success
- if test_status == "passed":
- test_status = "failed"
- self.ed.clear_all_events()
- # This sleep is required.Sometimes Anritsu box doesn't behave as
- # expected in executing the commands send to it without this delay.
- # May be it is in state transition.so the test doesn't proceed.
- # hence introduced this delay.
- time.sleep(5)
- bts_number, rat_info = self.anritsu.get_camping_cell()
- self.log.info("Making the attached NW as OUT_OF_STATE")
- if rat_info == BtsTechnology.LTE.value:
- self.lte_bts.service_state = BtsServiceState.SERVICE_STATE_OUT
- else:
- self.wcdma_bts.service_state = BtsServiceState.SERVICE_STATE_OUT
- self.log.info("Waiting for service state: OUT_OF_SERVICE")
- test_status, event = tel_test_utils.wait_for_network_state(
- self.ed, self.log, "OUT_OF_SERVICE", 120)
-
- # proceed with next step only if previous step is success
- if test_status == "passed":
- test_status = "failed"
- self.ed.clear_all_events()
- # This sleep is required.Sometimes Anritsu box doesn't behave as
- # expected in executing the commands send to it without this delay.
- # May be it is in state transition.so the test doesn't proceed.
- # hence introduced this delay.
- time.sleep(5)
- self.log.info("Making the NW service IN_SERVICE")
- self.lte_bts.service_state = BtsServiceState.SERVICE_STATE_IN
- self.log.info("Waiting for Network registration")
- test_status, event = tel_test_utils.wait_for_network_registration(
- self.ed, self.anritsu, self.log)
- self.log.info("Waiting for data state: DATA_CONNECTED")
- test_status, event = tel_test_utils.wait_for_data_state(
- self.ed, self.log, "DATA_CONNECTED", 120)
-
- if test_status == "passed":
- self.log.info("TEL-CO-06: Network returning to IN_SERVICE"
- " verification: Passed")
- return True
- else:
- self.log.info("TEL-CO-06: Network returning to IN_SERVICE"
- " verification: Failed")
- return False
-
- @TelephonyBaseTest.tel_test_wrap
- def test_set_preferred_network(self):
- '''
- Test ID: TEL-CO-07
- verifies the network is registered on Preferred network
-
- Steps
- -----
- 1. The device is in airplane mode
- 2. Turn off the airplane mode (This simulates the Boot up for modem)
- 3. check for the service state. expecting IN SERVICE
- 4. Set the preferred network type
- 5. check for the service state and registered network
- '''
- test_status = "failed"
- # turn on modem to start registration
- tel_test_utils.turn_on_modem(self.droid)
- self.log.info("Waiting for Network registration")
- test_status, event = tel_test_utils.wait_for_network_registration(
- self.ed, self.anritsu, self.log)
-
- # proceed with next step only if previous step is success
- if test_status == "passed":
- test_status = "failed"
- pref_nwtype = 0
- expected_nwtype = ""
- bts_number, rat_info = self.anritsu.get_camping_cell()
- if rat_info == BtsTechnology.WCDMA.value:
- pref_nwtype = tel_test_utils.NETWORK_MODE_LTE_ONLY
- expected_nwtype = "LTE"
- elif rat_info == BtsTechnology.LTE.value:
- pref_nwtype = tel_test_utils.NETWORK_MODE_WCDMA_ONLY
- expected_nwtype = "UMTS"
- else:
- raise ValueError("Incorrect value of RAT returned by MD8475A")
- self.log.info("Setting preferred Network to " + expected_nwtype)
- self.droid.telephonySetPreferredNetwork(pref_nwtype)
- self.log.info("Waiting for service state: IN_SERVICE in " +
- expected_nwtype)
- test_status, event = tel_test_utils.wait_for_network_registration(
- self.ed, self.anritsu, self.log, expected_nwtype)
-
- # proceed with next step only if previous step is success
- if test_status == "passed":
- test_status = "failed"
- pref_nwtype = 0
- expected_nwtype = ""
- bts_number, rat_info = self.anritsu.get_camping_cell()
- if rat_info == BtsTechnology.WCDMA.value:
- pref_nwtype = tel_test_utils.NETWORK_MODE_LTE_ONLY
- expected_nwtype = "LTE"
- elif rat_info == BtsTechnology.LTE.value:
- pref_nwtype = tel_test_utils.NETWORK_MODE_WCDMA_ONLY
- expected_nwtype = "UMTS"
- else:
- raise ValueError("Incorrect value of RAT returned by MD8475A")
- self.log.info("Setting preferred Network to " + expected_nwtype)
- self.droid.telephonySetPreferredNetwork(pref_nwtype)
- self.log.info("Waiting for service state: IN_SERVICE in " +
- expected_nwtype)
- test_status, event = tel_test_utils.wait_for_network_registration(
- self.ed, self.anritsu, self.log, expected_nwtype)
- # setting the preferred network type to default
- self.droid.telephonySetPreferredNetwork(
- tel_test_utils.NETWORK_MODE_LTE_GSM_WCDMA)
-
- if test_status == "passed":
- self.log.info("TEL-CO-07: Setting preferred Network"
- "verification: Passed")
- return True
- else:
- self.log.info("TEL-CO-07: Setting preferred Network"
- "verification: Failed")
- return False
-
- @TelephonyBaseTest.tel_test_wrap
- def test_network_emergency(self):
- '''
- Test ID: TEL-CO-05
- verifies the network state - emergency
-
- Steps
- -----
- 1. The device is in airplane mode
- 2. Turn off the airplane mode (This simulates the Boot up for modem)
- 3. check for the service state. expecting IN SERVICE
- 4. Make the device emergency only
- 5. check for the service state. expecting EMERGENCY_ONLY
- '''
- test_status = "failed"
- CAUSE_LA_NOTALLOWED = 12
- CAUSE_EPS_NOTALLOWED = 7
- triggermessage = self.anritsu.get_TriggerMessage()
- triggermessage.set_reply_type(TriggerMessageIDs.ATTACH_REQ,
- TriggerMessageReply.REJECT)
- triggermessage.set_reject_cause(TriggerMessageIDs.ATTACH_REQ,
- CAUSE_EPS_NOTALLOWED)
- # This sleep is required.Sometimes Anritsu box doesn't behave as
- # expected in executing the commands send to it without this delay.
- # May be it is in state transition.so the test doesn't proceed.
- # hence introduced this delay.
- time.sleep(5)
- triggermessage.set_reply_type(TriggerMessageIDs.MM_LOC_UPDATE_REQ,
- TriggerMessageReply.REJECT)
- triggermessage.set_reject_cause(TriggerMessageIDs.MM_LOC_UPDATE_REQ,
- CAUSE_LA_NOTALLOWED)
-
- # turn on modem to start registration
- tel_test_utils.turn_on_modem(self.droid)
- self.log.info("Waiting for service state: emergency")
- test_status, event = tel_test_utils.wait_for_network_state(
- self.ed, self.log, "EMERGENCY_ONLY", 300)
-
- if test_status == "passed":
- self.droid.connectivityToggleAirplaneMode(True)
- time_to_wait = 60
- sleep_interval = 1
- # Waiting for POWER OFF state in Anritsu
- start_time = time.time()
- end_time = start_time + time_to_wait
- while True:
- ue_status = self.anritsu.get_ue_status()
- if ue_status == ProcessingStatus.PROCESS_STATUS_POWEROFF:
- break
-
- if time.time() <= end_time:
- time.sleep(sleep_interval)
- time_to_wait = end_time - time.time()
- else:
- self.log.info("MD8475A has not come to POWEROFF state")
- break
-
- # This sleep is required.Sometimes Anritsu box doesn't behave as
- # expected in executing the commands send to it without this delay.
- # May be it is in state transition.so the test doesn't proceed.
- # hence introduced this delay.
- time.sleep(10)
- triggermessage.set_reply_type(TriggerMessageIDs.ATTACH_REQ,
- TriggerMessageReply.ACCEPT)
- triggermessage.set_reply_type(TriggerMessageIDs.MM_LOC_UPDATE_REQ,
- TriggerMessageReply.ACCEPT)
- self.droid.connectivityToggleAirplaneMode(False)
- tel_test_utils.wait_for_network_registration(self.ed, self.anritsu,
- self.log)
-
- if test_status == "passed":
- self.log.info("TEL-CO-05: Network emergency state"
- " verification: Passed")
- return True
- else:
- self.log.info("TEL-CO-05: Network emergency state"
- " verification: Failed")
-
- return False
-
- @TelephonyBaseTest.tel_test_wrap
- def test_manual_operator_selection(self):
- '''
- verifies the Manual Operator Selection
-
- Steps
- -----
- 1. The device is in airplane mode
- 2. Turn off the airplane mode (This simulates the Boot up for modem)
- 3. check for the service state. expecting IN SERVICE
- 4. search for NW operators and manually select a non-subscribed operator
- 5. search for NW operators and manually select the subscribed operator
- 6. verify the device is camped on subscribed operator
- '''
- # Android public APIs not available for this operation
- pass
-
- @TelephonyBaseTest.tel_test_wrap
- def test_auto_operator_selection(self):
- '''
- verifies the Automatic Operator Selection
-
- Steps
- -----
- 1. The device is in airplane mode
- 2. Turn off the airplane mode (This simulates the Boot up for modem)
- 3. check for the service state. expecting IN SERVICE
- 4. search for NW operators and manually select a non-subscribed operator
- 5. select the the subscribed operator automatically
- 6. verify the device is camped on subscribed operator
- '''
- # Android public APIs not available for this operation
- pass
-
- """ Tests End """
diff --git a/acts/tests/google/tel/live/TelephonyDataSanityTest.py b/acts/tests/google/tel/live/TelephonyDataSanityTest.py
deleted file mode 100644
index 4d6ae38..0000000
--- a/acts/tests/google/tel/live/TelephonyDataSanityTest.py
+++ /dev/null
@@ -1,150 +0,0 @@
-#/usr/bin/env python3.4
-#
-# Copyright 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.
-"""
-Sanity tests for connectivity tests in telephony
-"""
-
-import time
-from queue import Empty
-
-from acts.controllers.anritsu_lib.md8475a import BtsNumber
-from acts.controllers.anritsu_lib.md8475a import BtsTechnology
-from acts.controllers.anritsu_lib.md8475a import MD8475A
-from acts.test_utils.tel import tel_test_utils
-from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-
-
-class TelephonyDataSanityTest(TelephonyBaseTest):
- def __init__(self, controllers):
- TelephonyBaseTest.__init__(self, controllers)
- self.anritsu = MD8475A(tel_test_utils.MD8475A_IP_ADDRESS)
-
- def setup_test(self):
- self.lte_bts, self.wcdma_bts = tel_test_utils.set_system_model(
- self.anritsu, "LTE_WCDMA")
- tel_test_utils.init_phone(self.droid, self.ed)
- self.droid.telephonyStartTrackingServiceStateChange()
- self.droid.telephonyStartTrackingDataConnectionStateChange()
- self.log.info("Starting Simulation")
- self.anritsu.start_simulation()
- return True
-
- def teardown_test(self):
- self.droid.telephonyStopTrackingServiceStateChange()
- self.droid.telephonyStopTrackingDataConnectionStateChange()
- self.log.info("Stopping Simulation")
- self.anritsu.stop_simulation()
- # turn off modem
- tel_test_utils.turn_off_modem(self.droid)
-
- def teardown_class(self):
- self.anritsu.disconnect()
-
- def _wait_for_bts_state(self, btsnumber, state, timeout=30):
- ''' Wait till BTS state changes. state value are "IN" and "OUT" '''
- sleep_interval = 2
- status = "failed"
-
- wait_time = timeout
- while (wait_time > 0):
- if state == btsnumber.service_state:
- print(btsnumber.service_state)
- status = "passed"
- break
- else:
- time.sleep(sleep_interval)
- waiting_time = waiting_time - sleep_interval
-
- if status == "failed":
- self.log.info("Timeout: Expected state is not received.")
-
- """ Tests Begin """
-
- @TelephonyBaseTest.tel_test_wrap
- def test_data_conn_state_when_access_enabled(self):
- '''
- Check data conenction state after boot up
-
- Steps
- -----
- 1. Get the device is IN_SERVICE state
- 2. check the data conenction status
- '''
- test_status = "failed"
- # turn on modem to start registration
- tel_test_utils.turn_on_modem(self.droid)
- self.log.info("Waiting for Network registration")
- test_status, event = tel_test_utils.wait_for_network_registration(
- self.ed, self.anritsu, self.log)
-
- # proceed with next step only if previous step is success
- if test_status == "passed":
- self.log.info("Waiting for data state: DATA_CONNECTED")
- test_status, event = tel_test_utils.wait_for_data_state(
- self.ed, self.log, "DATA_CONNECTED", 120)
-
- if test_status == "passed":
- self.log.info("Data connection state(access enabled) "
- "verification: Passed")
- return True
- else:
- self.log.info("Data connection state(access enabled) "
- "verification: Failed")
- return False
-
- @TelephonyBaseTest.tel_test_wrap
- def test_data_conn_state_when_access_disabled(self):
- '''
- Check data conenction state after disabling data access
-
- Steps
- -----
- 1. Get the device is IN_SERVICE state
- 2. check the data conenction status ( data access enabled)
- 3. disable the data access
- 4. check the data conenction status ( data access enabled)
- '''
- test_status = "failed"
- # turn on modem to start registration
- tel_test_utils.turn_on_modem(self.droid)
- self.log.info("Waiting for Network registration")
- test_status, event = tel_test_utils.wait_for_network_registration(
- self.ed, self.anritsu, self.log)
-
- # proceed with next step only if previous step is success
- if test_status == "passed":
- self.log.info("Waiting for data state: DATA_CONNECTED")
- test_status, event = tel_test_utils.wait_for_data_state(
- self.ed, self.log, "DATA_CONNECTED", 120)
-
- if test_status == "passed":
- time.sleep(20)
- self.log.info("Disabling data access")
- self.droid.telephonyToggleDataConnection(False)
- self.log.info("Waiting for data state: DATA_DISCONNECTED")
- test_status, event = tel_test_utils.wait_for_data_state(
- self.ed, self.log, "DATA_DISCONNECTED", 120)
-
- if test_status == "passed":
- self.log.info("Data connection state(access disabled) "
- "verification: Passed")
- return True
- else:
- self.log.info("Data connection state(access disabled) "
- "verification: Failed")
- return False
-
- """ Tests End """
diff --git a/acts/tests/google/wifi/WifiEnterpriseTest.py b/acts/tests/google/wifi/WifiEnterpriseTest.py
index 58ae4db..41a2512 100755
--- a/acts/tests/google/wifi/WifiEnterpriseTest.py
+++ b/acts/tests/google/wifi/WifiEnterpriseTest.py
@@ -130,7 +130,6 @@
# Set screen lock password so ConfigStore is unlocked.
self.dut.droid.setDevicePassword(self.device_password)
self.tcpdump_pid = None
- self.tcpdump_file = None
def teardown_class(self):
wutils.reset_wifi(self.dut)
@@ -143,14 +142,12 @@
self.dut.droid.wakeUpNow()
wutils.reset_wifi(self.dut)
self.dut.ed.clear_all_events()
- (self.tcpdump_pid, self.tcpdump_file) = start_adb_tcpdump(
- self.dut, self.test_name, mask='all')
+ self.tcpdump_pid = start_adb_tcpdump(self.dut, self.test_name, mask='all')
def teardown_test(self):
if self.tcpdump_pid:
stop_adb_tcpdump(self.dut,
self.tcpdump_pid,
- self.tcpdump_file,
pull_tcpdump=True)
self.tcpdump_pid = None
self.dut.droid.wakeLockRelease()
diff --git a/acts/tests/google/wifi/WifiHiddenSSIDTest.py b/acts/tests/google/wifi/WifiHiddenSSIDTest.py
new file mode 100755
index 0000000..f794a36
--- /dev/null
+++ b/acts/tests/google/wifi/WifiHiddenSSIDTest.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2018 - 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 itertools
+import pprint
+import queue
+import time
+
+import acts.base_test
+import acts.signals
+import acts.test_utils.wifi.wifi_test_utils as wutils
+import acts.utils
+
+from acts import asserts
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
+
+
+class WifiHiddenSSIDTest(WifiBaseTest):
+ """Tests for APIs in Android's WifiManager class.
+
+ Test Bed Requirement:
+ * One Android device
+ * Several Wi-Fi networks visible to the device, including an open Wi-Fi
+ network.
+ """
+
+ def __init__(self, controllers):
+ WifiBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ self.dut = self.android_devices[0]
+ wutils.wifi_test_device_init(self.dut)
+ req_params = []
+ opt_param = [
+ "open_network", "reference_networks"]
+ self.unpack_userparams(
+ req_param_names=req_params, opt_param_names=opt_param)
+
+ if "AccessPoint" in self.user_params:
+ self.legacy_configure_ap_and_start(hidden=True)
+
+ asserts.assert_true(
+ len(self.reference_networks) > 0,
+ "Need at least one reference network with psk.")
+ self.open_hidden_2g = self.open_network[0]["2g"]
+ self.open_hidden_5g = self.open_network[0]["5g"]
+ self.wpa_hidden_2g = self.reference_networks[0]["2g"]
+ self.wpa_hidden_5g = self.reference_networks[0]["5g"]
+
+ def setup_test(self):
+ self.dut.droid.wakeLockAcquireBright()
+ self.dut.droid.wakeUpNow()
+
+ def teardown_test(self):
+ self.dut.droid.wakeLockRelease()
+ self.dut.droid.goToSleepNow()
+
+ def on_fail(self, test_name, begin_time):
+ self.dut.take_bug_report(test_name, begin_time)
+ self.dut.cat_adb_log(test_name, begin_time)
+
+ def teardown_class(self):
+ wutils.reset_wifi(self.dut)
+ if "AccessPoint" in self.user_params:
+ del self.user_params["reference_networks"]
+ del self.user_params["open_network"]
+
+ """Helper Functions"""
+
+ def check_hiddenSSID_in_scan(self, ap_ssid, max_tries=2):
+ """Check if the ap started by wifi tethering is seen in scan results.
+
+ Args:
+ ap_ssid: SSID of the ap we are looking for.
+ max_tries: Number of scans to try.
+ Returns:
+ True: if ap_ssid is found in scan results.
+ False: if ap_ssid is not found in scan results.
+ """
+ for num_tries in range(max_tries):
+ wutils.start_wifi_connection_scan(self.dut)
+ scan_results = self.dut.droid.wifiGetScanResults()
+ match_results = wutils.match_networks(
+ {wutils.WifiEnums.SSID_KEY: ap_ssid}, scan_results)
+ if len(match_results) > 0:
+ return True
+ return False
+
+ def add_hiddenSSID_and_connect(self, hidden_network):
+ """Add the hidden network and connect to it.
+
+ Args:
+ hidden_network: The hidden network config to connect to.
+
+ """
+ ret = self.dut.droid.wifiAddNetwork(hidden_network)
+ asserts.assert_true(ret != -1, "Add network %r failed" % hidden_network)
+ self.dut.droid.wifiEnableNetwork(ret, 0)
+ wutils.connect_to_wifi_network(self.dut, hidden_network)
+ if not wutils.validate_connection(self.dut):
+ raise signals.TestFailure("Fail to connect to internet on %s" %
+ hidden_network)
+
+ """Tests"""
+
+ @test_tracker_info(uuid="d0871f98-6049-4937-a288-ec4a2746c771")
+ def test_connect_to_wpa_hidden_2g(self):
+ """Connect to a WPA, 2G network.
+
+ Steps:
+ 1. Add a WPA, 2G hidden network.
+ 2. Ensure the network is visible in scan.
+ 3. Connect and run ping.
+
+ """
+ self.add_hiddenSSID_and_connect(self.wpa_hidden_2g)
+
+ @test_tracker_info(uuid="c558b31a-549a-4012-9052-275623992187")
+ def test_connect_to_wpa_hidden_5g(self):
+ """Connect to a WPA, 5G hidden network.
+
+ Steps:
+ 1. Add a WPA, 5G hidden network.
+ 2. Ensure the network is visible in scan.
+ 3. Connect and run ping.
+
+ """
+ self.add_hiddenSSID_and_connect(self.wpa_hidden_5g)
+
+ @test_tracker_info(uuid="cdfce76f-6374-439d-aa1d-e920508269d2")
+ def test_connect_to_open_hidden_2g(self):
+ """Connect to a Open, 2G hidden network.
+
+ Steps:
+ 1. Add a Open, 2G hidden network.
+ 2. Ensure the network is visible in scan.
+ 3. Connect and run ping.
+
+ """
+ self.add_hiddenSSID_and_connect(self.open_hidden_2g)
+
+ @test_tracker_info(uuid="29ccbae4-4382-4df8-8fc5-00e3104230d0")
+ def test_connect_to_open_hidden_5g(self):
+ """Connect to a Open, 5G hidden network.
+
+ Steps:
+ 1. Add a Open, 5G hidden network.
+ 2. Ensure the network is visible in scan.
+ 3. Connect and run ping.
+
+ """
+ self.add_hiddenSSID_and_connect(self.open_hidden_5g)
diff --git a/acts/tests/google/wifi/WifiManagerTest.py b/acts/tests/google/wifi/WifiManagerTest.py
index b2a7b53..3c81053 100755
--- a/acts/tests/google/wifi/WifiManagerTest.py
+++ b/acts/tests/google/wifi/WifiManagerTest.py
@@ -51,11 +51,6 @@
def setup_class(self):
self.dut = self.android_devices[0]
wutils.wifi_test_device_init(self.dut)
- # If running in a setup with attenuators, set attenuation on all
- # channels to zero.
- if getattr(self, "attenuators", []):
- for a in self.attenuators:
- a.set_atten(0)
req_params = []
opt_param = [
"open_network", "reference_networks", "iperf_server_address"
@@ -75,7 +70,8 @@
self.wpapsk_2g = self.reference_networks[0]["2g"]
self.wpapsk_5g = self.reference_networks[0]["5g"]
self.open_network = self.open_network[0]["2g"]
- self.iperf_server.start()
+ if hasattr(self, 'iperf_server'):
+ self.iperf_server.start()
def setup_test(self):
self.dut.droid.wakeLockAcquireBright()
@@ -87,7 +83,8 @@
wutils.reset_wifi(self.dut)
def teardown_class(self):
- self.iperf_server.stop()
+ if hasattr(self, 'iperf_server'):
+ self.iperf_server.stop()
def on_fail(self, test_name, begin_time):
self.dut.take_bug_report(test_name, begin_time)
diff --git a/acts/tests/google/wifi/WifiTeleCoexTest.py b/acts/tests/google/wifi/WifiTeleCoexTest.py
index b21ce20..3d30640 100644
--- a/acts/tests/google/wifi/WifiTeleCoexTest.py
+++ b/acts/tests/google/wifi/WifiTeleCoexTest.py
@@ -195,6 +195,7 @@
self.connect_to_wifi(self.dut, self.network)
wifi_utils.toggle_wifi_off_and_on(self.dut)
self.validate_cellular_and_wifi()
+ return True
@test_tracker_info(uuid="caf22447-6354-4a2e-99e5-0ff235fc8f20")
@@ -216,6 +217,7 @@
self.connect_to_wifi(self.dut, self.network)
wifi_utils.toggle_airplane_mode_on_and_off(self.dut)
self.validate_cellular_and_wifi()
+ return True
@test_tracker_info(uuid="dd888b35-f820-409a-89af-4b0f6551e4d6")
@@ -239,6 +241,7 @@
self.connect_to_wifi(self.dut, self.network)
self.stress_toggle_airplane_and_wifi(1)
self.validate_cellular_and_wifi()
+ return True
@test_tracker_info(uuid="15db5b7e-827e-4bc8-8e77-7fcce343a323")
@@ -260,6 +263,7 @@
self.connect_to_wifi(self.dut, self.network)
self.stress_toggle_wifi(self.stress_count)
self.validate_cellular_and_wifi()
+ return True
@test_tracker_info(uuid="80a2f1bf-5e41-453a-9b8e-be3b41d4d313")
@@ -281,6 +285,7 @@
self.connect_to_wifi(self.dut, self.network)
self.stress_toggle_airplane(self.stress_count)
self.validate_cellular_and_wifi()
+ return True
@test_tracker_info(uuid="b88ad3e7-6462-4280-ad57-22d0ac91fdd8")
@@ -305,3 +310,4 @@
self.connect_to_wifi(self.dut, self.network)
self.stress_toggle_airplane_and_wifi(self.stress_count)
self.validate_cellular_and_wifi()
+ return True
diff --git a/acts/tests/google/wifi/WifiTetheringTest.py b/acts/tests/google/wifi/WifiTetheringTest.py
index d471290..9b66112 100644
--- a/acts/tests/google/wifi/WifiTetheringTest.py
+++ b/acts/tests/google/wifi/WifiTetheringTest.py
@@ -23,12 +23,9 @@
from acts import test_runner
from acts.controllers import adb
from acts.test_decorators import test_tracker_info
-from acts.test_utils.tel import tel_data_utils
from acts.test_utils.tel import tel_defines
-from acts.test_utils.tel.tel_data_utils import toggle_airplane_mode
from acts.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
from acts.test_utils.tel.tel_test_utils import get_operator_name
-from acts.test_utils.tel.tel_test_utils import http_file_download_by_chrome
from acts.test_utils.tel.tel_test_utils import verify_http_connection
from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
@@ -42,15 +39,11 @@
def setup_class(self):
""" Setup devices for tethering and unpack params """
- self.convert_byte_to_mb = 1024.0 * 1024.0
- self.new_ssid = "wifi_tethering_test2"
- self.data_usage_error = 1
-
self.hotspot_device = self.android_devices[0]
self.tethered_devices = self.android_devices[1:]
- req_params = ("network", "url", "download_file", "file_size")
+ req_params = ("network", "url")
self.unpack_userparams(req_params)
- self.file_size = int(self.file_size)
+ self.new_ssid = "wifi_tethering_test2"
wutils.wifi_toggle_state(self.hotspot_device, False)
self.hotspot_device.droid.telephonyToggleDataConnection(True)
@@ -65,24 +58,6 @@
ad.droid.telephonyToggleDataConnection(False)
wutils.wifi_test_device_init(ad)
- # Set chrome browser start with no-first-run verification
- # Give permission to read from and write to storage
- commands = ["pm grant com.android.chrome "
- "android.permission.READ_EXTERNAL_STORAGE",
- "pm grant com.android.chrome "
- "android.permission.WRITE_EXTERNAL_STORAGE",
- "rm /data/local/chrome-command-line",
- "am set-debug-app --persistent com.android.chrome",
- 'echo "chrome --no-default-browser-check --no-first-run '
- '--disable-fre" > /data/local/tmp/chrome-command-line']
- for cmd in commands:
- for dut in self.tethered_devices:
- try:
- dut.adb.shell(cmd)
- except adb.AdbError:
- self.log.warn("adb command %s failed on %s"
- % (cmd, dut.serial))
-
def teardown_class(self):
""" Reset devices """
wutils.wifi_toggle_state(self.hotspot_device, True)
@@ -414,106 +389,6 @@
wutils.stop_wifi_tethering(self.hotspot_device)
return result
- @test_tracker_info(uuid="d4e18031-0af0-4b29-a574-8707cd4029b7")
- def test_wifi_tethering_verify_received_bytes(self):
- """ Steps:
-
- 1. Start wifi hotspot and connect tethered device to it
- 2. Get the data usage on hotspot device
- 3. Download data on tethered device
- 4. Get the new data usage on hotspot device
- 5. Verify that hotspot device's data usage
- increased by downloaded file size
- """
- wutils.toggle_wifi_off_and_on(self.hotspot_device)
- dut = self.hotspot_device
- self._start_wifi_tethering()
- wutils.wifi_connect(self.tethered_devices[0], self.network)
- subscriber_id = dut.droid.telephonyGetSubscriberId()
-
- # get data usage limit
- end_time = int(time.time() * 1000)
- bytes_before_download = dut.droid.connectivityGetRxBytesForDevice(
- subscriber_id, 0, end_time)
- self.log.info("Data usage before download: %s MB" %
- (bytes_before_download/self.convert_byte_to_mb))
-
- # download file
- self.log.info("Download file of size %sMB" % self.file_size)
- http_file_download_by_chrome(self.tethered_devices[0],
- self.download_file,
- self.file_size)
-
- # get data usage limit after download
- end_time = int(time.time() * 1000)
- bytes_after_download = dut.droid.connectivityGetRxBytesForDevice(
- subscriber_id, 0, end_time)
- self.log.info("Data usage after download: %s MB" %
- (bytes_after_download/self.convert_byte_to_mb))
-
- bytes_diff = bytes_after_download - bytes_before_download
- wutils.stop_wifi_tethering(self.hotspot_device)
-
- # verify data usage update is correct
- bytes_used = bytes_diff/self.convert_byte_to_mb
- self.log.info("Data usage on the device increased by %s" % bytes_used)
- return bytes_used > self.file_size \
- and bytes_used < self.file_size + self.data_usage_error
-
- @test_tracker_info(uuid="07a00c96-4770-44a1-a9db-b3d02d6a12b6")
- def test_wifi_tethering_data_usage_limit(self):
- """ Steps:
-
- 1. Set the data usage limit to current data usage + 10MB
- 2. Start wifi tethering and connect a dut to the SSID
- 3. Download 20MB data on tethered device
- a. file download should stop
- b. tethered device will lose internet connectivity
- c. data usage limit reached message should be displayed
- on the hotspot device
- 4. Verify data usage limit
- """
- wutils.toggle_wifi_off_and_on(self.hotspot_device)
- dut = self.hotspot_device
- data_usage_inc = 10 * self.convert_byte_to_mb
- subscriber_id = dut.droid.telephonyGetSubscriberId()
-
- self._start_wifi_tethering()
- wutils.wifi_connect(self.tethered_devices[0], self.network)
-
- # get current data usage
- end_time = int(time.time() * 1000)
- old_data_usage = dut.droid.connectivityQuerySummaryForDevice(
- subscriber_id, 0, end_time)
-
- # set data usage limit to current usage limit + 10MB
- dut.droid.connectivitySetDataUsageLimit(
- subscriber_id, str(int(old_data_usage + data_usage_inc)))
-
- # download file - size 20MB
- http_file_download_by_chrome(self.tethered_devices[0],
- self.download_file,
- self.file_size,
- timeout=120)
- end_time = int(time.time() * 1000)
- new_data_usage = dut.droid.connectivityQuerySummaryForDevice(
- subscriber_id, 0, end_time)
-
- # test network connectivity on tethered device
- asserts.assert_true(
- not wutils.validate_connection(self.tethered_devices[0]),
- "Tethered device has internet connectivity after data usage"
- "limit is reached on hotspot device")
- dut.droid.connectivityFactoryResetNetworkPolicies(subscriber_id)
- wutils.stop_wifi_tethering(self.hotspot_device)
-
- old_data_usage = (old_data_usage+data_usage_inc)/self.convert_byte_to_mb
- new_data_usage = new_data_usage/self.convert_byte_to_mb
- self.log.info("Expected data usage: %s MB" % old_data_usage)
- self.log.info("Actual data usage: %s MB" % new_data_usage)
-
- return (new_data_usage-old_data_usage) < self.data_usage_error
-
@test_tracker_info(uuid="2bc344cb-0277-4f06-b6cc-65b3972086ed")
def test_change_wifi_hotspot_ssid_when_hotspot_enabled(self):
""" Steps:
diff --git a/acts/tests/google/wifi/aware/functional/DataPathTest.py b/acts/tests/google/wifi/aware/functional/DataPathTest.py
index 7e77c79..66ec715 100644
--- a/acts/tests/google/wifi/aware/functional/DataPathTest.py
+++ b/acts/tests/google/wifi/aware/functional/DataPathTest.py
@@ -78,13 +78,18 @@
network_req = {"TransportType": 5, "NetworkSpecifier": ns}
return dut.droid.connectivityRequestWifiAwareNetwork(network_req)
- def set_up_discovery(self, ptype, stype, get_peer_id):
+ def set_up_discovery(self, ptype, stype, get_peer_id, pub_on_both=False,
+ pub_on_both_same=True):
"""Set up discovery sessions and wait for service discovery.
Args:
ptype: Publish discovery type
stype: Subscribe discovery type
get_peer_id: Send a message across to get the peer's id
+ pub_on_both: If True then set up a publisher on both devices. The second
+ publisher isn't used (existing to test use-case).
+ pub_on_both_same: If True then the second publish uses an identical
+ service name, otherwise a different service name.
"""
p_dut = self.android_devices[0]
p_dut.pretty_name = "Publisher"
@@ -102,6 +107,15 @@
p_disc_id = p_dut.droid.wifiAwarePublish(p_id, self.create_config(ptype))
autils.wait_for_event(p_dut, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
+ # Optionally set up a publish session on the Subscriber device
+ if pub_on_both:
+ p2_config = self.create_config(ptype)
+ if not pub_on_both_same:
+ p2_config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = (
+ p2_config[aconsts.DISCOVERY_KEY_SERVICE_NAME] + "-XYZXYZ")
+ s_dut.droid.wifiAwarePublish(s_id, p2_config)
+ autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
+
# Subscriber: start subscribe and wait for confirmation
s_disc_id = s_dut.droid.wifiAwareSubscribe(s_id, self.create_config(stype))
autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
@@ -132,7 +146,9 @@
stype,
encr_type,
use_peer_id,
- passphrase_to_use=None):
+ passphrase_to_use=None,
+ pub_on_both=False,
+ pub_on_both_same=True):
"""Runs the in-band data-path tests.
Args:
@@ -143,14 +159,21 @@
accept any request
passphrase_to_use: The passphrase to use if encr_type=ENCR_TYPE_PASSPHRASE
If None then use self.PASSPHRASE
+ pub_on_both: If True then set up a publisher on both devices. The second
+ publisher isn't used (existing to test use-case).
+ pub_on_both_same: If True then the second publish uses an identical
+ service name, otherwise a different service name.
"""
(p_dut, s_dut, p_id, s_id, p_disc_id, s_disc_id, peer_id_on_sub,
- peer_id_on_pub) = self.set_up_discovery(ptype, stype, use_peer_id)
+ peer_id_on_pub) = self.set_up_discovery(ptype, stype, use_peer_id,
+ pub_on_both=pub_on_both,
+ pub_on_both_same=pub_on_both_same)
passphrase = None
pmk = None
if encr_type == self.ENCR_TYPE_PASSPHRASE:
- passphrase = self.PASSPHRASE if passphrase_to_use == None else passphrase_to_use
+ passphrase = (
+ self.PASSPHRASE if passphrase_to_use == None else passphrase_to_use)
elif encr_type == self.ENCR_TYPE_PMK:
pmk = self.PMK
@@ -209,13 +232,17 @@
p_dut.droid.connectivityUnregisterNetworkCallback(p_req_key)
s_dut.droid.connectivityUnregisterNetworkCallback(s_req_key)
- def run_oob_data_path_test(self, encr_type, use_peer_id):
+ def run_oob_data_path_test(self, encr_type, use_peer_id,
+ setup_discovery_sessions=False):
"""Runs the out-of-band data-path tests.
Args:
encr_type: Encryption type, one of ENCR_TYPE_*
use_peer_id: On Responder: True to use peer ID, False to accept any
request
+ setup_discovery_sessions: If True also set up a (spurious) discovery
+ session (pub on both sides, sub on Responder side). Validates a corner
+ case.
"""
init_dut = self.android_devices[0]
init_dut.pretty_name = "Initiator"
@@ -240,6 +267,18 @@
# to execute the data-path request)
time.sleep(self.WAIT_FOR_CLUSTER)
+ if setup_discovery_sessions:
+ init_dut.droid.wifiAwarePublish(init_id, self.create_config(
+ aconsts.PUBLISH_TYPE_UNSOLICITED))
+ autils.wait_for_event(init_dut, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
+ resp_dut.droid.wifiAwarePublish(resp_id, self.create_config(
+ aconsts.PUBLISH_TYPE_UNSOLICITED))
+ autils.wait_for_event(resp_dut, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
+ resp_dut.droid.wifiAwareSubscribe(resp_id, self.create_config(
+ aconsts.SUBSCRIBE_TYPE_PASSIVE))
+ autils.wait_for_event(resp_dut, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
+ autils.wait_for_event(resp_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
+
passphrase = None
pmk = None
if encr_type == self.ENCR_TYPE_PASSPHRASE:
@@ -588,6 +627,89 @@
use_peer_id=False)
#######################################
+ # Positive In-Band (IB) with a publish session running on the subscriber
+ # tests key:
+ #
+ # names is: test_ib_extra_pub_<same|diff>_<pub_type>_<sub_type>
+ # _<encr_type>_<peer_spec>
+ # where:
+ #
+ # same|diff: Whether the extra publish session (on the subscriber) is the same
+ # or different from the primary session.
+ # pub_type: Type of publish discovery session: unsolicited or solicited.
+ # sub_type: Type of subscribe discovery session: passive or active.
+ # encr_type: Encription type: open, passphrase
+ # peer_spec: Peer specification method: any or specific
+ #
+ # Note: In-Band means using Wi-Fi Aware for discovery and referring to the
+ # peer using the Aware-provided peer handle (as opposed to a MAC address).
+ #######################################
+
+ def test_ib_extra_pub_same_unsolicited_passive_open_specific(self):
+ """Data-path: in-band, unsolicited/passive, open encryption, specific peer.
+
+ Configuration contains a publisher (for the same service) running on *both*
+ devices.
+
+ Verifies end-to-end discovery + data-path creation.
+ """
+ self.run_ib_data_path_test(
+ ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
+ stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
+ encr_type=self.ENCR_TYPE_OPEN,
+ use_peer_id=True,
+ pub_on_both=True,
+ pub_on_both_same=True)
+
+ def test_ib_extra_pub_same_unsolicited_passive_open_any(self):
+ """Data-path: in-band, unsolicited/passive, open encryption, any peer.
+
+ Configuration contains a publisher (for the same service) running on *both*
+ devices.
+
+ Verifies end-to-end discovery + data-path creation.
+ """
+ self.run_ib_data_path_test(
+ ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
+ stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
+ encr_type=self.ENCR_TYPE_OPEN,
+ use_peer_id=False,
+ pub_on_both=True,
+ pub_on_both_same=True)
+
+ def test_ib_extra_pub_diff_unsolicited_passive_open_specific(self):
+ """Data-path: in-band, unsolicited/passive, open encryption, specific peer.
+
+ Configuration contains a publisher (for a different service) running on
+ *both* devices.
+
+ Verifies end-to-end discovery + data-path creation.
+ """
+ self.run_ib_data_path_test(
+ ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
+ stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
+ encr_type=self.ENCR_TYPE_OPEN,
+ use_peer_id=True,
+ pub_on_both=True,
+ pub_on_both_same=False)
+
+ def test_ib_extra_pub_diff_unsolicited_passive_open_any(self):
+ """Data-path: in-band, unsolicited/passive, open encryption, any peer.
+
+ Configuration contains a publisher (for a different service) running on
+ *both* devices.
+
+ Verifies end-to-end discovery + data-path creation.
+ """
+ self.run_ib_data_path_test(
+ ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
+ stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
+ encr_type=self.ENCR_TYPE_OPEN,
+ use_peer_id=False,
+ pub_on_both=True,
+ pub_on_both_same=False)
+
+ #######################################
# Positive Out-of-Band (OOB) tests key:
#
# names is: test_oob_<encr_type>_<peer_spec>
@@ -596,6 +718,9 @@
# encr_type: Encription type: open, passphrase
# peer_spec: Peer specification method: any or specific
#
+ # Optionally set up an extra discovery session to test coexistence. If so
+ # add "ib_coex" to test name.
+ #
# Note: Out-of-Band means using a non-Wi-Fi Aware mechanism for discovery and
# exchange of MAC addresses and then Wi-Fi Aware for data-path.
#######################################
@@ -660,6 +785,30 @@
encr_type=self.ENCR_TYPE_PMK,
use_peer_id=False)
+ def test_oob_ib_coex_open_specific(self):
+ """Data-path: out-of-band, open encryption, specific peer - in-band coex:
+ set up a concurrent discovery session to verify no impact. The session
+ consists of Publisher on both ends, and a Subscriber on the Responder.
+
+ Verifies end-to-end discovery + data-path creation.
+ """
+ self.run_oob_data_path_test(
+ encr_type=self.ENCR_TYPE_OPEN,
+ use_peer_id=True,
+ setup_discovery_sessions=True)
+
+ def test_oob_ib_coex_open_any(self):
+ """Data-path: out-of-band, open encryption, any peer - in-band coex:
+ set up a concurrent discovery session to verify no impact. The session
+ consists of Publisher on both ends, and a Subscriber on the Responder.
+
+ Verifies end-to-end discovery + data-path creation.
+ """
+ self.run_oob_data_path_test(
+ encr_type=self.ENCR_TYPE_OPEN,
+ use_peer_id=False,
+ setup_discovery_sessions=True)
+
##############################################################
@test_tracker_info(uuid="1c2c9805-dc1e-43b5-a1b8-315e8c9a4337")
@@ -808,7 +957,7 @@
resp_ids = []
# Initiator+Responder: attach and wait for confirmation & identity
- # create 10 sessions to be used in the different (but identical) NDPs
+ # create N+M sessions to be used in the different (but identical) NDPs
for i in range(N + M):
id, init_mac = autils.attach_with_identity(init_dut)
init_ids.append(id)
@@ -851,7 +1000,7 @@
self.wait_for_request_responses(resp_dut, resp_req_keys, resp_aware_ifs)
self.wait_for_request_responses(init_dut, init_req_keys, init_aware_ifs)
- # issue N more requests for the same NDPs - tests post-setup multiple NDP
+ # issue M more requests for the same NDPs - tests post-setup multiple NDP
for i in range(M):
# Responder: request network
resp_req_keys.append(autils.request_network(
@@ -909,9 +1058,118 @@
for init_req_key in init_req_keys:
init_dut.droid.connectivityUnregisterNetworkCallback(init_req_key)
+ def test_identical_network_from_both_sides(self):
+ """Validate that requesting two identical NDPs (Open) each being initiated
+ from a different side, results in the same/single NDP.
+
+ Verify that the interface and IPv6 address is the same for all networks.
+ """
+ dut1 = self.android_devices[0]
+ dut2 = self.android_devices[1]
+
+ id1, mac1 = autils.attach_with_identity(dut1)
+ id2, mac2 = autils.attach_with_identity(dut2)
+
+ # wait for for devices to synchronize with each other - there are no other
+ # mechanisms to make sure this happens for OOB discovery (except retrying
+ # to execute the data-path request)
+ time.sleep(autils.WAIT_FOR_CLUSTER)
+
+ # first NDP: DUT1 (Init) -> DUT2 (Resp)
+ req_a_resp = autils.request_network(dut2,
+ dut2.droid.wifiAwareCreateNetworkSpecifierOob(
+ id2, aconsts.DATA_PATH_RESPONDER,
+ mac1))
+
+ req_a_init = autils.request_network(dut1,
+ dut1.droid.wifiAwareCreateNetworkSpecifierOob(
+ id1, aconsts.DATA_PATH_INITIATOR,
+ mac2))
+
+ req_a_resp_event = autils.wait_for_event_with_keys(
+ dut2, cconsts.EVENT_NETWORK_CALLBACK,
+ autils.EVENT_NDP_TIMEOUT,
+ (cconsts.NETWORK_CB_KEY_EVENT,
+ cconsts.NETWORK_CB_LINK_PROPERTIES_CHANGED),
+ (cconsts.NETWORK_CB_KEY_ID, req_a_resp))
+ req_a_init_event = autils.wait_for_event_with_keys(
+ dut1, cconsts.EVENT_NETWORK_CALLBACK,
+ autils.EVENT_NDP_TIMEOUT,
+ (cconsts.NETWORK_CB_KEY_EVENT,
+ cconsts.NETWORK_CB_LINK_PROPERTIES_CHANGED),
+ (cconsts.NETWORK_CB_KEY_ID, req_a_init))
+
+ req_a_if_resp = req_a_resp_event["data"][
+ cconsts.NETWORK_CB_KEY_INTERFACE_NAME]
+ req_a_if_init = req_a_init_event["data"][
+ cconsts.NETWORK_CB_KEY_INTERFACE_NAME]
+ self.log.info("Interface names for A: I=%s, R=%s", req_a_if_init,
+ req_a_if_resp)
+
+ req_a_ipv6_resp = \
+ dut2.droid.connectivityGetLinkLocalIpv6Address(req_a_if_resp).split("%")[0]
+ req_a_ipv6_init = \
+ dut1.droid.connectivityGetLinkLocalIpv6Address(req_a_if_init).split("%")[0]
+ self.log.info("Interface addresses (IPv6) for A: I=%s, R=%s",
+ req_a_ipv6_init, req_a_ipv6_resp)
+
+ # second NDP: DUT2 (Init) -> DUT1 (Resp)
+ req_b_resp = autils.request_network(dut1,
+ dut1.droid.wifiAwareCreateNetworkSpecifierOob(
+ id1, aconsts.DATA_PATH_RESPONDER,
+ mac2))
+
+ req_b_init = autils.request_network(dut2,
+ dut2.droid.wifiAwareCreateNetworkSpecifierOob(
+ id2, aconsts.DATA_PATH_INITIATOR,
+ mac1))
+
+ req_b_resp_event = autils.wait_for_event_with_keys(
+ dut1, cconsts.EVENT_NETWORK_CALLBACK,
+ autils.EVENT_NDP_TIMEOUT,
+ (cconsts.NETWORK_CB_KEY_EVENT,
+ cconsts.NETWORK_CB_LINK_PROPERTIES_CHANGED),
+ (cconsts.NETWORK_CB_KEY_ID, req_b_resp))
+ req_b_init_event = autils.wait_for_event_with_keys(
+ dut2, cconsts.EVENT_NETWORK_CALLBACK,
+ autils.EVENT_NDP_TIMEOUT,
+ (cconsts.NETWORK_CB_KEY_EVENT,
+ cconsts.NETWORK_CB_LINK_PROPERTIES_CHANGED),
+ (cconsts.NETWORK_CB_KEY_ID, req_b_init))
+
+ req_b_if_resp = req_b_resp_event["data"][
+ cconsts.NETWORK_CB_KEY_INTERFACE_NAME]
+ req_b_if_init = req_b_init_event["data"][
+ cconsts.NETWORK_CB_KEY_INTERFACE_NAME]
+ self.log.info("Interface names for B: I=%s, R=%s", req_b_if_init,
+ req_b_if_resp)
+
+ req_b_ipv6_resp = \
+ dut1.droid.connectivityGetLinkLocalIpv6Address(req_b_if_resp).split("%")[0]
+ req_b_ipv6_init = \
+ dut2.droid.connectivityGetLinkLocalIpv6Address(req_b_if_init).split("%")[0]
+ self.log.info("Interface addresses (IPv6) for B: I=%s, R=%s",
+ req_b_ipv6_init, req_b_ipv6_resp)
+
+ # validate equality of NDPs (using interface names & ipv6)
+ asserts.assert_equal(req_a_if_init, req_b_if_resp,
+ "DUT1 NDPs are on different interfaces")
+ asserts.assert_equal(req_a_if_resp, req_b_if_init,
+ "DUT2 NDPs are on different interfaces")
+ asserts.assert_equal(req_a_ipv6_init, req_b_ipv6_resp,
+ "DUT1 NDPs are using different IPv6 addresses")
+ asserts.assert_equal(req_a_ipv6_resp, req_b_ipv6_init,
+ "DUT2 NDPs are using different IPv6 addresses")
+
+ # release requests
+ dut1.droid.connectivityUnregisterNetworkCallback(req_a_init)
+ dut1.droid.connectivityUnregisterNetworkCallback(req_b_resp)
+ dut2.droid.connectivityUnregisterNetworkCallback(req_a_resp)
+ dut2.droid.connectivityUnregisterNetworkCallback(req_b_init)
+
########################################################################
- def run_multiple_ndi(self, sec_configs):
+ def run_multiple_ndi(self, sec_configs, flip_init_resp=False):
"""Validate that the device can create and use multiple NDIs.
The security configuration can be:
@@ -921,95 +1179,126 @@
Args:
sec_configs: list of security configurations
+ flip_init_resp: if True the roles of Initiator and Responder are flipped
+ between the 2 devices, otherwise same devices are always
+ configured in the same role.
"""
- init_dut = self.android_devices[0]
- init_dut.pretty_name = "Initiator"
- resp_dut = self.android_devices[1]
- resp_dut.pretty_name = "Responder"
+ dut1 = self.android_devices[0]
+ dut2 = self.android_devices[1]
- asserts.skip_if(init_dut.aware_capabilities[aconsts.CAP_MAX_NDI_INTERFACES]
+ asserts.skip_if(dut1.aware_capabilities[aconsts.CAP_MAX_NDI_INTERFACES]
< len(sec_configs) or
- resp_dut.aware_capabilities[aconsts.CAP_MAX_NDI_INTERFACES]
+ dut2.aware_capabilities[aconsts.CAP_MAX_NDI_INTERFACES]
< len(sec_configs),
- "Initiator or Responder do not support multiple NDIs")
+ "DUTs do not support enough NDIs")
- init_id, init_mac = autils.attach_with_identity(init_dut)
- resp_id, resp_mac = autils.attach_with_identity(resp_dut)
+ id1, mac1 = autils.attach_with_identity(dut1)
+ id2, mac2 = autils.attach_with_identity(dut2)
# wait for for devices to synchronize with each other - there are no other
# mechanisms to make sure this happens for OOB discovery (except retrying
# to execute the data-path request)
time.sleep(autils.WAIT_FOR_CLUSTER)
- resp_req_keys = []
- init_req_keys = []
- resp_aware_ifs = []
- init_aware_ifs = []
+ dut2_req_keys = []
+ dut1_req_keys = []
+ dut2_aware_ifs = []
+ dut1_aware_ifs = []
+ dut2_type = aconsts.DATA_PATH_RESPONDER
+ dut1_type = aconsts.DATA_PATH_INITIATOR
+ dut2_is_responder = True
for sec in sec_configs:
- # Responder: request network
- resp_req_key = autils.request_network(resp_dut,
- autils.get_network_specifier(
- resp_dut, resp_id,
- aconsts.DATA_PATH_RESPONDER,
- init_mac, sec))
- resp_req_keys.append(resp_req_key)
+ if dut2_is_responder:
+ # DUT2 (Responder): request network
+ dut2_req_key = autils.request_network(dut2,
+ autils.get_network_specifier(
+ dut2, id2,
+ dut2_type,
+ mac1, sec))
+ dut2_req_keys.append(dut2_req_key)
- # Initiator: request network
- init_req_key = autils.request_network(init_dut,
- autils.get_network_specifier(
- init_dut, init_id,
- aconsts.DATA_PATH_INITIATOR,
- resp_mac, sec))
- init_req_keys.append(init_req_key)
+ # DUT1 (Initiator): request network
+ dut1_req_key = autils.request_network(dut1,
+ autils.get_network_specifier(
+ dut1, id1,
+ dut1_type,
+ mac2, sec))
+ dut1_req_keys.append(dut1_req_key)
+ else:
+ # DUT1 (Responder): request network
+ dut1_req_key = autils.request_network(dut1,
+ autils.get_network_specifier(
+ dut1, id1,
+ dut1_type,
+ mac2, sec))
+ dut1_req_keys.append(dut1_req_key)
+
+ # DUT2 (Initiator): request network
+ dut2_req_key = autils.request_network(dut2,
+ autils.get_network_specifier(
+ dut2, id2,
+ dut2_type,
+ mac1, sec))
+ dut2_req_keys.append(dut2_req_key)
# Wait for network
- init_net_event = autils.wait_for_event_with_keys(
- init_dut, cconsts.EVENT_NETWORK_CALLBACK, autils.EVENT_TIMEOUT,
+ dut1_net_event = autils.wait_for_event_with_keys(
+ dut1, cconsts.EVENT_NETWORK_CALLBACK, autils.EVENT_TIMEOUT,
(cconsts.NETWORK_CB_KEY_EVENT,
cconsts.NETWORK_CB_LINK_PROPERTIES_CHANGED),
- (cconsts.NETWORK_CB_KEY_ID, init_req_key))
- resp_net_event = autils.wait_for_event_with_keys(
- resp_dut, cconsts.EVENT_NETWORK_CALLBACK, autils.EVENT_TIMEOUT,
+ (cconsts.NETWORK_CB_KEY_ID, dut1_req_key))
+ dut2_net_event = autils.wait_for_event_with_keys(
+ dut2, cconsts.EVENT_NETWORK_CALLBACK, autils.EVENT_TIMEOUT,
(cconsts.NETWORK_CB_KEY_EVENT,
cconsts.NETWORK_CB_LINK_PROPERTIES_CHANGED),
- (cconsts.NETWORK_CB_KEY_ID, resp_req_key))
+ (cconsts.NETWORK_CB_KEY_ID, dut2_req_key))
- resp_aware_ifs.append(
- resp_net_event["data"][cconsts.NETWORK_CB_KEY_INTERFACE_NAME])
- init_aware_ifs.append(
- init_net_event["data"][cconsts.NETWORK_CB_KEY_INTERFACE_NAME])
+ dut2_aware_ifs.append(
+ dut2_net_event["data"][cconsts.NETWORK_CB_KEY_INTERFACE_NAME])
+ dut1_aware_ifs.append(
+ dut1_net_event["data"][cconsts.NETWORK_CB_KEY_INTERFACE_NAME])
+
+ if flip_init_resp:
+ if dut2_is_responder:
+ dut2_type = aconsts.DATA_PATH_INITIATOR
+ dut1_type = aconsts.DATA_PATH_RESPONDER
+ else:
+ dut2_type = aconsts.DATA_PATH_RESPONDER
+ dut1_type = aconsts.DATA_PATH_INITIATOR
+ dut2_is_responder = not dut2_is_responder
# check that we are using 2 NDIs
- init_aware_ifs = list(set(init_aware_ifs))
- resp_aware_ifs = list(set(resp_aware_ifs))
+ dut1_aware_ifs = list(set(dut1_aware_ifs))
+ dut2_aware_ifs = list(set(dut2_aware_ifs))
- self.log.info("Interface names: I=%s, R=%s", init_aware_ifs, resp_aware_ifs)
- self.log.info("Initiator requests: %s", init_req_keys)
- self.log.info("Responder requests: %s", resp_req_keys)
+ self.log.info("Interface names: DUT1=%s, DUT2=%s", dut1_aware_ifs,
+ dut2_aware_ifs)
+ self.log.info("DUT1 requests: %s", dut1_req_keys)
+ self.log.info("DUT2 requests: %s", dut2_req_keys)
asserts.assert_equal(
- len(init_aware_ifs), len(sec_configs), "Multiple initiator interfaces")
+ len(dut1_aware_ifs), len(sec_configs), "Multiple DUT1 interfaces")
asserts.assert_equal(
- len(resp_aware_ifs), len(sec_configs), "Multiple responder interfaces")
+ len(dut2_aware_ifs), len(sec_configs), "Multiple DUT2 interfaces")
for i in range(len(sec_configs)):
if_name = "%s%d" % (aconsts.AWARE_NDI_PREFIX, i)
- init_ipv6 = autils.get_ipv6_addr(init_dut, if_name)
- resp_ipv6 = autils.get_ipv6_addr(resp_dut, if_name)
+ dut1_ipv6 = autils.get_ipv6_addr(dut1, if_name)
+ dut2_ipv6 = autils.get_ipv6_addr(dut2, if_name)
asserts.assert_equal(
- init_ipv6 is None, if_name not in init_aware_ifs,
- "Initiator interface %s in unexpected state" % if_name)
+ dut1_ipv6 is None, if_name not in dut1_aware_ifs,
+ "DUT1 interface %s in unexpected state" % if_name)
asserts.assert_equal(
- resp_ipv6 is None, if_name not in resp_aware_ifs,
- "Responder interface %s in unexpected state" % if_name)
+ dut2_ipv6 is None, if_name not in dut2_aware_ifs,
+ "DUT2 interface %s in unexpected state" % if_name)
# release requests
- for resp_req_key in resp_req_keys:
- resp_dut.droid.connectivityUnregisterNetworkCallback(resp_req_key)
- for init_req_key in init_req_keys:
- init_dut.droid.connectivityUnregisterNetworkCallback(init_req_key)
+ for dut2_req_key in dut2_req_keys:
+ dut2.droid.connectivityUnregisterNetworkCallback(dut2_req_key)
+ for dut1_req_key in dut1_req_keys:
+ dut1.droid.connectivityUnregisterNetworkCallback(dut1_req_key)
@test_tracker_info(uuid="2d728163-11cc-46ba-a973-c8e1e71397fc")
def test_multiple_ndi_open_passphrase(self):
@@ -1045,3 +1334,49 @@
configuration (using different PMKS). The result should use two different
NDIs"""
self.run_multiple_ndi([self.PMK, self.PMK2])
+
+ def test_multiple_ndi_open_passphrase_flip(self):
+ """Verify that can between 2 DUTs can create 2 NDPs with different security
+ configuration (one open, one using passphrase). The result should use two
+ different NDIs.
+
+ Flip Initiator and Responder roles.
+ """
+ self.run_multiple_ndi([None, self.PASSPHRASE], flip_init_resp=True)
+
+ def test_multiple_ndi_open_pmk_flip(self):
+ """Verify that can between 2 DUTs can create 2 NDPs with different security
+ configuration (one open, one using pmk). The result should use two
+ different NDIs
+
+ Flip Initiator and Responder roles.
+ """
+ self.run_multiple_ndi([None, self.PMK], flip_init_resp=True)
+
+ def test_multiple_ndi_passphrase_pmk_flip(self):
+ """Verify that can between 2 DUTs can create 2 NDPs with different security
+ configuration (one using passphrase, one using pmk). The result should use
+ two different NDIs
+
+ Flip Initiator and Responder roles.
+ """
+ self.run_multiple_ndi([self.PASSPHRASE, self.PMK], flip_init_resp=True)
+
+ def test_multiple_ndi_passphrases_flip(self):
+ """Verify that can between 2 DUTs can create 2 NDPs with different security
+ configuration (using different passphrases). The result should use two
+ different NDIs
+
+ Flip Initiator and Responder roles.
+ """
+ self.run_multiple_ndi([self.PASSPHRASE, self.PASSPHRASE2],
+ flip_init_resp=True)
+
+ def test_multiple_ndi_pmks_flip(self):
+ """Verify that can between 2 DUTs can create 2 NDPs with different security
+ configuration (using different PMKS). The result should use two different
+ NDIs
+
+ Flip Initiator and Responder roles.
+ """
+ self.run_multiple_ndi([self.PMK, self.PMK2], flip_init_resp=True)
diff --git a/acts/tests/google/wifi/aware/functional/DiscoveryTest.py b/acts/tests/google/wifi/aware/functional/DiscoveryTest.py
index 8732dbb..1784d12 100644
--- a/acts/tests/google/wifi/aware/functional/DiscoveryTest.py
+++ b/acts/tests/google/wifi/aware/functional/DiscoveryTest.py
@@ -829,3 +829,182 @@
s_type=aconsts.SUBSCRIBE_TYPE_ACTIVE,
p_mf_1="hello there string",
s_mf_1="goodbye there string")
+
+ #######################################
+ # Multiple concurrent services key
+ #######################################
+
+ def run_multiple_concurrent_services(self, type_x, type_y):
+ """Validate multiple identical discovery services running on both devices:
+ - DUT1 & DUT2 running Publish for X
+ - DUT1 & DUT2 running Publish for Y
+ - DUT1 Subscribes for X
+ - DUT2 Subscribes for Y
+ Message exchanges.
+
+ Note: test requires that devices support 2 publish sessions concurrently.
+ The test will be skipped if the devices are not capable.
+
+ Args:
+ type_x, type_y: A list of [ptype, stype] of the publish and subscribe
+ types for services X and Y respectively.
+ """
+ dut1 = self.android_devices[0]
+ dut2 = self.android_devices[1]
+
+ X_SERVICE_NAME = "ServiceXXX"
+ Y_SERVICE_NAME = "ServiceYYY"
+
+ asserts.skip_if(dut1.aware_capabilities[aconsts.CAP_MAX_PUBLISHES] < 2 or
+ dut2.aware_capabilities[aconsts.CAP_MAX_PUBLISHES] < 2,
+ "Devices do not support 2 publish sessions")
+
+ # attach and wait for confirmation
+ id1 = dut1.droid.wifiAwareAttach(False)
+ autils.wait_for_event(dut1, aconsts.EVENT_CB_ON_ATTACHED)
+ time.sleep(self.device_startup_offset)
+ id2 = dut2.droid.wifiAwareAttach(False)
+ autils.wait_for_event(dut2, aconsts.EVENT_CB_ON_ATTACHED)
+
+ # DUT1 & DUT2: start publishing both X & Y services and wait for
+ # confirmations
+ dut1_x_pid = dut1.droid.wifiAwarePublish(id1,
+ autils.create_discovery_config(
+ X_SERVICE_NAME, type_x[0]))
+ event = autils.wait_for_event(dut1, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
+ asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
+ dut1_x_pid,
+ "Unexpected DUT1 X publish session discovery ID")
+
+ dut1_y_pid = dut1.droid.wifiAwarePublish(id1,
+ autils.create_discovery_config(
+ Y_SERVICE_NAME, type_y[0]))
+ event = autils.wait_for_event(dut1, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
+ asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
+ dut1_y_pid,
+ "Unexpected DUT1 Y publish session discovery ID")
+
+ dut2_x_pid = dut2.droid.wifiAwarePublish(id2,
+ autils.create_discovery_config(
+ X_SERVICE_NAME, type_x[0]))
+ event = autils.wait_for_event(dut2, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
+ asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
+ dut2_x_pid,
+ "Unexpected DUT2 X publish session discovery ID")
+
+ dut2_y_pid = dut2.droid.wifiAwarePublish(id2,
+ autils.create_discovery_config(
+ Y_SERVICE_NAME, type_y[0]))
+ event = autils.wait_for_event(dut2, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
+ asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
+ dut2_y_pid,
+ "Unexpected DUT2 Y publish session discovery ID")
+
+ # DUT1: start subscribing for X
+ dut1_x_sid = dut1.droid.wifiAwareSubscribe(id1,
+ autils.create_discovery_config(
+ X_SERVICE_NAME, type_x[1]))
+ autils.wait_for_event(dut1, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
+
+ # DUT2: start subscribing for Y
+ dut2_y_sid = dut2.droid.wifiAwareSubscribe(id2,
+ autils.create_discovery_config(
+ Y_SERVICE_NAME, type_y[1]))
+ autils.wait_for_event(dut2, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
+
+ # DUT1 & DUT2: wait for service discovery
+ event = autils.wait_for_event(dut1,
+ aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
+ asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
+ dut1_x_sid,
+ "Unexpected DUT1 X subscribe session discovery ID")
+ dut1_peer_id_for_dut2_x = event["data"][aconsts.SESSION_CB_KEY_PEER_ID]
+
+ event = autils.wait_for_event(dut2,
+ aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
+ asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
+ dut2_y_sid,
+ "Unexpected DUT2 Y subscribe session discovery ID")
+ dut2_peer_id_for_dut1_y = event["data"][aconsts.SESSION_CB_KEY_PEER_ID]
+
+ # DUT1.X send message to DUT2
+ x_msg = "Hello X on DUT2!"
+ dut1.droid.wifiAwareSendMessage(dut1_x_sid, dut1_peer_id_for_dut2_x,
+ self.get_next_msg_id(), x_msg,
+ self.msg_retx_count)
+ autils.wait_for_event(dut1, aconsts.SESSION_CB_ON_MESSAGE_SENT)
+ event = autils.wait_for_event(dut2, aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
+ asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
+ dut2_x_pid,
+ "Unexpected publish session ID on DUT2 for meesage "
+ "received on service X")
+ asserts.assert_equal(
+ event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING], x_msg,
+ "Message on service X from DUT1 to DUT2 not received correctly")
+
+ # DUT2.Y send message to DUT1
+ y_msg = "Hello Y on DUT1!"
+ dut2.droid.wifiAwareSendMessage(dut2_y_sid, dut2_peer_id_for_dut1_y,
+ self.get_next_msg_id(), y_msg,
+ self.msg_retx_count)
+ autils.wait_for_event(dut2, aconsts.SESSION_CB_ON_MESSAGE_SENT)
+ event = autils.wait_for_event(dut1, aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
+ asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
+ dut1_y_pid,
+ "Unexpected publish session ID on DUT1 for meesage "
+ "received on service Y")
+ asserts.assert_equal(
+ event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING], y_msg,
+ "Message on service Y from DUT2 to DUT1 not received correctly")
+
+ def test_multiple_concurrent_services_both_unsolicited_passive(self):
+ """Validate multiple concurrent discovery sessions running on both devices.
+ - DUT1 & DUT2 running Publish for X
+ - DUT1 & DUT2 running Publish for Y
+ - DUT1 Subscribes for X
+ - DUT2 Subscribes for Y
+ Message exchanges.
+
+ Both sessions are Unsolicited/Passive.
+
+ Note: test requires that devices support 2 publish sessions concurrently.
+ The test will be skipped if the devices are not capable.
+ """
+ self.run_multiple_concurrent_services(
+ type_x=[aconsts.PUBLISH_TYPE_UNSOLICITED, aconsts.SUBSCRIBE_TYPE_PASSIVE],
+ type_y=[aconsts.PUBLISH_TYPE_UNSOLICITED, aconsts.SUBSCRIBE_TYPE_PASSIVE])
+
+ def test_multiple_concurrent_services_both_solicited_active(self):
+ """Validate multiple concurrent discovery sessions running on both devices.
+ - DUT1 & DUT2 running Publish for X
+ - DUT1 & DUT2 running Publish for Y
+ - DUT1 Subscribes for X
+ - DUT2 Subscribes for Y
+ Message exchanges.
+
+ Both sessions are Solicited/Active.
+
+ Note: test requires that devices support 2 publish sessions concurrently.
+ The test will be skipped if the devices are not capable.
+ """
+ self.run_multiple_concurrent_services(
+ type_x=[aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE],
+ type_y=[aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE])
+
+ def test_multiple_concurrent_services_mix_unsolicited_solicited(self):
+ """Validate multiple concurrent discovery sessions running on both devices.
+ - DUT1 & DUT2 running Publish for X
+ - DUT1 & DUT2 running Publish for Y
+ - DUT1 Subscribes for X
+ - DUT2 Subscribes for Y
+ Message exchanges.
+
+ Session A is Unsolicited/Passive.
+ Session B is Solicited/Active.
+
+ Note: test requires that devices support 2 publish sessions concurrently.
+ The test will be skipped if the devices are not capable.
+ """
+ self.run_multiple_concurrent_services(
+ type_x=[aconsts.PUBLISH_TYPE_UNSOLICITED, aconsts.SUBSCRIBE_TYPE_PASSIVE],
+ type_y=[aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE])
diff --git a/acts/tests/sample/ConfigurableAccessPointTest.py b/acts/tests/sample/ConfigurableAccessPointTest.py
index ccef716..de07b1e 100644
--- a/acts/tests/sample/ConfigurableAccessPointTest.py
+++ b/acts/tests/sample/ConfigurableAccessPointTest.py
@@ -14,7 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-
import logging
from acts import base_test
@@ -35,8 +34,7 @@
def test_setup_access_point(self):
config = hostapd_config.HostapdConfig(
- channel=6,
- ssid='ImagineYourNetworkHere')
+ channel=6, ssid='ImagineYourNetworkHere')
self.ap.start_ap(config)
logging.info('Your test logic should go here!')
diff --git a/acts/tests/sample/RelayDeviceSampleTest.py b/acts/tests/sample/RelayDeviceSampleTest.py
index 040ef62..a9304bc 100644
--- a/acts/tests/sample/RelayDeviceSampleTest.py
+++ b/acts/tests/sample/RelayDeviceSampleTest.py
@@ -14,7 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from acts import base_test
-from acts import test_runner
from acts.controllers.relay_lib.relay import SynchronizeRelays
@@ -98,7 +97,3 @@
# For more fine control over the wait time of relays, you can set
# Relay.transition_wait_time. This is not recommended unless you are
# using solid state relays, or async calls.
-
-
-if __name__ == "__main__":
- test_runner.main()
diff --git a/tools/commit_message_check.py b/tools/commit_message_check.py
deleted file mode 100755
index 9304ca5..0000000
--- a/tools/commit_message_check.py
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env python3.4
-#
-# Copyright 2017 - 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.
-from __future__ import print_function
-
-import logging
-import os
-import re
-import sys
-
-from acts.libs.proc import job
-
-GLOBAL_KEYWORDS_FILEPATH = 'vendor/google_testing/comms/framework/etc/' \
- 'commit_keywords'
-LOCAL_KEYWORDS_FILEPATH = '~/.repo_acts_commit_keywords'
-
-FIND_COMMIT_KEYWORDS = 'git log @{u}..| grep -i %s'
-GET_EMAIL_ADDRESS = 'git log --format=%ce -1'
-
-
-def main(argv):
- file_path = os.path.join(
- os.path.dirname(__file__), "../../../../%s" % GLOBAL_KEYWORDS_FILEPATH)
-
- if not os.path.isfile(file_path):
- file_path = os.path.expanduser(LOCAL_KEYWORDS_FILEPATH)
- if not os.path.exists(file_path) or not os.path.isfile(file_path):
- result = job.run(GET_EMAIL_ADDRESS)
- if result.stdout.endswith('@google.com'):
- logging.error(
- 'You do not have the necessary file %s. Please run '
- 'tools/ignore_commit_keywords.sh, or link it with the '
- 'following command:\n ln -sf <internal_master_root>/%s %s'
- % (LOCAL_KEYWORDS_FILEPATH, GLOBAL_KEYWORDS_FILEPATH,
- LOCAL_KEYWORDS_FILEPATH))
- exit(1)
- return
-
- with open(file_path) as file:
- # Places every line within quotes with -e before them.
- # i.e. '-e "line1" -e "line2" -e "line3"'
- grep_args = re.sub('^(.+?)$\n?', ' -e "\\1"',
- file.read(), 0, re.MULTILINE)
-
- result = job.run(FIND_COMMIT_KEYWORDS % grep_args, ignore_status=True)
-
- if result.stdout:
- logging.error('Your commit message contains at least one keyword.')
- logging.error('Keyword(s) found in the following line(s):')
- logging.error(result.stdout)
- logging.error('Please fix/remove these before committing.')
- exit(1)
-
-
-if __name__ == '__main__':
- main(sys.argv[1:])
diff --git a/tools/keyword_check.py b/tools/keyword_check.py
new file mode 100755
index 0000000..e124d29
--- /dev/null
+++ b/tools/keyword_check.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2017 - 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 logging
+import os
+import re
+import shellescape
+
+from acts.libs.proc import job
+
+GLOBAL_KEYWORDS_FILEPATH = 'vendor/google_testing/comms/framework/etc/' \
+ 'commit_keywords'
+LOCAL_KEYWORDS_FILEPATH = '~/.repo_acts_commit_keywords'
+
+GIT_FILE_ADDITIONS = r'git diff --unified=0 %s^! | grep "^+" | ' \
+ r'grep -Ev "^(\+\+\+ b/)" | cut -c 2-'
+
+GIT_FILE_NAMES = r'git diff-tree --no-commit-id --name-only -r %s'
+
+GIT_DIFF_REGION_FOUND = 'git diff %s^! | grep -A10 -B10 %s'
+COMMIT_ID_ENV_KEY = 'PREUPLOAD_COMMIT'
+
+FIND_COMMIT_KEYWORDS = 'git diff %s^! | grep -i %s'
+GET_EMAIL_ADDRESS = 'git log --format=%ce -1'
+
+
+def find_in_commit_message(keyword_list):
+ """Looks for keywords in commit messages.
+
+ Args:
+ keyword_list: A list of keywords
+ """
+ grep_args = ''
+ for keyword in keyword_list:
+ grep_args += '-e %s' % keyword
+
+ result = job.run(
+ FIND_COMMIT_KEYWORDS % (os.environ[COMMIT_ID_ENV_KEY], grep_args),
+ ignore_status=True)
+
+ if result.stdout:
+ logging.error('Your commit message contains at least one keyword.')
+ logging.error('Keyword(s) found in the following line(s):')
+ logging.error(result.stdout)
+ logging.error('Please fix/remove these before committing.')
+ exit(1)
+
+
+def get_words(string):
+ """Splits a string into an array of alphabetical words."""
+ s1 = re.sub('(.)([A-Z][a-z]+)', r'\1 \2', string)
+ s1 = re.sub('([a-z0-9])([A-Z])', r'\1 \2', s1).lower()
+ s1 = re.sub('[^a-z ]', ' ', s1)
+ return s1.split()
+
+
+def find_in_file_names(keyword_list):
+ """Looks for keywords in file names.
+
+ Args:
+ keyword_list: a list of keywords
+ """
+ changed_files = job.run(GIT_FILE_NAMES % os.environ[COMMIT_ID_ENV_KEY])
+
+ keyword_set = set(keyword_list)
+
+ for file_name in changed_files.stdout.split('\n'):
+ words = set(get_words(file_name))
+ if len(keyword_set.intersection(words)) > 0:
+ logging.error('Your commit has a file name that contain at least '
+ 'one keyword: %s.' % file_name)
+ logging.error('Please update or remove this before committing.')
+ exit(1)
+
+
+def find_in_code_additions(keyword_list):
+ """Looks for keywords in code additions.
+
+ Args:
+ keyword_list: a list of keywords
+ """
+ all_additions = job.run(GIT_FILE_ADDITIONS % os.environ[COMMIT_ID_ENV_KEY])
+
+ keyword_set = set(keyword_list)
+
+ for line in all_additions.stdout.split('\n'):
+ words = set(get_words(line))
+ if len(keyword_set.intersection(words)) > 0:
+ result = job.run(GIT_DIFF_REGION_FOUND %
+ (os.environ[COMMIT_ID_ENV_KEY],
+ shellescape.quote(line)))
+ logging.error('Your commit has code changes that contain at least '
+ 'one keyword. Below is an excerpt from the commit '
+ 'diff:')
+ logging.error(result.stdout)
+ logging.error('Please update or remove these before committing.')
+ exit(1)
+
+
+def main():
+ if COMMIT_ID_ENV_KEY not in os.environ:
+ logging.error('Missing commit id in environment.')
+ exit(1)
+ keyword_file = os.path.join(
+ os.path.dirname(__file__), '../../../../%s' % GLOBAL_KEYWORDS_FILEPATH)
+
+ if not os.path.isfile(keyword_file):
+ keyword_file = os.path.expanduser(LOCAL_KEYWORDS_FILEPATH)
+ if not os.path.exists(keyword_file) or not os.path.isfile(keyword_file):
+ result = job.run(GET_EMAIL_ADDRESS)
+ if result.stdout.endswith('@google.com'):
+ logging.error(
+ 'You do not have the necessary file %s. Please run '
+ 'tools/ignore_commit_keywords.sh, or link it with the '
+ 'following command:\n ln -sf <internal_master_root>/%s %s'
+ % (LOCAL_KEYWORDS_FILEPATH, GLOBAL_KEYWORDS_FILEPATH,
+ LOCAL_KEYWORDS_FILEPATH))
+ exit(1)
+ return
+
+ with open(keyword_file) as file:
+ keyword_list = file.read().lower().split()
+
+ find_in_code_additions(keyword_list)
+ find_in_commit_message(keyword_list)
+ find_in_file_names(keyword_list)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/lab/README.md b/tools/lab/README.md
index 5c5eee4..0fe5502 100644
--- a/tools/lab/README.md
+++ b/tools/lab/README.md
@@ -29,9 +29,10 @@
* num_users:
num_users: number of users (int)
* process_time:
- pid_times: a list of (time, PID) tuples where time is a string
- representing time elapsed in D-HR:MM:SS format and PID is a string
- representing the pid (string, string)
+ adb_processes, fastboot_processes: a list of (PID, serialnumber)
+ tuples
+ num_adb_processes, num_fastboot_processes: the number of tuples
+ in the previous lists
* ram:
total: total physical RAM available in KB (int)
used: total RAM used by system in KB (int)
@@ -45,19 +46,28 @@
load_avg_1_min: system load average for past 1 min (float)
load_avg_5_min: system load average for past 5 min (float)
load_avg_15_min: system load average for past 15 min (float)
+* time:
+ date_time: system date and time (string)
+* time_sync:
+ is_synchronized: whether NTP synchronized (bool)
* uptime:
time_seconds: uptime in seconds (float)
* usb:
devices: a list of Device objects, each with name of device, number of bytes
transferred, and the usb bus number/device id.
* verify:
- device serial number as key: device status as value
+ unauthorized: list of phone sn's that are unauthorized
+ offline: list of phone sn's that are offline
+ recovery: list of phone sn's that are in recovery mode
+ question: list of phone sn's in ??? mode
+ device: list of phone sn's that are in device mode
+ total: total number of offline, recovery, question or unauthorized devices
* version:
fastboot_version: which version of fastboot (string)
adb_version: which version of adb (string)
python_version: which version of python (string)
kernel_version: which version of kernel (string)
* zombie:
- adb_zombies: list of adb zombie processes (PID, state, name)
- fastboot_zombies: list of fastboot zombie processes (PID, state, name)
- other_zombies: list of other zombie processes (PID, state, name)
+ adb_zombies, fastboot_zombies, other_zombies: lists of
+ (PID, serial number) tuples
+ num_adb_zombies, num_fastboot_zombies, num_other_zombies: int
diff --git a/tools/lab/config.json b/tools/lab/config.json
index 5d9bf76..5ef8ff0 100644
--- a/tools/lab/config.json
+++ b/tools/lab/config.json
@@ -22,16 +22,16 @@
}
},
"time_sync": {
- "is_synchronized": {
- "constant": true,
- "compare":"EQUALS"
- }
+ "is_synchronized": {
+ "constant": true,
+ "compare": "EQUALS"
+ }
},
"network": {
- "connected": {
- "constant": true,
- "compare": "EQUALS_DICT"
- }
+ "connected": {
+ "constant": true,
+ "compare": "EQUALS_DICT"
+ }
},
"process_time": {
"num_adb_processes": {
@@ -40,9 +40,15 @@
}
},
"verify": {
- "devices": {
- "constant": "device",
- "compare": "EQUALS_DICT"
+ "total_unhealthy": {
+ "constant": "0",
+ "compare": "EQUALS"
+ }
+ },
+ "kernel_version": {
+ "kernel_release": {
+ "constant": "3.19",
+ "compare": "STARTS_WITH"
}
},
"zombie": {
@@ -51,5 +57,4 @@
"compare": "EQUALS"
}
}
-
}
diff --git a/tools/lab/health/constant_health_analyzer.py b/tools/lab/health/constant_health_analyzer.py
index 97e92a9..d7f9794 100644
--- a/tools/lab/health/constant_health_analyzer.py
+++ b/tools/lab/health/constant_health_analyzer.py
@@ -75,3 +75,16 @@
True if result is equal to constant
"""
return metric_results[self.key] == self._constant
+
+
+class HealthyIfStartsWith(ConstantHealthAnalyzer):
+ def is_healthy(self, metric_results):
+ """Returns whether result starts with a constant
+
+ Args:
+ metric_results: a dictionary of metric results.
+
+ Returns:
+ True if result starts with a constant
+ """
+ return metric_results[self.key].startswith(str(self._constant))
diff --git a/tools/lab/health_checker.py b/tools/lab/health_checker.py
index 4f9a87b..a917fe7 100644
--- a/tools/lab/health_checker.py
+++ b/tools/lab/health_checker.py
@@ -14,9 +14,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import logging
+
from health.constant_health_analyzer import HealthyIfGreaterThanConstantNumber
from health.constant_health_analyzer import HealthyIfLessThanConstantNumber
from health.constant_health_analyzer import HealthyIfEquals
+from health.constant_health_analyzer import HealthyIfStartsWith
from health.custom_health_analyzer import HealthyIfNotIpAddress
from health.constant_health_analyzer_wrapper import HealthyIfValsEqual
@@ -27,7 +30,6 @@
_analyzers: a list of metric, analyzer tuples where metric is a string
representing a metric name ('DiskMetric') and analyzer is a
constant_health_analyzer object
- _comparer_constructor: a dict that maps strings to comparer objects
config:
a dict formatted as follows:
{
@@ -47,7 +49,8 @@
'LESS_THAN': lambda k, c: HealthyIfLessThanConstantNumber(k, c),
'EQUALS': lambda k, c: HealthyIfEquals(k, c),
'IP_ADDR': lambda k, c: HealthyIfNotIpAddress(k),
- 'EQUALS_DICT': lambda k, c: HealthyIfValsEqual(k, c)
+ 'EQUALS_DICT': lambda k, c: HealthyIfValsEqual(k, c),
+ 'STARTS_WITH': lambda k, c: HealthyIfStartsWith(k, c)
}
def __init__(self, config):
@@ -77,7 +80,13 @@
# loop through and check if healthy
unhealthy_metrics = []
for (metric, analyzer) in self._analyzers:
- # if not healthy, add to list so value can be reported
- if not analyzer.is_healthy(response_dict[metric]):
- unhealthy_metrics.append(metric)
+ try:
+ # if not healthy, add to list so value can be reported
+ if not analyzer.is_healthy(response_dict[metric]):
+ unhealthy_metrics.append(metric)
+ # don't exit whole program if error in config file, just report
+ except KeyError as e:
+ logging.warning(
+ 'Error in config file, "%s" not a health metric\n' % e)
+
return unhealthy_metrics
diff --git a/tools/lab/lab_upload_hooks.py b/tools/lab/lab_upload_hooks.py
new file mode 100755
index 0000000..d1bfa5f
--- /dev/null
+++ b/tools/lab/lab_upload_hooks.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 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.
+
+import test_main
+from acts.libs.proc import job
+
+# Get the names of all files that have been modified from last upstream sync.
+GIT_MODIFIED_FILES = 'git show --pretty="" --name-only @{u}..'
+
+
+def main():
+ files = job.run(GIT_MODIFIED_FILES, ignore_status=True).stdout
+ for file in files.split():
+ if file.startswith('tools/lab/'):
+ test_main.main()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/lab/main.py b/tools/lab/main.py
index 6e26e1a..da517ac 100755
--- a/tools/lab/main.py
+++ b/tools/lab/main.py
@@ -34,6 +34,7 @@
from metrics.ram_metric import RamMetric
from metrics.read_metric import ReadMetric
from metrics.system_load_metric import SystemLoadMetric
+from metrics.time_metric import TimeMetric
from metrics.time_sync_metric import TimeSyncMetric
from metrics.uptime_metric import UptimeMetric
from metrics.usb_metric import UsbMetric
@@ -50,8 +51,8 @@
class RunnerFactory(object):
_reporter_constructor = {
- 'logger': lambda param: [LoggerReporter(param)],
- 'json': lambda param: [JsonReporter(param)]
+ 'logger': lambda param, output: [LoggerReporter(param)],
+ 'json': lambda param, output: [JsonReporter(param, output)]
}
_metric_constructor = {
@@ -78,6 +79,7 @@
RamMetric(),
ReadMetric(),
SystemLoadMetric(),
+ TimeMetric(),
TimeSyncMetric(),
UptimeMetric(),
UsbMetric(),
@@ -102,12 +104,13 @@
reporters = []
# Get health config file, if specified
- config_file = arg_dict.pop('config', None)
# If not specified, default to 'config.json'
- if not config_file:
- config_file = os.path.join(sys.path[0], 'config.json')
- else:
- config_file = config_file[0]
+ config_file = arg_dict.pop('config',
+ os.path.join(sys.path[0], 'config.json'))
+ # Get output file path, if specified
+ # If not specified, default to 'output.json'
+ output_file = arg_dict.pop('output', 'output.json')
+
try:
with open(config_file) as json_data:
health_config = json.load(json_data)
@@ -120,7 +123,8 @@
rep_list = arg_dict.pop('reporter')
if rep_list is not None:
for rep_type in rep_list:
- reporters += cls._reporter_constructor[rep_type](checker)
+ reporters += cls._reporter_constructor[rep_type](checker,
+ output_file)
else:
# If no reporter specified, default to logger.
reporters += [LoggerReporter(checker)]
@@ -216,10 +220,18 @@
parser.add_argument(
'-c',
'--config',
- nargs=1,
- default=None,
+ nargs='?',
+ default='config.json',
metavar="<PATH>",
help='Path to health configuration file, defaults to `config.json`')
+ parser.add_argument(
+ '-o',
+ '--output',
+ nargs='?',
+ default='output.json',
+ metavar="<PATH>",
+ help='Path to where output file will be written, if applicable,'
+ ' defaults to `output.json`')
return parser
diff --git a/tools/lab/metrics/process_time_metric.py b/tools/lab/metrics/process_time_metric.py
index 8071f72..bc7194b 100644
--- a/tools/lab/metrics/process_time_metric.py
+++ b/tools/lab/metrics/process_time_metric.py
@@ -32,13 +32,9 @@
"""Returns ADB and Fastboot processes and their time elapsed
Returns:
- A dict with the following fields:
- adb_processes, fastboot_processes: a list of (PID, serialnumber)
- tuples where PID is a string representing the pid and
- serialnumber is serial number as a string, or NONE if number
- wasn't in command
- num_adb_processes, num_fastboot_processes: the number of tuples
- in the previous lists
+ A dictionary with adb/fastboot_processes as a list of serial nums or
+ NONE if number wasn't in command. num_adb/fastboot_processes as
+ the number of serials in list.
"""
# Get the process ids
pids = self.get_adb_fastboot_pids()
@@ -73,9 +69,9 @@
serial_number = spl_ln[sn_index + 1]
# append to proper list
if 'fastboot' in output:
- fastboot_processes.append((str(pid), serial_number))
+ fastboot_processes.append(serial_number)
elif 'adb' in output:
- adb_processes.append((str(pid), serial_number))
+ adb_processes.append(serial_number)
# Create response dictionary
response = {
@@ -93,7 +89,7 @@
A list of PID strings
"""
# Get ids of processes with 'adb' or 'fastboot' in name
- adb_result = self._shell.get_pids('adb')
- fastboot_result = self._shell.get_pids('fastboot')
+ adb_result = self._shell.get_command_pids('adb')
+ fastboot_result = self._shell.get_command_pids('fastboot')
# concatenate two generator objects, return as list
return list(itertools.chain(adb_result, fastboot_result))
diff --git a/tools/lab/metrics/time_metric.py b/tools/lab/metrics/time_metric.py
new file mode 100644
index 0000000..2d9daf2
--- /dev/null
+++ b/tools/lab/metrics/time_metric.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+#
+# Copyright 2017 - 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.
+
+from metrics.metric import Metric
+
+
+class TimeMetric(Metric):
+
+ COMMAND = "date"
+ # Fields for response dictionary
+ DATE_TIME = 'date_time'
+
+ def gather_metric(self):
+ """Returns the system date and time
+
+ Returns:
+ A dict with the following fields:
+ date_time: String stystem date and time
+
+ """
+ # Run shell command
+ result = self._shell.run(self.COMMAND).stdout
+ # Example stdout:
+ # Wed Jul 19 16:53:15 PDT 2017
+
+ response = {
+ self.DATE_TIME: result,
+ }
+ return response
diff --git a/tools/lab/metrics/time_sync_metric.py b/tools/lab/metrics/time_sync_metric.py
index 450f300..f2f7e99 100644
--- a/tools/lab/metrics/time_sync_metric.py
+++ b/tools/lab/metrics/time_sync_metric.py
@@ -28,7 +28,7 @@
Returns:
A dict with the following fields:
- is_synchronized: True if synchronized, fales otherwise
+ is_synchronized: True if synchronized
"""
# Run shell command
diff --git a/tools/lab/metrics/uptime_metric.py b/tools/lab/metrics/uptime_metric.py
index 5683e8d..edf5c2a 100644
--- a/tools/lab/metrics/uptime_metric.py
+++ b/tools/lab/metrics/uptime_metric.py
@@ -18,27 +18,34 @@
class UptimeMetric(Metric):
-
- COMMAND = "cat /proc/uptime"
+ SECONDS_COMMAND = 'cat /proc/uptime | cut -f1 -d\' \''
+ READABLE_COMMAND = 'uptime -p | cut -f2- -d\' \''
# Fields for response dictionary
TIME_SECONDS = 'time_seconds'
+ TIME_READABLE = 'time_readable'
+
+ def get_readable(self):
+ # Example stdout:
+ # 2 days, 8 hours, 19 minutes
+ return self._shell.run(self.READABLE_COMMAND).stdout
+
+ def get_seconds(self):
+ # Example stdout:
+ # 358350.70
+ return self._shell.run(self.SECONDS_COMMAND).stdout
def gather_metric(self):
"""Tells how long system has been running
Returns:
A dict with the following fields:
- time_seconds: float uptime in total seconds
+ time_seconds: uptime in total seconds
+ time_readable: time in human readable format
"""
- # Run shell command
- result = self._shell.run(self.COMMAND).stdout
- # Example stdout:
- # 358350.70 14241538.06
- # Get only first number (total time)
- seconds = float(result.split()[0])
response = {
- self.TIME_SECONDS: seconds,
+ self.TIME_SECONDS: self.get_seconds(),
+ self.TIME_READABLE: self.get_readable()
}
return response
diff --git a/tools/lab/metrics/usb_metric.py b/tools/lab/metrics/usb_metric.py
index 2de56fb..cd4bb7a 100644
--- a/tools/lab/metrics/usb_metric.py
+++ b/tools/lab/metrics/usb_metric.py
@@ -17,7 +17,7 @@
import io
import os
import subprocess
-
+import logging
import sys
from metrics.metric import Metric
@@ -59,7 +59,7 @@
try:
self._shell.run(self.USBMON_CHECK_COMMAND)
except job.Error:
- print('Kernel module not loaded, attempting to load usbmon')
+ logging.info('Kernel module not loaded, attempting to load usbmon')
try:
self._shell.run(self.USBMON_INSTALL_COMMAND)
except job.Error as error:
diff --git a/tools/lab/metrics/verify_metric.py b/tools/lab/metrics/verify_metric.py
index e4ad572..49569cf 100644
--- a/tools/lab/metrics/verify_metric.py
+++ b/tools/lab/metrics/verify_metric.py
@@ -20,17 +20,32 @@
class VerifyMetric(Metric):
"""Gathers the information of connected devices via ADB"""
COMMAND = r"adb devices | sed '1d;$d'"
- DEVICES = 'devices'
+ UNAUTHORIZED = 'unauthorized'
+ OFFLINE = 'offline'
+ RECOVERY = 'recovery'
+ QUESTION = 'question'
+ DEVICE = 'device'
+ TOTAL_UNHEALTHY = 'total_unhealthy'
def gather_metric(self):
""" Gathers device info based on adb output.
Returns:
- A dictionary with the field:
- devices: a dict with device serial number as key and device status as
- value.
+ A dictionary with the fields:
+ unauthorized: list of phone sn's that are unauthorized
+ offline: list of phone sn's that are offline
+ recovery: list of phone sn's that are in recovery mode
+ question: list of phone sn's in ??? mode
+ device: list of phone sn's that are in device mode
+ total: total number of offline, recovery, question or unauthorized
+ devices
"""
- device_dict = {}
+ offline_list = list()
+ unauth_list = list()
+ recovery_list = list()
+ question_list = list()
+ device_list = list()
+
# Delete first and last line of output of adb.
output = self._shell.run(self.COMMAND).stdout
@@ -40,6 +55,32 @@
for line in output.split('\n'):
spl_line = line.split('\t')
# spl_line[0] is serial, [1] is status. See example line.
- device_dict[spl_line[0]] = spl_line[1]
+ phone_sn = spl_line[0]
+ phone_state = spl_line[1]
- return {self.DEVICES: device_dict}
+ if phone_state == 'device':
+ device_list.append(phone_sn)
+ elif phone_state == 'unauthorized':
+ unauth_list.append(phone_sn)
+ elif phone_state == 'recovery':
+ recovery_list.append(phone_sn)
+ elif '?' in phone_state:
+ question_list.append(phone_sn)
+ elif phone_state == 'offline':
+ offline_list.append(phone_sn)
+
+ return {
+ self.UNAUTHORIZED:
+ unauth_list,
+ self.OFFLINE:
+ offline_list,
+ self.RECOVERY:
+ recovery_list,
+ self.QUESTION:
+ question_list,
+ self.DEVICE:
+ device_list,
+ self.TOTAL_UNHEALTHY:
+ len(unauth_list) + len(offline_list) + len(recovery_list) +
+ len(question_list)
+ }
diff --git a/tools/lab/metrics/version_metric.py b/tools/lab/metrics/version_metric.py
index 32c7910..e0b1445 100644
--- a/tools/lab/metrics/version_metric.py
+++ b/tools/lab/metrics/version_metric.py
@@ -22,7 +22,7 @@
FASTBOOT_COMMAND = 'fastboot --version'
FASTBOOT_VERSION = 'fastboot_version'
- # String to return if Fastboot version is too old
+ # String to return if fastboot version is too old
FASTBOOT_ERROR_MESSAGE = ('this version is older than versions that'
'return versions properly')
@@ -34,10 +34,10 @@
fastboot_version: string representing version of fastboot
Older versions of fastboot do not have a version flag. On an
older version, this metric will print 'this version is older
- than versions that return veresions properly'
+ than versions that return versions properly'
"""
- result = self._shell.run(self.FASTBOOT_COMMAND)
+ result = self._shell.run(self.FASTBOOT_COMMAND, ignore_status=True)
# If '--version' flag isn't recognized, will print to stderr
if result.stderr:
version = self.FASTBOOT_ERROR_MESSAGE
@@ -67,8 +67,10 @@
result = self._shell.run(self.ADB_COMMAND)
stdout = result.stdout.splitlines()
adb_version = stdout[0].split()[-1]
- # Revision information will always be in next line
- adb_revision = stdout[1].split()[1]
+ adb_revision = ""
+ # Old versions of ADB do not have revision numbers.
+ if len(stdout) > 1:
+ adb_revision = stdout[1].split()[1]
response = {
self.ADB_VERSION: adb_version,
diff --git a/tools/lab/metrics/zombie_metric.py b/tools/lab/metrics/zombie_metric.py
index 7711333..647b2ce 100644
--- a/tools/lab/metrics/zombie_metric.py
+++ b/tools/lab/metrics/zombie_metric.py
@@ -32,11 +32,9 @@
If process does not have serial, None is returned instead.
Returns:
- A dict with the following fields:
- adb_zombies, fastboot_zombies, other_zombies: lists of
- (PID, serial number) tuples
- num_adb_zombies, num_fastboot_zombies, num_other_zombies: int
- representing the number of tuples in the respective list
+ A dict with the following fields: adb/fastboot/other_zombies; lists
+ of serial numbers and num_adb/fastboot/other_zombies; ints
+ representing the number of entries in the respective list
"""
adb_zombies, fastboot_zombies, other_zombies = [], [], []
result = self._shell.run(self.COMMAND).stdout
@@ -46,8 +44,8 @@
output = result.splitlines()
for ln in output:
- spl_ln = ln.split()
# spl_ln looks like ['1xx', 'Z+', 'adb', '<defunct'>, ...]
+ spl_ln = ln.split()
pid, state, name = spl_ln[:3]
if '-s' in spl_ln:
@@ -57,15 +55,15 @@
sn = None
else:
sn = spl_ln[sn_idx + 1]
- zombie = (pid, sn)
+ zombie = sn
else:
- zombie = (pid, None)
+ zombie = None
if 'adb' in ln:
adb_zombies.append(zombie)
elif 'fastboot' in ln:
fastboot_zombies.append(zombie)
else:
- other_zombies.append(zombie)
+ other_zombies.append(pid)
return {
self.ADB_ZOMBIES: adb_zombies,
diff --git a/tools/lab/reporters/json_reporter.py b/tools/lab/reporters/json_reporter.py
index 7aa779f..4a8bcf7 100644
--- a/tools/lab/reporters/json_reporter.py
+++ b/tools/lab/reporters/json_reporter.py
@@ -16,12 +16,25 @@
import json
-import health_checker
from metrics.usb_metric import Device
from reporters.reporter import Reporter
class JsonReporter(Reporter):
+ """Reporter class that reports information in JSON format to a file.
+
+ This defaults to writing to the current working directory with name
+ output.json
+
+ Attributes:
+ health_checker: a HealthChecker object
+ file_name: Path of file to write to.
+ """
+
+ def __init__(self, h_checker, file_name='output.json'):
+ super(JsonReporter, self).__init__(h_checker)
+ self.file_name = file_name
+
def report(self, metric_responses):
unhealthy_metrics = self.health_checker.get_unhealthy(metric_responses)
for metric_name in metric_responses:
@@ -29,7 +42,13 @@
metric_responses[metric_name]['is_healthy'] = True
else:
metric_responses[metric_name]['is_healthy'] = False
- print(json.dumps(metric_responses, indent=4, cls=AutoJsonEncoder))
+ # add a total unhealthy score
+ metric_responses['total_unhealthy'] = {
+ 'total_unhealthy': len(set(unhealthy_metrics))
+ }
+ with open(self.file_name, 'w') as outfile:
+ json.dump(
+ metric_responses, indent=4, cls=AutoJsonEncoder, fp=outfile)
class AutoJsonEncoder(json.JSONEncoder):
diff --git a/tools/lab/setup.py b/tools/lab/setup.py
index c2c77ba..20e9daa 100755
--- a/tools/lab/setup.py
+++ b/tools/lab/setup.py
@@ -74,7 +74,7 @@
def main():
setuptools.setup(
name='LabHealth',
- version='0.1',
+ version='0.3',
description='Android Test Lab Health',
license='Apache2.0',
cmdclass={
diff --git a/tools/lab/test_main.py b/tools/lab/test_main.py
index 5f7b644..23c14cd 100755
--- a/tools/lab/test_main.py
+++ b/tools/lab/test_main.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3.4
#
# Copyright 2017 - The Android Open Source Project
#
@@ -17,11 +17,16 @@
import sys
import unittest
-if __name__ == "__main__":
+
+def main():
suite = unittest.TestLoader().discover(
start_dir='./tools/lab', pattern='*_test.py')
runner = unittest.TextTestRunner()
- # Return exit code of tests, so preupload hook fails if tests don't pass
+ # Pass the return status of the tests to the exit code.
ret = not runner.run(suite).wasSuccessful()
sys.exit(ret)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/lab/tests/constant_health_analyzer_test.py b/tools/lab/tests/constant_health_analyzer_test.py
index ebf38b2..756b488 100644
--- a/tools/lab/tests/constant_health_analyzer_test.py
+++ b/tools/lab/tests/constant_health_analyzer_test.py
@@ -61,5 +61,29 @@
self.assertFalse(analyzer.is_healthy(sample_metric))
+class HealthIfStartsWithTest(unittest.TestCase):
+ def test_starts_with_true_str(self):
+ sample_metric = {'kernel_release': "3.19-generic-random-12"}
+ analyzer = ha.HealthyIfStartsWith(
+ key='kernel_release', constant="3.19")
+ self.assertTrue(analyzer.is_healthy(sample_metric))
+
+ def test_starts_with_false_str(self):
+ sample_metric = {'kernel_release': "3.19-generic-random-12"}
+ analyzer = ha.HealthyIfStartsWith(
+ key='kernel_release', constant="4.04")
+ self.assertFalse(analyzer.is_healthy(sample_metric))
+
+ def test_starts_with_true_non_str(self):
+ sample_metric = {'kernel_release': "3.19-generic-random-12"}
+ analyzer = ha.HealthyIfStartsWith(key='kernel_release', constant=3.19)
+ self.assertTrue(analyzer.is_healthy(sample_metric))
+
+ def test_starts_with_false_non_str(self):
+ sample_metric = {'kernel_release': "3.19-generic-random-12"}
+ analyzer = ha.HealthyIfStartsWith(key='kernel_release', constant=4.04)
+ self.assertFalse(analyzer.is_healthy(sample_metric))
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/tools/lab/tests/fake.py b/tools/lab/tests/fake.py
index 07aa4e0..be22e2a 100644
--- a/tools/lab/tests/fake.py
+++ b/tools/lab/tests/fake.py
@@ -57,7 +57,7 @@
else:
return self._fake_result
- def get_pids(self, identifier):
+ def get_command_pids(self, identifier):
"""Returns a generator of fake pids
Args:
diff --git a/tools/lab/tests/health_checker_test.py b/tools/lab/tests/health_checker_test.py
index 28d2e64..67b4504 100644
--- a/tools/lab/tests/health_checker_test.py
+++ b/tools/lab/tests/health_checker_test.py
@@ -16,6 +16,7 @@
import io
import mock
+import sys
import unittest
from health_checker import HealthChecker
@@ -159,6 +160,50 @@
set(checker.get_unhealthy(fake_metric_response)),
set(expected_unhealthy))
+ def test_catch_key_error_metric_name(self):
+ fake_config = {
+ "not_verify": {
+ "devices": {
+ "constant": "device",
+ "compare": "EQUALS_DICT"
+ }
+ }
+ }
+ checker = HealthChecker(fake_config)
+ fake_metric_response = {
+ 'verify': {
+ 'devices': {
+ 'serialnumber': 'device'
+ }
+ }
+ }
+ try:
+ checker.get_unhealthy(fake_metric_response)
+ except KeyError as error:
+ self.fail('did not catch %s' % error)
+
+ def test_catch_key_error_metric_field(self):
+ fake_config = {
+ "verify": {
+ "not_devices": {
+ "constant": "device",
+ "compare": "EQUALS_DICT"
+ }
+ }
+ }
+ checker = HealthChecker(fake_config)
+ fake_metric_response = {
+ 'verify': {
+ 'devices': {
+ 'serialnumber': 'device'
+ }
+ }
+ }
+ try:
+ checker.get_unhealthy(fake_metric_response)
+ except KeyError as error:
+ self.fail('get_unhealthy did not internally handle %s' % error)
+
if __name__ == '__main__':
unittest.main()
diff --git a/tools/lab/tests/process_time_metric_test.py b/tools/lab/tests/process_time_metric_test.py
index f3e4c8f..c9dbec3 100644
--- a/tools/lab/tests/process_time_metric_test.py
+++ b/tools/lab/tests/process_time_metric_test.py
@@ -60,7 +60,7 @@
process_time_metric.ProcessTimeMetric.NUM_ADB_PROCESSES:
0,
process_time_metric.ProcessTimeMetric.FASTBOOT_PROCESSES:
- [("456", 'FA6BM0305019')],
+ ['FA6BM0305019'],
process_time_metric.ProcessTimeMetric.NUM_FASTBOOT_PROCESSES:
1
}
@@ -80,7 +80,7 @@
metric_obj = process_time_metric.ProcessTimeMetric(shell=fake_shell)
expected_result = {
process_time_metric.ProcessTimeMetric.ADB_PROCESSES:
- [('123', 'FAKESN'), ('456', 'FAKESN2')],
+ ['FAKESN', 'FAKESN2'],
process_time_metric.ProcessTimeMetric.NUM_ADB_PROCESSES:
2,
process_time_metric.ProcessTimeMetric.FASTBOOT_PROCESSES: [],
diff --git a/tools/lab/tests/time_metric_test.py b/tools/lab/tests/time_metric_test.py
new file mode 100755
index 0000000..7d96299
--- /dev/null
+++ b/tools/lab/tests/time_metric_test.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+#
+# Copyright 2017 - 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 unittest
+
+from metrics import time_metric
+from tests import fake
+
+
+class TimeMetricTest(unittest.TestCase):
+ """Class for testing UptimeMetric."""
+
+ def test_correct_uptime(self):
+ # Create sample stdout string ShellCommand.run() would return
+ stdout_string = "Wed Jul 19 16:53:15 PDT 2017"
+ FAKE_RESULT = fake.FakeResult(stdout=stdout_string)
+ fake_shell = fake.MockShellCommand(fake_result=FAKE_RESULT)
+ metric_obj = time_metric.TimeMetric(shell=fake_shell)
+
+ expected_result = {
+ time_metric.TimeMetric.DATE_TIME: "Wed Jul 19 16:53:15 PDT 2017",
+ }
+ self.assertEqual(expected_result, metric_obj.gather_metric())
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tools/lab/tests/uptime_metric_test.py b/tools/lab/tests/uptime_metric_test.py
index 5c73523..185c4b1 100755
--- a/tools/lab/tests/uptime_metric_test.py
+++ b/tools/lab/tests/uptime_metric_test.py
@@ -23,17 +23,23 @@
class UptimeMetricTest(unittest.TestCase):
"""Class for testing UptimeMetric."""
- def test_correct_uptime(self):
- # Create sample stdout string ShellCommand.run() would return
- stdout_string = "358350.70 14241538.06"
+ def test_get_seconds(self):
+ stdout_string = '358350.70'
FAKE_RESULT = fake.FakeResult(stdout=stdout_string)
fake_shell = fake.MockShellCommand(fake_result=FAKE_RESULT)
metric_obj = uptime_metric.UptimeMetric(shell=fake_shell)
- expected_result = {
- uptime_metric.UptimeMetric.TIME_SECONDS: 358350.70,
- }
- self.assertEqual(expected_result, metric_obj.gather_metric())
+ expected_result = '358350.70'
+ self.assertEqual(expected_result, metric_obj.get_seconds())
+
+ def test_get_readable(self):
+ stdout_string = '2 days, 8 hours, 19 minutes'
+ FAKE_RESULT = fake.FakeResult(stdout=stdout_string)
+ fake_shell = fake.MockShellCommand(fake_result=FAKE_RESULT)
+ metric_obj = uptime_metric.UptimeMetric(shell=fake_shell)
+
+ expected_result = '2 days, 8 hours, 19 minutes'
+ self.assertEqual(expected_result, metric_obj.get_readable())
if __name__ == '__main__':
diff --git a/tools/lab/tests/verify_metric_test.py b/tools/lab/tests/verify_metric_test.py
index 67a08bc..8d5fa04 100644
--- a/tools/lab/tests/verify_metric_test.py
+++ b/tools/lab/tests/verify_metric_test.py
@@ -21,27 +21,102 @@
class VerifyMetricTest(unittest.TestCase):
+ def test_offline(self):
+ mock_output = '00serial01\toffline'
+ FAKE_RESULT = fake.FakeResult(stdout=mock_output)
+ fake_shell = fake.MockShellCommand(fake_result=FAKE_RESULT)
+ metric_obj = verify_metric.VerifyMetric(shell=fake_shell)
+
+ expected_result = {
+ verify_metric.VerifyMetric.TOTAL_UNHEALTHY: 1,
+ verify_metric.VerifyMetric.UNAUTHORIZED: [],
+ verify_metric.VerifyMetric.RECOVERY: [],
+ verify_metric.VerifyMetric.OFFLINE: ['00serial01'],
+ verify_metric.VerifyMetric.QUESTION: [],
+ verify_metric.VerifyMetric.DEVICE: []
+ }
+ self.assertEquals(metric_obj.gather_metric(), expected_result)
+
+ def test_unauth(self):
+ mock_output = '00serial01\tunauthorized'
+ FAKE_RESULT = fake.FakeResult(stdout=mock_output)
+ fake_shell = fake.MockShellCommand(fake_result=FAKE_RESULT)
+ metric_obj = verify_metric.VerifyMetric(shell=fake_shell)
+
+ expected_result = {
+ verify_metric.VerifyMetric.TOTAL_UNHEALTHY: 1,
+ verify_metric.VerifyMetric.UNAUTHORIZED: ['00serial01'],
+ verify_metric.VerifyMetric.RECOVERY: [],
+ verify_metric.VerifyMetric.OFFLINE: [],
+ verify_metric.VerifyMetric.QUESTION: [],
+ verify_metric.VerifyMetric.DEVICE: []
+ }
+ self.assertEquals(metric_obj.gather_metric(), expected_result)
+
+ def test_device(self):
+ mock_output = '00serial01\tdevice'
+ FAKE_RESULT = fake.FakeResult(stdout=mock_output)
+ fake_shell = fake.MockShellCommand(fake_result=FAKE_RESULT)
+ metric_obj = verify_metric.VerifyMetric(shell=fake_shell)
+
+ expected_result = {
+ verify_metric.VerifyMetric.TOTAL_UNHEALTHY: 0,
+ verify_metric.VerifyMetric.UNAUTHORIZED: [],
+ verify_metric.VerifyMetric.RECOVERY: [],
+ verify_metric.VerifyMetric.OFFLINE: [],
+ verify_metric.VerifyMetric.QUESTION: [],
+ verify_metric.VerifyMetric.DEVICE: ['00serial01']
+ }
+ self.assertEquals(metric_obj.gather_metric(), expected_result)
+
+ def test_both(self):
+ mock_output = '00serial01\toffline\n' \
+ '01serial00\tunauthorized\n' \
+ '0regan0\tdevice'
+ FAKE_RESULT = fake.FakeResult(stdout=mock_output)
+ fake_shell = fake.MockShellCommand(fake_result=FAKE_RESULT)
+ metric_obj = verify_metric.VerifyMetric(shell=fake_shell)
+
+ expected_result = {
+ verify_metric.VerifyMetric.TOTAL_UNHEALTHY: 2,
+ verify_metric.VerifyMetric.UNAUTHORIZED: ['01serial00'],
+ verify_metric.VerifyMetric.RECOVERY: [],
+ verify_metric.VerifyMetric.QUESTION: [],
+ verify_metric.VerifyMetric.OFFLINE: ['00serial01'],
+ verify_metric.VerifyMetric.DEVICE: ['0regan0']
+ }
+
+ self.assertEquals(metric_obj.gather_metric(), expected_result)
+
def test_gather_device_empty(self):
mock_output = ''
FAKE_RESULT = fake.FakeResult(stdout=mock_output)
fake_shell = fake.MockShellCommand(fake_result=FAKE_RESULT)
metric_obj = verify_metric.VerifyMetric(shell=fake_shell)
- expected_result = {verify_metric.VerifyMetric.DEVICES: {}}
+ expected_result = {
+ verify_metric.VerifyMetric.TOTAL_UNHEALTHY: 0,
+ verify_metric.VerifyMetric.UNAUTHORIZED: [],
+ verify_metric.VerifyMetric.RECOVERY: [],
+ verify_metric.VerifyMetric.OFFLINE: [],
+ verify_metric.VerifyMetric.QUESTION: [],
+ verify_metric.VerifyMetric.DEVICE: []
+ }
self.assertEquals(metric_obj.gather_metric(), expected_result)
- def test_gather_device_two(self):
- mock_output = '00serial01\toffline\n' \
- '01serial00\tdevice'
+ def test_gather_device_question(self):
+ mock_output = '00serial01\t???'
FAKE_RESULT = fake.FakeResult(stdout=mock_output)
fake_shell = fake.MockShellCommand(fake_result=FAKE_RESULT)
metric_obj = verify_metric.VerifyMetric(shell=fake_shell)
expected_result = {
- verify_metric.VerifyMetric.DEVICES: {
- '00serial01': 'offline',
- '01serial00': 'device',
- }
+ verify_metric.VerifyMetric.TOTAL_UNHEALTHY: 1,
+ verify_metric.VerifyMetric.UNAUTHORIZED: [],
+ verify_metric.VerifyMetric.RECOVERY: [],
+ verify_metric.VerifyMetric.OFFLINE: [],
+ verify_metric.VerifyMetric.QUESTION: ['00serial01'],
+ verify_metric.VerifyMetric.DEVICE: []
}
self.assertEquals(metric_obj.gather_metric(), expected_result)
diff --git a/tools/lab/tests/version_metric_test.py b/tools/lab/tests/version_metric_test.py
index 777d9bd..c069e1c 100755
--- a/tools/lab/tests/version_metric_test.py
+++ b/tools/lab/tests/version_metric_test.py
@@ -78,6 +78,19 @@
}
self.assertEqual(expected_result, metric_obj.gather_metric())
+ def test_get_adb_revision_does_not_exist(self):
+ stdout_str = ('Android Debug Bridge version 1.0.39\n')
+
+ FAKE_RESULT = fake.FakeResult(stdout=stdout_str)
+ fake_shell = fake.MockShellCommand(fake_result=FAKE_RESULT)
+ metric_obj = version_metric.AdbVersionMetric(shell=fake_shell)
+
+ expected_result = {
+ version_metric.AdbVersionMetric.ADB_VERSION: '1.0.39',
+ version_metric.AdbVersionMetric.ADB_REVISION: ''
+ }
+ self.assertEqual(expected_result, metric_obj.gather_metric())
+
def test_get_python_version(self):
stdout_str = 'Python 2.7.6'
FAKE_RESULT = fake.FakeResult(stdout=stdout_str)
diff --git a/tools/lab/tests/zombie_metric_test.py b/tools/lab/tests/zombie_metric_test.py
index 0392f4c..3314d1b 100755
--- a/tools/lab/tests/zombie_metric_test.py
+++ b/tools/lab/tests/zombie_metric_test.py
@@ -30,7 +30,7 @@
metric_obj = zombie_metric.ZombieMetric(shell=fake_shell)
expected_result = {
- zombie_metric.ZombieMetric.ADB_ZOMBIES: [('30888', None)],
+ zombie_metric.ZombieMetric.ADB_ZOMBIES: [None],
zombie_metric.ZombieMetric.NUM_ADB_ZOMBIES: 1,
zombie_metric.ZombieMetric.FASTBOOT_ZOMBIES: [],
zombie_metric.ZombieMetric.NUM_FASTBOOT_ZOMBIES: 0,
@@ -46,7 +46,7 @@
metric_obj = zombie_metric.ZombieMetric(shell=fake_shell)
expected_result = {
- zombie_metric.ZombieMetric.ADB_ZOMBIES: [('30888', None)],
+ zombie_metric.ZombieMetric.ADB_ZOMBIES: [None],
zombie_metric.ZombieMetric.NUM_ADB_ZOMBIES: 1,
zombie_metric.ZombieMetric.FASTBOOT_ZOMBIES: [],
zombie_metric.ZombieMetric.NUM_FASTBOOT_ZOMBIES: 0,
@@ -63,16 +63,12 @@
metric_obj = zombie_metric.ZombieMetric(shell=fake_shell)
expected_result = {
- zombie_metric.ZombieMetric.ADB_ZOMBIES: [('99999', 'OR3G4N0')],
- zombie_metric.ZombieMetric.NUM_ADB_ZOMBIES:
- 1,
- zombie_metric.ZombieMetric.FASTBOOT_ZOMBIES: [('12345',
- 'M4RKY_M4RK')],
- zombie_metric.ZombieMetric.NUM_FASTBOOT_ZOMBIES:
- 1,
+ zombie_metric.ZombieMetric.ADB_ZOMBIES: ['OR3G4N0'],
+ zombie_metric.ZombieMetric.NUM_ADB_ZOMBIES: 1,
+ zombie_metric.ZombieMetric.FASTBOOT_ZOMBIES: ['M4RKY_M4RK'],
+ zombie_metric.ZombieMetric.NUM_FASTBOOT_ZOMBIES: 1,
zombie_metric.ZombieMetric.OTHER_ZOMBIES: [],
- zombie_metric.ZombieMetric.NUM_OTHER_ZOMBIES:
- 0
+ zombie_metric.ZombieMetric.NUM_OTHER_ZOMBIES: 0
}
self.assertEquals(metric_obj.gather_metric(), expected_result)
@@ -83,15 +79,28 @@
metric_obj = zombie_metric.ZombieMetric(shell=fake_shell)
expected_result = {
- zombie_metric.ZombieMetric.ADB_ZOMBIES: [('99999', None)],
+ zombie_metric.ZombieMetric.ADB_ZOMBIES: [None],
zombie_metric.ZombieMetric.NUM_ADB_ZOMBIES: 1,
- zombie_metric.ZombieMetric.FASTBOOT_ZOMBIES: [('12345', None)],
+ zombie_metric.ZombieMetric.FASTBOOT_ZOMBIES: [None],
zombie_metric.ZombieMetric.NUM_FASTBOOT_ZOMBIES: 1,
zombie_metric.ZombieMetric.OTHER_ZOMBIES: [],
zombie_metric.ZombieMetric.NUM_OTHER_ZOMBIES: 0
}
self.assertEquals(metric_obj.gather_metric(), expected_result)
+ def test_gather_metric_no_adb_fastboot(self):
+ stdout_string = '12345 Z+ otters'
+ FAKE_RESULT = fake.FakeResult(stdout=stdout_string)
+ fake_shell = fake.MockShellCommand(fake_result=FAKE_RESULT)
+ metric_obj = zombie_metric.ZombieMetric(shell=fake_shell)
+ metric_obj_res = metric_obj.gather_metric()
+ exp_num = 1
+ exp_pid = ['12345']
+
+ self.assertEquals(metric_obj_res[metric_obj.NUM_OTHER_ZOMBIES],
+ exp_num)
+ self.assertEquals(metric_obj_res[metric_obj.OTHER_ZOMBIES], exp_pid)
+
if __name__ == '__main__':
unittest.main()
diff --git a/tools/lab/utils/shell.py b/tools/lab/utils/shell.py
index d1e8c48..02735e3 100644
--- a/tools/lab/utils/shell.py
+++ b/tools/lab/utils/shell.py
@@ -35,7 +35,7 @@
Args:
runner: The object that will run the shell commands.
working_dir: The directory that all commands should work in,
- if none then the runners enviroment default is used.
+ if none then the runners environment default is used.
"""
self._runner = runner
self._working_dir = working_dir
@@ -67,7 +67,7 @@
def is_alive(self, identifier):
"""Checks to see if a program is alive.
- Checks to see if a program is alive on the shells enviroment. This can
+ Checks to see if a program is alive on the shells environment. This can
be used to check on generic programs, or a specific program using
a pid.
@@ -91,6 +91,29 @@
except job.Error:
return False
+ def get_command_pids(self, identifier):
+ """Gets the pids of a program, based only upon the starting command
+
+ Searches for a program with a specific name and grabs the pids for all
+ programs that match only the command that started it. The arguments of
+ the command are ignored.
+
+ Args:
+ identifier: The search term that identifies the program.
+
+ Returns:
+ An array of ints of all pids that matched the identifier.
+ """
+ result = self.run(
+ 'ps -C %s --no-heading -o pid:1' % identifier, ignore_status=True)
+
+ # Output looks like pids on separate lines:
+ # 1245
+ # 5001
+
+ pids = result.stdout.splitlines()
+ return [int(pid) for pid in result.stdout.splitlines()]
+
def get_pids(self, identifier):
"""Gets the pids of a program.
@@ -195,7 +218,7 @@
that match the identifier until either all are dead or the timeout
finishes.
- Programs are guranteed to be killed after running this command.
+ Programs are guaranteed to be killed after running this command.
Args:
identifier: A string used to identify the program.
@@ -230,7 +253,7 @@
Args:
pid: The process id of the program to kill.
- sig: The singal to send.
+ sig: The signal to send.
Raises:
job.Error: Raised when the signal fail to reach
diff --git a/tools/yapf_checker.py b/tools/yapf_checker.py
index c9bf2c8..9c45a55 100755
--- a/tools/yapf_checker.py
+++ b/tools/yapf_checker.py
@@ -25,10 +25,9 @@
YAPF_COMMAND = 'yapf -d -p %s'
YAPF_OLD_COMMAND = 'yapf -d %s'
YAPF_INPLACE_FORMAT = 'yapf -p -i %s'
-YAPF_INPLACE_FORMAT_OLD = 'yapf -i %s'
-def main(argv):
+def main():
if COMMIT_ID_ENV_KEY not in os.environ:
logging.error('Missing commit id in environment.')
exit(1)
@@ -49,18 +48,14 @@
result = job.run(YAPF_COMMAND % files_param_string, ignore_status=True)
yapf_inplace_format = YAPF_INPLACE_FORMAT
- if result.exit_status:
- logging.warning('Using an old version of yapf. Please update soon.')
- result = job.run(YAPF_OLD_COMMAND % files_param_string)
- yapf_inplace_format = YAPF_INPLACE_FORMAT_OLD
if result.stdout:
logging.error(result.stdout)
logging.error('INVALID FORMATTING.')
- logging.error('Consider run:')
- logging.error(yapf_inplace_format % files_param_string)
+ logging.error('Please run:\n'
+ '%s' % yapf_inplace_format % files_param_string)
exit(1)
if __name__ == '__main__':
- main(sys.argv[1:])
+ main()