[WifiPnoTest] Fix: Make Wi-Fi connection to the saved networks before PNO scan. am: 96381028c2 am: 328fc979da
Original change: https://googleplex-android-review.googlesource.com/c/platform/tools/test/connectivity/+/17184490
Change-Id: Ia32e1e4201793af78bae3fccdec703305bb14023
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
\ No newline at end of file
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index a62e1f9..5260bc1 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,7 +1,7 @@
[Hook Scripts]
-yapf_hook = ./tools/yapf_checker.py
-proto_check = ./tools/proto_check.py
create_virtualenv = ./tools/create_virtualenv.sh
+yapf_hook = /tmp/acts_preupload_virtualenv/bin/python3 ./tools/yapf_checker.py
+proto_check = /tmp/acts_preupload_virtualenv/bin/python3 ./tools/proto_check.py
acts_unittests = /tmp/acts_preupload_virtualenv/bin/python3 ./acts_tests/tests/meta/ActsUnitTest.py
destroy_virtualenv = rm -rf /tmp/acts_preupload_virtualenv/
diff --git a/acts/framework/acts/config_parser.py b/acts/framework/acts/config_parser.py
index 549ebed..a639c38 100755
--- a/acts/framework/acts/config_parser.py
+++ b/acts/framework/acts/config_parser.py
@@ -207,7 +207,7 @@
tbs[name] = testbeds[name]
else:
raise ActsConfigError(
- 'Expected testbed named "%s", but none was found. Check'
+ 'Expected testbed named "%s", but none was found. Check '
'if you have the correct testbed names.' % name)
testbeds = tbs
diff --git a/acts/framework/acts/controllers/OWNERS b/acts/framework/acts/controllers/OWNERS
index 8155c96..ea76291 100644
--- a/acts/framework/acts/controllers/OWNERS
+++ b/acts/framework/acts/controllers/OWNERS
@@ -1,4 +1,5 @@
-per-file fuchsia_device.py = tturney@google.com, jmbrenna@google.com, haydennix@google.com
+per-file asus_axe11000_ap.py = martschneider@google.com
+per-file fuchsia_device.py = chcl@google.com, dhobsd@google.com, haydennix@google.com, jmbrenna@google.com, mnck@google.com, nickchee@google.com, sbalana@google.com, silberst@google.com, tturney@google.com
per-file bluetooth_pts_device.py = tturney@google.com
per-file cellular_simulator.py = iguarna@google.com, chaoyangf@google.com, codycaldwell@google.com, yixiang@google.com
-per-file openwrt_ap.py = jerrypcchen@google.com, martschneider@google.com, gmoturu@google.com
+per-file openwrt_ap.py = jerrypcchen@google.com, martschneider@google.com, gmoturu@google.com, sishichen@google.com
diff --git a/acts/framework/acts/controllers/access_point.py b/acts/framework/acts/controllers/access_point.py
index 193a93d..abc31dd 100755
--- a/acts/framework/acts/controllers/access_point.py
+++ b/acts/framework/acts/controllers/access_point.py
@@ -128,6 +128,13 @@
additional_ap_parameters: Additional parameters to send the AP.
password: Password to connect to WLAN if necessary.
check_connectivity: Whether to check for internet connectivity.
+
+ Returns:
+ An identifier for each ssid being started. These identifiers can be
+ used later by this controller to control the ap.
+
+ Raises:
+ Error: When the ap can't be brought up.
"""
ap = hostapd_ap_preset.create_ap_preset(profile_name=profile_name,
iface_wlan_2g=access_point.wlan_2g,
@@ -148,9 +155,10 @@
n_capabilities=n_capabilities,
ac_capabilities=ac_capabilities,
vht_bandwidth=vht_bandwidth)
- access_point.start_ap(hostapd_config=ap,
- setup_bridge=setup_bridge,
- additional_parameters=additional_ap_parameters)
+ return access_point.start_ap(
+ hostapd_config=ap,
+ setup_bridge=setup_bridge,
+ additional_parameters=additional_ap_parameters)
class Error(Exception):
@@ -212,10 +220,14 @@
self._dhcp = None
self._dhcp_bss = dict()
self.bridge = bridge_interface.BridgeInterface(self)
- self.interfaces = ap_get_interface.ApInterfaces(self)
self.iwconfig = ap_iwconfig.ApIwconfig(self)
- # Get needed interface names and initialize the unneccessary ones.
+ # Check to see if wan_interface is specified in acts_config for tests
+ # isolated from the internet and set this override.
+ self.interfaces = ap_get_interface.ApInterfaces(
+ self, configs.get('wan_interface'))
+
+ # Get needed interface names and initialize the unnecessary ones.
self.wan = self.interfaces.get_wan_interface()
self.wlan = self.interfaces.get_wlan_interface()
self.wlan_2g = self.wlan[0]
@@ -323,6 +335,7 @@
# Clear all routes to prevent old routes from interfering.
self._route_cmd.clear_routes(net_interface=interface)
+ self._dhcp_bss = dict()
if hostapd_config.bss_lookup:
# The self._dhcp_bss dictionary is created to hold the key/value
# pair of the interface name and the ip scope that will be
@@ -332,7 +345,6 @@
# is requested. This part is designed to bring up the
# hostapd interfaces and not the DHCP servers for each
# interface.
- self._dhcp_bss = dict()
counter = 1
for bss in hostapd_config.bss_lookup:
if interface_mac_orig:
@@ -357,7 +369,7 @@
interface_ip = ipaddress.ip_interface(
'%s/%s' % (subnet.router, subnet.network.netmask))
if setup_bridge is True:
- bridge_interface_name = 'br_lan'
+ bridge_interface_name = 'eth_test'
self.create_bridge(bridge_interface_name, [interface, self.lan])
self._ip_cmd.set_ipv4_address(bridge_interface_name, interface_ip)
else:
@@ -374,12 +386,9 @@
self._ip_cmd.set_ipv4_address(str(k), bss_interface_ip)
# Restart the DHCP server with our updated list of subnets.
- configured_subnets = [x.subnet for x in self._aps.values()]
- if hostapd_config.bss_lookup:
- for k, v in self._dhcp_bss.items():
- configured_subnets.append(v)
-
- self.start_dhcp(subnets=configured_subnets)
+ configured_subnets = self.get_configured_subnets()
+ dhcp_conf = dhcp_config.DhcpConfig(subnets=configured_subnets)
+ self.start_dhcp(dhcp_conf=dhcp_conf)
self.start_nat()
bss_interfaces = [bss for bss in hostapd_config.bss_lookup]
@@ -387,22 +396,60 @@
return bss_interfaces
- def start_dhcp(self, subnets):
+ def get_configured_subnets(self):
+ """Get the list of configured subnets on the access point.
+
+ This allows consumers of the access point objects create custom DHCP
+ configs with the correct subnets.
+
+ Returns: a list of dhcp_config.Subnet objects
+ """
+ configured_subnets = [x.subnet for x in self._aps.values()]
+ for k, v in self._dhcp_bss.items():
+ configured_subnets.append(v)
+ return configured_subnets
+
+ def start_dhcp(self, dhcp_conf):
"""Start a DHCP server for the specified subnets.
This allows consumers of the access point objects to control DHCP.
Args:
- subnets: A list of Subnets.
+ dhcp_conf: A dhcp_config.DhcpConfig object.
+
+ Raises:
+ Error: Raised when a dhcp server error is found.
"""
- return self._dhcp.start(config=dhcp_config.DhcpConfig(subnets))
+ self._dhcp.start(config=dhcp_conf)
def stop_dhcp(self):
"""Stop DHCP for this AP object.
This allows consumers of the access point objects to control DHCP.
"""
- return self._dhcp.stop()
+ self._dhcp.stop()
+
+ def get_dhcp_logs(self):
+ """Get DHCP logs for this AP object.
+
+ This allows consumers of the access point objects to validate DHCP
+ behavior.
+ """
+ return self._dhcp.get_logs()
+
+ def get_hostapd_logs(self):
+ """Get hostapd logs for all interfaces on AP object.
+
+ This allows consumers of the access point objects to validate hostapd
+ behavior.
+
+ Returns: A dict with {interface: log} from hostapd instances.
+ """
+ hostapd_logs = dict()
+ for identifier in self._aps:
+ hostapd_logs[identifier] = self._aps.get(
+ identifier).hostapd.pull_logs()
+ return hostapd_logs
def start_nat(self):
"""Start NAT on the AP.
@@ -452,6 +499,9 @@
self.ssh.run('brctl addif {bridge_name} {interface}'.format(
bridge_name=bridge_name, interface=interface))
+ self.ssh.run(
+ 'ip link set {bridge_name} up'.format(bridge_name=bridge_name))
+
def remove_bridge(self, bridge_name):
"""Removes the specified bridge
@@ -793,3 +843,18 @@
self.start_ap(config,
setup_bridge=setup_bridge,
additional_parameters=additional_parameters)
+
+ def channel_switch(self, identifier, channel_num):
+ """Switch to a different channel on the given AP."""
+ if identifier not in list(self._aps.keys()):
+ raise ValueError('Invalid identifier %s given' % identifier)
+ instance = self._aps.get(identifier)
+ self.log.info('channel switch to channel {}'.format(channel_num))
+ instance.hostapd.channel_switch(channel_num)
+
+ def get_current_channel(self, identifier):
+ """Find the current channel on the given AP."""
+ if identifier not in list(self._aps.keys()):
+ raise ValueError('Invalid identifier %s given' % identifier)
+ instance = self._aps.get(identifier)
+ return instance.hostapd.get_current_channel()
diff --git a/acts/framework/acts/controllers/adb.py b/acts/framework/acts/controllers/adb.py
index 53e56af..854ed23 100644
--- a/acts/framework/acts/controllers/adb.py
+++ b/acts/framework/acts/controllers/adb.py
@@ -269,7 +269,7 @@
def adb_call(*args, **kwargs):
usage_metadata_logger.log_usage(self.__module__, name)
clean_name = name.replace('_', '-')
- if clean_name in ['pull', 'push'] and 'timeout' not in kwargs:
+ if clean_name in ['pull', 'push', 'remount'] and 'timeout' not in kwargs:
kwargs['timeout'] = DEFAULT_ADB_PULL_TIMEOUT
arg_str = ' '.join(str(elem) for elem in args)
return self._exec_adb_cmd(clean_name, arg_str, **kwargs)
diff --git a/acts/framework/acts/controllers/amarisoft_lib/OWNERS b/acts/framework/acts/controllers/amarisoft_lib/OWNERS
new file mode 100644
index 0000000..edee4ef
--- /dev/null
+++ b/acts/framework/acts/controllers/amarisoft_lib/OWNERS
@@ -0,0 +1,4 @@
+markusliu@google.com
+mollychang@google.com
+angelayu@google.com
+zoeyliu@google.com
diff --git a/acts/framework/acts/controllers/amarisoft_lib/amarisoft_client.py b/acts/framework/acts/controllers/amarisoft_lib/amarisoft_client.py
new file mode 100644
index 0000000..bbfa174
--- /dev/null
+++ b/acts/framework/acts/controllers/amarisoft_lib/amarisoft_client.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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.
+
+import asyncio
+import json
+import logging
+from typing import Any, Mapping, Optional, Tuple
+
+from acts.controllers.amarisoft_lib import ssh_utils
+import immutabledict
+import websockets
+
+_CONFIG_DIR_MAPPING = immutabledict.immutabledict({
+ 'enb': '/config/enb.cfg',
+ 'mme': '/config/mme.cfg',
+ 'ims': '/config/ims.cfg',
+ 'mbms': '/config/mbmsgw.cfg',
+ 'ots': '/config/ots.cfg'
+})
+
+
+class MessageFailureError(Exception):
+ """Raises an error when the message execution fail."""
+
+
+class AmariSoftClient(ssh_utils.RemoteClient):
+ """The SSH client class interacts with Amarisoft.
+
+ A simulator used to simulate the base station can output different signals
+ according to the network configuration settings.
+ For example: T Mobile NSA LTE band 66 + NR band 71.
+ """
+
+ async def _send_message_to_callbox(self, uri: str,
+ msg: str) -> Tuple[str, str]:
+ """Implements async function for send message to the callbox.
+
+ Args:
+ uri: The uri of specific websocket interface.
+ msg: The message to be send to callbox.
+
+ Returns:
+ The response from callbox.
+ """
+ async with websockets.connect(
+ uri, extra_headers={'origin': 'Test'}) as websocket:
+ await websocket.send(msg)
+ head = await websocket.recv()
+ body = await websocket.recv()
+ return head, body
+
+ def send_message(self, port: str, msg: str) -> Tuple[str, str]:
+ """Sends a message to the callbox.
+
+ Args:
+ port: The port of specific websocket interface.
+ msg: The message to be send to callbox.
+
+ Returns:
+ The response from callbox.
+ """
+ return asyncio.get_event_loop().run_until_complete(
+ self._send_message_to_callbox(f'ws://{self.host}:{port}/', msg))
+
+ def verify_response(self, func: str, head: str,
+ body: str) -> Tuple[Mapping[str, Any], Mapping[str, Any]]:
+ """Makes sure there are no error messages in Amarisoft's response.
+
+ If a message produces an error, response will have an error string field
+ representing the error.
+ For example:
+ {
+ "message": "ready",
+ "message_id": <message id>,
+ "error": <error message>,
+ "type": "ENB",
+ "name: <name>,
+ }
+
+ Args:
+ func: The message send to Amarisoft.
+ head: Responsed message head.
+ body: Responsed message body.
+
+ Returns:
+ Standard output of the shell command.
+
+ Raises:
+ MessageFailureError: Raised when an error occurs in the response message.
+ """
+ loaded_head = json.loads(head)
+ loaded_body = json.loads(body)
+
+ if loaded_head.get('message') != 'ready':
+ raise MessageFailureError(
+ f'Fail to get response from callbox, message: {loaded_head["error"]}')
+ if 'error' in loaded_body:
+ raise MessageFailureError(
+ f'Fail to excute {func} with error message: {loaded_body["error"]}')
+ if loaded_body.get('message') != func:
+ raise MessageFailureError(
+ f'The message sent was {loaded_body["message"]} instead of {func}.')
+ return loaded_head, loaded_body
+
+ def lte_service_stop(self) -> None:
+ """Stops to output signal."""
+ self.run_cmd('systemctl stop lte')
+
+ def lte_service_start(self):
+ """Starts to output signal."""
+ self.run_cmd('systemctl start lte')
+
+ def lte_service_restart(self):
+ """Restarts to output signal."""
+ self.run_cmd('systemctl restart lte')
+
+ def lte_service_enable(self):
+ """lte service remains enable until next reboot."""
+ self.run_cmd('systemctl enable lte')
+
+ def lte_service_disable(self):
+ """lte service remains disable until next reboot."""
+ self.run_cmd('systemctl disable lte')
+
+ def lte_service_is_active(self) -> bool:
+ """Checks lte service is active or not.
+
+ Returns:
+ True if service active, False otherwise.
+ """
+ return not any('inactive' in line
+ for line in self.run_cmd('systemctl is-active lte'))
+
+ def set_config_dir(self, cfg_type: str, path: str) -> None:
+ """Sets the path of target configuration file.
+
+ Args:
+ cfg_type: The type of target configuration. (e.g. mme, enb ...etc.)
+ path: The path of target configuration. (e.g.
+ /root/lteenb-linux-2020-12-14)
+ """
+ path_old = self.get_config_dir(cfg_type)
+ if path != path_old:
+ logging.info('set new path %s (was %s)', path, path_old)
+ self.run_cmd(f'ln -sfn {path} /root/{cfg_type}')
+ else:
+ logging.info('path %s does not change.', path_old)
+
+ def get_config_dir(self, cfg_type: str) -> Optional[str]:
+ """Gets the path of target configuration.
+
+ Args:
+ cfg_type: Target configuration type. (e.g. mme, enb...etc.)
+
+ Returns:
+ The path of configuration.
+ """
+ result = self.run_cmd(f'readlink /root/{cfg_type}')
+ if result:
+ path = result[0].strip()
+ else:
+ logging.warning('%s path not found.', cfg_type)
+ return None
+ return path
+
+ def set_config_file(self, cfg_type: str, cfg_file: str) -> None:
+ """Sets the configuration to be executed.
+
+ Args:
+ cfg_type: The type of target configuration. (e.g. mme, enb...etc.)
+ cfg_file: The configuration to be executed. (e.g.
+ /root/lteenb-linux-2020-12-14/config/gnb.cfg )
+
+ Raises:
+ FileNotFoundError: Raised when a file or directory is requested but
+ doesn’t exist.
+ """
+ cfg_link = self.get_config_dir(cfg_type) + _CONFIG_DIR_MAPPING[cfg_type]
+ if not self.is_file_exist(cfg_file):
+ raise FileNotFoundError("The command file doesn't exist")
+ self.run_cmd(f'ln -sfn {cfg_file} {cfg_link}')
+
+ def get_config_file(self, cfg_type: str) -> Optional[str]:
+ """Gets the current configuration of specific configuration type.
+
+ Args:
+ cfg_type: The type of target configuration. (e.g. mme, enb...etc.)
+
+ Returns:
+ The current configuration with absolute path.
+ """
+ cfg_path = self.get_config_dir(cfg_type) + _CONFIG_DIR_MAPPING[cfg_type]
+ if cfg_path:
+ result = self.run_cmd(f'readlink {cfg_path}')
+ if result:
+ return result[0].strip()
+
+ def get_all_config_dir(self) -> Mapping[str, str]:
+ """Gets all configuration directions.
+
+ Returns:
+ All configuration directions.
+ """
+ config_dir = {}
+ for cfg_type in ('ots', 'enb', 'mme', 'mbms'):
+ config_dir[cfg_type] = self.get_config_dir(cfg_type)
+ logging.debug('get path of %s: %s', cfg_type, config_dir[cfg_type])
+ return config_dir
diff --git a/acts/framework/acts/controllers/amarisoft_lib/amarisoft_constants.py b/acts/framework/acts/controllers/amarisoft_lib/amarisoft_constants.py
new file mode 100644
index 0000000..c62bf2a
--- /dev/null
+++ b/acts/framework/acts/controllers/amarisoft_lib/amarisoft_constants.py
@@ -0,0 +1,14 @@
+"""Constants for test."""
+
+
+# ports of lte service websocket interface
+class PortNumber:
+ URI_MME = '9000'
+ URI_ENB = '9001'
+ URI_UE = '9002'
+ URI_IMS = '9003'
+ URI_MBMS = '9004'
+ URI_PROBE = '9005'
+ URI_LICENSE = '9006'
+ URI_MON = '9007'
+ URI_VIEW = '9008'
diff --git a/acts/framework/acts/controllers/amarisoft_lib/config_utils.py b/acts/framework/acts/controllers/amarisoft_lib/config_utils.py
new file mode 100644
index 0000000..3dad7a3
--- /dev/null
+++ b/acts/framework/acts/controllers/amarisoft_lib/config_utils.py
@@ -0,0 +1,201 @@
+!/usr/bin/env python3
+#
+# Copyright 2022 - 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.
+
+import enum
+import os
+import immutabledict
+
+from acts.controllers.amarisoft_lib import amarisoft_client
+
+TEMPLATE_PATH = os.path.dirname(os.path.abspath(__file__)) + '/config_templates'
+TEMPLATE_PATH_ENB = f'{TEMPLATE_PATH}/enb/'
+TEMPLATE_PATH_MME = f'{TEMPLATE_PATH}/mme/'
+
+_CLIENT_CONFIG_DIR_MAPPING = immutabledict.immutabledict({
+ 'enb': '/config/mhtest_enb.cfg',
+ 'mme': '/config/mhtest_mme.cfg',
+})
+
+
+class EnbCfg():
+ """MME configuration templates."""
+ ENB_GENERIC = 'enb-single-generic.cfg'
+ GNB_NSA_GENERIC = 'gnb-nsa-lte-ho-generic.cfg'
+ GNB_SA_GENERIC = 'gnb-sa-lte-ho-generic.cfg'
+
+
+class MmeCfg():
+ """MME configuration templates."""
+ MME_GENERIC = 'mme-generic.cfg'
+
+
+class SpecTech(enum.Enum):
+ """Spectrum usage techniques."""
+ FDD = 0
+ TDD = 1
+
+
+class ConfigUtils():
+ """Utilities for set Amarisoft configs.
+
+ Attributes:
+ remote: An amarisoft client.
+ """
+
+ def __init__(self, remote: amarisoft_client.AmariSoftClient):
+ self.remote = remote
+
+ def upload_enb_template(self, cfg: str) -> bool:
+ """Loads ENB configuration.
+
+ Args:
+ cfg: The ENB configuration to be loaded.
+
+ Returns:
+ True if the ENB configuration was loaded successfully, False otherwise.
+ """
+ cfg_template = TEMPLATE_PATH_ENB + cfg
+ if not os.path.isfile(cfg_template):
+ return False
+ cfg_path = self.remote.get_config_dir(
+ 'enb') + _CLIENT_CONFIG_DIR_MAPPING['enb']
+ self.remote.run_cmd('rm -f ' + cfg_path)
+ self.remote.sftp_upload(cfg_template, cfg_path)
+ self.remote.set_config_file('enb', cfg_path)
+ if not self.remote.is_file_exist(cfg_path):
+ return False
+ return True
+
+ def upload_mme_template(self, cfg: str) -> bool:
+ """Loads MME configuration.
+
+ Args:
+ cfg: The MME configuration to be loaded.
+
+ Returns:
+ True if the ENB configuration was loaded successfully, False otherwise.
+ """
+ cfg_template = TEMPLATE_PATH_MME + cfg
+ if not os.path.isfile(cfg_template):
+ return False
+ cfg_path = self.remote.get_config_dir(
+ 'mme') + _CLIENT_CONFIG_DIR_MAPPING['mme']
+ self.remote.run_cmd('rm -f ' + cfg_path)
+ self.remote.sftp_upload(cfg_template, cfg_path)
+ self.remote.set_config_file('mme', cfg_path)
+ if not self.remote.is_file_exist(cfg_path):
+ return False
+ return True
+
+ def enb_set_plmn(self, plmn: str) -> bool:
+ """Sets the PLMN in ENB configuration.
+
+ Args:
+ plmn: The PLMN to be set. ex: 311480
+
+ Returns:
+ True if set PLMN successfully, False otherwise.
+ """
+ cfg_path = self.remote.get_config_dir(
+ 'enb') + _CLIENT_CONFIG_DIR_MAPPING['enb']
+ if not self.remote.is_file_exist(cfg_path):
+ return False
+ string_from = '#define PLMN \"00101\"'
+ string_to = f'#define PLMN \"{plmn}\"'
+ self.remote.run_cmd(f'sed -i \'s/\\r//g\' {cfg_path}')
+ self.remote.run_cmd(
+ f'sed -i \':a;N;$!ba;s/{string_from}/{string_to}/g\' {cfg_path}')
+ return True
+
+ def mme_set_plmn(self, plmn: str) -> bool:
+ """Sets the PLMN in MME configuration.
+
+ Args:
+ plmn: The PLMN to be set. ex:'311480'
+
+ Returns:
+ True if set PLMN successfully, False otherwise.
+ """
+ cfg_path = self.remote.get_config_dir(
+ 'mme') + _CLIENT_CONFIG_DIR_MAPPING['mme']
+ if not self.remote.is_file_exist(cfg_path):
+ return False
+ string_from = '#define PLMN \"00101\"'
+ string_to = f'#define PLMN \"{plmn}\"'
+ self.remote.run_cmd(f'sed -i \'s/\\r//g\' {cfg_path}')
+ self.remote.run_cmd(
+ f'sed -i \':a;N;$!ba;s/{string_from}/{string_to}/g\' {cfg_path}')
+ return True
+
+ def enb_set_fdd_arfcn(self, arfcn: int) -> bool:
+ """Sets the FDD ARFCN in ENB configuration.
+
+ Args:
+ arfcn: The arfcn to be set. ex: 1400
+
+ Returns:
+ True if set FDD ARFCN successfully, False otherwise.
+ """
+ cfg_path = self.remote.get_config_dir(
+ 'enb') + _CLIENT_CONFIG_DIR_MAPPING['enb']
+ if not self.remote.is_file_exist(cfg_path):
+ return False
+ string_from = '#define FDD_CELL_earfcn 1400'
+ string_to = f'#define FDD_CELL_earfcn {arfcn}'
+ self.remote.run_cmd(f'sed -i \'s/\\r//g\' {cfg_path}')
+ self.remote.run_cmd(
+ f'sed -i \':a;N;$!ba;s/{string_from}/{string_to}/g\' {cfg_path}')
+ return True
+
+ def enb_set_tdd_arfcn(self, arfcn: int) -> bool:
+ """Sets the TDD ARFCN in ENB configuration.
+
+ Args:
+ arfcn: The arfcn to be set. ex: 1400
+
+ Returns:
+ True if set FDD ARFCN successfully, False otherwise.
+ """
+ cfg_path = self.remote.get_config_dir(
+ 'enb') + _CLIENT_CONFIG_DIR_MAPPING['enb']
+ if not self.remote.is_file_exist(cfg_path):
+ return False
+ string_from = '#define TDD_CELL_earfcn 40620'
+ string_to = f'#define TDD_CELL_earfcn {arfcn}'
+ self.remote.run_cmd(f'sed -i \'s/\\r//g\' {cfg_path}')
+ self.remote.run_cmd(
+ f'sed -i \':a;N;$!ba;s/{string_from}/{string_to}/g\' {cfg_path}')
+ return True
+
+ def enb_set_spectrum_tech(self, tech: int) -> bool:
+ """Sets the spectrum usage techniques in ENB configuration.
+
+ Args:
+ tech: the spectrum usage techniques. ex: SpecTech.FDD.name
+
+ Returns:
+ True if set spectrum usage techniques successfully, False otherwise.
+ """
+ cfg_path = self.remote.get_config_dir(
+ 'enb') + _CLIENT_CONFIG_DIR_MAPPING['enb']
+ if not self.remote.is_file_exist(cfg_path):
+ return False
+ string_from = '#define TDD 0'
+ string_to = f'#define TDD {tech}'
+ self.remote.run_cmd(f'sed -i \'s/\\r//g\' {cfg_path}')
+ self.remote.run_cmd(
+ f'sed -i \':a;N;$!ba;s/{string_from}/{string_to}/g\' {cfg_path}')
+ return True
diff --git a/acts/framework/acts/controllers/amarisoft_lib/ims.py b/acts/framework/acts/controllers/amarisoft_lib/ims.py
new file mode 100644
index 0000000..9289ba0
--- /dev/null
+++ b/acts/framework/acts/controllers/amarisoft_lib/ims.py
@@ -0,0 +1,156 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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.
+
+import json
+import logging
+from typing import Any, Mapping, Optional, Union
+
+from acts.controllers.amarisoft_lib import amarisoft_client
+from acts.controllers.amarisoft_lib import amarisoft_constants as const
+
+
+class ImsFunctions():
+ """Utilities for Amarisoft's IMS Remote API.
+
+ Attributes:
+ remote: An amarisoft client.
+ """
+
+ def __init__(self, remote: amarisoft_client.AmariSoftClient):
+ self.remote = remote
+
+ def make_call(self,
+ impi: str,
+ impu: str,
+ contact: str,
+ sip_file: str = 'mt_call_qos.sdp',
+ caller: str = 'Amarisoft',
+ duration: int = 30) -> None:
+ """Performs MT call from callbox to test device.
+
+ Args:
+ impi: IMPI (IP Multimedia Private identity) of user to call.
+ impu: IMPU (IP Multimedia Public identity) of user to call.
+ contact: Contact SIP uri of user to call.
+ sip_file: Define file to use as sdp.
+ caller: The number/ID is displayed as the caller.
+ duration: If set, call duration in seconds (The server will close the
+ dialog).
+ """
+ msg = {}
+ msg['message'] = 'mt_call'
+ msg['impi'] = impi
+ msg['impu'] = impu
+ msg['contact'] = contact
+ msg['sip_file'] = sip_file
+ msg['caller'] = caller
+ msg['duration'] = duration
+ dump_msg = json.dumps(msg)
+ logging.debug('mt_call dump msg = %s', dump_msg)
+ head, body = self.remote.send_message(const.PortNumber.URI_IMS, dump_msg)
+ self.remote.verify_response('mt_call', head, body)
+
+ def send_sms(self,
+ text: str,
+ impi: str,
+ sender: Optional[str] = 'Amarisoft') -> None:
+ """Sends SMS to assigned device which connect to Amarisoft.
+
+ Args:
+ text: SMS text to send.
+ impi: IMPI (IP Multimedia Private identity) of user.
+ sender: Sets SMS sender.
+ """
+ msg = {}
+ msg['message'] = 'sms'
+ msg['text'] = text
+ msg['impi'] = impi
+ msg['sender'] = sender
+ dump_msg = json.dumps(msg)
+ logging.debug('send_sms dump msg = %s', dump_msg)
+ head, body = self.remote.send_message(const.PortNumber.URI_IMS, dump_msg)
+ self.remote.verify_response('sms', head, body)
+
+ def send_mms(self, filename: str, sender: str, receiver: str) -> None:
+ """Sends MMS to assigned device which connect to Amarisoft.
+
+ Args:
+ filename: File name with absolute path to send. Extensions jpg, jpeg, png,
+ gif and txt are supported.
+ sender: IMPI (IP Multimedia Private identity) of user.
+ receiver: IMPU (IP Multimedia Public identity) of user.
+ """
+ msg = {}
+ msg['message'] = 'mms'
+ msg['filename'] = filename
+ msg['sender'] = sender
+ msg['receiver'] = receiver
+ dump_msg = json.dumps(msg)
+ logging.debug('send_mms dump msg = %s', dump_msg)
+ head, body = self.remote.send_message(const.PortNumber.URI_IMS, dump_msg)
+ self.remote.verify_response('mms', head, body)
+
+ def users_get(self, registered_only: bool = True) -> Mapping[str, Any]:
+ """Gets users state.
+
+ Args:
+ registered_only: If set, only registered user will be dumped.
+
+ Returns:
+ The user information.
+ """
+ msg = {}
+ msg['message'] = 'users_get'
+ msg['registered_only'] = registered_only
+ dump_msg = json.dumps(msg)
+ logging.debug('users_get dump msg = %s', dump_msg)
+ head, body = self.remote.send_message(const.PortNumber.URI_IMS, dump_msg)
+ _, loaded_body = self.remote.verify_response('users_get', head, body)
+ return loaded_body
+
+ def get_impu(self, impi) -> Union[str, None]:
+ """Obtains the IMPU of the target user according to IMPI.
+
+ Args:
+ impi: IMPI (IP Multimedia Private identity) of user to call. ex:
+ "310260123456785@ims.mnc260.mcc310.3gppnetwork.org"
+
+ Returns:
+ The IMPU of target user.
+ """
+ body = self.users_get(True)
+ for index in range(len(body['users'])):
+ if impi in body['users'][index]['impi']:
+ impu = body['users'][index]['bindings'][0]['impu'][1]
+ return impu
+ return None
+
+ def get_uri(self, impi) -> Union[str, None]:
+ """Obtains the URI of the target user according to IMPI.
+
+ Args:
+ impi: IMPI (IP Multimedia Private identity) of user to call. ex:
+ "310260123456785@ims.mnc260.mcc310.3gppnetwork.org"
+
+ Returns:
+ The URI of target user.
+ """
+ body = self.users_get(True)
+ for index in range(len(body['users'])):
+ if impi in body['users'][index]['impi']:
+ uri = body['users'][index]['bindings'][0]['uri']
+ return uri
+ return None
diff --git a/acts/framework/acts/controllers/amarisoft_lib/mme.py b/acts/framework/acts/controllers/amarisoft_lib/mme.py
new file mode 100644
index 0000000..58a6d4f
--- /dev/null
+++ b/acts/framework/acts/controllers/amarisoft_lib/mme.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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.
+
+import json
+import logging
+
+from acts.controllers.amarisoft_lib import amarisoft_constants as const
+from acts.controllers.amarisoft_lib import amarisoft_client
+
+
+class MmeFunctions():
+ """Utilities for Amarisoft's MME Remote API.
+
+ Attributes:
+ remote: An amarisoft client.
+ """
+
+ def __init__(self, remote: amarisoft_client.AmariSoftClient):
+ self.remote = remote
+
+ def pws_write(self, local_id: str, n50: bool = False):
+ """Broadcasts emergency alert message.
+
+ Args:
+ local_id: ID of the message as defined by local identifier in MME
+ configuration file.
+ n50: If True, N50 interface is used, otherwise SBC interface is used. (see TS 23.041)
+ """
+ msg = {}
+ msg['message'] = 'pws_write'
+ msg['local_id'] = local_id
+ msg['nf'] = n50
+ dump_msg = json.dumps(msg)
+ logging.debug('pws_write dump msg = %s', dump_msg)
+ head, body = self.remote.send_message(const.PortNumber.URI_MME, dump_msg)
+ self.remote.verify_response('pws_write', head, body)
+
+ def pws_kill(self, local_id: str, n50: bool = False):
+ """Stops broadcasts emergency alert message.
+
+ Args:
+ local_id: ID of the message as defined by local identifier in MME
+ configuration file.
+ n50: If True, N50 interface is used, otherwise SBC interface is used. (see TS 23.041)
+ """
+ msg = {}
+ msg['message'] = 'pws_kill'
+ msg['local_id'] = local_id
+ msg['nf'] = n50
+ dump_msg = json.dumps(msg)
+ logging.debug('pws_kill dump msg = %s', dump_msg)
+ head, body = self.remote.send_message(const.PortNumber.URI_MME, dump_msg)
+ self.remote.verify_response('pws_kill', head, body)
+
+ def ue_del(self, imsi: str):
+ """Remove UE from the UE database and force disconnect if necessary.
+
+ Args:
+ imsi: IMSI of the UE to delete.
+ """
+ msg = {}
+ msg['message'] = 'ue_del'
+ msg['imsi'] = imsi
+ dump_msg = json.dumps(msg)
+ logging.debug('ue_del dump msg = %s', dump_msg)
+ head, body = self.remote.send_message(const.PortNumber.URI_MME, dump_msg)
+ self.remote.verify_response('ue_del', head, body)
diff --git a/acts/framework/acts/controllers/amarisoft_lib/ssh_utils.py b/acts/framework/acts/controllers/amarisoft_lib/ssh_utils.py
new file mode 100644
index 0000000..a1673a5
--- /dev/null
+++ b/acts/framework/acts/controllers/amarisoft_lib/ssh_utils.py
@@ -0,0 +1,195 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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.
+
+import logging
+from typing import Sequence
+
+import paramiko
+
+COMMAND_RETRY_TIMES = 3
+
+
+class RunCommandError(Exception):
+ """Raises an error when run command fail."""
+
+
+class NotConnectedError(Exception):
+ """Raises an error when run command without SSH connect."""
+
+
+class RemoteClient:
+ """The SSH client class interacts with the test machine.
+
+ Attributes:
+ host: A string representing the IP address of amarisoft.
+ port: A string representing the default port of SSH.
+ username: A string representing the username of amarisoft.
+ password: A string representing the password of amarisoft.
+ ssh: A SSH client.
+ sftp: A SFTP client.
+ """
+
+ def __init__(self,
+ host: str,
+ username: str,
+ password: str,
+ port: str = '22') -> None:
+ self.host = host
+ self.port = port
+ self.username = username
+ self.password = password
+ self.ssh = paramiko.SSHClient()
+ self.sftp = None
+
+ def ssh_is_connected(self) -> bool:
+ """Checks SSH connect or not.
+
+ Returns:
+ True if SSH is connected, False otherwise.
+ """
+ return self.ssh and self.ssh.get_transport().is_active()
+
+ def ssh_close(self) -> bool:
+ """Closes the SSH connection.
+
+ Returns:
+ True if ssh session closed, False otherwise.
+ """
+ for _ in range(COMMAND_RETRY_TIMES):
+ if self.ssh_is_connected():
+ self.ssh.close()
+ else:
+ return True
+ return False
+
+ def connect(self) -> bool:
+ """Creats SSH connection.
+
+ Returns:
+ True if success, False otherwise.
+ """
+ for _ in range(COMMAND_RETRY_TIMES):
+ try:
+ self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ self.ssh.connect(self.host, self.port, self.username, self.password)
+ self.ssh.get_transport().set_keepalive(1)
+ self.sftp = paramiko.SFTPClient.from_transport(self.ssh.get_transport())
+ return True
+ except Exception: # pylint: disable=broad-except
+ self.ssh_close()
+ return False
+
+ def run_cmd(self, cmd: str) -> Sequence[str]:
+ """Runs shell command.
+
+ Args:
+ cmd: Command to be executed.
+
+ Returns:
+ Standard output of the shell command.
+
+ Raises:
+ RunCommandError: Raise error when command failed.
+ NotConnectedError: Raised when run command without SSH connect.
+ """
+ if not self.ssh_is_connected():
+ raise NotConnectedError('ssh remote has not been established')
+
+ logging.debug('ssh remote -> %s', cmd)
+ _, stdout, stderr = self.ssh.exec_command(cmd)
+ err = stderr.readlines()
+ if err:
+ logging.error('command failed.')
+ raise RunCommandError(err)
+ return stdout.readlines()
+
+ def is_file_exist(self, file: str) -> bool:
+ """Checks target file exist.
+
+ Args:
+ file: Target file with absolute path.
+
+ Returns:
+ True if file exist, false otherwise.
+ """
+ return any('exist' in line for line in self.run_cmd(
+ f'if [ -f "{file}" ]; then echo -e "exist"; fi'))
+
+ def sftp_upload(self, src: str, dst: str) -> bool:
+ """Uploads a local file to remote side.
+
+ Args:
+ src: The target file with absolute path.
+ dst: The absolute path to put the file with file name.
+ For example:
+ upload('/usr/local/google/home/zoeyliu/Desktop/sample_config.yml',
+ '/root/sample_config.yml')
+
+ Returns:
+ True if file upload success, False otherwise.
+
+ Raises:
+ NotConnectedError: Raised when run command without SSH connect.
+ """
+ if not self.ssh_is_connected():
+ raise NotConnectedError('ssh remote has not been established')
+ if not self.sftp:
+ raise NotConnectedError('sftp remote has not been established')
+
+ logging.info('[local] %s -> [remote] %s', src, dst)
+ self.sftp.put(src, dst)
+ return self.is_file_exist(dst)
+
+ def sftp_download(self, src: str, dst: str) -> bool:
+ """Downloads a file to local.
+
+ Args:
+ src: The target file with absolute path.
+ dst: The absolute path to put the file.
+
+ Returns:
+ True if file download success, False otherwise.
+
+ Raises:
+ NotConnectedError: Raised when run command without SSH connect.
+ """
+ if not self.ssh_is_connected():
+ raise NotConnectedError('ssh remote has not been established')
+ if not self.sftp:
+ raise NotConnectedError('sftp remote has not been established')
+
+ logging.info('[remote] %s -> [local] %s', src, dst)
+ self.sftp.get(src, dst)
+ return self.is_file_exist(dst)
+
+ def sftp_list_dir(self, path: str) -> Sequence[str]:
+ """Lists the names of the entries in the given path.
+
+ Args:
+ path: The path of the list.
+
+ Returns:
+ The names of the entries in the given path.
+
+ Raises:
+ NotConnectedError: Raised when run command without SSH connect.
+ """
+ if not self.ssh_is_connected():
+ raise NotConnectedError('ssh remote has not been established')
+ if not self.sftp:
+ raise NotConnectedError('sftp remote has not been established')
+ return sorted(self.sftp.listdir(path))
+
diff --git a/acts/framework/acts/controllers/android_device.py b/acts/framework/acts/controllers/android_device.py
index e5f568f..793cb23 100755
--- a/acts/framework/acts/controllers/android_device.py
+++ b/acts/framework/acts/controllers/android_device.py
@@ -19,6 +19,7 @@
import math
import os
import re
+import shutil
import socket
import time
from builtins import open
@@ -47,6 +48,10 @@
ACTS_CONTROLLER_REFERENCE_NAME = "android_devices"
ANDROID_DEVICE_PICK_ALL_TOKEN = "*"
+# Key name for SL4A extra params in config file
+ANDROID_DEVICE_SL4A_CLIENT_PORT_KEY = "sl4a_client_port"
+ANDROID_DEVICE_SL4A_FORWARDED_PORT_KEY = "sl4a_forwarded_port"
+ANDROID_DEVICE_SL4A_SERVER_PORT_KEY = "sl4a_server_port"
# Key name for adb logcat extra params in config file.
ANDROID_DEVICE_ADB_LOGCAT_PARAM_KEY = "adb_logcat_param"
ANDROID_DEVICE_EMPTY_CONFIG_MSG = "Configuration is empty, abort!"
@@ -56,8 +61,10 @@
"/data/vendor/ramdump/bluetooth", "/data/vendor/log/cbd")
CRASH_REPORT_SKIPS = ("RAMDUMP_RESERVED", "RAMDUMP_STATUS", "RAMDUMP_OUTPUT",
"bluetooth")
+ALWAYS_ON_LOG_PATH = "/data/vendor/radio/logs/always-on"
DEFAULT_QXDM_LOG_PATH = "/data/vendor/radio/diag_logs"
DEFAULT_SDM_LOG_PATH = "/data/vendor/slog/"
+DEFAULT_SCREENSHOT_PATH = "/sdcard/Pictures/screencap"
BUG_REPORT_TIMEOUT = 1800
PULL_TIMEOUT = 300
PORT_RETRY_COUNT = 3
@@ -232,12 +239,41 @@
raise errors.AndroidDeviceConfigError(
"Required value 'serial' is missing in AndroidDevice config %s."
% c)
+ client_port = 0
+ if ANDROID_DEVICE_SL4A_CLIENT_PORT_KEY in c:
+ try:
+ client_port = int(c.pop(ANDROID_DEVICE_SL4A_CLIENT_PORT_KEY))
+ except ValueError:
+ raise errors.AndroidDeviceConfigError(
+ "'%s' is not a valid number for config %s" %
+ (ANDROID_DEVICE_SL4A_CLIENT_PORT_KEY, c))
+ server_port = None
+ if ANDROID_DEVICE_SL4A_SERVER_PORT_KEY in c:
+ try:
+ server_port = int(c.pop(ANDROID_DEVICE_SL4A_SERVER_PORT_KEY))
+ except ValueError:
+ raise errors.AndroidDeviceConfigError(
+ "'%s' is not a valid number for config %s" %
+ (ANDROID_DEVICE_SL4A_SERVER_PORT_KEY, c))
+ forwarded_port = 0
+ if ANDROID_DEVICE_SL4A_FORWARDED_PORT_KEY in c:
+ try:
+ forwarded_port = int(
+ c.pop(ANDROID_DEVICE_SL4A_FORWARDED_PORT_KEY))
+ except ValueError:
+ raise errors.AndroidDeviceConfigError(
+ "'%s' is not a valid number for config %s" %
+ (ANDROID_DEVICE_SL4A_FORWARDED_PORT_KEY, c))
ssh_config = c.pop('ssh_config', None)
ssh_connection = None
if ssh_config is not None:
ssh_settings = settings.from_config(ssh_config)
ssh_connection = connection.SshConnection(ssh_settings)
- ad = AndroidDevice(serial, ssh_connection=ssh_connection)
+ ad = AndroidDevice(serial,
+ ssh_connection=ssh_connection,
+ client_port=client_port,
+ forwarded_port=forwarded_port,
+ server_port=server_port)
ad.load_config(c)
results.append(ad)
return results
@@ -357,14 +393,27 @@
adb: An AdbProxy object used for interacting with the device via adb.
fastboot: A FastbootProxy object used for interacting with the device
via fastboot.
+ client_port: Preferred client port number on the PC host side for SL4A
+ forwarded_port: Preferred server port number forwarded from Android
+ to the host PC via adb for SL4A connections
+ server_port: Preferred server port used by SL4A on Android device
+
"""
- def __init__(self, serial='', ssh_connection=None):
+ def __init__(self,
+ serial='',
+ ssh_connection=None,
+ client_port=0,
+ forwarded_port=0,
+ server_port=None):
self.serial = serial
# logging.log_path only exists when this is used in an ACTS test run.
log_path_base = getattr(logging, 'log_path', '/tmp/logs')
self.log_dir = 'AndroidDevice%s' % serial
self.log_path = os.path.join(log_path_base, self.log_dir)
+ self.client_port = client_port
+ self.forwarded_port = forwarded_port
+ self.server_port = server_port
self.log = tracelogger.TraceLogger(
AndroidDeviceLoggerAdapter(logging.getLogger(),
{'serial': serial}))
@@ -374,15 +423,15 @@
self.register_service(services.Sl4aService(self))
self.adb_logcat_process = None
self.adb = adb.AdbProxy(serial, ssh_connection=ssh_connection)
- self.fastboot = fastboot.FastbootProxy(
- serial, ssh_connection=ssh_connection)
+ self.fastboot = fastboot.FastbootProxy(serial,
+ ssh_connection=ssh_connection)
if not self.is_bootloader:
self.root_adb()
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)
+ self._sl4a_manager = sl4a_manager.create_sl4a_manager(self.adb)
self.last_logcat_timestamp = None
# Device info cache.
self._user_added_device_info = {}
@@ -399,6 +448,34 @@
if self._ssh_connection:
self._ssh_connection.close()
+ def recreate_services(self, serial):
+ """Clean up the AndroidDevice object and re-create adb/sl4a services.
+
+ Unregister the existing services and re-create adb and sl4a services,
+ call this method when the connection break after certain API call
+ (e.g., enable USB tethering by #startTethering)
+
+ Args:
+ serial: the serial number of the AndroidDevice
+ """
+ # Clean the old services
+ for service in self._services:
+ service.unregister()
+ self._services.clear()
+ if self._ssh_connection:
+ self._ssh_connection.close()
+ self._sl4a_manager.stop_service()
+
+ # Wait for old services to stop
+ time.sleep(5)
+
+ # Re-create the new adb and sl4a services
+ self.register_service(services.AdbLogcatService(self))
+ self.register_service(services.Sl4aService(self))
+ self.adb.wait_for_device()
+ self.terminate_all_sessions()
+ self.start_services()
+
def register_service(self, service):
"""Registers the service on the device. """
service.register()
@@ -425,8 +502,8 @@
Stop adb logcat and terminate sl4a sessions if exist.
"""
- event_bus.post(
- android_events.AndroidStopServicesEvent(self), ignore_errors=True)
+ event_bus.post(android_events.AndroidStopServicesEvent(self),
+ ignore_errors=True)
def is_connected(self):
out = self.adb.devices()
@@ -651,7 +728,13 @@
>>> ad = AndroidDevice()
>>> droid, ed = ad.get_droid()
"""
- session = self._sl4a_manager.create_session()
+ self.log.debug(
+ "Creating RPC client_port={}, forwarded_port={}, server_port={}".
+ format(self.client_port, self.forwarded_port, self.server_port))
+ session = self._sl4a_manager.create_session(
+ client_port=self.client_port,
+ forwarded_port=self.forwarded_port,
+ server_port=self.server_port)
droid = session.rpc_client
if handle_event:
ed = session.get_event_dispatcher()
@@ -671,9 +754,8 @@
"""
for cmd in ("ps -A", "ps"):
try:
- out = self.adb.shell(
- '%s | grep "S %s"' % (cmd, package_name),
- ignore_status=True)
+ out = self.adb.shell('%s | grep "S %s"' % (cmd, package_name),
+ ignore_status=True)
if package_name not in out:
continue
try:
@@ -683,11 +765,11 @@
except (IndexError, ValueError) as e:
# Possible ValueError from string to int cast.
# Possible IndexError from split.
- self.log.warn(
+ self.log.warning(
'Command \"%s\" returned output line: '
'\"%s\".\nError: %s', cmd, out, e)
except Exception as e:
- self.log.warn(
+ self.log.warning(
'Device fails to check if %s running with \"%s\"\n'
'Exception %s', package_name, cmd, e)
self.log.debug("apk %s is not running", package_name)
@@ -765,10 +847,10 @@
return adb_excerpt_path
def search_logcat(self,
- matching_string,
- begin_time=None,
- end_time=None,
- logcat_path=None):
+ matching_string,
+ begin_time=None,
+ end_time=None,
+ logcat_path=None):
"""Search logcat message with given string.
Args:
@@ -798,13 +880,12 @@
"""
if not logcat_path:
logcat_path = os.path.join(self.device_log_path,
- 'adblog_%s_debug.txt' % self.serial)
+ 'adblog_%s_debug.txt' % self.serial)
if not os.path.exists(logcat_path):
self.log.warning("Logcat file %s does not exist." % logcat_path)
return
- output = job.run(
- "grep '%s' %s" % (matching_string, logcat_path),
- ignore_status=True)
+ output = job.run("grep '%s' %s" % (matching_string, logcat_path),
+ ignore_status=True)
if not output.stdout or output.exit_status != 0:
return []
if begin_time:
@@ -812,13 +893,13 @@
log_begin_time = acts_logger.epoch_to_log_line_timestamp(
begin_time)
begin_time = datetime.strptime(log_begin_time,
- "%Y-%m-%d %H:%M:%S.%f")
+ "%Y-%m-%d %H:%M:%S.%f")
if end_time:
if not isinstance(end_time, datetime):
log_end_time = acts_logger.epoch_to_log_line_timestamp(
end_time)
end_time = datetime.strptime(log_end_time,
- "%Y-%m-%d %H:%M:%S.%f")
+ "%Y-%m-%d %H:%M:%S.%f")
result = []
logs = re.findall(r'(\S+\s\S+)(.*)', output.stdout)
for log in logs:
@@ -850,7 +931,7 @@
save the logcat in a file.
"""
if self.is_adb_logcat_on:
- self.log.warn(
+ self.log.warning(
'Android device %s already has a running adb logcat thread. ' %
self.serial)
return
@@ -871,7 +952,7 @@
"""Stops the adb logcat collection subprocess.
"""
if not self.is_adb_logcat_on:
- self.log.warn(
+ self.log.warning(
'Android device %s does not have an ongoing adb logcat ' %
self.serial)
return
@@ -890,14 +971,37 @@
Returns:
Linux UID for the apk.
"""
- output = self.adb.shell(
- "dumpsys package %s | grep userId=" % apk_name, ignore_status=True)
+ output = self.adb.shell("dumpsys package %s | grep userId=" % apk_name,
+ ignore_status=True)
result = re.search(r"userId=(\d+)", output)
if result:
return result.group(1)
else:
None
+ @record_api_usage
+ def get_apk_version(self, package_name):
+ """Get the version of the given apk.
+
+ Args:
+ package_name: Name of the package, e.g., com.android.phone.
+
+ Returns:
+ Version of the given apk.
+ """
+ try:
+ output = self.adb.shell("dumpsys package %s | grep versionName" %
+ package_name)
+ pattern = re.compile(r"versionName=(.+)", re.I)
+ result = pattern.findall(output)
+ if result:
+ return result[0]
+ except Exception as e:
+ self.log.warning("Fail to get the version of package %s: %s",
+ package_name, e)
+ self.log.debug("apk %s is not found", package_name)
+ return None
+
def is_apk_installed(self, package_name):
"""Check if the given apk is already installed.
@@ -934,14 +1038,13 @@
"""
for cmd in ("ps -A", "ps"):
try:
- out = self.adb.shell(
- '%s | grep "S %s"' % (cmd, package_name),
- ignore_status=True)
+ out = self.adb.shell('%s | grep "S %s"' % (cmd, package_name),
+ ignore_status=True)
if package_name in out:
self.log.info("apk %s is running", package_name)
return True
except Exception as e:
- self.log.warn(
+ self.log.warning(
"Device fails to check is %s running by %s "
"Exception %s", package_name, cmd, e)
continue
@@ -961,17 +1064,10 @@
True if package is installed. False otherwise.
"""
try:
- self.adb.shell(
- 'am force-stop %s' % package_name, ignore_status=True)
+ self.adb.shell('am force-stop %s' % package_name,
+ ignore_status=True)
except Exception as e:
- self.log.warn("Fail to stop package %s: %s", package_name, e)
-
- def stop_sl4a(self):
- # TODO(markdr): Move this into sl4a_manager.
- return self.force_stop_apk(SL4A_APK_NAME)
-
- def start_sl4a(self):
- self._sl4a_manager.start_sl4a_service()
+ self.log.warning("Fail to stop package %s: %s", package_name, e)
def take_bug_report(self, test_name, begin_time):
"""Takes a bug report on the device and stores it in a file.
@@ -1010,8 +1106,8 @@
br_out_path = out.split(':')[1].strip().split()[0]
self.adb.pull("%s %s" % (br_out_path, full_out_path))
else:
- self.adb.bugreport(
- " > {}".format(full_out_path), timeout=BUG_REPORT_TIMEOUT)
+ self.adb.bugreport(" > {}".format(full_out_path),
+ timeout=BUG_REPORT_TIMEOUT)
self.log.info("Bugreport for %s taken at %s.", test_name,
full_out_path)
self.adb.wait_for_device(timeout=WAIT_FOR_DEVICE_TIMEOUT)
@@ -1073,10 +1169,10 @@
if not host_path:
host_path = self.log_path
for device_path in device_paths:
- self.log.info(
- 'Pull from device: %s -> %s' % (device_path, host_path))
- self.adb.pull(
- "%s %s" % (device_path, host_path), timeout=PULL_TIMEOUT)
+ self.log.info('Pull from device: %s -> %s' %
+ (device_path, host_path))
+ self.adb.pull("%s %s" % (device_path, host_path),
+ timeout=PULL_TIMEOUT)
def check_crash_report(self,
test_name=None,
@@ -1091,10 +1187,9 @@
except Exception as e:
self.log.debug("received exception %s", e)
continue
- crashes = self.get_file_names(
- crash_path,
- skip_files=CRASH_REPORT_SKIPS,
- begin_time=begin_time)
+ 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:
@@ -1117,18 +1212,23 @@
# Sleep 10 seconds for the buffered log to be written in qxdm log file
time.sleep(10)
log_path = getattr(self, "qxdm_log_path", DEFAULT_QXDM_LOG_PATH)
- qxdm_logs = self.get_file_names(
- log_path, begin_time=begin_time, match_string="*.qmdl")
+ qxdm_logs = self.get_file_names(log_path,
+ begin_time=begin_time,
+ match_string="*.qmdl")
if qxdm_logs:
qxdm_log_path = os.path.join(self.device_log_path,
"QXDM_%s" % self.serial)
os.makedirs(qxdm_log_path, exist_ok=True)
+
self.log.info("Pull QXDM Log %s to %s", qxdm_logs, qxdm_log_path)
self.pull_files(qxdm_logs, qxdm_log_path)
- self.adb.pull(
- "/firmware/image/qdsp6m.qdb %s" % qxdm_log_path,
- timeout=PULL_TIMEOUT,
- ignore_status=True)
+
+ self.adb.pull("/firmware/image/qdsp6m.qdb %s" % qxdm_log_path,
+ timeout=PULL_TIMEOUT,
+ ignore_status=True)
+ # Zip Folder
+ utils.zip_directory('%s.zip' % qxdm_log_path, qxdm_log_path)
+ shutil.rmtree(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"):
@@ -1146,9 +1246,15 @@
"""Get sdm logs."""
# Sleep 10 seconds for the buffered log to be written in sdm log file
time.sleep(10)
- log_path = getattr(self, "sdm_log_path", DEFAULT_SDM_LOG_PATH)
- sdm_logs = self.get_file_names(
- log_path, begin_time=begin_time, match_string="*.sdm*")
+ log_paths = [
+ ALWAYS_ON_LOG_PATH,
+ getattr(self, "sdm_log_path", DEFAULT_SDM_LOG_PATH)
+ ]
+ sdm_logs = []
+ for path in log_paths:
+ sdm_logs += self.get_file_names(path,
+ begin_time=begin_time,
+ match_string="*.sdm*")
if sdm_logs:
sdm_log_path = os.path.join(self.device_log_path,
"SDM_%s" % self.serial)
@@ -1234,8 +1340,8 @@
status: true if iperf client start successfully.
results: results have data flow information
"""
- out = self.adb.shell(
- "iperf3 -c {} {}".format(server_host, extra_args), timeout=timeout)
+ out = self.adb.shell("iperf3 -c {} {}".format(server_host, extra_args),
+ timeout=timeout)
clean_out = out.split('\n')
if "error" in clean_out[0].lower():
return False, clean_out
@@ -1286,7 +1392,9 @@
'Device %s booting process timed out.' % self.serial,
serial=self.serial)
- def reboot(self, stop_at_lock_screen=False, timeout=180,
+ def reboot(self,
+ stop_at_lock_screen=False,
+ timeout=180,
wait_after_reboot_complete=1):
"""Reboots the device.
@@ -1323,8 +1431,8 @@
# want the device to be missing to prove the device has kicked
# off the reboot.
break
- self.wait_for_boot_completion(
- timeout=(timeout - time.time() + timeout_start))
+ self.wait_for_boot_completion(timeout=(timeout - time.time() +
+ timeout_start))
self.log.debug('Wait for a while after boot completion.')
time.sleep(wait_after_reboot_complete)
@@ -1359,8 +1467,8 @@
break
except adb.AdbError as e:
if timer + 1 == timeout:
- self.log.warning(
- 'Unable to find IP address for %s.' % interface)
+ self.log.warning('Unable to find IP address for %s.' %
+ interface)
return None
else:
time.sleep(1)
@@ -1406,10 +1514,9 @@
def get_my_current_focus_window(self):
"""Get the current focus window on screen"""
output = self.adb.shell(
- 'dumpsys window displays | grep -E mCurrentFocus',
+ 'dumpsys window displays | grep -E mCurrentFocus | grep -v null',
ignore_status=True)
- if not output or "not found" in output or "Can't find" in output or (
- "mCurrentFocus=null" in output):
+ if not output or "not found" in output or "Can't find" in output:
result = ''
else:
result = output.split(' ')[-1].strip("}")
@@ -1426,7 +1533,7 @@
for cmd in dumpsys_cmd:
output = self.adb.shell(cmd, ignore_status=True)
if not output or "not found" in output or "Can't find" in output or (
- "mFocusedApp=null" in output):
+ "mFocusedApp=null" in output):
result = ''
else:
result = output.split(' ')[-2]
@@ -1483,16 +1590,9 @@
@record_api_usage
def is_screen_lock_enabled(self):
"""Check if screen lock is enabled"""
- cmd = ("sqlite3 /data/system/locksettings.db .dump"
- " | grep lockscreen.password_type | grep -v alternate")
+ cmd = ("dumpsys window policy | grep showing=")
out = self.adb.shell(cmd, ignore_status=True)
- if "unable to open" in out:
- self.root_adb()
- out = self.adb.shell(cmd, ignore_status=True)
- if ",0,'0'" not in out and out != "":
- self.log.info("Screen lock is enabled")
- return True
- return False
+ return "true" in out
@record_api_usage
def is_waiting_for_unlock_pin(self):
@@ -1558,6 +1658,23 @@
self.send_keycode("BACK")
@record_api_usage
+ def screenshot(self, name=""):
+ """Take a screenshot on the device.
+
+ Args:
+ name: additional information of screenshot on the file name.
+ """
+ if name:
+ file_name = "%s_%s" % (DEFAULT_SCREENSHOT_PATH, name)
+ file_name = "%s_%s.png" % (file_name, utils.get_current_epoch_time())
+ self.ensure_screen_on()
+ self.log.info("Log screenshot to %s", file_name)
+ try:
+ self.adb.shell("screencap -p %s" % file_name)
+ except:
+ self.log.error("Fail to log screenshot to %s", file_name)
+
+ @record_api_usage
def exit_setup_wizard(self):
# Handling Android TV's setupwizard is ignored for now.
if 'feature:android.hardware.type.television' in self.adb.shell(
@@ -1565,11 +1682,11 @@
return
if not self.is_user_setup_complete() or self.is_setupwizard_on():
# b/116709539 need this to prevent reboot after skip setup wizard
- self.adb.shell(
- "am start -a com.android.setupwizard.EXIT", ignore_status=True)
- self.adb.shell(
- "pm disable %s" % self.get_setupwizard_package_name(),
- ignore_status=True)
+ self.adb.shell("am start -a com.android.setupwizard.EXIT",
+ ignore_status=True)
+ self.adb.shell("pm disable %s" %
+ self.get_setupwizard_package_name(),
+ ignore_status=True)
# Wait up to 5 seconds for user_setup_complete to be updated
end_time = time.time() + 5
while time.time() < end_time:
@@ -1619,8 +1736,8 @@
try:
self.ensure_verity_disabled()
self.adb.remount()
- out = self.adb.push(
- '%s %s' % (src_file_path, dst_file_path), timeout=push_timeout)
+ out = self.adb.push('%s %s' % (src_file_path, dst_file_path),
+ timeout=push_timeout)
if 'error' in out:
self.log.error('Unable to push system file %s to %s due to %s',
src_file_path, dst_file_path, out)
diff --git a/acts/framework/acts/controllers/android_lib/services.py b/acts/framework/acts/controllers/android_lib/services.py
index f4ff20b..42998f7 100644
--- a/acts/framework/acts/controllers/android_lib/services.py
+++ b/acts/framework/acts/controllers/android_lib/services.py
@@ -108,4 +108,3 @@
def _stop(self, _):
self.ad.terminate_all_sessions()
self.ad._sl4a_manager.stop_service()
- self.ad.stop_sl4a()
diff --git a/acts/framework/acts/controllers/anritsu_lib/md8475_cellular_simulator.py b/acts/framework/acts/controllers/anritsu_lib/md8475_cellular_simulator.py
index eea1c8a..a1b15db 100644
--- a/acts/framework/acts/controllers/anritsu_lib/md8475_cellular_simulator.py
+++ b/acts/framework/acts/controllers/anritsu_lib/md8475_cellular_simulator.py
@@ -86,41 +86,15 @@
self.anritsu.load_simulation_paramfile(sim_file_path)
self.anritsu.load_cell_paramfile(cell_file_path)
- self.anritsu.start_simulation()
- self.bts = [self.anritsu.get_BTS(md8475a.BtsNumber.BTS1)]
-
- self.num_carriers = 1
-
- def setup_lte_ca_scenario(self):
- """ Configures the equipment for an LTE with CA simulation. """
- cell_file_name = self.LTE_CA_BASIC_CELL_FILE
- sim_file_name = self.LTE_CA_BASIC_SIM_FILE
-
- cell_file_path = ntpath.join(self.CALLBOX_CONFIG_PATH, cell_file_name)
- sim_file_path = ntpath.join(self.CALLBOX_CONFIG_PATH, sim_file_name)
-
- # Load the simulation config file
- self.anritsu.load_simulation_paramfile(sim_file_path)
-
- # Enable all LTE base stations. This is needed so that base settings
- # can be applied.
- self.anritsu.set_simulation_model(
- *[md8475a.BtsTechnology.LTE for _ in range(self.LTE_MAX_CARRIERS)],
- reset=False)
-
- # Load cell settings
- self.anritsu.load_cell_paramfile(cell_file_path)
-
- self.anritsu.start_simulation()
-
+ # MD4875A supports only 2 carriers. The MD4875B class adds other cells.
self.bts = [
self.anritsu.get_BTS(md8475a.BtsNumber.BTS1),
self.anritsu.get_BTS(md8475a.BtsNumber.BTS2)
]
- def set_ca_combination(self, combination):
- """ Prepares the test equipment for the indicated CA combination.
+ def set_band_combination(self, bands):
+ """ Prepares the test equipment for the indicated band combination.
The reason why this is implemented in a separate method and not calling
LteSimulation.BtsConfig for each separate band is that configuring each
@@ -129,40 +103,8 @@
be shared in the test equipment.
Args:
- combination: carrier aggregation configurations are indicated
- with a list of strings consisting of the band number followed
- by the CA class. For example, for 5 CA using 3C 7C and 28A
- the parameter value should be [3c, 7c, 28a].
+ bands: a list of bands represented as ints or strings
"""
-
- # Obtain the list of bands from the carrier combination list
- bands = []
-
- for ca in combination:
- ca_class = ca[-1]
- band = ca[:-1]
-
- # If the band appears twice in the combo it means that carriers
- # must be in the same band but non contiguous.
- if band in bands:
- raise cc.CellularSimulatorError(
- 'Intra-band non-contiguous carrier aggregation is not '
- 'supported.')
-
- if ca_class.upper() == 'B':
- raise cc.CellularSimulatorError(
- 'Class B carrier aggregation is not supported')
- elif ca_class.upper() == 'A':
- bands.append(band)
- elif ca_class.upper() == 'C':
- # Class C means two contiguous carriers in the same band, so
- # add the band twice to the list.
- bands.append(band)
- bands.append(band)
- else:
- raise cc.CellularSimulatorError('Invalid carrier aggregation '
- 'configuration: ' + ca)
-
self.num_carriers = len(bands)
# Validate the number of carriers.
@@ -170,10 +112,6 @@
raise cc.CellularSimulatorError('The test equipment supports up '
'to {} carriers.'.format(
self.LTE_MAX_CARRIERS))
- elif self.num_carriers < 2:
- raise cc.CellularSimulatorError('At least two carriers need to be '
- 'indicated for the carrier '
- 'aggregation simulation.')
# Initialize the base stations in the test equipment
self.anritsu.set_simulation_model(
@@ -187,7 +125,7 @@
# both base stations.
self.bts[0].mimo_support = md8475a.LteMimoMode.MIMO_4X4
self.bts[1].mimo_support = md8475a.LteMimoMode.MIMO_4X4
- if self.num_carriers == 3:
+ elif self.num_carriers == 3:
# 4X4 can only be done in the second base station if it is shared
# with the primary. If the RF cards cannot be shared, then at most
# 2X2 can be done.
@@ -197,17 +135,17 @@
else:
self.bts[1].mimo_support = md8475a.LteMimoMode.MIMO_2X2
self.bts[2].mimo_support = md8475a.LteMimoMode.MIMO_2X2
+ elif self.num_carriers > 3:
+ raise NotImplementedError('The controller doesn\'t implement more '
+ 'than 3 carriers for MD8475B yet.')
- # Enable carrier aggregation
- self.anritsu.set_carrier_aggregation_enabled()
+ # Enable carrier aggregation if there is more than one carrier
+ if self.num_carriers > 1:
+ self.anritsu.set_carrier_aggregation_enabled()
# Restart the simulation as changing the simulation model will stop it.
self.anritsu.start_simulation()
- # Set the bands in each base station
- for bts_index in range(len(bands)):
- self.set_band(bts_index, bands[bts_index])
-
def set_input_power(self, bts_index, input_power):
""" Sets the input power for the indicated base station.
@@ -245,36 +183,40 @@
# Temporarily adding this line to workaround a bug in the
# Anritsu callbox in which the channel number needs to be set
# to a different value before setting it to the final one.
- self.bts[bts_index].dl_channel = str(channel_number + 1)
+ self.bts[bts_index].dl_channel = str(int(channel_number + 1))
time.sleep(8)
- self.bts[bts_index].dl_channel = str(channel_number)
+ self.bts[bts_index].dl_channel = str(int(channel_number))
- def set_dl_modulation(self, bts_index, modulation):
- """ Sets the DL modulation for the indicated base station.
+ def set_dl_256_qam_enabled(self, bts_index, enabled):
+ """ Determines what MCS table should be used for the downlink.
Args:
bts_index: the base station number
- modulation: the new DL modulation
+ enabled: whether 256 QAM should be used
"""
- self.bts[bts_index].lte_dl_modulation_order = modulation.value
+ if enabled and not self.LTE_SUPPORTS_DL_256QAM:
+ raise RuntimeError('256 QAM is not supported')
+ self.bts[bts_index].lte_dl_modulation_order = \
+ md8475a.ModulationType.Q256 if enabled else md8475a.ModulationType.Q64
- def set_ul_modulation(self, bts_index, modulation):
- """ Sets the UL modulation for the indicated base station.
+ def set_ul_64_qam_enabled(self, bts_index, enabled):
+ """ Determines what MCS table should be used for the uplink.
Args:
bts_index: the base station number
- modulation: the new UL modulation
+ enabled: whether 64 QAM should be used
"""
- self.bts[bts_index].lte_ul_modulation_order = modulation.value
+ self.bts[bts_index].lte_ul_modulation_order = \
+ md8475a.ModulationType.Q64 if enabled else md8475a.ModulationType.Q16
- def set_tbs_pattern_on(self, bts_index, tbs_pattern_on):
- """ Enables or disables TBS pattern in the indicated base station.
+ def set_mac_padding(self, bts_index, mac_padding):
+ """ Enables or disables MAC padding in the indicated base station.
Args:
bts_index: the base station number
- tbs_pattern_on: the new TBS pattern setting
+ mac_padding: the new MAC padding setting
"""
- if tbs_pattern_on:
+ if mac_padding:
self.bts[bts_index].tbs_pattern = 'FULLALLOCATION'
else:
self.bts[bts_index].tbs_pattern = 'OFF'
@@ -515,7 +457,8 @@
"number of DL antennas will override this "
"setting.")
bts.dl_antenna = 2
- elif mimo == LteSimulation.MimoMode.MIMO_4x4:
+ elif mimo == LteSimulation.MimoMode.MIMO_4x4 and \
+ self.LTE_SUPPORTS_4X4_MIMO:
if bts.transmode not in [
LteSimulation.TransmissionMode.TM2,
LteSimulation.TransmissionMode.TM3,
@@ -689,6 +632,11 @@
def detach(self):
""" Turns off all the base stations so the DUT loose connection."""
+ if self.anritsu.get_smartstudio_status() == \
+ md8475a.ProcessingStatus.PROCESS_STATUS_NOTRUN.value:
+ self.log.info('Device cannot be detached because simulation is '
+ 'not running.')
+ return
self.anritsu.set_simulation_state_to_poweroff()
def stop(self):
@@ -772,10 +720,10 @@
# formatted to replace {} with either A or B depending on the model.
CALLBOX_CONFIG_PATH = 'C:\\Users\\MD8475B\\Documents\\DAN_configs\\'
- def setup_lte_ca_scenario(self):
+ def setup_lte_scenario(self):
""" The B model can support up to five carriers. """
- super().setup_lte_ca_scenario()
+ super().setup_lte_scenario()
self.bts.extend([
self.anritsu.get_BTS(md8475a.BtsNumber.BTS3),
diff --git a/acts/framework/acts/controllers/anritsu_lib/md8475a.py b/acts/framework/acts/controllers/anritsu_lib/md8475a.py
index ffaade4..2f2865f 100644
--- a/acts/framework/acts/controllers/anritsu_lib/md8475a.py
+++ b/acts/framework/acts/controllers/anritsu_lib/md8475a.py
@@ -449,6 +449,13 @@
DISABLE = "DISABLE"
+class ModulationType(Enum):
+ """Supported Modulation Types."""
+ Q16 = '16QAM'
+ Q64 = '64QAM'
+ Q256 = '256QAM'
+
+
class MD8475A(object):
"""Class to communicate with Anritsu MD8475A Signalling Tester.
This uses GPIB command to interface with Anritsu MD8475A """
@@ -3350,6 +3357,8 @@
Returns:
None
"""
+ if isinstance(order, ModulationType):
+ order = order.value
cmd = "DLRMC_MOD {},{}".format(order, self._bts_number)
self._anritsu.send_command(cmd)
@@ -3376,6 +3385,8 @@
Returns:
None
"""
+ if isinstance(order, ModulationType):
+ order = order.value
cmd = "ULRMC_MOD {},{}".format(order, self._bts_number)
self._anritsu.send_command(cmd)
diff --git a/acts/framework/acts/controllers/ap_lib/ap_get_interface.py b/acts/framework/acts/controllers/ap_lib/ap_get_interface.py
index 2a801ec..2a206b5 100644
--- a/acts/framework/acts/controllers/ap_lib/ap_get_interface.py
+++ b/acts/framework/acts/controllers/ap_lib/ap_get_interface.py
@@ -30,13 +30,15 @@
"""Class to get network interface information for the device.
"""
- def __init__(self, ap):
+ def __init__(self, ap, wan_interface_override=None):
"""Initialize the ApInterface class.
Args:
ap: the ap object within ACTS
+ wan_interface_override: wan interface to use if specified by config
"""
self.ssh = ap.ssh
+ self.wan_interface_override = wan_interface_override
def get_all_interface(self):
"""Get all network interfaces on the device.
@@ -120,13 +122,17 @@
raise ApInterfacesError('Missing at least one WLAN interface')
def get_wan_interface(self):
- """Get the WAN interface which has internet connectivity.
+ """Get the WAN interface which has internet connectivity. If a wan
+ interface is already specified return that instead.
Returns:
wan: the only one WAN interface
Raises:
ApInterfacesError: no running WAN can be found
"""
+ if self.wan_interface_override:
+ return self.wan_interface_override
+
wan = None
interfaces_phy = self.get_physical_interface()
interfaces_wlan = self.get_wlan_interface()
diff --git a/acts/framework/acts/controllers/ap_lib/dhcp_config.py b/acts/framework/acts/controllers/ap_lib/dhcp_config.py
index ddf6ac1..ffc9db1 100644
--- a/acts/framework/acts/controllers/ap_lib/dhcp_config.py
+++ b/acts/framework/acts/controllers/ap_lib/dhcp_config.py
@@ -16,6 +16,8 @@
import copy
import ipaddress
+_ROUTER_DNS = '8.8.8.8, 4.4.4.4'
+
class Subnet(object):
"""Configs for a subnet on the dhcp server.
@@ -25,7 +27,9 @@
start: ipaddress.IPv4Address, the start ip address.
end: ipaddress.IPv4Address, the end ip address.
router: The router to give to all hosts in this subnet.
- lease: The lease time of all hosts in this subnet.
+ lease_time: The lease time of all hosts in this subnet.
+ additional_parameters: A dictionary corresponding to DHCP parameters.
+ additional_options: A dictionary corresponding to DHCP options.
"""
def __init__(self,
@@ -33,20 +37,26 @@
start=None,
end=None,
router=None,
- lease_time=None):
+ lease_time=None,
+ additional_parameters={},
+ additional_options={}):
"""
Args:
- subnet_address: ipaddress.IPv4Network, The network that this
- subnet is.
+ subnet: ipaddress.IPv4Network, The address space of the subnetwork
+ served by the DHCP server.
start: ipaddress.IPv4Address, The start of the address range to
- give hosts in this subnet. If not given then the first ip in
- the network is used.
+ give hosts in this subnet. If not given, the second ip in
+ the network is used, under the assumption that the first
+ address is the router.
end: ipaddress.IPv4Address, The end of the address range to give
- hosts. If not given then the last ip in the network is used.
+ hosts. If not given then the address prior to the broadcast
+ address (i.e. the second to last ip in the network) is used.
router: ipaddress.IPv4Address, The router hosts should use in this
subnet. If not given the first ip in the network is used.
lease_time: int, The amount of lease time in seconds
hosts in this subnet have.
+ additional_parameters: A dictionary corresponding to DHCP parameters.
+ additional_options: A dictionary corresponding to DHCP options.
"""
self.network = subnet
@@ -83,6 +93,10 @@
else:
# TODO: Use some more clever logic so that we don't have to search
# every host potentially.
+ # This is especially important if we support IPv6 networks in this
+ # configuration. The improved logic that we can use is:
+ # a) erroring out if start and end encompass the whole network, and
+ # b) picking any address before self.start or after self.end.
self.router = None
for host in self.network.hosts():
if host < self.start or host > self.end:
@@ -93,6 +107,10 @@
raise ValueError('No useable host found.')
self.lease_time = lease_time
+ self.additional_parameters = additional_parameters
+ self.additional_options = additional_options
+ if 'domain-name-servers' not in self.additional_options:
+ self.additional_options['domain-name-servers'] = _ROUTER_DNS
class StaticMapping(object):
@@ -131,3 +149,57 @@
if static_mappings else [])
self.default_lease_time = default_lease_time
self.max_lease_time = max_lease_time
+
+ def render_config_file(self):
+ """Renders the config parameters into a format compatible with
+ the ISC DHCP server (dhcpd).
+ """
+ lines = []
+
+ if self.default_lease_time:
+ lines.append('default-lease-time %d;' % self.default_lease_time)
+ if self.max_lease_time:
+ lines.append('max-lease-time %s;' % self.max_lease_time)
+
+ for subnet in self.subnets:
+ address = subnet.network.network_address
+ mask = subnet.network.netmask
+ router = subnet.router
+ start = subnet.start
+ end = subnet.end
+ lease_time = subnet.lease_time
+ additional_parameters = subnet.additional_parameters
+ additional_options = subnet.additional_options
+
+ lines.append('subnet %s netmask %s {' % (address, mask))
+ lines.append('\tpool {')
+ lines.append('\t\toption subnet-mask %s;' % mask)
+ lines.append('\t\toption routers %s;' % router)
+ lines.append('\t\trange %s %s;' % (start, end))
+ if lease_time:
+ lines.append('\t\tdefault-lease-time %d;' % lease_time)
+ lines.append('\t\tmax-lease-time %d;' % lease_time)
+ for param, value in additional_parameters.items():
+ lines.append('\t\t%s %s;' % (param, value))
+ for option, value in additional_options.items():
+ lines.append('\t\toption %s %s;' % (option, value))
+ lines.append('\t}')
+ lines.append('}')
+
+ for mapping in self.static_mappings:
+ identifier = mapping.identifier
+ fixed_address = mapping.ipv4_address
+ host_fake_name = 'host%s' % identifier.replace(':', '')
+ lease_time = mapping.lease_time
+
+ lines.append('host %s {' % host_fake_name)
+ lines.append('\thardware ethernet %s;' % identifier)
+ lines.append('\tfixed-address %s;' % fixed_address)
+ if lease_time:
+ lines.append('\tdefault-lease-time %d;' % lease_time)
+ lines.append('\tmax-lease-time %d;' % lease_time)
+ lines.append('}')
+
+ config_str = '\n'.join(lines)
+
+ return config_str
diff --git a/acts/framework/acts/controllers/ap_lib/dhcp_server.py b/acts/framework/acts/controllers/ap_lib/dhcp_server.py
index a94ecf8..b243e6f 100644
--- a/acts/framework/acts/controllers/ap_lib/dhcp_server.py
+++ b/acts/framework/acts/controllers/ap_lib/dhcp_server.py
@@ -16,8 +16,7 @@
from retry import retry
from acts.controllers.utils_lib.commands import shell
-
-_ROUTER_DNS = '8.8.8.8, 4.4.4.4'
+from acts import logger
class Error(Exception):
@@ -47,10 +46,12 @@
interface: string, The name of the interface to use.
working_dir: The directory to work out of.
"""
+ self._log = logger.create_logger(lambda msg: '[DHCP Server|%s] %s' % (
+ interface, msg))
self._runner = runner
self._working_dir = working_dir
self._shell = shell.ShellCommand(runner, working_dir)
- self._log_file = 'dhcpd_%s.log' % interface
+ self._stdio_log_file = 'dhcpd_%s.log' % interface
self._config_file = 'dhcpd_%s.conf' % interface
self._lease_file = 'dhcpd_%s.leases' % interface
self._pid_file = 'dhcpd_%s.pid' % interface
@@ -71,31 +72,32 @@
config: dhcp_config.DhcpConfig, Configs to start the dhcp server
with.
- 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 indefinitely
- it's infeasible to wait on. If you need to check if configs are ok
- then periodic checks to is_running and logs should be used.
+ Raises:
+ Error: Raised when a dhcp server error is found.
"""
if self.is_alive():
self.stop()
self._write_configs(config)
- self._shell.delete_file(self._log_file)
+ self._shell.delete_file(self._stdio_log_file)
+ self._shell.delete_file(self._pid_file)
self._shell.touch_file(self._lease_file)
dhcpd_command = '%s -cf "%s" -lf %s -f -pf "%s"' % (
self.PROGRAM_FILE, self._config_file, self._lease_file,
self._pid_file)
base_command = 'cd "%s"; %s' % (self._working_dir, dhcpd_command)
- job_str = '%s > "%s" 2>&1' % (base_command, self._log_file)
+ job_str = '%s > "%s" 2>&1' % (base_command, self._stdio_log_file)
self._runner.run_async(job_str)
try:
self._wait_for_process(timeout=timeout)
self._wait_for_server(timeout=timeout)
except:
+ self._log.warn("Failed to start DHCP server.")
+ self._log.info("DHCP configuration:\n" +
+ config.render_config_file() + "\n")
+ self._log.info("DHCP logs:\n" + self.get_logs() + "\n")
self.stop()
raise
@@ -117,7 +119,24 @@
Returns:
A string of the dhcp server logs.
"""
- return self._shell.read_file(self._log_file)
+ try:
+ # Try reading the PID file. This will fail if the server failed to
+ # start.
+ pid = self._shell.read_file(self._pid_file)
+ # `dhcpd` logs to the syslog, where its messages are interspersed
+ # with all other programs that use the syslog. Log lines contain
+ # `dhcpd[<pid>]`, which we can search for to extract all the logs
+ # from this particular dhcpd instance.
+ # The logs are preferable to the stdio output, since they contain
+ # a superset of the information from stdio, including leases
+ # that the server provides.
+ return self._shell.run(
+ f"grep dhcpd.{pid} /var/log/messages").stdout
+ except Exception:
+ self._log.info(
+ "Failed to read logs from syslog (likely because the server " +
+ "failed to start). Falling back to stdio output.")
+ return self._shell.read_file(self._stdio_log_file)
def _wait_for_process(self, timeout=60):
"""Waits for the process to come up.
@@ -146,7 +165,7 @@
start_time = time.time()
while time.time() - start_time < timeout:
success = self._shell.search_file(
- 'Wrote [0-9]* leases to leases file', self._log_file)
+ 'Wrote [0-9]* leases to leases file', self._stdio_log_file)
if success:
return
@@ -172,7 +191,7 @@
is_dead = not self.is_alive()
no_interface = self._shell.search_file(
- 'Not configured to listen on any interfaces', self._log_file)
+ 'Not configured to listen on any interfaces', self._stdio_log_file)
if no_interface:
raise NoInterfaceError(
'Dhcp does not contain a subnet for any of the networks the'
@@ -183,48 +202,6 @@
def _write_configs(self, config):
"""Writes the configs to the dhcp server config file."""
-
self._shell.delete_file(self._config_file)
-
- lines = []
-
- if config.default_lease_time:
- lines.append('default-lease-time %d;' % config.default_lease_time)
- if config.max_lease_time:
- lines.append('max-lease-time %s;' % config.max_lease_time)
-
- for subnet in config.subnets:
- address = subnet.network.network_address
- mask = subnet.network.netmask
- router = subnet.router
- start = subnet.start
- end = subnet.end
- lease_time = subnet.lease_time
-
- lines.append('subnet %s netmask %s {' % (address, mask))
- lines.append('\toption subnet-mask %s;' % mask)
- lines.append('\toption routers %s;' % router)
- lines.append('\toption domain-name-servers %s;' % _ROUTER_DNS)
- lines.append('\trange %s %s;' % (start, end))
- if lease_time:
- lines.append('\tdefault-lease-time %d;' % lease_time)
- lines.append('\tmax-lease-time %d;' % lease_time)
- lines.append('}')
-
- for mapping in config.static_mappings:
- identifier = mapping.identifier
- fixed_address = mapping.ipv4_address
- host_fake_name = 'host%s' % identifier.replace(':', '')
- lease_time = mapping.lease_time
-
- lines.append('host %s {' % host_fake_name)
- lines.append('\thardware ethernet %s;' % identifier)
- lines.append('\tfixed-address %s;' % fixed_address)
- if lease_time:
- lines.append('\tdefault-lease-time %d;' % lease_time)
- lines.append('\tmax-lease-time %d;' % lease_time)
- lines.append('}')
-
- config_str = '\n'.join(lines)
-
+ config_str = config.render_config_file()
self._shell.write_file(self._config_file, config_str)
diff --git a/acts/framework/acts/controllers/ap_lib/hostapd.py b/acts/framework/acts/controllers/ap_lib/hostapd.py
index 92b5ca3..d08caf2 100644
--- a/acts/framework/acts/controllers/ap_lib/hostapd.py
+++ b/acts/framework/acts/controllers/ap_lib/hostapd.py
@@ -16,9 +16,11 @@
import itertools
import logging
import os
+import re
import time
from acts.controllers.ap_lib import hostapd_config
+from acts.controllers.ap_lib import hostapd_constants
from acts.controllers.utils_lib.commands import shell
@@ -34,6 +36,7 @@
"""
PROGRAM_FILE = '/usr/sbin/hostapd'
+ CLI_PROGRAM_FILE = '/usr/bin/hostapd_cli'
def __init__(self, runner, interface, working_dir='/tmp'):
"""
@@ -102,6 +105,38 @@
if self.is_alive():
self._shell.kill(self._identifier)
+ def channel_switch(self, channel_num):
+ """Switches to the given channel.
+
+ Returns:
+ acts.libs.proc.job.Result containing the results of the command.
+ Raises: See _run_hostapd_cli_cmd
+ """
+ try:
+ channel_freq = hostapd_constants.FREQUENCY_MAP[channel_num]
+ except KeyError:
+ raise ValueError('Invalid channel number {}'.format(channel_num))
+ csa_beacon_count = 10
+ channel_switch_cmd = 'chan_switch {} {}'.format(
+ csa_beacon_count, channel_freq)
+ result = self._run_hostapd_cli_cmd(channel_switch_cmd)
+
+ def get_current_channel(self):
+ """Returns the current channel number.
+
+ Raises: See _run_hostapd_cli_cmd
+ """
+ status_cmd = 'status'
+ result = self._run_hostapd_cli_cmd(status_cmd)
+ match = re.search(r'^channel=(\d+)$', result.stdout, re.MULTILINE)
+ if not match:
+ raise Error('Current channel could not be determined')
+ try:
+ channel = int(match.group(1))
+ except ValueError:
+ raise Error('Internal error: current channel could not be parsed')
+ return channel
+
def is_alive(self):
"""
Returns:
@@ -118,6 +153,28 @@
# TODO: Auto pulling of logs when stop is called.
return self._shell.read_file(self._log_file)
+ def _run_hostapd_cli_cmd(self, cmd):
+ """Run the given hostapd_cli command.
+
+ Runs the command, waits for the output (up to default timeout), and
+ returns the result.
+
+ Returns:
+ acts.libs.proc.job.Result containing the results of the ssh command.
+
+ Raises:
+ acts.lib.proc.job.TimeoutError: When the remote command took too
+ long to execute.
+ acts.controllers.utils_lib.ssh.connection.Error: When the ssh
+ connection failed to be created.
+ acts.controllers.utils_lib.ssh.connection.CommandError: Ssh worked,
+ but the command had an error executing.
+ """
+ hostapd_cli_job = 'cd {}; {} -p {} {}'.format(self._working_dir,
+ self.CLI_PROGRAM_FILE,
+ self._ctrl_file, cmd)
+ return self._runner.run(hostapd_cli_job)
+
def _wait_for_process(self, timeout=60):
"""Waits for the process to come up.
@@ -142,12 +199,14 @@
"""
start_time = time.time()
while time.time() - start_time < timeout:
+ time.sleep(0.1)
success = self._shell.search_file('Setup of interface done',
self._log_file)
if success:
return
+ self._scan_for_errors(False)
- self._scan_for_errors(True)
+ self._scan_for_errors(True)
def _scan_for_errors(self, should_be_up):
"""Scans the hostapd log for any errors.
diff --git a/acts/framework/acts/controllers/ap_lib/radvd.py b/acts/framework/acts/controllers/ap_lib/radvd.py
index 187f9e7..e88701e 100644
--- a/acts/framework/acts/controllers/ap_lib/radvd.py
+++ b/acts/framework/acts/controllers/ap_lib/radvd.py
@@ -134,8 +134,9 @@
"""
start_time = time.time()
while time.time() - start_time < timeout and not self.is_alive():
- self._scan_for_errors(True)
time.sleep(0.1)
+ self._scan_for_errors(False)
+ self._scan_for_errors(True)
def _scan_for_errors(self, should_be_up):
"""Scans the radvd log for any errors.
diff --git a/acts/framework/acts/controllers/attenuator.py b/acts/framework/acts/controllers/attenuator.py
index ad5ad81..b7f4a6d 100644
--- a/acts/framework/acts/controllers/attenuator.py
+++ b/acts/framework/acts/controllers/attenuator.py
@@ -228,7 +228,7 @@
self.max_atten = AttenuatorInstrument.INVALID_MAX_ATTEN
self.properties = None
- def set_atten(self, idx, value, strict=True):
+ def set_atten(self, idx, value, strict=True, retry=False):
"""Sets the attenuation given its index in the instrument.
Args:
@@ -238,15 +238,17 @@
strict: if True, function raises an error when given out of
bounds attenuation values, if false, the function sets out of
bounds values to 0 or max_atten.
+ retry: if True, command will be retried if possible
"""
raise NotImplementedError('Base class should not be called directly!')
- def get_atten(self, idx):
+ def get_atten(self, idx, retry=False):
"""Returns the current attenuation of the attenuator at index idx.
Args:
idx: A zero based index used to identify a particular attenuator in
an instrument.
+ retry: if True, command will be retried if possible
Returns:
The current attenuation value as a floating point value
@@ -262,6 +264,7 @@
the physical implementation and allows the user to think only of attenuators
regardless of their location.
"""
+
def __init__(self, instrument, idx=0, offset=0):
"""This is the constructor for Attenuator
@@ -290,7 +293,7 @@
raise IndexError(
'Attenuator index out of range for attenuator instrument')
- def set_atten(self, value, strict=True):
+ def set_atten(self, value, strict=True, retry=False):
"""Sets the attenuation.
Args:
@@ -298,6 +301,7 @@
strict: if True, function raises an error when given out of
bounds attenuation values, if false, the function sets out of
bounds values to 0 or max_atten.
+ retry: if True, command will be retried if possible
Raises:
ValueError if value + offset is greater than the maximum value.
@@ -306,11 +310,14 @@
raise ValueError(
'Attenuator Value+Offset greater than Max Attenuation!')
- self.instrument.set_atten(self.idx, value + self.offset, strict)
+ self.instrument.set_atten(self.idx,
+ value + self.offset,
+ strict=strict,
+ retry=retry)
- def get_atten(self):
+ def get_atten(self, retry=False):
"""Returns the attenuation as a float, normalized by the offset."""
- return self.instrument.get_atten(self.idx) - self.offset
+ return self.instrument.get_atten(self.idx, retry) - self.offset
def get_max_atten(self):
"""Returns the max attenuation as a float, normalized by the offset."""
@@ -330,6 +337,7 @@
convenience to the user and avoid re-implementation of helper functions and
small loops scattered throughout user code.
"""
+
def __init__(self, name=''):
"""This constructor for AttenuatorGroup
diff --git a/acts/framework/acts/controllers/attenuator_lib/_tnhelper.py b/acts/framework/acts/controllers/attenuator_lib/_tnhelper.py
index 028814e..b7e0f8f 100644
--- a/acts/framework/acts/controllers/attenuator_lib/_tnhelper.py
+++ b/acts/framework/acts/controllers/attenuator_lib/_tnhelper.py
@@ -35,8 +35,9 @@
It should only be used by those implementation control libraries and not by
any user code directly.
"""
-
- def __init__(self, tx_cmd_separator='\n', rx_cmd_separator='\n',
+ def __init__(self,
+ tx_cmd_separator='\n',
+ rx_cmd_separator='\n',
prompt=''):
self._tn = None
self._ip_address = None
@@ -78,7 +79,8 @@
"""
logging.debug('Diagnosing telnet connection')
try:
- job_result = job.run('ping {} -c 5'.format(self._ip_address))
+ job_result = job.run('ping {} -c 5 -i 0.2'.format(
+ self._ip_address))
except:
logging.error("Unable to ping telnet server.")
return False
@@ -99,7 +101,7 @@
logging.debug('Telnet connection likely recovered')
return True
- def cmd(self, cmd_str, wait_ret=True):
+ def cmd(self, cmd_str, wait_ret=True, retry=False):
if not isinstance(cmd_str, str):
raise TypeError('Invalid command string', cmd_str)
@@ -117,16 +119,21 @@
match_idx, match_val, ret_text = self._tn.expect(
[_ascii_string('\S+' + self.rx_cmd_separator)], 1)
+ logging.debug('Telnet Command: {}'.format(cmd_str))
+ logging.debug('Telnet Reply: ({},{},{})'.format(
+ match_idx, match_val, ret_text))
+
if match_idx == -1:
- logging.debug('Telnet Command: {}'.format(cmd_str))
- logging.debug('Telnet Reply: ({},{},{})'.format(
- match_idx, match_val, ret_text))
- self.diagnose_telnet()
- raise attenuator.InvalidDataError(
- 'Telnet command failed to return valid data')
+ telnet_recovered = self.diagnose_telnet()
+ if telnet_recovered and retry:
+ logging.debug('Retrying telnet command once.')
+ return self.cmd(cmd_str, wait_ret, retry=False)
+ else:
+ raise attenuator.InvalidDataError(
+ 'Telnet command failed to return valid data')
ret_text = ret_text.decode()
- ret_text = ret_text.strip(
- self.tx_cmd_separator + self.rx_cmd_separator + self.prompt)
+ ret_text = ret_text.strip(self.tx_cmd_separator +
+ self.rx_cmd_separator + self.prompt)
- return ret_text
\ No newline at end of file
+ return ret_text
diff --git a/acts/framework/acts/controllers/attenuator_lib/aeroflex/telnet.py b/acts/framework/acts/controllers/attenuator_lib/aeroflex/telnet.py
index 8a7a2cd..2e46ebf 100644
--- a/acts/framework/acts/controllers/attenuator_lib/aeroflex/telnet.py
+++ b/acts/framework/acts/controllers/attenuator_lib/aeroflex/telnet.py
@@ -78,7 +78,7 @@
"""
self._tnhelper.close()
- def set_atten(self, idx, value):
+ def set_atten(self, idx, value, **_):
"""This function sets the attenuation of an attenuator given its index
in the instrument.
@@ -107,7 +107,7 @@
self._tnhelper.cmd('ATTN ' + str(idx + 1) + ' ' + str(value), False)
- def get_atten(self, idx):
+ def get_atten(self, idx, **_):
"""Returns the current attenuation of the attenuator at the given index.
Args:
diff --git a/acts/framework/acts/controllers/attenuator_lib/minicircuits/http.py b/acts/framework/acts/controllers/attenuator_lib/minicircuits/http.py
index f6d61e9..e1805f0 100644
--- a/acts/framework/acts/controllers/attenuator_lib/minicircuits/http.py
+++ b/acts/framework/acts/controllers/attenuator_lib/minicircuits/http.py
@@ -35,7 +35,6 @@
With the exception of HTTP-specific commands, all functionality is defined
by the AttenuatorInstrument class.
"""
-
def __init__(self, num_atten=1):
super(AttenuatorInstrument, self).__init__(num_atten)
self._ip_address = None
@@ -86,7 +85,7 @@
"""
pass
- def set_atten(self, idx, value, strict_flag=True):
+ def set_atten(self, idx, value, strict=True, retry=False, **_):
"""This function sets the attenuation of an attenuator given its index
in the instrument.
@@ -95,9 +94,10 @@
an instrument. For instruments that only have one channel, this
is ignored by the device.
value: A floating point value for nominal attenuation to be set.
- strict_flag: if True, function raises an error when given out of
+ strict: if True, function raises an error when given out of
bounds attenuation values, if false, the function sets out of
bounds values to 0 or max_atten.
+ retry: if True, command will be retried if possible
Raises:
InvalidDataError if the attenuator does not respond with the
@@ -107,25 +107,31 @@
raise IndexError('Attenuator index out of range!', self.num_atten,
idx)
- if value > self.max_atten and strict_flag:
+ if value > self.max_atten and strict:
raise ValueError('Attenuator value out of range!', self.max_atten,
value)
# The actual device uses one-based index for channel numbers.
+ adjusted_value = min(max(0, value), self.max_atten)
att_req = urllib.request.urlopen(
- 'http://{}:{}/CHAN:{}:SETATT:{}'.format(
- self._ip_address, self._port, idx + 1, value),
+ 'http://{}:{}/CHAN:{}:SETATT:{}'.format(self._ip_address,
+ self._port, idx + 1,
+ adjusted_value),
timeout=self._timeout)
- att_resp = att_req.read().decode('utf-8')
+ att_resp = att_req.read().decode('utf-8').strip()
if att_resp != '1':
- raise attenuator.InvalidDataError(
- 'Attenuator returned invalid data. Attenuator returned: {}'.
- format(att_resp))
+ if retry:
+ self.set_atten(idx, value, strict, retry=False)
+ else:
+ raise attenuator.InvalidDataError(
+ 'Attenuator returned invalid data. Attenuator returned: {}'
+ .format(att_resp))
- def get_atten(self, idx):
+ def get_atten(self, idx, retry=False, **_):
"""Returns the current attenuation of the attenuator at the given index.
Args:
idx: The index of the attenuator.
+ retry: if True, command will be retried if possible
Raises:
InvalidDataError if the attenuator does not respond with the
@@ -137,15 +143,17 @@
if not (0 <= idx < self.num_atten):
raise IndexError('Attenuator index out of range!', self.num_atten,
idx)
- att_req = urllib.request.urlopen(
- 'http://{}:{}/CHAN:{}:ATT?'.format(self._ip_address, self.port,
- idx + 1),
- timeout=self._timeout)
+ att_req = urllib.request.urlopen('http://{}:{}/CHAN:{}:ATT?'.format(
+ self._ip_address, self.port, idx + 1),
+ timeout=self._timeout)
att_resp = att_req.read().decode('utf-8')
try:
atten_val = float(att_resp)
except:
- raise attenuator.InvalidDataError(
- 'Attenuator returned invalid data. Attenuator returned: {}'.
- format(att_resp))
+ if retry:
+ self.get_atten(idx, retry=False)
+ else:
+ raise attenuator.InvalidDataError(
+ 'Attenuator returned invalid data. Attenuator returned: {}'
+ .format(att_resp))
return atten_val
diff --git a/acts/framework/acts/controllers/attenuator_lib/minicircuits/telnet.py b/acts/framework/acts/controllers/attenuator_lib/minicircuits/telnet.py
index 87d1d98..ddda6ab 100644
--- a/acts/framework/acts/controllers/attenuator_lib/minicircuits/telnet.py
+++ b/acts/framework/acts/controllers/attenuator_lib/minicircuits/telnet.py
@@ -37,6 +37,7 @@
the functionality of AttenuatorInstrument is contingent upon a telnet
connection being established.
"""
+
def __init__(self, num_atten=0):
super(AttenuatorInstrument, self).__init__(num_atten)
self._tnhelper = _tnhelper._TNHelper(tx_cmd_separator='\r\n',
@@ -84,7 +85,7 @@
"""
self._tnhelper.close()
- def set_atten(self, idx, value, strict_flag=True):
+ def set_atten(self, idx, value, strict=True, retry=False):
"""This function sets the attenuation of an attenuator given its index
in the instrument.
@@ -93,9 +94,10 @@
an instrument. For instruments that only have one channel, this
is ignored by the device.
value: A floating point value for nominal attenuation to be set.
- strict_flag: if True, function raises an error when given out of
+ strict: if True, function raises an error when given out of
bounds attenuation values, if false, the function sets out of
bounds values to 0 or max_atten.
+ retry: if True, command will be retried if possible
Raises:
InvalidOperationError if the telnet connection is not open.
@@ -111,17 +113,20 @@
raise IndexError('Attenuator index out of range!', self.num_atten,
idx)
- if value > self.max_atten and strict_flag:
+ if value > self.max_atten and strict:
raise ValueError('Attenuator value out of range!', self.max_atten,
value)
# The actual device uses one-based index for channel numbers.
- self._tnhelper.cmd('CHAN:%s:SETATT:%s' % (idx + 1, value))
+ adjusted_value = min(max(0, value), self.max_atten)
+ self._tnhelper.cmd('CHAN:%s:SETATT:%s' % (idx + 1, adjusted_value),
+ retry=retry)
- def get_atten(self, idx):
+ def get_atten(self, idx, retry=False):
"""Returns the current attenuation of the attenuator at the given index.
Args:
idx: The index of the attenuator.
+ retry: if True, command will be retried if possible
Raises:
InvalidOperationError if the telnet connection is not open.
@@ -137,8 +142,9 @@
idx)
if self.num_atten == 1:
- atten_val_str = self._tnhelper.cmd(':ATT?')
+ atten_val_str = self._tnhelper.cmd(':ATT?', retry=retry)
else:
- atten_val_str = self._tnhelper.cmd('CHAN:%s:ATT?' % (idx + 1))
+ atten_val_str = self._tnhelper.cmd('CHAN:%s:ATT?' % (idx + 1),
+ retry=retry)
atten_val = float(atten_val_str)
return atten_val
diff --git a/acts/framework/acts/controllers/bits.py b/acts/framework/acts/controllers/bits.py
index 5194f92..d89a9b3 100644
--- a/acts/framework/acts/controllers/bits.py
+++ b/acts/framework/acts/controllers/bits.py
@@ -1,9 +1,9 @@
"""Module managing the required definitions for using the bits power monitor"""
-from datetime import datetime
import logging
import os
import time
+import uuid
from acts import context
from acts.controllers import power_metrics
@@ -29,6 +29,32 @@
return [bits.config for bits in bitses]
+class BitsError(Exception):
+ pass
+
+
+class _BitsCollection(object):
+ """Object that represents a bits collection
+
+ Attributes:
+ name: The name given to the collection.
+ markers_buffer: An array of un-flushed markers, each marker is
+ represented by a bi-dimensional tuple with the format
+ (<nanoseconds_since_epoch or datetime>, <text>).
+ monsoon_output_path: A path to store monsoon-like data if possible, Bits
+ uses this path to attempt data extraction in monsoon format, if this
+ parameter is left as None such extraction is not attempted.
+ """
+
+ def __init__(self, name, monsoon_output_path=None):
+ self.monsoon_output_path = monsoon_output_path
+ self.name = name
+ self.markers_buffer = []
+
+ def add_marker(self, timestamp, marker_text):
+ self.markers_buffer.append((timestamp, marker_text))
+
+
def _transform_name(bits_metric_name):
"""Transform bits metrics names to a more succinct version.
@@ -62,7 +88,7 @@
elif 'mV' == unit:
suffix = 'avg_voltage'
else:
- logging.getLogger().warning('unknown unit type for unit %s' % unit)
+ logging.warning('unknown unit type for unit %s' % unit)
suffix = ''
if 'Monsoon' == rail:
@@ -87,7 +113,7 @@
elif 'mV' == unit:
unit_type = 'voltage'
else:
- logging.getLogger().warning('unknown unit type for unit %s' % unit)
+ logging.warning('unknown unit type for unit %s' % unit)
continue
name = _transform_name(sample['name'])
@@ -111,6 +137,10 @@
class Bits(object):
+
+ ROOT_RAIL_KEY = 'RootRail'
+ ROOT_RAIL_DEFAULT_VALUE = 'Monsoon:mA'
+
def __init__(self, index, config):
"""Creates an instance of a bits controller.
@@ -139,17 +169,26 @@
'serial': 'serial_2'
}
]
+ // optional
+ 'RootRail': 'Monsoon:mA'
}
"""
self.index = index
self.config = config
self._service = None
self._client = None
+ self._active_collection = None
+ self._collections_counter = 0
+ self._root_rail = config.get(self.ROOT_RAIL_KEY,
+ self.ROOT_RAIL_DEFAULT_VALUE)
def setup(self, *_, registry=None, **__):
"""Starts a bits_service in the background.
- This function needs to be
+ This function needs to be called with either a registry or after calling
+ power_monitor.update_registry, and it needs to be called before any other
+ method in this class.
+
Args:
registry: A dictionary with files used by bits. Format:
{
@@ -208,6 +247,8 @@
'bits_service_out_%s.txt' % self.index)
service_name = 'bits_config_%s' % self.index
+ self._active_collection = None
+ self._collections_counter = 0
self._service = bits_service.BitsService(config,
bits_service_binary,
output_log,
@@ -219,7 +260,7 @@
config)
# this call makes sure that the client can interact with the server.
devices = self._client.list_devices()
- logging.getLogger().debug(devices)
+ logging.debug(devices)
def disconnect_usb(self, *_, **__):
self._client.disconnect_usb()
@@ -227,16 +268,29 @@
def connect_usb(self, *_, **__):
self._client.connect_usb()
- def measure(self, *_, measurement_args=None, **__):
+ def measure(self, *_, measurement_args=None,
+ measurement_name=None, monsoon_output_path=None,
+ **__):
"""Blocking function that measures power through bits for the specified
duration. Results need to be consulted through other methods such as
- get_metrics or export_to_csv.
+ get_metrics or post processing files like the ones
+ generated at monsoon_output_path after calling `release_resources`.
Args:
measurement_args: A dictionary with the following structure:
{
'duration': <seconds to measure for>
+ 'hz': <samples per second>
+ 'measure_after_seconds': <sleep time before measurement>
}
+ The actual number of samples per second is limited by the
+ bits configuration. The value of hz is defaulted to 1000.
+ measurement_name: A name to give to the measurement (which is also
+ used as the Bits collection name. Bits collection names (and
+ therefore measurement names) need to be unique within the
+ context of a Bits object.
+ monsoon_output_path: If provided this path will be used to generate
+ a monsoon like formatted file at the release_resources step.
"""
if measurement_args is None:
raise ValueError('measurement_args can not be left undefined')
@@ -245,12 +299,41 @@
if duration is None:
raise ValueError(
'duration can not be left undefined within measurement_args')
- self._client.start_collection()
+
+ hz = measurement_args.get('hz', 1000)
+
+ # Delay the start of the measurement if an offset is required
+ measure_after_seconds = measurement_args.get('measure_after_seconds')
+ if measure_after_seconds:
+ time.sleep(measure_after_seconds)
+
+ if self._active_collection:
+ raise BitsError(
+ 'Attempted to start a collection while there is still an '
+ 'active one. Active collection: %s',
+ self._active_collection.name)
+
+ self._collections_counter = self._collections_counter + 1
+ # The name gets a random 8 characters salt suffix because the Bits
+ # client has a bug where files with the same name are considered to be
+ # the same collection and it won't load two files with the same name.
+ # b/153170987 b/153944171
+ if not measurement_name:
+ measurement_name = 'bits_collection_%s_%s' % (
+ str(self._collections_counter), str(uuid.uuid4())[0:8])
+
+ self._active_collection = _BitsCollection(measurement_name,
+ monsoon_output_path)
+ self._client.start_collection(self._active_collection.name,
+ default_sampling_rate=hz)
time.sleep(duration)
def get_metrics(self, *_, timestamps=None, **__):
"""Gets metrics for the segments delimited by the timestamps dictionary.
+ Must be called before releasing resources, otherwise it will fail adding
+ markers to the collection.
+
Args:
timestamps: A dictionary of the shape:
{
@@ -276,6 +359,9 @@
metrics = {}
for segment_name, times in timestamps.items():
+ if 'start' not in times or 'end' not in times:
+ continue
+
start = times['start']
end = times['end']
@@ -285,18 +371,96 @@
# The preferred way for new calls to this function should be using
# datetime instead which is unambiguous
if isinstance(start, (int, float)):
- start = times['start'] * 1e6
+ start = start * 1e6
if isinstance(end, (int, float)):
- end = times['end'] * 1e6
+ end = end * 1e6
- self._client.add_marker(start, 'start - %s' % segment_name)
- self._client.add_marker(end, 'end - %s' % segment_name)
- raw_metrics = self._client.get_metrics(start, end)
+ raw_metrics = self._client.get_metrics(self._active_collection.name,
+ start=start, end=end)
+ self._add_marker(start, 'start - %s' % segment_name)
+ self._add_marker(end, 'end - %s' % segment_name)
metrics[segment_name] = _raw_data_to_metrics(raw_metrics)
return metrics
+ def _add_marker(self, timestamp, marker_text):
+ if not self._active_collection:
+ raise BitsError(
+ 'markers can not be added without an active collection')
+ self._active_collection.add_marker(timestamp, marker_text)
+
def release_resources(self):
- self._client.stop_collection()
+ """Performs all the cleanup and export tasks.
+
+ In the way that Bits' is interfaced several tasks can not be performed
+ while a collection is still active (like exporting the data) and others
+ can only take place while the collection is still active (like adding
+ markers to a collection).
+
+ To workaround this unique workflow, the collections that are started
+ with the 'measure' method are not really stopped after the method
+ is unblocked, it is only stopped after this method is called.
+
+ All the export files (.7z.bits and monsoon-formatted file) are also
+ generated in this method.
+ """
+ if not self._active_collection:
+ raise BitsError(
+ 'Attempted to stop a collection without starting one')
+ self._client.add_markers(self._active_collection.name,
+ self._active_collection.markers_buffer)
+ self._client.stop_collection(self._active_collection.name)
+
+ export_file = os.path.join(
+ context.get_current_context().get_full_output_path(),
+ '%s.7z.bits' % self._active_collection.name)
+ self._client.export(self._active_collection.name, export_file)
+ if self._active_collection.monsoon_output_path:
+ self._attempt_monsoon_format()
+ self._active_collection = None
+
+ def _attempt_monsoon_format(self):
+ """Attempts to create a monsoon-formatted file.
+
+ In the case where there is not enough information to retrieve a
+ monsoon-like file, this function will do nothing.
+ """
+ available_channels = self._client.list_channels(
+ self._active_collection.name)
+ milli_amps_channel = None
+
+ for channel in available_channels:
+ if channel.endswith(self._root_rail):
+ milli_amps_channel = self._root_rail
+ break
+
+ if milli_amps_channel is None:
+ logging.debug('No monsoon equivalent channels were found when '
+ 'attempting to recreate monsoon file format. '
+ 'Available channels were: %s',
+ str(available_channels))
+ return
+
+ logging.debug('Recreating monsoon file format from channel: %s',
+ milli_amps_channel)
+ self._client.export_as_monsoon_format(
+ self._active_collection.monsoon_output_path,
+ self._active_collection.name,
+ milli_amps_channel)
+
+ def get_waveform(self, file_path=None):
+ """Parses a file generated in release_resources.
+
+ Args:
+ file_path: Path to a waveform file.
+
+ Returns:
+ A list of tuples in which the first element is a timestamp and the
+ second element is the sampled current at that time.
+ """
+ if file_path is None:
+ raise ValueError('file_path can not be None')
+
+ return list(power_metrics.import_raw_data(file_path))
def teardown(self):
if self._service is None:
diff --git a/acts/framework/acts/controllers/bits_lib/bits_client.py b/acts/framework/acts/controllers/bits_lib/bits_client.py
index 4c8e740..f33c44b 100644
--- a/acts/framework/acts/controllers/bits_lib/bits_client.py
+++ b/acts/framework/acts/controllers/bits_lib/bits_client.py
@@ -14,15 +14,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import logging
-import os
-import uuid
-import tempfile
-import yaml
+import csv
from datetime import datetime
+import logging
+import tempfile
from acts.libs.proc import job
-from acts import context
+import yaml
class BitsClientError(Exception):
@@ -52,26 +50,6 @@
'nanoseconds.' % type(timestamp))
-class _BitsCollection(object):
- """Object that represents a bits collection
-
- Attributes:
- name: The name given to the collection.
- markers_buffer: An array of un-flushed markers, each marker is
- represented by a bi-dimensional tuple with the format
- (<nanoseconds_since_epoch or datetime>, <text>).
- """
- def __init__(self, name):
- self.name = name
- self.markers_buffer = []
-
- def add_marker(self, timestamp, marker_text):
- self.markers_buffer.append((timestamp, marker_text))
-
- def clear_markers_buffer(self):
- self.markers_buffer.clear()
-
-
class BitsClient(object):
"""Helper class to issue bits' commands"""
@@ -89,115 +67,159 @@
self._binary = binary
self._service = service
self._server_config = service_config
- self._active_collection = None
- self._collections_counter = 0
def _acquire_monsoon(self):
"""Gets hold of a Monsoon so no other processes can use it.
Only works if there is a monsoon."""
- cmd = [self._binary,
- '--port',
- self._service.port,
- '--collector',
- 'Monsoon',
- '--collector_cmd',
- 'acquire_monsoon']
- self._log.info('acquiring monsoon')
- job.run(cmd, timeout=10)
+ self._log.debug('acquiring monsoon')
+ self.run_cmd('--collector',
+ 'Monsoon',
+ '--collector_cmd',
+ 'acquire_monsoon', timeout=10)
def _release_monsoon(self):
- cmd = [self._binary,
- '--port',
- self._service.port,
- '--collector',
- 'Monsoon',
- '--collector_cmd',
- 'release_monsoon']
- self._log.info('releasing monsoon')
- job.run(cmd, timeout=10)
+ self._log.debug('releasing monsoon')
+ self.run_cmd('--collector',
+ 'Monsoon',
+ '--collector_cmd',
+ 'release_monsoon', timeout=10)
- def _export(self):
- collection_path = os.path.join(
- context.get_current_context().get_full_output_path(),
- '%s.7z.bits' % self._active_collection.name)
- cmd = [self._binary,
- '--port',
- self._service.port,
- '--name',
- self._active_collection.name,
- '--ignore_gaps',
- '--export',
- '--export_path',
- collection_path]
- self._log.info('exporting collection %s to %s',
- self._active_collection.name,
- collection_path)
- job.run(cmd, timeout=600)
-
- def _flush_markers(self):
- for ts, marker in sorted(self._active_collection.markers_buffer,
- key=lambda x: x[0]):
- cmd = [self._binary,
- '--port',
- self._service.port,
- '--name',
- self._active_collection.name,
- '--log_ts',
- str(_to_ns(ts)),
- '--log',
- marker]
- job.run(cmd, timeout=10)
- self._active_collection.clear_markers_buffer()
-
- def add_marker(self, timestamp, marker_text):
- """Buffers a marker for the active collection.
-
- Bits does not allow inserting markers with timestamps out of order.
- The buffer of markers will be flushed when the collection is stopped to
- ensure all the timestamps are input in order.
+ def run_cmd(self, *args, timeout=60):
+ """Executes a generic bits.par command.
Args:
- timestamp: Numerical nanoseconds since epoch or datetime.
- marker_text: A string to label this marker with.
+ args: A bits.par command as a tokenized array. The path to the
+ binary and the service port are provided by default, cmd should
+ only contain the remaining tokens of the desired command.
+ timeout: Number of seconds to wait for the command to finish before
+ forcibly killing it.
"""
- if not self._active_collection:
- raise BitsClientError(
- 'markers can not be added without an active collection')
- self._active_collection.add_marker(timestamp, marker_text)
+ result = job.run([self._binary, '--port',
+ self._service.port] + [str(arg) for arg in args],
+ timeout=timeout)
+ return result.stdout
- def get_metrics(self, start, end):
+ def export(self, collection_name, path):
+ """Exports a collection to its bits persistent format.
+
+ Exported files can be shared and opened through the Bits UI.
+
+ Args:
+ collection_name: Collection to be exported.
+ path: Where the resulting file should be created. Bits requires that
+ the resulting file ends in .7z.bits.
+ """
+ if not path.endswith('.7z.bits'):
+ raise BitsClientError('Bits\' collections can only be exported to '
+ 'files ending in .7z.bits, got %s' % path)
+ self._log.debug('exporting collection %s to %s',
+ collection_name,
+ path)
+ self.run_cmd('--name',
+ collection_name,
+ '--ignore_gaps',
+ '--export',
+ '--export_path',
+ path,
+ timeout=600)
+
+ def export_as_csv(self, channels, collection_name, output_file):
+ """Export bits data as CSV.
+
+ Writes the selected channel data to the given output_file. Note that
+ the first line of the file contains headers.
+
+ Args:
+ channels: A list of string pattern matches for the channel to be
+ retrieved. For example, ":mW" will export all power channels,
+ ":mV" will export all voltage channels, "C1_01__" will export
+ power/voltage/current for the first fail of connector 1.
+ collection_name: A string for a collection that is sampling.
+ output_file: A string file path where the CSV will be written.
+ """
+ channels_arg = ','.join(channels)
+ cmd = ['--csvfile',
+ output_file,
+ '--name',
+ collection_name,
+ '--ignore_gaps',
+ '--csv_rawtimestamps',
+ '--channels',
+ channels_arg]
+ if self._server_config.has_virtual_metrics_file:
+ cmd = cmd + ['--vm_file', 'default']
+ self._log.debug(
+ 'exporting csv for collection %s to %s, with channels %s',
+ collection_name, output_file, channels_arg)
+ self.run_cmd(*cmd, timeout=600)
+
+ def add_markers(self, collection_name, markers):
+ """Appends markers to a collection.
+
+ These markers are displayed in the Bits UI and are useful to label
+ important test events.
+
+ Markers can only be added to collections that have not been
+ closed / stopped. Markers need to be added in chronological order,
+ this function ensures that at least the markers added in each
+ call are sorted in chronological order, but if this function
+ is called multiple times, then is up to the user to ensure that
+ the subsequent batches of markers are for timestamps higher (newer)
+ than all the markers passed in previous calls to this function.
+
+ Args:
+ collection_name: The name of the collection to add markers to.
+ markers: A list of tuples of the shape:
+
+ [(<nano_seconds_since_epoch or datetime>, <marker text>),
+ (<nano_seconds_since_epoch or datetime>, <marker text>),
+ (<nano_seconds_since_epoch or datetime>, <marker text>),
+ ...
+ ]
+ """
+ # sorts markers in chronological order before adding them. This is
+ # required by go/pixel-bits
+ for ts, marker in sorted(markers, key=lambda x: _to_ns(x[0])):
+ self._log.debug('Adding marker at %s: %s', str(ts), marker)
+ self.run_cmd('--name',
+ collection_name,
+ '--log_ts',
+ str(_to_ns(ts)),
+ '--log',
+ marker,
+ timeout=10)
+
+ def get_metrics(self, collection_name, start=None, end=None):
"""Extracts metrics for a period of time.
Args:
+ collection_name: The name of the collection to get metrics from
start: Numerical nanoseconds since epoch until the start of the
- period of interest or datetime.
+ period of interest or datetime. If not provided, start will be the
+ beginning of the collection.
end: Numerical nanoseconds since epoch until the end of the
- period of interest or datetime.
+ period of interest or datetime. If not provided, end will be the
+ end of the collection.
"""
- if not self._active_collection:
- raise BitsClientError(
- 'metrics can not be collected without an active collection')
-
with tempfile.NamedTemporaryFile(prefix='bits_metrics') as tf:
- cmd = [self._binary,
- '--port',
- self._service.port,
- '--name',
- self._active_collection.name,
+ cmd = ['--name',
+ collection_name,
'--ignore_gaps',
- '--abs_start_time',
- str(_to_ns(start)),
- '--abs_stop_time',
- str(_to_ns(end)),
'--aggregates_yaml_path',
tf.name]
+
+ if start is not None:
+ cmd = cmd + ['--abs_start_time', str(_to_ns(start))]
+ if end is not None:
+ cmd = cmd + ['--abs_stop_time', str(_to_ns(end))]
if self._server_config.has_virtual_metrics_file:
cmd = cmd + ['--vm_file', 'default']
- job.run(cmd)
+
+ self.run_cmd(*cmd)
with open(tf.name) as mf:
self._log.debug(
'bits aggregates for collection %s [%s-%s]: %s' % (
- self._active_collection.name, start, end,
+ collection_name, start, end,
mf.read()))
with open(tf.name) as mf:
@@ -205,82 +227,53 @@
def disconnect_usb(self):
"""Disconnects the monsoon's usb. Only works if there is a monsoon"""
- cmd = [self._binary,
- '--port',
- self._service.port,
- '--collector',
- 'Monsoon',
- '--collector_cmd',
- 'usb_disconnect']
- self._log.info('disconnecting monsoon\'s usb')
- job.run(cmd, timeout=10)
+ self._log.debug('disconnecting monsoon\'s usb')
+ self.run_cmd('--collector',
+ 'Monsoon',
+ '--collector_cmd',
+ 'usb_disconnect', timeout=10)
- def start_collection(self, postfix=None):
+ def start_collection(self, collection_name, default_sampling_rate=1000):
"""Indicates Bits to start a collection.
Args:
- postfix: Optional argument that can be used to identify the
- collection with.
+ collection_name: Name to give to the collection to be started.
+ Collection names must be unique at Bits' service level. If multiple
+ collections must be taken within the context of the same Bits'
+ service, ensure that each collection is given a different one.
+ default_sampling_rate: Samples per second to be collected
"""
- if self._active_collection:
- raise BitsClientError(
- 'Attempted to start a collection while there is still an '
- 'active one. Active collection: %s',
- self._active_collection.name)
- self._collections_counter = self._collections_counter + 1
- # The name gets a random 8 characters salt suffix because the Bits
- # client has a bug where files with the same name are considered to be
- # the same collection and it won't load two files with the same name.
- # b/153170987 b/153944171
- if not postfix:
- postfix = str(self._collections_counter)
- postfix = '%s_%s' % (postfix, str(uuid.uuid4())[0:8])
- self._active_collection = _BitsCollection(
- 'bits_collection_%s' % postfix)
- cmd = [self._binary,
- '--port',
- self._service.port,
- '--name',
- self._active_collection.name,
+ cmd = ['--name',
+ collection_name,
'--non_blocking',
'--time',
ONE_YEAR,
'--default_sampling_rate',
- '1000',
- '--disk_space_saver']
- self._log.info('starting collection %s', self._active_collection.name)
- job.run(cmd, timeout=10)
+ str(default_sampling_rate)]
+
+ if self._server_config.has_kibbles:
+ cmd = cmd + ['--disk_space_saver']
+
+ self._log.debug('starting collection %s', collection_name)
+ self.run_cmd(*cmd, timeout=10)
def connect_usb(self):
"""Connects the monsoon's usb. Only works if there is a monsoon."""
- cmd = [self._binary,
- '--port',
- self._service.port,
- '--collector',
+ cmd = ['--collector',
'Monsoon',
'--collector_cmd',
'usb_connect']
- self._log.info('connecting monsoon\'s usb')
- job.run(cmd, timeout=10)
+ self._log.debug('connecting monsoon\'s usb')
+ self.run_cmd(*cmd, timeout=10)
- def stop_collection(self):
+ def stop_collection(self, collection_name):
"""Stops the active collection."""
- if not self._active_collection:
- raise BitsClientError(
- 'Attempted to stop a collection without starting one')
- self._log.info('stopping collection %s', self._active_collection.name)
- self._flush_markers()
- cmd = [self._binary,
- '--port',
- self._service.port,
- '--name',
- self._active_collection.name,
- '--stop']
- job.run(cmd)
- self._export()
- self._log.info('stopped collection %s', self._active_collection.name)
- self._active_collection = None
+ self._log.debug('stopping collection %s', collection_name)
+ self.run_cmd('--name',
+ collection_name,
+ '--stop')
+ self._log.debug('stopped collection %s', collection_name)
def list_devices(self):
"""Lists devices managed by the bits_server this client is connected
@@ -289,11 +282,54 @@
Returns:
bits' output when called with --list devices.
"""
- cmd = [self._binary,
- '--port',
- self._service.port,
- '--list',
- 'devices']
self._log.debug('listing devices')
- result = job.run(cmd, timeout=20)
- return result.stdout
+ result = self.run_cmd('--list', 'devices', timeout=20)
+ return result
+
+ def list_channels(self, collection_name):
+ """Finds all the available channels in a given collection.
+
+ Args:
+ collection_name: The name of the collection to get channels from.
+ """
+ metrics = self.get_metrics(collection_name)
+ return [channel['name'] for channel in metrics['data']]
+
+ def export_as_monsoon_format(self, dest_path, collection_name,
+ channel_pattern):
+ """Exports data from a collection in monsoon style.
+
+ This function exists because there are tools that have been built on
+ top of the monsoon format. To be able to leverage such tools we need
+ to make the data compliant with the format.
+
+ The monsoon format is:
+
+ <time_since_epoch_in_secs> <amps>
+
+ Args:
+ dest_path: Path where the resulting file will be generated.
+ collection_name: The name of the Bits' collection to export data
+ from.
+ channel_pattern: A regex that matches the Bits' channel to be used
+ as source of data. If there are multiple matching channels, only the
+ first one will be used. The channel is always assumed to be
+ expressed en milli-amps, the resulting format requires amps, so the
+ values coming from the first matching channel will always be
+ multiplied by 1000.
+ """
+ with tempfile.NamedTemporaryFile(prefix='bits_csv_') as tmon:
+ self.export_as_csv([channel_pattern], collection_name, tmon.name)
+
+ self._log.debug(
+ 'massaging bits csv to monsoon format for collection'
+ ' %s', collection_name)
+ with open(tmon.name) as csv_file:
+ reader = csv.reader(csv_file)
+ headers = next(reader)
+ self._log.debug('csv headers %s', headers)
+ with open(dest_path, 'w') as dest:
+ for row in reader:
+ ts = float(row[0]) / 1e9
+ amps = float(row[1]) / 1e3
+ dest.write('%.7f %.12f\n' % (ts, amps))
diff --git a/acts/framework/acts/controllers/bits_lib/bits_service_config.py b/acts/framework/acts/controllers/bits_lib/bits_service_config.py
index b17ff3b..cb2d219 100644
--- a/acts/framework/acts/controllers/bits_lib/bits_service_config.py
+++ b/acts/framework/acts/controllers/bits_lib/bits_service_config.py
@@ -62,8 +62,8 @@
raise ValueError('Monsoon voltage can not be undefined. Received '
'config was: %s' % monsoon_config)
- self.serial_num = monsoon_config['serial_num']
- self.monsoon_voltage = monsoon_config['monsoon_voltage']
+ self.serial_num = int(monsoon_config['serial_num'])
+ self.monsoon_voltage = float(monsoon_config['monsoon_voltage'])
self.config_dic = copy.deepcopy(DEFAULT_MONSOON_CONFIG_DICT)
if float(self.serial_num) >= 20000:
diff --git a/acts/framework/acts/controllers/cellular_lib/BaseCellConfig.py b/acts/framework/acts/controllers/cellular_lib/BaseCellConfig.py
new file mode 100644
index 0000000..14540de
--- /dev/null
+++ b/acts/framework/acts/controllers/cellular_lib/BaseCellConfig.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+class BaseCellConfig:
+ """ Base cell configuration class.
+
+ Attributes:
+ output_power: a float indicating the required signal level at the
+ instrument's output.
+ input_power: a float indicating the required signal level at the
+ instrument's input.
+ """
+ # Configuration dictionary keys
+ PARAM_UL_PW = 'pul'
+ PARAM_DL_PW = 'pdl'
+
+ def __init__(self, log):
+ """ Initialize the base station config by setting all its
+ parameters to None.
+ Args:
+ log: logger object.
+ """
+ self.log = log
+ self.output_power = None
+ self.input_power = None
+ self.band = None
+
+ def incorporate(self, new_config):
+ """ Incorporates a different configuration by replacing the current
+ values with the new ones for all the parameters different to None.
+ Args:
+ new_config: 5G cell configuration object.
+ """
+ for attr, value in vars(new_config).items():
+ if value and not hasattr(self, attr):
+ setattr(self, attr, value)
diff --git a/acts/framework/acts/controllers/cellular_lib/BaseSimulation.py b/acts/framework/acts/controllers/cellular_lib/BaseSimulation.py
index f956f72..7427628 100644
--- a/acts/framework/acts/controllers/cellular_lib/BaseSimulation.py
+++ b/acts/framework/acts/controllers/cellular_lib/BaseSimulation.py
@@ -19,6 +19,7 @@
import numpy as np
from acts.controllers import cellular_simulator
+from acts.controllers.cellular_lib.BaseCellConfig import BaseCellConfig
class BaseSimulation(object):
@@ -59,40 +60,14 @@
DEFAULT_ATTACH_RETRIES = 3
# These two dictionaries allow to map from a string to a signal level and
- # have to be overriden by the simulations inheriting from this class.
+ # have to be overridden by the simulations inheriting from this class.
UPLINK_SIGNAL_LEVEL_DICTIONARY = {}
DOWNLINK_SIGNAL_LEVEL_DICTIONARY = {}
- # Units for downlink signal level. This variable has to be overriden by
+ # Units for downlink signal level. This variable has to be overridden by
# the simulations inheriting from this class.
DOWNLINK_SIGNAL_LEVEL_UNITS = None
- class BtsConfig:
- """ Base station configuration class. This class is only a container for
- base station parameters and should not interact with the instrument
- controller.
-
- Atributes:
- output_power: a float indicating the required signal level at the
- instrument's output.
- input_level: a float indicating the required signal level at the
- instrument's input.
- """
- def __init__(self):
- """ Initialize the base station config by setting all its
- parameters to None. """
- self.output_power = None
- self.input_power = None
- self.band = None
-
- def incorporate(self, new_config):
- """ Incorporates a different configuration by replacing the current
- values with the new ones for all the parameters different to None.
- """
- for attr, value in vars(new_config).items():
- if value:
- setattr(self, attr, value)
-
def __init__(self, simulator, log, dut, test_config, calibration_table):
""" Initializes the Simulation object.
@@ -145,8 +120,8 @@
self.attach_timeout = test_config.get(self.KEY_ATTACH_TIMEOUT,
self.DEFAULT_ATTACH_TIMEOUT)
- # Configuration object for the primary base station
- self.primary_config = self.BtsConfig()
+ # Create an empty list for cell configs.
+ self.cell_configs = []
# Store the current calibrated band
self.current_calibrated_band = None
@@ -199,11 +174,11 @@
time.sleep(2)
# Provide a good signal power for the phone to attach easily
- new_config = self.BtsConfig()
+ new_config = BaseCellConfig(self.log)
new_config.input_power = -10
new_config.output_power = -30
self.simulator.configure_bts(new_config)
- self.primary_config.incorporate(new_config)
+ self.cell_configs[0].incorporate(new_config)
# Try to attach the phone.
for i in range(self.attach_retries):
@@ -294,13 +269,13 @@
# Wait until it goes to communication state
self.simulator.wait_until_communication_state()
- # Set uplink power to a minimum before going to the actual desired
+ # Set uplink power to a low value before going to the actual desired
# value. This avoid inconsistencies produced by the hysteresis in the
# PA switching points.
- self.log.info('Setting UL power to -30 dBm before going to the '
+ self.log.info('Setting UL power to -5 dBm before going to the '
'requested value to avoid incosistencies caused by '
'hysteresis.')
- self.set_uplink_tx_power(-30)
+ self.set_uplink_tx_power(-5)
# Set signal levels obtained from the test parameters
self.set_downlink_rx_power(self.sim_dl_power)
@@ -325,51 +300,28 @@
# Stop IP traffic after setting the UL power level
self.stop_traffic_for_calibration()
- def parse_parameters(self, parameters):
- """ Configures simulation using a list of parameters.
+ def configure(self, parameters):
+ """ Configures simulation using a dictionary of parameters.
- Consumes parameters from a list.
Children classes need to call this method first.
Args:
- parameters: list of parameters
+ parameters: a configuration dictionary
"""
+ # Setup uplink power
+ ul_power = self.get_uplink_power_from_parameters(parameters)
- raise NotImplementedError()
+ # Power is not set on the callbox until after the simulation is
+ # started. Saving this value in a variable for later
+ self.sim_ul_power = ul_power
- def consume_parameter(self, parameters, parameter_name, num_values=0):
- """ Parses a parameter from a list.
+ # Setup downlink power
- Allows to parse the parameter list. Will delete parameters from the
- list after consuming them to ensure that they are not used twice.
+ dl_power = self.get_downlink_power_from_parameters(parameters)
- Args:
- parameters: list of parameters
- parameter_name: keyword to look up in the list
- num_values: number of arguments following the
- parameter name in the list
- Returns:
- A list containing the parameter name and the following num_values
- arguments
- """
-
- try:
- i = parameters.index(parameter_name)
- except ValueError:
- # parameter_name is not set
- return []
-
- return_list = []
-
- try:
- for j in range(num_values + 1):
- return_list.append(parameters.pop(i))
- except IndexError:
- raise ValueError(
- "Parameter {} has to be followed by {} values.".format(
- parameter_name, num_values))
-
- return return_list
+ # Power is not set on the callbox until after the simulation is
+ # started. Saving this value in a variable for later
+ self.sim_dl_power = dl_power
def set_uplink_tx_power(self, signal_level):
""" Configure the uplink tx power level
@@ -377,11 +329,11 @@
Args:
signal_level: calibrated tx power in dBm
"""
- new_config = self.BtsConfig()
+ new_config = BaseCellConfig(self.log)
new_config.input_power = self.calibrated_uplink_tx_power(
- self.primary_config, signal_level)
+ self.cell_configs[0], signal_level)
self.simulator.configure_bts(new_config)
- self.primary_config.incorporate(new_config)
+ self.cell_configs[0].incorporate(new_config)
def set_downlink_rx_power(self, signal_level):
""" Configure the downlink rx power level
@@ -389,51 +341,49 @@
Args:
signal_level: calibrated rx power in dBm
"""
- new_config = self.BtsConfig()
+ new_config = BaseCellConfig(self.log)
new_config.output_power = self.calibrated_downlink_rx_power(
- self.primary_config, signal_level)
+ self.cell_configs[0], signal_level)
self.simulator.configure_bts(new_config)
- self.primary_config.incorporate(new_config)
+ self.cell_configs[0].incorporate(new_config)
def get_uplink_power_from_parameters(self, parameters):
- """ Reads uplink power from a list of parameters. """
+ """ Reads uplink power from the parameter dictionary. """
- values = self.consume_parameter(parameters, self.PARAM_UL_PW, 1)
-
- if values:
- if values[1] in self.UPLINK_SIGNAL_LEVEL_DICTIONARY:
- return self.UPLINK_SIGNAL_LEVEL_DICTIONARY[values[1]]
+ if BaseCellConfig.PARAM_UL_PW in parameters:
+ value = parameters[BaseCellConfig.PARAM_UL_PW]
+ if value in self.UPLINK_SIGNAL_LEVEL_DICTIONARY:
+ return self.UPLINK_SIGNAL_LEVEL_DICTIONARY[value]
else:
try:
- if values[1][0] == 'n':
+ if isinstance(value[0], str) and value[0] == 'n':
# Treat the 'n' character as a negative sign
- return -int(values[1][1:])
+ return -int(value[1:])
else:
- return int(values[1])
+ return int(value)
except ValueError:
pass
# If the method got to this point it is because PARAM_UL_PW was not
# included in the test parameters or the provided value was invalid.
raise ValueError(
- "The test name needs to include parameter {} followed by the "
- "desired uplink power expressed by an integer number in dBm "
- "or by one the following values: {}. To indicate negative "
+ "The config dictionary must include a key {} with the desired "
+ "uplink power expressed by an integer number in dBm or with one of "
+ "the following values: {}. To indicate negative "
"values, use the letter n instead of - sign.".format(
- self.PARAM_UL_PW,
+ BaseCellConfig.PARAM_UL_PW,
list(self.UPLINK_SIGNAL_LEVEL_DICTIONARY.keys())))
def get_downlink_power_from_parameters(self, parameters):
- """ Reads downlink power from a list of parameters. """
+ """ Reads downlink power from a the parameter dictionary. """
- values = self.consume_parameter(parameters, self.PARAM_DL_PW, 1)
-
- if values:
- if values[1] not in self.DOWNLINK_SIGNAL_LEVEL_DICTIONARY:
- raise ValueError("Invalid signal level value {}.".format(
- values[1]))
+ if BaseCellConfig.PARAM_DL_PW in parameters:
+ value = parameters[BaseCellConfig.PARAM_DL_PW]
+ if value not in self.DOWNLINK_SIGNAL_LEVEL_DICTIONARY:
+ raise ValueError(
+ "Invalid signal level value {}.".format(value))
else:
- return self.DOWNLINK_SIGNAL_LEVEL_DICTIONARY[values[1]]
+ return self.DOWNLINK_SIGNAL_LEVEL_DICTIONARY[value]
else:
# Use default value
power = self.DOWNLINK_SIGNAL_LEVEL_DICTIONARY['excellent']
@@ -598,7 +548,7 @@
reported signal level and bts. use None if no conversion is
needed.
Returns:
- Dowlink calibration value and measured DL power.
+ Downlink calibration value and measured DL power.
"""
# Check if this parameter was set. Child classes may need to override
@@ -609,11 +559,11 @@
"reported by the phone.")
# Save initial output level to restore it after calibration
- restoration_config = self.BtsConfig()
- restoration_config.output_power = self.primary_config.output_power
+ restoration_config = BaseCellConfig(self.log)
+ restoration_config.output_power = self.cell_configs[0].output_power
# Set BTS to a good output level to minimize measurement error
- new_config = self.BtsConfig()
+ new_config = BaseCellConfig(self.log)
new_config.output_power = self.simulator.MAX_DL_POWER - 5
self.simulator.configure_bts(new_config)
@@ -640,7 +590,7 @@
# Convert from RSRP to signal power
if power_units_conversion_func:
avg_down_power = power_units_conversion_func(
- reported_asu_power, self.primary_config)
+ reported_asu_power, self.cell_configs[0])
else:
avg_down_power = reported_asu_power
@@ -670,13 +620,13 @@
"""
# Save initial input level to restore it after calibration
- restoration_config = self.BtsConfig()
- restoration_config.input_power = self.primary_config.input_power
+ restoration_config = BaseCellConfig(self.log)
+ restoration_config.input_power = self.cell_configs[0].input_power
# Set BTS1 to maximum input allowed in order to perform
# uplink calibration
target_power = self.MAX_PHONE_OUTPUT_POWER
- new_config = self.BtsConfig()
+ new_config = BaseCellConfig(self.log)
new_config.input_power = self.MAX_BTS_INPUT_POWER
self.simulator.configure_bts(new_config)
@@ -742,7 +692,7 @@
# Load the new ones
if self.calibration_required:
- band = self.primary_config.band
+ band = self.cell_configs[0].band
# Try loading the path loss values from the calibration table. If
# they are not available, use the automated calibration procedure.
diff --git a/acts/framework/acts/controllers/cellular_lib/GsmSimulation.py b/acts/framework/acts/controllers/cellular_lib/GsmSimulation.py
index b7237f3..f907567 100644
--- a/acts/framework/acts/controllers/cellular_lib/GsmSimulation.py
+++ b/acts/framework/acts/controllers/cellular_lib/GsmSimulation.py
@@ -26,6 +26,7 @@
from acts.controllers.anritsu_lib import md8475_cellular_simulator as anritsusim
from acts.controllers.cellular_lib import BaseCellularDut
from acts.controllers.cellular_lib.BaseSimulation import BaseSimulation
+from acts.controllers.cellular_lib.BaseCellConfig import BaseCellConfig
class GsmSimulation(BaseSimulation):
@@ -39,8 +40,7 @@
GSM_CELL_FILE = 'CELL_GSM_config.wnscp'
- # Test name parameters
-
+ # Configuration dictionary keys
PARAM_BAND = "band"
PARAM_GPRS = "gprs"
PARAM_EGPRS = "edge"
@@ -57,7 +57,7 @@
def __init__(self, simulator, log, dut, test_config, calibration_table):
""" Initializes the simulator for a single-carrier GSM simulation.
- Loads a simple LTE simulation enviroment with 1 basestation. It also
+ Loads a simple LTE simulation environment with 1 basestation. It also
creates the BTS handle so we can change the parameters as desired.
Args:
@@ -100,52 +100,48 @@
# Start simulation if it wasn't started
self.anritsu.start_simulation()
- def parse_parameters(self, parameters):
- """ Configs a GSM simulation using a list of parameters.
+ def configure(self, parameters):
+ """ Configures simulation using a dictionary of parameters.
- Calls the parent method first, then consumes parameters specific to GSM.
+ Processes GSM configuration parameters.
Args:
- parameters: list of parameters
+ parameters: a configuration dictionary
"""
+ # Don't call super() because Gsm doesn't control Tx power.
# Setup band
-
- values = self.consume_parameter(parameters, self.PARAM_BAND, 1)
-
- if not values:
+ if self.PARAM_BAND not in parameters:
raise ValueError(
- "The test name needs to include parameter '{}' followed by "
- "the required band number.".format(self.PARAM_BAND))
+ "The configuration dictionary must include key '{}' with the "
+ "required band number.".format(self.PARAM_BAND))
- self.set_band(self.bts1, values[1])
+ self.set_band(self.bts1, parameters[self.PARAM_BAND])
self.load_pathloss_if_required()
# Setup GPRS mode
- if self.consume_parameter(parameters, self.PARAM_GPRS):
+ if self.PARAM_GPRS in parameters:
self.bts1.gsm_gprs_mode = BtsGprsMode.GPRS
- elif self.consume_parameter(parameters, self.PARAM_EGPRS):
+ elif self.PARAM_EGPRS in parameters:
self.bts1.gsm_gprs_mode = BtsGprsMode.EGPRS
- elif self.consume_parameter(parameters, self.PARAM_NO_GPRS):
+ elif self.PARAM_NO_GPRS in parameters:
self.bts1.gsm_gprs_mode = BtsGprsMode.NO_GPRS
else:
raise ValueError(
- "GPRS mode needs to be indicated in the test name with either "
- "{}, {} or {}.".format(self.PARAM_GPRS, self.PARAM_EGPRS,
- self.PARAM_NO_GPRS))
+ "GPRS mode needs to be indicated in the config dictionary by "
+ "including either {}, {} or {} as a key.".format(
+ self.PARAM_GPRS, self.PARAM_EGPRS, self.PARAM_NO_GPRS))
# Setup slot allocation
-
- values = self.consume_parameter(parameters, self.PARAM_SLOTS, 2)
-
- if not values:
+ if self.PARAM_SLOTS not in parameters or len(
+ parameters[self.PARAM_SLOTS]) != 2:
raise ValueError(
- "The test name needs to include parameter {} followed by two "
+ "The config dictionary must include key {} with a list of two "
"int values indicating DL and UL slots.".format(
self.PARAM_SLOTS))
-
- self.bts1.gsm_slots = (int(values[1]), int(values[2]))
+ values = parameters[self.PARAM_SLOTS]
+ self.bts1.gsm_slots = (int(values[0]), int(values[1]))
def set_band(self, bts, band):
""" Sets the band used for communication.
diff --git a/acts/framework/acts/controllers/cellular_lib/LteCaSimulation.py b/acts/framework/acts/controllers/cellular_lib/LteCaSimulation.py
deleted file mode 100644
index 3f98a34..0000000
--- a/acts/framework/acts/controllers/cellular_lib/LteCaSimulation.py
+++ /dev/null
@@ -1,427 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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 re
-from acts.controllers.cellular_lib import LteSimulation
-
-
-class LteCaSimulation(LteSimulation.LteSimulation):
- """ Carrier aggregation LTE simulation. """
-
- # Dictionary of lower DL channel number bound for each band.
- LOWEST_DL_CN_DICTIONARY = {
- 1: 0,
- 2: 600,
- 3: 1200,
- 4: 1950,
- 5: 2400,
- 6: 2650,
- 7: 2750,
- 8: 3450,
- 9: 3800,
- 10: 4150,
- 11: 4750,
- 12: 5010,
- 13: 5180,
- 14: 5280,
- 17: 5730,
- 18: 5850,
- 19: 6000,
- 20: 6150,
- 21: 6450,
- 22: 6600,
- 23: 7500,
- 24: 7700,
- 25: 8040,
- 26: 8690,
- 27: 9040,
- 28: 9210,
- 29: 9660,
- 30: 9770,
- 31: 9870,
- 32: 36000,
- 33: 36200,
- 34: 36350,
- 35: 36950,
- 36: 37550,
- 37: 37750,
- 38: 38250,
- 39: 38650,
- 40: 39650,
- 41: 41590,
- 42: 45590,
- 66: 66436
- }
-
- # Simulation config keywords contained in the test name
- PARAM_CA = 'ca'
-
- # Test config keywords
- KEY_FREQ_BANDS = "freq_bands"
-
- def __init__(self, simulator, log, dut, test_config, calibration_table):
- """ Initializes the simulator for LTE simulation with carrier
- aggregation.
-
- Loads a simple LTE simulation enviroment with 5 basestations.
-
- Args:
- simulator: the cellular instrument controller
- log: a logger handle
- dut: a device handler implementing BaseCellularDut
- test_config: test configuration obtained from the config file
- calibration_table: a dictionary containing path losses for
- different bands.
-
- """
-
- super().__init__(simulator, log, dut, test_config, calibration_table)
-
- # Create a configuration object for each base station and copy initial
- # settings from the PCC base station.
- self.bts_configs = [self.primary_config]
-
- for bts_index in range(1, self.simulator.LTE_MAX_CARRIERS):
- new_config = self.BtsConfig()
- new_config.incorporate(self.primary_config)
- self.simulator.configure_bts(new_config, bts_index)
- self.bts_configs.append(new_config)
-
- # Get LTE CA frequency bands setting from the test configuration
- if self.KEY_FREQ_BANDS not in test_config:
- self.log.warning("The key '{}' is not set in the config file. "
- "Setting to null by default.".format(
- self.KEY_FREQ_BANDS))
-
- self.freq_bands = test_config.get(self.KEY_FREQ_BANDS, True)
-
- def setup_simulator(self):
- """ Do initial configuration in the simulator. """
- self.simulator.setup_lte_ca_scenario()
-
- def parse_parameters(self, parameters):
- """ Configs an LTE simulation with CA using a list of parameters.
-
- Args:
- parameters: list of parameters
- """
-
- # Get the CA band configuration
-
- values = self.consume_parameter(parameters, self.PARAM_CA, 1)
-
- if not values:
- raise ValueError(
- "The test name needs to include parameter '{}' followed by "
- "the CA configuration. For example: ca_3c7c28a".format(
- self.PARAM_CA))
-
- # Carrier aggregation configurations are indicated with the band numbers
- # followed by the CA classes in a single string. For example, for 5 CA
- # using 3C 7C and 28A the parameter value should be 3c7c28a.
- ca_configs = re.findall(r'(\d+[abcABC])', values[1])
-
- if not ca_configs:
- raise ValueError(
- "The CA configuration has to be indicated with one string as "
- "in the following example: ca_3c7c28a".format(self.PARAM_CA))
-
- # Apply the carrier aggregation combination
- self.simulator.set_ca_combination(ca_configs)
-
- # Save the bands to the bts config objects
- bts_index = 0
- for ca in ca_configs:
- ca_class = ca[-1]
- band = ca[:-1]
-
- self.bts_configs[bts_index].band = band
- bts_index += 1
-
- if ca_class.upper() == 'B' or ca_class.upper() == 'C':
- # Class B and C means two carriers with the same band
- self.bts_configs[bts_index].band = band
- bts_index += 1
-
- # Count the number of carriers in the CA combination
- self.num_carriers = 0
- for ca in ca_configs:
- ca_class = ca[-1]
- # Class C means that there are two contiguous carriers, while other
- # classes are a single one.
- if ca_class.upper() == 'C':
- self.num_carriers += 2
- else:
- self.num_carriers += 1
-
- # Create an array of configuration objects to set up the base stations.
- new_configs = [self.BtsConfig() for _ in range(self.num_carriers)]
-
- # Get the bw for each carrier
- # This is an optional parameter, by default the maximum bandwidth for
- # each band will be selected.
-
- values = self.consume_parameter(parameters, self.PARAM_BW,
- self.num_carriers)
-
- bts_index = 0
-
- for ca in ca_configs:
-
- band = int(ca[:-1])
- ca_class = ca[-1]
-
- if values:
- bw = int(values[1 + bts_index])
- else:
- bw = max(self.allowed_bandwidth_dictionary[band])
-
- new_configs[bts_index].bandwidth = bw
- bts_index += 1
-
- if ca_class.upper() == 'C':
-
- new_configs[bts_index].bandwidth = bw
-
- # Calculate the channel number for the second carrier to be
- # contiguous to the first one
- new_configs[bts_index].dl_channel = int(
- self.LOWEST_DL_CN_DICTIONARY[int(band)] + bw * 10 - 2)
-
- bts_index += 1
-
- # Get the TM for each carrier
- # This is an optional parameter, by the default value depends on the
- # MIMO mode for each carrier
-
- tm_values = self.consume_parameter(parameters, self.PARAM_TM,
- self.num_carriers)
-
- # Get the MIMO mode for each carrier
-
- mimo_values = self.consume_parameter(parameters, self.PARAM_MIMO,
- self.num_carriers)
-
- if not mimo_values:
- raise ValueError(
- "The test parameter '{}' has to be included in the "
- "test name followed by the MIMO mode for each "
- "carrier separated by underscores.".format(self.PARAM_MIMO))
-
- if len(mimo_values) != self.num_carriers + 1:
- raise ValueError(
- "The test parameter '{}' has to be followed by "
- "a number of MIMO mode values equal to the number "
- "of carriers being used.".format(self.PARAM_MIMO))
-
- for bts_index in range(self.num_carriers):
-
- # Parse and set the requested MIMO mode
-
- for mimo_mode in LteSimulation.MimoMode:
- if mimo_values[bts_index + 1] == mimo_mode.value:
- requested_mimo = mimo_mode
- break
- else:
- raise ValueError(
- "The mimo mode must be one of %s." %
- {elem.value
- for elem in LteSimulation.MimoMode})
-
- if (requested_mimo == LteSimulation.MimoMode.MIMO_4x4
- and not self.simulator.LTE_SUPPORTS_4X4_MIMO):
- raise ValueError("The test requires 4x4 MIMO, but that is not "
- "supported by the MD8475A callbox.")
-
- new_configs[bts_index].mimo_mode = requested_mimo
-
- # Parse and set the requested TM
-
- if tm_values:
- for tm in LteSimulation.TransmissionMode:
- if tm_values[bts_index + 1] == tm.value[2:]:
- requested_tm = tm
- break
- else:
- raise ValueError(
- "The TM must be one of %s." %
- {elem.value
- for elem in LteSimulation.MimoMode})
- else:
- # Provide default values if the TM parameter is not set
- if requested_mimo == LteSimulation.MimoMode.MIMO_1x1:
- requested_tm = LteSimulation.TransmissionMode.TM1
- else:
- requested_tm = LteSimulation.TransmissionMode.TM3
-
- new_configs[bts_index].transmission_mode = requested_tm
-
- self.log.info("Cell {} will be set to {} and {} MIMO.".format(
- bts_index + 1, requested_tm.value, requested_mimo.value))
-
- # Get uplink power
-
- ul_power = self.get_uplink_power_from_parameters(parameters)
-
- # Power is not set on the callbox until after the simulation is
- # started. Saving this value in a variable for later
- self.sim_ul_power = ul_power
-
- # Get downlink power
-
- dl_power = self.get_downlink_power_from_parameters(parameters)
-
- # Power is not set on the callbox until after the simulation is
- # started. Saving this value in a variable for later
- self.sim_dl_power = dl_power
-
- # Setup scheduling mode
-
- values = self.consume_parameter(parameters, self.PARAM_SCHEDULING, 1)
-
- if not values:
- scheduling = LteSimulation.SchedulingMode.STATIC
- self.log.warning(
- "The test name does not include the '{}' parameter. Setting to "
- "{} by default.".format(scheduling.value,
- self.PARAM_SCHEDULING))
- else:
- for scheduling_mode in LteSimulation.SchedulingMode:
- if values[1].upper() == scheduling_mode.value:
- scheduling = scheduling_mode
- break
- else:
- raise ValueError(
- "The test name parameter '{}' has to be followed by one of "
- "{}.".format(
- self.PARAM_SCHEDULING,
- {elem.value
- for elem in LteSimulation.SchedulingMode}))
-
- for bts_index in range(self.num_carriers):
- new_configs[bts_index].scheduling_mode = scheduling
-
- if scheduling == LteSimulation.SchedulingMode.STATIC:
-
- values = self.consume_parameter(parameters, self.PARAM_PATTERN, 2)
-
- if not values:
- self.log.warning(
- "The '{}' parameter was not set, using 100% RBs for both "
- "DL and UL. To set the percentages of total RBs include "
- "the '{}' parameter followed by two ints separated by an "
- "underscore indicating downlink and uplink percentages.".
- format(self.PARAM_PATTERN, self.PARAM_PATTERN))
- dl_pattern = 100
- ul_pattern = 100
- else:
- dl_pattern = int(values[1])
- ul_pattern = int(values[2])
-
- if (dl_pattern, ul_pattern) not in [(0, 100), (100, 0),
- (100, 100)]:
- raise ValueError(
- "Only full RB allocation for DL or UL is supported in CA "
- "sims. The allowed combinations are 100/0, 0/100 and "
- "100/100.")
-
- for bts_index in range(self.num_carriers):
-
- # Look for a DL MCS configuration in the test parameters. If it
- # is not present, use a default value.
- dlmcs = self.consume_parameter(parameters, self.PARAM_DL_MCS,
- 1)
- if dlmcs:
- mcs_dl = int(dlmcs[1])
- else:
- self.log.warning(
- 'The test name does not include the {} parameter. '
- 'Setting to the max value by default'.format(
- self.PARAM_DL_MCS))
-
- if self.dl_256_qam and new_configs[
- bts_index].bandwidth == 1.4:
- mcs_dl = 26
- elif (not self.dl_256_qam
- and self.primary_config.tbs_pattern_on
- and new_configs[bts_index].bandwidth != 1.4):
- mcs_dl = 28
- else:
- mcs_dl = 27
-
- # Look for an UL MCS configuration in the test parameters. If it
- # is not present, use a default value.
- ulmcs = self.consume_parameter(parameters, self.PARAM_UL_MCS,
- 1)
- if ulmcs:
- mcs_ul = int(ulmcs[1])
- else:
- self.log.warning(
- 'The test name does not include the {} parameter. '
- 'Setting to the max value by default'.format(
- self.PARAM_UL_MCS))
-
- if self.ul_64_qam:
- mcs_ul = 28
- else:
- mcs_ul = 23
-
- dl_rbs, ul_rbs = self.allocation_percentages_to_rbs(
- new_configs[bts_index].bandwidth,
- new_configs[bts_index].transmission_mode, dl_pattern,
- ul_pattern)
-
- new_configs[bts_index].dl_rbs = dl_rbs
- new_configs[bts_index].ul_rbs = ul_rbs
- new_configs[bts_index].dl_mcs = mcs_dl
- new_configs[bts_index].ul_mcs = mcs_ul
-
- # Setup the base stations with the obtained configurations and then save
- # these parameters in the current configuration objects
- for bts_index in range(len(new_configs)):
- self.simulator.configure_bts(new_configs[bts_index], bts_index)
- self.bts_configs[bts_index].incorporate(new_configs[bts_index])
-
- # Now that the band is set, calibrate the link for the PCC if necessary
- self.load_pathloss_if_required()
-
- def maximum_downlink_throughput(self):
- """ Calculates maximum downlink throughput as the sum of all the active
- carriers.
- """
- return sum(
- self.bts_maximum_downlink_throughtput(self.bts_configs[bts_index])
- for bts_index in range(self.num_carriers))
-
- def start(self):
- """ Set the signal level for the secondary carriers, as the base class
- implementation of this method will only set up downlink power for the
- primary carrier component.
-
- After that, attaches the secondary carriers."""
-
- super().start()
-
- if self.sim_dl_power:
- self.log.info('Setting DL power for secondary carriers.')
-
- for bts_index in range(1, self.num_carriers):
- new_config = self.BtsConfig()
- new_config.output_power = self.calibrated_downlink_rx_power(
- self.bts_configs[bts_index], self.sim_dl_power)
- self.simulator.configure_bts(new_config, bts_index)
- self.bts_configs[bts_index].incorporate(new_config)
-
- self.simulator.lte_attach_secondary_carriers(self.freq_bands)
diff --git a/acts/framework/acts/controllers/cellular_lib/LteCellConfig.py b/acts/framework/acts/controllers/cellular_lib/LteCellConfig.py
new file mode 100644
index 0000000..34b982d
--- /dev/null
+++ b/acts/framework/acts/controllers/cellular_lib/LteCellConfig.py
@@ -0,0 +1,485 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import acts.controllers.cellular_lib.BaseCellConfig as base_cell
+import acts.controllers.cellular_lib.LteSimulation as lte_sim
+import math
+
+
+class LteCellConfig(base_cell.BaseCellConfig):
+ """ Extension of the BaseBtsConfig to implement parameters that are
+ exclusive to LTE.
+
+ Attributes:
+ band: an integer indicating the required band number.
+ dlul_config: an integer indicating the TDD config number.
+ ssf_config: an integer indicating the Special Sub-Frame config.
+ bandwidth: a float indicating the required channel bandwidth.
+ mimo_mode: an instance of LteSimulation.MimoMode indicating the
+ required MIMO mode for the downlink signal.
+ transmission_mode: an instance of LteSimulation.TransmissionMode
+ indicating the required TM.
+ scheduling_mode: an instance of LteSimulation.SchedulingMode
+ indicating whether to use Static or Dynamic scheduling.
+ dl_rbs: an integer indicating the number of downlink RBs
+ ul_rbs: an integer indicating the number of uplink RBs
+ dl_mcs: an integer indicating the MCS for the downlink signal
+ ul_mcs: an integer indicating the MCS for the uplink signal
+ dl_256_qam_enabled: a boolean indicating if 256 QAM is enabled
+ ul_64_qam_enabled: a boolean indicating if 256 QAM is enabled
+ mac_padding: a boolean indicating whether RBs should be allocated
+ when there is no user data in static scheduling
+ dl_channel: an integer indicating the downlink channel number
+ cfi: an integer indicating the Control Format Indicator
+ paging_cycle: an integer indicating the paging cycle duration in
+ milliseconds
+ phich: a string indicating the PHICH group size parameter
+ drx_connected_mode: a boolean indicating whether cDRX mode is
+ on or off
+ drx_on_duration_timer: number of PDCCH subframes representing
+ DRX on duration
+ drx_inactivity_timer: number of PDCCH subframes to wait before
+ entering DRX mode
+ drx_retransmission_timer: number of consecutive PDCCH subframes
+ to wait for retransmission
+ drx_long_cycle: number of subframes representing one long DRX cycle.
+ One cycle consists of DRX sleep + DRX on duration
+ drx_long_cycle_offset: number representing offset in range
+ 0 to drx_long_cycle - 1
+ """
+ PARAM_FRAME_CONFIG = "tddconfig"
+ PARAM_BW = "bw"
+ PARAM_SCHEDULING = "scheduling"
+ PARAM_SCHEDULING_STATIC = "static"
+ PARAM_SCHEDULING_DYNAMIC = "dynamic"
+ PARAM_PATTERN = "pattern"
+ PARAM_TM = "tm"
+ PARAM_BAND = "band"
+ PARAM_MIMO = "mimo"
+ PARAM_DL_MCS = 'dlmcs'
+ PARAM_UL_MCS = 'ulmcs'
+ PARAM_SSF = 'ssf'
+ PARAM_CFI = 'cfi'
+ PARAM_PAGING = 'paging'
+ PARAM_PHICH = 'phich'
+ PARAM_DRX = 'drx'
+ PARAM_PADDING = 'mac_padding'
+ PARAM_DL_256_QAM_ENABLED = "256_qam_dl_enabled"
+ PARAM_UL_64_QAM_ENABLED = "64_qam_ul_enabled"
+ PARAM_DL_EARFCN = 'dl_earfcn'
+
+ def __init__(self, log):
+ """ Initialize the base station config by setting all its
+ parameters to None.
+ Args:
+ log: logger object.
+ """
+ super().__init__(log)
+ self.band = None
+ self.dlul_config = None
+ self.ssf_config = None
+ self.bandwidth = None
+ self.mimo_mode = None
+ self.transmission_mode = None
+ self.scheduling_mode = None
+ self.dl_rbs = None
+ self.ul_rbs = None
+ self.dl_mcs = None
+ self.ul_mcs = None
+ self.dl_256_qam_enabled = None
+ self.ul_64_qam_enabled = None
+ self.mac_padding = None
+ self.dl_channel = None
+ self.cfi = None
+ self.paging_cycle = None
+ self.phich = None
+ self.drx_connected_mode = None
+ self.drx_on_duration_timer = None
+ self.drx_inactivity_timer = None
+ self.drx_retransmission_timer = None
+ self.drx_long_cycle = None
+ self.drx_long_cycle_offset = None
+
+ def configure(self, parameters):
+ """ Configures an LTE cell using a dictionary of parameters.
+
+ Args:
+ parameters: a configuration dictionary
+ """
+ # Setup band
+ if self.PARAM_BAND not in parameters:
+ raise ValueError(
+ "The configuration dictionary must include a key '{}' with "
+ "the required band number.".format(self.PARAM_BAND))
+
+ self.band = parameters[self.PARAM_BAND]
+
+ if self.PARAM_DL_EARFCN not in parameters:
+ band = int(self.band)
+ channel = int(lte_sim.LteSimulation.LOWEST_DL_CN_DICTIONARY[band] +
+ lte_sim.LteSimulation.LOWEST_DL_CN_DICTIONARY[band +
+ 1]) / 2
+ self.log.warning(
+ "Key '{}' was not set. Using center band channel {} by default."
+ .format(self.PARAM_DL_EARFCN, channel))
+ self.dl_channel = channel
+ else:
+ self.dl_channel = parameters[self.PARAM_DL_EARFCN]
+
+ # Set TDD-only configs
+ if self.get_duplex_mode() == lte_sim.DuplexMode.TDD:
+
+ # Sub-frame DL/UL config
+ if self.PARAM_FRAME_CONFIG not in parameters:
+ raise ValueError("When a TDD band is selected the frame "
+ "structure has to be indicated with the '{}' "
+ "key with a value from 0 to 6.".format(
+ self.PARAM_FRAME_CONFIG))
+
+ self.dlul_config = int(parameters[self.PARAM_FRAME_CONFIG])
+
+ # Special Sub-Frame configuration
+ if self.PARAM_SSF not in parameters:
+ self.log.warning(
+ 'The {} parameter was not provided. Setting '
+ 'Special Sub-Frame config to 6 by default.'.format(
+ self.PARAM_SSF))
+ self.ssf_config = 6
+ else:
+ self.ssf_config = int(parameters[self.PARAM_SSF])
+
+ # Setup bandwidth
+ if self.PARAM_BW not in parameters:
+ raise ValueError(
+ "The config dictionary must include parameter {} with an "
+ "int value (to indicate 1.4 MHz use 14).".format(
+ self.PARAM_BW))
+
+ bw = float(parameters[self.PARAM_BW])
+
+ if abs(bw - 14) < 0.00000000001:
+ bw = 1.4
+
+ self.bandwidth = bw
+
+ # Setup mimo mode
+ if self.PARAM_MIMO not in parameters:
+ raise ValueError(
+ "The config dictionary must include parameter '{}' with the "
+ "mimo mode.".format(self.PARAM_MIMO))
+
+ for mimo_mode in lte_sim.MimoMode:
+ if parameters[self.PARAM_MIMO] == mimo_mode.value:
+ self.mimo_mode = mimo_mode
+ break
+ else:
+ raise ValueError("The value of {} must be one of the following:"
+ "1x1, 2x2 or 4x4.".format(self.PARAM_MIMO))
+
+ # Setup transmission mode
+ if self.PARAM_TM not in parameters:
+ raise ValueError(
+ "The config dictionary must include key {} with an "
+ "int value from 1 to 4 indicating transmission mode.".format(
+ self.PARAM_TM))
+
+ for tm in lte_sim.TransmissionMode:
+ if parameters[self.PARAM_TM] == tm.value[2:]:
+ self.transmission_mode = tm
+ break
+ else:
+ raise ValueError(
+ "The {} key must have one of the following values:"
+ "1, 2, 3, 4, 7, 8 or 9.".format(self.PARAM_TM))
+
+ # Setup scheduling mode
+ if self.PARAM_SCHEDULING not in parameters:
+ self.scheduling_mode = lte_sim.SchedulingMode.STATIC
+ self.log.warning(
+ "The test config does not include the '{}' key. Setting to "
+ "static by default.".format(self.PARAM_SCHEDULING))
+ elif parameters[
+ self.PARAM_SCHEDULING] == self.PARAM_SCHEDULING_DYNAMIC:
+ self.scheduling_mode = lte_sim.SchedulingMode.DYNAMIC
+ elif parameters[self.PARAM_SCHEDULING] == self.PARAM_SCHEDULING_STATIC:
+ self.scheduling_mode = lte_sim.SchedulingMode.STATIC
+ else:
+ raise ValueError("Key '{}' must have a value of "
+ "'dynamic' or 'static'.".format(
+ self.PARAM_SCHEDULING))
+
+ if self.scheduling_mode == lte_sim.SchedulingMode.STATIC:
+
+ if self.PARAM_PADDING not in parameters:
+ self.log.warning(
+ "The '{}' parameter was not set. Enabling MAC padding by "
+ "default.".format(self.PARAM_PADDING))
+ self.mac_padding = True
+ else:
+ self.mac_padding = parameters[self.PARAM_PADDING]
+
+ if self.PARAM_PATTERN not in parameters:
+ self.log.warning(
+ "The '{}' parameter was not set, using 100% RBs for both "
+ "DL and UL. To set the percentages of total RBs include "
+ "the '{}' key with a list of two ints indicating downlink "
+ "and uplink percentages.".format(self.PARAM_PATTERN,
+ self.PARAM_PATTERN))
+ dl_pattern = 100
+ ul_pattern = 100
+ else:
+ dl_pattern = int(parameters[self.PARAM_PATTERN][0])
+ ul_pattern = int(parameters[self.PARAM_PATTERN][1])
+
+ if not (0 <= dl_pattern <= 100 and 0 <= ul_pattern <= 100):
+ raise ValueError(
+ "The scheduling pattern parameters need to be two "
+ "positive numbers between 0 and 100.")
+
+ self.dl_rbs, self.ul_rbs = (self.allocation_percentages_to_rbs(
+ dl_pattern, ul_pattern))
+
+ # Check if 256 QAM is enabled for DL MCS
+ if self.PARAM_DL_256_QAM_ENABLED not in parameters:
+ self.log.warning("The key '{}' is not set in the test config. "
+ "Setting to false by default.".format(
+ self.PARAM_DL_256_QAM_ENABLED))
+
+ self.dl_256_qam_enabled = parameters.get(
+ self.PARAM_DL_256_QAM_ENABLED, False)
+
+ # Look for a DL MCS configuration in the test parameters. If it is
+ # not present, use a default value.
+ if self.PARAM_DL_MCS in parameters:
+ self.dl_mcs = int(parameters[self.PARAM_DL_MCS])
+ else:
+ self.log.warning(
+ 'The test config does not include the {} key. Setting '
+ 'to the max value by default'.format(self.PARAM_DL_MCS))
+ if self.dl_256_qam_enabled and self.bandwidth == 1.4:
+ self.dl_mcs = 26
+ elif (not self.dl_256_qam_enabled and self.mac_padding
+ and self.bandwidth != 1.4):
+ self.dl_mcs = 28
+ else:
+ self.dl_mcs = 27
+
+ # Check if 64 QAM is enabled for UL MCS
+ if self.PARAM_UL_64_QAM_ENABLED not in parameters:
+ self.log.warning("The key '{}' is not set in the config file. "
+ "Setting to false by default.".format(
+ self.PARAM_UL_64_QAM_ENABLED))
+
+ self.ul_64_qam_enabled = parameters.get(
+ self.PARAM_UL_64_QAM_ENABLED, False)
+
+ # Look for an UL MCS configuration in the test parameters. If it is
+ # not present, use a default value.
+ if self.PARAM_UL_MCS in parameters:
+ self.ul_mcs = int(parameters[self.PARAM_UL_MCS])
+ else:
+ self.log.warning(
+ 'The test config does not include the {} key. Setting '
+ 'to the max value by default'.format(self.PARAM_UL_MCS))
+ if self.ul_64_qam_enabled:
+ self.ul_mcs = 28
+ else:
+ self.ul_mcs = 23
+
+ # Configure the simulation for DRX mode
+ if self.PARAM_DRX in parameters and len(
+ parameters[self.PARAM_DRX]) == 5:
+ self.drx_connected_mode = True
+ self.drx_on_duration_timer = parameters[self.PARAM_DRX][0]
+ self.drx_inactivity_timer = parameters[self.PARAM_DRX][1]
+ self.drx_retransmission_timer = parameters[self.PARAM_DRX][2]
+ self.drx_long_cycle = parameters[self.PARAM_DRX][3]
+ try:
+ long_cycle = int(parameters[self.PARAM_DRX][3])
+ long_cycle_offset = int(parameters[self.PARAM_DRX][4])
+ if long_cycle_offset in range(0, long_cycle):
+ self.drx_long_cycle_offset = long_cycle_offset
+ else:
+ self.log.error(
+ ("The cDRX long cycle offset must be in the "
+ "range 0 to (long cycle - 1). Setting "
+ "long cycle offset to 0"))
+ self.drx_long_cycle_offset = 0
+
+ except ValueError:
+ self.log.error(("cDRX long cycle and long cycle offset "
+ "must be integers. Disabling cDRX mode."))
+ self.drx_connected_mode = False
+ else:
+ self.log.warning(
+ ("DRX mode was not configured properly. "
+ "Please provide a list with the following values: "
+ "1) DRX on duration timer "
+ "2) Inactivity timer "
+ "3) Retransmission timer "
+ "4) Long DRX cycle duration "
+ "5) Long DRX cycle offset "
+ "Example: [2, 6, 16, 20, 0]."))
+
+ # Channel Control Indicator
+ if self.PARAM_CFI not in parameters:
+ self.log.warning('The {} parameter was not provided. Setting '
+ 'CFI to BESTEFFORT.'.format(self.PARAM_CFI))
+ self.cfi = 'BESTEFFORT'
+ else:
+ self.cfi = parameters[self.PARAM_CFI]
+
+ # PHICH group size
+ if self.PARAM_PHICH not in parameters:
+ self.log.warning('The {} parameter was not provided. Setting '
+ 'PHICH group size to 1 by default.'.format(
+ self.PARAM_PHICH))
+ self.phich = '1'
+ else:
+ if parameters[self.PARAM_PHICH] == '16':
+ self.phich = '1/6'
+ elif parameters[self.PARAM_PHICH] == '12':
+ self.phich = '1/2'
+ elif parameters[self.PARAM_PHICH] in ['1/6', '1/2', '1', '2']:
+ self.phich = parameters[self.PARAM_PHICH]
+ else:
+ raise ValueError('The {} parameter can only be followed by 1,'
+ '2, 1/2 (or 12) and 1/6 (or 16).'.format(
+ self.PARAM_PHICH))
+
+ # Paging cycle duration
+ if self.PARAM_PAGING not in parameters:
+ self.log.warning('The {} parameter was not provided. Setting '
+ 'paging cycle duration to 1280 ms by '
+ 'default.'.format(self.PARAM_PAGING))
+ self.paging_cycle = 1280
+ else:
+ try:
+ self.paging_cycle = int(parameters[self.PARAM_PAGING])
+ except ValueError:
+ raise ValueError(
+ 'The {} key has to be followed by the paging cycle '
+ 'duration in milliseconds.'.format(self.PARAM_PAGING))
+
+ def get_duplex_mode(self):
+ """ Determines if the cell uses FDD or TDD duplex mode
+
+ Returns:
+ an variable of class DuplexMode indicating if band is FDD or TDD
+ """
+ if 33 <= int(self.band) <= 46:
+ return lte_sim.DuplexMode.TDD
+ else:
+ return lte_sim.DuplexMode.FDD
+
+ def allocation_percentages_to_rbs(self, dl, ul):
+ """ Converts usage percentages to number of DL/UL RBs
+
+ Because not any number of DL/UL RBs can be obtained for a certain
+ bandwidth, this function calculates the number of RBs that most
+ closely matches the desired DL/UL percentages.
+
+ Args:
+ dl: desired percentage of downlink RBs
+ ul: desired percentage of uplink RBs
+ Returns:
+ a tuple indicating the number of downlink and uplink RBs
+ """
+
+ # Validate the arguments
+ if (not 0 <= dl <= 100) or (not 0 <= ul <= 100):
+ raise ValueError("The percentage of DL and UL RBs have to be two "
+ "positive between 0 and 100.")
+
+ # Get min and max values from tables
+ max_rbs = lte_sim.TOTAL_RBS_DICTIONARY[self.bandwidth]
+ min_dl_rbs = lte_sim.MIN_DL_RBS_DICTIONARY[self.bandwidth]
+ min_ul_rbs = lte_sim.MIN_UL_RBS_DICTIONARY[self.bandwidth]
+
+ def percentage_to_amount(min_val, max_val, percentage):
+ """ Returns the integer between min_val and max_val that is closest
+ to percentage/100*max_val
+ """
+
+ # Calculate the value that corresponds to the required percentage.
+ closest_int = round(max_val * percentage / 100)
+ # Cannot be less than min_val
+ closest_int = max(closest_int, min_val)
+ # RBs cannot be more than max_rbs
+ closest_int = min(closest_int, max_val)
+
+ return closest_int
+
+ # Calculate the number of DL RBs
+
+ # Get the number of DL RBs that corresponds to
+ # the required percentage.
+ desired_dl_rbs = percentage_to_amount(min_val=min_dl_rbs,
+ max_val=max_rbs,
+ percentage=dl)
+
+ if self.transmission_mode == lte_sim.TransmissionMode.TM3 or \
+ self.transmission_mode == lte_sim.TransmissionMode.TM4:
+
+ # For TM3 and TM4 the number of DL RBs needs to be max_rbs or a
+ # multiple of the RBG size
+
+ if desired_dl_rbs == max_rbs:
+ dl_rbs = max_rbs
+ else:
+ dl_rbs = (math.ceil(
+ desired_dl_rbs / lte_sim.RBG_DICTIONARY[self.bandwidth]) *
+ lte_sim.RBG_DICTIONARY[self.bandwidth])
+
+ else:
+ # The other TMs allow any number of RBs between 1 and max_rbs
+ dl_rbs = desired_dl_rbs
+
+ # Calculate the number of UL RBs
+
+ # Get the number of UL RBs that corresponds
+ # to the required percentage
+ desired_ul_rbs = percentage_to_amount(min_val=min_ul_rbs,
+ max_val=max_rbs,
+ percentage=ul)
+
+ # Create a list of all possible UL RBs assignment
+ # The standard allows any number that can be written as
+ # 2**a * 3**b * 5**c for any combination of a, b and c.
+
+ def pow_range(max_value, base):
+ """ Returns a range of all possible powers of base under
+ the given max_value.
+ """
+ return range(int(math.ceil(math.log(max_value, base))))
+
+ possible_ul_rbs = [
+ 2 ** a * 3 ** b * 5 ** c for a in pow_range(max_rbs, 2)
+ for b in pow_range(max_rbs, 3)
+ for c in pow_range(max_rbs, 5)
+ if 2 ** a * 3 ** b * 5 ** c <= max_rbs] # yapf: disable
+
+ # Find the value in the list that is closest to desired_ul_rbs
+ differences = [abs(rbs - desired_ul_rbs) for rbs in possible_ul_rbs]
+ ul_rbs = possible_ul_rbs[differences.index(min(differences))]
+
+ # Report what are the obtained RB percentages
+ self.log.info("Requested a {}% / {}% RB allocation. Closest possible "
+ "percentages are {}% / {}%.".format(
+ dl, ul, round(100 * dl_rbs / max_rbs),
+ round(100 * ul_rbs / max_rbs)))
+
+ return dl_rbs, ul_rbs
diff --git a/acts/framework/acts/controllers/cellular_lib/LteSimulation.py b/acts/framework/acts/controllers/cellular_lib/LteSimulation.py
index 9627e9f..7601bb7 100644
--- a/acts/framework/acts/controllers/cellular_lib/LteSimulation.py
+++ b/acts/framework/acts/controllers/cellular_lib/LteSimulation.py
@@ -13,11 +13,12 @@
# 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 math
+import time
from enum import Enum
from acts.controllers.cellular_lib.BaseSimulation import BaseSimulation
+from acts.controllers.cellular_lib.LteCellConfig import LteCellConfig
+from acts.controllers.cellular_lib.NrCellConfig import NrCellConfig
from acts.controllers.cellular_lib import BaseCellularDut
@@ -50,6 +51,7 @@
FDD = "FDD"
TDD = "TDD"
+
class ModulationType(Enum):
"""DL/UL Modulation order."""
QPSK = 'QPSK'
@@ -58,34 +60,26 @@
Q256 = '256QAM'
+# Bandwidth [MHz] to RB group size
+RBG_DICTIONARY = {20: 4, 15: 4, 10: 3, 5: 2, 3: 2, 1.4: 1}
+
+# Bandwidth [MHz] to total RBs mapping
+TOTAL_RBS_DICTIONARY = {20: 100, 15: 75, 10: 50, 5: 25, 3: 15, 1.4: 6}
+
+# Bandwidth [MHz] to minimum number of DL RBs that can be assigned to a UE
+MIN_DL_RBS_DICTIONARY = {20: 16, 15: 12, 10: 9, 5: 4, 3: 4, 1.4: 2}
+
+# Bandwidth [MHz] to minimum number of UL RBs that can be assigned to a UE
+MIN_UL_RBS_DICTIONARY = {20: 8, 15: 6, 10: 4, 5: 2, 3: 2, 1.4: 1}
+
+
class LteSimulation(BaseSimulation):
""" Single-carrier LTE simulation. """
-
- # Simulation config keywords contained in the test name
- PARAM_FRAME_CONFIG = "tddconfig"
- PARAM_BW = "bw"
- PARAM_SCHEDULING = "scheduling"
- PARAM_SCHEDULING_STATIC = "static"
- PARAM_SCHEDULING_DYNAMIC = "dynamic"
- PARAM_PATTERN = "pattern"
- PARAM_TM = "tm"
- PARAM_UL_PW = 'pul'
- PARAM_DL_PW = 'pdl'
- PARAM_BAND = "band"
- PARAM_MIMO = "mimo"
- PARAM_DL_MCS = 'dlmcs'
- PARAM_UL_MCS = 'ulmcs'
- PARAM_SSF = 'ssf'
- PARAM_CFI = 'cfi'
- PARAM_PAGING = 'paging'
- PARAM_PHICH = 'phich'
- PARAM_RRC_STATUS_CHANGE_TIMER = "rrcstatuschangetimer"
- PARAM_DRX = 'drx'
-
# Test config keywords
- KEY_TBS_PATTERN = "tbs_pattern_on"
- KEY_DL_256_QAM = "256_qam_dl"
- KEY_UL_64_QAM = "64_qam_ul"
+ KEY_FREQ_BANDS = "freq_bands"
+
+ # Cell param keywords
+ PARAM_RRC_STATUS_CHANGE_TIMER = "rrcstatuschangetimer"
# Units in which signal level is defined in DOWNLINK_SIGNAL_LEVEL_DICTIONARY
DOWNLINK_SIGNAL_LEVEL_UNITS = "RSRP"
@@ -96,7 +90,8 @@
'excellent': -75,
'high': -110,
'medium': -115,
- 'weak': -120
+ 'weak': -120,
+ 'disconnected': -170
}
# Transmitted output power for the phone (dBm)
@@ -107,18 +102,6 @@
'low': -20
}
- # Bandwidth [MHz] to total RBs mapping
- total_rbs_dictionary = {20: 100, 15: 75, 10: 50, 5: 25, 3: 15, 1.4: 6}
-
- # Bandwidth [MHz] to RB group size
- rbg_dictionary = {20: 4, 15: 4, 10: 3, 5: 2, 3: 2, 1.4: 1}
-
- # Bandwidth [MHz] to minimum number of DL RBs that can be assigned to a UE
- min_dl_rbs_dictionary = {20: 16, 15: 12, 10: 9, 5: 4, 3: 4, 1.4: 2}
-
- # Bandwidth [MHz] to minimum number of UL RBs that can be assigned to a UE
- min_ul_rbs_dictionary = {20: 8, 15: 6, 10: 4, 5: 2, 3: 2, 1.4: 1}
-
# Allowed bandwidth for each band.
allowed_bandwidth_dictionary = {
1: [5, 10, 15, 20],
@@ -185,6 +168,52 @@
255: [20]
}
+ # Dictionary of lower DL channel number bound for each band.
+ LOWEST_DL_CN_DICTIONARY = {
+ 1: 0,
+ 2: 600,
+ 3: 1200,
+ 4: 1950,
+ 5: 2400,
+ 6: 2650,
+ 7: 2750,
+ 8: 3450,
+ 9: 3800,
+ 10: 4150,
+ 11: 4750,
+ 12: 5010,
+ 13: 5180,
+ 14: 5280,
+ 17: 5730,
+ 18: 5850,
+ 19: 6000,
+ 20: 6150,
+ 21: 6450,
+ 22: 6600,
+ 23: 7500,
+ 24: 7700,
+ 25: 8040,
+ 26: 8690,
+ 27: 9040,
+ 28: 9210,
+ 29: 9660,
+ 30: 9770,
+ 31: 9870,
+ 32: 9920,
+ 33: 36000,
+ 34: 36200,
+ 35: 36350,
+ 36: 36950,
+ 37: 37550,
+ 38: 37750,
+ 39: 38250,
+ 40: 38650,
+ 41: 39650,
+ 42: 41590,
+ 43: 45590,
+ 66: 66436
+ }
+
# Peak throughput lookup tables for each TDD subframe
# configuration and bandwidth
# yapf: disable
@@ -372,90 +401,18 @@
# Peak throughput lookup table dictionary
tdd_config_tput_lut_dict = {
'TDD_CONFIG1':
- tdd_config1_tput_lut, # DL 256QAM, UL 64QAM & TBS turned OFF
+ tdd_config1_tput_lut, # DL 256QAM, UL 64QAM & MAC padding turned OFF
'TDD_CONFIG2':
- tdd_config2_tput_lut, # DL 256QAM, UL 64 QAM turned ON & TBS OFF
+ tdd_config2_tput_lut, # DL 256QAM, UL 64 QAM ON & MAC padding OFF
'TDD_CONFIG3':
- tdd_config3_tput_lut, # DL 256QAM, UL 64QAM & TBS turned ON
+ tdd_config3_tput_lut, # DL 256QAM, UL 64QAM & MAC padding ON
'TDD_CONFIG4':
- tdd_config4_tput_lut # DL 256QAM, UL 64 QAM turned OFF & TBS ON
+ tdd_config4_tput_lut # DL 256QAM, UL 64 QAM OFF & MAC padding ON
}
- class BtsConfig(BaseSimulation.BtsConfig):
- """ Extension of the BaseBtsConfig to implement parameters that are
- exclusive to LTE.
-
- Attributes:
- band: an integer indicating the required band number.
- dlul_config: an integer indicating the TDD config number.
- ssf_config: an integer indicating the Special Sub-Frame config.
- bandwidth: a float indicating the required channel bandwidth.
- mimo_mode: an instance of LteSimulation.MimoMode indicating the
- required MIMO mode for the downlink signal.
- transmission_mode: an instance of LteSimulation.TransmissionMode
- indicating the required TM.
- scheduling_mode: an instance of LteSimulation.SchedulingMode
- indicating wether to use Static or Dynamic scheduling.
- dl_rbs: an integer indicating the number of downlink RBs
- ul_rbs: an integer indicating the number of uplink RBs
- dl_mcs: an integer indicating the MCS for the downlink signal
- ul_mcs: an integer indicating the MCS for the uplink signal
- dl_modulation_order: a string indicating a DL modulation scheme
- ul_modulation_order: a string indicating an UL modulation scheme
- tbs_pattern_on: a boolean indicating whether full allocation mode
- should be used or not
- dl_channel: an integer indicating the downlink channel number
- cfi: an integer indicating the Control Format Indicator
- paging_cycle: an integer indicating the paging cycle duration in
- milliseconds
- phich: a string indicating the PHICH group size parameter
- drx_connected_mode: a boolean indicating whether cDRX mode is
- on or off
- drx_on_duration_timer: number of PDCCH subframes representing
- DRX on duration
- drx_inactivity_timer: number of PDCCH subframes to wait before
- entering DRX mode
- drx_retransmission_timer: number of consecutive PDCCH subframes
- to wait for retransmission
- drx_long_cycle: number of subframes representing one long DRX cycle.
- One cycle consists of DRX sleep + DRX on duration
- drx_long_cycle_offset: number representing offset in range
- 0 to drx_long_cycle - 1
- """
- def __init__(self):
- """ Initialize the base station config by setting all its
- parameters to None. """
- super().__init__()
- self.band = None
- self.dlul_config = None
- self.ssf_config = None
- self.bandwidth = None
- self.mimo_mode = None
- self.transmission_mode = None
- self.scheduling_mode = None
- self.dl_rbs = None
- self.ul_rbs = None
- self.dl_mcs = None
- self.ul_mcs = None
- self.dl_modulation_order = None
- self.ul_modulation_order = None
- self.tbs_pattern_on = None
- self.dl_channel = None
- self.cfi = None
- self.paging_cycle = None
- self.phich = None
- self.drx_connected_mode = None
- self.drx_on_duration_timer = None
- self.drx_inactivity_timer = None
- self.drx_retransmission_timer = None
- self.drx_long_cycle = None
- self.drx_long_cycle_offset = None
-
def __init__(self, simulator, log, dut, test_config, calibration_table):
""" Initializes the simulator for a single-carrier LTE simulation.
- Loads a simple LTE simulation enviroment with 1 basestation.
-
Args:
simulator: a cellular simulator controller
log: a logger handle
@@ -468,370 +425,110 @@
super().__init__(simulator, log, dut, test_config, calibration_table)
+ self.num_carriers = None
+
+ # Force device to LTE only so that it connects faster
self.dut.set_preferred_network_type(
BaseCellularDut.PreferredNetworkType.LTE_ONLY)
- # Get TBS pattern setting from the test configuration
- if self.KEY_TBS_PATTERN not in test_config:
+ # Get LTE CA frequency bands setting from the test configuration
+ if self.KEY_FREQ_BANDS not in test_config:
self.log.warning("The key '{}' is not set in the config file. "
- "Setting to true by default.".format(
- self.KEY_TBS_PATTERN))
- self.primary_config.tbs_pattern_on = test_config.get(
- self.KEY_TBS_PATTERN, True)
+ "Setting to null by default.".format(
+ self.KEY_FREQ_BANDS))
- # Get the 256-QAM setting from the test configuration
- if self.KEY_DL_256_QAM not in test_config:
- self.log.warning("The key '{}' is not set in the config file. "
- "Setting to false by default.".format(
- self.KEY_DL_256_QAM))
-
- self.dl_256_qam = test_config.get(self.KEY_DL_256_QAM, False)
-
- if self.dl_256_qam:
- if not self.simulator.LTE_SUPPORTS_DL_256QAM:
- self.log.warning("The key '{}' is set to true but the "
- "simulator doesn't support that modulation "
- "order.".format(self.KEY_DL_256_QAM))
- self.dl_256_qam = False
- else:
- self.primary_config.dl_modulation_order = ModulationType.Q256
-
- else:
- self.log.warning('dl modulation 256QAM is not specified in config, '
- 'setting to default value 64QAM')
- self.primary_config.dl_modulation_order = ModulationType.Q64
- # Get the 64-QAM setting from the test configuration
- if self.KEY_UL_64_QAM not in test_config:
- self.log.warning("The key '{}' is not set in the config file. "
- "Setting to false by default.".format(
- self.KEY_UL_64_QAM))
-
- self.ul_64_qam = test_config.get(self.KEY_UL_64_QAM, False)
-
- if self.ul_64_qam:
- if not self.simulator.LTE_SUPPORTS_UL_64QAM:
- self.log.warning("The key '{}' is set to true but the "
- "simulator doesn't support that modulation "
- "order.".format(self.KEY_UL_64_QAM))
- self.ul_64_qam = False
- else:
- self.primary_config.ul_modulation_order = ModulationType.Q64
- else:
- self.log.warning('ul modulation 64QAM is not specified in config, '
- 'setting to default value 16QAM')
- self.primary_config.ul_modulation_order = ModulationType.Q16
-
- self.simulator.configure_bts(self.primary_config)
+ self.freq_bands = test_config.get(self.KEY_FREQ_BANDS, True)
def setup_simulator(self):
""" Do initial configuration in the simulator. """
self.simulator.setup_lte_scenario()
- def parse_parameters(self, parameters):
- """ Configs an LTE simulation using a list of parameters.
+ def configure(self, parameters):
+ """ Configures simulation using a dictionary of parameters.
- Calls the parent method first, then consumes parameters specific to LTE.
+ Processes LTE configuration parameters.
Args:
- parameters: list of parameters
+ parameters: a configuration dictionary if there is only one carrier,
+ a list if there are multiple cells.
"""
+ # If there is a single item, put in a list
+ if not isinstance(parameters, list):
+ parameters = [parameters]
- # Instantiate a new configuration object
- new_config = self.BtsConfig()
+ # Pass only PCC configs to BaseSimulation
+ super().configure(parameters[0])
- # Setup band
-
- values = self.consume_parameter(parameters, self.PARAM_BAND, 1)
-
- if not values:
- raise ValueError(
- "The test name needs to include parameter '{}' followed by "
- "the required band number.".format(self.PARAM_BAND))
-
- new_config.band = values[1]
-
- # Set TDD-only configs
- if self.get_duplex_mode(new_config.band) == DuplexMode.TDD:
-
- # Sub-frame DL/UL config
- values = self.consume_parameter(parameters,
- self.PARAM_FRAME_CONFIG, 1)
- if not values:
+ new_cell_list = []
+ for cell in parameters:
+ if LteCellConfig.PARAM_BAND not in cell:
raise ValueError(
- "When a TDD band is selected the frame "
- "structure has to be indicated with the '{}' "
- "parameter followed by a number from 0 to 6.".format(
- self.PARAM_FRAME_CONFIG))
+ "The configuration dictionary must include a key '{}' with "
+ "the required band number.".format(
+ LteCellConfig.PARAM_BAND))
- new_config.dlul_config = int(values[1])
+ band = cell[LteCellConfig.PARAM_BAND]
- # Special Sub-Frame configuration
- values = self.consume_parameter(parameters, self.PARAM_SSF, 1)
+ if isinstance(band, str) and not band.isdigit():
+ # If band starts with n then it is an NR band
+ if band[0] == 'n' and band[1:].isdigit():
+ # If the remaining string is only the band number, add
+ # the cell and continue
+ new_cell_list.append(cell)
- if not values:
- self.log.warning(
- 'The {} parameter was not provided. Setting '
- 'Special Sub-Frame config to 6 by default.'.format(
- self.PARAM_SSF))
- new_config.ssf_config = 6
- else:
- new_config.ssf_config = int(values[1])
+ ca_class = band[-1].upper()
+ band_num = band[:-1]
- # Setup bandwidth
-
- values = self.consume_parameter(parameters, self.PARAM_BW, 1)
-
- if not values:
- raise ValueError(
- "The test name needs to include parameter {} followed by an "
- "int value (to indicate 1.4 MHz use 14).".format(
- self.PARAM_BW))
-
- bw = float(values[1])
-
- if bw == 14:
- bw = 1.4
-
- new_config.bandwidth = bw
-
- # Setup mimo mode
-
- values = self.consume_parameter(parameters, self.PARAM_MIMO, 1)
-
- if not values:
- raise ValueError(
- "The test name needs to include parameter '{}' followed by the "
- "mimo mode.".format(self.PARAM_MIMO))
-
- for mimo_mode in MimoMode:
- if values[1] == mimo_mode.value:
- new_config.mimo_mode = mimo_mode
- break
- else:
- raise ValueError("The {} parameter needs to be followed by either "
- "1x1, 2x2 or 4x4.".format(self.PARAM_MIMO))
-
- if (new_config.mimo_mode == MimoMode.MIMO_4x4
- and not self.simulator.LTE_SUPPORTS_4X4_MIMO):
- raise ValueError("The test requires 4x4 MIMO, but that is not "
- "supported by the cellular simulator.")
-
- # Setup transmission mode
-
- values = self.consume_parameter(parameters, self.PARAM_TM, 1)
-
- if not values:
- raise ValueError(
- "The test name needs to include parameter {} followed by an "
- "int value from 1 to 4 indicating transmission mode.".format(
- self.PARAM_TM))
-
- for tm in TransmissionMode:
- if values[1] == tm.value[2:]:
- new_config.transmission_mode = tm
- break
- else:
- raise ValueError("The {} parameter needs to be followed by either "
- "TM1, TM2, TM3, TM4, TM7, TM8 or TM9.".format(
- self.PARAM_MIMO))
-
- # Setup scheduling mode
-
- values = self.consume_parameter(parameters, self.PARAM_SCHEDULING, 1)
-
- if not values:
- new_config.scheduling_mode = SchedulingMode.STATIC
- self.log.warning(
- "The test name does not include the '{}' parameter. Setting to "
- "static by default.".format(self.PARAM_SCHEDULING))
- elif values[1] == self.PARAM_SCHEDULING_DYNAMIC:
- new_config.scheduling_mode = SchedulingMode.DYNAMIC
- elif values[1] == self.PARAM_SCHEDULING_STATIC:
- new_config.scheduling_mode = SchedulingMode.STATIC
- else:
- raise ValueError(
- "The test name parameter '{}' has to be followed by either "
- "'dynamic' or 'static'.".format(self.PARAM_SCHEDULING))
-
- if new_config.scheduling_mode == SchedulingMode.STATIC:
-
- values = self.consume_parameter(parameters, self.PARAM_PATTERN, 2)
-
- if not values:
- self.log.warning(
- "The '{}' parameter was not set, using 100% RBs for both "
- "DL and UL. To set the percentages of total RBs include "
- "the '{}' parameter followed by two ints separated by an "
- "underscore indicating downlink and uplink percentages.".
- format(self.PARAM_PATTERN, self.PARAM_PATTERN))
- dl_pattern = 100
- ul_pattern = 100
- else:
- dl_pattern = int(values[1])
- ul_pattern = int(values[2])
-
- if not (0 <= dl_pattern <= 100 and 0 <= ul_pattern <= 100):
- raise ValueError(
- "The scheduling pattern parameters need to be two "
- "positive numbers between 0 and 100.")
-
- new_config.dl_rbs, new_config.ul_rbs = (
- self.allocation_percentages_to_rbs(
- new_config.bandwidth, new_config.transmission_mode,
- dl_pattern, ul_pattern))
-
- # Look for a DL MCS configuration in the test parameters. If it is
- # not present, use a default value.
- dlmcs = self.consume_parameter(parameters, self.PARAM_DL_MCS, 1)
-
- if dlmcs:
- new_config.dl_mcs = int(dlmcs[1])
- else:
- self.log.warning(
- 'The test name does not include the {} parameter. Setting '
- 'to the max value by default'.format(self.PARAM_DL_MCS))
- if self.dl_256_qam and new_config.bandwidth == 1.4:
- new_config.dl_mcs = 26
- elif (not self.dl_256_qam
- and self.primary_config.tbs_pattern_on
- and new_config.bandwidth != 1.4):
- new_config.dl_mcs = 28
+ if ca_class in ['A', 'C']:
+ # Remove the CA class label and add the cell
+ cell[LteCellConfig.PARAM_BAND].band = band_num
+ new_cell_list.append(cell)
+ elif ca_class == 'B':
+ raise RuntimeError('Class B LTE CA not supported.')
else:
- new_config.dl_mcs = 27
+ raise ValueError('Invalid band value: ' + band)
- # Look for an UL MCS configuration in the test parameters. If it is
- # not present, use a default value.
- ulmcs = self.consume_parameter(parameters, self.PARAM_UL_MCS, 1)
-
- if ulmcs:
- new_config.ul_mcs = int(ulmcs[1])
+ # Class C means that there are two contiguous carriers
+ if ca_class == 'C':
+ new_cell_list.append(cell)
+ bw = int(cell[LteCellConfig.PARAM_BW])
+ new_cell_list[-1].dl_earfcn = int(
+ self.LOWEST_DL_CN_DICTIONARY[band_num] + bw * 10 - 2)
else:
- self.log.warning(
- 'The test name does not include the {} parameter. Setting '
- 'to the max value by default'.format(self.PARAM_UL_MCS))
- if self.ul_64_qam:
- new_config.ul_mcs = 28
- else:
- new_config.ul_mcs = 23
+ # The band is just a number, so just add it to the list
+ new_cell_list.append(cell)
- # Configure the simulation for DRX mode
+ self.simulator.set_band_combination(
+ [c[LteCellConfig.PARAM_BAND] for c in new_cell_list])
- drx = self.consume_parameter(parameters, self.PARAM_DRX, 5)
+ self.num_carriers = len(new_cell_list)
- if drx and len(drx) == 6:
- new_config.drx_connected_mode = True
- new_config.drx_on_duration_timer = drx[1]
- new_config.drx_inactivity_timer = drx[2]
- new_config.drx_retransmission_timer = drx[3]
- new_config.drx_long_cycle = drx[4]
- try:
- long_cycle = int(drx[4])
- long_cycle_offset = int(drx[5])
- if long_cycle_offset in range(0, long_cycle):
- new_config.drx_long_cycle_offset = long_cycle_offset
- else:
- self.log.error(("The cDRX long cycle offset must be in the "
- "range 0 to (long cycle - 1). Setting "
- "long cycle offset to 0"))
- new_config.drx_long_cycle_offset = 0
-
- except ValueError:
- self.log.error(("cDRX long cycle and long cycle offset "
- "must be integers. Disabling cDRX mode."))
- new_config.drx_connected_mode = False
- else:
- self.log.warning(("DRX mode was not configured properly. "
- "Please provide the following 5 values: "
- "1) DRX on duration timer "
- "2) Inactivity timer "
- "3) Retransmission timer "
- "4) Long DRX cycle duration "
- "5) Long DRX cycle offset "
- "Example: drx_2_6_16_20_0"))
-
- # Setup LTE RRC status change function and timer for LTE idle test case
- values = self.consume_parameter(parameters,
- self.PARAM_RRC_STATUS_CHANGE_TIMER, 1)
- if not values:
- self.log.info(
- "The test name does not include the '{}' parameter. Disabled "
- "by default.".format(self.PARAM_RRC_STATUS_CHANGE_TIMER))
- self.simulator.set_lte_rrc_state_change_timer(False)
- else:
- timer = int(values[1])
- self.simulator.set_lte_rrc_state_change_timer(True, timer)
- self.rrc_sc_timer = timer
-
- # Channel Control Indicator
- values = self.consume_parameter(parameters, self.PARAM_CFI, 1)
-
- if not values:
- self.log.warning('The {} parameter was not provided. Setting '
- 'CFI to BESTEFFORT.'.format(self.PARAM_CFI))
- new_config.cfi = 'BESTEFFORT'
- else:
- new_config.cfi = values[1]
-
- # PHICH group size
- values = self.consume_parameter(parameters, self.PARAM_PHICH, 1)
-
- if not values:
- self.log.warning('The {} parameter was not provided. Setting '
- 'PHICH group size to 1 by default.'.format(
- self.PARAM_PHICH))
- new_config.phich = '1'
- else:
- if values[1] == '16':
- new_config.phich = '1/6'
- elif values[1] == '12':
- new_config.phich = '1/2'
- elif values[1] in ['1/6', '1/2', '1', '2']:
- new_config.phich = values[1]
+ # Setup the base stations with the obtain configuration
+ self.cell_configs = []
+ for i in range(self.num_carriers):
+ band = new_cell_list[i][LteCellConfig.PARAM_BAND]
+ if isinstance(band, str) and band[0] == 'n':
+ self.cell_configs.append(NrCellConfig(self.log))
else:
- raise ValueError('The {} parameter can only be followed by 1,'
- '2, 1/2 (or 12) and 1/6 (or 16).'.format(
- self.PARAM_PHICH))
-
- # Paging cycle duration
- values = self.consume_parameter(parameters, self.PARAM_PAGING, 1)
-
- if not values:
- self.log.warning('The {} parameter was not provided. Setting '
- 'paging cycle duration to 1280 ms by '
- 'default.'.format(self.PARAM_PAGING))
- new_config.paging_cycle = 1280
- else:
- try:
- new_config.paging_cycle = int(values[1])
- except ValueError:
- raise ValueError(
- 'The {} parameter has to be followed by the paging cycle '
- 'duration in milliseconds.'.format(self.PARAM_PAGING))
-
- # Get uplink power
-
- ul_power = self.get_uplink_power_from_parameters(parameters)
-
- # Power is not set on the callbox until after the simulation is
- # started. Saving this value in a variable for later
- self.sim_ul_power = ul_power
-
- # Get downlink power
-
- dl_power = self.get_downlink_power_from_parameters(parameters)
-
- # Power is not set on the callbox until after the simulation is
- # started. Saving this value in a variable for later
- self.sim_dl_power = dl_power
-
- # Setup the base station with the obtained configuration and then save
- # these parameters in the current configuration object
- self.simulator.configure_bts(new_config)
- self.primary_config.incorporate(new_config)
+ self.cell_configs.append(LteCellConfig(self.log))
+ self.cell_configs[i].configure(new_cell_list[i])
+ self.simulator.configure_bts(self.cell_configs[i], i)
# Now that the band is set, calibrate the link if necessary
self.load_pathloss_if_required()
+ # This shouldn't be a cell parameter but instead a simulation config
+ # Setup LTE RRC status change function and timer for LTE idle test case
+ if self.PARAM_RRC_STATUS_CHANGE_TIMER not in parameters[0]:
+ self.log.info(
+ "The test config does not include the '{}' key. Disabled "
+ "by default.".format(self.PARAM_RRC_STATUS_CHANGE_TIMER))
+ self.simulator.set_lte_rrc_state_change_timer(False)
+ else:
+ timer = int(parameters[0][self.PARAM_RRC_STATUS_CHANGE_TIMER])
+ self.simulator.set_lte_rrc_state_change_timer(True, timer)
+ self.rrc_sc_timer = timer
+
def calibrated_downlink_rx_power(self, bts_config, rsrp):
""" LTE simulation overrides this method so that it can convert from
RSRP to total signal power transmitted from the basestation.
@@ -861,7 +558,7 @@
self.rsrp_to_signal_power
Returns:
- Dowlink calibration value and measured DL power. Note that the
+ Downlink calibration value and measured DL power. Note that the
phone only reports RSRP of the primary chain
"""
@@ -909,8 +606,9 @@
Maximum throughput in mbps.
"""
-
- return self.bts_maximum_downlink_throughtput(self.primary_config)
+ return sum(
+ self.bts_maximum_downlink_throughtput(self.cell_configs[bts_index])
+ for bts_index in range(self.num_carriers))
def bts_maximum_downlink_throughtput(self, bts_config):
""" Calculates maximum achievable downlink throughput for a single
@@ -934,18 +632,18 @@
'because the MIMO mode has not been set.')
bandwidth = bts_config.bandwidth
- rb_ratio = bts_config.dl_rbs / self.total_rbs_dictionary[bandwidth]
+ rb_ratio = bts_config.dl_rbs / TOTAL_RBS_DICTIONARY[bandwidth]
mcs = bts_config.dl_mcs
max_rate_per_stream = None
tdd_subframe_config = bts_config.dlul_config
- duplex_mode = self.get_duplex_mode(bts_config.band)
+ duplex_mode = bts_config.get_duplex_mode()
if duplex_mode == DuplexMode.TDD:
- if self.dl_256_qam:
+ if bts_config.dl_256_qam_enabled:
if mcs == 27:
- if bts_config.tbs_pattern_on:
+ if bts_config.mac_padding:
max_rate_per_stream = self.tdd_config_tput_lut_dict[
'TDD_CONFIG3'][tdd_subframe_config][bandwidth][
'DL']
@@ -955,7 +653,7 @@
'DL']
else:
if mcs == 28:
- if bts_config.tbs_pattern_on:
+ if bts_config.mac_padding:
max_rate_per_stream = self.tdd_config_tput_lut_dict[
'TDD_CONFIG4'][tdd_subframe_config][bandwidth][
'DL']
@@ -965,7 +663,7 @@
'DL']
elif duplex_mode == DuplexMode.FDD:
- if (not self.dl_256_qam and bts_config.tbs_pattern_on
+ if (not bts_config.dl_256_qam_enabled and bts_config.mac_padding
and mcs == 28):
max_rate_per_stream = {
3: 9.96,
@@ -974,13 +672,13 @@
15: 52.7,
20: 72.2
}.get(bandwidth, None)
- if (not self.dl_256_qam and bts_config.tbs_pattern_on
+ if (not bts_config.dl_256_qam_enabled and bts_config.mac_padding
and mcs == 27):
max_rate_per_stream = {
1.4: 2.94,
}.get(bandwidth, None)
- elif (not self.dl_256_qam and not bts_config.tbs_pattern_on
- and mcs == 27):
+ elif (not bts_config.dl_256_qam_enabled
+ and not bts_config.mac_padding and mcs == 27):
max_rate_per_stream = {
1.4: 2.87,
3: 7.7,
@@ -989,7 +687,7 @@
15: 42.3,
20: 57.7
}.get(bandwidth, None)
- elif self.dl_256_qam and bts_config.tbs_pattern_on and mcs == 27:
+ elif bts_config.dl_256_qam_enabled and bts_config.mac_padding and mcs == 27:
max_rate_per_stream = {
3: 13.2,
5: 22.9,
@@ -997,11 +695,11 @@
15: 72.2,
20: 93.9
}.get(bandwidth, None)
- elif self.dl_256_qam and bts_config.tbs_pattern_on and mcs == 26:
+ elif bts_config.dl_256_qam_enabled and bts_config.mac_padding and mcs == 26:
max_rate_per_stream = {
1.4: 3.96,
}.get(bandwidth, None)
- elif (self.dl_256_qam and not bts_config.tbs_pattern_on
+ elif (bts_config.dl_256_qam_enabled and not bts_config.mac_padding
and mcs == 27):
max_rate_per_stream = {
3: 11.3,
@@ -1010,7 +708,7 @@
15: 68.1,
20: 88.4
}.get(bandwidth, None)
- elif (self.dl_256_qam and not bts_config.tbs_pattern_on
+ elif (bts_config.dl_256_qam_enabled and not bts_config.mac_padding
and mcs == 26):
max_rate_per_stream = {
1.4: 3.96,
@@ -1018,9 +716,9 @@
if not max_rate_per_stream:
raise NotImplementedError(
- "The calculation for tbs pattern = {} "
+ "The calculation for MAC padding = {} "
"and mcs = {} is not implemented.".format(
- "FULLALLOCATION" if bts_config.tbs_pattern_on else "OFF",
+ "FULLALLOCATION" if bts_config.mac_padding else "OFF",
mcs))
return max_rate_per_stream * streams * rb_ratio
@@ -1034,7 +732,7 @@
"""
- return self.bts_maximum_uplink_throughtput(self.primary_config)
+ return self.bts_maximum_uplink_throughtput(self.cell_configs[0])
def bts_maximum_uplink_throughtput(self, bts_config):
""" Calculates maximum achievable uplink throughput for the selected
@@ -1049,18 +747,18 @@
"""
bandwidth = bts_config.bandwidth
- rb_ratio = bts_config.ul_rbs / self.total_rbs_dictionary[bandwidth]
+ rb_ratio = bts_config.ul_rbs / TOTAL_RBS_DICTIONARY[bandwidth]
mcs = bts_config.ul_mcs
max_rate_per_stream = None
tdd_subframe_config = bts_config.dlul_config
- duplex_mode = self.get_duplex_mode(bts_config.band)
+ duplex_mode = bts_config.get_duplex_mode()
if duplex_mode == DuplexMode.TDD:
- if self.ul_64_qam:
+ if bts_config.ul_64_qam_enabled:
if mcs == 28:
- if bts_config.tbs_pattern_on:
+ if bts_config.mac_padding:
max_rate_per_stream = self.tdd_config_tput_lut_dict[
'TDD_CONFIG3'][tdd_subframe_config][bandwidth][
'UL']
@@ -1070,7 +768,7 @@
'UL']
else:
if mcs == 23:
- if bts_config.tbs_pattern_on:
+ if bts_config.mac_padding:
max_rate_per_stream = self.tdd_config_tput_lut_dict[
'TDD_CONFIG4'][tdd_subframe_config][bandwidth][
'UL']
@@ -1080,7 +778,7 @@
'UL']
elif duplex_mode == DuplexMode.FDD:
- if mcs == 23 and not self.ul_64_qam:
+ if mcs == 23 and not bts_config.ul_64_qam_enabled:
max_rate_per_stream = {
1.4: 2.85,
3: 7.18,
@@ -1089,7 +787,7 @@
15: 36.5,
20: 49.1
}.get(bandwidth, None)
- elif mcs == 28 and self.ul_64_qam:
+ elif mcs == 28 and bts_config.ul_64_qam_enabled:
max_rate_per_stream = {
1.4: 4.2,
3: 10.5,
@@ -1102,110 +800,11 @@
if not max_rate_per_stream:
raise NotImplementedError(
"The calculation fir mcs = {} is not implemented.".format(
- "FULLALLOCATION" if bts_config.tbs_pattern_on else "OFF",
+ "FULLALLOCATION" if bts_config.mac_padding else "OFF",
mcs))
return max_rate_per_stream * rb_ratio
- def allocation_percentages_to_rbs(self, bw, tm, dl, ul):
- """ Converts usage percentages to number of DL/UL RBs
-
- Because not any number of DL/UL RBs can be obtained for a certain
- bandwidth, this function calculates the number of RBs that most
- closely matches the desired DL/UL percentages.
-
- Args:
- bw: the bandwidth for the which the RB configuration is requested
- tm: the transmission in which the base station will be operating
- dl: desired percentage of downlink RBs
- ul: desired percentage of uplink RBs
- Returns:
- a tuple indicating the number of downlink and uplink RBs
- """
-
- # Validate the arguments
- if (not 0 <= dl <= 100) or (not 0 <= ul <= 100):
- raise ValueError("The percentage of DL and UL RBs have to be two "
- "positive between 0 and 100.")
-
- # Get min and max values from tables
- max_rbs = self.total_rbs_dictionary[bw]
- min_dl_rbs = self.min_dl_rbs_dictionary[bw]
- min_ul_rbs = self.min_ul_rbs_dictionary[bw]
-
- def percentage_to_amount(min_val, max_val, percentage):
- """ Returns the integer between min_val and max_val that is closest
- to percentage/100*max_val
- """
-
- # Calculate the value that corresponds to the required percentage.
- closest_int = round(max_val * percentage / 100)
- # Cannot be less than min_val
- closest_int = max(closest_int, min_val)
- # RBs cannot be more than max_rbs
- closest_int = min(closest_int, max_val)
-
- return closest_int
-
- # Calculate the number of DL RBs
-
- # Get the number of DL RBs that corresponds to
- # the required percentage.
- desired_dl_rbs = percentage_to_amount(min_val=min_dl_rbs,
- max_val=max_rbs,
- percentage=dl)
-
- if tm == TransmissionMode.TM3 or tm == TransmissionMode.TM4:
-
- # For TM3 and TM4 the number of DL RBs needs to be max_rbs or a
- # multiple of the RBG size
-
- if desired_dl_rbs == max_rbs:
- dl_rbs = max_rbs
- else:
- dl_rbs = (math.ceil(desired_dl_rbs / self.rbg_dictionary[bw]) *
- self.rbg_dictionary[bw])
-
- else:
- # The other TMs allow any number of RBs between 1 and max_rbs
- dl_rbs = desired_dl_rbs
-
- # Calculate the number of UL RBs
-
- # Get the number of UL RBs that corresponds
- # to the required percentage
- desired_ul_rbs = percentage_to_amount(min_val=min_ul_rbs,
- max_val=max_rbs,
- percentage=ul)
-
- # Create a list of all possible UL RBs assignment
- # The standard allows any number that can be written as
- # 2**a * 3**b * 5**c for any combination of a, b and c.
-
- def pow_range(max_value, base):
- """ Returns a range of all possible powers of base under
- the given max_value.
- """
- return range(int(math.ceil(math.log(max_value, base))))
-
- possible_ul_rbs = [
- 2**a * 3**b * 5**c for a in pow_range(max_rbs, 2)
- for b in pow_range(max_rbs, 3)
- for c in pow_range(max_rbs, 5)
- if 2**a * 3**b * 5**c <= max_rbs] # yapf: disable
-
- # Find the value in the list that is closest to desired_ul_rbs
- differences = [abs(rbs - desired_ul_rbs) for rbs in possible_ul_rbs]
- ul_rbs = possible_ul_rbs[differences.index(min(differences))]
-
- # Report what are the obtained RB percentages
- self.log.info("Requested a {}% / {}% RB allocation. Closest possible "
- "percentages are {}% / {}%.".format(
- dl, ul, round(100 * dl_rbs / max_rbs),
- round(100 * ul_rbs / max_rbs)))
-
- return dl_rbs, ul_rbs
-
def calibrate(self, band):
""" Calculates UL and DL path loss if it wasn't done before
@@ -1217,55 +816,37 @@
"""
# Save initial values in a configuration object so they can be restored
- restore_config = self.BtsConfig()
- restore_config.mimo_mode = self.primary_config.mimo_mode
- restore_config.transmission_mode = self.primary_config.transmission_mode
- restore_config.bandwidth = self.primary_config.bandwidth
+ restore_config = LteCellConfig(self.log)
+ restore_config.mimo_mode = self.cell_configs[0].mimo_mode
+ restore_config.transmission_mode = \
+ self.cell_configs[0].transmission_mode
+ restore_config.bandwidth = self.cell_configs[0].bandwidth
# Set up a temporary calibration configuration.
- temporary_config = self.BtsConfig()
+ temporary_config = LteCellConfig(self.log)
temporary_config.mimo_mode = MimoMode.MIMO_1x1
temporary_config.transmission_mode = TransmissionMode.TM1
temporary_config.bandwidth = max(
self.allowed_bandwidth_dictionary[int(band)])
self.simulator.configure_bts(temporary_config)
- self.primary_config.incorporate(temporary_config)
+ self.cell_configs[0].incorporate(temporary_config)
super().calibrate(band)
# Restore values as they were before changing them for calibration.
self.simulator.configure_bts(restore_config)
- self.primary_config.incorporate(restore_config)
+ self.cell_configs[0].incorporate(restore_config)
def start_traffic_for_calibration(self):
- """
- If TBS pattern is set to full allocation, there is no need to start
- IP traffic.
- """
- if not self.primary_config.tbs_pattern_on:
+ """ If MAC padding is enabled, there is no need to start IP traffic. """
+ if not self.cell_configs[0].mac_padding:
super().start_traffic_for_calibration()
def stop_traffic_for_calibration(self):
- """
- If TBS pattern is set to full allocation, IP traffic wasn't started
- """
- if not self.primary_config.tbs_pattern_on:
+ """ If MAC padding is enabled, IP traffic wasn't started. """
+ if not self.cell_configs[0].mac_padding:
super().stop_traffic_for_calibration()
- def get_duplex_mode(self, band):
- """ Determines if the band uses FDD or TDD duplex mode
-
- Args:
- band: a band number
- Returns:
- an variable of class DuplexMode indicating if band is FDD or TDD
- """
-
- if 33 <= int(band) <= 46:
- return DuplexMode.TDD
- else:
- return DuplexMode.FDD
-
def get_measured_ul_power(self, samples=5, wait_after_sample=3):
""" Calculates UL power using measurements from the callbox and the
calibration data.
@@ -1293,3 +874,25 @@
'uncalibrated values as measured by the '
'callbox.')
return ul_power_sum / samples
+
+ def start(self):
+ """ Set the signal level for the secondary carriers, as the base class
+ implementation of this method will only set up downlink power for the
+ primary carrier component.
+
+ After that, attaches the secondary carriers."""
+
+ super().start()
+
+ if self.num_carriers > 1:
+ if self.sim_dl_power:
+ self.log.info('Setting DL power for secondary carriers.')
+
+ for bts_index in range(1, self.num_carriers):
+ new_config = LteCellConfig(self.log)
+ new_config.output_power = self.calibrated_downlink_rx_power(
+ self.cell_configs[bts_index], self.sim_dl_power)
+ self.simulator.configure_bts(new_config, bts_index)
+ self.cell_configs[bts_index].incorporate(new_config)
+
+ self.simulator.lte_attach_secondary_carriers(self.freq_bands)
diff --git a/acts/framework/acts/controllers/cellular_lib/NrCellConfig.py b/acts/framework/acts/controllers/cellular_lib/NrCellConfig.py
new file mode 100644
index 0000000..5a18025
--- /dev/null
+++ b/acts/framework/acts/controllers/cellular_lib/NrCellConfig.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import acts.controllers.cellular_lib.BaseCellConfig as base_cell
+
+
+class NrCellConfig(base_cell.BaseCellConfig):
+ """ NR cell configuration class.
+
+ Attributes:
+ band: an integer indicating the required band number.
+ bandwidth: a integer indicating the required channel bandwidth
+ """
+
+ PARAM_BAND = "band"
+ PARAM_BW = "bw"
+
+ def __init__(self, log):
+ """ Initialize the base station config by setting all its
+ parameters to None.
+ Args:
+ log: logger object.
+ """
+ super().__init__(log)
+ self.band = None
+ self.bandwidth = None
+
+ def configure(self, parameters):
+ """ Configures an NR cell using a dictionary of parameters.
+
+ Args:
+ parameters: a configuration dictionary
+ """
+ if self.PARAM_BAND not in parameters:
+ raise ValueError(
+ "The configuration dictionary must include a key '{}' with "
+ "the required band number.".format(self.PARAM_BAND))
+
+ self.band = parameters[self.PARAM_BAND]
+
+ if self.PARAM_BW not in parameters:
+ raise ValueError(
+ "The config dictionary must include parameter {} with an "
+ "int value (to indicate 1.4 MHz use 14).".format(
+ self.PARAM_BW))
+
+ self.bandwidth = parameters[self.PARAM_BW]
diff --git a/acts/framework/acts/controllers/cellular_lib/UmtsSimulation.py b/acts/framework/acts/controllers/cellular_lib/UmtsSimulation.py
index b301a6b..1e60813 100644
--- a/acts/framework/acts/controllers/cellular_lib/UmtsSimulation.py
+++ b/acts/framework/acts/controllers/cellular_lib/UmtsSimulation.py
@@ -39,13 +39,11 @@
UMTS_R8_CELL_FILE = 'CELL_WCDMA_R8_config.wnscp'
- # Test name parameters
+ # Configuration dictionary keys
PARAM_RELEASE_VERSION = "r"
PARAM_RELEASE_VERSION_99 = "99"
PARAM_RELEASE_VERSION_8 = "8"
PARAM_RELEASE_VERSION_7 = "7"
- PARAM_UL_PW = 'pul'
- PARAM_DL_PW = 'pdl'
PARAM_BAND = "band"
PARAM_RRC_STATUS_CHANGE_TIMER = "rrcstatuschangetimer"
@@ -92,7 +90,7 @@
def __init__(self, simulator, log, dut, test_config, calibration_table):
""" Initializes the cellular simulator for a UMTS simulation.
- Loads a simple UMTS simulation enviroment with 1 basestation. It also
+ Loads a simple UMTS simulation environment with 1 basestation. It also
creates the BTS handle so we can change the parameters as desired.
Args:
@@ -136,72 +134,50 @@
# Start simulation if it wasn't started
self.anritsu.start_simulation()
- def parse_parameters(self, parameters):
- """ Configs an UMTS simulation using a list of parameters.
+ def configure(self, parameters):
+ """ Configures simulation using a dictionary of parameters.
- Calls the parent method and consumes parameters specific to UMTS.
+ Processes UMTS configuration parameters.
Args:
- parameters: list of parameters
+ parameters: a configuration dictionary
"""
+ super().configure(parameters)
# Setup band
-
- values = self.consume_parameter(parameters, self.PARAM_BAND, 1)
-
- if not values:
+ if self.PARAM_BAND not in parameters:
raise ValueError(
- "The test name needs to include parameter '{}' followed by "
+ "The configuration dictionary must include a key '{}' with "
"the required band number.".format(self.PARAM_BAND))
- self.set_band(self.bts1, values[1])
+ self.set_band(self.bts1, parameters[self.PARAM_BAND])
self.load_pathloss_if_required()
# Setup release version
-
- values = self.consume_parameter(parameters, self.PARAM_RELEASE_VERSION,
- 1)
-
- if not values or values[1] not in [
- self.PARAM_RELEASE_VERSION_7, self.PARAM_RELEASE_VERSION_8,
- self.PARAM_RELEASE_VERSION_99
- ]:
+ if (self.PARAM_RELEASE_VERSION not in parameters
+ or parameters[self.PARAM_RELEASE_VERSION] not in [
+ self.PARAM_RELEASE_VERSION_7, self.PARAM_RELEASE_VERSION_8,
+ self.PARAM_RELEASE_VERSION_99
+ ]):
raise ValueError(
- "The test name needs to include the parameter {} followed by a "
+ "The configuration dictionary must include a key '{}' with a "
"valid release version.".format(self.PARAM_RELEASE_VERSION))
- self.set_release_version(self.bts1, values[1])
+ self.set_release_version(self.bts1,
+ parameters[self.PARAM_RELEASE_VERSION])
# Setup W-CDMA RRC status change and CELL_DCH timer for idle test case
-
- values = self.consume_parameter(parameters,
- self.PARAM_RRC_STATUS_CHANGE_TIMER, 1)
- if not values:
+ if self.PARAM_RRC_STATUS_CHANGE_TIMER not in parameters:
self.log.info(
- "The test name does not include the '{}' parameter. Disabled "
+ "The config dictionary does not include a '{}' key. Disabled "
"by default.".format(self.PARAM_RRC_STATUS_CHANGE_TIMER))
self.anritsu.set_umts_rrc_status_change(False)
else:
- self.rrc_sc_timer = int(values[1])
+ self.rrc_sc_timer = int(
+ parameters[self.PARAM_RRC_STATUS_CHANGE_TIMER])
self.anritsu.set_umts_rrc_status_change(True)
self.anritsu.set_umts_dch_stat_timer(self.rrc_sc_timer)
- # Setup uplink power
-
- ul_power = self.get_uplink_power_from_parameters(parameters)
-
- # Power is not set on the callbox until after the simulation is
- # started. Saving this value in a variable for later
- self.sim_ul_power = ul_power
-
- # Setup downlink power
-
- dl_power = self.get_downlink_power_from_parameters(parameters)
-
- # Power is not set on the callbox until after the simulation is
- # started. Saving this value in a variable for later
- self.sim_dl_power = dl_power
-
def set_release_version(self, bts, release_version):
""" Sets the release version.
diff --git a/acts/framework/acts/controllers/cellular_simulator.py b/acts/framework/acts/controllers/cellular_simulator.py
index 99adbd8..0a026e6 100644
--- a/acts/framework/acts/controllers/cellular_simulator.py
+++ b/acts/framework/acts/controllers/cellular_simulator.py
@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from acts import logger
-from acts.controllers import cellular_lib as sims
+from acts.controllers import cellular_lib
class AbstractCellularSimulator:
@@ -25,15 +25,6 @@
This class defines the interface that every cellular simulator controller
needs to implement and shouldn't be instantiated by itself. """
- # Indicates if it is able to use 256 QAM as the downlink modulation for LTE
- LTE_SUPPORTS_DL_256QAM = None
-
- # Indicates if it is able to use 64 QAM as the uplink modulation for LTE
- LTE_SUPPORTS_UL_64QAM = None
-
- # Indicates if 4x4 MIMO is supported for LTE
- LTE_SUPPORTS_4X4_MIMO = None
-
# The maximum number of carriers that this simulator can support for LTE
LTE_MAX_CARRIERS = None
@@ -43,6 +34,7 @@
def __init__(self):
""" Initializes the cellular simulator. """
self.log = logger.create_tagged_trace_logger('CellularSimulator')
+ self.num_carriers = None
def destroy(self):
""" Sends finalization commands to the cellular equipment and closes
@@ -53,24 +45,11 @@
""" Configures the equipment for an LTE simulation. """
raise NotImplementedError()
- def setup_lte_ca_scenario(self):
- """ Configures the equipment for an LTE with CA simulation. """
- raise NotImplementedError()
-
- def set_ca_combination(self, combination):
+ def set_band_combination(self, bands):
""" Prepares the test equipment for the indicated CA combination.
- The reason why this is implemented in a separate method and not calling
- LteSimulation.BtsConfig for each separate band is that configuring each
- ssc cannot be done separately, as it is necessary to know which
- carriers are on the same band in order to decide which RF outputs can
- be shared in the test equipment.
-
Args:
- combination: carrier aggregation configurations are indicated
- with a list of strings consisting of the band number followed
- by the CA class. For example, for 5 CA using 3C 7C and 28A
- the parameter value should be [3c, 7c, 28a].
+ bands: a list of bands represented as ints or strings
"""
raise NotImplementedError()
@@ -90,7 +69,7 @@
if config.input_power:
self.set_input_power(bts_index, config.input_power)
- if isinstance(config, sims.LteSimulation.LteSimulation.BtsConfig):
+ if isinstance(config, cellular_lib.LteCellConfig.LteCellConfig):
self.configure_lte_bts(config, bts_index)
def configure_lte_bts(self, config, bts_index=0):
@@ -124,16 +103,16 @@
# Modulation order should be set before set_scheduling_mode being
# called.
- if config.dl_modulation_order:
- self.set_dl_modulation(bts_index, config.dl_modulation_order)
+ if config.dl_256_qam_enabled is not None:
+ self.set_dl_256_qam_enabled(bts_index, config.dl_256_qam_enabled)
- if config.ul_modulation_order:
- self.set_ul_modulation(bts_index, config.ul_modulation_order)
+ if config.ul_64_qam_enabled is not None:
+ self.set_ul_64_qam_enabled(bts_index, config.ul_64_qam_enabled)
if config.scheduling_mode:
if (config.scheduling_mode ==
- sims.LteSimulation.SchedulingMode.STATIC
+ cellular_lib.LteSimulation.SchedulingMode.STATIC
and not (config.dl_rbs and config.ul_rbs and config.dl_mcs
and config.ul_mcs)):
raise ValueError('When the scheduling mode is set to manual, '
@@ -147,8 +126,8 @@
# This variable stores a boolean value so the following is needed to
# differentiate False from None
- if config.tbs_pattern_on is not None:
- self.set_tbs_pattern_on(bts_index, config.tbs_pattern_on)
+ if config.mac_padding is not None:
+ self.set_mac_padding(bts_index, config.mac_padding)
if config.cfi:
self.set_cfi(bts_index, config.cfi)
@@ -286,30 +265,30 @@
"""
raise NotImplementedError()
- def set_dl_modulation(self, bts_index, modulation):
- """ Sets the DL modulation for the indicated base station.
+ def set_dl_256_qam_enabled(self, bts_index, enabled):
+ """ Determines what MCS table should be used for the downlink.
Args:
bts_index: the base station number
- modulation: the new DL modulation
+ enabled: whether 256 QAM should be used
"""
raise NotImplementedError()
- def set_ul_modulation(self, bts_index, modulation):
- """ Sets the UL modulation for the indicated base station.
+ def set_ul_64_qam_enabled(self, bts_index, enabled):
+ """ Determines what MCS table should be used for the uplink.
Args:
bts_index: the base station number
- modulation: the new UL modulation
+ enabled: whether 64 QAM should be used
"""
raise NotImplementedError()
- def set_tbs_pattern_on(self, bts_index, tbs_pattern_on):
- """ Enables or disables TBS pattern in the indicated base station.
+ def set_mac_padding(self, bts_index, mac_padding):
+ """ Enables or disables MAC padding in the indicated base station.
Args:
bts_index: the base station number
- tbs_pattern_on: the new TBS pattern setting
+ mac_padding: the new MAC padding setting
"""
raise NotImplementedError()
diff --git a/acts/framework/acts/controllers/fuchsia_device.py b/acts/framework/acts/controllers/fuchsia_device.py
index 6e4419e..f2b8866 100644
--- a/acts/framework/acts/controllers/fuchsia_device.py
+++ b/acts/framework/acts/controllers/fuchsia_device.py
@@ -17,57 +17,59 @@
import backoff
import json
import logging
-import platform
import os
import random
import re
import requests
-import subprocess
import socket
+import subprocess
import time
from acts import context
from acts import logger as acts_logger
-from acts import utils
from acts import signals
-
+from acts import utils
from acts.controllers import pdu
+from acts.libs.proc import job
+from acts.utils import get_fuchsia_mdns_ipv6_address
from acts.controllers.fuchsia_lib.audio_lib import FuchsiaAudioLib
from acts.controllers.fuchsia_lib.backlight_lib import FuchsiaBacklightLib
-from acts.controllers.fuchsia_lib.bt.avdtp_lib import FuchsiaAvdtpLib
-from acts.controllers.fuchsia_lib.bt.hfp_lib import FuchsiaHfpLib
-from acts.controllers.fuchsia_lib.light_lib import FuchsiaLightLib
-
from acts.controllers.fuchsia_lib.basemgr_lib import FuchsiaBasemgrLib
+from acts.controllers.fuchsia_lib.bt.avdtp_lib import FuchsiaAvdtpLib
from acts.controllers.fuchsia_lib.bt.ble_lib import FuchsiaBleLib
from acts.controllers.fuchsia_lib.bt.bts_lib import FuchsiaBtsLib
from acts.controllers.fuchsia_lib.bt.gattc_lib import FuchsiaGattcLib
from acts.controllers.fuchsia_lib.bt.gatts_lib import FuchsiaGattsLib
+from acts.controllers.fuchsia_lib.bt.hfp_lib import FuchsiaHfpLib
+from acts.controllers.fuchsia_lib.bt.rfcomm_lib import FuchsiaRfcommLib
from acts.controllers.fuchsia_lib.bt.sdp_lib import FuchsiaProfileServerLib
+from acts.controllers.fuchsia_lib.ffx import FFX
from acts.controllers.fuchsia_lib.gpio_lib import FuchsiaGpioLib
from acts.controllers.fuchsia_lib.hardware_power_statecontrol_lib import FuchsiaHardwarePowerStatecontrolLib
from acts.controllers.fuchsia_lib.hwinfo_lib import FuchsiaHwinfoLib
from acts.controllers.fuchsia_lib.i2c_lib import FuchsiaI2cLib
from acts.controllers.fuchsia_lib.input_report_lib import FuchsiaInputReportLib
from acts.controllers.fuchsia_lib.kernel_lib import FuchsiaKernelLib
+from acts.controllers.fuchsia_lib.lib_controllers.netstack_controller import NetstackController
+from acts.controllers.fuchsia_lib.lib_controllers.wlan_controller import WlanController
+from acts.controllers.fuchsia_lib.lib_controllers.wlan_policy_controller import WlanPolicyController
+from acts.controllers.fuchsia_lib.light_lib import FuchsiaLightLib
from acts.controllers.fuchsia_lib.location.regulatory_region_lib import FuchsiaRegulatoryRegionLib
from acts.controllers.fuchsia_lib.logging_lib import FuchsiaLoggingLib
from acts.controllers.fuchsia_lib.netstack.netstack_lib import FuchsiaNetstackLib
from acts.controllers.fuchsia_lib.ram_lib import FuchsiaRamLib
-from acts.controllers.fuchsia_lib.syslog_lib import FuchsiaSyslogError
-from acts.controllers.fuchsia_lib.syslog_lib import start_syslog
+from acts.controllers.fuchsia_lib.session_manager_lib import FuchsiaSessionManagerLib
from acts.controllers.fuchsia_lib.sysinfo_lib import FuchsiaSysInfoLib
-from acts.controllers.fuchsia_lib.utils_lib import create_ssh_connection
+from acts.controllers.fuchsia_lib.syslog_lib import FuchsiaSyslogError
+from acts.controllers.fuchsia_lib.syslog_lib import create_syslog_process
from acts.controllers.fuchsia_lib.utils_lib import SshResults
+from acts.controllers.fuchsia_lib.utils_lib import create_ssh_connection
+from acts.controllers.fuchsia_lib.utils_lib import flash
+from acts.controllers.fuchsia_lib.wlan_ap_policy_lib import FuchsiaWlanApPolicyLib
from acts.controllers.fuchsia_lib.wlan_deprecated_configuration_lib import FuchsiaWlanDeprecatedConfigurationLib
from acts.controllers.fuchsia_lib.wlan_lib import FuchsiaWlanLib
-from acts.controllers.fuchsia_lib.wlan_ap_policy_lib import FuchsiaWlanApPolicyLib
from acts.controllers.fuchsia_lib.wlan_policy_lib import FuchsiaWlanPolicyLib
-from acts.controllers.fuchsia_lib.lib_controllers.wlan_controller import WlanController
-from acts.controllers.fuchsia_lib.lib_controllers.wlan_policy_controller import WlanPolicyController
-from acts.libs.proc import job
-from acts.utils import get_fuchsia_mdns_ipv6_address
MOBLY_CONTROLLER_CONFIG_NAME = "FuchsiaDevice"
ACTS_CONTROLLER_REFERENCE_NAME = "fuchsia_devices"
@@ -104,13 +106,12 @@
FUCHSIA_RECONNECT_AFTER_REBOOT_TIME = 5
-ENABLE_LOG_LISTENER = True
-
CHANNEL_OPEN_TIMEOUT = 5
FUCHSIA_GET_VERSION_CMD = 'cat /config/build-info/version'
FUCHSIA_REBOOT_TYPE_SOFT = 'soft'
+FUCHSIA_REBOOT_TYPE_SOFT_AND_FLASH = 'flash'
FUCHSIA_REBOOT_TYPE_HARD = 'hard'
FUCHSIA_DEFAULT_CONNECT_TIMEOUT = 60
@@ -192,6 +193,7 @@
sl4f_port: The SL4F HTTP port number of the Fuchsia device.
ssh_config: The ssh_config for connecting to the Fuchsia device.
"""
+
def __init__(self, fd_conf_data):
"""
Args:
@@ -211,17 +213,30 @@
if "ip" not in fd_conf_data:
raise FuchsiaDeviceError(FUCHSIA_DEVICE_NO_IP_MSG)
self.ip = fd_conf_data["ip"]
+ self.orig_ip = fd_conf_data["ip"]
self.sl4f_port = fd_conf_data.get("sl4f_port", 80)
self.ssh_port = fd_conf_data.get("ssh_port", 22)
self.ssh_config = fd_conf_data.get("ssh_config", None)
+ self.ssh_priv_key = fd_conf_data.get("ssh_priv_key", None)
+ self.authorized_file = fd_conf_data.get("authorized_file_loc", None)
+ self.serial_number = fd_conf_data.get("serial_number", None)
+ self.device_type = fd_conf_data.get("device_type", None)
+ self.product_type = fd_conf_data.get("product_type", None)
+ self.board_type = fd_conf_data.get("board_type", None)
+ self.build_number = fd_conf_data.get("build_number", None)
+ self.build_type = fd_conf_data.get("build_type", None)
+ self.server_path = fd_conf_data.get("server_path", None)
+ self.specific_image = fd_conf_data.get("specific_image", None)
+ self.ffx_binary_path = fd_conf_data.get("ffx_binary_path", None)
+ self.mdns_name = fd_conf_data.get("mdns_name", None)
- # Instead of the input ssh_config, a new config with
- # proper ControlPath values is set and written to
- # /tmp/temp_fuchsia_ssh_config.config.
- self._set_control_path_config(self.ssh_config,
- "/tmp/temp_fuchsia_ssh_config.config")
-
- self.ssh_config = "/tmp/temp_fuchsia_ssh_config.config"
+ # Instead of the input ssh_config, a new config is generated with proper
+ # ControlPath to the test output directory.
+ output_path = context.get_current_context().get_base_output_path()
+ generated_ssh_config = os.path.join(output_path,
+ "ssh_config_{}".format(self.ip))
+ self._set_control_path_config(self.ssh_config, generated_ssh_config)
+ self.ssh_config = generated_ssh_config
self.ssh_username = fd_conf_data.get("ssh_username",
FUCHSIA_SSH_USERNAME)
@@ -234,6 +249,14 @@
'country_code', FUCHSIA_DEFAULT_COUNTRY_CODE_US).upper()
self._persistent_ssh_conn = None
+ # WLAN interface info is populated inside configure_wlan
+ self.wlan_client_interfaces = {}
+ self.wlan_ap_interfaces = {}
+ self.wlan_client_test_interface_name = fd_conf_data.get(
+ 'wlan_client_test_interface', None)
+ self.wlan_ap_test_interface_name = fd_conf_data.get(
+ 'wlan_ap_test_interface', None)
+
# Whether to use 'policy' or 'drivers' for WLAN connect/disconnect calls
# If set to None, wlan is not configured.
self.association_mechanism = None
@@ -259,13 +282,16 @@
else:
time.sleep(1)
if mdns_ip and utils.is_valid_ipv6_address(mdns_ip):
+ # self.ip was actually an mdns name. Use it for self.mdns_name
+ # unless one was explicitly provided.
+ self.mdns_name = self.mdns_name or self.ip
self.ip = mdns_ip
self.address = "http://[{}]:{}".format(self.ip, self.sl4f_port)
else:
raise ValueError('Invalid IP: %s' % self.ip)
self.log = acts_logger.create_tagged_trace_logger(
- "FuchsiaDevice | %s" % self.ip)
+ "FuchsiaDevice | %s" % self.orig_ip)
self.init_address = self.address + "/init"
self.cleanup_address = self.address + "/cleanup"
@@ -284,6 +310,41 @@
self.log_path, "fuchsialog_%s_debug.txt" % self.serial)
self.log_process = None
+ self.init_libraries()
+
+ self.setup_commands = fd_conf_data.get('setup_commands', [])
+ self.teardown_commands = fd_conf_data.get('teardown_commands', [])
+
+ try:
+ self.start_services()
+ self.run_commands_from_config(self.setup_commands)
+ except Exception as e:
+ # Prevent a threading error, since controller isn't fully up yet.
+ self.clean_up()
+ raise e
+
+ def _set_control_path_config(self, old_config, new_config):
+ """Given an input ssh_config, write to a new config with proper
+ ControlPath values in place, if it doesn't exist already.
+
+ Args:
+ old_config: string, path to the input config
+ new_config: string, path to store the new config
+ """
+ if os.path.isfile(new_config):
+ return
+
+ ssh_config_copy = ""
+
+ with open(old_config, 'r') as file:
+ ssh_config_copy = re.sub('(\sControlPath\s.*)',
+ CONTROL_PATH_REPLACE_VALUE,
+ file.read(),
+ flags=re.M)
+ with open(new_config, 'w') as file:
+ file.write(ssh_config_copy)
+
+ def init_libraries(self):
# Grab commands from FuchsiaAudioLib
self.audio_lib = FuchsiaAudioLib(self.address, self.test_counter,
self.client_id)
@@ -296,6 +357,10 @@
self.hfp_lib = FuchsiaHfpLib(self.address, self.test_counter,
self.client_id)
+ # Grab commands from FuchsiaRfcommLib
+ self.rfcomm_lib = FuchsiaRfcommLib(self.address, self.test_counter,
+ self.client_id)
+
# Grab commands from FuchsiaLightLib
self.light_lib = FuchsiaLightLib(self.address, self.test_counter,
self.client_id)
@@ -326,8 +391,10 @@
self.client_id)
# Grab commands from FuchsiaHardwarePowerStatecontrolLib
- self.hardware_power_statecontrol_lib = FuchsiaHardwarePowerStatecontrolLib(
- self.address, self.test_counter, self.client_id)
+ self.hardware_power_statecontrol_lib = (
+ FuchsiaHardwarePowerStatecontrolLib(self.address,
+ self.test_counter,
+ self.client_id))
# Grab commands from FuchsiaHwinfoLib
self.hwinfo_lib = FuchsiaHwinfoLib(self.address, self.test_counter,
@@ -370,9 +437,14 @@
self.sysinfo_lib = FuchsiaSysInfoLib(self.address, self.test_counter,
self.client_id)
+ # Grab commands from FuchsiaSessionManagerLib
+ self.session_manager_lib = FuchsiaSessionManagerLib(self)
+
# Grabs command from FuchsiaWlanDeprecatedConfigurationLib
- self.wlan_deprecated_configuration_lib = FuchsiaWlanDeprecatedConfigurationLib(
- self.address, self.test_counter, self.client_id)
+ self.wlan_deprecated_configuration_lib = (
+ FuchsiaWlanDeprecatedConfigurationLib(self.address,
+ self.test_counter,
+ self.client_id))
# Grab commands from FuchsiaWlanLib
self.wlan_lib = FuchsiaWlanLib(self.address, self.test_counter,
@@ -387,54 +459,23 @@
self.test_counter,
self.client_id)
+ # Contains Netstack functions
+ self.netstack_controller = NetstackController(self)
+
# Contains WLAN core functions
self.wlan_controller = WlanController(self)
# Contains WLAN policy functions like save_network, remove_network, etc
self.wlan_policy_controller = WlanPolicyController(self)
- self.skip_sl4f = False
- # Start sl4f on device
- self.start_services(skip_sl4f=self.skip_sl4f)
- # Init server
- self.init_server_connection()
-
- self.setup_commands = fd_conf_data.get('setup_commands', [])
- self.teardown_commands = fd_conf_data.get('teardown_commands', [])
-
- try:
- self.run_commands_from_config(self.setup_commands)
- except FuchsiaDeviceError:
- # Prevent a threading error, since controller isn't fully up yet.
- self.clean_up()
- raise FuchsiaDeviceError('Failed to run setup commands.')
-
- def _set_control_path_config(self, old_config, new_config):
- """Given an input ssh_config, write to a new config with
- proper ControlPath values in place.
-
- Args:
- old_config: string, path to the input config
- new_config: string, path to store the new config
- """
- ssh_config_copy = ""
-
- with open(old_config, 'r') as file:
- ssh_config_copy = re.sub('(\sControlPath\s.*)',
- CONTROL_PATH_REPLACE_VALUE,
- file.read(),
- flags=re.M)
- with open(new_config, 'w') as file:
- file.write(ssh_config_copy)
-
@backoff.on_exception(
backoff.constant,
(ConnectionRefusedError, requests.exceptions.ConnectionError),
interval=1.5,
max_tries=4)
- def init_server_connection(self):
+ def init_sl4f_connection(self):
"""Initializes HTTP connection with SL4F server."""
- self.log.debug("Initializing server connection")
+ self.log.debug("Initializing SL4F server connection")
init_data = json.dumps({
"jsonrpc": "2.0",
"id": self.build_id(self.test_counter),
@@ -447,6 +488,71 @@
requests.get(url=self.init_address, data=init_data)
self.test_counter += 1
+ def init_ffx_connection(self):
+ """Initializes ffx's connection to the device.
+
+ If ffx has already been initialized, it will be reinitialized. This will
+ break any running tests calling ffx for this device.
+ """
+ self.log.debug("Initializing ffx connection")
+
+ if not self.ffx_binary_path:
+ raise ValueError(
+ 'Must provide "ffx_binary_path: <path to FFX binary>" in the device config'
+ )
+ if not self.mdns_name:
+ raise ValueError(
+ 'Must provide "mdns_name: <device mDNS name>" in the device config'
+ )
+
+ if hasattr(self, 'ffx'):
+ self.ffx.clean_up()
+
+ self.ffx = FFX(self.ffx_binary_path, self.mdns_name, self.ssh_priv_key)
+
+ # Wait for the device to be available. If the device isn't available within
+ # a short time (e.g. 5 seconds), log a warning before waiting longer.
+ try:
+ self.ffx.run("target wait", timeout_sec=5)
+ except job.TimeoutError as e:
+ longer_wait_sec = 60
+ self.log.info(
+ "Device is not immediately available via ffx." +
+ f" Waiting up to {longer_wait_sec} seconds for device to be reachable."
+ )
+ self.ffx.run("target wait", timeout_sec=longer_wait_sec)
+
+ # Test actual connectivity to the device by getting device information.
+ # Use a shorter timeout than default because this command can hang for
+ # a long time if the device is not actually connectable.
+ try:
+ result = self.ffx.run("target show --json", timeout_sec=15)
+ except Exception as e:
+ self.log.error(
+ f'Failed to reach target device. Try running "{self.ffx_binary_path}'
+ + ' doctor" to diagnose issues.')
+ raise e
+
+ # Compare the device's version to the ffx version
+ result_json = json.loads(result.stdout)
+ build_info = next(
+ filter(lambda s: s.get('label') == 'build', result_json))
+ version_info = next(
+ filter(lambda s: s.get('label') == 'version', build_info['child']))
+ device_version = version_info.get('value')
+ ffx_version = self.ffx.run("version").stdout
+
+ if not getattr(self, '_have_logged_ffx_version', False):
+ self._have_logged_ffx_version = True
+ self.log.info(
+ f"Device version: {device_version}, ffx version: {ffx_version}"
+ )
+ if device_version != ffx_version:
+ self.log.warning(
+ "ffx versions that differ from device versions may" +
+ " have compatibility issues. It is recommended to" +
+ " use versions within 6 weeks of each other.")
+
def run_commands_from_config(self, cmd_dicts):
"""Runs commands on the Fuchsia device from the config file. Useful for
device and/or Fuchsia specific configuration.
@@ -552,6 +658,9 @@
self.wlan_policy_controller._configure_wlan(
preserve_saved_networks)
+ # Retrieve WLAN client and AP interfaces
+ self.wlan_controller.update_wlan_interfaces()
+
def deconfigure_wlan(self):
"""
Stops WLAN functionality (if it has been started). Used to allow
@@ -581,8 +690,8 @@
testbed_pdus=None):
"""Reboot a FuchsiaDevice.
- Soft reboots the device, verifies it becomes unreachable, then verfifies
- it comes back online. Reinitializes SL4F so the tests can continue.
+ Soft reboots the device, verifies it becomes unreachable, then verifies
+ it comes back online. Re-initializes services so the tests can continue.
Args:
use_ssh: bool, if True, use fuchsia shell command via ssh to reboot
@@ -599,6 +708,7 @@
ConnectionError, if device fails to become unreachable, fails to
come back up, or if SL4F does not setup correctly.
"""
+ skip_unreachable_check = False
# Call Reboot
if reboot_type == FUCHSIA_REBOOT_TYPE_SOFT:
if use_ssh:
@@ -615,8 +725,14 @@
self.hardware_power_statecontrol_lib.suspendReboot(
timeout=3)
self.clean_up_services()
+ elif reboot_type == FUCHSIA_REBOOT_TYPE_SOFT_AND_FLASH:
+ flash(self, use_ssh, FUCHSIA_RECONNECT_AFTER_REBOOT_TIME)
+ skip_unreachable_check = True
elif reboot_type == FUCHSIA_REBOOT_TYPE_HARD:
self.log.info('Power cycling FuchsiaDevice (%s)' % self.ip)
+ if not testbed_pdus:
+ raise AttributeError('Testbed PDUs must be supplied '
+ 'to hard reboot a fuchsia_device.')
device_pdu, device_pdu_port = pdu.get_pdu_port_for_device(
self.device_pdu_config, testbed_pdus)
with utils.SuppressLogOutput():
@@ -625,24 +741,26 @@
device_pdu.off(str(device_pdu_port))
else:
raise ValueError('Invalid reboot type: %s' % reboot_type)
- # Wait for unreachable
- self.log.info('Verifying device is unreachable.')
- timeout = time.time() + unreachable_timeout
- while (time.time() < timeout):
- if utils.can_ping(job, self.ip):
- self.log.debug('Device is still pingable. Retrying.')
+ if not skip_unreachable_check:
+ # Wait for unreachable
+ self.log.info('Verifying device is unreachable.')
+ timeout = time.time() + unreachable_timeout
+ while (time.time() < timeout):
+ if utils.can_ping(job, self.ip):
+ self.log.debug('Device is still pingable. Retrying.')
+ else:
+ if reboot_type == FUCHSIA_REBOOT_TYPE_HARD:
+ self.log.info(
+ 'Restoring power to FuchsiaDevice (%s)...' %
+ self.ip)
+ device_pdu.on(str(device_pdu_port))
+ break
else:
- if reboot_type == FUCHSIA_REBOOT_TYPE_HARD:
- self.log.info('Restoring power to FuchsiaDevice (%s)...' %
- self.ip)
- device_pdu.on(str(device_pdu_port))
- break
- else:
- self.log.info('Device failed to go offline. Reintializing Sl4F.')
- self.start_services()
- self.init_server_connection()
- raise ConnectionError('Device never went down.')
- self.log.info('Device is unreachable as expected.')
+ self.log.info(
+ 'Device failed to go offline. Restarting services...')
+ self.start_services()
+ raise ConnectionError('Device never went down.')
+ self.log.info('Device is unreachable as expected.')
if reboot_type == FUCHSIA_REBOOT_TYPE_HARD:
self.log.info('Restoring power to FuchsiaDevice (%s)...' % self.ip)
device_pdu.on(str(device_pdu_port))
@@ -676,16 +794,12 @@
# Creating new log process, start it, start new persistent ssh session,
# start SL4F, and connect via SL4F
- self.log.info(
- 'Restarting log process and reinitiating SL4F on FuchsiaDevice %s'
- % self.ip)
+ self.log.info(f'Restarting services on FuchsiaDevice {self.ip}')
self.start_services()
# Verify SL4F is up.
- self.log.info(
- 'Initiating connection to SL4F and verifying commands can run.')
+ self.log.info('Verifying SL4F commands can run.')
try:
- self.init_server_connection()
self.hwinfo_lib.getDeviceInfo()
except Exception as err:
raise ConnectionError(
@@ -758,6 +872,22 @@
ssh_conn.close()
return command_result
+ def version(self, timeout=FUCHSIA_DEFAULT_COMMAND_TIMEOUT):
+ """Returns the version of Fuchsia running on the device.
+
+ Args:
+ timeout: (int) Seconds to wait for command to run.
+
+ Returns:
+ A string containing the Fuchsia version number.
+ For example, "5.20210713.2.1".
+
+ Raises:
+ DeviceOffline: If SSH to the device fails.
+ """
+ return self.send_command_ssh(FUCHSIA_GET_VERSION_CMD,
+ timeout=timeout).stdout
+
def ping(self,
dest_ip,
count=3,
@@ -940,7 +1070,7 @@
process_name: the name of the process to start or stop
action: specify whether to start or stop a process
"""
- if not process_name[-4:] == '.cmx':
+ if not (process_name[-4:] == '.cmx' or process_name[-4:] == '.cml'):
process_name = '%s.cmx' % process_name
unable_to_connect_msg = None
process_state = False
@@ -1075,60 +1205,60 @@
(FuchsiaSyslogError, socket.timeout),
interval=1.5,
max_tries=4)
- def start_services(self, skip_sl4f=False):
+ def start_services(self):
"""Starts long running services on the Fuchsia device.
- 1. Start SL4F if not skipped.
+ Starts a syslog streaming process, SL4F server, initializes a connection
+ to the SL4F server, then starts an isolated ffx daemon.
- Args:
- skip_sl4f: Does not attempt to start SL4F if True.
"""
self.log.debug("Attempting to start Fuchsia device services on %s." %
self.ip)
if self.ssh_config:
- self.log_process = start_syslog(self.serial,
- self.log_path,
- self.ip,
- self.ssh_username,
- self.ssh_config,
- ssh_port=self.ssh_port)
+ self.log_process = create_syslog_process(self.serial,
+ self.log_path,
+ self.ip,
+ self.ssh_username,
+ self.ssh_config,
+ ssh_port=self.ssh_port)
- if ENABLE_LOG_LISTENER:
- try:
- self.log_process.start()
- except FuchsiaSyslogError as e:
- # Before backing off and retrying, stop the syslog if it
- # failed to setup correctly, to prevent threading error when
- # retrying
- self.log_process.stop()
- raise
+ try:
+ self.log_process.start()
+ except FuchsiaSyslogError as e:
+ # Before backing off and retrying, stop the syslog if it
+ # failed to setup correctly, to prevent threading error when
+ # retrying
+ self.log_process.stop()
+ raise
- if not skip_sl4f:
- self.control_daemon("sl4f.cmx", "start")
+ self.control_daemon("sl4f.cmx", "start")
+ self.init_sl4f_connection()
out_name = "fuchsia_device_%s_%s.txt" % (self.serial, 'fw_version')
full_out_path = os.path.join(self.log_path, out_name)
- fuchsia_version = self.send_command_ssh(
- FUCHSIA_GET_VERSION_CMD).stdout
fw_file = open(full_out_path, 'w')
- fw_file.write('%s\n' % fuchsia_version)
+ fw_file.write('%s\n' % self.version())
fw_file.close()
+ self.init_ffx_connection()
+
def stop_services(self):
"""Stops long running services on the fuchsia device.
- Terminate sl4f sessions if exist.
+ Terminates the syslog streaming process, the SL4F server on the device,
+ and the ffx daemon.
"""
self.log.debug("Attempting to stop Fuchsia device services on %s." %
self.ip)
+ if hasattr(self, 'ffx'):
+ self.ffx.clean_up()
if self.ssh_config:
try:
self.control_daemon("sl4f.cmx", "stop")
except Exception as err:
self.log.exception("Failed to stop sl4f.cmx with: %s" % err)
if self.log_process:
- if ENABLE_LOG_LISTENER:
- self.log_process.stop()
+ self.log_process.stop()
def load_config(self, config):
pass
diff --git a/acts/framework/acts/controllers/fuchsia_lib/OWNERS b/acts/framework/acts/controllers/fuchsia_lib/OWNERS
index ba880d9..130db54 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/OWNERS
+++ b/acts/framework/acts/controllers/fuchsia_lib/OWNERS
@@ -1,3 +1,9 @@
+chcl@google.com
+dhobsd@google.com
haydennix@google.com
jmbrenna@google.com
+mnck@google.com
+nickchee@google.com
+sbalana@google.com
+silberst@google.com
tturney@google.com
diff --git a/acts/framework/acts/controllers/fuchsia_lib/bt/hfp_lib.py b/acts/framework/acts/controllers/fuchsia_lib/bt/hfp_lib.py
index 220ba38..cd789cf 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/bt/hfp_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/bt/hfp_lib.py
@@ -75,7 +75,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetActivePeer"
- test_args = { "peer_id": peer_id }
+ test_args = {"peer_id": peer_id}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -94,18 +94,19 @@
return self.send_command(test_id, test_cmd, test_args)
- def newCall(self, remote, state):
+ def newCall(self, remote, state, direction):
"""Opens a new call channel and alerts the HFP peer.
Args:
remote: The number of the remote party.
state: The state of the call.
+ direction: The direction of the call. Can be "incoming" or "outgoing".
Returns:
Dictionary, call_id if success, error if error.
"""
test_cmd = "hfp_facade.NewCall"
- test_args = {"remote": remote, "state": state }
+ test_args = {"remote": remote, "state": state, "direction": direction}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -121,6 +122,23 @@
Dictionary, call_id if success, error if error.
"""
test_cmd = "hfp_facade.IncomingCall"
+ test_args = {"remote": remote}
+ test_id = self.build_id(self.test_counter)
+ self.test_counter += 1
+
+ return self.send_command(test_id, test_cmd, test_args)
+
+ def initiateIncomingWaitingCall(self, remote):
+ """Opens an incoming call when there is an onging call and alerts
+ the HFP peer.
+
+ Args:
+ remote: The number of the remote party.
+
+ Returns:
+ Dictionary, call_id if success, error if error.
+ """
+ test_cmd = "hfp_facade.IncomingWaitingCall"
test_args = {"remote": remote }
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -137,7 +155,7 @@
Dictionary, call_id if success, error if error.
"""
test_cmd = "hfp_facade.OutgoingCall"
- test_args = {"remote": remote }
+ test_args = {"remote": remote}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -153,7 +171,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetCallActive"
- test_args = {"call_id": call_id }
+ test_args = {"call_id": call_id}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -169,7 +187,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetCallHeld"
- test_args = {"call_id": call_id }
+ test_args = {"call_id": call_id}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -185,7 +203,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetCallTerminated"
- test_args = {"call_id": call_id }
+ test_args = {"call_id": call_id}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -201,7 +219,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetCallTransferredToAg"
- test_args = {"call_id": call_id }
+ test_args = {"call_id": call_id}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -217,7 +235,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetSpeakerGain"
- test_args = {"value": value }
+ test_args = {"value": value}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -233,7 +251,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetMicrophoneGain"
- test_args = {"value": value }
+ test_args = {"value": value}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -249,7 +267,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetServiceAvailable"
- test_args = {"value": value }
+ test_args = {"value": value}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -265,7 +283,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetRoaming"
- test_args = {"value": value }
+ test_args = {"value": value}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -281,7 +299,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetSignalStrength"
- test_args = {"value": value }
+ test_args = {"value": value}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -297,7 +315,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetSubscriberNumber"
- test_args = {"value": value }
+ test_args = {"value": value}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -313,7 +331,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetOperator"
- test_args = {"value": value }
+ test_args = {"value": value}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -329,7 +347,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetNrecSupport"
- test_args = {"value": value }
+ test_args = {"value": value}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -345,7 +363,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetBatteryLevel"
- test_args = {"value": value }
+ test_args = {"value": value}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -361,7 +379,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetLastDialed"
- test_args = {"number": number }
+ test_args = {"number": number}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -391,7 +409,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetMemoryLocation"
- test_args = {"location": location, "number": number }
+ test_args = {"location": location, "number": number}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -408,7 +426,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.ClearMemoryLocation"
- test_args = {"location": location }
+ test_args = {"location": location}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -426,7 +444,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "hfp_facade.SetDialResult"
- test_args = {"number": number, "status": status }
+ test_args = {"number": number, "status": status}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -444,3 +462,19 @@
self.test_counter += 1
return self.send_command(test_id, test_cmd, test_args)
+
+ def setConnectionBehavior(self, autoconnect):
+ """Set the Service Level Connection behavior when a new peer connects.
+
+ Args:
+ autoconnect: Enable/Disable autoconnection of SLC.
+
+ Returns:
+ Dictionary, None if success, error if error.
+ """
+ test_cmd = "hfp_facade.SetConnectionBehavior"
+ test_args = {"autoconnect": autoconnect}
+ test_id = self.build_id(self.test_counter)
+ self.test_counter += 1
+
+ return self.send_command(test_id, test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/bt/rfcomm_lib.py b/acts/framework/acts/controllers/fuchsia_lib/bt/rfcomm_lib.py
new file mode 100644
index 0000000..6cc08b8
--- /dev/null
+++ b/acts/framework/acts/controllers/fuchsia_lib/bt/rfcomm_lib.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from acts.controllers.fuchsia_lib.base_lib import BaseLib
+
+
+class FuchsiaRfcommLib(BaseLib):
+ def __init__(self, addr, tc, client_id):
+ self.address = addr
+ self.test_counter = tc
+ self.client_id = client_id
+
+ def init(self):
+ """Initializes the RFCOMM service.
+
+ Returns:
+ Dictionary, None if success, error if error.
+ """
+ test_cmd = "rfcomm_facade.RfcommInit"
+
+ test_args = {}
+ test_id = self.build_id(self.test_counter)
+ self.test_counter += 1
+
+ return self.send_command(test_id, test_cmd, test_args)
+
+ def removeService(self):
+ """Removes the RFCOMM service from the Fuchsia device
+
+ Returns:
+ Dictionary, None if success, error if error.
+ """
+ test_cmd = "rfcomm_facade.RfcommRemoveService"
+ test_args = {}
+ test_id = self.build_id(self.test_counter)
+ self.test_counter += 1
+
+ return self.send_command(test_id, test_cmd, test_args)
+
+ def disconnectSession(self, peer_id):
+ """Closes the RFCOMM Session with the remote peer
+
+ Returns:
+ Dictionary, None if success, error if error.
+ """
+ test_cmd = "rfcomm_facade.DisconnectSession"
+ test_args = {"peer_id": peer_id}
+ test_id = self.build_id(self.test_counter)
+ self.test_counter += 1
+
+ return self.send_command(test_id, test_cmd, test_args)
+
+ def connectRfcommChannel(self, peer_id, server_channel_number):
+ """Makes an outgoing RFCOMM connection to the remote peer
+
+ Returns:
+ Dictionary, None if success, error if error.
+ """
+ test_cmd = "rfcomm_facade.ConnectRfcommChannel"
+ test_args = {
+ "peer_id": peer_id,
+ "server_channel_number": server_channel_number
+ }
+ test_id = self.build_id(self.test_counter)
+ self.test_counter += 1
+
+ return self.send_command(test_id, test_cmd, test_args)
+
+ def disconnectRfcommChannel(self, peer_id, server_channel_number):
+ """Closes the RFCOMM channel with the remote peer
+
+ Returns:
+ Dictionary, None if success, error if error.
+ """
+ test_cmd = "rfcomm_facade.DisconnectRfcommChannel"
+ test_args = {
+ "peer_id": peer_id,
+ "server_channel_number": server_channel_number
+ }
+ test_id = self.build_id(self.test_counter)
+ self.test_counter += 1
+
+ return self.send_command(test_id, test_cmd, test_args)
+
+ def sendRemoteLineStatus(self, peer_id, server_channel_number):
+ """Sends a Remote Line Status update to the remote peer for the provided channel number
+
+ Returns:
+ Dictionary, None if success, error if error.
+ """
+ test_cmd = "rfcomm_facade.SendRemoteLineStatus"
+ test_args = {
+ "peer_id": peer_id,
+ "server_channel_number": server_channel_number
+ }
+ test_id = self.build_id(self.test_counter)
+ self.test_counter += 1
+
+ return self.send_command(test_id, test_cmd, test_args)
+
+ def writeRfcomm(self, peer_id, server_channel_number, data):
+ """Sends data to the remote peer over the RFCOMM channel
+
+ Returns:
+ Dictionary, None if success, error if error.
+ """
+ test_cmd = "rfcomm_facade.RfcommWrite"
+ test_args = {
+ "peer_id": peer_id,
+ "server_channel_number": server_channel_number,
+ "data": data
+ }
+ test_id = self.build_id(self.test_counter)
+ self.test_counter += 1
+
+ return self.send_command(test_id, test_cmd, test_args)
diff --git a/acts/framework/acts/controllers/fuchsia_lib/ffx.py b/acts/framework/acts/controllers/fuchsia_lib/ffx.py
new file mode 100644
index 0000000..3f0aa37
--- /dev/null
+++ b/acts/framework/acts/controllers/fuchsia_lib/ffx.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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 os
+import tempfile
+
+from pathlib import Path
+
+from acts import context
+from acts import logger
+from acts import signals
+from acts.libs.proc import job
+
+FFX_DEFAULT_COMMAND_TIMEOUT = 60
+
+
+class FFXError(signals.TestError):
+ pass
+
+
+class FFX:
+ """Device-specific controller for the ffx tool.
+
+ Attributes:
+ log: Logger for the device-specific instance of ffx.
+ binary_path: Path to the ffx binary.
+ config_path: Path to the ffx configuration JSON file.
+ ssh_auth_sock_path: Path to the temporary ssh_auth_sock file.
+ overnet_socket_path: Path to the temporary overnet socket file.
+ """
+
+ def __init__(self, binary_path, target, ssh_private_key_path=None):
+ """
+ Args:
+ binary_path: Path to ffx binary.
+ target: Fuchsia mDNS nodename of default target.
+ ssh_private_key_path: Path to SSH private key for talking to the
+ Fuchsia DUT.
+ """
+ self.log = logger.create_tagged_trace_logger(f"ffx | {target}")
+ self.binary_path = binary_path
+
+ # Create a new isolated environment for ffx. This is needed to avoid
+ # overlapping ffx daemons while testing in parallel, causing the ffx
+ # invocations to “upgrade” one daemon to another, which appears as a
+ # flap/restart to another test.
+ root_dir = context.get_current_context(
+ context.ContextLevel.ROOT).get_full_output_path()
+ target_dir = os.path.join(root_dir, target)
+ ffx_daemon_log_dir = os.path.join(target_dir, "ffx_daemon_logs")
+
+ for dir in [target_dir, ffx_daemon_log_dir]:
+ os.makedirs(dir, exist_ok=True)
+
+ # Sockets need to be created in a different directory to be guaranteed
+ # to stay under the maximum socket path length of 104 characters.
+ # See https://unix.stackexchange.com/q/367008
+ self.ssh_auth_sock_path = tempfile.mkstemp(suffix="ssh_auth_sock")[1]
+ self.overnet_socket_path = tempfile.mkstemp(suffix="overnet_socket")[1]
+
+ config = {
+ "target": {
+ "default": target,
+ },
+ # Use user-specific and device-specific locations for sockets.
+ # Avoids user permission errors in a multi-user test environment.
+ # Avoids daemon upgrades when running tests in parallel in a CI
+ # environment.
+ "ssh": {
+ "auth-sock": self.ssh_auth_sock_path,
+ },
+ "overnet": {
+ "socket": self.overnet_socket_path,
+ },
+ # Configure the ffx daemon to log to a place where we can read it.
+ # Note, ffx client will still output to stdout, not this log
+ # directory.
+ "log": {
+ "enabled": True,
+ "dir": [ffx_daemon_log_dir],
+ },
+ # Disable analytics to decrease noise on the network.
+ "ffx": {
+ "analytics": {
+ "disabled": True,
+ },
+ },
+ }
+
+ # ffx looks for the private key in several default locations. For
+ # testbeds which have the private key in another location, set it now.
+ if ssh_private_key_path:
+ config["ssh"]["priv"] = ssh_private_key_path
+
+ self.config_path = os.path.join(target_dir, "ffx_config.json")
+ with open(self.config_path, 'w', encoding="utf-8") as f:
+ json.dump(config, f, ensure_ascii=False, indent=4)
+
+ # The ffx daemon will started automatically when needed. There is no
+ # need to start it manually here.
+
+ def clean_up(self):
+ self.run("daemon stop")
+
+ # Remove socket files.
+ # TODO(https://fxbug.dev/93599): Replace the for-loop below once labs
+ # run Python 3.8 or higher. It should be replaced with:
+ # Path(self.ssh_auth_sock_path).unlink(missing_ok=True)
+ # Path(self.overnet_socket_path).unlink(missing_ok=True)
+ for filename in [self.ssh_auth_sock_path, self.overnet_socket_path]:
+ file = Path(filename)
+ if file.exists():
+ file.unlink()
+
+ def run(self,
+ command,
+ timeout_sec=FFX_DEFAULT_COMMAND_TIMEOUT,
+ skip_status_code_check=False):
+ """Runs an ffx command.
+
+ Args:
+ command: string, command to run with ffx.
+ timeout_sec: Seconds to wait for a command to complete.
+ skip_status_code_check: Whether to check for the status code.
+
+ Raises:
+ job.TimeoutError: when the command times out.
+ Error: when the command returns non-zero and skip_status_code_check is False.
+ FFXError: when stderr has contents and skip_status_code_check is False.
+
+ Returns:
+ A job.Result object containing the results of the command.
+ """
+ self.log.debug(f'Running "{command}".')
+
+ full_command = f'{self.binary_path} -c {self.config_path} {command}'
+ result = job.run(command=full_command,
+ timeout=timeout_sec,
+ ignore_status=skip_status_code_check)
+
+ if isinstance(result, Exception):
+ raise result
+
+ elif not skip_status_code_check and result.stderr:
+ self.log.warning(
+ f'Ran "{full_command}", exit status {result.exit_status}')
+ self.log.warning(f'stdout: {result.stdout}')
+ self.log.warning(f'stderr: {result.stderr}')
+
+ raise FFXError(
+ f'Error when running "{full_command}": {result.stderr}')
+
+ return result
diff --git a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/netstack_controller.py b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/netstack_controller.py
new file mode 100644
index 0000000..e7ca026
--- /dev/null
+++ b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/netstack_controller.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from acts import logger
+from acts import signals
+
+
+class NetstackControllerError(signals.ControllerError):
+ pass
+
+
+class NetstackController:
+ """Contains methods related to netstack, to be used in FuchsiaDevice object"""
+
+ def __init__(self, fuchsia_device):
+ self.device = fuchsia_device
+ self.log = logger.create_tagged_trace_logger(
+ 'NetstackController for FuchsiaDevice | %s' % self.device.ip)
+
+ def list_interfaces(self):
+ """Retrieve netstack interfaces from netstack facade
+
+ Returns:
+ List of dicts, one for each interface, containing interface
+ information
+ """
+ response = self.device.netstack_lib.netstackListInterfaces()
+ if response.get('error'):
+ raise NetstackControllerError(
+ 'Failed to get network interfaces list: %s' %
+ response['error'])
+ return response['result']
diff --git a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_controller.py b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_controller.py
index 032a93f..d50f726 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_controller.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_controller.py
@@ -30,6 +30,7 @@
class WlanController:
"""Contains methods related to wlan core, to be used in FuchsiaDevice object"""
+
def __init__(self, fuchsia_device):
self.device = fuchsia_device
self.log = logger.create_tagged_trace_logger(
@@ -44,86 +45,87 @@
def _deconfigure_wlan(self):
pass
- def get_wlan_client_interface_id(self):
- """ Returns the wlan interface id of the first found wlan client
- interface.
+ def update_wlan_interfaces(self):
+ """ Retrieves WLAN interfaces from device and sets the FuchsiaDevice
+ attributes.
"""
- # Retrieve wlan ifaces
+ wlan_interfaces = self.get_interfaces_by_role()
+ self.device.wlan_client_interfaces = wlan_interfaces['client']
+ self.device.wlan_ap_interfaces = wlan_interfaces['ap']
+
+ # Set test interfaces to value from config, else the first found
+ # interface, else None
+ self.device.wlan_client_test_interface_name = self.device.conf_data.get(
+ 'wlan_client_test_interface',
+ next(iter(self.device.wlan_client_interfaces), None))
+
+ self.device.wlan_ap_test_interface_name = self.device.conf_data.get(
+ 'wlan_ap_test_interface',
+ next(iter(self.device.wlan_ap_interfaces), None))
+
+ def get_interfaces_by_role(self):
+ """ Retrieves WLAN interface information, supplimented by netstack info.
+
+ Returns:
+ Dict with keys 'client' and 'ap', each of which contain WLAN
+ interfaces.
+ """
+
+ # Retrieve WLAN interface IDs
response = self.device.wlan_lib.wlanGetIfaceIdList()
if response.get('error'):
raise WlanControllerError('Failed to get WLAN iface ids: %s' %
response['error'])
- # If iface has role 'client', retunr id
- iface_ids = response.get('result', [])
- for id in iface_ids:
- query_response = self.device.wlan_lib.wlanQueryInterface(id)
- if query_response.get('error'):
+ wlan_iface_ids = response.get('result', [])
+ if len(wlan_iface_ids) < 1:
+ return {'client': {}, 'ap': {}}
+
+ # Use IDs to get WLAN interface info and mac addresses
+ wlan_ifaces_by_mac = {}
+ for id in wlan_iface_ids:
+ response = self.device.wlan_lib.wlanQueryInterface(id)
+ if response.get('error'):
raise WlanControllerError(
'Failed to query wlan iface id %s: %s' %
- (id, query_response['error']))
+ (id, response['error']))
- if query_response['result'].get('role').lower() == 'client':
- return id
+ mac = response['result'].get('sta_addr', None)
+ if mac is None:
+ # Fallback to older field name to maintain backwards
+ # compatibility with older versions of SL4F's
+ # QueryIfaceResponse. See https://fxrev.dev/562146.
+ mac = response['result'].get('mac_addr')
- return None
+ wlan_ifaces_by_mac[utils.mac_address_list_to_str(
+ mac)] = response['result']
- def get_wlan_interface_mac_addr_from_id(self, iface_id):
- """ Retrieves the mac address of a wlan iface, using the wlan iface
- id.
+ # Use mac addresses to query the interfaces from the netstack view,
+ # which allows us to supplement the interface information with the name,
+ # netstack_id, etc.
- Args:
- iface_id: int, wlan iface id
+ # TODO(fxb/75909): This tedium is necessary to get the interface name
+ # because only netstack has that information. The bug linked here is
+ # to reconcile some of the information between the two perspectives, at
+ # which point we can eliminate step.
+ net_ifaces = self.device.netstack_controller.list_interfaces()
+ wlan_ifaces_by_role = {'client': {}, 'ap': {}}
+ for iface in net_ifaces:
+ try:
+ # Some interfaces might not have a MAC
+ iface_mac = utils.mac_address_list_to_str(iface['mac'])
+ except Exception as e:
+ self.log.debug(f'Error {e} getting MAC for iface {iface}')
+ continue
+ if iface_mac in wlan_ifaces_by_mac:
+ wlan_ifaces_by_mac[iface_mac]['netstack_id'] = iface['id']
- Returns:
- string, mac address of wlan iface
- """
- query_response = self.device.wlan_lib.wlanQueryInterface(iface_id)
- if query_response.get('error'):
- raise WlanControllerError('Failed to query wlan iface id %s: %s' %
- (iface_id, query_response['error']))
- return utils.mac_address_list_to_str(
- query_response['result'].get('mac_addr'))
+ # Add to return dict, mapped by role then name.
+ wlan_ifaces_by_role[
+ wlan_ifaces_by_mac[iface_mac]['role'].lower()][
+ iface['name']] = wlan_ifaces_by_mac[iface_mac]
- def get_wlan_interface_name(self, mac_addr=None):
- """ Retrieves name (netstack) of wlan interface using the mac address. If
- mac address is not provided, returns the name of the first found wlan
- client (as opposed to AP) interface.
-
- Args:
- mac_addr: optional, string or list of decimal octets representing
- the mac addr of the wlan interface. e.g. "44:07:0b:50:c1:ef" or
- [68, 7, 11, 80, 193, 239]
-
- Returns:
- string, name of wlan interface
- """
- # Default to first found client wlan interface
- if not mac_addr:
- client_iface_id = self.get_wlan_client_interface_id()
- mac_addr = self.get_wlan_interface_mac_addr_from_id(
- client_iface_id)
-
- # Convert mac addr to list, for comparison
- if type(mac_addr) == str:
- mac_addr = utils.mac_address_str_to_list(mac_addr)
-
- err = self.device.netstack_lib.init().get('error')
- if err:
- raise WlanControllerError('Failed to init netstack_lib: %s' % err)
-
- # Retrieve net ifaces
- response = self.device.netstack_lib.netstackListInterfaces()
- if response.get('error'):
- raise WlanControllerError(
- 'Failed to get network interfaces list: %s' %
- response['error'])
-
- # Find iface with matching mac addr, and return name
- for iface_info in response['result']:
- if iface_info['mac'] == mac_addr:
- return iface_info['name']
- return None
+ return wlan_ifaces_by_role
def set_country_code(self, country_code):
"""Sets country code through the regulatory region service and waits
diff --git a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_policy_controller.py b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_policy_controller.py
index e99656e..e5b8fce 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_policy_controller.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_policy_controller.py
@@ -20,6 +20,10 @@
from acts import logger
from acts import signals
+import typing
+if typing.TYPE_CHECKING:
+ from acts.controllers.fuchsia_device import FuchsiaDevice
+
SAVED_NETWORKS = "saved_networks"
CLIENT_STATE = "client_connections_state"
CONNECTIONS_ENABLED = "ConnectionsEnabled"
@@ -39,13 +43,15 @@
"""Contains methods related to the wlan policy layer, to be used in the
FuchsiaDevice object.
"""
+
def __init__(self, fuchsia_device):
- self.device = fuchsia_device
+ self.device: FuchsiaDevice = fuchsia_device
self.log = logger.create_tagged_trace_logger(
'WlanPolicyController for FuchsiaDevice | %s' % self.device.ip)
self.client_controller = False
self.preserved_networks_and_client_state = None
self.policy_configured = False
+ self._paused_session = False
def _configure_wlan(self, preserve_saved_networks, timeout=15):
"""Sets up wlan policy layer.
@@ -56,7 +62,7 @@
"""
end_time = time.time() + timeout
- # Kill basemgr
+ # Kill basemgr (Component v1 version of session manager)
while time.time() < end_time:
response = self.device.basemgr_lib.killBasemgr()
if not response.get('error'):
@@ -68,6 +74,16 @@
raise WlanPolicyControllerError(
'Failed to issue successful basemgr kill call.')
+ # Stop the session manager, which also holds the Policy controller.
+ response = self.device.session_manager_lib.pauseSession()
+ if response.get('error'):
+ self.log.error('Failed to stop the session.')
+ raise WlanPolicyControllerError(response['error'])
+ else:
+ if response.get('result') == 'Success':
+ self._paused_session = True
+ self.log.debug(f"Paused session: {response.get('result')}")
+
# Acquire control of policy layer
while time.time() < end_time:
# Create a client controller
@@ -113,6 +129,13 @@
if not self.policy_configured:
self._configure_wlan()
self.restore_preserved_networks_and_client_state()
+ if self._paused_session:
+ response = self.device.session_manager_lib.resumeSession()
+ if response.get('error'):
+ self.log.warning('Failed to resume the session.')
+ self.log.warning(response['error'])
+ else:
+ self.log.debug(f"Resumed session: {response.get('result')}")
def start_client_connections(self):
"""Allow device to connect to networks via policy layer (including
@@ -474,6 +497,10 @@
Returns:
True, if successful. False, if still connected after timeout.
"""
+ # If there are already no existing connections when this function is called,
+ # then an update won't be generated by the device, and we'll time out.
+ # Force an update by getting a new listener.
+ self.device.wlan_policy_lib.wlanSetNewListener()
end_time = time.time() + timeout
while time.time() < end_time:
time_left = max(1, int(end_time - time.time()))
diff --git a/acts/framework/acts/controllers/fuchsia_lib/logging_lib.py b/acts/framework/acts/controllers/fuchsia_lib/logging_lib.py
index 71678aa..78a9dd4 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/logging_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/logging_lib.py
@@ -53,9 +53,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "logging_facade.LogInfo"
- test_args = {
- "message": '[%s] %s' % (datetime.datetime.now(), message)
- }
+ test_args = {"message": '[%s] %s' % (datetime.datetime.now(), message)}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -71,9 +69,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "logging_facade.LogWarn"
- test_args = {
- "message": '[%s] %s' % (datetime.datetime.now(), message)
- }
+ test_args = {"message": '[%s] %s' % (datetime.datetime.now(), message)}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
diff --git a/acts/framework/acts/controllers/fuchsia_lib/netstack/netstack_lib.py b/acts/framework/acts/controllers/fuchsia_lib/netstack/netstack_lib.py
index 578612c..173127c 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/netstack/netstack_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/netstack/netstack_lib.py
@@ -16,6 +16,7 @@
from acts.controllers.fuchsia_lib.base_lib import BaseLib
+
class FuchsiaNetstackLib(BaseLib):
def __init__(self, addr, tc, client_id):
self.address = addr
@@ -35,37 +36,6 @@
return self.send_command(test_id, test_cmd, test_args)
- def init(self):
- """ListInterfaces command
-
- Returns:
- Dictionary, None if success, error if error.
- """
- test_cmd = "netstack_facade.InitNetstack"
- test_args = {}
- test_id = self.build_id(self.test_counter)
- self.test_counter += 1
-
- return self.send_command(test_id, test_cmd, test_args)
-
- def getInterfaceInfo(self, id):
- """Get interface info.
-
- Args:
- id: The interface ID.
-
- Returns:
- Dictionary, None if success, error if error.
- """
- test_cmd = "netstack_facade.GetInterfaceInfo"
- test_args = {
- "identifier": id
- }
- test_id = self.build_id(self.test_counter)
- self.test_counter += 1
-
- return self.send_command(test_id, test_cmd, test_args)
-
def enableInterface(self, id):
"""Enable Interface
@@ -76,9 +46,7 @@
Dictionary, None if success, error if error.
"""
test_cmd = "netstack_facade.EnableInterface"
- test_args = {
- "identifier": id
- }
+ test_args = {"identifier": id}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
@@ -94,11 +62,8 @@
Dictionary, None if success, error if error.
"""
test_cmd = "netstack_facade.DisableInterface"
- test_args = {
- "identifier": id
- }
+ test_args = {"identifier": id}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
return self.send_command(test_id, test_cmd, test_args)
-
diff --git a/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py b/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py
new file mode 100644
index 0000000..fc03c14
--- /dev/null
+++ b/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import typing
+if typing.TYPE_CHECKING:
+ from acts.controllers.fuchsia_device import FuchsiaDevice
+
+
+class FuchsiaSessionManagerLib():
+ def __init__(self, fuchsia_device):
+ self.device: FuchsiaDevice = fuchsia_device
+
+ def resumeSession(self):
+ """Resumes a previously paused session
+
+ Returns:
+ Dictionary:
+ error: None, unless an error occurs
+ result: 'Success' or None if error
+ """
+ try:
+ self.device.ffx.run(
+ "component start /core/session-manager/session:session")
+ return {'error': None, 'result': 'Success'}
+ except Exception as e:
+ return {'error': e, 'result': None}
+
+ def pauseSession(self):
+ """Pause the session, allowing for later resumption
+
+ Returns:
+ Dictionary:
+ error: None, unless an error occurs
+ result: 'Success', 'NoSessionToPause', or None if error
+ """
+ result = self.device.ffx.run(
+ "component stop -r /core/session-manager/session:session",
+ skip_status_code_check=True)
+
+ if result.exit_status == 0:
+ return {'error': None, 'result': 'Success'}
+ else:
+ if "InstanceNotFound" in result.stderr:
+ return {'error': None, 'result': 'NoSessionToPause'}
+ else:
+ return {'error': result, 'result': None}
diff --git a/acts/framework/acts/controllers/fuchsia_lib/syslog_lib.py b/acts/framework/acts/controllers/fuchsia_lib/syslog_lib.py
index 17c0e5a..67a850a 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/syslog_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/syslog_lib.py
@@ -33,6 +33,7 @@
def _log_line_func(log, timestamp_tracker):
"""Returns a lambda that logs a message to the given logger."""
+
def log_line(message):
timestamp_tracker.read_output(message)
log.info(message)
@@ -40,13 +41,13 @@
return log_line
-def start_syslog(serial,
- base_path,
- ip_address,
- ssh_username,
- ssh_config,
- ssh_port=22,
- extra_params=''):
+def create_syslog_process(serial,
+ base_path,
+ ip_address,
+ ssh_username,
+ ssh_config,
+ ssh_port=22,
+ extra_params=''):
"""Creates a FuchsiaSyslogProcess that automatically attempts to reconnect.
Args:
@@ -80,12 +81,9 @@
class FuchsiaSyslogProcess(object):
"""A class representing a Fuchsia Syslog object that communicates over ssh.
"""
- def __init__(self,
- ssh_username,
- ssh_config,
- ip_address,
- extra_params,
- ssh_port):
+
+ def __init__(self, ssh_username, ssh_config, ip_address, extra_params,
+ ssh_port):
"""
Args:
ssh_username: The username to connect to Fuchsia over ssh.
diff --git a/acts/framework/acts/controllers/fuchsia_lib/utils_lib.py b/acts/framework/acts/controllers/fuchsia_lib/utils_lib.py
index 91f217e..3fc1813 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/utils_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/utils_lib.py
@@ -15,15 +15,21 @@
# limitations under the License.
import backoff
+import itertools
import os
import logging
import paramiko
+import psutil
+import shutil
import socket
+import tarfile
import time
+import usbinfo
from acts import utils
from acts.controllers.fuchsia_lib.base_lib import DeviceOffline
from acts.libs.proc import job
+from acts.utils import get_fuchsia_mdns_ipv6_address
logging.getLogger("paramiko").setLevel(logging.WARNING)
# paramiko-ng will throw INFO messages when things get disconnect or cannot
@@ -32,6 +38,15 @@
# Therefore, in order to reduce confusion in the logs the log level is set to
# WARNING.
+MDNS_LOOKUP_RETRY_MAX = 3
+FASTBOOT_TIMEOUT = 30
+AFTER_FLASH_BOOT_TIME = 30
+WAIT_FOR_EXISTING_FLASH_TO_FINISH_SEC = 360
+PROCESS_CHECK_WAIT_TIME_SEC = 30
+
+FUCHSIA_SDK_URL = "gs://fuchsia-sdk/development"
+FUCHSIA_RELEASE_TESTING_URL = "gs://fuchsia-release-testing/images"
+
def get_private_key(ip_address, ssh_config):
"""Tries to load various ssh key types.
@@ -82,6 +97,7 @@
ip_address: IP address of ssh server.
ssh_username: Username for ssh server.
ssh_config: ssh_config location for the ssh server.
+ ssh_port: port for the ssh server.
connect_timeout: Timeout value for connecting to ssh_server.
auth_timeout: Timeout value to wait for authentication.
banner_timeout: Timeout to wait for ssh banner.
@@ -156,6 +172,7 @@
stderr: The file descriptor to the stderr of the SSH connection.
exit_status: The file descriptor of the SSH command.
"""
+
def __init__(self, stdin, stdout, stderr, exit_status):
self._raw_stdout = stdout.read()
self._stdout = self._raw_stdout.decode('utf-8', errors='replace')
@@ -177,3 +194,171 @@
@property
def exit_status(self):
return self._exit_status
+
+
+def flash(fuchsia_device, use_ssh=False,
+ fuchsia_reconnect_after_reboot_time=5):
+ """A function to flash, not pave, a fuchsia_device
+
+ Args:
+ fuchsia_device: An ACTS fuchsia_device
+
+ Returns:
+ True if successful.
+ """
+ if not fuchsia_device.authorized_file:
+ raise ValueError('A ssh authorized_file must be present in the '
+ 'ACTS config to flash fuchsia_devices.')
+ # This is the product type from the fx set command.
+ # Do 'fx list-products' to see options in Fuchsia source tree.
+ if not fuchsia_device.product_type:
+ raise ValueError('A product type must be specified to flash '
+ 'fuchsia_devices.')
+ # This is the board type from the fx set command.
+ # Do 'fx list-boards' to see options in Fuchsia source tree.
+ if not fuchsia_device.board_type:
+ raise ValueError('A board type must be specified to flash '
+ 'fuchsia_devices.')
+ if not fuchsia_device.build_number:
+ fuchsia_device.build_number = 'LATEST'
+ if (utils.is_valid_ipv4_address(fuchsia_device.orig_ip)
+ or utils.is_valid_ipv6_address(fuchsia_device.orig_ip)):
+ raise ValueError('The fuchsia_device ip must be the mDNS name to be '
+ 'able to flash.')
+
+ if not fuchsia_device.specific_image:
+ file_download_needed = True
+ product_build = fuchsia_device.product_type
+ if fuchsia_device.build_type:
+ product_build = '{}_{}'.format(product_build,
+ fuchsia_device.build_type)
+ if 'LATEST' in fuchsia_device.build_number:
+ sdk_version = 'sdk'
+ if 'LATEST_F' in fuchsia_device.build_number:
+ f_branch = fuchsia_device.build_number.split('LATEST_F', 1)[1]
+ sdk_version = 'f{}_sdk'.format(f_branch)
+ file_to_download = '{}/{}-{}.{}-release.tgz'.format(
+ FUCHSIA_RELEASE_TESTING_URL, sdk_version, product_build,
+ fuchsia_device.board_type)
+ else:
+ # Must be a fully qualified build number (e.g. 5.20210721.4.1215)
+ file_to_download = '{}/{}/images/{}.{}-release.tgz'.format(
+ FUCHSIA_SDK_URL, fuchsia_device.build_number, product_build,
+ fuchsia_device.board_type)
+ elif 'gs://' in fuchsia_device.specific_image:
+ file_download_needed = True
+ file_to_download = fuchsia_device.specific_image
+ elif tarfile.is_tarfile(fuchsia_device.specific_image):
+ file_download_needed = False
+ file_to_download = fuchsia_device.specific_image
+ else:
+ raise ValueError('A suitable build could not be found.')
+
+ tmp_path = '/tmp/%s_%s' % (str(int(
+ time.time() * 10000)), fuchsia_device.board_type)
+ os.mkdir(tmp_path)
+ if file_download_needed:
+ job.run('gsutil cp %s %s' % (file_to_download, tmp_path))
+ logging.info('Downloading %s to %s' % (file_to_download, tmp_path))
+ image_tgz = os.path.basename(file_to_download)
+ else:
+ job.run('cp %s %s' % (fuchsia_device.specific_image, tmp_path))
+ logging.info('Copying %s to %s' % (file_to_download, tmp_path))
+ image_tgz = os.path.basename(fuchsia_device.specific_image)
+
+ job.run('tar xfvz %s/%s -C %s' % (tmp_path, image_tgz, tmp_path))
+ all_files = []
+ for root, _dirs, files in itertools.islice(os.walk(tmp_path), 1, None):
+ for filename in files:
+ all_files.append(os.path.join(root, filename))
+ for filename in all_files:
+ shutil.move(filename, tmp_path)
+
+ if use_ssh:
+ logging.info('Sending reboot command via SSH to '
+ 'get into bootloader.')
+ with utils.SuppressLogOutput():
+ fuchsia_device.clean_up_services()
+ # Sending this command will put the device in fastboot
+ # but it does not guarantee the device will be in fastboot
+ # after this command. There is no check so if there is an
+ # expectation of the device being in fastboot, then some
+ # other check needs to be done.
+ fuchsia_device.send_command_ssh(
+ 'dm rb',
+ timeout=fuchsia_reconnect_after_reboot_time,
+ skip_status_code_check=True)
+ else:
+ pass
+ ## Todo: Add elif for SL4F if implemented in SL4F
+
+ time_counter = 0
+ while time_counter < FASTBOOT_TIMEOUT:
+ logging.info('Checking to see if fuchsia_device(%s) SN: %s is in '
+ 'fastboot. (Attempt #%s Timeout: %s)' %
+ (fuchsia_device.orig_ip, fuchsia_device.serial_number,
+ str(time_counter + 1), FASTBOOT_TIMEOUT))
+ for usb_device in usbinfo.usbinfo():
+ if (usb_device['iSerialNumber'] == fuchsia_device.serial_number
+ and usb_device['iProduct'] == 'USB_download_gadget'):
+ logging.info(
+ 'fuchsia_device(%s) SN: %s is in fastboot.' %
+ (fuchsia_device.orig_ip, fuchsia_device.serial_number))
+ time_counter = FASTBOOT_TIMEOUT
+ time_counter = time_counter + 1
+ if time_counter == FASTBOOT_TIMEOUT:
+ for fail_usb_device in usbinfo.usbinfo():
+ logging.debug(fail_usb_device)
+ raise TimeoutError(
+ 'fuchsia_device(%s) SN: %s '
+ 'never went into fastboot' %
+ (fuchsia_device.orig_ip, fuchsia_device.serial_number))
+ time.sleep(1)
+
+ end_time = time.time() + WAIT_FOR_EXISTING_FLASH_TO_FINISH_SEC
+ # Attempt to wait for existing flashing process to finish
+ while time.time() < end_time:
+ flash_process_found = False
+ for proc in psutil.process_iter():
+ if "bash" in proc.name() and "flash.sh" in proc.cmdline():
+ logging.info(
+ "Waiting for existing flash.sh process to complete.")
+ time.sleep(PROCESS_CHECK_WAIT_TIME_SEC)
+ flash_process_found = True
+ if not flash_process_found:
+ break
+ logging.info(f'Flashing {fuchsia_device.orig_ip} with {tmp_path}/{image_tgz} using authorized keys "{fuchsia_device.authorized_file}".')
+ try:
+ flash_output = job.run(f'bash {tmp_path}/flash.sh --ssh-key={fuchsia_device.authorized_file} -s {fuchsia_device.serial_number}', timeout=120)
+ logging.debug(flash_output.stderr)
+ except job.TimeoutError as err:
+ raise TimeoutError(err)
+ try:
+ os.rmdir(tmp_path)
+ except Exception:
+ job.run('rm -fr %s' % tmp_path)
+ logging.info('Waiting %s seconds for device'
+ ' to come back up after flashing.' % AFTER_FLASH_BOOT_TIME)
+ time.sleep(AFTER_FLASH_BOOT_TIME)
+ logging.info('Updating device to new IP addresses.')
+ mdns_ip = None
+ for retry_counter in range(MDNS_LOOKUP_RETRY_MAX):
+ mdns_ip = get_fuchsia_mdns_ipv6_address(fuchsia_device.orig_ip)
+ if mdns_ip:
+ break
+ else:
+ time.sleep(1)
+ if mdns_ip and utils.is_valid_ipv6_address(mdns_ip):
+ logging.info('IP for fuchsia_device(%s) changed from %s to %s' %
+ (fuchsia_device.orig_ip, fuchsia_device.ip, mdns_ip))
+ fuchsia_device.ip = mdns_ip
+ fuchsia_device.address = "http://[{}]:{}".format(
+ fuchsia_device.ip, fuchsia_device.sl4f_port)
+ fuchsia_device.init_address = fuchsia_device.address + "/init"
+ fuchsia_device.cleanup_address = fuchsia_device.address + "/cleanup"
+ fuchsia_device.print_address = fuchsia_device.address + "/print_clients"
+ fuchsia_device.init_libraries()
+ else:
+ raise ValueError('Invalid IP: %s after flashing.' %
+ fuchsia_device.orig_ip)
+ return True
diff --git a/acts/framework/acts/controllers/fuchsia_lib/wlan_lib.py b/acts/framework/acts/controllers/fuchsia_lib/wlan_lib.py
index 8247041..d3dc448 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/wlan_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/wlan_lib.py
@@ -25,6 +25,7 @@
COMMAND_GET_PHY_ID_LIST = "wlan.get_phy_id_list"
COMMAND_DESTROY_IFACE = "wlan.destroy_iface"
COMMAND_GET_COUNTRY = "wlan_phy.get_country"
+COMMAND_GET_DEV_PATH = "wlan_phy.get_dev_path"
COMMAND_QUERY_IFACE = "wlan.query_iface"
@@ -130,18 +131,25 @@
return self.send_command(test_id, test_cmd, {})
- def wlanStatus(self):
+ def wlanStatus(self, iface_id=None):
""" Request connection status
+ Args:
+ iface_id: unsigned 16-bit int, the wlan interface id
+ (defaults to None)
+
Returns:
Client state summary containing WlanClientState and
status of various networks connections
"""
test_cmd = COMMAND_STATUS
+ test_args = {}
+ if iface_id:
+ test_args = {'iface_id': iface_id}
test_id = self.build_id(self.test_counter)
self.test_counter += 1
- return self.send_command(test_id, test_cmd, {})
+ return self.send_command(test_id, test_cmd, test_args)
def wlanGetCountry(self, phy_id):
""" Reads the currently configured country for `phy_id`.
@@ -159,6 +167,22 @@
return self.send_command(test_id, test_cmd, test_args)
+ def wlanGetDevPath(self, phy_id):
+ """ Queries the device path for `phy_id`.
+
+ Args:
+ phy_id: unsigned 16-bit integer.
+
+ Returns:
+ Dictionary, String if success, error if error.
+ """
+ test_cmd = COMMAND_GET_DEV_PATH
+ test_args = {"phy_id": phy_id}
+ test_id = self.build_id(self.test_counter)
+ self.test_counter += 1
+
+ return self.send_command(test_id, test_cmd, test_args)
+
def wlanQueryInterface(self, iface_id):
""" Retrieves interface info for given wlan iface id.
diff --git a/acts/framework/acts/controllers/gnss_lib/GnssSimulator.py b/acts/framework/acts/controllers/gnss_lib/GnssSimulator.py
new file mode 100644
index 0000000..7f64164
--- /dev/null
+++ b/acts/framework/acts/controllers/gnss_lib/GnssSimulator.py
@@ -0,0 +1,200 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Python module for General abstract GNSS Simulator.
+@author: Clay Liao (jianhsiungliao@)
+"""
+from time import sleep
+from acts.controllers.spectracom_lib import gsg6
+from acts.controllers.spirent_lib import gss7000
+from acts import logger
+from acts.utils import ping
+from acts.libs.proc import job
+
+
+class AbstractGnssSimulator:
+ """General abstract GNSS Simulator"""
+
+ def __init__(self, simulator, ip_addr, ip_port, ip_port_ctrl=7717):
+ """Init AbstractGnssSimulator
+
+ Args:
+ simulator: GNSS simulator name,
+ Type, str
+ Option 'gss7000/gsg6'
+ ip_addr: IP Address.
+ Type, str
+ ip_port: TCPIP Port,
+ Type, str
+ ip_port_ctrl: TCPIP port,
+ Type, int
+ Default, 7717
+ """
+ self.simulator_name = str(simulator).lower()
+ self.ip_addr = ip_addr
+ self.ip_port = ip_port
+ self.ip_port_ctrl = ip_port_ctrl
+ self._logger = logger.create_tagged_trace_logger(
+ '%s %s:%s' % (simulator, self.ip_addr, self.ip_port))
+ if self.simulator_name == 'gsg6':
+ self._logger.info('GNSS simulator is GSG6')
+ self.simulator = gsg6.GSG6(self.ip_addr, self.ip_port)
+ elif self.simulator_name == 'gss7000':
+ self._logger.info('GNSS simulator is GSS7000')
+ self.simulator = gss7000.GSS7000(self.ip_addr, self.ip_port,
+ self.ip_port_ctrl)
+ else:
+ self._logger.error('No matched GNSS simulator')
+ raise AttributeError(
+ 'The GNSS simulator in config file is {} which is not supported.'
+ .format(self.simulator_name))
+
+ def connect(self):
+ """Connect to GNSS Simulator"""
+ self._logger.debug('Connect to GNSS Simulator {}'.format(
+ self.simulator_name.upper()))
+ self.simulator.connect()
+
+ def close(self):
+ """Disconnect from GNSS Simulator"""
+ self._logger.debug('Disconnect from GNSS Simulator {}'.format(
+ self.simulator_name.upper()))
+ self.simulator.close()
+
+ def start_scenario(self, scenario=''):
+ """Start the running scenario.
+
+ Args:
+ scenario: path of scenario,
+ Type, str
+ """
+ self._logger.info('Start GNSS Scenario {}'.format(scenario))
+ self.simulator.start_scenario(scenario)
+
+ def stop_scenario(self):
+ """Stop the running scenario."""
+ self._logger.debug('Stop playing scenario')
+ self.simulator.stop_scenario()
+
+ def set_power(self, power_level=-130):
+ """Set scenario power level.
+ Args:
+ power_level: target power level in dBm for gsg6 or gss7000,
+ gsg6 power_level range is [-160, -65],
+ gss7000 power_level range is [-170, -115]
+ Type, float,
+ """
+ self.simulator.set_power(power_level)
+
+ def set_power_offset(self, gss7000_ant=1, pwr_offset=0):
+ """Set scenario power level offset based on reference level.
+ The default reference level is -130dBm for GPS L1.
+ Args:
+ ant: target gss7000 RF port,
+ Type, int
+ pwr_offset: target power offset in dB,
+ Type, float
+ """
+ if self.simulator_name == 'gsg6':
+ power_level = -130 + pwr_offset
+ self.simulator.set_power(power_level)
+ elif self.simulator_name == 'gss7000':
+ self.simulator.set_power_offset(gss7000_ant, pwr_offset)
+ else:
+ self._logger.error('No GNSS simulator is available')
+
+ def set_scenario_power(self,
+ power_level,
+ sat_id='',
+ sat_system='',
+ freq_band=''):
+ """Set dynamic power for the running scenario.
+
+ Args:
+ power_level: transmit power level
+ Type, float.
+ Decimal, unit [dBm]
+ sat_id: set power level for specific satellite identifiers
+ Type, str.
+ Option
+ For GSG-6: 'Gxx/Rxx/Exx/Cxx/Jxx/Ixx/Sxxx'
+ where xx is satellite identifiers number
+ e.g.: G10
+ For GSS7000: Provide SVID.
+ Default, '', assumed All.
+ sat_system: to set power level for all Satellites
+ Type, str
+ Option [GPS, GLO, GAL, BDS, QZSS, IRNSS, SBAS]
+ Default, '', assumed All.
+ freq_band: Frequency band to set the power level
+ Type, str
+ Default, '', assumed to be L1.
+ Raises:
+ RuntimeError: raise when instrument does not support this function.
+ """
+ self.simulator.set_scenario_power(power_level=power_level,
+ sat_id=sat_id,
+ sat_system=sat_system,
+ freq_band=freq_band)
+
+ def toggle_scenario_power(self,
+ toggle_onoff='ON',
+ sat_id='',
+ sat_system=''):
+ """Toggle ON OFF scenario.
+
+ Args:
+ toggle_onoff: turn on or off the satellites
+ Type, str. Option ON/OFF
+ Default, 'ON'
+ sat_id: satellite identifiers
+ Type, str.
+ Option 'Gxx/Rxx/Exx/Cxx/Jxx/Ixx/Sxxx'
+ where xx is satellite identifiers no.
+ e.g.: G10
+ sat_system: to toggle On/OFF for all Satellites
+ Type, str
+ Option 'GPS/GLO/GAL'
+ """
+ # TODO: [b/208719212] Currently only support GSG-6. Will implement GSS7000 feature.
+ if self.simulator_name == 'gsg6':
+ self.simulator.toggle_scenario_power(toggle_onoff=toggle_onoff,
+ sat_id=sat_id,
+ sat_system=sat_system)
+ else:
+ raise RuntimeError('{} does not support this function'.format(
+ self.simulator_name))
+
+ def ping_inst(self, retry=3, wait=1):
+ """Ping IP of instrument to check if the connection is stable.
+ Args:
+ retry: Retry times.
+ Type, int.
+ Default, 3.
+ wait: Wait time between each ping command when ping fail is met.
+ Type, int.
+ Default, 1.
+ Return:
+ True/False of ping result.
+ """
+ for i in range(retry):
+ ret = ping(job, self.ip_addr)
+ self._logger.debug(f'Ping return results: {ret}')
+ if ret.get('packet_loss') == '0':
+ return True
+ self._logger.warning(f'Fail to ping GNSS Simulator: {i+1}')
+ sleep(wait)
+ return False
diff --git a/acts/framework/acts/controllers/gnss_lib/__init__.py b/acts/framework/acts/controllers/gnss_lib/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/acts/framework/acts/controllers/gnss_lib/__init__.py
diff --git a/acts/framework/acts/controllers/iperf_client.py b/acts/framework/acts/controllers/iperf_client.py
index b31d54f..6c889b1 100644
--- a/acts/framework/acts/controllers/iperf_client.py
+++ b/acts/framework/acts/controllers/iperf_client.py
@@ -36,6 +36,7 @@
from acts.event.event import TestClassEndEvent
from acts.libs.proc import job
from paramiko.buffered_pipe import PipeTimeout
+from paramiko.ssh_exception import SSHException
MOBLY_CONTROLLER_CONFIG_NAME = 'IPerfClient'
ACTS_CONTROLLER_REFERENCE_NAME = 'iperf_clients'
@@ -243,8 +244,10 @@
except socket.timeout:
raise TimeoutError('Socket timeout. Timed out waiting for iperf '
'client to finish.')
- except Exception as e:
- logging.exception('iperf run failed.')
+ except SSHException as err:
+ raise ConnectionError('SSH connection failed: {}'.format(err))
+ except Exception as err:
+ logging.exception('iperf run failed: {}'.format(err))
return full_out_path
diff --git a/acts/framework/acts/controllers/iperf_server.py b/acts/framework/acts/controllers/iperf_server.py
index 78cb787..4be9d1e 100755
--- a/acts/framework/acts/controllers/iperf_server.py
+++ b/acts/framework/acts/controllers/iperf_server.py
@@ -243,8 +243,8 @@
"""
if not self._has_data():
return None
- instantaneous_rates = self.instantaneous_rates[iperf_ignored_interval:
- -1]
+ instantaneous_rates = self.instantaneous_rates[
+ iperf_ignored_interval:-1]
avg_rate = math.fsum(instantaneous_rates) / len(instantaneous_rates)
sqd_deviations = ([(rate - avg_rate)**2
for rate in instantaneous_rates])
@@ -497,6 +497,18 @@
self.start_ssh()
utils.renew_linux_ip_address(self._ssh_session, self.test_interface)
+ def _cleanup_iperf_port(self):
+ """Checks and kills zombie iperf servers occupying intended port."""
+ iperf_check_cmd = ('netstat -tulpn | grep LISTEN | grep iperf3'
+ ' | grep :{}').format(self.port)
+ iperf_check = self._ssh_session.run(iperf_check_cmd,
+ ignore_status=True)
+ iperf_check = iperf_check.stdout
+ if iperf_check:
+ logging.debug('Killing zombie server on port {}'.format(self.port))
+ iperf_pid = iperf_check.split(' ')[-1].split('/')[0]
+ self._ssh_session.run('kill -9 {}'.format(str(iperf_pid)))
+
def start(self, extra_args='', tag='', iperf_binary=None):
"""Starts iperf server on specified machine and port.
@@ -513,6 +525,7 @@
if not self._ssh_session:
self.start_ssh()
+ self._cleanup_iperf_port()
if not iperf_binary:
logging.debug('No iperf3 binary specified. '
'Assuming iperf3 is in the path.')
diff --git a/acts/framework/acts/controllers/openwrt_ap.py b/acts/framework/acts/controllers/openwrt_ap.py
index 8e8619a..482c901 100644
--- a/acts/framework/acts/controllers/openwrt_ap.py
+++ b/acts/framework/acts/controllers/openwrt_ap.py
@@ -3,21 +3,25 @@
import random
import re
import time
+
from acts import logger
from acts import signals
from acts.controllers.ap_lib import hostapd_constants
from acts.controllers.openwrt_lib import network_settings
from acts.controllers.openwrt_lib import wireless_config
from acts.controllers.openwrt_lib import wireless_settings_applier
+from acts.controllers.openwrt_lib.openwrt_constants import OpenWrtModelMap as modelmap
+from acts.controllers.openwrt_lib.openwrt_constants import OpenWrtWifiSetting
+from acts.controllers.openwrt_lib.openwrt_constants import SYSTEM_INFO_CMD
from acts.controllers.utils_lib.ssh import connection
from acts.controllers.utils_lib.ssh import settings
-from acts.controllers.openwrt_lib.openwrt_constants import OpenWrtWifiSetting
import yaml
+
MOBLY_CONTROLLER_CONFIG_NAME = "OpenWrtAP"
ACTS_CONTROLLER_REFERENCE_NAME = "access_points"
OPEN_SECURITY = "none"
-PSK1_SECURITY = 'psk'
+PSK1_SECURITY = "psk"
PSK_SECURITY = "psk2"
WEP_SECURITY = "wep"
ENT_SECURITY = "wpa2"
@@ -29,6 +33,7 @@
WIFI_2G = "wifi2g"
WIFI_5G = "wifi5g"
WAIT_TIME = 20
+DEFAULT_RADIOS = ("radio0", "radio1")
def create(configs):
@@ -98,7 +103,9 @@
ssh_settings: The ssh settings being used by the ssh connection.
log: Logging object for AccessPoint.
wireless_setting: object holding wireless configuration.
- network_setting: Object for network configuration
+ network_setting: Object for network configuration.
+ model: OpenWrt HW model.
+ radios: Fit interface for test.
"""
def __init__(self, config):
@@ -109,7 +116,12 @@
lambda msg: "[OpenWrtAP|%s] %s" % (self.ssh_settings.hostname, msg))
self.wireless_setting = None
self.network_setting = network_settings.NetworkSettings(
- self.ssh, config["ssh_config"]["host"], self.log)
+ self.ssh, self.ssh_settings, self.log)
+ self.model = self.get_model_name()
+ if self.model in modelmap.__dict__:
+ self.radios = modelmap.__dict__[self.model]
+ else:
+ self.radios = DEFAULT_RADIOS
def configure_ap(self, wifi_configs, channel_2g, channel_5g):
"""Configure AP with the required settings.
@@ -149,7 +161,7 @@
# generate wifi configs to configure
wireless_configs = self.generate_wireless_configs(wifi_configs)
self.wireless_setting = wireless_settings_applier.WirelessSettingsApplier(
- self.ssh, wireless_configs, channel_2g, channel_5g)
+ self.ssh, wireless_configs, channel_2g, channel_5g, self.radios[1], self.radios[0])
self.wireless_setting.apply_wireless_settings()
def start_ap(self):
@@ -181,31 +193,16 @@
Dictionary of SSID - BSSID map for both bands.
"""
bssid_map = {"2g": {}, "5g": {}}
- for radio in ["radio0", "radio1"]:
+ for radio in self.radios:
ssid_ifname_map = self.get_ifnames_for_ssids(radio)
- if radio == "radio0":
+ if radio == self.radios[0]:
for ssid, ifname in ssid_ifname_map.items():
bssid_map["5g"][ssid] = self.get_bssid(ifname)
- elif radio == "radio1":
+ elif radio == self.radios[1]:
for ssid, ifname in ssid_ifname_map.items():
bssid_map["2g"][ssid] = self.get_bssid(ifname)
return bssid_map
- def get_wifi_status(self):
- """Check if radios are up for both 2G and 5G bands.
-
- Returns:
- True if both radios are up. False if not.
- """
- radios = ["radio0", "radio1"]
- status = True
- for radio in radios:
- str_output = self.ssh.run("wifi status %s" % radio).stdout
- wifi_status = yaml.load(str_output.replace("\t", "").replace("\n", ""),
- Loader=yaml.FullLoader)
- status = wifi_status[radio]["up"] and status
- return status
-
def get_ifnames_for_ssids(self, radio):
"""Get interfaces for wifi networks.
@@ -218,7 +215,7 @@
ssid_ifname_map = {}
str_output = self.ssh.run("wifi status %s" % radio).stdout
wifi_status = yaml.load(str_output.replace("\t", "").replace("\n", ""),
- Loader=yaml.FullLoader)
+ Loader=yaml.SafeLoader)
wifi_status = wifi_status[radio]
if wifi_status["up"]:
interfaces = wifi_status["interfaces"]
@@ -249,32 +246,32 @@
"""
str_output = self.ssh.run("wifi status").stdout
wifi_status = yaml.load(str_output.replace("\t", "").replace("\n", ""),
- Loader=yaml.FullLoader)
+ Loader=yaml.SafeLoader)
# Counting how many interface are enabled.
total_interface = 0
- for radio in ["radio0", "radio1"]:
- num_interface = len(wifi_status[radio]['interfaces'])
+ for radio in self.radios:
+ num_interface = len(wifi_status[radio]["interfaces"])
total_interface += num_interface
# Iterates every interface to get and set wpa encryption.
default_extra_interface = 2
for i in range(total_interface + default_extra_interface):
origin_encryption = self.ssh.run(
- 'uci get wireless.@wifi-iface[{}].encryption'.format(i)).stdout
- origin_psk_pattern = re.match(r'psk\b', origin_encryption)
- target_psk_pattern = re.match(r'psk\b', encryption)
- origin_psk2_pattern = re.match(r'psk2\b', origin_encryption)
- target_psk2_pattern = re.match(r'psk2\b', encryption)
+ "uci get wireless.@wifi-iface[{}].encryption".format(i)).stdout
+ origin_psk_pattern = re.match(r"psk\b", origin_encryption)
+ target_psk_pattern = re.match(r"psk\b", encryption)
+ origin_psk2_pattern = re.match(r"psk2\b", origin_encryption)
+ target_psk2_pattern = re.match(r"psk2\b", encryption)
if origin_psk_pattern == target_psk_pattern:
self.ssh.run(
- 'uci set wireless.@wifi-iface[{}].encryption={}'.format(
+ "uci set wireless.@wifi-iface[{}].encryption={}".format(
i, encryption))
if origin_psk2_pattern == target_psk2_pattern:
self.ssh.run(
- 'uci set wireless.@wifi-iface[{}].encryption={}'.format(
+ "uci set wireless.@wifi-iface[{}].encryption={}".format(
i, encryption))
self.ssh.run("uci commit wireless")
@@ -295,7 +292,7 @@
self.log.error("Password must only contains ascii letters and digits")
else:
self.ssh.run(
- 'uci set wireless.@wifi-iface[{}].key={}'.format(3, pwd_5g))
+ "uci set wireless.@wifi-iface[{}].key={}".format(3, pwd_5g))
self.log.info("Set 5G password to :{}".format(pwd_5g))
if pwd_2g:
@@ -306,7 +303,7 @@
self.log.error("Password must only contains ascii letters and digits")
else:
self.ssh.run(
- 'uci set wireless.@wifi-iface[{}].key={}'.format(2, pwd_2g))
+ "uci set wireless.@wifi-iface[{}].key={}".format(2, pwd_2g))
self.log.info("Set 2G password to :{}".format(pwd_2g))
self.ssh.run("uci commit wireless")
@@ -325,7 +322,7 @@
# Only accept ascii letters and digits
else:
self.ssh.run(
- 'uci set wireless.@wifi-iface[{}].ssid={}'.format(3, ssid_5g))
+ "uci set wireless.@wifi-iface[{}].ssid={}".format(3, ssid_5g))
self.log.info("Set 5G SSID to :{}".format(ssid_5g))
if ssid_2g:
@@ -334,42 +331,44 @@
# Only accept ascii letters and digits
else:
self.ssh.run(
- 'uci set wireless.@wifi-iface[{}].ssid={}'.format(2, ssid_2g))
+ "uci set wireless.@wifi-iface[{}].ssid={}".format(2, ssid_2g))
self.log.info("Set 2G SSID to :{}".format(ssid_2g))
self.ssh.run("uci commit wireless")
self.ssh.run("wifi")
def generate_mobility_domain(self):
- """Generate 4-character hexadecimal ID
+ """Generate 4-character hexadecimal ID.
- Returns: String; a 4-character hexadecimal ID.
- """
- md = "{:04x}".format(random.getrandbits(16))
- self.log.info("Mobility Domain ID: {}".format(md))
- return md
+ Returns:
+ String; a 4-character hexadecimal ID.
+ """
+ md = "{:04x}".format(random.getrandbits(16))
+ self.log.info("Mobility Domain ID: {}".format(md))
+ return md
def enable_80211r(self, iface, md):
"""Enable 802.11r for one single radio.
- Args:
- iface: index number of wifi-iface.
+ Args:
+ iface: index number of wifi-iface.
2: radio1
3: radio0
- md: mobility domain. a 4-character hexadecimal ID.
- Raises: TestSkip if 2g or 5g radio is not up or 802.11r is not enabled.
- """
+ md: mobility domain. a 4-character hexadecimal ID.
+ Raises:
+ TestSkip if 2g or 5g radio is not up or 802.11r is not enabled.
+ """
str_output = self.ssh.run("wifi status").stdout
wifi_status = yaml.load(str_output.replace("\t", "").replace("\n", ""),
- Loader=yaml.FullLoader)
+ Loader=yaml.SafeLoader)
# Check if the radio is up.
if iface == OpenWrtWifiSetting.IFACE_2G:
- if wifi_status['radio1']['up']:
+ if wifi_status[self.radios[1]]["up"]:
self.log.info("2g network is ENABLED")
else:
raise signals.TestSkip("2g network is NOT ENABLED")
elif iface == OpenWrtWifiSetting.IFACE_5G:
- if wifi_status['radio0']['up']:
+ if wifi_status[self.radios[0]]["up"]:
self.log.info("5g network is ENABLED")
else:
raise signals.TestSkip("5g network is NOT ENABLED")
@@ -379,10 +378,10 @@
"uci set wireless.@wifi-iface[{}].ieee80211r='1'".format(iface))
self.ssh.run(
"uci set wireless.@wifi-iface[{}].ft_psk_generate_local='1'"
- .format(iface))
+ .format(iface))
self.ssh.run(
"uci set wireless.@wifi-iface[{}].mobility_domain='{}'"
- .format(iface, md))
+ .format(iface, md))
self.ssh.run(
"uci commit wireless")
self.ssh.run("wifi")
@@ -390,7 +389,7 @@
# Check if 802.11r is enabled.
result = self.ssh.run(
"uci get wireless.@wifi-iface[{}].ieee80211r".format(iface)).stdout
- if result == '1':
+ if result == "1":
self.log.info("802.11r is ENABLED")
else:
raise signals.TestSkip("802.11r is NOT ENABLED")
@@ -587,6 +586,51 @@
return wifi_network
return None
+ def get_wifi_status(self):
+ """Check if radios are up. Default are 2G and 5G bands.
+
+ Returns:
+ True if both radios are up. False if not.
+ """
+ status = True
+ for radio in self.radios:
+ str_output = self.ssh.run("wifi status %s" % radio).stdout
+ wifi_status = yaml.load(str_output.replace("\t", "").replace("\n", ""),
+ Loader=yaml.SafeLoader)
+ status = wifi_status[radio]["up"] and status
+ return status
+
+ def verify_wifi_status(self, timeout=20):
+ """Ensure wifi interfaces are ready.
+
+ Args:
+ timeout: An integer that is the number of times to try
+ wait for interface ready.
+ Returns:
+ True if both radios are up. False if not.
+ """
+ start_time = time.time()
+ end_time = start_time + timeout
+ while time.time() < end_time:
+ if self.get_wifi_status():
+ return True
+ time.sleep(1)
+ return False
+
+ def get_model_name(self):
+ """Get Openwrt model name.
+
+ Returns:
+ A string include device brand and model. e.g. NETGEAR_R8000
+ """
+ out = self.ssh.run(SYSTEM_INFO_CMD).stdout.split("\n")
+ for line in out:
+ if "board_name" in line:
+ model = (line.split()[1].strip("\",").split(","))
+ return "_".join(map(lambda i: i.upper(), model))
+ self.log.info("Failed to retrieve OpenWrt model information.")
+ return None
+
def close(self):
"""Reset wireless and network settings to default and stop AP."""
if self.network_setting.config:
@@ -597,3 +641,8 @@
def close_ssh(self):
"""Close SSH connection to AP."""
self.ssh.close()
+
+ def reboot(self):
+ """Reboot Openwrt."""
+ self.ssh.run("reboot")
+
diff --git a/acts/framework/acts/controllers/openwrt_lib/OWNERS b/acts/framework/acts/controllers/openwrt_lib/OWNERS
index 1840d87..6ddb5ea 100644
--- a/acts/framework/acts/controllers/openwrt_lib/OWNERS
+++ b/acts/framework/acts/controllers/openwrt_lib/OWNERS
@@ -1,3 +1,4 @@
jerrypcchen@google.com
gmoturu@google.com
martschneider@google.com
+sishichen@google.com
diff --git a/acts/framework/acts/controllers/openwrt_lib/network_const.py b/acts/framework/acts/controllers/openwrt_lib/network_const.py
index 76dd34b..3aba0de 100644
--- a/acts/framework/acts/controllers/openwrt_lib/network_const.py
+++ b/acts/framework/acts/controllers/openwrt_lib/network_const.py
@@ -1,3 +1,5 @@
+LOCALHOST = "192.168.1.1"
+
# params for ipsec.conf
IPSEC_CONF = {
"config setup": {
@@ -15,7 +17,7 @@
"conn L2TP_PSK": {
"keyexchange": "ikev1",
"type": "transport",
- "left": "192.168.1.1",
+ "left": LOCALHOST,
"leftprotoport": "17/1701",
"leftauth": "psk",
"right": "%any",
@@ -30,7 +32,7 @@
"conn L2TP_RSA": {
"keyexchange": "ikev1",
"type": "transport",
- "left": "192.168.1.1",
+ "left": LOCALHOST,
"leftprotoport": "17/1701",
"leftauth": "pubkey",
"leftcert": "serverCert.der",
@@ -42,9 +44,149 @@
}
}
+IPSEC_HYBRID_RSA = {
+ "conn HYBRID_RSA": {
+ "keyexchange": "ikev1",
+ "left": LOCALHOST,
+ "leftsubnet": "0.0.0.0/0",
+ "leftauth": "pubkey",
+ "leftcert": "serverCert.der",
+ "leftsendcert": "always",
+ "right": "%any",
+ "rightsubnet": "0.0.0.0/0",
+ "rightauth": "pubkey",
+ "rightauth2": "xauth",
+ "xauth": "server",
+ "auto": "add",
+ }
+}
+
+IPSEC_XAUTH_PSK = {
+ "conn XAUTH_PSK": {
+ "keyexchange": "ikev1",
+ "left": LOCALHOST,
+ "leftsubnet": "0.0.0.0/0",
+ "leftauth": "psk",
+ "right": "%any",
+ "rightsubnet": "0.0.0.0/0",
+ "rightauth": "psk",
+ "rightauth2": "xauth",
+ "auto": "add",
+ }
+}
+
+IPSEC_XAUTH_RSA = {
+ "conn XAUTH_RSA": {
+ "keyexchange": "ikev1",
+ "left": LOCALHOST,
+ "leftsubnet": "0.0.0.0/0",
+ "leftcert": "serverCert.der",
+ "leftsendcert": "always",
+ "right": "%any",
+ "rightsubnet": "0.0.0.0/0",
+ "rightauth": "xauth",
+ "xauth": "server",
+ "auto": "add",
+ }
+}
+
+IPSEC_IKEV2_MSCHAPV2 = {
+ "conn IKEV2_MSCHAPV2": {
+ "keyexchange": "ikev2",
+ "left": LOCALHOST,
+ "leftid": LOCALHOST,
+ "leftcert": "serverCert.der",
+ "leftsubnet": "0.0.0.0/0",
+ "leftauth": "pubkey",
+ "leftsendcert": "always",
+ "right": "%any",
+ "rightid": "vpntest",
+ "rightauth": "eap-mschapv2",
+ "auto": "add"
+ }
+}
+
+IPSEC_IKEV2_PSK = {
+ "conn IKEV2_PSK": {
+ "keyexchange": "ikev2",
+ "left": LOCALHOST,
+ "leftid": LOCALHOST,
+ "leftauth": "psk",
+ "leftsubnet": "0.0.0.0/0",
+ "right": "%any",
+ "rightid": "vpntest",
+ "rightauth": "psk",
+ "auto": "add"
+ }
+}
+
+IPSEC_IKEV2_RSA = {
+ "conn IKEV2_RSA": {
+ "keyexchange": "ikev2",
+ "left": LOCALHOST,
+ "leftid": LOCALHOST,
+ "leftcert": "serverCert.der",
+ "leftsubnet": "0.0.0.0/0",
+ "leftauth": "pubkey",
+ "leftsendcert": "always",
+ "right": "%any",
+ "rightid": "vpntest@%s" % LOCALHOST,
+ "rightauth": "pubkey",
+ "rightcert": "clientCert.pem",
+ "auto": "add"
+ }
+}
+
+IPSEC_IKEV2_MSCHAPV2_HOSTNAME = {
+ "conn IKEV2_MSCHAPV2_HOSTNAME": {
+ "keyexchange": "ikev2",
+ "left": LOCALHOST,
+ "leftid": "strongswan-vpn-server.android-iperf.com",
+ "leftcert": "serverCert.der",
+ "leftsubnet": "0.0.0.0/0",
+ "leftauth": "pubkey",
+ "leftsendcert": "always",
+ "right": "%any",
+ "rightid": "vpntest",
+ "rightauth": "eap-mschapv2",
+ "auto": "add"
+ }
+}
+
+IPSEC_IKEV2_PSK_HOSTNAME = {
+ "conn IKEV2_PSK_HOSTNAME": {
+ "keyexchange": "ikev2",
+ "left": LOCALHOST,
+ "leftid": "strongswan-vpn-server.android-iperf.com",
+ "leftauth": "psk",
+ "leftsubnet": "0.0.0.0/0",
+ "right": "%any",
+ "rightid": "vpntest",
+ "rightauth": "psk",
+ "auto": "add"
+ }
+}
+
+IPSEC_IKEV2_RSA_HOSTNAME = {
+ "conn IKEV2_RSA_HOSTNAME": {
+ "keyexchange": "ikev2",
+ "left": LOCALHOST,
+ "leftid": "strongswan-vpn-server.android-iperf.com",
+ "leftcert": "serverCert.der",
+ "leftsubnet": "0.0.0.0/0",
+ "leftauth": "pubkey",
+ "leftsendcert": "always",
+ "right": "%any",
+ "rightid": "vpntest@strongswan-vpn-server.android-iperf.com",
+ "rightauth": "pubkey",
+ "rightcert": "clientCert.pem",
+ "auto": "add"
+ }
+}
+
# parmas for lx2tpd
-XL2TPD_CONF_GLOBAL = [
+XL2TPD_CONF_GLOBAL = (
"[global]",
"ipsec saref = no",
"debug tunnel = no",
@@ -54,9 +196,9 @@
"access control = no",
"rand source = dev",
"port = 1701",
-]
+)
-XL2TPD_CONF_INS = [
+XL2TPD_CONF_INS = (
"[lns default]",
"require authentication = yes",
"pass peer = yes",
@@ -64,9 +206,9 @@
"length bit = yes",
"refuse pap = yes",
"refuse chap = yes",
-]
+)
-XL2TPD_OPTION = [
+XL2TPD_OPTION = (
"require-mschap-v2",
"refuse-mschap",
"ms-dns 8.8.8.8",
@@ -87,23 +229,22 @@
"lcp-echo-interval 30",
"lcp-echo-failure 4",
"nomppe"
-]
+)
# iptable rules for vpn_pptp
-FIREWALL_RULES_FOR_PPTP = [
+FIREWALL_RULES_FOR_PPTP = (
"iptables -A input_rule -i ppp+ -j ACCEPT",
"iptables -A output_rule -o ppp+ -j ACCEPT",
"iptables -A forwarding_rule -i ppp+ -j ACCEPT"
-]
+)
# iptable rules for vpn_l2tp
-FIREWALL_RULES_FOR_L2TP = [
+FIREWALL_RULES_FOR_L2TP = (
"iptables -I INPUT -m policy --dir in --pol ipsec --proto esp -j ACCEPT",
"iptables -I FORWARD -m policy --dir in --pol ipsec --proto esp -j ACCEPT",
"iptables -I FORWARD -m policy --dir out --pol ipsec --proto esp -j ACCEPT",
"iptables -I OUTPUT -m policy --dir out --pol ipsec --proto esp -j ACCEPT",
"iptables -t nat -I POSTROUTING -m policy --pol ipsec --dir out -j ACCEPT",
- "iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT",
"iptables -A INPUT -p esp -j ACCEPT",
"iptables -A INPUT -i eth0.2 -p udp --dport 500 -j ACCEPT",
"iptables -A INPUT -i eth0.2 -p tcp --dport 500 -j ACCEPT",
@@ -111,7 +252,14 @@
"iptables -A INPUT -p udp --dport 500 -j ACCEPT",
"iptables -A INPUT -p udp --dport 4500 -j ACCEPT",
"iptables -A INPUT -p udp -m policy --dir in --pol ipsec -m udp --dport 1701 -j ACCEPT"
-]
+)
+
+FIREWALL_RULES_DISABLE_DNS_RESPONSE = (
+ "iptables -I OUTPUT -p udp --sport 53 -j DROP",
+ "iptables -I OUTPUT -p tcp --sport 53 -j DROP",
+ "ip6tables -I OUTPUT -p udp --sport 53 -j DROP",
+ "ip6tables -I OUTPUT -p tcp --sport 53 -j DROP",
+)
# Object for vpn profile
diff --git a/acts/framework/acts/controllers/openwrt_lib/network_settings.py b/acts/framework/acts/controllers/openwrt_lib/network_settings.py
index 91cdb03..b3c1e4e 100644
--- a/acts/framework/acts/controllers/openwrt_lib/network_settings.py
+++ b/acts/framework/acts/controllers/openwrt_lib/network_settings.py
@@ -13,8 +13,13 @@
# limitations under the License.
import re
+import time
+
+from acts import signals
+from acts import utils
from acts.controllers.openwrt_lib import network_const
+
SERVICE_DNSMASQ = "dnsmasq"
SERVICE_STUNNEL = "stunnel"
SERVICE_NETWORK = "network"
@@ -22,8 +27,14 @@
SERVICE_FIREWALL = "firewall"
SERVICE_IPSEC = "ipsec"
SERVICE_XL2TPD = "xl2tpd"
+SERVICE_ODHCPD = "odhcpd"
+SERVICE_OPENNDS = "opennds"
+SERVICE_UHTTPD = "uhttpd"
PPTP_PACKAGE = "pptpd kmod-nf-nathelper-extra"
L2TP_PACKAGE = "strongswan-full openssl-util xl2tpd"
+NAT6_PACKAGE = "ip6tables kmod-ipt-nat6"
+CAPTIVE_PORTAL_PACKAGE = "opennds php7-cli php7-mod-openssl php7-cgi php7"
+MDNS_PACKAGE = "avahi-utils avahi-daemon-service-http avahi-daemon-service-ssh libavahi-client avahi-dbus-daemon"
STUNNEL_CONFIG_PATH = "/etc/stunnel/DoTServer.conf"
HISTORY_CONFIG_PATH = "/etc/dirty_configs"
PPTPD_OPTION_PATH = "/etc/ppp/options.pptpd"
@@ -31,6 +42,8 @@
XL2TPD_OPTION_CONFIG_PATH = "/etc/ppp/options.xl2tpd"
FIREWALL_CUSTOM_OPTION_PATH = "/etc/firewall.user"
PPP_CHAP_SECRET_PATH = "/etc/ppp/chap-secrets"
+IKEV2_VPN_CERT_KEYS_PATH = "/var/ikev2_cert.sh"
+TCPDUMP_DIR = "/tmp/tcpdump/"
LOCALHOST = "192.168.1.1"
DEFAULT_PACKAGE_INSTALL_TIMEOUT = 200
@@ -40,26 +53,30 @@
Attributes:
ssh: ssh connection object.
- service_manager: Object manage service configuration
+ ssh_settings: ssh settings for AccessPoint.
+ service_manager: Object manage service configuration.
+ user: username for ssh.
ip: ip address for AccessPoint.
log: Logging object for AccessPoint.
config: A list to store changes on network settings.
- firewall_rules_list: A list of firewall rule name list
+ firewall_rules_list: A list of firewall rule name list.
cleanup_map: A dict for compare oppo functions.
l2tp: profile for vpn l2tp server.
"""
- def __init__(self, ssh, ip, logger):
+ def __init__(self, ssh, ssh_settings, logger):
"""Initialize wireless settings.
Args:
ssh: ssh connection object.
- ip: ip address for AccessPoint.
+ ssh_settings: ssh settings for AccessPoint.
logger: Logging object for AccessPoint.
"""
self.ssh = ssh
self.service_manager = ServiceManager(ssh)
- self.ip = ip
+ self.ssh_settings = ssh_settings
+ self.user = self.ssh_settings.username
+ self.ip = self.ssh_settings.hostname
self.log = logger
self.config = set()
self.firewall_rules_list = []
@@ -67,7 +84,15 @@
"setup_dns_server": self.remove_dns_server,
"setup_vpn_pptp_server": self.remove_vpn_pptp_server,
"setup_vpn_l2tp_server": self.remove_vpn_l2tp_server,
- "disable_ipv6": self.enable_ipv6
+ "disable_ipv6": self.enable_ipv6,
+ "setup_ipv6_bridge": self.remove_ipv6_bridge,
+ "default_dns": self.del_default_dns,
+ "default_v6_dns": self.del_default_v6_dns,
+ "ipv6_prefer_option": self.remove_ipv6_prefer_option,
+ "block_dns_response": self.unblock_dns_response,
+ "setup_mdns": self.remove_mdns,
+ "add_dhcp_rapid_commit": self.remove_dhcp_rapid_commit,
+ "setup_captive_portal": self.remove_cpative_portal
}
# This map contains cleanup functions to restore the configuration to
# its default state. We write these keys to HISTORY_CONFIG_PATH prior to
@@ -75,6 +100,7 @@
# This makes it easier to recover after an aborted test.
self.update_firewall_rules_list()
self.cleanup_network_settings()
+ self.clear_tcpdump()
def cleanup_network_settings(self):
"""Reset all changes on Access point."""
@@ -88,7 +114,11 @@
if self.config:
temp = self.config.copy()
for change in temp:
- self.cleanup_map[change]()
+ change_list = change.split()
+ if len(change_list) > 1:
+ self.cleanup_map[change_list[0]](*change_list[1:])
+ else:
+ self.cleanup_map[change]()
self.config = set()
if self.file_exists(HISTORY_CONFIG_PATH):
@@ -161,13 +191,28 @@
return False
def path_exists(self, abs_path):
- """Check if dir exist on OpenWrt."""
+ """Check if dir exist on OpenWrt.
+
+ Args:
+ abs_path: absolutely path for create folder.
+ """
try:
self.ssh.run("ls %s" % abs_path)
except:
return False
return True
+ def create_folder(self, abs_path):
+ """If dir not exist, create it.
+
+ Args:
+ abs_path: absolutely path for create folder.
+ """
+ if not self.path_exists(abs_path):
+ self.ssh.run("mkdir %s" % abs_path)
+ else:
+ self.log.info("%s already existed." %abs_path)
+
def count(self, config, key):
"""Count in uci config.
@@ -397,11 +442,11 @@
org: Organization name for generate cert keys.
"""
self.l2tp = network_const.VpnL2tp(vpn_server_hostname,
- vpn_server_address,
- vpn_username,
- vpn_password,
- psk_secret,
- server_name)
+ vpn_server_address,
+ vpn_username,
+ vpn_password,
+ psk_secret,
+ server_name)
self.package_install(L2TP_PACKAGE)
self.config.add("setup_vpn_l2tp_server")
@@ -416,8 +461,14 @@
self.setup_ppp_secret()
# /etc/config/firewall & /etc/firewall.user
self.setup_firewall_rules_for_l2tp()
+ # setup vpn server local ip
+ self.setup_vpn_local_ip()
# generate cert and key for rsa
- self.generate_vpn_cert_keys(country, org)
+ if self.l2tp.name == "ikev2-server":
+ self.generate_ikev2_vpn_cert_keys(country, org)
+ self.add_resource_record(self.l2tp.hostname, LOCALHOST)
+ else:
+ self.generate_vpn_cert_keys(country, org)
# restart service
self.service_manager.need_restart(SERVICE_IPSEC)
self.service_manager.need_restart(SERVICE_XL2TPD)
@@ -428,6 +479,9 @@
"""Remove l2tp vpn server on OpenWrt."""
self.config.discard("setup_vpn_l2tp_server")
self.restore_firewall_rules_for_l2tp()
+ self.remove_vpn_local_ip()
+ if self.l2tp.name == "ikev2-server":
+ self.clear_resource_record()
self.service_manager.need_restart(SERVICE_IPSEC)
self.service_manager.need_restart(SERVICE_XL2TPD)
self.service_manager.need_restart(SERVICE_FIREWALL)
@@ -451,28 +505,41 @@
def setup_ipsec(self):
"""Setup ipsec config."""
- def load_config(data):
+ def load_ipsec_config(data, rightsourceip=False):
for i in data.keys():
config.append(i)
for j in data[i].keys():
config.append("\t %s=%s" % (j, data[i][j]))
+ if rightsourceip:
+ config.append("\t rightsourceip=%s.16/26" % self.l2tp.address.rsplit(".", 1)[0])
config.append("")
config = []
- load_config(network_const.IPSEC_CONF)
- load_config(network_const.IPSEC_L2TP_PSK)
- load_config(network_const.IPSEC_L2TP_RSA)
+ load_ipsec_config(network_const.IPSEC_IKEV2_MSCHAPV2, True)
+ load_ipsec_config(network_const.IPSEC_IKEV2_PSK, True)
+ load_ipsec_config(network_const.IPSEC_IKEV2_RSA, True)
+ load_ipsec_config(network_const.IPSEC_IKEV2_MSCHAPV2_HOSTNAME, True)
+ load_ipsec_config(network_const.IPSEC_IKEV2_PSK_HOSTNAME, True)
+ load_ipsec_config(network_const.IPSEC_IKEV2_RSA_HOSTNAME, True)
+ load_ipsec_config(network_const.IPSEC_CONF)
+ load_ipsec_config(network_const.IPSEC_L2TP_PSK)
+ load_ipsec_config(network_const.IPSEC_L2TP_RSA)
+ load_ipsec_config(network_const.IPSEC_HYBRID_RSA, True)
+ load_ipsec_config(network_const.IPSEC_XAUTH_PSK, True)
+ load_ipsec_config(network_const.IPSEC_XAUTH_RSA, True)
self.create_config_file("\n".join(config), "/etc/ipsec.conf")
ipsec_secret = []
ipsec_secret.append(r": PSK \"%s\"" % self.l2tp.psk_secret)
ipsec_secret.append(r": RSA \"%s\"" % "serverKey.der")
+ ipsec_secret.append(r"%s : XAUTH \"%s\"" % (self.l2tp.username,
+ self.l2tp.password))
self.create_config_file("\n".join(ipsec_secret), "/etc/ipsec.secrets")
def setup_xl2tpd(self, ip_range=20):
"""Setup xl2tpd config."""
net_id, host_id = self.l2tp.address.rsplit(".", 1)
- xl2tpd_conf = network_const.XL2TPD_CONF_GLOBAL
+ xl2tpd_conf = list(network_const.XL2TPD_CONF_GLOBAL)
xl2tpd_conf.append("auth file = %s" % PPP_CHAP_SECRET_PATH)
xl2tpd_conf.extend(network_const.XL2TPD_CONF_INS)
xl2tpd_conf.append("ip range = %s.%s-%s.%s" %
@@ -483,7 +550,7 @@
xl2tpd_conf.append("pppoptfile = %s" % XL2TPD_OPTION_CONFIG_PATH)
self.create_config_file("\n".join(xl2tpd_conf), XL2TPD_CONFIG_PATH)
- xl2tpd_option = network_const.XL2TPD_OPTION
+ xl2tpd_option = list(network_const.XL2TPD_OPTION)
xl2tpd_option.append("name %s" % self.l2tp.name)
self.create_config_file("\n".join(xl2tpd_option),
XL2TPD_OPTION_CONFIG_PATH)
@@ -547,6 +614,54 @@
self.ssh.run("mv clientPkcs.p12 /www/downloads/")
self.ssh.run("chmod 664 /www/downloads/clientPkcs.p12")
+ def generate_ikev2_vpn_cert_keys(self, country, org):
+ rsa = "--type rsa"
+ lifetime = "--lifetime 365"
+ size = "--size 4096"
+
+ if not self.path_exists("/www/downloads/"):
+ self.ssh.run("mkdir /www/downloads/")
+
+ ikev2_vpn_cert_keys = [
+ "ipsec pki --gen %s %s --outform der > caKey.der" % (rsa, size),
+ "ipsec pki --self --ca %s --in caKey.der %s --dn "
+ "\"C=%s, O=%s, CN=%s\" --outform der > caCert.der" %
+ (lifetime, rsa, country, org, self.l2tp.hostname),
+ "ipsec pki --gen %s %s --outform der > serverKey.der" % (size, rsa),
+ "ipsec pki --pub --in serverKey.der %s | ipsec pki --issue %s "
+ r"--cacert caCert.der --cakey caKey.der --dn \"C=%s, O=%s, CN=%s\" "
+ "--san %s --san %s --flag serverAuth --flag ikeIntermediate "
+ "--outform der > serverCert.der" % (rsa, lifetime, country, org,
+ self.l2tp.hostname, LOCALHOST,
+ self.l2tp.hostname),
+ "ipsec pki --gen %s %s --outform der > clientKey.der" % (size, rsa),
+ "ipsec pki --pub --in clientKey.der %s | ipsec pki --issue %s "
+ r"--cacert caCert.der --cakey caKey.der --dn \"C=%s, O=%s, CN=%s@%s\" "
+ r"--san \"%s\" --san \"%s@%s\" --san \"%s@%s\" --outform der "
+ "> clientCert.der" % (rsa, lifetime, country, org, self.l2tp.username,
+ self.l2tp.hostname, self.l2tp.username,
+ self.l2tp.username, LOCALHOST,
+ self.l2tp.username, self.l2tp.hostname),
+ "openssl rsa -inform DER -in clientKey.der "
+ "-out clientKey.pem -outform PEM",
+ "openssl x509 -inform DER -in clientCert.der "
+ "-out clientCert.pem -outform PEM",
+ "openssl x509 -inform DER -in caCert.der "
+ "-out caCert.pem -outform PEM",
+ "openssl pkcs12 -in clientCert.pem -inkey clientKey.pem "
+ "-certfile caCert.pem -export -out clientPkcs.p12 -passout pass:",
+ "mv caCert.pem /etc/ipsec.d/cacerts/",
+ "mv *Cert* /etc/ipsec.d/certs/",
+ "mv *Key* /etc/ipsec.d/private/",
+ "mv clientPkcs.p12 /www/downloads/",
+ "chmod 664 /www/downloads/clientPkcs.p12",
+ ]
+ file_string = "\n".join(ikev2_vpn_cert_keys)
+ self.create_config_file(file_string, IKEV2_VPN_CERT_KEYS_PATH)
+
+ self.ssh.run("chmod +x %s" % IKEV2_VPN_CERT_KEYS_PATH)
+ self.ssh.run("%s" % IKEV2_VPN_CERT_KEYS_PATH)
+
def update_firewall_rules_list(self):
"""Update rule list in /etc/config/firewall."""
new_rules_list = []
@@ -574,7 +689,7 @@
self.ssh.run("uci set firewall.@rule[-1].src='wan'")
self.ssh.run("uci set firewall.@rule[-1].proto='47'")
- iptable_rules = network_const.FIREWALL_RULES_FOR_PPTP
+ iptable_rules = list(network_const.FIREWALL_RULES_FOR_PPTP)
self.add_custom_firewall_rules(iptable_rules)
self.service_manager.need_restart(SERVICE_FIREWALL)
@@ -617,7 +732,7 @@
self.ssh.run("uci set firewall.@rule[-1].proto='ah'")
net_id = self.l2tp.address.rsplit(".", 1)[0]
- iptable_rules = network_const.FIREWALL_RULES_FOR_L2TP
+ iptable_rules = list(network_const.FIREWALL_RULES_FOR_L2TP)
iptable_rules.append("iptables -A FORWARD -s %s.0/24"
" -j ACCEPT" % net_id)
iptable_rules.append("iptables -t nat -A POSTROUTING"
@@ -670,6 +785,24 @@
"""Disable pptp service."""
self.package_remove(PPTP_PACKAGE)
+ def setup_vpn_local_ip(self):
+ """Setup VPN Server local ip on OpenWrt for client ping verify."""
+ self.ssh.run("uci set network.lan2=interface")
+ self.ssh.run("uci set network.lan2.type=bridge")
+ self.ssh.run("uci set network.lan2.ifname=eth1.2")
+ self.ssh.run("uci set network.lan2.proto=static")
+ self.ssh.run("uci set network.lan2.ipaddr=\"%s\"" % self.l2tp.address)
+ self.ssh.run("uci set network.lan2.netmask=255.255.255.0")
+ self.ssh.run("uci set network.lan2=interface")
+ self.service_manager.reload(SERVICE_NETWORK)
+ self.commit_changes()
+
+ def remove_vpn_local_ip(self):
+ """Discard vpn local ip on OpenWrt."""
+ self.ssh.run("uci delete network.lan2")
+ self.service_manager.reload(SERVICE_NETWORK)
+ self.commit_changes()
+
def enable_ipv6(self):
"""Enable ipv6 on OpenWrt."""
self.ssh.run("uci set network.lan.ipv6=1")
@@ -688,6 +821,248 @@
self.service_manager.reload(SERVICE_NETWORK)
self.commit_changes()
+ def setup_ipv6_bridge(self):
+ """Setup ipv6 bridge for client have ability to access network."""
+ self.config.add("setup_ipv6_bridge")
+
+ self.ssh.run("uci set dhcp.lan.dhcpv6=relay")
+ self.ssh.run("uci set dhcp.lan.ra=relay")
+ self.ssh.run("uci set dhcp.lan.ndp=relay")
+
+ self.ssh.run("uci set dhcp.wan6=dhcp")
+ self.ssh.run("uci set dhcp.wan6.dhcpv6=relay")
+ self.ssh.run("uci set dhcp.wan6.ra=relay")
+ self.ssh.run("uci set dhcp.wan6.ndp=relay")
+ self.ssh.run("uci set dhcp.wan6.master=1")
+ self.ssh.run("uci set dhcp.wan6.interface=wan6")
+
+ # Enable service
+ self.service_manager.need_restart(SERVICE_ODHCPD)
+ self.commit_changes()
+
+ def remove_ipv6_bridge(self):
+ """Discard ipv6 bridge on OpenWrt."""
+ if "setup_ipv6_bridge" in self.config:
+ self.config.discard("setup_ipv6_bridge")
+
+ self.ssh.run("uci set dhcp.lan.dhcpv6=server")
+ self.ssh.run("uci set dhcp.lan.ra=server")
+ self.ssh.run("uci delete dhcp.lan.ndp")
+
+ self.ssh.run("uci delete dhcp.wan6")
+
+ self.service_manager.need_restart(SERVICE_ODHCPD)
+ self.commit_changes()
+
+ def _add_dhcp_option(self, args):
+ self.ssh.run("uci add_list dhcp.lan.dhcp_option=\"%s\"" % args)
+
+ def _remove_dhcp_option(self, args):
+ self.ssh.run("uci del_list dhcp.lan.dhcp_option=\"%s\"" % args)
+
+ def add_default_dns(self, addr_list):
+ """Add default dns server for client.
+
+ Args:
+ addr_list: dns ip address for Openwrt client.
+ """
+ self._add_dhcp_option("6,%s" % ",".join(addr_list))
+ self.config.add("default_dns %s" % addr_list)
+ self.service_manager.need_restart(SERVICE_DNSMASQ)
+ self.commit_changes()
+
+ def del_default_dns(self, addr_list):
+ """Remove default dns server for client.
+
+ Args:
+ addr_list: list of dns ip address for Openwrt client.
+ """
+ self._remove_dhcp_option("6,%s" % addr_list)
+ self.config.discard("default_dns %s" % addr_list)
+ self.service_manager.need_restart(SERVICE_DNSMASQ)
+ self.commit_changes()
+
+ def add_default_v6_dns(self, addr_list):
+ """Add default v6 dns server for client.
+
+ Args:
+ addr_list: dns ip address for Openwrt client.
+ """
+ self.ssh.run("uci add_list dhcp.lan.dns=\"%s\"" % addr_list)
+ self.config.add("default_v6_dns %s" % addr_list)
+ self.service_manager.need_restart(SERVICE_ODHCPD)
+ self.commit_changes()
+
+ def del_default_v6_dns(self, addr_list):
+ """Del default v6 dns server for client.
+
+ Args:
+ addr_list: dns ip address for Openwrt client.
+ """
+ self.ssh.run("uci del_list dhcp.lan.dns=\"%s\"" % addr_list)
+ self.config.add("default_v6_dns %s" % addr_list)
+ self.service_manager.need_restart(SERVICE_ODHCPD)
+ self.commit_changes()
+
+ def add_ipv6_prefer_option(self):
+ self._add_dhcp_option("108,1800i")
+ self.config.add("ipv6_prefer_option")
+ self.service_manager.need_restart(SERVICE_DNSMASQ)
+ self.commit_changes()
+
+ def remove_ipv6_prefer_option(self):
+ self._remove_dhcp_option("108,1800i")
+ self.config.discard("ipv6_prefer_option")
+ self.service_manager.need_restart(SERVICE_DNSMASQ)
+ self.commit_changes()
+
+ def add_dhcp_rapid_commit(self):
+ self.create_config_file("dhcp-rapid-commit\n","/etc/dnsmasq.conf")
+ self.config.add("add_dhcp_rapid_commit")
+ self.service_manager.need_restart(SERVICE_DNSMASQ)
+ self.commit_changes()
+
+ def remove_dhcp_rapid_commit(self):
+ self.create_config_file("","/etc/dnsmasq.conf")
+ self.config.discard("add_dhcp_rapid_commit")
+ self.service_manager.need_restart(SERVICE_DNSMASQ)
+ self.commit_changes()
+
+ def start_tcpdump(self, test_name, args="", interface="br-lan"):
+ """"Start tcpdump on OpenWrt.
+
+ Args:
+ test_name: Test name for create tcpdump file name.
+ args: Option args for tcpdump.
+ interface: Interface to logging.
+ Returns:
+ tcpdump_file_name: tcpdump file name on OpenWrt.
+ pid: tcpdump process id.
+ """
+ self.package_install("tcpdump")
+ if not self.path_exists(TCPDUMP_DIR):
+ self.ssh.run("mkdir %s" % TCPDUMP_DIR)
+ tcpdump_file_name = "openwrt_%s_%s.pcap" % (test_name,
+ time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime(time.time())))
+ tcpdump_file_path = "".join([TCPDUMP_DIR, tcpdump_file_name])
+ cmd = "tcpdump -i %s -s0 %s -w %s" % (interface, args, tcpdump_file_path)
+ self.ssh.run_async(cmd)
+ pid = self._get_tcpdump_pid(tcpdump_file_name)
+ if not pid:
+ raise signals.TestFailure("Fail to start tcpdump on OpenWrt.")
+ # Set delay to prevent tcpdump fail to capture target packet.
+ time.sleep(15)
+ return tcpdump_file_name
+
+ def stop_tcpdump(self, tcpdump_file_name, pull_dir=None):
+ """Stop tcpdump on OpenWrt and pull the pcap file.
+
+ Args:
+ tcpdump_file_name: tcpdump file name on OpenWrt.
+ pull_dir: Keep none if no need to pull.
+ Returns:
+ tcpdump abs_path on host.
+ """
+ # Set delay to prevent tcpdump fail to capture target packet.
+ time.sleep(15)
+ pid = self._get_tcpdump_pid(tcpdump_file_name)
+ self.ssh.run("kill -9 %s" % pid, ignore_status=True)
+ if self.path_exists(TCPDUMP_DIR) and pull_dir:
+ tcpdump_path = "".join([TCPDUMP_DIR, tcpdump_file_name])
+ tcpdump_remote_path = "/".join([pull_dir, tcpdump_file_name])
+ tcpdump_local_path = "%s@%s:%s" % (self.user, self.ip, tcpdump_path)
+ utils.exe_cmd("scp %s %s" % (tcpdump_local_path, tcpdump_remote_path))
+
+ if self._get_tcpdump_pid(tcpdump_file_name):
+ raise signals.TestFailure("Failed to stop tcpdump on OpenWrt.")
+ if self.file_exists(tcpdump_path):
+ self.ssh.run("rm -f %s" % tcpdump_path)
+ return tcpdump_remote_path if pull_dir else None
+
+ def clear_tcpdump(self):
+ self.ssh.run("killall tcpdump", ignore_status=True)
+ if self.ssh.run("pgrep tcpdump", ignore_status=True).stdout:
+ raise signals.TestFailure("Failed to clean up tcpdump process.")
+ if self.path_exists(TCPDUMP_DIR):
+ self.ssh.run("rm -f %s/*" % TCPDUMP_DIR)
+
+ def _get_tcpdump_pid(self, tcpdump_file_name):
+ """Check tcpdump process on OpenWrt."""
+ return self.ssh.run("pgrep -f %s" % (tcpdump_file_name), ignore_status=True).stdout
+
+ def setup_mdns(self):
+ self.config.add("setup_mdns")
+ self.package_install(MDNS_PACKAGE)
+ self.commit_changes()
+
+ def remove_mdns(self):
+ self.config.discard("setup_mdns")
+ self.package_remove(MDNS_PACKAGE)
+ self.commit_changes()
+
+ def block_dns_response(self):
+ self.config.add("block_dns_response")
+ iptable_rules = list(network_const.FIREWALL_RULES_DISABLE_DNS_RESPONSE)
+ self.add_custom_firewall_rules(iptable_rules)
+ self.service_manager.need_restart(SERVICE_FIREWALL)
+ self.commit_changes()
+
+ def unblock_dns_response(self):
+ self.config.discard("block_dns_response")
+ self.remove_custom_firewall_rules()
+ self.service_manager.need_restart(SERVICE_FIREWALL)
+ self.commit_changes()
+
+ def setup_captive_portal(self, fas_fdqn,fas_port=2080):
+ """Create captive portal with Forwarding Authentication Service.
+
+ Args:
+ fas_fdqn: String for captive portal page's fdqn add to local dns server.
+ fas_port: Port for captive portal page.
+ """
+ self.package_install(CAPTIVE_PORTAL_PACKAGE)
+ self.config.add("setup_captive_portal %s" % fas_port)
+ self.ssh.run("uci set opennds.@opennds[0].fas_secure_enabled=2")
+ self.ssh.run("uci set opennds.@opennds[0].gatewayport=2050")
+ self.ssh.run("uci set opennds.@opennds[0].fasport=%s" % fas_port)
+ self.ssh.run("uci set opennds.@opennds[0].fasremotefqdn=%s" % fas_fdqn)
+ self.ssh.run("uci set opennds.@opennds[0].faspath=\"/nds/fas-aes.php\"")
+ self.ssh.run("uci set opennds.@opennds[0].faskey=1234567890")
+ self.service_manager.need_restart(SERVICE_OPENNDS)
+ # Config uhttpd
+ self.ssh.run("uci set uhttpd.main.interpreter=.php=/usr/bin/php-cgi")
+ self.ssh.run("uci add_list uhttpd.main.listen_http=0.0.0.0:%s" % fas_port)
+ self.ssh.run("uci add_list uhttpd.main.listen_http=[::]:%s" % fas_port)
+ self.service_manager.need_restart(SERVICE_UHTTPD)
+ # cp fas-aes.php
+ self.create_folder("/www/nds/")
+ self.ssh.run("cp /etc/opennds/fas-aes.php /www/nds")
+ # Add fdqn
+ self.add_resource_record(fas_fdqn, LOCALHOST)
+ self.commit_changes()
+
+ def remove_cpative_portal(self, fas_port=2080):
+ """Remove captive portal.
+
+ Args:
+ fas_port: Port for captive portal page.
+ """
+ # Remove package
+ self.package_remove(CAPTIVE_PORTAL_PACKAGE)
+ # Clean up config
+ self.ssh.run("rm /etc/config/opennds")
+ # Remove fdqn
+ self.clear_resource_record()
+ # Restore uhttpd
+ self.ssh.run("uci del uhttpd.main.interpreter")
+ self.ssh.run("uci del_list uhttpd.main.listen_http=\'0.0.0.0:%s\'" % fas_port)
+ self.ssh.run("uci del_list uhttpd.main.listen_http=\'[::]:%s\'" % fas_port)
+ self.service_manager.need_restart(SERVICE_UHTTPD)
+ # Clean web root
+ self.ssh.run("rm -r /www/nds")
+ self.config.discard("setup_captive_portal %s" % fas_port)
+ self.commit_changes()
+
class ServiceManager(object):
"""Class for service on OpenWrt.
@@ -720,6 +1095,8 @@
def restart_services(self):
"""Restart all services need to restart."""
for service in self._need_restart:
+ if service == SERVICE_NETWORK:
+ self.reload(service)
self.restart(service)
self._need_restart = set()
diff --git a/acts/framework/acts/controllers/openwrt_lib/openwrt_constants.py b/acts/framework/acts/controllers/openwrt_lib/openwrt_constants.py
index 5ab4124..c0a408d 100644
--- a/acts/framework/acts/controllers/openwrt_lib/openwrt_constants.py
+++ b/acts/framework/acts/controllers/openwrt_lib/openwrt_constants.py
@@ -14,6 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+SYSTEM_INFO_CMD = "ubus call system board"
+
+
class OpenWrtWifiSecurity:
# Used by OpenWrt AP
WPA_PSK_DEFAULT = "psk"
@@ -25,6 +28,11 @@
WPA2_PSK_TKIP = "psk2+tkip"
WPA2_PSK_TKIP_AND_CCMP = "psk2+tkip+ccmp"
+
class OpenWrtWifiSetting:
IFACE_2G = 2
- IFACE_5G = 3
\ No newline at end of file
+ IFACE_5G = 3
+
+
+class OpenWrtModelMap:
+ NETGEAR_R8000 = ("radio2", "radio1")
diff --git a/acts/framework/acts/controllers/openwrt_lib/wireless_settings_applier.py b/acts/framework/acts/controllers/openwrt_lib/wireless_settings_applier.py
index a366c02..dd37cc2 100644
--- a/acts/framework/acts/controllers/openwrt_lib/wireless_settings_applier.py
+++ b/acts/framework/acts/controllers/openwrt_lib/wireless_settings_applier.py
@@ -19,6 +19,8 @@
ENABLE_RADIO = "0"
DISABLE_RADIO = "1"
ENABLE_HIDDEN = "1"
+RADIO_2G = "radio1"
+RADIO_5G = "radio0"
class WirelessSettingsApplier(object):
@@ -33,7 +35,7 @@
channel_5g: channel for 5G band.
"""
- def __init__(self, ssh, configs, channel_2g, channel_5g):
+ def __init__(self, ssh, configs, channel_2g, channel_5g, radio_2g=RADIO_2G, radio_5g=RADIO_5G):
"""Initialize wireless settings.
Args:
@@ -48,59 +50,63 @@
self.wireless_configs = configs
self.channel_2g = channel_2g
self.channel_5g = channel_5g
+ self.radio_2g = radio_2g
+ self.radio_5g = radio_5g
def apply_wireless_settings(self):
"""Configure wireless settings from a list of configs."""
+ default_2g_iface = "default_" + self.radio_2g
+ default_5g_iface = "default_" + self.radio_5g
# set channels for 2G and 5G bands
- self.ssh.run("uci set wireless.radio1.channel='%s'" % self.channel_2g)
- self.ssh.run("uci set wireless.radio0.channel='%s'" % self.channel_5g)
+ self.ssh.run("uci set wireless.%s.channel='%s'" % (self.radio_2g, self.channel_2g))
+ self.ssh.run("uci set wireless.%s.channel='%s'" % (self.radio_5g, self.channel_5g))
if self.channel_5g == 165:
- self.ssh.run("uci set wireless.radio0.htmode='VHT20'")
+ self.ssh.run("uci set wireless.%s.htmode='VHT20'" % self.radio_5g)
elif self.channel_5g == 132 or self.channel_5g == 136:
self.ssh.run("iw reg set ZA")
- self.ssh.run("uci set wireless.radio0.htmode='VHT40'")
+ self.ssh.run("uci set wireless.%s.htmode='VHT40'" % self.radio_5g)
if self.channel_2g == 13:
self.ssh.run("iw reg set AU")
# disable default OpenWrt SSID
- self.ssh.run("uci set wireless.default_radio1.disabled='%s'" %
- DISABLE_RADIO)
- self.ssh.run("uci set wireless.default_radio0.disabled='%s'" %
- DISABLE_RADIO)
+ self.ssh.run("uci set wireless.%s.disabled='%s'" %
+ (default_2g_iface, DISABLE_RADIO))
+ self.ssh.run("uci set wireless.%s.disabled='%s'" %
+ (default_5g_iface, DISABLE_RADIO))
# Enable radios
- self.ssh.run("uci set wireless.radio1.disabled='%s'" % ENABLE_RADIO)
- self.ssh.run("uci set wireless.radio0.disabled='%s'" % ENABLE_RADIO)
+ self.ssh.run("uci set wireless.%s.disabled='%s'" % (self.radio_2g, ENABLE_RADIO))
+ self.ssh.run("uci set wireless.%s.disabled='%s'" % (self.radio_5g, ENABLE_RADIO))
for config in self.wireless_configs:
# configure open network
if config.security == OPEN_SECURITY:
if config.band == hostapd_constants.BAND_2G:
- self.ssh.run("uci set wireless.default_radio1.ssid='%s'" %
- config.ssid)
- self.ssh.run("uci set wireless.default_radio1.disabled='%s'" %
- ENABLE_RADIO)
+ self.ssh.run("uci set wireless.%s.ssid='%s'" %
+ (default_2g_iface, config.ssid))
+ self.ssh.run("uci set wireless.%s.disabled='%s'" %
+ (default_2g_iface, ENABLE_RADIO))
if config.hidden:
- self.ssh.run("uci set wireless.default_radio1.hidden='%s'" %
- ENABLE_HIDDEN)
+ self.ssh.run("uci set wireless.%s.hidden='%s'" %
+ (default_2g_iface, ENABLE_HIDDEN))
elif config.band == hostapd_constants.BAND_5G:
- self.ssh.run("uci set wireless.default_radio0.ssid='%s'" %
- config.ssid)
- self.ssh.run("uci set wireless.default_radio0.disabled='%s'" %
- ENABLE_RADIO)
+ self.ssh.run("uci set wireless.%s.ssid='%s'" %
+ (default_5g_iface, config.ssid))
+ self.ssh.run("uci set wireless.%s.disabled='%s'" %
+ (default_5g_iface, ENABLE_RADIO))
if config.hidden:
- self.ssh.run("uci set wireless.default_radio0.hidden='%s'" %
- ENABLE_HIDDEN)
+ self.ssh.run("uci set wireless.%s.hidden='%s'" %
+ (default_5g_iface, ENABLE_HIDDEN))
continue
self.ssh.run("uci set wireless.%s='wifi-iface'" % config.name)
if config.band == hostapd_constants.BAND_2G:
- self.ssh.run("uci set wireless.%s.device='radio1'" % config.name)
+ self.ssh.run("uci set wireless.%s.device='%s'" % (config.name, self.radio_2g))
else:
- self.ssh.run("uci set wireless.%s.device='radio0'" % config.name)
+ self.ssh.run("uci set wireless.%s.device='%s'" % (config.name, self.radio_5g))
self.ssh.run("uci set wireless.%s.network='%s'" %
(config.name, config.iface))
self.ssh.run("uci set wireless.%s.mode='ap'" % config.name)
@@ -145,3 +151,4 @@
self.ssh.run("cp %s.tmp %s" % (LEASE_FILE, LEASE_FILE))
self.service_manager.restart(SERVICE_DNSMASQ)
time.sleep(9)
+
diff --git a/acts/framework/acts/controllers/power_metrics.py b/acts/framework/acts/controllers/power_metrics.py
index f4d9edd..98599fe 100644
--- a/acts/framework/acts/controllers/power_metrics.py
+++ b/acts/framework/acts/controllers/power_metrics.py
@@ -15,6 +15,7 @@
# limitations under the License.
import math
+import numpy as np
# Metrics timestamp keys
START_TIMESTAMP = 'start'
@@ -166,6 +167,57 @@
yield float(time[:-1]), float(sample)
+def generate_percentiles(monsoon_file, timestamps, percentiles):
+ """Generates metrics .
+
+ Args:
+ monsoon_file: monsoon-like file where each line has two
+ numbers separated by a space, in the format:
+ seconds_since_epoch amperes
+ seconds_since_epoch amperes
+ timestamps: dict following the output format of
+ instrumentation_proto_parser.get_test_timestamps()
+ percentiles: percentiles to be returned
+ """
+ if timestamps is None:
+ timestamps = {}
+ test_starts = {}
+ test_ends = {}
+ for seg_name, times in timestamps.items():
+ if START_TIMESTAMP in times and END_TIMESTAMP in times:
+ test_starts[seg_name] = Metric(
+ times[START_TIMESTAMP], TIME, MILLISECOND).to_unit(
+ SECOND).value
+ test_ends[seg_name] = Metric(
+ times[END_TIMESTAMP], TIME, MILLISECOND).to_unit(
+ SECOND).value
+
+ arrays = {}
+ for seg_name in test_starts:
+ arrays[seg_name] = []
+
+ with open(monsoon_file, 'r') as m:
+ for line in m:
+ timestamp = float(line.strip().split()[0])
+ value = float(line.strip().split()[1])
+ for seg_name in arrays.keys():
+ if test_starts[seg_name] <= timestamp <= test_ends[seg_name]:
+ arrays[seg_name].append(value)
+
+ results = {}
+ for seg_name in arrays:
+ if len(arrays[seg_name]) == 0:
+ continue
+
+ pairs = zip(percentiles, np.percentile(arrays[seg_name],
+ percentiles))
+ results[seg_name] = [
+ Metric.amps(p[1], 'percentile_%s' % p[0]).to_unit(MILLIAMP) for p in
+ pairs
+ ]
+ return results
+
+
def generate_test_metrics(raw_data, timestamps=None,
voltage=None):
"""Split the data into individual test metrics, based on the timestamps
@@ -185,28 +237,18 @@
test_ends = {}
test_metrics = {}
for seg_name, times in timestamps.items():
- test_metrics[seg_name] = PowerMetrics(voltage)
- try:
+ if START_TIMESTAMP in times and END_TIMESTAMP in times:
+ test_metrics[seg_name] = PowerMetrics(voltage)
test_starts[seg_name] = Metric(
times[START_TIMESTAMP], TIME, MILLISECOND).to_unit(
SECOND).value
- except KeyError:
- raise ValueError(
- 'Missing start timestamp for test scenario "%s". Refer to '
- 'instrumentation_proto.txt for details.' % seg_name)
- try:
test_ends[seg_name] = Metric(
times[END_TIMESTAMP], TIME, MILLISECOND).to_unit(
SECOND).value
- except KeyError:
- raise ValueError(
- 'Missing end timestamp for test scenario "%s". Test '
- 'scenario may have terminated with errors. Refer to '
- 'instrumentation_proto.txt for details.' % seg_name)
# Assign data to tests based on timestamps
for timestamp, amps in raw_data:
- for seg_name in timestamps:
+ for seg_name in test_metrics.keys():
if test_starts[seg_name] <= timestamp <= test_ends[seg_name]:
test_metrics[seg_name].update_metrics(amps)
diff --git a/acts/framework/acts/controllers/rohdeschwarz_lib/cmw500.py b/acts/framework/acts/controllers/rohdeschwarz_lib/cmw500.py
index 5cbf766..755962e 100644
--- a/acts/framework/acts/controllers/rohdeschwarz_lib/cmw500.py
+++ b/acts/framework/acts/controllers/rohdeschwarz_lib/cmw500.py
@@ -86,7 +86,7 @@
class RbPosition(Enum):
- """Supported RB postions."""
+ """Supported RB positions."""
LOW = 'LOW'
HIGH = 'HIGH'
P5 = 'P5'
@@ -123,7 +123,7 @@
class MimoScenario(Enum):
- """Supportted mimo scenarios"""
+ """Supported mimo scenarios"""
SCEN1x1 = 'SCELl:FLEXible SUA1,RF1C,RX1,RF1C,TX1'
SCEN2x2 = 'TRO:FLEXible SUA1,RF1C,RX1,RF1C,TX1,RF3C,TX2'
SCEN4x4 = 'FRO FLEXible SUA1,RF1C,RX1,RF1C,TX1,RF3C,TX2,RF2C,TX3,RF4C,TX4'
@@ -319,7 +319,7 @@
Args:
state: the RRC state that is being waited for.
- timeout: timeout for phone to be in connnected state.
+ timeout: timeout for phone to be in connected state.
Raises:
CmwError on time out.
diff --git a/acts/framework/acts/controllers/rohdeschwarz_lib/cmw500_cellular_simulator.py b/acts/framework/acts/controllers/rohdeschwarz_lib/cmw500_cellular_simulator.py
index 6f97160..dfd7116 100644
--- a/acts/framework/acts/controllers/rohdeschwarz_lib/cmw500_cellular_simulator.py
+++ b/acts/framework/acts/controllers/rohdeschwarz_lib/cmw500_cellular_simulator.py
@@ -39,13 +39,6 @@
LteSimulation.MimoMode.MIMO_4x4: cmw500.MimoModes.MIMO4x4
}
-CMW_MODULATION_MAPPING = {
- LteSimulation.ModulationType.QPSK: cmw500.ModulationType.QPSK,
- LteSimulation.ModulationType.Q16: cmw500.ModulationType.Q16,
- LteSimulation.ModulationType.Q64: cmw500.ModulationType.Q64,
- LteSimulation.ModulationType.Q256: cmw500.ModulationType.Q256
-}
-
# get mcs vs tbsi map with 256-qam disabled(downlink)
get_mcs_tbsi_map_dl = {
cmw500.ModulationType.QPSK: {
@@ -167,15 +160,6 @@
""" A cellular simulator for telephony simulations based on the CMW 500
controller. """
- # Indicates if it is able to use 256 QAM as the downlink modulation for LTE
- LTE_SUPPORTS_DL_256QAM = True
-
- # Indicates if it is able to use 64 QAM as the uplink modulation for LTE
- LTE_SUPPORTS_UL_64QAM = True
-
- # Indicates if 4x4 MIMO is supported for LTE
- LTE_SUPPORTS_4X4_MIMO = True
-
# The maximum number of carriers that this simulator can support for LTE
LTE_MAX_CARRIERS = 1
@@ -208,9 +192,13 @@
self.bts = [self.cmw.get_base_station()]
self.cmw.switch_lte_signalling(cmw500.LteState.LTE_ON)
- def setup_lte_ca_scenario(self):
- """ Configures the equipment for an LTE with CA simulation. """
- raise NotImplementedError()
+ def set_band_combination(self, bands):
+ """ Prepares the test equipment for the indicated band combination.
+
+ Args:
+ bands: a list of bands represented as ints or strings
+ """
+ self.num_carriers = len(bands)
def set_lte_rrc_state_change_timer(self, enabled, time=10):
""" Configures the LTE RRC state change timer.
@@ -442,7 +430,7 @@
time.sleep(1)
- if self.dl_modulation == cmw500.ModulationType.Q256:
+ if self.dl_256_qam_enabled:
tbs = get_mcs_tbsi_map_for_256qam_dl[
self.dl_modulation][mcs_dl]
else:
@@ -452,49 +440,36 @@
self.log.info('dl rb configurations set to {}'.format(
bts.rb_configuration_dl))
- def set_dl_modulation(self, bts_index, modulation):
- """ Sets the DL modulation for the indicated base station.
-
- This function does not actually configure the test equipment with this
- setting, but stores the value to be used later on when setting the
- scheduling type. This is because the CMW500 API only allows to set
- this parameters together.
+ def set_dl_256_qam_enabled(self, bts_index, enabled):
+ """ Determines what MCS table should be used for the downlink.
+ This only saves the setting that will be used when configuring MCS.
Args:
bts_index: the base station number
- modulation: the new DL modulation
+ enabled: whether 256 QAM should be used
"""
- # Convert dl modulation type to CMW modulation type.
- self.dl_modulation = CMW_MODULATION_MAPPING[modulation]
+ self.log.info('Set 256 QAM DL MCS enabled: ' + str(enabled))
+ self.dl_modulation = cmw500.ModulationType.Q256
+ self.dl_256_qam_enabled = True
- self.log.warning('Modulation config stored but not applied until '
- 'set_scheduling_mode called.')
-
- def set_ul_modulation(self, bts_index, modulation):
- """ Sets the UL modulation for the indicated base station.
-
- This function does not actually configure the test equipment with this
- setting, but stores the value to be used later on when setting the
- scheduling type. This is because the CMW500 API only allows to set
- this parameters together.
+ def set_ul_64_qam_enabled(self, bts_index, enabled):
+ """ Determines what MCS table should be used for the uplink.
+ This only saves the setting that will be used when configuring MCS.
Args:
bts_index: the base station number
- modulation: the new UL modulation
+ enabled: whether 64 QAM should be used
"""
+ self.log.info('Set 64 QAM UL MCS enabled: ' + str(enabled))
+ self.dl_modulation = cmw500.ModulationType.Q64
+ self.ul_64_qam_enabled = True
- # Convert ul modulation type to CMW modulation type.
- self.ul_modulation = CMW_MODULATION_MAPPING[modulation]
-
- self.log.warning('Modulation config stored but not applied until '
- 'set_scheduling_mode called.')
-
- def set_tbs_pattern_on(self, bts_index, tbs_pattern_on):
- """ Enables or disables TBS pattern in the indicated base station.
+ def set_mac_padding(self, bts_index, mac_padding):
+ """ Enables or disables MAC padding in the indicated base station.
Args:
bts_index: the base station number
- tbs_pattern_on: the new TBS pattern setting
+ mac_padding: the new MAC padding setting
"""
# TODO (b/143918664): CMW500 doesn't have an equivalent setting.
pass
diff --git a/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500.py b/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500.py
index f5b298e..18c5ab3 100644
--- a/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500.py
+++ b/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2020 - The Android Open Source Project
+# Copyright 2021 - The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,47 +14,368 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import logging
+import time
+import sys
+
from enum import Enum
+from os import path
from acts.controllers import abstract_inst
-class BtsNumber(Enum):
- """Base station Identifiers."""
- BTS1 = 'PCC'
- BTS2 = 'SCC1'
- BTS3 = 'SCC2'
- BTS4 = 'SCC3'
- BTS5 = 'SCC4'
- BTS6 = 'SCC6'
- BTS7 = 'SCC7'
+DEFAULT_XLAPI_PATH = '/home/mobileharness/Rohde-Schwarz/XLAPI/latest/venv/lib/python3.7/site-packages'
+DEFAULT_LTE_STATE_CHANGE_TIMER = 10
+DEFAULT_CELL_SWITCH_ON_TIMER = 60
+DEFAULT_ENDC_TIMER = 300
+
+logger = logging.getLogger('Xlapi_cmx500')
+
+LTE_CELL_PROPERTIES = [
+ 'band',
+ 'bandwidth',
+ 'dl_earfcn',
+ 'ul_earfcn',
+ 'total_dl_power',
+ 'p_b',
+ 'dl_epre',
+ 'ref_signal_power',
+ 'm',
+ 'beamforming_antenna_ports',
+ 'p0_nominal_pusch',
+]
+
+LTE_MHZ_UPPER_BOUND_TO_RB = [
+ (1.5, 6),
+ (4.0, 15),
+ (7.5, 25),
+ (12.5, 50),
+ (17.5, 75),
+]
+
+class DciFormat(Enum):
+ """Support DCI Formats for MIMOs."""
+ DCI_FORMAT_0 = 1
+ DCI_FORMAT_1 = 2
+ DCI_FORMAT_1A = 3
+ DCI_FORMAT_1B = 4
+ DCI_FORMAT_1C = 5
+ DCI_FORMAT_2 = 6
+ DCI_FORMAT_2A = 7
+ DCI_FORMAT_2B = 8
+ DCI_FORMAT_2C = 9
+ DCI_FORMAT_2D = 10
+
+
+class DuplexMode(Enum):
+ """Duplex Modes."""
+ FDD = 'FDD'
+ TDD = 'TDD'
+ DL_ONLY = 'DL_ONLY'
+
+
+class LteBandwidth(Enum):
+ """Supported LTE bandwidths."""
+ BANDWIDTH_1MHz = 6 # MHZ_1 is RB_6
+ BANDWIDTH_3MHz = 15 # MHZ_3 is RB_15
+ BANDWIDTH_5MHz = 25 # MHZ_5 is RB_25
+ BANDWIDTH_10MHz = 50 # MHZ_10 is RB_50
+ BANDWIDTH_15MHz = 75 # MHZ_15 is RB_75
+ BANDWIDTH_20MHz = 100 # MHZ_20 is RB_100
+
+
+class LteState(Enum):
+ """LTE ON and OFF."""
+ LTE_ON = 'ON'
+ LTE_OFF = 'OFF'
+
+
+class MimoModes(Enum):
+ """MIMO Modes dl antennas."""
+ MIMO1x1 = 1
+ MIMO2x2 = 2
+ MIMO4x4 = 4
+
+
+class ModulationType(Enum):
+ """Supported Modulation Types."""
+ Q16 = 0
+ Q64 = 1
+ Q256 = 2
+
+
+class NasState(Enum):
+ """NAS state between callbox and dut."""
+ DEREGISTERED = 'OFF'
+ EMM_REGISTERED = 'EMM'
+ MM5G_REGISTERED = 'NR'
+
+
+class RrcState(Enum):
+ """States to enable/disable rrc."""
+ RRC_ON = 'ON'
+ RRC_OFF = 'OFF'
+
+
+class RrcConnectionState(Enum):
+ """RRC Connection states, describes possible DUT RRC connection states."""
+ IDLE = 1
+ IDLE_PAGING = 2
+ IDLE_CONNECTION_ESTABLISHMENT = 3
+ CONNECTED = 4
+ CONNECTED_CONNECTION_REESTABLISHMENT = 5
+ CONNECTED_SCG_FAILURE = 6
+ CONNECTED_HANDOVER = 7
+ CONNECTED_CONNECTION_RELEASE = 8
+
+
+class SchedulingMode(Enum):
+ """Supported scheduling modes."""
+ USERDEFINEDCH = 'UDCHannels'
+
+
+class TransmissionModes(Enum):
+ """Supported transmission modes."""
+ TM1 = 1
+ TM2 = 2
+ TM3 = 3
+ TM4 = 4
+ TM7 = 7
+ TM8 = 8
+ TM9 = 9
+
+
+MIMO_MAX_LAYER_MAPPING = {
+ MimoModes.MIMO1x1: 1,
+ MimoModes.MIMO2x2: 2,
+ MimoModes.MIMO4x4: 3,
+}
+
class Cmx500(abstract_inst.SocketInstrument):
- def __init__(self, ip_addr, port):
- """Init method to setup variables for controllers.
+ def __init__(self, ip_addr, port, xlapi_path=DEFAULT_XLAPI_PATH):
+ """Init method to setup variables for the controller.
Args:
ip_addr: Controller's ip address.
- port: Port
+ port: Port.
"""
- super(Cmx500, self).__init__(ip_addr, port)
- def switch_lte_signalling(self, state):
- """ Turns LTE signalling ON/OFF.
+ # keeps the socket connection for debug purpose for now
+ super().__init__(ip_addr, port)
+ if not xlapi_path in sys.path:
+ sys.path.insert(0, xlapi_path)
+ self._initial_xlapi()
+ self._settings.system.set_instrument_address(ip_addr)
+ logger.info('The instrument address is {}'.format(
+ self._settings.system.get_instrument_address()))
+
+ self.bts = []
+
+ # Stops all active cells if there is any
+ self.disconnect()
+
+ # loads cell default settings from parameter file if there is one
+ default_setup_path = 'default_cell_setup.rsxp'
+ if path.exists(default_setup_path):
+ self._settings.session.set_test_param_files(default_setup_path)
+
+ self.dut = self._network.get_dut()
+ self.lte_cell = self._network.create_lte_cell('ltecell0')
+ self.nr_cell = self._network.create_nr_cell('nrcell0')
+ self._config_antenna_ports()
+ self.lte_rrc_state_change_timer = DEFAULT_LTE_STATE_CHANGE_TIMER
+ self.rrc_state_change_time_enable = False
+ self.cell_switch_on_timer = DEFAULT_CELL_SWITCH_ON_TIMER
+
+ # _config_antenna_ports for the special RF connection with cmw500 + cmx500.
+ def _config_antenna_ports(self):
+ from rs_mrt.testenvironment.signaling.sri.rat.common import CsiRsAntennaPorts
+ from rs_mrt.testenvironment.signaling.sri.rat.lte import CrsAntennaPorts
+
+ max_csi_rs_ports = CsiRsAntennaPorts.NUMBER_CSI_RS_ANTENNA_PORTS_FOUR
+ max_crs_ports = CrsAntennaPorts.NUMBER_CRS_ANTENNA_PORTS_FOUR
+
+ lte_cell_max_config = self.lte_cell.stub.GetMaximumConfiguration()
+ lte_cell_max_config.csi_rs_antenna_ports = max_csi_rs_ports
+ lte_cell_max_config.crs_antenna_ports = max_crs_ports
+ self.lte_cell.stub.SetMaximumConfiguration(lte_cell_max_config)
+
+ nr_cell_max_config = self.nr_cell.stub.GetMaximumConfiguration()
+ nr_cell_max_config.csi_rs_antenna_ports = max_csi_rs_ports
+ self.nr_cell.stub.SetMaximumConfiguration(nr_cell_max_config)
+
+ def _initial_xlapi(self):
+ import xlapi
+ import mrtype
+ from xlapi import network
+ from xlapi import settings
+
+ self._xlapi = xlapi
+ self._network = network
+ self._settings = settings
+
+ def configure_mimo_settings(self, mimo, bts_index=0):
+ """Sets the mimo scenario for the test.
Args:
- state: an instance of LteState indicating the state to which LTE
- signal has to be set.
+ mimo: mimo scenario to set.
"""
+ self.bts[bts_index].set_mimo_mode(mimo)
+
+ @property
+ def connection_type(self):
+ """Gets the connection type applied in callbox."""
+ state = self.dut.state.rrc_connection_state
+ return RrcConnectionState(state.value)
+
+ def create_base_station(self, cell):
+ """Creates the base station object with cell and current object.
+
+ Args:
+ cell: the XLAPI cell.
+
+ Returns:
+ base station object.
+ Raise:
+ CmxError if the cell is neither LTE nor NR.
+ """
+ from xlapi.lte_cell import LteCell
+ from xlapi.nr_cell import NrCell
+ if isinstance(cell, LteCell):
+ return LteBaseStation(self, cell)
+ elif isinstance(cell, NrCell):
+ return NrBaseStation(self, cell)
+ else:
+ raise CmxError('The cell type is neither LTE nor NR')
+
+ def detach(self):
+ """Detach callbox and controller."""
+ for bts in self.bts:
+ bts.stop()
+
+ def disable_packet_switching(self):
+ """Disable packet switching in call box."""
raise NotImplementedError()
+ def disconnect(self):
+ """Disconnect controller from device and switch to local mode."""
+
+ # Stops all lte and nr_cell
+ for cell in self._network.get_all_lte_cells():
+ if cell.is_on():
+ cell.stop()
+
+ for cell in self._network.get_all_nr_cells():
+ if cell.is_on():
+ cell.stop()
+ self.bts.clear()
+ self._network.reset()
+
def enable_packet_switching(self):
"""Enable packet switching in call box."""
raise NotImplementedError()
- def disable_packet_switching(self):
- """Disable packet switching in call box."""
+ def get_base_station(self, bts_index=0):
+ """Gets the base station object based on bts num. By default
+ bts_index set to 0 (PCC).
+
+ Args:
+ bts_num: base station identifier
+
+ Returns:
+ base station object.
+ """
+ return self.bts[bts_index]
+
+ def get_network(self):
+ """ Gets the network object from cmx500 object."""
+ return self._network
+
+ def init_lte_measurement(self):
+ """Gets the class object for lte measurement which can be used to
+ initiate measurements.
+
+ Returns:
+ lte measurement object.
+ """
raise NotImplementedError()
+ def reset(self):
+ """System level reset."""
+
+ self.disconnect()
+
+ @property
+ def rrc_connection(self):
+ """Gets the RRC connection state."""
+ return self.dut.state.rrc.is_connected
+
+ def set_timer(self, timeout):
+ """Sets timer for the Cmx500 class."""
+ self.rrc_state_change_time_enable = True
+ self.lte_rrc_state_change_timer = timeout
+
+ def switch_lte_signalling(self, state):
+ """ Turns LTE signalling ON/OFF.
+
+ Args:
+ state: an instance of LteState indicating the state to which LTE
+ signal has to be set.
+ """
+ if not isinstance(state, LteState):
+ raise ValueError('state should be the instance of LteState.')
+
+ if self.bts:
+ self.disconnect()
+ self.bts.append(LteBaseStation(self, self.lte_cell))
+ # Switch on the primary Lte cell for on state and switch all lte cells
+ # if the state is off state
+ if state.value == 'ON':
+ self.bts[0].start()
+ cell_status = self.bts[0].wait_cell_on(self.cell_switch_on_timer)
+ if cell_status:
+ logger.info('The LTE pcell status is on')
+ else:
+ raise CmxError('The LTE pcell cannot be switched on')
+ else:
+ for bts in self.bts:
+ if isinstance(bts, LteBaseStation):
+ bts.stop()
+ logger.info(
+ 'The LTE cell status is {} after stop'.format(bts.is_on()))
+
+ def switch_on_nsa_signalling(self):
+ if self.bts:
+ self.disconnect()
+ logger.info('Switches on NSA signalling')
+ self.bts.append(LteBaseStation(self, self.lte_cell))
+ self.bts.append(NrBaseStation(self, self.nr_cell))
+ self.bts[0].start()
+ lte_cell_status = self.bts[0].wait_cell_on(self.cell_switch_on_timer)
+ if lte_cell_status:
+ logger.info('The LTE pcell status is on')
+ else:
+ raise CmxError('The LTE pcell cannot be switched on')
+
+ self.bts[1].start()
+ nr_cell_status = self.bts[1].wait_cell_on(self.cell_switch_on_timer)
+ if nr_cell_status:
+ logger.info('The NR cell status is on')
+ else:
+ raise CmxError('The NR cell cannot be switched on')
+
+ def update_lte_cell_config(self, config):
+ """Updates lte cell settings with config."""
+ set_counts = 0
+ for property in LTE_CELL_PROPERTIES:
+ if property in config:
+ setter_name = 'set_' + property
+ setter = getattr(self.lte_cell, setter_name)
+ setter(config[property])
+ set_counts += 1
+ if set_counts < len(config):
+ logger.warning('Not all configs were set in update_cell_config')
+
@property
def use_carrier_specific(self):
"""Gets current status of carrier specific duplex configuration."""
@@ -69,38 +390,29 @@
"""
raise NotImplementedError()
- def send_and_recv(self, cmd):
- """Send and recv the status of the command.
+ def wait_for_rrc_state(self, state, timeout=120):
+ """ Waits until a certain RRC state is set.
Args:
- cmd: Command to send.
-
- Returns:
- status: returns the status of the command sent.
- """
- raise NotImplementedError()
-
- def configure_mimo_settings(self, mimo):
- """Sets the mimo scenario for the test.
-
- Args:
- mimo: mimo scenario to set.
- """
- raise NotImplementedError()
-
- def wait_for_pswitched_state(self, timeout=10):
- """Wait until pswitched state.
-
- Args:
- timeout: timeout for lte pswitched state.
+ state: the RRC state that is being waited for.
+ timeout: timeout for phone to be in connected state.
Raises:
- CmxError on timeout.
+ CmxError on time out.
"""
- raise NotImplementedError()
+ is_idle = (state.value == 'OFF')
+ for idx in range(timeout):
+ time.sleep(1)
+ if self.dut.state.rrc.is_idle == is_idle:
+ logger.info('{} reached at {} s'.format(state.value, idx))
+ return True
+ error_message = 'Waiting for {} state timeout after {}'.format(
+ state.value, timeout)
+ logger.error(error_message)
+ raise CmxError(error_message)
- def wait_for_attached_state(self, timeout=120):
- """Attach the controller with device.
+ def wait_until_attached(self, timeout=120):
+ """Waits until Lte attached.
Args:
timeout: timeout for phone to get attached.
@@ -108,609 +420,665 @@
Raises:
CmxError on time out.
"""
- raise NotImplementedError()
-
- def wait_for_rrc_state(self, state, timeout=120):
- """ Waits until a certain RRC state is set.
-
- Args:
- state: the RRC state that is being waited for.
- timeout: timeout for phone to be in connnected state.
-
- Raises:
- CmxError on time out.
- """
- raise NotImplementedError()
-
- def reset(self):
- """System level reset"""
- raise NotImplementedError()
-
- @property
- def get_instrument_id(self):
- """Gets instrument identification number"""
- raise NotImplementedError()
-
- def disconnect(self):
- """Disconnect controller from device and switch to local mode."""
- raise NotImplementedError()
-
- def close_remote_mode(self):
- """Exits remote mode to local mode."""
- raise NotImplementedError()
-
- def detach(self):
- """Detach callbox and controller."""
- raise NotImplementedError()
-
- @property
- def rrc_connection(self):
- """Gets the RRC connection state."""
- raise NotImplementedError()
-
- @rrc_connection.setter
- def rrc_connection(self, state):
- """Selects whether the RRC connection is kept or released after attach.
-
- Args:
- mode: RRC State ON/OFF.
- """
- raise NotImplementedError()
-
- @property
- def rrc_connection_timer(self):
- """Gets the inactivity timeout for disabled rrc connection."""
- raise NotImplementedError()
-
- @rrc_connection_timer.setter
- def rrc_connection_timer(self, time_in_secs):
- """Sets the inactivity timeout for disabled rrc connection. By default
- the timeout is set to 5.
-
- Args:
- time_in_secs: timeout of inactivity in rrc connection.
- """
- raise NotImplementedError()
-
- @property
- def dl_mac_padding(self):
- """Gets the state of mac padding."""
- raise NotImplementedError()
-
- @dl_mac_padding.setter
- def dl_mac_padding(self, state):
- """Enables/Disables downlink padding at the mac layer.
-
- Args:
- state: ON/OFF
- """
- raise NotImplementedError()
-
- @property
- def connection_type(self):
- """Gets the connection type applied in callbox."""
- raise NotImplementedError()
-
- @connection_type.setter
- def connection_type(self, ctype):
- """Sets the connection type to be applied.
-
- Args:
- ctype: Connection type.
- """
- raise NotImplementedError()
-
- def get_base_station(self, bts_num=BtsNumber.BTS1):
- """Gets the base station object based on bts num. By default
- bts_num set to PCC
-
- Args:
- bts_num: base station identifier
-
- Returns:
- base station object.
- """
- raise NotImplementedError()
-
- def init_lte_measurement(self):
- """Gets the class object for lte measurement which can be used to
- initiate measurements.
-
- Returns:
- lte measurement object.
- """
- raise NotImplementedError()
+ try:
+ self.dut.signaling.wait_for_lte_attach(self.lte_cell, timeout)
+ except:
+ raise CmxError(
+ 'wait_until_attached timeout after {}'.format(timeout))
class BaseStation(object):
- """Class to interact with different base stations"""
+ """Class to interact with different the base stations."""
- def __init__(self, cmx, bts_num):
- if not isinstance(bts_num, BtsNumber):
- raise ValueError('bts_num should be an instance of BtsNumber.')
- self._bts = bts_num.value
+ def __init__(self, cmx, cell):
+ """Init method to setup variables for base station.
+
+ Args:
+ cmx: Controller (Cmx500) object.
+ cell: The cell for the base station.
+ """
+
+ self._cell = cell
self._cmx = cmx
+ self._cc = cmx.dut.cc(cell)
+ self._network = cmx.get_network()
+
+ @property
+ def band(self):
+ """Gets the current band of cell.
+
+ Return:
+ the band number in int.
+ """
+ cell_band = self._cell.get_band()
+ return int(cell_band)
+
+ @property
+ def dl_power(self):
+ """Gets RSPRE level.
+
+ Return:
+ the power level in dbm.
+ """
+ return self._cell.get_total_dl_power().in_dBm()
@property
def duplex_mode(self):
"""Gets current duplex of cell."""
- raise NotImplementedError()
+ band = self._cell.get_band()
+ if band.is_fdd():
+ return DuplexMode.FDD
+ if band.is_tdd():
+ return DuplexMode.TDD
+ if band.is_dl_only():
+ return DuplexMode.DL_ONLY
- @duplex_mode.setter
- def duplex_mode(self, mode):
- """Sets the Duplex mode of cell.
+ def is_on(self):
+ """Verifies if the cell is turned on.
- Args:
- mode: String indicating FDD or TDD.
+ Return:
+ boolean (if the cell is on).
"""
- raise NotImplementedError()
+ return self._cell.is_on()
- @property
- def band(self):
- """Gets the current band of cell."""
- raise NotImplementedError()
-
- @band.setter
- def band(self, band):
+ def set_band(self, band):
"""Sets the Band of cell.
Args:
band: band of cell.
"""
- raise NotImplementedError()
+ self._cell.set_band(band)
- @property
- def dl_channel(self):
- """Gets the downlink channel of cell."""
- raise NotImplementedError()
-
- @dl_channel.setter
- def dl_channel(self, channel):
- """Sets the downlink channel number of cell.
+ def set_dl_mac_padding(self, state):
+ """Enables/Disables downlink padding at the mac layer.
Args:
- channel: downlink channel number of cell.
+ state: a boolean
"""
- raise NotImplementedError()
+ self._cc.set_dl_mac_padding(state)
- @property
- def ul_channel(self):
- """Gets the uplink channel of cell."""
- raise NotImplementedError()
-
- @ul_channel.setter
- def ul_channel(self, channel):
- """Sets the up link channel number of cell.
-
- Args:
- channel: up link channel number of cell.
- """
- raise NotImplementedError()
-
- @property
- def bandwidth(self):
- """Get the channel bandwidth of the cell."""
- raise NotImplementedError()
-
- @bandwidth.setter
- def bandwidth(self, bandwidth):
- """Sets the channel bandwidth of the cell.
-
- Args:
- bandwidth: channel bandwidth of cell.
- """
- raise NotImplementedError()
-
- @property
- def ul_frequency(self):
- """Get the uplink frequency of the cell."""
- raise NotImplementedError()
-
- @ul_frequency.setter
- def ul_frequency(self, freq):
- """Get the uplink frequency of the cell.
-
- Args:
- freq: uplink frequency of the cell.
- """
- raise NotImplementedError()
-
- @property
- def dl_frequency(self):
- """Get the downlink frequency of the cell"""
- raise NotImplementedError()
-
- @dl_frequency.setter
- def dl_frequency(self, freq):
- """Get the downlink frequency of the cell.
-
- Args:
- freq: downlink frequency of the cell.
- """
- raise NotImplementedError()
-
- @property
- def transmode(self):
- """Gets the TM of cell."""
- raise NotImplementedError()
-
- @transmode.setter
- def transmode(self, tm_mode):
- """Sets the TM of cell.
-
- Args:
- tm_mode: TM of cell.
- """
- raise NotImplementedError()
-
- @property
- def downlink_power_level(self):
- """Gets RSPRE level."""
- raise NotImplementedError()
-
- @downlink_power_level.setter
- def downlink_power_level(self, pwlevel):
+ def set_dl_power(self, pwlevel):
"""Modifies RSPRE level.
Args:
pwlevel: power level in dBm.
"""
- raise NotImplementedError()
+ self._cell.set_total_dl_power(pwlevel)
- @property
- def uplink_power_control(self):
- """Gets open loop nominal power directly."""
- raise NotImplementedError()
-
- @uplink_power_control.setter
- def uplink_power_control(self, ul_power):
- """Sets open loop nominal power directly.
+ def set_ul_power(self, ul_power):
+ """Sets ul power
Args:
- ul_power: uplink power level.
+ ul_power: the uplink power in dbm
"""
- raise NotImplementedError()
+ self._cc.set_target_ul_power(ul_power)
- @property
- def uldl_configuration(self):
- """Gets uldl configuration of the cell."""
- raise NotImplementedError()
+ def start(self):
+ """Starts the cell."""
+ self._cell.start()
- @uldl_configuration.setter
- def uldl_configuration(self, uldl):
- """Sets the ul-dl configuration.
+ def stop(self):
+ """Stops the cell."""
+ self._cell.stop()
+
+ def wait_cell_on(self, timeout):
+ """Waits the cell on.
Args:
- uldl: Configuration value ranging from 0 to 6.
- """
- raise NotImplementedError()
-
- @property
- def tdd_special_subframe(self):
- """Gets special subframe of the cell."""
- raise NotImplementedError()
-
- @tdd_special_subframe.setter
- def tdd_special_subframe(self, sframe):
- """Sets the tdd special subframe of the cell.
-
- Args:
- sframe: Integer value ranging from 1 to 9.
- """
- raise NotImplementedError()
-
- @property
- def scheduling_mode(self):
- """Gets the current scheduling mode."""
- raise NotImplementedError()
-
- @scheduling_mode.setter
- def scheduling_mode(self, mode):
- """Sets the scheduling type for the cell.
-
- Args:
- mode: Selects the channel mode to be scheduled.
- """
- raise NotImplementedError()
-
- @property
- def rb_configuration_dl(self):
- """Gets rmc's rb configuration for down link. This function returns
- Number of Resource blocks, Resource block position and Modulation type.
- """
- raise NotImplementedError()
-
- @rb_configuration_dl.setter
- def rb_configuration_dl(self, rb_config):
- """Sets the rb configuration for down link for scheduling type.
-
- Args:
- rb_config: Tuple containing Number of resource blocks, resource
- block position and modulation type.
+ timeout: the time for waiting the cell on.
Raises:
- ValueError: If tuple unpacking fails.
+ CmxError on time out.
"""
- raise NotImplementedError()
+ waiting_time = 0
+ while waiting_time < timeout:
+ if self._cell.is_on():
+ return True
+ waiting_time += 1
+ time.sleep(1)
+ return self._cell.is_on()
- @property
- def rb_configuration_ul(self):
- """Gets rb configuration for up link. This function returns
- Number of Resource blocks, Resource block position and Modulation type.
- """
- raise NotImplementedError()
- @rb_configuration_ul.setter
- def rb_configuration_ul(self, rb_config):
- """Sets the rb configuration for down link for scheduling mode.
+class LteBaseStation(BaseStation):
+ """ LTE base station."""
+
+ def __init__(self, cmx, cell):
+ """Init method to setup variables for the LTE base station.
Args:
- rb_config: Tuple containing Number of resource blocks, resource
- block position and modulation type.
-
- Raises:
- ValueError: If tuple unpacking fails.
+ cmx: Controller (Cmx500) object.
+ cell: The cell for the LTE base station.
"""
- raise NotImplementedError()
+ from xlapi.lte_cell import LteCell
+ if not isinstance(cell, LteCell):
+ raise CmxError('The cell is not a LTE cell, LTE base station fails'
+ ' to create.')
+ super().__init__(cmx, cell)
- def validate_rb(self, rb):
- """Validates if rb is within the limits for bandwidth set.
+ def _config_scheduler(self, dl_mcs=None, dl_rb_alloc=None, dl_dci_ncce=None,
+ dl_dci_format=None, dl_tm=None, dl_num_layers=None, dl_mcs_table=None,
+ ul_mcs=None, ul_rb_alloc=None, ul_dci_ncce=None):
- Args:
- rb: No. of resource blocks.
+ from rs_mrt.testenvironment.signaling.sri.rat.lte import DciFormat
+ from rs_mrt.testenvironment.signaling.sri.rat.lte import DlTransmissionMode
+ from rs_mrt.testenvironment.signaling.sri.rat.lte import MaxLayersMIMO
+ from rs_mrt.testenvironment.signaling.sri.rat.lte import McsTable
+ from rs_mrt.testenvironment.signaling.sri.rat.lte import PdcchFormat
- Raises:
- ValueError if rb out of range.
- """
- raise NotImplementedError()
+ log_list = []
+ if dl_mcs:
+ log_list.append('dl_mcs: {}'.format(dl_mcs))
+ if ul_mcs:
+ log_list.append('ul_mcs: {}'.format(ul_mcs))
+ if dl_rb_alloc:
+ log_list.append('dl_rb_alloc: {}'.format(dl_rb_alloc))
+ if ul_rb_alloc:
+ log_list.append('ul_rb_alloc: {}'.format(ul_rb_alloc))
+ if dl_dci_ncce:
+ dl_dci_ncce = PdcchFormat(dl_dci_ncce)
+ log_list.append('dl_dci_ncce: {}'.format(dl_dci_ncce))
+ if ul_dci_ncce:
+ ul_dci_ncce = PdcchFormat(ul_dci_ncce)
+ log_list.append('ul_dci_ncce: {}'.format(ul_dci_ncce))
+ if dl_dci_format:
+ dl_dci_format = DciFormat(dl_dci_format)
+ log_list.append('dl_dci_format: {}'.format(dl_dci_format))
+ if dl_tm:
+ dl_tm = DlTransmissionMode(dl_tm.value)
+ log_list.append('dl_tm: {}'.format(dl_tm))
+ if dl_num_layers:
+ dl_num_layers = MaxLayersMIMO(dl_num_layers)
+ log_list.append('dl_num_layers: {}'.format(dl_num_layers))
+ if dl_mcs_table:
+ dl_mcs_table = McsTable(dl_mcs_table)
+ log_list.append('dl_mcs_table: {}'.format(dl_mcs_table))
+
+ is_on = self._cell.is_on()
+ num_crs_antenna_ports = self._cell.get_num_crs_antenna_ports()
+
+ # Sets num of crs antenna ports to 4 for configuring
+ if is_on:
+ self._cell.stop()
+ time.sleep(1)
+ self._cell.set_num_crs_antenna_ports(4)
+ scheduler = self._cmx.dut.get_scheduler(self._cell)
+ logger.info('configure scheduler for {}'.format(','.join(log_list)))
+ scheduler.configure_scheduler(
+ dl_mcs=dl_mcs, dl_rb_alloc=dl_rb_alloc, dl_dci_ncce=dl_dci_ncce,
+ dl_dci_format=dl_dci_format, dl_tm=dl_tm,
+ dl_num_layers=dl_num_layers, dl_mcs_table=dl_mcs_table,
+ ul_mcs=ul_mcs, ul_rb_alloc=ul_rb_alloc, ul_dci_ncce=ul_dci_ncce)
+ logger.info('Configure scheduler succeeds')
+
+ # Sets num of crs antenna ports back to previous value
+ self._cell.set_num_crs_antenna_ports(num_crs_antenna_ports)
+ self._network.apply_changes()
+
+ if is_on:
+ self._cell.start()
@property
- def rb_position_dl(self):
- """Gets the position of the allocated down link resource blocks within
- the channel band-width.
- """
- raise NotImplementedError()
+ def bandwidth(self):
+ """Get the channel bandwidth of the cell.
- @rb_position_dl.setter
- def rb_position_dl(self, rbpos):
- """Selects the position of the allocated down link resource blocks
- within the channel band-width
-
- Args:
- rbpos: position of resource blocks.
+ Return:
+ the number rb of the bandwidth.
"""
- raise NotImplementedError()
+ return self._cell.get_bandwidth().num_rb
@property
- def rb_position_ul(self):
- """Gets the position of the allocated up link resource blocks within
- the channel band-width.
- """
- raise NotImplementedError()
+ def dl_channel(self):
+ """Gets the downlink channel of cell.
- @rb_position_ul.setter
- def rb_position_ul(self, rbpos):
- """Selects the position of the allocated up link resource blocks
- within the channel band-width.
-
- Args:
- rbpos: position of resource blocks.
+ Return:
+ the downlink channel (earfcn) in int.
"""
- raise NotImplementedError()
+ return int(self._cell.get_dl_earfcn())
@property
- def dci_format(self):
- """Gets the downlink control information (DCI) format."""
- raise NotImplementedError()
+ def dl_frequency(self):
+ """Get the downlink frequency of the cell."""
+ from mrtype.frequency import Frequency
+ return self._cell.get_dl_earfcn().to_freq().in_units(
+ Frequency.Units.GHz)
- @dci_format.setter
- def dci_format(self, dci_format):
+ def _to_rb_bandwidth(self, bandwidth):
+ for idx in range(5):
+ if bandwidth < LTE_MHZ_UPPER_BOUND_TO_RB[idx][0]:
+ return LTE_MHZ_UPPER_BOUND_TO_RB[idx][1]
+ return 100
+
+ def set_bandwidth(self, bandwidth):
+ """Sets the channel bandwidth of the cell.
+
+ Args:
+ bandwidth: channel bandwidth of cell in MHz.
+ """
+ self._cell.set_bandwidth(self._to_rb_bandwidth(bandwidth))
+
+ def set_cell_frequency_band(self, tdd_cfg=None, ssf_cfg=None):
+ """Sets cell frequency band with tdd and ssf config.
+
+ Args:
+ tdd_cfg: the tdd subframe assignment config in number (from 0-6).
+ ssf_cfg: the special subframe pattern config in number (from 1-9).
+ """
+ from rs_mrt.testenvironment.signaling.sri.rat.lte import SpecialSubframePattern
+ from rs_mrt.testenvironment.signaling.sri.rat.lte import SubFrameAssignment
+ from rs_mrt.testenvironment.signaling.sri.rat.lte.config import CellFrequencyBand
+ from rs_mrt.testenvironment.signaling.sri.rat.lte.config import Tdd
+ tdd_subframe = None
+ ssf_pattern = None
+ if tdd_cfg:
+ tdd_subframe = SubFrameAssignment(tdd_cfg + 1)
+ if ssf_cfg:
+ ssf_pattern = SpecialSubframePattern(ssf_cfg)
+ tdd = Tdd(tdd_config=Tdd.TddConfigSignaling(
+ subframe_assignment=tdd_subframe,
+ special_subframe_pattern=ssf_pattern))
+ self._cell.stub.SetCellFrequencyBand(CellFrequencyBand(tdd=tdd))
+ self._network.apply_changes()
+
+ def set_cfi(self, cfi):
+ """Sets number of pdcch symbols (cfi).
+
+ Args:
+ cfi: the value of NumberOfPdcchSymbols
+ """
+ from rs_mrt.testenvironment.signaling.sri.rat.lte import NumberOfPdcchSymbols
+ from rs_mrt.testenvironment.signaling.sri.rat.lte.config import PdcchRegionReq
+
+ logger.info('The cfi enum to set is {}'.format(
+ NumberOfPdcchSymbols(cfi)))
+ req = PdcchRegionReq()
+ req.num_pdcch_symbols = NumberOfPdcchSymbols(cfi)
+ self._cell.stub.SetPdcchControlRegion(req)
+
+ def set_dci_format(self, dci_format):
"""Selects the downlink control information (DCI) format.
Args:
dci_format: supported dci.
"""
- raise NotImplementedError()
+ if not isinstance(dci_format, DciFormat):
+ raise CmxError('Wrong type for dci_format')
+ self._config_scheduler(dl_dci_format=dci_format.value)
+
+ def set_dl_channel(self, channel):
+ """Sets the downlink channel number of cell.
+
+ Args:
+ channel: downlink channel number of cell.
+ """
+ if self.dl_channel == channel:
+ logger.info('The dl_channel was at {}'.format(self.dl_channel))
+ return
+ self._cell.set_earfcn(channel)
+ logger.info('The dl_channel was set to {}'.format(self.dl_channel))
+
+ def set_dl_modulation_table(self, modulation):
+ """Sets down link modulation table.
+
+ Args:
+ modulation: modulation table setting (ModulationType).
+ """
+ if not isinstance(modulation, ModulationType):
+ raise CmxError('The modulation is not the type of Modulation')
+ self._config_scheduler(dl_mcs_table=modulation.value)
+
+ def set_mimo_mode(self, mimo):
+ """Sets mimo mode for Lte scenario.
+
+ Args:
+ mimo: the mimo mode.
+ """
+ if not isinstance(mimo, MimoModes):
+ raise CmxError("Wrong type of mimo mode")
+
+ is_on = self._cell.is_on()
+ if is_on:
+ self._cell.stop()
+ self._cell.set_num_crs_antenna_ports(mimo.value)
+ self._config_scheduler(dl_num_layers=MIMO_MAX_LAYER_MAPPING[mimo])
+ if is_on:
+ self._cell.start()
+
+ def set_scheduling_mode(
+ self, mcs_dl=None, mcs_ul=None, nrb_dl=None, nrb_ul=None):
+ """Sets scheduling mode.
+
+ Args:
+ scheduling: the new scheduling mode.
+ mcs_dl: Downlink MCS.
+ mcs_ul: Uplink MCS.
+ nrb_dl: Number of RBs for downlink.
+ nrb_ul: Number of RBs for uplink.
+ """
+ self._config_scheduler(dl_mcs=mcs_dl, ul_mcs=mcs_ul, dl_rb_alloc=nrb_dl,
+ ul_rb_alloc=nrb_ul)
+
+ def set_ssf_config(self, ssf_config):
+ """Sets ssf subframe assignment with tdd_config.
+
+ Args:
+ ssf_config: the special subframe pattern config (from 1-9).
+ """
+ self.set_cell_frequency_band(ssf_cfg=ssf_config)
+
+ def set_tdd_config(self, tdd_config):
+ """Sets tdd subframe assignment with tdd_config.
+
+ Args:
+ tdd_config: the subframe assignemnt config (from 0-6).
+ """
+ self.set_cell_frequency_band(tdd_cfg=tdd_config)
+
+ def set_transmission_mode(self, transmission_mode):
+ """Sets transmission mode with schedular.
+
+ Args:
+ transmission_mode: the download link transmission mode.
+ """
+ if not isinstance(transmission_mode, TransmissionModes):
+ raise CmxError('Wrong type of the trasmission mode')
+ self._config_scheduler(dl_tm=transmission_mode)
+
+ def set_ul_channel(self, channel):
+ """Sets the up link channel number of cell.
+
+ Args:
+ channel: up link channel number of cell.
+ """
+ if self.ul_channel == channel:
+ logger.info('The ul_channel is at {}'.format(self.ul_channel))
+ return
+ self._cell.set_earfcn(channel)
+ logger.info('The dl_channel was set to {}'.format(self.ul_channel))
@property
- def dl_antenna(self):
- """Gets dl antenna count of cell."""
- raise NotImplementedError()
+ def ul_channel(self):
+ """Gets the uplink channel of cell.
- @dl_antenna.setter
- def dl_antenna(self, num_antenna):
- """Sets the dl antenna count of cell.
-
- Args:
- num_antenna: Count of number of dl antennas to use.
+ Return:
+ the uplink channel (earfcn) in int
"""
- raise NotImplementedError()
+ return int(self._cell.get_ul_earfcn())
@property
- def reduced_pdcch(self):
- """Gets the reduction of PDCCH resources state."""
- raise NotImplementedError()
+ def ul_frequency(self):
+ """Get the uplink frequency of the cell.
- @reduced_pdcch.setter
- def reduced_pdcch(self, state):
- """Sets the reduction of PDCCH resources state.
+ Return:
+ The uplink frequency in GHz.
+ """
+ from mrtype.frequency import Frequency
+ return self._cell.get_ul_earfcn().to_freq().in_units(
+ Frequency.Units.GHz)
+
+ def set_ul_modulation_table(self, modulation):
+ """Sets up link modulation table.
Args:
- state: ON/OFF.
+ modulation: modulation table setting (ModulationType).
"""
- raise NotImplementedError()
+ if not isinstance(modulation, ModulationType):
+ raise CmxError('The modulation is not the type of Modulation')
+ if modulation == ModulationType.Q16:
+ self._cell.stub.SetPuschCommonConfig(False)
+ else:
+ self._cell.stub.SetPuschCommonConfig(True)
- def tpc_power_control(self, set_type):
- """Set and execute the Up Link Power Control via TPC.
+
+class NrBaseStation(BaseStation):
+ """ NR base station."""
+
+ def __init__(self, cmx, cell):
+ """Init method to setup variables for the NR base station.
Args:
- set_type: Type of tpc power control.
+ cmx: Controller (Cmx500) object.
+ cell: The cell for the NR base station.
"""
- raise NotImplementedError()
+ from xlapi.nr_cell import NrCell
+ if not isinstance(cell, NrCell):
+ raise CmxError('the cell is not a NR cell, NR base station fails'
+ ' to creat.')
+
+ super().__init__(cmx, cell)
+
+ def _config_scheduler(self, dl_mcs=None, dl_mcs_table=None,
+ dl_rb_alloc=None, dl_mimo_mode=None,
+ ul_mcs=None, ul_mcs_table=None, ul_rb_alloc=None,
+ ul_mimo_mode=None):
+
+ from rs_mrt.testenvironment.signaling.sri.rat.nr import McsTable
+
+ log_list = []
+ if dl_mcs:
+ log_list.append('dl_mcs: {}'.format(dl_mcs))
+ if ul_mcs:
+ log_list.append('ul_mcs: {}'.format(ul_mcs))
+
+ # If rb alloc is not a tuple, add 0 as start RBs for XLAPI NR scheduler
+ if dl_rb_alloc:
+ if not isinstance(dl_rb_alloc, tuple):
+ dl_rb_alloc = (0, dl_rb_alloc)
+ log_list.append('dl_rb_alloc: {}'.format(dl_rb_alloc))
+ if ul_rb_alloc:
+ if not isinstance(ul_rb_alloc, tuple):
+ ul_rb_alloc = (0, ul_rb_alloc)
+ log_list.append('ul_rb_alloc: {}'.format(ul_rb_alloc))
+ if dl_mcs_table:
+ dl_mcs_table = McsTable(dl_mcs_table)
+ log_list.append('dl_mcs_table: {}'.format(dl_mcs_table))
+ if ul_mcs_table:
+ ul_mcs_table = McsTable(ul_mcs_table)
+ log_list.append('ul_mcs_table: {}'.format(ul_mcs_table))
+ if dl_mimo_mode:
+ log_list.append('dl_mimo_mode: {}'.format(dl_mimo_mode))
+ if ul_mimo_mode:
+ log_list.append('ul_mimo_mode: {}'.format(ul_mimo_mode))
+
+ is_on = self._cell.is_on()
+ if is_on:
+ self._cell.stop()
+ time.sleep(1)
+ scheduler = self._cmx.dut.get_scheduler(self._cell)
+ logger.info('configure scheduler for {}'.format(','.join(log_list)))
+
+ scheduler.configure_ue_scheduler(
+ dl_mcs=dl_mcs, dl_mcs_table=dl_mcs_table,
+ dl_rb_alloc=dl_rb_alloc, dl_mimo_mode=dl_mimo_mode,
+ ul_mcs=ul_mcs, ul_mcs_table=ul_mcs_table,
+ ul_rb_alloc=ul_rb_alloc, ul_mimo_mode=ul_mimo_mode)
+ logger.info('Configure scheduler succeeds')
+ self._network.apply_changes()
+
+ if is_on:
+ self._cell.start()
+
+ def attach_as_secondary_cell(self, endc_timer=DEFAULT_ENDC_TIMER):
+ """Enable endc mode for NR cell.
+
+ Args:
+ endc_timer: timeout for endc state
+ """
+ logger.info('enable endc mode for nsa dual connection')
+ self._cmx.dut.signaling.nsa_dual_connect(self._cell)
+ time_count = 0
+ while time_count < endc_timer:
+ if str(self._cmx.dut.state.radio_connectivity) == \
+ 'RadioConnectivityMode.EPS_LTE_NR':
+ logger.info('enter endc mode')
+ return
+ time.sleep(1)
+ time_count += 1
+ if time_count % 30 == 0:
+ logger.info('did not reach endc at {} s'.format(time_count))
+ raise CmxError('Cannot reach endc after {} s'.format(endc_timer))
@property
- def tpc_closed_loop_target_power(self):
- """Gets the target powers for power control with the TPC setup."""
- raise NotImplementedError()
+ def dl_channel(self):
+ """Gets the downlink channel of cell.
- @tpc_closed_loop_target_power.setter
- def tpc_closed_loop_target_power(self, cltpower):
- """Sets the target powers for power control with the TPC setup.
+ Return:
+ the downlink channel (earfcn) in int.
+ """
+ return int(self._cell.get_dl_ref_a())
+
+ def _bandwidth_to_carrier_bandwidth(self, bandwidth):
+ """Converts bandwidth in MHz to CarrierBandwidth.
+ CarrierBandwidth Enum in XLAPI:
+ MHZ_5 = 0
+ MHZ_10 = 1
+ MHZ_15 = 2
+ MHZ_20 = 3
+ MHZ_25 = 4
+ MHZ_30 = 5
+ MHZ_40 = 6
+ MHZ_50 = 7
+ MHZ_60 = 8
+ MHZ_70 = 9
+ MHZ_80 = 10
+ MHZ_90 = 11
+ MHZ_100 = 12
+ MHZ_200 = 13
+ MHZ_400 = 14
+ Args:
+ bandwidth: channel bandwidth in MHz.
+
+ Return:
+ the corresponding NR Carrier Bandwidth.
+ """
+ from mrtype.nr.frequency import CarrierBandwidth
+ if bandwidth > 100:
+ return CarrierBandwidth(12 + bandwidth // 200)
+ elif bandwidth > 30:
+ return CarrierBandwidth(2 + bandwidth // 10)
+ else:
+ return CarrierBandwidth(bandwidth // 5 - 1)
+
+ def set_band(self, band, frequency_range=None):
+ """Sets the Band of cell.
Args:
- tpower: Target power.
+ band: band of cell.
+ frequency_range: LOW, MID and HIGH for NR cell
"""
- raise NotImplementedError()
+ from mrtype.frequency import FrequencyRange
+ if not frequency_range or frequency_range.upper() == 'LOW':
+ frequency_range = FrequencyRange.LOW
+ elif frequency_range.upper() == 'MID':
+ frequency_range = FrequencyRange.MID
+ elif frequency_range.upper() == 'HIGH':
+ frequency_range = FrequencyRange.HIGH
+ else:
+ raise CmxError('Wrong type FrequencyRange')
- @property
- def drx_connected_mode(self):
- """ Gets the Connected DRX LTE cell parameter
+ self._cell.set_dl_ref_a_offset(band, frequency_range)
+ logger.info('The band is set to {} and is {} after setting'.format(
+ band, self.band))
+
+ def set_bandwidth(self, bandwidth, scs=None):
+ """Sets the channel bandwidth of the cell.
Args:
- None
-
- Returns:
- DRX connected mode (OFF, AUTO, MANUAL)
+ bandwidth: channel bandwidth of cell.
+ scs: subcarrier spacing (SCS) of resource grid 0
"""
- raise NotImplementedError()
+ if not scs:
+ scs = self._cell.get_scs()
+ self._cell.set_carrier_bandwidth_and_scs(
+ self._bandwidth_to_carrier_bandwidth(bandwidth), scs)
+ logger.info('The bandwidth in MHz is {}. After setting, the value is {}'
+ .format(bandwidth, str(self._cell.get_carrier_bandwidth())))
- @drx_connected_mode.setter
- def drx_connected_mode(self, mode):
- """ Sets the Connected DRX LTE cell parameter
+ def set_dl_channel(self, channel):
+ """Sets the downlink channel number of cell.
Args:
- mode: DRX Connected mode
-
- Returns:
- None
+ channel: downlink channel number of cell.
"""
- raise NotImplementedError()
+ from mrtype.nr.frequency import NrArfcn
+ if self.dl_channel == channel:
+ logger.info('The dl_channel was at {}'.format(self.dl_channel))
+ return
+ self._cell.set_dl_ref_a_offset(self.band, NrArfcn(channel))
+ logger.info('The dl_channel was set to {}'.format(self.dl_channel))
- @property
- def drx_on_duration_timer(self):
- """ Gets the amount of PDCCH subframes to wait for data after
- waking up from a DRX cycle
+ def set_dl_modulation_table(self, modulation):
+ """Sets down link modulation table.
Args:
- None
-
- Returns:
- DRX mode duration timer
+ modulation: modulation table setting (ModulationType).
"""
- raise NotImplementedError()
+ if not isinstance(modulation, ModulationType):
+ raise CmxError('The modulation is not the type of Modulation')
+ self._config_scheduler(dl_mcs_table=modulation.value)
- @drx_on_duration_timer.setter
- def drx_on_duration_timer(self, time):
- """ Sets the amount of PDCCH subframes to wait for data after
- waking up from a DRX cycle
+ def set_mimo_mode(self, mimo):
+ """Sets mimo mode for NR nsa scenario.
Args:
- timer: Length of interval to wait for user data to be transmitted
-
- Returns:
- None
+ mimo: the mimo mode.
"""
- raise NotImplementedError()
+ from rs_mrt.testenvironment.signaling.sri.rat.nr import DownlinkMimoMode
+ if not isinstance(mimo, MimoModes):
+ raise CmxError("Wrong type of mimo mode")
- @property
- def drx_inactivity_timer(self):
- """ Gets the number of PDCCH subframes to wait before entering DRX mode
+ is_on = self._cell.is_on()
+ if is_on:
+ self._cell.stop()
+ self._cc.set_dl_mimo_mode(DownlinkMimoMode.Enum(mimo.value))
+ if is_on:
+ self._cell.start()
+
+ def set_scheduling_mode(
+ self, mcs_dl=None, mcs_ul=None, nrb_dl=None, nrb_ul=None):
+ """Sets scheduling mode.
Args:
- None
-
- Returns:
- DRX mode inactivity timer
+ mcs_dl: Downlink MCS.
+ mcs_ul: Uplink MCS.
+ nrb_dl: Number of RBs for downlink.
+ nrb_ul: Number of RBs for uplink.
"""
- raise NotImplementedError()
+ self._config_scheduler(dl_mcs=mcs_dl, ul_mcs=mcs_ul, dl_rb_alloc=nrb_dl,
+ ul_rb_alloc=nrb_ul)
- @drx_inactivity_timer.setter
- def drx_inactivity_timer(self, time):
- """ Sets the number of PDCCH subframes to wait before entering DRX mode
+ def set_ssf_config(self, ssf_config):
+ """Sets ssf subframe assignment with tdd_config.
Args:
- timer: Length of the interval to wait
-
- Returns:
- None
+ ssf_config: the special subframe pattern config (from 1-9).
"""
- raise NotImplementedError()
+ raise CmxError('the set ssf config for nr did not implemente yet')
- @property
- def drx_retransmission_timer(self):
- """ Gets the number of consecutive PDCCH subframes to wait
- for retransmission
+ def set_tdd_config(self, tdd_config):
+ """Sets tdd subframe assignment with tdd_config.
Args:
- None
-
- Returns:
- Number of PDCCH subframes to wait for retransmission
+ tdd_config: the subframe assignemnt config (from 0-6).
"""
- raise NotImplementedError()
+ raise CmxError('the set tdd config for nr did not implemente yet')
- @drx_retransmission_timer.setter
- def drx_retransmission_timer(self, time):
- """ Sets the number of consecutive PDCCH subframes to wait
- for retransmission
+ def set_transmission_mode(self, transmission_mode):
+ """Sets transmission mode with schedular.
Args:
- time: Number of PDCCH subframes to wait
- for retransmission
-
- Returns:
- None
+ transmission_mode: the download link transmission mode.
"""
- raise NotImplementedError()
+ logger.info('The set transmission mode for nr is set by mimo mode')
- @property
- def drx_long_cycle(self):
- """ Gets the amount of subframes representing a DRX long cycle
+ def set_ul_modulation_table(self, modulation):
+ """Sets down link modulation table.
Args:
- None
-
- Returns:
- The amount of subframes representing one long DRX cycle.
- One cycle consists of DRX sleep + DRX on duration
+ modulation: modulation table setting (ModulationType).
"""
- raise NotImplementedError()
-
- @drx_long_cycle.setter
- def drx_long_cycle(self, time):
- """ Sets the amount of subframes representing a DRX long cycle
-
- Args:
- long_cycle: The amount of subframes representing one long DRX cycle.
- One cycle consists of DRX sleep + DRX on duration
-
- Returns:
- None
- """
- raise NotImplementedError()
-
- @property
- def drx_long_cycle_offset(self):
- """ Gets the offset used to determine long cycle starting
- subframe
-
- Args:
- None
-
- Returns:
- Long cycle offset
- """
- raise NotImplementedError()
-
- @drx_long_cycle_offset.setter
- def drx_long_cycle_offset(self, offset):
- """ Sets the offset used to determine long cycle starting
- subframe
-
- Args:
- offset: Number in range 0...(long cycle - 1)
- """
- raise NotImplementedError()
+ if not isinstance(modulation, ModulationType):
+ raise CmxError('The modulation is not the type of Modulation')
+ self._config_scheduler(ul_mcs_table=modulation.value)
class CmxError(Exception):
diff --git a/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500_cellular_simulator.py b/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500_cellular_simulator.py
index 4175d5f..ca281d1 100644
--- a/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500_cellular_simulator.py
+++ b/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500_cellular_simulator.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2020 - The Android Open Source Project
+# Copyright 2021 - The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
@@ -14,15 +14,40 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import logging
from acts.controllers.rohdeschwarz_lib import cmx500
+from acts.controllers.rohdeschwarz_lib.cmx500 import LteBandwidth
+from acts.controllers.rohdeschwarz_lib.cmx500 import LteState
from acts.controllers import cellular_simulator as cc
+from acts.controllers.cellular_lib import LteSimulation
+
+
+CMX_TM_MAPPING = {
+ LteSimulation.TransmissionMode.TM1: cmx500.TransmissionModes.TM1,
+ LteSimulation.TransmissionMode.TM2: cmx500.TransmissionModes.TM2,
+ LteSimulation.TransmissionMode.TM3: cmx500.TransmissionModes.TM3,
+ LteSimulation.TransmissionMode.TM4: cmx500.TransmissionModes.TM4,
+ LteSimulation.TransmissionMode.TM7: cmx500.TransmissionModes.TM7,
+ LteSimulation.TransmissionMode.TM8: cmx500.TransmissionModes.TM8,
+ LteSimulation.TransmissionMode.TM9: cmx500.TransmissionModes.TM9,
+}
+
+CMX_SCH_MAPPING = {
+ LteSimulation.SchedulingMode.STATIC: cmx500.SchedulingMode.USERDEFINEDCH
+}
+
+CMX_MIMO_MAPPING = {
+ LteSimulation.MimoMode.MIMO_1x1: cmx500.MimoModes.MIMO1x1,
+ LteSimulation.MimoMode.MIMO_2x2: cmx500.MimoModes.MIMO2x2,
+ LteSimulation.MimoMode.MIMO_4x4: cmx500.MimoModes.MIMO4x4,
+}
class CMX500CellularSimulator(cc.AbstractCellularSimulator):
""" A cellular simulator for telephony simulations based on the CMX 500
controller. """
- def __init__(self, ip_address, port):
+ def __init__(self, ip_address, port='5025'):
""" Initializes the cellular simulator.
Args:
@@ -30,24 +55,40 @@
port: the port number for the CMX500 controller
"""
super().__init__()
-
try:
self.cmx = cmx500.Cmx500(ip_address, port)
- except cmx500.CmxError:
- raise cc.CellularSimulatorError('Could not connect to CMX500.')
+ except:
+ raise cc.CellularSimulatorError('Error when Initializes CMX500.')
+
+ self.bts = self.cmx.bts
def destroy(self):
""" Sends finalization commands to the cellular equipment and closes
the connection. """
- raise NotImplementedError()
+ self.log.info('destroy the cmx500 simulator')
+ self.cmx.disconnect()
def setup_lte_scenario(self):
""" Configures the equipment for an LTE simulation. """
+ self.log.info('setup lte scenario')
+ self.cmx.switch_lte_signalling(cmx500.LteState.LTE_ON)
+
+ def setup_nr_sa_scenario(self):
+ """ Configures the equipment for an NR stand alone simulation. """
raise NotImplementedError()
- def setup_lte_ca_scenario(self):
- """ Configures the equipment for an LTE with CA simulation. """
- raise NotImplementedError()
+ def setup_nr_nsa_scenario(self):
+ """ Configures the equipment for an NR non stand alone simulation. """
+ self.log.info('setup nsa scenario (start lte cell and nr cell')
+ self.cmx.switch_on_nsa_signalling()
+
+ def set_band_combination(self, bands):
+ """ Prepares the test equipment for the indicated band combination.
+
+ Args:
+ bands: a list of bands represented as ints or strings
+ """
+ self.num_carriers = len(bands)
def set_lte_rrc_state_change_timer(self, enabled, time=10):
""" Configures the LTE RRC state change timer.
@@ -56,16 +97,25 @@
enabled: a boolean indicating if the timer should be on or off.
time: time in seconds for the timer to expire
"""
- raise NotImplementedError()
+ self.log.info('set timer enabled to {} and the time to {}'.format(
+ enabled, time))
+ self.cmx.rrc_state_change_time_enable = enabled
+ self.cmx.lte_rrc_state_change_timer = time
- def set_band(self, bts_index, band):
+
+ def set_band(self, bts_index, band, frequency_range=None):
""" Sets the band for the indicated base station.
Args:
bts_index: the base station number
band: the new band
"""
- raise NotImplementedError()
+ self.log.info('set band to {}'.format(band))
+ if frequency_range:
+ self.bts[bts_index].set_band(
+ int(band), frequency_range=frequency_range)
+ else:
+ self.bts[bts_index].set_band(int(band))
def get_duplex_mode(self, band):
""" Determines if the band uses FDD or TDD duplex mode
@@ -76,7 +126,10 @@
Returns:
an variable of class DuplexMode indicating if band is FDD or TDD
"""
- raise NotImplementedError()
+ if 33 <= int(band) <= 46:
+ return cmx500.DuplexMode.TDD
+ else:
+ return cmx500.DuplexMode.FDD
def set_input_power(self, bts_index, input_power):
""" Sets the input power for the indicated base station.
@@ -85,7 +138,12 @@
bts_index: the base station number
input_power: the new input power
"""
- raise NotImplementedError()
+ if input_power > 23:
+ self.log.warning('Open loop supports -50dBm to 23 dBm. '
+ 'Setting it to max power 23 dBm')
+ input_power = 23
+ self.log.info('set input power to {}'.format(input_power))
+ self.bts[bts_index].set_ul_power(input_power)
def set_output_power(self, bts_index, output_power):
""" Sets the output power for the indicated base station.
@@ -94,16 +152,18 @@
bts_index: the base station number
output_power: the new output power
"""
- raise NotImplementedError()
+ self.log.info('set output power to {}'.format(output_power))
+ self.bts[bts_index].set_dl_power(output_power)
def set_tdd_config(self, bts_index, tdd_config):
""" Sets the tdd configuration number for the indicated base station.
Args:
bts_index: the base station number
- tdd_config: the new tdd configuration number
+ tdd_config: the new tdd configuration number (from 0 to 6)
"""
- raise NotImplementedError()
+ self.log.info('set tdd config to {}'.format(tdd_config))
+ self.bts[bts_index].set_tdd_config(tdd_config)
def set_ssf_config(self, bts_index, ssf_config):
""" Sets the Special Sub-Frame config number for the indicated
@@ -111,27 +171,32 @@
Args:
bts_index: the base station number
- ssf_config: the new ssf config number
+ ssf_config: the new ssf config number (from 0 to 9)
"""
- raise NotImplementedError()
+ self.log.info('set ssf config to {}'.format(ssf_config))
+ self.bts[bts_index].set_ssf_config(ssf_config)
def set_bandwidth(self, bts_index, bandwidth):
""" Sets the bandwidth for the indicated base station.
Args:
bts_index: the base station number
- bandwidth: the new bandwidth
+ bandwidth: the new bandwidth in MHz
"""
- raise NotImplementedError()
+ self.log.info('set bandwidth of bts {} to {}'.format(
+ bts_index, bandwidth))
+ self.bts[bts_index].set_bandwidth(int(bandwidth))
def set_downlink_channel_number(self, bts_index, channel_number):
""" Sets the downlink channel number for the indicated base station.
Args:
bts_index: the base station number
- channel_number: the new channel number
+ channel_number: the new channel number (earfcn)
"""
- raise NotImplementedError()
+ self.log.info('Sets the downlink channel number to {}'.format(
+ channel_number))
+ self.bts[bts_index].set_dl_channel(channel_number)
def set_mimo_mode(self, bts_index, mimo_mode):
""" Sets the mimo mode for the indicated base station.
@@ -140,7 +205,9 @@
bts_index: the base station number
mimo_mode: the new mimo mode
"""
- raise NotImplementedError()
+ self.log.info('set mimo mode to {}'.format(mimo_mode))
+ mimo_mode = CMX_MIMO_MAPPING[mimo_mode]
+ self.bts[bts_index].set_mimo_mode(mimo_mode)
def set_transmission_mode(self, bts_index, tmode):
""" Sets the transmission mode for the indicated base station.
@@ -149,7 +216,9 @@
bts_index: the base station number
tmode: the new transmission mode
"""
- raise NotImplementedError()
+ self.log.info('set TransmissionMode to {}'.format(tmode))
+ tmode = CMX_TM_MAPPING[tmode]
+ self.bts[bts_index].set_transmission_mode(tmode)
def set_scheduling_mode(self, bts_index, scheduling, mcs_dl=None,
mcs_ul=None, nrb_dl=None, nrb_ul=None):
@@ -163,34 +232,56 @@
nrb_dl: Number of RBs for downlink.
nrb_ul: Number of RBs for uplink.
"""
- raise NotImplementedError()
+ if scheduling not in CMX_SCH_MAPPING:
+ raise cc.CellularSimulatorError(
+ "This scheduling mode is not supported")
+ log_list = []
+ if mcs_dl:
+ log_list.append('mcs_dl: {}'.format(mcs_dl))
+ if mcs_ul:
+ log_list.append('mcs_ul: {}'.format(mcs_ul))
+ if nrb_dl:
+ log_list.append('nrb_dl: {}'.format(nrb_dl))
+ if nrb_ul:
+ log_list.append('nrb_ul: {}'.format(nrb_ul))
- def set_dl_modulation(self, bts_index, modulation):
- """ Sets the DL modulation for the indicated base station.
+ self.log.info('set scheduling mode to {}'.format(','.join(log_list)))
+ self.bts[bts_index].set_scheduling_mode(
+ mcs_dl=mcs_dl, mcs_ul=mcs_ul, nrb_dl=nrb_dl, nrb_ul=nrb_ul)
+
+ def set_dl_256_qam_enabled(self, bts_index, enabled):
+ """ Determines what MCS table should be used for the downlink.
Args:
bts_index: the base station number
- modulation: the new DL modulation
+ enabled: whether 256 QAM should be used
"""
- raise NotImplementedError()
+ self.log.info('Set 256 QAM DL MCS enabled: ' + str(enabled))
+ self.bts[bts_index].set_dl_modulation_table(
+ cmx500.ModulationType.Q256 if enabled else cmx500.ModulationType.
+ Q64)
- def set_ul_modulation(self, bts_index, modulation):
- """ Sets the UL modulation for the indicated base station.
+ def set_ul_64_qam_enabled(self, bts_index, enabled):
+ """ Determines what MCS table should be used for the uplink.
Args:
bts_index: the base station number
- modulation: the new UL modulation
+ enabled: whether 64 QAM should be used
"""
- raise NotImplementedError()
+ self.log.info('Set 64 QAM UL MCS enabled: ' + str(enabled))
+ self.bts[bts_index].set_ul_modulation_table(
+ cmx500.ModulationType.Q64 if enabled else cmx500.ModulationType.Q16
+ )
- def set_tbs_pattern_on(self, bts_index, tbs_pattern_on):
- """ Enables or disables TBS pattern in the indicated base station.
+ def set_mac_padding(self, bts_index, mac_padding):
+ """ Enables or disables MAC padding in the indicated base station.
Args:
bts_index: the base station number
- tbs_pattern_on: the new TBS pattern setting
+ mac_padding: the new MAC padding setting
"""
- raise NotImplementedError()
+ self.log.info('set mac pad on {}'.format(mac_padding))
+ self.bts[bts_index].set_dl_mac_padding(mac_padding)
def set_cfi(self, bts_index, cfi):
""" Sets the Channel Format Indicator for the indicated base station.
@@ -199,7 +290,16 @@
bts_index: the base station number
cfi: the new CFI setting
"""
- raise NotImplementedError()
+ if cfi == 'BESTEFFORT':
+ self.log.info('The cfi is BESTEFFORT, use default value')
+ return
+ try:
+ index = int(cfi) + 1
+ except Exception as e:
+ index = 1
+ finally:
+ self.log.info('set the cfi and the cfi index is {}'.format(index))
+ self.bts[bts_index].set_cfi(index)
def set_paging_cycle(self, bts_index, cycle_duration):
""" Sets the paging cycle duration for the indicated base station.
@@ -208,7 +308,8 @@
bts_index: the base station number
cycle_duration: the new paging cycle duration in milliseconds
"""
- raise NotImplementedError()
+ self.log.warning('The set_paging_cycle method is not implememted, '
+ 'use default value')
def set_phich_resource(self, bts_index, phich):
""" Sets the PHICH Resource setting for the indicated base station.
@@ -217,7 +318,8 @@
bts_index: the base station number
phich: the new PHICH resource setting
"""
- raise NotImplementedError()
+ self.log.warning('The set_phich_resource method is not implememted, '
+ 'use default value')
def lte_attach_secondary_carriers(self, ue_capability_enquiry):
""" Activates the secondary carriers for CA. Requires the DUT to be
@@ -227,7 +329,8 @@
ue_capability_enquiry: UE capability enquiry message to be sent to
the UE before starting carrier aggregation.
"""
- raise NotImplementedError()
+ self.wait_until_communication_state()
+ self.bts[1].attach_as_secondary_cell()
def wait_until_attached(self, timeout=120):
""" Waits until the DUT is attached to the primary carrier.
@@ -236,7 +339,8 @@
timeout: after this amount of time the method will raise a
CellularSimulatorError exception. Default is 120 seconds.
"""
- raise NotImplementedError()
+ self.log.info('wait until attached')
+ self.cmx.wait_until_attached(timeout)
def wait_until_communication_state(self, timeout=120):
""" Waits until the DUT is in Communication state.
@@ -244,8 +348,13 @@
Args:
timeout: after this amount of time the method will raise a
CellularSimulatorError exception. Default is 120 seconds.
+ Return:
+ True if cmx reach rrc state within timeout
+ Raise:
+ CmxError if tiemout
"""
- raise NotImplementedError()
+ self.log.info('wait for rrc on state')
+ return self.cmx.wait_for_rrc_state(cmx500.RrcState.RRC_ON, timeout)
def wait_until_idle_state(self, timeout=120):
""" Waits until the DUT is in Idle state.
@@ -253,22 +362,28 @@
Args:
timeout: after this amount of time the method will raise a
CellularSimulatorError exception. Default is 120 seconds.
+ Return:
+ True if cmx reach rrc state within timeout
+ Raise:
+ CmxError if tiemout
"""
- raise NotImplementedError()
+ self.log.info('wait for rrc off state')
+ return self.cmx.wait_for_rrc_state(cmx500.RrcState.RRC_OFF, timeout)
def detach(self):
""" Turns off all the base stations so the DUT loose connection."""
- self.cmx.detach()
+ self.log.info('Bypass simulator detach step for now')
def stop(self):
""" Stops current simulation. After calling this method, the simulator
will need to be set up again. """
- raise NotImplementedError()
+ self.log.info('Stops current simulation and disconnect cmx500')
+ self.cmx.disconnect()
def start_data_traffic(self):
""" Starts transmitting data from the instrument to the DUT. """
- raise NotImplementedError()
+ self.log.warning('The start_data_traffic is not implemented yet')
def stop_data_traffic(self):
""" Stops transmitting data from the instrument to the DUT. """
- raise NotImplementedError()
+ self.log.warning('The stop_data_traffic is not implemented yet')
diff --git a/acts/framework/acts/controllers/rohdeschwarz_lib/contest.py b/acts/framework/acts/controllers/rohdeschwarz_lib/contest.py
index f34a62b..4f7ebdc 100644
--- a/acts/framework/acts/controllers/rohdeschwarz_lib/contest.py
+++ b/acts/framework/acts/controllers/rohdeschwarz_lib/contest.py
@@ -121,7 +121,7 @@
def execute_testplan(self, testplan):
""" Executes a test plan with Contest's Remote Server sequencer.
- Waits until and exit code is provided in the output. Logs the ouput with
+ Waits until and exit code is provided in the output. Logs the output with
the class logger and pulls the json report from the server if the test
succeeds.
diff --git a/acts/framework/acts/controllers/sl4a_lib/error_reporter.py b/acts/framework/acts/controllers/sl4a_lib/error_reporter.py
index b910338..4e90326 100644
--- a/acts/framework/acts/controllers/sl4a_lib/error_reporter.py
+++ b/acts/framework/acts/controllers/sl4a_lib/error_reporter.py
@@ -75,6 +75,7 @@
return False
report = ErrorLogger('%s|%s' % (self.name, ticket))
+ report.info('Creating error report.')
(self.report_on_adb(sl4a_manager.adb, report)
and self.report_device_processes(sl4a_manager.adb, report) and
@@ -212,6 +213,7 @@
def _get_report_ticket(self):
"""Returns the next ticket, or none if all tickets have been used."""
+ logging.debug('Getting ticket for SL4A error report.')
with self._ticket_lock:
self._ticket_number += 1
ticket_number = self._ticket_number
diff --git a/acts/framework/acts/controllers/sl4a_lib/sl4a_manager.py b/acts/framework/acts/controllers/sl4a_lib/sl4a_manager.py
index 8d76f1f..959274d 100644
--- a/acts/framework/acts/controllers/sl4a_lib/sl4a_manager.py
+++ b/acts/framework/acts/controllers/sl4a_lib/sl4a_manager.py
@@ -25,6 +25,8 @@
ATTEMPT_INTERVAL = .25
MAX_WAIT_ON_SERVER_SECONDS = 5
+SL4A_PKG_NAME = 'com.googlecode.android_scripting'
+
_SL4A_LAUNCH_SERVER_CMD = (
'am startservice -a com.googlecode.android_scripting.action.LAUNCH_SERVER '
'--ei com.googlecode.android_scripting.extra.USE_SERVICE_PORT %s '
@@ -109,12 +111,12 @@
self._listen_for_port_lock = threading.Lock()
self._sl4a_ports = set()
self.adb = adb
- self.log = logger.create_logger(
- lambda msg: '[SL4A Manager|%s] %s' % (adb.serial, msg))
+ self.log = logger.create_logger(lambda msg: '[SL4A Manager|%s] %s' % (
+ adb.serial, msg))
self.sessions = {}
self._started = False
- self.error_reporter = error_reporter.ErrorReporter(
- 'SL4A %s' % adb.serial)
+ self.error_reporter = error_reporter.ErrorReporter('SL4A %s' %
+ adb.serial)
@property
def sl4a_ports_in_use(self):
@@ -161,8 +163,8 @@
raise rpc_client.Sl4aConnectionError(
'Unable to find a valid open port for a new server connection. '
- 'Expected port: %s. Open ports: %s' % (device_port,
- self._sl4a_ports))
+ 'Expected port: %s. Open ports: %s' %
+ (device_port, self._sl4a_ports))
def _get_all_ports_command(self):
"""Returns the list of all ports from the command to get ports."""
@@ -203,9 +205,7 @@
def is_sl4a_installed(self):
"""Returns True if SL4A is installed on the AndroidDevice."""
return bool(
- self.adb.shell(
- 'pm path com.googlecode\.android_scripting',
- ignore_status=True))
+ self.adb.shell('pm path %s' % SL4A_PKG_NAME, ignore_status=True))
def start_sl4a_service(self):
"""Starts the SL4A Service on the device.
@@ -218,13 +218,11 @@
if not self.is_sl4a_installed():
raise rpc_client.Sl4aNotInstalledError(
'SL4A is not installed on device %s' % self.adb.serial)
- if self.adb.shell(
- '(ps | grep "S com.googlecode.android_scripting") || true'):
+ if self.adb.shell('(ps | grep "S %s") || true' % SL4A_PKG_NAME):
# Close all SL4A servers not opened by this manager.
# TODO(markdr): revert back to closing all ports after
# b/76147680 is resolved.
- self.adb.shell(
- 'kill -9 $(pidof com.googlecode.android_scripting)')
+ self.adb.shell('kill -9 $(pidof %s)' % SL4A_PKG_NAME)
self.adb.shell(
'settings put global hidden_api_blacklist_exemptions "*"')
# Start the service if it is not up already.
@@ -244,6 +242,7 @@
def create_session(self,
max_connections=None,
client_port=0,
+ forwarded_port=0,
server_port=None):
"""Creates an SL4A server with the given ports if possible.
@@ -252,7 +251,9 @@
be randomized.
Args:
- client_port: The port on the host machine
+ client_port: The client port on the host machine
+ forwarded_port: The server port on the host machine forwarded
+ by adb from the Android device
server_port: The port on the Android device.
max_connections: The max number of client connections for the
session.
@@ -268,19 +269,27 @@
# Otherwise, open a new server on a random port.
else:
server_port = 0
+ self.log.debug(
+ "Creating SL4A session client_port={}, forwarded_port={}, server_port={}"
+ .format(client_port, forwarded_port, server_port))
self.start_sl4a_service()
- session = sl4a_session.Sl4aSession(
- self.adb,
- client_port,
- server_port,
- self.obtain_sl4a_server,
- self.diagnose_failure,
- max_connections=max_connections)
+ session = sl4a_session.Sl4aSession(self.adb,
+ client_port,
+ server_port,
+ self.obtain_sl4a_server,
+ self.diagnose_failure,
+ forwarded_port,
+ max_connections=max_connections)
self.sessions[session.uid] = session
return session
def stop_service(self):
- """Stops The SL4A Service."""
+ """Stops The SL4A Service. Force-stops the SL4A apk."""
+ try:
+ self.adb.shell('am force-stop %s' % SL4A_PKG_NAME,
+ ignore_status=True)
+ except Exception as e:
+ self.log.warning("Fail to stop package %s: %s", SL4A_PKG_NAME, e)
self._started = False
def terminate_all_sessions(self):
diff --git a/acts/framework/acts/controllers/sl4a_lib/sl4a_session.py b/acts/framework/acts/controllers/sl4a_lib/sl4a_session.py
index c0a4e1d..04fd787 100644
--- a/acts/framework/acts/controllers/sl4a_lib/sl4a_session.py
+++ b/acts/framework/acts/controllers/sl4a_lib/sl4a_session.py
@@ -55,6 +55,7 @@
device_port,
get_server_port_func,
on_error_callback,
+ forwarded_port=0,
max_connections=None):
"""Creates an SL4A Session.
@@ -67,6 +68,8 @@
server for its first connection.
device_port: The SL4A server port to be used as a hint for which
SL4A server to connect to.
+ forwarded_port: The server port on host machine forwarded by adb
+ from Android device to accept SL4A connection
"""
self._event_dispatcher = None
self._terminate_lock = threading.Lock()
@@ -79,24 +82,24 @@
self.log = logger.create_logger(_log_formatter)
+ self.forwarded_port = forwarded_port
self.server_port = device_port
self.uid = UNKNOWN_UID
self.obtain_server_port = get_server_port_func
self._on_error_callback = on_error_callback
connection_creator = self._rpc_connection_creator(host_port)
- self.rpc_client = rpc_client.RpcClient(
- self.uid,
- self.adb.serial,
- self.diagnose_failure,
- connection_creator,
- max_connections=max_connections)
+ self.rpc_client = rpc_client.RpcClient(self.uid,
+ self.adb.serial,
+ self.diagnose_failure,
+ connection_creator,
+ max_connections=max_connections)
def _rpc_connection_creator(self, host_port):
def create_client(uid):
- return self._create_rpc_connection(
- ports=sl4a_ports.Sl4aPorts(host_port, 0, self.server_port),
- uid=uid)
+ return self._create_rpc_connection(ports=sl4a_ports.Sl4aPorts(
+ host_port, self.forwarded_port, self.server_port),
+ uid=uid)
return create_client
@@ -156,10 +159,14 @@
ports.server_port = self.obtain_server_port(ports.server_port)
self.server_port = ports.server_port
# Forward the device port to the host.
- ports.forwarded_port = self._create_forwarded_port(ports.server_port)
+ ports.forwarded_port = self._create_forwarded_port(
+ ports.server_port, hinted_port=ports.forwarded_port)
client_socket, fd = self._create_client_side_connection(ports)
- client = rpc_connection.RpcConnection(
- self.adb, ports, client_socket, fd, uid=uid)
+ client = rpc_connection.RpcConnection(self.adb,
+ ports,
+ client_socket,
+ fd,
+ uid=uid)
client.open()
if uid == UNKNOWN_UID:
self.uid = client.uid
@@ -195,9 +202,9 @@
except OSError as e:
# If the port is in use, log and ask for any open port.
if e.errno == errno.EADDRINUSE:
- self.log.warning(
- 'Port %s is already in use on the host. '
- 'Generating a random port.' % ports.client_port)
+ self.log.warning('Port %s is already in use on the host. '
+ 'Generating a random port.' %
+ ports.client_port)
ports.client_port = 0
return self._create_client_side_connection(ports)
raise
diff --git a/acts/framework/acts/controllers/spectracom_lib/gsg6.py b/acts/framework/acts/controllers/spectracom_lib/gsg6.py
index a1c30cc..ef381e2 100644
--- a/acts/framework/acts/controllers/spectracom_lib/gsg6.py
+++ b/acts/framework/acts/controllers/spectracom_lib/gsg6.py
@@ -1,18 +1,3 @@
-#!/usr/bin/env python3
-#
-# Copyright 2019 - The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
"""Python module for Spectracom/Orolia GSG-6 GNSS simulator."""
from acts.controllers import abstract_inst
@@ -115,8 +100,8 @@
self._send(':SOUR:POW ' + str(round(power_level, 1)))
- infmsg = 'Set GSG-6 transmit power to "{}"'.format(
- round(power_level, 1))
+ infmsg = 'Set GSG-6 transmit power to "{}"'.format(round(
+ power_level, 1))
self._logger.debug(infmsg)
def get_nmealog(self):
@@ -128,3 +113,107 @@
nmea_data = self._query('SOUR:SCEN:LOG?')
return nmea_data
+
+ def toggle_scenario_power(self,
+ toggle_onoff='ON',
+ sat_id='',
+ sat_system=''):
+ """Toggle ON OFF scenario.
+
+ Args:
+ toggle_onoff: turn on or off the satellites
+ Type, str. Option ON/OFF
+ Default, 'ON'
+ sat_id: satellite identifiers
+ Type, str.
+ Option 'Gxx/Rxx/Exx/Cxx/Jxx/Ixx/Sxxx'
+ where xx is satellite identifiers no.
+ e.g.: G10
+ sat_system: to toggle On/OFF for all Satellites
+ Type, str
+ Option [GPS, GLO, GAL, BDS, QZSS, IRNSS, SBAS]
+ Raises:
+ GSG6Error: raise when toggle is not set.
+ """
+ if not sat_id and not sat_system:
+ self._send(':SOUR:SCEN:POW ' + str(toggle_onoff))
+ infmsg = 'Set GSG-6 Power to "{}"'.format(toggle_onoff)
+ self._logger.debug(infmsg)
+
+ elif sat_id and not sat_system:
+ self._send(':SOUR:SCEN:POW ' + str(sat_id) + ',' +
+ str(toggle_onoff))
+ infmsg = ('Set GSG-6 Power to "{}" for "{}" satellite '
+ 'identifiers').format(toggle_onoff, sat_id)
+ self._logger.debug(infmsg)
+
+ elif not sat_id and sat_system:
+ self._send(':SOUR:SCEN:POW ' + str(sat_system) + ',' +
+ str(toggle_onoff))
+ infmsg = 'Set GSG-6 Power to "{}" for "{}" satellite system'.format(
+ toggle_onoff, sat_system)
+ self._logger.debug(infmsg)
+
+ else:
+ errmsg = ('"toggle power" must have either of these value [ON/OFF],'
+ ' current input is {}').format(str(toggle_onoff))
+ raise GSG6Error(error=errmsg, command='toggle_scenario_power')
+
+ def set_scenario_power(self,
+ power_level,
+ sat_id='',
+ sat_system='',
+ freq_band=''):
+ """Set dynamic power for the running scenario.
+
+ Args:
+ power_level: transmit power level
+ Type, float.
+ Decimal, unit [dBm]
+ sat_id: set power level for specific satellite identifiers
+ Type, str. Option
+ 'Gxx/Rxx/Exx/Cxx/Jxx/Ixx/Sxxx'
+ where xx is satellite identifiers number
+ e.g.: G10
+ sat_system: to set power level for all Satellites
+ Type, str
+ Option [GPS, GLO, GAL, BDS, QZSS, IRNSS, SBAS]
+ freq_band: Frequency band to set the power level
+ Type, str
+ Option [L1, L2, L5, ALL]
+ Default, '', assumed to be L1.
+ Raises:
+ GSG6Error: raise when power level is not in [-160, -65] range.
+ """
+ if freq_band == 'ALL':
+ if not -100 <= power_level <= 100:
+ errmsg = ('"power_level" must be within [-100, 100], for '
+ '"freq_band"="ALL", current input is {}').format(
+ str(power_level))
+ raise GSG6Error(error=errmsg, command='set_scenario_power')
+ else:
+ if not -160 <= power_level <= -65:
+ errmsg = ('"power_level" must be within [-160, -65], for '
+ '"freq_band" != "ALL", current input is {}').format(
+ str(power_level))
+ raise GSG6Error(error=errmsg, command='set_scenario_power')
+
+ if sat_id and not sat_system:
+ self._send(':SOUR:SCEN:POW ' + str(sat_id) + ',' +
+ str(round(power_level, 1)) + ',' + str(freq_band))
+ infmsg = ('Set GSG-6 transmit power to "{}" for "{}" '
+ 'satellite id').format(round(power_level, 1), sat_id)
+ self._logger.debug(infmsg)
+
+ elif not sat_id and sat_system:
+ self._send(':SOUR:SCEN:POW ' + str(sat_system) + ',' +
+ str(round(power_level, 1)) + ',' + str(freq_band))
+ infmsg = ('Set GSG-6 transmit power to "{}" for "{}" '
+ 'satellite system').format(round(power_level, 1),
+ sat_system)
+ self._logger.debug(infmsg)
+
+ else:
+ errmsg = ('sat_id or sat_system must have value, current input of '
+ 'sat_id {} and sat_system {}').format(sat_id, sat_system)
+ raise GSG6Error(error=errmsg, command='set_scenario_power')
diff --git a/acts/framework/acts/controllers/spirent_lib/gss7000.py b/acts/framework/acts/controllers/spirent_lib/gss7000.py
new file mode 100644
index 0000000..961d4e8
--- /dev/null
+++ b/acts/framework/acts/controllers/spirent_lib/gss7000.py
@@ -0,0 +1,490 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Python module for Spirent GSS7000 GNSS simulator.
+@author: Clay Liao (jianhsiungliao@)
+"""
+from time import sleep
+import xml.etree.ElementTree as ET
+from acts.controllers import abstract_inst
+
+
+def get_xml_text(xml_string='', tag=''):
+ """Parse xml from string and return specific tag
+
+ Args:
+ xml_string: xml string,
+ Type, Str.
+ tag: tag in xml,
+ Type, Str.
+
+ Returns:
+ text: Text content in the tag
+ Type, Str.
+ """
+ if xml_string and tag:
+ root = ET.fromstring(xml_string)
+ try:
+ text = str(root.find(tag).text).rstrip().lstrip()
+ except ValueError:
+ text = 'INVALID DATA'
+ else:
+ text = 'INVALID DATA'
+ return text
+
+
+class GSS7000Error(abstract_inst.SocketInstrumentError):
+ """GSS7000 Instrument Error Class."""
+
+
+class AbstractInstGss7000(abstract_inst.SocketInstrument):
+ """Abstract instrument for GSS7000"""
+
+ def _query(self, cmd):
+ """query instrument via Socket.
+
+ Args:
+ cmd: Command to send,
+ Type, Str.
+
+ Returns:
+ resp: Response from Instrument via Socket,
+ Type, Str.
+ """
+ self._send(cmd)
+ self._wait()
+ resp = self._recv()
+ return resp
+
+ def _wait(self, wait_time=1):
+ """wait function
+ Args:
+ wait_time: wait time in sec.
+ Type, int,
+ Default, 1.
+ """
+ sleep(wait_time)
+
+
+class GSS7000Ctrl(AbstractInstGss7000):
+ """GSS7000 control daemon class"""
+
+ def __init__(self, ip_addr, ip_port=7717):
+ """Init method for GSS7000 Control Daemon.
+
+ Args:
+ ip_addr: IP Address.
+ Type, str.
+ ip_port: TCPIP Port.
+ Type, str.
+ """
+ super().__init__(ip_addr, ip_port)
+ self.idn = 'Spirent-GSS7000 Control Daemon'
+
+ def connect(self):
+ """Init and Connect to GSS7000 Control Daemon."""
+ # Connect socket then connect socket again
+ self._close_socket()
+ self._connect_socket()
+ # Stop GSS7000 Control Daeamon Then Start
+ self._query('STOP_ENGINE')
+ self._wait()
+ self._query('START_ENGINE')
+
+ def close(self):
+ """Close GSS7000 control daemon"""
+ self._close_socket()
+ self._logger.debug('Closed connection to GSS7000 control daemon')
+
+
+class GSS7000(AbstractInstGss7000):
+ """GSS7000 Class, inherted from abstract_inst SocketInstrument."""
+
+ def __init__(self, ip_addr, engine_ip_port=15650, ctrl_ip_port=7717):
+ """Init method for GSS7000.
+
+ Args:
+ ip_addr: IP Address.
+ Type, str.
+ engine_ip_port: TCPIP Port for
+ Type, str.
+ ctrl_ip_port: TCPIP Port for Control Daemon
+ """
+ super().__init__(ip_addr, engine_ip_port)
+ self.idn = ''
+ self.connected = False
+ self.capability = []
+ self.gss7000_ctrl_daemon = GSS7000Ctrl(ip_addr, ctrl_ip_port)
+ # Close control daemon and engine sockets at the beginning
+ self.gss7000_ctrl_daemon._close_socket()
+ self._close_socket()
+
+ def connect(self):
+ """Connect GSS7000 engine daemon"""
+ # Connect control daemon socket
+ self._logger.debug('Connect to GSS7000')
+ self.gss7000_ctrl_daemon.connect()
+ # Connect to remote engine socket
+ self._wait()
+ self._connect_socket()
+ self.connected = True
+ self.get_hw_capability()
+
+ def close(self):
+ """Close GSS7000 engine daemon"""
+ # Close GSS7000 control daemon
+ self.gss7000_ctrl_daemon.close()
+ # Close GSS7000 engine daemon
+ self._close_socket()
+ self._logger.debug('Closed connection to GSS7000 engine daemon')
+
+ def _parse_hw_cap(self, xml):
+ """Parse GSS7000 hardware capability xml to list.
+ Args:
+ xml: hardware capability xml,
+ Type, str.
+
+ Returns:
+ capability: Hardware capability dictionary
+ Type, list.
+ """
+ root = ET.fromstring(xml)
+ capability_ls = list()
+ sig_cap_list = root.find('data').find('Signal_capabilities').findall(
+ 'Signal')
+ for signal in sig_cap_list:
+ value = str(signal.text).rstrip().lstrip()
+ capability_ls.extend(value.upper().split(' '))
+ return capability_ls
+
+ def get_hw_capability(self):
+ """Check GSS7000 hardware capability
+
+ Returns:
+ capability: Hardware capability dictionary,
+ Type, list.
+ """
+ if self.connected:
+ capability_xml = self._query('GET_LICENCED_HARDWARE_CAPABILITY')
+ self.capability = self._parse_hw_cap(capability_xml)
+
+ return self.capability
+
+ def get_idn(self):
+ """Get the SimREPLAYplus Version
+
+ Returns:
+ SimREPLAYplus Version
+ """
+ idn_xml = self._query('*IDN?')
+ self.idn = get_xml_text(idn_xml, 'data')
+ return self.idn
+
+ def load_scenario(self, scenario=''):
+ """Load the scenario.
+
+ Args:
+ scenario: path of scenario,
+ Type, str
+ """
+ if scenario == '':
+ errmsg = ('Missing scenario file')
+ raise GSS7000Error(error=errmsg, command='load_scenario')
+ else:
+ self._logger.debug('Stopped the original scenario')
+ self._query('-,EN,1')
+ cmd = 'SC,' + scenario
+ self._logger.debug('Loading scenario')
+ self._query(cmd)
+ self._logger.debug('Scenario is loaded')
+ return True
+ return False
+
+ def start_scenario(self, scenario=''):
+ """Load and Start the running scenario.
+
+ Args:
+ scenario: path of scenario,
+ Type, str
+ """
+ if scenario:
+ if self.load_scenario(scenario):
+ self._query('RU')
+ else:
+ infmsg = 'No scenario is loaded. Stop running scenario'
+ self._logger.debug(infmsg)
+ else:
+ pass
+
+ if scenario:
+ infmsg = 'Started running scenario {}'.format(scenario)
+ else:
+ infmsg = 'Started running current scenario'
+
+ self._logger.debug(infmsg)
+
+ def get_scenario_name(self):
+ """Get current scenario name"""
+ sc_name_xml = self._query('SC_NAME')
+ return get_xml_text(sc_name_xml, 'data')
+
+ def stop_scenario(self):
+ """Stop the running scenario."""
+ self._query('-,EN,1')
+ self._logger.debug('Stopped running scenario')
+
+ def set_power_offset(self, ant=1, power_offset=0):
+ """Set Power Offset of GSS7000 Tx
+ Args:
+ ant: antenna number of GSS7000
+ power_offset: transmit power offset level
+ Type, float.
+ Decimal, unit [dB]
+
+ Raises:
+ GSS7000Error: raise when power offset level is not in [-49, 15] range.
+ """
+ if not -49 <= power_offset <= 15:
+ errmsg = (f'"power_offset" must be within [-49, 15], '
+ f'current input is {power_offset}')
+ raise GSS7000Error(error=errmsg, command='set_power_offset')
+
+ cmd = f'-,POW_LEV,V1_A{ant},{power_offset},GPS,0,0,1,1,1,1,0'
+ self._query(cmd)
+
+ infmsg = f'Set veichel 1 antenna {ant} power offset: {power_offset}'
+ self._logger.debug(infmsg)
+
+ def set_ref_power(self, ref_dBm=-130):
+ """Set Ref Power of GSS7000 Tx
+ Args:
+ ref_dBm: transmit reference power level in dBm for GSS7000
+ Type, float.
+ Decimal, unit [dBm]
+
+ Raises:
+ GSS7000Error: raise when power offset level is not in [-170, -115] range.
+ """
+ if not -170 <= ref_dBm <= -115:
+ errmsg = ('"power_offset" must be within [-170, -115], '
+ 'current input is {}').format(str(ref_dBm))
+ raise GSS7000Error(error=errmsg, command='set_ref_power')
+ cmd = 'REF_DBM,{}'.format(str(round(ref_dBm, 1)))
+ self._query(cmd)
+ infmsg = 'Set reference power level: {}'.format(str(round(ref_dBm, 1)))
+ self._logger.debug(infmsg)
+
+ def get_status(self, return_txt=False):
+ """Get current GSS7000 Status
+ Args:
+ return_txt: booling for determining the return results
+ Type, booling.
+ """
+ status_xml = self._query('NULL')
+ status = get_xml_text(status_xml, 'status')
+ if return_txt:
+ status_dict = {
+ '0': 'No Scenario loaded',
+ '1': 'Not completed loading a scenario',
+ '2': 'Idle, ready to run a scenario',
+ '3': 'Arming the scenario',
+ '4': 'Completed arming; or waiting for a command or'
+ 'trigger signal to start the scenario',
+ '5': 'Scenario running',
+ '6': 'Current scenario is paused.',
+ '7': 'Active scenario has stopped and has not been reset.'
+ 'Waiting for further commands.'
+ }
+ return status_dict.get(status)
+ else:
+ return int(status)
+
+ def set_power(self, power_level=-130):
+ """Set Power Level of GSS7000 Tx
+ Args:
+ power_level: transmit power level
+ Type, float.
+ Decimal, unit [dBm]
+
+ Raises:
+ GSS7000Error: raise when power level is not in [-170, -115] range.
+ """
+ if not -170 <= power_level <= -115:
+ errmsg = (f'"power_level" must be within [-170, -115], '
+ f'current input is {power_level}')
+ raise GSS7000Error(error=errmsg, command='set_power')
+
+ power_offset = power_level + 130
+ self.set_power_offset(1, power_offset)
+ self.set_power_offset(2, power_offset)
+
+ infmsg = 'Set GSS7000 transmit power to "{}"'.format(
+ round(power_level, 1))
+ self._logger.debug(infmsg)
+
+ def power_lev_offset_cal(self, power_level=-130, sat='GPS', band='L1'):
+ """Convert target power level to power offset for GSS7000 power setting
+ Args:
+ power_level: transmit power level
+ Type, float.
+ Decimal, unit [dBm]
+ Default. -130
+ sat_system: to set power level for all Satellites
+ Type, str
+ Option 'GPS/GLO/GAL'
+ Type, str
+ freq_band: Frequency band to set the power level
+ Type, str
+ Option 'L1/L5/B1I/B1C/B2A/E5'
+ Default, '', assumed to be L1.
+ Return:
+ power_offset: The calculated power offset for setting GSS7000 GNSS target power.
+ """
+ gss7000_tx_pwr = {
+ 'GPS_L1': -130,
+ 'GPS_L5': -127.9,
+ 'GLONASS_F1': -131,
+ 'GALILEO_L1': -127,
+ 'GALILEO_E5': -122,
+ 'BEIDOU_B1I': -133,
+ 'BEIDOU_B1C': -130,
+ 'BEIDOU_B2A': -127,
+ 'QZSS_L1': -128.5,
+ 'QZSS_L5': -124.9,
+ 'IRNSS_L5': -130
+ }
+
+ sat_band = f'{sat}_{band}'
+ infmsg = f'Target satellite system and band: {sat_band}'
+ self._logger.debug(infmsg)
+ default_pwr_lev = gss7000_tx_pwr.get(sat_band, -130)
+ power_offset = power_level - default_pwr_lev
+ infmsg = (
+ f'Targer power: {power_level}; Default power: {default_pwr_lev};'
+ f' Power offset: {power_offset}')
+ self._logger.debug(infmsg)
+
+ return power_offset
+
+ def sat_band_convert(self, sat, band):
+ """Satellite system and operation band conversion and check.
+ Args:
+ sat: to set power level for all Satellites
+ Type, str
+ Option 'GPS/GLO/GAL/BDS'
+ Type, str
+ band: Frequency band to set the power level
+ Type, str
+ Option 'L1/L5/B1I/B1C/B2A/F1/E5'
+ Default, '', assumed to be L1.
+ """
+ sat_system_dict = {
+ 'GPS': 'GPS',
+ 'GLO': 'GLONASS',
+ 'GAL': 'GALILEO',
+ 'BDS': 'BEIDOU',
+ 'IRNSS': 'IRNSS',
+ 'ALL': 'GPS'
+ }
+ sat = sat_system_dict.get(sat, 'GPS')
+ if band == '':
+ infmsg = 'No band is set. Set to default band = L1'
+ self._logger.debug(infmsg)
+ band = 'L1'
+ if sat == '':
+ infmsg = 'No satellite system is set. Set to default sat = GPS'
+ self._logger.debug(infmsg)
+ sat = 'GPS'
+ sat_band = f'{sat}_{band}'
+ self._logger.debug(f'Current band: {sat_band}')
+ self._logger.debug(f'Capability: {self.capability}')
+ # Check if satellite standard and band are supported
+ # If not in support list, return GPS_L1 as default
+ if not sat_band in self.capability:
+ errmsg = (
+ f'Satellite system and band ({sat_band}) are not supported.'
+ f'The GSS7000 support list: {self.capability}')
+ raise GSS7000Error(error=errmsg, command='set_scenario_power')
+ else:
+ sat_band_tp = tuple(sat_band.split('_'))
+
+ return sat_band_tp
+
+ def set_scenario_power(self,
+ power_level=-130,
+ sat_id='',
+ sat_system='',
+ freq_band='L1'):
+ """Set dynamic power for the running scenario.
+ Args:
+ power_level: transmit power level
+ Type, float.
+ Decimal, unit [dBm]
+ Default. -130
+ sat_id: set power level for specific satellite identifiers
+ Type, int.
+ sat_system: to set power level for all Satellites
+ Type, str
+ Option 'GPS/GLO/GAL/BDS'
+ Type, str
+ Default, '', assumed to be GPS.
+ freq_band: Frequency band to set the power level
+ Type, str
+ Option 'L1/L5/B1I/B1C/B2A/F1/E5/ALL'
+ Default, '', assumed to be L1.
+ Raises:
+ GSS7000Error: raise when power offset is not in [-49, -15] range.
+ """
+ band_dict = {
+ 'L1': 1,
+ 'L5': 2,
+ 'B2A': 2,
+ 'B1I': 1,
+ 'B1C': 1,
+ 'F1': 1,
+ 'E5': 2,
+ 'ALL': 3
+ }
+
+ # Convert and check satellite system and band
+ sat, band = self.sat_band_convert(sat_system, freq_band)
+ # Get freq band setting
+ band_cmd = band_dict.get(band, 1)
+
+ if not sat_id:
+ sat_id = 0
+ all_tx_type = 1
+ else:
+ all_tx_type = 0
+
+ # Convert absolute power level to absolute power offset.
+ power_offset = self.power_lev_offset_cal(power_level, sat, band)
+
+ if not -49 <= power_offset <= 15:
+ errmsg = (f'"power_offset" must be within [-49, 15], '
+ f'current input is {power_offset}')
+ raise GSS7000Error(error=errmsg, command='set_power_offset')
+
+ if band_cmd == 1:
+ cmd = f'-,POW_LEV,v1_a1,{power_offset},{sat},{sat_id},0,0,0,1,1,{all_tx_type}'
+ self._query(cmd)
+ elif band_cmd == 2:
+ cmd = f'-,POW_LEV,v1_a2,{power_offset},{sat},{sat_id},0,0,0,1,1,{all_tx_type}'
+ self._query(cmd)
+ elif band_cmd == 3:
+ cmd = f'-,POW_LEV,v1_a1,{power_offset},{sat},{sat_id},0,0,0,1,1,{all_tx_type}'
+ self._query(cmd)
+ cmd = f'-,POW_LEV,v1_a2,{power_offset},{sat},{sat_id},0,0,0,1,1,{all_tx_type}'
diff --git a/acts/framework/acts/controllers/utils_lib/commands/shell.py b/acts/framework/acts/controllers/utils_lib/commands/shell.py
index 81a2f13..8073e45 100644
--- a/acts/framework/acts/controllers/utils_lib/commands/shell.py
+++ b/acts/framework/acts/controllers/utils_lib/commands/shell.py
@@ -28,6 +28,7 @@
Note: At the moment this only works with the ssh runner.
"""
+
def __init__(self, runner, working_dir=None):
"""Creates a new shell command invoker.
@@ -103,8 +104,12 @@
"""
try:
result = self.run('ps aux | grep -v grep | grep %s' % identifier)
- except job.Error:
- raise StopIteration
+ except job.Error as e:
+ if e.exit_status == 1:
+ # Grep returns exit status 1 when no lines are selected. This is
+ # an expected return code.
+ return
+ raise e
lines = result.stdout.splitlines()
@@ -115,7 +120,10 @@
# USER PID ...
for line in lines:
pieces = line.split()
- yield int(pieces[1])
+ try:
+ yield int(pieces[1])
+ except StopIteration:
+ return
def search_file(self, search_string, file_name):
"""Searches through a file for a string.
diff --git a/acts/framework/acts/libs/proc/job.py b/acts/framework/acts/libs/proc/job.py
index a8128e1..4907ff6 100644
--- a/acts/framework/acts/libs/proc/job.py
+++ b/acts/framework/acts/libs/proc/job.py
@@ -25,6 +25,7 @@
class Error(Exception):
"""Indicates that a command failed, is fatal to the test unless caught."""
+
def __init__(self, result):
super(Error, self).__init__(result)
self.result = result
@@ -48,6 +49,7 @@
duration: How long the process ran for.
did_timeout: True if the program timed out and was killed.
"""
+
@property
def stdout(self):
"""String representation of standard output."""
@@ -128,8 +130,7 @@
Raises:
job.TimeoutError: When the remote command took to long to execute.
- Error: When the ssh connection failed to be created.
- CommandError: Ssh worked, but the command had an error executing.
+ Error: When the command had an error executing and ignore_status==False.
"""
start_time = time.time()
proc = subprocess.Popen(command,
diff --git a/acts/framework/acts/libs/utils/multithread.py b/acts/framework/acts/libs/utils/multithread.py
new file mode 100644
index 0000000..800b144
--- /dev/null
+++ b/acts/framework/acts/libs/utils/multithread.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import concurrent.futures
+import logging
+
+def task_wrapper(task):
+ """Task wrapper for multithread_func
+
+ Args:
+ task[0]: function to be wrapped.
+ task[1]: function args.
+
+ Returns:
+ Return value of wrapped function call.
+ """
+ func = task[0]
+ params = task[1]
+ 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.
+
+ Args:
+ log: log object.
+ tasks: a list of tasks to be executed in parallel.
+
+ Returns:
+ results for tasks.
+ """
+ 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()
+ if log:
+ log.info("multithread_func %s result: %s",
+ [task[0].__name__ for task in tasks], results)
+ return results
+
+
+def multithread_func(log, tasks):
+ """Multi-thread function wrapper.
+
+ Args:
+ log: log object.
+ tasks: tasks to be executed in parallel.
+
+ Returns:
+ True if all tasks return True.
+ False if any task return False.
+ """
+ results = run_multithread_func(log, tasks)
+ for r in results:
+ if not r:
+ return False
+ return True
+
+
+def multithread_func_and_check_results(log, tasks, expected_results):
+ """Multi-thread function wrapper.
+
+ Args:
+ log: log object.
+ tasks: tasks to be executed in parallel.
+ expected_results: check if the results from tasks match expected_results.
+
+ Returns:
+ True if expected_results are met.
+ False if expected_results are not met.
+ """
+ return_value = True
+ results = run_multithread_func(log, tasks)
+ log.info("multithread_func result: %s, expecting %s", results,
+ expected_results)
+ for task, result, expected_result in zip(tasks, results, expected_results):
+ if result != expected_result:
+ logging.info("Result for task %s is %s, expecting %s", task[0],
+ result, expected_result)
+ return_value = False
+ return return_value
diff --git a/acts/framework/acts/logger.py b/acts/framework/acts/logger.py
index f18190a..eba5620 100755
--- a/acts/framework/acts/logger.py
+++ b/acts/framework/acts/logger.py
@@ -247,7 +247,11 @@
link_path = os.path.join(os.path.dirname(actual_path), "latest")
if os.path.islink(link_path):
os.remove(link_path)
- os.symlink(actual_path, link_path)
+ try:
+ os.symlink(actual_path, link_path)
+ except OSError:
+ logging.warning('Failed to create symlink to latest logs dir.',
+ exc_info=True)
def setup_test_logger(log_path, prefix=None):
diff --git a/acts/framework/acts/utils.py b/acts/framework/acts/utils.py
index c07f044..70becb9 100755
--- a/acts/framework/acts/utils.py
+++ b/acts/framework/acts/utils.py
@@ -46,6 +46,9 @@
# the file names we output fits within the limit.
MAX_FILENAME_LEN = 255
+# All Fuchsia devices use this suffix for link-local mDNS host names.
+FUCHSIA_MDNS_TYPE = '_fuchsia._udp.local.'
+
class ActsUtilsError(Exception):
"""Generic error raised for exceptions in ACTS utils."""
@@ -558,6 +561,7 @@
Raises:
TimeoutError is raised when time out happens.
"""
+
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
@@ -970,6 +974,22 @@
return False
+def zip_directory(zip_name, src_dir):
+ """Compress a directory to a .zip file.
+
+ This implementation is thread-safe.
+
+ Args:
+ zip_name: str, name of the generated archive
+ src_dir: str, path to the source directory
+ """
+ with zipfile.ZipFile(zip_name, 'w', zipfile.ZIP_DEFLATED) as zip:
+ for root, dirs, files in os.walk(src_dir):
+ for file in files:
+ path = os.path.join(root, file)
+ zip.write(path, os.path.relpath(path, src_dir))
+
+
def unzip_maintain_permissions(zip_path, extract_location):
"""Unzip a .zip file while maintaining permissions.
@@ -1286,6 +1306,7 @@
"""Context manager used to suppress all logging output for the specified
logger and level(s).
"""
+
def __init__(self, logger=logging.getLogger(), log_levels=None):
"""Create a SuppressLogOutput context manager
@@ -1318,6 +1339,7 @@
"""Context manager used to block until a specified amount of time has
elapsed.
"""
+
def __init__(self, secs):
"""Initializes a BlockingTimer
@@ -1418,7 +1440,6 @@
ifconfig_output = comm_channel.run('ifconfig %s' % interface).stdout
elif type(comm_channel) is FuchsiaDevice:
all_interfaces_and_addresses = []
- comm_channel.netstack_lib.init()
interfaces = comm_channel.netstack_lib.netstackListInterfaces()
if interfaces.get('error') is not None:
raise ActsUtilsError('Failed with {}'.format(
@@ -1497,14 +1518,6 @@
all_ips_and_interfaces = comm_channel.run(
'(ip -o -4 addr show; ip -o -6 addr show) | '
'awk \'{print $2" "$4}\'').stdout
- #ipv4_addresses = comm_channel.run(
- # 'ip -o -4 addr show| awk \'{print $2": "$4}\'').stdout
- #ipv6_addresses = comm_channel._ssh_session.run(
- # 'ip -o -6 addr show| awk \'{print $2": "$4}\'').stdout
- #if desired_ip_address in ipv4_addresses:
- # ip_addresses_to_search = ipv4_addresses
- #elif desired_ip_address in ipv6_addresses:
- # ip_addresses_to_search = ipv6_addresses
for ip_address_and_interface in all_ips_and_interfaces.split('\n'):
if desired_ip_address in ip_address_and_interface:
return ip_address_and_interface.split()[1][:-1]
@@ -1551,7 +1564,7 @@
if os_type == 'Darwin':
if is_valid_ipv6_address(dest_ip):
# ping6 on MacOS doesn't support timeout
- logging.warn(
+ logging.debug(
'Ignoring timeout, as ping6 on MacOS does not support it.')
timeout_flag = []
else:
@@ -1681,7 +1694,7 @@
def can_ping(comm_channel,
dest_ip,
- count=1,
+ count=3,
interval=1000,
timeout=1000,
size=56,
@@ -1749,48 +1762,104 @@
def get_fuchsia_mdns_ipv6_address(device_mdns_name):
- """Gets the ipv6 link local address from a fuchsia device over mdns
+ """Finds the IPv6 link-local address of a Fuchsia device matching a mDNS
+ name.
Args:
- device_mdns_name: name of fuchsia device, ie gig-clone-sugar-slash
+ device_mdns_name: name of Fuchsia device (e.g. gig-clone-sugar-slash)
Returns:
- string, ipv6 link local address
+ string, IPv6 link-local address
"""
if not device_mdns_name:
return None
- mdns_type = '_fuchsia._udp.local.'
- interface_list = psutil.net_if_addrs()
- for interface in interface_list:
- interface_ipv6_link_local = \
- get_interface_ip_addresses(job, interface)['ipv6_link_local']
- if 'fe80::1' in interface_ipv6_link_local:
- logging.info('Removing IPv6 loopback IP from %s interface list.'
- ' Not modifying actual system IP addresses.' %
- interface)
- # This is needed as the Zeroconf library crashes if you try to
- # instantiate it on a IPv6 loopback IP address.
- interface_ipv6_link_local.remove('fe80::1')
- if interface_ipv6_link_local:
- zeroconf = Zeroconf(ip_version=IPVersion.V6Only,
- interfaces=interface_ipv6_link_local)
- device_records = (zeroconf.get_service_info(
- mdns_type, device_mdns_name + '.' + mdns_type))
- if device_records:
- for device_ip_address in device_records.parsed_addresses():
- device_ip_address = ipaddress.ip_address(device_ip_address)
- if (device_ip_address.version == 6
- and device_ip_address.is_link_local):
- if ping(job,
- dest_ip='%s%%%s' %
- (str(device_ip_address),
- interface))['exit_status'] == 0:
+ interfaces = psutil.net_if_addrs()
+ for interface in interfaces:
+ for addr in interfaces[interface]:
+ address = addr.address.split('%')[0]
+ if addr.family == socket.AF_INET6 and ipaddress.ip_address(
+ address).is_link_local and address != 'fe80::1':
+ logging.info('Sending mDNS query for device "%s" using "%s"' %
+ (device_mdns_name, addr.address))
+ try:
+ zeroconf = Zeroconf(ip_version=IPVersion.V6Only,
+ interfaces=[address])
+ except RuntimeError as e:
+ if 'No adapter found for IP address' in e.args[0]:
+ # Most likely, a device went offline and its control
+ # interface was deleted. This is acceptable since the
+ # device that went offline isn't guaranteed to be the
+ # device we're searching for.
+ logging.warning('No adapter found for "%s"' % address)
+ continue
+ raise
+
+ device_records = zeroconf.get_service_info(
+ FUCHSIA_MDNS_TYPE,
+ device_mdns_name + '.' + FUCHSIA_MDNS_TYPE)
+
+ if device_records:
+ for device_address in device_records.parsed_addresses():
+ device_ip_address = ipaddress.ip_address(
+ device_address)
+ scoped_address = '%s%%%s' % (device_address, interface)
+ if (device_ip_address.version == 6
+ and device_ip_address.is_link_local
+ and can_ping(job, dest_ip=scoped_address)):
+ logging.info('Found device "%s" at "%s"' %
+ (device_mdns_name, scoped_address))
zeroconf.close()
del zeroconf
- return ('%s%%%s' %
- (str(device_ip_address), interface))
- zeroconf.close()
- del zeroconf
- logging.error('Unable to get ip address for %s' % device_mdns_name)
+ return scoped_address
+
+ zeroconf.close()
+ del zeroconf
+
+ logging.error('Unable to find IP address for device "%s"' %
+ device_mdns_name)
return None
+
+
+def get_device(devices, device_type):
+ """Finds a unique device with the specified "device_type" attribute from a
+ list. If none is found, defaults to the first device in the list.
+
+ Example:
+ get_device(android_devices, device_type="DUT")
+ get_device(fuchsia_devices, device_type="DUT")
+ get_device(android_devices + fuchsia_devices, device_type="DUT")
+
+ Args:
+ devices: A list of device controller objects.
+ device_type: (string) Type of device to find, specified by the
+ "device_type" attribute.
+
+ Returns:
+ The matching device controller object, or the first device in the list
+ if not found.
+
+ Raises:
+ ValueError is raised if none or more than one device is
+ matched.
+ """
+ if not devices:
+ raise ValueError('No devices available')
+
+ matches = [
+ d for d in devices
+ if hasattr(d, 'device_type') and d.device_type == device_type
+ ]
+
+ if len(matches) == 0:
+ # No matches for the specified "device_type", use the first device
+ # declared.
+ return devices[0]
+ if len(matches) > 1:
+ # Specifing multiple devices with the same "device_type" is a
+ # configuration error.
+ raise ValueError(
+ 'More than one device matching "device_type" == "{}"'.format(
+ device_type))
+
+ return matches[0]
\ No newline at end of file
diff --git a/acts/framework/setup.py b/acts/framework/setup.py
index 6846b78..98a8fb0 100755
--- a/acts/framework/setup.py
+++ b/acts/framework/setup.py
@@ -31,6 +31,7 @@
'mock==3.0.5',
'pyserial',
'pyyaml>=5.1',
+ 'pynacl==1.4.0',
'protobuf>=3.14.0',
'retry',
'requests',
@@ -44,6 +45,7 @@
# ed25519 ssh keys, which is what Fuchsia uses.
'paramiko-ng',
'dlipower',
+ 'usbinfo',
'zeroconf'
]
@@ -57,9 +59,13 @@
elif sys.version_info < (3, 7):
# Python 3.6 uses scipy up to 1.5 and numpy up to 1.19.x
install_requires.append('scipy<1.6')
- install_requires.append('numpy==1.18.1')
+ install_requires.append('numpy<1.20')
+elif sys.version_info < (3, 8):
+ # Python 3.7 uses latest scipy up to 1.7.x and numpy up to 1.21.x
+ install_requires.append('scipy<1.8')
+ install_requires.append('numpy<1.22')
else:
- # Python 3.7+ is supported by latest scipy and numpy
+ # Python 3.8+ is supported by latest scipy and numpy
install_requires.append('scipy')
install_requires.append('numpy')
diff --git a/acts/framework/tests/acts_android_device_test.py b/acts/framework/tests/acts_android_device_test.py
index c30cacc..374a472 100755
--- a/acts/framework/tests/acts_android_device_test.py
+++ b/acts/framework/tests/acts_android_device_test.py
@@ -684,6 +684,34 @@
ret = ad.push_system_file('asdf', 'jkl')
self.assertFalse(ret)
+ @mock.patch(
+ 'acts.controllers.adb.AdbProxy',
+ return_value=MockAdbProxy(MOCK_SERIAL))
+ @mock.patch(
+ 'acts.controllers.fastboot.FastbootProxy',
+ return_value=MockFastbootProxy(MOCK_SERIAL))
+ def test_get_my_current_focus_window_return_empty_string(self, *_):
+ ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
+ ad.adb.return_value = ''
+
+ ret = ad.get_my_current_focus_window()
+
+ self.assertEqual('', ret)
+
+ @mock.patch(
+ 'acts.controllers.adb.AdbProxy',
+ return_value=MockAdbProxy(MOCK_SERIAL))
+ @mock.patch(
+ 'acts.controllers.fastboot.FastbootProxy',
+ return_value=MockFastbootProxy(MOCK_SERIAL))
+ def test_get_my_current_focus_window_return_current_window(self, *_):
+ ad = android_device.AndroidDevice(serial=MOCK_SERIAL)
+ ad.adb.return_value = 'mCurrentFocus=Window{a247ded u0 NotificationShade}'
+
+ ret = ad.get_my_current_focus_window()
+
+ self.assertEqual('NotificationShade', ret)
+
if __name__ == "__main__":
unittest.main()
diff --git a/acts/framework/tests/acts_import_unit_test.py b/acts/framework/tests/acts_import_unit_test.py
index 9823bfc..925a272 100755
--- a/acts/framework/tests/acts_import_unit_test.py
+++ b/acts/framework/tests/acts_import_unit_test.py
@@ -68,6 +68,8 @@
acts = import_acts()
self.assertIsNotNone(acts)
+ # TODO(b/190659975): Re-enable once permission issue is resolved.
+ @unittest.skip("Permission error: b/190659975")
def test_import_framework_successful(self):
"""Dynamically test all imports from the framework."""
acts = import_acts()
diff --git a/acts/framework/tests/acts_utils_test.py b/acts/framework/tests/acts_utils_test.py
index e1dbe05..601dc45 100755
--- a/acts/framework/tests/acts_utils_test.py
+++ b/acts/framework/tests/acts_utils_test.py
@@ -72,74 +72,68 @@
FUCHSIA_INTERFACES = {
'id':
'1',
- 'result': [{
- 'features':
- 4,
- 'filepath':
- '[none]',
- 'id':
- 1,
- 'ipv4_addresses': [[127, 0, 0, 1]],
- 'ipv6_addresses': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]],
- 'is_administrative_status_enabled':
- True,
- 'is_physical_status_up':
- True,
- 'mac': [0, 0, 0, 0, 0, 0],
- 'mtu':
- 65536,
- 'name':
- 'lo',
- 'topopath':
- 'loopback'
- }, {
- 'features':
- 0,
- 'filepath':
- '/dev/class/ethernet/000',
- 'id':
- 2,
- 'ipv4_addresses': [[100, 127, 110, 79]],
- 'ipv6_addresses':
- [[254, 128, 0, 0, 0, 0, 0, 0, 198, 109, 60, 117, 44, 236, 29, 114],
- [36, 1, 250, 0, 4, 128, 122, 0, 141, 79, 133, 255, 204, 92, 120, 126],
- [36, 1, 250, 0, 4, 128, 122, 0, 4, 89, 185, 147, 252, 191, 20, 25]],
- 'is_administrative_status_enabled':
- True,
- 'is_physical_status_up':
- True,
- 'mac': [0, 224, 76, 5, 76, 229],
- 'mtu':
- 1514,
- 'name':
- 'eno1',
- 'topopath':
- '@/dev/xhci/xhci/usb-bus/001/001/ifc-000/usb-cdc-ecm/ethernet'
- }, {
- 'features':
- 1,
- 'filepath':
- '/dev/class/ethernet/001',
- 'id':
- 3,
- 'ipv4_addresses': [],
- 'ipv6_addresses':
- [[254, 128, 0, 0, 0, 0, 0, 0, 96, 255, 93, 96, 52, 253, 253, 243],
- [254, 128, 0, 0, 0, 0, 0, 0, 70, 7, 11, 255, 254, 118, 126, 192]],
- 'is_administrative_status_enabled':
- False,
- 'is_physical_status_up':
- False,
- 'mac': [68, 7, 11, 118, 126, 192],
- 'mtu':
- 1500,
- 'name':
- 'wlanxc0',
- 'topopath':
- '@/dev/wifi/wlanphy/wlanif-client/wlan-ethernet/ethernet'
- }],
+ 'result': [
+ {
+ 'id': 1,
+ 'name': 'lo',
+ 'ipv4_addresses': [
+ [127, 0, 0, 1],
+ ],
+ 'ipv6_addresses': [
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
+ ],
+ 'online': True,
+ 'mac': [0, 0, 0, 0, 0, 0],
+ },
+ {
+ 'id':
+ 2,
+ 'name':
+ 'eno1',
+ 'ipv4_addresses': [
+ [100, 127, 110, 79],
+ ],
+ 'ipv6_addresses': [
+ [
+ 254, 128, 0, 0, 0, 0, 0, 0, 198, 109, 60, 117, 44, 236, 29,
+ 114
+ ],
+ [
+ 36, 1, 250, 0, 4, 128, 122, 0, 141, 79, 133, 255, 204, 92,
+ 120, 126
+ ],
+ [
+ 36, 1, 250, 0, 4, 128, 122, 0, 4, 89, 185, 147, 252, 191,
+ 20, 25
+ ],
+ ],
+ 'online':
+ True,
+ 'mac': [0, 224, 76, 5, 76, 229],
+ },
+ {
+ 'id':
+ 3,
+ 'name':
+ 'wlanxc0',
+ 'ipv4_addresses': [],
+ 'ipv6_addresses': [
+ [
+ 254, 128, 0, 0, 0, 0, 0, 0, 96, 255, 93, 96, 52, 253, 253,
+ 243
+ ],
+ [
+ 254, 128, 0, 0, 0, 0, 0, 0, 70, 7, 11, 255, 254, 118, 126,
+ 192
+ ],
+ ],
+ 'online':
+ False,
+ 'mac': [68, 7, 11, 118, 126, 192],
+ },
+ ],
'error':
- None
+ None,
}
CORRECT_FULL_IP_LIST = {
@@ -162,7 +156,9 @@
}
FUCHSIA_INIT_SERVER = ('acts.controllers.fuchsia_device.FuchsiaDevice.'
- 'init_server_connection')
+ 'init_sl4f_connection')
+FUCHSIA_INIT_FFX = ('acts.controllers.fuchsia_device.FuchsiaDevice.'
+ 'init_ffx_connection')
FUCHSIA_SET_CONTROL_PATH_CONFIG = ('acts.controllers.fuchsia_device.'
'FuchsiaDevice._set_control_path_config')
FUCHSIA_START_SERVICES = ('acts.controllers.fuchsia_device.FuchsiaDevice.'
@@ -171,12 +167,11 @@
'acts.controllers.'
'fuchsia_lib.netstack.netstack_lib.'
'FuchsiaNetstackLib.netstackListInterfaces')
-FUCHSIA_INIT_NETSTACK = ('acts.controllers.fuchsia_lib.netstack.'
- 'netstack_lib.FuchsiaNetstackLib.init')
class ByPassSetupWizardTests(unittest.TestCase):
"""This test class for unit testing acts.utils.bypass_setup_wizard."""
+
def test_start_standing_subproc(self):
with self.assertRaisesRegex(utils.ActsUtilsError,
'Process .* has terminated'):
@@ -310,6 +305,7 @@
class ConcurrentActionsTest(unittest.TestCase):
"""Tests acts.utils.run_concurrent_actions and related functions."""
+
@staticmethod
def function_returns_passed_in_arg(arg):
return arg
@@ -319,15 +315,15 @@
raise exception_type
def test_run_concurrent_actions_no_raise_returns_proper_return_values(
- self):
+ self):
"""Tests run_concurrent_actions_no_raise returns in the correct order.
Each function passed into run_concurrent_actions_no_raise returns the
values returned from each individual callable in the order passed in.
"""
ret_values = utils.run_concurrent_actions_no_raise(
- lambda: self.function_returns_passed_in_arg('ARG1'),
- lambda: self.function_returns_passed_in_arg('ARG2'),
+ lambda: self.function_returns_passed_in_arg(
+ 'ARG1'), lambda: self.function_returns_passed_in_arg('ARG2'),
lambda: self.function_returns_passed_in_arg('ARG3'))
self.assertEqual(len(ret_values), 3)
@@ -358,8 +354,8 @@
"""
ret_values = utils.run_concurrent_actions(
- lambda: self.function_returns_passed_in_arg('ARG1'),
- lambda: self.function_returns_passed_in_arg('ARG2'),
+ lambda: self.function_returns_passed_in_arg(
+ 'ARG1'), lambda: self.function_returns_passed_in_arg('ARG2'),
lambda: self.function_returns_passed_in_arg('ARG3'))
self.assertEqual(len(ret_values), 3)
@@ -393,6 +389,7 @@
class SuppressLogOutputTest(unittest.TestCase):
"""Tests SuppressLogOutput"""
+
def test_suppress_log_output(self):
"""Tests that the SuppressLogOutput context manager removes handlers
of the specified levels upon entry and re-adds handlers upon exit.
@@ -528,16 +525,16 @@
CORRECT_EMPTY_IP_LIST)
@mock.patch(FUCHSIA_INIT_SERVER)
+ @mock.patch(FUCHSIA_INIT_FFX)
@mock.patch(FUCHSIA_SET_CONTROL_PATH_CONFIG)
@mock.patch(FUCHSIA_START_SERVICES)
@mock.patch(FUCHSIA_NETSTACK_LIST_INTERFACES)
- @mock.patch(FUCHSIA_INIT_NETSTACK)
- def test_fuchsia_get_interface_ip_addresses_full(self, init_mock,
- list_interfaces_mock,
- start_services_mock,
- control_path_mock,
- fuchsia_device_mock):
- init_mock.return_value = None
+ def test_fuchsia_get_interface_ip_addresses_full(
+ self, list_interfaces_mock, start_services_mock, control_path_mock,
+ ffx_mock, fuchsia_device_mock):
+ # Will never actually be created/used.
+ logging.log_path = '/tmp/unit_test_garbage'
+
list_interfaces_mock.return_value = FUCHSIA_INTERFACES
fuchsia_device_mock.return_value = None
self.assertEqual(
@@ -546,16 +543,16 @@
CORRECT_FULL_IP_LIST)
@mock.patch(FUCHSIA_INIT_SERVER)
+ @mock.patch(FUCHSIA_INIT_FFX)
@mock.patch(FUCHSIA_SET_CONTROL_PATH_CONFIG)
@mock.patch(FUCHSIA_START_SERVICES)
@mock.patch(FUCHSIA_NETSTACK_LIST_INTERFACES)
- @mock.patch(FUCHSIA_INIT_NETSTACK)
- def test_fuchsia_get_interface_ip_addresses_empty(self, init_mock,
- list_interfaces_mock,
- start_services_mock,
- control_path_mock,
- fuchsia_device_mock):
- init_mock.return_value = None
+ def test_fuchsia_get_interface_ip_addresses_empty(
+ self, list_interfaces_mock, start_services_mock, control_path_mock,
+ ffx_mock, fuchsia_device_mock):
+ # Will never actually be created/used.
+ logging.log_path = '/tmp/unit_test_garbage'
+
list_interfaces_mock.return_value = FUCHSIA_INTERFACES
fuchsia_device_mock.return_value = None
self.assertEqual(
@@ -564,5 +561,33 @@
CORRECT_EMPTY_IP_LIST)
+class GetDeviceTest(unittest.TestCase):
+ class TestDevice:
+ def __init__(self, id, device_type=None) -> None:
+ self.id = id
+ if device_type:
+ self.device_type = device_type
+
+ def test_get_device_none(self):
+ devices = []
+ self.assertRaises(ValueError, utils.get_device, devices, 'DUT')
+
+ def test_get_device_default_one(self):
+ devices = [self.TestDevice(0)]
+ self.assertEqual(utils.get_device(devices, 'DUT').id, 0)
+
+ def test_get_device_default_many(self):
+ devices = [self.TestDevice(0), self.TestDevice(1)]
+ self.assertEqual(utils.get_device(devices, 'DUT').id, 0)
+
+ def test_get_device_specified_one(self):
+ devices = [self.TestDevice(0), self.TestDevice(1, 'DUT')]
+ self.assertEqual(utils.get_device(devices, 'DUT').id, 1)
+
+ def test_get_device_specified_many(self):
+ devices = [self.TestDevice(0, 'DUT'), self.TestDevice(1, 'DUT')]
+ self.assertRaises(ValueError, utils.get_device, devices, 'DUT')
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/acts/framework/tests/controllers/ap_lib/dhcp_config_test.py b/acts/framework/tests/controllers/ap_lib/dhcp_config_test.py
new file mode 100644
index 0000000..754655f
--- /dev/null
+++ b/acts/framework/tests/controllers/ap_lib/dhcp_config_test.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import ipaddress
+import unittest
+from unittest.mock import patch
+
+from acts.controllers.ap_lib.dhcp_config import DhcpConfig, Subnet, StaticMapping
+
+
+class DhcpConfigTest(unittest.TestCase):
+ def setUp(self):
+ super().setUp()
+ # These config files may have long diffs, modify this setting to
+ # ensure they're printed.
+ self.maxDiff = None
+
+ def test_basic_dhcp_config(self):
+ dhcp_conf = DhcpConfig()
+
+ expected_config = ('default-lease-time 600;\n' 'max-lease-time 7200;')
+
+ self.assertEqual(expected_config, dhcp_conf.render_config_file())
+
+ def test_dhcp_config_with_lease_times(self):
+ default_lease_time = 350
+ max_lease_time = 5000
+ dhcp_conf = DhcpConfig(default_lease_time=default_lease_time,
+ max_lease_time=max_lease_time)
+
+ expected_config = (f'default-lease-time {default_lease_time};\n'
+ f'max-lease-time {max_lease_time};')
+
+ self.assertEqual(expected_config, dhcp_conf.render_config_file())
+
+ def test_dhcp_config_with_subnets(self):
+ default_lease_time = 150
+ max_lease_time = 3000
+ subnets = [
+ # addresses from 10.10.1.0 - 10.10.1.255
+ Subnet(ipaddress.ip_network('10.10.1.0/24')),
+ # 4 addresses from 10.10.3.0 - 10.10.3.3
+ Subnet(ipaddress.ip_network('10.10.3.0/30')),
+ # 6 addresses from 10.10.5.20 - 10.10.5.25
+ Subnet(ipaddress.ip_network('10.10.5.0/24'),
+ start=ipaddress.ip_address('10.10.5.20'),
+ end=ipaddress.ip_address('10.10.5.25'),
+ router=ipaddress.ip_address('10.10.5.255'),
+ lease_time=60)
+ ]
+ dhcp_conf = DhcpConfig(subnets=subnets,
+ default_lease_time=default_lease_time,
+ max_lease_time=max_lease_time)
+
+ # Unless an explicit start/end address is provided, the second
+ # address in the range is used for "start", and the second to
+ # last address is used for "end".
+ expected_config = (f'default-lease-time {default_lease_time};\n'
+ f'max-lease-time {max_lease_time};\n'
+ 'subnet 10.10.1.0 netmask 255.255.255.0 {\n'
+ '\tpool {\n'
+ '\t\toption subnet-mask 255.255.255.0;\n'
+ '\t\toption routers 10.10.1.1;\n'
+ '\t\trange 10.10.1.2 10.10.1.254;\n'
+ '\t\toption domain-name-servers 8.8.8.8, 4.4.4.4;\n'
+ '\t}\n'
+ '}\n'
+ 'subnet 10.10.3.0 netmask 255.255.255.252 {\n'
+ '\tpool {\n'
+ '\t\toption subnet-mask 255.255.255.252;\n'
+ '\t\toption routers 10.10.3.1;\n'
+ '\t\trange 10.10.3.2 10.10.3.2;\n'
+ '\t\toption domain-name-servers 8.8.8.8, 4.4.4.4;\n'
+ '\t}\n'
+ '}\n'
+ 'subnet 10.10.5.0 netmask 255.255.255.0 {\n'
+ '\tpool {\n'
+ '\t\toption subnet-mask 255.255.255.0;\n'
+ '\t\toption routers 10.10.5.255;\n'
+ '\t\trange 10.10.5.20 10.10.5.25;\n'
+ '\t\tdefault-lease-time 60;\n'
+ '\t\tmax-lease-time 60;\n'
+ '\t\toption domain-name-servers 8.8.8.8, 4.4.4.4;\n'
+ '\t}\n'
+ '}')
+
+ self.assertEqual(expected_config, dhcp_conf.render_config_file())
+
+ def test_additional_subnet_parameters_and_options(self):
+ default_lease_time = 150
+ max_lease_time = 3000
+ subnets = [
+ Subnet(ipaddress.ip_network('10.10.1.0/24'),
+ additional_parameters={
+ 'allow': 'unknown-clients',
+ 'foo': 'bar'
+ },
+ additional_options={'my-option': 'some-value'}),
+ ]
+ dhcp_conf = DhcpConfig(subnets=subnets,
+ default_lease_time=default_lease_time,
+ max_lease_time=max_lease_time)
+
+ # Unless an explicit start/end address is provided, the second
+ # address in the range is used for "start", and the second to
+ # last address is used for "end".
+ expected_config = (f'default-lease-time {default_lease_time};\n'
+ f'max-lease-time {max_lease_time};\n'
+ 'subnet 10.10.1.0 netmask 255.255.255.0 {\n'
+ '\tpool {\n'
+ '\t\toption subnet-mask 255.255.255.0;\n'
+ '\t\toption routers 10.10.1.1;\n'
+ '\t\trange 10.10.1.2 10.10.1.254;\n'
+ '\t\tallow unknown-clients;\n'
+ '\t\tfoo bar;\n'
+ '\t\toption my-option some-value;\n'
+ '\t\toption domain-name-servers 8.8.8.8, 4.4.4.4;\n'
+ '\t}\n'
+ '}')
+
+ self.assertEqual(expected_config, dhcp_conf.render_config_file())
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/acts/framework/tests/controllers/ap_lib/radvd_test.py b/acts/framework/tests/controllers/ap_lib/radvd_test.py
index 452bd65..4f23b20 100644
--- a/acts/framework/tests/controllers/ap_lib/radvd_test.py
+++ b/acts/framework/tests/controllers/ap_lib/radvd_test.py
@@ -224,3 +224,7 @@
with open(radvd_config, 'r') as radvd_config_fileId:
config_data = radvd_config_fileId.read()
self.assertTrue(CORRECT_COMPLEX_RADVD_CONFIG == config_data)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/acts/framework/tests/controllers/bits_lib/bits_client_test.py b/acts/framework/tests/controllers/bits_lib/bits_client_test.py
index c4261d6..dda819d 100644
--- a/acts/framework/tests/controllers/bits_lib/bits_client_test.py
+++ b/acts/framework/tests/controllers/bits_lib/bits_client_test.py
@@ -17,6 +17,7 @@
from datetime import datetime
import unittest
+from acts.libs.proc import job
from acts.controllers.bits_lib import bits_client
from acts.controllers.bits_lib import bits_service_config
import mock
@@ -33,6 +34,18 @@
NON_MONSOONED_CONFIG = bits_service_config.BitsServiceConfig(
CONTROLLER_CONFIG_WITHOUT_MONSOON)
+KIBBLES_CONFIG = bits_service_config.BitsServiceConfig(
+ {
+ 'Kibbles': [{
+ 'board': 'board',
+ 'connector': 'connector',
+ 'serial': 'serial',
+ }],
+ },
+ kibble_bin='bin',
+ kibble_board_file='file.board',
+ virtual_metrics_file='file.vm')
+
class BitsClientTest(unittest.TestCase):
@@ -40,9 +53,25 @@
super().setUp()
self.mock_service = mock.Mock()
self.mock_service.port = '42'
- self.mock_active_collection = mock.Mock()
- self.mock_active_collection.name = 'my_active_collection'
- self.mock_active_collection.markers_buffer = []
+
+ @mock.patch('acts.libs.proc.job.run')
+ def test_execute_generic_command(self, mock_run):
+ mock_service = mock.Mock()
+ mock_service.port = '1337'
+ client = bits_client.BitsClient('bits.par', mock_service,
+ service_config=KIBBLES_CONFIG)
+
+ client.run_cmd('-i', '-am', '-not', '-a', '-teapot', timeout=12345)
+
+ expected_final_command = ['bits.par',
+ '--port',
+ '1337',
+ '-i',
+ '-am',
+ '-not',
+ '-a',
+ '-teapot']
+ mock_run.assert_called_with(expected_final_command, timeout=12345)
@mock.patch('acts.libs.proc.job.run')
def test_start_collection__without_monsoon__does_not_disconnect_monsoon(
@@ -51,7 +80,7 @@
client = bits_client.BitsClient('bits.par', self.mock_service,
service_config=NON_MONSOONED_CONFIG)
- client.start_collection()
+ client.start_collection('collection')
mock_run.assert_called()
args_list = mock_run.call_args_list
@@ -61,55 +90,57 @@
self.assertEqual(len(non_expected_call), 0,
'did not expect call with usb_disconnect')
- @mock.patch('acts.context.get_current_context')
@mock.patch('acts.libs.proc.job.run')
- def test_stop_collection__usb_not_automanaged__does_not_connect_monsoon(
- self,
- mock_run,
- mock_context):
- output_path = mock.MagicMock(return_value='out')
- mock_context.side_effect = lambda: output_path
+ def test_start_collection__frecuency_arg_gets_populated(self, mock_run):
client = bits_client.BitsClient('bits.par', self.mock_service,
service_config=MONSOONED_CONFIG)
- client._active_collection = self.mock_active_collection
- client.stop_collection()
+ client.start_collection('collection', default_sampling_rate=12345)
+
+ mock_run.assert_called()
+ args_list = mock_run.call_args_list
+ expected_calls = list(
+ filter(lambda call: '--time' in call.args[0], args_list))
+ self.assertEqual(len(expected_calls), 1, 'expected 1 calls with --time')
+ self.assertIn('--default_sampling_rate', expected_calls[0][0][0])
+ self.assertIn('12345', expected_calls[0][0][0])
+
+ @mock.patch('acts.libs.proc.job.run')
+ def test_start_collection__sampling_rate_defaults_to_1000(self, mock_run):
+ client = bits_client.BitsClient('bits.par', self.mock_service,
+ service_config=MONSOONED_CONFIG)
+
+ client.start_collection('collection')
+
+ mock_run.assert_called()
+ args_list = mock_run.call_args_list
+ expected_calls = list(
+ filter(lambda call: '--time' in call.args[0], args_list))
+ self.assertEqual(len(expected_calls), 1, 'expected 1 calls with --time')
+ self.assertIn('--default_sampling_rate', expected_calls[0][0][0])
+ self.assertIn('1000', expected_calls[0][0][0])
+
+ @mock.patch('acts.libs.proc.job.run')
+ def test_stop_collection__usb_not_automanaged__does_not_connect_monsoon(
+ self, mock_run):
+ client = bits_client.BitsClient('bits.par', self.mock_service,
+ service_config=MONSOONED_CONFIG)
+
+ client.stop_collection('collection')
mock_run.assert_called()
args_list = mock_run.call_args_list
non_expected_call = list(
filter(lambda call: 'usb_connect' in call.args[0], args_list))
- self.assertEquals(len(non_expected_call), 0,
- 'did not expect call with usb_connect')
+ self.assertEqual(len(non_expected_call), 0,
+ 'did not expect call with usb_connect')
- @mock.patch('acts.context.get_current_context')
@mock.patch('acts.libs.proc.job.run')
- def test_stop_collection__triggers_export(self, mock_run, mock_context):
- output_path = mock.MagicMock(return_value='out')
- mock_context.side_effect = lambda: output_path
+ def test_export_ignores_dataseries_gaps(self, mock_run):
client = bits_client.BitsClient('bits.par', self.mock_service,
service_config=MONSOONED_CONFIG)
- client._active_collection = self.mock_active_collection
- client.stop_collection()
-
- mock_run.assert_called()
- args_list = mock_run.call_args_list
- expected_call = list(
- filter(lambda call: '--export' in call.args[0], args_list))
- self.assertEqual(len(expected_call), 1,
- 'expected a call with --export')
-
- @mock.patch('acts.context.get_current_context')
- @mock.patch('acts.libs.proc.job.run')
- def test__export_ignores_dataseries_gaps(self, mock_run, mock_context):
- output_path = mock.MagicMock(return_value='out')
- mock_context.side_effect = lambda: output_path
- client = bits_client.BitsClient('bits.par', self.mock_service,
- service_config=MONSOONED_CONFIG)
- client._active_collection = self.mock_active_collection
-
- client._export()
+ client.export('collection', '/path/a.7z.bits')
mock_run.assert_called()
args_list = mock_run.call_args_list
@@ -121,92 +152,107 @@
'expected a call with --ignore_gaps and --export')
self.assertIn('--ignore_gaps', expected_call[0].args[0])
- @mock.patch('acts.libs.proc.job.run')
- def test_add_marker(self, _):
+ def test_export_path_must_end_in_bits_file_extension(self):
client = bits_client.BitsClient('bits.par', self.mock_service,
service_config=MONSOONED_CONFIG)
- client._active_collection = self.mock_active_collection
- client.add_marker(7133, 'my marker')
+ self.assertRaisesRegex(
+ bits_client.BitsClientError,
+ r'collections can only be exported to files ending in .7z.bits',
+ client.export, 'collection', '/path/')
- client._active_collection.add_marker.assert_called_with(7133,
- 'my marker')
-
- @mock.patch('acts.context.get_current_context')
@mock.patch('acts.libs.proc.job.run')
- def test_stop_collection__flushes_buffered_markers(self, mock_run,
- mock_context):
- output_path = mock.MagicMock(return_value='out')
- mock_context.side_effect = lambda: output_path
+ def test_export_as_csv(self, mock_run):
client = bits_client.BitsClient('bits.par', self.mock_service,
service_config=MONSOONED_CONFIG)
- self.mock_active_collection.markers_buffer.append((3, 'tres'))
- self.mock_active_collection.markers_buffer.append((1, 'uno'))
- self.mock_active_collection.markers_buffer.append((2, 'dos'))
- client._active_collection = self.mock_active_collection
+ output_file = '/path/to/csv'
+ collection = 'collection'
- client.stop_collection()
+ client.export_as_csv([':mW', ':mV'], collection, output_file)
+
+ mock_run.assert_called()
+ cmd = mock_run.call_args_list[0].args[0]
+ self.assertIn(collection, cmd)
+ self.assertIn(output_file, cmd)
+ self.assertIn(':mW,:mV', cmd)
+ self.assertNotIn('--vm_file', cmd)
+ self.assertNotIn('default', cmd)
+
+ @mock.patch('acts.libs.proc.job.run')
+ def test_export_as_csv_with_virtual_metrics_file(self, mock_run):
+ output_file = '/path/to/csv'
+ collection = 'collection'
+ client = bits_client.BitsClient('bits.par', self.mock_service,
+ service_config=KIBBLES_CONFIG)
+
+ client.export_as_csv([':mW', ':mV'], collection, output_file)
+
+ mock_run.assert_called()
+ cmd = mock_run.call_args_list[0].args[0]
+ self.assertIn(collection, cmd)
+ self.assertIn(':mW,:mV', cmd)
+ self.assertIn('--vm_file', cmd)
+ self.assertIn('default', cmd)
+
+ @mock.patch('acts.libs.proc.job.run')
+ def test_add_markers(self, mock_run):
+ client = bits_client.BitsClient('bits.par', self.mock_service,
+ service_config=MONSOONED_CONFIG)
+
+ client.add_markers('collection', [(1, 'ein'),
+ (2, 'zwei'),
+ (3, 'drei')])
mock_run.assert_called()
args_list = mock_run.call_args_list
expected_calls = list(
filter(lambda call: '--log' in call.args[0], args_list))
- self.assertEqual(len(expected_calls), 3,
- 'expected 3 calls with --log')
+ self.assertEqual(len(expected_calls), 3, 'expected 3 calls with --log')
self.assertIn('--log_ts', expected_calls[0][0][0])
self.assertIn('1', expected_calls[0][0][0])
- self.assertIn('uno', expected_calls[0][0][0])
+ self.assertIn('ein', expected_calls[0][0][0])
+
self.assertIn('--log_ts', expected_calls[1][0][0])
self.assertIn('2', expected_calls[1][0][0])
- self.assertIn('dos', expected_calls[1][0][0])
+ self.assertIn('zwei', expected_calls[1][0][0])
+
self.assertIn('--log_ts', expected_calls[2][0][0])
self.assertIn('3', expected_calls[2][0][0])
- self.assertIn('tres', expected_calls[2][0][0])
- self.mock_active_collection.clear_markers_buffer.assert_called()
+ self.assertIn('drei', expected_calls[2][0][0])
- @mock.patch('acts.context.get_current_context')
@mock.patch('acts.libs.proc.job.run')
- def test_stop_collection__flushes_buffered_datetime_markers(self,
- mock_run,
- mock_context):
- output_path = mock.MagicMock(return_value='out')
- mock_context.side_effect = lambda: output_path
+ def test_add_markers_with_datetimes(self, mock_run):
client = bits_client.BitsClient('bits.par', self.mock_service,
service_config=MONSOONED_CONFIG)
- self.mock_active_collection.markers_buffer.append(
- (datetime.utcfromtimestamp(3), 'tres'))
- self.mock_active_collection.markers_buffer.append(
- (datetime.utcfromtimestamp(1), 'uno'))
- self.mock_active_collection.markers_buffer.append(
- (datetime.utcfromtimestamp(2), 'dos'))
- client._active_collection = self.mock_active_collection
- client.stop_collection()
+ client.add_markers('collection',
+ [(datetime.utcfromtimestamp(1), 'ein'),
+ (2e9, 'zwei'),
+ (datetime.utcfromtimestamp(3), 'drei')])
mock_run.assert_called()
args_list = mock_run.call_args_list
expected_calls = list(
filter(lambda call: '--log' in call.args[0], args_list))
- self.assertEqual(len(expected_calls), 3,
- 'expected 3 calls with --log')
+ self.assertEqual(len(expected_calls), 3, 'expected 3 calls with --log')
self.assertIn('--log_ts', expected_calls[0][0][0])
self.assertIn(str(int(1e9)), expected_calls[0][0][0])
- self.assertIn('uno', expected_calls[0][0][0])
+ self.assertIn('ein', expected_calls[0][0][0])
+
self.assertIn('--log_ts', expected_calls[1][0][0])
self.assertIn(str(int(2e9)), expected_calls[1][0][0])
- self.assertIn('dos', expected_calls[1][0][0])
+ self.assertIn('zwei', expected_calls[1][0][0])
+
self.assertIn('--log_ts', expected_calls[2][0][0])
self.assertIn(str(int(3e9)), expected_calls[2][0][0])
- self.assertIn('tres', expected_calls[2][0][0])
- self.mock_active_collection.clear_markers_buffer.assert_called()
+ self.assertIn('drei', expected_calls[2][0][0])
@mock.patch('acts.libs.proc.job.run')
def test_get_metrics(self, mock_run):
client = bits_client.BitsClient('bits.par', self.mock_service,
service_config=MONSOONED_CONFIG)
- client._active_collection = self.mock_active_collection
- client.get_metrics(8888, 9999)
+ client.get_metrics('collection', 8888, 9999)
mock_run.assert_called()
args_list = mock_run.call_args_list
@@ -224,9 +270,9 @@
def test_get_metrics_with_datetime_markers(self, mock_run):
client = bits_client.BitsClient('bits.par', self.mock_service,
service_config=MONSOONED_CONFIG)
- client._active_collection = self.mock_active_collection
- client.get_metrics(datetime.utcfromtimestamp(1),
+ client.get_metrics('collection',
+ datetime.utcfromtimestamp(1),
datetime.utcfromtimestamp(2))
mock_run.assert_called()
@@ -247,7 +293,6 @@
service_config.has_virtual_metrics_file = True
client = bits_client.BitsClient('bits.par', self.mock_service,
service_config=service_config)
- client._active_collection = self.mock_active_collection
client.get_metrics(8888, 9999)
@@ -261,6 +306,21 @@
self.assertIn('--vm_file', expected_call[0][0][0])
self.assertIn('default', expected_call[0][0][0])
+ @mock.patch('acts.libs.proc.job.run',
+ return_value=job.Result(stdout=bytes('device', 'utf-8')))
+ def test_list_devices(self, mock_run):
+ service_config = mock.Mock()
+ client = bits_client.BitsClient('bits.par', self.mock_service,
+ service_config=service_config)
+
+ result = client.list_devices()
+
+ mock_run.assert_called()
+ cmd = mock_run.call_args_list[0].args[0]
+ self.assertIn('--list', cmd)
+ self.assertIn('devices', cmd)
+ self.assertEqual(result, 'device')
+
if __name__ == '__main__':
unittest.main()
diff --git a/acts/framework/tests/controllers/bits_test.py b/acts/framework/tests/controllers/bits_test.py
index e437bea..a7ea45c 100644
--- a/acts/framework/tests/controllers/bits_test.py
+++ b/acts/framework/tests/controllers/bits_test.py
@@ -3,6 +3,7 @@
# Copyright 2020 - 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
#
diff --git a/acts/framework/tests/controllers/iperf_server_test.py b/acts/framework/tests/controllers/iperf_server_test.py
index b5d91a5..00f7da3 100644
--- a/acts/framework/tests/controllers/iperf_server_test.py
+++ b/acts/framework/tests/controllers/iperf_server_test.py
@@ -35,20 +35,15 @@
class IPerfServerModuleTest(unittest.TestCase):
"""Tests the acts.controllers.iperf_server module."""
-
def test_create_creates_local_iperf_server_with_int(self):
self.assertIsInstance(
- iperf_server.create([12345])[0],
- IPerfServer,
- 'create() failed to create IPerfServer for integer input.'
- )
+ iperf_server.create([12345])[0], IPerfServer,
+ 'create() failed to create IPerfServer for integer input.')
def test_create_creates_local_iperf_server_with_str(self):
self.assertIsInstance(
- iperf_server.create(['12345'])[0],
- IPerfServer,
- 'create() failed to create IPerfServer for integer input.'
- )
+ iperf_server.create(['12345'])[0], IPerfServer,
+ 'create() failed to create IPerfServer for integer input.')
def test_create_cannot_create_local_iperf_server_with_bad_str(self):
with self.assertRaises(ValueError):
@@ -57,39 +52,47 @@
@mock.patch('acts.controllers.iperf_server.utils')
def test_create_creates_server_over_ssh_with_ssh_config_and_port(self, _):
self.assertIsInstance(
- iperf_server.create([{'ssh_config': {'user': '', 'host': ''},
- 'port': ''}])[0],
- IPerfServerOverSsh,
- 'create() failed to create IPerfServerOverSsh for a valid config.'
- )
+ iperf_server.create([{
+ 'ssh_config': {
+ 'user': '',
+ 'host': ''
+ },
+ 'port': ''
+ }])[0], IPerfServerOverSsh,
+ 'create() failed to create IPerfServerOverSsh for a valid config.')
def test_create_creates_server_over_adb_with_proper_config(self):
self.assertIsInstance(
- iperf_server.create([{'AndroidDevice': '53R147', 'port': 0}])[0],
- IPerfServerOverAdb,
- 'create() failed to create IPerfServerOverAdb for a valid config.'
- )
+ iperf_server.create([{
+ 'AndroidDevice': '53R147',
+ 'port': 0
+ }])[0], IPerfServerOverAdb,
+ 'create() failed to create IPerfServerOverAdb for a valid config.')
def test_create_raises_value_error_on_bad_config_dict(self):
with self.assertRaises(ValueError):
- iperf_server.create([{'AndroidDevice': '53R147', 'ssh_config': {}}])
+ iperf_server.create([{
+ 'AndroidDevice': '53R147',
+ 'ssh_config': {}
+ }])
def test_get_port_from_ss_output_returns_correct_port_ipv4(self):
ss_output = ('tcp LISTEN 0 5 127.0.0.1:<PORT> *:*'
' users:(("cmd",pid=<PID>,fd=3))')
self.assertEqual(
- iperf_server._get_port_from_ss_output(ss_output, '<PID>'), '<PORT>')
+ iperf_server._get_port_from_ss_output(ss_output, '<PID>'),
+ '<PORT>')
def test_get_port_from_ss_output_returns_correct_port_ipv6(self):
ss_output = ('tcp LISTEN 0 5 ff:ff:ff:ff:ff:ff:<PORT> *:*'
' users:(("cmd",pid=<PID>,fd=3))')
self.assertEqual(
- iperf_server._get_port_from_ss_output(ss_output, '<PID>'), '<PORT>')
+ iperf_server._get_port_from_ss_output(ss_output, '<PID>'),
+ '<PORT>')
class IPerfServerBaseTest(unittest.TestCase):
"""Tests acts.controllers.iperf_server.IPerfServerBase."""
-
@mock.patch('os.makedirs')
def test_get_full_file_path_creates_parent_directory(self, mock_makedirs):
# Will never actually be created/used.
@@ -99,15 +102,11 @@
full_file_path = server._get_full_file_path()
- self.assertTrue(
- mock_makedirs.called,
- 'Did not attempt to create a directory.'
- )
+ self.assertTrue(mock_makedirs.called,
+ 'Did not attempt to create a directory.')
self.assertEqual(
- os.path.dirname(full_file_path),
- mock_makedirs.call_args[ARGS][0],
- 'The parent directory of the full file path was not created.'
- )
+ os.path.dirname(full_file_path), mock_makedirs.call_args[ARGS][0],
+ 'The parent directory of the full file path was not created.')
class IPerfServerTest(unittest.TestCase):
@@ -152,10 +151,8 @@
server.start()
self.assertEqual(
- server._current_log_file,
- MOCK_LOGFILE_PATH,
- 'The _current_log_file was not received from _get_full_file_path.'
- )
+ server._current_log_file, MOCK_LOGFILE_PATH,
+ 'The _current_log_file was not received from _get_full_file_path.')
@mock.patch('builtins.open')
@mock.patch('acts.controllers.iperf_server.subprocess')
@@ -167,16 +164,14 @@
log_file = server.stop()
- self.assertEqual(
- log_file,
- MOCK_LOGFILE_PATH,
- 'The _current_log_file was not returned by stop().'
- )
+ self.assertEqual(log_file, MOCK_LOGFILE_PATH,
+ 'The _current_log_file was not returned by stop().')
@mock.patch('builtins.open')
@mock.patch('acts.controllers.iperf_server.subprocess')
@mock.patch('acts.controllers.iperf_server.job')
- def test_start_does_not_run_two_concurrent_processes(self, start_proc, _, __):
+ def test_start_does_not_run_two_concurrent_processes(
+ self, start_proc, _, __):
server = IPerfServer('port')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_process = mock.Mock()
@@ -185,8 +180,7 @@
self.assertFalse(
start_proc.called,
- 'start() should not begin a second process if another is running.'
- )
+ 'start() should not begin a second process if another is running.')
@mock.patch('acts.utils.stop_standing_subprocess')
def test_stop_exits_early_if_no_process_has_started(self, stop_proc):
@@ -198,8 +192,7 @@
self.assertFalse(
stop_proc.called,
- 'stop() should not kill a process if no process is running.'
- )
+ 'stop() should not kill a process if no process is running.')
class IPerfServerOverSshTest(unittest.TestCase):
@@ -212,6 +205,7 @@
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
+ server._cleanup_iperf_port = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server.start()
@@ -224,6 +218,7 @@
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
+ server._cleanup_iperf_port = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server.start()
@@ -236,21 +231,20 @@
def test_stop_returns_expected_log_file(self, _, __):
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
+ server._cleanup_iperf_port = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_pid = mock.Mock()
log_file = server.stop()
- self.assertEqual(
- log_file,
- MOCK_LOGFILE_PATH,
- 'The expected log file was not returned by stop().'
- )
+ self.assertEqual(log_file, MOCK_LOGFILE_PATH,
+ 'The expected log file was not returned by stop().')
@mock.patch('acts.controllers.iperf_server.connection')
def test_start_does_not_run_two_concurrent_processes(self, _):
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
+ server._cleanup_iperf_port = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_pid = mock.Mock()
@@ -258,14 +252,14 @@
self.assertFalse(
server._ssh_session.run_async.called,
- 'start() should not begin a second process if another is running.'
- )
+ 'start() should not begin a second process if another is running.')
@mock.patch('acts.utils.stop_standing_subprocess')
@mock.patch('acts.controllers.iperf_server.connection')
def test_stop_exits_early_if_no_process_has_started(self, _, __):
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
+ server._cleanup_iperf_port = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_pid = None
@@ -273,8 +267,7 @@
self.assertFalse(
server._ssh_session.run_async.called,
- 'stop() should not kill a process if no process is running.'
- )
+ 'stop() should not kill a process if no process is running.')
class IPerfServerOverAdbTest(unittest.TestCase):
@@ -320,11 +313,8 @@
log_file = server.stop()
- self.assertEqual(
- log_file,
- MOCK_LOGFILE_PATH,
- 'The expected log file was not returned by stop().'
- )
+ self.assertEqual(log_file, MOCK_LOGFILE_PATH,
+ 'The expected log file was not returned by stop().')
@mock.patch(ANDROID_DEVICE_PROP)
def test_start_does_not_run_two_concurrent_processes(self, android_device):
@@ -336,14 +326,13 @@
self.assertFalse(
android_device.adb.shell_nb.called,
- 'start() should not begin a second process if another is running.'
- )
+ 'start() should not begin a second process if another is running.')
@mock.patch('acts.libs.proc.job.run')
@mock.patch('builtins.open')
@mock.patch(ANDROID_DEVICE_PROP)
- def test_stop_exits_early_if_no_process_has_started(self, android_device, _,
- __):
+ def test_stop_exits_early_if_no_process_has_started(
+ self, android_device, _, __):
server = IPerfServerOverAdb('53R147', 'PORT')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_pid = None
@@ -352,8 +341,7 @@
self.assertFalse(
android_device.adb.shell_nb.called,
- 'stop() should not kill a process if no process is running.'
- )
+ 'stop() should not kill a process if no process is running.')
if __name__ == '__main__':
diff --git a/acts/framework/tests/controllers/pdu_lib/synaccess/np02b_test.py b/acts/framework/tests/controllers/pdu_lib/synaccess/np02b_test.py
index b5e7bda..c0af8c8 100644
--- a/acts/framework/tests/controllers/pdu_lib/synaccess/np02b_test.py
+++ b/acts/framework/tests/controllers/pdu_lib/synaccess/np02b_test.py
@@ -43,6 +43,7 @@
class _TNHelperNP02BTest(unittest.TestCase):
"""Unit tests for _TNHelperNP02B."""
+
@patch('acts.controllers.pdu_lib.synaccess.np02b.time.sleep')
@patch('acts.controllers.pdu_lib.synaccess.np02b.telnetlib')
def test_cmd_is_properly_written(self, telnetlib_mock, sleep_mock):
@@ -92,6 +93,7 @@
class NP02BPduDeviceTest(unittest.TestCase):
"""Unit tests for NP02B PduDevice implementation."""
+
@patch('acts.controllers.pdu_lib.synaccess.np02b._TNHelperNP02B.cmd')
def test_status_parses_output_to_valid_dictionary(self, tnhelper_cmd_mock):
"""status should parse helper response correctly into dict."""
@@ -116,4 +118,8 @@
np02b = PduDevice(HOST, None, None)
tnhelper_cmd_mock.return_value = STATUS_RESPONSE_STR
with self.assertRaises(PduError):
- self.assertTrue(np02b._verify_state(INVALID_STATUS_DICT))
\ No newline at end of file
+ self.assertTrue(np02b._verify_state(INVALID_STATUS_DICT))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/acts/framework/tests/controllers/power_metrics_test.py b/acts/framework/tests/controllers/power_metrics_test.py
index 1533998..a14ca8d 100644
--- a/acts/framework/tests/controllers/power_metrics_test.py
+++ b/acts/framework/tests/controllers/power_metrics_test.py
@@ -24,9 +24,9 @@
from acts.controllers.power_metrics import CURRENT
from acts.controllers.power_metrics import END_TIMESTAMP
from acts.controllers.power_metrics import HOUR
+from acts.controllers.power_metrics import Metric
from acts.controllers.power_metrics import MILLIAMP
from acts.controllers.power_metrics import MINUTE
-from acts.controllers.power_metrics import Metric
from acts.controllers.power_metrics import PowerMetrics
from acts.controllers.power_metrics import START_TIMESTAMP
from acts.controllers.power_metrics import TIME
@@ -137,20 +137,34 @@
"""Test that given test timestamps, a power metric is generated from
a subset of samples corresponding to the test."""
timestamps = {'sample_test': {START_TIMESTAMP: 3500,
- END_TIMESTAMP: 8500}}
+ END_TIMESTAMP: 8500}}
mock_power_metric = mock.Mock()
mock_power_metric_type.side_effect = lambda v: mock_power_metric
- metrics = power_metrics.generate_test_metrics(self.RAW_DATA,
- timestamps=timestamps,
- voltage=self.VOLTAGE)
+ power_metrics.generate_test_metrics(self.RAW_DATA,
+ timestamps=timestamps,
+ voltage=self.VOLTAGE)
self.assertEqual(mock_power_metric.update_metrics.call_count, 5)
+ def test_incomplete_timestamps_are_ignored(self):
+ """Test that given incomplete timestamps, a power metric is generated from
+ a subset of samples corresponding to the test."""
+ sample_test = 'sample_test'
+ test_end = 13500
+ test_timestamps = {sample_test: {
+ END_TIMESTAMP: test_end}}
+ # no error expected
+ metrics = (
+ power_metrics.generate_test_metrics(self.RAW_DATA,
+ timestamps=test_timestamps,
+ voltage=self.VOLTAGE))
+
+
def test_numeric_metrics(self):
"""Test that the numeric metrics have correct values."""
timestamps = {'sample_test': {START_TIMESTAMP: 0,
- END_TIMESTAMP: 10000}}
+ END_TIMESTAMP: 10000}}
metrics = power_metrics.generate_test_metrics(self.RAW_DATA,
timestamps=timestamps,
voltage=self.VOLTAGE)
diff --git a/acts/framework/tests/controllers/rohdeschwarz_lib/contest_test.py b/acts/framework/tests/controllers/rohdeschwarz_lib/contest_test.py
index d7bbc89..2139a76 100644
--- a/acts/framework/tests/controllers/rohdeschwarz_lib/contest_test.py
+++ b/acts/framework/tests/controllers/rohdeschwarz_lib/contest_test.py
@@ -14,11 +14,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from acts import base_test
+from acts import logger
from acts import asserts
+import unittest
from unittest import mock
import socket
import time
+from contextlib import closing
# TODO(markdr): Remove this hack after adding zeep to setup.py.
import sys
@@ -27,17 +29,31 @@
from acts.controllers.rohdeschwarz_lib import contest
-class ContestTest(base_test.BaseTestClass):
+def find_free_port():
+ """ Helper function to find a free port.
+ https://stackoverflow.com/a/45690594
+ """
+ with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
+ s.bind(('', 0))
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ return s.getsockname()[1]
+
+
+class ContestTest(unittest.TestCase):
""" Unit tests for the contest controller."""
LOCAL_HOST_IP = '127.0.0.1'
+ @classmethod
+ def setUpClass(self):
+ self.log = logger.create_tagged_trace_logger('contest_test')
+
def test_automation_server_end_to_end(self):
""" End to end test for the Contest object's ability to start an
Automation Server and respond to the commands sent through the
socket interface. """
- automation_port = 5555
+ automation_port = find_free_port()
# Instantiate the mock Contest object. This will start a thread in the
# background running the Automation server.
@@ -65,6 +81,7 @@
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((self.LOCAL_HOST_IP, automation_port))
s.sendall(b'AtTestcaseStart')
+ s.settimeout(1.0)
data = s.recv(1024)
asserts.assert_true(data == b'OK\n', "Received OK response.")
@@ -138,7 +155,7 @@
# immediately, rather than sleeping.
@mock.patch('time.sleep')
# Prevents the controller to try to download the results from the FTP server
- @mock.patch('acts.controllers.gnssinst_lib.rohdeschwarz.contest'
+ @mock.patch('acts.controllers.rohdeschwarz_lib.contest'
'.Contest.pull_test_results')
def test_execute_testplan_stops_reading_output_on_exit_line(
self, time_mock, results_func_mock):
@@ -162,16 +179,15 @@
with mock.patch('zeep.client.Client') as zeep_client:
zeep_client.return_value.service.DoGetOutput = service_output
- controller = contest.Contest(
- logger=self.log,
- remote_ip=None,
- remote_port=None,
- automation_listen_ip=None,
- automation_port=None,
- dut_on_func=None,
- dut_off_func=None,
- ftp_usr=None,
- ftp_pwd=None)
+ controller = contest.Contest(logger=self.log,
+ remote_ip=None,
+ remote_port=None,
+ automation_listen_ip=None,
+ automation_port=None,
+ dut_on_func=None,
+ dut_off_func=None,
+ ftp_usr=None,
+ ftp_pwd=None)
controller.execute_testplan('TestPlan')
controller.destroy()
@@ -197,22 +213,22 @@
# An array of what return values. If a value is an Exception, the
# Exception is raised instead.
service_output.side_effect = [
- 'Testplan Directory: {}{}\\ \n'.format(
- contest.Contest.FTP_ROOT, results_directory), 'Exit code: 0\n'
+ 'Testplan Directory: {}{}\\ \n'.format(contest.Contest.FTP_ROOT,
+ results_directory),
+ 'Exit code: 0\n'
]
with mock.patch('zeep.client.Client') as zeep_client:
zeep_client.return_value.service.DoGetOutput = service_output
- controller = contest.Contest(
- logger=self.log,
- remote_ip=None,
- remote_port=None,
- automation_listen_ip=None,
- automation_port=None,
- dut_on_func=None,
- dut_off_func=None,
- ftp_usr=None,
- ftp_pwd=None)
+ controller = contest.Contest(logger=self.log,
+ remote_ip=None,
+ remote_port=None,
+ automation_listen_ip=None,
+ automation_port=None,
+ dut_on_func=None,
+ dut_off_func=None,
+ ftp_usr=None,
+ ftp_pwd=None)
controller.execute_testplan('TestPlan')
@@ -245,16 +261,15 @@
with mock.patch('zeep.client.Client') as zeep_client:
zeep_client.return_value.service.DoGetOutput = service_output
- controller = contest.Contest(
- logger=self.log,
- remote_ip=None,
- remote_port=None,
- automation_listen_ip=None,
- automation_port=None,
- dut_on_func=None,
- dut_off_func=None,
- ftp_usr=None,
- ftp_pwd=None)
+ controller = contest.Contest(logger=self.log,
+ remote_ip=None,
+ remote_port=None,
+ automation_listen_ip=None,
+ automation_port=None,
+ dut_on_func=None,
+ dut_off_func=None,
+ ftp_usr=None,
+ ftp_pwd=None)
try:
controller.execute_testplan('TestPlan')
@@ -262,3 +277,7 @@
pass
controller.destroy()
+
+
+if __name__ == '__main__':
+ unittest.main()
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
index 042f226..5481f32 100644
--- 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
@@ -107,9 +107,8 @@
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)
+ 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'):
@@ -131,8 +130,14 @@
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)
+ 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)
+
+
+if __name__ == '__main__':
+ unittest.main()
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
index 536fd75..21659bf 100644
--- 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
@@ -31,8 +31,8 @@
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))
+ android_device.AndroidDevice(serial=serial,
+ ssh_connection=ssh_connection))
fb_proxy.reset_mock()
return ret
@@ -65,3 +65,7 @@
'')
runner.android_device.adb.getprop = mock.Mock(side_effect=['a', 'b'])
runner.update()
+
+
+if __name__ == '__main__':
+ unittest.main()
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
index 9e15177..1e38f97 100644
--- 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
@@ -47,3 +47,7 @@
ret_a = ota_tool_factory.create(MockOtaTool.__name__, 'command')
ret_b = ota_tool_factory.create(MockOtaTool.__name__, 'command')
self.assertEqual(ret_a, ret_b)
+
+
+if __name__ == '__main__':
+ unittest.main()
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
index 73ee599..3589009 100644
--- a/acts/framework/tests/libs/ota/ota_tools/ota_tool_test.py
+++ b/acts/framework/tests/libs/ota/ota_tools/ota_tool_test.py
@@ -37,3 +37,7 @@
ota_tool.OtaTool('').cleanup(obj)
except:
self.fail('End is not required and should be a virtual function.')
+
+
+if __name__ == '__main__':
+ unittest.main()
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
index a07719c..505b34f 100644
--- 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
@@ -30,8 +30,8 @@
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))
+ android_device.AndroidDevice(serial=serial,
+ ssh_connection=ssh_connection))
fb_proxy.reset_mock()
return ret
@@ -77,3 +77,7 @@
del tool
self.assertTrue(mkdtemp.called)
self.assertTrue(rmtree.called)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device.py b/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device.py
index e6dcc4e..ee4c240 100644
--- a/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device.py
+++ b/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device.py
@@ -439,7 +439,7 @@
def get_default_wlan_test_interface(self):
"""Returns name of the WLAN client interface"""
- return self.device.wlan_controller.get_wlan_interface_name()
+ return self.device.wlan_client_test_interface_name
def destroy_wlan_interface(self, iface_id):
"""Function to associate a Fuchsia WLAN device.
@@ -483,14 +483,23 @@
if response.get('error'):
raise ConnectionError(
'Failed to get client network connection status')
+ result = response.get('result')
+ if isinstance(result, dict):
+ connected_to = result.get('Connected')
+ # TODO(https://fxbug.dev/85938): Remove backwards compatibility once
+ # ACTS is versioned with Fuchsia.
+ if not connected_to:
+ connected_to = result.get('connected_to')
+ if not connected_to:
+ return False
- status = response.get('result')
- if status and status.get('connected_to'):
if ssid:
- connected_ssid = ''.join(
- chr(i) for i in status['connected_to']['ssid'])
- if ssid != connected_ssid:
- return False
+ # Replace encoding errors instead of raising an exception.
+ # Since `ssid` is a string, this will not affect the test
+ # for equality.
+ connected_ssid = bytearray(connected_to['ssid']).decode(
+ encoding='utf-8', errors='replace')
+ return ssid == connected_ssid
return True
return False
diff --git a/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device_lib/AbstractDeviceWlanDeviceBaseTest.py b/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device_lib/AbstractDeviceWlanDeviceBaseTest.py
index 239accf..ba05a53 100644
--- a/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device_lib/AbstractDeviceWlanDeviceBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device_lib/AbstractDeviceWlanDeviceBaseTest.py
@@ -13,26 +13,68 @@
# 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
+
+from acts import context
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
+from mobly import utils
+from mobly.base_test import STAGE_NAME_TEARDOWN_CLASS
+
class AbstractDeviceWlanDeviceBaseTest(WifiBaseTest):
def setup_class(self):
super().setup_class()
- def on_fail(self, test_name, begin_time):
- try:
- self.dut.get_log(test_name, begin_time)
- if (not hasattr(self.dut.device, "take_bug_report_on_fail")
- or self.dut.device.take_bug_report_on_fail):
- # Take a bug report if device does not have a take bug report flag,
- # or if the flag is true
- self.dut.take_bug_report(test_name, begin_time)
- except Exception:
- pass
+ def teardown_class(self):
+ begin_time = utils.get_current_epoch_time()
+ super().teardown_class()
+ for device in getattr(self, "android_devices", []):
+ device.take_bug_report(STAGE_NAME_TEARDOWN_CLASS, begin_time)
+ for device in getattr(self, "fuchsia_devices", []):
+ device.take_bug_report(STAGE_NAME_TEARDOWN_CLASS, begin_time)
- try:
- if self.dut.device.hard_reboot_on_fail:
- self.dut.hard_power_cycle(self.pdu_devices)
- except AttributeError:
- pass
+ def on_fail(self, test_name, begin_time):
+ """Gets a wlan_device log and calls the generic device fail on DUT."""
+ self.dut.get_log(test_name, begin_time)
+ self.on_device_fail(self.dut.device, test_name, begin_time)
+
+ def on_device_fail(self, device, test_name, begin_time):
+ """Gets a generic device DUT bug report.
+
+ This method takes a bug report if the generic device does not have a
+ 'take_bug_report_on_fail', or if the flag is true. This method also
+ power cycles if 'hard_reboot_on_fail' is True.
+
+ Args:
+ device: Generic device to gather logs from.
+ test_name: Name of the test that triggered this function.
+ begin_time: Logline format timestamp taken when the test started.
+ """
+ if (not hasattr(device, "take_bug_report_on_fail")
+ or device.take_bug_report_on_fail):
+ device.take_bug_report(test_name, begin_time)
+
+ if device.hard_reboot_on_fail:
+ device.reboot(reboot_type='hard', testbed_pdus=self.pdu_devices)
+
+ def download_ap_logs(self):
+ """Downloads the DHCP and hostapad logs from the access_point.
+
+ Using the current TestClassContext and TestCaseContext this method pulls
+ the DHCP and hostapd logs and outputs them to the correct path.
+ """
+ current_path = context.get_current_context().get_full_output_path()
+ dhcp_full_out_path = os.path.join(current_path, "dhcp_log.txt")
+
+ dhcp_log_file = open(dhcp_full_out_path, 'w')
+ dhcp_log_file.write(self.access_point.get_dhcp_logs())
+ dhcp_log_file.close()
+
+ hostapd_logs = self.access_point.get_hostapd_logs()
+ for interface in hostapd_logs:
+ out_name = interface + "_hostapd_log.txt"
+ hostapd_full_out_path = os.path.join(current_path, out_name)
+ hostapd_log_file = open(hostapd_full_out_path, 'w')
+ hostapd_log_file.write(hostapd_logs[interface])
+ hostapd_log_file.close()
diff --git a/acts_tests/acts_contrib/test_utils/bt/A2dpBaseTest.py b/acts_tests/acts_contrib/test_utils/bt/A2dpBaseTest.py
index e943083..36acdfd 100644
--- a/acts_tests/acts_contrib/test_utils/bt/A2dpBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/bt/A2dpBaseTest.py
@@ -16,14 +16,21 @@
"""Stream music through connected device from phone test implementation."""
import acts
import os
+import pandas as pd
import shutil
import time
import acts_contrib.test_utils.coex.audio_test_utils as atu
import acts_contrib.test_utils.bt.bt_test_utils as btutils
from acts import asserts
+from acts_contrib.test_utils.bt import bt_constants
+from acts_contrib.test_utils.bt import BtEnum
from acts_contrib.test_utils.abstract_devices.bluetooth_handsfree_abstract_device import BluetoothHandsfreeAbstractDeviceFactory as bt_factory
from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
+from acts_contrib.test_utils.bt.ble_performance_test_utils import plot_graph
+from acts_contrib.test_utils.power.PowerBTBaseTest import ramp_attenuation
+from acts_contrib.test_utils.bt.loggers import bluetooth_metric_logger as log
+from acts.signals import TestPass, TestError
PHONE_MUSIC_FILE_DIRECTORY = '/sdcard/Music'
INIT_ATTEN = 0
@@ -44,12 +51,15 @@
def setup_class(self):
super().setup_class()
+ self.bt_logger = log.BluetoothMetricLogger.for_test_case()
self.dut = self.android_devices[0]
- req_params = ['audio_params', 'music_files']
+ req_params = ['audio_params', 'music_files', 'system_path_loss']
+ opt_params = ['bugreport']
#'audio_params' is a dict, contains the audio device type, audio streaming
#settings such as volumn, duration, audio recording parameters such as
#channel, sampling rate/width, and thdn parameters for audio processing
self.unpack_userparams(req_params)
+ self.unpack_userparams(opt_params, bugreport=None)
# Find music file and push it to the dut
music_src = self.music_files[0]
music_dest = PHONE_MUSIC_FILE_DIRECTORY
@@ -113,6 +123,11 @@
self.bt_device.power_off()
btutils.disable_bluetooth(self.dut.droid)
+ def on_pass(self, test_name, begin_time):
+
+ if hasattr(self, 'bugreport') and self.bugreport == 1:
+ self._take_bug_report(test_name, begin_time)
+
def play_and_record_audio(self, duration):
"""Play and record audio for a set duration.
@@ -135,27 +150,45 @@
asserts.assert_true(audio_captured, 'Audio not recorded')
return audio_captured
- def _get_bt_link_metrics(self):
+ def _get_bt_link_metrics(self, tag=''):
"""Get bt link metrics such as rssi and tx pwls.
Returns:
- rssi_master: master rssi
- pwl_master: master tx pwl
- rssi_slave: slave rssi
+ master_metrics_list: list of metrics of central device
+ slave_metrics_list: list of metric of peripheral device
"""
+ self.raw_bt_metrics_path = os.path.join(self.log_path,
+ 'BT_Raw_Metrics')
self.media.play()
# Get master rssi and power level
- rssi_master = btutils.get_bt_metric(self.dut)['rssi']
- pwl_master = btutils.get_bt_metric(self.dut)['pwlv']
- # Get slave rssi if possible
+ process_data_dict = btutils.get_bt_metric(
+ self.dut, tag=tag, log_path=self.raw_bt_metrics_path)
+ rssi_master = process_data_dict.get('rssi')
+ pwl_master = process_data_dict.get('pwlv')
+ rssi_c0_master = process_data_dict.get('rssi_c0')
+ rssi_c1_master = process_data_dict.get('rssi_c1')
+ txpw_c0_master = process_data_dict.get('txpw_c0')
+ txpw_c1_master = process_data_dict.get('txpw_c1')
+ bftx_master = process_data_dict.get('bftx')
+ divtx_master = process_data_dict.get('divtx')
+
if isinstance(self.bt_device_controller,
acts.controllers.android_device.AndroidDevice):
- rssi_slave = btutils.get_bt_rssi(self.bt_device_controller)
+ rssi_slave = btutils.get_bt_rssi(self.bt_device_controller,
+ tag=tag,
+ log_path=self.raw_bt_metrics_path)
else:
rssi_slave = None
self.media.stop()
- return [rssi_master, pwl_master, rssi_slave]
+
+ master_metrics_list = [
+ rssi_master, pwl_master, rssi_c0_master, rssi_c1_master,
+ txpw_c0_master, txpw_c1_master, bftx_master, divtx_master
+ ]
+ slave_metrics_list = [rssi_slave]
+
+ return master_metrics_list, slave_metrics_list
def run_thdn_analysis(self, audio_captured, tag):
"""Calculate Total Harmonic Distortion plus Noise for latest recording.
@@ -205,3 +238,208 @@
else:
self.log.info('%i anomalies detected.' % num_anom)
return anom
+
+ def generate_proto(self, data_points, codec_type, sample_rate,
+ bits_per_sample, channel_mode):
+ """Generate a results protobuf.
+
+ Args:
+ data_points: list of dicts representing info to go into
+ AudioTestDataPoint protobuffer message.
+ codec_type: The codec type config to store in the proto.
+ sample_rate: The sample rate config to store in the proto.
+ bits_per_sample: The bits per sample config to store in the proto.
+ channel_mode: The channel mode config to store in the proto.
+ Returns:
+ dict: Dictionary with key 'proto' mapping to serialized protobuf,
+ 'proto_ascii' mapping to human readable protobuf info, and 'test'
+ mapping to the test class name that generated the results.
+ """
+
+ # Populate protobuf
+ test_case_proto = self.bt_logger.proto_module.BluetoothAudioTestResult(
+ )
+
+ for data_point in data_points:
+ audio_data_proto = test_case_proto.data_points.add()
+ log.recursive_assign(audio_data_proto, data_point)
+
+ codec_proto = test_case_proto.a2dp_codec_config
+ codec_proto.codec_type = bt_constants.codec_types[codec_type]
+ codec_proto.sample_rate = int(sample_rate)
+ codec_proto.bits_per_sample = int(bits_per_sample)
+ codec_proto.channel_mode = bt_constants.channel_modes[channel_mode]
+
+ self.bt_logger.add_config_data_to_proto(test_case_proto, self.dut,
+ self.bt_device)
+
+ self.bt_logger.add_proto_to_results(test_case_proto,
+ self.__class__.__name__)
+
+ proto_dict = self.bt_logger.get_proto_dict(self.__class__.__name__,
+ test_case_proto)
+ del proto_dict["proto_ascii"]
+ return proto_dict
+
+ def set_test_atten(self, atten):
+ """Set the attenuation(s) for current test condition.
+
+ """
+ if hasattr(self, 'dual_chain') and self.dual_chain == 1:
+ ramp_attenuation(self.atten_c0,
+ atten,
+ attenuation_step_max=2,
+ time_wait_in_between=1)
+ self.log.info('Set Chain 0 attenuation to %d dB', atten)
+ ramp_attenuation(self.atten_c1,
+ atten + self.gain_mismatch,
+ attenuation_step_max=2,
+ time_wait_in_between=1)
+ self.log.info('Set Chain 1 attenuation to %d dB',
+ atten + self.gain_mismatch)
+ else:
+ ramp_attenuation(self.attenuator, atten)
+ self.log.info('Set attenuation to %d dB', atten)
+
+ def run_a2dp_to_max_range(self, codec_config):
+ attenuation_range = range(self.attenuation_vector['start'],
+ self.attenuation_vector['stop'] + 1,
+ self.attenuation_vector['step'])
+
+ data_points = []
+ self.file_output = os.path.join(
+ self.log_path, '{}.csv'.format(self.current_test_name))
+
+ # Set Codec if needed
+ current_codec = self.dut.droid.bluetoothA2dpGetCurrentCodecConfig()
+ current_codec_type = BtEnum.BluetoothA2dpCodecType(
+ current_codec['codecType']).name
+ if current_codec_type != codec_config['codec_type']:
+ codec_set = btutils.set_bluetooth_codec(self.dut, **codec_config)
+ asserts.assert_true(codec_set, 'Codec configuration failed.')
+ else:
+ self.log.info('Current codec is {}, no need to change'.format(
+ current_codec_type))
+
+ #loop RSSI with the same codec setting
+ for atten in attenuation_range:
+ self.media.play()
+ self.set_test_atten(atten)
+
+ tag = 'codec_{}_attenuation_{}dB_'.format(
+ codec_config['codec_type'], atten)
+ recorded_file = self.play_and_record_audio(
+ self.audio_params['duration'])
+ thdns = self.run_thdn_analysis(recorded_file, tag)
+
+ # Collect Metrics for dashboard
+ [
+ rssi_master, pwl_master, rssi_c0_master, rssi_c1_master,
+ txpw_c0_master, txpw_c1_master, bftx_master, divtx_master
+ ], [rssi_slave] = self._get_bt_link_metrics(tag)
+
+ data_point = {
+ 'attenuation_db':
+ int(self.attenuator.get_atten()),
+ 'pathloss':
+ atten + self.system_path_loss,
+ 'rssi_primary':
+ rssi_master.get(self.dut.serial, -127),
+ 'tx_power_level_master':
+ pwl_master.get(self.dut.serial, -127),
+ 'rssi_secondary':
+ rssi_slave.get(self.bt_device_controller.serial, -127),
+ 'rssi_c0_dut':
+ rssi_c0_master.get(self.dut.serial, -127),
+ 'rssi_c1_dut':
+ rssi_c1_master.get(self.dut.serial, -127),
+ 'txpw_c0_dut':
+ txpw_c0_master.get(self.dut.serial, -127),
+ 'txpw_c1_dut':
+ txpw_c1_master.get(self.dut.serial, -127),
+ 'bftx_state':
+ bftx_master.get(self.dut.serial, -127),
+ 'divtx_state':
+ divtx_master.get(self.dut.serial, -127),
+ 'total_harmonic_distortion_plus_noise_percent':
+ thdns[0] * 100
+ }
+ self.log.info(data_point)
+ # bokeh data for generating BokehFigure
+ bokeh_data = {
+ 'x_label': 'Pathloss (dBm)',
+ 'primary_y_label': 'RSSI (dBm)',
+ 'log_path': self.log_path,
+ 'current_test_name': self.current_test_name
+ }
+ #plot_data for adding line to existing BokehFigure
+ plot_data = {
+ 'line_one': {
+ 'x_label': 'Pathloss (dBm)',
+ 'primary_y_label': 'RSSI (dBm)',
+ 'x_column': 'pathloss',
+ 'y_column': 'rssi_primary',
+ 'legend': 'DUT RSSI (dBm)',
+ 'marker': 'circle_x',
+ 'y_axis': 'default'
+ },
+ 'line_two': {
+ 'x_column': 'pathloss',
+ 'y_column': 'rssi_secondary',
+ 'legend': 'Remote device RSSI (dBm)',
+ 'marker': 'hex',
+ 'y_axis': 'default'
+ },
+ 'line_three': {
+ 'x_column': 'pathloss',
+ 'y_column': 'tx_power_level_master',
+ 'legend': 'DUT TX Power (dBm)',
+ 'marker': 'hex',
+ 'y_axis': 'secondary'
+ }
+ }
+
+ # Check thdn for glitches, stop if max range reached
+ if thdns[0] == 0:
+ proto_dict = self.generate_proto(data_points, **codec_config)
+ A2dpRange_df = pd.DataFrame(data_points)
+ A2dpRange_df.to_csv(self.file_output, index=False)
+ plot_graph(A2dpRange_df,
+ plot_data,
+ bokeh_data,
+ secondary_y_label='DUT TX Power')
+ raise TestError(
+ 'Music play/recording is not working properly or Connection has lost'
+ )
+
+ data_points.append(data_point)
+ A2dpRange_df = pd.DataFrame(data_points)
+
+ for thdn in thdns:
+ if thdn >= self.audio_params['thdn_threshold']:
+ self.log.info(
+ 'Max range at attenuation {} dB'.format(atten))
+ self.log.info('DUT rssi {} dBm, DUT tx power level {}, '
+ 'Remote rssi {} dBm'.format(
+ rssi_master, pwl_master, rssi_slave))
+ proto_dict = self.generate_proto(data_points,
+ **codec_config)
+ A2dpRange_df.to_csv(self.file_output, index=False)
+ plot_graph(A2dpRange_df,
+ plot_data,
+ bokeh_data,
+ secondary_y_label='DUT TX Power')
+ return True
+ raise TestPass('Max range reached and move to next codec',
+ extras=proto_dict)
+ # Save Data points to csv
+ A2dpRange_df.to_csv(self.file_output, index=False)
+ # Plot graph
+ plot_graph(A2dpRange_df,
+ plot_data,
+ bokeh_data,
+ secondary_y_label='DUT TX Power')
+ proto_dict = self.generate_proto(data_points, **codec_config)
+ return True
+ raise TestPass('Could not reach max range, need extra attenuation.',
+ extras=proto_dict)
diff --git a/acts_tests/acts_contrib/test_utils/bt/BluetoothCarHfpBaseTest.py b/acts_tests/acts_contrib/test_utils/bt/BluetoothCarHfpBaseTest.py
index 303b961..1c20301 100644
--- a/acts_tests/acts_contrib/test_utils/bt/BluetoothCarHfpBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/bt/BluetoothCarHfpBaseTest.py
@@ -25,7 +25,7 @@
from acts.keys import Config
from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
from acts_contrib.test_utils.bt.bt_test_utils import pair_pri_to_sec
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_default_state
from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
from acts_contrib.test_utils.tel.tel_test_utils import setup_droid_properties
diff --git a/acts_tests/acts_contrib/test_utils/bt/BtInterferenceBaseTest.py b/acts_tests/acts_contrib/test_utils/bt/BtInterferenceBaseTest.py
index 3c49bee..99ca5da 100644
--- a/acts_tests/acts_contrib/test_utils/bt/BtInterferenceBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/bt/BtInterferenceBaseTest.py
@@ -18,7 +18,9 @@
import json
import math
+import random
import time
+import logging
import acts.controllers.iperf_client as ipc
import acts.controllers.iperf_server as ipf
import acts_contrib.test_utils.bt.bt_test_utils as btutils
@@ -44,7 +46,7 @@
ap: access point object
bandwidth: bandwidth of the WiFi network to be setup
Returns:
- self.brconfigs: dict for bridge interface configs
+ brconfigs: dict for bridge interface configs
"""
wutils.wifi_toggle_state(dut, True)
brconfigs = wputils.ap_setup(ap, network, bandwidth=bandwidth)
@@ -103,6 +105,52 @@
return throughput
+def locate_interference_pair_by_channel(wifi_int_pairs, interference_channels):
+ """Function to find which attenautor to set based on channel info
+ Args:
+ interference_channels: list of interference channels
+ Return:
+ interference_pair_indices: list of indices for interference pair
+ in wifi_int_pairs
+ """
+ interference_pair_indices = []
+ for chan in interference_channels:
+ for i in range(len(wifi_int_pairs)):
+ if wifi_int_pairs[i].channel == chan:
+ interference_pair_indices.append(i)
+ return interference_pair_indices
+
+
+def inject_static_wifi_interference(wifi_int_pairs, interference_level,
+ channels):
+ """Function to inject wifi interference to bt link and read rssi.
+
+ Interference of IPERF traffic is always running, by setting attenuation,
+ the gate is opened to release the interference to the setup.
+ Args:
+ interference_level: the signal strength of wifi interference, use
+ attenuation level to represent this
+ channels: wifi channels where interference will
+ be injected, list
+ """
+ all_pair = range(len(wifi_int_pairs))
+ interference_pair_indices = locate_interference_pair_by_channel(
+ wifi_int_pairs, channels)
+ inactive_interference_pairs_indices = [
+ item for item in all_pair if item not in interference_pair_indices
+ ]
+ logging.info('WiFi interference at {} and inactive channels at {}'.format(
+ interference_pair_indices, inactive_interference_pairs_indices))
+ for i in interference_pair_indices:
+ wifi_int_pairs[i].attenuator.set_atten(interference_level)
+ logging.info('Set attenuation {} dB on attenuator {}'.format(
+ wifi_int_pairs[i].attenuator.get_atten(), i + 1))
+ for i in inactive_interference_pairs_indices:
+ wifi_int_pairs[i].attenuator.set_atten(MAX_ATTENUATION)
+ logging.info('Set attenuation {} dB on attenuator {}'.format(
+ wifi_int_pairs[i].attenuator.get_atten(), i + 1))
+
+
class BtInterferenceBaseTest(A2dpBaseTest):
def __init__(self, configs):
super().__init__(configs)
@@ -163,7 +211,6 @@
obj.iperf_server.port))
obj.iperf_server.stop()
self.log.info('Stop IPERF process on {}'.format(obj.dut.serial))
- obj.dut.adb.shell('pkill -9 iperf3')
#only for glinux machine
# wputils.bring_down_interface(obj.ether_int.interface)
obj.attenuator.set_atten(MAX_ATTENUATION)
@@ -172,7 +219,6 @@
def teardown_test(self):
super().teardown_test()
-
for obj in self.wifi_int_pairs:
obj.attenuator.set_atten(MAX_ATTENUATION)
diff --git a/acts_tests/acts_contrib/test_utils/bt/ble_performance_test_utils.py b/acts_tests/acts_contrib/test_utils/bt/ble_performance_test_utils.py
index 394e962..01231d3 100644
--- a/acts_tests/acts_contrib/test_utils/bt/ble_performance_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/bt/ble_performance_test_utils.py
@@ -16,19 +16,25 @@
import logging
import time
+import datetime
import statistics
-from queue import Empty
-from concurrent.futures import ThreadPoolExecutor
-
+import os
+from acts_contrib.test_utils.bt.bt_constants import advertising_set_started
+import acts_contrib.test_utils.wifi.wifi_performance_test_utils.bokeh_figure as bokeh_figure
+from acts_contrib.test_utils.bt.bt_constants import ble_scan_settings_phys
+from acts_contrib.test_utils.bt.bt_constants import ble_scan_settings_modes
from acts_contrib.test_utils.bt.bt_gatt_utils import close_gatt_client
from acts_contrib.test_utils.bt.bt_coc_test_utils import do_multi_connection_throughput
from acts_contrib.test_utils.bt.bt_gatt_utils import disconnect_gatt_connection
+from queue import Empty
from acts_contrib.test_utils.bt.bt_constants import gatt_cb_err
from acts_contrib.test_utils.bt.bt_constants import gatt_cb_strings
from acts_contrib.test_utils.bt.bt_constants import l2cap_coc_header_size
from acts_contrib.test_utils.bt.bt_gatt_utils import GattTestUtilsError
+from acts_contrib.test_utils.bt.bt_test_utils import generate_ble_scan_objects
from acts_contrib.test_utils.bt.bt_coc_test_utils import orchestrate_coc_connection
from acts_contrib.test_utils.bt.bt_gatt_utils import orchestrate_gatt_connection
+from concurrent.futures import ThreadPoolExecutor
default_event_timeout = 10
rssi_read_duration = 25
@@ -91,6 +97,43 @@
return ble_rssi
+def read_ble_scan_rssi(client_ad, scan_callback, rssi_read_duration=30):
+ """Function to Read BLE RSSI of the remote BLE device.
+ Args:
+ client_ad: the Android device performing the connection.
+ scan_callback: the scan callback of the server
+ Returns:
+ ble_rssi: RSSI value of the remote BLE device
+ raw_rssi: RSSI list of remote BLE device
+ """
+ raw_rssi = []
+ timestamp = []
+ end_time = time.time() + rssi_read_duration
+ logging.info("Reading BLE Scan RSSI for {} sec".format(rssi_read_duration))
+ while time.time() < end_time:
+ expected_event = gatt_cb_strings['rd_remote_ble_rssi'].format(
+ scan_callback)
+ try:
+ event = client_ad.ed.pop_event(expected_event,
+ default_event_timeout)
+ except Empty:
+ logging.error(
+ gatt_cb_err['rd_remote_rssi_err'].format(expected_event))
+ return False
+ rssi_value = event['data']['Result']['rssi']
+ epoch_time = event['time']
+ d = datetime.datetime.fromtimestamp(epoch_time / 1000)
+ tstamp = d.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
+ timestamp.append(tstamp)
+ raw_rssi.append(rssi_value)
+ logging.debug("First & Last reading of RSSI :{:03d} & {:03d}".format(
+ raw_rssi[0], raw_rssi[-1]))
+ ble_rssi = statistics.mean(raw_rssi)
+ ble_rssi = round(ble_rssi, 2)
+
+ return ble_rssi, raw_rssi, timestamp
+
+
def ble_coc_connection(client_ad, server_ad):
"""Sets up the CoC connection between two Android devices.
@@ -104,10 +147,10 @@
client connection ID: Client connection ID
and server connection ID : server connection ID
"""
- #secured_conn: True if using secured connection
- #le_connection_interval: LE Connection interval. 0 means use default.
- #buffer_size : is the number of bytes per L2CAP data buffer
- #le_tx_data_length: LE Data Length used by BT Controller to transmit.
+ # secured_conn: True if using secured connection
+ # le_connection_interval: LE Connection interval. 0 means use default.
+ # buffer_size : is the number of bytes per L2CAP data buffer
+ # le_tx_data_length: LE Data Length used by BT Controller to transmit.
is_secured = False
le_connection_interval = 30
buffer_size = 240
@@ -134,7 +177,9 @@
return True, gatt_callback, gatt_server, bluetooth_gatt, client_conn_id
-def run_ble_throughput(server_ad, client_conn_id, client_ad,
+def run_ble_throughput(server_ad,
+ client_conn_id,
+ client_ad,
num_iterations=30):
"""Function to measure Throughput from one client to one-or-many servers
@@ -208,3 +253,76 @@
logging.error(err)
return False
return True
+
+
+def plot_graph(df, plot_data, bokeh_data, secondary_y_label=None):
+ """ Plotting for generating bokeh figure
+
+ Args:
+ df: Summary of results contains attenuation, DUT RSSI, remote RSSI and Tx Power
+ plot_data: plot_data for adding line to existing BokehFigure
+ bokeh_data: bokeh data for generating BokehFigure
+ secondary_y_label : label for secondary y axis , None if not available
+ """
+ plot = bokeh_figure.BokehFigure(
+ title='{}'.format(bokeh_data['current_test_name']),
+ x_label=bokeh_data['x_label'],
+ primary_y_label=bokeh_data['primary_y_label'],
+ secondary_y_label=secondary_y_label,
+ axis_label_size='16pt',
+ legend_label_size='16pt',
+ axis_tick_label_size='16pt',
+ sizing_mode='stretch_both')
+
+ for data in plot_data:
+ plot.add_line(df[plot_data[data].get('x_column')],
+ df[plot_data[data].get('y_column')],
+ legend=plot_data[data].get('legend'),
+ marker=plot_data[data].get('marker'),
+ y_axis=plot_data[data].get('y_axis'))
+
+ results_file_path = os.path.join(
+ bokeh_data['log_path'],
+ '{}.html'.format(bokeh_data['current_test_name']))
+ plot.generate_figure()
+ bokeh_figure.BokehFigure.save_figures([plot], results_file_path)
+
+
+def start_advertising_and_scanning(client_ad, server_ad, Legacymode=True):
+ """Function to start bt5 advertisement.
+
+ Args:
+ client_ad: the Android device performing the scanning.
+ server_ad: the Android device performing the bt advertising
+ Legacymode: True for Legacy advertising mode, false for bt5 advertising mode
+ Returns:
+ adv_callback: the advertising callback
+ scan_callback: the scan_callback
+ """
+ adv_callback = server_ad.droid.bleAdvSetGenCallback()
+ adv_data = {
+ "includeDeviceName": True,
+ }
+ server_ad.droid.bleAdvSetStartAdvertisingSet(
+ {
+ "connectable": False,
+ "legacyMode": Legacymode,
+ "primaryPhy": "PHY_LE_1M",
+ "secondaryPhy": "PHY_LE_1M",
+ "interval": 320
+ }, adv_data, None, None, None, 0, 0, adv_callback)
+ server_ad.ed.pop_event(advertising_set_started.format(adv_callback),
+ default_event_timeout)
+ logging.info("Bt5 Advertiser Started Successfully")
+ client_ad.droid.bleSetScanSettingsLegacy(False)
+ client_ad.droid.bleSetScanSettingsScanMode(
+ ble_scan_settings_modes['low_latency'])
+ client_ad.droid.bleSetScanSettingsPhy(ble_scan_settings_phys['1m'])
+
+ filter_list, scan_settings, scan_callback = generate_ble_scan_objects(
+ client_ad.droid)
+ adv_device_name = server_ad.droid.bluetoothGetLocalName()
+ client_ad.droid.bleSetScanFilterDeviceName(adv_device_name)
+ client_ad.droid.bleBuildScanFilter(filter_list)
+ client_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback)
+ return adv_callback, scan_callback
diff --git a/acts_tests/acts_contrib/test_utils/bt/bt_carkit_lib.py b/acts_tests/acts_contrib/test_utils/bt/bt_carkit_lib.py
index 14a42b0..ce206da 100644
--- a/acts_tests/acts_contrib/test_utils/bt/bt_carkit_lib.py
+++ b/acts_tests/acts_contrib/test_utils/bt/bt_carkit_lib.py
@@ -26,17 +26,17 @@
from acts_contrib.test_utils.tel.tel_defines import AUDIO_ROUTE_EARPIECE
from acts_contrib.test_utils.tel.tel_defines import AUDIO_ROUTE_SPEAKER
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
-from acts_contrib.test_utils.tel.tel_test_utils import sms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
from acts_contrib.test_utils.tel.tel_voice_utils import get_audio_route
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
from acts_contrib.test_utils.tel.tel_voice_utils import set_audio_route
from acts_contrib.test_utils.tel.tel_voice_utils import swap_calls
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
from acts.utils import exe_cmd
from acts.utils import get_current_epoch_time
diff --git a/acts_tests/acts_contrib/test_utils/bt/bt_constants.py b/acts_tests/acts_contrib/test_utils/bt/bt_constants.py
index f7bc93f..ffb56b4 100644
--- a/acts_tests/acts_contrib/test_utils/bt/bt_constants.py
+++ b/acts_tests/acts_contrib/test_utils/bt/bt_constants.py
@@ -282,6 +282,12 @@
"high": 3
}
+# Bluetooth Low Energy advertise settings own address type
+ble_advertise_settings_own_address_types = {
+ "public": 0,
+ "random": 1
+}
+
# Bluetooth Low Energy service uuids for specific devices
ble_uuids = {
"p_service": "0000feef-0000-1000-8000-00805f9b34fb",
@@ -342,6 +348,7 @@
"desc_read": "GattConnect{}onDescriptorRead",
"desc_read_req": "GattServer{}onDescriptorReadRequest",
"rd_remote_rssi": "GattConnect{}onReadRemoteRssi",
+ "rd_remote_ble_rssi": "BleScan{}onScanResults",
"gatt_serv_disc": "GattConnect{}onServicesDiscovered",
"serv_added": "GattServer{}onServiceAdded",
"mtu_changed": "GattConnect{}onMtuChanged",
diff --git a/acts_tests/acts_contrib/test_utils/bt/bt_test_utils.py b/acts_tests/acts_contrib/test_utils/bt/bt_test_utils.py
index 9f9a518..ba66535 100644
--- a/acts_tests/acts_contrib/test_utils/bt/bt_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/bt/bt_test_utils.py
@@ -21,9 +21,12 @@
import string
import threading
import time
+try:
+ import pandas as pd
+except ModuleNotFoundError:
+ pass
from queue import Empty
from subprocess import call
-
from acts import asserts
from acts_contrib.test_utils.bt.bt_constants import adv_fail
from acts_contrib.test_utils.bt.bt_constants import adv_succ
@@ -105,8 +108,7 @@
ad.ed.pop_event(expected_bluetooth_on_event_name,
bt_default_timeout)
except Empty:
- ad.log.info(
- "Failed to toggle Bluetooth on(no broadcast received).")
+ ad.log.info("Failed to toggle Bluetooth on(no broadcast received).")
# Try one more time to poke at the actual state.
if ad.droid.bluetoothCheckState():
ad.log.info(".. actual state is ON")
@@ -219,7 +221,7 @@
method. False otherwise.
"""
headset_mac_address = headset.mac_address
- connected = is_a2dp_src_device_connected(android, headset_mac_address)
+ connected = android.droid.audioIsBluetoothA2dpOn()
log.info('Devices connected before pair attempt: %s' % connected)
if not connected:
# Turn on headset and initiate pairing mode.
@@ -230,9 +232,7 @@
while not connected and (time.time() - start_time < timeout):
bonded_info = android.droid.bluetoothGetBondedDevices()
connected_info = android.droid.bluetoothGetConnectedDevices()
- if headset.mac_address not in [
- info["address"] for info in bonded_info
- ]:
+ if headset.mac_address not in [info["address"] for info in bonded_info]:
# Use SL4A to pair and connect with headset.
headset.enter_pairing_mode()
android.droid.bluetoothDiscoverAndBond(headset_mac_address)
@@ -247,10 +247,11 @@
log.info('Waiting for connection...')
time.sleep(connection_check_period)
# Check for connection.
- connected = is_a2dp_src_device_connected(android, headset_mac_address)
+ connected = android.droid.audioIsBluetoothA2dpOn()
log.info('Devices connected after pair attempt: %s' % connected)
return connected
+
def connect_pri_to_sec(pri_ad, sec_ad, profiles_set, attempts=2):
"""Connects pri droid to secondary droid.
@@ -312,34 +313,33 @@
# 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)
@@ -600,8 +600,8 @@
def generate_id_by_size(size,
- chars=(string.ascii_lowercase +
- string.ascii_uppercase + string.digits)):
+ chars=(string.ascii_lowercase + string.ascii_uppercase +
+ string.digits)):
"""Generate random ascii characters of input size and input char types
Args:
@@ -710,7 +710,11 @@
return otp_dict
-def get_bt_metric(ad_list, duration=1, tag="bt_metric", processed=True):
+def get_bt_metric(ad_list,
+ duration=1,
+ bqr_tag='Monitoring , Handle:',
+ tag='',
+ log_path=False):
""" Function to get the bt metric from logcat.
Captures logcat for the specified duration and returns the bqr results.
@@ -719,21 +723,36 @@
Args:
ad_list: list of android_device objects
- duration: time duration (seconds) for which the logcat is parsed.
- tag: tag to be appended to the logcat dump.
- processed: flag to process bqr output.
+ duration: time duration (seconds) for which the logcat is parsed
+ bqr_tag: tag of bt metrics
+ tag: tag to be appended to the metrics raw data
+ log_path: path of metrics raw data
Returns:
- metrics_dict: dict of metrics for each android device.
+ process_data: dict of process raw data for each android devices
"""
- # Defining bqr quantitites and their regex to extract
+ # Defining bqr quantites and their regex to extract
regex_dict = {
- "vsp_txpl": "VSP_TxPL:\s(\S+)",
"pwlv": "PwLv:\s(\S+)",
- "rssi": "RSSI:\s[-](\d+)"
+ "rssi": "RSSI:\s[-](\d+)",
+ "rssi_c0": "RSSI_C0:\s[-](\d+)",
+ "rssi_c1": "RSSI_C1:\s[-](\d+)",
+ "txpw_c0": "\sTxPw_C0:\s(-?\d+)",
+ "txpw_c1": "\sTxPw_C1:\s(-?\d+)",
+ "bftx": "BFTx:\s(\w+)",
+ "divtx": "DivTx:\s(\w+)"
}
- metrics_dict = {"rssi": {}, "pwlv": {}, "vsp_txpl": {}}
+ metrics_dict = {
+ "rssi": {},
+ "pwlv": {},
+ "rssi_c0": {},
+ "rssi_c1": {},
+ "txpw_c0": {},
+ "txpw_c1": {},
+ "bftx": {},
+ "divtx": {}
+ }
# Converting a single android device object to list
if not isinstance(ad_list, list):
@@ -749,8 +768,7 @@
end_time = utils.get_current_epoch_time()
for ad in ad_list:
- bt_rssi_log = ad.cat_adb_log(tag, begin_time, end_time)
- bqr_tag = "Handle:"
+ bt_rssi_log = ad.cat_adb_log(tag + "_bt_metric", begin_time, end_time)
# Extracting supporting bqr quantities
for metric, regex in regex_dict.items():
@@ -762,35 +780,97 @@
m = re.findall(regex, line)[0].strip(",")
bqr_metric.append(m)
metrics_dict[metric][ad.serial] = bqr_metric
+ file_bt_log.close()
- # Ensures back-compatibility for vsp_txpl enabled DUTs
- if metrics_dict["vsp_txpl"][ad.serial]:
- metrics_dict["pwlv"][ad.serial] = metrics_dict["vsp_txpl"][
- ad.serial]
+ # Formatting and saving the raw data
+ metrics_to_be_formatted = [{
+ "name": "rssi",
+ "averagble": "y"
+ }, {
+ "name": "rssi_c0",
+ "averagble": "y"
+ }, {
+ "name": "rssi_c1",
+ "averagble": "y"
+ }, {
+ "name": "pwlv",
+ "averagble": "n"
+ }, {
+ "name": "txpw_c0",
+ "averagble": "n"
+ }, {
+ "name": "txpw_c1",
+ "averagble": "n"
+ }, {
+ "name": "bftx",
+ "averagble": "n"
+ }, {
+ "name": "divtx",
+ "averagble": "n"
+ }]
+ for metric in metrics_to_be_formatted:
+ if metric["averagble"] == "y":
+ metrics_dict[metric["name"]][ad.serial] = [
+ (-1) * int(x)
+ for x in metrics_dict[metric["name"]][ad.serial]
+ ]
+ else:
+ metrics_dict[metric["name"]][ad.serial] = [
+ int(x, 16) if '0x' in x else int(x, 10)
+ for x in metrics_dict[metric["name"]][ad.serial]
+ ]
+ # Saving metrics raw data for each attenuation
+ if log_path:
+ output_file_name = ad.serial + "_metrics_raw_data_" + tag + ".csv"
+ output_file = os.path.join(log_path, output_file_name)
+ os.makedirs(log_path, exist_ok=True)
+ df_save_metrics = {}
+ for item in metrics_dict.items():
+ df_save_metrics[item[0]] = next(iter(item[1].items()))[1]
+ MetricsDict_df = pd.DataFrame({key:pd.Series(value) for key, value in df_save_metrics.items()})
+ MetricsDict_df.to_csv(output_file)
+ # Defining the process_data_dict
+ process_data = {
+ "rssi": {},
+ "pwlv": {},
+ "rssi_c0": {},
+ "rssi_c1": {},
+ "txpw_c0": {},
+ "txpw_c1": {},
+ "bftx": {},
+ "divtx": {}
+ }
- # Formatting the raw data
- metrics_dict["rssi"][ad.serial] = [
- (-1) * int(x) for x in metrics_dict["rssi"][ad.serial]
- ]
- metrics_dict["pwlv"][ad.serial] = [
- int(x, 16) for x in metrics_dict["pwlv"][ad.serial]
- ]
+ # Computing and returning the raw data
+ for metric in metrics_to_be_formatted:
+ if metric["averagble"] == "y":
+ process_data[metric["name"]][ad.serial] = [
+ x for x in metrics_dict[metric["name"]][ad.serial]
+ if x != 0 and x != -127
+ ]
- # Processing formatted data if processing is required
- if processed:
- # Computes the average RSSI
- metrics_dict["rssi"][ad.serial] = round(
- sum(metrics_dict["rssi"][ad.serial]) /
- len(metrics_dict["rssi"][ad.serial]), 2)
- # Returns last noted value for power level
- metrics_dict["pwlv"][ad.serial] = float(
- sum(metrics_dict["pwlv"][ad.serial]) /
- len(metrics_dict["pwlv"][ad.serial]))
+ try:
+ #DOING AVERAGE
+ process_data[metric["name"]][ad.serial] = round(
+ sum(metrics_dict[metric["name"]][ad.serial]) /
+ len(metrics_dict[metric["name"]][ad.serial]), 2)
+ except ZeroDivisionError:
+ #SETTING VALUE TO 'n/a'
+ process_data[metric["name"]][ad.serial] = "n/a"
+ else:
+ try:
+ #GETTING MOST_COMMON_VALUE
+ process_data[metric["name"]][ad.serial] = max(
+ metrics_dict[metric["name"]][ad.serial],
+ key=metrics_dict[metric["name"]][ad.serial].count)
+ except ValueError:
+ #SETTING VALUE TO 'n/a'
+ process_data[metric["name"]][ad.serial] = "n/a"
- return metrics_dict
+ return process_data
-def get_bt_rssi(ad, duration=1, processed=True):
+def get_bt_rssi(ad, duration=1, processed=True, tag='', log_path=False):
"""Function to get average bt rssi from logcat.
This function returns the average RSSI for the given duration. RSSI values are
@@ -803,11 +883,7 @@
Returns:
avg_rssi: average RSSI on each android device for the given duration.
"""
- function_tag = "get_bt_rssi"
- bqr_results = get_bt_metric(ad,
- duration,
- tag=function_tag,
- processed=processed)
+ bqr_results = get_bt_metric(ad, duration, tag=tag, log_path=log_path)
return bqr_results["rssi"]
@@ -1203,8 +1279,7 @@
test_result = False
time.sleep(1)
if not test_result:
- client_ad.log.error(
- "Failed to establish a Bluetooth socket connection")
+ client_ad.log.error("Failed to establish a Bluetooth socket connection")
return False
return True
@@ -1255,9 +1330,8 @@
str(curr_attempts)))
return False
if not clear_bonded_devices(sec_ad):
- log.error(
- "Failed to clear bond for secondary device at attempt {}".
- format(str(curr_attempts)))
+ log.error("Failed to clear bond for secondary device at attempt {}".
+ format(str(curr_attempts)))
return False
# Wait 2 seconds after unbound
time.sleep(2)
@@ -1409,11 +1483,10 @@
droid, ed = android_device.droid, android_device.ed
if not droid.bluetoothA2dpSetCodecConfigPreference(
codec_types[codec_type], sample_rates[str(sample_rate)],
- bits_per_samples[str(bits_per_sample)],
- channel_modes[channel_mode], codec_specific_1):
- android_device.log.warning(
- "SL4A command returned False. Codec was not "
- "changed.")
+ bits_per_samples[str(bits_per_sample)], channel_modes[channel_mode],
+ codec_specific_1):
+ android_device.log.warning("SL4A command returned False. Codec was not "
+ "changed.")
else:
try:
ed.pop_event(bluetooth_a2dp_codec_config_changed,
@@ -1625,8 +1698,8 @@
out_name = ','.join((testname, device_model, serial))
snoop_path = os.path.join(ad.device_log_path, 'BluetoothSnoopLogs')
os.makedirs(snoop_path, exist_ok=True)
- cmd = ''.join(("adb -s ", serial, " pull ", btsnoop_log_path_on_device,
- " ", snoop_path + '/' + out_name, ".btsnoop_hci.log"))
+ cmd = ''.join(("adb -s ", serial, " pull ", btsnoop_log_path_on_device, " ",
+ snoop_path + '/' + out_name, ".btsnoop_hci.log"))
exe_cmd(cmd)
try:
cmd = ''.join(
@@ -1747,9 +1820,8 @@
timeout=bt_default_timeout)
sec_variant = sec_pairing_req["data"]["PairingVariant"]
sec_pin = sec_pairing_req["data"]["Pin"]
- sec_ad.log.info(
- "Secondary device received Pin: {}, Variant: {}".format(
- sec_pin, sec_variant))
+ sec_ad.log.info("Secondary device received Pin: {}, Variant: {}".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(
@@ -1815,6 +1887,7 @@
"""Media control using sl4a facade for general purpose.
"""
+
def __init__(self, android_device, music_file):
"""Initialize the media_control class.
diff --git a/acts_tests/acts_contrib/test_utils/cellular/cellular_base_test.py b/acts_tests/acts_contrib/test_utils/cellular/cellular_base_test.py
index 485b25f..87f04fd 100644
--- a/acts_tests/acts_contrib/test_utils/cellular/cellular_base_test.py
+++ b/acts_tests/acts_contrib/test_utils/cellular/cellular_base_test.py
@@ -23,12 +23,13 @@
from acts.controllers.rohdeschwarz_lib import cmw500_cellular_simulator as cmw
from acts.controllers.rohdeschwarz_lib import cmx500_cellular_simulator as cmx
from acts.controllers.cellular_lib import AndroidCellularDut
-from acts.controllers.cellular_lib import GsmSimulation
-from acts.controllers.cellular_lib import LteSimulation
-from acts.controllers.cellular_lib import UmtsSimulation
-from acts.controllers.cellular_lib import LteCaSimulation
-from acts.controllers.cellular_lib import LteImsSimulation
+from acts.controllers.cellular_lib import BaseSimulation as base_sim
+from acts.controllers.cellular_lib import GsmSimulation as gsm_sim
+from acts.controllers.cellular_lib import LteSimulation as lte_sim
+from acts.controllers.cellular_lib import UmtsSimulation as umts_sim
+from acts.controllers.cellular_lib import LteImsSimulation as lteims_sim
+from acts_contrib.test_utils.tel import tel_logging_utils
from acts_contrib.test_utils.tel import tel_test_utils as telutils
@@ -45,6 +46,7 @@
# Custom files
FILENAME_CALIBRATION_TABLE_UNFORMATTED = 'calibration_table_{}.json'
+ FILENAME_TEST_CONFIGS = 'cellular_test_config.json'
# Name of the files in the logs directory that will contain test results
# and other information in csv format.
@@ -62,6 +64,7 @@
self.simulation = None
self.cellular_simulator = None
self.calibration_table = {}
+ self.test_configs = {}
def setup_class(self):
""" Executed before any test case is started.
@@ -96,7 +99,8 @@
for file in self.custom_files:
if filename_calibration_table in file:
- self.calibration_table = self.unpack_custom_file(file, False)
+ with open(file, 'r') as f:
+ self.calibration_table = json.load(f)
self.log.info('Loading calibration table from ' + file)
self.log.debug(self.calibration_table)
break
@@ -104,6 +108,20 @@
# Ensure the calibration table only contains non-negative values
self.ensure_valid_calibration_table(self.calibration_table)
+ # Load test configs from json file
+ for file in self.custom_files:
+ if self.FILENAME_TEST_CONFIGS in file:
+ self.log.info('Loading test configs from ' + file)
+ with open(file, 'r') as f:
+ config_file = json.load(f)
+ self.test_configs = config_file.get(self.TAG)
+ if not self.test_configs:
+ self.log.debug(config_file)
+ raise RuntimeError('Test config file does not include '
+ 'class %s'.format(self.TAG))
+ self.log.debug(self.test_configs)
+ break
+
# Turn on airplane mode for all devices, as some might
# be unused during the test
for ad in self.android_devices:
@@ -214,23 +232,23 @@
# Changing cell parameters requires the phone to be detached
self.simulation.detach()
- # Parse simulation parameters.
- # This may throw a ValueError exception if incorrect values are passed
- # or if required arguments are omitted.
- try:
- self.simulation.parse_parameters(self.parameters)
- except ValueError as error:
- self.log.error(str(error))
- return False
-
- # Wait for new params to settle
- time.sleep(5)
+ # Configure simulation with parameters loaded from json file
+ sim_params = self.test_configs.get(self.test_name)
+ if not sim_params:
+ raise KeyError('Test config file does not contain '
+ 'settings for ' + self.test_name)
+ # Get class parameters and apply if not overwritten by test parameters
+ for key, val in self.test_configs.items():
+ if not key.startswith('test_') and key not in sim_params:
+ sim_params[key] = val
+ self.log.info('Simulation parameters: ' + str(sim_params))
+ self.simulation.configure(sim_params)
# Enable QXDM logger if required
if self.qxdm_logs:
self.log.info('Enabling the QXDM logger.')
- telutils.set_qxdm_logger_command(self.dut)
- telutils.start_qxdm_logger(self.dut)
+ tel_logging_utils.set_qxdm_logger_command(self.dut)
+ tel_logging_utils.start_qxdm_logger(self.dut)
# Start the simulation. This method will raise an exception if
# the phone is unable to attach.
@@ -250,7 +268,7 @@
# If QXDM logging was enabled pull the results
if self.qxdm_logs:
self.log.info('Stopping the QXDM logger and pulling results.')
- telutils.stop_qxdm_logger(self.dut)
+ tel_logging_utils.stop_qxdm_logger(self.dut)
self.dut.get_qxdm_logs()
def consume_parameter(self, parameter_name, num_values=0):
@@ -313,11 +331,11 @@
"""
simulation_dictionary = {
- self.PARAM_SIM_TYPE_LTE: LteSimulation.LteSimulation,
- self.PARAM_SIM_TYPE_UMTS: UmtsSimulation.UmtsSimulation,
- self.PARAM_SIM_TYPE_GSM: GsmSimulation.GsmSimulation,
- self.PARAM_SIM_TYPE_LTE_CA: LteCaSimulation.LteCaSimulation,
- self.PARAM_SIM_TYPE_LTE_IMS: LteImsSimulation.LteImsSimulation
+ self.PARAM_SIM_TYPE_LTE: lte_sim.LteSimulation,
+ self.PARAM_SIM_TYPE_LTE_CA: lte_sim.LteSimulation,
+ self.PARAM_SIM_TYPE_UMTS: umts_sim.UmtsSimulation,
+ self.PARAM_SIM_TYPE_GSM: gsm_sim.GsmSimulation,
+ self.PARAM_SIM_TYPE_LTE_IMS: lteims_sim.LteImsSimulation
}
if not sim_type in simulation_dictionary:
@@ -362,21 +380,3 @@
raise TypeError('Calibration table value must be a number')
elif val < 0.0:
raise ValueError('Calibration table contains negative values')
-
- def unpack_custom_file(self, file, test_specific=True):
- """Loads a json file.
-
- Args:
- file: the common file containing pass fail threshold.
- test_specific: if True, returns the JSON element within the file
- that starts with the test class name.
- """
- with open(file, 'r') as f:
- params = json.load(f)
- if test_specific:
- try:
- return params[self.TAG]
- except KeyError:
- pass
- else:
- return params
diff --git a/acts_tests/acts_contrib/test_utils/coex/coex_test_utils.py b/acts_tests/acts_contrib/test_utils/coex/coex_test_utils.py
index 62e12af..a335f09 100644
--- a/acts_tests/acts_contrib/test_utils/coex/coex_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/coex/coex_test_utils.py
@@ -50,17 +50,17 @@
from acts_contrib.test_utils.car.car_telecom_utils import wait_for_not_in_call
from acts_contrib.test_utils.car.car_telecom_utils import wait_for_ringing
from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import run_multithread_func
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
from acts_contrib.test_utils.tel.tel_test_utils import setup_droid_properties
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
from acts_contrib.test_utils.wifi.wifi_power_test_utils import get_phone_ip
from acts_contrib.test_utils.wifi.wifi_test_utils import reset_wifi
from acts_contrib.test_utils.wifi.wifi_test_utils import wifi_connect
from acts_contrib.test_utils.wifi.wifi_test_utils import wifi_test_device_init
from acts_contrib.test_utils.wifi.wifi_test_utils import wifi_toggle_state
from acts.utils import exe_cmd
+from acts.libs.utils.multithread import run_multithread_func
from bokeh.layouts import column
from bokeh.models import tools as bokeh_tools
from bokeh.plotting import figure, output_file, save
diff --git a/acts_tests/acts_contrib/test_utils/gnss/GnssBlankingBase.py b/acts_tests/acts_contrib/test_utils/gnss/GnssBlankingBase.py
new file mode 100644
index 0000000..9fe9fa4
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/gnss/GnssBlankingBase.py
@@ -0,0 +1,505 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+from glob import glob
+from time import sleep
+from collections import namedtuple
+from numpy import arange
+from pandas import DataFrame
+from acts.signals import TestError
+from acts.signals import TestFailure
+from acts.logger import epoch_to_log_line_timestamp
+from acts.context import get_current_context
+from acts_contrib.test_utils.gnss import LabTtffTestBase as lttb
+from acts_contrib.test_utils.gnss.gnss_test_utils import launch_eecoexer
+from acts_contrib.test_utils.gnss.gnss_test_utils import excute_eecoexer_function
+from acts_contrib.test_utils.gnss.gnss_test_utils import start_gnss_by_gtw_gpstool
+from acts_contrib.test_utils.gnss.gnss_test_utils import get_current_epoch_time
+from acts_contrib.test_utils.gnss.gnss_test_utils import check_current_focus_app
+from acts_contrib.test_utils.gnss.gnss_test_utils import process_ttff_by_gtw_gpstool
+from acts_contrib.test_utils.gnss.gnss_test_utils import check_ttff_data
+from acts_contrib.test_utils.gnss.gnss_test_utils import process_gnss_by_gtw_gpstool
+from acts_contrib.test_utils.gnss.gnss_test_utils import start_pixel_logger
+from acts_contrib.test_utils.gnss.gnss_test_utils import stop_pixel_logger
+from acts_contrib.test_utils.gnss.dut_log_test_utils import start_diagmdlog_background
+from acts_contrib.test_utils.gnss.dut_log_test_utils import get_gpstool_logs
+from acts_contrib.test_utils.gnss.dut_log_test_utils import stop_background_diagmdlog
+from acts_contrib.test_utils.gnss.dut_log_test_utils import get_pixellogger_bcm_log
+from acts_contrib.test_utils.gnss.gnss_testlog_utils import parse_gpstool_ttfflog_to_df
+
+
+def range_wi_end(ad, start, stop, step):
+ """
+ Generate a list of data from start to stop with the step. The list includes start and stop value
+ and also supports floating point.
+ Args:
+ start: start value.
+ Type, int or float.
+ stop: stop value.
+ Type, int or float.
+ step: step value.
+ Type, int or float.
+ Returns:
+ range_ls: the list of data.
+ """
+ if step == 0:
+ ad.log.warn('Step is 0. Return empty list')
+ range_ls = []
+ else:
+ if start == stop:
+ range_ls = [stop]
+ else:
+ range_ls = list(arange(start, stop, step))
+ if len(range_ls) > 0:
+ if (step < 0 and range_ls[-1] > stop) or (step > 0 and
+ range_ls[-1] < stop):
+ range_ls.append(stop)
+ return range_ls
+
+
+def check_ttff_pe(ad, ttff_data, ttff_mode, pe_criteria):
+ """Verify all TTFF results from ttff_data.
+
+ Args:
+ ad: An AndroidDevice object.
+ ttff_data: TTFF data of secs, position error and signal strength.
+ ttff_mode: TTFF Test mode for current test item.
+ pe_criteria: Criteria for current test item.
+
+ """
+ ret = True
+ ad.log.info("%d iterations of TTFF %s tests finished." %
+ (len(ttff_data.keys()), ttff_mode))
+ ad.log.info("%s PASS criteria is %f meters" % (ttff_mode, pe_criteria))
+ ad.log.debug("%s TTFF data: %s" % (ttff_mode, ttff_data))
+
+ if len(ttff_data.keys()) == 0:
+ ad.log.error("GTW_GPSTool didn't process TTFF properly.")
+ raise TestFailure("GTW_GPSTool didn't process TTFF properly.")
+
+ if any(
+ float(ttff_data[key].ttff_pe) >= pe_criteria
+ for key in ttff_data.keys()):
+ ad.log.error("One or more TTFF %s are over test criteria %f meters" %
+ (ttff_mode, pe_criteria))
+ ret = False
+ else:
+ ad.log.info("All TTFF %s are within test criteria %f meters." %
+ (ttff_mode, pe_criteria))
+ ret = True
+ return ret
+
+
+class GnssBlankingBase(lttb.LabTtffTestBase):
+ """ LAB GNSS Cellular Coex Tx Power Sweep TTFF/FFPE Tests"""
+
+ def __init__(self, controllers):
+ """ Initializes class attributes. """
+ super().__init__(controllers)
+ self.eecoex_func = ''
+ self.start_pwr = 10
+ self.stop_pwr = 24
+ self.offset = 1
+ self.result_cell_pwr = 10
+ self.gsm_sweep_params = None
+ self.lte_tdd_pc3_sweep_params = None
+ self.lte_tdd_pc2_sweep_params = None
+ self.sa_sensitivity = -150
+ self.gnss_pwr_lvl_offset = -5
+ self.maskfile = None
+
+ def setup_class(self):
+ super().setup_class()
+ req_params = ['sa_sensitivity', 'gnss_pwr_lvl_offset']
+ self.unpack_userparams(req_param_names=req_params)
+ cell_sweep_params = self.user_params.get('cell_pwr_sweep', [])
+ self.gsm_sweep_params = cell_sweep_params.get("GSM", [10, 33, 1])
+ self.lte_tdd_pc3_sweep_params = cell_sweep_params.get(
+ "LTE_TDD_PC3", [10, 24, 1])
+ self.lte_tdd_pc2_sweep_params = cell_sweep_params.get(
+ "LTE_TDD_PC2", [10, 26, 1])
+ self.sa_sensitivity = self.user_params.get('sa_sensitivity', -150)
+ self.gnss_pwr_lvl_offset = self.user_params.get('gnss_pwr_lvl_offset', -5)
+
+ def setup_test(self):
+ super().setup_test()
+ launch_eecoexer(self.dut)
+
+ # Set DUT temperature the limit to 60 degree
+ self.dut.adb.shell(
+ 'setprop persist.com.google.eecoexer.cellular.temperature_limit 60')
+
+ # Get current context full path to create the log folder.
+ cur_test_item_dir = get_current_context().get_full_output_path()
+ self.gnss_log_path = os.path.join(self.log_path, cur_test_item_dir)
+ os.makedirs(self.gnss_log_path, exist_ok=True)
+
+ # Start GNSS chip log
+ if self.diag_option == "QCOM":
+ start_diagmdlog_background(self.dut, maskfile=self.maskfile)
+ else:
+ start_pixel_logger(self.dut)
+
+ def teardown_test(self):
+ super().teardown_test()
+ # Set gnss_vendor_log_path based on GNSS solution vendor.
+ gnss_vendor_log_path = os.path.join(self.gnss_log_path,
+ self.diag_option)
+ os.makedirs(gnss_vendor_log_path, exist_ok=True)
+
+ # Stop GNSS chip log and pull the logs to local file system.
+ if self.diag_option == "QCOM":
+ stop_background_diagmdlog(self.dut,
+ gnss_vendor_log_path,
+ keep_logs=False)
+ else:
+ stop_pixel_logger(self.dut)
+ self.log.info('Getting Pixel BCM Log!')
+ get_pixellogger_bcm_log(self.dut,
+ gnss_vendor_log_path,
+ keep_logs=False)
+
+ # Stop cellular Tx and close GPStool and EEcoexer APPs.
+ self.stop_cell_tx()
+ self.log.debug('Close GPStool APP')
+ self.dut.force_stop_apk("com.android.gpstool")
+ self.log.debug('Close EEcoexer APP')
+ self.dut.force_stop_apk("com.google.eecoexer")
+
+ def stop_cell_tx(self):
+ """
+ Stop EEcoexer Tx power.
+ """
+ # EEcoexer cellular stop Tx command.
+ stop_cell_tx_cmd = 'CELLR,19'
+
+ # Stop cellular Tx by EEcoexer.
+ self.log.info('Stop EEcoexer Test Command: {}'.format(stop_cell_tx_cmd))
+ excute_eecoexer_function(self.dut, stop_cell_tx_cmd)
+
+ def analysis_ttff_ffpe(self, ttff_data, json_tag=''):
+ """
+ Pull logs and parsing logs into json file.
+ Args:
+ ttff_data: ttff_data from test results.
+ Type, list.
+ json_tag: tag for parsed json file name.
+ Type, str.
+ """
+ # Create log directory.
+ gps_log_path = os.path.join(self.gnss_log_path,
+ 'Cell_Pwr_Sweep_Results')
+
+ # Pull logs of GTW GPStool.
+ get_gpstool_logs(self.dut, gps_log_path, False)
+
+ # Parsing the log of GTW GPStool into pandas dataframe.
+ target_log_name_regx = os.path.join(gps_log_path, 'GPSLogs', 'files',
+ 'GNSS_*')
+ self.log.info('Get GPStool logs from: {}'.format(target_log_name_regx))
+ gps_api_log_ls = glob(target_log_name_regx)
+ latest_gps_api_log = max(gps_api_log_ls, key=os.path.getctime)
+ self.log.info(
+ 'Get latest GPStool log is: {}'.format(latest_gps_api_log))
+ try:
+ df_ttff_ffpe = DataFrame(
+ parse_gpstool_ttfflog_to_df(latest_gps_api_log))
+
+ # Add test case, TTFF and FFPE data into the dataframe.
+ ttff_dict = {}
+ for i in ttff_data:
+ data = ttff_data[i]._asdict()
+ ttff_dict[i] = dict(data)
+ ttff_time = []
+ ttff_pe = []
+ test_case = []
+ for value in ttff_dict.values():
+ ttff_time.append(value['ttff_sec'])
+ ttff_pe.append(value['ttff_pe'])
+ test_case.append(json_tag)
+ self.log.info('test_case length {}'.format(str(len(test_case))))
+
+ df_ttff_ffpe['test_case'] = test_case
+ df_ttff_ffpe['ttff_sec'] = ttff_time
+ df_ttff_ffpe['ttff_pe'] = ttff_pe
+ json_file = 'gps_log_{}.json'.format(json_tag)
+ json_path = os.path.join(gps_log_path, json_file)
+ # Save dataframe into json file.
+ df_ttff_ffpe.to_json(json_path, orient='table', index=False)
+ except ValueError:
+ self.log.warning('Can\'t create the parsed the log data in file.')
+
+ def gnss_hot_start_ttff_ffpe_test(self,
+ iteration,
+ sweep_enable=False,
+ json_tag=''):
+ """
+ GNSS hot start ttff ffpe tset
+
+ Args:
+ iteration: hot start TTFF test iteration.
+ Type, int.
+ Default, 1.
+ sweep_enable: Indicator for the function to check if it is run by cell_power_sweep()
+ Type, bool.
+ Default, False.
+ json_tag: if the function is run by cell_power_sweep(), the function would use
+ this as a part of file name to save TTFF and FFPE results into json file.
+ Type, str.
+ Default, ''.
+ Raise:
+ TestError: fail to send TTFF start_test_action.
+ """
+ # Start GTW GPStool.
+ test_type = namedtuple('Type', ['command', 'criteria'])
+ test_type_ttff = test_type('Hot Start', self.hs_ttff_criteria)
+ test_type_pe = test_type('Hot Start', self.hs_ttff_pecriteria)
+ self.dut.log.info("Restart GTW GPSTool")
+ start_gnss_by_gtw_gpstool(self.dut, state=True)
+
+ # Get current time and convert to human readable format
+ begin_time = get_current_epoch_time()
+ log_begin_time = epoch_to_log_line_timestamp(begin_time)
+ self.dut.log.debug('Start time is {}'.format(log_begin_time))
+
+ # Run hot start TTFF
+ for i in range(3):
+ self.log.info('Start hot start attempt %d' % (i + 1))
+ self.dut.adb.shell(
+ "am broadcast -a com.android.gpstool.ttff_action "
+ "--es ttff hs --es cycle {} --ez raninterval False".format(
+ iteration))
+ sleep(1)
+ if self.dut.search_logcat(
+ "act=com.android.gpstool.start_test_action", begin_time):
+ self.dut.log.info("Send TTFF start_test_action successfully.")
+ break
+ else:
+ check_current_focus_app(self.dut)
+ raise TestError("Fail to send TTFF start_test_action.")
+
+ # Verify hot start TTFF results
+ ttff_data = process_ttff_by_gtw_gpstool(self.dut, begin_time,
+ self.simulator_location)
+
+ # Stop GTW GPSTool
+ self.dut.log.info("Stop GTW GPSTool")
+ start_gnss_by_gtw_gpstool(self.dut, state=False)
+
+ if sweep_enable:
+ self.analysis_ttff_ffpe(ttff_data, json_tag)
+
+ result_ttff = check_ttff_data(self.dut,
+ ttff_data,
+ ttff_mode=test_type_ttff.command,
+ criteria=test_type_ttff.criteria)
+ result_pe = check_ttff_pe(self.dut,
+ ttff_data,
+ ttff_mode=test_type_pe.command,
+ pe_criteria=test_type_pe.criteria)
+ if not result_ttff or not result_pe:
+ self.dut.log.warning('%s TTFF fails to reach '
+ 'designated criteria' % test_type_ttff.command)
+ self.dut.log.info("Stop GTW GPSTool")
+ return False
+
+ return True
+
+ def hot_start_gnss_power_sweep(self,
+ start_pwr,
+ stop_pwr,
+ offset,
+ wait,
+ iteration=1,
+ sweep_enable=False,
+ title=''):
+ """
+ GNSS simulator power sweep of hot start test.
+
+ Args:
+ start_pwr: GNSS simulator power sweep start power level.
+ Type, int.
+ stop_pwr: GNSS simulator power sweep stop power level.
+ Type, int.
+ offset: GNSS simulator power sweep offset
+ Type, int.
+ wait: Wait time before the power sweep.
+ Type, int.
+ iteration: The iteration times of hot start test.
+ Type, int.
+ Default, 1.
+ sweep_enable: Indicator for power sweep.
+ It will be True only in GNSS sensitivity search case.
+ Type, bool.
+ Defaule, False.
+ title: the target log folder title for GNSS sensitivity search test items.
+ Type, str.
+ Default, ''.
+ """
+
+ # Calculate loop range list from gnss_simulator_power_level and sa_sensitivity
+ range_ls = range_wi_end(self.dut, start_pwr, stop_pwr, offset)
+ sweep_range = ','.join([str(x) for x in range_ls])
+
+ self.log.debug(
+ 'Start the GNSS simulator power sweep. The sweep range is [{}]'.
+ format(sweep_range))
+
+ if sweep_enable:
+ self.start_gnss_and_wait(wait)
+ else:
+ self.dut.log.info('Wait %d seconds to start TTFF HS' % wait)
+ sleep(wait)
+
+ # Sweep GNSS simulator power level in range_ls.
+ # Do hot start for every power level.
+ # Check the TTFF result if it can pass the criteria.
+ gnss_pwr_lvl = -130
+ for gnss_pwr_lvl in range_ls:
+
+ # Set GNSS Simulator power level
+ self.log.info('Set GNSS simulator power level to %.1f' %
+ gnss_pwr_lvl)
+ self.gnss_simulator.set_power(gnss_pwr_lvl)
+ json_tag = title + '_gnss_pwr_' + str(gnss_pwr_lvl)
+
+ # GNSS hot start test
+ if not self.gnss_hot_start_ttff_ffpe_test(iteration, sweep_enable,
+ json_tag):
+ sensitivity = gnss_pwr_lvl - offset
+ return False, sensitivity
+ return True, gnss_pwr_lvl
+
+ def gnss_init_power_setting(self, first_wait=180):
+ """
+ GNSS initial power level setting.
+ Args:
+ first_wait: wait time after the cold start.
+ Type, int.
+ Default, 180.
+ Returns:
+ True if the process is done successully and hot start results pass criteria.
+ Raise:
+ TestFailure: fail TTFF test criteria.
+ """
+
+ # Start and set GNSS simulator
+ self.start_and_set_gnss_simulator_power()
+
+ # Start 1st time cold start to obtain ephemeris
+ process_gnss_by_gtw_gpstool(self.dut, self.test_types['cs'].criteria)
+
+ self.hot_start_gnss_power_sweep(self.gnss_simulator_power_level,
+ self.sa_sensitivity,
+ self.gnss_pwr_lvl_offset, first_wait)
+
+ return True
+
+ def start_gnss_and_wait(self, wait=60):
+ """
+ The process of enable gnss and spend the wait time for GNSS to
+ gather enoung information that make sure the stability of testing.
+
+ Args:
+ wait: wait time between power sweep.
+ Type, int.
+ Default, 60.
+ """
+ # Create log path for waiting section logs of GPStool.
+ gnss_wait_log_dir = os.path.join(self.gnss_log_path, 'GNSS_wait')
+
+ # Enable GNSS to receive satellites' signals for "wait_between_pwr" seconds.
+ self.log.info('Enable GNSS for searching satellites')
+ start_gnss_by_gtw_gpstool(self.dut, state=True)
+ self.log.info('Wait for {} seconds'.format(str(wait)))
+ sleep(wait)
+
+ # Stop GNSS and pull the logs.
+ start_gnss_by_gtw_gpstool(self.dut, state=False)
+ get_gpstool_logs(self.dut, gnss_wait_log_dir, False)
+
+ def cell_power_sweep(self):
+ """
+ Linear search cellular power level. Doing GNSS hot start with cellular coexistence
+ and checking if hot start can pass hot start criteria or not.
+
+ Returns: final power level of cellular power
+ """
+ # Get parameters from user params.
+ ttft_iteration = self.user_params.get('ttff_iteration', 25)
+ wait_before_test = self.user_params.get('wait_before_test', 60)
+ wait_between_pwr = self.user_params.get('wait_between_pwr', 60)
+ power_th = self.start_pwr
+
+ # Generate the power sweep list.
+ power_search_ls = range_wi_end(self.dut, self.start_pwr, self.stop_pwr,
+ self.offset)
+
+ # Set GNSS simulator power level.
+ self.gnss_simulator.set_power(self.sa_sensitivity)
+
+ # Create gnss log folders for init and cellular sweep
+ gnss_init_log_dir = os.path.join(self.gnss_log_path, 'GNSS_init')
+
+ # Pull all exist GPStool logs into GNSS_init folder
+ get_gpstool_logs(self.dut, gnss_init_log_dir, False)
+
+ if power_search_ls:
+ # Run the cellular and GNSS coexistence test item.
+ for i, pwr_lvl in enumerate(power_search_ls):
+ self.log.info('Cellular power sweep loop: {}'.format(int(i)))
+ self.log.info('Cellular target power: {}'.format(int(pwr_lvl)))
+
+ # Enable GNSS to receive satellites' signals for "wait_between_pwr" seconds.
+ # Wait more time before 1st power level
+ if i == 0:
+ wait = wait_before_test
+ else:
+ wait = wait_between_pwr
+ self.start_gnss_and_wait(wait)
+
+ # Set cellular Tx power level.
+ eecoex_cmd = self.eecoex_func.format(str(pwr_lvl))
+ eecoex_cmd_file_str = eecoex_cmd.replace(',', '_')
+ excute_eecoexer_function(self.dut, eecoex_cmd)
+
+ # Get the last power level that can pass hots start ttff/ffpe spec.
+ if self.gnss_hot_start_ttff_ffpe_test(ttft_iteration, True,
+ eecoex_cmd_file_str):
+ if i + 1 == len(power_search_ls):
+ power_th = pwr_lvl
+ else:
+ if i == 0:
+ power_th = self.start_pwr
+ else:
+ power_th = power_search_ls[i - 1]
+
+ # Stop cellular Tx after a test cycle.
+ self.stop_cell_tx()
+
+ else:
+ # Run the stand alone test item.
+ self.start_gnss_and_wait(wait_between_pwr)
+
+ eecoex_cmd_file_str = 'no_cellular_coex'
+ self.gnss_hot_start_ttff_ffpe_test(ttft_iteration, True,
+ eecoex_cmd_file_str)
+
+ self.log.info('The GNSS WWAN coex celluar Tx power is {}'.format(
+ str(power_th)))
+
+ return power_th
diff --git a/acts_tests/acts_contrib/test_utils/gnss/LabTtffTestBase.py b/acts_tests/acts_contrib/test_utils/gnss/LabTtffTestBase.py
new file mode 100644
index 0000000..6a6bd5d
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/gnss/LabTtffTestBase.py
@@ -0,0 +1,349 @@
+#!/usr/bin/env python3
+#
+# Copyright 2020 - 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 time
+import glob
+import errno
+from collections import namedtuple
+from pandas import DataFrame
+from acts import utils
+from acts import signals
+from acts.base_test import BaseTestClass
+from acts.controllers.gnss_lib import GnssSimulator
+from acts.context import get_current_context
+from acts_contrib.test_utils.gnss import dut_log_test_utils as diaglog
+from acts_contrib.test_utils.gnss import gnss_test_utils as gutils
+from acts_contrib.test_utils.gnss import gnss_testlog_utils as glogutils
+from acts_contrib.test_utils.gnss.gnss_defines import DEVICE_GPSLOG_FOLDER
+from acts_contrib.test_utils.gnss.gnss_defines import GPS_PKG_NAME
+from acts_contrib.test_utils.gnss.gnss_defines import BCM_GPS_XML_PATH
+
+
+class LabTtffTestBase(BaseTestClass):
+ """ LAB TTFF Tests Base Class"""
+ GTW_GPSTOOL_APP = 'gtw_gpstool_apk'
+ GNSS_SIMULATOR_KEY = 'gnss_simulator'
+ GNSS_SIMULATOR_IP_KEY = 'gnss_simulator_ip'
+ GNSS_SIMULATOR_PORT_KEY = 'gnss_simulator_port'
+ GNSS_SIMULATOR_PORT_CTRL_KEY = 'gnss_simulator_port_ctrl'
+ GNSS_SIMULATOR_SCENARIO_KEY = 'gnss_simulator_scenario'
+ GNSS_SIMULATOR_POWER_LEVEL_KEY = 'gnss_simulator_power_level'
+ CUSTOM_FILES_KEY = 'custom_files'
+ CSTTFF_CRITERIA = 'cs_criteria'
+ HSTTFF_CRITERIA = 'hs_criteria'
+ WSTTFF_CRITERIA = 'ws_criteria'
+ CSTTFF_PECRITERIA = 'cs_ttff_pecriteria'
+ HSTTFF_PECRITERIA = 'hs_ttff_pecriteria'
+ WSTTFF_PECRITERIA = 'ws_ttff_pecriteria'
+ TTFF_ITERATION = 'ttff_iteration'
+ SIMULATOR_LOCATION = 'simulator_location'
+ DIAG_OPTION = 'diag_option'
+
+ def __init__(self, controllers):
+ """ Initializes class attributes. """
+
+ super().__init__(controllers)
+
+ self.dut = None
+ self.gnss_simulator = None
+ self.rockbottom_script = None
+ self.gnss_log_path = self.log_path
+ self.gps_xml_bk_path = BCM_GPS_XML_PATH + '.bk'
+
+ def setup_class(self):
+ super().setup_class()
+
+ req_params = [
+ self.GNSS_SIMULATOR_KEY, self.GNSS_SIMULATOR_IP_KEY,
+ self.GNSS_SIMULATOR_PORT_KEY, self.GNSS_SIMULATOR_SCENARIO_KEY,
+ self.GNSS_SIMULATOR_POWER_LEVEL_KEY, self.CSTTFF_CRITERIA,
+ self.HSTTFF_CRITERIA, self.WSTTFF_CRITERIA, self.TTFF_ITERATION,
+ self.SIMULATOR_LOCATION, self.DIAG_OPTION
+ ]
+
+ self.unpack_userparams(req_param_names=req_params)
+ self.dut = self.android_devices[0]
+ self.gnss_simulator_scenario = self.user_params[
+ self.GNSS_SIMULATOR_SCENARIO_KEY]
+ self.gnss_simulator_power_level = self.user_params[
+ self.GNSS_SIMULATOR_POWER_LEVEL_KEY]
+ self.gtw_gpstool_app = self.user_params[self.GTW_GPSTOOL_APP]
+ custom_files = self.user_params.get(self.CUSTOM_FILES_KEY, [])
+ self.cs_ttff_criteria = self.user_params.get(self.CSTTFF_CRITERIA, [])
+ self.hs_ttff_criteria = self.user_params.get(self.HSTTFF_CRITERIA, [])
+ self.ws_ttff_criteria = self.user_params.get(self.WSTTFF_CRITERIA, [])
+ self.cs_ttff_pecriteria = self.user_params.get(self.CSTTFF_PECRITERIA,
+ [])
+ self.hs_ttff_pecriteria = self.user_params.get(self.HSTTFF_PECRITERIA,
+ [])
+ self.ws_ttff_pecriteria = self.user_params.get(self.WSTTFF_PECRITERIA,
+ [])
+ self.ttff_iteration = self.user_params.get(self.TTFF_ITERATION, [])
+ self.simulator_location = self.user_params.get(self.SIMULATOR_LOCATION,
+ [])
+ self.diag_option = self.user_params.get(self.DIAG_OPTION, [])
+
+ # Create gnss_simulator instance
+ gnss_simulator_key = self.user_params[self.GNSS_SIMULATOR_KEY]
+ gnss_simulator_ip = self.user_params[self.GNSS_SIMULATOR_IP_KEY]
+ gnss_simulator_port = self.user_params[self.GNSS_SIMULATOR_PORT_KEY]
+ if gnss_simulator_key == 'gss7000':
+ gnss_simulator_port_ctrl = self.user_params[
+ self.GNSS_SIMULATOR_PORT_CTRL_KEY]
+ else:
+ gnss_simulator_port_ctrl = None
+ self.gnss_simulator = GnssSimulator.AbstractGnssSimulator(
+ gnss_simulator_key, gnss_simulator_ip, gnss_simulator_port,
+ gnss_simulator_port_ctrl)
+
+ test_type = namedtuple('Type', ['command', 'criteria'])
+ self.test_types = {
+ 'cs': test_type('Cold Start', self.cs_ttff_criteria),
+ 'ws': test_type('Warm Start', self.ws_ttff_criteria),
+ 'hs': test_type('Hot Start', self.hs_ttff_criteria)
+ }
+
+ # Unpack the rockbottom script file if its available.
+ for file in custom_files:
+ if 'rockbottom_' + self.dut.model in file:
+ self.rockbottom_script = file
+ break
+
+ def setup_test(self):
+
+ self.clear_gps_log()
+ self.gnss_simulator.stop_scenario()
+ self.gnss_simulator.close()
+ if self.rockbottom_script:
+ self.log.info('Running rockbottom script for this device ' +
+ self.dut.model)
+ self.dut_rockbottom()
+ else:
+ self.log.info('Not running rockbottom for this device ' +
+ self.dut.model)
+
+ utils.set_location_service(self.dut, True)
+ gutils.reinstall_package_apk(self.dut, GPS_PKG_NAME,
+ self.gtw_gpstool_app)
+
+ # For BCM DUTs, delete gldata.sto and set IgnoreRomAlm="true" based on b/196936791#comment20
+ if self.diag_option == "BCM":
+ gutils.remount_device(self.dut)
+ # Backup gps.xml
+ copy_cmd = "cp {} {}".format(BCM_GPS_XML_PATH, self.gps_xml_bk_path)
+ self.dut.adb.shell(copy_cmd)
+ gutils.delete_bcm_nvmem_sto_file(self.dut)
+ gutils.bcm_gps_ignore_rom_alm(self.dut)
+ # Reboot DUT to apply the setting
+ gutils.reboot(self.dut)
+ self.gnss_simulator.connect()
+
+ def dut_rockbottom(self):
+ """
+ Set the dut to rockbottom state
+
+ """
+ # The rockbottom script might include a device reboot, so it is
+ # necessary to stop SL4A during its execution.
+ self.dut.stop_services()
+ self.log.info('Executing rockbottom script for ' + self.dut.model)
+ os.chmod(self.rockbottom_script, 0o777)
+ os.system('{} {}'.format(self.rockbottom_script, self.dut.serial))
+ # Make sure the DUT is in root mode after coming back
+ self.dut.root_adb()
+ # Restart SL4A
+ self.dut.start_services()
+
+ def teardown_test(self):
+ """Teardown settings for the test class"""
+ super().teardown_test()
+ # Restore the gps.xml everytime after the test.
+ if self.diag_option == "BCM":
+ # Restore gps.xml
+ rm_cmd = "rm -rf {}".format(BCM_GPS_XML_PATH)
+ restore_cmd = "mv {} {}".format(self.gps_xml_bk_path,
+ BCM_GPS_XML_PATH)
+ self.dut.adb.shell(rm_cmd)
+ self.dut.adb.shell(restore_cmd)
+
+ def teardown_class(self):
+ """ Executed after completing all selected test cases."""
+ self.clear_gps_log()
+ if self.gnss_simulator:
+ self.gnss_simulator.stop_scenario()
+ self.gnss_simulator.close()
+
+ def start_and_set_gnss_simulator_power(self):
+ """
+ Start GNSS simulator secnario and set power level.
+
+ """
+
+ self.gnss_simulator.start_scenario(self.gnss_simulator_scenario)
+ time.sleep(25)
+ self.gnss_simulator.set_power(self.gnss_simulator_power_level)
+
+ def get_and_verify_ttff(self, mode):
+ """Retrieve ttff with designate mode.
+
+ Args:
+ mode: A string for identify gnss test mode.
+ """
+ if mode not in self.test_types:
+ raise signals.TestError('Unrecognized mode %s' % mode)
+ test_type = self.test_types.get(mode)
+
+ if mode != 'cs':
+ wait_time = 900
+ else:
+ wait_time = 300
+
+ gutils.process_gnss_by_gtw_gpstool(self.dut,
+ self.test_types['cs'].criteria)
+ begin_time = gutils.get_current_epoch_time()
+ gutils.start_ttff_by_gtw_gpstool(self.dut,
+ ttff_mode=mode,
+ iteration=self.ttff_iteration,
+ raninterval=True,
+ hot_warm_sleep=wait_time)
+ # Since Wear takes little longer to update the TTFF info.
+ # Workround to solve the wearable timing issue
+ if gutils.is_device_wearable(self.dut):
+ time.sleep(20)
+
+ ttff_data = gutils.process_ttff_by_gtw_gpstool(self.dut, begin_time,
+ self.simulator_location)
+
+ # Create folder for GTW GPStool's log
+ gps_log_path = os.path.join(self.gnss_log_path, 'GPSLogs')
+ os.makedirs(gps_log_path, exist_ok=True)
+
+ self.dut.adb.pull("{} {}".format(DEVICE_GPSLOG_FOLDER, gps_log_path))
+
+ gps_api_log = glob.glob(gps_log_path + '/*/GNSS_*.txt')
+ ttff_loop_log = glob.glob(gps_log_path +
+ '/*/GPS_{}_*.txt'.format(mode.upper()))
+
+ if not gps_api_log and ttff_loop_log:
+ raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT),
+ gps_log_path)
+
+ df = DataFrame(glogutils.parse_gpstool_ttfflog_to_df(gps_api_log[0]))
+
+ ttff_dict = {}
+ for i in ttff_data:
+ d = ttff_data[i]._asdict()
+ ttff_dict[i] = dict(d)
+
+ ttff_time = []
+ ttff_pe = []
+ ttff_haccu = []
+ for i in ttff_dict.keys():
+ ttff_time.append(ttff_dict[i]['ttff_sec'])
+ ttff_pe.append(ttff_dict[i]['ttff_pe'])
+ ttff_haccu.append(ttff_dict[i]['ttff_haccu'])
+ df['ttff_sec'] = ttff_time
+ df['ttff_pe'] = ttff_pe
+ df['ttff_haccu'] = ttff_haccu
+ df.to_json(gps_log_path + '/gps_log.json', orient='table')
+ result = gutils.check_ttff_data(self.dut,
+ ttff_data,
+ ttff_mode=test_type.command,
+ criteria=test_type.criteria)
+ if not result:
+ raise signals.TestFailure('%s TTFF fails to reach '
+ 'designated criteria' % test_type.command)
+ return ttff_data
+
+ def verify_pe(self, mode):
+ """
+ Verify ttff Position Error with designate mode.
+
+ Args:
+ mode: A string for identify gnss test mode.
+ """
+
+ ffpe_type = namedtuple('Type', ['command', 'pecriteria'])
+ ffpe_types = {
+ 'cs': ffpe_type('Cold Start', self.cs_ttff_pecriteria),
+ 'ws': ffpe_type('Warm Start', self.ws_ttff_pecriteria),
+ 'hs': ffpe_type('Hot Start', self.hs_ttff_pecriteria)
+ }
+
+ if mode not in ffpe_types:
+ raise signals.TestError('Unrecognized mode %s' % mode)
+ test_type = ffpe_types.get(mode)
+
+ ttff_data = self.get_and_verify_ttff(mode)
+ result = gutils.check_ttff_pe(self.dut,
+ ttff_data,
+ ttff_mode=test_type.command,
+ pe_criteria=test_type.pecriteria)
+ if not result:
+ raise signals.TestFailure('%s TTFF fails to reach '
+ 'designated criteria' % test_type.command)
+ return ttff_data
+
+ def clear_gps_log(self):
+ """
+ Delete the existing GPS GTW Log from DUT.
+
+ """
+ self.dut.adb.shell("rm -rf {}".format(DEVICE_GPSLOG_FOLDER))
+
+ def gnss_ttff_ffpe(self, mode, sub_context_path=''):
+ """
+ Base ttff and ffpe function
+ Args:
+ mode: Set the TTFF mode for testing. Definitions are as below.
+ cs(cold start), ws(warm start), hs(hot start)
+ sub_context_path: Set specifc log pathfor ttff_ffpe
+ """
+ # Create log file path
+ full_output_path = get_current_context().get_full_output_path()
+ self.gnss_log_path = os.path.join(full_output_path, sub_context_path)
+ os.makedirs(self.gnss_log_path, exist_ok=True)
+ self.log.debug('Create log path: {}'.format(self.gnss_log_path))
+
+ # Start and set GNSS simulator
+ self.start_and_set_gnss_simulator_power()
+
+ # Start GNSS chip log
+ if self.diag_option == "QCOM":
+ diaglog.start_diagmdlog_background(self.dut, maskfile=self.maskfile)
+ else:
+ gutils.start_pixel_logger(self.dut)
+
+ # Start verifying TTFF and FFPE
+ self.verify_pe(mode)
+
+ # Set gnss_vendor_log_path based on GNSS solution vendor
+ gnss_vendor_log_path = os.path.join(self.gnss_log_path,
+ self.diag_option)
+ os.makedirs(gnss_vendor_log_path, exist_ok=True)
+
+ # Stop GNSS chip log and pull the logs to local file system
+ if self.diag_option == "QCOM":
+ diaglog.stop_background_diagmdlog(self.dut,
+ gnss_vendor_log_path,
+ keep_logs=False)
+ else:
+ gutils.stop_pixel_logger(self.dut)
+ self.log.info('Getting Pixel BCM Log!')
+ diaglog.get_pixellogger_bcm_log(self.dut,
+ gnss_vendor_log_path,
+ keep_logs=False)
diff --git a/acts_tests/acts_contrib/test_utils/gnss/dut_log_test_utils.py b/acts_tests/acts_contrib/test_utils/gnss/dut_log_test_utils.py
index a685b65..cba71f1 100644
--- a/acts_tests/acts_contrib/test_utils/gnss/dut_log_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/gnss/dut_log_test_utils.py
@@ -18,12 +18,14 @@
import time
import errno
+
DEVICE_CFG_FOLDER = "/data/vendor/radio/diag_logs/cfg/"
DEVICE_DIAGMDLOG_FOLDER = "/data/vendor/radio/diag_logs/logs/"
MDLOG_SETTLING_TIME = 2
MDLOG_PROCESS_KILL_TIME = 3
NOHUP_CMD = "nohup diag_mdlog -f {} -o {} -s 100 -c &> /dev/null &"
DEVICE_GPSLOG_FOLDER = '/sdcard/Android/data/com.android.gpstool/files/'
+DEVICE_PIXEL_LOGGER_FOLDER = '/sdcard/Android/data/com.android.pixellogger/files/logs/gps/'
def find_device_qxdm_log_mask(ad, maskfile):
@@ -169,9 +171,30 @@
"""
gps_log_path = os.path.join(local_logpath, 'GPSLogs')
+ os.makedirs(gps_log_path, exist_ok=True)
ad.adb.pull("{} {}".format(DEVICE_GPSLOG_FOLDER, gps_log_path))
ad.log.debug("gpstool logs are pulled from device")
if not keep_logs:
- ad.adb.shell("rm -rf " + DEVICE_GPSLOG_FOLDER + "*.*")
- ad.log.debug("gpstool logs are deleted from device")
\ No newline at end of file
+ gpstool_log_path = os.path.join(DEVICE_GPSLOG_FOLDER, "*")
+ ad.adb.shell("rm -rf " + gpstool_log_path)
+ ad.log.debug("gpstool logs are deleted from device")
+
+def get_pixellogger_bcm_log(ad, local_logpath, keep_logs=True):
+ """
+
+ Pulls BCM Logs from android device
+
+ Args:
+ ad: the target android device, AndroidDevice object
+ local_logpath: Local file path to pull the gpstool logs
+ keep_logs: False, delete log files from the gpstool log path
+ """
+
+ ad.adb.pull("{} {}".format(DEVICE_PIXEL_LOGGER_FOLDER, local_logpath))
+ ad.log.debug("pixellogger logs are pulled from device")
+
+ if not keep_logs:
+ bcm_log_path = os.path.join(DEVICE_PIXEL_LOGGER_FOLDER, "*")
+ ad.adb.shell("rm -rf " + bcm_log_path)
+ ad.log.debug("pixellogger logs are deleted from device")
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/gnss/gnss_defines.py b/acts_tests/acts_contrib/test_utils/gnss/gnss_defines.py
new file mode 100644
index 0000000..24eef0f
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/gnss/gnss_defines.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+DEVICE_GPSLOG_FOLDER = '/sdcard/Android/data/com.android.gpstool/files/'
+GPS_PKG_NAME = 'com.android.gpstool'
+BCM_GPS_XML_PATH = '/vendor/etc/gnss/gps.xml'
+BCM_NVME_STO_PATH = '/data/vendor/gps/gldata.sto'
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/gnss/gnss_test_utils.py b/acts_tests/acts_contrib/test_utils/gnss/gnss_test_utils.py
index 565f014..5efa817 100644
--- a/acts_tests/acts_contrib/test_utils/gnss/gnss_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/gnss/gnss_test_utils.py
@@ -22,7 +22,10 @@
import fnmatch
import posixpath
import tempfile
+import zipfile
from collections import namedtuple
+from datetime import datetime
+from xml.etree import ElementTree
from acts import utils
from acts import asserts
@@ -33,11 +36,14 @@
from acts.controllers.android_device import DEFAULT_QXDM_LOG_PATH
from acts.controllers.android_device import SL4A_APK_NAME
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from acts_contrib.test_utils.tel import tel_logging_utils as tlutils
from acts_contrib.test_utils.tel import tel_test_utils as tutils
from acts_contrib.test_utils.instrumentation.device.command.instrumentation_command_builder import InstrumentationCommandBuilder
from acts_contrib.test_utils.instrumentation.device.command.instrumentation_command_builder import InstrumentationTestCommandBuilder
from acts.utils import get_current_epoch_time
from acts.utils import epoch_to_human_time
+from acts_contrib.test_utils.gnss.gnss_defines import BCM_GPS_XML_PATH
+from acts_contrib.test_utils.gnss.gnss_defines import BCM_NVME_STO_PATH
WifiEnums = wutils.WifiEnums
PULL_TIMEOUT = 300
@@ -46,7 +52,7 @@
QXDM_MASKS = ["GPS.cfg", "GPS-general.cfg", "default.cfg"]
TTFF_REPORT = namedtuple(
"TTFF_REPORT", "utc_time ttff_loop ttff_sec ttff_pe ttff_ant_cn "
- "ttff_base_cn")
+ "ttff_base_cn ttff_haccu")
TRACK_REPORT = namedtuple(
"TRACK_REPORT", "l5flag pe ant_top4cn ant_cn base_top4cn base_cn")
LOCAL_PROP_FILE_CONTENTS = """\
@@ -88,6 +94,11 @@
NORMAL_PSDS_SERVER="http://"
REALTIME_PSDS_SERVER="http://"
"""
+DISABLE_LTO_FILE_CONTENTS_R = """\
+XTRA_SERVER_1="http://"
+XTRA_SERVER_2="http://"
+XTRA_SERVER_3="http://"
+"""
class GnssTestUtilsError(Exception):
@@ -120,7 +131,7 @@
ad.log.info("Reboot device to make changes take effect.")
ad.reboot()
ad.unlock_screen(password=None)
- if not int(ad.adb.shell("settings get global mobile_data")) == 1:
+ if not is_mobile_data_on(ad):
set_mobile_data(ad, True)
utils.sync_device_time(ad)
@@ -184,7 +195,7 @@
"--es package com.google.android.location --es user \* "
"--esa flags %s --esa values %s --esa types %s "
"com.google.android.gms" % (flag, value, type))
- ad.adb.shell(cmd)
+ ad.adb.shell(cmd, ignore_status=True)
ad.adb.shell("am force-stop com.google.android.gms")
ad.adb.shell("am broadcast -a com.google.android.gms.INITIALIZE")
@@ -210,7 +221,9 @@
remount_device(ad)
ad.log.info("Enable SUPL mode.")
ad.adb.shell("echo -e '\nSUPL_MODE=1' >> /etc/gps_debug.conf")
- if not check_chipset_vendor_by_qualcomm(ad):
+ if is_device_wearable(ad):
+ lto_mode_wearable(ad, True)
+ elif not check_chipset_vendor_by_qualcomm(ad):
lto_mode(ad, True)
else:
reboot(ad)
@@ -225,7 +238,9 @@
remount_device(ad)
ad.log.info("Disable SUPL mode.")
ad.adb.shell("echo -e '\nSUPL_MODE=0' >> /etc/gps_debug.conf")
- if not check_chipset_vendor_by_qualcomm(ad):
+ if is_device_wearable(ad):
+ lto_mode_wearable(ad, True)
+ elif not check_chipset_vendor_by_qualcomm(ad):
lto_mode(ad, True)
else:
reboot(ad)
@@ -238,7 +253,9 @@
ad: An AndroidDevice object.
"""
ad.root_adb()
- if check_chipset_vendor_by_qualcomm(ad):
+ if is_device_wearable(ad):
+ lto_mode_wearable(ad, False)
+ elif check_chipset_vendor_by_qualcomm(ad):
ad.log.info("Disable XTRA-daemon until next reboot.")
ad.adb.shell("killall xtra-daemon", ignore_status=True)
else:
@@ -267,10 +284,14 @@
"""
enable_gnss_verbose_logging(ad)
enable_compact_and_particle_fusion_log(ad)
+ prepare_gps_overlay(ad)
if check_chipset_vendor_by_qualcomm(ad):
disable_xtra_throttle(ad)
enable_supl_mode(ad)
- ad.adb.shell("settings put system screen_off_timeout 1800000")
+ if is_device_wearable(ad):
+ ad.adb.shell("settings put global stay_on_while_plugged_in 7")
+ else:
+ ad.adb.shell("settings put system screen_off_timeout 1800000")
wutils.wifi_toggle_state(ad, False)
ad.log.info("Setting Bluetooth state to False")
ad.droid.bluetoothToggleState(False)
@@ -279,6 +300,61 @@
disable_private_dns_mode(ad)
reboot(ad)
init_gtw_gpstool(ad)
+ if not is_mobile_data_on(ad):
+ set_mobile_data(ad, True)
+
+
+def prepare_gps_overlay(ad):
+ """Set pixellogger gps log mask to
+ resolve gps logs unreplayable from brcm vendor
+ """
+ if not check_chipset_vendor_by_qualcomm(ad):
+ overlay_file = "/data/vendor/gps/overlay/gps_overlay.xml"
+ xml_file = generate_gps_overlay_xml(ad)
+ try:
+ ad.log.info("Push gps_overlay to device")
+ ad.adb.push(xml_file, overlay_file)
+ ad.adb.shell(f"chmod 777 {overlay_file}")
+ finally:
+ xml_folder = os.path.abspath(os.path.join(xml_file, os.pardir))
+ shutil.rmtree(xml_folder)
+
+
+def generate_gps_overlay_xml(ad):
+ """For r11 devices, the overlay setting is 'Replayable default'
+ For other brcm devices, the setting is 'Replayable debug'
+
+ Returns:
+ path to the xml file
+ """
+ root_attrib = {
+ "xmlns": "http://www.glpals.com/",
+ "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
+ "xsi:schemaLocation": "http://www.glpals.com/ glconfig.xsd",
+ }
+ sub_attrib = {"EnableOnChipStopNotification": "true"}
+ if not is_device_wearable(ad):
+ sub_attrib["LogPriMask"] = "LOG_DEBUG"
+ sub_attrib["LogFacMask"] = "LOG_GLLIO | LOG_GLLAPI | LOG_NMEA | LOG_RAWDATA"
+ sub_attrib["OnChipLogPriMask"] = "LOG_DEBUG"
+ sub_attrib["OnChipLogFacMask"] = "LOG_GLLIO | LOG_GLLAPI | LOG_NMEA | LOG_RAWDATA"
+
+ temp_path = tempfile.mkdtemp()
+ xml_file = os.path.join(temp_path, "gps_overlay.xml")
+
+ root = ElementTree.Element('glgps')
+ for key, value in root_attrib.items():
+ root.attrib[key] = value
+
+ ad.log.debug("Sub attrib is %s", sub_attrib)
+
+ sub = ElementTree.SubElement(root, 'gll')
+ for key, value in sub_attrib.items():
+ sub.attrib[key] = value
+
+ xml = ElementTree.ElementTree(root)
+ xml.write(xml_file, xml_declaration=True, encoding="utf-8", method="xml")
+ return xml_file
def connect_to_wifi_network(ad, network):
@@ -323,6 +399,7 @@
"""
remount_device(ad)
utils.set_location_service(ad, True)
+ ad.adb.shell("cmd location set-location-enabled true")
location_mode = int(ad.adb.shell("settings get secure location_mode"))
ad.log.info("Current Location Mode >> %d" % location_mode)
if location_mode != 3:
@@ -355,7 +432,7 @@
reboot(ad)
-def get_gnss_qxdm_log(ad, qdb_path):
+def get_gnss_qxdm_log(ad, qdb_path=None):
"""Get /storage/emulated/0/Android/data/com.android.gpstool/files and
/data/vendor/radio/diag_logs/logs for test item.
@@ -369,16 +446,17 @@
gnss_log_path = posixpath.join(log_path, gnss_log_name)
os.makedirs(gnss_log_path, exist_ok=True)
ad.log.info("Pull GnssStatus Log to %s" % gnss_log_path)
- ad.adb.pull("%s %s" % (GNSSSTATUS_LOG_PATH+".", gnss_log_path),
+ ad.adb.pull("%s %s" % (GNSSSTATUS_LOG_PATH + ".", gnss_log_path),
timeout=PULL_TIMEOUT, ignore_status=True)
shutil.make_archive(gnss_log_path, "zip", gnss_log_path)
- shutil.rmtree(gnss_log_path)
+ shutil.rmtree(gnss_log_path, ignore_errors=True)
if check_chipset_vendor_by_qualcomm(ad):
output_path = (
- "/sdcard/Android/data/com.android.pixellogger/files/logs/diag_logs")
+ "/sdcard/Android/data/com.android.pixellogger/files/logs/"
+ "diag_logs/.")
else:
output_path = (
- "/sdcard/Android/data/com.android.pixellogger/files/logs/gps/")
+ "/sdcard/Android/data/com.android.pixellogger/files/logs/gps/.")
qxdm_log_name = "PixelLogger_%s_%s" % (ad.model, ad.serial)
qxdm_log_path = posixpath.join(log_path, qxdm_log_name)
os.makedirs(qxdm_log_path, exist_ok=True)
@@ -394,7 +472,7 @@
continue
break
shutil.make_archive(qxdm_log_path, "zip", qxdm_log_path)
- shutil.rmtree(qxdm_log_path)
+ shutil.rmtree(qxdm_log_path, ignore_errors=True)
def set_mobile_data(ad, state):
@@ -406,19 +484,27 @@
"""
ad.root_adb()
if state:
- ad.log.info("Enable mobile data.")
- ad.adb.shell("svc data enable")
+ if is_device_wearable(ad):
+ ad.log.info("Enable wearable mobile data.")
+ ad.adb.shell("settings put global cell_on 1")
+ else:
+ ad.log.info("Enable mobile data via RPC call.")
+ ad.droid.telephonyToggleDataConnection(True)
else:
- ad.log.info("Disable mobile data.")
- ad.adb.shell("svc data disable")
+ if is_device_wearable(ad):
+ ad.log.info("Disable wearable mobile data.")
+ ad.adb.shell("settings put global cell_on 0")
+ else:
+ ad.log.info("Disable mobile data via RPC call.")
+ ad.droid.telephonyToggleDataConnection(False)
time.sleep(5)
- out = int(ad.adb.shell("settings get global mobile_data"))
- if state and out == 1:
- ad.log.info("Mobile data is enabled and set to %d" % out)
- elif not state and out == 0:
- ad.log.info("Mobile data is disabled and set to %d" % out)
+ ret_val = is_mobile_data_on(ad)
+ if state and ret_val:
+ ad.log.info("Mobile data is enabled and set to %s" % ret_val)
+ elif not state and not ret_val:
+ ad.log.info("Mobile data is disabled and set to %s" % ret_val)
else:
- ad.log.error("Mobile data is at unknown state and set to %d" % out)
+ ad.log.error("Mobile data is at unknown state and set to %s" % ret_val)
def gnss_trigger_modem_ssr_by_adb(ad, dwelltime=60):
@@ -503,6 +589,11 @@
ad.log.info("XTRA downloaded and injected successfully.")
return True
ad.log.error("XTRA downloaded FAIL.")
+ elif is_device_wearable(ad):
+ lto_results = ad.adb.shell("ls -al /data/vendor/gps/lto*")
+ if "lto2.dat" in lto_results:
+ ad.log.info("LTO downloaded and injected successfully.")
+ return True
else:
lto_results = ad.search_logcat("GnssPsdsAidl: injectPsdsData: "
"psdsType: 1", begin_time)
@@ -524,11 +615,10 @@
Returns:
The temp path of pulled apk.
"""
- apk_path = None
out = ad.adb.shell("pm path %s" % package_name)
result = re.search(r"package:(.*)", out)
if not result:
- tutils.abort_all_tests(ad.log, "Couldn't find apk of %s" % package_name)
+ raise signals.TestError("Couldn't find apk of %s" % package_name)
else:
apk_source = result.group(1)
ad.log.info("Get apk of %s from %s" % (package_name, apk_source))
@@ -592,9 +682,10 @@
remount_device(ad)
gpstool_path = pull_package_apk(ad, "com.android.gpstool")
reinstall_package_apk(ad, "com.android.gpstool", gpstool_path)
+ shutil.rmtree(gpstool_path, ignore_errors=True)
-def fastboot_factory_reset(ad):
+def fastboot_factory_reset(ad, state=True):
"""Factory reset the device in fastboot mode.
Pull sl4a apk from device. Terminate all sl4a sessions,
Reboot the device to bootloader,
@@ -604,23 +695,24 @@
Args:
ad: An AndroidDevice object.
+ State: True for exit_setup_wizard, False for not exit_setup_wizard.
Returns:
True if factory reset process complete.
"""
status = True
- skip_setup_wizard = True
+ mds_path = ""
+ gnss_cfg_file = ""
gnss_cfg_path = "/vendor/etc/mdlog"
default_gnss_cfg = "/vendor/etc/mdlog/DEFAULT+SECURITY+FULLDPL+GPS.cfg"
sl4a_path = pull_package_apk(ad, SL4A_APK_NAME)
gpstool_path = pull_package_apk(ad, "com.android.gpstool")
- mds_path = pull_package_apk(ad, "com.google.mdstest")
if check_chipset_vendor_by_qualcomm(ad):
+ mds_path = pull_package_apk(ad, "com.google.mdstest")
gnss_cfg_file = pull_gnss_cfg_file(ad, default_gnss_cfg)
stop_pixel_logger(ad)
ad.stop_services()
- attempts = 3
- for i in range(1, attempts + 1):
+ for i in range(1, 4):
try:
if ad.serial in list_adb_devices():
ad.log.info("Reboot to bootloader")
@@ -638,10 +730,13 @@
break
if ad.is_sl4a_installed():
break
+ if is_device_wearable(ad):
+ ad.log.info("Wait 5 mins for wearable projects system busy time.")
+ time.sleep(300)
reinstall_package_apk(ad, SL4A_APK_NAME, sl4a_path)
reinstall_package_apk(ad, "com.android.gpstool", gpstool_path)
- reinstall_package_apk(ad, "com.google.mdstest", mds_path)
if check_chipset_vendor_by_qualcomm(ad):
+ reinstall_package_apk(ad, "com.google.mdstest", mds_path)
ad.push_system_file(gnss_cfg_file, gnss_cfg_path)
time.sleep(10)
break
@@ -654,11 +749,13 @@
ad.start_adb_logcat()
except Exception as e:
ad.log.error(e)
- if skip_setup_wizard:
+ if state:
ad.exit_setup_wizard()
if ad.skip_sl4a:
return status
tutils.bring_up_sl4a(ad)
+ for path in [sl4a_path, gpstool_path, mds_path, gnss_cfg_file]:
+ shutil.rmtree(path, ignore_errors=True)
return status
@@ -761,7 +858,15 @@
raise signals.TestFailure("Fail to get %s location fixed within %d "
"attempts." % (type.upper(), retries))
-def start_ttff_by_gtw_gpstool(ad, ttff_mode, iteration, aid_data=False):
+
+def start_ttff_by_gtw_gpstool(ad,
+ ttff_mode,
+ iteration,
+ aid_data=False,
+ raninterval=False,
+ mininterval=10,
+ maxinterval=40,
+ hot_warm_sleep=300):
"""Identify which TTFF mode for different test items.
Args:
@@ -769,17 +874,28 @@
ttff_mode: TTFF Test mode for current test item.
iteration: Iteration of TTFF cycles.
aid_data: Boolean for identify aid_data existed or not
+ raninterval: Boolean for identify random interval of TTFF in enable or not.
+ mininterval: Minimum value of random interval pool. The unit is second.
+ maxinterval: Maximum value of random interval pool. The unit is second.
+ hot_warm_sleep: Wait time for acquiring Almanac.
"""
begin_time = get_current_epoch_time()
if (ttff_mode == "hs" or ttff_mode == "ws") and not aid_data:
- ad.log.info("Wait 5 minutes to start TTFF %s..." % ttff_mode.upper())
- time.sleep(300)
+ ad.log.info("Wait {} seconds to start TTFF {}...".format(
+ hot_warm_sleep, ttff_mode.upper()))
+ time.sleep(hot_warm_sleep)
if ttff_mode == "cs":
ad.log.info("Start TTFF Cold Start...")
time.sleep(3)
+ elif ttff_mode == "csa":
+ ad.log.info("Start TTFF CSWith Assist...")
+ time.sleep(3)
for i in range(1, 4):
ad.adb.shell("am broadcast -a com.android.gpstool.ttff_action "
- "--es ttff %s --es cycle %d" % (ttff_mode, iteration))
+ "--es ttff {} --es cycle {} --ez raninterval {} "
+ "--ei mininterval {} --ei maxinterval {}".format(
+ ttff_mode, iteration, raninterval, mininterval,
+ maxinterval))
time.sleep(1)
if ad.search_logcat("act=com.android.gpstool.start_test_action",
begin_time):
@@ -805,30 +921,13 @@
meas_flag: True to enable GnssMeasurement. False is not to. Default
set to False.
"""
- gnss_crash_list = [".*Fatal signal.*gnss",
- ".*Fatal signal.*xtra",
- ".*F DEBUG.*gnss"]
process_gnss_by_gtw_gpstool(
ad, criteria=criteria, type=type, meas_flag=meas_flag)
ad.log.info("Start %s tracking test for %d minutes" % (type.upper(),
testtime))
begin_time = get_current_epoch_time()
while get_current_epoch_time() - begin_time < testtime * 60 * 1000:
- if not ad.is_adb_logcat_on:
- ad.start_adb_logcat()
- for attr in gnss_crash_list:
- gnss_crash_result = ad.adb.shell(
- "logcat -d | grep -E -i '%s'" % attr)
- if gnss_crash_result:
- start_gnss_by_gtw_gpstool(ad, state=False, type=type)
- raise signals.TestFailure(
- "Test failed due to GNSS HAL crashed. \n%s" %
- gnss_crash_result)
- gpstool_crash_result = ad.search_logcat("Force finishing activity "
- "com.android.gpstool/.GPSTool",
- begin_time)
- if gpstool_crash_result:
- raise signals.TestError("GPSTool crashed. Abort test.")
+ detect_crash_during_tracking(ad, begin_time, type)
ad.log.info("Successfully tested for %d minutes" % testtime)
start_gnss_by_gtw_gpstool(ad, state=False, type=type)
@@ -966,6 +1065,8 @@
loc_time = int(
gnss_location_log[10].split("=")[-1].strip(","))
utc_time = epoch_to_human_time(loc_time)
+ ttff_haccu = float(
+ gnss_location_log[11].split("=")[-1].strip(","))
elif type == "flp":
flp_results = ad.search_logcat("GPSService: FLP Location",
begin_time)
@@ -975,12 +1076,14 @@
"log_message"].split()
ttff_lat = float(flp_location_log[8].split(",")[0])
ttff_lon = float(flp_location_log[8].split(",")[1])
+ ttff_haccu = float(flp_location_log[9].split("=")[1])
utc_time = epoch_to_human_time(get_current_epoch_time())
else:
ttff_ant_cn = float(ttff_log[19].strip("]"))
ttff_base_cn = float(ttff_log[26].strip("]"))
ttff_lat = 0
ttff_lon = 0
+ ttff_haccu = 0
utc_time = epoch_to_human_time(get_current_epoch_time())
ad.log.debug("TTFF Loop %d - (Lat, Lon) = (%s, %s)" % (ttff_loop,
ttff_lat,
@@ -992,16 +1095,19 @@
ttff_sec=ttff_sec,
ttff_pe=ttff_pe,
ttff_ant_cn=ttff_ant_cn,
- ttff_base_cn=ttff_base_cn)
+ ttff_base_cn=ttff_base_cn,
+ ttff_haccu=ttff_haccu)
ad.log.info("UTC Time = %s, Loop %d = %.1f seconds, "
"Position Error = %.1f meters, "
"Antenna Average Signal = %.1f dbHz, "
- "Baseband Average Signal = %.1f dbHz" % (utc_time,
+ "Baseband Average Signal = %.1f dbHz, "
+ "Horizontal Accuracy = %.1f meters" % (utc_time,
ttff_loop,
ttff_sec,
ttff_pe,
ttff_ant_cn,
- ttff_base_cn))
+ ttff_base_cn,
+ ttff_haccu))
stop_gps_results = ad.search_logcat("stop gps test", begin_time)
if stop_gps_results:
ad.send_keycode("HOME")
@@ -1066,6 +1172,8 @@
ttff_data.keys()]
base_cn_list = [float(ttff_data[key].ttff_base_cn) for key in
ttff_data.keys()]
+ haccu_list = [float(ttff_data[key].ttff_haccu) for key in
+ ttff_data.keys()]
timeoutcount = sec_list.count(0.0)
if len(sec_list) == timeoutcount:
avgttff = 9527
@@ -1079,6 +1187,7 @@
maxdis = max(pe_list)
ant_avgcn = sum(ant_cn_list)/len(ant_cn_list)
base_avgcn = sum(base_cn_list)/len(base_cn_list)
+ avg_haccu = sum(haccu_list)/len(haccu_list)
ad.log.info(prop_basename+"AvgTime %.1f" % avgttff)
ad.log.info(prop_basename+"MaxTime %.1f" % maxttff)
ad.log.info(prop_basename+"TimeoutCount %d" % timeoutcount)
@@ -1086,6 +1195,7 @@
ad.log.info(prop_basename+"MaxDis %.1f" % maxdis)
ad.log.info(prop_basename+"Ant_AvgSignal %.1f" % ant_avgcn)
ad.log.info(prop_basename+"Base_AvgSignal %.1f" % base_avgcn)
+ ad.log.info(prop_basename+"Avg_Horizontal_Accuracy %.1f" % avg_haccu)
def calculate_position_error(latitude, longitude, true_position):
@@ -1118,12 +1228,16 @@
"""
ad.log.info("Launch Google Map.")
try:
- ad.adb.shell("am start -S -n com.google.android.apps.maps/"
- "com.google.android.maps.MapsActivity")
+ if is_device_wearable(ad):
+ cmd = ("am start -S -n com.google.android.apps.maps/"
+ "com.google.android.apps.gmmwearable.MainActivity")
+ else:
+ cmd = ("am start -S -n com.google.android.apps.maps/"
+ "com.google.android.maps.MapsActivity")
+ ad.adb.shell(cmd)
ad.send_keycode("BACK")
ad.force_stop_apk("com.google.android.apps.maps")
- ad.adb.shell("am start -S -n com.google.android.apps.maps/"
- "com.google.android.maps.MapsActivity")
+ ad.adb.shell(cmd)
except Exception as e:
ad.log.error(e)
raise signals.TestError("Failed to launch google map.")
@@ -1158,7 +1272,7 @@
ad.log.info("Try to get location report from GnssLocationProvider API "
"- attempt %d" % (i+1))
while get_current_epoch_time() - begin_time <= 30000:
- logcat_results = ad.search_logcat("REPORT_LOCATION", begin_time)
+ logcat_results = ad.search_logcat("reportLocation", begin_time)
if logcat_results:
ad.log.info("%s" % logcat_results[-1]["log_message"])
ad.log.info("GnssLocationProvider reports location "
@@ -1169,6 +1283,7 @@
ad.log.error("GnssLocationProvider is unable to report location.")
return False
+
def check_network_location(ad, retries, location_type, criteria=30):
"""Verify if NLP reports location after requesting via GPSTool.
@@ -1247,9 +1362,9 @@
"""
try:
for mask in masks:
- if not tutils.find_qxdm_log_mask(ad, mask):
+ if not tlutils.find_qxdm_log_mask(ad, mask):
continue
- tutils.set_qxdm_logger_command(ad, mask)
+ tlutils.set_qxdm_logger_command(ad, mask)
break
except Exception as e:
ad.log.error(e)
@@ -1296,20 +1411,35 @@
ad: An AndroidDevice object.
extra_msg: Extra message before or after the change.
"""
+ mpss_version = ""
+ brcm_gps_version = ""
+ brcm_sensorhub_version = ""
try:
build_version = ad.adb.getprop("ro.build.id")
baseband_version = ad.adb.getprop("gsm.version.baseband")
gms_version = ad.adb.shell(
"dumpsys package com.google.android.gms | grep versionName"
).split("\n")[0].split("=")[1]
- mpss_version = ad.adb.shell("cat /sys/devices/soc0/images | grep MPSS "
- "| cut -d ':' -f 3")
+ if check_chipset_vendor_by_qualcomm(ad):
+ mpss_version = ad.adb.shell(
+ "cat /sys/devices/soc0/images | grep MPSS | cut -d ':' -f 3")
+ else:
+ brcm_gps_version = ad.adb.shell("cat /data/vendor/gps/chip.info")
+ sensorhub_version = ad.adb.shell(
+ "cat /vendor/firmware/SensorHub.patch | grep ChangeList")
+ brcm_sensorhub_version = re.compile(
+ r'<ChangeList=(\w+)>').search(sensorhub_version).group(1)
if not extra_msg:
ad.log.info("TestResult Build_Version %s" % build_version)
ad.log.info("TestResult Baseband_Version %s" % baseband_version)
ad.log.info(
"TestResult GMS_Version %s" % gms_version.replace(" ", ""))
- ad.log.info("TestResult MPSS_Version %s" % mpss_version)
+ if check_chipset_vendor_by_qualcomm(ad):
+ ad.log.info("TestResult MPSS_Version %s" % mpss_version)
+ else:
+ ad.log.info("TestResult GPS_Version %s" % brcm_gps_version)
+ ad.log.info(
+ "TestResult SensorHub_Version %s" % brcm_sensorhub_version)
else:
ad.log.info(
"%s, Baseband_Version = %s" % (extra_msg, baseband_version))
@@ -1331,7 +1461,14 @@
ad.adb.shell("am start -S -n com.android.gpstool/.GPSTool "
"--es mode toggle --es cycle %d" % iteration)
time.sleep(1)
- if ad.search_logcat("cmp=com.android.gpstool/.ToggleGPS",
+ if is_device_wearable(ad):
+ # Wait 20 seconds for Wearable low performance time.
+ time.sleep(20)
+ if ad.search_logcat("ToggleGPS onResume",
+ begin_time):
+ ad.log.info("Send ToggleGPS start_test_action successfully.")
+ break
+ elif ad.search_logcat("cmp=com.android.gpstool/.ToggleGPS",
begin_time):
ad.log.info("Send ToggleGPS start_test_action successfully.")
break
@@ -1340,7 +1477,11 @@
raise signals.TestError("Fail to send ToggleGPS "
"start_test_action within 3 attempts.")
time.sleep(2)
- test_start = ad.search_logcat("GPSTool_ToggleGPS: startService",
+ if is_device_wearable(ad):
+ test_start = ad.search_logcat("GPSService: create toggle GPS log",
+ begin_time)
+ else:
+ test_start = ad.search_logcat("GPSTool_ToggleGPS: startService",
begin_time)
if test_start:
ad.log.info(test_start[-1]["log_message"].split(":")[-1].strip())
@@ -1485,10 +1626,10 @@
pe_criteria: Criteria for current test item.
"""
- ad.log.info("%d iterations of TTFF %s tests finished.",
- (len(ttff_data.keys()), ttff_mode))
- ad.log.info("%s PASS criteria is %f meters", (ttff_mode, pe_criteria))
- ad.log.debug("%s TTFF data: %s", (ttff_mode, ttff_data))
+ ad.log.info("%d iterations of TTFF %s tests finished."
+ % (len(ttff_data.keys()), ttff_mode))
+ ad.log.info("%s PASS criteria is %f meters" % (ttff_mode, pe_criteria))
+ ad.log.debug("%s TTFF data: %s" % (ttff_mode, ttff_data))
if len(ttff_data.keys()) == 0:
ad.log.error("GTW_GPSTool didn't process TTFF properly.")
@@ -1496,11 +1637,13 @@
elif any(float(ttff_data[key].ttff_pe) >= pe_criteria for key in
ttff_data.keys()):
- ad.log.error("One or more TTFF %s are over test criteria %f meters",
- (ttff_mode, pe_criteria))
+ ad.log.error("One or more TTFF %s are over test criteria %f meters"
+ % (ttff_mode, pe_criteria))
raise signals.TestFailure("GTW_GPSTool didn't process TTFF properly.")
- ad.log.info("All TTFF %s are within test criteria %f meters.",
- (ttff_mode, pe_criteria))
+ else:
+ ad.log.info("All TTFF %s are within test criteria %f meters." % (
+ ttff_mode, pe_criteria))
+ return True
def check_adblog_functionality(ad):
@@ -1559,7 +1702,7 @@
def check_chipset_vendor_by_qualcomm(ad):
- """Check if cipset vendor is by Qualcomm.
+ """Check if chipset vendor is by Qualcomm.
Args:
ad: An AndroidDevice object.
@@ -1597,14 +1740,14 @@
"NORMAL_PSDS_SERVER",
"REALTIME_PSDS_SERVER"]
delete_lto_file(ad)
- tmp_path = tempfile.mkdtemp()
- ad.pull_files("/etc/gps_debug.conf", tmp_path)
- gps_conf_path = os.path.join(tmp_path, "gps_debug.conf")
- gps_conf_file = open(gps_conf_path, "r")
- lines = gps_conf_file.readlines()
- gps_conf_file.close()
- fout = open(gps_conf_path, "w")
if state:
+ tmp_path = tempfile.mkdtemp()
+ ad.pull_files("/etc/gps_debug.conf", tmp_path)
+ gps_conf_path = os.path.join(tmp_path, "gps_debug.conf")
+ gps_conf_file = open(gps_conf_path, "r")
+ lines = gps_conf_file.readlines()
+ gps_conf_file.close()
+ fout = open(gps_conf_path, "w")
for line in lines:
for server in server_list:
if server in line:
@@ -1614,6 +1757,7 @@
ad.push_system_file(gps_conf_path, "/etc/gps_debug.conf")
ad.log.info("Push back modified gps_debug.conf")
ad.log.info("LTO/RTO/RTI enabled")
+ shutil.rmtree(tmp_path, ignore_errors=True)
else:
ad.adb.shell("echo %r >> /etc/gps_debug.conf" %
DISABLE_LTO_FILE_CONTENTS)
@@ -1621,6 +1765,78 @@
reboot(ad)
+def lto_mode_wearable(ad, state):
+ """Enable or Disable LTO mode for wearable in Android R release.
+
+ Args:
+ ad: An AndroidDevice object.
+ state: True to enable. False to disable.
+ """
+ rto_enable = ' RtoEnable="true"\n'
+ rto_disable = ' RtoEnable="false"\n'
+ rti_enable = ' RtiEnable="true"\n'
+ rti_disable = ' RtiEnable="false"\n'
+ sync_lto_enable = ' HttpDirectSyncLto="true"\n'
+ sync_lto_disable = ' HttpDirectSyncLto="false"\n'
+ server_list = ["XTRA_SERVER_1", "XTRA_SERVER_2", "XTRA_SERVER_3"]
+ delete_lto_file(ad)
+ tmp_path = tempfile.mkdtemp()
+ ad.pull_files("/vendor/etc/gnss/gps.xml", tmp_path)
+ gps_xml_path = os.path.join(tmp_path, "gps.xml")
+ gps_xml_file = open(gps_xml_path, "r")
+ lines = gps_xml_file.readlines()
+ gps_xml_file.close()
+ fout = open(gps_xml_path, "w")
+ for line in lines:
+ if state:
+ if rto_disable in line:
+ line = line.replace(line, rto_enable)
+ ad.log.info("RTO enabled")
+ elif rti_disable in line:
+ line = line.replace(line, rti_enable)
+ ad.log.info("RTI enabled")
+ elif sync_lto_disable in line:
+ line = line.replace(line, sync_lto_enable)
+ ad.log.info("LTO sync enabled")
+ else:
+ if rto_enable in line:
+ line = line.replace(line, rto_disable)
+ ad.log.info("RTO disabled")
+ elif rti_enable in line:
+ line = line.replace(line, rti_disable)
+ ad.log.info("RTI disabled")
+ elif sync_lto_enable in line:
+ line = line.replace(line, sync_lto_disable)
+ ad.log.info("LTO sync disabled")
+ fout.write(line)
+ fout.close()
+ ad.push_system_file(gps_xml_path, "/vendor/etc/gnss/gps.xml")
+ ad.log.info("Push back modified gps.xml")
+ shutil.rmtree(tmp_path, ignore_errors=True)
+ if state:
+ xtra_tmp_path = tempfile.mkdtemp()
+ ad.pull_files("/etc/gps_debug.conf", xtra_tmp_path)
+ gps_conf_path = os.path.join(xtra_tmp_path, "gps_debug.conf")
+ gps_conf_file = open(gps_conf_path, "r")
+ lines = gps_conf_file.readlines()
+ gps_conf_file.close()
+ fout = open(gps_conf_path, "w")
+ for line in lines:
+ for server in server_list:
+ if server in line:
+ line = line.replace(line, "")
+ fout.write(line)
+ fout.close()
+ ad.push_system_file(gps_conf_path, "/etc/gps_debug.conf")
+ ad.log.info("Push back modified gps_debug.conf")
+ ad.log.info("LTO/RTO/RTI enabled")
+ shutil.rmtree(xtra_tmp_path, ignore_errors=True)
+ else:
+ ad.adb.shell(
+ "echo %r >> /etc/gps_debug.conf" % DISABLE_LTO_FILE_CONTENTS_R)
+ ad.log.info("LTO/RTO/RTI disabled")
+
+
def start_pixel_logger(ad, max_log_size_mb=100, max_number_of_files=500):
"""adb to start pixel logger for GNSS logging.
@@ -1634,31 +1850,35 @@
start_timeout_sec = 60
default_gnss_cfg = "/vendor/etc/mdlog/DEFAULT+SECURITY+FULLDPL+GPS.cfg"
if check_chipset_vendor_by_qualcomm(ad):
- start_cmd = ("am start-foreground-service -a com.android.pixellogger"
- ".service.logging.LoggingService.ACTION_START_LOGGING "
+ start_cmd = ("am startservice -a com.android.pixellogger."
+ "service.logging.LoggingService.ACTION_START_LOGGING "
"-e intent_key_cfg_path '%s' "
"--ei intent_key_max_log_size_mb %d "
- "--ei intent_key_max_number_of_files %d" % (
- default_gnss_cfg, max_log_size_mb, max_number_of_files))
+ "--ei intent_key_max_number_of_files %d" %
+ (default_gnss_cfg, max_log_size_mb, max_number_of_files))
else:
start_cmd = ("am startservice -a com.android.pixellogger."
"service.logging.LoggingService.ACTION_START_LOGGING "
- "-e intent_logger brcm_gps")
+ "-e intent_logger brcm_gps "
+ "--ei intent_key_max_log_size_mb %d "
+ "--ei intent_key_max_number_of_files %d" %
+ (max_log_size_mb, max_number_of_files))
for attempt in range(retries):
- begin_time = get_current_epoch_time()
- ad.log.info("Start Pixel Logger. - Attempt %d" % (attempt + 1))
+ begin_time = get_current_epoch_time() - 3000
+ ad.log.info("Start Pixel Logger - Attempt %d" % (attempt + 1))
ad.adb.shell(start_cmd)
while get_current_epoch_time() - begin_time <= start_timeout_sec * 1000:
if not ad.is_adb_logcat_on:
ad.start_adb_logcat()
if check_chipset_vendor_by_qualcomm(ad):
- start_result = ad.search_logcat("Start logging", begin_time)
+ start_result = ad.search_logcat(
+ "ModemLogger: Start logging", begin_time)
else:
start_result = ad.search_logcat("startRecording", begin_time)
if start_result:
ad.log.info("Pixel Logger starts recording successfully.")
return True
- ad.force_stop_apk("com.android.pixellogger")
+ stop_pixel_logger(ad)
else:
ad.log.warn("Pixel Logger fails to start recording in %d seconds "
"within %d attempts." % (start_timeout_sec, retries))
@@ -1671,17 +1891,18 @@
ad: An AndroidDevice object.
"""
retries = 3
- stop_timeout_sec = 300
+ stop_timeout_sec = 60
+ zip_timeout_sec = 30
if check_chipset_vendor_by_qualcomm(ad):
- stop_cmd = ("am start-foreground-service -a com.android.pixellogger"
- ".service.logging.LoggingService.ACTION_STOP_LOGGING")
+ stop_cmd = ("am startservice -a com.android.pixellogger."
+ "service.logging.LoggingService.ACTION_STOP_LOGGING")
else:
stop_cmd = ("am startservice -a com.android.pixellogger."
"service.logging.LoggingService.ACTION_STOP_LOGGING "
"-e intent_logger brcm_gps")
for attempt in range(retries):
- begin_time = get_current_epoch_time()
- ad.log.info("Stop Pixel Logger. - Attempt %d" % (attempt + 1))
+ begin_time = get_current_epoch_time() - 3000
+ ad.log.info("Stop Pixel Logger - Attempt %d" % (attempt + 1))
ad.adb.shell(stop_cmd)
while get_current_epoch_time() - begin_time <= stop_timeout_sec * 1000:
if not ad.is_adb_logcat_on:
@@ -1690,7 +1911,17 @@
"LoggingService: Stopping service", begin_time)
if stop_result:
ad.log.info("Pixel Logger stops successfully.")
- return True
+ zip_end_time = time.time() + zip_timeout_sec
+ while time.time() < zip_end_time:
+ zip_file_created = ad.search_logcat(
+ "FileUtil: Zip file has been created", begin_time)
+ if zip_file_created:
+ ad.log.info("Pixel Logger created zip file "
+ "successfully.")
+ return True
+ else:
+ ad.log.warn("Pixel Logger failed to create zip file.")
+ return False
ad.force_stop_apk("com.android.pixellogger")
else:
ad.log.warn("Pixel Logger fails to stop in %d seconds within %d "
@@ -1698,10 +1929,12 @@
def launch_eecoexer(ad):
- """adb to stop pixel logger for GNSS logging.
+ """Launch EEcoexer.
Args:
ad: An AndroidDevice object.
+ Raise:
+ signals.TestError if DUT fails to launch EEcoexer
"""
launch_cmd = ("am start -a android.intent.action.MAIN -n"
"com.google.eecoexer"
@@ -1715,20 +1948,26 @@
def excute_eecoexer_function(ad, eecoexer_args):
- """adb to stop pixel logger for GNSS logging.
+ """Execute EEcoexer commands.
Args:
ad: An AndroidDevice object.
eecoexer_args: EEcoexer function arguments
"""
+ cat_index = eecoexer_args.split(',')[:2]
+ cat_index = ','.join(cat_index)
enqueue_cmd = ("am broadcast -a com.google.eecoexer.action.LISTENER"
" --es sms_body ENQUEUE,{}".format(eecoexer_args))
exe_cmd = ("am broadcast -a com.google.eecoexer.action.LISTENER"
" --es sms_body EXECUTE")
+ wait_for_cmd = ("am broadcast -a com.google.eecoexer.action.LISTENER"
+ " --es sms_body WAIT_FOR_COMPLETE,{}".format(cat_index))
ad.log.info("EEcoexer Add Enqueue: {}".format(eecoexer_args))
ad.adb.shell(enqueue_cmd)
ad.log.info("EEcoexer Excute.")
ad.adb.shell(exe_cmd)
+ ad.log.info("Wait EEcoexer for complete")
+ ad.adb.shell(wait_for_cmd)
def restart_gps_daemons(ad):
@@ -1755,3 +1994,490 @@
break
else:
raise signals.TestError("Unable to restart \"%s\"" % service)
+
+
+def is_device_wearable(ad):
+ """Check device is wearable project or not.
+
+ Args:
+ ad: An AndroidDevice object.
+ """
+ package = ad.adb.getprop("ro.cw.home_package_names")
+ ad.log.debug("[ro.cw.home_package_names]: [%s]" % package)
+ return "wearable" in package
+
+
+def is_mobile_data_on(ad):
+ """Check if mobile data of device is on.
+
+ Args:
+ ad: An AndroidDevice object.
+ """
+ if is_device_wearable(ad):
+ cell_on = ad.adb.shell("settings get global cell_on")
+ ad.log.debug("Current mobile status is %s" % cell_on)
+ return "1" in cell_on
+ else:
+ return ad.droid.telephonyIsDataEnabled()
+
+
+def human_to_epoch_time(human_time):
+ """Convert human readable time to epoch time.
+
+ Args:
+ human_time: Human readable time. (Ex: 2020-08-04 13:24:28.900)
+
+ Returns:
+ epoch: Epoch time in milliseconds.
+ """
+ if "/" in human_time:
+ human_time.replace("/", "-")
+ try:
+ epoch_start = datetime.utcfromtimestamp(0)
+ if "." in human_time:
+ epoch_time = datetime.strptime(human_time, "%Y-%m-%d %H:%M:%S.%f")
+ else:
+ epoch_time = datetime.strptime(human_time, "%Y-%m-%d %H:%M:%S")
+ epoch = int((epoch_time - epoch_start).total_seconds() * 1000)
+ return epoch
+ except ValueError:
+ return None
+
+
+def check_dpo_rate_via_gnss_meas(ad, begin_time, dpo_threshold):
+ """Check DPO engage rate through "HardwareClockDiscontinuityCount" in
+ GnssMeasurement callback.
+
+ Args:
+ ad: An AndroidDevice object.
+ begin_time: test begin time.
+ dpo_threshold: The value to set threshold. (Ex: dpo_threshold = 60)
+ """
+ time_regex = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3})'
+ dpo_results = ad.search_logcat("HardwareClockDiscontinuityCount",
+ begin_time)
+ if not dpo_results:
+ raise signals.TestError(
+ "No \"HardwareClockDiscontinuityCount\" is found in logs.")
+ ad.log.info(dpo_results[0]["log_message"])
+ ad.log.info(dpo_results[-1]["log_message"])
+ start_time = re.compile(
+ time_regex).search(dpo_results[0]["log_message"]).group(1)
+ end_time = re.compile(
+ time_regex).search(dpo_results[-1]["log_message"]).group(1)
+ gnss_start_epoch = human_to_epoch_time(start_time)
+ gnss_stop_epoch = human_to_epoch_time(end_time)
+ test_time_in_sec = round((gnss_stop_epoch - gnss_start_epoch) / 1000) + 1
+ first_dpo_count = int(dpo_results[0]["log_message"].split()[-1])
+ final_dpo_count = int(dpo_results[-1]["log_message"].split()[-1])
+ dpo_rate = ((final_dpo_count - first_dpo_count)/test_time_in_sec)
+ dpo_engage_rate = "{percent:.2%}".format(percent=dpo_rate)
+ ad.log.info("DPO is ON for %d seconds during %d seconds test." % (
+ final_dpo_count - first_dpo_count, test_time_in_sec))
+ ad.log.info("TestResult DPO_Engage_Rate " + dpo_engage_rate)
+ threshold = "{percent:.0%}".format(percent=dpo_threshold / 100)
+ asserts.assert_true(dpo_rate * 100 > dpo_threshold,
+ "DPO only engaged %s in %d seconds test with "
+ "threshold %s." % (dpo_engage_rate,
+ test_time_in_sec,
+ threshold))
+
+
+def parse_brcm_nmea_log(ad, nmea_pattern, brcm_error_log_allowlist):
+ """Parse specific NMEA pattern out of BRCM NMEA log.
+
+ Args:
+ ad: An AndroidDevice object.
+ nmea_pattern: Specific NMEA pattern to parse.
+ brcm_error_log_allowlist: Benign error logs to exclude.
+
+ Returns:
+ brcm_log_list: A list of specific NMEA pattern logs.
+ """
+ brcm_log_list = []
+ brcm_log_error_pattern = ["lhd: FS: Start Failsafe dump", "E slog"]
+ brcm_error_log_list = []
+ stop_pixel_logger(ad)
+ pixellogger_path = (
+ "/sdcard/Android/data/com.android.pixellogger/files/logs/gps/.")
+ tmp_log_path = tempfile.mkdtemp()
+ ad.pull_files(pixellogger_path, tmp_log_path)
+ for path_key in os.listdir(tmp_log_path):
+ zip_path = posixpath.join(tmp_log_path, path_key)
+ if path_key.endswith(".zip"):
+ ad.log.info("Processing zip file: {}".format(zip_path))
+ with zipfile.ZipFile(zip_path, "r") as zip_file:
+ zip_file.extractall(tmp_log_path)
+ gl_logs = zip_file.namelist()
+ # b/214145973 check if hidden exists in pixel logger zip file
+ tmp_file = [name for name in gl_logs if 'tmp' in name]
+ if tmp_file:
+ ad.log.warn(f"Hidden file {tmp_file} exists in pixel logger zip file")
+ break
+ elif os.path.isdir(zip_path):
+ ad.log.info("BRCM logs didn't zip properly. Log path is directory.")
+ tmp_log_path = zip_path
+ gl_logs = os.listdir(tmp_log_path)
+ ad.log.info("Processing BRCM log files: {}".format(gl_logs))
+ break
+ else:
+ raise signals.TestError(
+ "No BRCM logs found in {}".format(os.listdir(tmp_log_path)))
+ gl_logs = [log for log in gl_logs
+ if log.startswith("gl") and log.endswith(".log")]
+ for file in gl_logs:
+ nmea_log_path = posixpath.join(tmp_log_path, file)
+ ad.log.info("Parsing log pattern of \"%s\" in %s" % (nmea_pattern,
+ nmea_log_path))
+ brcm_log = open(nmea_log_path, "r", encoding="UTF-8", errors="ignore")
+ lines = brcm_log.readlines()
+ for line in lines:
+ if nmea_pattern in line:
+ brcm_log_list.append(line)
+ for attr in brcm_log_error_pattern:
+ if attr in line:
+ benign_log = False
+ for allow_log in brcm_error_log_allowlist:
+ if allow_log in line:
+ benign_log = True
+ ad.log.info("\"%s\" is in allow-list and removed "
+ "from error." % allow_log)
+ if not benign_log:
+ brcm_error_log_list.append(line)
+ brcm_error_log = "".join(brcm_error_log_list)
+ shutil.rmtree(tmp_log_path, ignore_errors=True)
+ return brcm_log_list, brcm_error_log
+
+
+def check_dpo_rate_via_brcm_log(ad, dpo_threshold, brcm_error_log_allowlist):
+ """Check DPO engage rate through "$PGLOR,11,STA" in BRCM Log.
+ D - Disabled, Always full power.
+ F - Enabled, now in full power mode.
+ S - Enabled, now in power save mode.
+ H - Host off load mode.
+
+ Args:
+ ad: An AndroidDevice object.
+ dpo_threshold: The value to set threshold. (Ex: dpo_threshold = 60)
+ brcm_error_log_allowlist: Benign error logs to exclude.
+ """
+ always_full_power_count = 0
+ full_power_count = 0
+ power_save_count = 0
+ pglor_list, brcm_error_log = parse_brcm_nmea_log(
+ ad, "$PGLOR,11,STA", brcm_error_log_allowlist)
+ if not pglor_list:
+ raise signals.TestFailure("Fail to get DPO logs from pixel logger")
+
+ for pglor in pglor_list:
+ power_res = re.compile(r',P,(\w),').search(pglor).group(1)
+ if power_res == "D":
+ always_full_power_count += 1
+ elif power_res == "F":
+ full_power_count += 1
+ elif power_res == "S":
+ power_save_count += 1
+ ad.log.info(sorted(pglor_list)[0])
+ ad.log.info(sorted(pglor_list)[-1])
+ ad.log.info("TestResult Total_Count %d" % len(pglor_list))
+ ad.log.info("TestResult Always_Full_Power_Count %d" %
+ always_full_power_count)
+ ad.log.info("TestResult Full_Power_Mode_Count %d" % full_power_count)
+ ad.log.info("TestResult Power_Save_Mode_Count %d" % power_save_count)
+ dpo_rate = (power_save_count / len(pglor_list))
+ dpo_engage_rate = "{percent:.2%}".format(percent=dpo_rate)
+ ad.log.info("Power Save Mode is ON for %d seconds during %d seconds test."
+ % (power_save_count, len(pglor_list)))
+ ad.log.info("TestResult DPO_Engage_Rate " + dpo_engage_rate)
+ threshold = "{percent:.0%}".format(percent=dpo_threshold / 100)
+ asserts.assert_true((dpo_rate * 100 > dpo_threshold) and not brcm_error_log,
+ "Power Save Mode only engaged %s in %d seconds test "
+ "with threshold %s.\nAbnormal behavior found as below."
+ "\n%s" % (dpo_engage_rate,
+ len(pglor_list),
+ threshold,
+ brcm_error_log))
+
+
+def pair_to_wearable(ad, ad1):
+ """Pair phone to watch via Bluetooth.
+
+ Args:
+ ad: A pixel phone.
+ ad1: A wearable project.
+ """
+ check_location_service(ad1)
+ utils.sync_device_time(ad1)
+ bt_model_name = ad.adb.getprop("ro.product.model")
+ bt_sn_name = ad.adb.getprop("ro.serialno")
+ bluetooth_name = bt_model_name +" " + bt_sn_name[10:]
+ fastboot_factory_reset(ad, False)
+ ad.log.info("Wait 1 min for wearable system busy time.")
+ time.sleep(60)
+ ad.adb.shell("input keyevent 4")
+ # Clear Denali paired data in phone.
+ ad1.adb.shell("pm clear com.google.android.gms")
+ ad1.adb.shell("pm clear com.google.android.apps.wear.companion")
+ ad1.adb.shell("am start -S -n com.google.android.apps.wear.companion/"
+ "com.google.android.apps.wear.companion.application.RootActivity")
+ uia_click(ad1, "Next")
+ uia_click(ad1, "I agree")
+ uia_click(ad1, bluetooth_name)
+ uia_click(ad1, "Pair")
+ uia_click(ad1, "Skip")
+ uia_click(ad1, "Skip")
+ uia_click(ad1, "Finish")
+ ad.log.info("Wait 3 mins for complete pairing process.")
+ time.sleep(180)
+ ad.adb.shell("settings put global stay_on_while_plugged_in 7")
+ check_location_service(ad)
+ enable_gnss_verbose_logging(ad)
+ if is_bluetooth_connected(ad, ad1):
+ ad.log.info("Pairing successfully.")
+ else:
+ raise signals.TestFailure("Fail to pair watch and phone successfully.")
+
+
+def is_bluetooth_connected(ad, ad1):
+ """Check if device's Bluetooth status is connected or not.
+
+ Args:
+ ad: A wearable project
+ ad1: A pixel phone.
+ """
+ return ad.droid.bluetoothIsDeviceConnected(ad1.droid.bluetoothGetLocalAddress())
+
+
+def detect_crash_during_tracking(ad, begin_time, type):
+ """Check if GNSS or GPSTool crash happened druing GNSS Tracking.
+
+ Args:
+ ad: An AndroidDevice object.
+ begin_time: Start Time to check if crash happened in logs.
+ type: Using GNSS or FLP reading method in GNSS tracking.
+ """
+ gnss_crash_list = [".*Fatal signal.*gnss",
+ ".*Fatal signal.*xtra",
+ ".*F DEBUG.*gnss",
+ ".*Fatal signal.*gpsd"]
+ if not ad.is_adb_logcat_on:
+ ad.start_adb_logcat()
+ for attr in gnss_crash_list:
+ gnss_crash_result = ad.adb.shell(
+ "logcat -d | grep -E -i '%s'" % attr)
+ if gnss_crash_result:
+ start_gnss_by_gtw_gpstool(ad, state=False, type=type)
+ raise signals.TestFailure(
+ "Test failed due to GNSS HAL crashed. \n%s" %
+ gnss_crash_result)
+ gpstool_crash_result = ad.search_logcat("Force finishing activity "
+ "com.android.gpstool/.GPSTool",
+ begin_time)
+ if gpstool_crash_result:
+ raise signals.TestError("GPSTool crashed. Abort test.")
+
+
+def is_wearable_btwifi(ad):
+ """Check device is wearable btwifi sku or not.
+
+ Args:
+ ad: An AndroidDevice object.
+ """
+ package = ad.adb.getprop("ro.product.product.name")
+ ad.log.debug("[ro.product.product.name]: [%s]" % package)
+ return "btwifi" in package
+
+
+def compare_watch_phone_location(ad,watch_file, phone_file):
+ """Compare watch and phone's FLP location to see if the same or not.
+
+ Args:
+ ad: An AndroidDevice object.
+ watch_file: watch's FLP locations
+ phone_file: phone's FLP locations
+ """
+ not_match_location_counts = 0
+ not_match_location = []
+ for watch_key, watch_value in watch_file.items():
+ if phone_file.get(watch_key):
+ lat_ads = abs(float(watch_value[0]) - float(phone_file[watch_key][0]))
+ lon_ads = abs(float(watch_value[1]) - float(phone_file[watch_key][1]))
+ if lat_ads > 0.000002 or lon_ads > 0.000002:
+ not_match_location_counts += 1
+ not_match_location += (watch_key, watch_value, phone_file[watch_key])
+ if not_match_location_counts > 0:
+ ad.log.info("There are %s not match locations: %s" %(not_match_location_counts, not_match_location))
+ ad.log.info("Watch's locations are not using Phone's locations.")
+ return False
+ else:
+ ad.log.info("Watch's locations are using Phone's location.")
+ return True
+
+
+def check_tracking_file(ad):
+ """Check tracking file in device and save "Latitude", "Longitude", and "Time" information.
+
+ Args:
+ ad: An AndroidDevice object.
+
+ Returns:
+ location_reports: A dict with [latitude, longitude]
+ """
+ location_reports = dict()
+ test_logfile = {}
+ file_count = int(ad.adb.shell("find %s -type f -iname *.txt | wc -l"
+ % GNSSSTATUS_LOG_PATH))
+ if file_count != 1:
+ ad.log.error("%d API logs exist." % file_count)
+ dir_file = ad.adb.shell("ls %s" % GNSSSTATUS_LOG_PATH).split()
+ for path_key in dir_file:
+ if fnmatch.fnmatch(path_key, "*.txt"):
+ logpath = posixpath.join(GNSSSTATUS_LOG_PATH, path_key)
+ out = ad.adb.shell("wc -c %s" % logpath)
+ file_size = int(out.split(" ")[0])
+ if file_size < 10:
+ ad.log.info("Skip log %s due to log size %d bytes" %
+ (path_key, file_size))
+ continue
+ test_logfile = logpath
+ if not test_logfile:
+ raise signals.TestError("Failed to get test log file in device.")
+ lines = ad.adb.shell("cat %s" % test_logfile).split("\n")
+ for file_data in lines:
+ if "Latitude:" in file_data:
+ file_lat = ("%.6f" %float(file_data[9:]))
+ elif "Longitude:" in file_data:
+ file_long = ("%.6f" %float(file_data[11:]))
+ elif "Time:" in file_data:
+ file_time = (file_data[17:25])
+ location_reports[file_time] = [file_lat, file_long]
+ return location_reports
+
+
+def uia_click(ad, matching_text):
+ """Use uiautomator to click objects.
+
+ Args:
+ ad: An AndroidDevice object.
+ matching_text: Text of the target object to click
+ """
+ if ad.uia(textMatches=matching_text).wait.exists(timeout=60000):
+
+ ad.uia(textMatches=matching_text).click()
+ ad.log.info("Click button %s" % matching_text)
+ else:
+ ad.log.error("No button named %s" % matching_text)
+
+
+def delete_bcm_nvmem_sto_file(ad):
+ """Delete BCM's NVMEM ephemeris gldata.sto.
+
+ Args:
+ ad: An AndroidDevice object.
+ """
+ remount_device(ad)
+ rm_cmd = "rm -rf {}".format(BCM_NVME_STO_PATH)
+ status = ad.adb.shell(rm_cmd)
+ ad.log.info("Delete BCM's NVMEM ephemeris files.\n%s" % status)
+
+
+def bcm_gps_xml_add_option(ad,
+ search_line=None,
+ append_txt=None,
+ gps_xml_path=BCM_GPS_XML_PATH):
+ """Append parameter setting in gps.xml for BCM solution
+
+ Args:
+ ad: An AndroidDevice object.
+ search_line: Pattern matching of target
+ line for appending new line data.
+ append_txt: New line that will be appended after the search_line.
+ gps_xml_path: gps.xml file location of DUT
+ """
+ remount_device(ad)
+ #Update gps.xml
+ if not search_line or not append_txt:
+ ad.log.info("Nothing for update.")
+ else:
+ tmp_log_path = tempfile.mkdtemp()
+ ad.pull_files(gps_xml_path, tmp_log_path)
+ gps_xml_tmp_path = os.path.join(tmp_log_path, "gps.xml")
+ gps_xml_file = open(gps_xml_tmp_path, "r")
+ lines = gps_xml_file.readlines()
+ gps_xml_file.close()
+ fout = open(gps_xml_tmp_path, "w")
+ append_txt_tag = append_txt.strip()
+ for line in lines:
+ if append_txt_tag in line:
+ ad.log.info('{} is already in the file. Skip'.format(append_txt))
+ continue
+ fout.write(line)
+ if search_line in line:
+ fout.write(append_txt)
+ ad.log.info("Update new line: '{}' in gps.xml.".format(append_txt))
+ fout.close()
+
+ # Update gps.xml with gps_new.xml
+ ad.push_system_file(gps_xml_tmp_path, gps_xml_path)
+
+ # remove temp folder
+ shutil.rmtree(tmp_log_path, ignore_errors=True)
+
+
+def bcm_gps_ignore_rom_alm(ad):
+ """ Update BCM gps.xml with ignoreRomAlm="True"
+ Args:
+ ad: An AndroidDevice object.
+ """
+ search_line_tag = '<gll\n'
+ append_line_str = ' IgnoreRomAlm=\"true\"\n'
+ bcm_gps_xml_add_option(ad, search_line_tag, append_line_str)
+
+
+def check_inject_time(ad):
+ """Check if watch could get the UTC time.
+
+ Args:
+ ad: An AndroidDevice object.
+ """
+ for i in range(1, 6):
+ time.sleep(10)
+ inject_time_results = ad.search_logcat("GPSIC.OUT.gps_inject_time")
+ ad.log.info("Check time injected - attempt %s" % i)
+ if inject_time_results:
+ ad.log.info("Time is injected successfully.")
+ return True
+ raise signals.TestFailure("Fail to get time injected within %s attempts." % i)
+
+
+def enable_framework_log(ad):
+ """Enable framework log for wearable to check UTC time download.
+
+ Args:
+ ad: An AndroidDevice object.
+ """
+ remount_device(ad)
+ time.sleep(3)
+ ad.log.info("Start to enable framwork log for wearable.")
+ ad.adb.shell("echo 'log.tag.LocationManagerService=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.GnssLocationProvider=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.GpsNetInitiatedHandler=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.GnssNetInitiatedHandler=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.GnssNetworkConnectivityHandler=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.NtpTimeHelper=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.ConnectivityService=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.GnssPsdsDownloader=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.GnssVisibilityControl=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.Gnss=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.GnssConfiguration=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.ImsPhone=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.GsmCdmaPhone=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.Phone=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("echo 'log.tag.GCoreFlp=VERBOSE' >> /data/local.prop")
+ ad.adb.shell("chmod 644 /data/local.prop")
+ ad.adb.shell("echo 'LogEnabled=true' > /data/vendor/gps/libgps.conf")
+ ad.adb.shell("chown gps.system /data/vendor/gps/libgps.conf")
+ ad.adb.shell("sync")
+ reboot(ad)
+ ad.log.info("Wait 2 mins for Wearable booting system busy")
+ time.sleep(120)
diff --git a/acts_tests/acts_contrib/test_utils/net/connectivity_const.py b/acts_tests/acts_contrib/test_utils/net/connectivity_const.py
index 49996c6..591c83f 100644
--- a/acts_tests/acts_contrib/test_utils/net/connectivity_const.py
+++ b/acts_tests/acts_contrib/test_utils/net/connectivity_const.py
@@ -74,13 +74,29 @@
MULTIPATH_PREFERENCE_PERFORMANCE = 1 << 2
# Private DNS constants
-DNS_GOOGLE = "dns.google"
-DNS_QUAD9 = "dns.quad9.net"
-DNS_CLOUDFLARE = "1dot1dot1dot1.cloudflare-dns.com"
+DNS_GOOGLE_HOSTNAME = "dns.google"
+DNS_QUAD9_HOSTNAME = "dns.quad9.net"
+DNS_CLOUDFLARE_HOSTNAME = "1dot1dot1dot1.cloudflare-dns.com"
+DOH_CLOUDFLARE_HOSTNAME = "cloudflare-dns.com"
PRIVATE_DNS_MODE_OFF = "off"
PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic"
PRIVATE_DNS_MODE_STRICT = "hostname"
+DNS_SUPPORT_TYPE = {
+ DNS_GOOGLE_HOSTNAME: ["Do53", "DoT", "DoH"],
+ DNS_CLOUDFLARE_HOSTNAME: ["Do53","DoT"],
+ DOH_CLOUDFLARE_HOSTNAME: ["DoH"]
+}
+
+DNS_GOOGLE_ADDR_V4 = ["8.8.4.4", "8.8.8.8"]
+DNS_GOOGLE_ADDR_V6 = ["2001:4860:4860::8888",
+ "2001:4860:4860::8844"]
+DNS_CLOUDFLARE_ADDR_V4 = ["1.1.1.1", "1.0.0.1"]
+DOH_CLOUDFLARE_ADDR_V4 = ["104.16.248.249", "104.16.249.249"]
+DOH_CLOUDFLARE_ADDR_V6 = ["2606:4700::6810:f8f9",
+ "2606:4700::6810:f9f9"]
+
+
# IpSec constants
SOCK_STREAM = 1
SOCK_DGRAM = 2
diff --git a/acts_tests/acts_contrib/test_utils/net/connectivity_test_utils.py b/acts_tests/acts_contrib/test_utils/net/connectivity_test_utils.py
index d35fe04..1b547e3 100644
--- a/acts_tests/acts_contrib/test_utils/net/connectivity_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/net/connectivity_test_utils.py
@@ -104,7 +104,14 @@
msg = "Failed to receive confirmation of stopping socket keepalive"
return _listen_for_keepalive_event(ad, key, msg, "Stopped")
+
def set_private_dns(ad, dns_mode, hostname=None):
+ """ Set private DNS mode and DNS server hostname on DUT
+
+ :param ad: Device under test (DUT)
+ :param dns_mode: DNS mode, including OFF, OPPORTUNISTIC, STRICT
+ :param hostname: DNS server hostname
+ """
""" Set private DNS mode on dut """
if dns_mode == cconst.PRIVATE_DNS_MODE_OFF:
ad.droid.setPrivateDnsMode(False)
@@ -114,6 +121,3 @@
mode = ad.droid.getPrivateDnsMode()
host = ad.droid.getPrivateDnsSpecifier()
ad.log.info("DNS mode is %s and DNS server is %s" % (mode, host))
- asserts.assert_true(dns_mode == mode and host == hostname,
- "Failed to set DNS mode to %s and DNS to %s" % \
- (dns_mode, hostname))
diff --git a/acts_tests/acts_contrib/test_utils/net/net_test_utils.py b/acts_tests/acts_contrib/test_utils/net/net_test_utils.py
index ba1f513d..b281bd7 100644
--- a/acts_tests/acts_contrib/test_utils/net/net_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/net/net_test_utils.py
@@ -24,15 +24,18 @@
from acts import utils
from acts.controllers import adb
from acts.controllers.adb_lib.error import AdbError
+from acts.libs.proc import job
from acts.utils import start_standing_subprocess
from acts.utils import stop_standing_subprocess
from acts_contrib.test_utils.net import connectivity_const as cconst
+from acts_contrib.test_utils.tel import tel_defines
from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
-from scapy.all import get_if_list
+from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from scapy.config import conf
+from scapy.compat import plain_str
VPN_CONST = cconst.VpnProfile
VPN_TYPE = cconst.VpnProfileType
@@ -40,6 +43,8 @@
TCPDUMP_PATH = "/data/local/tmp/"
USB_CHARGE_MODE = "svc usb setFunctions"
USB_TETHERING_MODE = "svc usb setFunctions rndis"
+ENABLE_HARDWARE_OFFLOAD = "settings put global tether_offload_disabled 0"
+DISABLE_HARDWARE_OFFLOAD = "settings put global tether_offload_disabled 1"
DEVICE_IP_ADDRESS = "ip address"
LOCALHOST = "192.168.1.1"
@@ -287,7 +292,7 @@
return vpn_profile
-def start_tcpdump(ad, test_name):
+def start_tcpdump(ad, test_name, interface="any"):
"""Start tcpdump on all interfaces.
Args:
@@ -301,8 +306,8 @@
file_name = "%s/tcpdump_%s_%s.pcap" % (TCPDUMP_PATH, ad.serial, test_name)
ad.log.info("tcpdump file is %s", file_name)
- cmd = "adb -s {} shell tcpdump -i any -s0 -w {}".format(ad.serial,
- file_name)
+ cmd = "adb -s {} shell tcpdump -i {} -s0 -w {}".format(ad.serial,
+ interface, file_name)
try:
return start_standing_subprocess(cmd, 5)
except Exception:
@@ -462,6 +467,34 @@
return operator in carrier_supports_ipv6
+def is_carrier_supports_entitlement(dut):
+ """Verify if carrier supports entitlement
+
+ Args:
+ dut: Android device
+
+ Return:
+ True if carrier supports entitlement, otherwise false
+ """
+
+ carriers_supports_entitlement = [
+ tel_defines.CARRIER_VZW,
+ tel_defines.CARRIER_ATT,
+ tel_defines.CARRIER_TMO,
+ tel_defines.CARRIER_SBM]
+ operator = get_operator_name("log", dut)
+ return operator in carriers_supports_entitlement
+
+
+def set_cap_net_raw_capability():
+ """Set the CAP_NET_RAW capability
+
+ To send the Scapy packets, we need to get the CAP_NET_RAW capability first.
+ """
+ cap_net_raw = "sudo setcap cap_net_raw=eip $(readlink -f $(which act.py))"
+ utils.exe_cmd(cap_net_raw)
+
+
def supports_ipv6_tethering(self, dut):
"""Check if provider supports IPv6 tethering.
@@ -478,19 +511,15 @@
def start_usb_tethering(ad):
- """Start USB tethering.
+ """Start USB tethering using #startTethering API.
+
+ Enable USB tethering by #startTethering API will break the RPC session,
+ Make sure you call #ad.recreate_services after call this API - b/149116235
Args:
- ad: android device object
+ ad: AndroidDevice object
"""
- # TODO: test USB tethering by #startTethering API - b/149116235
- ad.log.info("Starting USB Tethering")
- ad.stop_services()
- ad.adb.shell(USB_TETHERING_MODE, ignore_status=True)
- ad.adb.wait_for_device()
- ad.start_services()
- if "rndis" not in ad.adb.shell(DEVICE_IP_ADDRESS):
- raise signals.TestFailure("Unable to enable USB tethering.")
+ ad.droid.connectivityStartTethering(tel_defines.TETHERING_USB, False)
def stop_usb_tethering(ad):
@@ -524,3 +553,54 @@
return new_ifaces.pop()
time.sleep(1)
asserts.fail("Timeout waiting for tethering interface on host")
+
+
+def get_if_list():
+ """Returns a list containing all network interfaces.
+
+ The newest version of Scapy.get_if_list() returns the cached interfaces,
+ which might be out-dated, and unable to perceive the interface changes.
+ Use this method when need to monitoring the network interfaces changes.
+ Reference: https://github.com/secdev/scapy/pull/2707
+
+ Returns:
+ A list of the latest network interfaces. For example:
+ ['cvd-ebr', ..., 'eno1', 'enx4afa19a8dde1', 'lo', 'wlxd03745d68d88']
+ """
+
+ # Get ifconfig output
+ result = job.run([conf.prog.ifconfig])
+ if result.exit_status:
+ raise asserts.fail(
+ "Failed to execute ifconfig: {}".format(plain_str(result.stderr)))
+
+ interfaces = [
+ line[:line.find(':')] for line in plain_str(result.stdout).splitlines()
+ if ": flags" in line.lower()
+ ]
+ return interfaces
+
+
+def enable_hardware_offload(ad):
+ """Enable hardware offload using adb shell command.
+
+ Args:
+ ad: Android device object
+ """
+ ad.log.info("Enabling hardware offload.")
+ ad.adb.shell(ENABLE_HARDWARE_OFFLOAD, ignore_status=True)
+ ad.reboot()
+ time.sleep(tel_defines.WAIT_TIME_AFTER_REBOOT)
+
+
+def disable_hardware_offload(ad):
+ """Disable hardware offload using adb shell command.
+
+ Args:
+ ad: Android device object
+ """
+ ad.log.info("Disabling hardware offload.")
+ ad.adb.shell(DISABLE_HARDWARE_OFFLOAD, ignore_status=True)
+ ad.reboot()
+ time.sleep(tel_defines.WAIT_TIME_AFTER_REBOOT)
+
diff --git a/acts_tests/acts_contrib/test_utils/net/ui_utils.py b/acts_tests/acts_contrib/test_utils/net/ui_utils.py
index 4dadda1..143719e 100644
--- a/acts_tests/acts_contrib/test_utils/net/ui_utils.py
+++ b/acts_tests/acts_contrib/test_utils/net/ui_utils.py
@@ -129,16 +129,23 @@
long_clickable
password
selected
+ A special key/value: matching_node key is used to identify If more than one nodes have the same key/value,
+ the matching_node stands for which matching node should be fetched.
Returns:
XML node of the UI element or None if not found.
"""
nodes = screen_dump_xml.getElementsByTagName('node')
+ matching_node = kwargs.pop('matching_node', 1)
+ count = 1
for node in nodes:
if match_node(node, **kwargs):
- logging.debug('Found a node matching conditions: %s',
- get_key_value_pair_strings(kwargs))
- return node
+ if count == matching_node:
+ logging.debug('Found a node matching conditions: %s',
+ get_key_value_pair_strings(kwargs))
+ return node
+ count += 1
+ return None
def wait_and_get_xml_node(device, timeout, child=None, sibling=None, **kwargs):
diff --git a/acts_tests/acts_contrib/test_utils/power/PowerBTBaseTest.py b/acts_tests/acts_contrib/test_utils/power/PowerBTBaseTest.py
index 056787c..8f19606 100644
--- a/acts_tests/acts_contrib/test_utils/power/PowerBTBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/power/PowerBTBaseTest.py
@@ -49,6 +49,7 @@
time.sleep(time_wait_in_between)
attenuation_delta = obj_atten.get_atten() - attenuation_target
obj_atten.set_atten(attenuation_target)
+ time.sleep(time_wait_in_between)
class PowerBTBaseTest(PBT.PowerBaseTest):
diff --git a/acts_tests/acts_contrib/test_utils/power/PowerBaseTest.py b/acts_tests/acts_contrib/test_utils/power/PowerBaseTest.py
index 1481e95..11094fb 100644
--- a/acts_tests/acts_contrib/test_utils/power/PowerBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/power/PowerBaseTest.py
@@ -21,6 +21,7 @@
import time
import acts.controllers.power_monitor as power_monitor_lib
+import acts.controllers.monsoon as monsoon_controller
import acts.controllers.iperf_server as ipf
from acts import asserts
from acts import base_test
@@ -28,7 +29,6 @@
from acts.metrics.loggers.blackbox import BlackboxMetricLogger
from acts_contrib.test_utils.power.loggers.power_metric_logger import PowerMetricLogger
from acts_contrib.test_utils.power import plot_utils
-from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
RESET_BATTERY_STATS = 'dumpsys batterystats --reset'
IPERF_TIMEOUT = 180
@@ -106,7 +106,14 @@
Raises an exception if there are no controllers available.
"""
- if hasattr(self, 'monsoons'):
+ if hasattr(self, 'bitses'):
+ if hasattr(self, 'monsoons'):
+ self.log.info('Destroying monsoon controller.')
+ monsoon_controller.destroy(self.monsoons)
+ time.sleep(2)
+ self.power_monitor = self.bitses[0]
+ self.power_monitor.setup(registry=self.user_params)
+ elif hasattr(self, 'monsoons'):
self.power_monitor = power_monitor_lib.PowerMonitorMonsoonFacade(
self.monsoons[0])
self.monsoons[0].set_max_current(8.0)
@@ -142,7 +149,8 @@
extra_wait=None,
iperf_duration=None,
pass_fail_tolerance=THRESHOLD_TOLERANCE_DEFAULT,
- mon_voltage=PHONE_BATTERY_VOLTAGE_DEFAULT)
+ mon_voltage=PHONE_BATTERY_VOLTAGE_DEFAULT,
+ ap_dtim_period=None)
# Setup the must have controllers, phone and monsoon
self.dut = self.android_devices[0]
@@ -185,7 +193,6 @@
# Sync device time, timezone and country code
utils.require_sl4a((self.dut, ))
utils.sync_device_time(self.dut)
- wutils.set_wifi_country_code(self.dut, 'US')
screen_on_img = self.user_params.get('screen_on_img', [])
if screen_on_img:
@@ -208,8 +215,6 @@
# Set the device into rockbottom state
self.dut_rockbottom()
- wutils.reset_wifi(self.dut)
- wutils.wifi_toggle_state(self.dut, False)
# Wait for extra time if needed for the first test
if self.extra_wait:
@@ -464,6 +469,7 @@
measure_after_seconds=self.mon_info.offset,
hz=self.mon_info.freq)
self.power_monitor.measure(measurement_args=measurement_args,
+ measurement_name=self.test_name,
start_time=device_to_host_offset,
monsoon_output_path=data_path)
self.power_monitor.release_resources()
diff --git a/acts_tests/acts_contrib/test_utils/power/PowerGTWGnssBaseTest.py b/acts_tests/acts_contrib/test_utils/power/PowerGTWGnssBaseTest.py
index 3f8fd3a..baedb7e 100644
--- a/acts_tests/acts_contrib/test_utils/power/PowerGTWGnssBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/power/PowerGTWGnssBaseTest.py
@@ -92,6 +92,7 @@
lowpower: a boolean to set GNSS Low Power Mode.
meas: a boolean to set GNSS Measurement registeration.
"""
+ c_power, c_tracking, c_acquisition = self.request_power_stat()
self.ad.adb.shell('settings put secure location_mode 3')
gutils.start_gnss_by_gtw_gpstool(self.ad, True, 'gnss', True, freq,
lowpower, meas)
@@ -106,6 +107,10 @@
self.ad.send_keycode('WAKEUP')
gutils.start_gnss_by_gtw_gpstool(self.ad, False, 'gnss')
+ n_power, n_tracking, n_acquisition = self.request_power_stat()
+ self.ad.log.info("TestResult Total_power: %.2f" %(n_power - c_power))
+ self.ad.log.info("TestResult Tracking: %.2f" %(n_tracking - c_tracking))
+ self.ad.log.info("TestResult Acquisition: %.2f" %(n_acquisition - c_acquisition))
gutils.parse_gtw_gpstool_log(self.ad, self.test_location, type='gnss')
def calibrate_avg_current(self, samples):
@@ -139,3 +144,33 @@
self.ad.log.info(result)
raise signals.TestFailure('DPO is not able to Turn: %s' % enable)
self.dut_rockbottom()
+
+ def request_power_stat(self):
+ """Request the power state via command.
+ Returns:
+ total_power, tracking, acquisition power consumption.
+ If the device does not support, return 0, 0, 0
+ """
+ self.ad.adb.shell('cmd location providers send-extra-command gps request_power_stats')
+ time.sleep(1)
+ res = self.ad.adb.shell('dumpsys location | grep -A 10 -i \'power stats\'')
+ if res:
+ for line in res.split("\n"):
+ if "total power" in line:
+ total_power = line.split(" ")[-1].split("mJ")[0]
+ if "single-band tracking" in line:
+ single_tracking = line.split(" ")[-1].split("mJ")[0]
+ self.ad.log.info(single_tracking)
+ if "multi-band tracking" in line:
+ multi_tracking = line.split(" ")[-1].split("mJ")[0]
+ if "single-band acquisition" in line:
+ single_acquisition = line.split(" ")[-1].split("mJ")[0]
+ if "multi-band acquisition" in line:
+ multi_acquisition = line.split(" ")[-1].split("mJ")[0]
+ tracking = float(single_tracking) + float(multi_tracking)
+ acquisition = float(single_acquisition) + float(multi_acquisition)
+ self.ad.log.info("total power: %.2f" %float(total_power))
+ self.ad.log.info("tracking: %.2f" %tracking)
+ self.ad.log.info("acquisition: %.2f" %acquisition)
+ return float(total_power), tracking, acquisition
+ return 0, 0, 0
diff --git a/acts_tests/acts_contrib/test_utils/power/PowerWiFiBaseTest.py b/acts_tests/acts_contrib/test_utils/power/PowerWiFiBaseTest.py
index 7ca573e..4a93afb 100644
--- a/acts_tests/acts_contrib/test_utils/power/PowerWiFiBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/power/PowerWiFiBaseTest.py
@@ -49,7 +49,9 @@
self.iperf_server = self.iperf_servers[0]
if self.iperf_duration:
self.mon_duration = self.iperf_duration - self.mon_offset - IPERF_TAIL
- self.create_monsoon_info()
+ self.mon_info = self.create_monsoon_info()
+
+ wutils.set_wifi_country_code(self.dut, 'US')
def teardown_test(self):
"""Tear down necessary objects after test case is finished.
@@ -118,7 +120,8 @@
network,
bandwidth=80,
connect=True,
- ap=None):
+ ap=None,
+ dtim_period=None):
"""Setup AP and connect DUT to it.
Args:
@@ -126,17 +129,23 @@
bandwidth: bandwidth of the WiFi network to be setup
connect: indicator of if connect dut to the network after setup
ap: access point object, default is None to find the main AP
+ dtim_period: the dtim period of access point
Returns:
self.brconfigs: dict for bridge interface configs
"""
wutils.wifi_toggle_state(self.dut, True)
+ if not dtim_period:
+ dtim_period = self.ap_dtim_period
if not ap:
if hasattr(self, 'access_points'):
- self.brconfigs = wputils.ap_setup(self.access_point,
- network,
- bandwidth=bandwidth)
+ self.brconfigs = wputils.ap_setup(
+ self.access_point,
+ network,
+ bandwidth=bandwidth,
+ dtim_period=dtim_period)
else:
- self.brconfigs = wputils.ap_setup(ap, network, bandwidth=bandwidth)
+ self.brconfigs = wputils.ap_setup(
+ ap, network, bandwidth=bandwidth, dtim_period=dtim_period)
if connect:
wutils.wifi_connect(self.dut, network, num_of_tries=3)
@@ -152,10 +161,23 @@
tag = ''
if self.iperf_duration:
throughput = self.process_iperf_results()
- plot_title = '{}_{}_{}_RSSI_{0:d}dBm_Throughput_{1:.2f}Mbps'.format(
- self.test_name, self.dut.model,
- self.dut.build_info['build_id'], self.RSSI, throughput)
+ plot_title = ('{0}_{1}_{2}_RSSI_{3:d}dBm_Throughput_{4:.2f}'
+ 'Mbps'.format(self.test_name,
+ self.dut.model,
+ self.dut.build_info['build_id'],
+ self.RSSI,
+ throughput))
plot_utils.current_waveform_plot(samples, self.mon_voltage,
self.mon_info.data_path,
plot_title)
return samples
+
+ def setup_test(self):
+ """Set up test specific parameters or configs.
+
+ """
+ super().setup_test()
+
+ wutils.reset_wifi(self.dut)
+ wutils.wifi_toggle_state(self.dut, False)
+
diff --git a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_hotspot_traffic_power_test.py b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_hotspot_traffic_power_test.py
index a4c2df6..755f511 100644
--- a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_hotspot_traffic_power_test.py
+++ b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_hotspot_traffic_power_test.py
@@ -15,8 +15,8 @@
# limitations under the License.
import time
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
import acts_contrib.test_utils.power.cellular.cellular_traffic_power_test as ctpt
diff --git a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_traffic_power_test.py b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_traffic_power_test.py
index 21e3dcf..67dc214 100644
--- a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_traffic_power_test.py
+++ b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_traffic_power_test.py
@@ -24,8 +24,9 @@
from acts_contrib.test_utils.power import IperfHelper as IPH
from acts_contrib.test_utils.power import plot_utils
import acts_contrib.test_utils.power.cellular.cellular_power_base_test as PWCEL
-from acts_contrib.test_utils.tel import tel_test_utils as telutils
-
+from acts_contrib.test_utils.tel.tel_logging_utils import start_adb_tcpdump
+from acts_contrib.test_utils.tel.tel_logging_utils import stop_adb_tcpdump
+from acts_contrib.test_utils.tel.tel_logging_utils import get_tcpdump_log
class PowerTelTrafficTest(PWCEL.PowerCellularLabBaseTest):
""" Cellular traffic power test.
@@ -204,8 +205,8 @@
# Pull TCP logs if enabled
if self.tcp_dumps:
self.log.info('Pulling TCP dumps.')
- telutils.stop_adb_tcpdump(self.dut)
- telutils.get_tcpdump_log(self.dut)
+ stop_adb_tcpdump(self.dut)
+ get_tcpdump_log(self.dut)
throughput = {}
@@ -333,7 +334,7 @@
# Enable TCP logger.
if self.tcp_dumps:
self.log.info('Enabling TCP logger.')
- telutils.start_adb_tcpdump(self.dut)
+ start_adb_tcpdump(self.dut)
return iperf_helpers
diff --git a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_voice_call_power_test.py b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_voice_call_power_test.py
index 802d8cc..f64a1e4 100644
--- a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_voice_call_power_test.py
+++ b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_voice_call_power_test.py
@@ -19,7 +19,8 @@
from acts.controllers.anritsu_lib.md8475a import VirtualPhoneAutoAnswer
import acts_contrib.test_utils.power.cellular.cellular_power_base_test as PWCEL
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call, hangup_call, set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_test_utils import set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call, hangup_call
class PowerTelVoiceCallTest(PWCEL.PowerCellularLabBaseTest):
diff --git a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_volte_power_test.py b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_volte_power_test.py
index 986878d..e3b9531 100644
--- a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_volte_power_test.py
+++ b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_volte_power_test.py
@@ -20,7 +20,8 @@
import acts.controllers.anritsu_lib.md8475a as md8475a
import acts_contrib.test_utils.power.cellular.cellular_power_base_test as PWCEL
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call, hangup_call, set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_test_utils import set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call, hangup_call
class PowerTelVoLTECallTest(PWCEL.PowerCellularLabBaseTest):
diff --git a/acts_tests/acts_contrib/test_utils/power/plot_utils.py b/acts_tests/acts_contrib/test_utils/power/plot_utils.py
index b2a42ab..99d22ac 100644
--- a/acts_tests/acts_contrib/test_utils/power/plot_utils.py
+++ b/acts_tests/acts_contrib/test_utils/power/plot_utils.py
@@ -14,16 +14,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os
+import datetime
import logging
-import numpy
import math
+import numpy
+import os
-from bokeh.layouts import layout
-from bokeh.models import CustomJS, ColumnDataSource
from bokeh.models import tools as bokeh_tools
+from bokeh.models import CustomJS, ColumnDataSource
from bokeh.models.widgets import DataTable, TableColumn
+from bokeh.models.formatters import DatetimeTickFormatter
from bokeh.plotting import figure, output_file, save
+from bokeh.layouts import layout
def current_waveform_plot(samples, voltage, dest_path, plot_title):
@@ -48,16 +50,17 @@
"""
logging.info('Plotting the power measurement data.')
- time_relative = [sample[0] for sample in samples]
- duration = time_relative[-1] - time_relative[0]
+ duration = samples[-1][0] - samples[0][0]
current_data = [sample[1] * 1000 for sample in samples]
avg_current = sum(current_data) / len(current_data)
-
color = ['navy'] * len(samples)
+ time_realtime = [
+ datetime.datetime.fromtimestamp(sample[0]) for sample in samples
+ ]
# Preparing the data and source link for bokehn java callback
source = ColumnDataSource(
- data=dict(x=time_relative, y=current_data, color=color))
+ data=dict(x=time_realtime, y=current_data, color=color))
s2 = ColumnDataSource(
data=dict(a=[duration],
b=[round(avg_current, 2)],
@@ -81,7 +84,8 @@
output_file(os.path.join(dest_path, plot_title + '.html'))
tools = 'box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save'
# Create a new plot with the datatable above
- plot = figure(plot_width=1300,
+ plot = figure(x_axis_type='datetime',
+ plot_width=1300,
plot_height=700,
title=plot_title,
tools=tools)
@@ -91,6 +95,13 @@
plot.circle('x', 'y', source=source, size=0.5, fill_color='color')
plot.xaxis.axis_label = 'Time (s)'
plot.yaxis.axis_label = 'Current (mA)'
+ plot.xaxis.formatter = DatetimeTickFormatter(
+ seconds=["%H:%M:%S"],
+ milliseconds=["%H:%M:%S:%3Ns"],
+ microseconds=["%H:%M:%S:%fus"],
+ minutes=["%H:%M:%S"],
+ minsec=["%H:%M:%S"],
+ hours=["%H:%M:%S"])
# Callback JavaScript
source.selected.js_on_change(
@@ -120,7 +131,7 @@
}
ym /= inds.length
ts = max - min
- d2['a'].push(Math.round(ts*1000.0)/1000.0)
+ d2['a'].push(Math.round(ts*1000.0)/1000000.0)
d2['b'].push(Math.round(ym*100.0)/100.0)
d2['c'].push(Math.round(ym*4.2*100.0)/100.0)
d2['d'].push(Math.round(ym*4.2*ts*100.0)/100.0)
diff --git a/acts_tests/acts_contrib/test_utils/tel/GFTInOutBaseTest.py b/acts_tests/acts_contrib/test_utils/tel/GFTInOutBaseTest.py
index a55959a..7e28139 100644
--- a/acts_tests/acts_contrib/test_utils/tel/GFTInOutBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/tel/GFTInOutBaseTest.py
@@ -14,42 +14,25 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-
-
-import sys
-import collections
-import random
import time
-import datetime
-import os
-import logging
-import subprocess
-import math
-import re
-
from acts import asserts
from acts.test_decorators import test_info
from acts.test_decorators import test_tracker_info
from acts.logger import epoch_to_log_line_timestamp
from acts.utils import get_current_epoch_time
-
+from acts.libs.utils.multithread import multithread_func
from acts.base_test import BaseTestClass
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import run_multithread_func
+from acts_contrib.test_utils.tel.tel_logging_utils import get_screen_shot_log
+from acts_contrib.test_utils.tel.tel_logging_utils import get_screen_shot_logs
+from acts_contrib.test_utils.tel.tel_logging_utils import log_screen_shot
from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_log
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_logs
-from acts_contrib.test_utils.tel.tel_test_utils import log_screen_shot
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call
-
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
from acts_contrib.test_utils.tel.gft_inout_utils import mo_voice_call
from acts_contrib.test_utils.tel.gft_inout_utils import get_voice_call_type
from acts_contrib.test_utils.tel.gft_inout_utils import verify_data_connection
from acts_contrib.test_utils.tel.gft_inout_utils import check_network_service
-
from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_POWER_LEVEL
from acts_contrib.test_utils.tel.gft_inout_defines import IN_SERVICE_POWER_LEVEL
from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_AREA
@@ -58,24 +41,27 @@
from acts_contrib.test_utils.tel.gft_inout_defines import NO_WIFI_AREA
from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_TIME
from acts_contrib.test_utils.tel.gft_inout_defines import WAIT_FOR_SERVICE_TIME
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
CELLULAR_PORT = 0
WIFI_PORT = 1
UNKNOWN = "UNKNOWN"
+
class GFTInOutBaseTest(TelephonyBaseTest):
def __init__(self, controllers):
TelephonyBaseTest.__init__(self, controllers)
self.my_error_msg = ""
+ self.tel_logger = TelephonyMetricLogger.for_test_case()
def setup_test(self):
TelephonyBaseTest.setup_test(self)
+ self.user_params["telephony_auto_rerun"] = 0
self.my_error_msg = ""
def teardown_test(self):
TelephonyBaseTest.teardown_test(self)
begin_time = get_current_epoch_time()
- self._take_bug_report(self.test_name, begin_time)
for ad in self.android_devices:
hangup_call(self.log, ad)
get_screen_shot_logs(self.android_devices)
@@ -84,20 +70,24 @@
def check_network(self):
"""check service state of network
-
Returns:
return True if android_devices are in service else return false
"""
for ad in self.android_devices:
network_type_voice = ad.droid.telephonyGetCurrentVoiceNetworkType()
network_type_data = ad.droid.telephonyGetCurrentDataNetworkType()
+ data_state = ad.droid.telephonyGetDataConnectionState()
service_state = get_service_state_by_adb(ad.log,ad)
- sim_state = ad.droid.telephonyGetSimState()
wifi_info = ad.droid.wifiGetConnectionInfo()
- if wifi_info["supplicant_state"] == "completed":
- ad.log.info("Wifi is connected to %s" %(wifi_info["SSID"]))
+ sim_state = ad.droid.telephonyGetSimState()
+ if ad.droid.wifiCheckState():
+ if wifi_info["supplicant_state"] == "completed":
+ ad.log.info("Wifi is connected=%s" %(wifi_info["SSID"]))
+ else:
+ ad.log.info("wifi_info =%s" %(wifi_info))
else:
- ad.log.info("wifi_info =%s" %(wifi_info))
+ ad.log.info("Wifi state is down.")
+ ad.log.info("data_state=%s" %(data_state))
ad.log.info("sim_state=%s" %(sim_state))
ad.log.info("networkType_voice=%s" %(network_type_voice))
ad.log.info("network_type_data=%s" %(network_type_data))
@@ -106,38 +96,41 @@
return False
return True
-
- def adjust_cellular_signal(self, power):
+ def adjust_cellular_signal(self, power, adjust_gradually=False):
"""Sets the attenuation value of cellular port
-
Args:
power: power level for attenuator to be set
-
Returns:
return True if ceullular port is set
"""
if self.user_params.get("Attenuator"):
- self.log.info("adjust cellular signal set mini-circuits to %s" %(power))
- self.attenuators[CELLULAR_PORT].set_atten(power)
+ if adjust_gradually:
+ self.log.info("adjust cellular signal gradually to mini-circuits to %s" %(power))
+ self.adjust_atten_slowly(10, NO_SERVICE_AREA)
+ else:
+ self.log.info("adjust cellular signal set mini-circuits to %s" %(power))
+ self.attenuators[CELLULAR_PORT].set_atten(power)
return True
else:
self.log.info("Attenuator is set to False in config file")
return False
- def adjust_wifi_signal(self, power):
+ def adjust_wifi_signal(self, power, adjust_gradually=False):
"""Sets the attenuation value of wifi port
-
Args:
power: power level for attenuator to be set
-
Returns:
return True if wifi port is set
"""
if self.user_params.get("Attenuator"):
- self.log.info("adjust wifi signal set mini-circuits to %s" %(power))
- self.attenuators[WIFI_PORT].set_atten(power)
- self.attenuators[2].set_atten(power)
- self.attenuators[3].set_atten(power)
+ if adjust_gradually:
+ self.log.info("adjust wifi signal set mini-circuits to %s" %(power))
+ self.adjust_atten_slowly(10, NO_WIFI_AREA)
+ else:
+ self.log.info("adjust wifi signal and set mini-circuits to %s" %(power))
+ self.attenuators[WIFI_PORT].set_atten(power)
+ self.attenuators[2].set_atten(power)
+ self.attenuators[3].set_atten(power)
else:
self.log.info("Attenuator is set to False in config file")
return False
@@ -145,10 +138,8 @@
def adjust_attens(self, power):
"""Sets the attenuation value of all attenuators in the group
-
Args:
power: power level for attenuator to be set
-
Returns:
return True if all ports are set
"""
@@ -165,11 +156,9 @@
def adjust_atten(self, port , power):
"""Sets the attenuation value of given port
-
Args:
port: port of attenuator
power: power level for attenuator to be set
-
Returns:
return True if given port is set
"""
@@ -183,11 +172,11 @@
def adjust_atten_slowly(self, adjust_level, move_to, step=9 , step_time=5):
"""adjust attenuator slowly
-
Args:
- port: port of attenuator
- power: power level for attenuator to be set
-
+ adjust_level: adjust power level for each cycle
+ move_to: NO_SERVICE_AREA, IN_SERVICE_AREA , WIFI_AREA, NO_WIFI_AREA
+ step: adjust attenuator how many time
+ step_time: wait for how many sec for each loop
Returns:
return True if given port is set
"""
@@ -234,28 +223,62 @@
self.check_network()
return True
- def verify_device_status(self, ad, call_type=None, end_call=True, talk_time=30):
+ def verify_device_status(self, ad, call_type=None, end_call=True,
+ talk_time=30, verify_data=True, verify_voice=True, data_retries=2, voice_retries=2):
"""verfiy device status includes network service, data connection and voice call
-
Args:
ad: android device
call_type: WFC call, VOLTE call. CSFB call, voice call
end_call: hangup call after voice call flag
talk_time: in call duration in sec
-
+ verify_data: flag to check data connection
+ verify_voice: flag to check voice
+ data_retries: retry times for data verification
+ voice_retris:retry times for voice call
Returns:
- return True if given port is set
+ return True if pass
"""
- test_result = True
tasks = [(check_network_service, (ad, )) for ad in self.android_devices]
if not multithread_func(self.log, tasks):
- test_result = False
- tasks = [(verify_data_connection, (ad, )) for ad in self.android_devices]
- if not multithread_func(self.log, tasks):
- test_result = False
- if call_type != None:
- tasks = [(mo_voice_call, (self.log, ad, call_type, end_call, talk_time))
+ log_screen_shot(ad, "check_network_service_fail")
+ ad.log.info("check_network_service fail")
+ return False
+ else:
+ self.log.info("check_network_service pass")
+ if verify_data:
+ tasks = [(verify_data_connection, (ad, data_retries ))
for ad in self.android_devices]
- if not multithread_func(self.log, tasks):
- test_result = False
- return test_result
+ if not multithread_func(self.log, tasks):
+ log_screen_shot(ad, "verify_data_connection_fail")
+ ad.log.info("verify_data_connection_fail")
+ return False
+ else:
+ self.log.info("verify_data_connection pass")
+ if verify_voice:
+ if call_type:
+ tasks = [(mo_voice_call, (self.log, ad, call_type, end_call,
+ talk_time, voice_retries)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ log_screen_shot(ad, "verify_voice_call_fail")
+ ad.log.info("verify_voice_call_fail")
+ return False
+ else:
+ self.log.info("verify_voice_call pass")
+ return True
+ return True
+
+
+ def _on_failure(self, error_msg="", assert_on_fail=True, test_result=False):
+ """ operation on fail
+
+ Args:
+ error_msg: error message to be written to log
+
+ """
+ if assert_on_fail:
+ asserts.assert_true(False, "assert_on_fail: %s."
+ %(error_msg),extras={"failure_cause": error_msg})
+ for ad in self.android_devices:
+ log_screen_shot(ad, error_msg)
+ self.log.info(error_msg)
+
diff --git a/acts_tests/acts_contrib/test_utils/tel/TelephonyBaseTest.py b/acts_tests/acts_contrib/test_utils/tel/TelephonyBaseTest.py
index 0eed808..c7cb108 100644
--- a/acts_tests/acts_contrib/test_utils/tel/TelephonyBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/tel/TelephonyBaseTest.py
@@ -24,73 +24,67 @@
import time
from acts import asserts
-from acts import logger as acts_logger
from acts import signals
from acts.base_test import BaseTestClass
from acts.controllers.android_device import DEFAULT_QXDM_LOG_PATH
-from acts.controllers.android_device import DEFAULT_SDM_LOG_PATH
from acts.keys import Config
from acts import records
from acts import utils
-
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- initial_set_up_for_subid_infomation
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- set_default_sub_for_all_services
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
-from acts_contrib.test_utils.tel.tel_test_utils import build_id_override
-from acts_contrib.test_utils.tel.tel_test_utils import disable_qxdm_logger
-from acts_contrib.test_utils.tel.tel_test_utils import enable_connectivity_metrics
-from acts_contrib.test_utils.tel.tel_test_utils import enable_radio_log_on
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import force_connectivity_metrics_upload
-from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_log
-from acts_contrib.test_utils.tel.tel_test_utils import get_sim_state
-from acts_contrib.test_utils.tel.tel_test_utils import get_tcpdump_log
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import print_radio_info
-from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
-from acts_contrib.test_utils.tel.tel_test_utils import recover_build_id
-from acts_contrib.test_utils.tel.tel_test_utils import run_multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import setup_droid_properties
-from acts_contrib.test_utils.tel.tel_test_utils import set_phone_screen_on
-from acts_contrib.test_utils.tel.tel_test_utils import set_phone_silent_mode
-from acts_contrib.test_utils.tel.tel_test_utils import set_qxdm_logger_command
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_logger
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
-from acts_contrib.test_utils.tel.tel_test_utils import start_sdm_loggers
-from acts_contrib.test_utils.tel.tel_test_utils import start_sdm_logger
-from acts_contrib.test_utils.tel.tel_test_utils import start_tcpdumps
-from acts_contrib.test_utils.tel.tel_test_utils import stop_qxdm_logger
-from acts_contrib.test_utils.tel.tel_test_utils import stop_sdm_loggers
-from acts_contrib.test_utils.tel.tel_test_utils import stop_sdm_logger
-from acts_contrib.test_utils.tel.tel_test_utils import stop_tcpdumps
-from acts_contrib.test_utils.tel.tel_test_utils import synchronize_device_time
-from acts_contrib.test_utils.tel.tel_test_utils import unlock_sim
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_sim_ready_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_sims_ready_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import activate_wfc_on_device
-from acts_contrib.test_utils.tel.tel_test_utils import install_googleaccountutil_apk
-from acts_contrib.test_utils.tel.tel_test_utils import add_google_account
-from acts_contrib.test_utils.tel.tel_test_utils import install_googlefi_apk
-from acts_contrib.test_utils.tel.tel_test_utils import activate_google_fi_account
-from acts_contrib.test_utils.tel.tel_test_utils import check_google_fi_activated
-from acts_contrib.test_utils.tel.tel_test_utils import check_fi_apk_installed
-from acts_contrib.test_utils.tel.tel_test_utils import phone_switch_to_msim_mode
-from acts_contrib.test_utils.tel.tel_test_utils import activate_esim_using_suw
+from acts.libs.utils.multithread import multithread_func
+from acts.libs.utils.multithread import run_multithread_func
from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_BACKGROUND
from acts_contrib.test_utils.tel.tel_defines import SINGLE_SIM_CONFIG, MULTI_SIM_CONFIG
from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_FOREGROUND
from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_RINGING
from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_ABSENT
from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_UNKNOWN
-from acts_contrib.test_utils.tel.tel_defines import WIFI_VERBOSE_LOGGING_ENABLED
from acts_contrib.test_utils.tel.tel_defines import WIFI_VERBOSE_LOGGING_DISABLED
from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
from acts_contrib.test_utils.tel.tel_defines import CHIPSET_MODELS_LIST
+from acts_contrib.test_utils.tel.tel_bootloader_utils import flash_radio
+from acts_contrib.test_utils.tel.tel_ims_utils import activate_wfc_on_device
+from acts_contrib.test_utils.tel.tel_logging_utils import disable_qxdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import get_screen_shot_log
+from acts_contrib.test_utils.tel.tel_logging_utils import set_qxdm_logger_command
+from acts_contrib.test_utils.tel.tel_logging_utils import start_dsp_logger_p21
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_logging_utils import stop_qxdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import start_sdm_loggers
+from acts_contrib.test_utils.tel.tel_logging_utils import start_sdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import stop_sdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import start_tcpdumps
+from acts_contrib.test_utils.tel.tel_logging_utils import stop_tcpdumps
+from acts_contrib.test_utils.tel.tel_logging_utils import get_tcpdump_log
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_idle
+from acts_contrib.test_utils.tel.tel_subscription_utils import initial_set_up_for_subid_information
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_default_sub_for_all_services
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
+from acts_contrib.test_utils.tel.tel_test_utils import build_id_override
+from acts_contrib.test_utils.tel.tel_test_utils import enable_connectivity_metrics
+from acts_contrib.test_utils.tel.tel_test_utils import enable_radio_log_on
+from acts_contrib.test_utils.tel.tel_test_utils import force_connectivity_metrics_upload
+from acts_contrib.test_utils.tel.tel_test_utils import get_sim_state
+from acts_contrib.test_utils.tel.tel_test_utils import install_apk
+from acts_contrib.test_utils.tel.tel_test_utils import print_radio_info
+from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
+from acts_contrib.test_utils.tel.tel_test_utils import recover_build_id
+from acts_contrib.test_utils.tel.tel_test_utils import setup_droid_properties
+from acts_contrib.test_utils.tel.tel_test_utils import set_phone_screen_on
+from acts_contrib.test_utils.tel.tel_test_utils import set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_test_utils import synchronize_device_time
+from acts_contrib.test_utils.tel.tel_test_utils import unlock_sim
+from acts_contrib.test_utils.tel.tel_test_utils import wait_for_sim_ready_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import wait_for_sims_ready_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import install_googleaccountutil_apk
+from acts_contrib.test_utils.tel.tel_test_utils import add_google_account
+from acts_contrib.test_utils.tel.tel_test_utils import install_googlefi_apk
+from acts_contrib.test_utils.tel.tel_test_utils import activate_google_fi_account
+from acts_contrib.test_utils.tel.tel_test_utils import check_google_fi_activated
+from acts_contrib.test_utils.tel.tel_test_utils import phone_switch_to_msim_mode
+from acts_contrib.test_utils.tel.tel_test_utils import activate_esim_using_suw
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
class TelephonyBaseTest(BaseTestClass):
@@ -164,6 +158,7 @@
self.log_path = getattr(logging, "log_path", None)
self.qxdm_log = self.user_params.get("qxdm_log", True)
self.sdm_log = self.user_params.get("sdm_log", False)
+ self.dsp_log_p21 = self.user_params.get("dsp_log_p21", False)
self.enable_radio_log_on = self.user_params.get(
"enable_radio_log_on", False)
self.cbrs_esim = self.user_params.get("cbrs_esim", False)
@@ -174,6 +169,32 @@
self.fi_util = self.user_params.get("fi_util", None)
if isinstance(self.fi_util, list):
self.fi_util = self.fi_util[0]
+ self.radio_img = self.user_params.get("radio_img", None)
+ if isinstance(self.radio_img, list):
+ self.radio_img = self.radio_img[0]
+ self.modem_bin = self.user_params.get("modem_bin", None)
+ if isinstance(self.modem_bin, list):
+ self.modem_bin = self.modem_bin[0]
+ self.extra_apk = self.user_params.get("extra_apk", None)
+ if isinstance(self.extra_apk, list):
+ self.extra_apk = self.extra_apk[0]
+ self.extra_package = self.user_params.get("extra_package", None)
+
+ if self.radio_img or self.modem_bin:
+ sideload_img = True
+ if self.radio_img:
+ file_path = self.radio_img
+ elif self.modem_bin:
+ file_path = self.modem_bin
+ sideload_img = False
+ tasks = [(flash_radio, [ad, file_path, True, sideload_img])
+ for ad in self.android_devices]
+ multithread_func(self.log, tasks)
+ if self.extra_apk and self.extra_package:
+ tasks = [(install_apk, [ad, self.extra_apk, self.extra_package])
+ for ad in self.android_devices]
+ multithread_func(self.log, tasks)
+
tasks = [(self._init_device, [ad]) for ad in self.android_devices]
multithread_func(self.log, tasks)
self.skip_reset_between_cases = self.user_params.get(
@@ -237,6 +258,7 @@
def _setup_device(self, ad, sim_conf_file, qxdm_log_mask_cfg=None):
ad.qxdm_log = getattr(ad, "qxdm_log", self.qxdm_log)
ad.sdm_log = getattr(ad, "sdm_log", self.sdm_log)
+ ad.dsp_log_p21 = getattr(ad, "dsp_log_p21", self.dsp_log_p21)
if self.user_params.get("enable_connectivity_metrics", False):
enable_connectivity_metrics(ad)
if self.user_params.get("build_id_override", False):
@@ -259,6 +281,8 @@
% phone_mode)
reboot_device(ad)
+ if ad.dsp_log_p21:
+ start_dsp_logger_p21(ad)
stop_qxdm_logger(ad)
if ad.qxdm_log:
qxdm_log_mask = getattr(ad, "qxdm_log_mask", None)
@@ -337,7 +361,7 @@
activate_wfc_on_device(self.log, ad)
# Sub ID setup
- initial_set_up_for_subid_infomation(self.log, ad)
+ initial_set_up_for_subid_information(self.log, ad)
#try:
@@ -456,7 +480,8 @@
start_qxdm_loggers(self.log, self.android_devices, self.begin_time)
if getattr(self, "sdm_log", False):
start_sdm_loggers(self.log, self.android_devices)
- if getattr(self, "tcpdump_log", False) or "wfc" in self.test_name:
+ if getattr(self, "tcpdump_log", False) or "wfc" in self.test_name or (
+ "iwlan" in self.test_name):
mask = getattr(self, "tcpdump_mask", "all")
interface = getattr(self, "tcpdump_interface", "wlan0")
start_tcpdumps(
@@ -483,6 +508,11 @@
stop_tcpdumps(self.android_devices)
def on_fail(self, test_name, begin_time):
+ for ad in self.android_devices:
+ # open Phone information page
+ ad.adb.shell("am start -n com.android.phone/.settings.RadioInfo")
+ time.sleep(3)
+ ad.screenshot(f"{ad.serial}_last_screen")
self._take_bug_report(test_name, begin_time)
def on_pass(self, test_name, begin_time):
diff --git a/acts_tests/acts_contrib/test_utils/tel/amarisoft_sim_utils.py b/acts_tests/acts_contrib/test_utils/tel/amarisoft_sim_utils.py
new file mode 100644
index 0000000..5acd6d9
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/amarisoft_sim_utils.py
@@ -0,0 +1,429 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import dataclasses
+import re
+import time
+from typing import List
+
+from acts import asserts
+from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_PIN_REQUIRED
+from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_PUK_REQUIRED
+from acts_contrib.test_utils.tel.tel_test_utils import is_sim_ready
+from acts_contrib.test_utils.tel.tel_test_utils import power_off_sim
+from acts_contrib.test_utils.tel.tel_test_utils import power_on_sim
+
+AT_COMMAND_INSTRUMENTATION = 'com.google.mdstest/com.google.mdstest.instrument.ModemATCommandInstrumentation'
+AT_COMMAND_FAILURE = 'INSTRUMENTATION_RESULT: result=FAILURE'
+LAB_PSIM_ADM_PW = '3131313131313131'
+LAB_ESIM_ADM_PW = '35363738FFFFFFFF'
+LAB_SIM_DEFAULT_PIN1 = '1234'
+LAB_SIM_DEFAULT_PUK1 = '12345678'
+UI_ELEMENT_TEXT_SECURITY_SIM_CARD_LOCK = 'SIM card lock'
+UI_ELEMENT_TEXT_LOCK_SIM_SET = 'Lock SIM card'
+UI_ELEMENT_TEXT_OK = 'OK'
+SHORT_MNC_LENGTH = 2
+
+
+@dataclasses.dataclass
+class SimInfo:
+ sub_id: int
+ slot_index: int
+ imsi: str
+ mcc_mnc: str
+ msin: str
+ display_name: str
+
+
+def get_sim_info(ad) -> List[SimInfo]:
+ """Get Lab SIM subscription information.
+
+ Args:
+ ad: Android device obj.
+
+ Returns:
+ List[SimInfo]: A list of sim information dataclass
+ """
+ sim_info = []
+ sub_info_list = ad.droid.subscriptionGetActiveSubInfoList()
+ if not sub_info_list:
+ asserts.skip('No Valid SIM in device')
+ for sub_info in sub_info_list:
+ sub_id = sub_info['subscriptionId']
+ imsi = get_sim_imsi(ad, sub_id)
+ mcc_mnc = get_sim_mcc_mnc(ad, sub_id)
+ msin = get_sim_msin(imsi, mcc_mnc)
+ sim_info.append(
+ SimInfo(
+ sub_id=sub_id,
+ slot_index=sub_info['simSlotIndex'],
+ imsi=imsi,
+ mcc_mnc=mcc_mnc,
+ msin=msin,
+ display_name=sub_info['displayName']))
+ ad.log.info(sim_info)
+ return sim_info
+
+
+def get_sim_msin(imsi, mcc_mnc):
+ """Split IMSI to get msin value."""
+ msin = imsi.split(mcc_mnc)[1]
+ return msin
+
+
+def get_sim_mcc_mnc(ad, sub_id):
+ """Get SIM MCC+MNC value by sub id."""
+ return ad.droid.telephonyGetSimOperatorForSubscription(sub_id)
+
+
+def get_sim_imsi(ad, sub_id):
+ """Get SIM IMSI value by sub id."""
+ return ad.droid.telephonyGetSubscriberIdForSubscription(sub_id)
+
+
+def unlock_sim_dsds(ad,
+ dsds=False,
+ pin=LAB_SIM_DEFAULT_PIN1,
+ puk=LAB_SIM_DEFAULT_PUK1) -> bool:
+ """Unlock SIM pin1/puk1 on single or dual sim mode.
+
+ Args:
+ ad: Android device obj.
+ dsds: True is dual sim mode, use adb command to unlock.
+ pin: pin1 code, use LAB_DEFAULT_PIN1 for default value.
+ puk: puk1 code, use LAB_DEFAULT_PUK1 for default value.
+
+ Returns:
+ True if unlock sim success. False otherwise.
+ """
+ ad.unlock_screen()
+ ad.log.info('[Dual_sim=%s] Unlock SIM', dsds)
+ if not dsds:
+ if is_sim_pin_locked(ad):
+ ad.log.info('Unlock SIM pin')
+ ad.droid.telephonySupplyPin(pin)
+ elif is_sim_puk_locked(ad):
+ ad.log.info('Unlock SIM puk')
+ ad.droid.telephonySupplyPuk(puk, pin)
+ time.sleep(1)
+ return is_sim_ready(ad.log, ad)
+ else:
+ # Checks both pSIM and eSIM states.
+ for slot_index in range(2):
+ if is_sim_pin_locked(ad, slot_index):
+ ad.log.info('[Slot index=%s] Unlock SIM PIN', slot_index)
+ if not unlock_pin_by_mds(ad, slot_index, pin):
+ ad.log.info('[Slot index=%s] AT+CPIN unlock error', slot_index)
+ elif is_sim_puk_locked(ad, slot_index):
+ ad.log.info('[Slot index=%s] Unlock SIM PUK', slot_index)
+ unlock_puk_by_adb(ad, pin, puk)
+ time.sleep(1)
+ if not is_sim_ready(ad.log, ad, slot_index):
+ return False
+ return True
+
+
+def unlock_puk_by_mds(ad, slot_index, pin, puk) -> bool:
+ """Runs AT command to disable SIM PUK1 locked.
+
+ Args:
+ ad: Android device obj.
+ slot_index: sim slot id.
+ pin: pin1 code.
+ puk: puk1 code.
+
+ Returns:
+ True if response 'OK'. False otherwise.
+ """
+ set_at_command_channel(ad, slot_index)
+ command = r'AT+CPIN=\"' + puk + r'\",\"' + pin + r'\"'
+ cmd = (f'am instrument -w -e request "{command}" '
+ f'-e response wait {AT_COMMAND_INSTRUMENTATION}')
+ ad.log.info('Unlock sim pin by AT command')
+ output = ad.adb.shell(cmd)
+ if grep(AT_COMMAND_FAILURE, output):
+ asserts.skip('Failed to run MDS test command')
+ if grep('OK', output):
+ return True
+ else:
+ return False
+
+
+def unlock_pin_by_mds(ad, slot_index, pin) -> bool:
+ """Runs AT command to disable SIM PIN1 locked.
+
+ Args:
+ ad: Android device obj.
+ slot_index: sim slot id.
+ pin: pin1 code, use LAB_DEFAULT_PIN1 for default value.
+
+ Returns:
+ True if response 'OK'. False otherwise.
+ """
+ set_at_command_channel(ad, slot_index)
+ command = r'AT+CPIN=\"' + pin + r'\"'
+ cmd = (f'am instrument -w -e request "{command}" '
+ f'-e response wait {AT_COMMAND_INSTRUMENTATION}')
+ ad.log.info('Unlock sim pin by AT command')
+ output = ad.adb.shell(cmd)
+ if grep(AT_COMMAND_FAILURE, output):
+ asserts.skip('Failed to run MDS test command')
+ if grep('OK', output):
+ return True
+ else:
+ return False
+
+
+def unlock_puk_by_adb(ad, pin, puk) -> None:
+ """Unlock puk1 by adb keycode.
+
+ Args:
+ ad: Android device obj.
+ pin: pin1 code.
+ puk: puk1 code.
+
+ """
+ for key_code in puk:
+ ad.send_keycode(key_code)
+ time.sleep(1)
+ ad.send_keycode('ENTER')
+ time.sleep(1)
+ # PIN required 2 times
+ for _ in range(2):
+ for key_code in pin:
+ ad.send_keycode(key_code)
+ time.sleep(1)
+ ad.send_keycode('ENTER')
+ time.sleep(1)
+
+
+def lock_puk_by_mds(ad, slot_index) -> bool:
+ """Inputs wrong PIN1 code 3 times to make PUK1 locked.
+
+ Args:
+ ad: Android device obj.
+ slot_index: Sim slot id.
+
+ Returns:
+ True if SIM puk1 locked. False otherwise.
+ """
+ ad.unlock_screen()
+ wrong_pin = '1111'
+ for count in range(3):
+ if not unlock_pin_by_mds(ad, slot_index, wrong_pin):
+ ad.log.info('Error input pin:%d', count+1)
+ time.sleep(1)
+ ad.reboot()
+ return is_sim_puk_locked(ad, slot_index)
+
+
+def is_sim_puk_locked(ad, slot_index=None) -> bool:
+ """Checks whether SIM puk1 is locked on single or dual sim mode.
+
+ Args:
+ ad: Android device obj.
+ slot_index: Check the SIM status for slot_index.
+ This is optional. If this is None, check default SIM.
+
+ Returns:
+ True if SIM puk1 locked. False otherwise.
+ """
+ if slot_index is None:
+ status = ad.droid.telephonyGetSimState()
+ else:
+ status = ad.droid.telephonyGetSimStateForSlotId(slot_index)
+ if status != SIM_STATE_PUK_REQUIRED:
+ ad.log.info('Sim state is %s', status)
+ return False
+ return True
+
+
+def is_sim_pin_locked(ad, slot_index=None) -> bool:
+ """Checks whether SIM pin is locked on single or dual sim mode.
+
+ Args:
+ ad: Android device obj.
+ slot_index: Check the SIM status for slot_index. This is optional. If this
+ is None, check default SIM.
+
+ Returns:
+ True if SIM pin1 locked. False otherwise.
+ """
+ if slot_index is None:
+ status = ad.droid.telephonyGetSimState()
+ else:
+ status = ad.droid.telephonyGetSimStateForSlotId(slot_index)
+ if status != SIM_STATE_PIN_REQUIRED:
+ ad.log.info('Sim state is %s', status)
+ return False
+ return True
+
+
+def set_at_command_channel(ad, slot_index: int) -> bool:
+ """Runs AT command to set AT command channel by MDS tool(pSIM=1,eSIM=2).
+
+ Args:
+ ad: Android device obj.
+ slot_index: Sim slot id.
+
+ Returns:
+ True if response 'OK'. False otherwise.
+ """
+ channel = slot_index + 1
+ command = f'AT+CSUS={channel}'
+ cmd = (f'am instrument -w -e request "{command}" '
+ f'-e response wait {AT_COMMAND_INSTRUMENTATION}')
+ ad.log.info('Set AT command channel')
+ output = ad.adb.shell(cmd)
+ if grep(AT_COMMAND_FAILURE, output):
+ asserts.skip('Failed to run MDS test command')
+ if grep('OK', output):
+ return True
+ else:
+ return False
+
+
+def sim_enable_pin_by_mds(ad, pin) -> bool:
+ """Runs AT command to enable SIM PIN1 locked by MDS tool.
+
+ Args:
+ ad: Android device obj.
+ pin: PIN1 code.
+
+ Returns:
+ True if response 'OK'. False otherwise.
+ """
+ command = r'AT+CLCK=\"SC\",1,\"' + pin + r'\"'
+ cmd = (f'am instrument -w -e request "{command}" '
+ f'-e response wait {AT_COMMAND_INSTRUMENTATION}')
+ ad.log.info('Enable sim pin by AT command')
+ output = ad.adb.shell(cmd)
+ if grep(AT_COMMAND_FAILURE, output):
+ asserts.skip('Failed to run MDS test command')
+ if grep('OK', output):
+ return True
+ else:
+ return False
+
+
+def sim_disable_pin_by_mds(ad, pin) -> bool:
+ """Runs AT command to disable SIM PIN1 locked by MDS tool.
+
+ Args:
+ ad: Android device obj.
+ pin: PIN1 code.
+
+ Returns:
+ True if response 'OK'. False otherwise.
+ """
+ command = r'AT+CLCK=\"SC\",0,\"' + pin + r'\"'
+ cmd = (f'am instrument -w -e request "{command}" '
+ f'-e response wait {AT_COMMAND_INSTRUMENTATION}')
+ ad.log.info('Disable sim pin by AT command')
+ output = ad.adb.shell(cmd)
+ if grep(AT_COMMAND_FAILURE, output):
+ asserts.skip('Failed to run MDS test command')
+ if grep('OK', output):
+ return True
+ else:
+ return False
+
+
+def set_sim_lock(ad, enable, slot_index, pin=LAB_SIM_DEFAULT_PIN1) -> bool:
+ """Enable/disable SIM card lock.
+
+ Args:
+ ad: Android device obj.
+ enable: True is to enable sim lock. False is to disable.
+ slot_index: Sim slot id.
+ pin: Pin1 code.
+
+ Returns:
+ True if enable/disable SIM lock successfully.False otherwise.
+ """
+ if enable:
+ ad.log.info('[Slot:%d]Enable SIM pin1 locked by mds', slot_index)
+ if not set_at_command_channel(ad, slot_index):
+ ad.log.info('[Slot:%d] set AT command on MDS tool not OK', slot_index)
+ if sim_enable_pin_by_mds(ad, pin):
+ ad.reboot()
+ return is_sim_pin_locked(ad, slot_index)
+ else:
+ ad.log.info('[Slot:%d]Disable SIM pin1 locked by mds', slot_index)
+ if not set_at_command_channel(ad, slot_index):
+ ad.log.info('[Slot:%d] set AT command on MDS tool not OK', slot_index)
+ if sim_disable_pin_by_mds(ad, pin):
+ ad.reboot()
+ return is_sim_ready(ad.log, ad, slot_index)
+
+
+def activate_sim(ad,
+ slot_index=None,
+ dsds=False,
+ pin=LAB_SIM_DEFAULT_PIN1,
+ puk=LAB_SIM_DEFAULT_PUK1) -> bool:
+ """Activate sim state with slot id. Check sim lock state after activating.
+
+ Args:
+ ad: Android_device obj.
+ slot_index: Sim slot id.
+ dsds: True is dual sim mode, False is single mode.
+ pin: pin1 code, use LAB_DEFAULT_PIN1 for default value.
+ puk: puk1 code, use LAB_DEFAULT_PUK1 for default value.
+ Returns:
+ True if activate SIM lock successfully.False otherwise.
+ """
+ ad.log.info('Disable SIM slot')
+ if not power_off_sim(ad, slot_index):
+ return False
+ time.sleep(2)
+ ad.log.info('Enable SIM slot')
+ if not power_on_sim(ad, slot_index):
+ return False
+ unlock_sim_dsds(ad, dsds, pin, puk)
+ return True
+
+
+def grep(regex, output):
+ """Returns the line in an output stream that matches a given regex pattern."""
+ lines = output.strip().splitlines()
+ results = []
+ for line in lines:
+ if re.search(regex, line):
+ results.append(line.strip())
+ return results
+
+
+def modify_sim_imsi(ad,
+ new_imsi,
+ sim_info,
+ sim_adm=LAB_PSIM_ADM_PW):
+ """Uses ADB Content Provider Command to Read/Update EF (go/pmw-see-adb).
+
+ Args:
+ ad: Android_device obj.
+ new_imsi: New IMSI string to be set.
+ sim_info: SimInfo dataclass log.
+ sim_adm: SIM slot adm password.
+ """
+ cmd = (f"content update --uri content://com.google.android.wsdsimeditor.EF/EFIMSI "
+ f"--bind data:s:'{new_imsi}' --bind format:s:'raw' "
+ f"--bind adm:s:'{sim_adm}' --where slot={sim_info.slot_index}")
+ ad.log.info('Update IMSI cmd = %s', cmd)
+ ad.adb.shell(cmd)
+ time.sleep(5)
+ modified_imsi = get_sim_imsi(ad, sim_info.sub_id)
+ asserts.assert_equal(new_imsi, modified_imsi)
diff --git a/acts_tests/acts_contrib/test_utils/tel/anritsu_utils.py b/acts_tests/acts_contrib/test_utils/tel/anritsu_utils.py
index 04a9e35..2e04dac 100644
--- a/acts_tests/acts_contrib/test_utils/tel/anritsu_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/anritsu_utils.py
@@ -47,11 +47,11 @@
from acts_contrib.test_utils.tel.tel_defines import EventSmsDeliverSuccess
from acts_contrib.test_utils.tel.tel_defines import EventSmsSentSuccess
from acts_contrib.test_utils.tel.tel_defines import EventSmsReceived
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_idle
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_droid_not_in_call
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_droid_not_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
# Timers
# Time to wait after registration before sending a command to Anritsu
@@ -480,7 +480,7 @@
None
"""
# Setting IP address for internet connection sharing
- # Google Fi _init_PDN
+ # Google Fi _init_PDN
if sim_card == FiTMO or sim_card == FiSPR or sim_card == FiUSCC:
pdn.ue_address_ipv4 = ipv4
pdn.ue_address_ipv6 = ipv6
@@ -498,9 +498,9 @@
pdn.secondary_dns_address_ipv4 = Fi_DNS_IPV4_ADDR_Sec
pdn.dns_address_ipv6 = Fi_DNS_IPV6_ADDR
pdn.cscf_address_ipv4 = Fi_CSCF_IPV4_ADDR_Data
- pdn.cscf_address_ipv6 = Fi_CSCF_IPV6_ADDR_Data
+ pdn.cscf_address_ipv6 = Fi_CSCF_IPV6_ADDR_Data
# Pixel Lab _init_PDN_
- else:
+ else:
anritsu_handle.gateway_ipv4addr = GATEWAY_IPV4_ADDR
pdn.ue_address_ipv4 = ipv4
pdn.ue_address_ipv6 = ipv6
@@ -550,7 +550,7 @@
vnid.cscf_monitoring_ua = CSCF_Monitoring_UA_URI
vnid.psap = Switch.ENABLE
vnid.psap_auto_answer = Switch.ENABLE
- else:
+ else:
vnid.cscf_address_ipv4 = CSCF_IPV4_ADDR
vnid.cscf_address_ipv6 = ipv6_address
vnid.imscscf_iptype = ip_type
diff --git a/acts_tests/acts_contrib/test_utils/tel/gft_inout_defines.py b/acts_tests/acts_contrib/test_utils/tel/gft_inout_defines.py
index 2ec1d21..536b13f 100644
--- a/acts_tests/acts_contrib/test_utils/tel/gft_inout_defines.py
+++ b/acts_tests/acts_contrib/test_utils/tel/gft_inout_defines.py
@@ -36,4 +36,5 @@
VOLTE_CALL = "volte"
CSFB_CALL = "csfb"
WFC_CALL = "wfc_call"
+NO_VOICE_CALL = "no voice call"
diff --git a/acts_tests/acts_contrib/test_utils/tel/gft_inout_utils.py b/acts_tests/acts_contrib/test_utils/tel/gft_inout_utils.py
index 8cfaa21..2e4cfd4 100644
--- a/acts_tests/acts_contrib/test_utils/tel/gft_inout_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/gft_inout_utils.py
@@ -14,60 +14,28 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-
-import json
-import logging
-import re
-import os
-import urllib.parse
import time
-from acts.controllers import android_device
-
-from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
-from acts_contrib.test_utils.tel.tel_test_utils import get_sim_state
-from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import start_youtube_video
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_ringing_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call_active
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_log
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_logs
-from acts_contrib.test_utils.tel.tel_test_utils import log_screen_shot
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_not_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_1x
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
-
-from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
-from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_DISCONNECTED
-from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_EMERGENCY_ONLY
-from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
-from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_UNKNOWN
-from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_OUT_OF_SERVICE
-from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_POWER_OFF
-from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_ABSENT
-from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_LOADED
-from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_NOT_READY
-from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_PIN_REQUIRED
-from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_READY
-from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_UNKNOWN
-
-from acts_contrib.test_utils.tel.gft_inout_defines import VOICE_CALL
from acts_contrib.test_utils.tel.gft_inout_defines import VOLTE_CALL
from acts_contrib.test_utils.tel.gft_inout_defines import CSFB_CALL
from acts_contrib.test_utils.tel.gft_inout_defines import WFC_CALL
+from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
+from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
+from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_OUT_OF_SERVICE
+from acts_contrib.test_utils.tel.tel_logging_utils import log_screen_shot
+from acts_contrib.test_utils.tel.tel_ims_utils import is_ims_registered
+from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
+from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
+from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
-
-def check_no_service_time(ad, timeout=30):
+def check_no_service_time(ad, timeout=120):
""" check device is no service or not
Args:
@@ -77,19 +45,23 @@
Returns:
True if pass; False if fail.
"""
+
for i in range (timeout):
service_state = get_service_state_by_adb(ad.log,ad)
if service_state != SERVICE_STATE_IN_SERVICE:
- ad.log.info("device becomes no/limited service in %s sec and service_state=%s" %(i+1, service_state))
+ ad.log.info("device becomes no/limited service in %s sec and service_state=%s"
+ %(i+1, service_state))
get_telephony_signal_strength(ad)
return True
time.sleep(1)
get_telephony_signal_strength(ad)
check_network_service(ad)
- ad.log.info("device does not become no/limited service in %s sec and service_state=%s" %(timeout, service_state))
+ ad.log.info("device does not become no/limited service in %s sec and service_state=%s"
+ %(timeout, service_state))
return False
-def check_back_to_service_time(ad, timeout=30):
+
+def check_back_to_service_time(ad, timeout=120):
""" check device is back to service or not
Args:
@@ -104,17 +76,21 @@
if service_state == SERVICE_STATE_IN_SERVICE:
if i==0:
check_network_service(ad)
- ad.log.info("Skip check_back_to_service_time. Device is in-service and service_state=%s" %(service_state))
+ ad.log.info("Skip check_back_to_service_time. Service_state=%s"
+ %(service_state))
return True
else:
- ad.log.info("device is back to service in %s sec and service_state=%s" %(i+1, service_state))
+ ad.log.info("device is back to service in %s sec and service_state=%s"
+ %(i+1, service_state))
get_telephony_signal_strength(ad)
return True
time.sleep(1)
get_telephony_signal_strength(ad)
- ad.log.info("device is not back in service in %s sec and service_state=%s" %(timeout, service_state))
+ ad.log.info("device is not back in service in %s sec and service_state=%s"
+ %(timeout, service_state))
return False
+
def check_network_service(ad):
""" check network service
@@ -133,10 +109,13 @@
ad.log.info("networkType_data=%s" %(network_type_data))
ad.log.info("service_state=%s" %(service_state))
if service_state == SERVICE_STATE_OUT_OF_SERVICE:
+ log_screen_shot(ad, "device_out_of_service")
return False
return True
-def mo_voice_call(log, ad, call_type, end_call=True, talk_time=15):
+
+def mo_voice_call(log, ad, call_type, end_call=True, talk_time=15,
+ retries=1, retry_time=30):
""" MO voice call and check call type.
End call if necessary.
@@ -146,35 +125,48 @@
call_type: WFC call, VOLTE call. CSFB call, voice call
end_call: hangup call after voice call flag
talk_time: in call duration in sec
+ retries: retry times
+ retry_time: wait for how many sec before next retry
Returns:
True if pass; False if fail.
"""
callee_number = ad.mt_phone_number
- ad.log.info("MO voice call")
+ ad.log.info("MO voice call. call_type=%s" %(call_type))
if is_phone_in_call(log, ad):
ad.log.info("%s is in call. hangup_call before initiate call" %(callee_number))
hangup_call(log, ad)
time.sleep(1)
- if initiate_call(log, ad, callee_number):
- time.sleep(5)
- check_voice_call_type(ad,call_type)
- get_voice_call_type(ad)
- else:
- ad.log.error("initiate_call fail")
- return False
+ for i in range(retries):
+ ad.log.info("mo_voice_call attempt %d", i + 1)
+ if initiate_call(log, ad, callee_number):
+ time.sleep(5)
+ check_voice_call_type(ad,call_type)
+ get_voice_call_type(ad)
+ break
+ else:
+ ad.log.error("initiate_call fail attempt %d", i + 1)
+ time.sleep(retry_time)
+ if i+1 == retries:
+ ad.log.error("mo_voice_call retry failure")
+ return False
- time.sleep(talk_time)
+ time.sleep(10)
if end_call:
+ time.sleep(talk_time)
if is_phone_in_call(log, ad):
ad.log.info("end voice call")
if not hangup_call(log, ad):
ad.log.error("end call fail")
+ ad.droid.telecomShowInCallScreen()
+ log_screen_shot(ad, "end_call_fail")
return False
else:
#Call drop is unexpected
ad.log.error("%s Unexpected call drop" %(call_type))
+ ad.droid.telecomShowInCallScreen()
+ log_screen_shot(ad, "call_drop")
return False
ad.log.info("%s successful" %(call_type))
return True
@@ -191,6 +183,7 @@
True if pass; False if fail.
"""
if is_phone_in_call(ad.log, ad):
+ ad.droid.telecomShowInCallScreen()
log_screen_shot(ad, "expected_call_type_%s" %call_type)
if call_type == CSFB_CALL:
if not is_phone_in_call_csfb(ad.log, ad):
@@ -239,16 +232,74 @@
ad.log.error("device is not in call")
return "UNKNOWN"
-def verify_data_connection(ad):
- data_state = ad.droid.telephonyGetDataConnectionState()
- if data_state != DATA_STATE_CONNECTED:
- ad.log.error("data is not connected. data_state=%s" %(data_state))
- return False
- else:
- #Verify internet connection by ping test and http connection
+
+def verify_data_connection(ad, retries=3, retry_time=30):
+ """ verify data connection
+
+ Args:
+ ad: android device
+ retries: retry times
+ retry_time: wait for how many sec before next retry
+
+ Returns:
+ True if pass; False if fail.
+ """
+ for i in range(retries):
+ data_state = ad.droid.telephonyGetDataConnectionState()
+ wifi_info = ad.droid.wifiGetConnectionInfo()
+ if wifi_info["supplicant_state"] == "completed":
+ ad.log.info("Wifi is connected=%s" %(wifi_info["SSID"]))
+ ad.log.info("verify_data_connection attempt %d", i + 1)
if not verify_internet_connection(ad.log, ad, retries=3):
data_state = ad.droid.telephonyGetDataConnectionState()
- ad.log.error("verify_internet_connection fail. data_state=%s" %(data_state))
+ network_type_data = ad.droid.telephonyGetCurrentDataNetworkType()
+ ad.log.error("verify_internet fail. data_state=%s, network_type_data=%s"
+ %(data_state, network_type_data))
+ ad.log.info("verify_data_connection fail attempt %d", i + 1)
+ log_screen_shot(ad, "verify_internet")
+ time.sleep(retry_time)
+ else:
+ ad.log.info("verify_data_connection pass")
+ return True
+ return False
+
+
+def check_ims_state(ad):
+ """ check current ism state
+
+ Args:
+ ad: android device
+
+ Returns:
+ ims state
+ """
+ r1 = is_ims_registered(ad.log, ad)
+ r2 = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByPlatform()
+ r3 = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
+ r4 = ad.droid.telephonyIsVolteAvailable()
+ ad.log.info("telephonyIsImsRegistered=%s" %(r1))
+ ad.log.info("imsIsEnhanced4gLteModeSettingEnabledByPlatform=%s" %(r2))
+ ad.log.info("imsIsEnhanced4gLteModeSettingEnabledByUser=%s" %(r3))
+ ad.log.info("telephonyIsVolteAvailable=%s" %(r4))
+ return r1
+
+
+def browsing_test_ping_retry(ad):
+ """ If browse test fails, use ping to test data connection
+
+ Args:
+ ad: android device
+
+ Returns:
+ True if pass; False if fail.
+ """
+ if not browsing_test(ad.log, ad):
+ ad.log.error("Failed to browse websites!")
+ if verify_data_connection(ad):
+ ad.log.info("Ping success!")
+ return True
+ else:
+ ad.log.info("Ping fail!")
return False
- ad.log.info("verify_data_connection pass")
- return True
+ else:
+ ad.log.info("Successful to browse websites!")
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/loggers/protos/telephony_stress_metric.proto b/acts_tests/acts_contrib/test_utils/tel/loggers/protos/telephony_stress_metric.proto
new file mode 100644
index 0000000..0a0b377
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/loggers/protos/telephony_stress_metric.proto
@@ -0,0 +1,18 @@
+/* Note: If making any changes to this file be sure to generate a new
+ compiled *_pb2.py file by running the following command from this
+ directory:
+ $ protoc -I=. --python_out=. telephony_stress_metric.proto
+
+ Be sure that you are compiling with protoc 3.4.0
+
+ More info can be found at:
+ https://developers.google.com/protocol-buffers/docs/pythontutorial
+*/
+
+syntax = "proto2";
+
+package wireless.android.platform.testing.telephony.metrics;
+
+message TelephonyStressTestResult {
+ map<string,int32> results_dict = 1;
+}
diff --git a/acts_tests/acts_contrib/test_utils/tel/loggers/protos/telephony_stress_metric_pb2.py b/acts_tests/acts_contrib/test_utils/tel/loggers/protos/telephony_stress_metric_pb2.py
new file mode 100644
index 0000000..6ccec95
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/loggers/protos/telephony_stress_metric_pb2.py
@@ -0,0 +1,119 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: telephony_stress_metric.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+ name='telephony_stress_metric.proto',
+ package='wireless.android.platform.testing.telephony.metrics',
+ syntax='proto2',
+ serialized_options=None,
+ create_key=_descriptor._internal_create_key,
+ serialized_pb=b'\n\x1dtelephony_stress_metric.proto\x12\x33wireless.android.platform.testing.telephony.metrics\"\xc6\x01\n\x19TelephonyStressTestResult\x12u\n\x0cresults_dict\x18\x01 \x03(\x0b\x32_.wireless.android.platform.testing.telephony.metrics.TelephonyStressTestResult.ResultsDictEntry\x1a\x32\n\x10ResultsDictEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01'
+)
+
+
+
+
+_TELEPHONYSTRESSTESTRESULT_RESULTSDICTENTRY = _descriptor.Descriptor(
+ name='ResultsDictEntry',
+ full_name='wireless.android.platform.testing.telephony.metrics.TelephonyStressTestResult.ResultsDictEntry',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ create_key=_descriptor._internal_create_key,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='key', full_name='wireless.android.platform.testing.telephony.metrics.TelephonyStressTestResult.ResultsDictEntry.key', index=0,
+ number=1, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=b"".decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
+ _descriptor.FieldDescriptor(
+ name='value', full_name='wireless.android.platform.testing.telephony.metrics.TelephonyStressTestResult.ResultsDictEntry.value', index=1,
+ number=2, type=5, cpp_type=1, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ serialized_options=b'8\001',
+ is_extendable=False,
+ syntax='proto2',
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=235,
+ serialized_end=285,
+)
+
+_TELEPHONYSTRESSTESTRESULT = _descriptor.Descriptor(
+ name='TelephonyStressTestResult',
+ full_name='wireless.android.platform.testing.telephony.metrics.TelephonyStressTestResult',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ create_key=_descriptor._internal_create_key,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='results_dict', full_name='wireless.android.platform.testing.telephony.metrics.TelephonyStressTestResult.results_dict', index=0,
+ number=1, type=11, cpp_type=10, label=3,
+ has_default_value=False, default_value=[],
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
+ ],
+ extensions=[
+ ],
+ nested_types=[_TELEPHONYSTRESSTESTRESULT_RESULTSDICTENTRY, ],
+ enum_types=[
+ ],
+ serialized_options=None,
+ is_extendable=False,
+ syntax='proto2',
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=87,
+ serialized_end=285,
+)
+
+_TELEPHONYSTRESSTESTRESULT_RESULTSDICTENTRY.containing_type = _TELEPHONYSTRESSTESTRESULT
+_TELEPHONYSTRESSTESTRESULT.fields_by_name['results_dict'].message_type = _TELEPHONYSTRESSTESTRESULT_RESULTSDICTENTRY
+DESCRIPTOR.message_types_by_name['TelephonyStressTestResult'] = _TELEPHONYSTRESSTESTRESULT
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+TelephonyStressTestResult = _reflection.GeneratedProtocolMessageType('TelephonyStressTestResult', (_message.Message,), {
+
+ 'ResultsDictEntry' : _reflection.GeneratedProtocolMessageType('ResultsDictEntry', (_message.Message,), {
+ 'DESCRIPTOR' : _TELEPHONYSTRESSTESTRESULT_RESULTSDICTENTRY,
+ '__module__' : 'telephony_stress_metric_pb2'
+ # @@protoc_insertion_point(class_scope:wireless.android.platform.testing.telephony.metrics.TelephonyStressTestResult.ResultsDictEntry)
+ })
+ ,
+ 'DESCRIPTOR' : _TELEPHONYSTRESSTESTRESULT,
+ '__module__' : 'telephony_stress_metric_pb2'
+ # @@protoc_insertion_point(class_scope:wireless.android.platform.testing.telephony.metrics.TelephonyStressTestResult)
+ })
+_sym_db.RegisterMessage(TelephonyStressTestResult)
+_sym_db.RegisterMessage(TelephonyStressTestResult.ResultsDictEntry)
+
+
+_TELEPHONYSTRESSTESTRESULT_RESULTSDICTENTRY._options = None
+# @@protoc_insertion_point(module_scope)
diff --git a/acts_tests/acts_contrib/test_utils/tel/loggers/telephony_stress_metric_logger.py b/acts_tests/acts_contrib/test_utils/tel/loggers/telephony_stress_metric_logger.py
new file mode 100644
index 0000000..456e8b2
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/loggers/telephony_stress_metric_logger.py
@@ -0,0 +1,49 @@
+# /usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import base64
+import os
+import time
+
+from acts.metrics.core import ProtoMetric
+from acts.metrics.logger import MetricLogger
+from acts_contrib.test_utils.tel.loggers.protos.telephony_stress_metric_pb2 import TelephonyStressTestResult
+
+# Initializes the path to the protobuf
+PROTO_PATH = os.path.join(os.path.dirname(__file__),
+ 'protos',
+ 'telephony_stress_metric.proto')
+
+
+class TelephonyStressMetricLogger(MetricLogger):
+ """A logger for gathering Telephony Stress test metrics
+
+ Attributes:
+ proto: Module used to store Telephony metrics in a proto
+ """
+
+ def __init__(self, event):
+ super().__init__(event=event)
+ self.proto = TelephonyStressTestResult()
+
+ def set_result(self, result_dict):
+ self.proto.results_dict = result_dict
+
+ def end(self, event):
+ metric = ProtoMetric(name='telephony_stress_test_result',
+ data=self.proto)
+ return self.publisher.publish(metric)
+
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_5g_test_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_5g_test_utils.py
index 91cdd38..5b81979 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_5g_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_5g_test_utils.py
@@ -15,61 +15,76 @@
# limitations under the License.
import time
-import random
-import re
-from queue import Empty
-from acts.utils import rand_ascii_str
-from acts_contrib.test_utils.tel.tel_defines import GEN_5G
+from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_NR_LTE_GSM_WCDMA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_NR_ONLY
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_defines import GEN_4G
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_WCDMA_ONLY
from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa
from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_sa
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_generation
+from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import get_current_override_network_type
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
-def provision_device_for_5g(log, ads, sa_5g=False, nsa_mmwave=False):
+def provision_device_for_5g(log, ads, nr_type = None, mmwave = None):
"""Provision Devices for 5G
Args:
log: Log object.
ads: android device object(s).
- sa_5g: Check for provision on sa_5G or not
- nsa_mmwave: If true, check the band of NSA network is mmWave. Default is to check sub-6.
+ nr_type: NR network type.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
Returns:
True: Device(s) are provisioned on 5G
False: Device(s) are not provisioned on 5G
"""
- if sa_5g:
- if not provision_device_for_5g_sa(log, ads):
+ if nr_type == 'sa':
+ if not provision_device_for_5g_sa(
+ log, ads, mmwave=mmwave):
+ return False
+ elif nr_type == 'nsa':
+ if not provision_device_for_5g_nsa(
+ log, ads, mmwave=mmwave):
+ return False
+ elif nr_type == 'mmwave':
+ if not provision_device_for_5g_nsa(
+ log, ads, mmwave=mmwave):
return False
else:
- if not provision_device_for_5g_nsa(log, ads, nsa_mmwave=nsa_mmwave):
+ if not provision_device_for_5g_nsa(
+ log, ads, mmwave=mmwave):
return False
return True
-def provision_device_for_5g_nsa(log, ads, nsa_mmwave=False):
+def provision_device_for_5g_nsa(log, ads, mmwave = None):
"""Provision Devices for 5G NSA
Args:
log: Log object.
ads: android device object(s).
- nsa_mmwave: If true, check the band of NSA network is mmWave. Default is to check sub-6.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
Returns:
True: Device(s) are provisioned on 5G NSA
False: Device(s) are not provisioned on 5G NSA
"""
+
if isinstance(ads, list):
# Mode Pref
tasks = [(set_preferred_mode_for_5g, [ad]) for ad in ads]
@@ -77,9 +92,9 @@
log.error("failed to set preferred network mode on 5g")
return False
# Attach
- tasks = [(is_current_network_5g_nsa, [ad, nsa_mmwave]) for ad in ads]
+ tasks = [(is_current_network_5g_nsa, [ad, None, mmwave]) for ad in ads]
if not multithread_func(log, tasks):
- log.error("phone not on 5g nsa")
+ log.error("phone not on 5g")
return False
return True
else:
@@ -87,8 +102,8 @@
set_preferred_mode_for_5g(ads)
# Attach nsa5g
- if not is_current_network_5g_nsa(ads, nsa_mmwave=nsa_mmwave):
- ads.log.error("Phone not attached on nsa 5g")
+ if not is_current_network_5g_nsa(ads, mmwave=mmwave):
+ ads.log.error("Phone not attached on 5g")
return False
return True
@@ -169,29 +184,32 @@
return True
-def verify_5g_attach_for_both_devices(log, ads, sa_5g=False, nsa_mmwave=False):
+def verify_5g_attach_for_both_devices(log, ads, nr_type = None, mmwave = None):
"""Verify the network is attached
Args:
log: Log object.
ads: android device object(s).
- sa_5g: Check for verify data network type is on 5G SA or not
- nsa_mmwave: If true, check the band of NSA network is mmWave. Default is to check sub-6.
+ nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone,
+ 'mmwave' for 5G millimeter wave.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
Returns:
True: Device(s) are attached on 5G
False: Device(s) are not attached on 5G NSA
"""
- if sa_5g:
+
+ if nr_type=='sa':
# Attach
- tasks = [(is_current_network_5g_sa, [ad]) for ad in ads]
+ tasks = [(is_current_network_5g_sa, [ad, None, mmwave]) for ad in ads]
if not multithread_func(log, tasks):
log.error("phone not on 5g sa")
return False
return True
else:
# Attach
- tasks = [(is_current_network_5g_nsa, [ad, nsa_mmwave]) for ad in ads]
+ tasks = [(is_current_network_5g_nsa, [ad, None, mmwave]) for ad in ads]
if not multithread_func(log, tasks):
log.error("phone not on 5g nsa")
return False
@@ -212,17 +230,20 @@
return set_preferred_network_mode_pref(ad.log, ad, sub_id, mode)
-def provision_device_for_5g_sa(log, ads):
+def provision_device_for_5g_sa(log, ads, mmwave = None):
"""Provision Devices for 5G SA
Args:
log: Log object.
ads: android device object(s).
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
Returns:
True: Device(s) are provisioned on 5G SA
False: Device(s) are not provisioned on 5G SA
"""
+
if isinstance(ads, list):
# Mode Pref
tasks = [(set_preferred_mode_for_5g, [ad, None, NETWORK_MODE_NR_ONLY]) for ad in ads]
@@ -230,7 +251,7 @@
log.error("failed to set preferred network mode on 5g SA")
return False
- tasks = [(is_current_network_5g_sa, [ad]) for ad in ads]
+ tasks = [(is_current_network_5g_sa, [ad, None, mmwave]) for ad in ads]
if not multithread_func(log, tasks):
log.error("phone not on 5g SA")
return False
@@ -239,30 +260,91 @@
# Mode Pref
set_preferred_mode_for_5g(ads, None, NETWORK_MODE_NR_ONLY)
- if not is_current_network_5g_sa(ads):
+ if not is_current_network_5g_sa(ads, None, mmwave):
ads.log.error("Phone not attached on SA 5g")
return False
return True
-def check_current_network_5g(ad, timeout=30, sa_5g=False, nsa_mmwave=False):
+def check_current_network_5g(
+ ad, sub_id = None, nr_type = None, mmwave = None, timeout = 30):
"""Verifies data network type is on 5G
Args:
ad: android device object.
- timeout: max time to wait for event
- sa_5g: Check for verify data network type is on 5G SA or not
- nsa_mmwave: If true, check the band of NSA network is mmWave. Default is to check sub-6.
+ sub_id: The target SIM for querying.
+ nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
+ wave.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
+ timeout: max time to wait for event.
Returns:
True: if data is on 5g
False: if data is not on 5g
"""
- if sa_5g:
- if not is_current_network_5g_sa(ad):
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
+ if nr_type == 'sa':
+ if not is_current_network_5g_sa(ad, sub_id, mmwave=mmwave):
return False
else:
- if not is_current_network_5g_nsa(ad, nsa_mmwave=nsa_mmwave, timeout=timeout):
+ if not is_current_network_5g_nsa(ad, sub_id, mmwave=mmwave,
+ timeout=timeout):
return False
return True
+
+def test_activation_by_condition(ad, sub_id=None, from_3g=False, nr_type=None,
+ precond_func=None, mmwave=None):
+ """Test 5G activation based on various pre-conditions.
+
+ Args:
+ ad: android device object.
+ sub_id: The target SIM for querying.
+ from_3g: If true, test 5G activation from 3G attaching. Otherwise, starting from 5G attaching.
+ nr_type: check the band of NR network. Default is to check sub-6.
+ precond_func: A function to execute pre conditions before testing 5G activation.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
+
+ Returns:
+ If success, return true. Otherwise, return false.
+ """
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
+ wifi_toggle_state(ad.log, ad, False)
+ toggle_airplane_mode(ad.log, ad, False)
+ if not from_3g:
+ set_preferred_mode_for_5g(ad)
+ for iteration in range(3):
+ ad.log.info("Attempt %d", iteration + 1)
+ sub_id=ad.droid.subscriptionGetDefaultSubId()
+ if from_3g:
+ # Set mode pref to 3G
+ set_preferred_network_mode_pref(ad.log,
+ ad,
+ sub_id,
+ NETWORK_MODE_WCDMA_ONLY)
+ time.sleep(15)
+ # Set mode pref to 5G
+ set_preferred_mode_for_5g(ad)
+
+ elif precond_func:
+ if not precond_func():
+ return False
+ # LTE attach
+ if not wait_for_network_generation(
+ ad.log, ad, GEN_4G, voice_or_data=NETWORK_SERVICE_DATA):
+ ad.log.error("Fail to ensure initial data in 4G")
+ # 5G attach
+ ad.log.info("Waiting for 5g NSA attach for 60 secs")
+ if is_current_network_5g_nsa(ad, sub_id, mmwave=mmwave, timeout=60):
+ ad.log.info("Success! attached on 5g NSA")
+ return True
+ else:
+ ad.log.error("Failure - expected NR_NSA, current %s",
+ get_current_override_network_type(ad))
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ ad.log.info("nsa5g attach test FAIL for all 3 iterations")
+ return False
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_5g_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_5g_utils.py
index fd9d4b3..f35272e 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_5g_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_5g_utils.py
@@ -19,79 +19,121 @@
from acts_contrib.test_utils.tel.tel_defines import DisplayInfoContainer
from acts_contrib.test_utils.tel.tel_defines import EventDisplayInfoChanged
-def is_current_network_5g_nsa(ad, nsa_mmwave=False, timeout=30):
+def is_current_network_5g_nsa(ad, sub_id = None, mmwave = None, timeout=30):
"""Verifies 5G NSA override network type
Args:
ad: android device object.
- nsa_mmwave: If true, check the band of NSA network is mmWave. Default is to check sub-6.
+ sub_id: The target SIM for querying.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
timeout: max time to wait for event.
+
Returns:
True: if data is on nsa5g NSA
False: if data is not on nsa5g NSA
"""
- ad.ed.clear_events(EventDisplayInfoChanged)
- ad.droid.telephonyStartTrackingDisplayInfoChange()
- nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_NSA
- if nsa_mmwave:
- nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_MMWAVE
- try:
- event = ad.ed.wait_for_event(
- EventDisplayInfoChanged,
- ad.ed.is_event_match,
- timeout=timeout,
- field=DisplayInfoContainer.OVERRIDE,
- value=nsa_band)
- ad.log.info("Got expected event %s", event)
- return True
- except Empty:
- ad.log.info("No event for display info change")
- return False
- finally:
- ad.droid.telephonyStopTrackingDisplayInfoChange()
- return None
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
+ def _nsa_display_monitor(ad, sub_id, mmwave, timeout):
+ ad.ed.clear_events(EventDisplayInfoChanged)
+ ad.droid.telephonyStartTrackingDisplayInfoChangeForSubscription(sub_id)
+ if mmwave:
+ nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_MMWAVE
+ else:
+ nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_NSA
+ try:
+ event = ad.ed.wait_for_event(
+ EventDisplayInfoChanged,
+ ad.ed.is_event_match,
+ timeout=timeout,
+ field=DisplayInfoContainer.OVERRIDE,
+ value=nsa_band)
+ ad.log.info("Got expected event %s", event)
+ return True
+ except Empty:
+ ad.log.info("No event for display info change with <%s>", nsa_band)
+ ad.screenshot("5g_nsa_icon_checking")
+ return False
+ finally:
+ ad.droid.telephonyStopTrackingServiceStateChangeForSubscription(
+ sub_id)
+
+ if mmwave is None:
+ return _nsa_display_monitor(
+ ad, sub_id, mmwave=False, timeout=timeout) or _nsa_display_monitor(
+ ad, sub_id, mmwave=True, timeout=timeout)
+ else:
+ return _nsa_display_monitor(ad, sub_id, mmwave, timeout)
-def is_current_network_5g_nsa_for_subscription(ad, nsa_mmwave=False, timeout=30, sub_id=None):
- """Verifies 5G NSA override network type for subscription id.
- Args:
- ad: android device object.
- nsa_mmwave: If true, check the band of NSA network is mmWave. Default is to check sub-6.
- timeout: max time to wait for event.
- sub_id: subscription id.
- Returns:
- True: if data is on nsa5g NSA
- False: if data is not on nsa5g NSA
- """
- if not sub_id:
- return is_current_network_5g_nsa(ad, nsa_mmwave=nsa_mmwave)
-
- voice_sub_id_changed = False
- current_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
- if current_sub_id != sub_id:
- ad.droid.subscriptionSetDefaultVoiceSubId(sub_id)
- voice_sub_id_changed = True
-
- result = is_current_network_5g_nsa(ad, nsa_mmwave=nsa_mmwave)
-
- if voice_sub_id_changed:
- ad.droid.subscriptionSetDefaultVoiceSubId(current_sub_id)
-
- return result
-
-def is_current_network_5g_sa(ad):
+def is_current_network_5g_sa(ad, sub_id = None, mmwave = None):
"""Verifies 5G SA override network type
Args:
ad: android device object.
+ sub_id: The target SIM for querying.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
Returns:
True: if data is on 5g SA
False: if data is not on 5g SA
"""
- network_connected = ad.droid.telephonyGetCurrentDataNetworkType()
- if network_connected == 'NR':
- ad.log.debug("Network is currently connected to %s", network_connected)
- return True
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+ current_rat = ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
+ sub_id)
+ # TODO(richardwychang): check SA MMWAVE when function ready.
+ sa_type = ['NR',]
+ if mmwave is None:
+ if current_rat in sa_type:
+ ad.log.debug("Network is currently connected to %s", current_rat)
+ return True
+ else:
+ ad.log.error(
+ "Network is currently connected to %s, Expected on %s",
+ current_rat, sa_type)
+ ad.screenshot("5g_sa_icon_checking")
+ return False
+ elif mmwave:
+ ad.log.error("SA MMWAVE currently not support.")
+ return False
else:
- ad.log.error("Network is currently connected to %s, Expected on NR", network_connected)
- return False
\ No newline at end of file
+ if current_rat == 'NR':
+ ad.log.debug("Network is currently connected to %s", current_rat)
+ return True
+ else:
+ ad.log.error(
+ "Network is currently connected to %s, Expected on NR",
+ current_rat)
+ ad.screenshot("5g_sa_icon_checking")
+ return False
+
+
+def is_current_network_5g(ad, sub_id = None, nr_type = None, mmwave = None,
+ timeout = 30):
+ """Verifies 5G override network type
+
+ Args:
+ ad: android device object
+ sub_id: The target SIM for querying.
+ nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
+ timeout: max time to wait for event.
+
+ Returns:
+ True: if data is on 5G regardless of SA or NSA
+ False: if data is not on 5G refardless of SA or NSA
+ """
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
+ if nr_type == 'nsa':
+ return is_current_network_5g_nsa(
+ ad, sub_id=sub_id, mmwave=mmwave, timeout=timeout)
+ elif nr_type == 'sa':
+ return is_current_network_5g_sa(ad, sub_id=sub_id, mmwave=mmwave)
+ else:
+ return is_current_network_5g_nsa(
+ ad, sub_id=sub_id, mmwave=mmwave,
+ timeout=timeout) or is_current_network_5g_sa(
+ ad, sub_id=sub_id, mmwave=mmwave)
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_atten_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_atten_utils.py
index 8e47a89..fdbbcc6 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_atten_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_atten_utils.py
@@ -31,7 +31,7 @@
Returns:
Current attenuation value.
"""
- return atten_obj.get_atten()
+ return atten_obj.get_atten(retry=True)
def set_atten(log, atten_obj, target_atten, step_size=0, time_per_step=0):
@@ -70,9 +70,9 @@
number_of_steps -= 1
current_atten += math.copysign(step_size,
(target_atten - current_atten))
- atten_obj.set_atten(current_atten)
+ atten_obj.set_atten(current_atten, retry=True)
time.sleep(time_per_step)
- atten_obj.set_atten(target_atten)
+ atten_obj.set_atten(target_atten, retry=True)
except Exception as e:
log.error("set_atten error happened: {}".format(e))
return False
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_bootloader_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_bootloader_utils.py
new file mode 100644
index 0000000..b503b19
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_bootloader_utils.py
@@ -0,0 +1,196 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+import re
+import time
+
+from acts.controllers.android_device import SL4A_APK_NAME
+from acts.controllers.android_device import list_adb_devices
+from acts.controllers.android_device import list_fastboot_devices
+from acts_contrib.test_utils.tel.tel_ims_utils import activate_wfc_on_device
+from acts_contrib.test_utils.tel.tel_logging_utils import set_qxdm_logger_command
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_logger
+from acts_contrib.test_utils.tel.tel_test_utils import abort_all_tests
+from acts_contrib.test_utils.tel.tel_test_utils import bring_up_sl4a
+from acts_contrib.test_utils.tel.tel_test_utils import refresh_sl4a_session
+from acts_contrib.test_utils.tel.tel_test_utils import set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_test_utils import synchronize_device_time
+from acts_contrib.test_utils.tel.tel_test_utils import unlock_sim
+
+
+def fastboot_wipe(ad, skip_setup_wizard=True):
+ """Wipe the device in fastboot mode.
+
+ Pull sl4a apk from device. Terminate all sl4a sessions,
+ Reboot the device to bootloader, wipe the device by fastboot.
+ Reboot the device. wait for device to complete booting
+ Re-intall and start an sl4a session.
+ """
+ status = True
+ # Pull sl4a apk from device
+ 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")
+ else:
+ sl4a_apk = result.group(1)
+ ad.log.info("Get sl4a apk from %s", sl4a_apk)
+ ad.pull_files([sl4a_apk], "/tmp/")
+ ad.stop_services()
+ attempts = 3
+ for i in range(1, attempts + 1):
+ try:
+ if ad.serial in list_adb_devices():
+ ad.log.info("Reboot to bootloader")
+ ad.adb.reboot("bootloader", ignore_status=True)
+ time.sleep(10)
+ if ad.serial in list_fastboot_devices():
+ ad.log.info("Wipe in fastboot")
+ ad.fastboot._w(timeout=300, ignore_status=True)
+ time.sleep(30)
+ ad.log.info("Reboot in fastboot")
+ ad.fastboot.reboot()
+ ad.wait_for_boot_completion()
+ ad.root_adb()
+ if ad.skip_sl4a:
+ break
+ if ad.is_sl4a_installed():
+ break
+ ad.log.info("Re-install sl4a")
+ ad.adb.shell("settings put global verifier_verify_adb_installs 0")
+ ad.adb.install("-r /tmp/base.apk")
+ time.sleep(10)
+ break
+ except Exception as e:
+ ad.log.warning(e)
+ if i == attempts:
+ abort_all_tests(ad.log, str(e))
+ time.sleep(5)
+ try:
+ ad.start_adb_logcat()
+ except:
+ ad.log.error("Failed to start adb logcat!")
+ if skip_setup_wizard:
+ ad.exit_setup_wizard()
+ if getattr(ad, "qxdm_log", True):
+ set_qxdm_logger_command(ad, mask=getattr(ad, "qxdm_log_mask", None))
+ start_qxdm_logger(ad)
+ if ad.skip_sl4a: return status
+ bring_up_sl4a(ad)
+ synchronize_device_time(ad)
+ set_phone_silent_mode(ad.log, ad)
+ # Activate WFC on Verizon, AT&T and Canada operators as per # b/33187374 &
+ # b/122327716
+ activate_wfc_on_device(ad.log, ad)
+ return status
+
+
+def flash_radio(ad, file_path, skip_setup_wizard=True, sideload_img=True):
+ """Flash radio image or modem binary.
+
+ Args:
+ file_path: The file path of test radio(radio.img)/binary(modem.bin).
+ skip_setup_wizard: Skip Setup Wizard if True.
+ sideload_img: True to flash radio, False to flash modem.
+ """
+ ad.stop_services()
+ ad.log.info("Reboot to bootloader")
+ ad.adb.reboot_bootloader(ignore_status=True)
+ ad.log.info("Sideload radio in fastboot")
+ try:
+ if sideload_img:
+ ad.fastboot.flash("radio %s" % file_path, timeout=300)
+ else:
+ ad.fastboot.flash("modem %s" % file_path, timeout=300)
+ except Exception as e:
+ ad.log.error(e)
+ ad.fastboot.reboot("bootloader")
+ time.sleep(5)
+ output = ad.fastboot.getvar("version-baseband")
+ result = re.search(r"version-baseband: (\S+)", output)
+ if not result:
+ ad.log.error("fastboot getvar version-baseband output = %s", output)
+ abort_all_tests(ad.log, "Radio version-baseband is not provided")
+ fastboot_radio_version_output = result.group(1)
+ for _ in range(2):
+ try:
+ ad.log.info("Reboot in fastboot")
+ ad.fastboot.reboot()
+ ad.wait_for_boot_completion()
+ break
+ except Exception as e:
+ ad.log.error("Exception error %s", e)
+ ad.root_adb()
+ adb_radio_version_output = ad.adb.getprop("gsm.version.baseband")
+ ad.log.info("adb getprop gsm.version.baseband = %s",
+ adb_radio_version_output)
+ if fastboot_radio_version_output not in adb_radio_version_output:
+ msg = ("fastboot radio version output %s does not match with adb"
+ " radio version output %s" % (fastboot_radio_version_output,
+ adb_radio_version_output))
+ abort_all_tests(ad.log, msg)
+ if not ad.ensure_screen_on():
+ ad.log.error("User window cannot come up")
+ ad.start_services(skip_setup_wizard=skip_setup_wizard)
+ unlock_sim(ad)
+
+
+def reset_device_password(ad, device_password=None):
+ # Enable or Disable Device Password per test bed config
+ unlock_sim(ad)
+ screen_lock = ad.is_screen_lock_enabled()
+ if 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
+ return
+ else:
+ # enable device password and log in for the first time
+ ad.log.info("Enable device password")
+ ad.adb.wait_for_device(timeout=180)
+ else:
+ if not screen_lock:
+ # no existing password, do not set password
+ return
+ else:
+ # password is enabled on the device
+ # 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.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)
+ if not ad.is_adb_logcat_on:
+ ad.start_adb_logcat()
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_bt_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_bt_utils.py
new file mode 100644
index 0000000..8f754ed
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_bt_utils.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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.
+
+import time
+
+from acts_contrib.test_utils.bt.bt_test_utils import bluetooth_enabled_check
+from acts_contrib.test_utils.bt.bt_test_utils import disable_bluetooth
+from acts_contrib.test_utils.bt.bt_test_utils import pair_pri_to_sec
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
+from acts_contrib.test_utils.tel.tel_data_utils import test_internet_connection
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+
+
+def enable_bluetooth_tethering_connection(log, provider, clients):
+ for ad in [provider] + clients:
+ if not bluetooth_enabled_check(ad):
+ ad.log.info("Bluetooth is not enabled")
+ return False
+ else:
+ ad.log.info("Bluetooth is enabled")
+ time.sleep(5)
+ provider.log.info("Provider enabling bluetooth tethering")
+ try:
+ provider.droid.bluetoothPanSetBluetoothTethering(True)
+ except Exception as e:
+ provider.log.warning(
+ "Failed to enable provider Bluetooth tethering with %s", e)
+ provider.droid.bluetoothPanSetBluetoothTethering(True)
+
+ 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
+ for client in clients:
+ if not (pair_pri_to_sec(provider, client)):
+ client.log.error("Client failed to pair with provider")
+ return False
+ else:
+ client.log.info("Client paired with provider")
+
+ time.sleep(5)
+ for client in clients:
+ client.droid.bluetoothConnectBonded(provider.droid.bluetoothGetLocalAddress())
+
+ time.sleep(20)
+ return True
+
+
+def verify_bluetooth_tethering_connection(log, provider, clients,
+ change_rat=None,
+ toggle_data=False,
+ toggle_tethering=False,
+ voice_call=False,
+ toggle_bluetooth=True):
+ """Setups up a bluetooth tethering connection between two android devices.
+
+ Returns:
+ True if PAN connection and verification is successful,
+ false if unsuccessful.
+ """
+
+
+ if not enable_bluetooth_tethering_connection(log, provider, clients):
+ return False
+
+ if not test_internet_connection(log, provider, clients):
+ log.error("Internet connection check failed")
+ return False
+ if voice_call:
+ log.info("====== Voice call test =====")
+ for caller, callee in [(provider, clients[0]),
+ (clients[0], provider)]:
+ if not call_setup_teardown(
+ log, caller, callee, ad_hangup=None):
+ log.error("Setup Call Failed.")
+ hangup_call(log, caller)
+ return False
+ log.info("Verify data.")
+ if not verify_internet_connection(
+ log, clients[0], retries=1):
+ clients[0].log.warning(
+ "client internet connection state is not on")
+ else:
+ clients[0].log.info(
+ "client internet connection state is on")
+ hangup_call(log, caller)
+ if not verify_internet_connection(
+ log, clients[0], retries=1):
+ clients[0].log.warning(
+ "client internet connection state is not on")
+ return False
+ else:
+ clients[0].log.info(
+ "client internet connection state is on")
+ if toggle_tethering:
+ log.info("====== Toggling provider bluetooth tethering =====")
+ provider.log.info("Disable bluetooth tethering")
+ provider.droid.bluetoothPanSetBluetoothTethering(False)
+ if not test_internet_connection(log, provider, clients, False, True):
+ log.error(
+ "Internet connection check failed after disable tethering")
+ return False
+ provider.log.info("Enable bluetooth tethering")
+ if not enable_bluetooth_tethering_connection(log,
+ provider, clients):
+ provider.log.error(
+ "Fail to re-enable bluetooth tethering")
+ return False
+ if not test_internet_connection(log, provider, clients, True, True):
+ log.error(
+ "Internet connection check failed after enable tethering")
+ return False
+ if toggle_bluetooth:
+ log.info("====== Toggling provider bluetooth =====")
+ provider.log.info("Disable provider bluetooth")
+ disable_bluetooth(provider.droid)
+ time.sleep(10)
+ if not test_internet_connection(log, provider, clients, False, True):
+ log.error(
+ "Internet connection check failed after disable bluetooth")
+ return False
+ if not enable_bluetooth_tethering_connection(log,
+ provider, clients):
+ provider.log.error(
+ "Fail to re-enable bluetooth tethering")
+ return False
+ if not test_internet_connection(log, provider, clients, True, True):
+ log.error(
+ "Internet connection check failed after enable bluetooth")
+ return False
+ if toggle_data:
+ log.info("===== Toggling provider data connection =====")
+ provider.log.info("Disable provider data connection")
+ provider.droid.telephonyToggleDataConnection(False)
+ time.sleep(10)
+ if not test_internet_connection(log, provider, clients, False, False):
+ return False
+ provider.log.info("Enable provider data connection")
+ provider.droid.telephonyToggleDataConnection(True)
+ if not wait_for_cell_data_connection(log, provider,
+ True):
+ provider.log.error(
+ "Provider failed to enable data connection.")
+ return False
+ if not test_internet_connection(log, provider, clients, True, True):
+ log.error(
+ "Internet connection check failed after enable data")
+ return False
+ if change_rat:
+ log.info("===== Change provider RAT to %s =====", change_rat)
+ if not ensure_network_generation(
+ log,
+ provider,
+ change_rat,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ toggle_apm_after_setting=False):
+ provider.log.error("Provider failed to reselect to %s.",
+ change_rat)
+ return False
+ if not test_internet_connection(log, provider, clients, True, True):
+ log.error(
+ "Internet connection check failed after RAT change to %s",
+ change_rat)
+ return False
+ return True
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_data_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_data_utils.py
index ff75bc1..05808f9 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_data_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_data_utils.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2016 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,94 +14,102 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+
+import logging
+import os
import time
import random
-import re
from queue import Empty
+from acts.controllers.android_device import SL4A_APK_NAME
from acts.utils import adb_shell_ping
from acts.utils import rand_ascii_str
from acts.utils import disable_doze
from acts.utils import enable_doze
-from acts_contrib.test_utils.bt.bt_test_utils import bluetooth_enabled_check
-from acts_contrib.test_utils.bt.bt_test_utils import disable_bluetooth
-from acts_contrib.test_utils.bt.bt_test_utils import pair_pri_to_sec
+from acts.libs.utils.multithread import multithread_func
+from acts.libs.utils.multithread import run_multithread_func
from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_subid_from_slot_index
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_data
+from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
+from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_DISCONNECTED
from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
+from acts_contrib.test_utils.tel.tel_defines import EventConnectivityChanged
from acts_contrib.test_utils.tel.tel_defines import EventNetworkCallback
from acts_contrib.test_utils.tel.tel_defines import GEN_5G
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_USER_PLANE_DATA
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WIFI_CONNECTION
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_CELL
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_WIFI
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
from acts_contrib.test_utils.tel.tel_defines import RAT_5G
-from acts_contrib.test_utils.tel.tel_defines import RAT_UNKNOWN
+from acts_contrib.test_utils.tel.tel_defines import TETHERING_MODE_WIFI
+from acts_contrib.test_utils.tel.tel_defines import TYPE_MOBILE
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_AFTER_REBOOT
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_REG_AND_CALL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_NW_VALID_FAIL
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL_RECOVERY
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL_FOR_IMS
-from acts_contrib.test_utils.tel.tel_defines import \
- WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING
-from acts_contrib.test_utils.tel.tel_defines import TETHERING_MODE_WIFI
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_TETHERING_AFTER_REBOOT
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import check_is_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import get_mobile_data_usage
+from acts_contrib.test_utils.tel.tel_defines import DataConnectionStateContainer
+from acts_contrib.test_utils.tel.tel_defines import EventDataConnectionStateChanged
+from acts_contrib.test_utils.tel.tel_5g_test_utils import check_current_network_5g
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_5g_test_utils import verify_5g_attach_for_both_devices
+from acts_contrib.test_utils.tel.tel_ims_utils import is_ims_registered
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_ims_registered
+from acts_contrib.test_utils.tel.tel_lookup_tables import connection_type_from_type_string
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_voice_attach_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import _check_file_existence
+from acts_contrib.test_utils.tel.tel_test_utils import _generate_file_directory_and_file_name
+from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state
+from acts_contrib.test_utils.tel.tel_test_utils import get_internet_connection_type
from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat_for_subscription
from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import get_wifi_usage
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
from acts_contrib.test_utils.tel.tel_test_utils import is_droid_in_network_generation_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import is_ims_registered
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
+from acts_contrib.test_utils.tel.tel_test_utils import is_event_match
from acts_contrib.test_utils.tel.tel_test_utils import rat_generation_from_rat
-from acts_contrib.test_utils.tel.tel_test_utils import set_wifi_to_default
-from acts_contrib.test_utils.tel.tel_test_utils import start_youtube_video
-from acts_contrib.test_utils.tel.tel_test_utils import start_wifi_tethering
-from acts_contrib.test_utils.tel.tel_test_utils import stop_wifi_tethering
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_data_attach_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_service
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
-from acts_contrib.test_utils.tel.tel_test_utils import \
- wait_for_voice_attach_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_reset
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_task
-from acts_contrib.test_utils.tel.tel_test_utils import run_multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_SSID_KEY
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call_active
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa
-from acts_contrib.test_utils.tel.tel_5g_test_utils import check_current_network_5g
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
-from acts_contrib.test_utils.tel.tel_5g_test_utils import verify_5g_attach_for_both_devices
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_short_seq
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_active
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
+from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_short_seq
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_SSID_KEY
+from acts_contrib.test_utils.tel.tel_wifi_utils import check_is_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import get_wifi_usage
+from acts_contrib.test_utils.tel.tel_wifi_utils import set_wifi_to_default
+from acts_contrib.test_utils.tel.tel_wifi_utils import start_wifi_tethering
+from acts_contrib.test_utils.tel.tel_wifi_utils import stop_wifi_tethering
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_reset
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
def wifi_tethering_cleanup(log, provider, client_list):
@@ -287,7 +295,12 @@
return False
-def wifi_cell_switching(log, ad, nw_gen, wifi_network_ssid=None, wifi_network_pass=None, sa_5g=False):
+def wifi_cell_switching(log,
+ ad,
+ nw_gen,
+ wifi_network_ssid=None,
+ wifi_network_pass=None,
+ nr_type=None):
"""Test data connection network switching when phone on <nw_gen>.
Ensure phone is on <nw_gen>
@@ -303,13 +316,14 @@
wifi_network_ssid: ssid for live wifi network.
wifi_network_pass: password for live wifi network.
nw_gen: network generation the phone should be camped on.
+ nr_type: check NR network.
Returns:
True if pass.
"""
try:
if nw_gen == GEN_5G:
- if not provision_device_for_5g(log, ad, sa_5g):
+ if not provision_device_for_5g(log, ad, nr_type):
return False
elif nw_gen:
if not ensure_network_generation_for_subscription(
@@ -443,7 +457,7 @@
toggle_airplane_mode(log, ad, False)
-def data_connectivity_single_bearer(log, ad, nw_gen=None, sa_5g=False):
+def data_connectivity_single_bearer(log, ad, nw_gen=None, nr_type=None):
"""Test data connection: single-bearer (no voice).
Turn off airplane mode, enable Cellular Data.
@@ -456,6 +470,7 @@
log: log object.
ad: android object.
nw_gen: network generation the phone should on.
+ nr_type: NR network type e.g. NSA, SA, MMWAVE
Returns:
True if success.
@@ -467,7 +482,7 @@
wait_time = 2 * wait_time
if nw_gen == GEN_5G:
- if not provision_device_for_5g(log, ad, sa_5g):
+ if not provision_device_for_5g(log, ad, nr_type):
return False
elif nw_gen:
if not ensure_network_generation_for_subscription(
@@ -512,7 +527,7 @@
return False
if nw_gen == GEN_5G:
- if not check_current_network_5g(ad, sa_5g):
+ if not check_current_network_5g(ad, nr_type=nr_type, timeout=60):
return False
else:
if not is_droid_in_network_generation_for_subscription(
@@ -835,7 +850,7 @@
nw_gen=None,
simultaneous_voice_data=True,
call_direction=DIRECTION_MOBILE_ORIGINATED,
- sa_5g=False):
+ nr_type=None):
"""Test data connection before call and in call.
Turn off airplane mode, disable WiFi, enable Cellular Data.
@@ -861,7 +876,7 @@
ensure_phones_idle(log, ad_list)
if nw_gen == GEN_5G:
- if not provision_device_for_5g(log, android_devices, sa_5g):
+ if not provision_device_for_5g(log, android_devices, nr_type=nr_type):
return False
elif nw_gen:
if not ensure_network_generation_for_subscription(
@@ -995,13 +1010,18 @@
return True
-def test_setup_tethering(log, provider, clients, network_generation=None, sa_5g=False):
+def test_setup_tethering(log,
+ provider,
+ clients,
+ network_generation=None,
+ nr_type=None):
"""Pre setup steps for WiFi tethering test.
Ensure all ads are idle.
Ensure tethering provider:
turn off APM, turn off WiFI, turn on Data.
have Internet connection, no active ongoing WiFi tethering.
+ nr_type: NR network type.
Returns:
True if success.
@@ -1012,7 +1032,7 @@
ensure_phones_idle(log, clients)
wifi_toggle_state(log, provider, False)
if network_generation == RAT_5G:
- if not provision_device_for_5g(log, provider, sa_5g):
+ if not provision_device_for_5g(log, provider, nr_type=nr_type):
return False
elif network_generation:
if not ensure_network_generation(
@@ -1036,7 +1056,7 @@
provider.log.info("Disable provider wifi tethering")
stop_wifi_tethering(log, provider)
provider.log.info("Provider disable bluetooth")
- disable_bluetooth(provider.droid)
+ provider.droid.bluetoothToggleState(False)
time.sleep(10)
for ad in clients:
@@ -1046,7 +1066,7 @@
ad.log.info("Client disable data")
ad.droid.telephonyToggleDataConnection(False)
ad.log.info("Client disable bluetooth")
- disable_bluetooth(ad.droid)
+ ad.droid.bluetoothToggleState(False)
ad.log.info("Client disable wifi")
wifi_toggle_state(log, ad, False)
@@ -1065,169 +1085,11 @@
return True
-def enable_bluetooth_tethering_connection(log, provider, clients):
- for ad in [provider] + clients:
- if not bluetooth_enabled_check(ad):
- ad.log.info("Bluetooth is not enabled")
- return False
- else:
- ad.log.info("Bluetooth is enabled")
- time.sleep(5)
- provider.log.info("Provider enabling bluetooth tethering")
- try:
- provider.droid.bluetoothPanSetBluetoothTethering(True)
- except Exception as e:
- provider.log.warning(
- "Failed to enable provider Bluetooth tethering with %s", e)
- provider.droid.bluetoothPanSetBluetoothTethering(True)
-
- 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
- for client in clients:
- if not (pair_pri_to_sec(provider, client)):
- client.log.error("Client failed to pair with provider")
- return False
- else:
- client.log.info("Client paired with provider")
-
- time.sleep(5)
- for client in clients:
- client.droid.bluetoothConnectBonded(provider.droid.bluetoothGetLocalAddress())
-
- time.sleep(20)
- return True
-
-
-def verify_bluetooth_tethering_connection(log, provider, clients,
- change_rat=None,
- toggle_data=False,
- toggle_tethering=False,
- voice_call=False,
- toggle_bluetooth=True):
- """Setups up a bluetooth tethering connection between two android devices.
-
- Returns:
- True if PAN connection and verification is successful,
- false if unsuccessful.
- """
-
-
- if not enable_bluetooth_tethering_connection(log, provider, clients):
- return False
-
- if not test_internet_connection(log, provider, clients):
- log.error("Internet connection check failed")
- return False
- if voice_call:
- log.info("====== Voice call test =====")
- for caller, callee in [(provider, clients[0]),
- (clients[0], provider)]:
- if not call_setup_teardown(
- log, caller, callee, ad_hangup=None):
- log.error("Setup Call Failed.")
- hangup_call(log, caller)
- return False
- log.info("Verify data.")
- if not verify_internet_connection(
- log, clients[0], retries=1):
- clients[0].log.warning(
- "client internet connection state is not on")
- else:
- clients[0].log.info(
- "client internet connection state is on")
- hangup_call(log, caller)
- if not verify_internet_connection(
- log, clients[0], retries=1):
- clients[0].log.warning(
- "client internet connection state is not on")
- return False
- else:
- clients[0].log.info(
- "client internet connection state is on")
- if toggle_tethering:
- log.info("====== Toggling provider bluetooth tethering =====")
- provider.log.info("Disable bluetooth tethering")
- provider.droid.bluetoothPanSetBluetoothTethering(False)
- if not test_internet_connection(log, provider, clients, False, True):
- log.error(
- "Internet connection check failed after disable tethering")
- return False
- provider.log.info("Enable bluetooth tethering")
- if not enable_bluetooth_tethering_connection(log,
- provider, clients):
- provider.log.error(
- "Fail to re-enable bluetooth tethering")
- return False
- if not test_internet_connection(log, provider, clients, True, True):
- log.error(
- "Internet connection check failed after enable tethering")
- return False
- if toggle_bluetooth:
- log.info("====== Toggling provider bluetooth =====")
- provider.log.info("Disable provider bluetooth")
- disable_bluetooth(provider.droid)
- time.sleep(10)
- if not test_internet_connection(log, provider, clients, False, True):
- log.error(
- "Internet connection check failed after disable bluetooth")
- return False
- if not enable_bluetooth_tethering_connection(log,
- provider, clients):
- provider.log.error(
- "Fail to re-enable bluetooth tethering")
- return False
- if not test_internet_connection(log, provider, clients, True, True):
- log.error(
- "Internet connection check failed after enable bluetooth")
- return False
- if toggle_data:
- log.info("===== Toggling provider data connection =====")
- provider.log.info("Disable provider data connection")
- provider.droid.telephonyToggleDataConnection(False)
- time.sleep(10)
- if not test_internet_connection(log, provider, clients, False, False):
- return False
- provider.log.info("Enable provider data connection")
- provider.droid.telephonyToggleDataConnection(True)
- if not wait_for_cell_data_connection(log, provider,
- True):
- provider.log.error(
- "Provider failed to enable data connection.")
- return False
- if not test_internet_connection(log, provider, clients, True, True):
- log.error(
- "Internet connection check failed after enable data")
- return False
- if change_rat:
- log.info("===== Change provider RAT to %s =====", change_rat)
- if not ensure_network_generation(
- log,
- provider,
- change_rat,
- voice_or_data=NETWORK_SERVICE_DATA,
- toggle_apm_after_setting=False):
- provider.log.error("Provider failed to reselect to %s.",
- change_rat)
- return False
- if not test_internet_connection(log, provider, clients, True, True):
- log.error(
- "Internet connection check failed after RAT change to %s",
- change_rat)
- return False
- return True
-
-
def test_tethering_wifi_and_voice_call(log, provider, clients,
provider_data_rat,
provider_setup_func,
provider_in_call_check_func,
- sa_5g=False):
+ nr_type=None):
if not test_setup_tethering(log, provider, clients, provider_data_rat):
log.error("Verify 4G Internet access failed.")
@@ -1240,7 +1102,7 @@
return False
if provider_setup_func == RAT_5G:
- if not provision_device_for_5g(log, provider, sa_5g):
+ if not provision_device_for_5g(log, provider, nr_type=nr_type):
return False
try:
log.info("1. Setup WiFi Tethering.")
@@ -1314,36 +1176,38 @@
True, False, True, False, False, True, False, False, False, False,
True, False, False, False, False, False, False, False, False
]
+ try:
+ for toggle in wifi_toggles:
- for toggle in wifi_toggles:
+ wifi_reset(log, ad, toggle)
- wifi_reset(log, ad, toggle)
+ if not wait_for_cell_data_connection(
+ log, ad, True, MAX_WAIT_TIME_WIFI_CONNECTION):
+ log.error("Failed data connection, aborting!")
+ return False
- if not wait_for_cell_data_connection(
- log, ad, True, MAX_WAIT_TIME_WIFI_CONNECTION):
- log.error("Failed wifi connection, aborting!")
- return False
+ if not verify_internet_connection(log, ad):
+ log.error("Failed to get user-plane traffic, aborting!")
+ return False
- if not verify_internet_connection(log, ad):
- log.error("Failed to get user-plane traffic, aborting!")
- return False
+ if toggle:
+ wifi_toggle_state(log, ad, True)
- if toggle:
- wifi_toggle_state(log, ad, True)
+ ensure_wifi_connected(log, ad, wifi_network_ssid,
+ wifi_network_pass)
- ensure_wifi_connected(log, ad, wifi_network_ssid,
- wifi_network_pass)
+ if not wait_for_wifi_data_connection(
+ log, ad, True, MAX_WAIT_TIME_WIFI_CONNECTION):
+ log.error("Failed wifi connection, aborting!")
+ return False
- if not wait_for_wifi_data_connection(
- log, ad, True, MAX_WAIT_TIME_WIFI_CONNECTION):
- log.error("Failed wifi connection, aborting!")
- return False
-
- if not verify_http_connection(
- log, ad, 'http://www.google.com', 100, .1):
- log.error("Failed to get user-plane traffic, aborting!")
- return False
- return True
+ if not verify_http_connection(
+ log, ad, 'http://www.google.com', 100, .1):
+ log.error("Failed to get user-plane traffic, aborting!")
+ return False
+ return True
+ finally:
+ wifi_toggle_state(log, ad, False)
def test_call_setup_in_active_data_transfer(
@@ -1352,7 +1216,7 @@
nw_gen=None,
call_direction=DIRECTION_MOBILE_ORIGINATED,
allow_data_transfer_interruption=False,
- sa_5g=False):
+ nr_type=None):
"""Test call can be established during active data connection.
Turn off airplane mode, disable WiFi, enable Cellular Data.
@@ -1385,7 +1249,7 @@
wait_time_in_call)
if nw_gen == GEN_5G:
- if not provision_device_for_5g(log, ads[0], sa_5g):
+ if not provision_device_for_5g(log, ads[0], nr_type=nr_type):
return False
elif nw_gen:
if not ensure_network_generation(log, ads[0], nw_gen,
@@ -1440,7 +1304,8 @@
return False
# Disable airplane mode if test under apm on.
toggle_airplane_mode(log, ads[0], False)
- if nw_gen == GEN_5G and not check_current_network_5g(ads[0], sa_5g):
+ if nw_gen == GEN_5G and not check_current_network_5g(ads[0],
+ nr_type=nr_type):
ads[0].log.error("Phone not attached on 5G after call.")
return False
return True
@@ -1452,7 +1317,7 @@
nw_gen=None,
call_direction=DIRECTION_MOBILE_ORIGINATED,
allow_data_transfer_interruption=False,
- sa_5g=False):
+ nr_type=None):
"""Test call can be established during active data connection.
Turn off airplane mode, disable WiFi, enable Cellular Data.
@@ -1471,7 +1336,7 @@
False if failed.
"""
if nw_gen == GEN_5G:
- if not provision_device_for_5g(log, ads[0], sa_5g):
+ if not provision_device_for_5g(log, ads[0], nr_type=nr_type):
return False
elif nw_gen:
if not ensure_network_generation(log, ads[0], nw_gen,
@@ -1518,7 +1383,8 @@
ad_download.force_stop_apk("com.google.android.youtube")
# Disable airplane mode if test under apm on.
toggle_airplane_mode(log, ads[0], False)
- if nw_gen == GEN_5G and not check_current_network_5g(ads[0], sa_5g):
+ if nw_gen == GEN_5G and not check_current_network_5g(ads[0],
+ nr_type=nr_type):
ads[0].log.error("Phone not attached on 5G after call.")
result = False
return result
@@ -1531,7 +1397,7 @@
wifi_ssid,
wifi_pwd,
nw_gen=None,
- sa_5g=False):
+ nr_type=None):
""" Test epdg<->epdg call functionality.
Make Sure PhoneA is set to make epdg call.
@@ -1565,7 +1431,7 @@
if not multithread_func(log, tasks):
log.error("Failed to turn off airplane mode")
return False
- if not provision_device_for_5g(log, ad, sa_5g):
+ if not provision_device_for_5g(log, ads, nr_type):
return False
tasks = [(phone_setup_iwlan, (log, ads[0], apm_mode, wfc_mode,
@@ -1588,7 +1454,8 @@
time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- if nw_gen == GEN_5G and not verify_5g_attach_for_both_devices(log, ads, sa_5g):
+ if nw_gen == GEN_5G and not verify_5g_attach_for_both_devices(
+ log, ads, nr_type=nr_type):
log.error("Phone not attached on 5G after epdg call.")
return False
@@ -1688,7 +1555,8 @@
do_cleanup=True,
ssid=None,
password=None,
- pre_teardown_func=None):
+ pre_teardown_func=None,
+ nr_type=None):
"""WiFi Tethering test
Args:
log: log object.
@@ -1711,9 +1579,10 @@
This is optional. Default value is None.
If it's None, a random string will be generated.
pre_teardown_func: execute custom actions between tethering setup adn teardown.
+ nr_type: NR network type e.g. NSA, SA, MMWAVE.
"""
- if not test_setup_tethering(log, provider, clients, nw_gen):
+ if not test_setup_tethering(log, provider, clients, nw_gen, nr_type=nr_type):
log.error("Verify %s Internet access failed.", nw_gen)
return False
@@ -2013,13 +1882,16 @@
def verify_toggle_data_during_wifi_tethering(log,
provider,
clients,
- new_gen=None):
+ new_gen=None,
+ nr_type=None):
"""Verify toggle Data network during WiFi Tethering.
Args:
log: log object.
provider: android device object for provider.
clients: android device objects for clients.
new_gen: network generation.
+ nr_type: NR network type e.g. NSA, SA, MMWAVE.
+
Returns:
True if pass, otherwise False.
@@ -2035,7 +1907,8 @@
check_interval=10,
check_iteration=2,
do_cleanup=False,
- ssid=ssid):
+ ssid=ssid,
+ nr_type=nr_type):
log.error("WiFi Tethering failed.")
return False
if not provider.droid.wifiIsApEnabled():
@@ -2082,3 +1955,914 @@
clients):
return False
return True
+
+def deactivate_and_verify_cellular_data(log, ad):
+ """Toggle off cellular data and ensure there is no internet connection.
+
+ Args:
+ ad: Android object
+
+ Returns:
+ True if cellular data is deactivated successfully. Otherwise False.
+ """
+ ad.log.info('Deactivating cellular data......')
+ ad.droid.telephonyToggleDataConnection(False)
+
+ if not wait_for_cell_data_connection(log, ad, False):
+ ad.log.error("Failed to deactivate cell data connection.")
+ return False
+
+ if not verify_internet_connection(log, ad, expected_state=False):
+ ad.log.error("Internet connection is still available.")
+ return False
+
+ return True
+
+def activate_and_verify_cellular_data(log, ad):
+ """Toggle on cellular data and ensure there is internet connection.
+
+ Args:
+ ad: Android object
+
+ Returns:
+ True if cellular data is activated successfully. Otherwise False.
+ """
+ ad.log.info('Activating cellular data......')
+ ad.droid.telephonyToggleDataConnection(True)
+
+ if not wait_for_cell_data_connection(log, ad, True):
+ ad.log.error("Failed to activate data connection.")
+ return False
+
+ if not verify_internet_connection(log, ad, retries=3):
+ ad.log.error("Internet connection is NOT available.")
+ return False
+
+ return True
+
+
+def wait_for_network_service(
+ log,
+ ad,
+ wifi_connected=False,
+ wifi_ssid=None,
+ ims_reg=True,
+ recover=False,
+ retry=3):
+ """ Wait for multiple network services in sequence, including:
+ - service state
+ - network connection
+ - wifi connection
+ - cellular data
+ - internet connection
+ - IMS registration
+
+ The mechanism (cycling airplane mode) to recover network services is
+ also provided if any service is not available.
+
+ Args:
+ log: log object
+ ad: android device
+ wifi_connected: True if wifi should be connected. Otherwise False.
+ ims_reg: True if IMS should be registered. Otherwise False.
+ recover: True if the mechanism (cycling airplane mode) to recover
+ network services should be enabled (by default False).
+ retry: times of retry.
+ """
+ times = 1
+ while times <= retry:
+ while True:
+ if not wait_for_state(
+ get_service_state_by_adb,
+ "IN_SERVICE",
+ MAX_WAIT_TIME_FOR_STATE_CHANGE,
+ WAIT_TIME_BETWEEN_STATE_CHECK,
+ log,
+ ad):
+ ad.log.error("Current service state is not 'IN_SERVICE'.")
+ break
+
+ if not wait_for_state(
+ ad.droid.connectivityNetworkIsConnected,
+ True,
+ MAX_WAIT_TIME_FOR_STATE_CHANGE,
+ WAIT_TIME_BETWEEN_STATE_CHECK):
+ ad.log.error("Network is NOT connected!")
+ break
+
+ if wifi_connected and wifi_ssid:
+ if not wait_for_state(
+ check_is_wifi_connected,
+ True,
+ MAX_WAIT_TIME_FOR_STATE_CHANGE,
+ WAIT_TIME_BETWEEN_STATE_CHECK,
+ log,
+ ad,
+ wifi_ssid):
+ ad.log.error("Failed to connect Wi-Fi SSID '%s'.", wifi_ssid)
+ break
+ else:
+ if not wait_for_cell_data_connection(log, ad, True):
+ ad.log.error("Failed to enable data connection.")
+ break
+
+ if not wait_for_state(
+ verify_internet_connection,
+ True,
+ MAX_WAIT_TIME_FOR_STATE_CHANGE,
+ WAIT_TIME_BETWEEN_STATE_CHECK,
+ log,
+ ad):
+ ad.log.error("Data not available on cell.")
+ break
+
+ if ims_reg:
+ if not wait_for_ims_registered(log, ad):
+ ad.log.error("IMS is not registered.")
+ break
+ ad.log.info("IMS is registered.")
+ return True
+
+ if recover:
+ ad.log.warning("Trying to recover by cycling airplane mode...")
+ if not toggle_airplane_mode(log, ad, True):
+ ad.log.error("Failed to enable airplane mode")
+ break
+
+ time.sleep(5)
+
+ if not toggle_airplane_mode(log, ad, False):
+ ad.log.error("Failed to disable airplane mode")
+ break
+
+ times = times + 1
+
+ else:
+ return False
+ return False
+
+
+def wait_for_cell_data_connection(
+ log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
+ """Wait for data connection status to be expected value for default
+ data subscription.
+
+ Wait for the data connection status to be DATA_STATE_CONNECTED
+ or DATA_STATE_DISCONNECTED.
+
+ Args:
+ log: Log object.
+ ad: Android Device Object.
+ state: Expected status: True or False.
+ 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 MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ sub_id = get_default_data_sub_id(ad)
+ return wait_for_cell_data_connection_for_subscription(
+ log, ad, sub_id, state, timeout_value)
+
+
+def _is_data_connection_state_match(log, ad, expected_data_connection_state):
+ return (expected_data_connection_state ==
+ ad.droid.telephonyGetDataConnectionState())
+
+
+def _is_network_connected_state_match(log, ad,
+ expected_network_connected_state):
+ return (expected_network_connected_state ==
+ ad.droid.connectivityNetworkIsConnected())
+
+
+def wait_for_cell_data_connection_for_subscription(
+ 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.
+
+ Wait for the data connection status to be DATA_STATE_CONNECTED
+ or DATA_STATE_DISCONNECTED.
+
+ Args:
+ log: Log object.
+ ad: Android Device Object.
+ sub_id: subscription Id
+ state: Expected status: True or False.
+ 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 MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ state_str = {
+ True: DATA_STATE_CONNECTED,
+ False: DATA_STATE_DISCONNECTED
+ }[state]
+
+ data_state = ad.droid.telephonyGetDataConnectionState()
+ if not state and ad.droid.telephonyGetDataConnectionState() == state_str:
+ return True
+
+ ad.ed.clear_events(EventDataConnectionStateChanged)
+ ad.droid.telephonyStartTrackingDataConnectionStateChangeForSubscription(
+ sub_id)
+ ad.droid.connectivityStartTrackingConnectivityStateChange()
+ try:
+ ad.log.info("User data enabled for sub_id %s: %s", sub_id,
+ ad.droid.telephonyIsDataEnabledForSubscription(sub_id))
+ data_state = ad.droid.telephonyGetDataConnectionState()
+ ad.log.info("Data connection state is %s", data_state)
+ ad.log.info("Network is connected: %s",
+ ad.droid.connectivityNetworkIsConnected())
+ if data_state == state_str:
+ return _wait_for_nw_data_connection(
+ log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
+
+ try:
+ ad.ed.wait_for_event(
+ EventDataConnectionStateChanged,
+ is_event_match,
+ timeout=timeout_value,
+ field=DataConnectionStateContainer.DATA_CONNECTION_STATE,
+ value=state_str)
+ except Empty:
+ ad.log.info("No expected event EventDataConnectionStateChanged %s",
+ state_str)
+
+ # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
+ # data connection state.
+ # Otherwise, the network state will not be correct.
+ # The bug is tracked here: b/20921915
+
+ # Previously we use _is_data_connection_state_match,
+ # but telephonyGetDataConnectionState sometimes return wrong value.
+ # The bug is tracked here: b/22612607
+ # So we use _is_network_connected_state_match.
+
+ 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)
+ else:
+ return False
+
+ finally:
+ ad.droid.telephonyStopTrackingDataConnectionStateChangeForSubscription(
+ sub_id)
+
+
+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
+ or DATA_STATE_DISCONNECTED.
+
+ Args:
+ log: Log object.
+ ad: Android Device Object.
+ state: Expected status: True or False.
+ 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 MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return _wait_for_nw_data_connection(log, ad, state, None, timeout_value)
+
+
+def wait_for_wifi_data_connection(
+ 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:
+ log: Log object.
+ ad: Android Device Object.
+ state: Expected status: True or False.
+ 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 MAX_WAIT_TIME_NW_SELECTION
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ ad.log.info("wait_for_wifi_data_connection")
+ return _wait_for_nw_data_connection(
+ log, ad, state, NETWORK_CONNECTION_TYPE_WIFI, timeout_value)
+
+
+def _connection_state_change(_event, target_state, connection_type):
+ if connection_type:
+ if 'TypeName' not in _event['data']:
+ return False
+ connection_type_string_in_event = _event['data']['TypeName']
+ cur_type = connection_type_from_type_string(
+ connection_type_string_in_event)
+ if cur_type != connection_type:
+ logging.info(
+ "_connection_state_change expect: %s, received: %s <type %s>",
+ connection_type, connection_type_string_in_event, cur_type)
+ return False
+
+ if 'isConnected' in _event['data'] and _event['data']['isConnected'] == target_state:
+ return True
+ return False
+
+
+def _wait_for_nw_data_connection(
+ log,
+ ad,
+ is_connected,
+ connection_type=None,
+ 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
+ or DATA_STATE_DISCONNECTED.
+
+ Args:
+ log: Log object.
+ ad: Android Device Object.
+ is_connected: Expected connection status: True or False.
+ If True, it will wait for status to be DATA_STATE_CONNECTED.
+ If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
+ 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 MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ ad.ed.clear_events(EventConnectivityChanged)
+ ad.droid.connectivityStartTrackingConnectivityStateChange()
+ try:
+ cur_data_connection_state = ad.droid.connectivityNetworkIsConnected()
+ if is_connected == cur_data_connection_state:
+ current_type = get_internet_connection_type(log, ad)
+ ad.log.info("current data connection type: %s", current_type)
+ if not connection_type:
+ return True
+ else:
+ if not is_connected and current_type != connection_type:
+ ad.log.info("data connection not on %s!", connection_type)
+ return True
+ elif is_connected and current_type == connection_type:
+ ad.log.info("data connection on %s as expected",
+ connection_type)
+ return True
+ else:
+ ad.log.info("current data connection state: %s target: %s",
+ cur_data_connection_state, is_connected)
+
+ try:
+ event = ad.ed.wait_for_event(
+ EventConnectivityChanged, _connection_state_change,
+ timeout_value, is_connected, connection_type)
+ ad.log.info("Got event: %s", event)
+ except Empty:
+ pass
+
+ log.info(
+ "_wait_for_nw_data_connection: check connection after wait event.")
+ # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
+ # 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, 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:
+ return True
+ else:
+ if not is_connected and current_type != connection_type:
+ ad.log.info("data connection not on %s", connection_type)
+ return True
+ elif is_connected and current_type == connection_type:
+ ad.log.info("after event wait, data connection on %s",
+ connection_type)
+ return True
+ else:
+ return False
+ else:
+ return False
+ except Exception as e:
+ ad.log.error("Exception error %s", str(e))
+ return False
+ finally:
+ ad.droid.connectivityStopTrackingConnectivityStateChange()
+
+
+def check_curl_availability(ad):
+ if not hasattr(ad, "curl_capable"):
+ try:
+ out = ad.adb.shell("/data/curl --version")
+ if not out or "not found" in out:
+ setattr(ad, "curl_capable", False)
+ ad.log.info("curl is unavailable, use chrome to download file")
+ else:
+ setattr(ad, "curl_capable", True)
+ except Exception:
+ setattr(ad, "curl_capable", False)
+ ad.log.info("curl is unavailable, use chrome to download file")
+ return ad.curl_capable
+
+
+def start_youtube_video(ad, url="vnd.youtube:watch?v=pSJoP0LR8CQ"):
+ ad.log.info("Open an youtube video")
+ for _ in range(3):
+ ad.ensure_screen_on()
+ ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
+ if wait_for_state(ad.droid.audioIsMusicActive, True, 15, 1):
+ ad.log.info("Started a video in youtube, audio is in MUSIC state")
+ return True
+ ad.log.info("Audio is not in MUSIC state. Quit Youtube.")
+ for _ in range(3):
+ ad.send_keycode("BACK")
+ time.sleep(1)
+ time.sleep(3)
+ return False
+
+
+def http_file_download_by_sl4a(ad,
+ url,
+ out_path=None,
+ expected_file_size=None,
+ remove_file_after_check=True,
+ timeout=300):
+ """Download http file by sl4a RPC call.
+
+ Args:
+ ad: Android Device Object.
+ url: The url that file to be downloaded from".
+ out_path: Optional. Where to download file to.
+ out_path is /sdcard/Download/ by default.
+ expected_file_size: Optional. Provided if checking the download file meet
+ expected file size in unit of byte.
+ remove_file_after_check: Whether to remove the downloaded file after
+ check.
+ timeout: timeout for file download to complete.
+ """
+ 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
+ try:
+ if not getattr(ad, "data_droid", None):
+ ad.data_droid, ad.data_ed = ad.get_droid()
+ ad.data_ed.start()
+ else:
+ try:
+ if not ad.data_droid.is_live:
+ ad.data_droid, ad.data_ed = ad.get_droid()
+ ad.data_ed.start()
+ except Exception:
+ ad.log.info("Start new sl4a session for file download")
+ ad.data_droid, ad.data_ed = ad.get_droid()
+ ad.data_ed.start()
+ data_accounting = {
+ "mobile_rx_bytes":
+ ad.droid.getMobileRxBytes(),
+ "subscriber_mobile_data_usage":
+ get_mobile_data_usage(ad, None, None),
+ "sl4a_mobile_data_usage":
+ get_mobile_data_usage(ad, None, accounting_apk)
+ }
+ ad.log.debug("Before downloading: %s", data_accounting)
+ ad.log.info("Download file from %s to %s by sl4a RPC call", url,
+ file_path)
+ try:
+ ad.data_droid.httpDownloadFile(url, file_path, timeout=timeout)
+ except Exception as e:
+ ad.log.warning("SL4A file download error: %s", e)
+ ad.data_droid.terminate()
+ return False
+ if _check_file_existence(ad, file_path, expected_file_size):
+ ad.log.info("%s is downloaded successfully", url)
+ new_data_accounting = {
+ "mobile_rx_bytes":
+ ad.droid.getMobileRxBytes(),
+ "subscriber_mobile_data_usage":
+ get_mobile_data_usage(ad, None, None),
+ "sl4a_mobile_data_usage":
+ get_mobile_data_usage(ad, None, accounting_apk)
+ }
+ ad.log.debug("After downloading: %s", new_data_accounting)
+ accounting_diff = {
+ key: value - data_accounting[key]
+ for key, value in new_data_accounting.items()
+ }
+ ad.log.debug("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.debug("%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
+ except Exception as e:
+ ad.log.error("Download %s failed with exception %s", url, e)
+ raise
+ finally:
+ 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)
+
+
+def http_file_download_by_curl(ad,
+ url,
+ out_path=None,
+ expected_file_size=None,
+ remove_file_after_check=True,
+ timeout=3600,
+ limit_rate=None,
+ retry=3):
+ """Download http file by adb curl.
+
+ Args:
+ ad: Android Device Object.
+ url: The url that file to be downloaded from".
+ out_path: Optional. Where to download file to.
+ out_path is /sdcard/Download/ by default.
+ expected_file_size: Optional. Provided if checking the download file meet
+ expected file size in unit of byte.
+ remove_file_after_check: Whether to remove the downloaded file after
+ check.
+ timeout: timeout for file download to complete.
+ limit_rate: download rate in bps. None, if do not apply rate limit.
+ retry: the retry request times provided in curl command.
+ """
+ file_directory, file_name = _generate_file_directory_and_file_name(
+ url, out_path)
+ file_path = os.path.join(file_directory, file_name)
+ curl_cmd = "/data/curl"
+ if limit_rate:
+ curl_cmd += " --limit-rate %s" % limit_rate
+ if retry:
+ curl_cmd += " --retry %s" % retry
+ curl_cmd += " --url %s > %s" % (url, file_path)
+ try:
+ 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_existence(ad, file_path, expected_file_size):
+ ad.log.info("%s is downloaded to %s successfully", url, file_path)
+ return True
+ else:
+ ad.log.warning("Fail to download %s", url)
+ return False
+ except Exception as e:
+ ad.log.warning("Download %s failed with exception %s", url, e)
+ return False
+ finally:
+ 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)
+
+
+def open_url_by_adb(ad, url):
+ ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
+
+
+def http_file_download_by_chrome(ad,
+ url,
+ expected_file_size=None,
+ remove_file_after_check=True,
+ timeout=3600):
+ """Download http file by chrome.
+
+ Args:
+ ad: Android Device Object.
+ url: The url that file to be downloaded from".
+ expected_file_size: Optional. Provided if checking the download file meet
+ expected file size in unit of byte.
+ remove_file_after_check: Whether to remove the downloaded file after
+ 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(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/.*")
+ 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),
+ "chrome_mobile_data_usage": get_mobile_data_usage(
+ ad, None, chrome_apk)
+ }
+ ad.log.debug("Before downloading: %s", data_accounting)
+ ad.log.info("Download %s with timeout %s", url, timeout)
+ ad.ensure_screen_on()
+ open_url_by_adb(ad, url)
+ elapse_time = 0
+ result = True
+ while elapse_time < timeout:
+ time.sleep(30)
+ if _check_file_existence(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 -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),
+ "chrome_mobile_data_usage":
+ get_mobile_data_usage(ad, None, chrome_apk)
+ }
+ 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.debug("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_existence(ad, "%s.crdownload" % file_path):
+ ad.log.info("Chrome is downloading %s", url)
+ elif elapse_time < 60:
+ # download not started, retry download wit chrome again
+ open_url_by_adb(ad, url)
+ else:
+ ad.log.error("Unable to download file from %s", url)
+ break
+ elapse_time += 30
+ ad.log.warning("Fail to download file from %s", url)
+ ad.force_stop_apk("com.android.chrome")
+ 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 get_mobile_data_usage(ad, sid=None, apk=None):
+ if not sid:
+ sid = ad.droid.subscriptionGetDefaultDataSubId()
+ current_time = int(time.time() * 1000)
+ begin_time = current_time - 10 * 24 * 60 * 60 * 1000
+ end_time = current_time + 10 * 24 * 60 * 60 * 1000
+
+ if apk:
+ uid = ad.get_apk_uid(apk)
+ ad.log.debug("apk %s uid = %s", apk, uid)
+ try:
+ usage_info = ad.droid.getMobileDataUsageInfoForUid(uid, sid)
+ ad.log.debug("Mobile data usage info for uid %s = %s", uid,
+ usage_info)
+ return usage_info["UsageLevel"]
+ except:
+ try:
+ return ad.droid.connectivityQueryDetailsForUid(
+ TYPE_MOBILE,
+ ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+ begin_time, end_time, uid)
+ except:
+ return ad.droid.connectivityQueryDetailsForUid(
+ ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+ begin_time, end_time, uid)
+ else:
+ try:
+ usage_info = ad.droid.getMobileDataUsageInfo(sid)
+ ad.log.debug("Mobile data usage info = %s", usage_info)
+ return usage_info["UsageLevel"]
+ except:
+ try:
+ return ad.droid.connectivityQuerySummaryForDevice(
+ TYPE_MOBILE,
+ ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+ begin_time, end_time)
+ except:
+ return ad.droid.connectivityQuerySummaryForDevice(
+ ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+ begin_time, end_time)
+
+
+def set_mobile_data_usage_limit(ad, limit, subscriber_id=None):
+ if not subscriber_id:
+ subscriber_id = ad.droid.telephonyGetSubscriberId()
+ ad.log.debug("Set subscriber mobile data usage limit to %s", limit)
+ ad.droid.logV("Setting subscriber mobile data usage limit to %s" % limit)
+ try:
+ ad.droid.connectivitySetDataUsageLimit(subscriber_id, str(limit))
+ except:
+ ad.droid.connectivitySetDataUsageLimit(subscriber_id, limit)
+
+
+def remove_mobile_data_usage_limit(ad, subscriber_id=None):
+ if not subscriber_id:
+ subscriber_id = ad.droid.telephonyGetSubscriberId()
+ ad.log.debug("Remove subscriber mobile data usage limit")
+ ad.droid.logV(
+ "Setting subscriber mobile data usage limit to -1, unlimited")
+ try:
+ ad.droid.connectivitySetDataUsageLimit(subscriber_id, "-1")
+ except:
+ ad.droid.connectivitySetDataUsageLimit(subscriber_id, -1)
+
+
+def active_file_download_task(log, ad, file_name="5MB", method="curl"):
+ # 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
+ file_size_map = {
+ '1MB': 1000000,
+ '5MB': 5000000,
+ '10MB': 10000000,
+ '20MB': 20000000,
+ '50MB': 50000000,
+ '100MB': 100000000,
+ '200MB': 200000000,
+ '512MB': 512000000
+ }
+ url_map = {
+ "1MB": [
+ "http://146.148.91.8/download/1MB.zip",
+ "http://ipv4.download.thinkbroadband.com/1MB.zip"
+ ],
+ "5MB": [
+ "http://146.148.91.8/download/5MB.zip",
+ "http://212.183.159.230/5MB.zip",
+ "http://ipv4.download.thinkbroadband.com/5MB.zip"
+ ],
+ "10MB": [
+ "http://146.148.91.8/download/10MB.zip",
+ "http://212.183.159.230/10MB.zip",
+ "http://ipv4.download.thinkbroadband.com/10MB.zip",
+ "http://lax.futurehosting.com/test.zip",
+ "http://ovh.net/files/10Mio.dat"
+ ],
+ "20MB": [
+ "http://146.148.91.8/download/20MB.zip",
+ "http://212.183.159.230/20MB.zip",
+ "http://ipv4.download.thinkbroadband.com/20MB.zip"
+ ],
+ "50MB": [
+ "http://146.148.91.8/download/50MB.zip",
+ "http://212.183.159.230/50MB.zip",
+ "http://ipv4.download.thinkbroadband.com/50MB.zip"
+ ],
+ "100MB": [
+ "http://146.148.91.8/download/100MB.zip",
+ "http://212.183.159.230/100MB.zip",
+ "http://ipv4.download.thinkbroadband.com/100MB.zip",
+ "http://speedtest-ca.turnkeyinternet.net/100mb.bin",
+ "http://ovh.net/files/100Mio.dat",
+ "http://lax.futurehosting.com/test100.zip"
+ ],
+ "200MB": [
+ "http://146.148.91.8/download/200MB.zip",
+ "http://212.183.159.230/200MB.zip",
+ "http://ipv4.download.thinkbroadband.com/200MB.zip"
+ ],
+ "512MB": [
+ "http://146.148.91.8/download/512MB.zip",
+ "http://212.183.159.230/512MB.zip",
+ "http://ipv4.download.thinkbroadband.com/512MB.zip"
+ ]
+ }
+
+ file_size = file_size_map.get(file_name)
+ file_urls = url_map.get(file_name)
+ file_url = None
+ for url in file_urls:
+ url_splits = url.split("/")
+ if verify_http_connection(log, ad, url=url, retry=1):
+ output_path = "/sdcard/Download/%s" % url_splits[-1]
+ file_url = url
+ break
+ if not file_url:
+ ad.log.error("No url is available to download %s", file_name)
+ return False
+ timeout = min(max(file_size / 100000, 600), 3600)
+ if method == "sl4a":
+ return (http_file_download_by_sl4a, (ad, file_url, output_path,
+ file_size, True, timeout))
+ if method == "curl" and check_curl_availability(ad):
+ return (http_file_download_by_curl, (ad, file_url, output_path,
+ file_size, True, timeout))
+ elif method == "sl4a" or method == "curl":
+ return (http_file_download_by_sl4a, (ad, file_url, output_path,
+ file_size, True, timeout))
+ else:
+ return (http_file_download_by_chrome, (ad, file_url, file_size, True,
+ timeout))
+
+
+def active_file_download_test(log, ad, file_name="5MB", method="sl4a"):
+ task = active_file_download_task(log, ad, file_name, method=method)
+ if not task:
+ return False
+ return task[0](*task[1])
+
+
+def check_data_stall_detection(ad, wait_time=WAIT_TIME_FOR_DATA_STALL):
+ data_stall_detected = False
+ time_var = 1
+ try:
+ while (time_var < wait_time):
+ out = ad.adb.shell("dumpsys network_stack " \
+ "| grep \"Suspecting data stall\"",
+ ignore_status=True)
+ ad.log.debug("Output is %s", out)
+ if out:
+ ad.log.info("NetworkMonitor detected - %s", out)
+ data_stall_detected = True
+ break
+ time.sleep(30)
+ time_var += 30
+ except Exception as e:
+ ad.log.error(e)
+ return data_stall_detected
+
+
+def check_network_validation_fail(ad, begin_time=None,
+ wait_time=WAIT_TIME_FOR_NW_VALID_FAIL):
+ network_validation_fail = False
+ time_var = 1
+ try:
+ while (time_var < wait_time):
+ time_var += 30
+ nw_valid = ad.search_logcat("validation failed",
+ begin_time)
+ if nw_valid:
+ ad.log.info("Validation Failed received here - %s",
+ nw_valid[0]["log_message"])
+ network_validation_fail = True
+ break
+ time.sleep(30)
+ except Exception as e:
+ ad.log.error(e)
+ return network_validation_fail
+
+
+def check_data_stall_recovery(ad, begin_time=None,
+ wait_time=WAIT_TIME_FOR_DATA_STALL_RECOVERY):
+ data_stall_recovery = False
+ time_var = 1
+ try:
+ while (time_var < wait_time):
+ time_var += 30
+ recovery = ad.search_logcat("doRecovery() cleanup all connections",
+ begin_time)
+ if recovery:
+ ad.log.info("Recovery Performed here - %s",
+ recovery[-1]["log_message"])
+ data_stall_recovery = True
+ break
+ time.sleep(30)
+ except Exception as e:
+ ad.log.error(e)
+ return data_stall_recovery
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_defines.py b/acts_tests/acts_contrib/test_utils/tel/tel_defines.py
index 6761380..a8b4108 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_defines.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_defines.py
@@ -354,6 +354,9 @@
CARRIER_KDDI = 'kddi'
CARRIER_RAKUTEN = 'rakuten'
CARRIER_SBM = 'sbm'
+CARRIER_SKT = 'skt'
+CARRIER_KT = 'kt'
+CARRIER_LG_UPLUS = 'lg_uplus'
RAT_FAMILY_CDMA = 'cdma'
RAT_FAMILY_CDMA2000 = 'cdma2000'
@@ -684,10 +687,17 @@
NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA = "NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA"
NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = "NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA"
+# Constants for APP Package Name
+DIALER_PACKAGE_NAME = "com.google.android.dialer"
+MESSAGE_PACKAGE_NAME = "com.google.android.apps.messaging"
+YOUTUBE_PACKAGE_NAME = "com.google.android.youtube"
+SL4A_PACKAGE_NAME = "com.googlecode.android_scripting"
+
# Constants for CellBroadcast module test
CARRIER_TEST_CONF_XML_PATH = "/data/user_de/0/com.android.phone/files/"
MAIN_ACTIVITY = "android.intent.action.MAIN"
CBR_PACKAGE = "com.google.android.cellbroadcastreceiver"
+SYSUI_PACKAGE = "com.android.systemui"
CBR_ACTIVITY = "com.android.cellbroadcastreceiver.CellBroadcastSettings"
CBR_TEST_APK = "com.android.cellbroadcastreceiver.tests"
MCC_MNC = "mccmnc"
@@ -696,15 +706,34 @@
WAIT_TIME_FOR_ALERTS_TO_POPULATE = 60
WAIT_TIME_FOR_UI = 5
SCROLL_DOWN = "input swipe 300 900 300 300"
+WAIT_TIME_FOR_ALERT_TO_RECEIVE = 15
+DEFAULT_SOUND_TIME = 16
+DEFAULT_VIBRATION_TIME = 10
+DEFAULT_OFFSET = 1
+EXIT_ALERT_LIST = ["Got it", "OK", "Hide", "TO CLOSE", "Yes"]
+CMD_DND_OFF = "cmd notification set_dnd off"
+CMD_DND_ON = "cmd notification set_dnd on"
+DUMPSYS_VIBRATION = "dumpsys vibrator_manager | grep -i com.google.android.cellbroadcastreceiver | tail -1"
+DEFAULT_ALERT_TYPE = "popup"
+EXPAND_NOTIFICATION_BAR = "cmd statusbar expand-notifications"
+COLLAPSE_NOTIFICATION_BAR = "cmd statusbar collapse"
+CLEAR_NOTIFICATION_BAR = "service call notification 1"
# Countries/Carriers for Compliance Testing
+AUSTRALIA = "australia"
BRAZIL = "brazil"
CANADA = "canada"
-CHILE = "chile"
+CHILE_ENTEL = "chile_entel"
+CHILE_TELEFONICA = "chile_telefonica"
COLUMBIA = "columbia"
-EQUADOR = "equador"
+ECUADOR_TELEFONICA = "ecuador_telefonica"
+ECUADOR_CLARO = "ecuador_claro"
+ELSALVADOR_TELEFONICA = "elsalvador_telefonica"
ESTONIA = "estonia"
+FRANCE = "france"
GREECE = "greece"
+GERMANY_TELEKOM = "germany_telekom"
+QATAR_VODAFONE = "qatar_vodafone"
HONGKONG = "hongkong"
ISRAEL = "israel"
ITALY = "italy"
@@ -713,10 +742,12 @@
KOREA = "korea"
LATVIA = "latvia"
LITHUANIA = "lithuania"
+MEXICO_TELEFONICA = "mexico_telefonica"
NETHERLANDS = "netherlands"
NEWZEALAND = "newzealand"
OMAN = "oman"
-PERU = "peru"
+PERU_ENTEL = "peru_entel"
+PERU_TELEFONICA = "peru_telefonica"
PUERTORICO = "puertorico"
ROMANIA = "romania"
SAUDIARABIA = "saudiarabia"
@@ -724,6 +755,9 @@
TAIWAN = "taiwan"
UAE = "uae"
UK = "uk"
+US_ATT = "us_att"
+US_TMO = "us_tmo"
+US_VZW = "us_vzw"
# Carrier Config Update
CARRIER_ID_VERSION = "3"
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_dsds_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_dsds_utils.py
new file mode 100644
index 0000000..e9279be
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_dsds_utils.py
@@ -0,0 +1,2762 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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.
+
+from datetime import datetime, timedelta
+import re
+import time
+from typing import Optional, Sequence
+
+from acts import signals
+from acts import tracelogger
+from acts.controllers.android_device import AndroidDevice
+from acts.utils import rand_ascii_str
+from acts.libs.utils.multithread import multithread_func
+from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
+from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import YOUTUBE_PACKAGE_NAME
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_data_utils import start_youtube_video
+from acts_contrib.test_utils.tel.tel_message_utils import log_messaging_screen_shot
+from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify_for_subscription
+from acts_contrib.test_utils.tel.tel_ss_utils import erase_call_forwarding_by_mmi
+from acts_contrib.test_utils.tel.tel_ss_utils import set_call_forwarding_by_mmi
+from acts_contrib.test_utils.tel.tel_ss_utils import set_call_waiting
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc_for_subscription
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_on_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_idle
+from acts_contrib.test_utils.tel.tel_ss_utils import three_phone_call_forwarding_short_seq
+from acts_contrib.test_utils.tel.tel_ss_utils import three_phone_call_waiting_short_seq
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_message_subid
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_data
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_voice_sub_id
+from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
+from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
+from acts_contrib.test_utils.tel.tel_test_utils import power_off_sim
+from acts_contrib.test_utils.tel.tel_test_utils import power_on_sim
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
+from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_ims_conference_merge_drop_second_call_from_participant
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_wcdma_conference_merge_drop
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _three_phone_call_mo_add_mt
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat
+from acts_contrib.test_utils.tel.tel_voice_utils import swap_calls
+from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_msim_for_slot
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_reject_call_for_subscription
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
+
+CallResult = TelephonyVoiceTestResult.CallResult.Value
+
+
+def dsds_dds_swap_message_streaming_test(
+ log: tracelogger.TraceLogger,
+ ads: Sequence[AndroidDevice],
+ test_rat: list,
+ test_slot: list,
+ init_dds: int,
+ msg_type: str = "SMS",
+ direction: str = "mt",
+ streaming: bool = True,
+ expected_result: bool = True) -> bool:
+ """Make MO and MT message at specific slot in specific RAT with DDS at
+ specific slot and do the same steps after dds swap.
+
+ Args:
+ log: Logger object.
+ ads: A list of Android device objects.
+ test_rat: RAT for both slots of primary device.
+ test_slot: The slot which make/receive MO/MT SMS/MMS of primary device.
+ dds_slot: Preferred data slot of primary device.
+ msg_type: SMS or MMS to send.
+ direction: The direction of message("mo" or "mt") at first.
+ streaming: True for playing Youtube before send/receive SMS/MMS and
+ False on the contrary.
+ expected_result: True or False
+
+ Returns:
+ TestFailure if failed.
+ """
+ result = True
+
+ for test_slot, dds_slot in zip(test_slot, [init_dds, 1-init_dds]):
+ ads[0].log.info("test_slot: %d, dds_slot: %d", test_slot, dds_slot)
+ result = result and dsds_message_streaming_test(
+ log=log,
+ ads=ads,
+ test_rat=test_rat,
+ test_slot=test_slot,
+ dds_slot=dds_slot,
+ msg_type=msg_type,
+ direction=direction,
+ streaming=streaming,
+ expected_result=expected_result
+ )
+ if not result:
+ return result
+
+ log.info("Switch DDS back.")
+ if not set_dds_on_slot(ads[0], init_dds):
+ ads[0].log.error(
+ "Failed to set DDS at slot %s on %s",(init_dds, ads[0].serial))
+ return False
+
+ log.info("Check phones is in desired RAT.")
+ phone_setup_on_rat(
+ log,
+ ads[0],
+ test_rat[test_slot],
+ get_subid_from_slot_index(log, ads[0], init_dds)
+ )
+
+ log.info("Check HTTP connection after DDS switch.")
+ if not verify_http_connection(log, ads[0]):
+ ads[0].log.error("Failed to verify http connection.")
+ return False
+ else:
+ ads[0].log.info("Verify http connection successfully.")
+
+ return result
+
+
+def dsds_dds_swap_call_streaming_test(
+ log: tracelogger.TraceLogger,
+ tel_logger: TelephonyMetricLogger.for_test_case,
+ ads: Sequence[AndroidDevice],
+ test_rat: list,
+ test_slot: list,
+ init_dds: int,
+ direction: str = "mo",
+ duration: int = 360,
+ streaming: bool = True,
+ is_airplane_mode: bool = False,
+ wfc_mode: Sequence[str] = [
+ WFC_MODE_CELLULAR_PREFERRED,
+ WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid: Optional[str] = None,
+ wifi_network_pass: Optional[str] = None,
+ turn_off_wifi_in_the_end: bool = False,
+ turn_off_airplane_mode_in_the_end: bool = False) -> bool:
+ """Make MO/MT call at specific slot in specific RAT with DDS at specific
+ slot and do the same steps after dds swap.
+
+ Args:
+ log: Logger object.
+ tel_logger: Logger object for telephony proto.
+ ads: A list of Android device objects.
+ test_rat: RAT for both slots of primary device.
+ test_slot: The slot which make/receive MO/MT call of primary device.
+ init_dds: Initial preferred data slot of primary device.
+ direction: The direction of call("mo" or "mt").
+ streaming: True for playing Youtube and False on the contrary.
+ is_airplane_mode: True or False for WFC setup
+ wfc_mode: Cellular preferred or Wi-Fi preferred.
+ wifi_network_ssid: SSID of Wi-Fi AP.
+ wifi_network_pass: Password of Wi-Fi AP SSID.
+ turn_off_wifi_in_the_end: True to turn off Wi-Fi and False not to turn
+ off Wi-Fi in the end of the function.
+ turn_off_airplane_mode_in_the_end: True to turn off airplane mode and
+ False not to turn off airplane mode in the end of the function.
+
+ Returns:
+ TestFailure if failed.
+ """
+ result = True
+
+ for test_slot, dds_slot in zip(test_slot, [init_dds, 1-init_dds]):
+ ads[0].log.info("test_slot: %d, dds_slot: %d", test_slot, dds_slot)
+ result = result and dsds_long_call_streaming_test(
+ log=log,
+ tel_logger=tel_logger,
+ ads=ads,
+ test_rat=test_rat,
+ test_slot=test_slot,
+ dds_slot=dds_slot,
+ direction=direction,
+ duration=duration,
+ streaming=streaming,
+ is_airplane_mode=is_airplane_mode,
+ wfc_mode=wfc_mode,
+ wifi_network_ssid=wifi_network_ssid,
+ wifi_network_pass=wifi_network_pass,
+ turn_off_wifi_in_the_end=turn_off_wifi_in_the_end,
+ turn_off_airplane_mode_in_the_end=turn_off_airplane_mode_in_the_end
+ )
+ if not result:
+ return result
+
+ log.info("Switch DDS back.")
+ if not set_dds_on_slot(ads[0], init_dds):
+ ads[0].log.error(
+ "Failed to set DDS at slot %s on %s",(init_dds, ads[0].serial))
+ return False
+
+ log.info("Check phones is in desired RAT.")
+ phone_setup_on_rat(
+ log,
+ ads[0],
+ test_rat[test_slot],
+ get_subid_from_slot_index(log, ads[0], init_dds)
+ )
+
+ log.info("Check HTTP connection after DDS switch.")
+ if not verify_http_connection(log, ads[0]):
+ ads[0].log.error("Failed to verify http connection.")
+ return False
+ else:
+ ads[0].log.info("Verify http connection successfully.")
+
+ return result
+
+
+def dsds_long_call_streaming_test(
+ log: tracelogger.TraceLogger,
+ tel_logger: TelephonyMetricLogger.for_test_case,
+ ads: Sequence[AndroidDevice],
+ test_rat: list,
+ test_slot: int,
+ dds_slot: int,
+ direction: str = "mo",
+ duration: int = 360,
+ streaming: bool = True,
+ is_airplane_mode: bool = False,
+ wfc_mode: Sequence[str] = [
+ WFC_MODE_CELLULAR_PREFERRED,
+ WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid: Optional[str] = None,
+ wifi_network_pass: Optional[str] = None,
+ turn_off_wifi_in_the_end: bool = False,
+ turn_off_airplane_mode_in_the_end: bool = False) -> bool:
+ """Make MO/MT call at specific slot in specific RAT with DDS at specific
+ slot for the given time.
+
+ Args:
+ log: Logger object.
+ tel_logger: Logger object for telephony proto.
+ ads: A list of Android device objects.
+ test_rat: RAT for both slots of primary device.
+ test_slot: The slot which make/receive MO/MT call of primary device.
+ dds_slot: Preferred data slot of primary device.
+ direction: The direction of call("mo" or "mt").
+ streaming: True for playing Youtube and False on the contrary.
+ is_airplane_mode: True or False for WFC setup
+ wfc_mode: Cellular preferred or Wi-Fi preferred.
+ wifi_network_ssid: SSID of Wi-Fi AP.
+ wifi_network_pass: Password of Wi-Fi AP SSID.
+ turn_off_wifi_in_the_end: True to turn off Wi-Fi and False not to turn
+ off Wi-Fi in the end of the function.
+ turn_off_airplane_mode_in_the_end: True to turn off airplane mode and
+ False not to turn off airplane mode in the end of the function.
+
+ Returns:
+ TestFailure if failed.
+ """
+ log.info("Step 1: Switch DDS.")
+ if not set_dds_on_slot(ads[0], dds_slot):
+ ads[0].log.error(
+ "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
+ return False
+
+ log.info("Step 2: Check HTTP connection after DDS switch.")
+ if not verify_http_connection(log, ads[0]):
+ ads[0].log.error("Failed to verify http connection.")
+ return False
+ else:
+ ads[0].log.info("Verify http connection successfully.")
+
+ log.info("Step 3: Set up phones in desired RAT.")
+ if direction == "mo":
+ # setup voice subid on primary device.
+ ad_mo = ads[0]
+ mo_sub_id = get_subid_from_slot_index(log, ad_mo, test_slot)
+ if mo_sub_id == INVALID_SUB_ID:
+ ad_mo.log.warning("Failed to get sub ID at slot %s.", test_slot)
+ return False
+ mo_other_sub_id = get_subid_from_slot_index(
+ log, ad_mo, 1-test_slot)
+ sub_id_list = [mo_sub_id, mo_other_sub_id]
+ set_voice_sub_id(ad_mo, mo_sub_id)
+ ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", test_slot,
+ get_outgoing_voice_sub_id(ad_mo))
+
+ # setup voice subid on secondary device.
+ ad_mt = ads[1]
+ _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+ if mt_sub_id == INVALID_SUB_ID:
+ ad_mt.log.warning("Failed to get sub ID at default voice slot.")
+ return False
+ mt_slot = get_slot_index_from_subid(ad_mt, mt_sub_id)
+ set_voice_sub_id(ad_mt, mt_sub_id)
+ ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot,
+ get_outgoing_voice_sub_id(ad_mt))
+
+ # setup the rat on non-test slot(primary device).
+ phone_setup_on_rat(
+ log,
+ ad_mo,
+ test_rat[1-test_slot],
+ mo_other_sub_id,
+ is_airplane_mode,
+ wfc_mode[1-test_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+ # assign phone setup argv for test slot.
+ mo_phone_setup_func_argv = (
+ log,
+ ad_mo,
+ test_rat[test_slot],
+ mo_sub_id,
+ is_airplane_mode,
+ wfc_mode[test_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+ verify_caller_func = is_phone_in_call_on_rat(
+ log, ad_mo, test_rat[test_slot], only_return_fn=True)
+ mt_phone_setup_func_argv = (log, ad_mt, 'general')
+ verify_callee_func = is_phone_in_call_on_rat(
+ log, ad_mt, 'general', only_return_fn=True)
+ else:
+ # setup voice subid on primary device.
+ ad_mt = ads[0]
+ mt_sub_id = get_subid_from_slot_index(log, ad_mt, test_slot)
+ if mt_sub_id == INVALID_SUB_ID:
+ ad_mt.log.warning("Failed to get sub ID at slot %s.", test_slot)
+ return False
+ mt_other_sub_id = get_subid_from_slot_index(
+ log, ad_mt, 1-test_slot)
+ sub_id_list = [mt_sub_id, mt_other_sub_id]
+ set_voice_sub_id(ad_mt, mt_sub_id)
+ ad_mt.log.info("Sub ID for incoming call at slot %s: %s", test_slot,
+ get_outgoing_voice_sub_id(ad_mt))
+
+ # setup voice subid on secondary device.
+ ad_mo = ads[1]
+ _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+ if mo_sub_id == INVALID_SUB_ID:
+ ad_mo.log.warning("Failed to get sub ID at default voice slot.")
+ return False
+ mo_slot = get_slot_index_from_subid(ad_mo, mo_sub_id)
+ set_voice_sub_id(ad_mo, mo_sub_id)
+ ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", mo_slot,
+ get_outgoing_voice_sub_id(ad_mo))
+
+ # setup the rat on non-test slot(primary device).
+ phone_setup_on_rat(
+ log,
+ ad_mt,
+ test_rat[1-test_slot],
+ mt_other_sub_id,
+ is_airplane_mode,
+ wfc_mode[1-test_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+ # assign phone setup argv for test slot.
+ mt_phone_setup_func_argv = (
+ log,
+ ad_mt,
+ test_rat[test_slot],
+ mt_sub_id,
+ is_airplane_mode,
+ wfc_mode[test_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+ verify_callee_func = is_phone_in_call_on_rat(
+ log, ad_mt, test_rat[test_slot], only_return_fn=True)
+ mo_phone_setup_func_argv = (log, ad_mo, 'general')
+ verify_caller_func = is_phone_in_call_on_rat(
+ log, ad_mo, 'general', only_return_fn=True)
+
+ tasks = [(phone_setup_on_rat, mo_phone_setup_func_argv),
+ (phone_setup_on_rat, mt_phone_setup_func_argv)]
+ if not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+ if streaming:
+ log.info("Step 4-0: Start Youtube streaming.")
+ if not start_youtube_video(ads[0]):
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Fail to bring up youtube video."})
+ time.sleep(10)
+
+ log.info("Step 4: Make voice call.")
+ result = call_setup_teardown(log,
+ ad_mo,
+ ad_mt,
+ ad_hangup=ad_mo,
+ verify_caller_func=verify_caller_func,
+ verify_callee_func=verify_callee_func,
+ wait_time_in_call=duration)
+ tel_logger.set_result(result.result_value)
+
+ if not result:
+ log.error(
+ "Failed to make %s call from %s slot %s to %s slot %s",
+ direction, ad_mo.serial, mo_slot, ad_mt.serial, mt_slot)
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": str(result.result_value)})
+
+ log.info("Step 5: Verify RAT and HTTP connection.")
+ # For the tese cases related to WFC in which airplane mode will be turned
+ # off in the end.
+ if turn_off_airplane_mode_in_the_end:
+ log.info("Step 5-1: Turning off airplane mode......")
+ if not toggle_airplane_mode(log, ads[0], False):
+ ads[0].log.error('Failed to toggle off airplane mode.')
+
+ # For the tese cases related to WFC in which Wi-Fi will be turned off in the
+ # end.
+ rat_list = [test_rat[test_slot], test_rat[1-test_slot]]
+
+ if turn_off_wifi_in_the_end:
+ log.info("Step 5-2: Turning off Wi-Fi......")
+ if not wifi_toggle_state(log, ads[0], False):
+ ads[0].log.error('Failed to toggle off Wi-Fi.')
+ return False
+
+ for index, value in enumerate(rat_list):
+ if value == '5g_wfc':
+ rat_list[index] = '5g'
+ elif value == 'wfc':
+ rat_list[index] = '4g'
+
+ for rat, sub_id in zip(rat_list, sub_id_list):
+ if not wait_for_network_idle(log, ads[0], rat, sub_id):
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Idle state of sub ID %s does not match the "
+ "given RAT %s." % (sub_id, rat)})
+
+ if not verify_http_connection(log, ads[0]):
+ ads[0].log.error("Failed to verify http connection.")
+ return False
+ else:
+ ads[0].log.info("Verify http connection successfully.")
+
+ if streaming:
+ ads[0].force_stop_apk(YOUTUBE_PACKAGE_NAME)
+
+ return True
+
+
+def dsds_voice_call_test(
+ log,
+ tel_logger,
+ ads,
+ mo_slot,
+ mt_slot,
+ dds,
+ mo_rat=["", ""],
+ mt_rat=["", ""],
+ call_direction="mo",
+ is_airplane_mode=False,
+ wfc_mode=[
+ WFC_MODE_CELLULAR_PREFERRED,
+ WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=None,
+ wifi_network_pass=None,
+ turn_off_wifi_in_the_end=False,
+ turn_off_airplane_mode_in_the_end=False):
+ """Make MO/MT voice call at specific slot in specific RAT with DDS at
+ specific slot.
+
+ Test step:
+ 1. Get sub IDs of specific slots of both MO and MT devices.
+ 2. Switch DDS to specific slot.
+ 3. Check HTTP connection after DDS switch.
+ 4. Set up phones in desired RAT.
+ 5. Make voice call.
+ 6. Turn off airplane mode if necessary.
+ 7. Turn off Wi-Fi if necessary.
+ 8. Verify RAT and HTTP connection.
+
+ Args:
+ log: logger object
+ tel_logger: logger object for telephony proto
+ ads: list of android devices
+ mo_slot: Slot making MO call (0 or 1)
+ mt_slot: Slot receiving MT call (0 or 1)
+ dds: Preferred data slot
+ mo_rat: RAT for both slots of MO device
+ mt_rat: RAT for both slots of MT device
+ call_direction: "mo" or "mt"
+ is_airplane_mode: True or False for WFC setup
+ wfc_mode: Cellular preferred or Wi-Fi preferred.
+ wifi_network_ssid: SSID of Wi-Fi AP
+ wifi_network_pass: Password of Wi-Fi AP SSID
+ turn_off_wifi_in_the_end: True to turn off Wi-Fi and False not to turn
+ off Wi-Fi in the end of the function.
+ turn_off_airplane_mode_in_the_end: True to turn off airplane mode and
+ False not to turn off airplane mode in the end of the function.
+
+ Returns:
+ TestFailure if failed.
+ """
+ if not toggle_airplane_mode(log, ads[0], False):
+ ads[0].log.error("Failed to disable airplane mode.")
+ return False
+
+ if call_direction == "mo":
+ ad_mo = ads[0]
+ ad_mt = ads[1]
+ else:
+ ad_mo = ads[1]
+ ad_mt = ads[0]
+
+ if mo_slot is not None:
+ mo_sub_id = get_subid_from_slot_index(log, ad_mo, mo_slot)
+ if mo_sub_id == INVALID_SUB_ID:
+ ad_mo.log.warning("Failed to get sub ID ar slot %s.", mo_slot)
+ return False
+ mo_other_sub_id = get_subid_from_slot_index(
+ log, ad_mo, 1-mo_slot)
+ set_voice_sub_id(ad_mo, mo_sub_id)
+ else:
+ _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+ if mo_sub_id == INVALID_SUB_ID:
+ ad_mo.log.warning("Failed to get sub ID ar slot %s.", mo_slot)
+ return False
+ mo_slot = "auto"
+ set_voice_sub_id(ad_mo, mo_sub_id)
+ ad_mo.log.info("Sub ID for outgoing call at slot %s: %s",
+ mo_slot, get_outgoing_voice_sub_id(ad_mo))
+
+ if mt_slot is not None:
+ mt_sub_id = get_subid_from_slot_index(log, ad_mt, mt_slot)
+ if mt_sub_id == INVALID_SUB_ID:
+ ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
+ return False
+ mt_other_sub_id = get_subid_from_slot_index(
+ log, ad_mt, 1-mt_slot)
+ set_voice_sub_id(ad_mt, mt_sub_id)
+ else:
+ _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+ if mt_sub_id == INVALID_SUB_ID:
+ ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
+ return False
+ mt_slot = "auto"
+ set_voice_sub_id(ad_mt, mt_sub_id)
+ ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot,
+ get_incoming_voice_sub_id(ad_mt))
+
+ log.info("Step 1: Switch DDS.")
+ if not set_dds_on_slot(ads[0], dds):
+ log.error(
+ "Failed to set DDS at slot %s on %s",(dds, ads[0].serial))
+ return False
+
+ log.info("Step 2: Check HTTP connection after DDS switch.")
+ if not verify_http_connection(log, ads[0]):
+ log.error("Failed to verify http connection.")
+ return False
+ else:
+ log.info("Verify http connection successfully.")
+
+ log.info("Step 3: Set up phones in desired RAT.")
+ if mo_slot == 0 or mo_slot == 1:
+ phone_setup_on_rat(
+ log,
+ ad_mo,
+ mo_rat[1-mo_slot],
+ mo_other_sub_id,
+ is_airplane_mode,
+ wfc_mode[1-mo_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+
+ mo_phone_setup_func_argv = (
+ log,
+ ad_mo,
+ mo_rat[mo_slot],
+ mo_sub_id,
+ is_airplane_mode,
+ wfc_mode[mo_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+
+ is_mo_in_call = is_phone_in_call_on_rat(
+ log, ad_mo, mo_rat[mo_slot], only_return_fn=True)
+ else:
+ mo_phone_setup_func_argv = (log, ad_mo, 'general')
+ is_mo_in_call = is_phone_in_call_on_rat(
+ log, ad_mo, 'general', only_return_fn=True)
+
+ if mt_slot == 0 or mt_slot == 1:
+ phone_setup_on_rat(
+ log,
+ ad_mt,
+ mt_rat[1-mt_slot],
+ mt_other_sub_id,
+ is_airplane_mode,
+ wfc_mode[1-mt_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+
+ mt_phone_setup_func_argv = (
+ log,
+ ad_mt,
+ mt_rat[mt_slot],
+ mt_sub_id,
+ is_airplane_mode,
+ wfc_mode[mt_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+
+ is_mt_in_call = is_phone_in_call_on_rat(
+ log, ad_mt, mt_rat[mt_slot], only_return_fn=True)
+ else:
+ mt_phone_setup_func_argv = (log, ad_mt, 'general')
+ is_mt_in_call = is_phone_in_call_on_rat(
+ log, ad_mt, 'general', only_return_fn=True)
+
+ tasks = [(phone_setup_on_rat, mo_phone_setup_func_argv),
+ (phone_setup_on_rat, mt_phone_setup_func_argv)]
+ if not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+
+ log.info("Step 4: Make voice call.")
+ result = two_phone_call_msim_for_slot(
+ log,
+ ad_mo,
+ get_slot_index_from_subid(ad_mo, mo_sub_id),
+ None,
+ is_mo_in_call,
+ ad_mt,
+ get_slot_index_from_subid(ad_mt, mt_sub_id),
+ None,
+ is_mt_in_call)
+
+ tel_logger.set_result(result.result_value)
+
+ if not result:
+ log.error(
+ "Failed to make MO call from %s slot %s to %s slot %s",
+ ad_mo.serial, mo_slot, ad_mt.serial, mt_slot)
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": str(result.result_value)})
+
+ log.info("Step 5: Verify RAT and HTTP connection.")
+ if call_direction == "mo":
+ rat_list = [mo_rat[mo_slot], mo_rat[1-mo_slot]]
+ sub_id_list = [mo_sub_id, mo_other_sub_id]
+ else:
+ rat_list = [mt_rat[mt_slot], mt_rat[1-mt_slot]]
+ sub_id_list = [mt_sub_id, mt_other_sub_id]
+
+ # For the tese cases related to WFC in which airplane mode will be turned
+ # off in the end.
+ if turn_off_airplane_mode_in_the_end:
+ log.info("Step 5-1: Turning off airplane mode......")
+ if not toggle_airplane_mode(log, ads[0], False):
+ ads[0].log.error('Failed to toggle off airplane mode.')
+
+ # For the tese cases related to WFC in which Wi-Fi will be turned off in the
+ # end.
+ if turn_off_wifi_in_the_end:
+ log.info("Step 5-2: Turning off Wi-Fi......")
+ if not wifi_toggle_state(log, ads[0], False):
+ ads[0].log.error('Failed to toggle off Wi-Fi.')
+ return False
+
+ for index, value in enumerate(rat_list):
+ if value == '5g_wfc':
+ rat_list[index] = '5g'
+ elif value == 'wfc':
+ rat_list[index] = '4g'
+
+ for rat, sub_id in zip(rat_list, sub_id_list):
+ if not wait_for_network_idle(log, ads[0], rat, sub_id):
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Idle state of sub ID %s does not match the "
+ "given RAT %s." % (sub_id, rat)})
+
+
+def dsds_message_streaming_test(
+ log: tracelogger.TraceLogger,
+ ads: Sequence[AndroidDevice],
+ test_rat: list,
+ test_slot: int,
+ dds_slot: int,
+ msg_type: str = "SMS",
+ direction: str = "mt",
+ streaming: bool = True,
+ expected_result: bool = True) -> bool:
+ """Make MO and MT SMS/MMS at specific slot in specific RAT with DDS at
+ specific slot.
+
+ Test step:
+ 1. Get sub IDs of specific slots of both MO and MT devices.
+ 2. Switch DDS to specific slot.
+ 3. Check HTTP connection after DDS switch.
+ 4. Set up phones in desired RAT.
+ 5. Receive and Send SMS/MMS.
+
+ Args:
+ log: Logger object.
+ ads: A list of Android device objects.
+ test_rat: RAT for both slots of primary device.
+ test_slot: The slot which make/receive MO/MT SMS/MMS of primary device.
+ dds_slot: Preferred data slot of primary device.
+ msg_type: SMS or MMS to send.
+ direction: The direction of message("mo" or "mt") at first.
+ streaming: True for playing Youtube before send/receive SMS/MMS and
+ False on the contrary.
+ expected_result: True or False
+
+ Returns:
+ TestFailure if failed.
+ """
+ log.info("Step 1: Switch DDS.")
+ if not set_dds_on_slot(ads[0], dds_slot):
+ ads[0].log.error(
+ "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
+ return False
+
+ log.info("Step 2: Check HTTP connection after DDS switch.")
+ if not verify_http_connection(log, ads[0]):
+ ads[0].log.error("Failed to verify http connection.")
+ return False
+ else:
+ ads[0].log.info("Verify http connection successfully.")
+
+ log.info("Step 3: Set up phones in desired RAT.")
+ if direction == "mo":
+ # setup message subid on primary device.
+ ad_mo = ads[0]
+ mo_sub_id = get_subid_from_slot_index(log, ad_mo, test_slot)
+ if mo_sub_id == INVALID_SUB_ID:
+ ad_mo.log.warning("Failed to get sub ID at slot %s.", test_slot)
+ return False
+ mo_other_sub_id = get_subid_from_slot_index(
+ log, ad_mo, 1-test_slot)
+ sub_id_list = [mo_sub_id, mo_other_sub_id]
+ set_message_subid(ad_mo, mo_sub_id)
+ ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", test_slot,
+ get_outgoing_message_sub_id(ad_mo))
+
+ # setup message subid on secondary device.
+ ad_mt = ads[1]
+ _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads, type="sms")
+ if mt_sub_id == INVALID_SUB_ID:
+ ad_mt.log.warning("Failed to get sub ID at default voice slot.")
+ return False
+ mt_slot = get_slot_index_from_subid(ad_mt, mt_sub_id)
+ set_message_subid(ad_mt, mt_sub_id)
+ ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot,
+ get_outgoing_message_sub_id(ad_mt))
+
+ # setup the rat on non-test slot(primary device).
+ phone_setup_on_rat(
+ log,
+ ad_mo,
+ test_rat[1-test_slot],
+ mo_other_sub_id)
+ # assign phone setup argv for test slot.
+ mo_phone_setup_func_argv = (
+ log,
+ ad_mo,
+ test_rat[test_slot],
+ mo_sub_id)
+ else:
+ # setup message subid on primary device.
+ ad_mt = ads[0]
+ mt_sub_id = get_subid_from_slot_index(log, ad_mt, test_slot)
+ if mt_sub_id == INVALID_SUB_ID:
+ ad_mt.log.warning("Failed to get sub ID at slot %s.", test_slot)
+ return False
+ mt_other_sub_id = get_subid_from_slot_index(
+ log, ad_mt, 1-test_slot)
+ sub_id_list = [mt_sub_id, mt_other_sub_id]
+ set_message_subid(ad_mt, mt_sub_id)
+ ad_mt.log.info("Sub ID for incoming call at slot %s: %s", test_slot,
+ get_outgoing_message_sub_id(ad_mt))
+
+ # setup message subid on secondary device.
+ ad_mo = ads[1]
+ _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads, type="sms")
+ if mo_sub_id == INVALID_SUB_ID:
+ ad_mo.log.warning("Failed to get sub ID at default voice slot.")
+ return False
+ mo_slot = get_slot_index_from_subid(ad_mo, mo_sub_id)
+ set_message_subid(ad_mo, mo_sub_id)
+ ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", mo_slot,
+ get_outgoing_message_sub_id(ad_mo))
+
+ # setup the rat on non-test slot(primary device).
+ phone_setup_on_rat(
+ log,
+ ad_mt,
+ test_rat[1-test_slot],
+ mt_other_sub_id)
+ # assign phone setup argv for test slot.
+ mt_phone_setup_func_argv = (
+ log,
+ ad_mt,
+ test_rat[test_slot],
+ mt_sub_id)
+ mo_phone_setup_func_argv = (log, ad_mo, 'general')
+
+ tasks = [(phone_setup_on_rat, mo_phone_setup_func_argv),
+ (phone_setup_on_rat, mt_phone_setup_func_argv)]
+ if not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+
+ if streaming:
+ log.info("Step 4-0: Start Youtube streaming.")
+ if not start_youtube_video(ads[0]):
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Fail to bring up youtube video."})
+ time.sleep(10)
+
+ log.info("Step 4: Send %s.", msg_type)
+ if msg_type == "MMS":
+ for ad, current_data_sub_id, current_msg_sub_id in [
+ [ ads[0],
+ get_default_data_sub_id(ads[0]),
+ get_outgoing_message_sub_id(ads[0]) ],
+ [ ads[1],
+ get_default_data_sub_id(ads[1]),
+ get_outgoing_message_sub_id(ads[1]) ]]:
+ if current_data_sub_id != current_msg_sub_id:
+ ad.log.warning(
+ "Current data sub ID (%s) does not match message"
+ " sub ID (%s). MMS should NOT be sent.",
+ current_data_sub_id,
+ current_msg_sub_id)
+ expected_result = False
+
+ result_first = msim_message_test(log, ad_mo, ad_mt, mo_sub_id, mt_sub_id,
+ msg=msg_type, expected_result=expected_result)
+
+ if not result_first:
+ log_messaging_screen_shot(ad_mo, test_name="%s_tx" % msg_type)
+ log_messaging_screen_shot(ad_mt, test_name="%s_rx" % msg_type)
+
+ result_second = msim_message_test(log, ad_mt, ad_mo, mt_sub_id, mo_sub_id,
+ msg=msg_type, expected_result=expected_result)
+
+ if not result_second:
+ log_messaging_screen_shot(ad_mt, test_name="%s_tx" % msg_type)
+ log_messaging_screen_shot(ad_mo, test_name="%s_rx" % msg_type)
+
+ result = result_first and result_second
+
+ log.info("Step 5: Verify RAT and HTTP connection.")
+ rat_list = [test_rat[test_slot], test_rat[1-test_slot]]
+ for rat, sub_id in zip(rat_list, sub_id_list):
+ if not wait_for_network_idle(log, ads[0], rat, sub_id):
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Idle state of sub ID %s does not match the "
+ "given RAT %s." % (sub_id, rat)})
+
+ if streaming:
+ ads[0].force_stop_apk(YOUTUBE_PACKAGE_NAME)
+
+ return result
+
+
+def dsds_message_test(
+ log,
+ ads,
+ mo_slot,
+ mt_slot,
+ dds_slot,
+ msg="SMS",
+ mo_rat=["", ""],
+ mt_rat=["", ""],
+ direction="mo",
+ streaming=False,
+ expected_result=True):
+ """Make MO/MT SMS/MMS at specific slot in specific RAT with DDS at
+ specific slot.
+
+ Test step:
+ 1. Get sub IDs of specific slots of both MO and MT devices.
+ 2. Switch DDS to specific slot.
+ 3. Check HTTP connection after DDS switch.
+ 4. Set up phones in desired RAT.
+ 5. Send SMS/MMS.
+
+ Args:
+ mo_slot: Slot sending MO SMS (0 or 1)
+ mt_slot: Slot receiving MT SMS (0 or 1)
+ dds_slot: Preferred data slot
+ mo_rat: RAT for both slots of MO device
+ mt_rat: RAT for both slots of MT device
+ direction: "mo" or "mt"
+ streaming: True for playing Youtube before send/receive SMS/MMS and
+ False on the contrary.
+ expected_result: True or False
+
+ Returns:
+ TestFailure if failed.
+ """
+ if direction == "mo":
+ ad_mo = ads[0]
+ ad_mt = ads[1]
+ else:
+ ad_mo = ads[1]
+ ad_mt = ads[0]
+
+ if mo_slot is not None:
+ mo_sub_id = get_subid_from_slot_index(log, ad_mo, mo_slot)
+ if mo_sub_id == INVALID_SUB_ID:
+ ad_mo.log.warning("Failed to get sub ID at slot %s.", mo_slot)
+ return False
+ mo_other_sub_id = get_subid_from_slot_index(
+ log, ad_mo, 1-mo_slot)
+ set_message_subid(ad_mo, mo_sub_id)
+ else:
+ _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(
+ ads, type="sms")
+ if mo_sub_id == INVALID_SUB_ID:
+ ad_mo.log.warning("Failed to get sub ID at slot %s.", mo_slot)
+ return False
+ mo_slot = "auto"
+ set_message_subid(ad_mo, mo_sub_id)
+ if msg == "MMS":
+ set_subid_for_data(ad_mo, mo_sub_id)
+ ad_mo.droid.telephonyToggleDataConnection(True)
+ ad_mo.log.info("Sub ID for outgoing %s at slot %s: %s", msg, mo_slot,
+ get_outgoing_message_sub_id(ad_mo))
+
+ if mt_slot is not None:
+ mt_sub_id = get_subid_from_slot_index(log, ad_mt, mt_slot)
+ if mt_sub_id == INVALID_SUB_ID:
+ ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
+ return False
+ mt_other_sub_id = get_subid_from_slot_index(log, ad_mt, 1-mt_slot)
+ set_message_subid(ad_mt, mt_sub_id)
+ else:
+ _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
+ ads, type="sms")
+ if mt_sub_id == INVALID_SUB_ID:
+ ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
+ return False
+ mt_slot = "auto"
+ set_message_subid(ad_mt, mt_sub_id)
+ if msg == "MMS":
+ set_subid_for_data(ad_mt, mt_sub_id)
+ ad_mt.droid.telephonyToggleDataConnection(True)
+ ad_mt.log.info("Sub ID for incoming %s at slot %s: %s", msg, mt_slot,
+ get_outgoing_message_sub_id(ad_mt))
+
+ log.info("Step 1: Switch DDS.")
+ if not set_dds_on_slot(ads[0], dds_slot):
+ log.error(
+ "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
+ return False
+
+ log.info("Step 2: Check HTTP connection after DDS switch.")
+ if not verify_http_connection(log, ads[0]):
+ log.error("Failed to verify http connection.")
+ return False
+ else:
+ log.info("Verify http connection successfully.")
+
+ if mo_slot == 0 or mo_slot == 1:
+ phone_setup_on_rat(log, ad_mo, mo_rat[1-mo_slot], mo_other_sub_id)
+ mo_phone_setup_func_argv = (log, ad_mo, mo_rat[mo_slot], mo_sub_id)
+ else:
+ mo_phone_setup_func_argv = (log, ad_mo, 'general', mo_sub_id)
+
+ if mt_slot == 0 or mt_slot == 1:
+ phone_setup_on_rat(log, ad_mt, mt_rat[1-mt_slot], mt_other_sub_id)
+ mt_phone_setup_func_argv = (log, ad_mt, mt_rat[mt_slot], mt_sub_id)
+ else:
+ mt_phone_setup_func_argv = (log, ad_mt, 'general', mt_sub_id)
+
+ log.info("Step 3: Set up phones in desired RAT.")
+ tasks = [(phone_setup_on_rat, mo_phone_setup_func_argv),
+ (phone_setup_on_rat, mt_phone_setup_func_argv)]
+ if not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+
+ if streaming:
+ log.info("Step 4: Start Youtube streaming.")
+ if not start_youtube_video(ads[0]):
+ log.warning("Fail to bring up youtube video")
+ time.sleep(10)
+ else:
+ log.info("Step 4: Skip Youtube streaming.")
+
+ log.info("Step 5: Send %s.", msg)
+ if msg == "MMS":
+ for ad, current_data_sub_id, current_msg_sub_id in [
+ [ ads[0],
+ get_default_data_sub_id(ads[0]),
+ get_outgoing_message_sub_id(ads[0]) ],
+ [ ads[1],
+ get_default_data_sub_id(ads[1]),
+ get_outgoing_message_sub_id(ads[1]) ]]:
+ if current_data_sub_id != current_msg_sub_id:
+ ad.log.warning(
+ "Current data sub ID (%s) does not match message"
+ " sub ID (%s). MMS should NOT be sent.",
+ current_data_sub_id,
+ current_msg_sub_id)
+ expected_result = False
+
+ result = msim_message_test(log, ad_mo, ad_mt, mo_sub_id, mt_sub_id,
+ msg=msg, expected_result=expected_result)
+
+ if not result:
+ log_messaging_screen_shot(ad_mo, test_name="%s_tx" % msg)
+ log_messaging_screen_shot(ad_mt, test_name="%s_rx" % msg)
+
+ if streaming:
+ ads[0].force_stop_apk(YOUTUBE_PACKAGE_NAME)
+ return result
+
+
+def dds_switch_during_data_transfer_test(
+ log,
+ tel_logger,
+ ads,
+ nw_rat=["volte", "volte"],
+ call_slot=0,
+ call_direction=None,
+ call_or_sms_or_mms="call",
+ streaming=True,
+ is_airplane_mode=False,
+ wfc_mode=[WFC_MODE_CELLULAR_PREFERRED, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=None,
+ wifi_network_pass=None):
+ """Switch DDS and make voice call(VoLTE/WFC/CS call)/SMS/MMS together with
+ Youtube playing after each DDS switch at specific slot in specific RAT.
+
+ Test step:
+ 1. Get sub ID of each slot of the primary device.
+ 2. Set up phones in desired RAT.
+ 3. Switch DDS to slot 0.
+ 4. Check HTTP connection after DDS switch.
+ 5. Play Youtube.
+ 6. Make voice call (VoLTE/WFC/CS call)/SMS/MMS
+ 7. Switch DDS to slot 1 and repeat step 4-6.
+ 8. Switch DDS to slot 0 again and repeat step 4-6.
+
+ Args:
+ log: logger object
+ tel_logger: logger object for telephony proto
+ ads: list of android devices
+ nw_rat: RAT for both slots of the primary device
+ call_slot: Slot for making voice call
+ call_direction: "mo" or "mt" or None to stoping making call.
+ call_or_sms_or_mms: Voice call or SMS or MMS
+ streaming: True for playing Youtube after DDS switch and False on the contrary.
+ is_airplane_mode: True or False for WFC setup
+ wfc_mode: Cellular preferred or Wi-Fi preferred.
+ wifi_network_ssid: SSID of Wi-Fi AP
+ wifi_network_pass: Password of Wi-Fi AP SSID
+
+ Returns:
+ TestFailure if failed.
+ """
+ ad = ads[0]
+ slot_0_subid = get_subid_from_slot_index(log, ad, 0)
+ slot_1_subid = get_subid_from_slot_index(log, ad, 1)
+
+ if slot_0_subid == INVALID_SUB_ID or slot_1_subid == INVALID_SUB_ID:
+ ad.log.error("Not all slots have valid sub ID.")
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Not all slots have valid sub ID"})
+
+ ad.log.info(
+ "Step 0: Set up phone in desired RAT (slot 0: %s, slot 1: %s)",
+ nw_rat[0], nw_rat[1])
+
+ if not phone_setup_on_rat(
+ log,
+ ad,
+ nw_rat[0],
+ slot_0_subid,
+ is_airplane_mode,
+ wfc_mode[0],
+ wifi_network_ssid,
+ wifi_network_pass):
+ log.error("Phone Failed to Set Up Properly.")
+ tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+
+ if not phone_setup_on_rat(
+ log,
+ ad,
+ nw_rat[1],
+ slot_1_subid,
+ is_airplane_mode,
+ wfc_mode[1],
+ wifi_network_ssid,
+ wifi_network_pass):
+ log.error("Phone Failed to Set Up Properly.")
+ tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+
+ is_slot0_in_call = is_phone_in_call_on_rat(
+ log, ad, nw_rat[0], True)
+ is_slot1_in_call = is_phone_in_call_on_rat(
+ log, ad, nw_rat[1], True)
+
+ for attempt in range(3):
+ if attempt != 0:
+ ad.log.info("Repeat step 1 to 4.")
+
+ ad.log.info("Step 1: Switch DDS.")
+ if attempt % 2 == 0:
+ set_dds_on_slot(ad, 0)
+ else:
+ set_dds_on_slot(ad, 1)
+
+ ad.log.info("Step 2: Check HTTP connection after DDS switch.")
+ if not verify_http_connection(log, ad):
+ ad.log.error("Failed to verify http connection.")
+ return False
+ else:
+ ad.log.info("Verify http connection successfully.")
+
+ if streaming:
+ ad.log.info("Step 3: Start Youtube streaming.")
+ if not start_youtube_video(ad):
+ ad.log.warning("Fail to bring up youtube video")
+ time.sleep(10)
+ else:
+ ad.log.info("Step 3: Skip Youtube streaming.")
+
+ if not call_direction:
+ return True
+ else:
+ expected_result = True
+ if call_direction == "mo":
+ ad_mo = ads[0]
+ ad_mt = ads[1]
+ phone_setup_on_rat(log, ad_mt, 'general')
+ mo_sub_id = get_subid_from_slot_index(log, ad, call_slot)
+ if call_or_sms_or_mms == "call":
+ set_voice_sub_id(ad_mo, mo_sub_id)
+ _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
+ ads)
+
+ if call_slot == 0:
+ is_mo_in_call = is_slot0_in_call
+ elif call_slot == 1:
+ is_mo_in_call = is_slot1_in_call
+ is_mt_in_call = None
+
+ elif call_or_sms_or_mms == "sms":
+ set_message_subid(ad_mo, mo_sub_id)
+ _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
+ ads, type="sms")
+ set_message_subid(ad_mt, mt_sub_id)
+
+ elif call_or_sms_or_mms == "mms":
+ current_data_sub_id = get_default_data_sub_id(ad_mo)
+ if mo_sub_id != current_data_sub_id:
+ ad_mo.log.warning(
+ "Current data sub ID (%s) does not match"
+ " message sub ID (%s). MMS should NOT be sent.",
+ current_data_sub_id, mo_sub_id)
+ expected_result = False
+ set_message_subid(ad_mo, mo_sub_id)
+ _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
+ ads, type="sms")
+ set_message_subid(ad_mt, mt_sub_id)
+ set_subid_for_data(ad_mt, mt_sub_id)
+ ad_mt.droid.telephonyToggleDataConnection(True)
+
+ elif call_direction == "mt":
+ ad_mo = ads[1]
+ ad_mt = ads[0]
+ phone_setup_on_rat(log, ad_mo, 'general')
+ mt_sub_id = get_subid_from_slot_index(log, ad, call_slot)
+ if call_or_sms_or_mms == "call":
+ set_voice_sub_id(ad_mt, mt_sub_id)
+ _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(
+ ads)
+
+ if call_slot == 0:
+ is_mt_in_call = is_slot0_in_call
+ elif call_slot == 1:
+ is_mt_in_call = is_slot1_in_call
+ is_mo_in_call = None
+
+ elif call_or_sms_or_mms == "sms":
+ set_message_subid(ad_mt, mt_sub_id)
+ _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(
+ ads, type="sms")
+ set_message_subid(ad_mo, mo_sub_id)
+
+ elif call_or_sms_or_mms == "mms":
+ current_data_sub_id = get_default_data_sub_id(ad_mt)
+ if mt_sub_id != current_data_sub_id:
+ ad_mt.log.warning(
+ "Current data sub ID (%s) does not match"
+ " message sub ID (%s). MMS should NOT be"
+ " received.", current_data_sub_id, mt_sub_id)
+ expected_result = False
+ set_message_subid(ad_mt, mt_sub_id)
+ _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(
+ ads, type="sms")
+ set_message_subid(ad_mo, mo_sub_id)
+ set_subid_for_data(ad_mo, mo_sub_id)
+ ad_mo.droid.telephonyToggleDataConnection(True)
+
+ if call_or_sms_or_mms == "call":
+ log.info("Step 4: Make voice call.")
+ mo_slot = get_slot_index_from_subid(ad_mo, mo_sub_id)
+ mt_slot = get_slot_index_from_subid(ad_mt, mt_sub_id)
+ result = two_phone_call_msim_for_slot(
+ log,
+ ad_mo,
+ mo_slot,
+ None,
+ is_mo_in_call,
+ ad_mt,
+ mt_slot,
+ None,
+ is_mt_in_call)
+ tel_logger.set_result(result.result_value)
+
+ if not result:
+ log.error(
+ "Failed to make MO call from %s slot %s to %s"
+ " slot %s", ad_mo.serial, mo_slot, ad_mt.serial,
+ mt_slot)
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": str(result.result_value)})
+ else:
+ log.info("Step 4: Send %s.", call_or_sms_or_mms)
+ if call_or_sms_or_mms == "sms":
+ result = msim_message_test(
+ ad_mo,
+ ad_mt,
+ mo_sub_id,
+ mt_sub_id,
+ msg=call_or_sms_or_mms.upper())
+ elif call_or_sms_or_mms == "mms":
+ result = msim_message_test(
+ ad_mo,
+ ad_mt,
+ mo_sub_id,
+ mt_sub_id,
+ msg=call_or_sms_or_mms.upper(),
+ expected_result=expected_result)
+ if not result:
+ log_messaging_screen_shot(
+ ad_mo, test_name="%s_tx" % call_or_sms_or_mms)
+ log_messaging_screen_shot(
+ ad_mt, test_name="%s_rx" % call_or_sms_or_mms)
+ return False
+ if streaming:
+ ad.force_stop_apk(YOUTUBE_PACKAGE_NAME)
+ return True
+
+
+def enable_slot_after_voice_call_test(
+ log,
+ tel_logger,
+ ads,
+ mo_slot,
+ mt_slot,
+ disabled_slot,
+ mo_rat=["", ""],
+ mt_rat=["", ""],
+ call_direction="mo"):
+ """Disable/enable pSIM or eSIM with voice call
+
+ Test step:
+ 1. Get sub IDs of specific slots of both MO and MT devices.
+ 2. Set up phones in desired RAT.
+ 3. Disable assigned slot.
+ 4. Switch DDS to the other slot.
+ 5. Verify RAT and HTTP connection after DDS switch.
+ 6. Make voice call.
+ 7. Enable assigned slot.
+ 8. Switch DDS to the assigned slot.
+ 9. Verify RAT and HTTP connection after DDS switch.
+
+ Args:
+ log: logger object
+ tel_logger: logger object for telephony proto
+ ads: list of android devices
+ mo_slot: Slot making MO call (0 or 1)
+ mt_slot: Slot receiving MT call (0 or 1)
+ disabled_slot: slot to be disabled/enabled
+ mo_rat: RAT for both slots of MO device
+ mt_rat: RAT for both slots of MT device
+ call_direction: "mo" or "mt"
+
+ Returns:
+ TestFailure if failed.
+ """
+ if call_direction == "mo":
+ ad_mo = ads[0]
+ ad_mt = ads[1]
+ else:
+ ad_mo = ads[1]
+ ad_mt = ads[0]
+
+ if mo_slot is not None:
+ mo_sub_id = get_subid_from_slot_index(log, ad_mo, mo_slot)
+ if mo_sub_id == INVALID_SUB_ID:
+ ad_mo.log.warning("Failed to get sub ID at slot %s.", mo_slot)
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Failed to get sub ID at slot %s." % mo_slot})
+ mo_other_sub_id = get_subid_from_slot_index(
+ log, ad_mo, 1-mo_slot)
+ set_voice_sub_id(ad_mo, mo_sub_id)
+ else:
+ _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+ if mo_sub_id == INVALID_SUB_ID:
+ ad_mo.log.warning("Failed to get sub ID at slot %s.", mo_slot)
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Failed to get sub ID at slot %s." % mo_slot})
+ mo_slot = "auto"
+ set_voice_sub_id(ad_mo, mo_sub_id)
+ ad_mo.log.info("Sub ID for outgoing call at slot %s: %s",
+ mo_slot, get_outgoing_voice_sub_id(ad_mo))
+
+ if mt_slot is not None:
+ mt_sub_id = get_subid_from_slot_index(log, ad_mt, mt_slot)
+ if mt_sub_id == INVALID_SUB_ID:
+ ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Failed to get sub ID at slot %s." % mt_slot})
+ mt_other_sub_id = get_subid_from_slot_index(
+ log, ad_mt, 1-mt_slot)
+ set_voice_sub_id(ad_mt, mt_sub_id)
+ else:
+ _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+ if mt_sub_id == INVALID_SUB_ID:
+ ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Failed to get sub ID at slot %s." % mt_slot})
+ mt_slot = "auto"
+ set_voice_sub_id(ad_mt, mt_sub_id)
+ ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot,
+ get_incoming_voice_sub_id(ad_mt))
+
+ if mo_slot == 0 or mo_slot == 1:
+ phone_setup_on_rat(log, ad_mo, mo_rat[1-mo_slot], mo_other_sub_id)
+ mo_phone_setup_func_argv = (log, ad_mo, mo_rat[mo_slot], mo_sub_id)
+ is_mo_in_call = is_phone_in_call_on_rat(
+ log, ad_mo, mo_rat[mo_slot], only_return_fn=True)
+ else:
+ mo_phone_setup_func_argv = (log, ad_mo, 'general')
+ is_mo_in_call = is_phone_in_call_on_rat(
+ log, ad_mo, 'general', only_return_fn=True)
+
+ if mt_slot == 0 or mt_slot == 1:
+ phone_setup_on_rat(log, ad_mt, mt_rat[1-mt_slot], mt_other_sub_id)
+ mt_phone_setup_func_argv = (log, ad_mt, mt_rat[mt_slot], mt_sub_id)
+ is_mt_in_call = is_phone_in_call_on_rat(
+ log, ad_mt, mt_rat[mt_slot], only_return_fn=True)
+ else:
+ mt_phone_setup_func_argv = (log, ad_mt, 'general')
+ is_mt_in_call = is_phone_in_call_on_rat(
+ log, ad_mt, 'general', only_return_fn=True)
+
+ log.info("Step 1: Set up phones in desired RAT.")
+ tasks = [(phone_setup_on_rat, mo_phone_setup_func_argv),
+ (phone_setup_on_rat, mt_phone_setup_func_argv)]
+ if not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+
+ log.info("Step 2: Disable slot %s.", disabled_slot)
+ if not power_off_sim(ads[0], disabled_slot):
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Failed to disable slot %s." % disabled_slot})
+
+ log.info("Step 3: Switch DDS.")
+ if not set_dds_on_slot(ads[0], 1-disabled_slot):
+ log.error(
+ "Failed to set DDS at slot %s on %s.",
+ (1-disabled_slot, ads[0].serial))
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Failed to set DDS at slot %s on %s." % (
+ 1-disabled_slot, ads[0].serial)})
+
+ log.info("Step 4: Verify RAT and HTTP connection after DDS switch.")
+ if mo_slot == 0 or mo_slot == 1:
+ if not wait_for_network_idle(
+ log, ad_mo, mo_rat[1-disabled_slot], mo_sub_id):
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Idle state does not match the given "
+ "RAT %s." % mo_rat[1-disabled_slot]})
+
+ if mt_slot == 0 or mt_slot == 1:
+ if not wait_for_network_idle(
+ log, ad_mt, mt_rat[1-disabled_slot], mt_sub_id):
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Idle state does not match the given "
+ "RAT %s." % mt_rat[1-disabled_slot]})
+
+ if not verify_http_connection(log, ads[0]):
+ log.error("Failed to verify http connection.")
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Failed to verify http connection."})
+ else:
+ log.info("Verify http connection successfully.")
+
+ log.info("Step 5: Make voice call.")
+ result = two_phone_call_msim_for_slot(
+ log,
+ ad_mo,
+ get_slot_index_from_subid(ad_mo, mo_sub_id),
+ None,
+ is_mo_in_call,
+ ad_mt,
+ get_slot_index_from_subid(ad_mt, mt_sub_id),
+ None,
+ is_mt_in_call)
+
+ tel_logger.set_result(result.result_value)
+
+ if not result:
+ log.error(
+ "Failed to make MO call from %s slot %s to %s slot %s",
+ ad_mo.serial, mo_slot, ad_mt.serial, mt_slot)
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": str(result.result_value)})
+
+ log.info("Step 6: Enable slot %s.", disabled_slot)
+ if not power_on_sim(ads[0], disabled_slot):
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Failed to enable slot %s." % disabled_slot})
+
+ log.info("Step 7: Switch DDS to slot %s.", disabled_slot)
+ if not set_dds_on_slot(ads[0], disabled_slot):
+ log.error(
+ "Failed to set DDS at slot %s on %s.",(disabled_slot, ads[0].serial))
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Failed to set DDS at slot %s on %s." % (
+ disabled_slot, ads[0].serial)})
+
+ log.info("Step 8: Verify RAT and HTTP connection after DDS switch.")
+ if mo_slot == 0 or mo_slot == 1:
+ if not wait_for_network_idle(
+ log, ad_mo, mo_rat[disabled_slot], mo_other_sub_id):
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Idle state does not match the given "
+ "RAT %s." % mo_rat[mo_slot]})
+
+ if mt_slot == 0 or mt_slot == 1:
+ if not wait_for_network_idle(
+ log, ad_mt, mt_rat[disabled_slot], mt_other_sub_id):
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Idle state does not match the given "
+ "RAT %s." % mt_rat[mt_slot]})
+
+ if not verify_http_connection(log, ads[0]):
+ log.error("Failed to verify http connection.")
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Failed to verify http connection."})
+ else:
+ log.info("Verify http connection successfully.")
+
+
+def enable_slot_after_data_call_test(
+ log,
+ ad,
+ disabled_slot,
+ rat=["", ""]):
+ """Disable/enable pSIM or eSIM with data call
+
+ Test step:
+ 1. Get sub IDs of specific slots of both MO and MT devices.
+ 2. Set up phones in desired RAT.
+ 3. Disable assigned slot.
+ 4. Switch DDS to the other slot.
+ 5. Verify RAT and HTTP connection after DDS switch.
+ 6. Make a data call by http download.
+ 7. Enable assigned slot.
+ 8. Switch DDS to the assigned slot.
+ 9. Verify RAT and HTTP connection after DDS switch.
+
+ Args:
+ log: logger object
+ ads: list of android devices
+ disabled_slot: slot to be disabled/enabled
+ mo_rat: RAT for both slots of MO device
+ mt_rat: RAT for both slots of MT device
+
+ Returns:
+ TestFailure if failed.
+ """
+ data_sub_id = get_subid_from_slot_index(log, ad, 1-disabled_slot)
+ if data_sub_id == INVALID_SUB_ID:
+ ad.log.warning("Failed to get sub ID at slot %s.", 1-disabled_slot)
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Failed to get sub ID at slot %s." % (
+ 1-disabled_slot)})
+ other_sub_id = get_subid_from_slot_index(log, ad, disabled_slot)
+
+ log.info("Step 1: Set up phones in desired RAT.")
+ if not phone_setup_on_rat(log, ad, rat[1-disabled_slot], data_sub_id):
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+
+ if not phone_setup_on_rat(log, ad, rat[disabled_slot], other_sub_id):
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+
+ log.info("Step 2: Disable slot %s.", disabled_slot)
+ if not power_off_sim(ad, disabled_slot):
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Failed to disable slot %s." % disabled_slot})
+
+ log.info("Step 3: Switch DDS.")
+ if not set_dds_on_slot(ad, 1-disabled_slot):
+ log.error(
+ "Failed to set DDS at slot %s on %s.",(1-disabled_slot, ad.serial))
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Failed to set DDS at slot %s on %s." % (
+ 1-disabled_slot, ad.serial)})
+
+ log.info("Step 4: Verify RAT and HTTP connection after DDS switch.")
+ if not wait_for_network_idle(log, ad, rat[1-disabled_slot], data_sub_id):
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Idle state does not match the given "
+ "RAT %s." % rat[1-disabled_slot]})
+
+ if not verify_http_connection(log, ad):
+ log.error("Failed to verify http connection.")
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Failed to verify http connection."})
+ else:
+ log.info("Verify http connection successfully.")
+
+ duration = 30
+ start_time = datetime.now()
+ while datetime.now() - start_time <= timedelta(seconds=duration):
+ if not active_file_download_test(
+ log, ad, file_name='20MB', method='sl4a'):
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Failed to download by sl4a."})
+
+ log.info("Step 6: Enable slot %s.", disabled_slot)
+ if not power_on_sim(ad, disabled_slot):
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Failed to enable slot %s." % disabled_slot})
+
+ log.info("Step 7: Switch DDS to slot %s.", disabled_slot)
+ if not set_dds_on_slot(ad, disabled_slot):
+ log.error(
+ "Failed to set DDS at slot %s on %s.",(disabled_slot, ad.serial))
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Failed to set DDS at slot %s on %s." % (
+ disabled_slot, ad.serial)})
+
+ log.info("Step 8: Verify RAT and HTTP connection after DDS switch.")
+ if not wait_for_network_idle(log, ad, rat[disabled_slot], other_sub_id):
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Idle state does not match the given "
+ "RAT %s." % rat[disabled_slot]})
+
+ if not verify_http_connection(log, ad):
+ log.error("Failed to verify http connection.")
+ raise signals.TestFailure(
+ "Failed",
+ extras={"fail_reason": "Failed to verify http connection."})
+ else:
+ log.info("Verify http connection successfully.")
+
+
+def erase_call_forwarding(log, ad):
+ slot0_sub_id = get_subid_from_slot_index(log, ad, 0)
+ slot1_sub_id = get_subid_from_slot_index(log, ad, 1)
+ current_voice_sub_id = get_incoming_voice_sub_id(ad)
+ for sub_id in (slot0_sub_id, slot1_sub_id):
+ set_voice_sub_id(ad, sub_id)
+ get_operator_name(log, ad, sub_id)
+ erase_call_forwarding_by_mmi(log, ad)
+ set_voice_sub_id(ad, current_voice_sub_id)
+
+
+def three_way_calling_mo_and_mt_with_hangup_once(
+ log,
+ ads,
+ phone_setups,
+ verify_funcs,
+ reject_once=False):
+ """Use 3 phones to make MO call and MT call.
+
+ Call from PhoneA to PhoneB, accept on PhoneB.
+ Call from PhoneC to PhoneA, accept on PhoneA.
+
+ Args:
+ ads: list of ad object.
+ The list should have three objects.
+ phone_setups: list of phone setup functions.
+ The list should have three objects.
+ verify_funcs: list of phone call verify functions.
+ The list should have three objects.
+
+ Returns:
+ If success, return 'call_AB' id in PhoneA.
+ if fail, return None.
+ """
+
+ class _CallException(Exception):
+ pass
+
+ try:
+ verify_func_a, verify_func_b, verify_func_c = verify_funcs
+ tasks = []
+ for ad, setup_func in zip(ads, phone_setups):
+ if setup_func is not None:
+ tasks.append((setup_func, (log, ad, get_incoming_voice_sub_id(ad))))
+ if tasks != [] and not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ raise _CallException("Setup failed.")
+ for ad in ads:
+ ad.droid.telecomCallClearCallList()
+ if num_active_calls(log, ad) != 0:
+ ad.log.error("Phone Call List is not empty.")
+ raise _CallException("Clear call list failed.")
+
+ log.info("Step1: Call From PhoneA to PhoneB.")
+ if not call_setup_teardown(
+ log,
+ ads[0],
+ ads[1],
+ ad_hangup=None,
+ verify_caller_func=verify_func_a,
+ verify_callee_func=verify_func_b):
+ raise _CallException("PhoneA call PhoneB failed.")
+
+ calls = ads[0].droid.telecomCallGetCallIds()
+ ads[0].log.info("Calls in PhoneA %s", calls)
+ if num_active_calls(log, ads[0]) != 1:
+ raise _CallException("Call list verify failed.")
+ call_ab_id = calls[0]
+
+ log.info("Step2: Call From PhoneC to PhoneA.")
+ if reject_once:
+ log.info("Step2-1: Reject incoming call once.")
+ if not initiate_call(
+ log,
+ ads[2],
+ ads[0].telephony['subscription'][get_incoming_voice_sub_id(
+ ads[0])]['phone_num']):
+ ads[2].log.error("Initiate call failed.")
+ raise _CallException("Failed to initiate call.")
+
+ if not wait_and_reject_call_for_subscription(
+ log,
+ ads[0],
+ get_incoming_voice_sub_id(ads[0]),
+ incoming_number= \
+ ads[2].telephony['subscription'][
+ get_incoming_voice_sub_id(
+ ads[2])]['phone_num']):
+ ads[0].log.error("Reject call fail.")
+ raise _CallException("Failed to reject call.")
+
+ hangup_call(log, ads[2])
+ time.sleep(15)
+
+ if not call_setup_teardown(
+ log,
+ ads[2],
+ ads[0],
+ ad_hangup=None,
+ verify_caller_func=verify_func_c,
+ verify_callee_func=verify_func_a):
+ raise _CallException("PhoneA call PhoneC failed.")
+ if not verify_incall_state(log, [ads[0], ads[1], ads[2]],
+ True):
+ raise _CallException("Not All phones are in-call.")
+
+ except Exception as e:
+ setattr(ads[0], "exception", e)
+ return None
+
+ return call_ab_id
+
+
+def msim_message_test(
+ log,
+ ad_mo,
+ ad_mt,
+ mo_sub_id,
+ mt_sub_id, msg="SMS",
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
+ expected_result=True):
+ """Make MO/MT SMS/MMS at specific slot.
+
+ Args:
+ ad_mo: Android object of the device sending SMS/MMS
+ ad_mt: Android object of the device receiving SMS/MMS
+ mo_sub_id: Sub ID of MO device
+ mt_sub_id: Sub ID of MT device
+ max_wait_time: Max wait time before SMS/MMS is received.
+ expected_result: True for successful sending/receiving and False on
+ the contrary
+
+ Returns:
+ True if the result matches expected_result and False on the
+ contrary.
+ """
+ message_lengths = (50, 160, 180)
+ if msg == "SMS":
+ for length in message_lengths:
+ message_array = [rand_ascii_str(length)]
+ if not sms_send_receive_verify_for_subscription(
+ log,
+ ad_mo,
+ ad_mt,
+ mo_sub_id,
+ mt_sub_id,
+ message_array,
+ max_wait_time):
+ ad_mo.log.warning(
+ "%s of length %s test failed", msg, length)
+ return False
+ else:
+ ad_mo.log.info(
+ "%s of length %s test succeeded", msg, length)
+ log.info("%s test of length %s characters succeeded.",
+ msg, message_lengths)
+
+ elif msg == "MMS":
+ for length in message_lengths:
+ message_array = [("Test Message", rand_ascii_str(length), None)]
+
+ if not mms_send_receive_verify(
+ log,
+ ad_mo,
+ ad_mt,
+ message_array,
+ max_wait_time,
+ expected_result):
+ log.warning("%s of body length %s test failed",
+ msg, length)
+ return False
+ else:
+ log.info(
+ "%s of body length %s test succeeded", msg, length)
+ log.info("%s test of body lengths %s succeeded",
+ msg, message_lengths)
+ return True
+
+
+def msim_call_forwarding(
+ log,
+ tel_logger,
+ ads,
+ caller_slot,
+ callee_slot,
+ forwarded_callee_slot,
+ dds_slot,
+ caller_rat=["", ""],
+ callee_rat=["", ""],
+ forwarded_callee_rat=["", ""],
+ call_forwarding_type="unconditional"):
+ """Make MO voice call to the primary device at specific slot in specific
+ RAT with DDS at specific slot, and then forwarded to 3rd device with
+ specific call forwarding type.
+
+ Test step:
+ 1. Get sub IDs of specific slots of both MO and MT devices.
+ 2. Switch DDS to specific slot.
+ 3. Check HTTP connection after DDS switch.
+ 4. Set up phones in desired RAT.
+ 5. Register and enable call forwarding with specifc type.
+ 5. Make voice call to the primary device and wait for being forwarded
+ to 3rd device.
+
+ Args:
+ log: logger object
+ tel_logger: logger object for telephony proto
+ ads: list of android devices
+ caller_slot: Slot of 2nd device making MO call (0 or 1)
+ callee_slot: Slot of primary device receiving and forwarding MT call
+ (0 or 1)
+ forwarded_callee_slot: Slot of 3rd device receiving forwarded call.
+ dds_slot: Preferred data slot
+ caller_rat: RAT for both slots of the 2nd device
+ callee_rat: RAT for both slots of the primary device
+ forwarded_callee_rat: RAT for both slots of the 3rd device
+ call_forwarding_type:
+ "unconditional"
+ "busy"
+ "not_answered"
+ "not_reachable"
+
+ Returns:
+ True or False
+ """
+ ad_caller = ads[1]
+ ad_callee = ads[0]
+ ad_forwarded_callee = ads[2]
+
+ if callee_slot is not None:
+ callee_sub_id = get_subid_from_slot_index(
+ log, ad_callee, callee_slot)
+ if callee_sub_id == INVALID_SUB_ID:
+ ad_callee.log.warning(
+ "Failed to get sub ID at slot %s.", callee_slot)
+ return False
+ callee_other_sub_id = get_subid_from_slot_index(
+ log, ad_callee, 1-callee_slot)
+ set_voice_sub_id(ad_callee, callee_sub_id)
+ else:
+ callee_sub_id, _, _ = get_subid_on_same_network_of_host_ad(ads)
+ if callee_sub_id == INVALID_SUB_ID:
+ ad_callee.log.warning(
+ "Failed to get sub ID at slot %s.", callee_slot)
+ return False
+ callee_slot = "auto"
+ set_voice_sub_id(ad_callee, callee_sub_id)
+ ad_callee.log.info(
+ "Sub ID for incoming call at slot %s: %s",
+ callee_slot, get_incoming_voice_sub_id(ad_callee))
+
+ if caller_slot is not None:
+ caller_sub_id = get_subid_from_slot_index(
+ log, ad_caller, caller_slot)
+ if caller_sub_id == INVALID_SUB_ID:
+ ad_caller.log.warning(
+ "Failed to get sub ID at slot %s.", caller_slot)
+ return False
+ caller_other_sub_id = get_subid_from_slot_index(
+ log, ad_caller, 1-caller_slot)
+ set_voice_sub_id(ad_caller, caller_sub_id)
+ else:
+ _, caller_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+ if caller_sub_id == INVALID_SUB_ID:
+ ad_caller.log.warning(
+ "Failed to get sub ID at slot %s.", caller_slot)
+ return False
+ caller_slot = "auto"
+ set_voice_sub_id(ad_caller, caller_sub_id)
+ ad_caller.log.info(
+ "Sub ID for outgoing call at slot %s: %s",
+ caller_slot, get_outgoing_voice_sub_id(ad_caller))
+
+ if forwarded_callee_slot is not None:
+ forwarded_callee_sub_id = get_subid_from_slot_index(
+ log, ad_forwarded_callee, forwarded_callee_slot)
+ if forwarded_callee_sub_id == INVALID_SUB_ID:
+ ad_forwarded_callee.log.warning(
+ "Failed to get sub ID at slot %s.", forwarded_callee_slot)
+ return False
+ forwarded_callee_other_sub_id = get_subid_from_slot_index(
+ log, ad_forwarded_callee, 1-forwarded_callee_slot)
+ set_voice_sub_id(
+ ad_forwarded_callee, forwarded_callee_sub_id)
+ else:
+ _, _, forwarded_callee_sub_id = \
+ get_subid_on_same_network_of_host_ad(ads)
+ if forwarded_callee_sub_id == INVALID_SUB_ID:
+ ad_forwarded_callee.log.warning(
+ "Failed to get sub ID at slot %s.", forwarded_callee_slot)
+ return False
+ forwarded_callee_slot = "auto"
+ set_voice_sub_id(
+ ad_forwarded_callee, forwarded_callee_sub_id)
+ ad_forwarded_callee.log.info(
+ "Sub ID for incoming call at slot %s: %s",
+ forwarded_callee_slot,
+ get_incoming_voice_sub_id(ad_forwarded_callee))
+
+ log.info("Step 1: Switch DDS.")
+ if not set_dds_on_slot(ads[0], dds_slot):
+ log.error(
+ "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
+ return False
+
+ log.info("Step 2: Check HTTP connection after DDS switch.")
+ if not verify_http_connection(log, ads[0]):
+ log.error("Failed to verify http connection.")
+ return False
+ else:
+ log.info("Verify http connection successfully.")
+
+ if caller_slot == 1:
+ phone_setup_on_rat(
+ log,
+ ad_caller,
+ caller_rat[0],
+ caller_other_sub_id)
+
+ elif caller_slot == 0:
+ phone_setup_on_rat(
+ log,
+ ad_caller,
+ caller_rat[1],
+ caller_other_sub_id)
+ else:
+ phone_setup_on_rat(
+ log,
+ ad_caller,
+ 'general')
+
+ if callee_slot == 1:
+ phone_setup_on_rat(
+ log,
+ ad_callee,
+ callee_rat[0],
+ callee_other_sub_id)
+
+ elif callee_slot == 0:
+ phone_setup_on_rat(
+ log,
+ ad_callee,
+ callee_rat[1],
+ callee_other_sub_id)
+ else:
+ phone_setup_on_rat(
+ log,
+ ad_callee,
+ 'general')
+
+ if forwarded_callee_slot == 1:
+ phone_setup_on_rat(
+ log,
+ ad_forwarded_callee,
+ forwarded_callee_rat[0],
+ forwarded_callee_other_sub_id)
+
+ elif forwarded_callee_slot == 0:
+ phone_setup_on_rat(
+ log,
+ ad_forwarded_callee,
+ forwarded_callee_rat[1],
+ forwarded_callee_other_sub_id)
+ else:
+ phone_setup_on_rat(
+ log,
+ ad_forwarded_callee,
+ 'general')
+
+ if caller_slot == 0 or caller_slot == 1:
+ caller_phone_setup_func_argv = (log, ad_caller, caller_rat[caller_slot], caller_sub_id)
+ else:
+ caller_phone_setup_func_argv = (log, ad_caller, 'general')
+
+ callee_phone_setup_func_argv = (log, ad_callee, callee_rat[callee_slot], callee_sub_id)
+
+ if forwarded_callee_slot == 0 or forwarded_callee_slot == 1:
+ forwarded_callee_phone_setup_func_argv = (
+ log,
+ ad_forwarded_callee,
+ forwarded_callee_rat[forwarded_callee_slot],
+ forwarded_callee_sub_id)
+ else:
+ forwarded_callee_phone_setup_func_argv = (
+ log,
+ ad_forwarded_callee,
+ 'general')
+
+ log.info("Step 3: Set up phones in desired RAT.")
+ tasks = [(phone_setup_on_rat, caller_phone_setup_func_argv),
+ (phone_setup_on_rat, callee_phone_setup_func_argv),
+ (phone_setup_on_rat,
+ forwarded_callee_phone_setup_func_argv)]
+ if not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+
+ is_callee_in_call = is_phone_in_call_on_rat(
+ log, ad_callee, callee_rat[callee_slot], only_return_fn=True)
+
+ is_call_waiting = re.search(
+ "call_waiting (True (\d)|False)", call_forwarding_type, re.I)
+ if is_call_waiting:
+ if is_call_waiting.group(1) == "False":
+ call_waiting = False
+ scenario = None
+ else:
+ call_waiting = True
+ scenario = int(is_call_waiting.group(2))
+
+ log.info(
+ "Step 4: Make voice call with call waiting enabled = %s.",
+ call_waiting)
+ result = three_phone_call_waiting_short_seq(
+ log,
+ ads[0],
+ None,
+ is_callee_in_call,
+ ads[1],
+ ads[2],
+ call_waiting=call_waiting, scenario=scenario)
+ else:
+ log.info(
+ "Step 4: Make voice call with call forwarding %s.",
+ call_forwarding_type)
+ result = three_phone_call_forwarding_short_seq(
+ log,
+ ads[0],
+ None,
+ is_callee_in_call,
+ ads[1],
+ ads[2],
+ call_forwarding_type=call_forwarding_type)
+
+ if not result:
+ if is_call_waiting:
+ pass
+ else:
+ log.error(
+ "Failed to make MO call from %s slot %s to %s slot %s"
+ " and forward to %s slot %s",
+ ad_caller.serial,
+ caller_slot,
+ ad_callee.serial,
+ callee_slot,
+ ad_forwarded_callee.serial,
+ forwarded_callee_slot)
+
+ return result
+
+
+def msim_call_voice_conf(
+ log,
+ tel_logger,
+ ads,
+ host_slot,
+ p1_slot,
+ p2_slot,
+ dds_slot,
+ host_rat=["volte", "volte"],
+ p1_rat="",
+ p2_rat="",
+ merge=True,
+ disable_cw=False):
+ """Make a voice conference call at specific slot in specific RAT with
+ DDS at specific slot.
+
+ Test step:
+ 1. Get sub IDs of specific slots of both MO and MT devices.
+ 2. Switch DDS to specific slot.
+ 3. Check HTTP connection after DDS switch.
+ 4. Set up phones in desired RAT and make 3-way voice call.
+ 5. Swap calls.
+ 6. Merge calls.
+
+ Args:
+ log: logger object
+ tel_logger: logger object for telephony proto
+ ads: list of android devices
+ host_slot: Slot on the primary device to host the comference call.
+ 0 or 1 (0 for pSIM or 1 for eSIM)
+ p1_slot: Slot on the participant device for the call
+ p2_slot: Slot on another participant device for the call
+ dds_slot: Preferred data slot
+ host_rat: RAT for both slots of the primary device
+ p1_rat: RAT for both slots of the participant device
+ p2_rat: RAT for both slots of another participant device
+ merge: True for merging 2 calls into the conference call. False for
+ not merging 2 separated call.
+ disable_cw: True for disabling call waiting and False on the
+ contrary.
+
+ Returns:
+ True or False
+ """
+ ad_host = ads[0]
+ ad_p1 = ads[1]
+ ad_p2 = ads[2]
+
+ if host_slot is not None:
+ host_sub_id = get_subid_from_slot_index(
+ log, ad_host, host_slot)
+ if host_sub_id == INVALID_SUB_ID:
+ ad_host.log.warning("Failed to get sub ID at slot.", host_slot)
+ return False
+ host_other_sub_id = get_subid_from_slot_index(
+ log, ad_host, 1-host_slot)
+ set_voice_sub_id(ad_host, host_sub_id)
+ else:
+ host_sub_id, _, _ = get_subid_on_same_network_of_host_ad(ads)
+ if host_sub_id == INVALID_SUB_ID:
+ ad_host.log.warning("Failed to get sub ID at slot.", host_slot)
+ return False
+ host_slot = "auto"
+ set_voice_sub_id(ad_host, host_sub_id)
+
+ ad_host.log.info("Sub ID for outgoing call at slot %s: %s",
+ host_slot, get_outgoing_voice_sub_id(ad_host))
+
+ if p1_slot is not None:
+ p1_sub_id = get_subid_from_slot_index(log, ad_p1, p1_slot)
+ if p1_sub_id == INVALID_SUB_ID:
+ ad_p1.log.warning("Failed to get sub ID at slot %s.", p1_slot)
+ return False
+ set_voice_sub_id(ad_p1, p1_sub_id)
+ else:
+ _, p1_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+ if p1_sub_id == INVALID_SUB_ID:
+ ad_p1.log.warning("Failed to get sub ID at slot %s.", p1_slot)
+ return False
+ p1_slot = "auto"
+ set_voice_sub_id(ad_p1, p1_sub_id)
+ ad_p1.log.info("Sub ID for incoming call at slot %s: %s",
+ p1_slot, get_incoming_voice_sub_id(ad_p1))
+
+ if p2_slot is not None:
+ p2_sub_id = get_subid_from_slot_index(log, ad_p2, p2_slot)
+ if p2_sub_id == INVALID_SUB_ID:
+ ad_p2.log.warning("Failed to get sub ID at slot %s.", p2_slot)
+ return False
+ set_voice_sub_id(ad_p2, p2_sub_id)
+ else:
+ _, _, p2_sub_id = get_subid_on_same_network_of_host_ad(ads)
+ if p2_sub_id == INVALID_SUB_ID:
+ ad_p2.log.warning("Failed to get sub ID at slot %s.", p2_slot)
+ return False
+ p2_slot = "auto"
+ set_voice_sub_id(ad_p2, p2_sub_id)
+ ad_p2.log.info("Sub ID for incoming call at slot %s: %s",
+ p2_slot, get_incoming_voice_sub_id(ad_p2))
+
+ log.info("Step 1: Switch DDS.")
+ if not set_dds_on_slot(ads[0], dds_slot):
+ log.error(
+ "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
+ return False
+
+ log.info("Step 2: Check HTTP connection after DDS switch.")
+ if not verify_http_connection(log, ads[0]):
+ log.error("Failed to verify http connection.")
+ return False
+ else:
+ log.info("Verify http connection successfully.")
+
+ if disable_cw:
+ if not set_call_waiting(log, ad_host, enable=0):
+ return False
+ else:
+ if not set_call_waiting(log, ad_host, enable=1):
+ return False
+
+ if host_slot == 1:
+ phone_setup_on_rat(
+ log,
+ ad_host,
+ host_rat[0],
+ host_other_sub_id)
+
+ elif host_slot == 0:
+ phone_setup_on_rat(
+ log,
+ ad_host,
+ host_rat[1],
+ host_other_sub_id)
+
+ if host_slot == 0 or host_slot == 1:
+ host_phone_setup_func_argv = (log, ad_host, host_rat[host_slot], host_sub_id)
+ is_host_in_call = is_phone_in_call_on_rat(
+ log, ad_host, host_rat[host_slot], only_return_fn=True)
+ else:
+ host_phone_setup_func_argv = (log, ad_host, 'general')
+ is_host_in_call = is_phone_in_call_on_rat(
+ log, ad_host, 'general', only_return_fn=True)
+
+ if p1_rat:
+ p1_phone_setup_func_argv = (log, ad_p1, p1_rat, p1_sub_id)
+ is_p1_in_call = is_phone_in_call_on_rat(
+ log, ad_p1, p1_rat, only_return_fn=True)
+ else:
+ p1_phone_setup_func_argv = (log, ad_p1, 'general')
+ is_p1_in_call = is_phone_in_call_on_rat(
+ log, ad_p1, 'general', only_return_fn=True)
+
+ if p2_rat:
+ p2_phone_setup_func_argv = (log, ad_p2, p2_rat, p2_sub_id)
+ is_p2_in_call = is_phone_in_call_on_rat(
+ log, ad_p2, p2_rat, only_return_fn=True)
+ else:
+ p2_phone_setup_func_argv = (log, ad_p2, 'general')
+ is_p2_in_call = is_phone_in_call_on_rat(
+ log, ad_p2, 'general', only_return_fn=True)
+
+ log.info("Step 3: Set up phone in desired RAT and make 3-way"
+ " voice call.")
+
+ tasks = [(phone_setup_on_rat, host_phone_setup_func_argv),
+ (phone_setup_on_rat, p1_phone_setup_func_argv),
+ (phone_setup_on_rat, p2_phone_setup_func_argv)]
+ if not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+
+ call_ab_id = three_way_calling_mo_and_mt_with_hangup_once(
+ log,
+ [ad_host, ad_p1, ad_p2],
+ [None, None, None], [
+ is_host_in_call, is_p1_in_call,
+ is_p2_in_call
+ ])
+
+ if call_ab_id is None:
+ if disable_cw:
+ set_call_waiting(log, ad_host, enable=1)
+ if str(getattr(ad_host, "exception", None)) == \
+ "PhoneA call PhoneC failed.":
+ ads[0].log.info("PhoneA failed to call PhoneC due to call"
+ " waiting being disabled.")
+ delattr(ad_host, "exception")
+ return True
+ log.error("Failed to get call_ab_id")
+ return False
+ else:
+ if disable_cw:
+ return False
+
+ calls = ads[0].droid.telecomCallGetCallIds()
+ ads[0].log.info("Calls in PhoneA %s", calls)
+ if num_active_calls(log, ads[0]) != 2:
+ return False
+ if calls[0] == call_ab_id:
+ call_ac_id = calls[1]
+ else:
+ call_ac_id = calls[0]
+
+ if call_ac_id is None:
+ log.error("Failed to get call_ac_id")
+ return False
+
+ num_swaps = 2
+ log.info("Step 4: Begin Swap x%s test.", num_swaps)
+ if not swap_calls(log, ads, call_ab_id, call_ac_id,
+ num_swaps):
+ log.error("Swap test failed.")
+ return False
+
+ if not merge:
+ result = True
+ if not hangup_call(log, ads[1]):
+ result = False
+ if not hangup_call(log, ads[2]):
+ result = False
+ return result
+ else:
+ log.info("Step 5: Merge calls.")
+ if host_rat[host_slot] == "volte":
+ return _test_ims_conference_merge_drop_second_call_from_participant(
+ log, ads, call_ab_id, call_ac_id)
+ else:
+ return _test_wcdma_conference_merge_drop(
+ log, ads, call_ab_id, call_ac_id)
+
+
+def msim_volte_wfc_call_forwarding(
+ log,
+ tel_logger,
+ ads,
+ callee_slot,
+ dds_slot,
+ callee_rat=["5g_wfc", "5g_wfc"],
+ call_forwarding_type="unconditional",
+ is_airplane_mode=False,
+ is_wifi_connected=False,
+ wfc_mode=[
+ WFC_MODE_CELLULAR_PREFERRED,
+ WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=None,
+ wifi_network_pass=None):
+ """Make VoLTE/WFC call to the primary device at specific slot with DDS
+ at specific slot, and then forwarded to 3rd device with specific call
+ forwarding type.
+
+ Test step:
+ 1. Get sub IDs of specific slots of both MO and MT devices.
+ 2. Switch DDS to specific slot.
+ 3. Check HTTP connection after DDS switch.
+ 4. Set up phones in desired RAT.
+ 5. Register and enable call forwarding with specifc type.
+ 6. Make VoLTE/WFC call to the primary device and wait for being
+ forwarded to 3rd device.
+
+ Args:
+ log: logger object
+ tel_logger: logger object for telephony proto
+ ads: list of android devices
+ callee_slot: Slot of primary device receiving and forwarding MT call
+ (0 or 1)
+ dds_slot: Preferred data slot
+ callee_rat: RAT for both slots of the primary device
+ call_forwarding_type:
+ "unconditional"
+ "busy"
+ "not_answered"
+ "not_reachable"
+ is_airplane_mode: True or False for WFC setup
+ wfc_mode: Cellular preferred or Wi-Fi preferred.
+ wifi_network_ssid: SSID of Wi-Fi AP
+ wifi_network_pass: Password of Wi-Fi AP SSID
+
+ Returns:
+ True or False
+ """
+ ad_caller = ads[1]
+ ad_callee = ads[0]
+ ad_forwarded_callee = ads[2]
+
+ if not toggle_airplane_mode(log, ad_callee, False):
+ ad_callee.log.error("Failed to disable airplane mode.")
+ return False
+
+ # Set up callee (primary device)
+ callee_sub_id = get_subid_from_slot_index(
+ log, ad_callee, callee_slot)
+ if callee_sub_id == INVALID_SUB_ID:
+ log.warning(
+ "Failed to get sub ID at slot %s.", callee_slot)
+ return
+ callee_other_sub_id = get_subid_from_slot_index(
+ log, ad_callee, 1-callee_slot)
+ set_voice_sub_id(ad_callee, callee_sub_id)
+ ad_callee.log.info(
+ "Sub ID for incoming call at slot %s: %s",
+ callee_slot, get_incoming_voice_sub_id(ad_callee))
+
+ # Set up caller
+ _, caller_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+ if caller_sub_id == INVALID_SUB_ID:
+ ad_caller.log.warning("Failed to get proper sub ID of the caller")
+ return
+ set_voice_sub_id(ad_caller, caller_sub_id)
+ ad_caller.log.info(
+ "Sub ID for outgoing call of the caller: %s",
+ get_outgoing_voice_sub_id(ad_caller))
+
+ # Set up forwarded callee
+ _, _, forwarded_callee_sub_id = get_subid_on_same_network_of_host_ad(
+ ads)
+ if forwarded_callee_sub_id == INVALID_SUB_ID:
+ ad_forwarded_callee.log.warning(
+ "Failed to get proper sub ID of the forwarded callee.")
+ return
+ set_voice_sub_id(ad_forwarded_callee, forwarded_callee_sub_id)
+ ad_forwarded_callee.log.info(
+ "Sub ID for incoming call of the forwarded callee: %s",
+ get_incoming_voice_sub_id(ad_forwarded_callee))
+
+ log.info("Step 1: Switch DDS.")
+ if not set_dds_on_slot(ads[0], dds_slot):
+ log.error(
+ "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
+ return False
+
+ log.info("Step 2: Check HTTP connection after DDS switch.")
+ if not verify_http_connection(log, ad_callee):
+ ad_callee.log.error("Failed to verify http connection.")
+ return False
+ else:
+ ad_callee.log.info("Verify http connection successfully.")
+
+ is_callee_in_call = is_phone_in_call_on_rat(
+ log, ad_callee, callee_rat[callee_slot], only_return_fn=True)
+
+ if is_airplane_mode:
+ set_call_forwarding_by_mmi(log, ad_callee, ad_forwarded_callee)
+
+ log.info("Step 3: Set up phones in desired RAT.")
+ if callee_slot == 1:
+ phone_setup_on_rat(
+ log,
+ ad_callee,
+ callee_rat[0],
+ callee_other_sub_id,
+ is_airplane_mode,
+ wfc_mode[0],
+ wifi_network_ssid,
+ wifi_network_pass)
+
+ elif callee_slot == 0:
+ phone_setup_on_rat(
+ log,
+ ad_callee,
+ callee_rat[1],
+ callee_other_sub_id,
+ is_airplane_mode,
+ wfc_mode[1],
+ wifi_network_ssid,
+ wifi_network_pass)
+
+ argv = (
+ log,
+ ad_callee,
+ callee_rat[callee_slot],
+ callee_sub_id,
+ is_airplane_mode,
+ wfc_mode[callee_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+
+ tasks = [(phone_setup_voice_general, (log, ad_caller)),
+ (phone_setup_on_rat, argv),
+ (phone_setup_voice_general, (log, ad_forwarded_callee))]
+
+ if not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+
+ if is_wifi_connected:
+ if not ensure_wifi_connected(
+ log,
+ ad_callee,
+ wifi_network_ssid,
+ wifi_network_pass,
+ apm=is_airplane_mode):
+ return False
+ time.sleep(5)
+
+ if "wfc" not in callee_rat[callee_slot]:
+ if not toggle_wfc_for_subscription(
+ log,
+ ad_callee,
+ new_state=True,
+ sub_id=callee_sub_id):
+ return False
+ if not set_wfc_mode_for_subscription(
+ ad_callee, wfc_mode[callee_slot], sub_id=callee_sub_id):
+ return False
+
+ log.info(
+ "Step 4: Make voice call with call forwarding %s.",
+ call_forwarding_type)
+ result = three_phone_call_forwarding_short_seq(
+ log,
+ ad_callee,
+ None,
+ is_callee_in_call,
+ ad_caller,
+ ad_forwarded_callee,
+ call_forwarding_type=call_forwarding_type)
+
+ if not result:
+ log.error(
+ "Failed to make MO call from %s to %s slot %s and forward"
+ " to %s.",
+ ad_caller.serial,
+ ad_callee.serial,
+ callee_slot,
+ ad_forwarded_callee.serial)
+ return result
+
+
+def msim_volte_wfc_call_voice_conf(
+ log,
+ tel_logger,
+ ads,
+ host_slot,
+ dds_slot,
+ host_rat=["5g_wfc", "5g_wfc"],
+ merge=True,
+ disable_cw=False,
+ is_airplane_mode=False,
+ is_wifi_connected=False,
+ wfc_mode=[WFC_MODE_CELLULAR_PREFERRED, WFC_MODE_CELLULAR_PREFERRED],
+ reject_once=False,
+ wifi_network_ssid=None,
+ wifi_network_pass=None):
+ """Make a VoLTE/WFC conference call at specific slot with DDS at
+ specific slot.
+
+ Test step:
+ 1. Get sub IDs of specific slots of both MO and MT devices.
+ 2. Set up phones in desired RAT
+ 3. Enable VoLTE/WFC.
+ 4. Switch DDS to specific slot.
+ 5. Check HTTP connection after DDS switch.
+ 6. Make 3-way VoLTE/WFC call.
+ 7. Swap calls.
+ 8. Merge calls.
+
+ Args:
+ log: logger object
+ tel_logger: logger object for telephony proto
+ ads: list of android devices
+ host_slot: Slot on the primary device to host the comference call.
+ 0 or 1 (0 for pSIM or 1 for eSIM)call
+ dds_slot: Preferred data slot
+ host_rat: RAT for both slots of the primary devicevice
+ merge: True for merging 2 calls into the conference call. False for
+ not merging 2 separated call.
+ disable_cw: True for disabling call waiting and False on the
+ contrary.
+ enable_volte: True for enabling and False for disabling VoLTE for
+ each slot on the primary device
+ enable_wfc: True for enabling and False for disabling WFC for
+ each slot on the primary device
+ is_airplane_mode: True or False for WFC setup
+ wfc_mode: Cellular preferred or Wi-Fi preferred.
+ reject_once: True for rejecting the 2nd call once from the 3rd
+ device (Phone C) to the primary device (Phone A).
+ wifi_network_ssid: SSID of Wi-Fi AP
+ wifi_network_pass: Password of Wi-Fi AP SSID
+
+ Returns:
+ True or False
+ """
+ ad_host = ads[0]
+ ad_p1 = ads[1]
+ ad_p2 = ads[2]
+
+ host_sub_id = get_subid_from_slot_index(log, ad_host, host_slot)
+ if host_sub_id == INVALID_SUB_ID:
+ ad_host.log.warning("Failed to get sub ID at slot.", host_slot)
+ return
+ host_other_sub_id = get_subid_from_slot_index(
+ log, ad_host, 1-host_slot)
+ set_voice_sub_id(ad_host, host_sub_id)
+ ad_host.log.info(
+ "Sub ID for outgoing call at slot %s: %s",
+ host_slot, get_outgoing_voice_sub_id(ad_host))
+
+ _, p1_sub_id, p2_sub_id = get_subid_on_same_network_of_host_ad(ads)
+
+ if p1_sub_id == INVALID_SUB_ID:
+ ad_p1.log.warning("Failed to get proper sub ID.")
+ return
+ set_voice_sub_id(ad_p1, p1_sub_id)
+ ad_p1.log.info(
+ "Sub ID for incoming call: %s",
+ get_incoming_voice_sub_id(ad_p1))
+
+ if p2_sub_id == INVALID_SUB_ID:
+ ad_p2.log.warning("Failed to get proper sub ID.")
+ return
+ set_voice_sub_id(ad_p2, p2_sub_id)
+ ad_p2.log.info(
+ "Sub ID for incoming call: %s", get_incoming_voice_sub_id(ad_p2))
+
+ log.info("Step 1: Switch DDS.")
+ if not set_dds_on_slot(ads[0], dds_slot):
+ log.error(
+ "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
+ return False
+
+ log.info("Step 2: Check HTTP connection after DDS switch.")
+ if not verify_http_connection(log, ads[0]):
+ ad_host.log.error("Failed to verify http connection.")
+ return False
+ else:
+ ad_host.log.info("Verify http connection successfully.")
+
+ if disable_cw:
+ if not set_call_waiting(log, ad_host, enable=0):
+ return False
+
+ log.info("Step 3: Set up phones in desired RAT.")
+ if host_slot == 1:
+ phone_setup_on_rat(
+ log,
+ ad_host,
+ host_rat[0],
+ host_other_sub_id,
+ is_airplane_mode,
+ wfc_mode[0],
+ wifi_network_ssid,
+ wifi_network_pass)
+
+ elif host_slot == 0:
+ phone_setup_on_rat(
+ log,
+ ad_host,
+ host_rat[1],
+ host_other_sub_id,
+ is_airplane_mode,
+ wfc_mode[1],
+ wifi_network_ssid,
+ wifi_network_pass)
+
+ argv = (
+ log,
+ ad_host,
+ host_rat[host_slot],
+ host_sub_id,
+ is_airplane_mode,
+ wfc_mode[host_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+
+ tasks = [(phone_setup_voice_general, (log, ad_p1)),
+ (phone_setup_on_rat, argv),
+ (phone_setup_voice_general, (log, ad_p2))]
+
+ if not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+
+ if is_wifi_connected:
+ if not ensure_wifi_connected(
+ log,
+ ad_host,
+ wifi_network_ssid,
+ wifi_network_pass,
+ apm=is_airplane_mode):
+ return False
+ time.sleep(5)
+
+ if "wfc" not in host_rat[host_slot]:
+ if not toggle_wfc_for_subscription(
+ log,
+ ad_host,
+ new_state=True,
+ sub_id=host_sub_id):
+ return False
+ if not set_wfc_mode_for_subscription(
+ ad_host, wfc_mode[host_slot], sub_id=host_sub_id):
+ return False
+
+ log.info("Step 4: Make 3-way voice call.")
+ is_host_in_call = is_phone_in_call_on_rat(
+ log, ad_host, host_rat[host_slot], only_return_fn=True)
+ call_ab_id = _three_phone_call_mo_add_mt(
+ log,
+ [ad_host, ad_p1, ad_p2],
+ [None, None, None],
+ [is_host_in_call, None, None],
+ reject_once=reject_once)
+
+ if call_ab_id is None:
+ if disable_cw:
+ set_call_waiting(log, ad_host, enable=1)
+ if str(getattr(ad_host, "exception", None)) == \
+ "PhoneA call PhoneC failed.":
+ ads[0].log.info("PhoneA failed to call PhoneC due to call"
+ " waiting being disabled.")
+ delattr(ad_host, "exception")
+ return True
+ log.error("Failed to get call_ab_id")
+ return False
+ else:
+ if disable_cw:
+ set_call_waiting(log, ad_host, enable=0)
+ return False
+
+ calls = ads[0].droid.telecomCallGetCallIds()
+ ads[0].log.info("Calls in PhoneA %s", calls)
+ if num_active_calls(log, ads[0]) != 2:
+ return False
+ if calls[0] == call_ab_id:
+ call_ac_id = calls[1]
+ else:
+ call_ac_id = calls[0]
+
+ if call_ac_id is None:
+ log.error("Failed to get call_ac_id")
+ return False
+
+ num_swaps = 2
+ log.info("Step 5: Begin Swap x%s test.", num_swaps)
+ if not swap_calls(log, ads, call_ab_id, call_ac_id,
+ num_swaps):
+ ad_host.log.error("Swap test failed.")
+ return False
+
+ if not merge:
+ result = True
+ if not hangup_call(log, ads[1]):
+ result = False
+ if not hangup_call(log, ads[2]):
+ result = False
+ return result
+ else:
+ log.info("Step 6: Merge calls.")
+
+ if re.search('csfb|2g|3g', host_rat[host_slot].lower(), re.I):
+ return _test_wcdma_conference_merge_drop(
+ log, ads, call_ab_id, call_ac_id)
+ else:
+ return _test_ims_conference_merge_drop_second_call_from_participant(
+ log, ads, call_ab_id, call_ac_id)
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_ims_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_ims_utils.py
index 7287971..4001f9b 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_ims_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_ims_utils.py
@@ -14,252 +14,778 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import time
+
+from acts import signals
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE
-from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
-from acts_contrib.test_utils.tel.tel_defines import CarrierConfigs
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
-from acts_contrib.test_utils.tel.tel_defines import RAT_LTE
-from acts_contrib.test_utils.tel.tel_defines import RAT_NR
-from acts_contrib.test_utils.tel.tel_defines import RAT_UNKNOWN
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_incoming_voice_sub_id
+from acts_contrib.test_utils.tel.tel_defines import CARRIER_FRE
+from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOLTE_ENABLED
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_DISABLED
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import get_user_config_profile
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_wfc
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_not_network_rat
+from acts_contrib.test_utils.tel.tel_defines import CARRIER_VZW, CARRIER_ATT, \
+ CARRIER_BELL, CARRIER_ROGERS, CARRIER_KOODO, CARRIER_VIDEOTRON, CARRIER_TELUS
+from acts_contrib.test_utils.tel.tel_logging_utils import start_adb_tcpdump
+from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state
+from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import bring_up_sl4a
+from acts_contrib.test_utils.tel.tel_test_utils import change_voice_subid_temporarily
+from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_voice_attach
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_volte_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_disabled
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-def check_call(log, dut, dut_client):
+class TelImsUtilsError(Exception):
+ pass
+
+
+def show_enhanced_4g_lte(ad, sub_id):
result = True
- if not call_setup_teardown(log, dut_client, dut,
- dut):
- if not call_setup_teardown(log, dut_client,
- dut, dut):
- dut.log.error("MT call failed")
+ capabilities = ad.telephony["subscription"][sub_id].get("capabilities", [])
+ if capabilities:
+ if "hide_enhanced_4g_lte" in capabilities:
result = False
- if not call_setup_teardown(log, dut, dut_client,
- dut):
- dut.log.error("MO call failed")
- result = False
+ ad.log.info(
+ '"Enhanced 4G LTE MODE" is hidden for sub ID %s.', sub_id)
+ show_enhanced_4g_lte_mode = getattr(
+ ad, "show_enhanced_4g_lte_mode", False)
+ if show_enhanced_4g_lte_mode in ["true", "True"]:
+ current_voice_sub_id = get_outgoing_voice_sub_id(ad)
+ if sub_id != current_voice_sub_id:
+ set_incoming_voice_sub_id(ad, sub_id)
+
+ ad.log.info(
+ 'Show "Enhanced 4G LTE MODE" forcibly for sub ID %s.',
+ sub_id)
+ ad.adb.shell(
+ "am broadcast \
+ -a com.google.android.carrier.action.LOCAL_OVERRIDE \
+ -n com.google.android.carrier/.ConfigOverridingReceiver \
+ --ez hide_enhanced_4g_lte_bool false")
+ ad.telephony["subscription"][sub_id]["capabilities"].remove(
+ "hide_enhanced_4g_lte")
+
+ if sub_id != current_voice_sub_id:
+ set_incoming_voice_sub_id(ad, current_voice_sub_id)
+
+ result = True
return result
-def check_call_in_wfc(log, dut, dut_client):
+def toggle_volte(log, ad, new_state=None):
+ """Toggle enable/disable VoLTE for default voice subscription.
+
+ Args:
+ ad: Android device object.
+ new_state: VoLTE mode state to set to.
+ True for enable, False for disable.
+ If None, opposite of the current state.
+
+ Raises:
+ TelImsUtilsError if platform does not support VoLTE.
+ """
+ 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):
+ """Toggle enable/disable VoLTE for specified voice subscription.
+
+ Args:
+ ad: Android device object.
+ sub_id: Optional. If not assigned the default sub ID for voice call will
+ be used.
+ new_state: VoLTE mode state to set to.
+ True for enable, False for disable.
+ If None, opposite of the current state.
+ """
+ if not show_enhanced_4g_lte(ad, sub_id):
+ return False
+
+ current_state = None
result = True
- if not call_setup_teardown(log, dut_client, dut,
- dut, None, is_phone_in_call_iwlan):
- if not call_setup_teardown(log, dut_client,
- dut, dut, None,
- is_phone_in_call_iwlan):
- dut.log.error("MT WFC call failed")
+
+ if sub_id is None:
+ sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
+
+ try:
+ current_state = ad.droid.imsMmTelIsAdvancedCallingEnabled(sub_id)
+ except Exception as e:
+ ad.log.warning(e)
+
+ if current_state is not None:
+ if new_state is None:
+ new_state = not current_state
+ if new_state != current_state:
+ ad.log.info(
+ "Toggle Enhanced 4G LTE Mode from %s to %s on sub_id %s",
+ current_state, new_state, sub_id)
+ ad.droid.imsMmTelSetAdvancedCallingEnabled(sub_id, new_state)
+ check_state = ad.droid.imsMmTelIsAdvancedCallingEnabled(sub_id)
+ if check_state != new_state:
+ ad.log.error("Failed to toggle Enhanced 4G LTE Mode to %s, still \
+ set to %s on sub_id %s", new_state, check_state, sub_id)
result = False
- if not call_setup_teardown(log, dut, dut_client,
- dut, is_phone_in_call_iwlan):
- dut.log.error("MO WFC call failed")
- result = False
- return result
-
-
-def check_call_in_volte(log, dut, dut_client):
- result = True
- if not call_setup_teardown(log, dut_client, dut,
- dut, None, is_phone_in_call_volte):
- if not call_setup_teardown(log, dut_client,
- dut, dut, None,
- is_phone_in_call_volte):
- dut.log.error("MT VoLTE call failed")
- result = False
- if not call_setup_teardown(log, dut, dut_client,
- dut, is_phone_in_call_volte):
- dut.log.error("MO VoLTE call failed")
- result = False
- return result
-
-
-def change_ims_setting(log,
- ad,
- dut_client,
- wifi_network_ssid,
- wifi_network_pass,
- subid,
- dut_capabilities,
- airplane_mode,
- wifi_enabled,
- volte_enabled,
- wfc_enabled,
- nw_gen=RAT_LTE,
- wfc_mode=None):
- result = True
- ad.log.info(
- "Setting APM %s, WIFI %s, VoLTE %s, WFC %s, WFC mode %s",
- airplane_mode, wifi_enabled, volte_enabled, wfc_enabled, wfc_mode)
-
- toggle_airplane_mode_by_adb(log, ad, airplane_mode)
- if wifi_enabled:
- if not ensure_wifi_connected(log, ad,
- wifi_network_ssid,
- wifi_network_pass,
- apm=airplane_mode):
- ad.log.error("Fail to connected to WiFi")
- result = False
+ return result
else:
- if not wifi_toggle_state(log, ad, False):
- ad.log.error("Failed to turn off WiFi.")
+ # TODO: b/26293960 No framework API available to set IMS by SubId.
+ voice_sub_id_changed = False
+ current_sub_id = get_incoming_voice_sub_id(ad)
+ if current_sub_id != sub_id:
+ set_incoming_voice_sub_id(ad, sub_id)
+ voice_sub_id_changed = True
+
+ # b/139641554
+ ad.terminate_all_sessions()
+ bring_up_sl4a(ad)
+
+ if not ad.droid.imsIsEnhanced4gLteModeSettingEnabledByPlatform():
+ ad.log.info(
+ "Enhanced 4G Lte Mode Setting is not enabled by platform for \
+ sub ID %s.", sub_id)
+ return False
+
+ current_state = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
+ ad.log.info("Current state of Enhanced 4G Lte Mode Setting for sub \
+ ID %s: %s", sub_id, current_state)
+ ad.log.info("New desired state of Enhanced 4G Lte Mode Setting for sub \
+ ID %s: %s", sub_id, new_state)
+
+ if new_state is None:
+ new_state = not current_state
+ if new_state != current_state:
+ ad.log.info(
+ "Toggle Enhanced 4G LTE Mode from %s to %s for sub ID %s.",
+ current_state, new_state, sub_id)
+ ad.droid.imsSetEnhanced4gMode(new_state)
+ time.sleep(5)
+
+ check_state = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
+ if check_state != new_state:
+ ad.log.error("Failed to toggle Enhanced 4G LTE Mode to %s, \
+ still set to %s on sub_id %s", new_state, check_state, sub_id)
result = False
- toggle_volte(log, ad, volte_enabled)
- toggle_wfc(log, ad, wfc_enabled)
- if wfc_mode:
- set_wfc_mode(log, ad, wfc_mode)
- wfc_mode = ad.droid.imsGetWfcMode()
- if wifi_enabled or not airplane_mode:
- if not ensure_phone_subscription(log, ad):
- ad.log.error("Failed to find valid subscription")
- result = False
- if airplane_mode:
- if (CAPABILITY_WFC in dut_capabilities) and (wifi_enabled
- and wfc_enabled):
- if not wait_for_wfc_enabled(log, ad):
- result = False
- elif not check_call_in_wfc(log, ad, dut_client):
- result = False
- else:
- if not wait_for_state(
- ad.droid.telephonyGetCurrentVoiceNetworkType,
- RAT_UNKNOWN):
- ad.log.error(
- "Voice RAT is %s not UNKNOWN",
- ad.droid.telephonyGetCurrentVoiceNetworkType())
- result = False
- else:
- ad.log.info("Voice RAT is in UNKKNOWN")
- else:
- if (wifi_enabled and wfc_enabled) and (
- wfc_mode == WFC_MODE_WIFI_PREFERRED) and (
- CAPABILITY_WFC in dut_capabilities):
- if not wait_for_wfc_enabled(log, ad):
- result = False
- if not wait_for_state(
- ad.droid.telephonyGetCurrentVoiceNetworkType,
- RAT_UNKNOWN):
- ad.log.error(
- "Voice RAT is %s, not UNKNOWN",
- ad.droid.telephonyGetCurrentVoiceNetworkType())
- if not check_call_in_wfc(log, ad, dut_client):
- result = False
- else:
- if not wait_for_wfc_disabled(log, ad):
- ad.log.error("WFC is not disabled")
- result = False
- if volte_enabled and CAPABILITY_VOLTE in dut_capabilities:
- if not wait_for_volte_enabled(log, ad):
- result = False
- if not check_call_in_volte(log, ad, dut_client):
- result = False
- else:
- if not wait_for_not_network_rat(
- log,
- ad,
- nw_gen,
- voice_or_data=NETWORK_SERVICE_VOICE):
- ad.log.error(
- "Voice RAT is %s",
- ad.droid.telephonyGetCurrentVoiceNetworkType(
- ))
- result = False
- if not wait_for_voice_attach(log, ad):
- result = False
- if not check_call(log, ad, dut_client):
- result = False
- user_config_profile = get_user_config_profile(ad)
- ad.log.info("user_config_profile: %s ",
- sorted(user_config_profile.items()))
- return result
+
+ if voice_sub_id_changed:
+ set_incoming_voice_sub_id(ad, current_sub_id)
+
+ return result
-def verify_default_ims_setting(log,
- ad,
- dut_client,
- carrier_configs,
- default_wfc_enabled,
- default_volte,
- wfc_mode=None):
+def toggle_wfc(log, ad, new_state=None):
+ """ Toggle WFC enable/disable
+
+ Args:
+ log: Log object
+ ad: Android device object.
+ new_state: WFC state to set to.
+ True for enable, False for disable.
+ If None, opposite of the current state.
+ """
+ return toggle_wfc_for_subscription(
+ log, ad, new_state, get_outgoing_voice_sub_id(ad))
+
+
+def toggle_wfc_for_subscription(log, ad, new_state=None, sub_id=None):
+ """ Toggle WFC enable/disable for specified voice subscription.
+
+ Args:
+ ad: Android device object.
+ sub_id: Optional. If not assigned the default sub ID for voice call will
+ be used.
+ new_state: WFC state to set to.
+ True for enable, False for disable.
+ If None, opposite of the current state.
+ """
+ current_state = None
result = True
- airplane_mode = ad.droid.connectivityCheckAirplaneMode()
- default_wfc_mode = carrier_configs.get(
- CarrierConfigs.DEFAULT_WFC_IMS_MODE_INT, wfc_mode)
- if default_wfc_enabled:
- wait_for_wfc_enabled(log, ad)
- else:
- wait_for_wfc_disabled(log, ad)
- if airplane_mode:
- wait_for_network_rat(
- log,
- ad,
- RAT_UNKNOWN,
- voice_or_data=NETWORK_SERVICE_VOICE)
- else:
- if default_volte:
- wait_for_volte_enabled(log, ad)
- else:
- wait_for_not_network_rat(
- log,
- ad,
- RAT_UNKNOWN,
- voice_or_data=NETWORK_SERVICE_VOICE)
- if not ensure_phone_subscription(log, ad):
- ad.log.error("Failed to find valid subscription")
- result = False
- user_config_profile = get_user_config_profile(ad)
- ad.log.info("user_config_profile = %s ",
- sorted(user_config_profile.items()))
- if user_config_profile["VoLTE Enabled"] != default_volte:
- ad.log.error("VoLTE mode is not %s", default_volte)
- result = False
- else:
- ad.log.info("VoLTE mode is %s as expected",
- default_volte)
- if user_config_profile["WFC Enabled"] != default_wfc_enabled:
- ad.log.error("WFC enabled is not %s", default_wfc_enabled)
- if user_config_profile["WFC Enabled"]:
- if user_config_profile["WFC Mode"] != default_wfc_mode:
- ad.log.error(
- "WFC mode is not %s after IMS factory reset",
- default_wfc_mode)
+ if sub_id is None:
+ sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
+
+ try:
+ current_state = ad.droid.imsMmTelIsVoWiFiSettingEnabled(sub_id)
+ except Exception as e:
+ ad.log.warning(e)
+
+ if current_state is not None:
+ if new_state is None:
+ new_state = not current_state
+ if new_state != current_state:
+ ad.log.info(
+ "Toggle Wi-Fi calling from %s to %s on sub_id %s",
+ current_state, new_state, sub_id)
+ ad.droid.imsMmTelSetVoWiFiSettingEnabled(sub_id, new_state)
+ check_state = ad.droid.imsMmTelIsVoWiFiSettingEnabled(sub_id)
+ if check_state != new_state:
+ ad.log.error("Failed to toggle Wi-Fi calling to %s, \
+ still set to %s on sub_id %s", new_state, check_state, sub_id)
result = False
+ return result
+ else:
+ voice_sub_id_changed = False
+ if not sub_id:
+ sub_id = get_outgoing_voice_sub_id(ad)
else:
- ad.log.info("WFC mode is %s as expected",
- default_wfc_mode)
- if default_wfc_enabled and \
- default_wfc_mode == WFC_MODE_WIFI_PREFERRED:
- if not check_call_in_wfc(log, ad, dut_client):
- result = False
- elif not airplane_mode:
- if default_volte:
- if not check_call_in_volte(log, ad, dut_client):
- result = False
+ current_sub_id = get_incoming_voice_sub_id(ad)
+ if current_sub_id != sub_id:
+ set_incoming_voice_sub_id(ad, sub_id)
+ voice_sub_id_changed = True
+
+ # b/139641554
+ ad.terminate_all_sessions()
+ bring_up_sl4a(ad)
+
+ if not ad.droid.imsIsWfcEnabledByPlatform():
+ ad.log.info("WFC is not enabled by platform for sub ID %s.", sub_id)
+ return False
+
+ current_state = ad.droid.imsIsWfcEnabledByUser()
+ ad.log.info("Current state of WFC Setting for sub ID %s: %s",
+ sub_id, current_state)
+ ad.log.info("New desired state of WFC Setting for sub ID %s: %s",
+ sub_id, new_state)
+
+ if new_state is None:
+ new_state = not current_state
+ if new_state != current_state:
+ ad.log.info("Toggle WFC user enabled from %s to %s for sub ID %s",
+ current_state, new_state, sub_id)
+ ad.droid.imsSetWfcSetting(new_state)
+
+ if voice_sub_id_changed:
+ set_incoming_voice_sub_id(ad, current_sub_id)
+
+ return True
+
+
+def is_enhanced_4g_lte_mode_setting_enabled(ad, sub_id, enabled_by="platform"):
+ voice_sub_id_changed = False
+ current_sub_id = get_incoming_voice_sub_id(ad)
+ if current_sub_id != sub_id:
+ set_incoming_voice_sub_id(ad, sub_id)
+ voice_sub_id_changed = True
+ if enabled_by == "platform":
+ res = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByPlatform()
+ else:
+ res = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
+ if not res:
+ ad.log.info("Enhanced 4G Lte Mode Setting is NOT enabled by %s for sub \
+ ID %s.", enabled_by, sub_id)
+ if voice_sub_id_changed:
+ set_incoming_voice_sub_id(ad, current_sub_id)
+ return False
+ if voice_sub_id_changed:
+ set_incoming_voice_sub_id(ad, current_sub_id)
+ ad.log.info("Enhanced 4G Lte Mode Setting is enabled by %s for sub ID %s.",
+ enabled_by, sub_id)
+ return True
+
+
+def set_enhanced_4g_mode(ad, sub_id, state):
+ voice_sub_id_changed = False
+ current_sub_id = get_incoming_voice_sub_id(ad)
+ if current_sub_id != sub_id:
+ set_incoming_voice_sub_id(ad, sub_id)
+ voice_sub_id_changed = True
+
+ ad.droid.imsSetEnhanced4gMode(state)
+ time.sleep(5)
+
+ if voice_sub_id_changed:
+ set_incoming_voice_sub_id(ad, current_sub_id)
+
+
+def wait_for_enhanced_4g_lte_setting(log,
+ ad,
+ sub_id,
+ max_time=MAX_WAIT_TIME_FOR_STATE_CHANGE):
+ """Wait for android device to enable enhance 4G LTE setting.
+
+ Args:
+ log: log object.
+ ad: android device.
+ max_time: maximal wait time.
+
+ Returns:
+ Return True if device report VoLTE enabled bit true within max_time.
+ Return False if timeout.
+ """
+ return wait_for_state(
+ is_enhanced_4g_lte_mode_setting_enabled,
+ True,
+ max_time,
+ WAIT_TIME_BETWEEN_STATE_CHECK,
+ ad,
+ sub_id,
+ enabled_by="platform")
+
+
+def set_wfc_mode(log, ad, wfc_mode):
+ """Set WFC enable/disable and mode.
+
+ Args:
+ log: Log object
+ ad: Android device object.
+ wfc_mode: WFC mode to set to.
+ Valid mode includes: WFC_MODE_WIFI_ONLY, WFC_MODE_CELLULAR_PREFERRED,
+ WFC_MODE_WIFI_PREFERRED, WFC_MODE_DISABLED.
+
+ Returns:
+ True if success. False if ad does not support WFC or error happened.
+ """
+ return set_wfc_mode_for_subscription(
+ ad, wfc_mode, get_outgoing_voice_sub_id(ad))
+
+
+def set_wfc_mode_for_subscription(ad, wfc_mode, sub_id=None):
+ """Set WFC enable/disable and mode subscription based
+
+ Args:
+ ad: Android device object.
+ wfc_mode: WFC mode to set to.
+ Valid mode includes: WFC_MODE_WIFI_ONLY, WFC_MODE_CELLULAR_PREFERRED,
+ WFC_MODE_WIFI_PREFERRED.
+ sub_id: subscription Id
+
+ Returns:
+ True if success. False if ad does not support WFC or error happened.
+ """
+ if wfc_mode not in [
+ WFC_MODE_WIFI_ONLY,
+ WFC_MODE_CELLULAR_PREFERRED,
+ WFC_MODE_WIFI_PREFERRED,
+ WFC_MODE_DISABLED]:
+
+ ad.log.error("Given WFC mode (%s) is not correct.", wfc_mode)
+ return False
+
+ current_mode = None
+ result = True
+
+ if sub_id is None:
+ sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
+
+ try:
+ current_mode = ad.droid.imsMmTelGetVoWiFiModeSetting(sub_id)
+ ad.log.info("Current WFC mode of sub ID %s: %s", sub_id, current_mode)
+ except Exception as e:
+ ad.log.warning(e)
+
+ if current_mode is not None:
+ try:
+ if not ad.droid.imsMmTelIsVoWiFiSettingEnabled(sub_id):
+ if wfc_mode is WFC_MODE_DISABLED:
+ ad.log.info("WFC is already disabled.")
+ return True
+ ad.log.info(
+ "WFC is disabled for sub ID %s. Enabling WFC...", sub_id)
+ ad.droid.imsMmTelSetVoWiFiSettingEnabled(sub_id, True)
+
+ if wfc_mode is WFC_MODE_DISABLED:
+ ad.log.info(
+ "WFC is enabled for sub ID %s. Disabling WFC...", sub_id)
+ ad.droid.imsMmTelSetVoWiFiSettingEnabled(sub_id, False)
+ return True
+
+ ad.log.info("Set wfc mode to %s for sub ID %s.", wfc_mode, sub_id)
+ ad.droid.imsMmTelSetVoWiFiModeSetting(sub_id, wfc_mode)
+ mode = ad.droid.imsMmTelGetVoWiFiModeSetting(sub_id)
+ if mode != wfc_mode:
+ ad.log.error("WFC mode for sub ID %s is %s, not in %s",
+ sub_id, mode, wfc_mode)
+ return False
+ except Exception as e:
+ ad.log.error(e)
+ return False
+ return True
+ else:
+ voice_sub_id_changed = False
+ if not sub_id:
+ sub_id = get_outgoing_voice_sub_id(ad)
else:
- if not check_call(log, ad, dut_client):
- result = False
- if result == False:
- user_config_profile = get_user_config_profile(ad)
- ad.log.info("user_config_profile = %s ",
- sorted(user_config_profile.items()))
- return result
+ current_sub_id = get_incoming_voice_sub_id(ad)
+ if current_sub_id != sub_id:
+ set_incoming_voice_sub_id(ad, sub_id)
+ voice_sub_id_changed = True
+
+ # b/139641554
+ ad.terminate_all_sessions()
+ bring_up_sl4a(ad)
+
+ if wfc_mode != WFC_MODE_DISABLED and wfc_mode not in ad.telephony[
+ "subscription"][get_outgoing_voice_sub_id(ad)].get("wfc_modes", []):
+ ad.log.error("WFC mode %s is not supported", wfc_mode)
+ raise signals.TestSkip("WFC mode %s is not supported" % wfc_mode)
+ try:
+ ad.log.info("Set wfc mode to %s", wfc_mode)
+ if wfc_mode != WFC_MODE_DISABLED:
+ start_adb_tcpdump(ad, interface="wlan0", mask="all")
+ if not ad.droid.imsIsWfcEnabledByPlatform():
+ if wfc_mode == WFC_MODE_DISABLED:
+ if voice_sub_id_changed:
+ set_incoming_voice_sub_id(ad, current_sub_id)
+ return True
+ else:
+ ad.log.error("WFC not supported by platform.")
+ if voice_sub_id_changed:
+ set_incoming_voice_sub_id(ad, current_sub_id)
+ return False
+ ad.droid.imsSetWfcMode(wfc_mode)
+ mode = ad.droid.imsGetWfcMode()
+ if voice_sub_id_changed:
+ set_incoming_voice_sub_id(ad, current_sub_id)
+ if mode != wfc_mode:
+ ad.log.error("WFC mode is %s, not in %s", mode, wfc_mode)
+ return False
+ except Exception as e:
+ ad.log.error(e)
+ if voice_sub_id_changed:
+ set_incoming_voice_sub_id(ad, current_sub_id)
+ return False
+ return True
+def set_ims_provisioning_for_subscription(ad, feature_flag, value, sub_id=None):
+ """ Sets Provisioning Values for Subscription Id
+ Args:
+ ad: Android device object.
+ sub_id: Subscription Id
+ feature_flag: voice or video
+ value: enable or disable
+ """
+ try:
+ if sub_id is None:
+ sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
+ ad.log.info("SubId %s - setprovisioning for %s to %s",
+ sub_id, feature_flag, value)
+ result = ad.droid.provisioningSetProvisioningIntValue(sub_id,
+ feature_flag, value)
+ if result == 0:
+ return True
+ return False
+ except Exception as e:
+ ad.log.error(e)
+ return False
+
+
+def get_ims_provisioning_for_subscription(ad, feature_flag, tech, sub_id=None):
+ """ Gets Provisioning Values for Subscription Id
+
+ Args:
+ ad: Android device object.
+ sub_id: Subscription Id
+ feature_flag: voice, video, ut, sms
+ tech: lte, iwlan
+ """
+ try:
+ if sub_id is None:
+ sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
+ result = ad.droid.provisioningGetProvisioningStatusForCapability(
+ sub_id, feature_flag, tech)
+ ad.log.info("SubId %s - getprovisioning for %s on %s - %s",
+ sub_id, feature_flag, tech, result)
+ return result
+ except Exception as e:
+ ad.log.error(e)
+ return False
+
+
+def activate_wfc_on_device(log, ad):
+ """ Activates WiFi calling on device.
+
+ Required for certain network operators.
+
+ Args:
+ log: Log object
+ ad: Android device object
+ """
+ activate_wfc_on_device_for_subscription(log, ad,
+ ad.droid.subscriptionGetDefaultSubId())
+
+
+def activate_wfc_on_device_for_subscription(log, ad, sub_id):
+ """ Activates WiFi calling on device for a subscription.
+
+ Args:
+ log: Log object
+ ad: Android device object
+ sub_id: Subscription id (integer)
+ """
+ if not sub_id or INVALID_SUB_ID == sub_id:
+ ad.log.error("Subscription id invalid")
+ return
+ operator_name = get_operator_name(log, ad, sub_id)
+ if operator_name in (CARRIER_VZW, CARRIER_ATT, CARRIER_BELL, CARRIER_ROGERS,
+ CARRIER_TELUS, CARRIER_KOODO, CARRIER_VIDEOTRON, CARRIER_FRE):
+ ad.log.info("Activating WFC on operator : %s", operator_name)
+ if not ad.is_apk_installed("com.google.android.wfcactivation"):
+ ad.log.error("WFC Activation Failed, wfc activation apk not installed")
+ return
+ wfc_activate_cmd ="am start --ei EXTRA_LAUNCH_CARRIER_APP 0 --ei " \
+ "android.telephony.extra.SUBSCRIPTION_INDEX {} -n ".format(sub_id)
+ if CARRIER_ATT == operator_name:
+ ad.adb.shell("setprop dbg.att.force_wfc_nv_enabled true")
+ wfc_activate_cmd = wfc_activate_cmd+\
+ "\"com.google.android.wfcactivation/" \
+ ".WfcActivationActivity\""
+ elif CARRIER_VZW == operator_name:
+ ad.adb.shell("setprop dbg.vzw.force_wfc_nv_enabled true")
+ wfc_activate_cmd = wfc_activate_cmd + \
+ "\"com.google.android.wfcactivation/" \
+ ".VzwEmergencyAddressActivity\""
+ else:
+ wfc_activate_cmd = wfc_activate_cmd+ \
+ "\"com.google.android.wfcactivation/" \
+ ".can.WfcActivationCanadaActivity\""
+ ad.adb.shell(wfc_activate_cmd)
+
+
+def is_ims_registered(log, ad, sub_id=None):
+ """Return True if IMS registered.
+
+ Args:
+ log: log object.
+ ad: android device.
+ sub_id: Optional. If not assigned the default sub ID of voice call will
+ be used.
+
+ Returns:
+ Return True if IMS registered.
+ Return False if IMS not registered.
+ """
+ if not sub_id:
+ return ad.droid.telephonyIsImsRegistered()
+ else:
+ return change_voice_subid_temporarily(
+ ad, sub_id, ad.droid.telephonyIsImsRegistered)
+
+
+def wait_for_ims_registered(log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
+ """Wait for android device to register on ims.
+
+ Args:
+ log: log object.
+ ad: android device.
+ max_time: maximal wait time.
+
+ Returns:
+ Return True if device register ims successfully within max_time.
+ Return False if timeout.
+ """
+ return _wait_for_droid_in_state(log, ad, max_time, is_ims_registered)
+
+
+def is_volte_available(log, ad, sub_id=None):
+ """Return True if VoLTE is available.
+
+ Args:
+ log: log object.
+ ad: android device.
+ sub_id: Optional. If not assigned the default sub ID of voice call will
+ be used.
+
+ Returns:
+ Return True if VoLTE is available.
+ Return False if VoLTE is not available.
+ """
+ if not sub_id:
+ return ad.droid.telephonyIsVolteAvailable()
+ else:
+ return change_voice_subid_temporarily(
+ ad, sub_id, ad.droid.telephonyIsVolteAvailable)
+
+
+def is_volte_enabled(log, ad, sub_id=None):
+ """Return True if VoLTE feature bit is True.
+
+ Args:
+ log: log object.
+ ad: android device.
+ sub_id: Optional. If not assigned the default sub ID of voice call will
+ be used.
+
+ Returns:
+ Return True if VoLTE feature bit is True and IMS registered.
+ Return False if VoLTE feature bit is False or IMS not registered.
+ """
+ if not is_ims_registered(log, ad, sub_id):
+ ad.log.info("IMS is not registered for sub ID %s.", sub_id)
+ return False
+ if not is_volte_available(log, ad, sub_id):
+ ad.log.info("IMS is registered for sub ID %s, IsVolteCallingAvailable "
+ "is False", sub_id)
+ return False
+ else:
+ ad.log.info("IMS is registered for sub ID %s, IsVolteCallingAvailable "
+ "is True", sub_id)
+ return True
+
+
+def wait_for_volte_enabled(
+ log, ad, max_time=MAX_WAIT_TIME_VOLTE_ENABLED,sub_id=None):
+ """Wait for android device to report VoLTE enabled bit true.
+
+ Args:
+ log: log object.
+ ad: android device.
+ max_time: maximal wait time.
+
+ Returns:
+ Return True if device report VoLTE enabled bit true within max_time.
+ Return False if timeout.
+ """
+ if not sub_id:
+ return _wait_for_droid_in_state(log, ad, max_time, is_volte_enabled)
+ else:
+ return _wait_for_droid_in_state_for_subscription(
+ log, ad, sub_id, max_time, is_volte_enabled)
+
+
+def toggle_video_calling(log, ad, new_state=None):
+ """Toggle enable/disable Video calling for default voice subscription.
+
+ Args:
+ ad: Android device object.
+ new_state: Video mode state to set to.
+ True for enable, False for disable.
+ If None, opposite of the current state.
+
+ Raises:
+ TelImsUtilsError if platform does not support Video calling.
+ """
+ if not ad.droid.imsIsVtEnabledByPlatform():
+ if new_state is not False:
+ raise TelImsUtilsError("VT not supported by platform.")
+ # if the user sets VT false and it's unavailable we just let it go
+ return False
+
+ current_state = ad.droid.imsIsVtEnabledByUser()
+ if new_state is None:
+ new_state = not current_state
+ if new_state != current_state:
+ ad.droid.imsSetVtSetting(new_state)
+ return True
+
+
+def toggle_video_calling_for_subscription(ad, new_state=None, sub_id=None):
+ """Toggle enable/disable Video calling for subscription.
+
+ Args:
+ ad: Android device object.
+ new_state: Video mode state to set to.
+ True for enable, False for disable.
+ If None, opposite of the current state.
+ sub_id: subscription Id
+ """
+ try:
+ if sub_id is None:
+ sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
+ current_state = ad.droid.imsMmTelIsVtSettingEnabled(sub_id)
+ if new_state is None:
+ new_state = not current_state
+ if new_state != current_state:
+ ad.log.info("SubId %s - Toggle VT from %s to %s", sub_id,
+ current_state, new_state)
+ ad.droid.imsMmTelSetVtSettingEnabled(sub_id, new_state)
+ except Exception as e:
+ ad.log.error(e)
+ return False
+ return True
+
+
+def is_video_enabled(log, ad):
+ """Return True if Video Calling feature bit is True.
+
+ Args:
+ log: log object.
+ ad: android device.
+
+ Returns:
+ Return True if Video Calling feature bit is True and IMS registered.
+ Return False if Video Calling feature bit is False or IMS not registered.
+ """
+ video_status = ad.droid.telephonyIsVideoCallingAvailable()
+ if video_status is True and is_ims_registered(log, ad) is False:
+ ad.log.error(
+ "Error! Video Call is Available, but IMS is not registered.")
+ return False
+ return video_status
+
+
+def wait_for_video_enabled(log, ad, max_time=MAX_WAIT_TIME_VOLTE_ENABLED):
+ """Wait for android device to report Video Telephony enabled bit true.
+
+ Args:
+ log: log object.
+ ad: android device.
+ max_time: maximal wait time.
+
+ Returns:
+ Return True if device report Video Telephony enabled bit true within max_time.
+ Return False if timeout.
+ """
+ return _wait_for_droid_in_state(log, ad, max_time, is_video_enabled)
+
+
+def is_wfc_enabled(log, ad):
+ """Return True if WiFi Calling feature bit is True.
+
+ Args:
+ log: log object.
+ ad: android device.
+
+ Returns:
+ Return True if WiFi Calling feature bit is True and IMS registered.
+ Return False if WiFi Calling feature bit is False or IMS not registered.
+ """
+ if not is_ims_registered(log, ad):
+ ad.log.info("IMS is not registered.")
+ return False
+ if not ad.droid.telephonyIsWifiCallingAvailable():
+ ad.log.info("IMS is registered, IsWifiCallingAvailable is False")
+ return False
+ else:
+ ad.log.info("IMS is registered, IsWifiCallingAvailable is True")
+ return True
+
+
+def wait_for_wfc_enabled(log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
+ """Wait for android device to report WiFi Calling enabled bit true.
+
+ Args:
+ log: log object.
+ ad: android device.
+ max_time: maximal wait time.
+ Default value is MAX_WAIT_TIME_WFC_ENABLED.
+
+ Returns:
+ Return True if device report WiFi Calling enabled bit true within max_time.
+ Return False if timeout.
+ """
+ return _wait_for_droid_in_state(log, ad, max_time, is_wfc_enabled)
+
+
+def wait_for_wfc_disabled(log, ad, max_time=MAX_WAIT_TIME_WFC_DISABLED):
+ """Wait for android device to report WiFi Calling enabled bit false.
+
+ Args:
+ log: log object.
+ ad: android device.
+ max_time: maximal wait time.
+ Default value is MAX_WAIT_TIME_WFC_DISABLED.
+
+ Returns:
+ Return True if device report WiFi Calling enabled bit false within max_time.
+ Return False if timeout.
+ """
+ return _wait_for_droid_in_state(
+ log, ad, max_time, lambda log, ad: not is_wfc_enabled(log, ad))
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_logging_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_logging_utils.py
new file mode 100644
index 0000000..8ab69f6
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_logging_utils.py
@@ -0,0 +1,611 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+from datetime import datetime
+import os
+import re
+import shutil
+import time
+
+from acts import utils
+from acts.libs.proc import job
+from acts.controllers.android_device import DEFAULT_QXDM_LOG_PATH
+from acts.controllers.android_device import DEFAULT_SDM_LOG_PATH
+from acts.libs.utils.multithread import run_multithread_func
+from acts.utils import get_current_epoch_time
+from acts.utils import start_standing_subprocess
+
+
+_LS_MASK_NAME = "Lassen default + TCP"
+
+_LS_ENABLE_LOG_SHELL = f"""\
+am broadcast -n com.android.pixellogger/.receiver.AlwaysOnLoggingReceiver \
+ -a com.android.pixellogger.service.logging.LoggingService.ACTION_CONFIGURE_ALWAYS_ON_LOGGING \
+ -e intent_key_enable "true" -e intent_key_config "{_LS_MASK_NAME}" \
+ --ei intent_key_max_log_size_mb 100 --ei intent_key_max_number_of_files 100
+"""
+_LS_DISABLE_LOG_SHELL = """\
+am broadcast -n com.android.pixellogger/.receiver.AlwaysOnLoggingReceiver \
+ -a com.android.pixellogger.service.logging.LoggingService.ACTION_CONFIGURE_ALWAYS_ON_LOGGING \
+ -e intent_key_enable "false"
+"""
+
+
+def check_if_tensor_platform(ad):
+ """Check if current platform belongs to the Tensor platform
+
+ Args:
+ ad: Android object
+
+ Returns:
+ True if current platform belongs to the Tensor platform. Otherwise False.
+ """
+ result = ad.adb.getprop("ro.boot.hardware.platform")
+ if re.search('^gs', result, re.I):
+ return True
+ return False
+
+
+def start_pixellogger_always_on_logging(ad):
+ """Start always-on logging of Pixellogger for both Qualcomm and Tensor
+ platform.
+
+ Args:
+ ad: Android object
+
+ Returns:
+ True if the property is set correctly. Otherwise False.
+ """
+ setattr(ad, 'enable_always_on_modem_logger', True)
+ if check_if_tensor_platform(ad):
+ key = "persist.vendor.sys.modem.logging.enable"
+ else:
+ key = "persist.vendor.sys.modem.diag.mdlog"
+
+ if ad.adb.getprop(key) == "false":
+ ad.adb.shell("setprop persist.vendor.sys.modem.logging.enable true")
+ time.sleep(5)
+ if ad.adb.getprop(key) == "true":
+ return True
+ else:
+ return False
+ else:
+ return True
+
+
+def start_dsp_logger_p21(ad, retry=3):
+ """Start DSP logging for P21 devices.
+
+ Args:
+ ad: Android object.
+ retry: times of retry to enable DSP logger.
+
+ Returns:
+ True if DSP logger is enabled correctly. Otherwise False.
+ """
+ if not getattr(ad, "dsp_log_p21", False): return
+
+ def _is_dsp_enabled(ad):
+ return "00" in ad.adb.shell('am instrument -w -e request '
+ 'at+googgetnv=\\"\\!LTEL1\\.HAL\\.DSP\\ clkgating\\ Enb\\/Dis\\" '
+ '-e response wait "com.google.mdstest/com.google.mdstest.'
+ 'instrument.ModemATCommandInstrumentation"')
+
+ for _ in range(retry):
+ if not _is_dsp_enabled(ad):
+ ad.adb.shell('am instrument -w -e request at+googsetnv=\\"'
+ '\\!LTEL1\\.HAL\\.DSP\\ clkgating\\ Enb\\/Dis\\"\\,0\\,\\"'
+ '00\\" -e response wait "com.google.mdstest/com.google.mdstest.'
+ 'instrument.ModemATCommandInstrumentation"')
+ time.sleep(3)
+ else:
+ ad.log.info("DSP logger is enabled, reboot to start.")
+ ad.reboot()
+ return True
+ ad.log.warning("DSP logger enable failed")
+ return False
+
+
+def start_sdm_logger(ad):
+ """Start SDM logger."""
+ if not getattr(ad, "sdm_log", True): return
+
+ # Delete existing SDM logs which were created 15 mins prior
+ ad.sdm_log_path = DEFAULT_SDM_LOG_PATH
+ file_count = ad.adb.shell(
+ f"find {ad.sdm_log_path} -type f -iname sbuff_[0-9]*.sdm* | wc -l")
+ if int(file_count) > 3:
+ seconds = 15 * 60
+ # Remove sdm logs modified more than specified seconds ago
+ ad.adb.shell(
+ f"find {ad.sdm_log_path} -type f -iname sbuff_[0-9]*.sdm* "
+ f"-not -mtime -{seconds}s -delete")
+
+ # Disable modem logging already running
+ stop_sdm_logger(ad)
+
+ # start logging
+ ad.log.debug("start sdm logging")
+ while int(
+ ad.adb.shell(f"find {ad.sdm_log_path} -type f "
+ "-iname sbuff_profile.sdm | wc -l") == 0 or
+ int(
+ ad.adb.shell(f"find {ad.sdm_log_path} -type f "
+ "-iname sbuff_[0-9]*.sdm* | wc -l")) == 0):
+ ad.adb.shell(_LS_ENABLE_LOG_SHELL, ignore_status=True)
+ time.sleep(5)
+
+
+def stop_sdm_logger(ad):
+ """Stop SDM logger."""
+ ad.sdm_log_path = DEFAULT_SDM_LOG_PATH
+ cycle = 1
+
+ ad.log.debug("stop sdm logging")
+ while int(
+ ad.adb.shell(
+ f"find {ad.sdm_log_path} -type f -iname sbuff_profile.sdm -o "
+ "-iname sbuff_[0-9]*.sdm* | wc -l")) != 0:
+ if cycle == 1 and int(
+ ad.adb.shell(f"find {ad.sdm_log_path} -type f "
+ "-iname sbuff_profile.sdm | wc -l")) == 0:
+ ad.adb.shell(_LS_ENABLE_LOG_SHELL, ignore_status=True)
+ time.sleep(5)
+ ad.adb.shell(_LS_DISABLE_LOG_SHELL, ignore_status=True)
+ cycle += 1
+ time.sleep(15)
+
+
+def start_sdm_loggers(log, ads):
+ tasks = [(start_sdm_logger, [ad]) for ad in ads
+ if getattr(ad, "sdm_log", True)]
+ if tasks: run_multithread_func(log, tasks)
+
+
+def stop_sdm_loggers(log, ads):
+ tasks = [(stop_sdm_logger, [ad]) for ad in ads]
+ run_multithread_func(log, tasks)
+
+
+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/", "/vendor/etc/modem/"):
+ 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/"):
+ setattr(ad, "qxdm_log_path", DEFAULT_QXDM_LOG_PATH)
+ else:
+ setattr(ad, "qxdm_log_path", path)
+ return out.split("\n")[0]
+ for mask_file in ("/vendor/etc/mdlog/", "/vendor/etc/modem/"):
+ if mask in ad.adb.shell("ls %s" % mask_file, ignore_status=True):
+ setattr(ad, "qxdm_log_path", DEFAULT_QXDM_LOG_PATH)
+ return "%s/%s" % (mask_file, mask)
+ else:
+ out = ad.adb.shell("ls %s" % mask, ignore_status=True)
+ if out and "No such" not in out:
+ qxdm_log_path, cfg_name = os.path.split(mask)
+ setattr(ad, "qxdm_log_path", qxdm_log_path)
+ 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.
+
+ """
+ ## 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 90 -c" %
+ (mask_path, output_path))
+ return True
+
+
+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
+ current_time = get_current_epoch_time()
+ if getattr(ad, "qxdm_log_path", None):
+ seconds = None
+ file_count = ad.adb.shell(
+ "find %s -type f -iname *.qmdl | wc -l" % ad.qxdm_log_path)
+ if int(file_count) > 3:
+ if begin_time:
+ # if begin_time specified, delete old qxdm logs modified
+ # 10 minutes before begin time
+ seconds = int((current_time - begin_time) / 1000.0) + 10 * 60
+ else:
+ # if begin_time is not specified, delete old qxdm logs modified
+ # 15 minutes before current time
+ seconds = 15 * 60
+ if seconds:
+ # Remove qxdm logs modified more than specified seconds ago
+ ad.adb.shell(
+ "find %s -type f -iname *.qmdl -not -mtime -%ss -delete" %
+ (ad.qxdm_log_path, seconds))
+ ad.adb.shell(
+ "find %s -type f -iname *.xml -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 non-matching 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)
+ time.sleep(10)
+ else:
+ run_time = check_qxdm_logger_run_time(ad)
+ if run_time < 600:
+ # the last diag_mdlog started within 10 minutes ago
+ # no need to restart
+ return True
+ if ad.search_logcat(
+ "Diag_Lib: diag: In delete_log",
+ begin_time=current_time -
+ run_time) or not ad.get_file_names(
+ ad.qxdm_log_path,
+ begin_time=current_time - 600000,
+ match_string="*.qmdl"):
+ # diag_mdlog starts deleting files or no qmdl logs were
+ # modified in the past 10 minutes
+ ad.log.debug("Quit existing diag_mdlog and start a new one")
+ stop_qxdm_logger(ad)
+ ad.adb.shell_nb(ad.qxdm_logger_command)
+ time.sleep(10)
+ return True
+
+
+def disable_qxdm_logger(ad):
+ for prop in ("persist.sys.modem.diag.mdlog",
+ "persist.vendor.sys.modem.diag.mdlog",
+ "vendor.sys.modem.diag.mdlog_on"):
+ if ad.adb.getprop(prop):
+ ad.adb.shell("setprop %s false" % prop, ignore_status=True)
+ for apk in ("com.android.nexuslogger", "com.android.pixellogger"):
+ if ad.is_apk_installed(apk) and ad.is_apk_running(apk):
+ ad.force_stop_apk(apk)
+ stop_qxdm_logger(ad)
+ return True
+
+
+def check_qxdm_logger_run_time(ad):
+ output = ad.adb.shell("ps -eo etime,cmd | grep diag_mdlog")
+ result = re.search(r"(\d+):(\d+):(\d+) diag_mdlog", output)
+ if result:
+ return int(result.group(1)) * 60 * 60 + int(
+ result.group(2)) * 60 + int(result.group(3))
+ else:
+ result = re.search(r"(\d+):(\d+) diag_mdlog", output)
+ if result:
+ return int(result.group(1)) * 60 + int(result.group(2))
+ else:
+ return 0
+
+
+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 check_qxdm_logger_mask(ad, mask_file="QC_Default.cfg"):
+ """Check if QXDM logger always on is set.
+
+ Args:
+ ad: android device object.
+
+ """
+ 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
+ return True
+
+
+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 READ_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",):
+ ad.adb.shell("pm grant %s android.permission.%s_EXTERNAL_STORAGE" %
+ (qxdm_logger_apk, perm))
+ time.sleep(2)
+ for i in range(3):
+ ad.unlock_screen()
+ 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 start_tcpdumps(ads,
+ test_name="",
+ begin_time=None,
+ interface="any",
+ mask="all"):
+ for ad in ads:
+ try:
+ start_adb_tcpdump(
+ ad,
+ test_name=test_name,
+ begin_time=begin_time,
+ interface=interface,
+ mask=mask)
+ except Exception as e:
+ ad.log.warning("Fail to start tcpdump due to %s", e)
+
+
+def start_adb_tcpdump(ad,
+ test_name="",
+ begin_time=None,
+ interface="any",
+ mask="all"):
+ """Start tcpdump on any iface
+
+ Args:
+ ad: android device object.
+ test_name: tcpdump file name will have this
+
+ """
+ out = ad.adb.shell("ls -l /data/local/tmp/tcpdump/", ignore_status=True)
+ if "No such file" in out or not out:
+ ad.adb.shell("mkdir /data/local/tmp/tcpdump")
+ else:
+ ad.adb.shell(
+ "find /data/local/tmp/tcpdump -type f -not -mtime -1800s -delete",
+ ignore_status=True)
+ ad.adb.shell(
+ "find /data/local/tmp/tcpdump -type f -size +5G -delete",
+ ignore_status=True)
+
+ if not begin_time:
+ begin_time = get_current_epoch_time()
+
+ out = ad.adb.shell(
+ 'ifconfig | grep -v -E "r_|-rmnet" | grep -E "lan|data"',
+ ignore_status=True,
+ timeout=180)
+ intfs = re.findall(r"(\S+).*", out)
+ if interface and interface not in ("any", "all"):
+ if interface not in intfs: return
+ intfs = [interface]
+
+ out = ad.adb.shell("ps -ef | grep tcpdump")
+ cmds = []
+ for intf in intfs:
+ if intf in out:
+ ad.log.info("tcpdump on interface %s is already running", intf)
+ continue
+ else:
+ log_file_name = "/data/local/tmp/tcpdump/tcpdump_%s_%s_%s_%s.pcap" \
+ % (ad.serial, intf, test_name, begin_time)
+ if mask == "ims":
+ cmds.append(
+ "adb -s %s shell tcpdump -i %s -s0 -n -p udp port 500 or "
+ "udp port 4500 -w %s" % (ad.serial, intf, log_file_name))
+ else:
+ cmds.append("adb -s %s shell tcpdump -i %s -s0 -w %s" %
+ (ad.serial, intf, log_file_name))
+ if "Qualcomm" not in str(ad.adb.shell("getprop gsm.version.ril-impl")):
+ log_file_name = ("/data/local/tmp/tcpdump/tcpdump_%s_any_%s_%s.pcap"
+ % (ad.serial, test_name, begin_time))
+ cmds.append("adb -s %s shell nohup tcpdump -i any -s0 -w %s" %
+ (ad.serial, log_file_name))
+ for cmd in cmds:
+ ad.log.info(cmd)
+ try:
+ start_standing_subprocess(cmd, 10)
+ except Exception as e:
+ ad.log.error(e)
+ if cmds:
+ time.sleep(5)
+
+
+def stop_tcpdumps(ads):
+ for ad in ads:
+ stop_adb_tcpdump(ad)
+
+
+def stop_adb_tcpdump(ad, interface="any"):
+ """Stops tcpdump on any iface
+ Pulls the tcpdump file in the tcpdump dir
+
+ Args:
+ ad: android device object.
+
+ """
+ if interface == "any":
+ try:
+ ad.adb.shell("killall -9 tcpdump", ignore_status=True)
+ except Exception as e:
+ ad.log.error("Killing tcpdump with exception %s", e)
+ else:
+ out = ad.adb.shell("ps -ef | grep tcpdump | grep %s" % interface)
+ if "tcpdump -i" in out:
+ pids = re.findall(r"\S+\s+(\d+).*tcpdump -i", out)
+ for pid in pids:
+ ad.adb.shell("kill -9 %s" % pid)
+ ad.adb.shell(
+ "find /data/local/tmp/tcpdump -type f -not -mtime -1800s -delete",
+ ignore_status=True)
+
+
+def get_tcpdump_log(ad, test_name="", begin_time=None):
+ """Stops tcpdump on any iface
+ Pulls the tcpdump file in the tcpdump dir
+ Zips all tcpdump files
+
+ Args:
+ ad: android device object.
+ test_name: test case name
+ begin_time: test begin time
+ """
+ logs = ad.get_file_names("/data/local/tmp/tcpdump", begin_time=begin_time)
+ if logs:
+ ad.log.info("Pulling tcpdumps %s", logs)
+ log_path = os.path.join(
+ ad.device_log_path, "TCPDUMP_%s_%s" % (ad.model, ad.serial))
+ os.makedirs(log_path, exist_ok=True)
+ ad.pull_files(logs, log_path)
+ shutil.make_archive(log_path, "zip", log_path)
+ shutil.rmtree(log_path)
+ return True
+
+
+def wait_for_log(ad, pattern, begin_time=None, end_time=None, max_wait_time=120):
+ """Wait for logcat logs matching given pattern. This function searches in
+ logcat for strings matching given pattern by using search_logcat per second
+ until max_wait_time reaches.
+
+ Args:
+ ad: android device object
+ pattern: pattern to be searched in grep format
+ begin_time: only the lines in logcat with time stamps later than
+ begin_time will be searched.
+ end_time: only the lines in logcat with time stamps earlier than
+ end_time will be searched.
+ max_wait_time: timeout of this function
+
+ Returns:
+ All matched lines will be returned. If no line matches the given pattern
+ None will be returned.
+ """
+ start_time = datetime.now()
+ while True:
+ ad.log.info(
+ '====== Searching logcat for "%s" ====== ', pattern)
+ res = ad.search_logcat(
+ pattern, begin_time=begin_time, end_time=end_time)
+ if res:
+ return res
+ time.sleep(1)
+ stop_time = datetime.now()
+ passed_time = (stop_time - start_time).total_seconds()
+ if passed_time > max_wait_time:
+ return
+
+
+def extract_test_log(log, src_file, dst_file, test_tag):
+ os.makedirs(os.path.dirname(dst_file), exist_ok=True)
+ cmd = "grep -n '%s' %s" % (test_tag, src_file)
+ result = job.run(cmd, ignore_status=True)
+ if not result.stdout or result.exit_status == 1:
+ log.warning("Command %s returns %s", cmd, result)
+ return
+ line_nums = re.findall(r"(\d+).*", result.stdout)
+ if line_nums:
+ begin_line = int(line_nums[0])
+ end_line = int(line_nums[-1])
+ if end_line - begin_line <= 5:
+ result = job.run("wc -l < %s" % src_file)
+ if result.stdout:
+ end_line = int(result.stdout)
+ log.info("Extract %s from line %s to line %s to %s", src_file,
+ begin_line, end_line, dst_file)
+ job.run("awk 'NR >= %s && NR <= %s' %s > %s" % (begin_line, end_line,
+ src_file, dst_file))
+
+
+def log_screen_shot(ad, test_name=""):
+ file_name = "/sdcard/Pictures/screencap"
+ if test_name:
+ file_name = "%s_%s" % (file_name, test_name)
+ file_name = "%s_%s.png" % (file_name, utils.get_current_epoch_time())
+ try:
+ ad.adb.shell("screencap -p %s" % file_name)
+ except:
+ ad.log.error("Fail to log screen shot to %s", file_name)
+
+
+def get_screen_shot_log(ad, test_name="", begin_time=None):
+ logs = ad.get_file_names("/sdcard/Pictures", begin_time=begin_time)
+ if logs:
+ ad.log.info("Pulling %s", logs)
+ log_path = os.path.join(ad.device_log_path, "Screenshot_%s" % ad.serial)
+ os.makedirs(log_path, exist_ok=True)
+ ad.pull_files(logs, log_path)
+ ad.adb.shell("rm -rf /sdcard/Pictures/screencap_*", ignore_status=True)
+
+
+def get_screen_shot_logs(ads, test_name="", begin_time=None):
+ for ad in ads:
+ get_screen_shot_log(ad, test_name=test_name, begin_time=begin_time)
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_lookup_tables.py b/acts_tests/acts_contrib/test_utils/tel/tel_lookup_tables.py
index 247f65e..df3336b 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_lookup_tables.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_lookup_tables.py
@@ -158,7 +158,10 @@
"Ntt Docomo" : tel_defines.CARRIER_NTT_DOCOMO,
"KDDI" : tel_defines.CARRIER_KDDI,
"Rakuten": tel_defines.CARRIER_RAKUTEN,
- "SBM": tel_defines.CARRIER_SBM
+ "SBM": tel_defines.CARRIER_SBM,
+ "SK Telecom": tel_defines.CARRIER_SKT,
+ "KT": tel_defines.CARRIER_KT,
+ "LG U+": tel_defines.CARRIER_LG_UPLUS
}
operator_id_to_name = {
@@ -277,7 +280,40 @@
#Telstra (Australia)
'52501': tel_defines.CARRIER_SING,
- '50501': tel_defines.CARRIER_TSA
+ '50501': tel_defines.CARRIER_TSA,
+
+ #KT (South Korea)
+ '45002': tel_defines.CARRIER_KT,
+ '45004': tel_defines.CARRIER_KT,
+ '45008': tel_defines.CARRIER_KT,
+
+ #Softbank (Japan)
+ '44004': tel_defines.CARRIER_SBM,
+ '44006': tel_defines.CARRIER_SBM,
+ '44020': tel_defines.CARRIER_SBM,
+ '44040': tel_defines.CARRIER_SBM,
+ '44041': tel_defines.CARRIER_SBM,
+ '44042': tel_defines.CARRIER_SBM,
+ '44043': tel_defines.CARRIER_SBM,
+ '44044': tel_defines.CARRIER_SBM,
+ '44045': tel_defines.CARRIER_SBM,
+ '44046': tel_defines.CARRIER_SBM,
+ '44047': tel_defines.CARRIER_SBM,
+ '44048': tel_defines.CARRIER_SBM,
+ '44090': tel_defines.CARRIER_SBM,
+ '44092': tel_defines.CARRIER_SBM,
+ '44093': tel_defines.CARRIER_SBM,
+ '44094': tel_defines.CARRIER_SBM,
+ '44095': tel_defines.CARRIER_SBM,
+ '44096': tel_defines.CARRIER_SBM,
+ '44097': tel_defines.CARRIER_SBM,
+ '44098': tel_defines.CARRIER_SBM,
+
+ #SK Telecom (South Korea)
+ '45005': tel_defines.CARRIER_SKT,
+
+ #LG U+ (South Korea)
+ '45006': tel_defines.CARRIER_LG_UPLUS
}
technology_gen_tbl = [
@@ -624,7 +660,10 @@
tel_defines.CARRIER_ESP: default_umts_operator_network_tbl,
tel_defines.CARRIER_ORG: default_umts_operator_network_tbl,
tel_defines.CARRIER_TEL: default_umts_operator_network_tbl,
- tel_defines.CARRIER_TSA: default_umts_operator_network_tbl
+ tel_defines.CARRIER_TSA: default_umts_operator_network_tbl,
+ tel_defines.CARRIER_KT: default_umts_operator_network_tbl,
+ tel_defines.CARRIER_SKT: default_umts_operator_network_tbl,
+ tel_defines.CARRIER_LG_UPLUS: default_umts_operator_network_tbl
}
operator_network_tbl_by_phone_type = {
tel_defines.PHONE_TYPE_GSM: default_umts_operator_network_tbl,
@@ -653,7 +692,10 @@
tel_defines.CARRIER_VZW: cdma_allowable_network_preference_tbl,
tel_defines.CARRIER_SPT: cdma_allowable_network_preference_tbl,
tel_defines.CARRIER_EEUK: umts_allowable_network_preference_tbl,
- tel_defines.CARRIER_VFUK: umts_allowable_network_preference_tbl
+ tel_defines.CARRIER_VFUK: umts_allowable_network_preference_tbl,
+ tel_defines.CARRIER_KT: umts_allowable_network_preference_tbl,
+ tel_defines.CARRIER_SKT: umts_allowable_network_preference_tbl,
+ tel_defines.CARRIER_LG_UPLUS: umts_allowable_network_preference_tbl
}
allowable_network_preference_tbl_by_phone_type = {
tel_defines.PHONE_TYPE_GSM: umts_allowable_network_preference_tbl,
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_message_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_message_utils.py
new file mode 100644
index 0000000..21c418f
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_message_utils.py
@@ -0,0 +1,1839 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+import re
+import time
+from queue import Empty
+from acts import signals
+from acts.utils import rand_ascii_str
+from acts.libs.utils.multithread import multithread_func
+from acts.libs.utils.multithread import run_multithread_func
+from acts_contrib.test_utils.tel.tel_defines import EventCallStateChanged
+from acts_contrib.test_utils.tel.tel_defines import EventMmsSentFailure
+from acts_contrib.test_utils.tel.tel_defines import EventMmsSentSuccess
+from acts_contrib.test_utils.tel.tel_defines import EventMmsDownloaded
+from acts_contrib.test_utils.tel.tel_defines import EventSmsDeliverFailure
+from acts_contrib.test_utils.tel.tel_defines import EventSmsDeliverSuccess
+from acts_contrib.test_utils.tel.tel_defines import EventSmsReceived
+from acts_contrib.test_utils.tel.tel_defines import EventSmsSentFailure
+from acts_contrib.test_utils.tel.tel_defines import EventSmsSentSuccess
+from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_BACKGROUND
+from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_SENT_SUCCESS_IN_COLLISION
+from acts_contrib.test_utils.tel.tel_defines import SMS_OVER_WIFI_PROVIDERS
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
+from acts_contrib.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_on_rat
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_message_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_message
+from acts_contrib.test_utils.tel.tel_test_utils import CallResult
+from acts_contrib.test_utils.tel.tel_test_utils import TelResultWrapper
+from acts_contrib.test_utils.tel.tel_test_utils import check_phone_number_match
+from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import last_call_drop_reason
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_in_call_active
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_call_end
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_call_offhook_for_subscription
+from acts_contrib.test_utils.tel.tel_video_utils import is_phone_in_call_video_bidirectional
+from acts_contrib.test_utils.tel.tel_video_utils import video_call_setup_teardown
+from acts_contrib.test_utils.tel.tel_video_utils import phone_idle_video
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+
+
+def send_message_with_random_message_body(
+ log, ad_mo, ad_mt, msg_type='sms', long_msg=False, mms_expected_result=True):
+ """Test SMS/MMS between two phones.
+ Returns:
+ True if success.
+ False if failed.
+ """
+ message_lengths = (50, 160, 180)
+
+ if long_msg:
+ message_lengths = (800, 1600)
+ message_lengths_of_jp_carriers = (800, 1530)
+ sender_message_sub_id = get_outgoing_message_sub_id(ad_mo)
+ sender_mcc = ad_mo.telephony["subscription"][sender_message_sub_id]["mcc"]
+ if str(sender_mcc) in ["440", "441"]:
+ message_lengths = message_lengths_of_jp_carriers
+
+ if msg_type == 'sms':
+ for length in message_lengths:
+ message_array = [rand_ascii_str(length)]
+ if not sms_send_receive_verify(log, ad_mo, ad_mt, message_array):
+ ad_mo.log.error("SMS of length %s test failed", length)
+ return False
+ else:
+ ad_mo.log.info("SMS of length %s test succeeded", length)
+ log.info("SMS test of length %s characters succeeded.",
+ message_lengths)
+ elif msg_type == 'mms':
+ is_roaming = False
+ for ad in [ad_mo, ad_mt]:
+ ad.sms_over_wifi = False
+ # verizon supports sms over wifi. will add more carriers later
+ for sub in ad.telephony["subscription"].values():
+ if sub["operator"] in SMS_OVER_WIFI_PROVIDERS:
+ ad.sms_over_wifi = True
+
+ if getattr(ad, 'roaming', False):
+ is_roaming = True
+
+ if is_roaming:
+ # roaming device does not allow message of length 180
+ message_lengths = (50, 160)
+
+ for length in message_lengths:
+ message_array = [("Test Message", rand_ascii_str(length), None)]
+ result = True
+ if not mms_send_receive_verify(
+ log,
+ ad_mo,
+ ad_mt,
+ message_array,
+ expected_result=mms_expected_result):
+
+ if mms_expected_result is True:
+ if ad_mo.droid.telecomIsInCall() or ad_mt.droid.telecomIsInCall():
+ if not mms_receive_verify_after_call_hangup(
+ log, ad_mo, ad_mt, message_array):
+ result = False
+ else:
+ result = False
+
+ if not result:
+ log.error("MMS of body length %s test failed", length)
+ return False
+ else:
+ log.info("MMS of body length %s test succeeded", length)
+ log.info("MMS test of body lengths %s succeeded", message_lengths)
+ return True
+
+def message_test(
+ log,
+ ad_mo,
+ ad_mt,
+ mo_rat='general',
+ mt_rat='general',
+ msg_type='sms',
+ long_msg=False,
+ mms_expected_result=True,
+ msg_in_call=False,
+ video_or_voice='voice',
+ is_airplane_mode=False,
+ wfc_mode=None,
+ wifi_ssid=None,
+ wifi_pwd=None):
+
+ mo_phone_setup_argv = (
+ log, ad_mo, 'general', None, False, None, None, None, None, 'sms')
+ mt_phone_setup_argv = (
+ log, ad_mt, 'general', None, False, None, None, None, None, 'sms')
+ verify_caller_func = None
+ verify_callee_func = None
+
+ if mo_rat:
+ mo_phone_setup_argv = (
+ log,
+ ad_mo,
+ mo_rat,
+ None,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid,
+ wifi_pwd,
+ None,
+ 'sms')
+ verify_caller_func = is_phone_in_call_on_rat(
+ log, ad_mo, rat=mo_rat, only_return_fn=True)
+
+ if mt_rat:
+ mt_phone_setup_argv = (
+ log,
+ ad_mt,
+ mt_rat,
+ None,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid,
+ wifi_pwd,
+ None,
+ 'sms')
+ verify_callee_func = is_phone_in_call_on_rat(
+ log, ad_mo, rat=mt_rat, only_return_fn=True)
+
+ tasks = [(phone_setup_on_rat, mo_phone_setup_argv),
+ (phone_setup_on_rat, mt_phone_setup_argv)]
+ if not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+
+ if wifi_ssid:
+ if not wfc_mode or wfc_mode == WFC_MODE_DISABLED:
+ tasks = [(ensure_wifi_connected, (log, ad_mo, wifi_ssid, wifi_pwd)),
+ (ensure_wifi_connected, (log, ad_mt, wifi_ssid, wifi_pwd))]
+ if not multithread_func(log, tasks):
+ log.error("Failed to connected to Wi-Fi.")
+ return False
+
+ if msg_in_call:
+ if video_or_voice == 'voice':
+ if not call_setup_teardown(
+ log,
+ ad_mo,
+ ad_mt,
+ ad_hangup=None,
+ verify_caller_func=verify_caller_func,
+ verify_callee_func=verify_callee_func):
+ log.error("Failed to setup a voice call")
+ return False
+ elif video_or_voice == 'video':
+ tasks = [
+ (phone_idle_video, (log, ad_mo)),
+ (phone_idle_video, (log, ad_mt))]
+ if not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ return False
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ if not video_call_setup_teardown(
+ log,
+ ad_mo,
+ ad_mt,
+ None,
+ video_state=VT_STATE_BIDIRECTIONAL,
+ verify_caller_func=is_phone_in_call_video_bidirectional,
+ verify_callee_func=is_phone_in_call_video_bidirectional):
+ log.error("Failed to setup a video call")
+ return False
+
+ result = True
+ if not send_message_with_random_message_body(
+ log, ad_mo, ad_mt, msg_type, long_msg, mms_expected_result):
+ log.error("Test failed.")
+ result = False
+
+ if msg_in_call:
+ if not hangup_call(log, ad_mo):
+ ad_mo.log.info("Failed to hang up call!")
+ result = False
+
+ return result
+
+def sms_send_receive_verify(log,
+ ad_tx,
+ ad_rx,
+ array_message,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
+ expected_result=True,
+ slot_id_rx=None):
+ """Send SMS, receive SMS, and verify content and sender's number.
+
+ Send (several) SMS from droid_tx to droid_rx.
+ Verify SMS is sent, delivered and received.
+ Verify received content and sender's number are correct.
+
+ Args:
+ log: Log object.
+ ad_tx: Sender's Android Device Object
+ ad_rx: Receiver's Android Device Object
+ array_message: the array of message to send/receive
+ slot_id_rx: the slot on the Receiver's android device (0/1)
+ """
+ subid_tx = get_outgoing_message_sub_id(ad_tx)
+ if slot_id_rx is None:
+ subid_rx = get_incoming_message_sub_id(ad_rx)
+ else:
+ subid_rx = get_subid_from_slot_index(log, ad_rx, slot_id_rx)
+
+ result = sms_send_receive_verify_for_subscription(
+ log, ad_tx, ad_rx, subid_tx, subid_rx, array_message, max_wait_time)
+ if result != expected_result:
+ log_messaging_screen_shot(ad_tx, test_name="sms_tx")
+ log_messaging_screen_shot(ad_rx, test_name="sms_rx")
+ return result == expected_result
+
+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.
+ Verify SMS is sent, delivered and received.
+ Verify received content and sender's number are correct.
+
+ Args:
+ log: Log object.
+ ad_tx: Sender's Android Device Object..
+ ad_rx: Receiver's Android Device Object.
+ subid_tx: Sender's subscription ID to be used for SMS
+ subid_rx: Receiver's subscription ID to be used for SMS
+ array_message: the array of message to send/receive
+ """
+ phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
+ phonenumber_rx = ad_rx.telephony['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()
+ else:
+ ad.messaging_ed.clear_all_events()
+ ad.messaging_droid.logI(
+ "Start sms_send_receive_verify_for_subscription test")
+ except Exception:
+ ad.log.info("Create new sl4a session for messaging")
+ ad.messaging_droid, ad.messaging_ed = ad.get_droid()
+ ad.messaging_ed.start()
+
+ for text in array_message:
+ length = len(text)
+ ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
+ phonenumber_tx, phonenumber_rx, length, text)
+ try:
+ ad_rx.messaging_ed.clear_events(EventSmsReceived)
+ ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
+ ad_tx.messaging_ed.clear_events(EventSmsSentFailure)
+ ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
+ time.sleep(1) #sleep 100ms after starting event tracking
+ ad_tx.messaging_droid.logI("Sending SMS of length %s" % length)
+ ad_rx.messaging_droid.logI("Expecting SMS of length %s" % length)
+ ad_tx.messaging_droid.smsSendTextMessage(phonenumber_rx, text,
+ True)
+ try:
+ events = ad_tx.messaging_ed.pop_events(
+ "(%s|%s|%s|%s)" %
+ (EventSmsSentSuccess, EventSmsSentFailure,
+ EventSmsDeliverSuccess,
+ EventSmsDeliverFailure), max_wait_time)
+ for event in events:
+ ad_tx.log.info("Got event %s", event["name"])
+ if event["name"] == EventSmsSentFailure or event["name"] == EventSmsDeliverFailure:
+ if event.get("data") and event["data"].get("Reason"):
+ ad_tx.log.error("%s with reason: %s",
+ event["name"],
+ event["data"]["Reason"])
+ return False
+ elif event["name"] == EventSmsSentSuccess or event["name"] == EventSmsDeliverSuccess:
+ break
+ except Empty:
+ ad_tx.log.error("No %s or %s event for SMS of length %s.",
+ EventSmsSentSuccess, EventSmsSentFailure,
+ length)
+ return False
+
+ if not wait_for_matching_sms(
+ log,
+ ad_rx,
+ phonenumber_tx,
+ text,
+ max_wait_time,
+ allow_multi_part_long_sms=True):
+ 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.messaging_droid.smsStopTrackingIncomingSmsMessage()
+ return True
+
+def sms_in_collision_send_receive_verify(
+ log,
+ ad_rx,
+ ad_rx2,
+ ad_tx,
+ ad_tx2,
+ array_message,
+ array_message2,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
+ """Send 2 SMS', receive both SMS', and verify content and sender's number of
+ each SMS.
+
+ Send 2 SMS'. One from ad_tx to ad_rx and the other from ad_tx2 to ad_rx2.
+ When ad_rx is identical to ad_rx2, the scenario of SMS' in collision can
+ be tested.
+ Verify both SMS' are sent, delivered and received.
+ Verify received content and sender's number of each SMS is correct.
+
+ Args:
+ log: Log object.
+ ad_tx: Sender's Android Device Object..
+ ad_rx: Receiver's Android Device Object.
+ ad_tx2: 2nd sender's Android Device Object..
+ ad_rx2: 2nd receiver's Android Device Object.
+ array_message: the array of message to send/receive from ad_tx to ad_rx
+ array_message2: the array of message to send/receive from ad_tx2 to
+ ad_rx2
+ max_wait_time: Max time to wait for reception of SMS
+ """
+ rx_sub_id = get_outgoing_message_sub_id(ad_rx)
+ rx2_sub_id = get_outgoing_message_sub_id(ad_rx2)
+
+ _, tx_sub_id, _ = get_subid_on_same_network_of_host_ad(
+ [ad_rx, ad_tx, ad_tx2],
+ host_sub_id=rx_sub_id)
+ set_subid_for_message(ad_tx, tx_sub_id)
+
+ _, _, tx2_sub_id = get_subid_on_same_network_of_host_ad(
+ [ad_rx2, ad_tx, ad_tx2],
+ host_sub_id=rx2_sub_id)
+ set_subid_for_message(ad_tx2, tx2_sub_id)
+
+ if not sms_in_collision_send_receive_verify_for_subscription(
+ log,
+ ad_tx,
+ ad_tx2,
+ ad_rx,
+ ad_rx2,
+ tx_sub_id,
+ tx2_sub_id,
+ rx_sub_id,
+ rx_sub_id,
+ array_message,
+ array_message2,
+ max_wait_time):
+ log_messaging_screen_shot(
+ ad_rx, test_name="sms rx subid: %s" % rx_sub_id)
+ log_messaging_screen_shot(
+ ad_rx2, test_name="sms rx2 subid: %s" % rx2_sub_id)
+ log_messaging_screen_shot(
+ ad_tx, test_name="sms tx subid: %s" % tx_sub_id)
+ log_messaging_screen_shot(
+ ad_tx2, test_name="sms tx subid: %s" % tx2_sub_id)
+ return False
+ return True
+
+def sms_in_collision_send_receive_verify_for_subscription(
+ log,
+ ad_tx,
+ ad_tx2,
+ ad_rx,
+ ad_rx2,
+ subid_tx,
+ subid_tx2,
+ subid_rx,
+ subid_rx2,
+ array_message,
+ array_message2,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
+ """Send 2 SMS', receive both SMS', and verify content and sender's number of
+ each SMS.
+
+ Send 2 SMS'. One from ad_tx to ad_rx and the other from ad_tx2 to ad_rx2.
+ When ad_rx is identical to ad_rx2, the scenario of SMS' in collision can
+ be tested.
+ Verify both SMS' are sent, delivered and received.
+ Verify received content and sender's number of each SMS is correct.
+
+ Args:
+ log: Log object.
+ ad_tx: Sender's Android Device Object..
+ ad_rx: Receiver's Android Device Object.
+ ad_tx2: 2nd sender's Android Device Object..
+ ad_rx2: 2nd receiver's Android Device Object.
+ subid_tx: Sub ID of ad_tx as default Sub ID for outgoing SMS
+ subid_tx2: Sub ID of ad_tx2 as default Sub ID for outgoing SMS
+ subid_rx: Sub ID of ad_rx as default Sub ID for incoming SMS
+ subid_rx2: Sub ID of ad_rx2 as default Sub ID for incoming SMS
+ array_message: the array of message to send/receive from ad_tx to ad_rx
+ array_message2: the array of message to send/receive from ad_tx2 to
+ ad_rx2
+ max_wait_time: Max time to wait for reception of SMS
+ """
+
+ phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
+ phonenumber_tx2 = ad_tx2.telephony['subscription'][subid_tx2]['phone_num']
+ phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
+ phonenumber_rx2 = ad_rx2.telephony['subscription'][subid_rx2]['phone_num']
+
+ for ad in (ad_tx, ad_tx2, ad_rx, ad_rx2):
+ ad.send_keycode("BACK")
+ 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()
+ else:
+ ad.messaging_ed.clear_all_events()
+ ad.messaging_droid.logI(
+ "Start sms_send_receive_verify_for_subscription test")
+ except Exception:
+ ad.log.info("Create new sl4a session for messaging")
+ ad.messaging_droid, ad.messaging_ed = ad.get_droid()
+ ad.messaging_ed.start()
+
+ for text, text2 in zip(array_message, array_message2):
+ length = len(text)
+ length2 = len(text2)
+ ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
+ phonenumber_tx, phonenumber_rx, length, text)
+ ad_tx2.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
+ phonenumber_tx2, phonenumber_rx2, length2, text2)
+
+ try:
+ ad_rx.messaging_ed.clear_events(EventSmsReceived)
+ ad_rx2.messaging_ed.clear_events(EventSmsReceived)
+ ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
+ ad_tx.messaging_ed.clear_events(EventSmsSentFailure)
+ ad_tx2.messaging_ed.clear_events(EventSmsSentSuccess)
+ ad_tx2.messaging_ed.clear_events(EventSmsSentFailure)
+ ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
+ if ad_rx2 != ad_rx:
+ ad_rx2.messaging_droid.smsStartTrackingIncomingSmsMessage()
+ time.sleep(1)
+ ad_tx.messaging_droid.logI("Sending SMS of length %s" % length)
+ ad_tx2.messaging_droid.logI("Sending SMS of length %s" % length2)
+ ad_rx.messaging_droid.logI(
+ "Expecting SMS of length %s from %s" % (length, ad_tx.serial))
+ ad_rx2.messaging_droid.logI(
+ "Expecting SMS of length %s from %s" % (length2, ad_tx2.serial))
+
+ tasks = [
+ (ad_tx.messaging_droid.smsSendTextMessage,
+ (phonenumber_rx, text, True)),
+ (ad_tx2.messaging_droid.smsSendTextMessage,
+ (phonenumber_rx2, text2, True))]
+ multithread_func(log, tasks)
+ try:
+ tasks = [
+ (ad_tx.messaging_ed.pop_events, ("(%s|%s|%s|%s)" % (
+ EventSmsSentSuccess,
+ EventSmsSentFailure,
+ EventSmsDeliverSuccess,
+ EventSmsDeliverFailure), max_wait_time)),
+ (ad_tx2.messaging_ed.pop_events, ("(%s|%s|%s|%s)" % (
+ EventSmsSentSuccess,
+ EventSmsSentFailure,
+ EventSmsDeliverSuccess,
+ EventSmsDeliverFailure), max_wait_time))
+ ]
+ results = run_multithread_func(log, tasks)
+ res = True
+ _ad = ad_tx
+ for ad, events in [(ad_tx, results[0]),(ad_tx2, results[1])]:
+ _ad = ad
+ for event in events:
+ ad.log.info("Got event %s", event["name"])
+ if event["name"] == EventSmsSentFailure or \
+ event["name"] == EventSmsDeliverFailure:
+ if event.get("data") and event["data"].get("Reason"):
+ ad.log.error("%s with reason: %s",
+ event["name"],
+ event["data"]["Reason"])
+ res = False
+ elif event["name"] == EventSmsSentSuccess or \
+ event["name"] == EventSmsDeliverSuccess:
+ break
+ if not res:
+ return False
+ except Empty:
+ _ad.log.error("No %s or %s event for SMS of length %s.",
+ EventSmsSentSuccess, EventSmsSentFailure,
+ length)
+ return False
+ if ad_rx == ad_rx2:
+ if not wait_for_matching_mt_sms_in_collision(
+ log,
+ ad_rx,
+ phonenumber_tx,
+ phonenumber_tx2,
+ text,
+ text2,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
+
+ ad_rx.log.error(
+ "No matching received SMS of length %s from %s.",
+ length,
+ ad_rx.serial)
+ return False
+ else:
+ if not wait_for_matching_mt_sms_in_collision_with_mo_sms(
+ log,
+ ad_rx,
+ ad_rx2,
+ phonenumber_tx,
+ phonenumber_tx2,
+ text,
+ text2,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
+ return False
+ except Exception as e:
+ log.error("Exception error %s", e)
+ raise
+ finally:
+ ad_rx.messaging_droid.smsStopTrackingIncomingSmsMessage()
+ ad_rx2.messaging_droid.smsStopTrackingIncomingSmsMessage()
+ return True
+
+def sms_rx_power_off_multiple_send_receive_verify(
+ log,
+ ad_rx,
+ ad_tx,
+ ad_tx2,
+ array_message_length,
+ array_message2_length,
+ num_array_message,
+ num_array_message2,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
+
+ rx_sub_id = get_outgoing_message_sub_id(ad_rx)
+
+ _, tx_sub_id, _ = get_subid_on_same_network_of_host_ad(
+ [ad_rx, ad_tx, ad_tx2],
+ host_sub_id=rx_sub_id)
+ set_subid_for_message(ad_tx, tx_sub_id)
+
+ _, _, tx2_sub_id = get_subid_on_same_network_of_host_ad(
+ [ad_rx, ad_tx, ad_tx2],
+ host_sub_id=rx_sub_id)
+ set_subid_for_message(ad_tx2, tx2_sub_id)
+
+ if not sms_rx_power_off_multiple_send_receive_verify_for_subscription(
+ log,
+ ad_tx,
+ ad_tx2,
+ ad_rx,
+ tx_sub_id,
+ tx2_sub_id,
+ rx_sub_id,
+ rx_sub_id,
+ array_message_length,
+ array_message2_length,
+ num_array_message,
+ num_array_message2):
+ log_messaging_screen_shot(
+ ad_rx, test_name="sms rx subid: %s" % rx_sub_id)
+ log_messaging_screen_shot(
+ ad_tx, test_name="sms tx subid: %s" % tx_sub_id)
+ log_messaging_screen_shot(
+ ad_tx2, test_name="sms tx subid: %s" % tx2_sub_id)
+ return False
+ return True
+
+def sms_rx_power_off_multiple_send_receive_verify_for_subscription(
+ log,
+ ad_tx,
+ ad_tx2,
+ ad_rx,
+ subid_tx,
+ subid_tx2,
+ subid_rx,
+ subid_rx2,
+ array_message_length,
+ array_message2_length,
+ num_array_message,
+ num_array_message2,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
+
+ phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
+ phonenumber_tx2 = ad_tx2.telephony['subscription'][subid_tx2]['phone_num']
+ phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
+ phonenumber_rx2 = ad_rx.telephony['subscription'][subid_rx2]['phone_num']
+
+ if not toggle_airplane_mode(log, ad_rx, True):
+ ad_rx.log.error("Failed to enable Airplane Mode")
+ return False
+ ad_rx.stop_services()
+ ad_rx.log.info("Rebooting......")
+ ad_rx.adb.reboot()
+
+ message_dict = {phonenumber_tx: [], phonenumber_tx2: []}
+ for index in range(max(num_array_message, num_array_message2)):
+ array_message = [rand_ascii_str(array_message_length)]
+ array_message2 = [rand_ascii_str(array_message2_length)]
+ for text, text2 in zip(array_message, array_message2):
+ message_dict[phonenumber_tx].append(text)
+ message_dict[phonenumber_tx2].append(text2)
+ length = len(text)
+ length2 = len(text2)
+
+ ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
+ phonenumber_tx, phonenumber_rx, length, text)
+ ad_tx2.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
+ phonenumber_tx2, phonenumber_rx2, length2, text2)
+
+ try:
+ for ad in (ad_tx, ad_tx2):
+ ad.send_keycode("BACK")
+ 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()
+ else:
+ ad.messaging_ed.clear_all_events()
+ ad.messaging_droid.logI(
+ "Start sms_send_receive_verify_for_subscription"
+ " test")
+ except Exception:
+ ad.log.info("Create new sl4a session for messaging")
+ ad.messaging_droid, ad.messaging_ed = ad.get_droid()
+ ad.messaging_ed.start()
+
+ ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
+ ad_tx.messaging_ed.clear_events(EventSmsSentFailure)
+ ad_tx2.messaging_ed.clear_events(EventSmsSentSuccess)
+ ad_tx2.messaging_ed.clear_events(EventSmsSentFailure)
+
+ if index < num_array_message and index < num_array_message2:
+ ad_tx.messaging_droid.logI(
+ "Sending SMS of length %s" % length)
+ ad_tx2.messaging_droid.logI(
+ "Sending SMS of length %s" % length2)
+ tasks = [
+ (ad_tx.messaging_droid.smsSendTextMessage,
+ (phonenumber_rx, text, True)),
+ (ad_tx2.messaging_droid.smsSendTextMessage,
+ (phonenumber_rx2, text2, True))]
+ multithread_func(log, tasks)
+ else:
+ if index < num_array_message:
+ ad_tx.messaging_droid.logI(
+ "Sending SMS of length %s" % length)
+ ad_tx.messaging_droid.smsSendTextMessage(
+ phonenumber_rx, text, True)
+ if index < num_array_message2:
+ ad_tx2.messaging_droid.logI(
+ "Sending SMS of length %s" % length2)
+ ad_tx2.messaging_droid.smsSendTextMessage(
+ phonenumber_rx2, text2, True)
+
+ try:
+ if index < num_array_message and index < num_array_message2:
+ tasks = [
+ (ad_tx.messaging_ed.pop_events, ("(%s|%s|%s|%s)" % (
+ EventSmsSentSuccess,
+ EventSmsSentFailure,
+ EventSmsDeliverSuccess,
+ EventSmsDeliverFailure),
+ max_wait_time)),
+ (ad_tx2.messaging_ed.pop_events, ("(%s|%s|%s|%s)" % (
+ EventSmsSentSuccess,
+ EventSmsSentFailure,
+ EventSmsDeliverSuccess,
+ EventSmsDeliverFailure),
+ max_wait_time))
+ ]
+ results = run_multithread_func(log, tasks)
+ res = True
+ _ad = ad_tx
+ for ad, events in [
+ (ad_tx, results[0]), (ad_tx2, results[1])]:
+ _ad = ad
+ for event in events:
+ ad.log.info("Got event %s", event["name"])
+ if event["name"] == EventSmsSentFailure or \
+ event["name"] == EventSmsDeliverFailure:
+ if event.get("data") and \
+ event["data"].get("Reason"):
+ ad.log.error("%s with reason: %s",
+ event["name"],
+ event["data"]["Reason"])
+ res = False
+ elif event["name"] == EventSmsSentSuccess or \
+ event["name"] == EventSmsDeliverSuccess:
+ break
+ if not res:
+ return False
+ else:
+ if index < num_array_message:
+ result = ad_tx.messaging_ed.pop_events(
+ "(%s|%s|%s|%s)" % (
+ EventSmsSentSuccess,
+ EventSmsSentFailure,
+ EventSmsDeliverSuccess,
+ EventSmsDeliverFailure),
+ max_wait_time)
+ res = True
+ _ad = ad_tx
+ for ad, events in [(ad_tx, result)]:
+ _ad = ad
+ for event in events:
+ ad.log.info("Got event %s", event["name"])
+ if event["name"] == EventSmsSentFailure or \
+ event["name"] == EventSmsDeliverFailure:
+ if event.get("data") and \
+ event["data"].get("Reason"):
+ ad.log.error(
+ "%s with reason: %s",
+ event["name"],
+ event["data"]["Reason"])
+ res = False
+ elif event["name"] == EventSmsSentSuccess \
+ or event["name"] == EventSmsDeliverSuccess:
+ break
+ if not res:
+ return False
+ if index < num_array_message2:
+ result = ad_tx2.messaging_ed.pop_events(
+ "(%s|%s|%s|%s)" % (
+ EventSmsSentSuccess,
+ EventSmsSentFailure,
+ EventSmsDeliverSuccess,
+ EventSmsDeliverFailure),
+ max_wait_time)
+ res = True
+ _ad = ad_tx2
+ for ad, events in [(ad_tx2, result)]:
+ _ad = ad
+ for event in events:
+ ad.log.info("Got event %s", event["name"])
+ if event["name"] == EventSmsSentFailure or \
+ event["name"] == EventSmsDeliverFailure:
+ if event.get("data") and \
+ event["data"].get("Reason"):
+ ad.log.error(
+ "%s with reason: %s",
+ event["name"],
+ event["data"]["Reason"])
+ res = False
+ elif event["name"] == EventSmsSentSuccess \
+ or event["name"] == EventSmsDeliverSuccess:
+ break
+ if not res:
+ return False
+
+
+ except Empty:
+ _ad.log.error("No %s or %s event for SMS of length %s.",
+ EventSmsSentSuccess, EventSmsSentFailure,
+ length)
+ return False
+
+ except Exception as e:
+ log.error("Exception error %s", e)
+ raise
+
+ ad_rx.wait_for_boot_completion()
+ ad_rx.root_adb()
+ ad_rx.start_services(skip_setup_wizard=False)
+
+ output = ad_rx.adb.logcat("-t 1")
+ match = re.search(r"\d+-\d+\s\d+:\d+:\d+.\d+", output)
+ if match:
+ ad_rx.test_log_begin_time = match.group(0)
+
+ ad_rx.messaging_droid, ad_rx.messaging_ed = ad_rx.get_droid()
+ ad_rx.messaging_ed.start()
+ ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
+ time.sleep(1) #sleep 100ms after starting event tracking
+
+ if not toggle_airplane_mode(log, ad_rx, False):
+ ad_rx.log.error("Failed to disable Airplane Mode")
+ return False
+
+ res = True
+ try:
+ if not wait_for_matching_multiple_sms(log,
+ ad_rx,
+ phonenumber_tx,
+ phonenumber_tx2,
+ messages=message_dict,
+ max_wait_time=max_wait_time):
+ res = False
+ except Exception as e:
+ log.error("Exception error %s", e)
+ raise
+ finally:
+ ad_rx.messaging_droid.smsStopTrackingIncomingSmsMessage()
+
+ return res
+
+def is_sms_match(event, phonenumber_tx, text):
+ """Return True if 'text' equals to event['data']['Text']
+ and phone number match.
+
+ Args:
+ event: Event object to verify.
+ phonenumber_tx: phone number for sender.
+ text: text string to verify.
+
+ Returns:
+ 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'].strip() == text)
+
+def is_sms_partial_match(event, phonenumber_tx, text):
+ """Return True if 'text' starts with event['data']['Text']
+ and phone number match.
+
+ Args:
+ event: Event object to verify.
+ phonenumber_tx: phone number for sender.
+ text: text string to verify.
+
+ Returns:
+ Return True if 'text' starts with event['data']['Text']
+ and phone number match.
+ """
+ event_text = event['data']['Text'].strip()
+ if event_text.startswith("("):
+ event_text = event_text.split(")")[-1]
+ return (check_phone_number_match(event['data']['Sender'], phonenumber_tx)
+ and text.startswith(event_text))
+
+def is_sms_in_collision_match(
+ event, phonenumber_tx, phonenumber_tx2, text, text2):
+ event_text = event['data']['Text'].strip()
+ if event_text.startswith("("):
+ event_text = event_text.split(")")[-1]
+
+ for phonenumber, txt in [[phonenumber_tx, text], [phonenumber_tx2, text2]]:
+ if check_phone_number_match(
+ event['data']['Sender'], phonenumber) and txt.startswith(event_text):
+ return True
+ return False
+
+def is_sms_in_collision_partial_match(
+ event, phonenumber_tx, phonenumber_tx2, text, text2):
+ for phonenumber, txt in [[phonenumber_tx, text], [phonenumber_tx2, text2]]:
+ if check_phone_number_match(
+ event['data']['Sender'], phonenumber) and \
+ event['data']['Text'].strip() == txt:
+ return True
+ return False
+
+def is_sms_match_among_multiple_sms(
+ event, phonenumber_tx, phonenumber_tx2, texts=[], texts2=[]):
+ for txt in texts:
+ if check_phone_number_match(
+ event['data']['Sender'], phonenumber_tx) and \
+ event['data']['Text'].strip() == txt:
+ return True
+
+ for txt in texts2:
+ if check_phone_number_match(
+ event['data']['Sender'], phonenumber_tx2) and \
+ event['data']['Text'].strip() == txt:
+ return True
+
+ return False
+
+def is_sms_partial_match_among_multiple_sms(
+ event, phonenumber_tx, phonenumber_tx2, texts=[], texts2=[]):
+ event_text = event['data']['Text'].strip()
+ if event_text.startswith("("):
+ event_text = event_text.split(")")[-1]
+
+ for txt in texts:
+ if check_phone_number_match(
+ event['data']['Sender'], phonenumber_tx) and \
+ txt.startswith(event_text):
+ return True
+
+ for txt in texts2:
+ if check_phone_number_match(
+ event['data']['Sender'], phonenumber_tx2) and \
+ txt.startswith(event_text):
+ return True
+
+ return False
+
+def wait_for_matching_sms(log,
+ ad_rx,
+ phonenumber_tx,
+ text,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
+ allow_multi_part_long_sms=True):
+ """Wait for matching incoming SMS.
+
+ Args:
+ log: Log object.
+ ad_rx: Receiver's Android Device Object
+ phonenumber_tx: Sender's phone number.
+ text: SMS content string.
+ allow_multi_part_long_sms: is long SMS allowed to be received as
+ multiple short SMS. This is optional, default value is True.
+
+ Returns:
+ True if matching incoming SMS is received.
+ """
+ if not allow_multi_part_long_sms:
+ try:
+ ad_rx.messaging_ed.wait_for_event(EventSmsReceived, is_sms_match,
+ max_wait_time, phonenumber_tx,
+ text)
+ ad_rx.log.info("Got event %s", EventSmsReceived)
+ return True
+ except Empty:
+ ad_rx.log.error("No matched SMS received event.")
+ return False
+ else:
+ try:
+ received_sms = ''
+ remaining_text = text
+ while (remaining_text != ''):
+ event = ad_rx.messaging_ed.wait_for_event(
+ EventSmsReceived, is_sms_partial_match, max_wait_time,
+ phonenumber_tx, remaining_text)
+ event_text = event['data']['Text'].split(")")[-1].strip()
+ event_text_length = len(event_text)
+ ad_rx.log.info("Got event %s of text length %s from %s",
+ EventSmsReceived, event_text_length,
+ phonenumber_tx)
+ remaining_text = remaining_text[event_text_length:]
+ received_sms += event_text
+ ad_rx.log.info("Received SMS of length %s", len(received_sms))
+ return True
+ except Empty:
+ ad_rx.log.error(
+ "Missing SMS received event of text length %s from %s",
+ len(remaining_text), phonenumber_tx)
+ if received_sms != '':
+ ad_rx.log.error(
+ "Only received partial matched SMS of length %s",
+ len(received_sms))
+ return False
+
+def wait_for_matching_mt_sms_in_collision(log,
+ ad_rx,
+ phonenumber_tx,
+ phonenumber_tx2,
+ text,
+ text2,
+ allow_multi_part_long_sms=True,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
+
+ if not allow_multi_part_long_sms:
+ try:
+ ad_rx.messaging_ed.wait_for_event(
+ EventSmsReceived,
+ is_sms_in_collision_match,
+ max_wait_time,
+ phonenumber_tx,
+ phonenumber_tx2,
+ text,
+ text2)
+ ad_rx.log.info("Got event %s", EventSmsReceived)
+ return True
+ except Empty:
+ ad_rx.log.error("No matched SMS received event.")
+ return False
+ else:
+ try:
+ received_sms = ''
+ received_sms2 = ''
+ remaining_text = text
+ remaining_text2 = text2
+ while (remaining_text != '' or remaining_text2 != ''):
+ event = ad_rx.messaging_ed.wait_for_event(
+ EventSmsReceived,
+ is_sms_in_collision_partial_match,
+ max_wait_time,
+ phonenumber_tx,
+ phonenumber_tx2,
+ remaining_text,
+ remaining_text2)
+ event_text = event['data']['Text'].split(")")[-1].strip()
+ event_text_length = len(event_text)
+
+ if event_text in remaining_text:
+ ad_rx.log.info("Got event %s of text length %s from %s",
+ EventSmsReceived, event_text_length,
+ phonenumber_tx)
+ remaining_text = remaining_text[event_text_length:]
+ received_sms += event_text
+ elif event_text in remaining_text2:
+ ad_rx.log.info("Got event %s of text length %s from %s",
+ EventSmsReceived, event_text_length,
+ phonenumber_tx2)
+ remaining_text2 = remaining_text2[event_text_length:]
+ received_sms2 += event_text
+
+ ad_rx.log.info("Received SMS of length %s", len(received_sms))
+ ad_rx.log.info("Received SMS of length %s", len(received_sms2))
+ return True
+ except Empty:
+ ad_rx.log.error(
+ "Missing SMS received event.")
+ if received_sms != '':
+ ad_rx.log.error(
+ "Only received partial matched SMS of length %s from %s",
+ len(received_sms), phonenumber_tx)
+ if received_sms2 != '':
+ ad_rx.log.error(
+ "Only received partial matched SMS of length %s from %s",
+ len(received_sms2), phonenumber_tx2)
+ return False
+
+def wait_for_matching_mt_sms_in_collision_with_mo_sms(log,
+ ad_rx,
+ ad_rx2,
+ phonenumber_tx,
+ phonenumber_tx2,
+ text,
+ text2,
+ allow_multi_part_long_sms=True,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
+
+ if not allow_multi_part_long_sms:
+ result = True
+ try:
+ ad_rx.messaging_ed.wait_for_call_offhook_event(
+ EventSmsReceived,
+ is_sms_match,
+ max_wait_time,
+ phonenumber_tx,
+ text)
+ ad_rx.log.info("Got event %s", EventSmsReceived)
+ except Empty:
+ ad_rx.log.error("No matched SMS received event.")
+ result = False
+
+ try:
+ ad_rx2.messaging_ed.wait_for_call_offhook_event(
+ EventSmsReceived,
+ is_sms_match,
+ max_wait_time,
+ phonenumber_tx2,
+ text2)
+ ad_rx2.log.info("Got event %s", EventSmsReceived)
+ except Empty:
+ ad_rx2.log.error("No matched SMS received event.")
+ result = False
+
+ return result
+ else:
+ result = True
+ try:
+ received_sms = ''
+ remaining_text = text
+ while remaining_text != '':
+ event = ad_rx.messaging_ed.wait_for_event(
+ EventSmsReceived, is_sms_partial_match, max_wait_time,
+ phonenumber_tx, remaining_text)
+ event_text = event['data']['Text'].split(")")[-1].strip()
+ event_text_length = len(event_text)
+
+ if event_text in remaining_text:
+ ad_rx.log.info("Got event %s of text length %s from %s",
+ EventSmsReceived, event_text_length,
+ phonenumber_tx)
+ remaining_text = remaining_text[event_text_length:]
+ received_sms += event_text
+
+ ad_rx.log.info("Received SMS of length %s", len(received_sms))
+ except Empty:
+ ad_rx.log.error(
+ "Missing SMS received event.")
+ if received_sms != '':
+ ad_rx.log.error(
+ "Only received partial matched SMS of length %s from %s",
+ len(received_sms), phonenumber_tx)
+ result = False
+
+ try:
+ received_sms2 = ''
+ remaining_text2 = text2
+ while remaining_text2 != '':
+ event2 = ad_rx2.messaging_ed.wait_for_event(
+ EventSmsReceived, is_sms_partial_match, max_wait_time,
+ phonenumber_tx2, remaining_text2)
+ event_text2 = event2['data']['Text'].split(")")[-1].strip()
+ event_text_length2 = len(event_text2)
+
+ if event_text2 in remaining_text2:
+ ad_rx2.log.info("Got event %s of text length %s from %s",
+ EventSmsReceived, event_text_length2,
+ phonenumber_tx2)
+ remaining_text2 = remaining_text2[event_text_length2:]
+ received_sms2 += event_text2
+
+ ad_rx2.log.info("Received SMS of length %s", len(received_sms2))
+ except Empty:
+ ad_rx2.log.error(
+ "Missing SMS received event.")
+ if received_sms2 != '':
+ ad_rx2.log.error(
+ "Only received partial matched SMS of length %s from %s",
+ len(received_sms2), phonenumber_tx2)
+ result = False
+
+ return result
+
+def wait_for_matching_multiple_sms(log,
+ ad_rx,
+ phonenumber_tx,
+ phonenumber_tx2,
+ messages={},
+ allow_multi_part_long_sms=True,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
+
+ if not allow_multi_part_long_sms:
+ try:
+ ad_rx.messaging_ed.wait_for_event(
+ EventSmsReceived,
+ is_sms_match_among_multiple_sms,
+ max_wait_time,
+ phonenumber_tx,
+ phonenumber_tx2,
+ messages[phonenumber_tx],
+ messages[phonenumber_tx2])
+ ad_rx.log.info("Got event %s", EventSmsReceived)
+ return True
+ except Empty:
+ ad_rx.log.error("No matched SMS received event.")
+ return False
+ else:
+ all_msgs = []
+ for tx, msgs in messages.items():
+ for msg in msgs:
+ all_msgs.append([tx, msg, msg, ''])
+
+ all_msgs_copy = all_msgs.copy()
+
+ try:
+ while (all_msgs != []):
+ event = ad_rx.messaging_ed.wait_for_event(
+ EventSmsReceived,
+ is_sms_partial_match_among_multiple_sms,
+ max_wait_time,
+ phonenumber_tx,
+ phonenumber_tx2,
+ messages[phonenumber_tx],
+ messages[phonenumber_tx2])
+ event_text = event['data']['Text'].split(")")[-1].strip()
+ event_text_length = len(event_text)
+
+ for msg in all_msgs_copy:
+ if event_text in msg[2]:
+ ad_rx.log.info("Got event %s of text length %s from %s",
+ EventSmsReceived, event_text_length,
+ msg[0])
+ msg[2] = msg[2][event_text_length:]
+ msg[3] += event_text
+
+ if msg[2] == "":
+ all_msgs.remove(msg)
+
+ ad_rx.log.info("Received all SMS' sent when power-off.")
+ except Empty:
+ ad_rx.log.error(
+ "Missing SMS received event.")
+
+ for msg in all_msgs_copy:
+ if msg[3] != '':
+ ad_rx.log.error(
+ "Only received partial matched SMS of length %s from %s",
+ len(msg[3]), msg[0])
+ return False
+
+ return True
+
+def wait_for_sending_sms(ad_tx, max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
+ try:
+ events = ad_tx.messaging_ed.pop_events(
+ "(%s|%s|%s|%s)" %
+ (EventSmsSentSuccess, EventSmsSentFailure,
+ EventSmsDeliverSuccess,
+ EventSmsDeliverFailure), max_wait_time)
+ for event in events:
+ ad_tx.log.info("Got event %s", event["name"])
+ if event["name"] == EventSmsSentFailure or \
+ event["name"] == EventSmsDeliverFailure:
+ if event.get("data") and event["data"].get("Reason"):
+ ad_tx.log.error("%s with reason: %s",
+ event["name"],
+ event["data"]["Reason"])
+ return False
+ elif event["name"] == EventSmsSentSuccess or \
+ event["name"] == EventSmsDeliverSuccess:
+ return True
+ except Empty:
+ ad_tx.log.error("No %s or %s event for SMS.",
+ EventSmsSentSuccess, EventSmsSentFailure)
+ return False
+
+def voice_call_in_collision_with_mt_sms_msim(
+ log,
+ ad_primary,
+ ad_sms,
+ ad_voice,
+ sms_subid_ad_primary,
+ sms_subid_ad_sms,
+ voice_subid_ad_primary,
+ voice_subid_ad_voice,
+ array_message,
+ ad_hangup=None,
+ verify_caller_func=None,
+ verify_callee_func=None,
+ call_direction="mo",
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ dialing_number_length=None,
+ video_state=None):
+
+ ad_tx = ad_sms
+ ad_rx = ad_primary
+ subid_tx = sms_subid_ad_sms
+ subid_rx = sms_subid_ad_primary
+
+ if call_direction == "mo":
+ ad_caller = ad_primary
+ ad_callee = ad_voice
+ subid_caller = voice_subid_ad_primary
+ subid_callee = voice_subid_ad_voice
+ elif call_direction == "mt":
+ ad_callee = ad_primary
+ ad_caller = ad_voice
+ subid_callee = voice_subid_ad_primary
+ subid_caller = voice_subid_ad_voice
+
+
+ phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
+ phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
+
+ tel_result_wrapper = TelResultWrapper(CallResult('SUCCESS'))
+
+ for ad in (ad_tx, ad_rx):
+ ad.send_keycode("BACK")
+ 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()
+ else:
+ ad.messaging_ed.clear_all_events()
+ except Exception:
+ ad.log.info("Create new sl4a session for messaging")
+ ad.messaging_droid, ad.messaging_ed = ad.get_droid()
+ ad.messaging_ed.start()
+
+ if not verify_caller_func:
+ verify_caller_func = is_phone_in_call
+ if not verify_callee_func:
+ verify_callee_func = is_phone_in_call
+
+ caller_number = ad_caller.telephony['subscription'][subid_caller][
+ 'phone_num']
+ callee_number = ad_callee.telephony['subscription'][subid_callee][
+ 'phone_num']
+ if dialing_number_length:
+ skip_test = False
+ trunc_position = 0 - int(dialing_number_length)
+ try:
+ caller_area_code = caller_number[:trunc_position]
+ callee_area_code = callee_number[:trunc_position]
+ callee_dial_number = callee_number[trunc_position:]
+ except:
+ skip_test = True
+ if caller_area_code != callee_area_code:
+ skip_test = True
+ if skip_test:
+ msg = "Cannot make call from %s to %s by %s digits" % (
+ caller_number, callee_number, dialing_number_length)
+ ad_caller.log.info(msg)
+ raise signals.TestSkip(msg)
+ else:
+ callee_number = callee_dial_number
+
+ msg = "Call from %s to %s" % (caller_number, callee_number)
+ if video_state:
+ msg = "Video %s" % msg
+ video = True
+ else:
+ video = False
+ if ad_hangup:
+ msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
+ ad_caller.log.info(msg)
+
+ for ad in (ad_caller, ad_callee):
+ call_ids = ad.droid.telecomCallGetCallIds()
+ setattr(ad, "call_ids", call_ids)
+ if call_ids:
+ ad.log.info("Pre-exist CallId %s before making call", call_ids)
+
+ ad_caller.ed.clear_events(EventCallStateChanged)
+ call_begin_time = get_device_epoch_time(ad)
+ ad_caller.droid.telephonyStartTrackingCallStateForSubscription(subid_caller)
+
+ for text in array_message:
+ length = len(text)
+ ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
+ phonenumber_tx, phonenumber_rx, length, text)
+ try:
+ ad_rx.messaging_ed.clear_events(EventSmsReceived)
+ ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
+ ad_tx.messaging_ed.clear_events(EventSmsSentFailure)
+ ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
+ time.sleep(1) #sleep 100ms after starting event tracking
+ ad_tx.messaging_droid.logI("Sending SMS of length %s" % length)
+ ad_rx.messaging_droid.logI("Expecting SMS of length %s" % length)
+ ad_caller.log.info("Make a phone call to %s", callee_number)
+
+ tasks = [
+ (ad_tx.messaging_droid.smsSendTextMessage,
+ (phonenumber_rx, text, True)),
+ (ad_caller.droid.telecomCallNumber,
+ (callee_number, video))]
+
+ run_multithread_func(log, tasks)
+
+ try:
+ # Verify OFFHOOK state
+ if not wait_for_call_offhook_for_subscription(
+ log,
+ ad_caller,
+ subid_caller,
+ event_tracking_started=True):
+ ad_caller.log.info(
+ "sub_id %s not in call offhook state", subid_caller)
+ last_call_drop_reason(ad_caller, begin_time=call_begin_time)
+
+ ad_caller.log.error("Initiate call failed.")
+ tel_result_wrapper.result_value = CallResult(
+ 'INITIATE_FAILED')
+ return tel_result_wrapper
+ else:
+ ad_caller.log.info("Caller initate call successfully")
+ finally:
+ ad_caller.droid.telephonyStopTrackingCallStateChangeForSubscription(
+ subid_caller)
+ if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
+ ad_caller.droid.telecomShowInCallScreen()
+ elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
+ ad_caller.droid.showHomeScreen()
+
+ if not wait_and_answer_call_for_subscription(
+ log,
+ ad_callee,
+ subid_callee,
+ incoming_number=caller_number,
+ caller=ad_caller,
+ incall_ui_display=incall_ui_display,
+ video_state=video_state):
+ ad_callee.log.error("Answer call fail.")
+ tel_result_wrapper.result_value = CallResult(
+ 'NO_RING_EVENT_OR_ANSWER_FAILED')
+ return tel_result_wrapper
+ else:
+ ad_callee.log.info("Callee answered the call successfully")
+
+ for ad, call_func in zip([ad_caller, ad_callee],
+ [verify_caller_func, verify_callee_func]):
+ call_ids = ad.droid.telecomCallGetCallIds()
+ new_call_ids = set(call_ids) - set(ad.call_ids)
+ if not new_call_ids:
+ ad.log.error(
+ "No new call ids are found after call establishment")
+ ad.log.error("telecomCallGetCallIds returns %s",
+ ad.droid.telecomCallGetCallIds())
+ tel_result_wrapper.result_value = CallResult(
+ 'NO_CALL_ID_FOUND')
+ for new_call_id in new_call_ids:
+ if not wait_for_in_call_active(ad, call_id=new_call_id):
+ tel_result_wrapper.result_value = CallResult(
+ 'CALL_STATE_NOT_ACTIVE_DURING_ESTABLISHMENT')
+ else:
+ ad.log.info(
+ "callProperties = %s",
+ ad.droid.telecomCallGetProperties(new_call_id))
+
+ if not ad.droid.telecomCallGetAudioState():
+ ad.log.error("Audio is not in call state")
+ tel_result_wrapper.result_value = CallResult(
+ 'AUDIO_STATE_NOT_INCALL_DURING_ESTABLISHMENT')
+
+ if call_func(log, ad):
+ ad.log.info("Call is in %s state", call_func.__name__)
+ else:
+ ad.log.error("Call is not in %s state, voice in RAT %s",
+ call_func.__name__,
+ ad.droid.telephonyGetCurrentVoiceNetworkType())
+ tel_result_wrapper.result_value = CallResult(
+ 'CALL_DROP_OR_WRONG_STATE_DURING_ESTABLISHMENT')
+ if not tel_result_wrapper:
+ return tel_result_wrapper
+
+ if not wait_for_sending_sms(
+ ad_tx,
+ max_wait_time=MAX_WAIT_TIME_SMS_SENT_SUCCESS_IN_COLLISION):
+ return False
+
+ tasks = [
+ (wait_for_matching_sms,
+ (log, ad_rx, phonenumber_tx, text,
+ MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION, True)),
+ (wait_for_call_end,
+ (log, ad_caller, ad_callee, ad_hangup, verify_caller_func,
+ verify_callee_func, call_begin_time, 5, tel_result_wrapper,
+ WAIT_TIME_IN_CALL))]
+
+ results = run_multithread_func(log, tasks)
+
+ if not results[0]:
+ ad_rx.log.error("No matching received SMS of length %s.",
+ length)
+ return False
+
+ tel_result_wrapper = results[1]
+
+ except Exception as e:
+ log.error("Exception error %s", e)
+ raise
+ finally:
+ ad_rx.messaging_droid.smsStopTrackingIncomingSmsMessage()
+
+ return tel_result_wrapper
+
+
+def is_mms_match(event, phonenumber_tx, text):
+ """Return True if 'text' equals to event['data']['Text']
+ and phone number match.
+
+ Args:
+ event: Event object to verify.
+ phonenumber_tx: phone number for sender.
+ text: text string to verify.
+
+ Returns:
+ Return True if 'text' equals to event['data']['Text']
+ and phone number match.
+ """
+ #TODO: add mms matching after mms message parser is added in sl4a. b/34276948
+ return True
+
+
+def wait_for_matching_mms(log,
+ ad_rx,
+ phonenumber_tx,
+ text,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
+ """Wait for matching incoming SMS.
+
+ Args:
+ log: Log object.
+ ad_rx: Receiver's Android Device Object
+ phonenumber_tx: Sender's phone number.
+ text: SMS content string.
+ allow_multi_part_long_sms: is long SMS allowed to be received as
+ multiple short SMS. This is optional, default value is True.
+
+ Returns:
+ True if matching incoming SMS is received.
+ """
+ try:
+ #TODO: add mms matching after mms message parser is added in sl4a. b/34276948
+ ad_rx.messaging_ed.wait_for_event(EventMmsDownloaded, is_mms_match,
+ max_wait_time, phonenumber_tx, text)
+ ad_rx.log.info("Got event %s", EventMmsDownloaded)
+ return True
+ except Empty:
+ ad_rx.log.warning("No matched MMS downloaded event.")
+ return False
+
+
+def mms_send_receive_verify(log,
+ ad_tx,
+ ad_rx,
+ array_message,
+ max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
+ expected_result=True,
+ slot_id_rx=None):
+ """Send MMS, receive MMS, and verify content and sender's number.
+
+ Send (several) MMS from droid_tx to droid_rx.
+ Verify MMS is sent, delivered and received.
+ Verify received content and sender's number are correct.
+
+ Args:
+ log: Log object.
+ ad_tx: Sender's Android Device Object
+ ad_rx: Receiver's Android Device Object
+ array_message: the array of message to send/receive
+ """
+ subid_tx = get_outgoing_message_sub_id(ad_tx)
+ if slot_id_rx is None:
+ subid_rx = get_incoming_message_sub_id(ad_rx)
+ else:
+ subid_rx = get_subid_from_slot_index(log, ad_rx, slot_id_rx)
+
+ result = mms_send_receive_verify_for_subscription(
+ log, ad_tx, ad_rx, subid_tx, subid_rx, array_message, max_wait_time)
+ if result != expected_result:
+ log_messaging_screen_shot(ad_tx, test_name="mms_tx")
+ log_messaging_screen_shot(ad_rx, test_name="mms_rx")
+ return result == expected_result
+
+
+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 %s sent successful log message: %s", type,
+ log_results[-1]["log_message"])
+ 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: %s",
+ type, log_result["log_message"])
+ return True
+ return False
+
+
+def sms_mms_receive_logcat_check(ad, type, begin_time):
+ type = type.upper()
+ smshandle_logs = ad.search_logcat(
+ "InboundSmsHandler: No broadcast sent on processing EVENT_BROADCAST_SMS",
+ begin_time=begin_time)
+ if smshandle_logs:
+ ad.log.warning("Found %s", smshandle_logs[-1]["log_message"])
+ 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: %s", type,
+ log_results[-1]["log_message"])
+ 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: %s", type,
+ log_results[-1]["log_message"])
+ log_results = ad.search_logcat(
+ "ProcessDownloadedMmsAction", begin_time=begin_time)
+ for log_result in log_results:
+ ad.log.info("Found %s", log_result["log_message"])
+ if "status is SUCCEEDED" in log_result["log_message"]:
+ ad.log.info("Download succeed with ProcessDownloadedMmsAction")
+ 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,
+ 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.
+ Verify MMS is sent, delivered and received.
+ Verify received content and sender's number are correct.
+
+ Args:
+ log: Log object.
+ ad_tx: Sender's Android Device Object..
+ ad_rx: Receiver's Android Device Object.
+ subid_tx: Sender's subscription ID to be used for SMS
+ subid_rx: Receiver's subscription ID to be used for SMS
+ array_message: the array of message to send/receive
+ """
+
+ phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
+ phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
+ toggle_enforce = False
+
+ for ad in (ad_tx, ad_rx):
+ if "Permissive" not in ad.adb.shell("su root getenforce"):
+ ad.adb.shell("su root setenforce 0")
+ toggle_enforce = True
+ 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()
+ else:
+ ad.messaging_ed.clear_all_events()
+ ad.messaging_droid.logI(
+ "Start mms_send_receive_verify_for_subscription test")
+ except Exception:
+ ad.log.info("Create new sl4a session for messaging")
+ ad.messaging_droid, ad.messaging_ed = ad.get_droid()
+ ad.messaging_ed.start()
+
+ for subject, message, filename in array_payload:
+ ad_tx.messaging_ed.clear_events(EventMmsSentSuccess)
+ ad_tx.messaging_ed.clear_events(EventMmsSentFailure)
+ 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)
+ try:
+ ad_tx.messaging_droid.smsSendMultimediaMessage(
+ phonenumber_rx, subject, message, phonenumber_tx, filename)
+ try:
+ events = ad_tx.messaging_ed.pop_events(
+ "(%s|%s)" % (EventMmsSentSuccess,
+ EventMmsSentFailure), max_wait_time)
+ for event in events:
+ ad_tx.log.info("Got event %s", event["name"])
+ if event["name"] == EventMmsSentFailure:
+ if event.get("data") and event["data"].get("Reason"):
+ ad_tx.log.error("%s with reason: %s",
+ event["name"],
+ event["data"]["Reason"])
+ return False
+ elif event["name"] == EventMmsSentSuccess:
+ break
+ except Empty:
+ ad_tx.log.warning("No %s or %s event.", EventMmsSentSuccess,
+ EventMmsSentFailure)
+ return False
+
+ if not wait_for_matching_mms(log, ad_rx, phonenumber_tx,
+ message, max_wait_time):
+ return False
+ except Exception as e:
+ log.error("Exception error %s", e)
+ raise
+ finally:
+ ad_rx.messaging_droid.smsStopTrackingIncomingMmsMessage()
+ for ad in (ad_tx, ad_rx):
+ if toggle_enforce:
+ ad.send_keycode("BACK")
+ ad.adb.shell("su root setenforce 1")
+ return True
+
+
+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.
+ Verify MMS is sent, delivered and received.
+ Verify received content and sender's number are correct.
+
+ Args:
+ log: Log object.
+ ad_tx: Sender's Android Device Object
+ ad_rx: Receiver's Android Device Object
+ 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, 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,
+ 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.
+ Verify MMS is sent, delivered and received.
+ Verify received content and sender's number are correct.
+
+ Args:
+ log: Log object.
+ ad_tx: Sender's Android Device Object..
+ ad_rx: Receiver's Android Device Object.
+ subid_tx: Sender's subscription ID to be used for SMS
+ subid_rx: Receiver's subscription ID to be used for SMS
+ array_message: the array of message to send/receive
+ """
+
+ phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
+ phonenumber_rx = ad_rx.telephony['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:
+ ad_rx.log.info(
+ "Waiting MMS from %s to %s, subject: %s, message: %s, file: %s.",
+ phonenumber_tx, phonenumber_rx, subject, message, filename)
+ ad_rx.messaging_droid.smsStartTrackingIncomingMmsMessage()
+ time.sleep(5)
+ try:
+ hangup_call(log, ad_tx)
+ hangup_call(log, ad_rx)
+ try:
+ ad_tx.messaging_ed.pop_event(EventMmsSentSuccess,
+ max_wait_time)
+ ad_tx.log.info("Got event %s", EventMmsSentSuccess)
+ except Empty:
+ log.warning("No sent_success event.")
+ if not wait_for_matching_mms(log, ad_rx, phonenumber_tx, message):
+ return False
+ finally:
+ ad_rx.messaging_droid.smsStopTrackingIncomingMmsMessage()
+ return True
+
+
+def log_messaging_screen_shot(ad, test_name=""):
+ ad.ensure_screen_on()
+ ad.send_keycode("HOME")
+ ad.adb.shell("am start -n com.google.android.apps.messaging/.ui."
+ "ConversationListActivity")
+ time.sleep(3)
+ ad.screenshot(test_name)
+ ad.adb.shell("am start -n com.google.android.apps.messaging/com.google."
+ "android.apps.messaging.ui.conversation."
+ "LaunchConversationShimActivity -e conversation_id 1")
+ time.sleep(3)
+ ad.screenshot(test_name)
+ ad.send_keycode("HOME")
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_mms_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_mms_utils.py
index 92bd9cf..d9d85a7 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_mms_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_mms_utils.py
@@ -16,14 +16,15 @@
import time
from acts.utils import rand_ascii_str
-from acts_contrib.test_utils.tel.tel_test_utils import mms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_message_utils import mms_receive_verify_after_call_hangup
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_test_utils import mms_receive_verify_after_call_hangup
message_lengths = (50, 160, 180)
long_message_lengths = (800, 1600)
+
def _mms_test_mo(log, ads, expected_result=True):
return _mms_test(log,
[ads[0], ads[1]], expected_result=expected_result)
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_ops_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_ops_utils.py
new file mode 100644
index 0000000..02b23b4
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_ops_utils.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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.
+
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_task
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
+
+
+def initiate_call_verify_operation(log,
+ caller,
+ callee,
+ download=False):
+ """Initiate call and verify operations with an option of data idle or data download
+
+ Args:
+ log: log object.
+ caller: android device object as caller.
+ callee: android device object as callee.
+ download: True if download operation is to be performed else False
+
+ Return:
+ True: if call initiated and verified operations successfully
+ False: for errors
+ """
+ caller_number = caller.telephony['subscription'][
+ get_outgoing_voice_sub_id(caller)]['phone_num']
+ callee_number = callee.telephony['subscription'][
+ get_outgoing_voice_sub_id(callee)]['phone_num']
+ if not initiate_call(log, caller, callee_number):
+ caller.log.error("Phone was unable to initate a call")
+ return False
+
+ if not wait_and_answer_call(log, callee, caller_number):
+ callee.log.error("Callee failed to receive incoming call or answered the call.")
+ return False
+
+ if download:
+ if not active_file_download_task(log, caller, "10MB"):
+ caller.log.error("Unable to download file")
+ return False
+
+ if not hangup_call(log, caller):
+ caller.log.error("Unable to hang up the call")
+ return False
+ return True
+
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_parse_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_parse_utils.py
new file mode 100644
index 0000000..6d8811b
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_parse_utils.py
@@ -0,0 +1,1844 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+import copy
+import re
+import statistics
+
+from acts import signals
+from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_data_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_voice_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
+
+SETUP_DATA_CALL = 'SETUP_DATA_CALL'
+SETUP_DATA_CALL_REQUEST = '> SETUP_DATA_CALL'
+SETUP_DATA_CALL_RESPONSE = '< SETUP_DATA_CALL'
+IS_CAPTIVEPORTAL = r'isCaptivePortal: isSuccessful()=true'
+
+DEACTIVATE_DATA_CALL = 'DEACTIVATE_DATA_CALL'
+DEACTIVATE_DATA_CALL_REQUEST = '> DEACTIVATE_DATA_CALL'
+DEACTIVATE_DATA_CALL_RESPONSE = '< DEACTIVATE_DATA_CALL'
+UNSOL_DATA_CALL_LIST_CHANGED = 'UNSOL_DATA_CALL_LIST_CHANGED'
+
+IWLAN_DATA_SERVICE = 'IWlanDataService'
+IWLAN_SETUP_DATA_CALL_REQUEST = '> REQUEST_SETUP_DATA_CALL'
+IWLAN_SETUP_DATA_CALL_RESPONSE = 'setupDataCallResponse'
+IWLAN_SEND_ACK = '> send ACK for serial'
+
+IWLAN_DEACTIVATE_DATA_CALL_REQUEST = '> REQUEST_DEACTIVATE_DATA_CALL'
+IWLAN_DEACTIVATE_DATA_CALL_RESPONSE = 'deactivateDataCallResponse'
+
+SET_PREFERRED_DATA_MODEM = 'SET_PREFERRED_DATA_MODEM'
+
+WHI_IWLAN_DATA_SERVICE = 'IwlanDataService'
+WHI_IWLAN_SETUP_DATA_CALL_REQUEST = r'IwlanDataService\[\d\]: Setup data call'
+WHI_IWLAN_SETUP_DATA_CALL_RESPONSE = r'IwlanDataService\[\d\]: Tunnel opened!'
+WHI_IWLAN_DEACTIVATE_DATA_CALL_REQUEST = r'IwlanDataService\[\d\]: Deactivate data call'
+WHI_IWLAN_DEACTIVATE_DATA_CALL_RESPONSE = r'IwlanDataService\[\d\]: Tunnel closed!'
+
+ON_ENABLE_APN_IMS_SLOT0 = 'DCT-C-0 : onEnableApn: apnType=ims, request type=NORMAL'
+ON_ENABLE_APN_IMS_SLOT1 = 'DCT-C-1 : onEnableApn: apnType=ims, request type=NORMAL'
+ON_ENABLE_APN_IMS_HANDOVER_SLOT0 = 'DCT-C-0 : onEnableApn: apnType=ims, request type=HANDOVER'
+ON_ENABLE_APN_IMS_HANDOVER_SLOT1 = 'DCT-C-1 : onEnableApn: apnType=ims, request type=HANDOVER'
+RADIO_ON_4G_SLOT0 = r'GsmCdmaPhone: \[0\] Event EVENT_RADIO_ON Received'
+RADIO_ON_4G_SLOT1 = r'GsmCdmaPhone: \[1\] Event EVENT_RADIO_ON Received'
+RADIO_ON_IWLAN = 'Switching to new default network.*WIFI CONNECTED'
+WIFI_OFF = 'setWifiEnabled.*enable=false'
+ON_IMS_MM_TEL_CONNECTED_4G_SLOT0 = r'ImsPhone: \[0\].*onImsMmTelConnected imsRadioTech=WWAN'
+ON_IMS_MM_TEL_CONNECTED_4G_SLOT1 = r'ImsPhone: \[1\].*onImsMmTelConnected imsRadioTech=WWAN'
+ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT0 = r'ImsPhone: \[0\].*onImsMmTelConnected imsRadioTech=WLAN'
+ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT1 = r'ImsPhone: \[1\].*onImsMmTelConnected imsRadioTech=WLAN'
+
+DEFAULT_MO_SMS_BODY = 'MO SMS body not yet found'
+DEFAULT_MT_SMS_BODY = 'MT SMS body not yet found'
+
+MMS_SERVICE = 'MmsService:'
+MMS_SEND_REQUEST_ID_PATTERN = r'SendRequest@(\S+)'
+MMS_DOWNLOAD_REQUEST_ID_PATTERN = r'DownloadRequest@(\S+)'
+MMS_START_NEW_NW_REQUEST = 'start new network request'
+MMS_200_OK = '200 OK'
+
+SMS_SEND_TEXT_MESSAGE = 'smsSendTextMessage'
+MO_SMS_LOGCAT_PATTERN = r'smsSendTextMessage.*"(\S+)", true|false'
+SEND_SMS = 'SEND_SMS'
+SEND_SMS_REQUEST = '> SEND_SMS'
+SEND_SMS_RESPONSE = '< SEND_SMS'
+SEND_SMS_EXPECT_MORE = 'SEND_SMS_EXPECT_MORE'
+UNSOL_RESPONSE_NEW_SMS = '< UNSOL_RESPONSE_NEW_SMS'
+SMS_RECEIVED = 'SmsReceived'
+MT_SMS_CONTENT_PATTERN = 'sl4a.*?SmsReceived.*?"Text":"(.*?)"'
+
+SEND_SMS_OVER_IMS = r'ImsSmsDispatcher \[(\d)\]'
+SEND_SMS_REQUEST_OVER_IMS = 'sendSms: mRetryCount'
+SEND_SMS_RESPONSE_OVER_IMS = 'onSendSmsResult token'
+SMS_RECEIVED_OVER_IMS = 'SMS received'
+SMS_RECEIVED_OVER_IMS_SLOT0 = r'ImsSmsDispatcher \[0\]: SMS received'
+SMS_RECEIVED_OVER_IMS_SLOT1 = r'ImsSmsDispatcher \[1\]: SMS received'
+
+
+def print_nested_dict(ad, d):
+ divider = "------"
+ for k, v in d.items():
+ if isinstance(v, dict):
+ ad.log.info('%s %s %s', divider, k, divider)
+ print_nested_dict(ad, v)
+ else:
+ ad.log.info('%s: %s', k, v)
+
+
+def get_slot_from_logcat(msg):
+ """Get slot index from specific pattern in logcat
+
+ Args:
+ msg: logcat message string
+
+ Returns:
+ 0 for pSIM or 1 for eSIM
+ """
+ res = re.findall(r'\[(PHONE[\d])\]', msg)
+ try:
+ phone = res[0]
+ except:
+ phone = None
+ return phone
+
+
+def get_apn_from_logcat(msg):
+ """Get APN from logcat
+
+ Args:
+ msg: logcat message string
+
+ Returns:
+ APN
+ """
+ res = re.findall(r'DataProfile=[^/]+/[^/]+/[^/]+/([^/]+)/', msg)
+ try:
+ apn = res[0]
+ except:
+ apn = None
+ return apn
+
+
+def parse_setup_data_call(ad, apn='internet', dds_switch=False):
+ """Search in logcat for lines containing data call setup procedure.
+ Calculate the data call setup time with given APN and validation
+ time on LTE.
+
+ Args:
+ ad: Android object
+ apn: access point name
+ dds_switch: True for switching DDS. Otherwise False.
+
+ Returns:
+ setup_data_call: Dictionary containing data call setup request and
+ response messages for each data call. The format is shown as
+ below:
+ {
+ message_id:
+ {
+ 'request':
+ {
+ 'message': logcat message body of data call setup
+ request message
+ 'time_stamp': time stamp in text format
+ 'datetime_obj': datetime object of time stamp
+ 'apn': access point name of this request
+ 'phone': 0 for pSIM or 1 for eSIM
+ }
+ 'response':
+ {
+ 'message': logcat message body of data call setup
+ response message
+ 'time_stamp': time stamp in text format
+ 'datetime_obj': datetime object of time stamp
+ 'cause': failure cause if data call setup failed
+ 'cid': PDP context ID
+ 'ifname': the name of the interface of the network
+ 'phone': 0 for pSIM or 1 for eSIM
+ 'unsol_data_call_list_changed': message of
+ unsol_data_call_list_changed
+ 'unsol_data_call_list_changed_time': time stamp of
+ the message unsol_data_call_list_changed
+ 'is_captive_portal': message of LTE validation pass
+ 'data_call_setup_time': time between data call setup
+ request and unsol_data_call_list_changed
+ 'validation_time_on_lte': time between data call
+ setup response and LTE validation pass
+ }
+ }
+ }
+
+ data_call_setup_time_list: List. This is a summary of necessary
+ messages of data call setup procedure The format is shown as
+ below:
+ [
+ {
+ 'request': logcat message body of data call setup
+ request message
+ 'response': logcat message body of data call setup
+ response message
+ 'unsol_data_call_list_changed': message of
+ unsol_data_call_list_changed
+ 'start': time stamp of data call setup request
+ 'end': time stamp of the message
+ unsol_data_call_list_changed
+ 'duration': time between data call setup request and
+ unsol_data_call_list_changed
+ 'validation_time_on_lte': time between data call
+ setup response and LTE validation pass
+ }
+ ]
+
+ avg_data_call_setup_time: average of data call setup time
+
+ avg_validation_time_on_lte: average of time for validation time on
+ LTE
+ """
+ ad.log.info('====== Start to search logcat ====== ')
+ logcat = ad.search_logcat(
+ r'%s\|%s\|%s\|%s' % (
+ SET_PREFERRED_DATA_MODEM,
+ SETUP_DATA_CALL,
+ UNSOL_DATA_CALL_LIST_CHANGED, IS_CAPTIVEPORTAL))
+
+ if not logcat:
+ return False
+
+ for msg in logcat:
+ ad.log.info(msg["log_message"])
+
+ dds_slot = get_slot_index_from_data_sub_id(ad)
+
+ set_preferred_data_modem = {}
+ setup_data_call = {}
+ data_call_setup_time_list = []
+ last_message_id = None
+
+ for line in logcat:
+ if line['message_id']:
+ if SET_PREFERRED_DATA_MODEM in line['log_message']:
+ set_preferred_data_modem['message'] = line['log_message']
+ set_preferred_data_modem['time_stamp'] = line['time_stamp']
+ set_preferred_data_modem[
+ 'datetime_obj'] = line['datetime_obj']
+
+ if SETUP_DATA_CALL_REQUEST in line['log_message']:
+ found_apn = get_apn_from_logcat(line['log_message'])
+ if found_apn != apn:
+ continue
+
+ phone = get_slot_from_logcat(line['log_message'])
+ if not phone:
+ continue
+
+ if not dds_switch:
+ if str(dds_slot) not in phone:
+ continue
+
+ msg_id = line['message_id']
+ last_message_id = line['message_id']
+ if msg_id not in setup_data_call:
+ setup_data_call[msg_id] = {}
+
+ setup_data_call[msg_id]['request'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj'],
+ 'apn': found_apn,
+ 'phone': phone}
+
+ if set_preferred_data_modem:
+ setup_data_call[msg_id]['request'][
+ 'set_preferred_data_modem_message'] = set_preferred_data_modem['message']
+ setup_data_call[msg_id]['request'][
+ 'set_preferred_data_modem_time_stamp'] = set_preferred_data_modem['time_stamp']
+ setup_data_call[msg_id]['request'][
+ 'set_preferred_data_modem_datetime_obj'] = set_preferred_data_modem['datetime_obj']
+ set_preferred_data_modem = {}
+
+ if SETUP_DATA_CALL_RESPONSE in line['log_message']:
+ phone = get_slot_from_logcat(line['log_message'])
+ if not phone:
+ continue
+
+ if not dds_switch:
+ if str(dds_slot) not in phone:
+ continue
+
+ msg_id = line['message_id']
+ if msg_id not in setup_data_call:
+ continue
+
+ if 'request' not in setup_data_call[msg_id]:
+ continue
+
+ last_message_id = line['message_id']
+
+ setup_data_call[msg_id]['response'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj'],
+ 'cause': '0',
+ 'cid': None,
+ 'ifname': None,
+ 'phone': phone,
+ 'unsol_data_call_list_changed': None,
+ 'unsol_data_call_list_changed_time': None,
+ 'is_captive_portal': None,
+ 'data_call_setup_time': None,
+ 'validation_time_on_lte': None}
+
+ res = re.findall(r'cause=(\d+)', line['log_message'])
+ try:
+ cause = res[0]
+ setup_data_call[msg_id]['response']['cause'] = cause
+ except:
+ pass
+
+ res = re.findall(r'cid=(\d+)', line['log_message'])
+ try:
+ cid = res[0]
+ setup_data_call[msg_id]['response']['cid'] = cid
+ except:
+ pass
+
+ res = re.findall(r'ifname=(\S+)', line['log_message'])
+ try:
+ ifname = res[0]
+ setup_data_call[msg_id]['response']['ifname'] = ifname
+ except:
+ pass
+
+ if UNSOL_DATA_CALL_LIST_CHANGED in line['log_message']:
+ if not last_message_id:
+ continue
+
+ phone = get_slot_from_logcat(line['log_message'])
+ if not phone:
+ continue
+
+ if not dds_switch:
+ if str(dds_slot) not in phone:
+ continue
+
+ if 'request' not in setup_data_call[last_message_id]:
+ continue
+
+ if 'response' not in setup_data_call[last_message_id]:
+ continue
+
+ cid = setup_data_call[last_message_id]['response']['cid']
+ if 'cid = %s' % cid not in line['log_message']:
+ continue
+
+ if setup_data_call[last_message_id]['response']['cause'] != '0':
+ continue
+
+ if dds_switch:
+ if 'set_preferred_data_modem_message' not in setup_data_call[
+ last_message_id]['request']:
+ continue
+ data_call_start_time = setup_data_call[last_message_id][
+ 'request']['set_preferred_data_modem_datetime_obj']
+
+ else:
+ data_call_start_time = setup_data_call[last_message_id][
+ 'request']['datetime_obj']
+
+ data_call_end_time = line['datetime_obj']
+ setup_data_call[last_message_id]['response'][
+ 'unsol_data_call_list_changed_time'] = data_call_end_time
+ setup_data_call[last_message_id]['response'][
+ 'unsol_data_call_list_changed'] = line['log_message']
+ data_call_setup_time = data_call_end_time - data_call_start_time
+ setup_data_call[last_message_id]['response'][
+ 'data_call_setup_time'] = data_call_setup_time.total_seconds()
+
+ if apn == 'ims':
+ data_call_setup_time_list.append(
+ {'request': setup_data_call[
+ last_message_id]['request']['message'],
+ 'response': setup_data_call[
+ last_message_id]['response']['message'],
+ 'unsol_data_call_list_changed': setup_data_call[
+ last_message_id]['response'][
+ 'unsol_data_call_list_changed'],
+ 'start': data_call_start_time,
+ 'end': data_call_end_time,
+ 'duration': setup_data_call[last_message_id]['response'][
+ 'data_call_setup_time']})
+
+ last_message_id = None
+
+ if IS_CAPTIVEPORTAL in line['log_message']:
+ if not last_message_id:
+ continue
+
+ if 'request' not in setup_data_call[last_message_id]:
+ continue
+
+ if 'response' not in setup_data_call[last_message_id]:
+ continue
+
+ if dds_switch:
+ data_call_start_time = setup_data_call[last_message_id][
+ 'request']['set_preferred_data_modem_datetime_obj']
+
+ else:
+ data_call_start_time = setup_data_call[last_message_id][
+ 'request']['datetime_obj']
+
+ setup_data_call[last_message_id]['response'][
+ 'is_captive_portal'] = line['log_message']
+ validation_start_time_on_lte = setup_data_call[
+ last_message_id]['response']['datetime_obj']
+ validation_end_time_on_lte = line['datetime_obj']
+ validation_time_on_lte = (
+ validation_end_time_on_lte - validation_start_time_on_lte).total_seconds()
+ setup_data_call[last_message_id]['response'][
+ 'validation_time_on_lte'] = validation_time_on_lte
+
+ data_call_setup_time_list.append(
+ {'request': setup_data_call[last_message_id]['request'][
+ 'message'],
+ 'response': setup_data_call[last_message_id]['response'][
+ 'message'],
+ 'unsol_data_call_list_changed': setup_data_call[
+ last_message_id]['response']['unsol_data_call_list_changed'],
+ 'start': data_call_start_time,
+ 'end': setup_data_call[last_message_id]['response'][
+ 'unsol_data_call_list_changed_time'],
+ 'duration': setup_data_call[last_message_id]['response'][
+ 'data_call_setup_time'],
+ 'validation_time_on_lte': validation_time_on_lte})
+
+ last_message_id = None
+
+ duration_list = []
+ for item in data_call_setup_time_list:
+ if 'duration' in item:
+ duration_list.append(item['duration'])
+
+ try:
+ avg_data_call_setup_time = statistics.mean(duration_list)
+ except:
+ avg_data_call_setup_time = None
+
+ validation_time_on_lte_list = []
+ for item in data_call_setup_time_list:
+ if 'validation_time_on_lte' in item:
+ validation_time_on_lte_list.append(
+ item['validation_time_on_lte'])
+
+ try:
+ avg_validation_time_on_lte = statistics.mean(
+ validation_time_on_lte_list)
+ except:
+ avg_validation_time_on_lte = None
+
+ return (
+ setup_data_call,
+ data_call_setup_time_list,
+ avg_data_call_setup_time,
+ avg_validation_time_on_lte)
+
+
+def parse_setup_data_call_on_iwlan(ad):
+ """Search in logcat for lines containing data call setup procedure.
+ Calculate the data call setup time with given APN on iwlan.
+
+ Args:
+ ad: Android object
+ apn: access point name
+
+ Returns:
+ setup_data_call: Dictionary containing data call setup request and
+ response messages for each data call. The format is shown as
+ below:
+ {
+ message_id:
+ {
+ 'request':
+ {
+ 'message': logcat message body of data call setup
+ request message
+ 'time_stamp': time stamp in text format
+ 'datetime_obj': datetime object of time stamp
+ }
+ 'response':
+ {
+ 'message': logcat message body of data call setup
+ response message
+ 'time_stamp': time stamp in text format
+ 'datetime_obj': datetime object of time stamp
+ 'cause': failure cause if data call setup failed
+ 'data_call_setup_time': time between data call setup
+ request and response
+ }
+ }
+ }
+
+ data_call_setup_time_list:
+ List. This is a summary of mecessary messages of data call setup
+ procedure The format is shown as below:
+ [
+ {
+ 'request': logcat message body of data call setup
+ request message
+ 'response': logcat message body of data call setup
+ response message
+ 'start': time stamp of data call setup request
+ 'end': time stamp of data call setup response
+ 'duration': time between data call setup request and
+ response
+ }
+ ]
+
+ avg_data_call_setup_time: average of data call setup time
+ """
+ ad.log.info('====== Start to search logcat ====== ')
+ logcat = ad.search_logcat(r'%s\|%s' % (
+ IWLAN_DATA_SERVICE, WHI_IWLAN_DATA_SERVICE))
+
+ found_iwlan_data_service = 1
+ if not logcat:
+ found_iwlan_data_service = 0
+
+ if not found_iwlan_data_service:
+ (
+ setup_data_call,
+ data_call_setup_time_list,
+ avg_data_call_setup_time,
+ _) = parse_setup_data_call(ad, apn='ims')
+
+ return (
+ setup_data_call,
+ data_call_setup_time_list,
+ avg_data_call_setup_time)
+
+ for msg in logcat:
+ ad.log.info(msg["log_message"])
+
+ setup_data_call = {}
+ data_call_setup_time_list = []
+ last_message_id = None
+
+ whi_msg_index = None
+ for line in logcat:
+ serial = None
+ cause = None
+ if IWLAN_SETUP_DATA_CALL_REQUEST in line['log_message']:
+ match_res = re.findall(
+ r'%s:\s(\d+)' % IWLAN_DATA_SERVICE, line['log_message'])
+ if match_res:
+ try:
+ serial = match_res[0]
+ except:
+ pass
+
+ if not serial:
+ continue
+
+ msg_id = serial
+ last_message_id = serial
+ if msg_id not in setup_data_call:
+ setup_data_call[msg_id] = {}
+
+ setup_data_call[msg_id]['request'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj']}
+
+ else:
+ if re.search(
+ WHI_IWLAN_SETUP_DATA_CALL_REQUEST, line['log_message']):
+ if whi_msg_index is None:
+ whi_msg_index = 0
+ else:
+ whi_msg_index = whi_msg_index + 1
+
+ if str(whi_msg_index) not in setup_data_call:
+ setup_data_call[str(whi_msg_index)] = {}
+
+ setup_data_call[str(whi_msg_index)]['request'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj']}
+
+ if IWLAN_SETUP_DATA_CALL_RESPONSE in line['log_message']:
+ match_res = re.findall(r'Serial = (\d+)', line['log_message'])
+ if match_res:
+ try:
+ serial = match_res[0]
+ except:
+ pass
+
+ if serial:
+ msg_id = serial
+ else:
+ msg_id = last_message_id
+
+ if msg_id not in setup_data_call:
+ continue
+
+ if 'request' not in setup_data_call[msg_id]:
+ continue
+
+ setup_data_call[msg_id]['response'] = {
+ 'message': None,
+ 'time_stamp': None,
+ 'datetime_obj': None,
+ 'cause': None,
+ 'data_call_setup_time': None}
+
+ match_res = re.findall(
+ r'Fail Cause = (\d+)', line['log_message'])
+ if match_res:
+ try:
+ cause = match_res[0]
+ except:
+ cause = None
+
+ if cause != '0':
+ continue
+
+ setup_data_call[msg_id]['response']['message'] = line[
+ 'log_message']
+ setup_data_call[msg_id]['response']['time_stamp'] = line[
+ 'time_stamp']
+ setup_data_call[msg_id]['response']['datetime_obj'] = line[
+ 'datetime_obj']
+ setup_data_call[msg_id]['response']['cause'] = 0
+
+ data_call_start_time = setup_data_call[last_message_id][
+ 'request']['datetime_obj']
+ data_call_end_time = line['datetime_obj']
+ data_call_setup_time = data_call_end_time - data_call_start_time
+ setup_data_call[last_message_id]['response'][
+ 'data_call_setup_time'] = data_call_setup_time.total_seconds()
+
+ data_call_setup_time_list.append(
+ {'request': setup_data_call[last_message_id]['request'][
+ 'message'],
+ 'response': setup_data_call[last_message_id]['response'][
+ 'message'],
+ 'start': setup_data_call[last_message_id]['request'][
+ 'datetime_obj'],
+ 'end': setup_data_call[last_message_id]['response'][
+ 'datetime_obj'],
+ 'duration': setup_data_call[last_message_id]['response'][
+ 'data_call_setup_time']})
+
+ last_message_id = None
+
+ else:
+ if re.search(
+ WHI_IWLAN_SETUP_DATA_CALL_RESPONSE, line['log_message']):
+ if whi_msg_index is None:
+ continue
+
+ if 'response' in setup_data_call[str(whi_msg_index)]:
+ ad.log.error('Duplicated setup data call response is '
+ 'found or the request message is lost.')
+ continue
+
+ setup_data_call[str(whi_msg_index)]['response'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj'],
+ 'data_call_setup_time': None}
+
+ data_call_start_time = setup_data_call[str(whi_msg_index)][
+ 'request']['datetime_obj']
+ data_call_end_time = line['datetime_obj']
+ data_call_setup_time = data_call_end_time - data_call_start_time
+ setup_data_call[str(whi_msg_index)]['response'][
+ 'data_call_setup_time'] = data_call_setup_time.total_seconds()
+
+ data_call_setup_time_list.append(
+ {'request': setup_data_call[str(whi_msg_index)][
+ 'request']['message'],
+ 'response': setup_data_call[str(whi_msg_index)][
+ 'response']['message'],
+ 'start': setup_data_call[str(whi_msg_index)]['request'][
+ 'datetime_obj'],
+ 'end': setup_data_call[str(whi_msg_index)]['response'][
+ 'datetime_obj'],
+ 'duration': setup_data_call[str(whi_msg_index)][
+ 'response']['data_call_setup_time']})
+
+ duration_list = []
+ for item in data_call_setup_time_list:
+ if 'duration' in item:
+ duration_list.append(item['duration'])
+
+ try:
+ avg_data_call_setup_time = statistics.mean(duration_list)
+ except:
+ avg_data_call_setup_time = None
+
+ ad.log.warning('setup_data_call: %s', setup_data_call)
+ ad.log.warning('duration list: %s', duration_list)
+ ad.log.warning('avg_data_call_setup_time: %s', avg_data_call_setup_time)
+
+ return (
+ setup_data_call,
+ data_call_setup_time_list,
+ avg_data_call_setup_time)
+
+
+def parse_deactivate_data_call(ad):
+ """Search in logcat for lines containing data call deactivation procedure.
+ Calculate the data call deactivation time on LTE.
+
+ Args:
+ ad: Android object
+
+ Returns:
+ deactivate_data_call: Dictionary containing data call deactivation
+ request and response messages for each data call. The format is
+ shown as below:
+ {
+ message_id:
+ {
+ 'request':
+ {
+ 'message': logcat message body of data call
+ deactivation request message
+ 'time_stamp': time stamp in text format
+ 'datetime_obj': datetime object of time stamp
+ 'cid': PDP context ID
+ 'phone': 0 for pSIM or 1 for eSIM
+ }
+ 'response':
+ {
+ 'message': logcat message body of data call
+ deactivation response message
+ 'time_stamp': time stamp in text format
+ 'datetime_obj': datetime object of time stamp
+ 'phone': 0 for pSIM or 1 for eSIM
+ 'unsol_data_call_list_changed': message of
+ unsol_data_call_list_changed
+ 'deactivate_data_call_time': time between data call
+ deactivation request and unsol_data_call_list_changed
+ }
+ }
+ }
+
+ deactivate_data_call_time_list: List. This is a summary of necessary
+ messages of data call deactivation procedure The format is shown
+ as below:
+ [
+ {
+ 'request': logcat message body of data call
+ deactivation request message
+ 'response': logcat message body of data call
+ deactivation response message
+ 'unsol_data_call_list_changed': message of
+ unsol_data_call_list_changed
+ 'start': time stamp of data call deactivation request
+ 'end': time stamp of the message
+ unsol_data_call_list_changed
+ 'duration': time between data call deactivation
+ request and unsol_data_call_list_changed
+ }
+ ]
+
+ avg_deactivate_data_call_time: average of data call deactivation time
+ """
+ ad.log.info('====== Start to search logcat ====== ')
+ logcat = ad.search_logcat(
+ r'%s\|%s' % (DEACTIVATE_DATA_CALL, UNSOL_DATA_CALL_LIST_CHANGED))
+ if not logcat:
+ return False
+
+ for msg in logcat:
+ ad.log.info(msg["log_message"])
+
+ dds_slot = get_slot_index_from_data_sub_id(ad)
+
+ deactivate_data_call = {}
+ deactivate_data_call_time_list = []
+ last_message_id = None
+
+ for line in logcat:
+ if line['message_id']:
+ if DEACTIVATE_DATA_CALL_REQUEST in line['log_message']:
+ phone = get_slot_from_logcat(line['log_message'])
+ if not phone:
+ continue
+
+ if str(dds_slot) not in phone:
+ continue
+
+ msg_id = line['message_id']
+ last_message_id = line['message_id']
+ if msg_id not in deactivate_data_call:
+ deactivate_data_call[msg_id] = {}
+
+ deactivate_data_call[msg_id]['request'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj'],
+ 'cid': None,
+ 'phone': dds_slot}
+
+ res = re.findall(r'cid = (\d+)', line['log_message'])
+ try:
+ cid = res[0]
+ deactivate_data_call[msg_id]['request']['cid'] = cid
+ except:
+ pass
+
+ if DEACTIVATE_DATA_CALL_RESPONSE in line['log_message']:
+ phone = get_slot_from_logcat(line['log_message'])
+ if not phone:
+ continue
+
+ if str(dds_slot) not in phone:
+ continue
+
+ msg_id = line['message_id']
+ if msg_id not in deactivate_data_call:
+ continue
+
+ if 'request' not in deactivate_data_call[msg_id]:
+ continue
+
+ last_message_id = line['message_id']
+
+ deactivate_data_call[msg_id]['response'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj'],
+ 'phone': dds_slot,
+ 'unsol_data_call_list_changed': None,
+ 'deactivate_data_call_time': None}
+
+ if UNSOL_DATA_CALL_LIST_CHANGED in line['log_message']:
+ if not last_message_id:
+ continue
+
+ phone = get_slot_from_logcat(line['log_message'])
+ if not phone:
+ continue
+
+ if str(dds_slot) not in phone:
+ continue
+
+ if 'request' not in deactivate_data_call[last_message_id]:
+ continue
+
+ if 'response' not in deactivate_data_call[last_message_id]:
+ continue
+
+ cid = deactivate_data_call[last_message_id]['request']['cid']
+ if 'cid = %s' % cid not in line['log_message']:
+ continue
+
+ deactivate_data_call_start_time = deactivate_data_call[
+ last_message_id]['request']['datetime_obj']
+ deactivate_data_call_end_time = line['datetime_obj']
+ deactivate_data_call[last_message_id]['response'][
+ 'unsol_data_call_list_changed'] = line['log_message']
+ deactivate_data_call_time = (
+ deactivate_data_call_end_time - deactivate_data_call_start_time)
+ deactivate_data_call[last_message_id]['response'][
+ 'deactivate_data_call_time'] = deactivate_data_call_time.total_seconds()
+ deactivate_data_call_time_list.append(
+ {'request': deactivate_data_call[last_message_id][
+ 'request']['message'],
+ 'response': deactivate_data_call[last_message_id][
+ 'response']['message'],
+ 'unsol_data_call_list_changed': deactivate_data_call[
+ last_message_id]['response'][
+ 'unsol_data_call_list_changed'],
+ 'start': deactivate_data_call_start_time,
+ 'end': deactivate_data_call_end_time,
+ 'duration': deactivate_data_call_time.total_seconds()})
+
+ last_message_id = None
+
+ duration_list = []
+ for item in deactivate_data_call_time_list:
+ if 'duration' in item:
+ duration_list.append(item['duration'])
+
+ try:
+ avg_deactivate_data_call_time = statistics.mean(duration_list)
+ except:
+ avg_deactivate_data_call_time = None
+
+ return (
+ deactivate_data_call,
+ deactivate_data_call_time_list,
+ avg_deactivate_data_call_time)
+
+
+def parse_deactivate_data_call_on_iwlan(ad):
+ """Search in logcat for lines containing data call deactivation procedure.
+ Calculate the data call deactivation time on iwlan.
+
+ Args:
+ ad: Android object
+
+ Returns:
+ deactivate_data_call: Dictionary containing data call deactivation
+ request and response messages for each data call. The format is
+ shown as below:
+ {
+ message_id:
+ {
+ 'request':
+ {
+ 'message': logcat message body of data call
+ deactivation request message
+ 'time_stamp': time stamp in text format
+ 'datetime_obj': datetime object of time stamp
+ }
+ 'response':
+ {
+ 'message': logcat message body of data call
+ deactivation response message
+ 'time_stamp': time stamp in text format
+ 'datetime_obj': datetime object of time stamp
+ 'send_ack_for_serial_time': time stamp of ACK
+ 'deactivate_data_call_time': time between data call
+ deactivation request and ACK
+ }
+ }
+ }
+
+ deactivate_data_call_time_list: List. This is a summary of necessary
+ messages of data call deactivation procedure The format is shown
+ as below:
+ [
+ {
+ 'request': logcat message body of data call
+ deactivation request message
+ 'response': logcat message body of data call
+ deactivation response message
+ 'start': time stamp of data call deactivation request
+ 'end': time stamp of the ACK
+ 'duration': time between data call deactivation
+ request and ACK
+ }
+ ]
+
+ avg_deactivate_data_call_time: average of data call deactivation time
+ """
+ ad.log.info('====== Start to search logcat ====== ')
+ logcat = ad.search_logcat(r'%s\|%s' % (
+ IWLAN_DATA_SERVICE, WHI_IWLAN_DATA_SERVICE))
+
+ found_iwlan_data_service = 1
+ if not logcat:
+ found_iwlan_data_service = 0
+
+ if not found_iwlan_data_service:
+ (
+ deactivate_data_call,
+ deactivate_data_call_time_list,
+ avg_deactivate_data_call_time) = parse_deactivate_data_call(ad)
+
+ return (
+ deactivate_data_call,
+ deactivate_data_call_time_list,
+ avg_deactivate_data_call_time)
+
+ for msg in logcat:
+ ad.log.info(msg["log_message"])
+
+ deactivate_data_call = {}
+ deactivate_data_call_time_list = []
+ last_message_id = None
+
+ whi_msg_index = None
+ for line in logcat:
+ serial = None
+ if IWLAN_DEACTIVATE_DATA_CALL_REQUEST in line['log_message']:
+ match_res = re.findall(
+ r'%s:\s(\d+)' % IWLAN_DATA_SERVICE, line['log_message'])
+ if match_res:
+ try:
+ serial = match_res[0]
+ except:
+ serial = None
+
+ if not serial:
+ continue
+
+ msg_id = serial
+ last_message_id = serial
+ if msg_id not in deactivate_data_call:
+ deactivate_data_call[msg_id] = {}
+
+ deactivate_data_call[msg_id]['request'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj']}
+ else:
+ if re.search(WHI_IWLAN_DEACTIVATE_DATA_CALL_REQUEST, line[
+ 'log_message']):
+ if whi_msg_index is None:
+ whi_msg_index = 0
+ else:
+ whi_msg_index = whi_msg_index + 1
+
+ if str(whi_msg_index) not in deactivate_data_call:
+ deactivate_data_call[str(whi_msg_index)] = {}
+
+ deactivate_data_call[str(whi_msg_index)]['request'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj']}
+
+ if IWLAN_DEACTIVATE_DATA_CALL_RESPONSE in line['log_message']:
+ if 'response' not in deactivate_data_call[last_message_id]:
+ deactivate_data_call[msg_id]['response'] = {}
+
+ deactivate_data_call[msg_id]['response'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj'],
+ 'send_ack_for_serial_time': None,
+ 'deactivate_data_call_time': None}
+
+ else:
+ if re.search(WHI_IWLAN_DEACTIVATE_DATA_CALL_RESPONSE, line[
+ 'log_message']):
+ if whi_msg_index is None:
+ continue
+
+ if 'response' in deactivate_data_call[str(whi_msg_index)]:
+ ad.log.error('Duplicated deactivate data call response'
+ 'is found or the request message is lost.')
+ continue
+
+ deactivate_data_call[str(whi_msg_index)]['response'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj'],
+ 'deactivate_data_call_time': None}
+
+ deactivate_data_call_start_time = deactivate_data_call[
+ str(whi_msg_index)]['request']['datetime_obj']
+ deactivate_data_call_end_time = line['datetime_obj']
+ deactivate_data_call_time = (
+ deactivate_data_call_end_time - deactivate_data_call_start_time)
+ deactivate_data_call[str(whi_msg_index)]['response'][
+ 'deactivate_data_call_time'] = deactivate_data_call_time.total_seconds()
+ deactivate_data_call_time_list.append(
+ {'request': deactivate_data_call[str(whi_msg_index)][
+ 'request']['message'],
+ 'response': deactivate_data_call[str(whi_msg_index)][
+ 'response']['message'],
+ 'start': deactivate_data_call_start_time,
+ 'end': deactivate_data_call_end_time,
+ 'duration': deactivate_data_call_time.total_seconds()})
+
+ if IWLAN_SEND_ACK in line['log_message']:
+ match_res = re.findall(
+ r'%s:\s(\d+)' % IWLAN_DATA_SERVICE, line['log_message'])
+ if match_res:
+ try:
+ serial = match_res[0]
+ except:
+ serial = None
+
+ if not serial:
+ continue
+
+ msg_id = serial
+
+ if msg_id not in deactivate_data_call:
+ continue
+
+ if 'response' not in deactivate_data_call[msg_id]:
+ continue
+
+ deactivate_data_call[msg_id]['response'][
+ 'send_ack_for_serial_time'] = line['datetime_obj']
+
+ deactivate_data_call_start_time = deactivate_data_call[msg_id][
+ 'request']['datetime_obj']
+ deactivate_data_call_end_time = line['datetime_obj']
+ deactivate_data_call_time = (
+ deactivate_data_call_end_time - deactivate_data_call_start_time)
+ deactivate_data_call[msg_id]['response'][
+ 'deactivate_data_call_time'] = deactivate_data_call_time.total_seconds()
+ deactivate_data_call_time_list.append(
+ {'request': deactivate_data_call[msg_id]['request'][
+ 'message'],
+ 'response': deactivate_data_call[msg_id]['response'][
+ 'message'],
+ 'start': deactivate_data_call_start_time,
+ 'end': deactivate_data_call_end_time,
+ 'duration': deactivate_data_call_time.total_seconds()})
+
+ last_message_id = None
+
+ duration_list = []
+ for item in deactivate_data_call_time_list:
+ if 'duration' in item:
+ duration_list.append(item['duration'])
+
+ try:
+ avg_deactivate_data_call_time = statistics.mean(duration_list)
+ except:
+ avg_deactivate_data_call_time = None
+
+ return (
+ deactivate_data_call,
+ deactivate_data_call_time_list,
+ avg_deactivate_data_call_time)
+
+
+def parse_ims_reg(
+ ad,
+ search_intervals=None,
+ rat='4g',
+ reboot_or_apm='reboot',
+ slot=None):
+ """Search in logcat for lines containing messages about IMS registration.
+
+ Args:
+ ad: Android object
+ search_intervals: List. Only lines with time stamp in given time
+ intervals will be parsed.
+ E.g., [(begin_time1, end_time1), (begin_time2, end_time2)]
+ Both begin_time and end_time should be datetime object.
+ rat: "4g" for IMS over LTE or "iwlan" for IMS over Wi-Fi
+ reboot_or_apm: specify the scenario "reboot" or "apm"
+ slot: 0 for pSIM and 1 for eSIM
+
+ Returns:
+ (ims_reg, parsing_fail, avg_ims_reg_duration)
+
+ ims_reg: List of dictionaries containing found lines for start and
+ end time stamps. Each dict represents a cycle of the test.
+
+ [
+ {'start': message on start time stamp,
+ 'end': message on end time stamp,
+ 'duration': time difference between start and end}
+ ]
+ parsing_fail: List of dictionaries containing the cycle number and
+ missing messages of each failed cycle
+
+ [
+ 'attempt': failed cycle number
+ 'missing_msg' missing messages which should be found
+ ]
+ avg_ims_reg_duration: average of the duration in ims_reg
+
+ """
+ if slot is None:
+ slot = get_slot_index_from_voice_sub_id(ad)
+ ad.log.info('Default voice slot: %s', slot)
+ else:
+ if get_subid_from_slot_index(ad.log, ad, slot) == INVALID_SUB_ID:
+ ad.log.error('Slot %s is invalid.', slot)
+ raise signals.TestFailure('Failed',
+ extras={'fail_reason': 'Slot %s is invalid.' % slot})
+
+ ad.log.info('Assigned slot: %s', slot)
+
+ start_command = {
+ 'reboot': {
+ '0': {'4g': ON_ENABLE_APN_IMS_SLOT0,
+ 'iwlan': ON_ENABLE_APN_IMS_HANDOVER_SLOT0 + '\|' + ON_ENABLE_APN_IMS_SLOT0},
+ '1': {'4g': ON_ENABLE_APN_IMS_SLOT1,
+ 'iwlan': ON_ENABLE_APN_IMS_HANDOVER_SLOT1 + '\|' + ON_ENABLE_APN_IMS_SLOT1}
+ },
+ 'apm':{
+ '0': {'4g': RADIO_ON_4G_SLOT0, 'iwlan': RADIO_ON_IWLAN},
+ '1': {'4g': RADIO_ON_4G_SLOT1, 'iwlan': RADIO_ON_IWLAN}
+ },
+ 'wifi_off':{
+ '0': {'4g': WIFI_OFF, 'iwlan': WIFI_OFF},
+ '1': {'4g': WIFI_OFF, 'iwlan': WIFI_OFF}
+ },
+ }
+
+ end_command = {
+ '0': {'4g': ON_IMS_MM_TEL_CONNECTED_4G_SLOT0,
+ 'iwlan': ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT0},
+ '1': {'4g': ON_IMS_MM_TEL_CONNECTED_4G_SLOT1,
+ 'iwlan': ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT1}
+ }
+
+ ad.log.info('====== Start to search logcat ======')
+ logcat = ad.search_logcat('%s\|%s' % (
+ start_command[reboot_or_apm][str(slot)][rat],
+ end_command[str(slot)][rat]))
+
+ if not logcat:
+ raise signals.TestFailure('Failed',
+ extras={'fail_reason': 'No line matching the given pattern can '
+ 'be found in logcat.'})
+
+ for msg in logcat:
+ ad.log.info(msg["log_message"])
+
+ ims_reg = []
+ ims_reg_duration_list = []
+ parsing_fail = []
+
+ start_command['reboot'] = {
+ '0': {'4g': ON_ENABLE_APN_IMS_SLOT0,
+ 'iwlan': ON_ENABLE_APN_IMS_HANDOVER_SLOT0 + '|' + ON_ENABLE_APN_IMS_SLOT0},
+ '1': {'4g': ON_ENABLE_APN_IMS_SLOT1,
+ 'iwlan': ON_ENABLE_APN_IMS_HANDOVER_SLOT1 + '|' + ON_ENABLE_APN_IMS_SLOT1}
+ }
+
+ keyword_dict = {
+ 'start': start_command[reboot_or_apm][str(slot)][rat],
+ 'end': end_command[str(slot)][rat]
+ }
+
+ for attempt, interval in enumerate(search_intervals):
+ if isinstance(interval, list):
+ try:
+ begin_time, end_time = interval
+ except Exception as e:
+ ad.log.error(e)
+ continue
+
+ ad.log.info('Parsing begin time: %s', begin_time)
+ ad.log.info('Parsing end time: %s', end_time)
+
+ temp_keyword_dict = copy.deepcopy(keyword_dict)
+ for line in logcat:
+ if begin_time and line['datetime_obj'] < begin_time:
+ continue
+
+ if end_time and line['datetime_obj'] > end_time:
+ break
+
+ for key in temp_keyword_dict:
+ if temp_keyword_dict[key] and not isinstance(
+ temp_keyword_dict[key], dict):
+ res = re.findall(
+ temp_keyword_dict[key], line['log_message'])
+ if res:
+ ad.log.info('Found: %s', line['log_message'])
+ temp_keyword_dict[key] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['datetime_obj']}
+ break
+
+ for key in temp_keyword_dict:
+ if temp_keyword_dict[key] == keyword_dict[key]:
+ ad.log.error(
+ '"%s" is missing in cycle %s.',
+ keyword_dict[key],
+ attempt)
+ parsing_fail.append({
+ 'attempt': attempt,
+ 'missing_msg': keyword_dict[key]})
+ try:
+ ims_reg_duration = (
+ temp_keyword_dict['end'][
+ 'time_stamp'] - temp_keyword_dict[
+ 'start'][
+ 'time_stamp']).total_seconds()
+ ims_reg_duration_list.append(ims_reg_duration)
+ ims_reg.append({
+ 'start': temp_keyword_dict['start'][
+ 'message'],
+ 'end': temp_keyword_dict['end'][
+ 'message'],
+ 'duration': ims_reg_duration})
+ except Exception as e:
+ ad.log.error(e)
+
+ try:
+ avg_ims_reg_duration = statistics.mean(ims_reg_duration_list)
+ except:
+ avg_ims_reg_duration = None
+
+ return ims_reg, parsing_fail, avg_ims_reg_duration
+
+
+def parse_mo_sms(logcat):
+ """Search in logcat for lines containing messages about SMS sending on
+ LTE.
+
+ Args:
+ logcat: List containing lines of logcat
+
+ Returns:
+ send_sms: Dictionary containing found lines for each SMS
+ request and response messages together with their time stamps.
+ {
+ 'message_id':{
+ 'request':{
+ 'message': logcat message body of SMS request
+ 'time_stamp': time stamp in text format
+ 'datetime_obj': datetime object of the time stamp
+ },
+ 'response':{
+ 'message': logcat message body of SMS response
+ 'time_stamp': time stamp in text format
+ 'datetime_obj': datetime object of the time stamp
+ 'sms_delivery_time': time between SMS request and
+ response
+ }
+ }
+ }
+
+ summary: the format is listed below:
+ {
+ 'request': logcat message body of SMS request
+ 'response': logcat message body of SMS response
+ 'unsol_response_new_sms': unsolicited response message upon
+ SMS receiving on MT UE
+ 'sms_body': message body of SMS
+ 'mo_start': time stamp of MO SMS request message
+ 'mo_end': time stamp of MO SMS response message
+ 'mo_signal_duration': time between MO SMS request and response
+ 'delivery_time': time between MO SMS request and
+ unsol_response_new_sms on MT UE
+ }
+
+ avg_setup_time: average of mo_signal_duration
+ """
+ send_sms = {}
+ summary = []
+ sms_body = DEFAULT_MO_SMS_BODY
+ msg_id = None
+ if not logcat:
+ return False
+
+ for line in logcat:
+ res = re.findall(MO_SMS_LOGCAT_PATTERN, line['log_message'])
+ if res:
+ try:
+ sms_body = res[0]
+ except:
+ sms_body = 'Cannot find MO SMS body'
+
+ if line['message_id']:
+ msg_id = line['message_id']
+ if SEND_SMS_REQUEST in line[
+ 'log_message'] and SEND_SMS_EXPECT_MORE not in line[
+ 'log_message']:
+ if msg_id not in send_sms:
+ send_sms[msg_id] = {}
+
+ send_sms[msg_id]['sms_body'] = sms_body
+ sms_body = DEFAULT_MO_SMS_BODY
+ send_sms[msg_id]['request'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj']}
+
+ if SEND_SMS_RESPONSE in line[
+ 'log_message'] and SEND_SMS_EXPECT_MORE not in line[
+ 'log_message']:
+ if msg_id not in send_sms:
+ continue
+
+ if 'request' not in send_sms[msg_id]:
+ continue
+
+ if "error" in line['log_message']:
+ continue
+
+ send_sms[msg_id]['response'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj'],
+ 'sms_delivery_time': None}
+
+ mo_sms_start_time = send_sms[msg_id]['request'][
+ 'datetime_obj']
+ mo_sms_end_time = line['datetime_obj']
+ sms_delivery_time = mo_sms_end_time - mo_sms_start_time
+ send_sms[msg_id]['response'][
+ 'sms_delivery_time'] = sms_delivery_time.total_seconds()
+ summary.append(
+ {'request': send_sms[msg_id]['request']['message'],
+ 'response': send_sms[msg_id]['response']['message'],
+ 'unsol_response_new_sms': None,
+ 'sms_body': send_sms[msg_id]['sms_body'],
+ 'mo_start': mo_sms_start_time,
+ 'mo_end': mo_sms_end_time,
+ 'mo_signal_duration': sms_delivery_time.total_seconds(),
+ 'delivery_time': None})
+
+ duration_list = []
+ for item in summary:
+ if 'mo_signal_duration' in item:
+ duration_list.append(item['mo_signal_duration'])
+
+ try:
+ avg_setup_time = statistics.mean(duration_list)
+ except:
+ avg_setup_time = None
+
+ return send_sms, summary, avg_setup_time
+
+
+def parse_mo_sms_iwlan(logcat):
+ """Search in logcat for lines containing messages about SMS sending on
+ iwlan.
+
+ Args:
+ logcat: List containing lines of logcat
+
+ Returns:
+ send_sms: Dictionary containing found lines for each SMS
+ request and response messages together with their time stamps.
+ {
+ 'message_id':{
+ 'request':{
+ 'message': logcat message body of SMS request
+ 'time_stamp': time stamp in text format
+ 'datetime_obj': datetime object of the time stamp
+ },
+ 'response':{
+ 'message': logcat message body of SMS response
+ 'time_stamp': time stamp in text format
+ 'datetime_obj': datetime object of the time stamp
+ 'sms_delivery_time': time between SMS request and
+ response
+ }
+ }
+ }
+
+ summary: List containing dictionaries for each SMS. The format is
+ listed below:
+ [
+ {
+ 'request': logcat message body of SMS request
+ 'response': logcat message body of SMS response
+ 'sms_body': message body of SMS
+ 'mo_start': time stamp of MO SMS request message
+ 'mo_end': time stamp of MO SMS response message
+ 'mo_signal_duration': time between MO SMS request and
+ response
+ 'delivery_time': time between MO SMS request and
+ MT SMS received message
+ }
+ ]
+
+ avg_setup_time: average of mo_signal_duration
+ """
+ send_sms = {}
+ summary = []
+ sms_body = DEFAULT_MO_SMS_BODY
+ msg_id = None
+
+ if not logcat:
+ return False
+
+ for line in logcat:
+ res = re.findall(MO_SMS_LOGCAT_PATTERN, line['log_message'])
+ if res:
+ try:
+ sms_body = res[0]
+ except:
+ sms_body = 'Cannot find MO SMS body'
+
+ if SEND_SMS_REQUEST_OVER_IMS in line['log_message']:
+ if msg_id is None:
+ msg_id = '0'
+ else:
+ msg_id = str(int(msg_id) + 1)
+
+ if msg_id not in send_sms:
+ send_sms[msg_id] = {}
+
+ send_sms[msg_id]['sms_body'] = sms_body
+ sms_body = DEFAULT_MO_SMS_BODY
+ send_sms[msg_id]['request'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj']}
+
+ if SEND_SMS_RESPONSE_OVER_IMS in line['log_message']:
+
+ if msg_id not in send_sms:
+ continue
+
+ if 'request' not in send_sms[msg_id]:
+ continue
+
+ if "error" in line['log_message']:
+ continue
+
+ send_sms[msg_id]['response'] = {
+ 'message': line['log_message'],
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj'],
+ 'sms_delivery_time': None}
+
+ mo_sms_start_time = send_sms[msg_id]['request'][
+ 'datetime_obj']
+ mo_sms_end_time = line['datetime_obj']
+ sms_delivery_time = mo_sms_end_time - mo_sms_start_time
+ send_sms[msg_id]['response'][
+ 'sms_delivery_time'] = sms_delivery_time.total_seconds()
+ summary.append(
+ {'request': send_sms[msg_id]['request']['message'],
+ 'response': send_sms[msg_id]['response']['message'],
+ 'unsol_response_new_sms': None,
+ 'sms_body': send_sms[msg_id]['sms_body'],
+ 'mo_start': mo_sms_start_time,
+ 'mo_end': mo_sms_end_time,
+ 'mo_signal_duration': sms_delivery_time.total_seconds(),
+ 'delivery_time': None})
+
+ duration_list = []
+ for item in summary:
+ if 'mo_signal_duration' in item:
+ duration_list.append(item['mo_signal_duration'])
+
+ try:
+ avg_setup_time = statistics.mean(duration_list)
+ except:
+ avg_setup_time = None
+
+ return send_sms, summary, avg_setup_time
+
+
+def parse_mt_sms(logcat):
+ """Search in logcat for lines containing messages about SMS receiving on
+ LTE.
+
+ Args:
+ logcat: List containing lines of logcat
+
+ Returns:
+ received_sms_list: List containing dictionaries for each received
+ SMS. The format is listed below:
+ [
+ {
+ 'message': logcat message body of unsolicited response
+ message
+ 'sms_body': message body of SMS
+ 'time_stamp': time stamp of unsolicited response message in
+ text format
+ 'datetime_obj': datetime object of the time stamp
+ 'sms_delivery_time': time between SMS request and
+ response
+ }
+ ]
+ """
+ received_sms_list = []
+ if not logcat:
+ return False
+
+ for line in logcat:
+ if UNSOL_RESPONSE_NEW_SMS in line['log_message']:
+
+ # if received_sms_list:
+ # if received_sms_list[-1]['sms_body'] is None:
+ # del received_sms_list[-1]
+
+ received_sms_list.append(
+ {'message': line['log_message'],
+ 'sms_body': DEFAULT_MT_SMS_BODY,
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj']})
+ else:
+ res = re.findall(MT_SMS_CONTENT_PATTERN, line['log_message'])
+
+ if res:
+ try:
+ sms_body = res[0]
+ except:
+ sms_body = 'Cannot find MT SMS body'
+
+ if received_sms_list[-1]['sms_body'] == DEFAULT_MT_SMS_BODY:
+ received_sms_list[-1]['sms_body'] = sms_body
+ continue
+
+ return received_sms_list
+
+
+def parse_mt_sms_iwlan(logcat):
+ """Search in logcat for lines containing messages about SMS receiving on
+ iwlan.
+
+ Args:
+ logcat: List containing lines of logcat
+
+ Returns:
+ received_sms_list: List containing dictionaries for each received
+ SMS. The format is listed below:
+ [
+ {
+ 'message': logcat message body of SMS received message
+ 'sms_body': message body of SMS
+ 'time_stamp': time stamp of SMS received message in
+ text format
+ 'datetime_obj': datetime object of the time stamp
+ }
+ ]
+ """
+ received_sms_list = []
+ if not logcat:
+ return False
+
+ for line in logcat:
+ if re.findall(
+ SMS_RECEIVED_OVER_IMS_SLOT0 + '|' + SMS_RECEIVED_OVER_IMS_SLOT1,
+ line['log_message']):
+ received_sms_list.append(
+ {'message': line['log_message'],
+ 'sms_body': DEFAULT_MT_SMS_BODY,
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj']})
+ else:
+ res = re.findall(MT_SMS_CONTENT_PATTERN, line['log_message'])
+
+ if res:
+ try:
+ sms_body = res[0]
+ except:
+ sms_body = 'Cannot find MT SMS body'
+
+ if received_sms_list[-1]['sms_body'] == DEFAULT_MT_SMS_BODY:
+ received_sms_list[-1]['sms_body'] = sms_body
+ continue
+
+ return received_sms_list
+
+
+def parse_sms_delivery_time(log, ad_mo, ad_mt, rat='4g'):
+ """Calculate the SMS delivery time (time between MO SMS request and MT
+ unsolicited response message or MT SMS received message) from logcat
+ of both MO and MT UE.
+
+ Args:
+ ad_mo: MO Android object
+ ad_mt: MT Android object
+ rat: '4g' for LTE and 'iwlan' for iwlan
+
+ Returns:
+ None
+ """
+ ad_mo.log.info('====== Start to search logcat ====== ')
+ mo_logcat = ad_mo.search_logcat(
+ r'%s\|%s\|%s\|%s' % (
+ SMS_SEND_TEXT_MESSAGE,
+ SEND_SMS,
+ SEND_SMS_REQUEST_OVER_IMS,
+ SEND_SMS_RESPONSE_OVER_IMS))
+ ad_mt.log.info('====== Start to search logcat ====== ')
+ mt_logcat = ad_mt.search_logcat(
+ r'%s\|%s\|%s' % (
+ UNSOL_RESPONSE_NEW_SMS, SMS_RECEIVED, SMS_RECEIVED_OVER_IMS))
+
+ for msg in mo_logcat:
+ ad_mo.log.info(msg["log_message"])
+ for msg in mt_logcat:
+ ad_mt.log.info(msg["log_message"])
+
+ if rat == 'iwlan':
+ _, mo_sms_summary, avg = parse_mo_sms_iwlan(mo_logcat)
+ received_sms_list = parse_mt_sms_iwlan(mt_logcat)
+ else:
+ _, mo_sms_summary, avg = parse_mo_sms(mo_logcat)
+ received_sms_list = parse_mt_sms(mt_logcat)
+
+ sms_delivery_time = []
+ for mo_sms in mo_sms_summary:
+ for mt_sms in received_sms_list:
+ if mo_sms['sms_body'] == mt_sms['sms_body']:
+ mo_sms['delivery_time'] = (
+ mt_sms['datetime_obj'] - mo_sms['mo_start']).total_seconds()
+ mo_sms['unsol_response_new_sms'] = mt_sms['message']
+ sms_delivery_time.append(mo_sms['delivery_time'])
+
+ try:
+ avg_sms_delivery_time = statistics.mean(sms_delivery_time)
+ except:
+ avg_sms_delivery_time = None
+
+ ad_mo.log.info('====== MO SMS summary ======')
+ for item in mo_sms_summary:
+ ad_mo.log.info('------------------')
+ print_nested_dict(ad_mo, item)
+ ad_mt.log.info('====== Received SMS list ======')
+ for item in received_sms_list:
+ ad_mt.log.info('------------------')
+ print_nested_dict(ad_mt, item)
+
+ ad_mo.log.info('%s SMS were actually sent.', len(mo_sms_summary))
+ ad_mt.log.info('%s SMS were actually received.', len(received_sms_list))
+ ad_mo.log.info('Average MO SMS setup time: %.2f sec.', avg)
+ log.info(
+ 'Average SMS delivery time: %.2f sec.', avg_sms_delivery_time)
+
+
+def parse_mms(ad_mo, ad_mt):
+ """Search in logcat for lines containing messages about SMS sending and
+ receiving. Calculate MO & MT MMS setup time.
+
+ Args:
+ ad_mo: MO Android object
+ ad_mt: MT Android object
+
+ Returns:
+ send_mms: Dictionary containing each sent MMS. The format is shown
+ as below:
+ {
+ mms_msg_id:
+ {
+ MMS_START_NEW_NW_REQUEST:
+ {
+ 'time_stamp': time stamp of MMS request on MO UE in
+ text format
+ 'datetime_obj': datetime object of time stamp
+ },
+ MMS_200_OK:
+ {
+ 'time_stamp': time stamp of '200 OK' for MMS request
+ in text format
+ 'datetime_obj': datetime object of time stamp
+ 'setup_time': MO MMS setup time. Time between MMS
+ request and 200 OK
+ }
+ }
+
+ }
+
+ mo_avg_setup_time: average of MO MMS setup time
+
+ receive_mms: Dictionary containing each received MMS. The format is
+ shown as below:
+ {
+ mms_msg_id:
+ {
+ MMS_START_NEW_NW_REQUEST:
+ {
+ 'time_stamp': time stamp of MMS request on MT UE in
+ text format
+ 'datetime_obj': datetime object of time stamp
+ },
+ MMS_200_OK:
+ {
+ 'time_stamp': time stamp of '200 OK' for MMS request
+ in text format
+ 'datetime_obj': datetime object of time stamp
+ 'setup_time': MT MMS setup time. Time between MMS
+ request and 200 OK
+ }
+ }
+
+ }
+
+ mt_avg_setup_time: average of MT MMS setup time
+ """
+ send_mms = {}
+ receive_mms = {}
+ mo_setup_time_list = []
+ mt_setup_time_list = []
+
+ ad_mo.log.info('====== Start to search logcat ====== ')
+ mo_logcat = ad_mo.search_logcat(MMS_SERVICE)
+ for msg in mo_logcat:
+ ad_mo.log.info(msg["log_message"])
+
+ ad_mt.log.info('====== Start to search logcat ====== ')
+ mt_logcat = ad_mt.search_logcat(MMS_SERVICE)
+ for msg in mt_logcat:
+ ad_mt.log.info(msg["log_message"])
+
+ if not mo_logcat or not mt_logcat:
+ return False
+
+ for line in mo_logcat:
+ find_res = re.findall(
+ MMS_SEND_REQUEST_ID_PATTERN, line['log_message'])
+
+ message_id = None
+ try:
+ message_id = find_res[0]
+ except:
+ pass
+
+ if message_id:
+ mms_msg_id = message_id
+ if mms_msg_id not in send_mms:
+ send_mms[mms_msg_id] = {}
+ if MMS_START_NEW_NW_REQUEST in line['log_message']:
+ send_mms[mms_msg_id][MMS_START_NEW_NW_REQUEST] = {
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj']}
+
+ if MMS_200_OK in line['log_message']:
+ send_mms[mms_msg_id][MMS_200_OK] = {
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj'],
+ 'setup_time': None}
+
+ if MMS_START_NEW_NW_REQUEST in send_mms[mms_msg_id]:
+ setup_time = line['datetime_obj'] - send_mms[mms_msg_id][
+ MMS_START_NEW_NW_REQUEST]['datetime_obj']
+ send_mms[mms_msg_id][MMS_200_OK][
+ 'setup_time'] = setup_time.total_seconds()
+ mo_setup_time_list.append(setup_time.total_seconds())
+
+ for line in mt_logcat:
+ find_res = re.findall(
+ MMS_DOWNLOAD_REQUEST_ID_PATTERN, line['log_message'])
+
+ message_id = None
+ try:
+ message_id = find_res[0]
+ except:
+ pass
+
+ if message_id:
+ mms_msg_id = message_id
+ if mms_msg_id not in receive_mms:
+ receive_mms[mms_msg_id] = {}
+ if MMS_START_NEW_NW_REQUEST in line['log_message']:
+ receive_mms[mms_msg_id][MMS_START_NEW_NW_REQUEST] = {
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj']}
+
+ if MMS_200_OK in line['log_message']:
+ receive_mms[mms_msg_id][MMS_200_OK] = {
+ 'time_stamp': line['time_stamp'],
+ 'datetime_obj': line['datetime_obj'],
+ 'setup_time': None}
+
+ if MMS_START_NEW_NW_REQUEST in receive_mms[mms_msg_id]:
+ setup_time = line['datetime_obj'] - receive_mms[
+ mms_msg_id][MMS_START_NEW_NW_REQUEST]['datetime_obj']
+ receive_mms[mms_msg_id][MMS_200_OK][
+ 'setup_time'] = setup_time.total_seconds()
+ mt_setup_time_list.append(setup_time.total_seconds())
+
+ try:
+ mo_avg_setup_time = statistics.mean(mo_setup_time_list)
+ except:
+ mo_avg_setup_time = None
+
+ try:
+ mt_avg_setup_time = statistics.mean(mt_setup_time_list)
+ except:
+ mt_avg_setup_time = None
+
+ return send_mms, mo_avg_setup_time, receive_mms, mt_avg_setup_time
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_phone_setup_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_phone_setup_utils.py
new file mode 100644
index 0000000..6077d9c
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_phone_setup_utils.py
@@ -0,0 +1,1758 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+import time
+from acts import signals
+from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE
+from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
+from acts_contrib.test_utils.tel.tel_defines import CARRIER_FRE
+from acts_contrib.test_utils.tel.tel_defines import CARRIER_TMO
+from acts_contrib.test_utils.tel.tel_defines import GEN_2G
+from acts_contrib.test_utils.tel.tel_defines import GEN_3G
+from acts_contrib.test_utils.tel.tel_defines import GEN_4G
+from acts_contrib.test_utils.tel.tel_defines import GEN_5G
+from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_DROP
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOLTE_ENABLED
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_CDMA
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_ONLY
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_UMTS
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_CDMA_EVDO
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_ONLY
+from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
+from acts_contrib.test_utils.tel.tel_defines import RAT_5G
+from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_CDMA2000
+from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
+from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
+from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WCDMA
+from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WLAN
+from acts_contrib.test_utils.tel.tel_defines import RAT_UNKNOWN
+from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_IDLE
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_1XRTT_VOICE_ATTACH
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte_for_subscription
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode_for_subscription
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_enhanced_4g_lte_setting
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_volte_enabled
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_disabled
+from acts_contrib.test_utils.tel.tel_lookup_tables import network_preference_for_generation
+from acts_contrib.test_utils.tel.tel_lookup_tables import rat_families_for_network_preference
+from acts_contrib.test_utils.tel.tel_lookup_tables import rat_family_for_generation
+from acts_contrib.test_utils.tel.tel_lookup_tables import rat_family_from_rat
+from acts_contrib.test_utils.tel.tel_lookup_tables import rat_generation_from_rat
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
+from acts_contrib.test_utils.tel.tel_test_utils import _is_attached
+from acts_contrib.test_utils.tel.tel_test_utils import _is_attached_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state
+from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import get_cell_data_roaming_state_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
+from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
+from acts_contrib.test_utils.tel.tel_test_utils import is_droid_in_network_generation_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import is_droid_in_rat_family_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import is_droid_in_rat_family_list_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import reset_preferred_network_type_to_allowable_range
+from acts_contrib.test_utils.tel.tel_test_utils import set_cell_data_roaming_state_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import wait_for_data_attach_for_subscription
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import set_wifi_to_default
+from acts.libs.utils.multithread import multithread_func
+
+
+def phone_setup_iwlan(log,
+ ad,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid=None,
+ wifi_pwd=None,
+ nw_gen=None):
+ """Phone setup function for epdg call test.
+ Set WFC mode according to wfc_mode.
+ Set airplane mode according to is_airplane_mode.
+ Make sure phone connect to WiFi. (If wifi_ssid is not None.)
+ Wait for phone to be in iwlan data network type.
+ Wait for phone to report wfc enabled flag to be true.
+ Args:
+ log: Log object.
+ ad: Android device object.
+ is_airplane_mode: True to turn on airplane mode. False to turn off airplane mode.
+ wfc_mode: WFC mode to set to.
+ wifi_ssid: WiFi network SSID. This is optional.
+ If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi.
+ wifi_pwd: WiFi network password. This is optional.
+ nw_gen: network type selection. This is optional.
+ GEN_4G for 4G, GEN_5G for 5G or None for doing nothing.
+ Returns:
+ True if success. False if fail.
+ """
+ return phone_setup_iwlan_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad),
+ is_airplane_mode, wfc_mode,
+ wifi_ssid, wifi_pwd, nw_gen)
+
+
+def phone_setup_iwlan_for_subscription(log,
+ ad,
+ sub_id,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid=None,
+ wifi_pwd=None,
+ nw_gen=None,
+ nr_type=None):
+ """Phone setup function for epdg call test for subscription id.
+ Set WFC mode according to wfc_mode.
+ Set airplane mode according to is_airplane_mode.
+ Make sure phone connect to WiFi. (If wifi_ssid is not None.)
+ Wait for phone to be in iwlan data network type.
+ Wait for phone to report wfc enabled flag to be true.
+ Args:
+ log: Log object.
+ ad: Android device object.
+ sub_id: subscription id.
+ is_airplane_mode: True to turn on airplane mode. False to turn off airplane mode.
+ wfc_mode: WFC mode to set to.
+ wifi_ssid: WiFi network SSID. This is optional.
+ If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi.
+ wifi_pwd: WiFi network password. This is optional.
+ nw_gen: network type selection. This is optional.
+ GEN_4G for 4G, GEN_5G for 5G or None for doing nothing.
+ nr_type: NR network type
+ Returns:
+ True if success. False if fail.
+ """
+ if not get_capability_for_subscription(ad, CAPABILITY_WFC, sub_id):
+ ad.log.error("WFC is not supported, abort test.")
+ raise signals.TestSkip("WFC is not supported, abort test.")
+
+ if nw_gen:
+ if not ensure_network_generation_for_subscription(
+ log, ad, sub_id, nw_gen, voice_or_data=NETWORK_SERVICE_DATA,
+ nr_type=nr_type):
+ ad.log.error("Failed to set to %s data.", nw_gen)
+ return False
+ toggle_airplane_mode(log, ad, is_airplane_mode, strict_checking=False)
+
+ # Pause at least for 4 seconds is necessary after airplane mode was turned
+ # on due to the mechanism of deferring Wi-Fi (b/191481736)
+ if is_airplane_mode:
+ time.sleep(5)
+
+ # check if WFC supported phones
+ if wfc_mode != WFC_MODE_DISABLED and not ad.droid.imsIsWfcEnabledByPlatform(
+ ):
+ ad.log.error("WFC is not enabled on this device by checking "
+ "ImsManager.isWfcEnabledByPlatform")
+ return False
+ if wifi_ssid is not None:
+ if not ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd, apm=is_airplane_mode):
+ ad.log.error("Fail to bring up WiFi connection on %s.", wifi_ssid)
+ return False
+ else:
+ ad.log.info("WiFi network SSID not specified, available user "
+ "parameters are: wifi_network_ssid, wifi_network_ssid_2g, "
+ "wifi_network_ssid_5g")
+ if not set_wfc_mode_for_subscription(ad, wfc_mode, sub_id):
+ ad.log.error("Unable to set WFC mode to %s.", wfc_mode)
+ return False
+
+ if wfc_mode != WFC_MODE_DISABLED:
+ if not wait_for_wfc_enabled(log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
+ ad.log.error("WFC is not enabled")
+ return False
+
+ return True
+
+
+def phone_setup_iwlan_cellular_preferred(log,
+ ad,
+ wifi_ssid=None,
+ wifi_pwd=None):
+ """Phone setup function for iwlan Non-APM CELLULAR_PREFERRED test.
+ Set WFC mode according to CELLULAR_PREFERRED.
+ Set airplane mode according to False.
+ Make sure phone connect to WiFi. (If wifi_ssid is not None.)
+ Make sure phone don't report iwlan data network type.
+ Make sure phone don't report wfc enabled flag to be true.
+
+ Args:
+ log: Log object.
+ ad: Android device object.
+ wifi_ssid: WiFi network SSID. This is optional.
+ If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi.
+ wifi_pwd: WiFi network password. This is optional.
+
+ Returns:
+ True if success. False if fail.
+ """
+ toggle_airplane_mode(log, ad, False, strict_checking=False)
+ try:
+ toggle_volte(log, ad, True)
+ if not wait_for_network_generation(
+ log, ad, GEN_4G, voice_or_data=NETWORK_SERVICE_DATA):
+ if not ensure_network_generation(
+ log, ad, GEN_4G, voice_or_data=NETWORK_SERVICE_DATA):
+ ad.log.error("Fail to ensure data in 4G")
+ return False
+ except Exception as e:
+ ad.log.error(e)
+ ad.droid.telephonyToggleDataConnection(True)
+ if wifi_ssid is not None:
+ if not ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd):
+ ad.log.error("Connect to WiFi failed.")
+ return False
+ if not set_wfc_mode(log, ad, WFC_MODE_CELLULAR_PREFERRED):
+ ad.log.error("Set WFC mode failed.")
+ return False
+ if not wait_for_not_network_rat(
+ log, ad, RAT_FAMILY_WLAN, voice_or_data=NETWORK_SERVICE_DATA):
+ ad.log.error("Data rat in iwlan mode.")
+ return False
+ elif not wait_for_wfc_disabled(log, ad, MAX_WAIT_TIME_WFC_ENABLED):
+ ad.log.error("Should report wifi calling disabled within %s.",
+ MAX_WAIT_TIME_WFC_ENABLED)
+ return False
+ return True
+
+
+def phone_setup_data_for_subscription(log, ad, sub_id, network_generation,
+ nr_type=None):
+ """Setup Phone <sub_id> Data to <network_generation>
+
+ Args:
+ log: log object
+ ad: android device object
+ sub_id: subscription id
+ network_generation: network generation, e.g. GEN_2G, GEN_3G, GEN_4G, GEN_5G
+ nr_type: NR network type e.g. NSA, SA, MMWAVE
+
+ Returns:
+ 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
+ if not ensure_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ network_generation,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ nr_type=nr_type):
+ get_telephony_signal_strength(ad)
+ return False
+ return True
+
+
+def phone_setup_5g(log, ad, nr_type=None):
+ """Setup Phone default data sub_id data to 5G.
+
+ Args:
+ log: log object
+ ad: android device object
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_5g_for_subscription(log, ad,
+ get_default_data_sub_id(ad), nr_type=nr_type)
+
+
+def phone_setup_5g_for_subscription(log, ad, sub_id, nr_type=None):
+ """Setup Phone <sub_id> Data to 5G.
+
+ Args:
+ log: log object
+ ad: android device object
+ sub_id: subscription id
+ nr_type: NR network type e.g. NSA, SA, MMWAVE
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_data_for_subscription(log, ad, sub_id, GEN_5G,
+ nr_type=nr_type)
+
+
+def phone_setup_4g(log, ad):
+ """Setup Phone default data sub_id data to 4G.
+
+ Args:
+ log: log object
+ ad: android device object
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_4g_for_subscription(log, ad,
+ get_default_data_sub_id(ad))
+
+
+def phone_setup_4g_for_subscription(log, ad, sub_id):
+ """Setup Phone <sub_id> Data to 4G.
+
+ Args:
+ log: log object
+ ad: android device object
+ sub_id: subscription id
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_data_for_subscription(log, ad, sub_id, GEN_4G)
+
+
+def phone_setup_3g(log, ad):
+ """Setup Phone default data sub_id data to 3G.
+
+ Args:
+ log: log object
+ ad: android device object
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_3g_for_subscription(log, ad,
+ get_default_data_sub_id(ad))
+
+
+def phone_setup_3g_for_subscription(log, ad, sub_id):
+ """Setup Phone <sub_id> Data to 3G.
+
+ Args:
+ log: log object
+ ad: android device object
+ sub_id: subscription id
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_data_for_subscription(log, ad, sub_id, GEN_3G)
+
+
+def phone_setup_2g(log, ad):
+ """Setup Phone default data sub_id data to 2G.
+
+ Args:
+ log: log object
+ ad: android device object
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_2g_for_subscription(log, ad,
+ get_default_data_sub_id(ad))
+
+
+def phone_setup_2g_for_subscription(log, ad, sub_id):
+ """Setup Phone <sub_id> Data to 3G.
+
+ Args:
+ log: log object
+ ad: android device object
+ sub_id: subscription id
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_data_for_subscription(log, ad, sub_id, GEN_2G)
+
+
+def phone_setup_csfb(log, ad, nw_gen=GEN_4G, nr_type=None):
+ """Setup phone for CSFB call test.
+
+ Setup Phone to be in 4G mode.
+ Disabled VoLTE.
+
+ Args:
+ log: log object
+ ad: Android device object.
+ nw_gen: GEN_4G or GEN_5G
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ return phone_setup_csfb_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad), nw_gen, nr_type=nr_type)
+
+
+def phone_setup_csfb_for_subscription(log, ad, sub_id, nw_gen=GEN_4G, nr_type=None):
+ """Setup phone for CSFB call test for subscription id.
+
+ Setup Phone to be in 4G mode.
+ Disabled VoLTE.
+
+ Args:
+ log: log object
+ ad: Android device object.
+ sub_id: subscription id.
+ nw_gen: GEN_4G or GEN_5G
+ nr_type: NR network type e.g. NSA, SA, MMWAVE
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ capabilities = ad.telephony["subscription"][sub_id].get("capabilities", [])
+ if capabilities:
+ if "hide_enhanced_4g_lte" in capabilities:
+ show_enhanced_4g_lte_mode = getattr(ad, "show_enhanced_4g_lte_mode", False)
+ if show_enhanced_4g_lte_mode in ["false", "False", False]:
+ ad.log.warning("'VoLTE' option is hidden. Test will be skipped.")
+ raise signals.TestSkip("'VoLTE' option is hidden. Test will be skipped.")
+
+ if nw_gen == GEN_4G:
+ if not phone_setup_4g_for_subscription(log, ad, sub_id):
+ ad.log.error("Failed to set to 4G data.")
+ return False
+ elif nw_gen == GEN_5G:
+ if not phone_setup_5g_for_subscription(log, ad, sub_id, nr_type=nr_type):
+ ad.log.error("Failed to set to 5G data.")
+ return False
+
+ if not toggle_volte_for_subscription(log, ad, sub_id, False):
+ return False
+
+ if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
+ MAX_WAIT_TIME_NW_SELECTION):
+ return False
+
+ return phone_idle_csfb_for_subscription(log, ad, sub_id, nw_gen)
+
+
+def phone_setup_volte(log, ad, nw_gen=GEN_4G, nr_type=None):
+ """Setup VoLTE enable.
+
+ Args:
+ log: log object
+ ad: android device object.
+ nw_gen: GEN_4G or GEN_5G
+
+ Returns:
+ True: if VoLTE is enabled successfully.
+ False: for errors
+ """
+ if not get_capability_for_subscription(ad, CAPABILITY_VOLTE,
+ get_outgoing_voice_sub_id(ad)):
+ ad.log.error("VoLTE is not supported, abort test.")
+ raise signals.TestSkip("VoLTE is not supported, abort test.")
+ return phone_setup_volte_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad), nw_gen, nr_type= nr_type)
+
+
+def phone_setup_volte_for_subscription(log, ad, sub_id, nw_gen=GEN_4G,
+ nr_type=None):
+ """Setup VoLTE enable for subscription id.
+ Args:
+ log: log object
+ ad: android device object.
+ sub_id: subscription id.
+ nw_gen: GEN_4G or GEN_5G.
+ nr_type: NR network type.
+
+ Returns:
+ True: if VoLTE is enabled successfully.
+ False: for errors
+ """
+ if not get_capability_for_subscription(ad, CAPABILITY_VOLTE,
+ get_outgoing_voice_sub_id(ad)):
+ ad.log.error("VoLTE is not supported, abort test.")
+ raise signals.TestSkip("VoLTE is not supported, abort test.")
+
+ if nw_gen == GEN_4G:
+ if not phone_setup_4g_for_subscription(log, ad, sub_id):
+ ad.log.error("Failed to set to 4G data.")
+ return False
+ elif nw_gen == GEN_5G:
+ if not phone_setup_5g_for_subscription(log, ad, sub_id,
+ nr_type=nr_type):
+ ad.log.error("Failed to set to 5G data.")
+ return False
+ operator_name = get_operator_name(log, ad, sub_id)
+ if operator_name == CARRIER_TMO:
+ return True
+ else:
+ if not wait_for_enhanced_4g_lte_setting(log, ad, sub_id):
+ ad.log.error("Enhanced 4G LTE setting is not available")
+ return False
+ toggle_volte_for_subscription(log, ad, sub_id, True)
+ return phone_idle_volte_for_subscription(log, ad, sub_id, nw_gen,
+ nr_type=nr_type)
+
+
+def phone_setup_voice_3g(log, ad):
+ """Setup phone voice to 3G.
+
+ Args:
+ log: log object
+ ad: Android device object.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ return phone_setup_voice_3g_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_setup_voice_3g_for_subscription(log, ad, sub_id):
+ """Setup phone voice to 3G for subscription id.
+
+ Args:
+ log: log object
+ ad: Android device object.
+ sub_id: subscription id.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ if not phone_setup_3g_for_subscription(log, ad, sub_id):
+ ad.log.error("Failed to set to 3G data.")
+ return False
+ if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
+ MAX_WAIT_TIME_NW_SELECTION):
+ return False
+ return phone_idle_3g_for_subscription(log, ad, sub_id)
+
+
+def phone_setup_voice_2g(log, ad):
+ """Setup phone voice to 2G.
+
+ Args:
+ log: log object
+ ad: Android device object.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ return phone_setup_voice_2g_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_setup_voice_2g_for_subscription(log, ad, sub_id):
+ """Setup phone voice to 2G for subscription id.
+
+ Args:
+ log: log object
+ ad: Android device object.
+ sub_id: subscription id.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ if not phone_setup_2g_for_subscription(log, ad, sub_id):
+ ad.log.error("Failed to set to 2G data.")
+ return False
+ if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
+ MAX_WAIT_TIME_NW_SELECTION):
+ return False
+ return phone_idle_2g_for_subscription(log, ad, sub_id)
+
+
+def phone_setup_voice_general(log, ad):
+ """Setup phone for voice general call test.
+
+ Make sure phone attached to voice.
+ Make necessary delay.
+
+ Args:
+ ad: Android device object.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ return phone_setup_voice_general_for_subscription(
+ log, ad, get_outgoing_voice_sub_id(ad))
+
+
+def phone_setup_voice_general_for_slot(log,ad,slot_id):
+ return phone_setup_voice_general_for_subscription(
+ log, ad, get_subid_from_slot_index(log,ad,slot_id))
+
+
+def phone_setup_voice_general_for_subscription(log, ad, sub_id):
+ """Setup phone for voice general call test for subscription id.
+
+ Make sure phone attached to voice.
+ Make necessary delay.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ toggle_airplane_mode(log, ad, False, strict_checking=False)
+ if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
+ MAX_WAIT_TIME_NW_SELECTION):
+ # if phone can not attach voice, try phone_setup_voice_3g
+ return phone_setup_voice_3g_for_subscription(log, ad, sub_id)
+ return True
+
+
+def phone_setup_data_general(log, ad):
+ """Setup phone for data general test.
+
+ Make sure phone attached to data.
+ Make necessary delay.
+
+ Args:
+ ad: Android device object.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ return phone_setup_data_general_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultDataSubId())
+
+
+def phone_setup_data_general_for_subscription(log, ad, sub_id):
+ """Setup phone for data general test for subscription id.
+
+ Make sure phone attached to data.
+ Make necessary delay.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ toggle_airplane_mode(log, ad, False, strict_checking=False)
+ if not wait_for_data_attach_for_subscription(log, ad, sub_id,
+ MAX_WAIT_TIME_NW_SELECTION):
+ # if phone can not attach data, try reset network preference settings
+ reset_preferred_network_type_to_allowable_range(log, ad)
+
+ return wait_for_data_attach_for_subscription(log, ad, sub_id,
+ MAX_WAIT_TIME_NW_SELECTION)
+
+
+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
+ return ensure_network_rat_for_subscription(log, ad, sub_id,
+ network_preference, rat_family)
+
+
+def phone_setup_lte_gsm_wcdma(log, ad):
+ return phone_setup_lte_gsm_wcdma_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId())
+
+
+def phone_setup_lte_gsm_wcdma_for_subscription(log, ad, sub_id):
+ return phone_setup_rat_for_subscription(
+ log, ad, sub_id, NETWORK_MODE_LTE_GSM_WCDMA, RAT_FAMILY_LTE)
+
+
+def phone_setup_gsm_umts(log, ad):
+ return phone_setup_gsm_umts_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId())
+
+
+def phone_setup_gsm_umts_for_subscription(log, ad, sub_id):
+ return phone_setup_rat_for_subscription(
+ log, ad, sub_id, NETWORK_MODE_GSM_UMTS, RAT_FAMILY_WCDMA)
+
+
+def phone_setup_gsm_only(log, ad):
+ return phone_setup_gsm_only_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId())
+
+
+def phone_setup_gsm_only_for_subscription(log, ad, sub_id):
+ return phone_setup_rat_for_subscription(
+ log, ad, sub_id, NETWORK_MODE_GSM_ONLY, RAT_FAMILY_GSM)
+
+
+def phone_setup_lte_cdma_evdo(log, ad):
+ return phone_setup_lte_cdma_evdo_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId())
+
+
+def phone_setup_lte_cdma_evdo_for_subscription(log, ad, sub_id):
+ return phone_setup_rat_for_subscription(
+ log, ad, sub_id, NETWORK_MODE_LTE_CDMA_EVDO, RAT_FAMILY_LTE)
+
+
+def phone_setup_cdma(log, ad):
+ return phone_setup_cdma_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId())
+
+
+def phone_setup_cdma_for_subscription(log, ad, sub_id):
+ return phone_setup_rat_for_subscription(log, ad, sub_id, NETWORK_MODE_CDMA,
+ RAT_FAMILY_CDMA2000)
+
+
+def phone_idle_volte(log, ad):
+ """Return if phone is idle for VoLTE call test.
+
+ Args:
+ ad: Android device object.
+ """
+ return phone_idle_volte_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_idle_volte_for_subscription(log, ad, sub_id, nw_gen=GEN_4G,
+ nr_type=None):
+ """Return if phone is idle for VoLTE call test for subscription id.
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ nw_gen: GEN_4G or GEN_5G.
+ nr_type: NR network type e.g. NSA, SA, MMWAVE
+ """
+ if nw_gen == GEN_5G:
+ if not is_current_network_5g(ad, sub_id=sub_id, nr_type=nr_type):
+ ad.log.error("Not in 5G coverage.")
+ return False
+ else:
+ if not wait_for_network_rat_for_subscription(
+ log, ad, sub_id, RAT_FAMILY_LTE,
+ voice_or_data=NETWORK_SERVICE_VOICE):
+ ad.log.error("Voice rat not in LTE mode.")
+ return False
+ if not wait_for_volte_enabled(log, ad, MAX_WAIT_TIME_VOLTE_ENABLED, sub_id):
+ ad.log.error(
+ "Failed to <report volte enabled true> within %s seconds.",
+ MAX_WAIT_TIME_VOLTE_ENABLED)
+ return False
+ return True
+
+
+def phone_idle_iwlan(log, ad):
+ """Return if phone is idle for WiFi calling call test.
+
+ Args:
+ ad: Android device object.
+ """
+ return phone_idle_iwlan_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_idle_iwlan_for_subscription(log, ad, sub_id):
+ """Return if phone is idle for WiFi calling call test for subscription id.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ """
+ if not wait_for_wfc_enabled(log, ad, MAX_WAIT_TIME_WFC_ENABLED):
+ ad.log.error("Failed to <report wfc enabled true> within %s seconds.",
+ MAX_WAIT_TIME_WFC_ENABLED)
+ return False
+ return True
+
+
+def phone_idle_not_iwlan(log, ad):
+ """Return if phone is idle for non WiFi calling call test.
+
+ Args:
+ ad: Android device object.
+ """
+ return phone_idle_not_iwlan_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_idle_not_iwlan_for_subscription(log, ad, sub_id):
+ """Return if phone is idle for non WiFi calling call test for sub id.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ """
+ if not wait_for_not_network_rat_for_subscription(
+ log, ad, sub_id, RAT_FAMILY_WLAN,
+ voice_or_data=NETWORK_SERVICE_DATA):
+ log.error("{} data rat in iwlan mode.".format(ad.serial))
+ return False
+ return True
+
+
+def phone_idle_csfb(log, ad):
+ """Return if phone is idle for CSFB call test.
+
+ Args:
+ ad: Android device object.
+ """
+ return phone_idle_csfb_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_idle_csfb_for_subscription(log, ad, sub_id, nw_gen=GEN_4G, nr_type=None):
+ """Return if phone is idle for CSFB call test for subscription id.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ nw_gen: GEN_4G or GEN_5G
+ """
+ if nw_gen == GEN_5G:
+ if not is_current_network_5g(ad, sub_id=sub_id, nr_type=nr_type):
+ ad.log.error("Not in 5G coverage.")
+ return False
+ else:
+ if not wait_for_network_rat_for_subscription(
+ log, ad, sub_id, RAT_FAMILY_LTE,
+ voice_or_data=NETWORK_SERVICE_DATA):
+ ad.log.error("Data rat not in lte mode.")
+ return False
+ return True
+
+
+def phone_idle_3g(log, ad):
+ """Return if phone is idle for 3G call test.
+
+ Args:
+ ad: Android device object.
+ """
+ return phone_idle_3g_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_idle_3g_for_subscription(log, ad, sub_id):
+ """Return if phone is idle for 3G call test for subscription id.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ """
+ return wait_for_network_generation_for_subscription(
+ log, ad, sub_id, GEN_3G, voice_or_data=NETWORK_SERVICE_VOICE)
+
+
+def phone_idle_2g(log, ad):
+ """Return if phone is idle for 2G call test.
+
+ Args:
+ ad: Android device object.
+ """
+ return phone_idle_2g_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_idle_2g_for_subscription(log, ad, sub_id):
+ """Return if phone is idle for 2G call test for subscription id.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ """
+ return wait_for_network_generation_for_subscription(
+ log, ad, sub_id, GEN_2G, voice_or_data=NETWORK_SERVICE_VOICE)
+
+
+def phone_setup_on_rat(
+ log,
+ ad,
+ rat='volte',
+ sub_id=None,
+ is_airplane_mode=False,
+ wfc_mode=None,
+ wifi_ssid=None,
+ wifi_pwd=None,
+ only_return_fn=None,
+ sub_id_type='voice',
+ nr_type='nsa'):
+
+ if sub_id is None:
+ if sub_id_type == 'sms':
+ sub_id = get_outgoing_message_sub_id(ad)
+ else:
+ sub_id = get_outgoing_voice_sub_id(ad)
+
+ if get_default_data_sub_id(ad) != sub_id and '5g' in rat.lower():
+ ad.log.warning('Default data sub ID is NOT given sub ID %s.', sub_id)
+ network_preference = network_preference_for_generation(
+ GEN_5G,
+ ad.telephony["subscription"][sub_id]["operator"],
+ ad.telephony["subscription"][sub_id]["phone_type"])
+
+ ad.log.info("Network preference for %s is %s", GEN_5G,
+ network_preference)
+
+ if not set_preferred_network_mode_pref(log, ad, sub_id,
+ network_preference):
+ return False
+
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_5G,
+ max_wait_time=30,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ nr_type=nr_type):
+
+ ad.log.warning('Non-DDS slot (sub ID: %s) cannot attach 5G network.', sub_id)
+ ad.log.info('Check if sub ID %s can attach LTE network.', sub_id)
+
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_4G,
+ voice_or_data=NETWORK_SERVICE_DATA):
+ return False
+
+ if "volte" in rat.lower():
+ phone_setup_volte_for_subscription(log, ad, sub_id, None)
+ elif "wfc" in rat.lower():
+ return phone_setup_iwlan_for_subscription(
+ log,
+ ad,
+ sub_id,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid,
+ wifi_pwd)
+ elif "csfb" in rat.lower():
+ return phone_setup_csfb_for_subscription(log, ad, sub_id, None)
+ return True
+
+ if rat.lower() == '5g_volte':
+ if only_return_fn:
+ return phone_setup_volte_for_subscription
+ else:
+ return phone_setup_volte_for_subscription(log, ad, sub_id, GEN_5G, nr_type='nsa')
+
+ elif rat.lower() == '5g_nsa_mmw_volte':
+ if only_return_fn:
+ return phone_setup_volte_for_subscription
+ else:
+ return phone_setup_volte_for_subscription(log, ad, sub_id, GEN_5G,
+ nr_type='mmwave')
+
+ elif rat.lower() == '5g_csfb':
+ if only_return_fn:
+ return phone_setup_csfb_for_subscription
+ else:
+ return phone_setup_csfb_for_subscription(log, ad, sub_id, GEN_5G, nr_type='nsa')
+
+ elif rat.lower() == '5g_wfc':
+ if only_return_fn:
+ return phone_setup_iwlan_for_subscription
+ else:
+ return phone_setup_iwlan_for_subscription(
+ log,
+ ad,
+ sub_id,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid,
+ wifi_pwd,
+ GEN_5G,
+ nr_type='nsa')
+
+ elif rat.lower() == '5g_nsa_mmw_wfc':
+ if only_return_fn:
+ return phone_setup_iwlan_for_subscription
+ else:
+ return phone_setup_iwlan_for_subscription(
+ log,
+ ad,
+ sub_id,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid,
+ wifi_pwd,
+ GEN_5G,
+ nr_type='mmwave')
+
+ elif rat.lower() == 'volte':
+ if only_return_fn:
+ return phone_setup_volte_for_subscription
+ else:
+ return phone_setup_volte_for_subscription(log, ad, sub_id)
+
+ elif rat.lower() == 'csfb':
+ if only_return_fn:
+ return phone_setup_csfb_for_subscription
+ else:
+ return phone_setup_csfb_for_subscription(log, ad, sub_id)
+
+ elif rat.lower() == '5g':
+ if only_return_fn:
+ return phone_setup_5g_for_subscription
+ else:
+ return phone_setup_5g_for_subscription(log, ad, sub_id, nr_type='nsa')
+
+ elif rat.lower() == '5g_nsa_mmwave':
+ if only_return_fn:
+ return phone_setup_5g_for_subscription
+ else:
+ return phone_setup_5g_for_subscription(log, ad, sub_id,
+ nr_type='mmwave')
+
+ elif rat.lower() == '3g':
+ if only_return_fn:
+ return phone_setup_voice_3g_for_subscription
+ else:
+ return phone_setup_voice_3g_for_subscription(log, ad, sub_id)
+
+ elif rat.lower() == '2g':
+ if only_return_fn:
+ return phone_setup_voice_2g_for_subscription
+ else:
+ return phone_setup_voice_2g_for_subscription(log, ad, sub_id)
+
+ elif rat.lower() == 'wfc':
+ if only_return_fn:
+ return phone_setup_iwlan_for_subscription
+ else:
+ return phone_setup_iwlan_for_subscription(
+ log,
+ ad,
+ sub_id,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid,
+ wifi_pwd)
+ elif rat.lower() == 'default':
+ if only_return_fn:
+ return ensure_phone_default_state
+ else:
+ return ensure_phone_default_state(log, ad)
+ else:
+ if only_return_fn:
+ return phone_setup_voice_general_for_subscription
+ else:
+ return phone_setup_voice_general_for_subscription(log, ad, sub_id)
+
+
+def wait_for_network_idle(
+ log,
+ ad,
+ rat,
+ sub_id,
+ nr_type='nsa'):
+ """Wait for attaching to network with assigned RAT and IMS/WFC registration
+
+ This function can be used right after network service recovery after turning
+ off airplane mode or switching DDS. It will ensure DUT has attached to the
+ network with assigned RAT, and VoLTE/WFC has been ready.
+
+ Args:
+ log: log object
+ ad: Android object
+ rat: following RAT are supported:
+ - 5g
+ - 5g_volte
+ - 5g_csfb
+ - 5g_wfc
+ - 4g (LTE)
+ - volte (LTE)
+ - csfb (LTE)
+ - wfc (LTE)
+
+ Returns:
+ True or False
+ """
+ if get_default_data_sub_id(ad) != sub_id and '5g' in rat.lower():
+ ad.log.warning('Default data sub ID is NOT given sub ID %s.', sub_id)
+ network_preference = network_preference_for_generation(
+ GEN_5G,
+ ad.telephony["subscription"][sub_id]["operator"],
+ ad.telephony["subscription"][sub_id]["phone_type"])
+
+ ad.log.info("Network preference for %s is %s", GEN_5G,
+ network_preference)
+
+ if not set_preferred_network_mode_pref(log, ad, sub_id,
+ network_preference):
+ return False
+
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_5G,
+ max_wait_time=30,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ nr_type=nr_type):
+
+ ad.log.warning('Non-DDS slot (sub ID: %s) cannot attach 5G network.', sub_id)
+ ad.log.info('Check if sub ID %s can attach LTE network.', sub_id)
+
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_4G,
+ voice_or_data=NETWORK_SERVICE_DATA):
+ return False
+
+ if rat.lower() == '5g':
+ rat = '4g'
+ elif rat.lower() == '5g_volte':
+ rat = 'volte'
+ elif rat.lower() == '5g_wfc':
+ rat = 'wfc'
+ elif rat.lower() == '5g_csfb':
+ rat = 'csfb'
+
+ if rat.lower() == '5g_volte':
+ if not phone_idle_volte_for_subscription(log, ad, sub_id, GEN_5G, nr_type=nr_type):
+ return False
+ elif rat.lower() == '5g_csfb':
+ if not phone_idle_csfb_for_subscription(log, ad, sub_id, GEN_5G, nr_type=nr_type):
+ return False
+ elif rat.lower() == '5g_wfc':
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_5G,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ nr_type=nr_type):
+ return False
+ if not wait_for_wfc_enabled(log, ad):
+ return False
+ elif rat.lower() == '5g':
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_5G,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ nr_type=nr_type):
+ return False
+ elif rat.lower() == 'volte':
+ if not phone_idle_volte_for_subscription(log, ad, sub_id, GEN_4G):
+ return False
+ elif rat.lower() == 'csfb':
+ if not phone_idle_csfb_for_subscription(log, ad, sub_id, GEN_4G):
+ return False
+ elif rat.lower() == 'wfc':
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_4G,
+ voice_or_data=NETWORK_SERVICE_DATA):
+ return False
+ if not wait_for_wfc_enabled(log, ad):
+ return False
+ elif rat.lower() == '4g':
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_4G,
+ voice_or_data=NETWORK_SERVICE_DATA):
+ return False
+ return True
+
+
+def ensure_preferred_network_type_for_subscription(
+ ad,
+ network_preference
+ ):
+ sub_id = ad.droid.subscriptionGetDefaultSubId()
+ if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
+ network_preference, sub_id):
+ ad.log.error("Set sub_id %s Preferred Networks Type %s failed.",
+ sub_id, network_preference)
+ return True
+
+
+def ensure_network_rat(log,
+ ad,
+ network_preference,
+ rat_family,
+ voice_or_data=None,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ toggle_apm_after_setting=False):
+ """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)
+
+
+def ensure_network_rat_for_subscription(
+ log,
+ ad,
+ sub_id,
+ network_preference,
+ rat_family,
+ voice_or_data=None,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ toggle_apm_after_setting=False):
+ """Ensure ad's current network is in expected rat_family.
+ """
+ if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
+ network_preference, sub_id):
+ ad.log.error("Set sub_id %s Preferred Networks Type %s failed.",
+ sub_id, network_preference)
+ return False
+ if is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family,
+ voice_or_data):
+ ad.log.info("Sub_id %s in RAT %s for %s", sub_id, rat_family,
+ voice_or_data)
+ return True
+
+ if toggle_apm_after_setting:
+ toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ toggle_airplane_mode(log, ad, new_state=None, strict_checking=False)
+
+ result = wait_for_network_rat_for_subscription(
+ log, ad, sub_id, rat_family, max_wait_time, voice_or_data)
+
+ log.info(
+ "End of ensure_network_rat_for_subscription for %s. "
+ "Setting to %s, Expecting %s %s. Current: voice: %s(family: %s), "
+ "data: %s(family: %s)", ad.serial, network_preference, rat_family,
+ voice_or_data,
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
+ rat_family_from_rat(
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
+ sub_id)),
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
+ rat_family_from_rat(
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
+ sub_id)))
+ return result
+
+
+def ensure_network_preference(log,
+ ad,
+ network_preference,
+ voice_or_data=None,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ toggle_apm_after_setting=False):
+ """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,
+ voice_or_data, max_wait_time, toggle_apm_after_setting)
+
+
+def ensure_network_preference_for_subscription(
+ log,
+ ad,
+ sub_id,
+ network_preference,
+ voice_or_data=None,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ toggle_apm_after_setting=False):
+ """Ensure ad's network preference is <network_preference> for sub_id.
+ """
+ rat_family_list = rat_families_for_network_preference(network_preference)
+ if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
+ network_preference, sub_id):
+ log.error("Set Preferred Networks failed.")
+ return False
+ if is_droid_in_rat_family_list_for_subscription(
+ log, ad, sub_id, rat_family_list, voice_or_data):
+ return True
+
+ if toggle_apm_after_setting:
+ toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ toggle_airplane_mode(log, ad, new_state=False, strict_checking=False)
+
+ result = wait_for_preferred_network_for_subscription(
+ log, ad, sub_id, network_preference, max_wait_time, voice_or_data)
+
+ ad.log.info(
+ "End of ensure_network_preference_for_subscription. "
+ "Setting to %s, Expecting %s %s. Current: voice: %s(family: %s), "
+ "data: %s(family: %s)", network_preference, rat_family_list,
+ voice_or_data,
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
+ rat_family_from_rat(
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
+ sub_id)),
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
+ rat_family_from_rat(
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
+ sub_id)))
+ return result
+
+
+def ensure_network_generation(log,
+ ad,
+ generation,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None,
+ toggle_apm_after_setting=False,
+ nr_type=None):
+ """Ensure ad's network is <network generation> for default subscription ID.
+
+ Set preferred network generation to <generation>.
+ Toggle ON/OFF airplane mode if necessary.
+ 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, nr_type=nr_type)
+
+
+def ensure_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ generation,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None,
+ toggle_apm_after_setting=False,
+ nr_type=None):
+ """Ensure ad's network is <network generation> for specified subscription ID.
+
+ Set preferred network generation to <generation>.
+ Toggle ON/OFF airplane mode if necessary.
+ Wait for ad in expected network type.
+
+ Args:
+ log: log object.
+ ad: android device object.
+ sub_id: subscription id.
+ generation: network generation, e.g. GEN_2G, GEN_3G, GEN_4G, GEN_5G.
+ max_wait_time: the time to wait for NW selection.
+ voice_or_data: check voice network generation or data network generation
+ This parameter is optional. If voice_or_data is None, then if
+ either voice or data in expected generation, function will return True.
+ toggle_apm_after_setting: Cycle airplane mode if True, otherwise do nothing.
+
+ Returns:
+ True if success, False if fail.
+ """
+ ad.log.info(
+ "RAT network type voice: %s, data: %s",
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id))
+
+ try:
+ ad.log.info("Finding the network preference for generation %s for "
+ "operator %s phone type %s", generation,
+ ad.telephony["subscription"][sub_id]["operator"],
+ ad.telephony["subscription"][sub_id]["phone_type"])
+ network_preference = network_preference_for_generation(
+ generation, ad.telephony["subscription"][sub_id]["operator"],
+ ad.telephony["subscription"][sub_id]["phone_type"])
+ if ad.telephony["subscription"][sub_id]["operator"] == CARRIER_FRE \
+ and generation == GEN_4G:
+ network_preference = NETWORK_MODE_LTE_ONLY
+ ad.log.info("Network preference for %s is %s", generation,
+ network_preference)
+ rat_family = rat_family_for_generation(
+ generation, ad.telephony["subscription"][sub_id]["operator"],
+ ad.telephony["subscription"][sub_id]["phone_type"])
+ except KeyError as e:
+ ad.log.error("Failed to find a rat_family entry for generation %s"
+ " for subscriber id %s with error %s", generation,
+ sub_id, e)
+ return False
+
+ if not set_preferred_network_mode_pref(log, ad, sub_id,
+ network_preference):
+ return False
+
+ if hasattr(ad, "dsds") and voice_or_data == "data" and sub_id != get_default_data_sub_id(ad):
+ ad.log.info("MSIM - Non DDS, ignore data RAT")
+ return True
+
+ if (generation == GEN_5G) or (generation == RAT_5G):
+ if is_current_network_5g(ad, sub_id=sub_id, nr_type=nr_type):
+ ad.log.info("Current network type is 5G.")
+ return True
+ else:
+ ad.log.error("Not in 5G coverage for Sub %s.", sub_id)
+ return False
+
+ if is_droid_in_network_generation_for_subscription(
+ log, ad, sub_id, generation, voice_or_data):
+ return True
+
+ if toggle_apm_after_setting:
+ toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ toggle_airplane_mode(log, ad, new_state=False, strict_checking=False)
+
+ result = wait_for_network_generation_for_subscription(
+ log, ad, sub_id, generation, max_wait_time, voice_or_data)
+
+ ad.log.info(
+ "Ensure network %s %s %s. With network preference %s, "
+ "current: voice: %s(family: %s), data: %s(family: %s)", generation,
+ voice_or_data, result, network_preference,
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
+ rat_generation_from_rat(
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
+ sub_id)),
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
+ rat_generation_from_rat(
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
+ sub_id)))
+ if not result:
+ get_telephony_signal_strength(ad)
+ return result
+
+
+def wait_for_network_rat(log,
+ ad,
+ rat_family,
+ 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)
+
+
+def wait_for_network_rat_for_subscription(
+ log,
+ ad,
+ sub_id,
+ rat_family,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None):
+ return _wait_for_droid_in_state_for_subscription(
+ log, ad, sub_id, max_wait_time,
+ is_droid_in_rat_family_for_subscription, rat_family, voice_or_data)
+
+
+def wait_for_not_network_rat(log,
+ ad,
+ rat_family,
+ 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)
+
+
+def wait_for_not_network_rat_for_subscription(
+ log,
+ ad,
+ sub_id,
+ rat_family,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None):
+ return _wait_for_droid_in_state_for_subscription(
+ log, ad, sub_id, max_wait_time,
+ lambda log, ad, sub_id, *args, **kwargs: not is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family, voice_or_data)
+ )
+
+
+def wait_for_preferred_network(log,
+ ad,
+ network_preference,
+ 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,
+ max_wait_time, voice_or_data)
+
+
+def wait_for_preferred_network_for_subscription(
+ log,
+ ad,
+ sub_id,
+ network_preference,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None):
+ rat_family_list = rat_families_for_network_preference(network_preference)
+ return _wait_for_droid_in_state_for_subscription(
+ log, ad, sub_id, max_wait_time,
+ is_droid_in_rat_family_list_for_subscription, rat_family_list,
+ voice_or_data)
+
+
+def wait_for_network_generation(log,
+ ad,
+ generation,
+ 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)
+
+
+def wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ generation,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None,
+ nr_type=None):
+
+ if generation == GEN_5G:
+ if is_current_network_5g(ad, sub_id=sub_id, nr_type=nr_type):
+ ad.log.info("Current network type is 5G.")
+ return True
+ else:
+ ad.log.error("Not in 5G coverage for Sub %s.", sub_id)
+ return False
+
+ return _wait_for_droid_in_state_for_subscription(
+ log, ad, sub_id, max_wait_time,
+ is_droid_in_network_generation_for_subscription, generation,
+ voice_or_data)
+
+
+def ensure_phones_idle(log, ads, max_time=MAX_WAIT_TIME_CALL_DROP):
+ """Ensure ads idle (not in call).
+ """
+ result = True
+ for ad in ads:
+ if not ensure_phone_idle(log, ad, max_time=max_time):
+ result = False
+ return result
+
+
+def ensure_phone_idle(log, ad, max_time=MAX_WAIT_TIME_CALL_DROP, retry=2):
+ """Ensure ad idle (not in call).
+ """
+ while ad.droid.telecomIsInCall() and retry > 0:
+ ad.droid.telecomEndCall()
+ time.sleep(3)
+ retry -= 1
+ if not wait_for_droid_not_in_call(log, ad, max_time=max_time):
+ ad.log.error("Failed to end call")
+ return False
+ return True
+
+
+def ensure_phone_subscription(log, ad):
+ """Ensure Phone Subscription.
+ """
+ #check for sim and service
+ duration = 0
+ while duration < MAX_WAIT_TIME_NW_SELECTION:
+ subInfo = ad.droid.subscriptionGetAllSubInfoList()
+ if subInfo and len(subInfo) >= 1:
+ ad.log.debug("Find valid subcription %s", subInfo)
+ break
+ else:
+ ad.log.info("Did not find any subscription")
+ time.sleep(5)
+ duration += 5
+ else:
+ ad.log.error("Unable to find a valid subscription!")
+ return False
+ while duration < MAX_WAIT_TIME_NW_SELECTION:
+ data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
+ voice_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
+ if data_sub_id > INVALID_SUB_ID or voice_sub_id > INVALID_SUB_ID:
+ ad.log.debug("Find valid voice or data sub id")
+ break
+ else:
+ ad.log.info("Did not find valid data or voice sub id")
+ time.sleep(5)
+ duration += 5
+ else:
+ ad.log.error("Unable to find valid data or voice sub id")
+ return False
+ while duration < MAX_WAIT_TIME_NW_SELECTION:
+ data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
+ if data_sub_id > INVALID_SUB_ID:
+ data_rat = get_network_rat_for_subscription(
+ log, ad, data_sub_id, NETWORK_SERVICE_DATA)
+ else:
+ data_rat = RAT_UNKNOWN
+ if voice_sub_id > INVALID_SUB_ID:
+ voice_rat = get_network_rat_for_subscription(
+ log, ad, voice_sub_id, NETWORK_SERVICE_VOICE)
+ else:
+ voice_rat = RAT_UNKNOWN
+ if data_rat != RAT_UNKNOWN or voice_rat != RAT_UNKNOWN:
+ ad.log.info("Data sub_id %s in %s, voice sub_id %s in %s",
+ data_sub_id, data_rat, voice_sub_id, voice_rat)
+ return True
+ else:
+ ad.log.info("Did not attach for data or voice service")
+ time.sleep(5)
+ duration += 5
+ else:
+ ad.log.error("Did not attach for voice or data service")
+ return False
+
+
+def ensure_phone_default_state(log, ad, check_subscription=True, retry=2):
+ """Ensure ad in default state.
+ Phone not in call.
+ Phone have no stored WiFi network and WiFi disconnected.
+ Phone not in airplane mode.
+ """
+ result = True
+ if not toggle_airplane_mode(log, ad, False, False):
+ ad.log.error("Fail to turn off airplane mode")
+ result = False
+ try:
+ set_wifi_to_default(log, ad)
+ while ad.droid.telecomIsInCall() and retry > 0:
+ ad.droid.telecomEndCall()
+ time.sleep(3)
+ retry -= 1
+ if not wait_for_droid_not_in_call(log, ad):
+ ad.log.error("Failed to end call")
+ #ad.droid.telephonyFactoryReset()
+ 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,
+ RAT_FAMILY_WLAN)
+ result = False
+
+ if check_subscription and not ensure_phone_subscription(log, ad):
+ ad.log.error("Unable to find a valid subscription!")
+ result = False
+ except Exception as e:
+ ad.log.error("%s failure, toggle APM instead", e)
+ toggle_airplane_mode_by_adb(log, ad, True)
+ toggle_airplane_mode_by_adb(log, ad, False)
+ ad.send_keycode("ENDCALL")
+ ad.adb.shell("settings put global wfc_ims_enabled 0")
+ ad.adb.shell("settings put global mobile_data 1")
+
+ return result
+
+
+def ensure_phones_default_state(log, ads, check_subscription=True):
+ """Ensure ads in default state.
+ Phone not in call.
+ Phone have no stored WiFi network and WiFi disconnected.
+ Phone not in airplane mode.
+
+ Returns:
+ True if all steps of restoring default state succeed.
+ False if any of the steps to restore default state fails.
+ """
+ tasks = []
+ for ad in ads:
+ tasks.append((ensure_phone_default_state, (log, ad,
+ check_subscription)))
+ if not multithread_func(log, tasks):
+ log.error("Ensure_phones_default_state Fail.")
+ return False
+ return True
+
+
+def is_phone_not_in_call(log, ad):
+ """Return True if phone not in call.
+
+ Args:
+ log: log object.
+ ad: android device.
+ """
+ in_call = ad.droid.telecomIsInCall()
+ call_state = ad.droid.telephonyGetCallState()
+ if in_call:
+ ad.log.info("Device is In Call")
+ if call_state != TELEPHONY_STATE_IDLE:
+ ad.log.info("Call_state is %s, not %s", call_state,
+ TELEPHONY_STATE_IDLE)
+ return ((not in_call) and (call_state == TELEPHONY_STATE_IDLE))
+
+
+def wait_for_droid_not_in_call(log, ad, max_time=MAX_WAIT_TIME_CALL_DROP):
+ """Wait for android to be not in call state.
+
+ Args:
+ log: log object.
+ ad: android device.
+ max_time: maximal wait time.
+
+ Returns:
+ If phone become not in call state within max_time, return True.
+ Return False if timeout.
+ """
+ return _wait_for_droid_in_state(log, ad, max_time, is_phone_not_in_call)
+
+
+def wait_for_voice_attach(log, ad, max_time=MAX_WAIT_TIME_NW_SELECTION):
+ """Wait for android device to attach on voice.
+
+ Args:
+ log: log object.
+ ad: android device.
+ max_time: maximal wait time.
+
+ Returns:
+ Return True if device attach voice within max_time.
+ Return False if timeout.
+ """
+ return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
+ NETWORK_SERVICE_VOICE)
+
+
+def wait_for_voice_attach_for_subscription(
+ log, ad, sub_id, max_time=MAX_WAIT_TIME_NW_SELECTION):
+ """Wait for android device to attach on voice in subscription id.
+
+ Args:
+ log: log object.
+ ad: android device.
+ sub_id: subscription id.
+ max_time: maximal wait time.
+
+ Returns:
+ Return True if device attach voice within max_time.
+ Return False if timeout.
+ """
+ if not _wait_for_droid_in_state_for_subscription(
+ log, ad, sub_id, max_time, _is_attached_for_subscription,
+ NETWORK_SERVICE_VOICE):
+ return False
+
+ # TODO: b/26295983 if pone attach to 1xrtt from unknown, phone may not
+ # receive incoming call immediately.
+ if ad.droid.telephonyGetCurrentVoiceNetworkType() == RAT_1XRTT:
+ time.sleep(WAIT_TIME_1XRTT_VOICE_ATTACH)
+ return True
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_sms_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_sms_utils.py
index dc68671..891e6b1 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_sms_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_sms_utils.py
@@ -17,14 +17,14 @@
import time
from acts.utils import rand_ascii_str
-from acts_contrib.test_utils.tel.tel_test_utils import sms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
-
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
message_lengths = (50, 160, 180)
+
def _sms_test(log, ads):
"""Test SMS between two phones.
Returns:
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_ss_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_ss_utils.py
new file mode 100644
index 0000000..dafd078
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_ss_utils.py
@@ -0,0 +1,1701 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+from acts import signals
+import re
+import time
+
+from acts.utils import get_current_epoch_time
+from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
+from acts_contrib.test_utils.tel.tel_defines import NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_REG_AND_CALL
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
+from acts_contrib.test_utils.tel.tel_test_utils import _phone_number_remove_prefix
+from acts_contrib.test_utils.tel.tel_test_utils import check_call_state_ring_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import check_call_state_idle_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
+from acts_contrib.test_utils.tel.tel_test_utils import get_user_config_profile
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_msim
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import dial_phone_number
+from acts_contrib.test_utils.tel.tel_voice_utils import disconnect_call_by_id
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import last_call_drop_reason
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_call_id_clearing
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_call_offhook_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_in_call_active
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_ringing_call_for_subscription
+
+
+def call_setup_teardown_for_call_forwarding(
+ log,
+ ad_caller,
+ ad_callee,
+ forwarded_callee,
+ ad_hangup=None,
+ verify_callee_func=None,
+ verify_after_cf_disabled=None,
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ dialing_number_length=None,
+ video_state=None,
+ call_forwarding_type="unconditional"):
+ """ Call process for call forwarding, including make a phone call from
+ caller, forward from callee, accept from the forwarded callee and hang up.
+ The call is on default voice subscription
+
+ In call process, call from <ad_caller> to <ad_callee>, forwarded to
+ <forwarded_callee>, accept the call, (optional) and then hang up from
+ <ad_hangup>.
+
+ Args:
+ ad_caller: Caller Android Device Object.
+ ad_callee: Callee Android Device Object which forwards the call.
+ forwarded_callee: Callee Android Device Object which answers the call.
+ ad_hangup: Android Device Object end the phone call.
+ Optional. Default value is None, and phone call will continue.
+ verify_callee_func: func_ptr to verify callee in correct mode
+ Optional. Default is None
+ verify_after_cf_disabled: If True the test of disabling call forwarding
+ will be appended.
+ wait_time_in_call: the call duration of a connected call
+ incall_ui_display: after answer the call, bring in-call UI to foreground
+ or background.
+ Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
+ if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
+ if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
+ else, do nothing.
+ dialing_number_length: the number of digits used for dialing
+ video_state: video call or voice call. Default is voice call.
+ call_forwarding_type: type of call forwarding listed below:
+ - unconditional
+ - busy
+ - not_answered
+ - not_reachable
+
+ Returns:
+ True if call process without any error.
+ False if error happened.
+
+ """
+ subid_caller = get_outgoing_voice_sub_id(ad_caller)
+ subid_callee = get_incoming_voice_sub_id(ad_callee)
+ subid_forwarded_callee = get_incoming_voice_sub_id(forwarded_callee)
+ return call_setup_teardown_for_call_forwarding_for_subscription(
+ log,
+ ad_caller,
+ ad_callee,
+ forwarded_callee,
+ subid_caller,
+ subid_callee,
+ subid_forwarded_callee,
+ ad_hangup,
+ verify_callee_func,
+ wait_time_in_call,
+ incall_ui_display,
+ dialing_number_length,
+ video_state,
+ call_forwarding_type,
+ verify_after_cf_disabled)
+
+
+def call_setup_teardown_for_call_forwarding_for_subscription(
+ log,
+ ad_caller,
+ ad_callee,
+ forwarded_callee,
+ subid_caller,
+ subid_callee,
+ subid_forwarded_callee,
+ ad_hangup=None,
+ verify_callee_func=None,
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ dialing_number_length=None,
+ video_state=None,
+ call_forwarding_type="unconditional",
+ verify_after_cf_disabled=None):
+ """ Call process for call forwarding, including make a phone call from caller,
+ forward from callee, accept from the forwarded callee and hang up.
+ The call is on specified subscription
+
+ In call process, call from <ad_caller> to <ad_callee>, forwarded to
+ <forwarded_callee>, accept the call, (optional) and then hang up from
+ <ad_hangup>.
+
+ Args:
+ ad_caller: Caller Android Device Object.
+ ad_callee: Callee Android Device Object which forwards the call.
+ forwarded_callee: Callee Android Device Object which answers the call.
+ subid_caller: Caller subscription ID
+ subid_callee: Callee subscription ID
+ subid_forwarded_callee: Forwarded callee subscription ID
+ ad_hangup: Android Device Object end the phone call.
+ Optional. Default value is None, and phone call will continue.
+ verify_callee_func: func_ptr to verify callee in correct mode
+ Optional. Default is None
+ wait_time_in_call: the call duration of a connected call
+ incall_ui_display: after answer the call, bring in-call UI to foreground
+ or background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
+ if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
+ if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
+ else, do nothing.
+ dialing_number_length: the number of digits used for dialing
+ video_state: video call or voice call. Default is voice call.
+ call_forwarding_type: type of call forwarding listed below:
+ - unconditional
+ - busy
+ - not_answered
+ - not_reachable
+ verify_after_cf_disabled: If True the call forwarding will not be
+ enabled. This argument is used to verify if the call can be received
+ successfully after call forwarding was disabled.
+
+ Returns:
+ True if call process without any error.
+ False if error happened.
+
+ """
+ CHECK_INTERVAL = 5
+ begin_time = get_current_epoch_time()
+ verify_caller_func = is_phone_in_call
+ if not verify_callee_func:
+ verify_callee_func = is_phone_in_call
+ verify_forwarded_callee_func = is_phone_in_call
+
+ caller_number = ad_caller.telephony['subscription'][subid_caller][
+ 'phone_num']
+ callee_number = ad_callee.telephony['subscription'][subid_callee][
+ 'phone_num']
+ forwarded_callee_number = forwarded_callee.telephony['subscription'][
+ subid_forwarded_callee]['phone_num']
+
+ if dialing_number_length:
+ skip_test = False
+ trunc_position = 0 - int(dialing_number_length)
+ try:
+ caller_area_code = caller_number[:trunc_position]
+ callee_area_code = callee_number[:trunc_position]
+ callee_dial_number = callee_number[trunc_position:]
+ except:
+ skip_test = True
+ if caller_area_code != callee_area_code:
+ skip_test = True
+ if skip_test:
+ msg = "Cannot make call from %s to %s by %s digits" % (
+ caller_number, callee_number, dialing_number_length)
+ ad_caller.log.info(msg)
+ raise signals.TestSkip(msg)
+ else:
+ callee_number = callee_dial_number
+
+ result = True
+ msg = "Call from %s to %s (forwarded to %s)" % (
+ caller_number, callee_number, forwarded_callee_number)
+ if video_state:
+ msg = "Video %s" % msg
+ video = True
+ else:
+ video = False
+ if ad_hangup:
+ msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
+ ad_caller.log.info(msg)
+
+ for ad in (ad_caller, forwarded_callee):
+ call_ids = ad.droid.telecomCallGetCallIds()
+ setattr(ad, "call_ids", call_ids)
+ if call_ids:
+ ad.log.info("Pre-exist CallId %s before making call", call_ids)
+
+ if not verify_after_cf_disabled:
+ if not set_call_forwarding_by_mmi(
+ log,
+ ad_callee,
+ forwarded_callee,
+ call_forwarding_type=call_forwarding_type):
+ raise signals.TestFailure(
+ "Failed to register or activate call forwarding.",
+ extras={"fail_reason": "Failed to register or activate call"
+ " forwarding."})
+
+ if call_forwarding_type == "not_reachable":
+ if not toggle_airplane_mode_msim(
+ log,
+ ad_callee,
+ new_state=True,
+ strict_checking=True):
+ return False
+
+ if call_forwarding_type == "busy":
+ ad_callee.log.info("Callee is making a phone call to 0000000000 to make"
+ " itself busy.")
+ ad_callee.droid.telecomCallNumber("0000000000", False)
+ time.sleep(2)
+
+ if check_call_state_idle_by_adb(ad_callee):
+ ad_callee.log.error("Call state of the callee is idle.")
+ if not verify_after_cf_disabled:
+ erase_call_forwarding_by_mmi(
+ log,
+ ad_callee,
+ call_forwarding_type=call_forwarding_type)
+ return False
+
+ try:
+ if not initiate_call(
+ log,
+ ad_caller,
+ callee_number,
+ incall_ui_display=incall_ui_display,
+ video=video):
+
+ ad_caller.log.error("Caller failed to initiate the call.")
+ result = False
+
+ if call_forwarding_type == "not_reachable":
+ if toggle_airplane_mode_msim(
+ log,
+ ad_callee,
+ new_state=False,
+ strict_checking=True):
+ time.sleep(10)
+ elif call_forwarding_type == "busy":
+ hangup_call(log, ad_callee)
+
+ if not verify_after_cf_disabled:
+ erase_call_forwarding_by_mmi(
+ log,
+ ad_callee,
+ call_forwarding_type=call_forwarding_type)
+ return False
+ else:
+ ad_caller.log.info("Caller initated the call successfully.")
+
+ if call_forwarding_type == "not_answered":
+ if not wait_for_ringing_call_for_subscription(
+ log,
+ ad_callee,
+ subid_callee,
+ incoming_number=caller_number,
+ caller=ad_caller,
+ event_tracking_started=True):
+ ad.log.info("Incoming call ringing check failed.")
+ return False
+
+ _timeout = 30
+ while check_call_state_ring_by_adb(ad_callee) == 1 and _timeout >= 0:
+ time.sleep(1)
+ _timeout = _timeout - 1
+
+ if not wait_and_answer_call_for_subscription(
+ log,
+ forwarded_callee,
+ subid_forwarded_callee,
+ incoming_number=caller_number,
+ caller=ad_caller,
+ incall_ui_display=incall_ui_display,
+ video_state=video_state):
+
+ if not verify_after_cf_disabled:
+ forwarded_callee.log.error("Forwarded callee failed to receive"
+ "or answer the call.")
+ result = False
+ else:
+ forwarded_callee.log.info("Forwarded callee did not receive or"
+ " answer the call.")
+
+ if call_forwarding_type == "not_reachable":
+ if toggle_airplane_mode_msim(
+ log,
+ ad_callee,
+ new_state=False,
+ strict_checking=True):
+ time.sleep(10)
+ elif call_forwarding_type == "busy":
+ hangup_call(log, ad_callee)
+
+ if not verify_after_cf_disabled:
+ erase_call_forwarding_by_mmi(
+ log,
+ ad_callee,
+ call_forwarding_type=call_forwarding_type)
+ return False
+
+ else:
+ if not verify_after_cf_disabled:
+ forwarded_callee.log.info("Forwarded callee answered the call"
+ " successfully.")
+ else:
+ forwarded_callee.log.error("Forwarded callee should not be able"
+ " to answer the call.")
+ hangup_call(log, ad_caller)
+ result = False
+
+ for ad, subid, call_func in zip(
+ [ad_caller, forwarded_callee],
+ [subid_caller, subid_forwarded_callee],
+ [verify_caller_func, verify_forwarded_callee_func]):
+ call_ids = ad.droid.telecomCallGetCallIds()
+ new_call_ids = set(call_ids) - set(ad.call_ids)
+ if not new_call_ids:
+ if not verify_after_cf_disabled:
+ ad.log.error(
+ "No new call ids are found after call establishment")
+ ad.log.error("telecomCallGetCallIds returns %s",
+ ad.droid.telecomCallGetCallIds())
+ result = False
+ for new_call_id in new_call_ids:
+ if not verify_after_cf_disabled:
+ if not wait_for_in_call_active(ad, call_id=new_call_id):
+ result = False
+ else:
+ ad.log.info("callProperties = %s",
+ ad.droid.telecomCallGetProperties(new_call_id))
+ else:
+ ad.log.error("No new call id should be found.")
+
+ if not ad.droid.telecomCallGetAudioState():
+ if not verify_after_cf_disabled:
+ ad.log.error("Audio is not in call state")
+ result = False
+
+ if call_func(log, ad):
+ if not verify_after_cf_disabled:
+ ad.log.info("Call is in %s state", call_func.__name__)
+ else:
+ ad.log.error("Call is in %s state", call_func.__name__)
+ else:
+ if not verify_after_cf_disabled:
+ ad.log.error(
+ "Call is not in %s state, voice in RAT %s",
+ call_func.__name__,
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
+ result = False
+
+ if not result:
+ if call_forwarding_type == "not_reachable":
+ if toggle_airplane_mode_msim(
+ log,
+ ad_callee,
+ new_state=False,
+ strict_checking=True):
+ time.sleep(10)
+ elif call_forwarding_type == "busy":
+ hangup_call(log, ad_callee)
+
+ if not verify_after_cf_disabled:
+ erase_call_forwarding_by_mmi(
+ log,
+ ad_callee,
+ call_forwarding_type=call_forwarding_type)
+ return False
+
+ elapsed_time = 0
+ while (elapsed_time < wait_time_in_call):
+ CHECK_INTERVAL = min(CHECK_INTERVAL,
+ wait_time_in_call - elapsed_time)
+ time.sleep(CHECK_INTERVAL)
+ elapsed_time += CHECK_INTERVAL
+ time_message = "at <%s>/<%s> second." % (elapsed_time,
+ wait_time_in_call)
+ for ad, subid, call_func in [
+ (ad_caller, subid_caller, verify_caller_func),
+ (forwarded_callee, subid_forwarded_callee,
+ verify_forwarded_callee_func)]:
+ if not call_func(log, ad):
+ if not verify_after_cf_disabled:
+ ad.log.error(
+ "NOT in correct %s state at %s, voice in RAT %s",
+ call_func.__name__, time_message,
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
+ result = False
+ else:
+ if not verify_after_cf_disabled:
+ ad.log.info("In correct %s state at %s",
+ call_func.__name__, time_message)
+ else:
+ ad.log.error("In correct %s state at %s",
+ call_func.__name__, time_message)
+
+ if not ad.droid.telecomCallGetAudioState():
+ if not verify_after_cf_disabled:
+ ad.log.error("Audio is not in call state at %s",
+ time_message)
+ result = False
+
+ if not result:
+ if call_forwarding_type == "not_reachable":
+ if toggle_airplane_mode_msim(
+ log,
+ ad_callee,
+ new_state=False,
+ strict_checking=True):
+ time.sleep(10)
+ elif call_forwarding_type == "busy":
+ hangup_call(log, ad_callee)
+
+ if not verify_after_cf_disabled:
+ erase_call_forwarding_by_mmi(
+ log,
+ ad_callee,
+ call_forwarding_type=call_forwarding_type)
+ return False
+
+ if ad_hangup:
+ if not hangup_call(log, ad_hangup):
+ ad_hangup.log.info("Failed to hang up the call")
+ result = False
+ if call_forwarding_type == "not_reachable":
+ if toggle_airplane_mode_msim(
+ log,
+ ad_callee,
+ new_state=False,
+ strict_checking=True):
+ time.sleep(10)
+ elif call_forwarding_type == "busy":
+ hangup_call(log, ad_callee)
+
+ if not verify_after_cf_disabled:
+ erase_call_forwarding_by_mmi(
+ log,
+ ad_callee,
+ call_forwarding_type=call_forwarding_type)
+ return False
+ finally:
+ if not result:
+ if verify_after_cf_disabled:
+ result = True
+ else:
+ for ad in (ad_caller, forwarded_callee):
+ last_call_drop_reason(ad, begin_time)
+ try:
+ if ad.droid.telecomIsInCall():
+ ad.log.info("In call. End now.")
+ ad.droid.telecomEndCall()
+ except Exception as e:
+ log.error(str(e))
+
+ if ad_hangup or not result:
+ for ad in (ad_caller, forwarded_callee):
+ if not wait_for_call_id_clearing(
+ ad, getattr(ad, "caller_ids", [])):
+ result = False
+
+ if call_forwarding_type == "not_reachable":
+ if toggle_airplane_mode_msim(
+ log,
+ ad_callee,
+ new_state=False,
+ strict_checking=True):
+ time.sleep(10)
+ elif call_forwarding_type == "busy":
+ hangup_call(log, ad_callee)
+
+ if not verify_after_cf_disabled:
+ erase_call_forwarding_by_mmi(
+ log,
+ ad_callee,
+ call_forwarding_type=call_forwarding_type)
+
+ if not result:
+ return result
+
+ ad_caller.log.info(
+ "Make a normal call to callee to ensure the call can be connected after"
+ " call forwarding was disabled")
+ return call_setup_teardown_for_subscription(
+ log, ad_caller, ad_callee, subid_caller, subid_callee, ad_caller,
+ verify_caller_func, verify_callee_func, wait_time_in_call,
+ incall_ui_display, dialing_number_length, video_state)
+
+
+def get_call_forwarding_by_adb(log, ad, call_forwarding_type="unconditional"):
+ """ Get call forwarding status by adb shell command
+ 'dumpsys telephony.registry'.
+
+ Args:
+ log: log object
+ ad: android object
+ call_forwarding_type:
+ - "unconditional"
+ - "busy" (todo)
+ - "not_answered" (todo)
+ - "not_reachable" (todo)
+ Returns:
+ - "true": if call forwarding unconditional is enabled.
+ - "false": if call forwarding unconditional is disabled.
+ - "unknown": if the type is other than 'unconditional'.
+ - False: any case other than above 3 cases.
+ """
+ if call_forwarding_type != "unconditional":
+ return "unknown"
+
+ slot_index_of_default_voice_subid = get_slot_index_from_subid(ad,
+ get_incoming_voice_sub_id(ad))
+ output = ad.adb.shell("dumpsys telephony.registry | grep mCallForwarding")
+ if "mCallForwarding" in output:
+ result_list = re.findall(r"mCallForwarding=(true|false)", output)
+ if result_list:
+ result = result_list[slot_index_of_default_voice_subid]
+ ad.log.info("mCallForwarding is %s", result)
+
+ if re.search("false", result, re.I):
+ return "false"
+ elif re.search("true", result, re.I):
+ return "true"
+ else:
+ return False
+ else:
+ return False
+ else:
+ ad.log.error("'mCallForwarding' cannot be found in dumpsys.")
+ return False
+
+
+def erase_call_forwarding_by_mmi(
+ log,
+ ad,
+ retry=2,
+ call_forwarding_type="unconditional"):
+ """ Erase setting of call forwarding (erase the number and disable call
+ forwarding) by MMI code.
+
+ Args:
+ log: log object
+ ad: android object
+ retry: times of retry if the erasure failed.
+ call_forwarding_type:
+ - "unconditional"
+ - "busy"
+ - "not_answered"
+ - "not_reachable"
+ Returns:
+ True by successful erasure. Otherwise False.
+ """
+ operator_name = get_operator_name(log, ad)
+
+ run_get_call_forwarding_by_adb = 1
+ if operator_name in NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST:
+ run_get_call_forwarding_by_adb = 0
+
+ if run_get_call_forwarding_by_adb:
+ res = get_call_forwarding_by_adb(log, ad,
+ call_forwarding_type=call_forwarding_type)
+ if res == "false":
+ return True
+
+ user_config_profile = get_user_config_profile(ad)
+ is_airplane_mode = user_config_profile["Airplane Mode"]
+ is_wfc_enabled = user_config_profile["WFC Enabled"]
+ wfc_mode = user_config_profile["WFC Mode"]
+ is_wifi_on = user_config_profile["WiFi State"]
+
+ if is_airplane_mode:
+ if not toggle_airplane_mode(log, ad, False):
+ ad.log.error("Failed to disable airplane mode.")
+ return False
+
+ code_dict = {
+ "Verizon": {
+ "unconditional": "73",
+ "busy": "73",
+ "not_answered": "73",
+ "not_reachable": "73",
+ "mmi": "*%s"
+ },
+ "Sprint": {
+ "unconditional": "720",
+ "busy": "740",
+ "not_answered": "730",
+ "not_reachable": "720",
+ "mmi": "*%s"
+ },
+ "Far EasTone": {
+ "unconditional": "142",
+ "busy": "143",
+ "not_answered": "144",
+ "not_reachable": "144",
+ "mmi": "*%s*2"
+ },
+ 'Generic': {
+ "unconditional": "21",
+ "busy": "67",
+ "not_answered": "61",
+ "not_reachable": "62",
+ "mmi": "##%s#"
+ }
+ }
+
+ if operator_name in code_dict:
+ code = code_dict[operator_name][call_forwarding_type]
+ mmi = code_dict[operator_name]["mmi"]
+ else:
+ code = code_dict['Generic'][call_forwarding_type]
+ mmi = code_dict['Generic']["mmi"]
+
+ result = False
+ while retry >= 0:
+ if run_get_call_forwarding_by_adb:
+ res = get_call_forwarding_by_adb(
+ log, ad, call_forwarding_type=call_forwarding_type)
+ if res == "false":
+ ad.log.info("Call forwarding is already disabled.")
+ result = True
+ break
+
+ ad.log.info("Erasing and deactivating call forwarding %s..." %
+ call_forwarding_type)
+
+ ad.droid.telecomDialNumber(mmi % code)
+
+ time.sleep(3)
+ ad.send_keycode("ENTER")
+ time.sleep(15)
+
+ # To dismiss the pop-out dialog
+ ad.send_keycode("BACK")
+ time.sleep(5)
+ ad.send_keycode("BACK")
+
+ if run_get_call_forwarding_by_adb:
+ res = get_call_forwarding_by_adb(
+ log, ad, call_forwarding_type=call_forwarding_type)
+ if res == "false" or res == "unknown":
+ result = True
+ break
+ else:
+ ad.log.error("Failed to erase and deactivate call forwarding by "
+ "MMI code ##%s#." % code)
+ retry = retry - 1
+ time.sleep(30)
+ else:
+ result = True
+ break
+
+ if is_airplane_mode:
+ if not toggle_airplane_mode(log, ad, True):
+ ad.log.error("Failed to enable airplane mode again.")
+ else:
+ if is_wifi_on:
+ ad.droid.wifiToggleState(True)
+ if is_wfc_enabled:
+ if not wait_for_wfc_enabled(
+ log, ad,max_time=MAX_WAIT_TIME_WFC_ENABLED):
+ ad.log.error("WFC is not enabled")
+
+ return result
+
+def set_call_forwarding_by_mmi(
+ log,
+ ad,
+ ad_forwarded,
+ call_forwarding_type="unconditional",
+ retry=2):
+ """ Set up the forwarded number and enable call forwarding by MMI code.
+
+ Args:
+ log: log object
+ ad: android object of the device forwarding the call (primary device)
+ ad_forwarded: android object of the device receiving forwarded call.
+ retry: times of retry if the erasure failed.
+ call_forwarding_type:
+ - "unconditional"
+ - "busy"
+ - "not_answered"
+ - "not_reachable"
+ Returns:
+ True by successful erasure. Otherwise False.
+ """
+
+ res = get_call_forwarding_by_adb(log, ad,
+ call_forwarding_type=call_forwarding_type)
+ if res == "true":
+ return True
+
+ if ad.droid.connectivityCheckAirplaneMode():
+ ad.log.warning("%s is now in airplane mode.", ad.serial)
+ return True
+
+ operator_name = get_operator_name(log, ad)
+
+ code_dict = {
+ "Verizon": {
+ "unconditional": "72",
+ "busy": "71",
+ "not_answered": "71",
+ "not_reachable": "72",
+ "mmi": "*%s%s"
+ },
+ "Sprint": {
+ "unconditional": "72",
+ "busy": "74",
+ "not_answered": "73",
+ "not_reachable": "72",
+ "mmi": "*%s%s"
+ },
+ "Far EasTone": {
+ "unconditional": "142",
+ "busy": "143",
+ "not_answered": "144",
+ "not_reachable": "144",
+ "mmi": "*%s*%s"
+ },
+ 'Generic': {
+ "unconditional": "21",
+ "busy": "67",
+ "not_answered": "61",
+ "not_reachable": "62",
+ "mmi": "*%s*%s#",
+ "mmi_for_plus_sign": "*%s*"
+ }
+ }
+
+ if operator_name in code_dict:
+ code = code_dict[operator_name][call_forwarding_type]
+ mmi = code_dict[operator_name]["mmi"]
+ if "mmi_for_plus_sign" in code_dict[operator_name]:
+ mmi_for_plus_sign = code_dict[operator_name]["mmi_for_plus_sign"]
+ else:
+ code = code_dict['Generic'][call_forwarding_type]
+ mmi = code_dict['Generic']["mmi"]
+ mmi_for_plus_sign = code_dict['Generic']["mmi_for_plus_sign"]
+
+ while retry >= 0:
+ if not erase_call_forwarding_by_mmi(
+ log, ad, call_forwarding_type=call_forwarding_type):
+ retry = retry - 1
+ continue
+
+ forwarded_number = ad_forwarded.telephony['subscription'][
+ ad_forwarded.droid.subscriptionGetDefaultVoiceSubId()][
+ 'phone_num']
+ ad.log.info("Registering and activating call forwarding %s to %s..." %
+ (call_forwarding_type, forwarded_number))
+
+ (forwarded_number_no_prefix, _) = _phone_number_remove_prefix(
+ forwarded_number)
+
+ if operator_name == "Far EasTone":
+ forwarded_number_no_prefix = "0" + forwarded_number_no_prefix
+
+ run_get_call_forwarding_by_adb = 1
+ if operator_name in NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST:
+ run_get_call_forwarding_by_adb = 0
+
+ _found_plus_sign = 0
+ if re.search("^\+", forwarded_number):
+ _found_plus_sign = 1
+ forwarded_number.replace("+", "")
+
+ if operator_name in code_dict:
+ ad.droid.telecomDialNumber(mmi % (code, forwarded_number_no_prefix))
+ else:
+ if _found_plus_sign == 0:
+ ad.droid.telecomDialNumber(mmi % (code, forwarded_number))
+ else:
+ ad.droid.telecomDialNumber(mmi_for_plus_sign % code)
+ ad.send_keycode("PLUS")
+
+ if "#" in mmi:
+ dial_phone_number(ad, forwarded_number + "#")
+ else:
+ dial_phone_number(ad, forwarded_number)
+
+ time.sleep(3)
+ ad.send_keycode("ENTER")
+ time.sleep(15)
+
+ # To dismiss the pop-out dialog
+ ad.send_keycode("BACK")
+ time.sleep(5)
+ ad.send_keycode("BACK")
+
+ if not run_get_call_forwarding_by_adb:
+ return True
+
+ result = get_call_forwarding_by_adb(
+ log, ad, call_forwarding_type=call_forwarding_type)
+ if result == "false":
+ retry = retry - 1
+ elif result == "true":
+ return True
+ elif result == "unknown":
+ return True
+ else:
+ retry = retry - 1
+
+ if retry >= 0:
+ ad.log.warning("Failed to register or activate call forwarding %s "
+ "to %s. Retry after 15 seconds." % (call_forwarding_type,
+ forwarded_number))
+ time.sleep(15)
+
+ ad.log.error("Failed to register or activate call forwarding %s to %s." %
+ (call_forwarding_type, forwarded_number))
+ return False
+
+
+def call_setup_teardown_for_call_waiting(log,
+ ad_caller,
+ ad_callee,
+ ad_caller2,
+ ad_hangup=None,
+ ad_hangup2=None,
+ verify_callee_func=None,
+ end_first_call_before_answering_second_call=True,
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ dialing_number_length=None,
+ video_state=None,
+ call_waiting=True):
+ """ Call process for call waiting, including make the 1st phone call from
+ caller, answer the call by the callee, and receive the 2nd call from the
+ caller2. The call is on default voice subscription
+
+ In call process, 1st call from <ad_caller> to <ad_callee>, 2nd call from
+ <ad_caller2> to <ad_callee>, hang up the existing call or reject the
+ incoming call according to the test scenario.
+
+ Args:
+ ad_caller: Caller Android Device Object.
+ ad_callee: Callee Android Device Object.
+ ad_caller2: Caller2 Android Device Object.
+ ad_hangup: Android Device Object end the 1st phone call.
+ Optional. Default value is None, and phone call will continue.
+ ad_hangup2: Android Device Object end the 2nd phone call.
+ Optional. Default value is None, and phone call will continue.
+ verify_callee_func: func_ptr to verify callee in correct mode
+ Optional. Default is None
+ end_first_call_before_answering_second_call: If True the 2nd call will
+ be rejected on the ringing stage.
+ wait_time_in_call: the call duration of a connected call
+ incall_ui_display: after answer the call, bring in-call UI to foreground
+ or background.
+ Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
+ if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
+ if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
+ else, do nothing.
+ dialing_number_length: the number of digits used for dialing
+ video_state: video call or voice call. Default is voice call.
+ call_waiting: True to enable call waiting and False to disable.
+
+ Returns:
+ True if call process without any error.
+ False if error happened.
+
+ """
+ subid_caller = get_outgoing_voice_sub_id(ad_caller)
+ subid_callee = get_incoming_voice_sub_id(ad_callee)
+ subid_caller2 = get_incoming_voice_sub_id(ad_caller2)
+ return call_setup_teardown_for_call_waiting_for_subscription(
+ log,
+ ad_caller,
+ ad_callee,
+ ad_caller2,
+ subid_caller,
+ subid_callee,
+ subid_caller2,
+ ad_hangup, ad_hangup2,
+ verify_callee_func,
+ end_first_call_before_answering_second_call,
+ wait_time_in_call,
+ incall_ui_display,
+ dialing_number_length,
+ video_state,
+ call_waiting)
+
+
+def call_setup_teardown_for_call_waiting_for_subscription(
+ log,
+ ad_caller,
+ ad_callee,
+ ad_caller2,
+ subid_caller,
+ subid_callee,
+ subid_caller2,
+ ad_hangup=None,
+ ad_hangup2=None,
+ verify_callee_func=None,
+ end_first_call_before_answering_second_call=True,
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ dialing_number_length=None,
+ video_state=None,
+ call_waiting=True):
+ """ Call process for call waiting, including make the 1st phone call from
+ caller, answer the call by the callee, and receive the 2nd call from the
+ caller2. The call is on specified subscription.
+
+ In call process, 1st call from <ad_caller> to <ad_callee>, 2nd call from
+ <ad_caller2> to <ad_callee>, hang up the existing call or reject the
+ incoming call according to the test scenario.
+
+ Args:
+ ad_caller: Caller Android Device Object.
+ ad_callee: Callee Android Device Object.
+ ad_caller2: Caller2 Android Device Object.
+ subid_caller: Caller subscription ID.
+ subid_callee: Callee subscription ID.
+ subid_caller2: Caller2 subscription ID.
+ ad_hangup: Android Device Object end the 1st phone call.
+ Optional. Default value is None, and phone call will continue.
+ ad_hangup2: Android Device Object end the 2nd phone call.
+ Optional. Default value is None, and phone call will continue.
+ verify_callee_func: func_ptr to verify callee in correct mode
+ Optional. Default is None
+ end_first_call_before_answering_second_call: If True the 2nd call will
+ be rejected on the ringing stage.
+ wait_time_in_call: the call duration of a connected call
+ incall_ui_display: after answer the call, bring in-call UI to foreground
+ or background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
+ if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
+ if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
+ else, do nothing.
+ dialing_number_length: the number of digits used for dialing
+ video_state: video call or voice call. Default is voice call.
+ call_waiting: True to enable call waiting and False to disable.
+
+ Returns:
+ True if call process without any error.
+ False if error happened.
+
+ """
+
+ CHECK_INTERVAL = 5
+ begin_time = get_current_epoch_time()
+ verify_caller_func = is_phone_in_call
+ if not verify_callee_func:
+ verify_callee_func = is_phone_in_call
+ verify_caller2_func = is_phone_in_call
+
+ caller_number = ad_caller.telephony['subscription'][subid_caller][
+ 'phone_num']
+ callee_number = ad_callee.telephony['subscription'][subid_callee][
+ 'phone_num']
+ caller2_number = ad_caller2.telephony['subscription'][subid_caller2][
+ 'phone_num']
+ if dialing_number_length:
+ skip_test = False
+ trunc_position = 0 - int(dialing_number_length)
+ try:
+ caller_area_code = caller_number[:trunc_position]
+ callee_area_code = callee_number[:trunc_position]
+ callee_dial_number = callee_number[trunc_position:]
+ except:
+ skip_test = True
+ if caller_area_code != callee_area_code:
+ skip_test = True
+ if skip_test:
+ msg = "Cannot make call from %s to %s by %s digits" % (
+ caller_number, callee_number, dialing_number_length)
+ ad_caller.log.info(msg)
+ raise signals.TestSkip(msg)
+ else:
+ callee_number = callee_dial_number
+
+ result = True
+ msg = "Call from %s to %s" % (caller_number, callee_number)
+ if video_state:
+ msg = "Video %s" % msg
+ video = True
+ else:
+ video = False
+ if ad_hangup:
+ msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
+ ad_caller.log.info(msg)
+
+ for ad in (ad_caller, ad_callee, ad_caller2):
+ call_ids = ad.droid.telecomCallGetCallIds()
+ setattr(ad, "call_ids", call_ids)
+ if call_ids:
+ ad.log.info("Pre-exist CallId %s before making call", call_ids)
+
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=0)
+ else:
+ set_call_waiting(log, ad_callee, enable=1)
+
+ first_call_ids = []
+ try:
+ if not initiate_call(
+ log,
+ ad_caller,
+ callee_number,
+ incall_ui_display=incall_ui_display,
+ video=video):
+ ad_caller.log.error("Initiate call failed.")
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ result = False
+ return False
+ else:
+ ad_caller.log.info("Caller initate call successfully")
+ if not wait_and_answer_call_for_subscription(
+ log,
+ ad_callee,
+ subid_callee,
+ incoming_number=caller_number,
+ caller=ad_caller,
+ incall_ui_display=incall_ui_display,
+ video_state=video_state):
+ ad_callee.log.error("Answer call fail.")
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ result = False
+ return False
+ else:
+ ad_callee.log.info("Callee answered the call successfully")
+
+ for ad, subid, call_func in zip(
+ [ad_caller, ad_callee],
+ [subid_caller, subid_callee],
+ [verify_caller_func, verify_callee_func]):
+ call_ids = ad.droid.telecomCallGetCallIds()
+ new_call_ids = set(call_ids) - set(ad.call_ids)
+ if not new_call_ids:
+ ad.log.error(
+ "No new call ids are found after call establishment")
+ ad.log.error("telecomCallGetCallIds returns %s",
+ ad.droid.telecomCallGetCallIds())
+ result = False
+ for new_call_id in new_call_ids:
+ first_call_ids.append(new_call_id)
+ if not wait_for_in_call_active(ad, call_id=new_call_id):
+ result = False
+ else:
+ ad.log.info("callProperties = %s",
+ ad.droid.telecomCallGetProperties(new_call_id))
+
+ if not ad.droid.telecomCallGetAudioState():
+ ad.log.error("Audio is not in call state")
+ result = False
+
+ if call_func(log, ad):
+ ad.log.info("Call is in %s state", call_func.__name__)
+ else:
+ ad.log.error("Call is not in %s state, voice in RAT %s",
+ call_func.__name__,
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
+ result = False
+ if not result:
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ return False
+
+ time.sleep(3)
+ if not call_waiting:
+ if not initiate_call(
+ log,
+ ad_caller2,
+ callee_number,
+ incall_ui_display=incall_ui_display,
+ video=video):
+ ad_caller2.log.info("Initiate call failed.")
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ result = False
+ return False
+ else:
+ ad_caller2.log.info("Caller 2 initate 2nd call successfully")
+
+ if not wait_and_answer_call_for_subscription(
+ log,
+ ad_callee,
+ subid_callee,
+ incoming_number=caller2_number,
+ caller=ad_caller2,
+ incall_ui_display=incall_ui_display,
+ video_state=video_state):
+ ad_callee.log.info(
+ "Answering 2nd call fail due to call waiting deactivate.")
+ else:
+ ad_callee.log.error("Callee should not be able to answer the"
+ " 2nd call due to call waiting deactivated.")
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ result = False
+ return False
+
+ time.sleep(3)
+ if not hangup_call(log, ad_caller2):
+ ad_caller2.log.info("Failed to hang up the 2nd call")
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ result = False
+ return False
+
+ else:
+
+ for ad in (ad_callee, ad_caller2):
+ call_ids = ad.droid.telecomCallGetCallIds()
+ setattr(ad, "call_ids", call_ids)
+ if call_ids:
+ ad.log.info("Current existing CallId %s before making the"
+ " second call.", call_ids)
+
+ if not initiate_call(
+ log,
+ ad_caller2,
+ callee_number,
+ incall_ui_display=incall_ui_display,
+ video=video):
+ ad_caller2.log.info("Initiate 2nd call failed.")
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ result = False
+ return False
+ else:
+ ad_caller2.log.info("Caller 2 initate 2nd call successfully")
+
+ if end_first_call_before_answering_second_call:
+ try:
+ if not wait_for_ringing_call_for_subscription(
+ log,
+ ad_callee,
+ subid_callee,
+ incoming_number=caller2_number,
+ caller=ad_caller2,
+ event_tracking_started=True):
+ ad_callee.log.info(
+ "2nd incoming call ringing check failed.")
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ return False
+
+ time.sleep(3)
+
+ ad_hangup.log.info("Disconnecting first call...")
+ for call_id in first_call_ids:
+ disconnect_call_by_id(log, ad_hangup, call_id)
+ time.sleep(3)
+
+ ad_callee.log.info("Answering the 2nd ring call...")
+ ad_callee.droid.telecomAcceptRingingCall(video_state)
+
+ if wait_for_call_offhook_for_subscription(
+ log,
+ ad_callee,
+ subid_callee,
+ event_tracking_started=True):
+ ad_callee.log.info(
+ "Callee answered the 2nd call successfully.")
+ else:
+ ad_callee.log.error("Could not answer the 2nd call.")
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ return False
+ except Exception as e:
+ log.error(e)
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ return False
+
+ else:
+ if not wait_and_answer_call_for_subscription(
+ log,
+ ad_callee,
+ subid_callee,
+ incoming_number=caller2_number,
+ caller=ad_caller2,
+ incall_ui_display=incall_ui_display,
+ video_state=video_state):
+ ad_callee.log.error("Failed to answer 2nd call.")
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ result = False
+ return False
+ else:
+ ad_callee.log.info(
+ "Callee answered the 2nd call successfully.")
+
+ for ad, subid, call_func in zip(
+ [ad_callee, ad_caller2],
+ [subid_callee, subid_caller2],
+ [verify_callee_func, verify_caller2_func]):
+ call_ids = ad.droid.telecomCallGetCallIds()
+ new_call_ids = set(call_ids) - set(ad.call_ids)
+ if not new_call_ids:
+ ad.log.error(
+ "No new call ids are found after 2nd call establishment")
+ ad.log.error("telecomCallGetCallIds returns %s",
+ ad.droid.telecomCallGetCallIds())
+ result = False
+ for new_call_id in new_call_ids:
+ if not wait_for_in_call_active(ad, call_id=new_call_id):
+ result = False
+ else:
+ ad.log.info("callProperties = %s",
+ ad.droid.telecomCallGetProperties(new_call_id))
+
+ if not ad.droid.telecomCallGetAudioState():
+ ad.log.error("Audio is not in 2nd call state")
+ result = False
+
+ if call_func(log, ad):
+ ad.log.info("2nd call is in %s state", call_func.__name__)
+ else:
+ ad.log.error("2nd call is not in %s state, voice in RAT %s",
+ call_func.__name__,
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
+ result = False
+ if not result:
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ return False
+
+ elapsed_time = 0
+ while (elapsed_time < wait_time_in_call):
+ CHECK_INTERVAL = min(CHECK_INTERVAL,
+ wait_time_in_call - elapsed_time)
+ time.sleep(CHECK_INTERVAL)
+ elapsed_time += CHECK_INTERVAL
+ time_message = "at <%s>/<%s> second." % (elapsed_time,
+ wait_time_in_call)
+
+ if not end_first_call_before_answering_second_call or \
+ not call_waiting:
+ for ad, subid, call_func in [
+ (ad_caller, subid_caller, verify_caller_func),
+ (ad_callee, subid_callee, verify_callee_func)]:
+ if not call_func(log, ad):
+ ad.log.error(
+ "The first call NOT in correct %s state at %s,"
+ " voice in RAT %s",
+ call_func.__name__, time_message,
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
+ result = False
+ else:
+ ad.log.info("The first call in correct %s state at %s",
+ call_func.__name__, time_message)
+ if not ad.droid.telecomCallGetAudioState():
+ ad.log.error(
+ "The first call audio is not in call state at %s",
+ time_message)
+ result = False
+ if not result:
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ return False
+
+ if call_waiting:
+ for ad, call_func in [(ad_caller2, verify_caller2_func),
+ (ad_callee, verify_callee_func)]:
+ if not call_func(log, ad):
+ ad.log.error(
+ "The 2nd call NOT in correct %s state at %s,"
+ " voice in RAT %s",
+ call_func.__name__, time_message,
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
+ result = False
+ else:
+ ad.log.info("The 2nd call in correct %s state at %s",
+ call_func.__name__, time_message)
+ if not ad.droid.telecomCallGetAudioState():
+ ad.log.error(
+ "The 2nd call audio is not in call state at %s",
+ time_message)
+ result = False
+ if not result:
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ return False
+
+ if not end_first_call_before_answering_second_call or not call_waiting:
+ ad_hangup.log.info("Hanging up the first call...")
+ for call_id in first_call_ids:
+ disconnect_call_by_id(log, ad_hangup, call_id)
+ time.sleep(5)
+
+ if ad_hangup2 and call_waiting:
+ if not hangup_call(log, ad_hangup2):
+ ad_hangup2.log.info("Failed to hang up the 2nd call")
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ result = False
+ return False
+ finally:
+ if not result:
+ for ad in (ad_caller, ad_callee, ad_caller2):
+ last_call_drop_reason(ad, begin_time)
+ try:
+ if ad.droid.telecomIsInCall():
+ ad.log.info("In call. End now.")
+ ad.droid.telecomEndCall()
+ except Exception as e:
+ log.error(str(e))
+
+ if ad_hangup or not result:
+ for ad in (ad_caller, ad_callee):
+ if not wait_for_call_id_clearing(
+ ad, getattr(ad, "caller_ids", [])):
+ result = False
+
+ if call_waiting:
+ if ad_hangup2 or not result:
+ for ad in (ad_caller2, ad_callee):
+ if not wait_for_call_id_clearing(
+ ad, getattr(ad, "caller_ids", [])):
+ result = False
+ if not call_waiting:
+ set_call_waiting(log, ad_callee, enable=1)
+ return result
+
+
+def get_call_waiting_status(log, ad):
+ """ (Todo) Get call waiting status (activated or deactivated) when there is
+ any proper method available.
+ """
+ return True
+
+
+def set_call_waiting(log, ad, enable=1, retry=1):
+ """ Activate/deactivate call waiting by dialing MMI code.
+
+ Args:
+ log: log object.
+ ad: android object.
+ enable: 1 for activation and 0 fir deactivation
+ retry: times of retry if activation/deactivation fails
+
+ Returns:
+ True by successful activation/deactivation; otherwise False.
+ """
+ operator_name = get_operator_name(log, ad)
+
+ if operator_name in ["Verizon", "Sprint"]:
+ return True
+
+ while retry >= 0:
+ if enable:
+ ad.log.info("Activating call waiting...")
+ ad.droid.telecomDialNumber("*43#")
+ else:
+ ad.log.info("Deactivating call waiting...")
+ ad.droid.telecomDialNumber("#43#")
+
+ time.sleep(3)
+ ad.send_keycode("ENTER")
+ time.sleep(15)
+
+ ad.send_keycode("BACK")
+ time.sleep(5)
+ ad.send_keycode("BACK")
+
+ if get_call_waiting_status(log, ad):
+ return True
+ else:
+ retry = retry + 1
+
+ return False
+
+
+def three_phone_call_forwarding_short_seq(log,
+ phone_a,
+ phone_a_idle_func,
+ phone_a_in_call_check_func,
+ phone_b,
+ phone_c,
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ call_forwarding_type="unconditional",
+ retry=2):
+ """Short sequence of call process with call forwarding.
+ Test steps:
+ 1. Ensure all phones are initially in idle state.
+ 2. Enable call forwarding on Phone A.
+ 3. Make a call from Phone B to Phone A, The call should be forwarded to
+ PhoneC. Accept the call on Phone C.
+ 4. Ensure the call is connected and in correct phone state.
+ 5. Hang up the call on Phone B.
+ 6. Ensure all phones are in idle state.
+ 7. Disable call forwarding on Phone A.
+ 7. Make a call from Phone B to Phone A, The call should NOT be forwarded
+ to PhoneC. Accept the call on Phone A.
+ 8. Ensure the call is connected and in correct phone state.
+ 9. Hang up the call on Phone B.
+
+ Args:
+ phone_a: android object of Phone A
+ phone_a_idle_func: function to check idle state on Phone A
+ phone_a_in_call_check_func: function to check in-call state on Phone A
+ phone_b: android object of Phone B
+ phone_c: android object of Phone C
+ wait_time_in_call: time to wait in call.
+ This is optional, default is WAIT_TIME_IN_CALL
+ call_forwarding_type:
+ - "unconditional"
+ - "busy"
+ - "not_answered"
+ - "not_reachable"
+ retry: times of retry
+
+ Returns:
+ True: if call sequence succeed.
+ False: for errors
+ """
+ ads = [phone_a, phone_b, phone_c]
+
+ call_params = [
+ (ads[1], ads[0], ads[2], ads[1], phone_a_in_call_check_func, False)
+ ]
+
+ if call_forwarding_type != "unconditional":
+ call_params.append((
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[1],
+ phone_a_in_call_check_func,
+ True))
+
+ for param in call_params:
+ ensure_phones_idle(log, ads)
+ if phone_a_idle_func and not phone_a_idle_func(log, phone_a):
+ phone_a.log.error("Phone A Failed to Reselect")
+ return False
+
+ time.sleep(WAIT_TIME_BETWEEN_REG_AND_CALL)
+
+ log.info(
+ "---> Call forwarding %s (caller: %s, callee: %s, callee forwarded:"
+ " %s) <---",
+ call_forwarding_type,
+ param[0].serial,
+ param[1].serial,
+ param[2].serial)
+ while not call_setup_teardown_for_call_forwarding(
+ log,
+ *param,
+ wait_time_in_call=wait_time_in_call,
+ call_forwarding_type=call_forwarding_type) and retry >= 0:
+
+ if retry <= 0:
+ log.error("Call forwarding %s failed." % call_forwarding_type)
+ return False
+ else:
+ log.info(
+ "RERUN the test case: 'Call forwarding %s'" %
+ call_forwarding_type)
+
+ retry = retry - 1
+
+ return True
+
+def three_phone_call_waiting_short_seq(log,
+ phone_a,
+ phone_a_idle_func,
+ phone_a_in_call_check_func,
+ phone_b,
+ phone_c,
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ call_waiting=True,
+ scenario=None,
+ retry=2):
+ """Short sequence of call process with call waiting.
+ Test steps:
+ 1. Ensure all phones are initially in idle state.
+ 2. Enable call waiting on Phone A.
+ 3. Make the 1st call from Phone B to Phone A. Accept the call on Phone B.
+ 4. Ensure the call is connected and in correct phone state.
+ 5. Make the 2nd call from Phone C to Phone A. The call should be able to
+ income correctly. Whether or not the 2nd call should be answered by
+ Phone A depends on the scenario listed in the next step.
+ 6. Following 8 scenarios will be tested:
+ - 1st call ended first by Phone B during 2nd call incoming. 2nd call
+ ended by Phone C
+ - 1st call ended first by Phone B during 2nd call incoming. 2nd call
+ ended by Phone A
+ - 1st call ended first by Phone A during 2nd call incoming. 2nd call
+ ended by Phone C
+ - 1st call ended first by Phone A during 2nd call incoming. 2nd call
+ ended by Phone A
+ - 1st call ended by Phone B. 2nd call ended by Phone C
+ - 1st call ended by Phone B. 2nd call ended by Phone A
+ - 1st call ended by Phone A. 2nd call ended by Phone C
+ - 1st call ended by Phone A. 2nd call ended by Phone A
+ 7. Ensure all phones are in idle state.
+
+ Args:
+ phone_a: android object of Phone A
+ phone_a_idle_func: function to check idle state on Phone A
+ phone_a_in_call_check_func: function to check in-call state on Phone A
+ phone_b: android object of Phone B
+ phone_c: android object of Phone C
+ wait_time_in_call: time to wait in call.
+ This is optional, default is WAIT_TIME_IN_CALL
+ call_waiting: True for call waiting enabled and False for disabled
+ scenario: 1-8 for scenarios listed above
+ retry: times of retry
+
+ Returns:
+ True: if call sequence succeed.
+ False: for errors
+ """
+ ads = [phone_a, phone_b, phone_c]
+
+ sub_test_cases = [
+ {
+ "description": "1st call ended first by caller1 during 2nd call"
+ " incoming. 2nd call ended by caller2",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[1],
+ ads[2],
+ phone_a_in_call_check_func,
+ True)},
+ {
+ "description": "1st call ended first by caller1 during 2nd call"
+ " incoming. 2nd call ended by callee",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[1],
+ ads[0],
+ phone_a_in_call_check_func,
+ True)},
+ {
+ "description": "1st call ended first by callee during 2nd call"
+ " incoming. 2nd call ended by caller2",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[0],
+ ads[2],
+ phone_a_in_call_check_func,
+ True)},
+ {
+ "description": "1st call ended first by callee during 2nd call"
+ " incoming. 2nd call ended by callee",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[0],
+ ads[0],
+ phone_a_in_call_check_func,
+ True)},
+ {
+ "description": "1st call ended by caller1. 2nd call ended by"
+ " caller2",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[1],
+ ads[2],
+ phone_a_in_call_check_func,
+ False)},
+ {
+ "description": "1st call ended by caller1. 2nd call ended by callee",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[1],
+ ads[0],
+ phone_a_in_call_check_func,
+ False)},
+ {
+ "description": "1st call ended by callee. 2nd call ended by caller2",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[0],
+ ads[2],
+ phone_a_in_call_check_func,
+ False)},
+ {
+ "description": "1st call ended by callee. 2nd call ended by callee",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[0],
+ ads[0],
+ phone_a_in_call_check_func,
+ False)}
+ ]
+
+ if call_waiting:
+ if not scenario:
+ test_cases = sub_test_cases
+ else:
+ test_cases = [sub_test_cases[scenario-1]]
+ else:
+ test_cases = [
+ {
+ "description": "Call waiting deactivated",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[0],
+ ads[0],
+ phone_a_in_call_check_func,
+ False)}
+ ]
+
+ results = []
+
+ for test_case in test_cases:
+ ensure_phones_idle(log, ads)
+ if phone_a_idle_func and not phone_a_idle_func(log, phone_a):
+ phone_a.log.error("Phone A Failed to Reselect")
+ return False
+
+ time.sleep(WAIT_TIME_BETWEEN_REG_AND_CALL)
+
+ log.info(
+ "---> %s (caller1: %s, caller2: %s, callee: %s) <---",
+ test_case["description"],
+ test_case["params"][1].serial,
+ test_case["params"][2].serial,
+ test_case["params"][0].serial)
+
+ while not call_setup_teardown_for_call_waiting(
+ log,
+ *test_case["params"],
+ wait_time_in_call=wait_time_in_call,
+ call_waiting=call_waiting) and retry >= 0:
+
+ if retry <= 0:
+ log.error("Call waiting sub-case: '%s' failed." % test_case[
+ "description"])
+ results.append(False)
+ else:
+ log.info("RERUN the sub-case: '%s'" % test_case["description"])
+
+ retry = retry - 1
+
+ for result in results:
+ if not result:
+ return False
+
+ return True
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_subscription_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_subscription_utils.py
index 953f3851..6fd9e90 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_subscription_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_subscription_utils.py
@@ -16,17 +16,19 @@
# This is test util for subscription setup.
# It will be deleted once we have better solution for subscription ids.
-from future import standard_library
-standard_library.install_aliases()
-from acts_contrib.test_utils.tel.tel_defines import CHIPSET_MODELS_LIST
-from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_DATA_SUB_ID
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
-
+import re
import time
+from acts_contrib.test_utils.tel.tel_defines import CHIPSET_MODELS_LIST
+from acts_contrib.test_utils.tel.tel_defines import INVALID_SIM_SLOT_INDEX
+from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_DATA_SUB_ID
+from future import standard_library
-def initial_set_up_for_subid_infomation(log, ad):
+standard_library.install_aliases()
+
+
+def initial_set_up_for_subid_information(log, ad):
"""Initial subid setup for voice, message and data according to ad's
attribute.
@@ -157,6 +159,28 @@
return ad.droid.subscriptionGetDefaultSmsSubId()
+def get_subid_by_adb(ad, sim_slot_index):
+ """Get the subscription ID for a SIM at a particular slot via adb command.
+
+ Args:
+ ad: android device object.
+ sim_slot_index: slot 0 or slot 1.
+
+ Returns:
+ Subscription ID.
+ """
+ try:
+ output = ad.adb.shell("dumpsys isub | grep subIds")
+ pattern = re.compile(r"sSlotIndexToSubId\[%d\]:\s*subIds=%d=\[(\d)\]" %
+ (sim_slot_index, sim_slot_index))
+ sub_id = pattern.findall(output)
+ except Exception as e:
+ error_msg = "%s due to %s" % ("Failed to get the subid", e)
+ ad.log.error(error_msg)
+ return INVALID_SUB_ID
+ return int(sub_id[0]) if sub_id else INVALID_SUB_ID
+
+
def get_subid_from_slot_index(log, ad, sim_slot_index):
""" Get the subscription ID for a SIM at a particular slot
@@ -205,6 +229,7 @@
return info['carrierId']
return None
+
def get_isopportunistic_from_slot_index(ad, sim_slot_index):
""" Get the isOppotunistic field for a particular slot
@@ -221,6 +246,7 @@
return info['isOpportunistic']
return None
+
def set_subid_for_data(ad, sub_id, time_to_sleep=WAIT_TIME_CHANGE_DATA_SUB_ID):
"""Set subId for data
@@ -317,23 +343,6 @@
ad.outgoing_voice_sub_id = sub_id
-def set_voice_sub_id(ad, sub_id):
- """Set default subId for both incoming and outgoing voice calls
-
- Args:
- ad: android device object.
- sub_id: subscription id (integer)
-
- Returns:
- None
- """
- ad.droid.subscriptionSetDefaultVoiceSubId(sub_id)
- if hasattr(ad, "incoming_voice_sub_id"):
- ad.incoming_voice_sub_id = sub_id
- if hasattr(ad, "outgoing_voice_sub_id"):
- ad.outgoing_voice_sub_id = sub_id
-
-
def set_default_sub_for_all_services(ad, slot_id=0):
"""Set subId for all services
@@ -418,6 +427,34 @@
return False
+def set_dds_on_slot(ad, dds_slot):
+ """Switch DDS to given slot.
+
+ Args:
+ ad: android device object.
+ dds_slot: the slot which be set to DDS.
+
+ Returns:
+ True if success, False if fail.
+ """
+ sub_id = get_subid_from_slot_index(ad.log, ad, dds_slot)
+ if sub_id == INVALID_SUB_ID:
+ ad.log.warning("Invalid sub ID at slot %d", dds_slot)
+ return False
+ operator = get_operatorname_from_slot_index(ad, dds_slot)
+ if get_default_data_sub_id(ad) == sub_id:
+ ad.log.info("Current DDS is already on %s", operator)
+ return True
+ ad.log.info("Setting DDS on %s", operator)
+ set_subid_for_data(ad, sub_id)
+ ad.droid.telephonyToggleDataConnection(True)
+ time.sleep(WAIT_TIME_CHANGE_DATA_SUB_ID)
+ if get_default_data_sub_id(ad) == sub_id:
+ return True
+ else:
+ return False
+
+
def set_always_allow_mms_data(ad, sub_id, state=True):
"""Set always allow mms data on sub_id
@@ -525,3 +562,65 @@
p2_mnc = mnc
return host_sub_id, p1_sub_id, p2_sub_id
+
+
+def get_slot_index_from_subid(ad, sub_id):
+ try:
+ info = ad.droid.subscriptionGetSubInfoForSubscriber(sub_id)
+ return info['simSlotIndex']
+ except KeyError:
+ return INVALID_SIM_SLOT_INDEX
+
+
+def get_slot_index_from_data_sub_id(ad):
+ """Get slot index from given sub ID for data
+
+ Args:
+ ad: Android object
+
+ Returns:
+ 0 for pSIM or 1 for eSIM. Otherwise -1 will be returned.
+ """
+ data_sub_id = get_default_data_sub_id(ad)
+ sub_info = ad.droid.subscriptionGetAllSubInfoList()
+ for info in sub_info:
+ if info['subscriptionId'] == data_sub_id:
+ return info['simSlotIndex']
+ return INVALID_SUB_ID
+
+
+def get_slot_index_from_voice_sub_id(ad):
+ """Get slot index from the current voice sub ID.
+
+ Args:
+ ad: android object
+
+ Returns:
+ 0: pSIM
+ 1: eSIM
+ INVALID_SUB_ID (-1): if no sub ID is equal to current voice sub ID.
+ """
+ voice_sub_id = get_incoming_voice_sub_id(ad)
+ sub_info = ad.droid.subscriptionGetAllSubInfoList()
+ for info in sub_info:
+ if info['subscriptionId'] == voice_sub_id:
+ return info['simSlotIndex']
+ return INVALID_SUB_ID
+
+
+def get_all_sub_id(ad):
+ """Return all valid subscription IDs.
+
+ Args:
+ ad: Android object
+
+ Returns:
+ List containing all valid subscription IDs.
+ """
+ sub_id_list = []
+ sub_info = ad.droid.subscriptionGetAllSubInfoList()
+ for info in sub_info:
+ if info['simSlotIndex'] != INVALID_SUB_ID:
+ sub_id_list.append(info['subscriptionId'])
+
+ return sub_id_list
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_test_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_test_utils.py
index 31433b7..3d7e935 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_test_utils.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2016 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,11 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from datetime import datetime
from future import standard_library
standard_library.install_aliases()
-import concurrent.futures
import json
import logging
import re
@@ -26,24 +24,18 @@
import urllib.parse
import time
import acts.controllers.iperf_server as ipf
-import shutil
import struct
from acts import signals
-from acts import utils
from queue import Empty
from acts.asserts import abort_all
-from acts.asserts import fail
-from acts.controllers.adb_lib.error import AdbError
+from acts.controllers.adb_lib.error import AdbCommandError, AdbError
from acts.controllers.android_device import list_adb_devices
from acts.controllers.android_device import list_fastboot_devices
-from acts.controllers.android_device import DEFAULT_QXDM_LOG_PATH
-from acts.controllers.android_device import DEFAULT_SDM_LOG_PATH
-from acts.controllers.android_device import SL4A_APK_NAME
-from acts.libs.proc import job
+
+from acts.libs.proc.job import TimeoutError
from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
-from acts_contrib.test_utils.tel.tel_defines import CarrierConfigs, CARRIER_NTT_DOCOMO, CARRIER_KDDI, CARRIER_RAKUTEN, \
- CARRIER_SBM
+from acts_contrib.test_utils.tel.tel_defines import CarrierConfigs
from acts_contrib.test_utils.tel.tel_defines import AOSP_PREFIX
from acts_contrib.test_utils.tel.tel_defines import CARD_POWER_DOWN
from acts_contrib.test_utils.tel.tel_defines import CARD_POWER_UP
@@ -56,57 +48,23 @@
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC_MODE_CHANGE
from acts_contrib.test_utils.tel.tel_defines import CARRIER_UNKNOWN
-from acts_contrib.test_utils.tel.tel_defines import CARRIER_FRE
from acts_contrib.test_utils.tel.tel_defines import COUNTRY_CODE_LIST
-from acts_contrib.test_utils.tel.tel_defines import NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST
-from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
-from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_DISCONNECTED
+from acts_contrib.test_utils.tel.tel_defines import DIALER_PACKAGE_NAME
from acts_contrib.test_utils.tel.tel_defines import DATA_ROAMING_ENABLE
from acts_contrib.test_utils.tel.tel_defines import DATA_ROAMING_DISABLE
from acts_contrib.test_utils.tel.tel_defines import GEN_4G
-from acts_contrib.test_utils.tel.tel_defines import GEN_5G
from acts_contrib.test_utils.tel.tel_defines import GEN_UNKNOWN
-from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_BACKGROUND
-from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
from acts_contrib.test_utils.tel.tel_defines import INVALID_SIM_SLOT_INDEX
from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
-from acts_contrib.test_utils.tel.tel_defines import MAX_SAVED_VOICE_MAIL
from acts_contrib.test_utils.tel.tel_defines import MAX_SCREEN_ON_TIME
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_AIRPLANEMODE_EVENT
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_DROP
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_INITIATION
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALLEE_RINGING
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_DATA_SUB_CHANGE
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_IDLE_EVENT
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_SENT_SUCCESS
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_SENT_SUCCESS_IN_COLLISION
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_TELECOM_RINGING
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOICE_MAIL_COUNT
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOLTE_ENABLED
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_DISABLED
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_NW_VALID_FAIL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL_RECOVERY
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_ONLY
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_CELL
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_WIFI
+from acts_contrib.test_utils.tel.tel_defines import MESSAGE_PACKAGE_NAME
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_7_DIGIT
from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_10_DIGIT
from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_11_DIGIT
from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_12_DIGIT
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WLAN
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WCDMA
-from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
from acts_contrib.test_utils.tel.tel_defines import RAT_UNKNOWN
from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_EMERGENCY_ONLY
from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
@@ -119,103 +77,49 @@
from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_PIN_REQUIRED
from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_READY
from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_UNKNOWN
-from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_IDLE
-from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_OFFHOOK
-from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_RINGING
-from acts_contrib.test_utils.tel.tel_defines import VOICEMAIL_DELETE_DIGIT
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_1XRTT_VOICE_ATTACH
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_DATA_SUB_ID
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_LEAVE_VOICE_MAIL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_REJECT_CALL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_SYNC_DATE_TIME_FROM_NETWORK
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import TYPE_MOBILE
-from acts_contrib.test_utils.tel.tel_defines import TYPE_WIFI
-from acts_contrib.test_utils.tel.tel_defines import EventCallStateChanged
from acts_contrib.test_utils.tel.tel_defines import EventActiveDataSubIdChanged
from acts_contrib.test_utils.tel.tel_defines import EventDisplayInfoChanged
-from acts_contrib.test_utils.tel.tel_defines import EventConnectivityChanged
-from acts_contrib.test_utils.tel.tel_defines import EventDataConnectionStateChanged
-from acts_contrib.test_utils.tel.tel_defines import EventDataSmsReceived
-from acts_contrib.test_utils.tel.tel_defines import EventMessageWaitingIndicatorChanged
from acts_contrib.test_utils.tel.tel_defines import EventServiceStateChanged
-from acts_contrib.test_utils.tel.tel_defines import EventMmsSentFailure
-from acts_contrib.test_utils.tel.tel_defines import EventMmsSentSuccess
-from acts_contrib.test_utils.tel.tel_defines import EventMmsDownloaded
-from acts_contrib.test_utils.tel.tel_defines import EventSmsReceived
-from acts_contrib.test_utils.tel.tel_defines import EventSmsDeliverFailure
-from acts_contrib.test_utils.tel.tel_defines import EventSmsDeliverSuccess
-from acts_contrib.test_utils.tel.tel_defines import EventSmsSentFailure
-from acts_contrib.test_utils.tel.tel_defines import EventSmsSentSuccess
-from acts_contrib.test_utils.tel.tel_defines import CallStateContainer
-from acts_contrib.test_utils.tel.tel_defines import DataConnectionStateContainer
-from acts_contrib.test_utils.tel.tel_defines import MessageWaitingIndicatorContainer
from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackContainer
from acts_contrib.test_utils.tel.tel_defines import ServiceStateContainer
from acts_contrib.test_utils.tel.tel_defines import DisplayInfoContainer
from acts_contrib.test_utils.tel.tel_defines import OverrideNetworkContainer
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_NR_LTE_GSM_WCDMA
-from acts_contrib.test_utils.tel.tel_defines import CARRIER_VZW, CARRIER_ATT, \
- CARRIER_BELL, CARRIER_ROGERS, CARRIER_KOODO, CARRIER_VIDEOTRON, CARRIER_TELUS
+from acts_contrib.test_utils.tel.tel_logging_utils import disable_qxdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import get_screen_shot_log
+from acts_contrib.test_utils.tel.tel_logging_utils import log_screen_shot
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_logger
from acts_contrib.test_utils.tel.tel_lookup_tables import connection_type_from_type_string
from acts_contrib.test_utils.tel.tel_lookup_tables import is_valid_rat
from acts_contrib.test_utils.tel.tel_lookup_tables import get_allowable_network_preference
from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_count_check_function
from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_check_number
-from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_delete_digit
from acts_contrib.test_utils.tel.tel_lookup_tables import network_preference_for_generation
from acts_contrib.test_utils.tel.tel_lookup_tables import operator_name_from_network_name
from acts_contrib.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id
-from acts_contrib.test_utils.tel.tel_lookup_tables import rat_families_for_network_preference
-from acts_contrib.test_utils.tel.tel_lookup_tables import rat_family_for_generation
from acts_contrib.test_utils.tel.tel_lookup_tables import rat_family_from_rat
from acts_contrib.test_utils.tel.tel_lookup_tables import rat_generation_from_rat
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id, get_subid_from_slot_index
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_by_adb
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_message_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_outgoing_call
from acts_contrib.test_utils.tel.tel_subscription_utils import set_incoming_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_message
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa_for_subscription
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa
-from acts_contrib.test_utils.wifi import wifi_test_utils
-from acts_contrib.test_utils.wifi import wifi_constants
-from acts_contrib.test_utils.gnss import gnss_test_utils as gutils
from acts.utils import adb_shell_ping
from acts.utils import load_config
-from acts.utils import start_standing_subprocess
-from acts.utils import stop_standing_subprocess
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
-from acts.utils import rand_ascii_str
-
-WIFI_SSID_KEY = wifi_test_utils.WifiEnums.SSID_KEY
-WIFI_PWD_KEY = wifi_test_utils.WifiEnums.PWD_KEY
-WIFI_CONFIG_APBAND_2G = 1
-WIFI_CONFIG_APBAND_5G = 2
-WIFI_CONFIG_APBAND_AUTO = wifi_test_utils.WifiEnums.WIFI_CONFIG_APBAND_AUTO
log = logging
STORY_LINE = "+19523521350"
CallResult = TelephonyVoiceTestResult.CallResult.Value
-voice_call_type = {}
-result_dict ={}
-
-class TelTestUtilsError(Exception):
- pass
class TelResultWrapper(object):
@@ -311,9 +215,6 @@
return setup_droid_properties_by_adb(
log, ad, sim_filename=sim_filename)
refresh_droid_config(log, ad)
- device_props = {}
- device_props['subscription'] = {}
-
sim_data = {}
if sim_filename:
try:
@@ -392,6 +293,7 @@
droid = ad.droid
sub_info_list = droid.subscriptionGetAllSubInfoList()
ad.log.info("SubInfoList is %s", sub_info_list)
+ if not sub_info_list: return
active_sub_id = get_outgoing_voice_sub_id(ad)
for sub_info in sub_info_list:
sub_id = sub_info["subscriptionId"]
@@ -479,7 +381,6 @@
else:
sub_record["phone_num"] = phone_number_formatter(
sub_info["number"])
- #ad.telephony['subscription'][sub_id] = sub_record
ad.log.info("SubId %s info: %s", sub_id, sorted(
sub_record.items()))
@@ -533,14 +434,6 @@
}
-def get_slot_index_from_subid(log, ad, sub_id):
- try:
- info = ad.droid.subscriptionGetSubInfoForSubscriber(sub_id)
- return info['simSlotIndex']
- except KeyError:
- return INVALID_SIM_SLOT_INDEX
-
-
def get_num_active_sims(log, ad):
""" Get the number of active SIM cards by counting slots
@@ -629,12 +522,6 @@
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 get_lte_rsrp(ad):
try:
if ad.adb.getprop("ro.build.version.release")[0] in ("9", "P"):
@@ -659,66 +546,6 @@
return None
-def check_data_stall_detection(ad, wait_time=WAIT_TIME_FOR_DATA_STALL):
- data_stall_detected = False
- time_var = 1
- try:
- while (time_var < wait_time):
- out = ad.adb.shell("dumpsys network_stack " \
- "| grep \"Suspecting data stall\"",
- ignore_status=True)
- ad.log.debug("Output is %s", out)
- if out:
- ad.log.info("NetworkMonitor detected - %s", out)
- data_stall_detected = True
- break
- time.sleep(30)
- time_var += 30
- except Exception as e:
- ad.log.error(e)
- return data_stall_detected
-
-
-def check_network_validation_fail(ad, begin_time=None,
- wait_time=WAIT_TIME_FOR_NW_VALID_FAIL):
- network_validation_fail = False
- time_var = 1
- try:
- while (time_var < wait_time):
- time_var += 30
- nw_valid = ad.search_logcat("validation failed",
- begin_time)
- if nw_valid:
- ad.log.info("Validation Failed received here - %s",
- nw_valid[0]["log_message"])
- network_validation_fail = True
- break
- time.sleep(30)
- except Exception as e:
- ad.log.error(e)
- return network_validation_fail
-
-
-def check_data_stall_recovery(ad, begin_time=None,
- wait_time=WAIT_TIME_FOR_DATA_STALL_RECOVERY):
- data_stall_recovery = False
- time_var = 1
- try:
- while (time_var < wait_time):
- time_var += 30
- recovery = ad.search_logcat("doRecovery() cleanup all connections",
- begin_time)
- if recovery:
- ad.log.info("Recovery Performed here - %s",
- recovery[-1]["log_message"])
- data_stall_recovery = True
- break
- time.sleep(30)
- except Exception as e:
- ad.log.error(e)
- return data_stall_recovery
-
-
def break_internet_except_sl4a_port(ad, sl4a_port):
ad.log.info("Breaking internet using iptables rules")
ad.adb.shell("iptables -I INPUT 1 -p tcp --dport %s -j ACCEPT" % sl4a_port,
@@ -1011,434 +838,6 @@
return True
-def wait_and_answer_call(log,
- ad,
- incoming_number=None,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- caller=None,
- video_state=None):
- """Wait for an incoming call on default voice subscription and
- accepts the call.
-
- Args:
- ad: android device object.
- incoming_number: Expected incoming number.
- Optional. Default is None
- incall_ui_display: after answer the call, bring in-call UI to foreground or
- background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
- if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
- if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
- else, do nothing.
-
- Returns:
- True: if incoming call is received and answered successfully.
- False: for errors
- """
- return wait_and_answer_call_for_subscription(
- log,
- ad,
- get_incoming_voice_sub_id(ad),
- incoming_number,
- incall_ui_display=incall_ui_display,
- caller=caller,
- video_state=video_state)
-
-
-def _wait_for_ringing_event(log, ad, wait_time):
- """Wait for ringing event.
-
- Args:
- log: log object.
- ad: android device object.
- wait_time: max time to wait for ringing event.
-
- Returns:
- event_ringing if received ringing event.
- otherwise return None.
- """
- event_ringing = None
-
- try:
- event_ringing = ad.ed.wait_for_event(
- EventCallStateChanged,
- is_event_match,
- timeout=wait_time,
- field=CallStateContainer.CALL_STATE,
- value=TELEPHONY_STATE_RINGING)
- ad.log.info("Receive ringing event")
- except Empty:
- ad.log.info("No Ringing Event")
- finally:
- return event_ringing
-
-
-def wait_for_ringing_call(log, ad, incoming_number=None):
- """Wait for an incoming call on default voice subscription and
- accepts the call.
-
- Args:
- log: log object.
- ad: android device object.
- incoming_number: Expected incoming number.
- Optional. Default is None
-
- Returns:
- True: if incoming call is received and answered successfully.
- False: for errors
- """
- return wait_for_ringing_call_for_subscription(
- log, ad, get_incoming_voice_sub_id(ad), incoming_number)
-
-
-def wait_for_ringing_call_for_subscription(
- log,
- ad,
- sub_id,
- incoming_number=None,
- caller=None,
- event_tracking_started=False,
- timeout=MAX_WAIT_TIME_CALLEE_RINGING,
- interval=WAIT_TIME_BETWEEN_STATE_CHECK):
- """Wait for an incoming call on specified subscription.
-
- Args:
- log: log object.
- ad: android device object.
- sub_id: subscription ID
- incoming_number: Expected incoming number. Default is None
- event_tracking_started: True if event tracking already state outside
- timeout: time to wait for ring
- interval: checking interval
-
- Returns:
- True: if incoming call is received and answered successfully.
- False: for errors
- """
- if not event_tracking_started:
- ad.ed.clear_events(EventCallStateChanged)
- ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
- ring_event_received = False
- end_time = time.time() + timeout
- try:
- while time.time() < end_time:
- if not ring_event_received:
- event_ringing = _wait_for_ringing_event(log, ad, interval)
- if event_ringing:
- if incoming_number and not check_phone_number_match(
- event_ringing['data']
- [CallStateContainer.INCOMING_NUMBER], incoming_number):
- ad.log.error(
- "Incoming Number not match. Expected number:%s, actual number:%s",
- incoming_number, event_ringing['data'][
- CallStateContainer.INCOMING_NUMBER])
- return False
- ring_event_received = True
- telephony_state = ad.droid.telephonyGetCallStateForSubscription(
- sub_id)
- telecom_state = ad.droid.telecomGetCallState()
- if telephony_state == TELEPHONY_STATE_RINGING and (
- telecom_state == TELEPHONY_STATE_RINGING):
- ad.log.info("callee is in telephony and telecom RINGING state")
- if caller:
- if caller.droid.telecomIsInCall():
- caller.log.info("Caller telecom is in call state")
- return True
- else:
- caller.log.info("Caller telecom is NOT in call state")
- else:
- return True
- else:
- ad.log.info(
- "telephony in %s, telecom in %s, expecting RINGING state",
- telephony_state, telecom_state)
- time.sleep(interval)
- finally:
- if not event_tracking_started:
- ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
- sub_id)
-
-
-def wait_for_call_offhook_for_subscription(
- log,
- ad,
- sub_id,
- event_tracking_started=False,
- timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT,
- interval=WAIT_TIME_BETWEEN_STATE_CHECK):
- """Wait for an incoming call on specified subscription.
-
- Args:
- log: log object.
- ad: android device object.
- sub_id: subscription ID
- timeout: time to wait for ring
- interval: checking interval
-
- Returns:
- True: if incoming call is received and answered successfully.
- False: for errors
- """
- if not event_tracking_started:
- ad.ed.clear_events(EventCallStateChanged)
- ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
- offhook_event_received = False
- end_time = time.time() + timeout
- try:
- while time.time() < end_time:
- if not offhook_event_received:
- if wait_for_call_offhook_event(log, ad, sub_id, True,
- interval):
- offhook_event_received = True
- telephony_state = ad.droid.telephonyGetCallStateForSubscription(
- sub_id)
- telecom_state = ad.droid.telecomGetCallState()
- if telephony_state == TELEPHONY_STATE_OFFHOOK and (
- telecom_state == TELEPHONY_STATE_OFFHOOK):
- ad.log.info("telephony and telecom are in OFFHOOK state")
- return True
- else:
- ad.log.info(
- "telephony in %s, telecom in %s, expecting OFFHOOK state",
- telephony_state, telecom_state)
- if offhook_event_received:
- time.sleep(interval)
- finally:
- if not event_tracking_started:
- ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
- sub_id)
-
-
-def wait_for_call_offhook_event(
- log,
- ad,
- sub_id,
- event_tracking_started=False,
- timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT):
- """Wait for an incoming call on specified subscription.
-
- Args:
- log: log object.
- ad: android device object.
- event_tracking_started: True if event tracking already state outside
- timeout: time to wait for event
-
- Returns:
- True: if call offhook event is received.
- False: if call offhook event is not received.
- """
- if not event_tracking_started:
- ad.ed.clear_events(EventCallStateChanged)
- ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
- try:
- ad.ed.wait_for_event(
- EventCallStateChanged,
- is_event_match,
- timeout=timeout,
- field=CallStateContainer.CALL_STATE,
- value=TELEPHONY_STATE_OFFHOOK)
- ad.log.info("Got event %s", TELEPHONY_STATE_OFFHOOK)
- except Empty:
- ad.log.info("No event for call state change to OFFHOOK")
- return False
- finally:
- if not event_tracking_started:
- ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
- sub_id)
- return True
-
-
-def wait_and_answer_call_for_subscription(
- log,
- ad,
- sub_id,
- incoming_number=None,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- timeout=MAX_WAIT_TIME_CALLEE_RINGING,
- caller=None,
- video_state=None):
- """Wait for an incoming call on specified subscription and
- accepts the call.
-
- Args:
- log: log object.
- ad: android device object.
- sub_id: subscription ID
- incoming_number: Expected incoming number.
- Optional. Default is None
- incall_ui_display: after answer the call, bring in-call UI to foreground or
- background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
- if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
- if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
- else, do nothing.
-
- Returns:
- True: if incoming call is received and answered successfully.
- False: for errors
- """
- ad.ed.clear_events(EventCallStateChanged)
- ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
- try:
- if not wait_for_ringing_call_for_subscription(
- log,
- ad,
- sub_id,
- incoming_number=incoming_number,
- caller=caller,
- event_tracking_started=True,
- timeout=timeout):
- ad.log.info("Incoming call ringing check failed.")
- return False
- ad.log.info("Accept the ring call")
- ad.droid.telecomAcceptRingingCall(video_state)
-
- if wait_for_call_offhook_for_subscription(
- log, ad, sub_id, event_tracking_started=True):
- return True
- else:
- ad.log.error("Could not answer the call.")
- return False
- except Exception as e:
- log.error(e)
- return False
- finally:
- ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
- if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
- ad.droid.telecomShowInCallScreen()
- elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
- ad.droid.showHomeScreen()
-
-
-def wait_and_reject_call(log,
- ad,
- incoming_number=None,
- delay_reject=WAIT_TIME_REJECT_CALL,
- reject=True):
- """Wait for an incoming call on default voice subscription and
- reject the call.
-
- Args:
- log: log object.
- ad: android device object.
- incoming_number: Expected incoming number.
- Optional. Default is None
- delay_reject: time to wait before rejecting the call
- Optional. Default is WAIT_TIME_REJECT_CALL
-
- Returns:
- 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)
-
-
-def wait_and_reject_call_for_subscription(log,
- ad,
- sub_id,
- incoming_number=None,
- delay_reject=WAIT_TIME_REJECT_CALL,
- reject=True):
- """Wait for an incoming call on specific subscription and
- reject the call.
-
- Args:
- log: log object.
- ad: android device object.
- sub_id: subscription ID
- incoming_number: Expected incoming number.
- Optional. Default is None
- delay_reject: time to wait before rejecting the call
- Optional. Default is WAIT_TIME_REJECT_CALL
-
- Returns:
- True: if incoming call is received and reject successfully.
- False: for errors
- """
-
- if not wait_for_ringing_call_for_subscription(log, ad, sub_id,
- incoming_number):
- ad.log.error(
- "Could not reject a call: incoming call in ringing check failed.")
- return False
-
- ad.ed.clear_events(EventCallStateChanged)
- ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
- if reject is True:
- # Delay between ringing and reject.
- time.sleep(delay_reject)
- is_find = False
- # Loop the call list and find the matched one to disconnect.
- for call in ad.droid.telecomCallGetCallIds():
- if check_phone_number_match(
- get_number_from_tel_uri(get_call_uri(ad, call)),
- incoming_number):
- ad.droid.telecomCallDisconnect(call)
- ad.log.info("Callee reject the call")
- is_find = True
- if is_find is False:
- ad.log.error("Callee did not find matching call to reject.")
- return False
- else:
- # don't reject on callee. Just ignore the incoming call.
- ad.log.info("Callee received incoming call. Ignore it.")
- try:
- ad.ed.wait_for_event(
- EventCallStateChanged,
- is_event_match_for_list,
- timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
- field=CallStateContainer.CALL_STATE,
- value_list=[TELEPHONY_STATE_IDLE, TELEPHONY_STATE_OFFHOOK])
- except Empty:
- ad.log.error("No onCallStateChangedIdle event received.")
- return False
- finally:
- ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
- return True
-
-
-def hangup_call(log, ad, is_emergency=False):
- """Hang up ongoing active call.
-
- Args:
- log: log object.
- ad: android device object.
-
- Returns:
- True: if all calls are cleared
- False: for errors
- """
- # short circuit in case no calls are active
- if not ad.droid.telecomIsInCall():
- ad.log.warning("No active call exists.")
- return True
- ad.ed.clear_events(EventCallStateChanged)
- ad.droid.telephonyStartTrackingCallState()
- ad.log.info("Hangup call.")
- if is_emergency:
- for call in ad.droid.telecomCallGetCallIds():
- ad.droid.telecomCallDisconnect(call)
- else:
- ad.droid.telecomEndCall()
-
- try:
- ad.ed.wait_for_event(
- EventCallStateChanged,
- is_event_match,
- timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
- field=CallStateContainer.CALL_STATE,
- value=TELEPHONY_STATE_IDLE)
- except Empty:
- ad.log.warning("Call state IDLE event is not received after hang up.")
- finally:
- ad.droid.telephonyStopTrackingCallStateChange()
- if not wait_for_state(ad.droid.telecomIsInCall, False, 15, 1):
- ad.log.error("Telecom is in call, hangup call failed.")
- return False
- return True
-
-
def wait_for_cbrs_data_active_sub_change_event(
ad,
event_tracking_started=False,
@@ -1528,12 +927,6 @@
ad.droid.telephonyStopTrackingDisplayInfoChange()
return -1
-def disconnect_call_by_id(log, ad, call_id):
- """Disconnect call by call id.
- """
- ad.droid.telecomCallDisconnect(call_id)
- return True
-
def _phone_number_remove_prefix(number):
"""Remove the country code and other prefix from the input phone number.
@@ -1604,88 +997,8 @@
return False
-def initiate_call(log,
- ad,
- callee_number,
- emergency=False,
- timeout=MAX_WAIT_TIME_CALL_INITIATION,
- checking_interval=5,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- video=False,
- voice_type_init=None,
- call_stats_check=False,
- result_info=result_dict,
- nsa_5g_for_stress=False):
- """Make phone call from caller to callee.
-
- Args:
- ad_caller: Caller android device object.
- callee_number: Callee phone number.
- emergency : specify the call is emergency.
- Optional. Default value is False.
- incall_ui_display: show the dialer UI foreground or backgroud
- video: whether to initiate as video call
-
- Returns:
- result: if phone call is placed successfully.
- """
- ad.ed.clear_events(EventCallStateChanged)
- sub_id = get_outgoing_voice_sub_id(ad)
- begin_time = get_device_epoch_time(ad)
- ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
- try:
- # Make a Call
- ad.log.info("Make a phone call to %s", callee_number)
- if emergency:
- ad.droid.telecomCallEmergencyNumber(callee_number)
- else:
- ad.droid.telecomCallNumber(callee_number, video)
-
- # Verify OFFHOOK state
- if not wait_for_call_offhook_for_subscription(
- log, ad, sub_id, event_tracking_started=True):
- ad.log.info("sub_id %s not in call offhook state", sub_id)
- last_call_drop_reason(ad, begin_time=begin_time)
- return False
- else:
- return True
-
- if call_stats_check:
- voice_type_in_call = ad.droid.telephonyGetCurrentVoiceNetworkType()
- phone_call_type = check_call_status(ad,
- voice_type_init,
- voice_type_in_call)
- result_info["Call Stats"] = phone_call_type
- ad.log.debug("Voice Call Type: %s", phone_call_type)
-
- finally:
- if hasattr(ad, "sdm_log") and getattr(ad, "sdm_log"):
- ad.adb.shell("i2cset -fy 3 64 6 1 b", ignore_status=True)
- ad.adb.shell("i2cset -fy 3 65 6 1 b", ignore_status=True)
- ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
-
- if nsa_5g_for_stress:
- if not is_current_network_5g_nsa(ad):
- ad.log.error("Phone is not attached on 5G NSA")
-
- if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
- ad.droid.telecomShowInCallScreen()
- elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
- ad.droid.showHomeScreen()
-
-
-def dial_phone_number(ad, callee_number):
- for number in str(callee_number):
- if number == "#":
- ad.send_keycode("POUND")
- elif number == "*":
- ad.send_keycode("STAR")
- elif number in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]:
- ad.send_keycode("%s" % number)
-
-
def get_call_state_by_adb(ad):
- slot_index_of_default_voice_subid = get_slot_index_from_subid(ad.log, ad,
+ slot_index_of_default_voice_subid = get_slot_index_from_subid(ad,
get_incoming_voice_sub_id(ad))
output = ad.adb.shell("dumpsys telephony.registry | grep mCallState")
if "mCallState" in output:
@@ -1712,78 +1025,6 @@
return re.search(r"mCallIncomingNumber=(.*)", output).group(1)
-def emergency_dialer_call_by_keyevent(ad, callee_number):
- for i in range(3):
- if "EmergencyDialer" in ad.get_my_current_focus_window():
- ad.log.info("EmergencyDialer is the current focus window")
- break
- elif i <= 2:
- ad.adb.shell("am start -a com.android.phone.EmergencyDialer.DIAL")
- time.sleep(1)
- else:
- ad.log.error("Unable to bring up EmergencyDialer")
- return False
- ad.log.info("Make a phone call to %s", callee_number)
- dial_phone_number(ad, callee_number)
- ad.send_keycode("CALL")
-
-
-def initiate_emergency_dialer_call_by_adb(
- log,
- ad,
- callee_number,
- timeout=MAX_WAIT_TIME_CALL_INITIATION,
- checking_interval=5):
- """Make emergency call by EmergencyDialer.
-
- Args:
- ad: Caller android device object.
- callee_number: Callee phone number.
- emergency : specify the call is emergency.
- Optional. Default value is False.
-
- Returns:
- result: if phone call is placed successfully.
- """
- 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(
- "am start -a android.intent.action.CALL_EMERGENCY -d tel:%s" %
- callee_number)
- if not timeout: return True
- ad.log.info("Check call state")
- # Verify Call State
- elapsed_time = 0
- while elapsed_time < timeout:
- time.sleep(checking_interval)
- elapsed_time += checking_interval
- if check_call_state_connected_by_adb(ad):
- ad.log.info("Call to %s is connected", callee_number)
- return True
- if check_call_state_idle_by_adb(ad):
- ad.log.info("Call to %s failed", callee_number)
- return False
- ad.log.info("Make call to %s failed", callee_number)
- return False
- except Exception as e:
- ad.log.error("initiate emergency call failed with error %s", e)
-
-
-def hangup_call_by_adb(ad):
- """Make emergency call by EmergencyDialer.
-
- Args:
- ad: Caller android device object.
- callee_number: Callee phone number.
- """
- ad.log.info("End call by adb")
- ad.send_keycode("ENDCALL")
-
-
def dumpsys_all_call_info(ad):
""" Get call information by dumpsys telecom. """
output = ad.adb.shell("dumpsys telecom")
@@ -1807,49 +1048,6 @@
return calls_info
-def dumpsys_last_call_info(ad):
- """ Get call information by dumpsys telecom. """
- num = dumpsys_last_call_number(ad)
- output = ad.adb.shell("dumpsys telecom")
- result = re.search(r"Call TC@%s: {(.*?)}" % num, output, re.DOTALL)
- call_info = {"TC": num}
- if result:
- result = result.group(1)
- for attr in ("startTime", "endTime", "direction", "isInterrupted",
- "callTechnologies", "callTerminationsReason",
- "isVideoCall", "callProperties"):
- match = re.search(r"%s: (.*)" % attr, result)
- if match:
- if attr in ("startTime", "endTime"):
- call_info[attr] = epoch_to_log_line_timestamp(
- int(match.group(1)))
- else:
- call_info[attr] = match.group(1)
- ad.log.debug("call_info = %s", call_info)
- return call_info
-
-
-def dumpsys_last_call_number(ad):
- output = ad.adb.shell("dumpsys telecom")
- call_nums = re.findall("Call TC@(\d+):", output)
- if not call_nums:
- return 0
- else:
- return int(call_nums[-1])
-
-
-def dumpsys_new_call_info(ad, last_tc_number, retries=3, interval=5):
- for i in range(retries):
- if dumpsys_last_call_number(ad) > last_tc_number:
- call_info = dumpsys_last_call_info(ad)
- ad.log.info("New call info = %s", sorted(call_info.items()))
- return call_info
- else:
- time.sleep(interval)
- ad.log.error("New call is not in sysdump telecom")
- return {}
-
-
def dumpsys_carrier_config(ad):
output = ad.adb.shell("dumpsys carrier_config").split("\n")
output_phone_id_0 = []
@@ -2006,1602 +1204,6 @@
return False
-def call_reject(log, ad_caller, ad_callee, reject=True):
- """Caller call Callee, then reject on callee.
-
-
- """
- subid_caller = ad_caller.droid.subscriptionGetDefaultVoiceSubId()
- subid_callee = ad_callee.incoming_voice_sub_id
- ad_caller.log.info("Sub-ID Caller %s, Sub-ID Callee %s", subid_caller,
- subid_callee)
- return call_reject_for_subscription(log, ad_caller, ad_callee,
- subid_caller, subid_callee, reject)
-
-
-def call_reject_for_subscription(log,
- ad_caller,
- ad_callee,
- subid_caller,
- subid_callee,
- reject=True):
- """
- """
-
- caller_number = ad_caller.telephony['subscription'][subid_caller][
- 'phone_num']
- callee_number = ad_callee.telephony['subscription'][subid_callee][
- 'phone_num']
-
- ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
- if not initiate_call(log, ad_caller, callee_number):
- ad_caller.log.error("Initiate call failed")
- return False
-
- if not wait_and_reject_call_for_subscription(
- log, ad_callee, subid_callee, caller_number, WAIT_TIME_REJECT_CALL,
- reject):
- ad_callee.log.error("Reject call fail.")
- return False
- # Check if incoming call is cleared on callee or not.
- if ad_callee.droid.telephonyGetCallStateForSubscription(
- subid_callee) == TELEPHONY_STATE_RINGING:
- ad_callee.log.error("Incoming call is not cleared")
- return False
- # Hangup on caller
- hangup_call(log, ad_caller)
- return True
-
-
-def call_reject_leave_message(log,
- ad_caller,
- ad_callee,
- verify_caller_func=None,
- wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
- """On default voice subscription, Call from caller to callee,
- reject on callee, caller leave a voice mail.
-
- 1. Caller call Callee.
- 2. Callee reject incoming call.
- 3. Caller leave a voice mail.
- 4. Verify callee received the voice mail notification.
-
- Args:
- ad_caller: caller android device object.
- ad_callee: callee android device object.
- verify_caller_func: function to verify caller is in correct state while in-call.
- This is optional, default is None.
- wait_time_in_call: time to wait when leaving a voice mail.
- This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
-
- Returns:
- True: if voice message is received on callee successfully.
- False: for errors
- """
- subid_caller = get_outgoing_voice_sub_id(ad_caller)
- subid_callee = get_incoming_voice_sub_id(ad_callee)
- return call_reject_leave_message_for_subscription(
- log, ad_caller, ad_callee, subid_caller, subid_callee,
- verify_caller_func, wait_time_in_call)
-
-
-def check_reject_needed_for_voice_mail(log, ad_callee):
- """Check if the carrier requires reject call to receive voice mail or just keep ringing
- Requested in b//155935290
- Four Japan carriers do not need to reject
- SBM, KDDI, Ntt Docomo, Rakuten
- Args:
- log: log object
- ad_callee: android device object
- Returns:
- True if callee's carrier is not one of the four Japan carriers
- False if callee's carrier is one of the four Japan carriers
- """
-
- operators_no_reject = [CARRIER_NTT_DOCOMO,
- CARRIER_KDDI,
- CARRIER_RAKUTEN,
- CARRIER_SBM]
- operator_name = get_operator_name(log, ad_callee)
-
- return operator_name not in operators_no_reject
-
-
-def call_reject_leave_message_for_subscription(
- log,
- ad_caller,
- ad_callee,
- subid_caller,
- subid_callee,
- verify_caller_func=None,
- wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
- """On specific voice subscription, Call from caller to callee,
- reject on callee, caller leave a voice mail.
-
- 1. Caller call Callee.
- 2. Callee reject incoming call.
- 3. Caller leave a voice mail.
- 4. Verify callee received the voice mail notification.
-
- Args:
- ad_caller: caller android device object.
- ad_callee: callee android device object.
- subid_caller: caller's subscription id.
- subid_callee: callee's subscription id.
- verify_caller_func: function to verify caller is in correct state while in-call.
- This is optional, default is None.
- wait_time_in_call: time to wait when leaving a voice mail.
- This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
-
- Returns:
- True: if voice message is received on callee successfully.
- False: for errors
- """
-
- # Currently this test utility only works for TMO and ATT and SPT.
- # It does not work for VZW (see b/21559800)
- # "with VVM TelephonyManager APIs won't work for vm"
-
- caller_number = ad_caller.telephony['subscription'][subid_caller][
- 'phone_num']
- callee_number = ad_callee.telephony['subscription'][subid_callee][
- 'phone_num']
-
- ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
-
- try:
- voice_mail_count_before = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
- subid_callee)
- ad_callee.log.info("voice mail count is %s", voice_mail_count_before)
- # -1 means there are unread voice mail, but the count is unknown
- # 0 means either this API not working (VZW) or no unread voice mail.
- if voice_mail_count_before != 0:
- log.warning("--Pending new Voice Mail, please clear on phone.--")
-
- if not initiate_call(log, ad_caller, callee_number):
- ad_caller.log.error("Initiate call failed.")
- return False
- if check_reject_needed_for_voice_mail(log, ad_callee):
- carrier_specific_delay_reject = 30
- else:
- carrier_specific_delay_reject = 2
- carrier_reject_call = not check_reject_needed_for_voice_mail(log, ad_callee)
-
- if not wait_and_reject_call_for_subscription(
- log, ad_callee, subid_callee, incoming_number=caller_number, delay_reject=carrier_specific_delay_reject,
- reject=carrier_reject_call):
- ad_callee.log.error("Reject call fail.")
- return False
-
- ad_callee.droid.telephonyStartTrackingVoiceMailStateChangeForSubscription(
- subid_callee)
-
- # ensure that all internal states are updated in telecom
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- ad_callee.ed.clear_events(EventCallStateChanged)
-
- if verify_caller_func and not verify_caller_func(log, ad_caller):
- ad_caller.log.error("Caller not in correct state!")
- return False
-
- # TODO: b/26293512 Need to play some sound to leave message.
- # Otherwise carrier voice mail server may drop this voice mail.
- time.sleep(wait_time_in_call)
-
- if not verify_caller_func:
- caller_state_result = ad_caller.droid.telecomIsInCall()
- else:
- caller_state_result = verify_caller_func(log, ad_caller)
- if not caller_state_result:
- ad_caller.log.error("Caller not in correct state after %s seconds",
- wait_time_in_call)
-
- if not hangup_call(log, ad_caller):
- ad_caller.log.error("Error in Hanging-Up Call")
- return False
-
- ad_callee.log.info("Wait for voice mail indicator on callee.")
- try:
- event = ad_callee.ed.wait_for_event(
- EventMessageWaitingIndicatorChanged,
- _is_on_message_waiting_event_true)
- ad_callee.log.info("Got event %s", event)
- except Empty:
- ad_callee.log.warning("No expected event %s",
- EventMessageWaitingIndicatorChanged)
- return False
- voice_mail_count_after = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
- subid_callee)
- ad_callee.log.info(
- "telephonyGetVoiceMailCount output - before: %s, after: %s",
- voice_mail_count_before, voice_mail_count_after)
-
- # voice_mail_count_after should:
- # either equals to (voice_mail_count_before + 1) [For ATT and SPT]
- # or equals to -1 [For TMO]
- # -1 means there are unread voice mail, but the count is unknown
- if not check_voice_mail_count(log, ad_callee, voice_mail_count_before,
- voice_mail_count_after):
- log.error("before and after voice mail count is not incorrect.")
- return False
- finally:
- ad_callee.droid.telephonyStopTrackingVoiceMailStateChangeForSubscription(
- subid_callee)
- return True
-
-
-def call_voicemail_erase_all_pending_voicemail(log, ad):
- """Script for phone to erase all pending voice mail.
- This script only works for TMO and ATT and SPT currently.
- This script only works if phone have already set up voice mail options,
- and phone should disable password protection for voice mail.
-
- 1. If phone don't have pending voice message, return True.
- 2. Dial voice mail number.
- For TMO, the number is '123'
- For ATT, the number is phone's number
- For SPT, the number is phone's number
- 3. Wait for voice mail connection setup.
- 4. Wait for voice mail play pending voice message.
- 5. Send DTMF to delete one message.
- The digit is '7'.
- 6. Repeat steps 4 and 5 until voice mail server drop this call.
- (No pending message)
- 6. Check telephonyGetVoiceMailCount result. it should be 0.
-
- Args:
- log: log object
- ad: android device object
- Returns:
- False if error happens. True is succeed.
- """
- log.info("Erase all pending voice mail.")
- count = ad.droid.telephonyGetVoiceMailCount()
- if count == 0:
- ad.log.info("No Pending voice mail.")
- return True
- if count == -1:
- ad.log.info("There is pending voice mail, but the count is unknown")
- count = MAX_SAVED_VOICE_MAIL
- else:
- ad.log.info("There are %s voicemails", count)
-
- voice_mail_number = get_voice_mail_number(log, ad)
- delete_digit = get_voice_mail_delete_digit(get_operator_name(log, ad))
- if not initiate_call(log, ad, voice_mail_number):
- log.error("Initiate call to voice mail failed.")
- return False
- time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
- callId = ad.droid.telecomCallGetCallIds()[0]
- time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
- while (is_phone_in_call(log, ad) and (count > 0)):
- ad.log.info("Press %s to delete voice mail.", delete_digit)
- ad.droid.telecomCallPlayDtmfTone(callId, delete_digit)
- ad.droid.telecomCallStopDtmfTone(callId)
- time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
- count -= 1
- if is_phone_in_call(log, ad):
- hangup_call(log, ad)
-
- # wait for telephonyGetVoiceMailCount to update correct result
- remaining_time = MAX_WAIT_TIME_VOICE_MAIL_COUNT
- while ((remaining_time > 0)
- and (ad.droid.telephonyGetVoiceMailCount() != 0)):
- time.sleep(1)
- remaining_time -= 1
- current_voice_mail_count = ad.droid.telephonyGetVoiceMailCount()
- ad.log.info("telephonyGetVoiceMailCount: %s", current_voice_mail_count)
- return (current_voice_mail_count == 0)
-
-
-def _is_on_message_waiting_event_true(event):
- """Private function to return if the received EventMessageWaitingIndicatorChanged
- event MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING field is True.
- """
- return event['data'][MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING]
-
-
-def call_setup_teardown(log,
- ad_caller,
- ad_callee,
- ad_hangup=None,
- verify_caller_func=None,
- verify_callee_func=None,
- wait_time_in_call=WAIT_TIME_IN_CALL,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- dialing_number_length=None,
- video_state=None,
- slot_id_callee=None,
- voice_type_init=None,
- call_stats_check=False,
- result_info=result_dict,
- nsa_5g_for_stress=False):
- """ Call process, including make a phone call from caller,
- accept from callee, and hang up. The call is on default voice subscription
-
- In call process, call from <droid_caller> to <droid_callee>,
- accept the call, (optional)then hang up from <droid_hangup>.
-
- Args:
- ad_caller: Caller Android Device Object.
- ad_callee: Callee Android Device Object.
- ad_hangup: Android Device Object end the phone call.
- Optional. Default value is None, and phone call will continue.
- verify_call_mode_caller: func_ptr to verify caller in correct mode
- Optional. Default is None
- verify_call_mode_caller: func_ptr to verify caller in correct mode
- Optional. Default is None
- incall_ui_display: after answer the call, bring in-call UI to foreground or
- background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
- if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
- if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
- else, do nothing.
- dialing_number_length: the number of digits used for dialing
- slot_id_callee : the slot if of the callee to call to
-
- Returns:
- True if call process without any error.
- False if error happened.
-
- """
- subid_caller = get_outgoing_voice_sub_id(ad_caller)
- if slot_id_callee is None:
- subid_callee = get_incoming_voice_sub_id(ad_callee)
- else:
- subid_callee = get_subid_from_slot_index(log, ad_callee, slot_id_callee)
-
- return call_setup_teardown_for_subscription(
- log, ad_caller, ad_callee, subid_caller, subid_callee, ad_hangup,
- verify_caller_func, verify_callee_func, wait_time_in_call,
- incall_ui_display, dialing_number_length, video_state,
- voice_type_init, call_stats_check, result_info, nsa_5g_for_stress)
-
-
-
-def call_setup_teardown_for_subscription(
- log,
- ad_caller,
- ad_callee,
- subid_caller,
- subid_callee,
- ad_hangup=None,
- verify_caller_func=None,
- verify_callee_func=None,
- wait_time_in_call=WAIT_TIME_IN_CALL,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- dialing_number_length=None,
- video_state=None,
- voice_type_init=None,
- call_stats_check=False,
- result_info=result_dict,
- nsa_5g_for_stress=False):
- """ Call process, including make a phone call from caller,
- accept from callee, and hang up. The call is on specified subscription
-
- In call process, call from <droid_caller> to <droid_callee>,
- accept the call, (optional)then hang up from <droid_hangup>.
-
- Args:
- ad_caller: Caller Android Device Object.
- ad_callee: Callee Android Device Object.
- subid_caller: Caller subscription ID
- subid_callee: Callee subscription ID
- ad_hangup: Android Device Object end the phone call.
- Optional. Default value is None, and phone call will continue.
- verify_call_mode_caller: func_ptr to verify caller in correct mode
- Optional. Default is None
- verify_call_mode_caller: func_ptr to verify caller in correct mode
- Optional. Default is None
- incall_ui_display: after answer the call, bring in-call UI to foreground or
- background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
- if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
- if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
- else, do nothing.
-
- Returns:
- TelResultWrapper which will evaluate as False if error.
-
- """
- CHECK_INTERVAL = 5
- begin_time = get_current_epoch_time()
- if not verify_caller_func:
- verify_caller_func = is_phone_in_call
- if not verify_callee_func:
- verify_callee_func = is_phone_in_call
-
- caller_number = ad_caller.telephony['subscription'][subid_caller][
- 'phone_num']
- callee_number = ad_callee.telephony['subscription'][subid_callee][
- 'phone_num']
- if dialing_number_length:
- skip_test = False
- trunc_position = 0 - int(dialing_number_length)
- try:
- caller_area_code = caller_number[:trunc_position]
- callee_area_code = callee_number[:trunc_position]
- callee_dial_number = callee_number[trunc_position:]
- except:
- skip_test = True
- if caller_area_code != callee_area_code:
- skip_test = True
- if skip_test:
- msg = "Cannot make call from %s to %s by %s digits" % (
- caller_number, callee_number, dialing_number_length)
- ad_caller.log.info(msg)
- raise signals.TestSkip(msg)
- else:
- callee_number = callee_dial_number
-
- tel_result_wrapper = TelResultWrapper(CallResult('SUCCESS'))
- msg = "Call from %s to %s" % (caller_number, callee_number)
- if video_state:
- msg = "Video %s" % msg
- video = True
- else:
- video = False
- if ad_hangup:
- msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
- ad_caller.log.info(msg)
-
- for ad in (ad_caller, ad_callee):
- call_ids = ad.droid.telecomCallGetCallIds()
- setattr(ad, "call_ids", call_ids)
- if call_ids:
- ad.log.info("Pre-exist CallId %s before making call", call_ids)
- try:
- if not initiate_call(
- log,
- ad_caller,
- callee_number,
- incall_ui_display=incall_ui_display,
- video=video):
- ad_caller.log.error("Initiate call failed.")
- tel_result_wrapper.result_value = CallResult('INITIATE_FAILED')
- return tel_result_wrapper
- else:
- ad_caller.log.info("Caller initate call successfully")
- if not wait_and_answer_call_for_subscription(
- log,
- ad_callee,
- subid_callee,
- incoming_number=caller_number,
- caller=ad_caller,
- incall_ui_display=incall_ui_display,
- video_state=video_state):
- ad_callee.log.error("Answer call fail.")
- tel_result_wrapper.result_value = CallResult(
- 'NO_RING_EVENT_OR_ANSWER_FAILED')
- return tel_result_wrapper
- else:
- ad_callee.log.info("Callee answered the call successfully")
-
- for ad, call_func in zip([ad_caller, ad_callee],
- [verify_caller_func, verify_callee_func]):
- call_ids = ad.droid.telecomCallGetCallIds()
- new_call_ids = set(call_ids) - set(ad.call_ids)
- if not new_call_ids:
- ad.log.error(
- "No new call ids are found after call establishment")
- ad.log.error("telecomCallGetCallIds returns %s",
- ad.droid.telecomCallGetCallIds())
- tel_result_wrapper.result_value = CallResult('NO_CALL_ID_FOUND')
- for new_call_id in new_call_ids:
- if not wait_for_in_call_active(ad, call_id=new_call_id):
- tel_result_wrapper.result_value = CallResult(
- 'CALL_STATE_NOT_ACTIVE_DURING_ESTABLISHMENT')
- else:
- ad.log.info("callProperties = %s",
- ad.droid.telecomCallGetProperties(new_call_id))
-
- if not ad.droid.telecomCallGetAudioState():
- ad.log.error("Audio is not in call state")
- tel_result_wrapper.result_value = CallResult(
- 'AUDIO_STATE_NOT_INCALL_DURING_ESTABLISHMENT')
-
- if call_func(log, ad):
- ad.log.info("Call is in %s state", call_func.__name__)
- else:
- ad.log.error("Call is not in %s state, voice in RAT %s",
- call_func.__name__,
- ad.droid.telephonyGetCurrentVoiceNetworkType())
- tel_result_wrapper.result_value = CallResult(
- 'CALL_DROP_OR_WRONG_STATE_DURING_ESTABLISHMENT')
- if not tel_result_wrapper:
- return tel_result_wrapper
-
- if call_stats_check:
- voice_type_in_call = check_voice_network_type([ad_caller, ad_callee], voice_init=False)
- phone_a_call_type = check_call_status(ad_caller,
- voice_type_init[0],
- voice_type_in_call[0])
- result_info["Call Stats"] = phone_a_call_type
- ad_caller.log.debug("Voice Call Type: %s", phone_a_call_type)
- phone_b_call_type = check_call_status(ad_callee,
- voice_type_init[1],
- voice_type_in_call[1])
- result_info["Call Stats"] = phone_b_call_type
- ad_callee.log.debug("Voice Call Type: %s", phone_b_call_type)
-
- elapsed_time = 0
- while (elapsed_time < wait_time_in_call):
- CHECK_INTERVAL = min(CHECK_INTERVAL,
- wait_time_in_call - elapsed_time)
- time.sleep(CHECK_INTERVAL)
- elapsed_time += CHECK_INTERVAL
- time_message = "at <%s>/<%s> second." % (elapsed_time,
- wait_time_in_call)
- 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, voice in RAT %s",
- call_func.__name__, time_message,
- ad.droid.telephonyGetCurrentVoiceNetworkType())
- tel_result_wrapper.result_value = CallResult(
- 'CALL_DROP_OR_WRONG_STATE_AFTER_CONNECTED')
- 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)
- tel_result_wrapper.result_value = CallResult(
- 'AUDIO_STATE_NOT_INCALL_AFTER_CONNECTED')
- if not tel_result_wrapper:
- return tel_result_wrapper
-
- if ad_hangup:
- if not hangup_call(log, ad_hangup):
- ad_hangup.log.info("Failed to hang up the call")
- tel_result_wrapper.result_value = CallResult('CALL_HANGUP_FAIL')
- return tel_result_wrapper
- finally:
- if not tel_result_wrapper:
- for ad in (ad_caller, ad_callee):
- last_call_drop_reason(ad, begin_time)
- try:
- if ad.droid.telecomIsInCall():
- ad.log.info("In call. End now.")
- ad.droid.telecomEndCall()
- except Exception as e:
- log.error(str(e))
-
- if nsa_5g_for_stress:
- for ad in (ad_caller, ad_callee):
- if not is_current_network_5g_nsa(ad):
- ad.log.error("Phone not attached on 5G NSA")
-
- if ad_hangup or not tel_result_wrapper:
- for ad in (ad_caller, ad_callee):
- if not wait_for_call_id_clearing(
- ad, getattr(ad, "caller_ids", [])):
- tel_result_wrapper.result_value = CallResult(
- 'CALL_ID_CLEANUP_FAIL')
- return tel_result_wrapper
-
-
-def call_setup_teardown_for_call_forwarding(
- log,
- ad_caller,
- ad_callee,
- forwarded_callee,
- ad_hangup=None,
- verify_callee_func=None,
- verify_after_cf_disabled=None,
- wait_time_in_call=WAIT_TIME_IN_CALL,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- dialing_number_length=None,
- video_state=None,
- call_forwarding_type="unconditional"):
- """ Call process for call forwarding, including make a phone call from
- caller, forward from callee, accept from the forwarded callee and hang up.
- The call is on default voice subscription
-
- In call process, call from <ad_caller> to <ad_callee>, forwarded to
- <forwarded_callee>, accept the call, (optional) and then hang up from
- <ad_hangup>.
-
- Args:
- ad_caller: Caller Android Device Object.
- ad_callee: Callee Android Device Object which forwards the call.
- forwarded_callee: Callee Android Device Object which answers the call.
- ad_hangup: Android Device Object end the phone call.
- Optional. Default value is None, and phone call will continue.
- verify_callee_func: func_ptr to verify callee in correct mode
- Optional. Default is None
- verify_after_cf_disabled: If True the test of disabling call forwarding
- will be appended.
- wait_time_in_call: the call duration of a connected call
- incall_ui_display: after answer the call, bring in-call UI to foreground
- or background.
- Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
- if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
- if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
- else, do nothing.
- dialing_number_length: the number of digits used for dialing
- video_state: video call or voice call. Default is voice call.
- call_forwarding_type: type of call forwarding listed below:
- - unconditional
- - busy
- - not_answered
- - not_reachable
-
- Returns:
- True if call process without any error.
- False if error happened.
-
- """
- subid_caller = get_outgoing_voice_sub_id(ad_caller)
- subid_callee = get_incoming_voice_sub_id(ad_callee)
- subid_forwarded_callee = get_incoming_voice_sub_id(forwarded_callee)
- return call_setup_teardown_for_call_forwarding_for_subscription(
- log,
- ad_caller,
- ad_callee,
- forwarded_callee,
- subid_caller,
- subid_callee,
- subid_forwarded_callee,
- ad_hangup,
- verify_callee_func,
- wait_time_in_call,
- incall_ui_display,
- dialing_number_length,
- video_state,
- call_forwarding_type,
- verify_after_cf_disabled)
-
-
-def call_setup_teardown_for_call_forwarding_for_subscription(
- log,
- ad_caller,
- ad_callee,
- forwarded_callee,
- subid_caller,
- subid_callee,
- subid_forwarded_callee,
- ad_hangup=None,
- verify_callee_func=None,
- wait_time_in_call=WAIT_TIME_IN_CALL,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- dialing_number_length=None,
- video_state=None,
- call_forwarding_type="unconditional",
- verify_after_cf_disabled=None):
- """ Call process for call forwarding, including make a phone call from caller,
- forward from callee, accept from the forwarded callee and hang up.
- The call is on specified subscription
-
- In call process, call from <ad_caller> to <ad_callee>, forwarded to
- <forwarded_callee>, accept the call, (optional) and then hang up from
- <ad_hangup>.
-
- Args:
- ad_caller: Caller Android Device Object.
- ad_callee: Callee Android Device Object which forwards the call.
- forwarded_callee: Callee Android Device Object which answers the call.
- subid_caller: Caller subscription ID
- subid_callee: Callee subscription ID
- subid_forwarded_callee: Forwarded callee subscription ID
- ad_hangup: Android Device Object end the phone call.
- Optional. Default value is None, and phone call will continue.
- verify_callee_func: func_ptr to verify callee in correct mode
- Optional. Default is None
- wait_time_in_call: the call duration of a connected call
- incall_ui_display: after answer the call, bring in-call UI to foreground
- or background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
- if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
- if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
- else, do nothing.
- dialing_number_length: the number of digits used for dialing
- video_state: video call or voice call. Default is voice call.
- call_forwarding_type: type of call forwarding listed below:
- - unconditional
- - busy
- - not_answered
- - not_reachable
- verify_after_cf_disabled: If True the call forwarding will not be
- enabled. This argument is used to verify if the call can be received
- successfully after call forwarding was disabled.
-
- Returns:
- True if call process without any error.
- False if error happened.
-
- """
- CHECK_INTERVAL = 5
- begin_time = get_current_epoch_time()
- verify_caller_func = is_phone_in_call
- if not verify_callee_func:
- verify_callee_func = is_phone_in_call
- verify_forwarded_callee_func = is_phone_in_call
-
- caller_number = ad_caller.telephony['subscription'][subid_caller][
- 'phone_num']
- callee_number = ad_callee.telephony['subscription'][subid_callee][
- 'phone_num']
- forwarded_callee_number = forwarded_callee.telephony['subscription'][
- subid_forwarded_callee]['phone_num']
-
- if dialing_number_length:
- skip_test = False
- trunc_position = 0 - int(dialing_number_length)
- try:
- caller_area_code = caller_number[:trunc_position]
- callee_area_code = callee_number[:trunc_position]
- callee_dial_number = callee_number[trunc_position:]
- except:
- skip_test = True
- if caller_area_code != callee_area_code:
- skip_test = True
- if skip_test:
- msg = "Cannot make call from %s to %s by %s digits" % (
- caller_number, callee_number, dialing_number_length)
- ad_caller.log.info(msg)
- raise signals.TestSkip(msg)
- else:
- callee_number = callee_dial_number
-
- result = True
- msg = "Call from %s to %s (forwarded to %s)" % (
- caller_number, callee_number, forwarded_callee_number)
- if video_state:
- msg = "Video %s" % msg
- video = True
- else:
- video = False
- if ad_hangup:
- msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
- ad_caller.log.info(msg)
-
- for ad in (ad_caller, forwarded_callee):
- call_ids = ad.droid.telecomCallGetCallIds()
- setattr(ad, "call_ids", call_ids)
- if call_ids:
- ad.log.info("Pre-exist CallId %s before making call", call_ids)
-
- if not verify_after_cf_disabled:
- if not set_call_forwarding_by_mmi(
- log,
- ad_callee,
- forwarded_callee,
- call_forwarding_type=call_forwarding_type):
- raise signals.TestFailure(
- "Failed to register or activate call forwarding.",
- extras={"fail_reason": "Failed to register or activate call"
- " forwarding."})
-
- if call_forwarding_type == "not_reachable":
- if not toggle_airplane_mode_msim(
- log,
- ad_callee,
- new_state=True,
- strict_checking=True):
- return False
-
- if call_forwarding_type == "busy":
- ad_callee.log.info("Callee is making a phone call to 0000000000 to make"
- " itself busy.")
- ad_callee.droid.telecomCallNumber("0000000000", False)
- time.sleep(2)
-
- if check_call_state_idle_by_adb(ad_callee):
- ad_callee.log.error("Call state of the callee is idle.")
- if not verify_after_cf_disabled:
- erase_call_forwarding_by_mmi(
- log,
- ad_callee,
- call_forwarding_type=call_forwarding_type)
- return False
-
- try:
- if not initiate_call(
- log,
- ad_caller,
- callee_number,
- incall_ui_display=incall_ui_display,
- video=video):
-
- ad_caller.log.error("Caller failed to initiate the call.")
- result = False
-
- if call_forwarding_type == "not_reachable":
- if toggle_airplane_mode_msim(
- log,
- ad_callee,
- new_state=False,
- strict_checking=True):
- time.sleep(10)
- elif call_forwarding_type == "busy":
- hangup_call(log, ad_callee)
-
- if not verify_after_cf_disabled:
- erase_call_forwarding_by_mmi(
- log,
- ad_callee,
- call_forwarding_type=call_forwarding_type)
- return False
- else:
- ad_caller.log.info("Caller initated the call successfully.")
-
- if call_forwarding_type == "not_answered":
- if not wait_for_ringing_call_for_subscription(
- log,
- ad_callee,
- subid_callee,
- incoming_number=caller_number,
- caller=ad_caller,
- event_tracking_started=True):
- ad.log.info("Incoming call ringing check failed.")
- return False
-
- _timeout = 30
- while check_call_state_ring_by_adb(ad_callee) == 1 and _timeout >= 0:
- time.sleep(1)
- _timeout = _timeout - 1
-
- if not wait_and_answer_call_for_subscription(
- log,
- forwarded_callee,
- subid_forwarded_callee,
- incoming_number=caller_number,
- caller=ad_caller,
- incall_ui_display=incall_ui_display,
- video_state=video_state):
-
- if not verify_after_cf_disabled:
- forwarded_callee.log.error("Forwarded callee failed to receive"
- "or answer the call.")
- result = False
- else:
- forwarded_callee.log.info("Forwarded callee did not receive or"
- " answer the call.")
-
- if call_forwarding_type == "not_reachable":
- if toggle_airplane_mode_msim(
- log,
- ad_callee,
- new_state=False,
- strict_checking=True):
- time.sleep(10)
- elif call_forwarding_type == "busy":
- hangup_call(log, ad_callee)
-
- if not verify_after_cf_disabled:
- erase_call_forwarding_by_mmi(
- log,
- ad_callee,
- call_forwarding_type=call_forwarding_type)
- return False
-
- else:
- if not verify_after_cf_disabled:
- forwarded_callee.log.info("Forwarded callee answered the call"
- " successfully.")
- else:
- forwarded_callee.log.error("Forwarded callee should not be able"
- " to answer the call.")
- hangup_call(log, ad_caller)
- result = False
-
- for ad, subid, call_func in zip(
- [ad_caller, forwarded_callee],
- [subid_caller, subid_forwarded_callee],
- [verify_caller_func, verify_forwarded_callee_func]):
- call_ids = ad.droid.telecomCallGetCallIds()
- new_call_ids = set(call_ids) - set(ad.call_ids)
- if not new_call_ids:
- if not verify_after_cf_disabled:
- ad.log.error(
- "No new call ids are found after call establishment")
- ad.log.error("telecomCallGetCallIds returns %s",
- ad.droid.telecomCallGetCallIds())
- result = False
- for new_call_id in new_call_ids:
- if not verify_after_cf_disabled:
- if not wait_for_in_call_active(ad, call_id=new_call_id):
- result = False
- else:
- ad.log.info("callProperties = %s",
- ad.droid.telecomCallGetProperties(new_call_id))
- else:
- ad.log.error("No new call id should be found.")
-
- if not ad.droid.telecomCallGetAudioState():
- if not verify_after_cf_disabled:
- ad.log.error("Audio is not in call state")
- result = False
-
- if call_func(log, ad):
- if not verify_after_cf_disabled:
- ad.log.info("Call is in %s state", call_func.__name__)
- else:
- ad.log.error("Call is in %s state", call_func.__name__)
- else:
- if not verify_after_cf_disabled:
- ad.log.error(
- "Call is not in %s state, voice in RAT %s",
- call_func.__name__,
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
- result = False
-
- if not result:
- if call_forwarding_type == "not_reachable":
- if toggle_airplane_mode_msim(
- log,
- ad_callee,
- new_state=False,
- strict_checking=True):
- time.sleep(10)
- elif call_forwarding_type == "busy":
- hangup_call(log, ad_callee)
-
- if not verify_after_cf_disabled:
- erase_call_forwarding_by_mmi(
- log,
- ad_callee,
- call_forwarding_type=call_forwarding_type)
- return False
-
- elapsed_time = 0
- while (elapsed_time < wait_time_in_call):
- CHECK_INTERVAL = min(CHECK_INTERVAL,
- wait_time_in_call - elapsed_time)
- time.sleep(CHECK_INTERVAL)
- elapsed_time += CHECK_INTERVAL
- time_message = "at <%s>/<%s> second." % (elapsed_time,
- wait_time_in_call)
- for ad, subid, call_func in [
- (ad_caller, subid_caller, verify_caller_func),
- (forwarded_callee, subid_forwarded_callee,
- verify_forwarded_callee_func)]:
- if not call_func(log, ad):
- if not verify_after_cf_disabled:
- ad.log.error(
- "NOT in correct %s state at %s, voice in RAT %s",
- call_func.__name__, time_message,
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
- result = False
- else:
- if not verify_after_cf_disabled:
- ad.log.info("In correct %s state at %s",
- call_func.__name__, time_message)
- else:
- ad.log.error("In correct %s state at %s",
- call_func.__name__, time_message)
-
- if not ad.droid.telecomCallGetAudioState():
- if not verify_after_cf_disabled:
- ad.log.error("Audio is not in call state at %s",
- time_message)
- result = False
-
- if not result:
- if call_forwarding_type == "not_reachable":
- if toggle_airplane_mode_msim(
- log,
- ad_callee,
- new_state=False,
- strict_checking=True):
- time.sleep(10)
- elif call_forwarding_type == "busy":
- hangup_call(log, ad_callee)
-
- if not verify_after_cf_disabled:
- erase_call_forwarding_by_mmi(
- log,
- ad_callee,
- call_forwarding_type=call_forwarding_type)
- return False
-
- if ad_hangup:
- if not hangup_call(log, ad_hangup):
- ad_hangup.log.info("Failed to hang up the call")
- result = False
- if call_forwarding_type == "not_reachable":
- if toggle_airplane_mode_msim(
- log,
- ad_callee,
- new_state=False,
- strict_checking=True):
- time.sleep(10)
- elif call_forwarding_type == "busy":
- hangup_call(log, ad_callee)
-
- if not verify_after_cf_disabled:
- erase_call_forwarding_by_mmi(
- log,
- ad_callee,
- call_forwarding_type=call_forwarding_type)
- return False
- finally:
- if not result:
- if verify_after_cf_disabled:
- result = True
- else:
- for ad in (ad_caller, forwarded_callee):
- last_call_drop_reason(ad, begin_time)
- try:
- if ad.droid.telecomIsInCall():
- ad.log.info("In call. End now.")
- ad.droid.telecomEndCall()
- except Exception as e:
- log.error(str(e))
-
- if ad_hangup or not result:
- for ad in (ad_caller, forwarded_callee):
- if not wait_for_call_id_clearing(
- ad, getattr(ad, "caller_ids", [])):
- result = False
-
- if call_forwarding_type == "not_reachable":
- if toggle_airplane_mode_msim(
- log,
- ad_callee,
- new_state=False,
- strict_checking=True):
- time.sleep(10)
- elif call_forwarding_type == "busy":
- hangup_call(log, ad_callee)
-
- if not verify_after_cf_disabled:
- erase_call_forwarding_by_mmi(
- log,
- ad_callee,
- call_forwarding_type=call_forwarding_type)
-
- if not result:
- return result
-
- ad_caller.log.info(
- "Make a normal call to callee to ensure the call can be connected after"
- " call forwarding was disabled")
- return call_setup_teardown_for_subscription(
- log, ad_caller, ad_callee, subid_caller, subid_callee, ad_caller,
- verify_caller_func, verify_callee_func, wait_time_in_call,
- incall_ui_display, dialing_number_length, video_state)
-
-
-def call_setup_teardown_for_call_waiting(log,
- ad_caller,
- ad_callee,
- ad_caller2,
- ad_hangup=None,
- ad_hangup2=None,
- verify_callee_func=None,
- end_first_call_before_answering_second_call=True,
- wait_time_in_call=WAIT_TIME_IN_CALL,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- dialing_number_length=None,
- video_state=None,
- call_waiting=True):
- """ Call process for call waiting, including make the 1st phone call from
- caller, answer the call by the callee, and receive the 2nd call from the
- caller2. The call is on default voice subscription
-
- In call process, 1st call from <ad_caller> to <ad_callee>, 2nd call from
- <ad_caller2> to <ad_callee>, hang up the existing call or reject the
- incoming call according to the test scenario.
-
- Args:
- ad_caller: Caller Android Device Object.
- ad_callee: Callee Android Device Object.
- ad_caller2: Caller2 Android Device Object.
- ad_hangup: Android Device Object end the 1st phone call.
- Optional. Default value is None, and phone call will continue.
- ad_hangup2: Android Device Object end the 2nd phone call.
- Optional. Default value is None, and phone call will continue.
- verify_callee_func: func_ptr to verify callee in correct mode
- Optional. Default is None
- end_first_call_before_answering_second_call: If True the 2nd call will
- be rejected on the ringing stage.
- wait_time_in_call: the call duration of a connected call
- incall_ui_display: after answer the call, bring in-call UI to foreground
- or background.
- Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
- if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
- if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
- else, do nothing.
- dialing_number_length: the number of digits used for dialing
- video_state: video call or voice call. Default is voice call.
- call_waiting: True to enable call waiting and False to disable.
-
- Returns:
- True if call process without any error.
- False if error happened.
-
- """
- subid_caller = get_outgoing_voice_sub_id(ad_caller)
- subid_callee = get_incoming_voice_sub_id(ad_callee)
- subid_caller2 = get_incoming_voice_sub_id(ad_caller2)
- return call_setup_teardown_for_call_waiting_for_subscription(
- log,
- ad_caller,
- ad_callee,
- ad_caller2,
- subid_caller,
- subid_callee,
- subid_caller2,
- ad_hangup, ad_hangup2,
- verify_callee_func,
- end_first_call_before_answering_second_call,
- wait_time_in_call,
- incall_ui_display,
- dialing_number_length,
- video_state,
- call_waiting)
-
-
-def call_setup_teardown_for_call_waiting_for_subscription(
- log,
- ad_caller,
- ad_callee,
- ad_caller2,
- subid_caller,
- subid_callee,
- subid_caller2,
- ad_hangup=None,
- ad_hangup2=None,
- verify_callee_func=None,
- end_first_call_before_answering_second_call=True,
- wait_time_in_call=WAIT_TIME_IN_CALL,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- dialing_number_length=None,
- video_state=None,
- call_waiting=True):
- """ Call process for call waiting, including make the 1st phone call from
- caller, answer the call by the callee, and receive the 2nd call from the
- caller2. The call is on specified subscription.
-
- In call process, 1st call from <ad_caller> to <ad_callee>, 2nd call from
- <ad_caller2> to <ad_callee>, hang up the existing call or reject the
- incoming call according to the test scenario.
-
- Args:
- ad_caller: Caller Android Device Object.
- ad_callee: Callee Android Device Object.
- ad_caller2: Caller2 Android Device Object.
- subid_caller: Caller subscription ID.
- subid_callee: Callee subscription ID.
- subid_caller2: Caller2 subscription ID.
- ad_hangup: Android Device Object end the 1st phone call.
- Optional. Default value is None, and phone call will continue.
- ad_hangup2: Android Device Object end the 2nd phone call.
- Optional. Default value is None, and phone call will continue.
- verify_callee_func: func_ptr to verify callee in correct mode
- Optional. Default is None
- end_first_call_before_answering_second_call: If True the 2nd call will
- be rejected on the ringing stage.
- wait_time_in_call: the call duration of a connected call
- incall_ui_display: after answer the call, bring in-call UI to foreground
- or background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
- if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
- if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
- else, do nothing.
- dialing_number_length: the number of digits used for dialing
- video_state: video call or voice call. Default is voice call.
- call_waiting: True to enable call waiting and False to disable.
-
- Returns:
- True if call process without any error.
- False if error happened.
-
- """
-
- CHECK_INTERVAL = 5
- begin_time = get_current_epoch_time()
- verify_caller_func = is_phone_in_call
- if not verify_callee_func:
- verify_callee_func = is_phone_in_call
- verify_caller2_func = is_phone_in_call
-
- caller_number = ad_caller.telephony['subscription'][subid_caller][
- 'phone_num']
- callee_number = ad_callee.telephony['subscription'][subid_callee][
- 'phone_num']
- caller2_number = ad_caller2.telephony['subscription'][subid_caller2][
- 'phone_num']
- if dialing_number_length:
- skip_test = False
- trunc_position = 0 - int(dialing_number_length)
- try:
- caller_area_code = caller_number[:trunc_position]
- callee_area_code = callee_number[:trunc_position]
- callee_dial_number = callee_number[trunc_position:]
- except:
- skip_test = True
- if caller_area_code != callee_area_code:
- skip_test = True
- if skip_test:
- msg = "Cannot make call from %s to %s by %s digits" % (
- caller_number, callee_number, dialing_number_length)
- ad_caller.log.info(msg)
- raise signals.TestSkip(msg)
- else:
- callee_number = callee_dial_number
-
- result = True
- msg = "Call from %s to %s" % (caller_number, callee_number)
- if video_state:
- msg = "Video %s" % msg
- video = True
- else:
- video = False
- if ad_hangup:
- msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
- ad_caller.log.info(msg)
-
- for ad in (ad_caller, ad_callee, ad_caller2):
- call_ids = ad.droid.telecomCallGetCallIds()
- setattr(ad, "call_ids", call_ids)
- if call_ids:
- ad.log.info("Pre-exist CallId %s before making call", call_ids)
-
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=0)
- else:
- set_call_waiting(log, ad_callee, enable=1)
-
- first_call_ids = []
- try:
- if not initiate_call(
- log,
- ad_caller,
- callee_number,
- incall_ui_display=incall_ui_display,
- video=video):
- ad_caller.log.error("Initiate call failed.")
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- result = False
- return False
- else:
- ad_caller.log.info("Caller initate call successfully")
- if not wait_and_answer_call_for_subscription(
- log,
- ad_callee,
- subid_callee,
- incoming_number=caller_number,
- caller=ad_caller,
- incall_ui_display=incall_ui_display,
- video_state=video_state):
- ad_callee.log.error("Answer call fail.")
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- result = False
- return False
- else:
- ad_callee.log.info("Callee answered the call successfully")
-
- for ad, subid, call_func in zip(
- [ad_caller, ad_callee],
- [subid_caller, subid_callee],
- [verify_caller_func, verify_callee_func]):
- call_ids = ad.droid.telecomCallGetCallIds()
- new_call_ids = set(call_ids) - set(ad.call_ids)
- if not new_call_ids:
- ad.log.error(
- "No new call ids are found after call establishment")
- ad.log.error("telecomCallGetCallIds returns %s",
- ad.droid.telecomCallGetCallIds())
- result = False
- for new_call_id in new_call_ids:
- first_call_ids.append(new_call_id)
- if not wait_for_in_call_active(ad, call_id=new_call_id):
- result = False
- else:
- ad.log.info("callProperties = %s",
- ad.droid.telecomCallGetProperties(new_call_id))
-
- if not ad.droid.telecomCallGetAudioState():
- ad.log.error("Audio is not in call state")
- result = False
-
- if call_func(log, ad):
- ad.log.info("Call is in %s state", call_func.__name__)
- else:
- ad.log.error("Call is not in %s state, voice in RAT %s",
- call_func.__name__,
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
- result = False
- if not result:
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- return False
-
- time.sleep(3)
- if not call_waiting:
- if not initiate_call(
- log,
- ad_caller2,
- callee_number,
- incall_ui_display=incall_ui_display,
- video=video):
- ad_caller2.log.info("Initiate call failed.")
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- result = False
- return False
- else:
- ad_caller2.log.info("Caller 2 initate 2nd call successfully")
-
- if not wait_and_answer_call_for_subscription(
- log,
- ad_callee,
- subid_callee,
- incoming_number=caller2_number,
- caller=ad_caller2,
- incall_ui_display=incall_ui_display,
- video_state=video_state):
- ad_callee.log.info(
- "Answering 2nd call fail due to call waiting deactivate.")
- else:
- ad_callee.log.error("Callee should not be able to answer the"
- " 2nd call due to call waiting deactivated.")
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- result = False
- return False
-
- time.sleep(3)
- if not hangup_call(log, ad_caller2):
- ad_caller2.log.info("Failed to hang up the 2nd call")
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- result = False
- return False
-
- else:
-
- for ad in (ad_callee, ad_caller2):
- call_ids = ad.droid.telecomCallGetCallIds()
- setattr(ad, "call_ids", call_ids)
- if call_ids:
- ad.log.info("Current existing CallId %s before making the"
- " second call.", call_ids)
-
- if not initiate_call(
- log,
- ad_caller2,
- callee_number,
- incall_ui_display=incall_ui_display,
- video=video):
- ad_caller2.log.info("Initiate 2nd call failed.")
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- result = False
- return False
- else:
- ad_caller2.log.info("Caller 2 initate 2nd call successfully")
-
- if end_first_call_before_answering_second_call:
- try:
- if not wait_for_ringing_call_for_subscription(
- log,
- ad_callee,
- subid_callee,
- incoming_number=caller2_number,
- caller=ad_caller2,
- event_tracking_started=True):
- ad_callee.log.info(
- "2nd incoming call ringing check failed.")
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- return False
-
- time.sleep(3)
-
- ad_hangup.log.info("Disconnecting first call...")
- for call_id in first_call_ids:
- disconnect_call_by_id(log, ad_hangup, call_id)
- time.sleep(3)
-
- ad_callee.log.info("Answering the 2nd ring call...")
- ad_callee.droid.telecomAcceptRingingCall(video_state)
-
- if wait_for_call_offhook_for_subscription(
- log,
- ad_callee,
- subid_callee,
- event_tracking_started=True):
- ad_callee.log.info(
- "Callee answered the 2nd call successfully.")
- else:
- ad_callee.log.error("Could not answer the 2nd call.")
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- return False
- except Exception as e:
- log.error(e)
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- return False
-
- else:
- if not wait_and_answer_call_for_subscription(
- log,
- ad_callee,
- subid_callee,
- incoming_number=caller2_number,
- caller=ad_caller2,
- incall_ui_display=incall_ui_display,
- video_state=video_state):
- ad_callee.log.error("Failed to answer 2nd call.")
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- result = False
- return False
- else:
- ad_callee.log.info(
- "Callee answered the 2nd call successfully.")
-
- for ad, subid, call_func in zip(
- [ad_callee, ad_caller2],
- [subid_callee, subid_caller2],
- [verify_callee_func, verify_caller2_func]):
- call_ids = ad.droid.telecomCallGetCallIds()
- new_call_ids = set(call_ids) - set(ad.call_ids)
- if not new_call_ids:
- ad.log.error(
- "No new call ids are found after 2nd call establishment")
- ad.log.error("telecomCallGetCallIds returns %s",
- ad.droid.telecomCallGetCallIds())
- result = False
- for new_call_id in new_call_ids:
- if not wait_for_in_call_active(ad, call_id=new_call_id):
- result = False
- else:
- ad.log.info("callProperties = %s",
- ad.droid.telecomCallGetProperties(new_call_id))
-
- if not ad.droid.telecomCallGetAudioState():
- ad.log.error("Audio is not in 2nd call state")
- result = False
-
- if call_func(log, ad):
- ad.log.info("2nd call is in %s state", call_func.__name__)
- else:
- ad.log.error("2nd call is not in %s state, voice in RAT %s",
- call_func.__name__,
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
- result = False
- if not result:
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- return False
-
- elapsed_time = 0
- while (elapsed_time < wait_time_in_call):
- CHECK_INTERVAL = min(CHECK_INTERVAL,
- wait_time_in_call - elapsed_time)
- time.sleep(CHECK_INTERVAL)
- elapsed_time += CHECK_INTERVAL
- time_message = "at <%s>/<%s> second." % (elapsed_time,
- wait_time_in_call)
-
- if not end_first_call_before_answering_second_call or \
- not call_waiting:
- for ad, subid, call_func in [
- (ad_caller, subid_caller, verify_caller_func),
- (ad_callee, subid_callee, verify_callee_func)]:
- if not call_func(log, ad):
- ad.log.error(
- "The first call NOT in correct %s state at %s,"
- " voice in RAT %s",
- call_func.__name__, time_message,
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
- result = False
- else:
- ad.log.info("The first call in correct %s state at %s",
- call_func.__name__, time_message)
- if not ad.droid.telecomCallGetAudioState():
- ad.log.error(
- "The first call audio is not in call state at %s",
- time_message)
- result = False
- if not result:
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- return False
-
- if call_waiting:
- for ad, call_func in [(ad_caller2, verify_caller2_func),
- (ad_callee, verify_callee_func)]:
- if not call_func(log, ad):
- ad.log.error(
- "The 2nd call NOT in correct %s state at %s,"
- " voice in RAT %s",
- call_func.__name__, time_message,
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
- result = False
- else:
- ad.log.info("The 2nd call in correct %s state at %s",
- call_func.__name__, time_message)
- if not ad.droid.telecomCallGetAudioState():
- ad.log.error(
- "The 2nd call audio is not in call state at %s",
- time_message)
- result = False
- if not result:
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- return False
-
- if not end_first_call_before_answering_second_call or not call_waiting:
- ad_hangup.log.info("Hanging up the first call...")
- for call_id in first_call_ids:
- disconnect_call_by_id(log, ad_hangup, call_id)
- time.sleep(5)
-
- if ad_hangup2 and call_waiting:
- if not hangup_call(log, ad_hangup2):
- ad_hangup2.log.info("Failed to hang up the 2nd call")
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- result = False
- return False
- finally:
- if not result:
- for ad in (ad_caller, ad_callee, ad_caller2):
- last_call_drop_reason(ad, begin_time)
- try:
- if ad.droid.telecomIsInCall():
- ad.log.info("In call. End now.")
- ad.droid.telecomEndCall()
- except Exception as e:
- log.error(str(e))
-
- if ad_hangup or not result:
- for ad in (ad_caller, ad_callee):
- if not wait_for_call_id_clearing(
- ad, getattr(ad, "caller_ids", [])):
- result = False
-
- if call_waiting:
- if ad_hangup2 or not result:
- for ad in (ad_caller2, ad_callee):
- if not wait_for_call_id_clearing(
- ad, getattr(ad, "caller_ids", [])):
- result = False
- if not call_waiting:
- set_call_waiting(log, ad_callee, enable=1)
- return result
-
-
-def wait_for_call_id_clearing(ad,
- previous_ids,
- timeout=MAX_WAIT_TIME_CALL_DROP):
- while timeout > 0:
- new_call_ids = ad.droid.telecomCallGetCallIds()
- if len(new_call_ids) <= len(previous_ids):
- return True
- time.sleep(5)
- timeout = timeout - 5
- ad.log.error("Call id clearing failed. Before: %s; After: %s",
- previous_ids, new_call_ids)
- return False
-
-
-def last_call_drop_reason(ad, begin_time=None):
- reasons = ad.search_logcat(
- "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause", begin_time)
- reason_string = ""
- if reasons:
- log_msg = "Logcat call drop reasons:"
- for reason in reasons:
- log_msg = "%s\n\t%s" % (log_msg, reason["log_message"])
- if "ril reason str" in reason["log_message"]:
- reason_string = reason["log_message"].split(":")[-1].strip()
- ad.log.info(log_msg)
- reasons = ad.search_logcat("ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION",
- begin_time)
- if reasons:
- ad.log.warning("ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION is seen")
- ad.log.info("last call dumpsys: %s",
- sorted(dumpsys_last_call_info(ad).items()))
- return reason_string
-
-
def phone_number_formatter(input_string, formatter=None):
"""Get expected format of input phone number string.
@@ -3623,13 +1225,20 @@
# make sure input_string is 10 digital
# Remove white spaces, dashes, dots
input_string = input_string.replace(" ", "").replace("-", "").replace(
- ".", "").lstrip("0")
- if not formatter:
- return input_string
- # Remove +81 and add 0 for Japan Carriers only.
- if (len(input_string) == 13 and input_string[0:3] == "+81"):
+ ".", "")
+
+ # Remove a country code with '+' sign and add 0 for Japan/Korea Carriers.
+ if (len(input_string) == 13
+ and (input_string[0:3] == "+81" or input_string[0:3] == "+82")):
input_string = "0" + input_string[3:]
return input_string
+
+ if not formatter:
+ return input_string
+
+ # Remove leading 0 for the phone with area code started with 0
+ input_string = input_string.lstrip("0")
+
# Remove "1" or "+1"from front
if (len(input_string) == PHONE_NUMBER_STRING_FORMAT_11_DIGIT
and input_string[0] == "1"):
@@ -3727,7 +1336,7 @@
return file_directory, file_name
-def _check_file_existance(ad, file_path, expected_file_size=None):
+def _check_file_existence(ad, file_path, expected_file_size=None):
"""Check file existance by file_path. If expected_file_size
is provided, then also check if the file meet the file size requirement.
"""
@@ -3755,132 +1364,6 @@
return False
-def check_curl_availability(ad):
- if not hasattr(ad, "curl_capable"):
- try:
- out = ad.adb.shell("/data/curl --version")
- if not out or "not found" in out:
- setattr(ad, "curl_capable", False)
- ad.log.info("curl is unavailable, use chrome to download file")
- else:
- setattr(ad, "curl_capable", True)
- except Exception:
- setattr(ad, "curl_capable", False)
- ad.log.info("curl is unavailable, use chrome to download file")
- return ad.curl_capable
-
-
-def start_youtube_video(ad, url="vnd.youtube:watch?v=pSJoP0LR8CQ"):
- ad.log.info("Open an youtube video")
- for _ in range(3):
- ad.ensure_screen_on()
- ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
- if wait_for_state(ad.droid.audioIsMusicActive, True, 15, 1):
- ad.log.info("Started a video in youtube, audio is in MUSIC state")
- return True
- ad.log.info("Audio is not in MUSIC state. Quit Youtube.")
- for _ in range(3):
- ad.send_keycode("BACK")
- time.sleep(1)
- time.sleep(3)
- return False
-
-
-def active_file_download_task(log, ad, file_name="5MB", method="curl"):
- # 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
- file_size_map = {
- '1MB': 1000000,
- '5MB': 5000000,
- '10MB': 10000000,
- '20MB': 20000000,
- '50MB': 50000000,
- '100MB': 100000000,
- '200MB': 200000000,
- '512MB': 512000000
- }
- url_map = {
- "1MB": [
- "http://146.148.91.8/download/1MB.zip",
- "http://ipv4.download.thinkbroadband.com/1MB.zip"
- ],
- "5MB": [
- "http://146.148.91.8/download/5MB.zip",
- "http://212.183.159.230/5MB.zip",
- "http://ipv4.download.thinkbroadband.com/5MB.zip"
- ],
- "10MB": [
- "http://146.148.91.8/download/10MB.zip",
- "http://212.183.159.230/10MB.zip",
- "http://ipv4.download.thinkbroadband.com/10MB.zip",
- "http://lax.futurehosting.com/test.zip",
- "http://ovh.net/files/10Mio.dat"
- ],
- "20MB": [
- "http://146.148.91.8/download/20MB.zip",
- "http://212.183.159.230/20MB.zip",
- "http://ipv4.download.thinkbroadband.com/20MB.zip"
- ],
- "50MB": [
- "http://146.148.91.8/download/50MB.zip",
- "http://212.183.159.230/50MB.zip",
- "http://ipv4.download.thinkbroadband.com/50MB.zip"
- ],
- "100MB": [
- "http://146.148.91.8/download/100MB.zip",
- "http://212.183.159.230/100MB.zip",
- "http://ipv4.download.thinkbroadband.com/100MB.zip",
- "http://speedtest-ca.turnkeyinternet.net/100mb.bin",
- "http://ovh.net/files/100Mio.dat",
- "http://lax.futurehosting.com/test100.zip"
- ],
- "200MB": [
- "http://146.148.91.8/download/200MB.zip",
- "http://212.183.159.230/200MB.zip",
- "http://ipv4.download.thinkbroadband.com/200MB.zip"
- ],
- "512MB": [
- "http://146.148.91.8/download/512MB.zip",
- "http://212.183.159.230/512MB.zip",
- "http://ipv4.download.thinkbroadband.com/512MB.zip"
- ]
- }
-
- file_size = file_size_map.get(file_name)
- file_urls = url_map.get(file_name)
- file_url = None
- for url in file_urls:
- url_splits = url.split("/")
- if verify_http_connection(log, ad, url=url, retry=1):
- output_path = "/sdcard/Download/%s" % url_splits[-1]
- file_url = url
- break
- if not file_url:
- ad.log.error("No url is available to download %s", file_name)
- return False
- timeout = min(max(file_size / 100000, 600), 3600)
- if method == "sl4a":
- return (http_file_download_by_sl4a, (ad, file_url, output_path,
- file_size, True, timeout))
- if method == "curl" and check_curl_availability(ad):
- return (http_file_download_by_curl, (ad, file_url, output_path,
- file_size, True, timeout))
- elif method == "sl4a" or method == "curl":
- return (http_file_download_by_sl4a, (ad, file_url, output_path,
- file_size, True, timeout))
- else:
- return (http_file_download_by_chrome, (ad, file_url, file_size, True,
- timeout))
-
-
-def active_file_download_test(log, ad, file_name="5MB", method="sl4a"):
- task = active_file_download_task(log, ad, file_name, method=method)
- if not task:
- return False
- return task[0](*task[1])
-
-
def verify_internet_connection_by_ping(log,
ad,
retries=1,
@@ -3983,7 +1466,7 @@
log_file_path=log_file_path)
return True
result, data = ad.run_iperf_client(
- iperf_server, iperf_option, timeout=timeout + 60)
+ iperf_server, iperf_option, timeout=timeout + 120)
ad.log.info("iperf test result with server %s is %s", iperf_server,
result)
if result:
@@ -4027,7 +1510,8 @@
ipv6=False,
rate_dict=None,
blocking=True,
- log_file_path=None):
+ log_file_path=None,
+ retry=5):
"""Iperf test by adb using UDP.
Args:
@@ -4043,29 +1527,36 @@
rate_dict: dictionary that can be passed in to save data
blocking: run iperf in blocking mode if True
log_file_path: location to save logs
+ retry: times of retry when the server is unavailable
"""
iperf_option = "-u -i 1 -t %s -O %s -J" % (timeout, omit)
if limit_rate:
iperf_option += " -b %s" % limit_rate
if pacing_timer:
iperf_option += " --pacing-timer %s" % pacing_timer
- if port_num:
- iperf_option += " -p %s" % port_num
if ipv6:
iperf_option += " -6"
if reverse:
iperf_option += " -R"
- try:
- return iperf_test_with_options(log,
- ad,
- iperf_server,
- iperf_option,
- timeout,
- rate_dict,
- blocking,
- log_file_path)
- except AdbError:
- return False
+ for _ in range(retry):
+ if port_num:
+ iperf_option_final = iperf_option + " -p %s" % port_num
+ port_num += 1
+ else:
+ iperf_option_final = iperf_option
+ try:
+ return iperf_test_with_options(log,
+ ad,
+ iperf_server,
+ iperf_option_final,
+ timeout,
+ rate_dict,
+ blocking,
+ log_file_path)
+ except (AdbCommandError, TimeoutError) as error:
+ continue
+ except AdbError:
+ return False
def iperf_test_by_adb(log,
@@ -4079,7 +1570,8 @@
ipv6=False,
rate_dict=None,
blocking=True,
- log_file_path=None):
+ log_file_path=None,
+ retry=5):
"""Iperf test by adb using TCP.
Args:
@@ -4095,368 +1587,34 @@
rate_dict: dictionary that can be passed in to save data
blocking: run iperf in blocking mode if True
log_file_path: location to save logs
+ retry: times of retry when the server is unavailable
"""
iperf_option = "-t %s -O %s -J" % (timeout, omit)
if limit_rate:
iperf_option += " -b %s" % limit_rate
- if port_num:
- iperf_option += " -p %s" % port_num
if ipv6:
iperf_option += " -6"
if reverse:
iperf_option += " -R"
- try:
- return iperf_test_with_options(log,
- ad,
- iperf_server,
- iperf_option,
- timeout,
- rate_dict,
- blocking,
- log_file_path)
- except AdbError:
- return False
-
-
-def http_file_download_by_curl(ad,
- url,
- out_path=None,
- expected_file_size=None,
- remove_file_after_check=True,
- timeout=3600,
- limit_rate=None,
- retry=3):
- """Download http file by adb curl.
-
- Args:
- ad: Android Device Object.
- url: The url that file to be downloaded from".
- out_path: Optional. Where to download file to.
- out_path is /sdcard/Download/ by default.
- expected_file_size: Optional. Provided if checking the download file meet
- expected file size in unit of byte.
- remove_file_after_check: Whether to remove the downloaded file after
- check.
- timeout: timeout for file download to complete.
- limit_rate: download rate in bps. None, if do not apply rate limit.
- retry: the retry request times provided in curl command.
- """
- file_directory, file_name = _generate_file_directory_and_file_name(
- url, out_path)
- file_path = os.path.join(file_directory, file_name)
- curl_cmd = "/data/curl"
- if limit_rate:
- curl_cmd += " --limit-rate %s" % limit_rate
- if retry:
- curl_cmd += " --retry %s" % retry
- curl_cmd += " --url %s > %s" % (url, file_path)
- try:
- 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
+ for _ in range(retry):
+ if port_num:
+ iperf_option_final = iperf_option + " -p %s" % port_num
+ port_num += 1
else:
- ad.log.warning("Fail to download %s", url)
+ iperf_option_final = iperf_option
+ try:
+ return iperf_test_with_options(log,
+ ad,
+ iperf_server,
+ iperf_option_final,
+ timeout,
+ rate_dict=rate_dict,
+ blocking=blocking,
+ log_file_path=log_file_path)
+ except (AdbCommandError, TimeoutError) as error:
+ continue
+ except AdbError:
return False
- except Exception as e:
- ad.log.warning("Download %s failed with exception %s", url, e)
- return False
- finally:
- 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)
-
-
-def open_url_by_adb(ad, url):
- ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
-
-
-def http_file_download_by_chrome(ad,
- url,
- expected_file_size=None,
- remove_file_after_check=True,
- timeout=3600):
- """Download http file by chrome.
-
- Args:
- ad: Android Device Object.
- url: The url that file to be downloaded from".
- expected_file_size: Optional. Provided if checking the download file meet
- expected file size in unit of byte.
- remove_file_after_check: Whether to remove the downloaded file after
- 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(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/.*")
- 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),
- "chrome_mobile_data_usage": get_mobile_data_usage(
- ad, None, chrome_apk)
- }
- ad.log.debug("Before downloading: %s", data_accounting)
- ad.log.info("Download %s with timeout %s", url, timeout)
- ad.ensure_screen_on()
- 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 -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),
- "chrome_mobile_data_usage":
- get_mobile_data_usage(ad, None, chrome_apk)
- }
- 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.debug("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:
- # download not started, retry download wit chrome again
- open_url_by_adb(ad, url)
- else:
- ad.log.error("Unable to download file from %s", url)
- break
- elapse_time += 30
- ad.log.warning("Fail to download file from %s", url)
- ad.force_stop_apk("com.android.chrome")
- 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(ad,
- url,
- out_path=None,
- expected_file_size=None,
- remove_file_after_check=True,
- timeout=300):
- """Download http file by sl4a RPC call.
-
- Args:
- ad: Android Device Object.
- url: The url that file to be downloaded from".
- out_path: Optional. Where to download file to.
- out_path is /sdcard/Download/ by default.
- expected_file_size: Optional. Provided if checking the download file meet
- expected file size in unit of byte.
- remove_file_after_check: Whether to remove the downloaded file after
- check.
- timeout: timeout for file download to complete.
- """
- 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
- try:
- if not getattr(ad, "data_droid", None):
- ad.data_droid, ad.data_ed = ad.get_droid()
- ad.data_ed.start()
- else:
- try:
- if not ad.data_droid.is_live:
- ad.data_droid, ad.data_ed = ad.get_droid()
- ad.data_ed.start()
- except Exception:
- ad.log.info("Start new sl4a session for file download")
- ad.data_droid, ad.data_ed = ad.get_droid()
- ad.data_ed.start()
- data_accounting = {
- "mobile_rx_bytes":
- ad.droid.getMobileRxBytes(),
- "subscriber_mobile_data_usage":
- get_mobile_data_usage(ad, None, None),
- "sl4a_mobile_data_usage":
- get_mobile_data_usage(ad, None, accounting_apk)
- }
- ad.log.debug("Before downloading: %s", data_accounting)
- ad.log.info("Download file from %s to %s by sl4a RPC call", url,
- file_path)
- try:
- ad.data_droid.httpDownloadFile(url, file_path, timeout=timeout)
- except Exception as e:
- ad.log.warning("SL4A file download error: %s", e)
- ad.data_droid.terminate()
- return False
- if _check_file_existance(ad, file_path, expected_file_size):
- ad.log.info("%s is downloaded successfully", url)
- new_data_accounting = {
- "mobile_rx_bytes":
- ad.droid.getMobileRxBytes(),
- "subscriber_mobile_data_usage":
- get_mobile_data_usage(ad, None, None),
- "sl4a_mobile_data_usage":
- get_mobile_data_usage(ad, None, accounting_apk)
- }
- ad.log.debug("After downloading: %s", new_data_accounting)
- accounting_diff = {
- key: value - data_accounting[key]
- for key, value in new_data_accounting.items()
- }
- ad.log.debug("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.debug("%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
- except Exception as e:
- ad.log.error("Download %s failed with exception %s", url, e)
- raise
- finally:
- 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)
-
-
-def get_wifi_usage(ad, sid=None, apk=None):
- if not sid:
- sid = ad.droid.subscriptionGetDefaultDataSubId()
- current_time = int(time.time() * 1000)
- begin_time = current_time - 10 * 24 * 60 * 60 * 1000
- end_time = current_time + 10 * 24 * 60 * 60 * 1000
-
- if apk:
- uid = ad.get_apk_uid(apk)
- ad.log.debug("apk %s uid = %s", apk, uid)
- try:
- return ad.droid.connectivityQueryDetailsForUid(
- TYPE_WIFI,
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time, uid)
- except:
- return ad.droid.connectivityQueryDetailsForUid(
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time, uid)
- else:
- try:
- return ad.droid.connectivityQuerySummaryForDevice(
- TYPE_WIFI,
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time)
- except:
- return ad.droid.connectivityQuerySummaryForDevice(
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time)
-
-
-def get_mobile_data_usage(ad, sid=None, apk=None):
- if not sid:
- sid = ad.droid.subscriptionGetDefaultDataSubId()
- current_time = int(time.time() * 1000)
- begin_time = current_time - 10 * 24 * 60 * 60 * 1000
- end_time = current_time + 10 * 24 * 60 * 60 * 1000
-
- if apk:
- uid = ad.get_apk_uid(apk)
- ad.log.debug("apk %s uid = %s", apk, uid)
- try:
- usage_info = ad.droid.getMobileDataUsageInfoForUid(uid, sid)
- ad.log.debug("Mobile data usage info for uid %s = %s", uid,
- usage_info)
- return usage_info["UsageLevel"]
- except:
- try:
- return ad.droid.connectivityQueryDetailsForUid(
- TYPE_MOBILE,
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time, uid)
- except:
- return ad.droid.connectivityQueryDetailsForUid(
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time, uid)
- else:
- try:
- usage_info = ad.droid.getMobileDataUsageInfo(sid)
- ad.log.debug("Mobile data usage info = %s", usage_info)
- return usage_info["UsageLevel"]
- except:
- try:
- return ad.droid.connectivityQuerySummaryForDevice(
- TYPE_MOBILE,
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time)
- except:
- return ad.droid.connectivityQuerySummaryForDevice(
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time)
-
-
-def set_mobile_data_usage_limit(ad, limit, subscriber_id=None):
- if not subscriber_id:
- subscriber_id = ad.droid.telephonyGetSubscriberId()
- ad.log.debug("Set subscriber mobile data usage limit to %s", limit)
- ad.droid.logV("Setting subscriber mobile data usage limit to %s" % limit)
- try:
- ad.droid.connectivitySetDataUsageLimit(subscriber_id, str(limit))
- except:
- ad.droid.connectivitySetDataUsageLimit(subscriber_id, limit)
-
-
-def remove_mobile_data_usage_limit(ad, subscriber_id=None):
- if not subscriber_id:
- subscriber_id = ad.droid.telephonyGetSubscriberId()
- ad.log.debug("Remove subscriber mobile data usage limit")
- ad.droid.logV(
- "Setting subscriber mobile data usage limit to -1, unlimited")
- try:
- ad.droid.connectivitySetDataUsageLimit(subscriber_id, "-1")
- except:
- ad.droid.connectivitySetDataUsageLimit(subscriber_id, -1)
def trigger_modem_crash(ad, timeout=120):
@@ -4612,276 +1770,6 @@
reboot_device(ad)
-def _connection_state_change(_event, target_state, connection_type):
- if connection_type:
- if 'TypeName' not in _event['data']:
- return False
- connection_type_string_in_event = _event['data']['TypeName']
- cur_type = connection_type_from_type_string(
- connection_type_string_in_event)
- if cur_type != connection_type:
- log.info(
- "_connection_state_change expect: %s, received: %s <type %s>",
- connection_type, connection_type_string_in_event, cur_type)
- return False
-
- if 'isConnected' in _event['data'] and _event['data']['isConnected'] == target_state:
- return True
- return False
-
-
-def wait_for_cell_data_connection(
- log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
- """Wait for data connection status to be expected value for default
- data subscription.
-
- Wait for the data connection status to be DATA_STATE_CONNECTED
- or DATA_STATE_DISCONNECTED.
-
- Args:
- log: Log object.
- ad: Android Device Object.
- state: Expected status: True or False.
- 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 MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
-
- Returns:
- True if success.
- False if failed.
- """
- sub_id = get_default_data_sub_id(ad)
- return wait_for_cell_data_connection_for_subscription(
- log, ad, sub_id, state, timeout_value)
-
-
-def _is_data_connection_state_match(log, ad, expected_data_connection_state):
- return (expected_data_connection_state ==
- ad.droid.telephonyGetDataConnectionState())
-
-
-def _is_network_connected_state_match(log, ad,
- expected_network_connected_state):
- return (expected_network_connected_state ==
- ad.droid.connectivityNetworkIsConnected())
-
-
-def wait_for_cell_data_connection_for_subscription(
- 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.
-
- Wait for the data connection status to be DATA_STATE_CONNECTED
- or DATA_STATE_DISCONNECTED.
-
- Args:
- log: Log object.
- ad: Android Device Object.
- sub_id: subscription Id
- state: Expected status: True or False.
- 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 MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
-
- Returns:
- True if success.
- False if failed.
- """
- state_str = {
- True: DATA_STATE_CONNECTED,
- False: DATA_STATE_DISCONNECTED
- }[state]
-
- data_state = ad.droid.telephonyGetDataConnectionState()
- if not state and ad.droid.telephonyGetDataConnectionState() == state_str:
- return True
-
- ad.ed.clear_events(EventDataConnectionStateChanged)
- ad.droid.telephonyStartTrackingDataConnectionStateChangeForSubscription(
- sub_id)
- ad.droid.connectivityStartTrackingConnectivityStateChange()
- try:
- ad.log.info("User data enabled for sub_id %s: %s", sub_id,
- ad.droid.telephonyIsDataEnabledForSubscription(sub_id))
- data_state = ad.droid.telephonyGetDataConnectionState()
- ad.log.info("Data connection state is %s", data_state)
- ad.log.info("Network is connected: %s",
- ad.droid.connectivityNetworkIsConnected())
- if data_state == state_str:
- return _wait_for_nw_data_connection(
- log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
-
- try:
- ad.ed.wait_for_event(
- EventDataConnectionStateChanged,
- is_event_match,
- timeout=timeout_value,
- field=DataConnectionStateContainer.DATA_CONNECTION_STATE,
- value=state_str)
- except Empty:
- ad.log.info("No expected event EventDataConnectionStateChanged %s",
- state_str)
-
- # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
- # data connection state.
- # Otherwise, the network state will not be correct.
- # The bug is tracked here: b/20921915
-
- # Previously we use _is_data_connection_state_match,
- # but telephonyGetDataConnectionState sometimes return wrong value.
- # The bug is tracked here: b/22612607
- # So we use _is_network_connected_state_match.
-
- 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)
- else:
- return False
-
- finally:
- ad.droid.telephonyStopTrackingDataConnectionStateChangeForSubscription(
- sub_id)
-
-
-def wait_for_wifi_data_connection(
- 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:
- log: Log object.
- ad: Android Device Object.
- state: Expected status: True or False.
- 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 MAX_WAIT_TIME_NW_SELECTION
-
- Returns:
- True if success.
- False if failed.
- """
- ad.log.info("wait_for_wifi_data_connection")
- return _wait_for_nw_data_connection(
- log, ad, state, NETWORK_CONNECTION_TYPE_WIFI, timeout_value)
-
-
-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
- or DATA_STATE_DISCONNECTED.
-
- Args:
- log: Log object.
- ad: Android Device Object.
- state: Expected status: True or False.
- 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 MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
-
- Returns:
- True if success.
- False if failed.
- """
- return _wait_for_nw_data_connection(log, ad, state, None, timeout_value)
-
-
-def _wait_for_nw_data_connection(
- log,
- ad,
- is_connected,
- connection_type=None,
- 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
- or DATA_STATE_DISCONNECTED.
-
- Args:
- log: Log object.
- ad: Android Device Object.
- is_connected: Expected connection status: True or False.
- If True, it will wait for status to be DATA_STATE_CONNECTED.
- If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
- 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 MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
-
- Returns:
- True if success.
- False if failed.
- """
- ad.ed.clear_events(EventConnectivityChanged)
- ad.droid.connectivityStartTrackingConnectivityStateChange()
- try:
- cur_data_connection_state = ad.droid.connectivityNetworkIsConnected()
- if is_connected == cur_data_connection_state:
- current_type = get_internet_connection_type(log, ad)
- ad.log.info("current data connection type: %s", current_type)
- if not connection_type:
- return True
- else:
- if not is_connected and current_type != connection_type:
- ad.log.info("data connection not on %s!", connection_type)
- return True
- elif is_connected and current_type == connection_type:
- ad.log.info("data connection on %s as expected",
- connection_type)
- return True
- else:
- ad.log.info("current data connection state: %s target: %s",
- cur_data_connection_state, is_connected)
-
- try:
- event = ad.ed.wait_for_event(
- EventConnectivityChanged, _connection_state_change,
- timeout_value, is_connected, connection_type)
- ad.log.info("Got event: %s", event)
- except Empty:
- pass
-
- log.info(
- "_wait_for_nw_data_connection: check connection after wait event.")
- # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
- # 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, 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:
- return True
- else:
- if not is_connected and current_type != connection_type:
- ad.log.info("data connection not on %s", connection_type)
- return True
- elif is_connected and current_type == connection_type:
- ad.log.info("after event wait, data connection on %s",
- connection_type)
- return True
- else:
- return False
- else:
- return False
- except Exception as e:
- ad.log.error("Exception error %s", str(e))
- return False
- finally:
- ad.droid.connectivityStopTrackingConnectivityStateChange()
-
-
def get_cell_data_roaming_state_by_adb(ad):
"""Get Cell Data Roaming state. True for enabled, False for disabled"""
state_mapping = {"1": True, "0": False}
@@ -4983,461 +1871,6 @@
return len(calls) if calls else 0
-def show_enhanced_4g_lte(ad, sub_id):
- result = True
- capabilities = ad.telephony["subscription"][sub_id].get("capabilities", [])
- if capabilities:
- if "hide_enhanced_4g_lte" in capabilities:
- result = False
- ad.log.info(
- '"Enhanced 4G LTE MODE" is hidden for sub ID %s.', sub_id)
- show_enhanced_4g_lte_mode = getattr(
- ad, "show_enhanced_4g_lte_mode", False)
- if show_enhanced_4g_lte_mode in ["true", "True"]:
- current_voice_sub_id = get_outgoing_voice_sub_id(ad)
- if sub_id != current_voice_sub_id:
- set_incoming_voice_sub_id(ad, sub_id)
-
- ad.log.info(
- 'Show "Enhanced 4G LTE MODE" forcibly for sub ID %s.',
- sub_id)
- ad.adb.shell(
- "am broadcast \
- -a com.google.android.carrier.action.LOCAL_OVERRIDE \
- -n com.google.android.carrier/.ConfigOverridingReceiver \
- --ez hide_enhanced_4g_lte_bool false")
- ad.telephony["subscription"][sub_id]["capabilities"].remove(
- "hide_enhanced_4g_lte")
-
- if sub_id != current_voice_sub_id:
- set_incoming_voice_sub_id(ad, current_voice_sub_id)
-
- result = True
- return result
-
-
-def toggle_volte(log, ad, new_state=None):
- """Toggle enable/disable VoLTE for default voice subscription.
-
- Args:
- ad: Android device object.
- new_state: VoLTE mode state to set to.
- True for enable, False for disable.
- If None, opposite of the current state.
-
- Raises:
- TelTestUtilsError if platform does not support VoLTE.
- """
- 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):
- """Toggle enable/disable VoLTE for specified voice subscription.
-
- Args:
- ad: Android device object.
- sub_id: Optional. If not assigned the default sub ID for voice call will
- be used.
- new_state: VoLTE mode state to set to.
- True for enable, False for disable.
- If None, opposite of the current state.
-
- """
- if not show_enhanced_4g_lte(ad, sub_id):
- return False
-
- current_state = None
- result = True
-
- if sub_id is None:
- sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
-
- try:
- current_state = ad.droid.imsMmTelIsAdvancedCallingEnabled(sub_id)
- except Exception as e:
- ad.log.warning(e)
-
- if current_state is not None:
- if new_state is None:
- new_state = not current_state
- if new_state != current_state:
- ad.log.info(
- "Toggle Enhanced 4G LTE Mode from %s to %s on sub_id %s",
- current_state, new_state, sub_id)
- ad.droid.imsMmTelSetAdvancedCallingEnabled(sub_id, new_state)
- check_state = ad.droid.imsMmTelIsAdvancedCallingEnabled(sub_id)
- if check_state != new_state:
- ad.log.error("Failed to toggle Enhanced 4G LTE Mode to %s, still \
- set to %s on sub_id %s", new_state, check_state, sub_id)
- result = False
- return result
- else:
- # TODO: b/26293960 No framework API available to set IMS by SubId.
- voice_sub_id_changed = False
- current_sub_id = get_incoming_voice_sub_id(ad)
- if current_sub_id != sub_id:
- set_incoming_voice_sub_id(ad, sub_id)
- voice_sub_id_changed = True
-
- # b/139641554
- ad.terminate_all_sessions()
- bring_up_sl4a(ad)
-
- if not ad.droid.imsIsEnhanced4gLteModeSettingEnabledByPlatform():
- ad.log.info(
- "Enhanced 4G Lte Mode Setting is not enabled by platform for \
- sub ID %s.", sub_id)
- return False
-
- current_state = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
- ad.log.info("Current state of Enhanced 4G Lte Mode Setting for sub \
- ID %s: %s", sub_id, current_state)
- ad.log.info("New desired state of Enhanced 4G Lte Mode Setting for sub \
- ID %s: %s", sub_id, new_state)
-
- if new_state is None:
- new_state = not current_state
- if new_state != current_state:
- ad.log.info(
- "Toggle Enhanced 4G LTE Mode from %s to %s for sub ID %s.",
- current_state, new_state, sub_id)
- ad.droid.imsSetEnhanced4gMode(new_state)
- time.sleep(5)
-
- check_state = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
- if check_state != new_state:
- ad.log.error("Failed to toggle Enhanced 4G LTE Mode to %s, \
- still set to %s on sub_id %s", new_state, check_state, sub_id)
- result = False
-
- if voice_sub_id_changed:
- set_incoming_voice_sub_id(ad, current_sub_id)
-
- return result
-
-
-def toggle_wfc(log, ad, new_state=None):
- """ Toggle WFC enable/disable
-
- Args:
- log: Log object
- ad: Android device object.
- new_state: WFC state to set to.
- True for enable, False for disable.
- If None, opposite of the current state.
- """
- return toggle_wfc_for_subscription(
- log, ad, new_state, get_outgoing_voice_sub_id(ad))
-
-
-def toggle_wfc_for_subscription(log, ad, new_state=None, sub_id=None):
- """ Toggle WFC enable/disable for specified voice subscription.
-
- Args:
- ad: Android device object.
- sub_id: Optional. If not assigned the default sub ID for voice call will
- be used.
- new_state: WFC state to set to.
- True for enable, False for disable.
- If None, opposite of the current state.
- """
- current_state = None
- result = True
-
- if sub_id is None:
- sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
-
- try:
- current_state = ad.droid.imsMmTelIsVoWiFiSettingEnabled(sub_id)
- except Exception as e:
- ad.log.warning(e)
-
- if current_state is not None:
- if new_state is None:
- new_state = not current_state
- if new_state != current_state:
- ad.log.info(
- "Toggle Wi-Fi calling from %s to %s on sub_id %s",
- current_state, new_state, sub_id)
- ad.droid.imsMmTelSetVoWiFiSettingEnabled(sub_id, new_state)
- check_state = ad.droid.imsMmTelIsVoWiFiSettingEnabled(sub_id)
- if check_state != new_state:
- ad.log.error("Failed to toggle Wi-Fi calling to %s, \
- still set to %s on sub_id %s", new_state, check_state, sub_id)
- result = False
- return result
- else:
- voice_sub_id_changed = False
- if not sub_id:
- sub_id = get_outgoing_voice_sub_id(ad)
- else:
- current_sub_id = get_incoming_voice_sub_id(ad)
- if current_sub_id != sub_id:
- set_incoming_voice_sub_id(ad, sub_id)
- voice_sub_id_changed = True
-
- # b/139641554
- ad.terminate_all_sessions()
- bring_up_sl4a(ad)
-
- if not ad.droid.imsIsWfcEnabledByPlatform():
- ad.log.info("WFC is not enabled by platform for sub ID %s.", sub_id)
- return False
-
- current_state = ad.droid.imsIsWfcEnabledByUser()
- ad.log.info("Current state of WFC Setting for sub ID %s: %s",
- sub_id, current_state)
- ad.log.info("New desired state of WFC Setting for sub ID %s: %s",
- sub_id, new_state)
-
- if new_state is None:
- new_state = not current_state
- if new_state != current_state:
- ad.log.info("Toggle WFC user enabled from %s to %s for sub ID %s",
- current_state, new_state, sub_id)
- ad.droid.imsSetWfcSetting(new_state)
-
- if voice_sub_id_changed:
- set_incoming_voice_sub_id(ad, current_sub_id)
-
- return True
-
-
-def is_enhanced_4g_lte_mode_setting_enabled(ad, sub_id, enabled_by="platform"):
- voice_sub_id_changed = False
- current_sub_id = get_incoming_voice_sub_id(ad)
- if current_sub_id != sub_id:
- set_incoming_voice_sub_id(ad, sub_id)
- voice_sub_id_changed = True
- if enabled_by == "platform":
- res = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByPlatform()
- else:
- res = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
- if not res:
- ad.log.info("Enhanced 4G Lte Mode Setting is NOT enabled by %s for sub \
- ID %s.", enabled_by, sub_id)
- if voice_sub_id_changed:
- set_incoming_voice_sub_id(ad, current_sub_id)
- return False
- if voice_sub_id_changed:
- set_incoming_voice_sub_id(ad, current_sub_id)
- ad.log.info("Enhanced 4G Lte Mode Setting is enabled by %s for sub ID %s.",
- enabled_by, sub_id)
- return True
-
-def set_enhanced_4g_mode(ad, sub_id, state):
- voice_sub_id_changed = False
- current_sub_id = get_incoming_voice_sub_id(ad)
- if current_sub_id != sub_id:
- set_incoming_voice_sub_id(ad, sub_id)
- voice_sub_id_changed = True
-
- ad.droid.imsSetEnhanced4gMode(state)
- time.sleep(5)
-
- if voice_sub_id_changed:
- set_incoming_voice_sub_id(ad, current_sub_id)
-
-
-def wait_for_enhanced_4g_lte_setting(log,
- ad,
- sub_id,
- max_time=MAX_WAIT_TIME_FOR_STATE_CHANGE):
- """Wait for android device to enable enhance 4G LTE setting.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time.
-
- Returns:
- Return True if device report VoLTE enabled bit true within max_time.
- Return False if timeout.
- """
- return wait_for_state(
- is_enhanced_4g_lte_mode_setting_enabled,
- True,
- max_time,
- WAIT_TIME_BETWEEN_STATE_CHECK,
- ad,
- sub_id,
- enabled_by="platform")
-
-
-def set_wfc_mode(log, ad, wfc_mode):
- """Set WFC enable/disable and mode.
-
- Args:
- log: Log object
- ad: Android device object.
- wfc_mode: WFC mode to set to.
- Valid mode includes: WFC_MODE_WIFI_ONLY, WFC_MODE_CELLULAR_PREFERRED,
- WFC_MODE_WIFI_PREFERRED, WFC_MODE_DISABLED.
-
- Returns:
- True if success. False if ad does not support WFC or error happened.
- """
- return set_wfc_mode_for_subscription(
- ad, wfc_mode, get_outgoing_voice_sub_id(ad))
-
-
-def set_wfc_mode_for_subscription(ad, wfc_mode, sub_id=None):
- """Set WFC enable/disable and mode subscription based
-
- Args:
- ad: Android device object.
- wfc_mode: WFC mode to set to.
- Valid mode includes: WFC_MODE_WIFI_ONLY, WFC_MODE_CELLULAR_PREFERRED,
- WFC_MODE_WIFI_PREFERRED.
- sub_id: subscription Id
-
- Returns:
- True if success. False if ad does not support WFC or error happened.
- """
- if wfc_mode not in [
- WFC_MODE_WIFI_ONLY,
- WFC_MODE_CELLULAR_PREFERRED,
- WFC_MODE_WIFI_PREFERRED,
- WFC_MODE_DISABLED]:
-
- ad.log.error("Given WFC mode (%s) is not correct.", wfc_mode)
- return False
-
- current_mode = None
- result = True
-
- if sub_id is None:
- sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
-
- try:
- current_mode = ad.droid.imsMmTelGetVoWiFiModeSetting(sub_id)
- ad.log.info("Current WFC mode of sub ID %s: %s", sub_id, current_mode)
- except Exception as e:
- ad.log.warning(e)
-
- if current_mode is not None:
- try:
- if not ad.droid.imsMmTelIsVoWiFiSettingEnabled(sub_id):
- if wfc_mode is WFC_MODE_DISABLED:
- ad.log.info("WFC is already disabled.")
- return True
- ad.log.info(
- "WFC is disabled for sub ID %s. Enabling WFC...", sub_id)
- ad.droid.imsMmTelSetVoWiFiSettingEnabled(sub_id, True)
-
- if wfc_mode is WFC_MODE_DISABLED:
- ad.log.info(
- "WFC is enabled for sub ID %s. Disabling WFC...", sub_id)
- ad.droid.imsMmTelSetVoWiFiSettingEnabled(sub_id, False)
- return True
-
- ad.log.info("Set wfc mode to %s for sub ID %s.", wfc_mode, sub_id)
- ad.droid.imsMmTelSetVoWiFiModeSetting(sub_id, wfc_mode)
- mode = ad.droid.imsMmTelGetVoWiFiModeSetting(sub_id)
- if mode != wfc_mode:
- ad.log.error("WFC mode for sub ID %s is %s, not in %s",
- sub_id, mode, wfc_mode)
- return False
- except Exception as e:
- ad.log.error(e)
- return False
- return True
- else:
- voice_sub_id_changed = False
- if not sub_id:
- sub_id = get_outgoing_voice_sub_id(ad)
- else:
- current_sub_id = get_incoming_voice_sub_id(ad)
- if current_sub_id != sub_id:
- set_incoming_voice_sub_id(ad, sub_id)
- voice_sub_id_changed = True
-
- # b/139641554
- ad.terminate_all_sessions()
- bring_up_sl4a(ad)
-
- if wfc_mode != WFC_MODE_DISABLED and wfc_mode not in ad.telephony[
- "subscription"][get_outgoing_voice_sub_id(ad)].get("wfc_modes", []):
- ad.log.error("WFC mode %s is not supported", wfc_mode)
- raise signals.TestSkip("WFC mode %s is not supported" % wfc_mode)
- try:
- ad.log.info("Set wfc mode to %s", wfc_mode)
- if wfc_mode != WFC_MODE_DISABLED:
- start_adb_tcpdump(ad, interface="wlan0", mask="all")
- if not ad.droid.imsIsWfcEnabledByPlatform():
- if wfc_mode == WFC_MODE_DISABLED:
- if voice_sub_id_changed:
- set_incoming_voice_sub_id(ad, current_sub_id)
- return True
- else:
- ad.log.error("WFC not supported by platform.")
- if voice_sub_id_changed:
- set_incoming_voice_sub_id(ad, current_sub_id)
- return False
- ad.droid.imsSetWfcMode(wfc_mode)
- mode = ad.droid.imsGetWfcMode()
- if voice_sub_id_changed:
- set_incoming_voice_sub_id(ad, current_sub_id)
- if mode != wfc_mode:
- ad.log.error("WFC mode is %s, not in %s", mode, wfc_mode)
- return False
- except Exception as e:
- log.error(e)
- if voice_sub_id_changed:
- set_incoming_voice_sub_id(ad, current_sub_id)
- return False
- return True
-
-
-def set_ims_provisioning_for_subscription(ad, feature_flag, value, sub_id=None):
- """ Sets Provisioning Values for Subscription Id
-
- Args:
- ad: Android device object.
- sub_id: Subscription Id
- feature_flag: voice or video
- value: enable or disable
-
- """
- try:
- if sub_id is None:
- sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
- ad.log.info("SubId %s - setprovisioning for %s to %s",
- sub_id, feature_flag, value)
- result = ad.droid.provisioningSetProvisioningIntValue(sub_id,
- feature_flag, value)
- if result == 0:
- return True
- return False
- except Exception as e:
- ad.log.error(e)
- return False
-
-
-def get_ims_provisioning_for_subscription(ad, feature_flag, tech, sub_id=None):
- """ Gets Provisioning Values for Subscription Id
-
- Args:
- ad: Android device object.
- sub_id: Subscription Id
- feature_flag: voice, video, ut, sms
- tech: lte, iwlan
-
- """
- try:
- if sub_id is None:
- sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
- result = ad.droid.provisioningGetProvisioningStatusForCapability(
- sub_id, feature_flag, tech)
- ad.log.info("SubId %s - getprovisioning for %s on %s - %s",
- sub_id, feature_flag, tech, result)
- return result
- except Exception as e:
- ad.log.error(e)
- return False
-
-
def get_carrier_provisioning_for_subscription(ad, feature_flag,
tech, sub_id=None):
""" Gets Provisioning Values for Subscription Id
@@ -5461,111 +1894,6 @@
return False
-def activate_wfc_on_device(log, ad):
- """ Activates WiFi calling on device.
-
- Required for certain network operators.
-
- Args:
- log: Log object
- ad: Android device object
-
- """
- activate_wfc_on_device_for_subscription(log, ad,
- ad.droid.subscriptionGetDefaultSubId())
-
-
-def activate_wfc_on_device_for_subscription(log, ad, sub_id):
- """ Activates WiFi calling on device for a subscription.
-
- Args:
- log: Log object
- ad: Android device object
- sub_id: Subscription id (integer)
-
- """
- if not sub_id or INVALID_SUB_ID == sub_id:
- ad.log.error("Subscription id invalid")
- return
- operator_name = get_operator_name(log, ad, sub_id)
- if operator_name in (CARRIER_VZW, CARRIER_ATT, CARRIER_BELL, CARRIER_ROGERS,
- CARRIER_TELUS, CARRIER_KOODO, CARRIER_VIDEOTRON, CARRIER_FRE):
- ad.log.info("Activating WFC on operator : %s", operator_name)
- if not ad.is_apk_installed("com.google.android.wfcactivation"):
- ad.log.error("WFC Activation Failed, wfc activation apk not installed")
- return
- wfc_activate_cmd ="am start --ei EXTRA_LAUNCH_CARRIER_APP 0 --ei " \
- "android.telephony.extra.SUBSCRIPTION_INDEX {} -n ".format(sub_id)
- if CARRIER_ATT == operator_name:
- ad.adb.shell("setprop dbg.att.force_wfc_nv_enabled true")
- wfc_activate_cmd = wfc_activate_cmd+\
- "\"com.google.android.wfcactivation/" \
- ".WfcActivationActivity\""
- elif CARRIER_VZW == operator_name:
- ad.adb.shell("setprop dbg.vzw.force_wfc_nv_enabled true")
- wfc_activate_cmd = wfc_activate_cmd + \
- "\"com.google.android.wfcactivation/" \
- ".VzwEmergencyAddressActivity\""
- else:
- wfc_activate_cmd = wfc_activate_cmd+ \
- "\"com.google.android.wfcactivation/" \
- ".can.WfcActivationCanadaActivity\""
- ad.adb.shell(wfc_activate_cmd)
-
-
-def toggle_video_calling(log, ad, new_state=None):
- """Toggle enable/disable Video calling for default voice subscription.
-
- Args:
- ad: Android device object.
- new_state: Video mode state to set to.
- True for enable, False for disable.
- If None, opposite of the current state.
-
- Raises:
- TelTestUtilsError if platform does not support Video calling.
- """
- if not ad.droid.imsIsVtEnabledByPlatform():
- if new_state is not False:
- raise TelTestUtilsError("VT not supported by platform.")
- # if the user sets VT false and it's unavailable we just let it go
- return False
-
- current_state = ad.droid.imsIsVtEnabledByUser()
- if new_state is None:
- new_state = not current_state
- if new_state != current_state:
- ad.droid.imsSetVtSetting(new_state)
- return True
-
-
-def toggle_video_calling_for_subscription(ad, new_state=None, sub_id=None):
- """Toggle enable/disable Video calling for subscription.
-
- Args:
- ad: Android device object.
- new_state: Video mode state to set to.
- True for enable, False for disable.
- If None, opposite of the current state.
- sub_id: subscription Id
-
- """
- try:
- if sub_id is None:
- sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
- current_state = ad.droid.imsMmTelIsVtSettingEnabled(sub_id)
- if new_state is None:
- new_state = not current_state
- if new_state != current_state:
- ad.log.info("SubId %s - Toggle VT from %s to %s", sub_id,
- current_state, new_state)
- ad.droid.imsMmTelSetVtSettingEnabled(sub_id, new_state)
- except Exception as e:
- ad.log.error(e)
- return False
- return True
-
-
def _wait_for_droid_in_state(log, ad, max_time, state_check_func, *args,
**kwargs):
while max_time >= 0:
@@ -5607,125 +1935,6 @@
return False
-def is_phone_in_call(log, ad):
- """Return True if phone in call.
-
- Args:
- log: log object.
- ad: android device.
- """
- 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):
- """Return True if phone not in call.
-
- Args:
- log: log object.
- ad: android device.
- """
- in_call = ad.droid.telecomIsInCall()
- call_state = ad.droid.telephonyGetCallState()
- if in_call:
- ad.log.info("Device is In Call")
- if call_state != TELEPHONY_STATE_IDLE:
- ad.log.info("Call_state is %s, not %s", call_state,
- TELEPHONY_STATE_IDLE)
- return ((not in_call) and (call_state == TELEPHONY_STATE_IDLE))
-
-
-def wait_for_droid_in_call(log, ad, max_time):
- """Wait for android to be in call state.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time.
-
- Returns:
- If phone become in call state within max_time, return True.
- Return False if timeout.
- """
- 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 ad.droid.telecomIsInCall():
- 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"
- else:
- ad.log.info("Not in telecomIsInCall")
- return False
-
-
-def wait_for_in_call_active(ad,
- timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT,
- interval=WAIT_TIME_BETWEEN_STATE_CHECK,
- 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.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time. This is optional.
- Default Value is MAX_WAIT_TIME_TELECOM_RINGING.
-
- Returns:
- If phone become in telecom ringing state within max_time, return True.
- Return False if timeout.
- """
- return _wait_for_droid_in_state(
- log, ad, max_time, lambda log, ad: ad.droid.telecomIsRinging())
-
-
-def wait_for_droid_not_in_call(log, ad, max_time=MAX_WAIT_TIME_CALL_DROP):
- """Wait for android to be not in call state.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time.
-
- Returns:
- If phone become not in call state within max_time, return True.
- Return False if timeout.
- """
- return _wait_for_droid_in_state(log, ad, max_time, is_phone_not_in_call)
-
-
def _is_attached(log, ad, voice_or_data):
return _is_attached_for_subscription(
log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
@@ -5743,48 +1952,6 @@
log, ad, ad.droid.subscriptionGetDefaultSubId(), NETWORK_SERVICE_VOICE)
-def wait_for_voice_attach(log, ad, max_time=MAX_WAIT_TIME_NW_SELECTION):
- """Wait for android device to attach on voice.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time.
-
- Returns:
- Return True if device attach voice within max_time.
- Return False if timeout.
- """
- return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
- NETWORK_SERVICE_VOICE)
-
-
-def wait_for_voice_attach_for_subscription(
- log, ad, sub_id, max_time=MAX_WAIT_TIME_NW_SELECTION):
- """Wait for android device to attach on voice in subscription id.
-
- Args:
- log: log object.
- ad: android device.
- sub_id: subscription id.
- max_time: maximal wait time.
-
- Returns:
- Return True if device attach voice within max_time.
- Return False if timeout.
- """
- if not _wait_for_droid_in_state_for_subscription(
- log, ad, sub_id, max_time, _is_attached_for_subscription,
- NETWORK_SERVICE_VOICE):
- return False
-
- # TODO: b/26295983 if pone attach to 1xrtt from unknown, phone may not
- # receive incoming call immediately.
- if ad.droid.telephonyGetCurrentVoiceNetworkType() == RAT_1XRTT:
- time.sleep(WAIT_TIME_1XRTT_VOICE_ATTACH)
- return True
-
-
def wait_for_data_attach(log, ad, max_time):
"""Wait for android device to attach on data.
@@ -5819,196 +1986,6 @@
NETWORK_SERVICE_DATA)
-def is_ims_registered(log, ad, sub_id=None):
- """Return True if IMS registered.
-
- Args:
- log: log object.
- ad: android device.
- sub_id: Optional. If not assigned the default sub ID of voice call will
- be used.
-
- Returns:
- Return True if IMS registered.
- Return False if IMS not registered.
- """
- if not sub_id:
- return ad.droid.telephonyIsImsRegistered()
- else:
- return change_voice_subid_temporarily(
- ad, sub_id, ad.droid.telephonyIsImsRegistered)
-
-
-def wait_for_ims_registered(log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
- """Wait for android device to register on ims.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time.
-
- Returns:
- Return True if device register ims successfully within max_time.
- Return False if timeout.
- """
- return _wait_for_droid_in_state(log, ad, max_time, is_ims_registered)
-
-
-def is_volte_available(log, ad, sub_id):
- """Return True if VoLTE is available.
-
- Args:
- log: log object.
- ad: android device.
- sub_id: Optional. If not assigned the default sub ID of voice call will
- be used.
-
- Returns:
- Return True if VoLTE is available.
- Return False if VoLTE is not available.
- """
- if not sub_id:
- return ad.droid.telephonyIsVolteAvailable()
- else:
- return change_voice_subid_temporarily(
- ad, sub_id, ad.droid.telephonyIsVolteAvailable)
-
-
-def is_volte_enabled(log, ad, sub_id=None):
- """Return True if VoLTE feature bit is True.
-
- Args:
- log: log object.
- ad: android device.
- sub_id: Optional. If not assigned the default sub ID of voice call will
- be used.
-
- Returns:
- Return True if VoLTE feature bit is True and IMS registered.
- Return False if VoLTE feature bit is False or IMS not registered.
- """
- if not is_ims_registered(log, ad, sub_id):
- ad.log.info("IMS is not registered for sub ID %s.", sub_id)
- return False
- if not is_volte_available(log, ad, sub_id):
- ad.log.info("IMS is registered for sub ID %s, IsVolteCallingAvailable "
- "is False", sub_id)
- return False
- else:
- ad.log.info("IMS is registered for sub ID %s, IsVolteCallingAvailable "
- "is True", sub_id)
- return True
-
-
-def is_video_enabled(log, ad):
- """Return True if Video Calling feature bit is True.
-
- Args:
- log: log object.
- ad: android device.
-
- Returns:
- Return True if Video Calling feature bit is True and IMS registered.
- Return False if Video Calling feature bit is False or IMS not registered.
- """
- video_status = ad.droid.telephonyIsVideoCallingAvailable()
- if video_status is True and is_ims_registered(log, ad) is False:
- ad.log.error(
- "Error! Video Call is Available, but IMS is not registered.")
- return False
- return video_status
-
-
-def wait_for_volte_enabled(
- log, ad, max_time=MAX_WAIT_TIME_VOLTE_ENABLED,sub_id=None):
- """Wait for android device to report VoLTE enabled bit true.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time.
-
- Returns:
- Return True if device report VoLTE enabled bit true within max_time.
- Return False if timeout.
- """
- if not sub_id:
- return _wait_for_droid_in_state(log, ad, max_time, is_volte_enabled)
- else:
- return _wait_for_droid_in_state_for_subscription(
- log, ad, sub_id, max_time, is_volte_enabled)
-
-
-def wait_for_video_enabled(log, ad, max_time=MAX_WAIT_TIME_VOLTE_ENABLED):
- """Wait for android device to report Video Telephony enabled bit true.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time.
-
- Returns:
- Return True if device report Video Telephony enabled bit true within max_time.
- Return False if timeout.
- """
- return _wait_for_droid_in_state(log, ad, max_time, is_video_enabled)
-
-
-def is_wfc_enabled(log, ad):
- """Return True if WiFi Calling feature bit is True.
-
- Args:
- log: log object.
- ad: android device.
-
- Returns:
- Return True if WiFi Calling feature bit is True and IMS registered.
- Return False if WiFi Calling feature bit is False or IMS not registered.
- """
- if not is_ims_registered(log, ad):
- ad.log.info("IMS is not registered.")
- return False
- if not ad.droid.telephonyIsWifiCallingAvailable():
- ad.log.info("IMS is registered, IsWifiCallingAvailable is False")
- return False
- else:
- ad.log.info("IMS is registered, IsWifiCallingAvailable is True")
- return True
-
-
-def wait_for_wfc_enabled(log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
- """Wait for android device to report WiFi Calling enabled bit true.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time.
- Default value is MAX_WAIT_TIME_WFC_ENABLED.
-
- Returns:
- Return True if device report WiFi Calling enabled bit true within max_time.
- Return False if timeout.
- """
- return _wait_for_droid_in_state(log, ad, max_time, is_wfc_enabled)
-
-
-def wait_for_wfc_disabled(log, ad, max_time=MAX_WAIT_TIME_WFC_DISABLED):
- """Wait for android device to report WiFi Calling enabled bit false.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time.
- Default value is MAX_WAIT_TIME_WFC_DISABLED.
-
- Returns:
- Return True if device report WiFi Calling enabled bit false within max_time.
- Return False if timeout.
- """
- return _wait_for_droid_in_state(
- log, ad, max_time, lambda log, ad: not is_wfc_enabled(log, ad))
-
-
def get_phone_number(log, ad):
"""Get phone number for default subscription
@@ -6125,867 +2102,6 @@
return model
-def is_sms_match(event, phonenumber_tx, text):
- """Return True if 'text' equals to event['data']['Text']
- and phone number match.
-
- Args:
- event: Event object to verify.
- phonenumber_tx: phone number for sender.
- text: text string to verify.
-
- Returns:
- 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'].strip() == text)
-
-
-def is_sms_partial_match(event, phonenumber_tx, text):
- """Return True if 'text' starts with event['data']['Text']
- and phone number match.
-
- Args:
- event: Event object to verify.
- phonenumber_tx: phone number for sender.
- text: text string to verify.
-
- Returns:
- Return True if 'text' starts with event['data']['Text']
- and phone number match.
- """
- event_text = event['data']['Text'].strip()
- if event_text.startswith("("):
- event_text = event_text.split(")")[-1]
- return (check_phone_number_match(event['data']['Sender'], phonenumber_tx)
- and text.startswith(event_text))
-
-
-def sms_send_receive_verify(log,
- ad_tx,
- ad_rx,
- array_message,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
- expected_result=True,
- slot_id_rx=None):
- """Send SMS, receive SMS, and verify content and sender's number.
-
- Send (several) SMS from droid_tx to droid_rx.
- Verify SMS is sent, delivered and received.
- Verify received content and sender's number are correct.
-
- Args:
- log: Log object.
- ad_tx: Sender's Android Device Object
- ad_rx: Receiver's Android Device Object
- array_message: the array of message to send/receive
- slot_id_rx: the slot on the Receiver's android device (0/1)
- """
- subid_tx = get_outgoing_message_sub_id(ad_tx)
- if slot_id_rx is None:
- subid_rx = get_incoming_message_sub_id(ad_rx)
- else:
- subid_rx = get_subid_from_slot_index(log, ad_rx, slot_id_rx)
-
- result = sms_send_receive_verify_for_subscription(
- log, ad_tx, ad_rx, subid_tx, subid_rx, array_message, max_wait_time)
- if result != expected_result:
- log_messaging_screen_shot(ad_tx, test_name="sms_tx")
- log_messaging_screen_shot(ad_rx, test_name="sms_rx")
- return result == expected_result
-
-
-def wait_for_matching_sms(log,
- ad_rx,
- phonenumber_tx,
- text,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
- allow_multi_part_long_sms=True):
- """Wait for matching incoming SMS.
-
- Args:
- log: Log object.
- ad_rx: Receiver's Android Device Object
- phonenumber_tx: Sender's phone number.
- text: SMS content string.
- allow_multi_part_long_sms: is long SMS allowed to be received as
- multiple short SMS. This is optional, default value is True.
-
- Returns:
- True if matching incoming SMS is received.
- """
- if not allow_multi_part_long_sms:
- try:
- ad_rx.messaging_ed.wait_for_event(EventSmsReceived, is_sms_match,
- max_wait_time, phonenumber_tx,
- text)
- ad_rx.log.info("Got event %s", EventSmsReceived)
- return True
- except Empty:
- ad_rx.log.error("No matched SMS received event.")
- return False
- else:
- try:
- received_sms = ''
- remaining_text = text
- while (remaining_text != ''):
- event = ad_rx.messaging_ed.wait_for_event(
- EventSmsReceived, is_sms_partial_match, max_wait_time,
- phonenumber_tx, remaining_text)
- event_text = event['data']['Text'].split(")")[-1].strip()
- event_text_length = len(event_text)
- ad_rx.log.info("Got event %s of text length %s from %s",
- EventSmsReceived, event_text_length,
- phonenumber_tx)
- remaining_text = remaining_text[event_text_length:]
- received_sms += event_text
- ad_rx.log.info("Received SMS of length %s", len(received_sms))
- return True
- except Empty:
- ad_rx.log.error(
- "Missing SMS received event of text length %s from %s",
- len(remaining_text), phonenumber_tx)
- if received_sms != '':
- ad_rx.log.error(
- "Only received partial matched SMS of length %s",
- len(received_sms))
- return False
-
-
-def is_mms_match(event, phonenumber_tx, text):
- """Return True if 'text' equals to event['data']['Text']
- and phone number match.
-
- Args:
- event: Event object to verify.
- phonenumber_tx: phone number for sender.
- text: text string to verify.
-
- Returns:
- Return True if 'text' equals to event['data']['Text']
- and phone number match.
- """
- #TODO: add mms matching after mms message parser is added in sl4a. b/34276948
- return True
-
-
-def wait_for_matching_mms(log,
- ad_rx,
- phonenumber_tx,
- text,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
- """Wait for matching incoming SMS.
-
- Args:
- log: Log object.
- ad_rx: Receiver's Android Device Object
- phonenumber_tx: Sender's phone number.
- text: SMS content string.
- allow_multi_part_long_sms: is long SMS allowed to be received as
- multiple short SMS. This is optional, default value is True.
-
- Returns:
- True if matching incoming SMS is received.
- """
- try:
- #TODO: add mms matching after mms message parser is added in sl4a. b/34276948
- ad_rx.messaging_ed.wait_for_event(EventMmsDownloaded, is_mms_match,
- max_wait_time, phonenumber_tx, text)
- ad_rx.log.info("Got event %s", EventMmsDownloaded)
- return True
- except Empty:
- ad_rx.log.warning("No matched MMS downloaded event.")
- return False
-
-
-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.
- Verify SMS is sent, delivered and received.
- Verify received content and sender's number are correct.
-
- Args:
- log: Log object.
- ad_tx: Sender's Android Device Object..
- ad_rx: Receiver's Android Device Object.
- subid_tx: Sender's subsciption ID to be used for SMS
- subid_rx: Receiver's subsciption ID to be used for SMS
- array_message: the array of message to send/receive
- """
- phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
- phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
-
- for ad in (ad_tx, ad_rx):
- ad.send_keycode("BACK")
- 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()
- else:
- ad.messaging_ed.clear_all_events()
- ad.messaging_droid.logI(
- "Start sms_send_receive_verify_for_subscription test")
- except Exception:
- ad.log.info("Create new sl4a session for messaging")
- ad.messaging_droid, ad.messaging_ed = ad.get_droid()
- ad.messaging_ed.start()
-
- for text in array_message:
- length = len(text)
- ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
- phonenumber_tx, phonenumber_rx, length, text)
- try:
- ad_rx.messaging_ed.clear_events(EventSmsReceived)
- ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
- ad_tx.messaging_ed.clear_events(EventSmsSentFailure)
- ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
- time.sleep(1) #sleep 100ms after starting event tracking
- ad_tx.messaging_droid.logI("Sending SMS of length %s" % length)
- ad_rx.messaging_droid.logI("Expecting SMS of length %s" % length)
- ad_tx.messaging_droid.smsSendTextMessage(phonenumber_rx, text,
- True)
- try:
- events = ad_tx.messaging_ed.pop_events(
- "(%s|%s|%s|%s)" %
- (EventSmsSentSuccess, EventSmsSentFailure,
- EventSmsDeliverSuccess,
- EventSmsDeliverFailure), max_wait_time)
- for event in events:
- ad_tx.log.info("Got event %s", event["name"])
- if event["name"] == EventSmsSentFailure or event["name"] == EventSmsDeliverFailure:
- if event.get("data") and event["data"].get("Reason"):
- ad_tx.log.error("%s with reason: %s",
- event["name"],
- event["data"]["Reason"])
- return False
- elif event["name"] == EventSmsSentSuccess or event["name"] == EventSmsDeliverSuccess:
- break
- except Empty:
- ad_tx.log.error("No %s or %s event for SMS of length %s.",
- EventSmsSentSuccess, EventSmsSentFailure,
- length)
- return False
-
- if not wait_for_matching_sms(
- log,
- ad_rx,
- phonenumber_tx,
- text,
- max_wait_time,
- allow_multi_part_long_sms=True):
- 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.messaging_droid.smsStopTrackingIncomingSmsMessage()
- return True
-
-
-def mms_send_receive_verify(log,
- ad_tx,
- ad_rx,
- array_message,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
- expected_result=True,
- slot_id_rx=None):
- """Send MMS, receive MMS, and verify content and sender's number.
-
- Send (several) MMS from droid_tx to droid_rx.
- Verify MMS is sent, delivered and received.
- Verify received content and sender's number are correct.
-
- Args:
- log: Log object.
- ad_tx: Sender's Android Device Object
- ad_rx: Receiver's Android Device Object
- array_message: the array of message to send/receive
- """
- subid_tx = get_outgoing_message_sub_id(ad_tx)
- if slot_id_rx is None:
- subid_rx = get_incoming_message_sub_id(ad_rx)
- else:
- subid_rx = get_subid_from_slot_index(log, ad_rx, slot_id_rx)
-
- result = mms_send_receive_verify_for_subscription(
- log, ad_tx, ad_rx, subid_tx, subid_rx, array_message, max_wait_time)
- if result != expected_result:
- log_messaging_screen_shot(ad_tx, test_name="mms_tx")
- log_messaging_screen_shot(ad_rx, test_name="mms_rx")
- return result == expected_result
-
-
-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 %s sent successful log message: %s", type,
- log_results[-1]["log_message"])
- 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: %s",
- type, log_result["log_message"])
- return True
- return False
-
-
-def sms_mms_receive_logcat_check(ad, type, begin_time):
- type = type.upper()
- smshandle_logs = ad.search_logcat(
- "InboundSmsHandler: No broadcast sent on processing EVENT_BROADCAST_SMS",
- begin_time=begin_time)
- if smshandle_logs:
- ad.log.warning("Found %s", smshandle_logs[-1]["log_message"])
- 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: %s", type,
- log_results[-1]["log_message"])
- 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: %s", type,
- log_results[-1]["log_message"])
- log_results = ad.search_logcat(
- "ProcessDownloadedMmsAction", begin_time=begin_time)
- for log_result in log_results:
- ad.log.info("Found %s", log_result["log_message"])
- if "status is SUCCEEDED" in log_result["log_message"]:
- ad.log.info("Download succeed with ProcessDownloadedMmsAction")
- 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,
- 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.
- Verify MMS is sent, delivered and received.
- Verify received content and sender's number are correct.
-
- Args:
- log: Log object.
- ad_tx: Sender's Android Device Object..
- ad_rx: Receiver's Android Device Object.
- subid_tx: Sender's subsciption ID to be used for SMS
- subid_rx: Receiver's subsciption ID to be used for SMS
- array_message: the array of message to send/receive
- """
-
- phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
- phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
- toggle_enforce = False
-
- for ad in (ad_tx, ad_rx):
- ad.send_keycode("BACK")
- if "Permissive" not in ad.adb.shell("su root getenforce"):
- ad.adb.shell("su root setenforce 0")
- toggle_enforce = True
- 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()
- else:
- ad.messaging_ed.clear_all_events()
- ad.messaging_droid.logI(
- "Start mms_send_receive_verify_for_subscription test")
- except Exception:
- ad.log.info("Create new sl4a session for messaging")
- ad.messaging_droid, ad.messaging_ed = ad.get_droid()
- ad.messaging_ed.start()
-
- for subject, message, filename in array_payload:
- ad_tx.messaging_ed.clear_events(EventMmsSentSuccess)
- ad_tx.messaging_ed.clear_events(EventMmsSentFailure)
- 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)
- try:
- ad_tx.messaging_droid.smsSendMultimediaMessage(
- phonenumber_rx, subject, message, phonenumber_tx, filename)
- try:
- events = ad_tx.messaging_ed.pop_events(
- "(%s|%s)" % (EventMmsSentSuccess,
- EventMmsSentFailure), max_wait_time)
- for event in events:
- ad_tx.log.info("Got event %s", event["name"])
- if event["name"] == EventMmsSentFailure:
- if event.get("data") and event["data"].get("Reason"):
- ad_tx.log.error("%s with reason: %s",
- event["name"],
- event["data"]["Reason"])
- return False
- elif event["name"] == EventMmsSentSuccess:
- break
- except Empty:
- ad_tx.log.warning("No %s or %s event.", EventMmsSentSuccess,
- EventMmsSentFailure)
- return False
-
- if not wait_for_matching_mms(log, ad_rx, phonenumber_tx,
- message, max_wait_time):
- return False
- except Exception as e:
- log.error("Exception error %s", e)
- raise
- finally:
- ad_rx.messaging_droid.smsStopTrackingIncomingMmsMessage()
- for ad in (ad_tx, ad_rx):
- if toggle_enforce:
- ad.send_keycode("BACK")
- ad.adb.shell("su root setenforce 1")
- return True
-
-
-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.
- Verify MMS is sent, delivered and received.
- Verify received content and sender's number are correct.
-
- Args:
- log: Log object.
- ad_tx: Sender's Android Device Object
- ad_rx: Receiver's Android Device Object
- 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, 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,
- 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.
- Verify MMS is sent, delivered and received.
- Verify received content and sender's number are correct.
-
- Args:
- log: Log object.
- ad_tx: Sender's Android Device Object..
- ad_rx: Receiver's Android Device Object.
- subid_tx: Sender's subsciption ID to be used for SMS
- subid_rx: Receiver's subsciption ID to be used for SMS
- array_message: the array of message to send/receive
- """
-
- phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
- phonenumber_rx = ad_rx.telephony['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:
- ad_rx.log.info(
- "Waiting MMS from %s to %s, subject: %s, message: %s, file: %s.",
- phonenumber_tx, phonenumber_rx, subject, message, filename)
- ad_rx.messaging_droid.smsStartTrackingIncomingMmsMessage()
- time.sleep(5)
- try:
- hangup_call(log, ad_tx)
- hangup_call(log, ad_rx)
- try:
- ad_tx.messaging_ed.pop_event(EventMmsSentSuccess,
- max_wait_time)
- ad_tx.log.info("Got event %s", EventMmsSentSuccess)
- except Empty:
- log.warning("No sent_success event.")
- if not wait_for_matching_mms(log, ad_rx, phonenumber_tx, message):
- return False
- finally:
- ad_rx.messaging_droid.smsStopTrackingIncomingMmsMessage()
- return True
-
-
-def ensure_preferred_network_type_for_subscription(
- ad,
- network_preference
- ):
- sub_id = ad.droid.subscriptionGetDefaultSubId()
- if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
- network_preference, sub_id):
- ad.log.error("Set sub_id %s Preferred Networks Type %s failed.",
- sub_id, network_preference)
- return True
-
-
-def ensure_network_rat(log,
- ad,
- network_preference,
- rat_family,
- voice_or_data=None,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- toggle_apm_after_setting=False):
- """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)
-
-
-def ensure_network_rat_for_subscription(
- log,
- ad,
- sub_id,
- network_preference,
- rat_family,
- voice_or_data=None,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- toggle_apm_after_setting=False):
- """Ensure ad's current network is in expected rat_family.
- """
- if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
- network_preference, sub_id):
- ad.log.error("Set sub_id %s Preferred Networks Type %s failed.",
- sub_id, network_preference)
- return False
- if is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family,
- voice_or_data):
- ad.log.info("Sub_id %s in RAT %s for %s", sub_id, rat_family,
- voice_or_data)
- return True
-
- if toggle_apm_after_setting:
- toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- toggle_airplane_mode(log, ad, new_state=None, strict_checking=False)
-
- result = wait_for_network_rat_for_subscription(
- log, ad, sub_id, rat_family, max_wait_time, voice_or_data)
-
- log.info(
- "End of ensure_network_rat_for_subscription for %s. "
- "Setting to %s, Expecting %s %s. Current: voice: %s(family: %s), "
- "data: %s(family: %s)", ad.serial, network_preference, rat_family,
- voice_or_data,
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
- rat_family_from_rat(
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
- sub_id)),
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
- rat_family_from_rat(
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
- sub_id)))
- return result
-
-
-def ensure_network_preference(log,
- ad,
- network_preference,
- voice_or_data=None,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- toggle_apm_after_setting=False):
- """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,
- voice_or_data, max_wait_time, toggle_apm_after_setting)
-
-
-def ensure_network_preference_for_subscription(
- log,
- ad,
- sub_id,
- network_preference,
- voice_or_data=None,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- toggle_apm_after_setting=False):
- """Ensure ad's network preference is <network_preference> for sub_id.
- """
- rat_family_list = rat_families_for_network_preference(network_preference)
- if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
- network_preference, sub_id):
- log.error("Set Preferred Networks failed.")
- return False
- if is_droid_in_rat_family_list_for_subscription(
- log, ad, sub_id, rat_family_list, voice_or_data):
- return True
-
- if toggle_apm_after_setting:
- toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- toggle_airplane_mode(log, ad, new_state=False, strict_checking=False)
-
- result = wait_for_preferred_network_for_subscription(
- log, ad, sub_id, network_preference, max_wait_time, voice_or_data)
-
- ad.log.info(
- "End of ensure_network_preference_for_subscription. "
- "Setting to %s, Expecting %s %s. Current: voice: %s(family: %s), "
- "data: %s(family: %s)", network_preference, rat_family_list,
- voice_or_data,
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
- rat_family_from_rat(
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
- sub_id)),
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
- rat_family_from_rat(
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
- sub_id)))
- return result
-
-
-def ensure_network_generation(log,
- ad,
- generation,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None,
- toggle_apm_after_setting=False):
- """Ensure ad's network is <network generation> for default subscription ID.
-
- Set preferred network generation to <generation>.
- Toggle ON/OFF airplane mode if necessary.
- 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)
-
-
-def ensure_network_generation_for_subscription(
- log,
- ad,
- sub_id,
- generation,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None,
- toggle_apm_after_setting=False):
- """Ensure ad's network is <network generation> for specified subscription ID.
-
- Set preferred network generation to <generation>.
- Toggle ON/OFF airplane mode if necessary.
- Wait for ad in expected network type.
-
- Args:
- log: log object.
- ad: android device object.
- sub_id: subscription id.
- generation: network generation, e.g. GEN_2G, GEN_3G, GEN_4G, GEN_5G.
- max_wait_time: the time to wait for NW selection.
- voice_or_data: check voice network generation or data network generation
- This parameter is optional. If voice_or_data is None, then if
- either voice or data in expected generation, function will return True.
- toggle_apm_after_setting: Cycle airplane mode if True, otherwise do nothing.
-
- Returns:
- True if success, False if fail.
- """
- ad.log.info(
- "RAT network type voice: %s, data: %s",
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id))
-
- try:
- ad.log.info("Finding the network preference for generation %s for "
- "operator %s phone type %s", generation,
- ad.telephony["subscription"][sub_id]["operator"],
- ad.telephony["subscription"][sub_id]["phone_type"])
- network_preference = network_preference_for_generation(
- generation, ad.telephony["subscription"][sub_id]["operator"],
- ad.telephony["subscription"][sub_id]["phone_type"])
- if ad.telephony["subscription"][sub_id]["operator"] == CARRIER_FRE \
- and generation == GEN_4G:
- network_preference = NETWORK_MODE_LTE_ONLY
- ad.log.info("Network preference for %s is %s", generation,
- network_preference)
- rat_family = rat_family_for_generation(
- generation, ad.telephony["subscription"][sub_id]["operator"],
- ad.telephony["subscription"][sub_id]["phone_type"])
- except KeyError as e:
- ad.log.error("Failed to find a rat_family entry for generation %s"
- " for subscriber id %s with error %s", generation,
- sub_id, e)
- return False
-
- if not set_preferred_network_mode_pref(log, ad, sub_id,
- network_preference):
- return False
-
- if hasattr(ad, "dsds") and voice_or_data == "data" and sub_id != get_default_data_sub_id(ad):
- ad.log.info("MSIM - Non DDS, ignore data RAT")
- return True
-
- if generation == GEN_5G:
- if is_current_network_5g_nsa_for_subscription(ad, sub_id=sub_id):
- ad.log.info("Current network type is 5G NSA.")
- return True
- else:
- ad.log.error("Not in 5G NSA coverage for Sub %s.", sub_id)
- return False
-
- if is_droid_in_network_generation_for_subscription(
- log, ad, sub_id, generation, voice_or_data):
- return True
-
- if toggle_apm_after_setting:
- toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- toggle_airplane_mode(log, ad, new_state=False, strict_checking=False)
-
- result = wait_for_network_generation_for_subscription(
- log, ad, sub_id, generation, max_wait_time, voice_or_data)
-
- ad.log.info(
- "Ensure network %s %s %s. With network preference %s, "
- "current: voice: %s(family: %s), data: %s(family: %s)", generation,
- voice_or_data, result, network_preference,
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
- rat_generation_from_rat(
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
- sub_id)),
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
- rat_generation_from_rat(
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
- sub_id)))
- if not result:
- get_telephony_signal_strength(ad)
- return result
-
-
-def wait_for_network_rat(log,
- ad,
- rat_family,
- 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)
-
-
-def wait_for_network_rat_for_subscription(
- log,
- ad,
- sub_id,
- rat_family,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None):
- return _wait_for_droid_in_state_for_subscription(
- log, ad, sub_id, max_wait_time,
- is_droid_in_rat_family_for_subscription, rat_family, voice_or_data)
-
-
-def wait_for_not_network_rat(log,
- ad,
- rat_family,
- 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)
-
-
-def wait_for_not_network_rat_for_subscription(
- log,
- ad,
- sub_id,
- rat_family,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None):
- return _wait_for_droid_in_state_for_subscription(
- log, ad, sub_id, max_wait_time,
- lambda log, ad, sub_id, *args, **kwargs: not is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family, voice_or_data)
- )
-
-
-def wait_for_preferred_network(log,
- ad,
- network_preference,
- 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,
- max_wait_time, voice_or_data)
-
-
-def wait_for_preferred_network_for_subscription(
- log,
- ad,
- sub_id,
- network_preference,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None):
- rat_family_list = rat_families_for_network_preference(network_preference)
- return _wait_for_droid_in_state_for_subscription(
- log, ad, sub_id, max_wait_time,
- is_droid_in_rat_family_list_for_subscription, rat_family_list,
- voice_or_data)
-
-
-def wait_for_network_generation(log,
- ad,
- generation,
- 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)
-
-
-def wait_for_network_generation_for_subscription(
- log,
- ad,
- sub_id,
- generation,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None):
- return _wait_for_droid_in_state_for_subscription(
- log, ad, sub_id, max_wait_time,
- is_droid_in_network_generation_for_subscription, generation,
- voice_or_data)
-
-
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,
@@ -7178,324 +2294,6 @@
return voice_mail_number
-def ensure_phones_idle(log, ads, max_time=MAX_WAIT_TIME_CALL_DROP):
- """Ensure ads idle (not in call).
- """
- result = True
- for ad in ads:
- if not ensure_phone_idle(log, ad, max_time=max_time):
- result = False
- return result
-
-
-def ensure_phone_idle(log, ad, max_time=MAX_WAIT_TIME_CALL_DROP, retry=2):
- """Ensure ad idle (not in call).
- """
- while ad.droid.telecomIsInCall() and retry > 0:
- ad.droid.telecomEndCall()
- time.sleep(3)
- retry -= 1
- if not wait_for_droid_not_in_call(log, ad, max_time=max_time):
- ad.log.error("Failed to end call")
- return False
- return True
-
-
-def ensure_phone_subscription(log, ad):
- """Ensure Phone Subscription.
- """
- #check for sim and service
- duration = 0
- while duration < MAX_WAIT_TIME_NW_SELECTION:
- subInfo = ad.droid.subscriptionGetAllSubInfoList()
- if subInfo and len(subInfo) >= 1:
- ad.log.debug("Find valid subcription %s", subInfo)
- break
- else:
- ad.log.info("Did not find any subscription")
- time.sleep(5)
- duration += 5
- else:
- ad.log.error("Unable to find a valid subscription!")
- return False
- while duration < MAX_WAIT_TIME_NW_SELECTION:
- data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
- voice_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
- if data_sub_id > INVALID_SUB_ID or voice_sub_id > INVALID_SUB_ID:
- ad.log.debug("Find valid voice or data sub id")
- break
- else:
- ad.log.info("Did not find valid data or voice sub id")
- time.sleep(5)
- duration += 5
- else:
- ad.log.error("Unable to find valid data or voice sub id")
- return False
- while duration < MAX_WAIT_TIME_NW_SELECTION:
- data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
- if data_sub_id > INVALID_SUB_ID:
- data_rat = get_network_rat_for_subscription(
- log, ad, data_sub_id, NETWORK_SERVICE_DATA)
- else:
- data_rat = RAT_UNKNOWN
- if voice_sub_id > INVALID_SUB_ID:
- voice_rat = get_network_rat_for_subscription(
- log, ad, voice_sub_id, NETWORK_SERVICE_VOICE)
- else:
- voice_rat = RAT_UNKNOWN
- if data_rat != RAT_UNKNOWN or voice_rat != RAT_UNKNOWN:
- ad.log.info("Data sub_id %s in %s, voice sub_id %s in %s",
- data_sub_id, data_rat, voice_sub_id, voice_rat)
- return True
- else:
- ad.log.info("Did not attach for data or voice service")
- time.sleep(5)
- duration += 5
- else:
- ad.log.error("Did not attach for voice or data service")
- return False
-
-
-def ensure_phone_default_state(log, ad, check_subscription=True, retry=2):
- """Ensure ad in default state.
- Phone not in call.
- Phone have no stored WiFi network and WiFi disconnected.
- Phone not in airplane mode.
- """
- result = True
- if not toggle_airplane_mode(log, ad, False, False):
- ad.log.error("Fail to turn off airplane mode")
- result = False
- try:
- set_wifi_to_default(log, ad)
- while ad.droid.telecomIsInCall() and retry > 0:
- ad.droid.telecomEndCall()
- time.sleep(3)
- retry -= 1
- if not wait_for_droid_not_in_call(log, ad):
- ad.log.error("Failed to end call")
- #ad.droid.telephonyFactoryReset()
- 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,
- RAT_FAMILY_WLAN)
- result = False
-
- if check_subscription and not ensure_phone_subscription(log, ad):
- ad.log.error("Unable to find a valid subscription!")
- result = False
- except Exception as e:
- ad.log.error("%s failure, toggle APM instead", e)
- toggle_airplane_mode_by_adb(log, ad, True)
- toggle_airplane_mode_by_adb(log, ad, False)
- ad.send_keycode("ENDCALL")
- ad.adb.shell("settings put global wfc_ims_enabled 0")
- ad.adb.shell("settings put global mobile_data 1")
-
- return result
-
-
-def ensure_phones_default_state(log, ads, check_subscription=True):
- """Ensure ads in default state.
- Phone not in call.
- Phone have no stored WiFi network and WiFi disconnected.
- Phone not in airplane mode.
-
- Returns:
- True if all steps of restoring default state succeed.
- False if any of the steps to restore default state fails.
- """
- tasks = []
- for ad in ads:
- tasks.append((ensure_phone_default_state, (log, ad,
- check_subscription)))
- if not multithread_func(log, tasks):
- log.error("Ensure_phones_default_state Fail.")
- return False
- return True
-
-
-def check_is_wifi_connected(log, ad, wifi_ssid):
- """Check if ad is connected to wifi wifi_ssid.
-
- Args:
- log: Log object.
- ad: Android device object.
- wifi_ssid: WiFi network SSID.
-
- Returns:
- True if wifi is connected to wifi_ssid
- False if wifi is not connected to wifi_ssid
- """
- 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
-
-
-def ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd=None, retries=3, apm=False):
- """Ensure ad connected to wifi on network wifi_ssid.
-
- Args:
- log: Log object.
- ad: Android device object.
- wifi_ssid: WiFi network SSID.
- wifi_pwd: optional secure network password.
- retries: the number of retries.
-
- Returns:
- True if wifi is connected to wifi_ssid
- False if wifi is not connected to wifi_ssid
- """
- if not toggle_airplane_mode(log, ad, apm, strict_checking=False):
- return False
-
- network = {WIFI_SSID_KEY: wifi_ssid}
- if wifi_pwd:
- network[WIFI_PWD_KEY] = wifi_pwd
- for i in range(retries):
- if not ad.droid.wifiCheckState():
- ad.log.info("Wifi state is down. Turn on Wifi")
- ad.droid.wifiToggleState(True)
- if check_is_wifi_connected(log, ad, wifi_ssid):
- ad.log.info("Wifi is connected to %s", wifi_ssid)
- return verify_internet_connection(log, ad, retries=3)
- else:
- ad.log.info("Connecting to wifi %s", wifi_ssid)
- try:
- ad.droid.wifiConnectByConfig(network)
- except Exception:
- ad.log.info("Connecting to wifi by wifiConnect instead")
- ad.droid.wifiConnect(network)
- time.sleep(20)
- if check_is_wifi_connected(log, ad, wifi_ssid):
- ad.log.info("Connected to Wifi %s", wifi_ssid)
- return verify_internet_connection(log, ad, retries=3)
- ad.log.info("Fail to connected to wifi %s", wifi_ssid)
- return False
-
-
-def forget_all_wifi_networks(log, ad):
- """Forget all stored wifi network information
-
- Args:
- log: log object
- ad: AndroidDevice object
-
- Returns:
- boolean success (True) or failure (False)
- """
- if not ad.droid.wifiGetConfiguredNetworks():
- ad.on_mobile_data = True
- return True
- try:
- old_state = ad.droid.wifiCheckState()
- wifi_test_utils.reset_wifi(ad)
- wifi_toggle_state(log, ad, old_state)
- except Exception as e:
- log.error("forget_all_wifi_networks with exception: %s", e)
- return False
- ad.on_mobile_data = True
- return True
-
-
-def wifi_reset(log, ad, disable_wifi=True):
- """Forget all stored wifi networks and (optionally) disable WiFi
-
- Args:
- log: log object
- ad: AndroidDevice object
- disable_wifi: boolean to disable wifi, defaults to True
- Returns:
- boolean success (True) or failure (False)
- """
- if not forget_all_wifi_networks(log, ad):
- ad.log.error("Unable to forget all networks")
- return False
- if not wifi_toggle_state(log, ad, not disable_wifi):
- ad.log.error("Failed to toggle WiFi state to %s!", not disable_wifi)
- return False
- return True
-
-
-def set_wifi_to_default(log, ad):
- """Set wifi to default state (Wifi disabled and no configured network)
-
- Args:
- log: log object
- ad: AndroidDevice object
-
- Returns:
- boolean success (True) or failure (False)
- """
- ad.droid.wifiFactoryReset()
- ad.droid.wifiToggleState(False)
- ad.on_mobile_data = True
-
-
-def wifi_toggle_state(log, ad, state, retries=3):
- """Toggle the WiFi State
-
- Args:
- log: log object
- ad: AndroidDevice object
- state: True, False, or None
-
- Returns:
- boolean success (True) or failure (False)
- """
- 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
-
-
-def start_wifi_tethering(log, ad, ssid, password, ap_band=None):
- """Start a Tethering Session
-
- Args:
- log: log object
- ad: AndroidDevice object
- ssid: the name of the WiFi network
- password: optional password, used for secure networks.
- ap_band=DEPRECATED specification of 2G or 5G tethering
- Returns:
- boolean success (True) or failure (False)
- """
- return wifi_test_utils._assert_on_fail_handler(
- wifi_test_utils.start_wifi_tethering,
- False,
- ad,
- ssid,
- password,
- band=ap_band)
-
-
-def stop_wifi_tethering(log, ad):
- """Stop a Tethering Session
-
- Args:
- log: log object
- ad: AndroidDevice object
- Returns:
- boolean success (True) or failure (False)
- """
- return wifi_test_utils._assert_on_fail_handler(
- wifi_test_utils.stop_wifi_tethering, False, ad)
-
-
def reset_preferred_network_type_to_allowable_range(log, ad):
"""If preferred network type is not in allowable range, reset to GEN_4G
preferred network type.
@@ -7522,109 +2320,6 @@
pass
-def task_wrapper(task):
- """Task wrapper for multithread_func
-
- Args:
- task[0]: function to be wrapped.
- task[1]: function args.
-
- Returns:
- Return value of wrapped function call.
- """
- func = task[0]
- params = task[1]
- 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.
-
- Args:
- log: log object.
- tasks: a list of tasks to be executed in parallel.
-
- Returns:
- results for tasks.
- """
- 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()
- if log:
- log.info("multithread_func %s result: %s",
- [task[0].__name__ for task in tasks], results)
- return results
-
-
-def multithread_func(log, tasks):
- """Multi-thread function wrapper.
-
- Args:
- log: log object.
- tasks: tasks to be executed in parallel.
-
- Returns:
- True if all tasks return True.
- False if any task return False.
- """
- results = run_multithread_func(log, tasks)
- for r in results:
- if not r:
- return False
- return True
-
-
-def multithread_func_and_check_results(log, tasks, expected_results):
- """Multi-thread function wrapper.
-
- Args:
- log: log object.
- tasks: tasks to be executed in parallel.
- expected_results: check if the results from tasks match expected_results.
-
- Returns:
- True if expected_results are met.
- False if expected_results are not met.
- """
- return_value = True
- results = run_multithread_func(log, tasks)
- log.info("multithread_func result: %s, expecting %s", results,
- expected_results)
- for task, result, expected_result in zip(tasks, results, expected_results):
- if result != expected_result:
- logging.info("Result for task %s is %s, expecting %s", task[0],
- result, expected_result)
- return_value = False
- return return_value
-
-
def set_phone_screen_on(log, ad, screen_on_time=MAX_SCREEN_ON_TIME):
"""Set phone screen on time.
@@ -7701,61 +2396,6 @@
return False
-def set_preferred_subid_for_sms(log, ad, sub_id):
- """set subscription id for SMS
-
- Args:
- log: Log object.
- ad: Android device object.
- sub_id :Subscription ID.
-
- """
- ad.log.info("Setting subscription %s as preferred SMS SIM", sub_id)
- ad.droid.subscriptionSetDefaultSmsSubId(sub_id)
- # Wait to make sure settings take effect
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- return sub_id == ad.droid.subscriptionGetDefaultSmsSubId()
-
-
-def set_preferred_subid_for_data(log, ad, sub_id):
- """set subscription id for data
-
- Args:
- log: Log object.
- ad: Android device object.
- sub_id :Subscription ID.
-
- """
- ad.log.info("Setting subscription %s as preferred Data SIM", sub_id)
- ad.droid.subscriptionSetDefaultDataSubId(sub_id)
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- # Wait to make sure settings take effect
- # Data SIM change takes around 1 min
- # Check whether data has changed to selected sim
- if not wait_for_data_connection(log, ad, True,
- MAX_WAIT_TIME_DATA_SUB_CHANGE):
- log.error("Data Connection failed - Not able to switch Data SIM")
- return False
- return True
-
-
-def set_preferred_subid_for_voice(log, ad, sub_id):
- """set subscription id for voice
-
- Args:
- log: Log object.
- ad: Android device object.
- sub_id :Subscription ID.
-
- """
- ad.log.info("Setting subscription %s as Voice SIM", sub_id)
- ad.droid.subscriptionSetDefaultVoiceSubId(sub_id)
- ad.droid.telecomSetUserSelectedOutgoingPhoneAccountBySubId(sub_id)
- # Wait to make sure settings take effect
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- return True
-
-
def set_call_state_listen_level(log, ad, value, sub_id):
"""Set call state listen level for subscription id.
@@ -7780,34 +2420,6 @@
return True
-def setup_sim(log, ad, sub_id, voice=False, sms=False, data=False):
- """set subscription id for voice, sms and data
-
- Args:
- log: Log object.
- ad: Android device object.
- sub_id :Subscription ID.
- voice: True if to set subscription as default voice subscription
- sms: True if to set subscription as default sms subscription
- data: True if to set subscription as default data subscription
-
- """
- if sub_id == INVALID_SUB_ID:
- log.error("Invalid Subscription ID")
- return False
- else:
- if voice:
- if not set_preferred_subid_for_voice(log, ad, sub_id):
- return False
- if sms:
- if not set_preferred_subid_for_sms(log, ad, sub_id):
- return False
- if data:
- if not set_preferred_subid_for_data(log, ad, sub_id):
- return False
- return True
-
-
def is_event_match(event, field, value):
"""Return if <field> in "event" match <value> or not.
@@ -7954,467 +2566,6 @@
return None
-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/", "/vendor/etc/modem/"):
- 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/"):
- setattr(ad, "qxdm_log_path", DEFAULT_QXDM_LOG_PATH)
- else:
- setattr(ad, "qxdm_log_path", path)
- return out.split("\n")[0]
- for mask_file in ("/vendor/etc/mdlog/", "/vendor/etc/modem/"):
- if mask in ad.adb.shell("ls %s" % mask_file, ignore_status=True):
- setattr(ad, "qxdm_log_path", DEFAULT_QXDM_LOG_PATH)
- return "%s/%s" % (mask_file, mask)
- else:
- out = ad.adb.shell("ls %s" % mask, ignore_status=True)
- if out and "No such" not in out:
- qxdm_log_path, cfg_name = os.path.split(mask)
- setattr(ad, "qxdm_log_path", qxdm_log_path)
- 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.
-
- """
- ## 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 90 -c" %
- (mask_path, output_path))
- return True
-
-
-
-def start_sdm_logger(ad):
- """Start SDM logger."""
- if not getattr(ad, "sdm_log", True): return
- # Delete existing SDM logs which were created 15 mins prior
- ad.sdm_log_path = DEFAULT_SDM_LOG_PATH
- file_count = ad.adb.shell(
- "find %s -type f -iname sbuff_[0-9]*.sdm* | wc -l" % ad.sdm_log_path)
- if int(file_count) > 3:
- seconds = 15 * 60
- # Remove sdm logs modified more than specified seconds ago
- ad.adb.shell(
- "find %s -type f -iname sbuff_[0-9]*.sdm* -not -mtime -%ss -delete" %
- (ad.sdm_log_path, seconds))
- # Disable any modem logging already running
- ad.adb.shell("setprop persist.vendor.sys.modem.logging.enable false")
- ad.adb.shell('echo "modem_logging_control START -n 10 -s 100 -i 1" > /data/vendor/radio/logs/always-on.conf')
- # start logging
- cmd = "setprop vendor.sys.modem.logging.enable true"
- ad.log.debug("start sdm logging")
- ad.adb.shell(cmd, ignore_status=True)
- time.sleep(5)
-
-
-def stop_sdm_logger(ad):
- """Stop SDM logger."""
- cmd = "setprop vendor.sys.modem.logging.enable false"
- ad.log.debug("stop sdm logging")
- ad.adb.shell(cmd, ignore_status=True)
- time.sleep(5)
-
-
-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
- current_time = get_current_epoch_time()
- if getattr(ad, "qxdm_log_path", None):
- seconds = None
- file_count = ad.adb.shell(
- "find %s -type f -iname *.qmdl | wc -l" % ad.qxdm_log_path)
- if int(file_count) > 50:
- if begin_time:
- # if begin_time specified, delete old qxdm logs modified
- # 10 minutes before begin time
- seconds = int((current_time - begin_time) / 1000.0) + 10 * 60
- else:
- # if begin_time is not specified, delete old qxdm logs modified
- # 15 minutes before current time
- seconds = 15 * 60
- if seconds:
- # Remove qxdm logs modified more than specified seconds ago
- ad.adb.shell(
- "find %s -type f -iname *.qmdl -not -mtime -%ss -delete" %
- (ad.qxdm_log_path, seconds))
- ad.adb.shell(
- "find %s -type f -iname *.xml -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 non-matching 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)
- time.sleep(10)
- else:
- run_time = check_qxdm_logger_run_time(ad)
- if run_time < 600:
- # the last diag_mdlog started within 10 minutes ago
- # no need to restart
- return True
- if ad.search_logcat(
- "Diag_Lib: diag: In delete_log",
- begin_time=current_time -
- run_time) or not ad.get_file_names(
- ad.qxdm_log_path,
- begin_time=current_time - 600000,
- match_string="*.qmdl"):
- # diag_mdlog starts deleting files or no qmdl logs were
- # modified in the past 10 minutes
- ad.log.debug("Quit existing diag_mdlog and start a new one")
- stop_qxdm_logger(ad)
- ad.adb.shell_nb(ad.qxdm_logger_command)
- time.sleep(10)
- return True
-
-
-def disable_qxdm_logger(ad):
- for prop in ("persist.sys.modem.diag.mdlog",
- "persist.vendor.sys.modem.diag.mdlog",
- "vendor.sys.modem.diag.mdlog_on"):
- if ad.adb.getprop(prop):
- ad.adb.shell("setprop %s false" % prop, ignore_status=True)
- for apk in ("com.android.nexuslogger", "com.android.pixellogger"):
- if ad.is_apk_installed(apk) and ad.is_apk_running(apk):
- ad.force_stop_apk(apk)
- stop_qxdm_logger(ad)
- return True
-
-
-def check_qxdm_logger_run_time(ad):
- output = ad.adb.shell("ps -eo etime,cmd | grep diag_mdlog")
- result = re.search(r"(\d+):(\d+):(\d+) diag_mdlog", output)
- if result:
- return int(result.group(1)) * 60 * 60 + int(
- result.group(2)) * 60 + int(result.group(3))
- else:
- result = re.search(r"(\d+):(\d+) diag_mdlog", output)
- if result:
- return int(result.group(1)) * 60 + int(result.group(2))
- else:
- return 0
-
-
-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_sdm_loggers(log, ads):
- tasks = [(start_sdm_logger, [ad]) for ad in ads
- if getattr(ad, "sdm_log", True)]
- if tasks: run_multithread_func(log, tasks)
-
-
-def stop_sdm_loggers(log, ads):
- tasks = [(stop_sdm_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.unlock_screen()
- 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.
-
- """
- 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
- return True
-
-
-def start_tcpdumps(ads,
- test_name="",
- begin_time=None,
- interface="any",
- mask="all"):
- for ad in ads:
- try:
- start_adb_tcpdump(
- ad,
- test_name=test_name,
- begin_time=begin_time,
- interface=interface,
- mask=mask)
- except Exception as e:
- ad.log.warning("Fail to start tcpdump due to %s", e)
-
-
-def start_adb_tcpdump(ad,
- test_name="",
- begin_time=None,
- interface="any",
- mask="all"):
- """Start tcpdump on any iface
-
- Args:
- ad: android device object.
- test_name: tcpdump file name will have this
-
- """
- out = ad.adb.shell("ls -l /data/local/tmp/tcpdump/", ignore_status=True)
- if "No such file" in out or not out:
- ad.adb.shell("mkdir /data/local/tmp/tcpdump")
- else:
- ad.adb.shell(
- "find /data/local/tmp/tcpdump -type f -not -mtime -1800s -delete",
- ignore_status=True)
- ad.adb.shell(
- "find /data/local/tmp/tcpdump -type f -size +5G -delete",
- ignore_status=True)
-
- if not begin_time:
- begin_time = get_current_epoch_time()
-
- out = ad.adb.shell(
- 'ifconfig | grep -v -E "r_|-rmnet" | grep -E "lan|data"',
- ignore_status=True,
- timeout=180)
- intfs = re.findall(r"(\S+).*", out)
- if interface and interface not in ("any", "all"):
- if interface not in intfs: return
- intfs = [interface]
-
- out = ad.adb.shell("ps -ef | grep tcpdump")
- cmds = []
- for intf in intfs:
- if intf in out:
- ad.log.info("tcpdump on interface %s is already running", intf)
- continue
- else:
- log_file_name = "/data/local/tmp/tcpdump/tcpdump_%s_%s_%s_%s.pcap" \
- % (ad.serial, intf, test_name, begin_time)
- if mask == "ims":
- cmds.append(
- "adb -s %s shell tcpdump -i %s -s0 -n -p udp port 500 or "
- "udp port 4500 -w %s" % (ad.serial, intf, log_file_name))
- else:
- cmds.append("adb -s %s shell tcpdump -i %s -s0 -w %s" %
- (ad.serial, intf, log_file_name))
- if not gutils.check_chipset_vendor_by_qualcomm(ad):
- log_file_name = ("/data/local/tmp/tcpdump/tcpdump_%s_any_%s_%s.pcap"
- % (ad.serial, test_name, begin_time))
- cmds.append("adb -s %s shell nohup tcpdump -i any -s0 -w %s" %
- (ad.serial, log_file_name))
- for cmd in cmds:
- ad.log.info(cmd)
- try:
- start_standing_subprocess(cmd, 10)
- except Exception as e:
- ad.log.error(e)
- if cmds:
- time.sleep(5)
-
-
-def stop_tcpdumps(ads):
- for ad in ads:
- stop_adb_tcpdump(ad)
-
-
-def stop_adb_tcpdump(ad, interface="any"):
- """Stops tcpdump on any iface
- Pulls the tcpdump file in the tcpdump dir
-
- Args:
- ad: android device object.
-
- """
- if interface == "any":
- try:
- ad.adb.shell("killall -9 tcpdump", ignore_status=True)
- except Exception as e:
- ad.log.error("Killing tcpdump with exception %s", e)
- else:
- out = ad.adb.shell("ps -ef | grep tcpdump | grep %s" % interface)
- if "tcpdump -i" in out:
- pids = re.findall(r"\S+\s+(\d+).*tcpdump -i", out)
- for pid in pids:
- ad.adb.shell("kill -9 %s" % pid)
- ad.adb.shell(
- "find /data/local/tmp/tcpdump -type f -not -mtime -1800s -delete",
- ignore_status=True)
-
-
-def get_tcpdump_log(ad, test_name="", begin_time=None):
- """Stops tcpdump on any iface
- Pulls the tcpdump file in the tcpdump dir
- Zips all tcpdump files
-
- Args:
- ad: android device object.
- test_name: test case name
- begin_time: test begin time
- """
- logs = ad.get_file_names("/data/local/tmp/tcpdump", begin_time=begin_time)
- if logs:
- ad.log.info("Pulling tcpdumps %s", logs)
- log_path = os.path.join(
- ad.device_log_path, "TCPDUMP_%s_%s" % (ad.model, ad.serial))
- os.makedirs(log_path, exist_ok=True)
- ad.pull_files(logs, log_path)
- shutil.make_archive(log_path, "zip", log_path)
- shutil.rmtree(log_path)
- return True
-
-
-def fastboot_wipe(ad, skip_setup_wizard=True):
- """Wipe the device in fastboot mode.
-
- Pull sl4a apk from device. Terminate all sl4a sessions,
- Reboot the device to bootloader, wipe the device by fastboot.
- Reboot the device. wait for device to complete booting
- Re-intall and start an sl4a session.
- """
- status = True
- # Pull sl4a apk from device
- 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")
- else:
- sl4a_apk = result.group(1)
- ad.log.info("Get sl4a apk from %s", sl4a_apk)
- ad.pull_files([sl4a_apk], "/tmp/")
- ad.stop_services()
- attemps = 3
- for i in range(1, attemps + 1):
- try:
- if ad.serial in list_adb_devices():
- ad.log.info("Reboot to bootloader")
- ad.adb.reboot("bootloader", ignore_status=True)
- time.sleep(10)
- if ad.serial in list_fastboot_devices():
- ad.log.info("Wipe in fastboot")
- ad.fastboot._w(timeout=300, ignore_status=True)
- time.sleep(30)
- ad.log.info("Reboot in fastboot")
- ad.fastboot.reboot()
- ad.wait_for_boot_completion()
- ad.root_adb()
- if ad.skip_sl4a:
- break
- if ad.is_sl4a_installed():
- break
- ad.log.info("Re-install sl4a")
- ad.adb.shell("settings put global verifier_verify_adb_installs 0")
- ad.adb.install("-r /tmp/base.apk")
- time.sleep(10)
- break
- except Exception as e:
- ad.log.warning(e)
- if i == attemps:
- abort_all_tests(log, str(e))
- time.sleep(5)
- try:
- ad.start_adb_logcat()
- except:
- ad.log.error("Failed to start adb logcat!")
- if skip_setup_wizard:
- ad.exit_setup_wizard()
- if getattr(ad, "qxdm_log", True):
- set_qxdm_logger_command(ad, mask=getattr(ad, "qxdm_log_mask", None))
- start_qxdm_logger(ad)
- if ad.skip_sl4a: return status
- bring_up_sl4a(ad)
- synchronize_device_time(ad)
- set_phone_silent_mode(ad.log, ad)
- # Activate WFC on Verizon, AT&T and Canada operators as per # b/33187374 &
- # b/122327716
- activate_wfc_on_device(ad.log, ad)
- return status
-
-
def install_carriersettings_apk(ad, carriersettingsapk, skip_setup_wizard=True):
""" Carrier Setting Installation Steps
@@ -8527,54 +2678,6 @@
bring_up_sl4a(ad)
-def reset_device_password(ad, device_password=None):
- # Enable or Disable Device Password per test bed config
- unlock_sim(ad)
- screen_lock = ad.is_screen_lock_enabled()
- if 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
- return
- else:
- # enable device password and log in for the first time
- ad.log.info("Enable device password")
- ad.adb.wait_for_device(timeout=180)
- else:
- if not screen_lock:
- # no existing password, do not set password
- return
- else:
- # password is enabled on the device
- # 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.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)
- if not ad.is_adb_logcat_on:
- ad.start_adb_logcat()
-
-
def get_sim_state(ad):
try:
state = ad.droid.telephonyGetSimState()
@@ -8766,47 +2869,6 @@
return True
-def flash_radio(ad, file_path, skip_setup_wizard=True):
- """Flash radio image."""
- ad.stop_services()
- ad.log.info("Reboot to bootloader")
- ad.adb.reboot_bootloader(ignore_status=True)
- ad.log.info("Flash radio in fastboot")
- try:
- ad.fastboot.flash("radio %s" % file_path, timeout=300)
- except Exception as e:
- ad.log.error(e)
- ad.fastboot.reboot("bootloader")
- time.sleep(5)
- output = ad.fastboot.getvar("version-baseband")
- result = re.search(r"version-baseband: (\S+)", output)
- if not result:
- ad.log.error("fastboot getvar version-baseband output = %s", output)
- abort_all_tests(ad.log, "Radio version-baseband is not provided")
- fastboot_radio_version_output = result.group(1)
- for _ in range(2):
- try:
- ad.log.info("Reboot in fastboot")
- ad.fastboot.reboot()
- ad.wait_for_boot_completion()
- break
- except Exception as e:
- ad.log.error("Exception error %s", e)
- ad.root_adb()
- adb_radio_version_output = ad.adb.getprop("gsm.version.baseband")
- ad.log.info("adb getprop gsm.version.baseband = %s",
- adb_radio_version_output)
- if adb_radio_version_output != fastboot_radio_version_output:
- msg = ("fastboot radio version output %s does not match with adb"
- " radio version output %s" % (fastboot_radio_version_output,
- adb_radio_version_output))
- abort_all_tests(ad.log, msg)
- if not ad.ensure_screen_on():
- ad.log.error("User window cannot come up")
- ad.start_services(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
@@ -8885,6 +2947,101 @@
return False
+def power_off_sim_by_adb(ad, sim_slot_id,
+ timeout=MAX_WAIT_TIME_FOR_STATE_CHANGE):
+ """Disable pSIM/eSIM SUB by adb command.
+
+ Args:
+ ad: android device object.
+ sim_slot_id: slot 0 or slot 1.
+ timeout: wait time for state change.
+
+ Returns:
+ True if success, False otherwise.
+ """
+ release_version = int(ad.adb.getprop("ro.build.version.release"))
+ if sim_slot_id == 0 and release_version < 12:
+ ad.log.error(
+ "The disable pSIM SUB command only support for Android S or higher "
+ "version, abort test.")
+ raise signals.TestSkip(
+ "The disable pSIM SUB command only support for Android S or higher "
+ "version, abort test.")
+ try:
+ if sim_slot_id:
+ ad.adb.shell("am broadcast -a android.telephony.euicc.action."
+ "TEST_PROFILE -n com.google.android.euicc/com.android.euicc."
+ "receiver.ProfileTestReceiver --es 'operation' 'switch' --ei "
+ "'subscriptionId' -1")
+ else:
+ sub_id = get_subid_by_adb(ad, sim_slot_id)
+ # The command only support for Android S. (b/159605922)
+ ad.adb.shell(
+ "cmd phone disable-physical-subscription %d" % sub_id)
+ except Exception as e:
+ ad.log.error(e)
+ return False
+ while timeout > 0:
+ if get_subid_by_adb(ad, sim_slot_id) == INVALID_SUB_ID:
+ return True
+ timeout = timeout - WAIT_TIME_BETWEEN_STATE_CHECK
+ time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
+ sim_state = ad.adb.getprop("gsm.sim.state").split(",")
+ ad.log.warning("Fail to power off SIM slot %d, sim_state=%s",
+ sim_slot_id, sim_state[sim_slot_id])
+ return False
+
+
+def power_on_sim_by_adb(ad, sim_slot_id,
+ timeout=MAX_WAIT_TIME_FOR_STATE_CHANGE):
+ """Enable pSIM/eSIM SUB by adb command.
+
+ Args:
+ ad: android device object.
+ sim_slot_id: slot 0 or slot 1.
+ timeout: wait time for state change.
+
+ Returns:
+ True if success, False otherwise.
+ """
+ release_version = int(ad.adb.getprop("ro.build.version.release"))
+ if sim_slot_id == 0 and release_version < 12:
+ ad.log.error(
+ "The enable pSIM SUB command only support for Android S or higher "
+ "version, abort test.")
+ raise signals.TestSkip(
+ "The enable pSIM SUB command only support for Android S or higher "
+ "version, abort test.")
+ try:
+ output = ad.adb.shell(
+ "dumpsys isub | grep addSubInfoRecord | grep slotIndex=%d" %
+ sim_slot_id)
+ pattern = re.compile(r"subId=(\d+)")
+ sub_id = pattern.findall(output)
+ sub_id = int(sub_id[-1]) if sub_id else INVALID_SUB_ID
+ if sim_slot_id:
+ ad.adb.shell("am broadcast -a android.telephony.euicc.action."
+ "TEST_PROFILE -n com.google.android.euicc/com.android.euicc."
+ "receiver.ProfileTestReceiver --es 'operation' 'switch' --ei "
+ "'subscriptionId' %d" % sub_id)
+ else:
+ # The command only support for Android S or higher. (b/159605922)
+ ad.adb.shell(
+ "cmd phone enable-physical-subscription %d" % sub_id)
+ except Exception as e:
+ ad.log.error(e)
+ return False
+ while timeout > 0:
+ if get_subid_by_adb(ad, sim_slot_id) != INVALID_SUB_ID:
+ return True
+ timeout = timeout - WAIT_TIME_BETWEEN_STATE_CHECK
+ time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
+ sim_state = ad.adb.getprop("gsm.sim.state").split(",")
+ ad.log.warning("Fail to power on SIM slot %d, sim_state=%s",
+ sim_slot_id, sim_state[sim_slot_id])
+ return False
+
+
def power_off_sim(ad, sim_slot_id=None,
timeout=MAX_WAIT_TIME_FOR_STATE_CHANGE):
try:
@@ -8902,7 +3059,8 @@
return False
while timeout > 0:
sim_state = verify_func(*verify_args)
- if sim_state in (SIM_STATE_UNKNOWN, SIM_STATE_ABSENT):
+ if sim_state in (
+ SIM_STATE_UNKNOWN, SIM_STATE_ABSENT, SIM_STATE_NOT_READY):
ad.log.info("SIM slot is powered off, SIM state is %s", sim_state)
return True
timeout = timeout - WAIT_TIME_BETWEEN_STATE_CHECK
@@ -8938,27 +3096,6 @@
return False
-def extract_test_log(log, src_file, dst_file, test_tag):
- os.makedirs(os.path.dirname(dst_file), exist_ok=True)
- cmd = "grep -n '%s' %s" % (test_tag, src_file)
- result = job.run(cmd, ignore_status=True)
- if not result.stdout or result.exit_status == 1:
- log.warning("Command %s returns %s", cmd, result)
- return
- line_nums = re.findall(r"(\d+).*", result.stdout)
- if line_nums:
- begin_line = int(line_nums[0])
- end_line = int(line_nums[-1])
- if end_line - begin_line <= 5:
- result = job.run("wc -l < %s" % src_file)
- if result.stdout:
- end_line = int(result.stdout)
- log.info("Extract %s from line %s to line %s to %s", src_file,
- begin_line, end_line, dst_file)
- job.run("awk 'NR >= %s && NR <= %s' %s > %s" % (begin_line, end_line,
- src_file, dst_file))
-
-
def get_device_epoch_time(ad):
return int(1000 * float(ad.adb.shell("date +%s.%N")))
@@ -9033,47 +3170,6 @@
return result
-def log_messaging_screen_shot(ad, test_name=""):
- ad.ensure_screen_on()
- ad.send_keycode("HOME")
- ad.adb.shell("am start -n com.google.android.apps.messaging/.ui."
- "ConversationListActivity")
- time.sleep(3)
- log_screen_shot(ad, test_name)
- ad.adb.shell("am start -n com.google.android.apps.messaging/com.google."
- "android.apps.messaging.ui.conversation."
- "LaunchConversationShimActivity -e conversation_id 1")
- time.sleep(3)
- log_screen_shot(ad, test_name)
- ad.send_keycode("HOME")
-
-
-def log_screen_shot(ad, test_name=""):
- file_name = "/sdcard/Pictures/screencap"
- if test_name:
- file_name = "%s_%s" % (file_name, test_name)
- file_name = "%s_%s.png" % (file_name, utils.get_current_epoch_time())
- try:
- ad.adb.shell("screencap -p %s" % file_name)
- except:
- ad.log.error("Fail to log screen shot to %s", file_name)
-
-
-def get_screen_shot_log(ad, test_name="", begin_time=None):
- logs = ad.get_file_names("/sdcard/Pictures", begin_time=begin_time)
- if logs:
- ad.log.info("Pulling %s", logs)
- log_path = os.path.join(ad.device_log_path, "Screenshot_%s" % ad.serial)
- os.makedirs(log_path, exist_ok=True)
- ad.pull_files(logs, log_path)
- ad.adb.shell("rm -rf /sdcard/Pictures/screencap_*", ignore_status=True)
-
-
-def get_screen_shot_logs(ads, test_name="", begin_time=None):
- for ad in ads:
- get_screen_shot_log(ad, test_name=test_name, begin_time=begin_time)
-
-
def get_carrier_id_version(ad):
out = ad.adb.shell("dumpsys activity service TelephonyDebugService | " \
"grep -i carrier_list_version")
@@ -9133,6 +3229,72 @@
ad.log.error("Failed to add google account - %s", output)
return False
+def install_apk(ad, apk_path, app_package_name):
+ """Install assigned apk to specific device.
+
+ Args:
+ ad: android device object
+ apk_path: The path of apk (please refer to the "Resources" section in
+ go/mhbe-resources for supported file stores.)
+ app_package_name: package name of the application
+
+ Returns:
+ True if success, False if fail.
+ """
+ ad.log.info("Install %s from %s", app_package_name, apk_path)
+ ad.adb.install("-r -g %s" % apk_path, timeout=300, ignore_status=True)
+ time.sleep(3)
+ if not ad.is_apk_installed(app_package_name):
+ ad.log.info("%s is not installed.", app_package_name)
+ return False
+ if ad.get_apk_version(app_package_name):
+ ad.log.info("Current version of %s: %s", app_package_name,
+ ad.get_apk_version(app_package_name))
+ return True
+
+def install_dialer_apk(ad, dialer_util):
+ """Install dialer.apk to specific device.
+
+ Args:
+ ad: android device object.
+ dialer_util: path of dialer.apk
+
+ Returns:
+ True if success, False if fail.
+ """
+ ad.log.info("Install dialer_util %s", dialer_util)
+ ad.adb.install("-r -g %s" % dialer_util, timeout=300, ignore_status=True)
+ time.sleep(3)
+ if not ad.is_apk_installed(DIALER_PACKAGE_NAME):
+ ad.log.info("%s is not installed", DIALER_PACKAGE_NAME)
+ return False
+ if ad.get_apk_version(DIALER_PACKAGE_NAME):
+ ad.log.info("Current version of %s: %s", DIALER_PACKAGE_NAME,
+ ad.get_apk_version(DIALER_PACKAGE_NAME))
+ return True
+
+
+def install_message_apk(ad, message_util):
+ """Install message.apk to specific device.
+
+ Args:
+ ad: android device object.
+ message_util: path of message.apk
+
+ Returns:
+ True if success, False if fail.
+ """
+ ad.log.info("Install message_util %s", message_util)
+ ad.adb.install("-r -g %s" % message_util, timeout=300, ignore_status=True)
+ time.sleep(3)
+ if not ad.is_apk_installed(MESSAGE_PACKAGE_NAME):
+ ad.log.info("%s is not installed", MESSAGE_PACKAGE_NAME)
+ return False
+ if ad.get_apk_version(MESSAGE_PACKAGE_NAME):
+ ad.log.info("Current version of %s: %s", MESSAGE_PACKAGE_NAME,
+ ad.get_apk_version(MESSAGE_PACKAGE_NAME))
+ return True
+
def install_googleaccountutil_apk(ad, account_util):
ad.log.info("Install account_util %s", account_util)
@@ -9476,380 +3638,6 @@
return monitor_setting == expected_monitor_setting
-def get_call_forwarding_by_adb(log, ad, call_forwarding_type="unconditional"):
- """ Get call forwarding status by adb shell command
- 'dumpsys telephony.registry'.
-
- Args:
- log: log object
- ad: android object
- call_forwarding_type:
- - "unconditional"
- - "busy" (todo)
- - "not_answered" (todo)
- - "not_reachable" (todo)
- Returns:
- - "true": if call forwarding unconditional is enabled.
- - "false": if call forwarding unconditional is disabled.
- - "unknown": if the type is other than 'unconditional'.
- - False: any case other than above 3 cases.
- """
- if call_forwarding_type != "unconditional":
- return "unknown"
-
- slot_index_of_default_voice_subid = get_slot_index_from_subid(log, ad,
- get_incoming_voice_sub_id(ad))
- output = ad.adb.shell("dumpsys telephony.registry | grep mCallForwarding")
- if "mCallForwarding" in output:
- result_list = re.findall(r"mCallForwarding=(true|false)", output)
- if result_list:
- result = result_list[slot_index_of_default_voice_subid]
- ad.log.info("mCallForwarding is %s", result)
-
- if re.search("false", result, re.I):
- return "false"
- elif re.search("true", result, re.I):
- return "true"
- else:
- return False
- else:
- return False
- else:
- ad.log.error("'mCallForwarding' cannot be found in dumpsys.")
- return False
-
-
-def erase_call_forwarding_by_mmi(
- log,
- ad,
- retry=2,
- call_forwarding_type="unconditional"):
- """ Erase setting of call forwarding (erase the number and disable call
- forwarding) by MMI code.
-
- Args:
- log: log object
- ad: android object
- retry: times of retry if the erasure failed.
- call_forwarding_type:
- - "unconditional"
- - "busy"
- - "not_answered"
- - "not_reachable"
- Returns:
- True by successful erasure. Otherwise False.
- """
- operator_name = get_operator_name(log, ad)
-
- run_get_call_forwarding_by_adb = 1
- if operator_name in NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST:
- run_get_call_forwarding_by_adb = 0
-
- if run_get_call_forwarding_by_adb:
- res = get_call_forwarding_by_adb(log, ad,
- call_forwarding_type=call_forwarding_type)
- if res == "false":
- return True
-
- user_config_profile = get_user_config_profile(ad)
- is_airplane_mode = user_config_profile["Airplane Mode"]
- is_wfc_enabled = user_config_profile["WFC Enabled"]
- wfc_mode = user_config_profile["WFC Mode"]
- is_wifi_on = user_config_profile["WiFi State"]
-
- if is_airplane_mode:
- if not toggle_airplane_mode(log, ad, False):
- ad.log.error("Failed to disable airplane mode.")
- return False
-
- code_dict = {
- "Verizon": {
- "unconditional": "73",
- "busy": "73",
- "not_answered": "73",
- "not_reachable": "73",
- "mmi": "*%s"
- },
- "Sprint": {
- "unconditional": "720",
- "busy": "740",
- "not_answered": "730",
- "not_reachable": "720",
- "mmi": "*%s"
- },
- "Far EasTone": {
- "unconditional": "142",
- "busy": "143",
- "not_answered": "144",
- "not_reachable": "144",
- "mmi": "*%s*2"
- },
- 'Generic': {
- "unconditional": "21",
- "busy": "67",
- "not_answered": "61",
- "not_reachable": "62",
- "mmi": "##%s#"
- }
- }
-
- if operator_name in code_dict:
- code = code_dict[operator_name][call_forwarding_type]
- mmi = code_dict[operator_name]["mmi"]
- else:
- code = code_dict['Generic'][call_forwarding_type]
- mmi = code_dict['Generic']["mmi"]
-
- result = False
- while retry >= 0:
- if run_get_call_forwarding_by_adb:
- res = get_call_forwarding_by_adb(
- log, ad, call_forwarding_type=call_forwarding_type)
- if res == "false":
- ad.log.info("Call forwarding is already disabled.")
- result = True
- break
-
- ad.log.info("Erasing and deactivating call forwarding %s..." %
- call_forwarding_type)
-
- ad.droid.telecomDialNumber(mmi % code)
-
- time.sleep(3)
- ad.send_keycode("ENTER")
- time.sleep(15)
-
- # To dismiss the pop-out dialog
- ad.send_keycode("BACK")
- time.sleep(5)
- ad.send_keycode("BACK")
-
- if run_get_call_forwarding_by_adb:
- res = get_call_forwarding_by_adb(
- log, ad, call_forwarding_type=call_forwarding_type)
- if res == "false" or res == "unknown":
- result = True
- break
- else:
- ad.log.error("Failed to erase and deactivate call forwarding by "
- "MMI code ##%s#." % code)
- retry = retry - 1
- time.sleep(30)
- else:
- result = True
- break
-
- if is_airplane_mode:
- if not toggle_airplane_mode(log, ad, True):
- ad.log.error("Failed to enable airplane mode again.")
- else:
- if is_wifi_on:
- ad.droid.wifiToggleState(True)
- if is_wfc_enabled:
- if not wait_for_wfc_enabled(
- log, ad,max_time=MAX_WAIT_TIME_WFC_ENABLED):
- ad.log.error("WFC is not enabled")
-
- return result
-
-def set_call_forwarding_by_mmi(
- log,
- ad,
- ad_forwarded,
- call_forwarding_type="unconditional",
- retry=2):
- """ Set up the forwarded number and enable call forwarding by MMI code.
-
- Args:
- log: log object
- ad: android object of the device forwarding the call (primary device)
- ad_forwarded: android object of the device receiving forwarded call.
- retry: times of retry if the erasure failed.
- call_forwarding_type:
- - "unconditional"
- - "busy"
- - "not_answered"
- - "not_reachable"
- Returns:
- True by successful erasure. Otherwise False.
- """
-
- res = get_call_forwarding_by_adb(log, ad,
- call_forwarding_type=call_forwarding_type)
- if res == "true":
- return True
-
- if ad.droid.connectivityCheckAirplaneMode():
- ad.log.warning("%s is now in airplane mode.", ad.serial)
- return False
-
- operator_name = get_operator_name(log, ad)
-
- code_dict = {
- "Verizon": {
- "unconditional": "72",
- "busy": "71",
- "not_answered": "71",
- "not_reachable": "72",
- "mmi": "*%s%s"
- },
- "Sprint": {
- "unconditional": "72",
- "busy": "74",
- "not_answered": "73",
- "not_reachable": "72",
- "mmi": "*%s%s"
- },
- "Far EasTone": {
- "unconditional": "142",
- "busy": "143",
- "not_answered": "144",
- "not_reachable": "144",
- "mmi": "*%s*%s"
- },
- 'Generic': {
- "unconditional": "21",
- "busy": "67",
- "not_answered": "61",
- "not_reachable": "62",
- "mmi": "*%s*%s#",
- "mmi_for_plus_sign": "*%s*"
- }
- }
-
- if operator_name in code_dict:
- code = code_dict[operator_name][call_forwarding_type]
- mmi = code_dict[operator_name]["mmi"]
- if "mmi_for_plus_sign" in code_dict[operator_name]:
- mmi_for_plus_sign = code_dict[operator_name]["mmi_for_plus_sign"]
- else:
- code = code_dict['Generic'][call_forwarding_type]
- mmi = code_dict['Generic']["mmi"]
- mmi_for_plus_sign = code_dict['Generic']["mmi_for_plus_sign"]
-
- while retry >= 0:
- if not erase_call_forwarding_by_mmi(
- log, ad, call_forwarding_type=call_forwarding_type):
- retry = retry - 1
- continue
-
- forwarded_number = ad_forwarded.telephony['subscription'][
- ad_forwarded.droid.subscriptionGetDefaultVoiceSubId()][
- 'phone_num']
- ad.log.info("Registering and activating call forwarding %s to %s..." %
- (call_forwarding_type, forwarded_number))
-
- (forwarded_number_no_prefix, _) = _phone_number_remove_prefix(
- forwarded_number)
-
- if operator_name == "Far EasTone":
- forwarded_number_no_prefix = "0" + forwarded_number_no_prefix
-
- run_get_call_forwarding_by_adb = 1
- if operator_name in NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST:
- run_get_call_forwarding_by_adb = 0
-
- _found_plus_sign = 0
- if re.search("^\+", forwarded_number):
- _found_plus_sign = 1
- forwarded_number.replace("+", "")
-
- if operator_name in code_dict:
- ad.droid.telecomDialNumber(mmi % (code, forwarded_number_no_prefix))
- else:
- if _found_plus_sign == 0:
- ad.droid.telecomDialNumber(mmi % (code, forwarded_number))
- else:
- ad.droid.telecomDialNumber(mmi_for_plus_sign % code)
- ad.send_keycode("PLUS")
-
- if "#" in mmi:
- dial_phone_number(ad, forwarded_number + "#")
- else:
- dial_phone_number(ad, forwarded_number)
-
- time.sleep(3)
- ad.send_keycode("ENTER")
- time.sleep(15)
-
- # To dismiss the pop-out dialog
- ad.send_keycode("BACK")
- time.sleep(5)
- ad.send_keycode("BACK")
-
- if not run_get_call_forwarding_by_adb:
- return True
-
- result = get_call_forwarding_by_adb(
- log, ad, call_forwarding_type=call_forwarding_type)
- if result == "false":
- retry = retry - 1
- elif result == "true":
- return True
- elif result == "unknown":
- return True
- else:
- retry = retry - 1
-
- if retry >= 0:
- ad.log.warning("Failed to register or activate call forwarding %s "
- "to %s. Retry after 15 seconds." % (call_forwarding_type,
- forwarded_number))
- time.sleep(15)
-
- ad.log.error("Failed to register or activate call forwarding %s to %s." %
- (call_forwarding_type, forwarded_number))
- return False
-
-
-def get_call_waiting_status(log, ad):
- """ (Todo) Get call waiting status (activated or deactivated) when there is
- any proper method available.
- """
- return True
-
-
-def set_call_waiting(log, ad, enable=1, retry=1):
- """ Activate/deactivate call waiting by dialing MMI code.
-
- Args:
- log: log object.
- ad: android object.
- enable: 1 for activation and 0 fir deactivation
- retry: times of retry if activation/deactivation fails
-
- Returns:
- True by successful activation/deactivation; otherwise False.
- """
- operator_name = get_operator_name(log, ad)
-
- if operator_name in ["Verizon", "Sprint"]:
- return True
-
- while retry >= 0:
- if enable:
- ad.log.info("Activating call waiting...")
- ad.droid.telecomDialNumber("*43#")
- else:
- ad.log.info("Deactivating call waiting...")
- ad.droid.telecomDialNumber("#43#")
-
- time.sleep(3)
- ad.send_keycode("ENTER")
- time.sleep(15)
-
- ad.send_keycode("BACK")
- time.sleep(5)
- ad.send_keycode("BACK")
-
- if get_call_waiting_status(log, ad):
- return True
- else:
- retry = retry + 1
-
- return False
-
-
def get_rx_tx_power_levels(log, ad):
""" Obtains Rx and Tx power levels from the MDS application.
@@ -9917,819 +3705,6 @@
return rx_power, tx_power
-def sms_in_collision_send_receive_verify(
- log,
- ad_rx,
- ad_rx2,
- ad_tx,
- ad_tx2,
- array_message,
- array_message2,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
- """Send 2 SMS', receive both SMS', and verify content and sender's number of
- each SMS.
-
- Send 2 SMS'. One from ad_tx to ad_rx and the other from ad_tx2 to ad_rx2.
- When ad_rx is identical to ad_rx2, the scenario of SMS' in collision can
- be tested.
- Verify both SMS' are sent, delivered and received.
- Verify received content and sender's number of each SMS is correct.
-
- Args:
- log: Log object.
- ad_tx: Sender's Android Device Object..
- ad_rx: Receiver's Android Device Object.
- ad_tx2: 2nd sender's Android Device Object..
- ad_rx2: 2nd receiver's Android Device Object.
- array_message: the array of message to send/receive from ad_tx to ad_rx
- array_message2: the array of message to send/receive from ad_tx2 to
- ad_rx2
- max_wait_time: Max time to wait for reception of SMS
- """
-
- rx_sub_id = get_outgoing_message_sub_id(ad_rx)
- rx2_sub_id = get_outgoing_message_sub_id(ad_rx2)
-
- _, tx_sub_id, _ = get_subid_on_same_network_of_host_ad(
- [ad_rx, ad_tx, ad_tx2],
- host_sub_id=rx_sub_id)
- set_subid_for_message(ad_tx, tx_sub_id)
-
- _, _, tx2_sub_id = get_subid_on_same_network_of_host_ad(
- [ad_rx2, ad_tx, ad_tx2],
- host_sub_id=rx2_sub_id)
- set_subid_for_message(ad_tx2, tx2_sub_id)
-
- if not sms_in_collision_send_receive_verify_for_subscription(
- log,
- ad_tx,
- ad_tx2,
- ad_rx,
- ad_rx2,
- tx_sub_id,
- tx2_sub_id,
- rx_sub_id,
- rx_sub_id,
- array_message,
- array_message2,
- max_wait_time):
- log_messaging_screen_shot(
- ad_rx, test_name="sms rx subid: %s" % rx_sub_id)
- log_messaging_screen_shot(
- ad_rx2, test_name="sms rx2 subid: %s" % rx2_sub_id)
- log_messaging_screen_shot(
- ad_tx, test_name="sms tx subid: %s" % tx_sub_id)
- log_messaging_screen_shot(
- ad_tx2, test_name="sms tx subid: %s" % tx2_sub_id)
- return False
- return True
-
-
-def sms_in_collision_send_receive_verify_for_subscription(
- log,
- ad_tx,
- ad_tx2,
- ad_rx,
- ad_rx2,
- subid_tx,
- subid_tx2,
- subid_rx,
- subid_rx2,
- array_message,
- array_message2,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
- """Send 2 SMS', receive both SMS', and verify content and sender's number of
- each SMS.
-
- Send 2 SMS'. One from ad_tx to ad_rx and the other from ad_tx2 to ad_rx2.
- When ad_rx is identical to ad_rx2, the scenario of SMS' in collision can
- be tested.
- Verify both SMS' are sent, delivered and received.
- Verify received content and sender's number of each SMS is correct.
-
- Args:
- log: Log object.
- ad_tx: Sender's Android Device Object..
- ad_rx: Receiver's Android Device Object.
- ad_tx2: 2nd sender's Android Device Object..
- ad_rx2: 2nd receiver's Android Device Object.
- subid_tx: Sub ID of ad_tx as default Sub ID for outgoing SMS
- subid_tx2: Sub ID of ad_tx2 as default Sub ID for outgoing SMS
- subid_rx: Sub ID of ad_rx as default Sub ID for incoming SMS
- subid_rx2: Sub ID of ad_rx2 as default Sub ID for incoming SMS
- array_message: the array of message to send/receive from ad_tx to ad_rx
- array_message2: the array of message to send/receive from ad_tx2 to
- ad_rx2
- max_wait_time: Max time to wait for reception of SMS
- """
-
- phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
- phonenumber_tx2 = ad_tx2.telephony['subscription'][subid_tx2]['phone_num']
- phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
- phonenumber_rx2 = ad_rx2.telephony['subscription'][subid_rx2]['phone_num']
-
- for ad in (ad_tx, ad_tx2, ad_rx, ad_rx2):
- ad.send_keycode("BACK")
- 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()
- else:
- ad.messaging_ed.clear_all_events()
- ad.messaging_droid.logI(
- "Start sms_send_receive_verify_for_subscription test")
- except Exception:
- ad.log.info("Create new sl4a session for messaging")
- ad.messaging_droid, ad.messaging_ed = ad.get_droid()
- ad.messaging_ed.start()
-
- for text, text2 in zip(array_message, array_message2):
- length = len(text)
- length2 = len(text2)
- ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
- phonenumber_tx, phonenumber_rx, length, text)
- ad_tx2.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
- phonenumber_tx2, phonenumber_rx2, length2, text2)
-
- try:
- ad_rx.messaging_ed.clear_events(EventSmsReceived)
- ad_rx2.messaging_ed.clear_events(EventSmsReceived)
- ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
- ad_tx.messaging_ed.clear_events(EventSmsSentFailure)
- ad_tx2.messaging_ed.clear_events(EventSmsSentSuccess)
- ad_tx2.messaging_ed.clear_events(EventSmsSentFailure)
- ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
- if ad_rx2 != ad_rx:
- ad_rx2.messaging_droid.smsStartTrackingIncomingSmsMessage()
- time.sleep(1)
- ad_tx.messaging_droid.logI("Sending SMS of length %s" % length)
- ad_tx2.messaging_droid.logI("Sending SMS of length %s" % length2)
- ad_rx.messaging_droid.logI(
- "Expecting SMS of length %s from %s" % (length, ad_tx.serial))
- ad_rx2.messaging_droid.logI(
- "Expecting SMS of length %s from %s" % (length2, ad_tx2.serial))
-
- tasks = [
- (ad_tx.messaging_droid.smsSendTextMessage,
- (phonenumber_rx, text, True)),
- (ad_tx2.messaging_droid.smsSendTextMessage,
- (phonenumber_rx2, text2, True))]
- multithread_func(log, tasks)
- try:
- tasks = [
- (ad_tx.messaging_ed.pop_events, ("(%s|%s|%s|%s)" % (
- EventSmsSentSuccess,
- EventSmsSentFailure,
- EventSmsDeliverSuccess,
- EventSmsDeliverFailure), max_wait_time)),
- (ad_tx2.messaging_ed.pop_events, ("(%s|%s|%s|%s)" % (
- EventSmsSentSuccess,
- EventSmsSentFailure,
- EventSmsDeliverSuccess,
- EventSmsDeliverFailure), max_wait_time))
- ]
- results = run_multithread_func(log, tasks)
- res = True
- _ad = ad_tx
- for ad, events in [(ad_tx, results[0]),(ad_tx2, results[1])]:
- _ad = ad
- for event in events:
- ad.log.info("Got event %s", event["name"])
- if event["name"] == EventSmsSentFailure or \
- event["name"] == EventSmsDeliverFailure:
- if event.get("data") and event["data"].get("Reason"):
- ad.log.error("%s with reason: %s",
- event["name"],
- event["data"]["Reason"])
- res = False
- elif event["name"] == EventSmsSentSuccess or \
- event["name"] == EventSmsDeliverSuccess:
- break
- if not res:
- return False
- except Empty:
- _ad.log.error("No %s or %s event for SMS of length %s.",
- EventSmsSentSuccess, EventSmsSentFailure,
- length)
- return False
- if ad_rx == ad_rx2:
- if not wait_for_matching_mt_sms_in_collision(
- log,
- ad_rx,
- phonenumber_tx,
- phonenumber_tx2,
- text,
- text2,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
-
- ad_rx.log.error(
- "No matching received SMS of length %s from %s.",
- length,
- ad_rx.serial)
- return False
- else:
- if not wait_for_matching_mt_sms_in_collision_with_mo_sms(
- log,
- ad_rx,
- ad_rx2,
- phonenumber_tx,
- phonenumber_tx2,
- text,
- text2,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
- return False
- except Exception as e:
- log.error("Exception error %s", e)
- raise
- finally:
- ad_rx.messaging_droid.smsStopTrackingIncomingSmsMessage()
- ad_rx2.messaging_droid.smsStopTrackingIncomingSmsMessage()
- return True
-
-
-def sms_rx_power_off_multiple_send_receive_verify(
- log,
- ad_rx,
- ad_tx,
- ad_tx2,
- array_message_length,
- array_message2_length,
- num_array_message,
- num_array_message2,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
-
- rx_sub_id = get_outgoing_message_sub_id(ad_rx)
-
- _, tx_sub_id, _ = get_subid_on_same_network_of_host_ad(
- [ad_rx, ad_tx, ad_tx2],
- host_sub_id=rx_sub_id)
- set_subid_for_message(ad_tx, tx_sub_id)
-
- _, _, tx2_sub_id = get_subid_on_same_network_of_host_ad(
- [ad_rx, ad_tx, ad_tx2],
- host_sub_id=rx_sub_id)
- set_subid_for_message(ad_tx2, tx2_sub_id)
-
- if not sms_rx_power_off_multiple_send_receive_verify_for_subscription(
- log,
- ad_tx,
- ad_tx2,
- ad_rx,
- tx_sub_id,
- tx2_sub_id,
- rx_sub_id,
- rx_sub_id,
- array_message_length,
- array_message2_length,
- num_array_message,
- num_array_message2):
- log_messaging_screen_shot(
- ad_rx, test_name="sms rx subid: %s" % rx_sub_id)
- log_messaging_screen_shot(
- ad_tx, test_name="sms tx subid: %s" % tx_sub_id)
- log_messaging_screen_shot(
- ad_tx2, test_name="sms tx subid: %s" % tx2_sub_id)
- return False
- return True
-
-
-def sms_rx_power_off_multiple_send_receive_verify_for_subscription(
- log,
- ad_tx,
- ad_tx2,
- ad_rx,
- subid_tx,
- subid_tx2,
- subid_rx,
- subid_rx2,
- array_message_length,
- array_message2_length,
- num_array_message,
- num_array_message2,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
-
- phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
- phonenumber_tx2 = ad_tx2.telephony['subscription'][subid_tx2]['phone_num']
- phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
- phonenumber_rx2 = ad_rx.telephony['subscription'][subid_rx2]['phone_num']
-
- if not toggle_airplane_mode(log, ad_rx, True):
- ad_rx.log.error("Failed to enable Airplane Mode")
- return False
- ad_rx.stop_services()
- ad_rx.log.info("Rebooting......")
- ad_rx.adb.reboot()
-
- message_dict = {phonenumber_tx: [], phonenumber_tx2: []}
- for index in range(max(num_array_message, num_array_message2)):
- array_message = [rand_ascii_str(array_message_length)]
- array_message2 = [rand_ascii_str(array_message2_length)]
- for text, text2 in zip(array_message, array_message2):
- message_dict[phonenumber_tx].append(text)
- message_dict[phonenumber_tx2].append(text2)
- length = len(text)
- length2 = len(text2)
-
- ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
- phonenumber_tx, phonenumber_rx, length, text)
- ad_tx2.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
- phonenumber_tx2, phonenumber_rx2, length2, text2)
-
- try:
- for ad in (ad_tx, ad_tx2):
- ad.send_keycode("BACK")
- 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()
- else:
- ad.messaging_ed.clear_all_events()
- ad.messaging_droid.logI(
- "Start sms_send_receive_verify_for_subscription"
- " test")
- except Exception:
- ad.log.info("Create new sl4a session for messaging")
- ad.messaging_droid, ad.messaging_ed = ad.get_droid()
- ad.messaging_ed.start()
-
- ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
- ad_tx.messaging_ed.clear_events(EventSmsSentFailure)
- ad_tx2.messaging_ed.clear_events(EventSmsSentSuccess)
- ad_tx2.messaging_ed.clear_events(EventSmsSentFailure)
-
- if index < num_array_message and index < num_array_message2:
- ad_tx.messaging_droid.logI(
- "Sending SMS of length %s" % length)
- ad_tx2.messaging_droid.logI(
- "Sending SMS of length %s" % length2)
- tasks = [
- (ad_tx.messaging_droid.smsSendTextMessage,
- (phonenumber_rx, text, True)),
- (ad_tx2.messaging_droid.smsSendTextMessage,
- (phonenumber_rx2, text2, True))]
- multithread_func(log, tasks)
- else:
- if index < num_array_message:
- ad_tx.messaging_droid.logI(
- "Sending SMS of length %s" % length)
- ad_tx.messaging_droid.smsSendTextMessage(
- phonenumber_rx, text, True)
- if index < num_array_message2:
- ad_tx2.messaging_droid.logI(
- "Sending SMS of length %s" % length2)
- ad_tx2.messaging_droid.smsSendTextMessage(
- phonenumber_rx2, text2, True)
-
- try:
- if index < num_array_message and index < num_array_message2:
- tasks = [
- (ad_tx.messaging_ed.pop_events, ("(%s|%s|%s|%s)" % (
- EventSmsSentSuccess,
- EventSmsSentFailure,
- EventSmsDeliverSuccess,
- EventSmsDeliverFailure),
- max_wait_time)),
- (ad_tx2.messaging_ed.pop_events, ("(%s|%s|%s|%s)" % (
- EventSmsSentSuccess,
- EventSmsSentFailure,
- EventSmsDeliverSuccess,
- EventSmsDeliverFailure),
- max_wait_time))
- ]
- results = run_multithread_func(log, tasks)
- res = True
- _ad = ad_tx
- for ad, events in [
- (ad_tx, results[0]), (ad_tx2, results[1])]:
- _ad = ad
- for event in events:
- ad.log.info("Got event %s", event["name"])
- if event["name"] == EventSmsSentFailure or \
- event["name"] == EventSmsDeliverFailure:
- if event.get("data") and \
- event["data"].get("Reason"):
- ad.log.error("%s with reason: %s",
- event["name"],
- event["data"]["Reason"])
- res = False
- elif event["name"] == EventSmsSentSuccess or \
- event["name"] == EventSmsDeliverSuccess:
- break
- if not res:
- return False
- else:
- if index < num_array_message:
- result = ad_tx.messaging_ed.pop_events(
- "(%s|%s|%s|%s)" % (
- EventSmsSentSuccess,
- EventSmsSentFailure,
- EventSmsDeliverSuccess,
- EventSmsDeliverFailure),
- max_wait_time)
- res = True
- _ad = ad_tx
- for ad, events in [(ad_tx, result)]:
- _ad = ad
- for event in events:
- ad.log.info("Got event %s", event["name"])
- if event["name"] == EventSmsSentFailure or \
- event["name"] == EventSmsDeliverFailure:
- if event.get("data") and \
- event["data"].get("Reason"):
- ad.log.error(
- "%s with reason: %s",
- event["name"],
- event["data"]["Reason"])
- res = False
- elif event["name"] == EventSmsSentSuccess \
- or event["name"] == EventSmsDeliverSuccess:
- break
- if not res:
- return False
- if index < num_array_message2:
- result = ad_tx2.messaging_ed.pop_events(
- "(%s|%s|%s|%s)" % (
- EventSmsSentSuccess,
- EventSmsSentFailure,
- EventSmsDeliverSuccess,
- EventSmsDeliverFailure),
- max_wait_time)
- res = True
- _ad = ad_tx2
- for ad, events in [(ad_tx2, result)]:
- _ad = ad
- for event in events:
- ad.log.info("Got event %s", event["name"])
- if event["name"] == EventSmsSentFailure or \
- event["name"] == EventSmsDeliverFailure:
- if event.get("data") and \
- event["data"].get("Reason"):
- ad.log.error(
- "%s with reason: %s",
- event["name"],
- event["data"]["Reason"])
- res = False
- elif event["name"] == EventSmsSentSuccess \
- or event["name"] == EventSmsDeliverSuccess:
- break
- if not res:
- return False
-
-
- except Empty:
- _ad.log.error("No %s or %s event for SMS of length %s.",
- EventSmsSentSuccess, EventSmsSentFailure,
- length)
- return False
-
- except Exception as e:
- log.error("Exception error %s", e)
- raise
-
- ad_rx.wait_for_boot_completion()
- ad_rx.root_adb()
- ad_rx.start_services(skip_setup_wizard=False)
-
- output = ad_rx.adb.logcat("-t 1")
- match = re.search(r"\d+-\d+\s\d+:\d+:\d+.\d+", output)
- if match:
- ad_rx.test_log_begin_time = match.group(0)
-
- ad_rx.messaging_droid, ad_rx.messaging_ed = ad_rx.get_droid()
- ad_rx.messaging_ed.start()
- ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
- time.sleep(1) #sleep 100ms after starting event tracking
-
- if not toggle_airplane_mode(log, ad_rx, False):
- ad_rx.log.error("Failed to disable Airplane Mode")
- return False
-
- res = True
- try:
- if not wait_for_matching_multiple_sms(log,
- ad_rx,
- phonenumber_tx,
- phonenumber_tx2,
- messages=message_dict,
- max_wait_time=max_wait_time):
- res = False
- except Exception as e:
- log.error("Exception error %s", e)
- raise
- finally:
- ad_rx.messaging_droid.smsStopTrackingIncomingSmsMessage()
-
- return res
-
-
-def wait_for_matching_mt_sms_in_collision(log,
- ad_rx,
- phonenumber_tx,
- phonenumber_tx2,
- text,
- text2,
- allow_multi_part_long_sms=True,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
-
- if not allow_multi_part_long_sms:
- try:
- ad_rx.messaging_ed.wait_for_event(
- EventSmsReceived,
- is_sms_in_collision_match,
- max_wait_time,
- phonenumber_tx,
- phonenumber_tx2,
- text,
- text2)
- ad_rx.log.info("Got event %s", EventSmsReceived)
- return True
- except Empty:
- ad_rx.log.error("No matched SMS received event.")
- return False
- else:
- try:
- received_sms = ''
- received_sms2 = ''
- remaining_text = text
- remaining_text2 = text2
- while (remaining_text != '' or remaining_text2 != ''):
- event = ad_rx.messaging_ed.wait_for_event(
- EventSmsReceived,
- is_sms_in_collision_partial_match,
- max_wait_time,
- phonenumber_tx,
- phonenumber_tx2,
- remaining_text,
- remaining_text2)
- event_text = event['data']['Text'].split(")")[-1].strip()
- event_text_length = len(event_text)
-
- if event_text in remaining_text:
- ad_rx.log.info("Got event %s of text length %s from %s",
- EventSmsReceived, event_text_length,
- phonenumber_tx)
- remaining_text = remaining_text[event_text_length:]
- received_sms += event_text
- elif event_text in remaining_text2:
- ad_rx.log.info("Got event %s of text length %s from %s",
- EventSmsReceived, event_text_length,
- phonenumber_tx2)
- remaining_text2 = remaining_text2[event_text_length:]
- received_sms2 += event_text
-
- ad_rx.log.info("Received SMS of length %s", len(received_sms))
- ad_rx.log.info("Received SMS of length %s", len(received_sms2))
- return True
- except Empty:
- ad_rx.log.error(
- "Missing SMS received event.")
- if received_sms != '':
- ad_rx.log.error(
- "Only received partial matched SMS of length %s from %s",
- len(received_sms), phonenumber_tx)
- if received_sms2 != '':
- ad_rx.log.error(
- "Only received partial matched SMS of length %s from %s",
- len(received_sms2), phonenumber_tx2)
- return False
-
-
-def wait_for_matching_mt_sms_in_collision_with_mo_sms(log,
- ad_rx,
- ad_rx2,
- phonenumber_tx,
- phonenumber_tx2,
- text,
- text2,
- allow_multi_part_long_sms=True,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
-
- if not allow_multi_part_long_sms:
- result = True
- try:
- ad_rx.messaging_ed.wait_for_call_offhook_event(
- EventSmsReceived,
- is_sms_match,
- max_wait_time,
- phonenumber_tx,
- text)
- ad_rx.log.info("Got event %s", EventSmsReceived)
- except Empty:
- ad_rx.log.error("No matched SMS received event.")
- result = False
-
- try:
- ad_rx2.messaging_ed.wait_for_call_offhook_event(
- EventSmsReceived,
- is_sms_match,
- max_wait_time,
- phonenumber_tx2,
- text2)
- ad_rx2.log.info("Got event %s", EventSmsReceived)
- except Empty:
- ad_rx2.log.error("No matched SMS received event.")
- result = False
-
- return result
- else:
- result = True
- try:
- received_sms = ''
- remaining_text = text
- while remaining_text != '':
- event = ad_rx.messaging_ed.wait_for_event(
- EventSmsReceived, is_sms_partial_match, max_wait_time,
- phonenumber_tx, remaining_text)
- event_text = event['data']['Text'].split(")")[-1].strip()
- event_text_length = len(event_text)
-
- if event_text in remaining_text:
- ad_rx.log.info("Got event %s of text length %s from %s",
- EventSmsReceived, event_text_length,
- phonenumber_tx)
- remaining_text = remaining_text[event_text_length:]
- received_sms += event_text
-
- ad_rx.log.info("Received SMS of length %s", len(received_sms))
- except Empty:
- ad_rx.log.error(
- "Missing SMS received event.")
- if received_sms != '':
- ad_rx.log.error(
- "Only received partial matched SMS of length %s from %s",
- len(received_sms), phonenumber_tx)
- result = False
-
- try:
- received_sms2 = ''
- remaining_text2 = text2
- while remaining_text2 != '':
- event2 = ad_rx2.messaging_ed.wait_for_event(
- EventSmsReceived, is_sms_partial_match, max_wait_time,
- phonenumber_tx2, remaining_text2)
- event_text2 = event2['data']['Text'].split(")")[-1].strip()
- event_text_length2 = len(event_text2)
-
- if event_text2 in remaining_text2:
- ad_rx2.log.info("Got event %s of text length %s from %s",
- EventSmsReceived, event_text_length2,
- phonenumber_tx2)
- remaining_text2 = remaining_text2[event_text_length2:]
- received_sms2 += event_text2
-
- ad_rx2.log.info("Received SMS of length %s", len(received_sms2))
- except Empty:
- ad_rx2.log.error(
- "Missing SMS received event.")
- if received_sms2 != '':
- ad_rx2.log.error(
- "Only received partial matched SMS of length %s from %s",
- len(received_sms2), phonenumber_tx2)
- result = False
-
- return result
-
-
-def wait_for_matching_multiple_sms(log,
- ad_rx,
- phonenumber_tx,
- phonenumber_tx2,
- messages={},
- allow_multi_part_long_sms=True,
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
-
- if not allow_multi_part_long_sms:
- try:
- ad_rx.messaging_ed.wait_for_event(
- EventSmsReceived,
- is_sms_match_among_multiple_sms,
- max_wait_time,
- phonenumber_tx,
- phonenumber_tx2,
- messages[phonenumber_tx],
- messages[phonenumber_tx2])
- ad_rx.log.info("Got event %s", EventSmsReceived)
- return True
- except Empty:
- ad_rx.log.error("No matched SMS received event.")
- return False
- else:
- all_msgs = []
- for tx, msgs in messages.items():
- for msg in msgs:
- all_msgs.append([tx, msg, msg, ''])
-
- all_msgs_copy = all_msgs.copy()
-
- try:
- while (all_msgs != []):
- event = ad_rx.messaging_ed.wait_for_event(
- EventSmsReceived,
- is_sms_partial_match_among_multiple_sms,
- max_wait_time,
- phonenumber_tx,
- phonenumber_tx2,
- messages[phonenumber_tx],
- messages[phonenumber_tx2])
- event_text = event['data']['Text'].split(")")[-1].strip()
- event_text_length = len(event_text)
-
- for msg in all_msgs_copy:
- if event_text in msg[2]:
- ad_rx.log.info("Got event %s of text length %s from %s",
- EventSmsReceived, event_text_length,
- msg[0])
- msg[2] = msg[2][event_text_length:]
- msg[3] += event_text
-
- if msg[2] == "":
- all_msgs.remove(msg)
-
- ad_rx.log.info("Received all SMS' sent when power-off.")
- except Empty:
- ad_rx.log.error(
- "Missing SMS received event.")
-
- for msg in all_msgs_copy:
- if msg[3] != '':
- ad_rx.log.error(
- "Only received partial matched SMS of length %s from %s",
- len(msg[3]), msg[0])
- return False
-
- return True
-
-
-def is_sms_in_collision_match(
- event, phonenumber_tx, phonenumber_tx2, text, text2):
- event_text = event['data']['Text'].strip()
- if event_text.startswith("("):
- event_text = event_text.split(")")[-1]
-
- for phonenumber, txt in [[phonenumber_tx, text], [phonenumber_tx2, text2]]:
- if check_phone_number_match(
- event['data']['Sender'], phonenumber) and txt.startswith(event_text):
- return True
- return False
-
-
-def is_sms_in_collision_partial_match(
- event, phonenumber_tx, phonenumber_tx2, text, text2):
- for phonenumber, txt in [[phonenumber_tx, text], [phonenumber_tx2, text2]]:
- if check_phone_number_match(
- event['data']['Sender'], phonenumber) and \
- event['data']['Text'].strip() == txt:
- return True
- return False
-
-
-def is_sms_match_among_multiple_sms(
- event, phonenumber_tx, phonenumber_tx2, texts=[], texts2=[]):
- for txt in texts:
- if check_phone_number_match(
- event['data']['Sender'], phonenumber_tx) and \
- event['data']['Text'].strip() == txt:
- return True
-
- for txt in texts2:
- if check_phone_number_match(
- event['data']['Sender'], phonenumber_tx2) and \
- event['data']['Text'].strip() == txt:
- return True
-
- return False
-
-
-def is_sms_partial_match_among_multiple_sms(
- event, phonenumber_tx, phonenumber_tx2, texts=[], texts2=[]):
- event_text = event['data']['Text'].strip()
- if event_text.startswith("("):
- event_text = event_text.split(")")[-1]
-
- for txt in texts:
- if check_phone_number_match(
- event['data']['Sender'], phonenumber_tx) and \
- txt.startswith(event_text):
- return True
-
- for txt in texts2:
- if check_phone_number_match(
- event['data']['Sender'], phonenumber_tx2) and \
- txt.startswith(event_text):
- return True
-
- return False
-
-
def set_time_sync_from_network(ad, action):
if (action == 'enable'):
ad.log.info('Enabling sync time from network.')
@@ -10767,327 +3742,6 @@
return get_value
-def wait_for_sending_sms(ad_tx, max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
- try:
- events = ad_tx.messaging_ed.pop_events(
- "(%s|%s|%s|%s)" %
- (EventSmsSentSuccess, EventSmsSentFailure,
- EventSmsDeliverSuccess,
- EventSmsDeliverFailure), max_wait_time)
- for event in events:
- ad_tx.log.info("Got event %s", event["name"])
- if event["name"] == EventSmsSentFailure or \
- event["name"] == EventSmsDeliverFailure:
- if event.get("data") and event["data"].get("Reason"):
- ad_tx.log.error("%s with reason: %s",
- event["name"],
- event["data"]["Reason"])
- return False
- elif event["name"] == EventSmsSentSuccess or \
- event["name"] == EventSmsDeliverSuccess:
- return True
- except Empty:
- ad_tx.log.error("No %s or %s event for SMS.",
- EventSmsSentSuccess, EventSmsSentFailure)
- return False
-
-
-def wait_for_call_end(
- log,
- ad_caller,
- ad_callee,
- ad_hangup,
- verify_caller_func,
- verify_callee_func,
- call_begin_time,
- check_interval=5,
- tel_result_wrapper=TelResultWrapper(CallResult('SUCCESS')),
- wait_time_in_call=WAIT_TIME_IN_CALL):
- elapsed_time = 0
- while (elapsed_time < wait_time_in_call):
- check_interval = min(check_interval, wait_time_in_call - elapsed_time)
- time.sleep(check_interval)
- elapsed_time += check_interval
- time_message = "at <%s>/<%s> second." % (elapsed_time, wait_time_in_call)
- 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, voice in RAT %s",
- call_func.__name__,
- time_message,
- ad.droid.telephonyGetCurrentVoiceNetworkType())
- tel_result_wrapper.result_value = CallResult(
- 'CALL_DROP_OR_WRONG_STATE_AFTER_CONNECTED')
- 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)
- tel_result_wrapper.result_value = CallResult(
- 'AUDIO_STATE_NOT_INCALL_AFTER_CONNECTED')
- if not tel_result_wrapper:
- return tel_result_wrapper
-
- if ad_hangup:
- if not hangup_call(log, ad_hangup):
- ad_hangup.log.info("Failed to hang up the call")
- tel_result_wrapper.result_value = CallResult('CALL_HANGUP_FAIL')
-
- if not tel_result_wrapper:
- for ad in (ad_caller, ad_callee):
- last_call_drop_reason(ad, call_begin_time)
- try:
- if ad.droid.telecomIsInCall():
- ad.log.info("In call. End now.")
- ad.droid.telecomEndCall()
- except Exception as e:
- log.error(str(e))
- if ad_hangup or not tel_result_wrapper:
- for ad in (ad_caller, ad_callee):
- if not wait_for_call_id_clearing(ad, getattr(ad, "caller_ids", [])):
- tel_result_wrapper.result_value = CallResult(
- 'CALL_ID_CLEANUP_FAIL')
-
- return tel_result_wrapper
-
-
-def voice_call_in_collision_with_mt_sms_msim(
- log,
- ad_primary,
- ad_sms,
- ad_voice,
- sms_subid_ad_primary,
- sms_subid_ad_sms,
- voice_subid_ad_primary,
- voice_subid_ad_voice,
- array_message,
- ad_hangup=None,
- verify_caller_func=None,
- verify_callee_func=None,
- call_direction="mo",
- wait_time_in_call=WAIT_TIME_IN_CALL,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- dialing_number_length=None,
- video_state=None):
-
- ad_tx = ad_sms
- ad_rx = ad_primary
- subid_tx = sms_subid_ad_sms
- subid_rx = sms_subid_ad_primary
-
- if call_direction == "mo":
- ad_caller = ad_primary
- ad_callee = ad_voice
- subid_caller = voice_subid_ad_primary
- subid_callee = voice_subid_ad_voice
- elif call_direction == "mt":
- ad_callee = ad_primary
- ad_caller = ad_voice
- subid_callee = voice_subid_ad_primary
- subid_caller = voice_subid_ad_voice
-
-
- phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
- phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
-
- tel_result_wrapper = TelResultWrapper(CallResult('SUCCESS'))
-
- for ad in (ad_tx, ad_rx):
- ad.send_keycode("BACK")
- 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()
- else:
- ad.messaging_ed.clear_all_events()
- except Exception:
- ad.log.info("Create new sl4a session for messaging")
- ad.messaging_droid, ad.messaging_ed = ad.get_droid()
- ad.messaging_ed.start()
-
- if not verify_caller_func:
- verify_caller_func = is_phone_in_call
- if not verify_callee_func:
- verify_callee_func = is_phone_in_call
-
- caller_number = ad_caller.telephony['subscription'][subid_caller][
- 'phone_num']
- callee_number = ad_callee.telephony['subscription'][subid_callee][
- 'phone_num']
- if dialing_number_length:
- skip_test = False
- trunc_position = 0 - int(dialing_number_length)
- try:
- caller_area_code = caller_number[:trunc_position]
- callee_area_code = callee_number[:trunc_position]
- callee_dial_number = callee_number[trunc_position:]
- except:
- skip_test = True
- if caller_area_code != callee_area_code:
- skip_test = True
- if skip_test:
- msg = "Cannot make call from %s to %s by %s digits" % (
- caller_number, callee_number, dialing_number_length)
- ad_caller.log.info(msg)
- raise signals.TestSkip(msg)
- else:
- callee_number = callee_dial_number
-
- msg = "Call from %s to %s" % (caller_number, callee_number)
- if video_state:
- msg = "Video %s" % msg
- video = True
- else:
- video = False
- if ad_hangup:
- msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
- ad_caller.log.info(msg)
-
- for ad in (ad_caller, ad_callee):
- call_ids = ad.droid.telecomCallGetCallIds()
- setattr(ad, "call_ids", call_ids)
- if call_ids:
- ad.log.info("Pre-exist CallId %s before making call", call_ids)
-
- ad_caller.ed.clear_events(EventCallStateChanged)
- call_begin_time = get_device_epoch_time(ad)
- ad_caller.droid.telephonyStartTrackingCallStateForSubscription(subid_caller)
-
- for text in array_message:
- length = len(text)
- ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
- phonenumber_tx, phonenumber_rx, length, text)
- try:
- ad_rx.messaging_ed.clear_events(EventSmsReceived)
- ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
- ad_tx.messaging_ed.clear_events(EventSmsSentFailure)
- ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
- time.sleep(1) #sleep 100ms after starting event tracking
- ad_tx.messaging_droid.logI("Sending SMS of length %s" % length)
- ad_rx.messaging_droid.logI("Expecting SMS of length %s" % length)
- ad_caller.log.info("Make a phone call to %s", callee_number)
-
- tasks = [
- (ad_tx.messaging_droid.smsSendTextMessage,
- (phonenumber_rx, text, True)),
- (ad_caller.droid.telecomCallNumber,
- (callee_number, video))]
-
- run_multithread_func(log, tasks)
-
- try:
- # Verify OFFHOOK state
- if not wait_for_call_offhook_for_subscription(
- log,
- ad_caller,
- subid_caller,
- event_tracking_started=True):
- ad_caller.log.info(
- "sub_id %s not in call offhook state", subid_caller)
- last_call_drop_reason(ad_caller, begin_time=call_begin_time)
-
- ad_caller.log.error("Initiate call failed.")
- tel_result_wrapper.result_value = CallResult(
- 'INITIATE_FAILED')
- return tel_result_wrapper
- else:
- ad_caller.log.info("Caller initate call successfully")
- finally:
- ad_caller.droid.telephonyStopTrackingCallStateChangeForSubscription(
- subid_caller)
- if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
- ad_caller.droid.telecomShowInCallScreen()
- elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
- ad_caller.droid.showHomeScreen()
-
- if not wait_and_answer_call_for_subscription(
- log,
- ad_callee,
- subid_callee,
- incoming_number=caller_number,
- caller=ad_caller,
- incall_ui_display=incall_ui_display,
- video_state=video_state):
- ad_callee.log.error("Answer call fail.")
- tel_result_wrapper.result_value = CallResult(
- 'NO_RING_EVENT_OR_ANSWER_FAILED')
- return tel_result_wrapper
- else:
- ad_callee.log.info("Callee answered the call successfully")
-
- for ad, call_func in zip([ad_caller, ad_callee],
- [verify_caller_func, verify_callee_func]):
- call_ids = ad.droid.telecomCallGetCallIds()
- new_call_ids = set(call_ids) - set(ad.call_ids)
- if not new_call_ids:
- ad.log.error(
- "No new call ids are found after call establishment")
- ad.log.error("telecomCallGetCallIds returns %s",
- ad.droid.telecomCallGetCallIds())
- tel_result_wrapper.result_value = CallResult(
- 'NO_CALL_ID_FOUND')
- for new_call_id in new_call_ids:
- if not wait_for_in_call_active(ad, call_id=new_call_id):
- tel_result_wrapper.result_value = CallResult(
- 'CALL_STATE_NOT_ACTIVE_DURING_ESTABLISHMENT')
- else:
- ad.log.info(
- "callProperties = %s",
- ad.droid.telecomCallGetProperties(new_call_id))
-
- if not ad.droid.telecomCallGetAudioState():
- ad.log.error("Audio is not in call state")
- tel_result_wrapper.result_value = CallResult(
- 'AUDIO_STATE_NOT_INCALL_DURING_ESTABLISHMENT')
-
- if call_func(log, ad):
- ad.log.info("Call is in %s state", call_func.__name__)
- else:
- ad.log.error("Call is not in %s state, voice in RAT %s",
- call_func.__name__,
- ad.droid.telephonyGetCurrentVoiceNetworkType())
- tel_result_wrapper.result_value = CallResult(
- 'CALL_DROP_OR_WRONG_STATE_DURING_ESTABLISHMENT')
- if not tel_result_wrapper:
- return tel_result_wrapper
-
- if not wait_for_sending_sms(
- ad_tx,
- max_wait_time=MAX_WAIT_TIME_SMS_SENT_SUCCESS_IN_COLLISION):
- return False
-
- tasks = [
- (wait_for_matching_sms,
- (log, ad_rx, phonenumber_tx, text,
- MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION, True)),
- (wait_for_call_end,
- (log, ad_caller, ad_callee, ad_hangup, verify_caller_func,
- verify_callee_func, call_begin_time, 5, tel_result_wrapper,
- WAIT_TIME_IN_CALL))]
-
- results = run_multithread_func(log, tasks)
-
- if not results[0]:
- ad_rx.log.error("No matching received SMS of length %s.",
- length)
- return False
-
- tel_result_wrapper = results[1]
-
- except Exception as e:
- log.error("Exception error %s", e)
- raise
- finally:
- ad_rx.messaging_droid.smsStopTrackingIncomingSmsMessage()
-
- return tel_result_wrapper
-
-
def change_voice_subid_temporarily(ad, sub_id, state_check_func, params=None):
result = False
voice_sub_id_changed = False
@@ -11109,107 +3763,6 @@
return result
-def wait_for_network_service(
- log,
- ad,
- wifi_connected=False,
- wifi_ssid=None,
- ims_reg=True,
- recover=False,
- retry=3):
- """ Wait for multiple network services in sequence, including:
- - service state
- - network connection
- - wifi connection
- - cellular data
- - internet connection
- - IMS registration
-
- The mechanism (cycling airplane mode) to recover network services is
- also provided if any service is not available.
-
- Args:
- log: log object
- ad: android device
- wifi_connected: True if wifi should be connected. Otherwise False.
- ims_reg: True if IMS should be registered. Otherwise False.
- recover: True if the mechanism (cycling airplane mode) to recover
- network services should be enabled (by default False).
- retry: times of retry.
- """
- times = 1
- while times <= retry:
- while True:
- if not wait_for_state(
- get_service_state_by_adb,
- "IN_SERVICE",
- MAX_WAIT_TIME_FOR_STATE_CHANGE,
- WAIT_TIME_BETWEEN_STATE_CHECK,
- log,
- ad):
- ad.log.error("Current service state is not 'IN_SERVICE'.")
- break
-
- if not wait_for_state(
- ad.droid.connectivityNetworkIsConnected,
- True,
- MAX_WAIT_TIME_FOR_STATE_CHANGE,
- WAIT_TIME_BETWEEN_STATE_CHECK):
- ad.log.error("Network is NOT connected!")
- break
-
- if wifi_connected and wifi_ssid:
- if not wait_for_state(
- check_is_wifi_connected,
- True,
- MAX_WAIT_TIME_FOR_STATE_CHANGE,
- WAIT_TIME_BETWEEN_STATE_CHECK,
- log,
- ad,
- wifi_ssid):
- ad.log.error("Failed to connect Wi-Fi SSID '%s'.", wifi_ssid)
- break
- else:
- if not wait_for_cell_data_connection(log, ad, True):
- ad.log.error("Failed to enable data connection.")
- break
-
- if not wait_for_state(
- verify_internet_connection,
- True,
- MAX_WAIT_TIME_FOR_STATE_CHANGE,
- WAIT_TIME_BETWEEN_STATE_CHECK,
- log,
- ad):
- ad.log.error("Data not available on cell.")
- break
-
- if ims_reg:
- if not wait_for_ims_registered(log, ad):
- ad.log.error("IMS is not registered.")
- break
- ad.log.info("IMS is registered.")
- return True
-
- if recover:
- ad.log.warning("Trying to recover by cycling airplane mode...")
- if not toggle_airplane_mode(log, ad, True):
- ad.log.error("Failed to enable airplane mode")
- break
-
- time.sleep(5)
-
- if not toggle_airplane_mode(log, ad, False):
- ad.log.error("Failed to disable airplane mode")
- break
-
- times = times + 1
-
- else:
- return False
- return False
-
-
def check_voice_network_type(ads, voice_init=True):
"""
Args:
@@ -11230,75 +3783,13 @@
return voice_network_list
-def check_call_status(ad, voice_type_init=None, voice_type_in_call=None):
- """"
- Args:
- ad: Android device object
- voice_type_init: Voice network type before initiate call
- voice_type_in_call: Voice network type in call state
-
- Return:
- voice_call_type_dict: Voice call status
- """
- dut = str(ad.serial)
- network_type = voice_type_init + "_" + voice_type_in_call
- if network_type == "NR_NR":
- voice_call_type_dict = update_voice_call_type_dict(dut, "VoNR")
- elif network_type == "NR_LTE":
- voice_call_type_dict = update_voice_call_type_dict(dut, "EPSFB")
- elif network_type == "LTE_LTE":
- voice_call_type_dict = update_voice_call_type_dict(dut, "VoLTE")
- elif network_type == "LTE_WCDMA":
- voice_call_type_dict = update_voice_call_type_dict(dut, "CSFB")
- else:
- voice_call_type_dict = update_voice_call_type_dict(dut, "UNKNOWN")
- return voice_call_type_dict
-
-
-def update_voice_call_type_dict(dut, key):
- """
- Args:
- dut: Serial Number of android device object
- key: Network subscription parameter (VoNR or EPSFB or VoLTE or CSFB or UNKNOWN)
- Return:
- voice_call_type: Voice call status
- """
- if dut in voice_call_type.keys():
- voice_call_type[dut][key] += 1
- else:
- voice_call_type[dut] = {key:0}
- voice_call_type[dut][key] += 1
- return voice_call_type
-
-
-def wait_for_log(ad, pattern, begin_time=None, end_time=None, max_wait_time=120):
- """Wait for logcat logs matching given pattern. This function searches in
- logcat for strings matching given pattern by using search_logcat per second
- until max_wait_time reaches.
-
- Args:
- ad: android device object
- pattern: pattern to be searched in grep format
- begin_time: only the lines in logcat with time stamps later than
- begin_time will be searched.
- end_time: only the lines in logcat with time stamps earlier than
- end_time will be searched.
- max_wait_time: timeout of this function
-
- Returns:
- All matched lines will be returned. If no line matches the given pattern
- None will be returned.
- """
- start_time = datetime.now()
- while True:
- ad.log.info(
- '====== Searching logcat for "%s" ====== ', pattern)
- res = ad.search_logcat(
- pattern, begin_time=begin_time, end_time=end_time)
- if res:
- return res
- time.sleep(1)
- stop_time = datetime.now()
- passed_time = (stop_time - start_time).total_seconds()
- if passed_time > max_wait_time:
- return
+def cycle_airplane_mode(ad):
+ """Turn on APM and then off."""
+ # APM toggle
+ if not toggle_airplane_mode(ad.log, ad, True):
+ ad.log.info("Failed to turn on airplane mode.")
+ return False
+ if not toggle_airplane_mode(ad.log, ad, False):
+ ad.log.info("Failed to turn off airplane mode.")
+ return False
+ return True
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_video_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_video_utils.py
index 047b512..26751cf 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_video_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_video_utils.py
@@ -17,25 +17,12 @@
import time
from queue import Empty
from acts_contrib.test_utils.tel.tel_defines import AUDIO_ROUTE_EARPIECE
-from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_RINGING
-from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_BACKGROUND
from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_INITIATION
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALLEE_RINGING
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_TELECOM_RINGING
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VIDEO_SESSION_EVENT
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOLTE_ENABLED
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
from acts_contrib.test_utils.tel.tel_defines import GEN_4G
-from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
from acts_contrib.test_utils.tel.tel_defines import RAT_IWLAN
-from acts_contrib.test_utils.tel.tel_defines import RAT_LTE
-from acts_contrib.test_utils.tel.tel_defines import RAT_UMTS
-from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_OFFHOOK
-from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_RINGING
from acts_contrib.test_utils.tel.tel_defines import VT_STATE_AUDIO_ONLY
from acts_contrib.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
from acts_contrib.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL_PAUSED
@@ -45,37 +32,27 @@
from acts_contrib.test_utils.tel.tel_defines import VT_STATE_TX_PAUSED
from acts_contrib.test_utils.tel.tel_defines import VT_STATE_STATE_INVALID
from acts_contrib.test_utils.tel.tel_defines import VT_VIDEO_QUALITY_DEFAULT
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ACCEPT_VIDEO_CALL_TO_CHECK_STATE
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
-from acts_contrib.test_utils.tel.tel_defines import EventCallStateChanged
from acts_contrib.test_utils.tel.tel_defines import EventTelecomVideoCallSessionModifyRequestReceived
from acts_contrib.test_utils.tel.tel_defines import EventTelecomVideoCallSessionModifyResponseReceived
from acts_contrib.test_utils.tel.tel_defines import EVENT_VIDEO_SESSION_MODIFY_RESPONSE_RECEIVED
from acts_contrib.test_utils.tel.tel_defines import EVENT_VIDEO_SESSION_MODIFY_REQUEST_RECEIVED
-from acts_contrib.test_utils.tel.tel_defines import CallStateContainer
+from acts_contrib.test_utils.tel.tel_ims_utils import is_wfc_enabled
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode_for_subscription
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_video_enabled
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_generation
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import is_event_match
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte
-from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_rat_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_ringing_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_telecom_ringing
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_video_enabled
from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import is_wfc_enabled
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
from acts_contrib.test_utils.tel.tel_voice_utils import is_call_hd
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call_for_subscription
def phone_setup_video(
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_voice_conf_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_voice_conf_utils.py
index 75ff64b..721e83e 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_voice_conf_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_voice_conf_utils.py
@@ -17,26 +17,26 @@
import time
from acts import signals
+from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.tel_defines import CALL_CAPABILITY_MANAGE_CONFERENCE
from acts_contrib.test_utils.tel.tel_defines import CALL_PROPERTY_CONFERENCE
from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_ACTIVE
from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_HOLDING
from acts_contrib.test_utils.tel.tel_defines import PHONE_TYPE_GSM
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
from acts_contrib.test_utils.tel.tel_test_utils import get_call_uri
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
-from acts_contrib.test_utils.tel.tel_voice_utils import get_cep_conference_call_id
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_wcdma
from acts_contrib.test_utils.tel.tel_test_utils import is_uri_equivalent
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import get_cep_conference_call_id
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
from acts_contrib.test_utils.tel.tel_voice_utils import swap_calls
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_reject_call_for_subscription
def _three_phone_call_mo_add_mo(log, ads, phone_setups, verify_funcs):
@@ -219,41 +219,41 @@
ads[0].droid.telecomCallGetProperties(call_conf_id))
return None
- if (CALL_CAPABILITY_MANAGE_CONFERENCE not in ads[0]
- .droid.telecomCallGetCapabilities(call_conf_id)):
- ads[0].log.error(
- "Conf call id %s capabilities wrong: %s", call_conf_id,
- ads[0].droid.telecomCallGetCapabilities(call_conf_id))
- return None
+ if (CALL_CAPABILITY_MANAGE_CONFERENCE not in ads[0]
+ .droid.telecomCallGetCapabilities(call_conf_id)):
+ ads[0].log.error(
+ "Conf call id %s capabilities wrong: %s", call_conf_id,
+ ads[0].droid.telecomCallGetCapabilities(call_conf_id))
+ return None
- if (call_ab_id in calls) or (call_ac_id in calls):
- log.error("Previous call ids should not in new call"
- " list after merge.")
- return None
- else:
- for call_id in calls:
- if call_id != call_ab_id and call_id != call_ac_id:
- call_conf_id = call_id
- log.info("CEP not enabled.")
+ if (call_ab_id in calls) or (call_ac_id in calls):
+ log.error("Previous call ids should not in new call"
+ " list after merge.")
+ return None
+ else:
+ for call_id in calls:
+ if call_id != call_ab_id and call_id != call_ac_id:
+ call_conf_id = call_id
+ log.info("CEP not enabled.")
- if not call_conf_id:
- log.error("Merge call fail, no new conference call id.")
- raise signals.TestFailure(
- "Calls were not merged. Failed to merge calls.",
- extras={"fail_reason": "Calls were not merged."
- " Failed to merge calls."})
- if not verify_incall_state(log, [ads[0], ads[1], ads[2]], True):
- return False
+ if not call_conf_id:
+ log.error("Merge call fail, no new conference call id.")
+ raise signals.TestFailure(
+ "Calls were not merged. Failed to merge calls.",
+ extras={"fail_reason": "Calls were not merged."
+ " Failed to merge calls."})
+ if not verify_incall_state(log, [ads[0], ads[1], ads[2]], True):
+ return False
- # Check if Conf Call is currently active
- if ads[0].droid.telecomCallGetCallState(
- call_conf_id) != CALL_STATE_ACTIVE:
- ads[0].log.error(
- "Call_ID: %s, state: %s, expected: STATE_ACTIVE", call_conf_id,
- ads[0].droid.telecomCallGetCallState(call_conf_id))
- return None
+ # Check if Conf Call is currently active
+ if ads[0].droid.telecomCallGetCallState(
+ call_conf_id) != CALL_STATE_ACTIVE:
+ ads[0].log.error(
+ "Call_ID: %s, state: %s, expected: STATE_ACTIVE", call_conf_id,
+ ads[0].droid.telecomCallGetCallState(call_conf_id))
+ return None
- return call_conf_id
+ return call_conf_id
def _hangup_call(log, ad, device_description='Device'):
@@ -266,7 +266,7 @@
def _test_ims_conference_merge_drop_second_call_from_participant(
log, ads, call_ab_id, call_ac_id):
"""Test conference merge and drop in IMS (VoLTE or WiFi Calling) call.
- (CEP enabled).
+ (supporting both cases of CEP enabled and disabled).
PhoneA in IMS (VoLTE or WiFi Calling) call with PhoneB.
PhoneA in IMS (VoLTE or WiFi Calling) call with PhoneC.
@@ -336,10 +336,19 @@
calls = ads[0].droid.telecomCallGetCallIds()
calls.remove(call_conf_id)
+ if not calls:
+ raise signals.TestSkip('CEP is not supported. The test will be skipped.')
+
log.info("Step5: Disconnect call A-C and verify call continues.")
call_to_disconnect = None
for call in calls:
- if is_uri_equivalent(call_ac_uri, get_call_uri(ads[0], call)):
+ new_uri = get_call_uri(ads[0], call)
+ if not new_uri:
+ ads[0].log.warning('New URI should NOT be None.')
+ raise signals.TestSkip('Invalid URI is found on the host. The test will be skipped.')
+ else:
+ ads[0].log.info('URI for call ID %s: %s', call, new_uri)
+ if is_uri_equivalent(call_ac_uri, new_uri):
call_to_disconnect = call
calls.remove(call_to_disconnect)
break
@@ -359,7 +368,13 @@
calls = ads[0].droid.telecomCallGetCallIds()
call_to_disconnect = None
for call in calls:
- if is_uri_equivalent(call_ab_uri, get_call_uri(ads[0], call)):
+ new_uri = get_call_uri(ads[0], call)
+ if not new_uri:
+ ads[0].log.warning('New URI should NOT be None.')
+ raise signals.TestSkip('Invalid URI is found on the host. The test will be skipped.')
+ else:
+ ads[0].log.info('URI for call ID %s: %s', call, new_uri)
+ if is_uri_equivalent(call_ab_uri, new_uri):
call_to_disconnect = call
calls.remove(call_to_disconnect)
break
@@ -444,10 +459,19 @@
calls = ads[0].droid.telecomCallGetCallIds()
calls.remove(call_conf_id)
+ if not calls:
+ raise signals.TestSkip('CEP is not supported. The test will be skipped.')
+
log.info("Step5: Disconnect call A-B and verify call continues.")
call_to_disconnect = None
for call in calls:
- if is_uri_equivalent(call_ab_uri, get_call_uri(ads[0], call)):
+ new_uri = get_call_uri(ads[0], call)
+ if not new_uri:
+ ads[0].log.warning('New URI should NOT be None.')
+ raise signals.TestSkip('Invalid URI is found on the host. The test will be skipped.')
+ else:
+ ads[0].log.info('URI for call ID %s: %s', call, new_uri)
+ if is_uri_equivalent(call_ab_uri, new_uri):
call_to_disconnect = call
calls.remove(call_to_disconnect)
break
@@ -467,7 +491,13 @@
calls = ads[0].droid.telecomCallGetCallIds()
call_to_disconnect = None
for call in calls:
- if is_uri_equivalent(call_ac_uri, get_call_uri(ads[0], call)):
+ new_uri = get_call_uri(ads[0], call)
+ if not new_uri:
+ ads[0].log.warning('New URI should NOT be None.')
+ raise signals.TestSkip('Invalid URI is found on the host. The test will be skipped.')
+ else:
+ ads[0].log.info('URI for call ID %s: %s', call, new_uri)
+ if is_uri_equivalent(call_ac_uri, new_uri):
call_to_disconnect = call
calls.remove(call_to_disconnect)
break
@@ -482,7 +512,12 @@
return True
-def _three_phone_call_mo_add_mt(log, ads, phone_setups, verify_funcs):
+def _three_phone_call_mo_add_mt(
+ log,
+ ads,
+ phone_setups,
+ verify_funcs,
+ reject_once=False):
"""Use 3 phones to make MO call and MT call.
Call from PhoneA to PhoneB, accept on PhoneB.
@@ -495,6 +530,7 @@
The list should have three objects.
verify_funcs: list of phone call verify functions.
The list should have three objects.
+ reject_once: True for rejecting the second call once.
Returns:
If success, return 'call_AB' id in PhoneA.
@@ -536,6 +572,30 @@
call_ab_id = calls[0]
log.info("Step2: Call From PhoneC to PhoneA.")
+ if reject_once:
+ log.info("Step2-1: Reject incoming call once.")
+ if not initiate_call(
+ log,
+ ads[2],
+ ads[0].telephony['subscription'][get_incoming_voice_sub_id(
+ ads[0])]['phone_num']):
+ ads[2].log.error("Initiate call failed.")
+ raise _CallException("Failed to initiate call.")
+
+ if not wait_and_reject_call_for_subscription(
+ log,
+ ads[0],
+ get_incoming_voice_sub_id(ads[0]),
+ incoming_number= \
+ ads[2].telephony['subscription'][
+ get_incoming_voice_sub_id(
+ ads[2])]['phone_num']):
+ ads[0].log.error("Reject call fail.")
+ raise _CallException("Failed to reject call.")
+
+ _hangup_call(log, ads[2], "PhoneC")
+ time.sleep(15)
+
if not call_setup_teardown(
log,
ads[2],
@@ -691,7 +751,6 @@
return call_ab_id
-
def _test_call_mt_mt_add_swap_x(log,
ads,
num_swaps,
@@ -780,7 +839,6 @@
True if no error happened. Otherwise False.
"""
-
ad_hangup.log.info("Hangup, verify call continues.")
if not _hangup_call(log, ad_hangup):
ad_hangup.log.error("Phone fails to hang up")
@@ -812,4 +870,74 @@
return CALL_STATE_ACTIVE
return CALL_STATE_HOLDING
+def _test_wcdma_conference_merge_drop(log, ads, call_ab_id, call_ac_id):
+ """Test conference merge and drop in WCDMA/CSFB_WCDMA call.
+ PhoneA in WCDMA (or CSFB_WCDMA) call with PhoneB.
+ PhoneA in WCDMA (or CSFB_WCDMA) call with PhoneC.
+ Merge calls to conference on PhoneA.
+ Hangup on PhoneC, check call continues between AB.
+ Hangup on PhoneB, check A ends.
+
+ Args:
+ call_ab_id: call id for call_AB on PhoneA.
+ call_ac_id: call id for call_AC on PhoneA.
+
+ Returns:
+ True if succeed;
+ False if failed.
+ """
+ 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)
+ calls = ads[0].droid.telecomCallGetCallIds()
+ ads[0].log.info("Calls in PhoneA %s", calls)
+ num_calls = num_active_calls(log, ads[0])
+ if num_calls != 3:
+ ads[0].log.error("Total number of call ids is not 3.")
+ if num_calls == 2:
+ if call_ab_id in calls and call_ac_id in calls:
+ ads[0].log.error("Calls were not merged."
+ " Failed to merge calls.")
+ raise signals.TestFailure(
+ "Calls were not merged. Failed to merge calls.",
+ extras={"fail_reason": "Calls were not merged."
+ " Failed to merge calls."})
+ return False
+ call_conf_id = None
+ for call_id in calls:
+ if call_id != call_ab_id and call_id != call_ac_id:
+ call_conf_id = call_id
+ if not call_conf_id:
+ log.error("Merge call fail, no new conference call id.")
+ return False
+ if not verify_incall_state(log, [ads[0], ads[1], ads[2]], True):
+ return False
+
+ if ads[0].droid.telecomCallGetCallState(
+ call_conf_id) != CALL_STATE_ACTIVE:
+ ads[0].log.error(
+ "Call_id: %s, state: %s, expected: STATE_ACTIVE", call_conf_id,
+ ads[0].droid.telecomCallGetCallState(call_conf_id))
+ return False
+
+ log.info("Step5: End call on PhoneC and verify call continues.")
+ if not _hangup_call(log, ads[2], "PhoneC"):
+ return False
+ time.sleep(WAIT_TIME_IN_CALL)
+ calls = ads[0].droid.telecomCallGetCallIds()
+ ads[0].log.info("Calls in PhoneA %s", calls)
+ if num_active_calls(log, ads[0]) != 1:
+ return False
+ if not verify_incall_state(log, [ads[0], ads[1]], True):
+ return False
+ if not verify_incall_state(log, [ads[2]], False):
+ return False
+
+ log.info("Step6: End call on PhoneB and verify PhoneA end.")
+ if not _hangup_call(log, ads[1], "PhoneB"):
+ return False
+ time.sleep(WAIT_TIME_IN_CALL)
+ if not verify_incall_state(log, [ads[0], ads[1], ads[2]], False):
+ return False
+ return True
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_voice_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_voice_utils.py
index 3f4d518..89d8f05 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_voice_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_voice_utils.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2016 - Google
+# Copyright 2021 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,101 +14,922 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import re
import time
+from queue import Empty
from acts import signals
+from acts.logger import epoch_to_log_line_timestamp
+from acts.utils import get_current_epoch_time
from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
+from acts_contrib.test_utils.tel.tel_defines import CarrierConfigs
+from acts_contrib.test_utils.tel.tel_defines import CARRIER_NTT_DOCOMO, CARRIER_KDDI, CARRIER_RAKUTEN, CARRIER_SBM
from acts_contrib.test_utils.tel.tel_defines import CALL_PROPERTY_HIGH_DEF_AUDIO
from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_ACTIVE
from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_HOLDING
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
-from acts_contrib.test_utils.tel.tel_defines import CARRIER_TMO
+from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
from acts_contrib.test_utils.tel.tel_defines import GEN_2G
from acts_contrib.test_utils.tel.tel_defines import GEN_3G
-from acts_contrib.test_utils.tel.tel_defines import GEN_4G
-from acts_contrib.test_utils.tel.tel_defines import GEN_5G
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOLTE_ENABLED
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
+from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_BACKGROUND
+from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
+from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
+from acts_contrib.test_utils.tel.tel_defines import MAX_SAVED_VOICE_MAIL
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_DROP
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_IDLE_EVENT
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_INITIATION
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALLEE_RINGING
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_TELECOM_RINGING
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOICE_MAIL_COUNT
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_CDMA2000
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WCDMA
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WLAN
from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
from acts_contrib.test_utils.tel.tel_defines import RAT_IWLAN
from acts_contrib.test_utils.tel.tel_defines import RAT_LTE
from acts_contrib.test_utils.tel.tel_defines import RAT_UMTS
+from acts_contrib.test_utils.tel.tel_defines import RAT_UNKNOWN
+from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_IDLE
+from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_OFFHOOK
+from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_RINGING
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_REG_AND_CALL
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_LEAVE_VOICE_MAIL
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_CDMA
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_ONLY
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_UMTS
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_CDMA_EVDO
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
-from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
-from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_REJECT_CALL
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import EventCallStateChanged
+from acts_contrib.test_utils.tel.tel_defines import EventMessageWaitingIndicatorChanged
+from acts_contrib.test_utils.tel.tel_defines import CallStateContainer
+from acts_contrib.test_utils.tel.tel_defines import MessageWaitingIndicatorContainer
+from acts_contrib.test_utils.tel.tel_ims_utils import is_wfc_enabled
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_volte_enabled
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_disabled
+from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_delete_digit
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_not_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_voice_attach
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_outgoing_call
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import call_reject_leave_message
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown_for_call_forwarding
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown_for_call_waiting
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import \
- ensure_network_generation_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import \
- ensure_network_rat_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state
+from acts_contrib.test_utils.tel.tel_test_utils import check_call_state_connected_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import check_call_state_idle_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import check_phone_number_match
+from acts_contrib.test_utils.tel.tel_test_utils import check_voice_mail_count
+from acts_contrib.test_utils.tel.tel_test_utils import check_voice_network_type
+from acts_contrib.test_utils.tel.tel_test_utils import get_call_uri
+from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
from acts_contrib.test_utils.tel.tel_test_utils import get_network_gen_for_subscription
from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat
from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
+from acts_contrib.test_utils.tel.tel_test_utils import get_number_from_tel_uri
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_test_utils import is_wfc_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import \
- reset_preferred_network_type_to_allowable_range
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import set_wifi_to_default
-from acts_contrib.test_utils.tel.tel_test_utils import TelResultWrapper
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
-from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import \
- wait_for_data_attach_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_enhanced_4g_lte_setting
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import \
- wait_for_network_generation_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_not_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import \
- wait_for_network_rat_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import \
- wait_for_not_network_rat_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_volte_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import \
- wait_for_voice_attach_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_disabled
-from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import get_user_config_profile
+from acts_contrib.test_utils.tel.tel_test_utils import get_voice_mail_number
+from acts_contrib.test_utils.tel.tel_test_utils import is_event_match
+from acts_contrib.test_utils.tel.tel_test_utils import is_event_match_for_list
from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import TelResultWrapper
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
+from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
CallResult = TelephonyVoiceTestResult.CallResult.Value
+result_dict ={}
+voice_call_type = {}
+
+
+def check_call_status(ad, voice_type_init=None, voice_type_in_call=None):
+ """"
+ Args:
+ ad: Android device object
+ voice_type_init: Voice network type before initiate call
+ voice_type_in_call: Voice network type in call state
+
+ Return:
+ voice_call_type_dict: Voice call status
+ """
+ dut = str(ad.serial)
+ network_type = voice_type_init + "_" + voice_type_in_call
+ if network_type == "NR_NR":
+ voice_call_type_dict = update_voice_call_type_dict(dut, "VoNR")
+ elif network_type == "NR_LTE":
+ voice_call_type_dict = update_voice_call_type_dict(dut, "EPSFB")
+ elif network_type == "LTE_LTE":
+ voice_call_type_dict = update_voice_call_type_dict(dut, "VoLTE")
+ elif network_type == "LTE_WCDMA":
+ voice_call_type_dict = update_voice_call_type_dict(dut, "CSFB")
+ else:
+ voice_call_type_dict = update_voice_call_type_dict(dut, "UNKNOWN")
+ return voice_call_type_dict
+
+
+def update_voice_call_type_dict(dut, key):
+ """
+ Args:
+ dut: Serial Number of android device object
+ key: Network subscription parameter (VoNR or EPSFB or VoLTE or CSFB or UNKNOWN)
+ Return:
+ voice_call_type: Voice call status
+ """
+ if dut in voice_call_type.keys():
+ voice_call_type[dut][key] += 1
+ else:
+ voice_call_type[dut] = {key:0}
+ voice_call_type[dut][key] += 1
+ return voice_call_type
+
+
+def dial_phone_number(ad, callee_number):
+ for number in str(callee_number):
+ if number == "#":
+ ad.send_keycode("POUND")
+ elif number == "*":
+ ad.send_keycode("STAR")
+ elif number in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]:
+ ad.send_keycode("%s" % number)
+
+
+def disconnect_call_by_id(log, ad, call_id):
+ """Disconnect call by call id.
+ """
+ ad.droid.telecomCallDisconnect(call_id)
+ return True
+
+
+def dumpsys_last_call_info(ad):
+ """ Get call information by dumpsys telecom. """
+ num = dumpsys_last_call_number(ad)
+ output = ad.adb.shell("dumpsys telecom")
+ result = re.search(r"Call TC@%s: {(.*?)}" % num, output, re.DOTALL)
+ call_info = {"TC": num}
+ if result:
+ result = result.group(1)
+ for attr in ("startTime", "endTime", "direction", "isInterrupted",
+ "callTechnologies", "callTerminationsReason",
+ "isVideoCall", "callProperties"):
+ match = re.search(r"%s: (.*)" % attr, result)
+ if match:
+ if attr in ("startTime", "endTime"):
+ call_info[attr] = epoch_to_log_line_timestamp(
+ int(match.group(1)))
+ else:
+ call_info[attr] = match.group(1)
+ ad.log.debug("call_info = %s", call_info)
+ return call_info
+
+
+def dumpsys_last_call_number(ad):
+ output = ad.adb.shell("dumpsys telecom")
+ call_nums = re.findall("Call TC@(\d+):", output)
+ if not call_nums:
+ return 0
+ else:
+ return int(call_nums[-1])
+
+
+def dumpsys_new_call_info(ad, last_tc_number, retries=3, interval=5):
+ for i in range(retries):
+ if dumpsys_last_call_number(ad) > last_tc_number:
+ call_info = dumpsys_last_call_info(ad)
+ ad.log.info("New call info = %s", sorted(call_info.items()))
+ return call_info
+ else:
+ time.sleep(interval)
+ ad.log.error("New call is not in sysdump telecom")
+ return {}
+
+
+def emergency_dialer_call_by_keyevent(ad, callee_number):
+ for i in range(3):
+ if "EmergencyDialer" in ad.get_my_current_focus_window():
+ ad.log.info("EmergencyDialer is the current focus window")
+ break
+ elif i <= 2:
+ ad.adb.shell("am start -a com.android.phone.EmergencyDialer.DIAL")
+ time.sleep(1)
+ else:
+ ad.log.error("Unable to bring up EmergencyDialer")
+ return False
+ ad.log.info("Make a phone call to %s", callee_number)
+ dial_phone_number(ad, callee_number)
+ ad.send_keycode("CALL")
+
+
+def get_current_voice_rat(log, ad):
+ """Return current Voice RAT
+
+ Args:
+ ad: Android device object.
+ """
+ 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.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ """
+ return get_network_rat_for_subscription(log, ad, sub_id,
+ NETWORK_SERVICE_VOICE)
+
+
+def hangup_call_by_adb(ad):
+ """Make emergency call by EmergencyDialer.
+
+ Args:
+ ad: Caller android device object.
+ callee_number: Callee phone number.
+ """
+ ad.log.info("End call by adb")
+ ad.send_keycode("ENDCALL")
+
+
+def hangup_call(log, ad, is_emergency=False):
+ """Hang up ongoing active call.
+
+ Args:
+ log: log object.
+ ad: android device object.
+
+ Returns:
+ True: if all calls are cleared
+ False: for errors
+ """
+ # short circuit in case no calls are active
+ if not ad.droid.telecomIsInCall():
+ ad.log.warning("No active call exists.")
+ return True
+ ad.ed.clear_events(EventCallStateChanged)
+ ad.droid.telephonyStartTrackingCallState()
+ ad.log.info("Hangup call.")
+ if is_emergency:
+ for call in ad.droid.telecomCallGetCallIds():
+ ad.droid.telecomCallDisconnect(call)
+ else:
+ ad.droid.telecomEndCall()
+
+ try:
+ ad.ed.wait_for_event(
+ EventCallStateChanged,
+ is_event_match,
+ timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
+ field=CallStateContainer.CALL_STATE,
+ value=TELEPHONY_STATE_IDLE)
+ except Empty:
+ ad.log.warning("Call state IDLE event is not received after hang up.")
+ finally:
+ ad.droid.telephonyStopTrackingCallStateChange()
+ if not wait_for_state(ad.droid.telecomIsInCall, False, 15, 1):
+ ad.log.error("Telecom is in call, hangup call failed.")
+ return False
+ return True
+
+
+def initiate_emergency_dialer_call_by_adb(
+ log,
+ ad,
+ callee_number,
+ timeout=MAX_WAIT_TIME_CALL_INITIATION,
+ checking_interval=5):
+ """Make emergency call by EmergencyDialer.
+
+ Args:
+ ad: Caller android device object.
+ callee_number: Callee phone number.
+ emergency : specify the call is emergency.
+ Optional. Default value is False.
+
+ Returns:
+ result: if phone call is placed successfully.
+ """
+ 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(
+ "am start -a android.intent.action.CALL_EMERGENCY -d tel:%s" %
+ callee_number)
+ if not timeout: return True
+ ad.log.info("Check call state")
+ # Verify Call State
+ elapsed_time = 0
+ while elapsed_time < timeout:
+ time.sleep(checking_interval)
+ elapsed_time += checking_interval
+ if check_call_state_connected_by_adb(ad):
+ ad.log.info("Call to %s is connected", callee_number)
+ return True
+ if check_call_state_idle_by_adb(ad):
+ ad.log.info("Call to %s failed", callee_number)
+ return False
+ ad.log.info("Make call to %s failed", callee_number)
+ return False
+ except Exception as e:
+ ad.log.error("initiate emergency call failed with error %s", e)
+
+
+def initiate_call(log,
+ ad,
+ callee_number,
+ emergency=False,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ video=False):
+ """Make phone call from caller to callee.
+
+ Args:
+ ad_caller: Caller android device object.
+ callee_number: Callee phone number.
+ emergency : specify the call is emergency.
+ Optional. Default value is False.
+ incall_ui_display: show the dialer UI foreground or backgroud
+ video: whether to initiate as video call
+
+ Returns:
+ result: if phone call is placed successfully.
+ """
+ ad.ed.clear_events(EventCallStateChanged)
+ sub_id = get_outgoing_voice_sub_id(ad)
+ begin_time = get_device_epoch_time(ad)
+ ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
+ try:
+ # Make a Call
+ ad.log.info("Make a phone call to %s", callee_number)
+ if emergency:
+ ad.droid.telecomCallEmergencyNumber(callee_number)
+ else:
+ ad.droid.telecomCallNumber(callee_number, video)
+
+ # Verify OFFHOOK state
+ if not wait_for_call_offhook_for_subscription(
+ log, ad, sub_id, event_tracking_started=True):
+ ad.log.info("sub_id %s not in call offhook state", sub_id)
+ last_call_drop_reason(ad, begin_time=begin_time)
+ return False
+ else:
+ return True
+
+ finally:
+ if hasattr(ad, "sdm_log") and getattr(ad, "sdm_log"):
+ ad.adb.shell("i2cset -fy 3 64 6 1 b", ignore_status=True)
+ ad.adb.shell("i2cset -fy 3 65 6 1 b", ignore_status=True)
+ ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
+
+ if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
+ ad.droid.telecomShowInCallScreen()
+ elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
+ ad.droid.showHomeScreen()
+
+
+def last_call_drop_reason(ad, begin_time=None):
+ reasons = ad.search_logcat(
+ "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause", begin_time)
+ reason_string = ""
+ if reasons:
+ log_msg = "Logcat call drop reasons:"
+ for reason in reasons:
+ log_msg = "%s\n\t%s" % (log_msg, reason["log_message"])
+ if "ril reason str" in reason["log_message"]:
+ reason_string = reason["log_message"].split(":")[-1].strip()
+ ad.log.info(log_msg)
+ reasons = ad.search_logcat("ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION",
+ begin_time)
+ if reasons:
+ ad.log.warning("ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION is seen")
+ ad.log.info("last call dumpsys: %s",
+ sorted(dumpsys_last_call_info(ad).items()))
+ return reason_string
+
+
+def call_reject(log, ad_caller, ad_callee, reject=True):
+ """Caller call Callee, then reject on callee.
+
+
+ """
+ subid_caller = ad_caller.droid.subscriptionGetDefaultVoiceSubId()
+ subid_callee = ad_callee.incoming_voice_sub_id
+ ad_caller.log.info("Sub-ID Caller %s, Sub-ID Callee %s", subid_caller,
+ subid_callee)
+ return call_reject_for_subscription(log, ad_caller, ad_callee,
+ subid_caller, subid_callee, reject)
+
+
+def call_reject_for_subscription(log,
+ ad_caller,
+ ad_callee,
+ subid_caller,
+ subid_callee,
+ reject=True):
+ """
+ """
+
+ caller_number = ad_caller.telephony['subscription'][subid_caller][
+ 'phone_num']
+ callee_number = ad_callee.telephony['subscription'][subid_callee][
+ 'phone_num']
+
+ ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
+ if not initiate_call(log, ad_caller, callee_number):
+ ad_caller.log.error("Initiate call failed")
+ return False
+
+ if not wait_and_reject_call_for_subscription(
+ log, ad_callee, subid_callee, caller_number, WAIT_TIME_REJECT_CALL,
+ reject):
+ ad_callee.log.error("Reject call fail.")
+ return False
+ # Check if incoming call is cleared on callee or not.
+ if ad_callee.droid.telephonyGetCallStateForSubscription(
+ subid_callee) == TELEPHONY_STATE_RINGING:
+ ad_callee.log.error("Incoming call is not cleared")
+ return False
+ # Hangup on caller
+ hangup_call(log, ad_caller)
+ return True
+
+
+def call_reject_leave_message(log,
+ ad_caller,
+ ad_callee,
+ verify_caller_func=None,
+ wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
+ """On default voice subscription, Call from caller to callee,
+ reject on callee, caller leave a voice mail.
+
+ 1. Caller call Callee.
+ 2. Callee reject incoming call.
+ 3. Caller leave a voice mail.
+ 4. Verify callee received the voice mail notification.
+
+ Args:
+ ad_caller: caller android device object.
+ ad_callee: callee android device object.
+ verify_caller_func: function to verify caller is in correct state while in-call.
+ This is optional, default is None.
+ wait_time_in_call: time to wait when leaving a voice mail.
+ This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
+
+ Returns:
+ True: if voice message is received on callee successfully.
+ False: for errors
+ """
+ subid_caller = get_outgoing_voice_sub_id(ad_caller)
+ subid_callee = get_incoming_voice_sub_id(ad_callee)
+ return call_reject_leave_message_for_subscription(
+ log, ad_caller, ad_callee, subid_caller, subid_callee,
+ verify_caller_func, wait_time_in_call)
+
+
+def check_reject_needed_for_voice_mail(log, ad_callee):
+ """Check if the carrier requires reject call to receive voice mail or just keep ringing
+ Requested in b//155935290
+ Four Japan carriers do not need to reject
+ SBM, KDDI, Ntt Docomo, Rakuten
+ Args:
+ log: log object
+ ad_callee: android device object
+ Returns:
+ True if callee's carrier is not one of the four Japan carriers
+ False if callee's carrier is one of the four Japan carriers
+ """
+
+ operators_no_reject = [CARRIER_NTT_DOCOMO,
+ CARRIER_KDDI,
+ CARRIER_RAKUTEN,
+ CARRIER_SBM]
+ operator_name = get_operator_name(log, ad_callee)
+
+ return operator_name not in operators_no_reject
+
+
+def _is_on_message_waiting_event_true(event):
+ """Private function to return if the received EventMessageWaitingIndicatorChanged
+ event MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING field is True.
+ """
+ return event['data'][MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING]
+
+
+def call_reject_leave_message_for_subscription(
+ log,
+ ad_caller,
+ ad_callee,
+ subid_caller,
+ subid_callee,
+ verify_caller_func=None,
+ wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
+ """On specific voice subscription, Call from caller to callee,
+ reject on callee, caller leave a voice mail.
+
+ 1. Caller call Callee.
+ 2. Callee reject incoming call.
+ 3. Caller leave a voice mail.
+ 4. Verify callee received the voice mail notification.
+
+ Args:
+ ad_caller: caller android device object.
+ ad_callee: callee android device object.
+ subid_caller: caller's subscription id.
+ subid_callee: callee's subscription id.
+ verify_caller_func: function to verify caller is in correct state while in-call.
+ This is optional, default is None.
+ wait_time_in_call: time to wait when leaving a voice mail.
+ This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
+
+ Returns:
+ True: if voice message is received on callee successfully.
+ False: for errors
+ """
+
+ # Currently this test utility only works for TMO and ATT and SPT.
+ # It does not work for VZW (see b/21559800)
+ # "with VVM TelephonyManager APIs won't work for vm"
+
+ caller_number = ad_caller.telephony['subscription'][subid_caller][
+ 'phone_num']
+ callee_number = ad_callee.telephony['subscription'][subid_callee][
+ 'phone_num']
+
+ ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
+
+ try:
+ voice_mail_count_before = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
+ subid_callee)
+ ad_callee.log.info("voice mail count is %s", voice_mail_count_before)
+ # -1 means there are unread voice mail, but the count is unknown
+ # 0 means either this API not working (VZW) or no unread voice mail.
+ if voice_mail_count_before != 0:
+ log.warning("--Pending new Voice Mail, please clear on phone.--")
+
+ if not initiate_call(log, ad_caller, callee_number):
+ ad_caller.log.error("Initiate call failed.")
+ return False
+ if check_reject_needed_for_voice_mail(log, ad_callee):
+ carrier_specific_delay_reject = 30
+ else:
+ carrier_specific_delay_reject = 2
+ carrier_reject_call = not check_reject_needed_for_voice_mail(log, ad_callee)
+
+ if not wait_and_reject_call_for_subscription(
+ log, ad_callee, subid_callee, incoming_number=caller_number, delay_reject=carrier_specific_delay_reject,
+ reject=carrier_reject_call):
+ ad_callee.log.error("Reject call fail.")
+ return False
+
+ ad_callee.droid.telephonyStartTrackingVoiceMailStateChangeForSubscription(
+ subid_callee)
+
+ # ensure that all internal states are updated in telecom
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ ad_callee.ed.clear_events(EventCallStateChanged)
+
+ if verify_caller_func and not verify_caller_func(log, ad_caller):
+ ad_caller.log.error("Caller not in correct state!")
+ return False
+
+ # TODO: b/26293512 Need to play some sound to leave message.
+ # Otherwise carrier voice mail server may drop this voice mail.
+ time.sleep(wait_time_in_call)
+
+ if not verify_caller_func:
+ caller_state_result = ad_caller.droid.telecomIsInCall()
+ else:
+ caller_state_result = verify_caller_func(log, ad_caller)
+ if not caller_state_result:
+ ad_caller.log.error("Caller not in correct state after %s seconds",
+ wait_time_in_call)
+
+ if not hangup_call(log, ad_caller):
+ ad_caller.log.error("Error in Hanging-Up Call")
+ return False
+
+ ad_callee.log.info("Wait for voice mail indicator on callee.")
+ try:
+ event = ad_callee.ed.wait_for_event(
+ EventMessageWaitingIndicatorChanged,
+ _is_on_message_waiting_event_true)
+ ad_callee.log.info("Got event %s", event)
+ except Empty:
+ ad_callee.log.warning("No expected event %s",
+ EventMessageWaitingIndicatorChanged)
+ return False
+ voice_mail_count_after = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
+ subid_callee)
+ ad_callee.log.info(
+ "telephonyGetVoiceMailCount output - before: %s, after: %s",
+ voice_mail_count_before, voice_mail_count_after)
+
+ # voice_mail_count_after should:
+ # either equals to (voice_mail_count_before + 1) [For ATT and SPT]
+ # or equals to -1 [For TMO]
+ # -1 means there are unread voice mail, but the count is unknown
+ if not check_voice_mail_count(log, ad_callee, voice_mail_count_before,
+ voice_mail_count_after):
+ log.error("before and after voice mail count is not incorrect.")
+ return False
+ finally:
+ ad_callee.droid.telephonyStopTrackingVoiceMailStateChangeForSubscription(
+ subid_callee)
+ return True
+
+
+def call_voicemail_erase_all_pending_voicemail(log, ad):
+ """Script for phone to erase all pending voice mail.
+ This script only works for TMO and ATT and SPT currently.
+ This script only works if phone have already set up voice mail options,
+ and phone should disable password protection for voice mail.
+
+ 1. If phone don't have pending voice message, return True.
+ 2. Dial voice mail number.
+ For TMO, the number is '123'
+ For ATT, the number is phone's number
+ For SPT, the number is phone's number
+ 3. Wait for voice mail connection setup.
+ 4. Wait for voice mail play pending voice message.
+ 5. Send DTMF to delete one message.
+ The digit is '7'.
+ 6. Repeat steps 4 and 5 until voice mail server drop this call.
+ (No pending message)
+ 6. Check telephonyGetVoiceMailCount result. it should be 0.
+
+ Args:
+ log: log object
+ ad: android device object
+ Returns:
+ False if error happens. True is succeed.
+ """
+ log.info("Erase all pending voice mail.")
+ count = ad.droid.telephonyGetVoiceMailCount()
+ if count == 0:
+ ad.log.info("No Pending voice mail.")
+ return True
+ if count == -1:
+ ad.log.info("There is pending voice mail, but the count is unknown")
+ count = MAX_SAVED_VOICE_MAIL
+ else:
+ ad.log.info("There are %s voicemails", count)
+
+ voice_mail_number = get_voice_mail_number(log, ad)
+ delete_digit = get_voice_mail_delete_digit(get_operator_name(log, ad))
+ if not initiate_call(log, ad, voice_mail_number):
+ log.error("Initiate call to voice mail failed.")
+ return False
+ time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
+ callId = ad.droid.telecomCallGetCallIds()[0]
+ time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
+ while (is_phone_in_call(log, ad) and (count > 0)):
+ ad.log.info("Press %s to delete voice mail.", delete_digit)
+ ad.droid.telecomCallPlayDtmfTone(callId, delete_digit)
+ ad.droid.telecomCallStopDtmfTone(callId)
+ time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
+ count -= 1
+ if is_phone_in_call(log, ad):
+ hangup_call(log, ad)
+
+ # wait for telephonyGetVoiceMailCount to update correct result
+ remaining_time = MAX_WAIT_TIME_VOICE_MAIL_COUNT
+ while ((remaining_time > 0)
+ and (ad.droid.telephonyGetVoiceMailCount() != 0)):
+ time.sleep(1)
+ remaining_time -= 1
+ current_voice_mail_count = ad.droid.telephonyGetVoiceMailCount()
+ ad.log.info("telephonyGetVoiceMailCount: %s", current_voice_mail_count)
+ return (current_voice_mail_count == 0)
+
+
+def call_setup_teardown(log,
+ ad_caller,
+ ad_callee,
+ ad_hangup=None,
+ verify_caller_func=None,
+ verify_callee_func=None,
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ dialing_number_length=None,
+ video_state=None,
+ slot_id_callee=None,
+ voice_type_init=None,
+ call_stats_check=False,
+ result_info=result_dict):
+ """ Call process, including make a phone call from caller,
+ accept from callee, and hang up. The call is on default voice subscription
+
+ In call process, call from <droid_caller> to <droid_callee>,
+ accept the call, (optional)then hang up from <droid_hangup>.
+
+ Args:
+ ad_caller: Caller Android Device Object.
+ ad_callee: Callee Android Device Object.
+ ad_hangup: Android Device Object end the phone call.
+ Optional. Default value is None, and phone call will continue.
+ verify_call_mode_caller: func_ptr to verify caller in correct mode
+ Optional. Default is None
+ verify_call_mode_caller: func_ptr to verify caller in correct mode
+ Optional. Default is None
+ incall_ui_display: after answer the call, bring in-call UI to foreground or
+ background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
+ if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
+ if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
+ else, do nothing.
+ dialing_number_length: the number of digits used for dialing
+ slot_id_callee : the slot if of the callee to call to
+
+ Returns:
+ True if call process without any error.
+ False if error happened.
+
+ """
+ subid_caller = get_outgoing_voice_sub_id(ad_caller)
+ if slot_id_callee is None:
+ subid_callee = get_incoming_voice_sub_id(ad_callee)
+ else:
+ subid_callee = get_subid_from_slot_index(log, ad_callee, slot_id_callee)
+
+ return call_setup_teardown_for_subscription(
+ log, ad_caller, ad_callee, subid_caller, subid_callee, ad_hangup,
+ verify_caller_func, verify_callee_func, wait_time_in_call,
+ incall_ui_display, dialing_number_length, video_state,
+ voice_type_init, call_stats_check, result_info)
+
+
+def call_setup_teardown_for_subscription(
+ log,
+ ad_caller,
+ ad_callee,
+ subid_caller,
+ subid_callee,
+ ad_hangup=None,
+ verify_caller_func=None,
+ verify_callee_func=None,
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ dialing_number_length=None,
+ video_state=None,
+ voice_type_init=None,
+ call_stats_check=False,
+ result_info=result_dict):
+ """ Call process, including make a phone call from caller,
+ accept from callee, and hang up. The call is on specified subscription
+
+ In call process, call from <droid_caller> to <droid_callee>,
+ accept the call, (optional)then hang up from <droid_hangup>.
+
+ Args:
+ ad_caller: Caller Android Device Object.
+ ad_callee: Callee Android Device Object.
+ subid_caller: Caller subscription ID
+ subid_callee: Callee subscription ID
+ ad_hangup: Android Device Object end the phone call.
+ Optional. Default value is None, and phone call will continue.
+ verify_call_mode_caller: func_ptr to verify caller in correct mode
+ Optional. Default is None
+ verify_call_mode_caller: func_ptr to verify caller in correct mode
+ Optional. Default is None
+ incall_ui_display: after answer the call, bring in-call UI to foreground or
+ background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
+ if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
+ if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
+ else, do nothing.
+
+ Returns:
+ TelResultWrapper which will evaluate as False if error.
+
+ """
+ CHECK_INTERVAL = 5
+ begin_time = get_current_epoch_time()
+ if not verify_caller_func:
+ verify_caller_func = is_phone_in_call
+ if not verify_callee_func:
+ verify_callee_func = is_phone_in_call
+
+ caller_number = ad_caller.telephony['subscription'][subid_caller][
+ 'phone_num']
+ callee_number = ad_callee.telephony['subscription'][subid_callee][
+ 'phone_num']
+
+ callee_number = truncate_phone_number(
+ log,
+ caller_number,
+ callee_number,
+ dialing_number_length)
+
+ tel_result_wrapper = TelResultWrapper(CallResult('SUCCESS'))
+ msg = "Call from %s to %s" % (caller_number, callee_number)
+ if video_state:
+ msg = "Video %s" % msg
+ video = True
+ else:
+ video = False
+ if ad_hangup:
+ msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
+ ad_caller.log.info(msg)
+
+ for ad in (ad_caller, ad_callee):
+ call_ids = ad.droid.telecomCallGetCallIds()
+ setattr(ad, "call_ids", call_ids)
+ if call_ids:
+ ad.log.info("Pre-exist CallId %s before making call", call_ids)
+
+ if not initiate_call(
+ log,
+ ad_caller,
+ callee_number,
+ incall_ui_display=incall_ui_display,
+ video=video):
+ ad_caller.log.error("Initiate call failed.")
+ tel_result_wrapper.result_value = CallResult('INITIATE_FAILED')
+ return tel_result_wrapper
+ else:
+ ad_caller.log.info("Caller initate call successfully")
+ if not wait_and_answer_call_for_subscription(
+ log,
+ ad_callee,
+ subid_callee,
+ incoming_number=caller_number,
+ caller=ad_caller,
+ incall_ui_display=incall_ui_display,
+ video_state=video_state):
+ ad_callee.log.error("Answer call fail.")
+ tel_result_wrapper.result_value = CallResult(
+ 'NO_RING_EVENT_OR_ANSWER_FAILED')
+ return tel_result_wrapper
+ else:
+ ad_callee.log.info("Callee answered the call successfully")
+
+ for ad, call_func in zip([ad_caller, ad_callee],
+ [verify_caller_func, verify_callee_func]):
+ call_ids = ad.droid.telecomCallGetCallIds()
+ new_call_ids = set(call_ids) - set(ad.call_ids)
+ if not new_call_ids:
+ ad.log.error(
+ "No new call ids are found after call establishment")
+ ad.log.error("telecomCallGetCallIds returns %s",
+ ad.droid.telecomCallGetCallIds())
+ tel_result_wrapper.result_value = CallResult('NO_CALL_ID_FOUND')
+ for new_call_id in new_call_ids:
+ if not wait_for_in_call_active(ad, call_id=new_call_id):
+ tel_result_wrapper.result_value = CallResult(
+ 'CALL_STATE_NOT_ACTIVE_DURING_ESTABLISHMENT')
+ else:
+ ad.log.info("callProperties = %s",
+ ad.droid.telecomCallGetProperties(new_call_id))
+
+ if not ad.droid.telecomCallGetAudioState():
+ ad.log.error("Audio is not in call state")
+ tel_result_wrapper.result_value = CallResult(
+ 'AUDIO_STATE_NOT_INCALL_DURING_ESTABLISHMENT')
+
+ if call_func(log, ad):
+ ad.log.info("Call is in %s state", call_func.__name__)
+ else:
+ ad.log.error("Call is not in %s state, voice in RAT %s",
+ call_func.__name__,
+ ad.droid.telephonyGetCurrentVoiceNetworkType())
+ tel_result_wrapper.result_value = CallResult(
+ 'CALL_DROP_OR_WRONG_STATE_DURING_ESTABLISHMENT')
+ if not tel_result_wrapper:
+ return tel_result_wrapper
+
+ if call_stats_check:
+ voice_type_in_call = check_voice_network_type([ad_caller, ad_callee], voice_init=False)
+ phone_a_call_type = check_call_status(ad_caller,
+ voice_type_init[0],
+ voice_type_in_call[0])
+ result_info["Call Stats"] = phone_a_call_type
+ ad_caller.log.debug("Voice Call Type: %s", phone_a_call_type)
+ phone_b_call_type = check_call_status(ad_callee,
+ voice_type_init[1],
+ voice_type_in_call[1])
+ result_info["Call Stats"] = phone_b_call_type
+ ad_callee.log.debug("Voice Call Type: %s", phone_b_call_type)
+
+ return wait_for_call_end(
+ log,
+ ad_caller,
+ ad_callee,
+ ad_hangup,
+ verify_caller_func,
+ verify_callee_func,
+ begin_time,
+ check_interval=CHECK_INTERVAL,
+ tel_result_wrapper=TelResultWrapper(CallResult('SUCCESS')),
+ wait_time_in_call=wait_time_in_call)
def two_phone_call_leave_voice_mail(
@@ -495,1098 +1316,38 @@
return tel_result
-def three_phone_call_forwarding_short_seq(log,
- phone_a,
- phone_a_idle_func,
- phone_a_in_call_check_func,
- phone_b,
- phone_c,
- wait_time_in_call=WAIT_TIME_IN_CALL,
- call_forwarding_type="unconditional",
- retry=2):
- """Short sequence of call process with call forwarding.
- Test steps:
- 1. Ensure all phones are initially in idle state.
- 2. Enable call forwarding on Phone A.
- 3. Make a call from Phone B to Phone A, The call should be forwarded to
- PhoneC. Accept the call on Phone C.
- 4. Ensure the call is connected and in correct phone state.
- 5. Hang up the call on Phone B.
- 6. Ensure all phones are in idle state.
- 7. Disable call forwarding on Phone A.
- 7. Make a call from Phone B to Phone A, The call should NOT be forwarded
- to PhoneC. Accept the call on Phone A.
- 8. Ensure the call is connected and in correct phone state.
- 9. Hang up the call on Phone B.
+
+def is_phone_in_call(log, ad):
+ """Return True if phone in call.
Args:
- phone_a: android object of Phone A
- phone_a_idle_func: function to check idle state on Phone A
- phone_a_in_call_check_func: function to check in-call state on Phone A
- phone_b: android object of Phone B
- phone_c: android object of Phone C
- wait_time_in_call: time to wait in call.
- This is optional, default is WAIT_TIME_IN_CALL
- call_forwarding_type:
- - "unconditional"
- - "busy"
- - "not_answered"
- - "not_reachable"
- retry: times of retry
-
- Returns:
- True: if call sequence succeed.
- False: for errors
+ log: log object.
+ ad: android device.
"""
- ads = [phone_a, phone_b, phone_c]
-
- call_params = [
- (ads[1], ads[0], ads[2], ads[1], phone_a_in_call_check_func, False)
- ]
-
- if call_forwarding_type != "unconditional":
- call_params.append((
- ads[1],
- ads[0],
- ads[2],
- ads[1],
- phone_a_in_call_check_func,
- True))
-
- for param in call_params:
- ensure_phones_idle(log, ads)
- if phone_a_idle_func and not phone_a_idle_func(log, phone_a):
- phone_a.log.error("Phone A Failed to Reselect")
- return False
-
- time.sleep(WAIT_TIME_BETWEEN_REG_AND_CALL)
-
- log.info(
- "---> Call forwarding %s (caller: %s, callee: %s, callee forwarded:"
- " %s) <---",
- call_forwarding_type,
- param[0].serial,
- param[1].serial,
- param[2].serial)
- while not call_setup_teardown_for_call_forwarding(
- log,
- *param,
- wait_time_in_call=wait_time_in_call,
- call_forwarding_type=call_forwarding_type) and retry >= 0:
-
- if retry <= 0:
- log.error("Call forwarding %s failed." % call_forwarding_type)
- return False
- else:
- log.info(
- "RERUN the test case: 'Call forwarding %s'" %
- call_forwarding_type)
-
- retry = retry - 1
-
- return True
-
-def three_phone_call_waiting_short_seq(log,
- phone_a,
- phone_a_idle_func,
- phone_a_in_call_check_func,
- phone_b,
- phone_c,
- wait_time_in_call=WAIT_TIME_IN_CALL,
- call_waiting=True,
- scenario=None,
- retry=2):
- """Short sequence of call process with call waiting.
- Test steps:
- 1. Ensure all phones are initially in idle state.
- 2. Enable call waiting on Phone A.
- 3. Make the 1st call from Phone B to Phone A. Accept the call on Phone B.
- 4. Ensure the call is connected and in correct phone state.
- 5. Make the 2nd call from Phone C to Phone A. The call should be able to
- income correctly. Whether or not the 2nd call should be answered by
- Phone A depends on the scenario listed in the next step.
- 6. Following 8 scenarios will be tested:
- - 1st call ended first by Phone B during 2nd call incoming. 2nd call
- ended by Phone C
- - 1st call ended first by Phone B during 2nd call incoming. 2nd call
- ended by Phone A
- - 1st call ended first by Phone A during 2nd call incoming. 2nd call
- ended by Phone C
- - 1st call ended first by Phone A during 2nd call incoming. 2nd call
- ended by Phone A
- - 1st call ended by Phone B. 2nd call ended by Phone C
- - 1st call ended by Phone B. 2nd call ended by Phone A
- - 1st call ended by Phone A. 2nd call ended by Phone C
- - 1st call ended by Phone A. 2nd call ended by Phone A
- 7. Ensure all phones are in idle state.
-
- Args:
- phone_a: android object of Phone A
- phone_a_idle_func: function to check idle state on Phone A
- phone_a_in_call_check_func: function to check in-call state on Phone A
- phone_b: android object of Phone B
- phone_c: android object of Phone C
- wait_time_in_call: time to wait in call.
- This is optional, default is WAIT_TIME_IN_CALL
- call_waiting: True for call waiting enabled and False for disabled
- scenario: 1-8 for scenarios listed above
- retry: times of retry
-
- Returns:
- True: if call sequence succeed.
- False: for errors
- """
- ads = [phone_a, phone_b, phone_c]
-
- sub_test_cases = [
- {
- "description": "1st call ended first by caller1 during 2nd call"
- " incoming. 2nd call ended by caller2",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[1],
- ads[2],
- phone_a_in_call_check_func,
- True)},
- {
- "description": "1st call ended first by caller1 during 2nd call"
- " incoming. 2nd call ended by callee",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[1],
- ads[0],
- phone_a_in_call_check_func,
- True)},
- {
- "description": "1st call ended first by callee during 2nd call"
- " incoming. 2nd call ended by caller2",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[0],
- ads[2],
- phone_a_in_call_check_func,
- True)},
- {
- "description": "1st call ended first by callee during 2nd call"
- " incoming. 2nd call ended by callee",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[0],
- ads[0],
- phone_a_in_call_check_func,
- True)},
- {
- "description": "1st call ended by caller1. 2nd call ended by"
- " caller2",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[1],
- ads[2],
- phone_a_in_call_check_func,
- False)},
- {
- "description": "1st call ended by caller1. 2nd call ended by callee",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[1],
- ads[0],
- phone_a_in_call_check_func,
- False)},
- {
- "description": "1st call ended by callee. 2nd call ended by caller2",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[0],
- ads[2],
- phone_a_in_call_check_func,
- False)},
- {
- "description": "1st call ended by callee. 2nd call ended by callee",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[0],
- ads[0],
- phone_a_in_call_check_func,
- False)}
- ]
-
- if call_waiting:
- if not scenario:
- test_cases = sub_test_cases
- else:
- test_cases = [sub_test_cases[scenario-1]]
- else:
- test_cases = [
- {
- "description": "Call waiting deactivated",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[0],
- ads[0],
- phone_a_in_call_check_func,
- False)}
- ]
-
- results = []
-
- for test_case in test_cases:
- ensure_phones_idle(log, ads)
- if phone_a_idle_func and not phone_a_idle_func(log, phone_a):
- phone_a.log.error("Phone A Failed to Reselect")
- return False
-
- time.sleep(WAIT_TIME_BETWEEN_REG_AND_CALL)
-
- log.info(
- "---> %s (caller1: %s, caller2: %s, callee: %s) <---",
- test_case["description"],
- test_case["params"][1].serial,
- test_case["params"][2].serial,
- test_case["params"][0].serial)
-
- while not call_setup_teardown_for_call_waiting(
- log,
- *test_case["params"],
- wait_time_in_call=wait_time_in_call,
- call_waiting=call_waiting) and retry >= 0:
-
- if retry <= 0:
- log.error("Call waiting sub-case: '%s' failed." % test_case[
- "description"])
- results.append(False)
- else:
- log.info("RERUN the sub-case: '%s'" % test_case["description"])
-
- retry = retry - 1
-
- for result in results:
- if not result:
- return False
-
- return True
-
-def phone_setup_iwlan(log,
- ad,
- is_airplane_mode,
- wfc_mode,
- wifi_ssid=None,
- wifi_pwd=None,
- nw_gen=None):
- """Phone setup function for epdg call test.
- Set WFC mode according to wfc_mode.
- Set airplane mode according to is_airplane_mode.
- Make sure phone connect to WiFi. (If wifi_ssid is not None.)
- Wait for phone to be in iwlan data network type.
- Wait for phone to report wfc enabled flag to be true.
- Args:
- log: Log object.
- ad: Android device object.
- is_airplane_mode: True to turn on airplane mode. False to turn off airplane mode.
- wfc_mode: WFC mode to set to.
- wifi_ssid: WiFi network SSID. This is optional.
- If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi.
- wifi_pwd: WiFi network password. This is optional.
- nw_gen: network type selection. This is optional.
- GEN_4G for 4G, GEN_5G for 5G or None for doing nothing.
- Returns:
- True if success. False if fail.
- """
- return phone_setup_iwlan_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad),
- is_airplane_mode, wfc_mode,
- wifi_ssid, wifi_pwd, nw_gen)
-
-
-def phone_setup_iwlan_for_subscription(log,
- ad,
- sub_id,
- is_airplane_mode,
- wfc_mode,
- wifi_ssid=None,
- wifi_pwd=None,
- nw_gen=None):
- """Phone setup function for epdg call test for subscription id.
- Set WFC mode according to wfc_mode.
- Set airplane mode according to is_airplane_mode.
- Make sure phone connect to WiFi. (If wifi_ssid is not None.)
- Wait for phone to be in iwlan data network type.
- Wait for phone to report wfc enabled flag to be true.
- Args:
- log: Log object.
- ad: Android device object.
- sub_id: subscription id.
- is_airplane_mode: True to turn on airplane mode. False to turn off airplane mode.
- wfc_mode: WFC mode to set to.
- wifi_ssid: WiFi network SSID. This is optional.
- If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi.
- wifi_pwd: WiFi network password. This is optional.
- nw_gen: network type selection. This is optional.
- GEN_4G for 4G, GEN_5G for 5G or None for doing nothing.
- Returns:
- True if success. False if fail.
- """
- if not get_capability_for_subscription(ad, CAPABILITY_WFC, sub_id):
- ad.log.error("WFC is not supported, abort test.")
- raise signals.TestSkip("WFC is not supported, abort test.")
-
- if nw_gen:
- if not ensure_network_generation_for_subscription(
- log, ad, sub_id, nw_gen, voice_or_data=NETWORK_SERVICE_DATA):
- ad.log.error("Failed to set to %s data.", nw_gen)
- return False
- toggle_airplane_mode(log, ad, is_airplane_mode, strict_checking=False)
-
- if not toggle_volte_for_subscription(log, ad, sub_id, new_state=True):
- return False
-
- # check if WFC supported phones
- if wfc_mode != WFC_MODE_DISABLED and not ad.droid.imsIsWfcEnabledByPlatform(
- ):
- ad.log.error("WFC is not enabled on this device by checking "
- "ImsManager.isWfcEnabledByPlatform")
- return False
- if wifi_ssid is not None:
- if not ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd, apm=is_airplane_mode):
- ad.log.error("Fail to bring up WiFi connection on %s.", wifi_ssid)
- return False
- else:
- ad.log.info("WiFi network SSID not specified, available user "
- "parameters are: wifi_network_ssid, wifi_network_ssid_2g, "
- "wifi_network_ssid_5g")
- if not set_wfc_mode_for_subscription(ad, wfc_mode, sub_id):
- ad.log.error("Unable to set WFC mode to %s.", wfc_mode)
- return False
-
- if wfc_mode != WFC_MODE_DISABLED:
- if not wait_for_wfc_enabled(log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
- ad.log.error("WFC is not enabled")
- return False
-
- return True
-
-
-def phone_setup_iwlan_cellular_preferred(log,
- ad,
- wifi_ssid=None,
- wifi_pwd=None):
- """Phone setup function for iwlan Non-APM CELLULAR_PREFERRED test.
- Set WFC mode according to CELLULAR_PREFERRED.
- Set airplane mode according to False.
- Make sure phone connect to WiFi. (If wifi_ssid is not None.)
- Make sure phone don't report iwlan data network type.
- Make sure phone don't report wfc enabled flag to be true.
-
- Args:
- log: Log object.
- ad: Android device object.
- wifi_ssid: WiFi network SSID. This is optional.
- If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi.
- wifi_pwd: WiFi network password. This is optional.
-
- Returns:
- True if success. False if fail.
- """
- toggle_airplane_mode(log, ad, False, strict_checking=False)
try:
- toggle_volte(log, ad, True)
- if not wait_for_network_generation(
- log, ad, GEN_4G, voice_or_data=NETWORK_SERVICE_DATA):
- if not ensure_network_generation(
- log, ad, GEN_4G, voice_or_data=NETWORK_SERVICE_DATA):
- ad.log.error("Fail to ensure data in 4G")
- return False
- except Exception as e:
- ad.log.error(e)
- ad.droid.telephonyToggleDataConnection(True)
- if wifi_ssid is not None:
- if not ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd):
- ad.log.error("Connect to WiFi failed.")
- return False
- if not set_wfc_mode(log, ad, WFC_MODE_CELLULAR_PREFERRED):
- ad.log.error("Set WFC mode failed.")
- return False
- if not wait_for_not_network_rat(
- log, ad, RAT_FAMILY_WLAN, voice_or_data=NETWORK_SERVICE_DATA):
- ad.log.error("Data rat in iwlan mode.")
- return False
- elif not wait_for_wfc_disabled(log, ad, MAX_WAIT_TIME_WFC_ENABLED):
- ad.log.error("Should report wifi calling disabled within %s.",
- MAX_WAIT_TIME_WFC_ENABLED)
- return False
- return True
+ return ad.droid.telecomIsInCall()
+ except:
+ return "mCallState=2" in ad.adb.shell(
+ "dumpsys telephony.registry | grep mCallState")
-def phone_setup_data_for_subscription(log, ad, sub_id, network_generation):
- """Setup Phone <sub_id> Data to <network_generation>
+def is_phone_in_call_active(ad, call_id=None):
+ """Return True if phone in active call.
Args:
- log: log object
- ad: android device object
- sub_id: subscription id
- network_generation: network generation, e.g. GEN_2G, GEN_3G, GEN_4G, GEN_5G
-
- Returns:
- True if success, False if fail.
+ log: log object.
+ ad: android device.
+ call_id: the call id
"""
- 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
- if not ensure_network_generation_for_subscription(
- log,
- ad,
- sub_id,
- network_generation,
- voice_or_data=NETWORK_SERVICE_DATA):
- get_telephony_signal_strength(ad)
- return False
- return True
-
-
-def phone_setup_5g(log, ad):
- """Setup Phone default data sub_id data to 5G.
-
- Args:
- log: log object
- ad: android device object
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_5g_for_subscription(log, ad,
- get_default_data_sub_id(ad))
-
-
-def phone_setup_5g_for_subscription(log, ad, sub_id):
- """Setup Phone <sub_id> Data to 5G.
-
- Args:
- log: log object
- ad: android device object
- sub_id: subscription id
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_data_for_subscription(log, ad, sub_id, GEN_5G)
-
-
-def phone_setup_4g(log, ad):
- """Setup Phone default data sub_id data to 4G.
-
- Args:
- log: log object
- ad: android device object
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_4g_for_subscription(log, ad,
- get_default_data_sub_id(ad))
-
-
-def phone_setup_4g_for_subscription(log, ad, sub_id):
- """Setup Phone <sub_id> Data to 4G.
-
- Args:
- log: log object
- ad: android device object
- sub_id: subscription id
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_data_for_subscription(log, ad, sub_id, GEN_4G)
-
-
-def phone_setup_3g(log, ad):
- """Setup Phone default data sub_id data to 3G.
-
- Args:
- log: log object
- ad: android device object
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_3g_for_subscription(log, ad,
- get_default_data_sub_id(ad))
-
-
-def phone_setup_3g_for_subscription(log, ad, sub_id):
- """Setup Phone <sub_id> Data to 3G.
-
- Args:
- log: log object
- ad: android device object
- sub_id: subscription id
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_data_for_subscription(log, ad, sub_id, GEN_3G)
-
-
-def phone_setup_2g(log, ad):
- """Setup Phone default data sub_id data to 2G.
-
- Args:
- log: log object
- ad: android device object
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_2g_for_subscription(log, ad,
- get_default_data_sub_id(ad))
-
-
-def phone_setup_2g_for_subscription(log, ad, sub_id):
- """Setup Phone <sub_id> Data to 3G.
-
- Args:
- log: log object
- ad: android device object
- sub_id: subscription id
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_data_for_subscription(log, ad, sub_id, GEN_2G)
-
-
-def phone_setup_csfb(log, ad, nw_gen=GEN_4G):
- """Setup phone for CSFB call test.
-
- Setup Phone to be in 4G mode.
- Disabled VoLTE.
-
- Args:
- log: log object
- ad: Android device object.
- nw_gen: GEN_4G or GEN_5G
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- return phone_setup_csfb_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad), nw_gen)
-
-
-def phone_setup_csfb_for_subscription(log, ad, sub_id, nw_gen=GEN_4G):
- """Setup phone for CSFB call test for subscription id.
-
- Setup Phone to be in 4G mode.
- Disabled VoLTE.
-
- Args:
- log: log object
- ad: Android device object.
- sub_id: subscription id.
- nw_gen: GEN_4G or GEN_5G
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- capabilities = ad.telephony["subscription"][sub_id].get("capabilities", [])
- if capabilities:
- if "hide_enhanced_4g_lte" in capabilities:
- show_enhanced_4g_lte_mode = getattr(ad, "show_enhanced_4g_lte_mode", False)
- if show_enhanced_4g_lte_mode in ["false", "False", False]:
- ad.log.warning("'VoLTE' option is hidden. Test will be skipped.")
- raise signals.TestSkip("'VoLTE' option is hidden. Test will be skipped.")
-
- if nw_gen == GEN_4G:
- if not phone_setup_4g_for_subscription(log, ad, sub_id):
- ad.log.error("Failed to set to 4G data.")
- return False
- elif nw_gen == GEN_5G:
- if not phone_setup_5g_for_subscription(log, ad, sub_id):
- ad.log.error("Failed to set to 5G data.")
- return False
-
- toggle_volte_for_subscription(log, ad, sub_id, False)
-
- if not ensure_network_generation_for_subscription(
- log, ad, sub_id, nw_gen, voice_or_data=NETWORK_SERVICE_DATA):
- return False
-
- if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
- MAX_WAIT_TIME_NW_SELECTION):
- return False
-
- return phone_idle_csfb_for_subscription(log, ad, sub_id, nw_gen)
-
-def phone_setup_volte(log, ad, nw_gen=GEN_4G):
- """Setup VoLTE enable.
-
- Args:
- log: log object
- ad: android device object.
- nw_gen: GEN_4G or GEN_5G
-
- Returns:
- True: if VoLTE is enabled successfully.
- False: for errors
- """
- if not get_capability_for_subscription(ad, CAPABILITY_VOLTE,
- get_outgoing_voice_sub_id(ad)):
- ad.log.error("VoLTE is not supported, abort test.")
- raise signals.TestSkip("VoLTE is not supported, abort test.")
- return phone_setup_volte_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad), nw_gen)
-
-def phone_setup_volte_for_subscription(log, ad, sub_id, nw_gen=GEN_4G):
- """Setup VoLTE enable for subscription id.
- Args:
- log: log object
- ad: android device object.
- sub_id: subscription id.
- nw_gen: GEN_4G or GEN_5G
-
- Returns:
- True: if VoLTE is enabled successfully.
- False: for errors
- """
- if not get_capability_for_subscription(ad, CAPABILITY_VOLTE,
- get_outgoing_voice_sub_id(ad)):
- ad.log.error("VoLTE is not supported, abort test.")
- raise signals.TestSkip("VoLTE is not supported, abort test.")
-
- if nw_gen == GEN_4G:
- if not phone_setup_4g_for_subscription(log, ad, sub_id):
- ad.log.error("Failed to set to 4G data.")
- return False
- elif nw_gen == GEN_5G:
- if not phone_setup_5g_for_subscription(log, ad, sub_id):
- ad.log.error("Failed to set to 5G data.")
- return False
- operator_name = get_operator_name(log, ad, sub_id)
- if operator_name == CARRIER_TMO:
- return True
+ if ad.droid.telecomIsInCall():
+ 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"
else:
- if not wait_for_enhanced_4g_lte_setting(log, ad, sub_id):
- ad.log.error("Enhanced 4G LTE setting is not available")
- return False
- toggle_volte_for_subscription(log, ad, sub_id, True)
- return phone_idle_volte_for_subscription(log, ad, sub_id, nw_gen)
-
-
-def phone_setup_voice_3g(log, ad):
- """Setup phone voice to 3G.
-
- Args:
- log: log object
- ad: Android device object.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- return phone_setup_voice_3g_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_setup_voice_3g_for_subscription(log, ad, sub_id):
- """Setup phone voice to 3G for subscription id.
-
- Args:
- log: log object
- ad: Android device object.
- sub_id: subscription id.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- if not phone_setup_3g_for_subscription(log, ad, sub_id):
- ad.log.error("Failed to set to 3G data.")
+ ad.log.info("Not in telecomIsInCall")
return False
- if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
- MAX_WAIT_TIME_NW_SELECTION):
- return False
- return phone_idle_3g_for_subscription(log, ad, sub_id)
-
-
-def phone_setup_voice_2g(log, ad):
- """Setup phone voice to 2G.
-
- Args:
- log: log object
- ad: Android device object.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- return phone_setup_voice_2g_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_setup_voice_2g_for_subscription(log, ad, sub_id):
- """Setup phone voice to 2G for subscription id.
-
- Args:
- log: log object
- ad: Android device object.
- sub_id: subscription id.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- if not phone_setup_2g_for_subscription(log, ad, sub_id):
- ad.log.error("Failed to set to 2G data.")
- return False
- if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
- MAX_WAIT_TIME_NW_SELECTION):
- return False
- return phone_idle_2g_for_subscription(log, ad, sub_id)
-
-
-def phone_setup_voice_general(log, ad):
- """Setup phone for voice general call test.
-
- Make sure phone attached to voice.
- Make necessary delay.
-
- Args:
- ad: Android device object.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- return phone_setup_voice_general_for_subscription(
- log, ad, get_outgoing_voice_sub_id(ad))
-
-
-def phone_setup_voice_general_for_slot(log,ad,slot_id):
- return phone_setup_voice_general_for_subscription(
- log, ad, get_subid_from_slot_index(log,ad,slot_id))
-
-
-def phone_setup_voice_general_for_subscription(log, ad, sub_id):
- """Setup phone for voice general call test for subscription id.
-
- Make sure phone attached to voice.
- Make necessary delay.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- toggle_airplane_mode(log, ad, False, strict_checking=False)
- if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
- MAX_WAIT_TIME_NW_SELECTION):
- # if phone can not attach voice, try phone_setup_voice_3g
- return phone_setup_voice_3g_for_subscription(log, ad, sub_id)
- return True
-
-
-def phone_setup_data_general(log, ad):
- """Setup phone for data general test.
-
- Make sure phone attached to data.
- Make necessary delay.
-
- Args:
- ad: Android device object.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- return phone_setup_data_general_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultDataSubId())
-
-
-def phone_setup_data_general_for_subscription(log, ad, sub_id):
- """Setup phone for data general test for subscription id.
-
- Make sure phone attached to data.
- Make necessary delay.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- toggle_airplane_mode(log, ad, False, strict_checking=False)
- if not wait_for_data_attach_for_subscription(log, ad, sub_id,
- MAX_WAIT_TIME_NW_SELECTION):
- # if phone can not attach data, try reset network preference settings
- reset_preferred_network_type_to_allowable_range(log, ad)
-
- return wait_for_data_attach_for_subscription(log, ad, sub_id,
- MAX_WAIT_TIME_NW_SELECTION)
-
-
-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
- return ensure_network_rat_for_subscription(log, ad, sub_id,
- network_preference, rat_family)
-
-
-def phone_setup_lte_gsm_wcdma(log, ad):
- return phone_setup_lte_gsm_wcdma_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId())
-
-
-def phone_setup_lte_gsm_wcdma_for_subscription(log, ad, sub_id):
- return phone_setup_rat_for_subscription(
- log, ad, sub_id, NETWORK_MODE_LTE_GSM_WCDMA, RAT_FAMILY_LTE)
-
-
-def phone_setup_gsm_umts(log, ad):
- return phone_setup_gsm_umts_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId())
-
-
-def phone_setup_gsm_umts_for_subscription(log, ad, sub_id):
- return phone_setup_rat_for_subscription(
- log, ad, sub_id, NETWORK_MODE_GSM_UMTS, RAT_FAMILY_WCDMA)
-
-
-def phone_setup_gsm_only(log, ad):
- return phone_setup_gsm_only_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId())
-
-
-def phone_setup_gsm_only_for_subscription(log, ad, sub_id):
- return phone_setup_rat_for_subscription(
- log, ad, sub_id, NETWORK_MODE_GSM_ONLY, RAT_FAMILY_GSM)
-
-
-def phone_setup_lte_cdma_evdo(log, ad):
- return phone_setup_lte_cdma_evdo_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId())
-
-
-def phone_setup_lte_cdma_evdo_for_subscription(log, ad, sub_id):
- return phone_setup_rat_for_subscription(
- log, ad, sub_id, NETWORK_MODE_LTE_CDMA_EVDO, RAT_FAMILY_LTE)
-
-
-def phone_setup_cdma(log, ad):
- return phone_setup_cdma_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId())
-
-
-def phone_setup_cdma_for_subscription(log, ad, sub_id):
- return phone_setup_rat_for_subscription(log, ad, sub_id, NETWORK_MODE_CDMA,
- RAT_FAMILY_CDMA2000)
-
-
-def phone_idle_volte(log, ad):
- """Return if phone is idle for VoLTE call test.
-
- Args:
- ad: Android device object.
- """
- return phone_idle_volte_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_idle_volte_for_subscription(log, ad, sub_id, nw_gen=GEN_4G):
- """Return if phone is idle for VoLTE call test for subscription id.
- Args:
- ad: Android device object.
- sub_id: subscription id.
- nw_gen: GEN_4G or GEN_5G
- """
- if nw_gen == GEN_5G:
- if not is_current_network_5g_nsa_for_subscription(ad, sub_id=sub_id):
- ad.log.error("Not in 5G NSA coverage.")
- return False
- else:
- if not wait_for_network_rat_for_subscription(
- log, ad, sub_id, RAT_FAMILY_LTE,
- voice_or_data=NETWORK_SERVICE_VOICE):
- ad.log.error("Voice rat not in LTE mode.")
- return False
- if not wait_for_volte_enabled(log, ad, MAX_WAIT_TIME_VOLTE_ENABLED, sub_id):
- ad.log.error(
- "Failed to <report volte enabled true> within %s seconds.",
- MAX_WAIT_TIME_VOLTE_ENABLED)
- return False
- return True
-
-
-def phone_idle_iwlan(log, ad):
- """Return if phone is idle for WiFi calling call test.
-
- Args:
- ad: Android device object.
- """
- return phone_idle_iwlan_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_idle_iwlan_for_subscription(log, ad, sub_id):
- """Return if phone is idle for WiFi calling call test for subscription id.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
- """
- if not wait_for_wfc_enabled(log, ad, MAX_WAIT_TIME_WFC_ENABLED):
- ad.log.error("Failed to <report wfc enabled true> within %s seconds.",
- MAX_WAIT_TIME_WFC_ENABLED)
- return False
- return True
-
-
-def phone_idle_not_iwlan(log, ad):
- """Return if phone is idle for non WiFi calling call test.
-
- Args:
- ad: Android device object.
- """
- return phone_idle_not_iwlan_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_idle_not_iwlan_for_subscription(log, ad, sub_id):
- """Return if phone is idle for non WiFi calling call test for sub id.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
- """
- if not wait_for_not_network_rat_for_subscription(
- log, ad, sub_id, RAT_FAMILY_WLAN,
- voice_or_data=NETWORK_SERVICE_DATA):
- log.error("{} data rat in iwlan mode.".format(ad.serial))
- return False
- return True
-
-
-def phone_idle_csfb(log, ad):
- """Return if phone is idle for CSFB call test.
-
- Args:
- ad: Android device object.
- """
- return phone_idle_csfb_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_idle_csfb_for_subscription(log, ad, sub_id, nw_gen=GEN_4G):
- """Return if phone is idle for CSFB call test for subscription id.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
- nw_gen: GEN_4G or GEN_5G
- """
- if nw_gen == GEN_5G:
- if not is_current_network_5g_nsa_for_subscription(ad, sub_id=sub_id):
- ad.log.error("Not in 5G NSA coverage.")
- return False
- else:
- if not wait_for_network_rat_for_subscription(
- log, ad, sub_id, RAT_FAMILY_LTE,
- voice_or_data=NETWORK_SERVICE_DATA):
- ad.log.error("Data rat not in lte mode.")
- return False
- return True
-
-
-def phone_idle_3g(log, ad):
- """Return if phone is idle for 3G call test.
-
- Args:
- ad: Android device object.
- """
- return phone_idle_3g_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_idle_3g_for_subscription(log, ad, sub_id):
- """Return if phone is idle for 3G call test for subscription id.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
- """
- return wait_for_network_generation_for_subscription(
- log, ad, sub_id, GEN_3G, voice_or_data=NETWORK_SERVICE_VOICE)
-
-
-def phone_idle_2g(log, ad):
- """Return if phone is idle for 2G call test.
-
- Args:
- ad: Android device object.
- """
- return phone_idle_2g_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_idle_2g_for_subscription(log, ad, sub_id):
- """Return if phone is idle for 2G call test for subscription id.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
- """
- 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
-
- Args:
- ad: Android device object.
- """
- 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.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
- """
- return get_network_rat_for_subscription(log, ad, sub_id,
- NETWORK_SERVICE_VOICE)
def is_phone_in_call_volte(log, ad):
@@ -1967,85 +1728,6 @@
return call
return None
-def phone_setup_on_rat(
- log,
- ad,
- rat='volte',
- sub_id=None,
- is_airplane_mode=False,
- wfc_mode=None,
- wifi_ssid=None,
- wifi_pwd=None,
- only_return_fn=None,
- sub_id_type='voice'):
-
- if sub_id is None:
- if sub_id_type == 'sms':
- sub_id = get_outgoing_message_sub_id(ad)
- else:
- sub_id = get_outgoing_voice_sub_id(ad)
-
- if rat.lower() == '5g_volte':
- if only_return_fn:
- return phone_setup_volte_for_subscription
- else:
- return phone_setup_volte_for_subscription(log, ad, sub_id, GEN_5G)
-
- elif rat.lower() == '5g_csfb':
- if only_return_fn:
- return phone_setup_csfb_for_subscription
- else:
- return phone_setup_csfb_for_subscription(log, ad, sub_id, GEN_5G)
-
- elif rat.lower() == '5g_wfc':
- if only_return_fn:
- return phone_setup_iwlan_for_subscription
- else:
- return phone_setup_iwlan_for_subscription(
- log,
- ad,
- sub_id,
- is_airplane_mode,
- wfc_mode,
- wifi_ssid,
- wifi_pwd,
- GEN_5G)
-
- elif rat.lower() == 'volte':
- if only_return_fn:
- return phone_setup_volte_for_subscription
- else:
- return phone_setup_volte_for_subscription(log, ad, sub_id)
-
- elif rat.lower() == 'csfb':
- if only_return_fn:
- return phone_setup_csfb_for_subscription
- else:
- return phone_setup_csfb_for_subscription(log, ad, sub_id)
-
- elif rat.lower() == '3g':
- if only_return_fn:
- return phone_setup_voice_3g_for_subscription
- else:
- return phone_setup_voice_3g_for_subscription(log, ad, sub_id)
-
- elif rat.lower() == 'wfc':
- if only_return_fn:
- return phone_setup_iwlan_for_subscription
- else:
- return phone_setup_iwlan_for_subscription(
- log,
- ad,
- sub_id,
- is_airplane_mode,
- wfc_mode,
- wifi_ssid,
- wifi_pwd)
- else:
- if only_return_fn:
- return phone_setup_voice_general_for_subscription
- else:
- return phone_setup_voice_general_for_subscription(log, ad, sub_id)
def is_phone_in_call_on_rat(log, ad, rat='volte', only_return_fn=None):
if rat.lower() == 'volte' or rat.lower() == '5g_volte':
@@ -2066,7 +1748,13 @@
else:
return is_phone_in_call_3g(log, ad)
- elif rat.lower() == 'wfc':
+ elif rat.lower() == '2g':
+ if only_return_fn:
+ return is_phone_in_call_2g
+ else:
+ return is_phone_in_call_2g(log, ad)
+
+ elif rat.lower() == 'wfc' or rat.lower() == '5g_wfc':
if only_return_fn:
return is_phone_in_call_iwlan
else:
@@ -2207,4 +1895,790 @@
ads[1],
ads[0],
verify_caller_func=dut_incall_check_func,
- wait_time_in_call=total_duration)
\ No newline at end of file
+ wait_time_in_call=total_duration)
+
+
+def _wait_for_ringing_event(log, ad, wait_time):
+ """Wait for ringing event.
+
+ Args:
+ log: log object.
+ ad: android device object.
+ wait_time: max time to wait for ringing event.
+
+ Returns:
+ event_ringing if received ringing event.
+ otherwise return None.
+ """
+ event_ringing = None
+
+ try:
+ event_ringing = ad.ed.wait_for_event(
+ EventCallStateChanged,
+ is_event_match,
+ timeout=wait_time,
+ field=CallStateContainer.CALL_STATE,
+ value=TELEPHONY_STATE_RINGING)
+ ad.log.info("Receive ringing event")
+ except Empty:
+ ad.log.info("No Ringing Event")
+ finally:
+ return event_ringing
+
+
+def wait_for_telecom_ringing(log, ad, max_time=MAX_WAIT_TIME_TELECOM_RINGING):
+ """Wait for android to be in telecom ringing state.
+
+ Args:
+ log: log object.
+ ad: android device.
+ max_time: maximal wait time. This is optional.
+ Default Value is MAX_WAIT_TIME_TELECOM_RINGING.
+
+ Returns:
+ If phone become in telecom ringing state within max_time, return True.
+ Return False if timeout.
+ """
+ return _wait_for_droid_in_state(
+ log, ad, max_time, lambda log, ad: ad.droid.telecomIsRinging())
+
+
+def wait_for_ringing_call(log, ad, incoming_number=None):
+ """Wait for an incoming call on default voice subscription and
+ accepts the call.
+
+ Args:
+ log: log object.
+ ad: android device object.
+ incoming_number: Expected incoming number.
+ Optional. Default is None
+
+ Returns:
+ True: if incoming call is received and answered successfully.
+ False: for errors
+ """
+ return wait_for_ringing_call_for_subscription(
+ log, ad, get_incoming_voice_sub_id(ad), incoming_number)
+
+
+def wait_for_ringing_call_for_subscription(
+ log,
+ ad,
+ sub_id,
+ incoming_number=None,
+ caller=None,
+ event_tracking_started=False,
+ timeout=MAX_WAIT_TIME_CALLEE_RINGING,
+ interval=WAIT_TIME_BETWEEN_STATE_CHECK):
+ """Wait for an incoming call on specified subscription.
+
+ Args:
+ log: log object.
+ ad: android device object.
+ sub_id: subscription ID
+ incoming_number: Expected incoming number. Default is None
+ event_tracking_started: True if event tracking already state outside
+ timeout: time to wait for ring
+ interval: checking interval
+
+ Returns:
+ True: if incoming call is received and answered successfully.
+ False: for errors
+ """
+ if not event_tracking_started:
+ ad.ed.clear_events(EventCallStateChanged)
+ ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
+ ring_event_received = False
+ end_time = time.time() + timeout
+ try:
+ while time.time() < end_time:
+ if not ring_event_received:
+ event_ringing = _wait_for_ringing_event(log, ad, interval)
+ if event_ringing:
+ if incoming_number and not check_phone_number_match(
+ event_ringing['data']
+ [CallStateContainer.INCOMING_NUMBER], incoming_number):
+ ad.log.error(
+ "Incoming Number not match. Expected number:%s, actual number:%s",
+ incoming_number, event_ringing['data'][
+ CallStateContainer.INCOMING_NUMBER])
+ return False
+ ring_event_received = True
+ telephony_state = ad.droid.telephonyGetCallStateForSubscription(
+ sub_id)
+ telecom_state = ad.droid.telecomGetCallState()
+ if telephony_state == TELEPHONY_STATE_RINGING and (
+ telecom_state == TELEPHONY_STATE_RINGING):
+ ad.log.info("callee is in telephony and telecom RINGING state")
+ if caller:
+ if caller.droid.telecomIsInCall():
+ caller.log.info("Caller telecom is in call state")
+ return True
+ else:
+ caller.log.info("Caller telecom is NOT in call state")
+ else:
+ return True
+ else:
+ ad.log.info(
+ "telephony in %s, telecom in %s, expecting RINGING state",
+ telephony_state, telecom_state)
+ time.sleep(interval)
+ finally:
+ if not event_tracking_started:
+ ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
+ sub_id)
+
+
+def wait_for_call_offhook_for_subscription(
+ log,
+ ad,
+ sub_id,
+ event_tracking_started=False,
+ timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT,
+ interval=WAIT_TIME_BETWEEN_STATE_CHECK):
+ """Wait for an incoming call on specified subscription.
+
+ Args:
+ log: log object.
+ ad: android device object.
+ sub_id: subscription ID
+ timeout: time to wait for ring
+ interval: checking interval
+
+ Returns:
+ True: if incoming call is received and answered successfully.
+ False: for errors
+ """
+ if not event_tracking_started:
+ ad.ed.clear_events(EventCallStateChanged)
+ ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
+ offhook_event_received = False
+ end_time = time.time() + timeout
+ try:
+ while time.time() < end_time:
+ if not offhook_event_received:
+ if wait_for_call_offhook_event(log, ad, sub_id, True,
+ interval):
+ offhook_event_received = True
+ telephony_state = ad.droid.telephonyGetCallStateForSubscription(
+ sub_id)
+ telecom_state = ad.droid.telecomGetCallState()
+ if telephony_state == TELEPHONY_STATE_OFFHOOK and (
+ telecom_state == TELEPHONY_STATE_OFFHOOK):
+ ad.log.info("telephony and telecom are in OFFHOOK state")
+ return True
+ else:
+ ad.log.info(
+ "telephony in %s, telecom in %s, expecting OFFHOOK state",
+ telephony_state, telecom_state)
+ if offhook_event_received:
+ time.sleep(interval)
+ finally:
+ if not event_tracking_started:
+ ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
+ sub_id)
+
+
+def wait_for_call_offhook_event(
+ log,
+ ad,
+ sub_id,
+ event_tracking_started=False,
+ timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT):
+ """Wait for an incoming call on specified subscription.
+
+ Args:
+ log: log object.
+ ad: android device object.
+ event_tracking_started: True if event tracking already state outside
+ timeout: time to wait for event
+
+ Returns:
+ True: if call offhook event is received.
+ False: if call offhook event is not received.
+ """
+ if not event_tracking_started:
+ ad.ed.clear_events(EventCallStateChanged)
+ ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
+ try:
+ ad.ed.wait_for_event(
+ EventCallStateChanged,
+ is_event_match,
+ timeout=timeout,
+ field=CallStateContainer.CALL_STATE,
+ value=TELEPHONY_STATE_OFFHOOK)
+ ad.log.info("Got event %s", TELEPHONY_STATE_OFFHOOK)
+ except Empty:
+ ad.log.info("No event for call state change to OFFHOOK")
+ return False
+ finally:
+ if not event_tracking_started:
+ ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
+ sub_id)
+ return True
+
+
+def wait_and_answer_call_for_subscription(
+ log,
+ ad,
+ sub_id,
+ incoming_number=None,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ timeout=MAX_WAIT_TIME_CALLEE_RINGING,
+ caller=None,
+ video_state=None):
+ """Wait for an incoming call on specified subscription and
+ accepts the call.
+
+ Args:
+ log: log object.
+ ad: android device object.
+ sub_id: subscription ID
+ incoming_number: Expected incoming number.
+ Optional. Default is None
+ incall_ui_display: after answer the call, bring in-call UI to foreground or
+ background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
+ if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
+ if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
+ else, do nothing.
+
+ Returns:
+ True: if incoming call is received and answered successfully.
+ False: for errors
+ """
+ ad.ed.clear_events(EventCallStateChanged)
+ ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
+ try:
+ if not wait_for_ringing_call_for_subscription(
+ log,
+ ad,
+ sub_id,
+ incoming_number=incoming_number,
+ caller=caller,
+ event_tracking_started=True,
+ timeout=timeout):
+ ad.log.info("Incoming call ringing check failed.")
+ return False
+ ad.log.info("Accept the ring call")
+ ad.droid.telecomAcceptRingingCall(video_state)
+
+ if wait_for_call_offhook_for_subscription(
+ log, ad, sub_id, event_tracking_started=True):
+ return True
+ else:
+ ad.log.error("Could not answer the call.")
+ return False
+ except Exception as e:
+ log.error(e)
+ return False
+ finally:
+ ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
+ if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
+ ad.droid.telecomShowInCallScreen()
+ elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
+ ad.droid.showHomeScreen()
+
+
+def wait_and_reject_call(log,
+ ad,
+ incoming_number=None,
+ delay_reject=WAIT_TIME_REJECT_CALL,
+ reject=True):
+ """Wait for an incoming call on default voice subscription and
+ reject the call.
+
+ Args:
+ log: log object.
+ ad: android device object.
+ incoming_number: Expected incoming number.
+ Optional. Default is None
+ delay_reject: time to wait before rejecting the call
+ Optional. Default is WAIT_TIME_REJECT_CALL
+
+ Returns:
+ 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)
+
+
+def wait_and_reject_call_for_subscription(log,
+ ad,
+ sub_id,
+ incoming_number=None,
+ delay_reject=WAIT_TIME_REJECT_CALL,
+ reject=True):
+ """Wait for an incoming call on specific subscription and
+ reject the call.
+
+ Args:
+ log: log object.
+ ad: android device object.
+ sub_id: subscription ID
+ incoming_number: Expected incoming number.
+ Optional. Default is None
+ delay_reject: time to wait before rejecting the call
+ Optional. Default is WAIT_TIME_REJECT_CALL
+
+ Returns:
+ True: if incoming call is received and reject successfully.
+ False: for errors
+ """
+
+ if not wait_for_ringing_call_for_subscription(log, ad, sub_id,
+ incoming_number):
+ ad.log.error(
+ "Could not reject a call: incoming call in ringing check failed.")
+ return False
+
+ ad.ed.clear_events(EventCallStateChanged)
+ ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
+ if reject is True:
+ # Delay between ringing and reject.
+ time.sleep(delay_reject)
+ is_find = False
+ # Loop the call list and find the matched one to disconnect.
+ for call in ad.droid.telecomCallGetCallIds():
+ if check_phone_number_match(
+ get_number_from_tel_uri(get_call_uri(ad, call)),
+ incoming_number):
+ ad.droid.telecomCallDisconnect(call)
+ ad.log.info("Callee reject the call")
+ is_find = True
+ if is_find is False:
+ ad.log.error("Callee did not find matching call to reject.")
+ return False
+ else:
+ # don't reject on callee. Just ignore the incoming call.
+ ad.log.info("Callee received incoming call. Ignore it.")
+ try:
+ ad.ed.wait_for_event(
+ EventCallStateChanged,
+ is_event_match_for_list,
+ timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
+ field=CallStateContainer.CALL_STATE,
+ value_list=[TELEPHONY_STATE_IDLE, TELEPHONY_STATE_OFFHOOK])
+ except Empty:
+ ad.log.error("No onCallStateChangedIdle event received.")
+ return False
+ finally:
+ ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
+ return True
+
+
+def wait_and_answer_call(log,
+ ad,
+ incoming_number=None,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ caller=None,
+ video_state=None):
+ """Wait for an incoming call on default voice subscription and
+ accepts the call.
+
+ Args:
+ ad: android device object.
+ incoming_number: Expected incoming number.
+ Optional. Default is None
+ incall_ui_display: after answer the call, bring in-call UI to foreground or
+ background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
+ if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
+ if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
+ else, do nothing.
+
+ Returns:
+ True: if incoming call is received and answered successfully.
+ False: for errors
+ """
+ return wait_and_answer_call_for_subscription(
+ log,
+ ad,
+ get_incoming_voice_sub_id(ad),
+ incoming_number,
+ incall_ui_display=incall_ui_display,
+ caller=caller,
+ video_state=video_state)
+
+
+def wait_for_in_call_active(ad,
+ timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT,
+ interval=WAIT_TIME_BETWEEN_STATE_CHECK,
+ 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_droid_in_call(log, ad, max_time):
+ """Wait for android to be in call state.
+
+ Args:
+ log: log object.
+ ad: android device.
+ max_time: maximal wait time.
+
+ Returns:
+ If phone become in call state within max_time, return True.
+ Return False if timeout.
+ """
+ return _wait_for_droid_in_state(log, ad, max_time, is_phone_in_call)
+
+
+def wait_for_call_id_clearing(ad,
+ previous_ids,
+ timeout=MAX_WAIT_TIME_CALL_DROP):
+ while timeout > 0:
+ new_call_ids = ad.droid.telecomCallGetCallIds()
+ if len(new_call_ids) <= len(previous_ids):
+ return True
+ time.sleep(5)
+ timeout = timeout - 5
+ ad.log.error("Call id clearing failed. Before: %s; After: %s",
+ previous_ids, new_call_ids)
+ return False
+
+
+def wait_for_call_end(
+ log,
+ ad_caller,
+ ad_callee,
+ ad_hangup,
+ verify_caller_func,
+ verify_callee_func,
+ call_begin_time,
+ check_interval=5,
+ tel_result_wrapper=TelResultWrapper(CallResult('SUCCESS')),
+ wait_time_in_call=WAIT_TIME_IN_CALL):
+ elapsed_time = 0
+ while (elapsed_time < wait_time_in_call):
+ check_interval = min(check_interval, wait_time_in_call - elapsed_time)
+ time.sleep(check_interval)
+ elapsed_time += check_interval
+ time_message = "at <%s>/<%s> second." % (elapsed_time, wait_time_in_call)
+ 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, voice in RAT %s",
+ call_func.__name__,
+ time_message,
+ ad.droid.telephonyGetCurrentVoiceNetworkType())
+ tel_result_wrapper.result_value = CallResult(
+ 'CALL_DROP_OR_WRONG_STATE_AFTER_CONNECTED')
+ 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)
+ tel_result_wrapper.result_value = CallResult(
+ 'AUDIO_STATE_NOT_INCALL_AFTER_CONNECTED')
+
+ if not tel_result_wrapper:
+ break
+
+ if not tel_result_wrapper:
+ for ad in (ad_caller, ad_callee):
+ last_call_drop_reason(ad, call_begin_time)
+ try:
+ if ad.droid.telecomIsInCall():
+ ad.log.info("In call. End now.")
+ ad.droid.telecomEndCall()
+ except Exception as e:
+ log.error(str(e))
+ else:
+ if ad_hangup:
+ if not hangup_call(log, ad_hangup):
+ ad_hangup.log.info("Failed to hang up the call")
+ tel_result_wrapper.result_value = CallResult('CALL_HANGUP_FAIL')
+
+ if ad_hangup or not tel_result_wrapper:
+ for ad in (ad_caller, ad_callee):
+ if not wait_for_call_id_clearing(ad, getattr(ad, "caller_ids", [])):
+ tel_result_wrapper.result_value = CallResult(
+ 'CALL_ID_CLEANUP_FAIL')
+
+ return tel_result_wrapper
+
+
+def check_call(log, dut, dut_client):
+ result = True
+ if not call_setup_teardown(log, dut_client, dut,
+ dut):
+ if not call_setup_teardown(log, dut_client,
+ dut, dut):
+ dut.log.error("MT call failed")
+ result = False
+ if not call_setup_teardown(log, dut, dut_client,
+ dut):
+ dut.log.error("MO call failed")
+ result = False
+ return result
+
+
+def check_call_in_wfc(log, dut, dut_client):
+ result = True
+ if not call_setup_teardown(log, dut_client, dut,
+ dut, None, is_phone_in_call_iwlan):
+ if not call_setup_teardown(log, dut_client,
+ dut, dut, None,
+ is_phone_in_call_iwlan):
+ dut.log.error("MT WFC call failed")
+ result = False
+ if not call_setup_teardown(log, dut, dut_client,
+ dut, is_phone_in_call_iwlan):
+ dut.log.error("MO WFC call failed")
+ result = False
+ return result
+
+
+def check_call_in_volte(log, dut, dut_client):
+ result = True
+ if not call_setup_teardown(log, dut_client, dut,
+ dut, None, is_phone_in_call_volte):
+ if not call_setup_teardown(log, dut_client,
+ dut, dut, None,
+ is_phone_in_call_volte):
+ dut.log.error("MT VoLTE call failed")
+ result = False
+ if not call_setup_teardown(log, dut, dut_client,
+ dut, is_phone_in_call_volte):
+ dut.log.error("MO VoLTE call failed")
+ result = False
+ return result
+
+
+def change_ims_setting(log,
+ ad,
+ dut_client,
+ wifi_network_ssid,
+ wifi_network_pass,
+ subid,
+ dut_capabilities,
+ airplane_mode,
+ wifi_enabled,
+ volte_enabled,
+ wfc_enabled,
+ nw_gen=RAT_LTE,
+ wfc_mode=None):
+ result = True
+ ad.log.info(
+ "Setting APM %s, WIFI %s, VoLTE %s, WFC %s, WFC mode %s",
+ airplane_mode, wifi_enabled, volte_enabled, wfc_enabled, wfc_mode)
+
+ toggle_airplane_mode_by_adb(log, ad, airplane_mode)
+ if wifi_enabled:
+ if not ensure_wifi_connected(log, ad,
+ wifi_network_ssid,
+ wifi_network_pass,
+ apm=airplane_mode):
+ ad.log.error("Fail to connected to WiFi")
+ result = False
+ else:
+ if not wifi_toggle_state(log, ad, False):
+ ad.log.error("Failed to turn off WiFi.")
+ result = False
+ toggle_volte(log, ad, volte_enabled)
+ toggle_wfc(log, ad, wfc_enabled)
+ if wfc_mode:
+ set_wfc_mode(log, ad, wfc_mode)
+ wfc_mode = ad.droid.imsGetWfcMode()
+ if wifi_enabled or not airplane_mode:
+ if not ensure_phone_subscription(log, ad):
+ ad.log.error("Failed to find valid subscription")
+ result = False
+ if airplane_mode:
+ if (CAPABILITY_WFC in dut_capabilities) and (wifi_enabled
+ and wfc_enabled):
+ if not wait_for_wfc_enabled(log, ad):
+ result = False
+ elif not check_call_in_wfc(log, ad, dut_client):
+ result = False
+ else:
+ if not wait_for_state(
+ ad.droid.telephonyGetCurrentVoiceNetworkType,
+ RAT_UNKNOWN):
+ ad.log.error(
+ "Voice RAT is %s not UNKNOWN",
+ ad.droid.telephonyGetCurrentVoiceNetworkType())
+ result = False
+ else:
+ ad.log.info("Voice RAT is in UNKKNOWN")
+ else:
+ if (wifi_enabled and wfc_enabled) and (
+ wfc_mode == WFC_MODE_WIFI_PREFERRED) and (
+ CAPABILITY_WFC in dut_capabilities):
+ if not wait_for_wfc_enabled(log, ad):
+ result = False
+ if not wait_for_state(
+ ad.droid.telephonyGetCurrentVoiceNetworkType,
+ RAT_UNKNOWN):
+ ad.log.error(
+ "Voice RAT is %s, not UNKNOWN",
+ ad.droid.telephonyGetCurrentVoiceNetworkType())
+ if not check_call_in_wfc(log, ad, dut_client):
+ result = False
+ else:
+ if not wait_for_wfc_disabled(log, ad):
+ ad.log.error("WFC is not disabled")
+ result = False
+ if volte_enabled and CAPABILITY_VOLTE in dut_capabilities:
+ if not wait_for_volte_enabled(log, ad):
+ result = False
+ if not check_call_in_volte(log, ad, dut_client):
+ result = False
+ else:
+ if not wait_for_not_network_rat(
+ log,
+ ad,
+ nw_gen,
+ voice_or_data=NETWORK_SERVICE_VOICE):
+ ad.log.error(
+ "Voice RAT is %s",
+ ad.droid.telephonyGetCurrentVoiceNetworkType(
+ ))
+ result = False
+ if not wait_for_voice_attach(log, ad):
+ result = False
+ if not check_call(log, ad, dut_client):
+ result = False
+ user_config_profile = get_user_config_profile(ad)
+ ad.log.info("user_config_profile: %s ",
+ sorted(user_config_profile.items()))
+ return result
+
+
+def verify_default_ims_setting(log,
+ ad,
+ dut_client,
+ carrier_configs,
+ default_wfc_enabled,
+ default_volte,
+ wfc_mode=None):
+ result = True
+ airplane_mode = ad.droid.connectivityCheckAirplaneMode()
+ default_wfc_mode = carrier_configs.get(
+ CarrierConfigs.DEFAULT_WFC_IMS_MODE_INT, wfc_mode)
+ if default_wfc_enabled:
+ wait_for_wfc_enabled(log, ad)
+ else:
+ wait_for_wfc_disabled(log, ad)
+ if airplane_mode:
+ wait_for_network_rat(
+ log,
+ ad,
+ RAT_UNKNOWN,
+ voice_or_data=NETWORK_SERVICE_VOICE)
+ else:
+ if default_volte:
+ wait_for_volte_enabled(log, ad)
+ else:
+ wait_for_not_network_rat(
+ log,
+ ad,
+ RAT_UNKNOWN,
+ voice_or_data=NETWORK_SERVICE_VOICE)
+
+ if not ensure_phone_subscription(log, ad):
+ ad.log.error("Failed to find valid subscription")
+ result = False
+ user_config_profile = get_user_config_profile(ad)
+ ad.log.info("user_config_profile = %s ",
+ sorted(user_config_profile.items()))
+ if user_config_profile["VoLTE Enabled"] != default_volte:
+ ad.log.error("VoLTE mode is not %s", default_volte)
+ result = False
+ else:
+ ad.log.info("VoLTE mode is %s as expected",
+ default_volte)
+ if user_config_profile["WFC Enabled"] != default_wfc_enabled:
+ ad.log.error("WFC enabled is not %s", default_wfc_enabled)
+ if user_config_profile["WFC Enabled"]:
+ if user_config_profile["WFC Mode"] != default_wfc_mode:
+ ad.log.error(
+ "WFC mode is not %s after IMS factory reset",
+ default_wfc_mode)
+ result = False
+ else:
+ ad.log.info("WFC mode is %s as expected",
+ default_wfc_mode)
+ if default_wfc_enabled and \
+ default_wfc_mode == WFC_MODE_WIFI_PREFERRED:
+ if not check_call_in_wfc(log, ad, dut_client):
+ result = False
+ elif not airplane_mode:
+ if default_volte:
+ if not check_call_in_volte(log, ad, dut_client):
+ result = False
+ else:
+ if not check_call(log, ad, dut_client):
+ result = False
+ if result == False:
+ user_config_profile = get_user_config_profile(ad)
+ ad.log.info("user_config_profile = %s ",
+ sorted(user_config_profile.items()))
+ return result
+
+
+def truncate_phone_number(
+ log,
+ caller_number,
+ callee_number,
+ dialing_number_length,
+ skip_inter_area_call=True):
+ """This function truncates the phone number of the caller/callee to test
+ 7/10/11/12 digit dialing for North American numbering plan, and distinguish
+ if this is an inter-area call by comparing the area code.
+
+ Args:
+ log: logger object
+ caller_number: phone number of the caller
+ callee_number: phone number of the callee
+ dialing_number_length: the length of phone number (usually 7/10/11/12)
+ skip_inter_area_call: True to raise a TestSkip exception to skip dialing
+ the inter-area call. Otherwise False.
+
+ Returns:
+ The truncated phone number of the callee
+ """
+
+ if not dialing_number_length:
+ return callee_number
+
+ trunc_position = 0 - int(dialing_number_length)
+ try:
+ caller_area_code = caller_number[:trunc_position]
+ callee_area_code = callee_number[:trunc_position]
+ callee_dial_number = callee_number[trunc_position:]
+
+ if caller_area_code != callee_area_code:
+ skip_inter_area_call = True
+
+ except:
+ skip_inter_area_call = True
+
+ if skip_inter_area_call:
+ msg = "Cannot make call from %s to %s by %s digits since inter-area "
+ "call is not allowed" % (
+ caller_number, callee_number, dialing_number_length)
+ log.info(msg)
+ raise signals.TestSkip(msg)
+ else:
+ callee_number = callee_dial_number
+
+ return callee_number
+
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_wifi_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_wifi_utils.py
new file mode 100644
index 0000000..997b77b
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_wifi_utils.py
@@ -0,0 +1,243 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+import time
+
+from acts_contrib.test_utils.tel.tel_defines import TYPE_WIFI
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.wifi import wifi_test_utils
+
+WIFI_SSID_KEY = wifi_test_utils.WifiEnums.SSID_KEY
+WIFI_PWD_KEY = wifi_test_utils.WifiEnums.PWD_KEY
+WIFI_CONFIG_APBAND_2G = 1
+WIFI_CONFIG_APBAND_5G = 2
+WIFI_CONFIG_APBAND_AUTO = wifi_test_utils.WifiEnums.WIFI_CONFIG_APBAND_AUTO
+
+
+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 get_wifi_usage(ad, sid=None, apk=None):
+ if not sid:
+ sid = ad.droid.subscriptionGetDefaultDataSubId()
+ current_time = int(time.time() * 1000)
+ begin_time = current_time - 10 * 24 * 60 * 60 * 1000
+ end_time = current_time + 10 * 24 * 60 * 60 * 1000
+
+ if apk:
+ uid = ad.get_apk_uid(apk)
+ ad.log.debug("apk %s uid = %s", apk, uid)
+ try:
+ return ad.droid.connectivityQueryDetailsForUid(
+ TYPE_WIFI,
+ ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+ begin_time, end_time, uid)
+ except:
+ return ad.droid.connectivityQueryDetailsForUid(
+ ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+ begin_time, end_time, uid)
+ else:
+ try:
+ return ad.droid.connectivityQuerySummaryForDevice(
+ TYPE_WIFI,
+ ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+ begin_time, end_time)
+ except:
+ return ad.droid.connectivityQuerySummaryForDevice(
+ ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+ begin_time, end_time)
+
+
+def check_is_wifi_connected(log, ad, wifi_ssid):
+ """Check if ad is connected to wifi wifi_ssid.
+
+ Args:
+ log: Log object.
+ ad: Android device object.
+ wifi_ssid: WiFi network SSID.
+
+ Returns:
+ True if wifi is connected to wifi_ssid
+ False if wifi is not connected to wifi_ssid
+ """
+ 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
+
+
+def ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd=None, retries=3, apm=False):
+ """Ensure ad connected to wifi on network wifi_ssid.
+
+ Args:
+ log: Log object.
+ ad: Android device object.
+ wifi_ssid: WiFi network SSID.
+ wifi_pwd: optional secure network password.
+ retries: the number of retries.
+
+ Returns:
+ True if wifi is connected to wifi_ssid
+ False if wifi is not connected to wifi_ssid
+ """
+ if not toggle_airplane_mode(log, ad, apm, strict_checking=False):
+ return False
+
+ network = {WIFI_SSID_KEY: wifi_ssid}
+ if wifi_pwd:
+ network[WIFI_PWD_KEY] = wifi_pwd
+ for i in range(retries):
+ if not ad.droid.wifiCheckState():
+ ad.log.info("Wifi state is down. Turn on Wifi")
+ ad.droid.wifiToggleState(True)
+ if check_is_wifi_connected(log, ad, wifi_ssid):
+ ad.log.info("Wifi is connected to %s", wifi_ssid)
+ return verify_internet_connection(log, ad, retries=3)
+ else:
+ ad.log.info("Connecting to wifi %s", wifi_ssid)
+ try:
+ ad.droid.wifiConnectByConfig(network)
+ except Exception:
+ ad.log.info("Connecting to wifi by wifiConnect instead")
+ ad.droid.wifiConnect(network)
+ time.sleep(20)
+ if check_is_wifi_connected(log, ad, wifi_ssid):
+ ad.log.info("Connected to Wifi %s", wifi_ssid)
+ return verify_internet_connection(log, ad, retries=3)
+ ad.log.info("Fail to connected to wifi %s", wifi_ssid)
+ return False
+
+
+def forget_all_wifi_networks(log, ad):
+ """Forget all stored wifi network information
+
+ Args:
+ log: log object
+ ad: AndroidDevice object
+
+ Returns:
+ boolean success (True) or failure (False)
+ """
+ if not ad.droid.wifiGetConfiguredNetworks():
+ ad.on_mobile_data = True
+ return True
+ try:
+ old_state = ad.droid.wifiCheckState()
+ wifi_test_utils.reset_wifi(ad)
+ wifi_toggle_state(log, ad, old_state)
+ except Exception as e:
+ log.error("forget_all_wifi_networks with exception: %s", e)
+ return False
+ ad.on_mobile_data = True
+ return True
+
+
+def wifi_reset(log, ad, disable_wifi=True):
+ """Forget all stored wifi networks and (optionally) disable WiFi
+
+ Args:
+ log: log object
+ ad: AndroidDevice object
+ disable_wifi: boolean to disable wifi, defaults to True
+ Returns:
+ boolean success (True) or failure (False)
+ """
+ if not forget_all_wifi_networks(log, ad):
+ ad.log.error("Unable to forget all networks")
+ return False
+ if not wifi_toggle_state(log, ad, not disable_wifi):
+ ad.log.error("Failed to toggle WiFi state to %s!", not disable_wifi)
+ return False
+ return True
+
+
+def set_wifi_to_default(log, ad):
+ """Set wifi to default state (Wifi disabled and no configured network)
+
+ Args:
+ log: log object
+ ad: AndroidDevice object
+
+ Returns:
+ boolean success (True) or failure (False)
+ """
+ ad.droid.wifiFactoryReset()
+ ad.droid.wifiToggleState(False)
+ ad.on_mobile_data = True
+
+
+def wifi_toggle_state(log, ad, state, retries=3):
+ """Toggle the WiFi State
+
+ Args:
+ log: log object
+ ad: AndroidDevice object
+ state: True, False, or None
+
+ Returns:
+ boolean success (True) or failure (False)
+ """
+ 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
+
+
+def start_wifi_tethering(log, ad, ssid, password, ap_band=None):
+ """Start a Tethering Session
+
+ Args:
+ log: log object
+ ad: AndroidDevice object
+ ssid: the name of the WiFi network
+ password: optional password, used for secure networks.
+ ap_band=DEPRECATED specification of 2G or 5G tethering
+ Returns:
+ boolean success (True) or failure (False)
+ """
+ return wifi_test_utils._assert_on_fail_handler(
+ wifi_test_utils.start_wifi_tethering,
+ False,
+ ad,
+ ssid,
+ password,
+ band=ap_band)
+
+
+def stop_wifi_tethering(log, ad):
+ """Stop a Tethering Session
+
+ Args:
+ log: log object
+ ad: AndroidDevice object
+ Returns:
+ boolean success (True) or failure (False)
+ """
+ return wifi_test_utils._assert_on_fail_handler(
+ wifi_test_utils.stop_wifi_tethering, False, ad)
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/wifi/aware/AwareBaseTest.py b/acts_tests/acts_contrib/test_utils/wifi/aware/AwareBaseTest.py
index c0c1075..14c5c0e 100644
--- a/acts_tests/acts_contrib/test_utils/wifi/aware/AwareBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/wifi/aware/AwareBaseTest.py
@@ -36,7 +36,7 @@
device_startup_offset = 2
def setup_class(self):
- opt_param = ["pixel_models", "cnss_diag_file"]
+ opt_param = ["pixel_models", "cnss_diag_file", "ranging_role_concurrency_flexible_models"]
self.unpack_userparams(opt_param_names=opt_param)
if hasattr(self, "cnss_diag_file"):
if isinstance(self.cnss_diag_file, list):
diff --git a/acts_tests/acts_contrib/test_utils/wifi/ota_chamber.py b/acts_tests/acts_contrib/test_utils/wifi/ota_chamber.py
index 4274603..d74e785 100644
--- a/acts_tests/acts_contrib/test_utils/wifi/ota_chamber.py
+++ b/acts_tests/acts_contrib/test_utils/wifi/ota_chamber.py
@@ -89,6 +89,7 @@
self.log = logger.create_tagged_trace_logger('OtaChamber|{}'.format(
self.device_id))
self.current_mode = None
+ self.SUPPORTED_BANDS = ['2.4GHz', 'UNII-1', 'UNII-2', 'UNII-3', '6GHz']
def set_orientation(self, orientation):
self.log.info('Setting orientation to {} degrees.'.format(orientation))
@@ -128,6 +129,7 @@
utils.exe_cmd('sudo {} -d {} -i 0'.format(self.TURNTABLE_FILE_PATH,
self.device_id))
self.current_mode = None
+ self.SUPPORTED_BANDS = ['2.4GHz', 'UNII-1', 'UNII-2', 'UNII-3', '6GHz']
def set_orientation(self, orientation):
self.log.info('Setting orientation to {} degrees.'.format(orientation))
@@ -165,6 +167,7 @@
self.chamber = ChamberAutoConnect(flow.Flow(), self.config)
self.stirrer_ids = [0, 1, 2]
self.current_mode = None
+ self.SUPPORTED_BANDS = ['2.4GHz', 'UNII-1', 'UNII-2', 'UNII-3']
# Capture print output decorator
@staticmethod
@@ -248,8 +251,8 @@
def __init__(self, config):
self.config = config.copy()
self.device_id = self.config['device_id']
- self.log = logger.create_tagged_trace_logger('EInstrumentChamber|{}'.format(
- self.device_id))
+ self.log = logger.create_tagged_trace_logger(
+ 'EInstrumentChamber|{}'.format(self.device_id))
self.current_mode = None
self.ser = self._get_serial(config['port'])
diff --git a/acts_tests/acts_contrib/test_utils/wifi/ota_sniffer.py b/acts_tests/acts_contrib/test_utils/wifi/ota_sniffer.py
index a20936f..395fed2 100644
--- a/acts_tests/acts_contrib/test_utils/wifi/ota_sniffer.py
+++ b/acts_tests/acts_contrib/test_utils/wifi/ota_sniffer.py
@@ -136,7 +136,7 @@
network: dict of network credentials.
duration: duration of the sniff.
"""
- self.log.info('Starting sniffer.')
+ self.log.debug('Starting sniffer.')
def stop_capture(self):
"""Stops the sniffer.
@@ -145,7 +145,7 @@
log_file: name of processed sniffer.
"""
- self.log.info('Stopping sniffer.')
+ self.log.debug('Stopping sniffer.')
log_file = self._get_full_file_path()
with open(log_file, 'w') as file:
file.write('this is a sniffer dump.')
@@ -235,6 +235,7 @@
self.sniffer_output_file_type = config['output_file_type']
self.sniffer_snap_length = config['snap_length']
self.sniffer_interface = config['interface']
+ self.sniffer_disabled = False
#Logging into sniffer
self.log.info('Logging into sniffer.')
@@ -325,13 +326,13 @@
Args:
sniffer_command: sniffer command to execute.
"""
- self.log.info('Starting sniffer.')
+ self.log.debug('Starting sniffer.')
sniffer_job = self._sniffer_server.run_async(sniffer_command)
self.sniffer_proc_pid = sniffer_job.stdout
def _stop_tshark(self):
""" Stops the sniffer."""
- self.log.info('Stopping sniffer')
+ self.log.debug('Stopping sniffer')
# while loop to kill the sniffer process
stop_time = time.time() + SNIFFER_TIMEOUT
@@ -408,7 +409,7 @@
"""
# Checking for existing sniffer processes
if self._started:
- self.log.info('Sniffer already running')
+ self.log.debug('Sniffer already running')
return
# Configure sniffer
@@ -429,7 +430,7 @@
"""
# Checking if there is an ongoing sniffer capture
if not self._started:
- self.log.error('No sniffer process running')
+ self.log.debug('No sniffer process running')
return
# Killing sniffer process
self._stop_tshark()
@@ -495,6 +496,30 @@
# e.g. setting monitor mode (which will fail if above is not complete)
time.sleep(1)
+ def start_capture(self, network, chan, bw, duration=60):
+ """Starts sniffer capture on the specified machine.
+
+ Args:
+ network: dict describing network to sniff on.
+ duration: duration of sniff.
+ """
+ # If sniffer doesnt support the channel, return
+ if '6g' in str(chan):
+ self.log.debug('Channel not supported on sniffer')
+ return
+ # Checking for existing sniffer processes
+ if self._started:
+ self.log.debug('Sniffer already running')
+ return
+
+ # Configure sniffer
+ self._configure_sniffer(network, chan, bw)
+ tshark_command = self._get_tshark_command(duration)
+ sniffer_command = self._get_sniffer_command(tshark_command)
+
+ # Starting sniffer capture by executing tshark command
+ self._run_tshark(sniffer_command)
+
def set_monitor_mode(self, chan, bw):
"""Function to configure interface to monitor mode
diff --git a/acts_tests/acts_contrib/test_utils/wifi/rtt/RttBaseTest.py b/acts_tests/acts_contrib/test_utils/wifi/rtt/RttBaseTest.py
index bb58b02..c11f66a 100644
--- a/acts_tests/acts_contrib/test_utils/wifi/rtt/RttBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/wifi/rtt/RttBaseTest.py
@@ -29,7 +29,7 @@
class RttBaseTest(BaseTestClass):
def setup_class(self):
- opt_param = ["pixel_models", "cnss_diag_file"]
+ opt_param = ["pixel_models", "cnss_diag_file", "ranging_role_concurrency_flexible_models"]
self.unpack_userparams(opt_param_names=opt_param)
if hasattr(self, "cnss_diag_file"):
if isinstance(self.cnss_diag_file, list):
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils.py
deleted file mode 100644
index 1862889..0000000
--- a/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils.py
+++ /dev/null
@@ -1,1718 +0,0 @@
-#!/usr/bin/env python3.4
-#
-# Copyright 2019 - The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the 'License');
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an 'AS IS' BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import bokeh, bokeh.plotting, bokeh.io
-import collections
-import hashlib
-import ipaddress
-import itertools
-import json
-import logging
-import math
-import os
-import re
-import statistics
-import time
-from acts.controllers.android_device import AndroidDevice
-from acts.controllers.utils_lib import ssh
-from acts import asserts
-from acts import utils
-from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
-from concurrent.futures import ThreadPoolExecutor
-
-SHORT_SLEEP = 1
-MED_SLEEP = 6
-TEST_TIMEOUT = 10
-STATION_DUMP = 'iw wlan0 station dump'
-SCAN = 'wpa_cli scan'
-SCAN_RESULTS = 'wpa_cli scan_results'
-SIGNAL_POLL = 'wpa_cli signal_poll'
-WPA_CLI_STATUS = 'wpa_cli status'
-DISCONNECTION_MESSAGE_BRCM = 'driver adapter not found'
-CONST_3dB = 3.01029995664
-RSSI_ERROR_VAL = float('nan')
-RTT_REGEX = re.compile(r'^\[(?P<timestamp>\S+)\] .*? time=(?P<rtt>\S+)')
-LOSS_REGEX = re.compile(r'(?P<loss>\S+)% packet loss')
-FW_REGEX = re.compile(r'FW:(?P<firmware>\S+) HW:')
-
-
-# Threading decorator
-def nonblocking(f):
- """Creates a decorator transforming function calls to non-blocking"""
- def wrap(*args, **kwargs):
- executor = ThreadPoolExecutor(max_workers=1)
- thread_future = executor.submit(f, *args, **kwargs)
- # Ensure resources are freed up when executor ruturns or raises
- executor.shutdown(wait=False)
- return thread_future
-
- return wrap
-
-
-# JSON serializer
-def serialize_dict(input_dict):
- """Function to serialize dicts to enable JSON output"""
- output_dict = collections.OrderedDict()
- for key, value in input_dict.items():
- output_dict[_serialize_value(key)] = _serialize_value(value)
- return output_dict
-
-
-def _serialize_value(value):
- """Function to recursively serialize dict entries to enable JSON output"""
- if isinstance(value, tuple):
- return str(value)
- if isinstance(value, list):
- return [_serialize_value(x) for x in value]
- elif isinstance(value, dict):
- return serialize_dict(value)
- else:
- return value
-
-
-# Miscellaneous Wifi Utilities
-def extract_sub_dict(full_dict, fields):
- sub_dict = collections.OrderedDict(
- (field, full_dict[field]) for field in fields)
- return sub_dict
-
-
-def validate_network(dut, ssid):
- """Check that DUT has a valid internet connection through expected SSID
-
- Args:
- dut: android device of interest
- ssid: expected ssid
- """
- current_network = dut.droid.wifiGetConnectionInfo()
- try:
- connected = wutils.validate_connection(dut) is not None
- except:
- connected = False
- if connected and current_network['SSID'] == ssid:
- return True
- else:
- return False
-
-
-def get_server_address(ssh_connection, dut_ip, subnet_mask):
- """Get server address on a specific subnet,
-
- This function retrieves the LAN or WAN IP of a remote machine used in
- testing. If subnet_mask is set to 'public' it returns a machines global ip,
- else it returns the ip belonging to the dut local network given the dut's
- ip and subnet mask.
-
- Args:
- ssh_connection: object representing server for which we want an ip
- dut_ip: string in ip address format, i.e., xxx.xxx.xxx.xxx
- subnet_mask: string representing subnet mask (public for global ip)
- """
- ifconfig_out = ssh_connection.run('ifconfig').stdout
- ip_list = re.findall('inet (?:addr:)?(\d+.\d+.\d+.\d+)', ifconfig_out)
- ip_list = [ipaddress.ip_address(ip) for ip in ip_list]
-
- if subnet_mask == 'public':
- for ip in ip_list:
- # is_global is not used to allow for CGNAT ips in 100.x.y.z range
- if not ip.is_private:
- return str(ip)
- else:
- dut_network = ipaddress.ip_network('{}/{}'.format(dut_ip, subnet_mask),
- strict=False)
- for ip in ip_list:
- if ip in dut_network:
- return str(ip)
- logging.error('No IP address found in requested subnet')
-
-
-# Plotting Utilities
-class BokehFigure():
- """Class enabling simplified Bokeh plotting."""
-
- COLORS = [
- 'black',
- 'blue',
- 'blueviolet',
- 'brown',
- 'burlywood',
- 'cadetblue',
- 'cornflowerblue',
- 'crimson',
- 'cyan',
- 'darkblue',
- 'darkgreen',
- 'darkmagenta',
- 'darkorange',
- 'darkred',
- 'deepskyblue',
- 'goldenrod',
- 'green',
- 'grey',
- 'indigo',
- 'navy',
- 'olive',
- 'orange',
- 'red',
- 'salmon',
- 'teal',
- 'yellow',
- ]
- MARKERS = [
- 'asterisk', 'circle', 'circle_cross', 'circle_x', 'cross', 'diamond',
- 'diamond_cross', 'hex', 'inverted_triangle', 'square', 'square_x',
- 'square_cross', 'triangle', 'x'
- ]
-
- TOOLS = ('box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save')
- TOOLTIPS = [
- ('index', '$index'),
- ('(x,y)', '($x, $y)'),
- ('info', '@hover_text'),
- ]
-
- def __init__(self,
- title=None,
- x_label=None,
- primary_y_label=None,
- secondary_y_label=None,
- height=700,
- width=1100,
- title_size='15pt',
- axis_label_size='12pt',
- json_file=None):
- if json_file:
- self.load_from_json(json_file)
- else:
- self.figure_data = []
- self.fig_property = {
- 'title': title,
- 'x_label': x_label,
- 'primary_y_label': primary_y_label,
- 'secondary_y_label': secondary_y_label,
- 'num_lines': 0,
- 'height': height,
- 'width': width,
- 'title_size': title_size,
- 'axis_label_size': axis_label_size
- }
-
- def init_plot(self):
- self.plot = bokeh.plotting.figure(
- sizing_mode='scale_both',
- plot_width=self.fig_property['width'],
- plot_height=self.fig_property['height'],
- title=self.fig_property['title'],
- tools=self.TOOLS,
- output_backend='webgl')
- self.plot.hover.tooltips = self.TOOLTIPS
- self.plot.add_tools(
- bokeh.models.tools.WheelZoomTool(dimensions='width'))
- self.plot.add_tools(
- bokeh.models.tools.WheelZoomTool(dimensions='height'))
-
- def _filter_line(self, x_data, y_data, hover_text=None):
- """Function to remove NaN points from bokeh plots."""
- x_data_filtered = []
- y_data_filtered = []
- hover_text_filtered = []
- for x, y, hover in itertools.zip_longest(x_data, y_data, hover_text):
- if not math.isnan(y):
- x_data_filtered.append(x)
- y_data_filtered.append(y)
- hover_text_filtered.append(hover)
- return x_data_filtered, y_data_filtered, hover_text_filtered
-
- def add_line(self,
- x_data,
- y_data,
- legend,
- hover_text=None,
- color=None,
- width=3,
- style='solid',
- marker=None,
- marker_size=10,
- shaded_region=None,
- y_axis='default'):
- """Function to add line to existing BokehFigure.
-
- Args:
- x_data: list containing x-axis values for line
- y_data: list containing y_axis values for line
- legend: string containing line title
- hover_text: text to display when hovering over lines
- color: string describing line color
- width: integer line width
- style: string describing line style, e.g, solid or dashed
- marker: string specifying line marker, e.g., cross
- shaded region: data describing shaded region to plot
- y_axis: identifier for y-axis to plot line against
- """
- if y_axis not in ['default', 'secondary']:
- raise ValueError('y_axis must be default or secondary')
- if color == None:
- color = self.COLORS[self.fig_property['num_lines'] %
- len(self.COLORS)]
- if style == 'dashed':
- style = [5, 5]
- if not hover_text:
- hover_text = ['y={}'.format(y) for y in y_data]
- x_data_filter, y_data_filter, hover_text_filter = self._filter_line(
- x_data, y_data, hover_text)
- self.figure_data.append({
- 'x_data': x_data_filter,
- 'y_data': y_data_filter,
- 'legend': legend,
- 'hover_text': hover_text_filter,
- 'color': color,
- 'width': width,
- 'style': style,
- 'marker': marker,
- 'marker_size': marker_size,
- 'shaded_region': shaded_region,
- 'y_axis': y_axis
- })
- self.fig_property['num_lines'] += 1
-
- def add_scatter(self,
- x_data,
- y_data,
- legend,
- hover_text=None,
- color=None,
- marker=None,
- marker_size=10,
- y_axis='default'):
- """Function to add line to existing BokehFigure.
-
- Args:
- x_data: list containing x-axis values for line
- y_data: list containing y_axis values for line
- legend: string containing line title
- hover_text: text to display when hovering over lines
- color: string describing line color
- marker: string specifying marker, e.g., cross
- y_axis: identifier for y-axis to plot line against
- """
- if y_axis not in ['default', 'secondary']:
- raise ValueError('y_axis must be default or secondary')
- if color == None:
- color = self.COLORS[self.fig_property['num_lines'] %
- len(self.COLORS)]
- if marker == None:
- marker = self.MARKERS[self.fig_property['num_lines'] %
- len(self.MARKERS)]
- if not hover_text:
- hover_text = ['y={}'.format(y) for y in y_data]
- self.figure_data.append({
- 'x_data': x_data,
- 'y_data': y_data,
- 'legend': legend,
- 'hover_text': hover_text,
- 'color': color,
- 'width': 0,
- 'style': 'solid',
- 'marker': marker,
- 'marker_size': marker_size,
- 'shaded_region': None,
- 'y_axis': y_axis
- })
- self.fig_property['num_lines'] += 1
-
- def generate_figure(self, output_file=None, save_json=True):
- """Function to generate and save BokehFigure.
-
- Args:
- output_file: string specifying output file path
- """
- self.init_plot()
- two_axes = False
- for line in self.figure_data:
- source = bokeh.models.ColumnDataSource(
- data=dict(x=line['x_data'],
- y=line['y_data'],
- hover_text=line['hover_text']))
- if line['width'] > 0:
- self.plot.line(x='x',
- y='y',
- legend_label=line['legend'],
- line_width=line['width'],
- color=line['color'],
- line_dash=line['style'],
- name=line['y_axis'],
- y_range_name=line['y_axis'],
- source=source)
- if line['shaded_region']:
- band_x = line['shaded_region']['x_vector']
- band_x.extend(line['shaded_region']['x_vector'][::-1])
- band_y = line['shaded_region']['lower_limit']
- band_y.extend(line['shaded_region']['upper_limit'][::-1])
- self.plot.patch(band_x,
- band_y,
- color='#7570B3',
- line_alpha=0.1,
- fill_alpha=0.1)
- if line['marker'] in self.MARKERS:
- marker_func = getattr(self.plot, line['marker'])
- marker_func(x='x',
- y='y',
- size=line['marker_size'],
- legend_label=line['legend'],
- line_color=line['color'],
- fill_color=line['color'],
- name=line['y_axis'],
- y_range_name=line['y_axis'],
- source=source)
- if line['y_axis'] == 'secondary':
- two_axes = True
-
- #x-axis formatting
- self.plot.xaxis.axis_label = self.fig_property['x_label']
- self.plot.x_range.range_padding = 0
- self.plot.xaxis[0].axis_label_text_font_size = self.fig_property[
- 'axis_label_size']
- #y-axis formatting
- self.plot.yaxis[0].axis_label = self.fig_property['primary_y_label']
- self.plot.yaxis[0].axis_label_text_font_size = self.fig_property[
- 'axis_label_size']
- self.plot.y_range = bokeh.models.DataRange1d(names=['default'])
- if two_axes and 'secondary' not in self.plot.extra_y_ranges:
- self.plot.extra_y_ranges = {
- 'secondary': bokeh.models.DataRange1d(names=['secondary'])
- }
- self.plot.add_layout(
- bokeh.models.LinearAxis(
- y_range_name='secondary',
- axis_label=self.fig_property['secondary_y_label'],
- axis_label_text_font_size=self.
- fig_property['axis_label_size']), 'right')
- # plot formatting
- self.plot.legend.location = 'top_right'
- self.plot.legend.click_policy = 'hide'
- self.plot.title.text_font_size = self.fig_property['title_size']
-
- if output_file is not None:
- self.save_figure(output_file, save_json)
- return self.plot
-
- def load_from_json(self, file_path):
- with open(file_path, 'r') as json_file:
- fig_dict = json.load(json_file)
- self.fig_property = fig_dict['fig_property']
- self.figure_data = fig_dict['figure_data']
-
- def _save_figure_json(self, output_file):
- """Function to save a json format of a figure"""
- figure_dict = collections.OrderedDict(fig_property=self.fig_property,
- figure_data=self.figure_data)
- output_file = output_file.replace('.html', '_plot_data.json')
- with open(output_file, 'w') as outfile:
- json.dump(figure_dict, outfile, indent=4)
-
- def save_figure(self, output_file, save_json=True):
- """Function to save BokehFigure.
-
- Args:
- output_file: string specifying output file path
- save_json: flag controlling json outputs
- """
- if save_json:
- self._save_figure_json(output_file)
- bokeh.io.output_file(output_file)
- bokeh.io.save(self.plot)
-
- @staticmethod
- def save_figures(figure_array, output_file_path, save_json=True):
- """Function to save list of BokehFigures in one file.
-
- Args:
- figure_array: list of BokehFigure object to be plotted
- output_file: string specifying output file path
- """
- for idx, figure in enumerate(figure_array):
- figure.generate_figure()
- if save_json:
- json_file_path = output_file_path.replace(
- '.html', '{}-plot_data.json'.format(idx))
- figure._save_figure_json(json_file_path)
- plot_array = [figure.plot for figure in figure_array]
- all_plots = bokeh.layouts.column(children=plot_array,
- sizing_mode='scale_width')
- bokeh.plotting.output_file(output_file_path)
- bokeh.plotting.save(all_plots)
-
-
-# Ping utilities
-class PingResult(object):
- """An object that contains the results of running ping command.
-
- Attributes:
- connected: True if a connection was made. False otherwise.
- packet_loss_percentage: The total percentage of packets lost.
- transmission_times: The list of PingTransmissionTimes containing the
- timestamps gathered for transmitted packets.
- rtts: An list-like object enumerating all round-trip-times of
- transmitted packets.
- timestamps: A list-like object enumerating the beginning timestamps of
- each packet transmission.
- ping_interarrivals: A list-like object enumerating the amount of time
- between the beginning of each subsequent transmission.
- """
- def __init__(self, ping_output):
- self.packet_loss_percentage = 100
- self.transmission_times = []
-
- self.rtts = _ListWrap(self.transmission_times, lambda entry: entry.rtt)
- self.timestamps = _ListWrap(self.transmission_times,
- lambda entry: entry.timestamp)
- self.ping_interarrivals = _PingInterarrivals(self.transmission_times)
-
- self.start_time = 0
- for line in ping_output:
- if 'loss' in line:
- match = re.search(LOSS_REGEX, line)
- self.packet_loss_percentage = float(match.group('loss'))
- if 'time=' in line:
- match = re.search(RTT_REGEX, line)
- if self.start_time == 0:
- self.start_time = float(match.group('timestamp'))
- self.transmission_times.append(
- PingTransmissionTimes(
- float(match.group('timestamp')) - self.start_time,
- float(match.group('rtt'))))
- self.connected = len(
- ping_output) > 1 and self.packet_loss_percentage < 100
-
- def __getitem__(self, item):
- if item == 'rtt':
- return self.rtts
- if item == 'connected':
- return self.connected
- if item == 'packet_loss_percentage':
- return self.packet_loss_percentage
- raise ValueError('Invalid key. Please use an attribute instead.')
-
- def as_dict(self):
- return {
- 'connected': 1 if self.connected else 0,
- 'rtt': list(self.rtts),
- 'time_stamp': list(self.timestamps),
- 'ping_interarrivals': list(self.ping_interarrivals),
- 'packet_loss_percentage': self.packet_loss_percentage
- }
-
-
-class PingTransmissionTimes(object):
- """A class that holds the timestamps for a packet sent via the ping command.
-
- Attributes:
- rtt: The round trip time for the packet sent.
- timestamp: The timestamp the packet started its trip.
- """
- def __init__(self, timestamp, rtt):
- self.rtt = rtt
- self.timestamp = timestamp
-
-
-class _ListWrap(object):
- """A convenient helper class for treating list iterators as native lists."""
- def __init__(self, wrapped_list, func):
- self.__wrapped_list = wrapped_list
- self.__func = func
-
- def __getitem__(self, key):
- return self.__func(self.__wrapped_list[key])
-
- def __iter__(self):
- for item in self.__wrapped_list:
- yield self.__func(item)
-
- def __len__(self):
- return len(self.__wrapped_list)
-
-
-class _PingInterarrivals(object):
- """A helper class for treating ping interarrivals as a native list."""
- def __init__(self, ping_entries):
- self.__ping_entries = ping_entries
-
- def __getitem__(self, key):
- return (self.__ping_entries[key + 1].timestamp -
- self.__ping_entries[key].timestamp)
-
- def __iter__(self):
- for index in range(len(self.__ping_entries) - 1):
- yield self[index]
-
- def __len__(self):
- return max(0, len(self.__ping_entries) - 1)
-
-
-def get_ping_stats(src_device, dest_address, ping_duration, ping_interval,
- ping_size):
- """Run ping to or from the DUT.
-
- The function computes either pings the DUT or pings a remote ip from
- DUT.
-
- Args:
- src_device: object representing device to ping from
- dest_address: ip address to ping
- ping_duration: timeout to set on the the ping process (in seconds)
- ping_interval: time between pings (in seconds)
- ping_size: size of ping packet payload
- Returns:
- ping_result: dict containing ping results and other meta data
- """
- ping_count = int(ping_duration / ping_interval)
- ping_deadline = int(ping_count * ping_interval) + 1
- ping_cmd_linux = 'ping -c {} -w {} -i {} -s {} -D'.format(
- ping_count,
- ping_deadline,
- ping_interval,
- ping_size,
- )
-
- ping_cmd_macos = 'ping -c {} -t {} -i {} -s {}'.format(
- ping_count,
- ping_deadline,
- ping_interval,
- ping_size,
- )
-
- if isinstance(src_device, AndroidDevice):
- ping_cmd = '{} {}'.format(ping_cmd_linux, dest_address)
- ping_output = src_device.adb.shell(ping_cmd,
- timeout=ping_deadline + SHORT_SLEEP,
- ignore_status=True)
- elif isinstance(src_device, ssh.connection.SshConnection):
- platform = src_device.run('uname').stdout
- if 'linux' in platform.lower():
- ping_cmd = 'sudo {} {}'.format(ping_cmd_linux, dest_address)
- elif 'darwin' in platform.lower():
- ping_cmd = "sudo {} {}| while IFS= read -r line; do printf '[%s] %s\n' \"$(gdate '+%s.%N')\" \"$line\"; done".format(
- ping_cmd_macos, dest_address)
- ping_output = src_device.run(ping_cmd,
- timeout=ping_deadline + SHORT_SLEEP,
- ignore_status=True).stdout
- else:
- raise TypeError('Unable to ping using src_device of type %s.' %
- type(src_device))
- return PingResult(ping_output.splitlines())
-
-
-@nonblocking
-def get_ping_stats_nb(src_device, dest_address, ping_duration, ping_interval,
- ping_size):
- return get_ping_stats(src_device, dest_address, ping_duration,
- ping_interval, ping_size)
-
-
-# Iperf utilities
-@nonblocking
-def start_iperf_client_nb(iperf_client, iperf_server_address, iperf_args, tag,
- timeout):
- return iperf_client.start(iperf_server_address, iperf_args, tag, timeout)
-
-
-def get_iperf_arg_string(duration,
- reverse_direction,
- interval=1,
- traffic_type='TCP',
- socket_size=None,
- num_processes=1,
- udp_throughput='1000M',
- ipv6=False):
- """Function to format iperf client arguments.
-
- This function takes in iperf client parameters and returns a properly
- formatter iperf arg string to be used in throughput tests.
-
- Args:
- duration: iperf duration in seconds
- reverse_direction: boolean controlling the -R flag for iperf clients
- interval: iperf print interval
- traffic_type: string specifying TCP or UDP traffic
- socket_size: string specifying TCP window or socket buffer, e.g., 2M
- num_processes: int specifying number of iperf processes
- udp_throughput: string specifying TX throughput in UDP tests, e.g. 100M
- ipv6: boolean controlling the use of IP V6
- Returns:
- iperf_args: string of formatted iperf args
- """
- iperf_args = '-i {} -t {} -J '.format(interval, duration)
- if ipv6:
- iperf_args = iperf_args + '-6 '
- if traffic_type.upper() == 'UDP':
- iperf_args = iperf_args + '-u -b {} -l 1470 -P {} '.format(
- udp_throughput, num_processes)
- elif traffic_type.upper() == 'TCP':
- iperf_args = iperf_args + '-P {} '.format(num_processes)
- if socket_size:
- iperf_args = iperf_args + '-w {} '.format(socket_size)
- if reverse_direction:
- iperf_args = iperf_args + ' -R'
- return iperf_args
-
-
-# Attenuator Utilities
-def atten_by_label(atten_list, path_label, atten_level):
- """Attenuate signals according to their path label.
-
- Args:
- atten_list: list of attenuators to iterate over
- path_label: path label on which to set desired attenuation
- atten_level: attenuation desired on path
- """
- for atten in atten_list:
- if path_label in atten.path:
- atten.set_atten(atten_level)
-
-
-def get_atten_for_target_rssi(target_rssi, attenuators, dut, ping_server):
- """Function to estimate attenuation to hit a target RSSI.
-
- This function estimates a constant attenuation setting on all atennuation
- ports to hit a target RSSI. The estimate is not meant to be exact or
- guaranteed.
-
- Args:
- target_rssi: rssi of interest
- attenuators: list of attenuator ports
- dut: android device object assumed connected to a wifi network.
- ping_server: ssh connection object to ping server
- Returns:
- target_atten: attenuation setting to achieve target_rssi
- """
- logging.info('Searching attenuation for RSSI = {}dB'.format(target_rssi))
- # Set attenuator to 0 dB
- for atten in attenuators:
- atten.set_atten(0, strict=False)
- # Start ping traffic
- dut_ip = dut.droid.connectivityGetIPv4Addresses('wlan0')[0]
- # Measure starting RSSI
- ping_future = get_ping_stats_nb(src_device=ping_server,
- dest_address=dut_ip,
- ping_duration=1.5,
- ping_interval=0.02,
- ping_size=64)
- current_rssi = get_connected_rssi(dut,
- num_measurements=4,
- polling_frequency=0.25,
- first_measurement_delay=0.5,
- disconnect_warning=1,
- ignore_samples=1)
- current_rssi = current_rssi['signal_poll_rssi']['mean']
- ping_future.result()
- target_atten = 0
- logging.debug('RSSI @ {0:.2f}dB attenuation = {1:.2f}'.format(
- target_atten, current_rssi))
- within_range = 0
- for idx in range(20):
- atten_delta = max(min(current_rssi - target_rssi, 20), -20)
- target_atten = int((target_atten + atten_delta) * 4) / 4
- if target_atten < 0:
- return 0
- if target_atten > attenuators[0].get_max_atten():
- return attenuators[0].get_max_atten()
- for atten in attenuators:
- atten.set_atten(target_atten, strict=False)
- ping_future = get_ping_stats_nb(src_device=ping_server,
- dest_address=dut_ip,
- ping_duration=1.5,
- ping_interval=0.02,
- ping_size=64)
- current_rssi = get_connected_rssi(dut,
- num_measurements=4,
- polling_frequency=0.25,
- first_measurement_delay=0.5,
- disconnect_warning=1,
- ignore_samples=1)
- current_rssi = current_rssi['signal_poll_rssi']['mean']
- ping_future.result()
- logging.info('RSSI @ {0:.2f}dB attenuation = {1:.2f}'.format(
- target_atten, current_rssi))
- if abs(current_rssi - target_rssi) < 1:
- if within_range:
- logging.info(
- 'Reached RSSI: {0:.2f}. Target RSSI: {1:.2f}.'
- 'Attenuation: {2:.2f}, Iterations = {3:.2f}'.format(
- current_rssi, target_rssi, target_atten, idx))
- return target_atten
- else:
- within_range = True
- else:
- within_range = False
- return target_atten
-
-
-def get_current_atten_dut_chain_map(attenuators,
- dut,
- ping_server,
- ping_from_dut=False):
- """Function to detect mapping between attenuator ports and DUT chains.
-
- This function detects the mapping between attenuator ports and DUT chains
- in cases where DUT chains are connected to only one attenuator port. The
- function assumes the DUT is already connected to a wifi network. The
- function starts by measuring per chain RSSI at 0 attenuation, then
- attenuates one port at a time looking for the chain that reports a lower
- RSSI.
-
- Args:
- attenuators: list of attenuator ports
- dut: android device object assumed connected to a wifi network.
- ping_server: ssh connection object to ping server
- ping_from_dut: boolean controlling whether to ping from or to dut
- Returns:
- chain_map: list of dut chains, one entry per attenuator port
- """
- # Set attenuator to 0 dB
- for atten in attenuators:
- atten.set_atten(0, strict=False)
- # Start ping traffic
- dut_ip = dut.droid.connectivityGetIPv4Addresses('wlan0')[0]
- if ping_from_dut:
- ping_future = get_ping_stats_nb(dut, ping_server._settings.hostname,
- 11, 0.02, 64)
- else:
- ping_future = get_ping_stats_nb(ping_server, dut_ip, 11, 0.02, 64)
- # Measure starting RSSI
- base_rssi = get_connected_rssi(dut, 4, 0.25, 1)
- chain0_base_rssi = base_rssi['chain_0_rssi']['mean']
- chain1_base_rssi = base_rssi['chain_1_rssi']['mean']
- if chain0_base_rssi < -70 or chain1_base_rssi < -70:
- logging.warning('RSSI might be too low to get reliable chain map.')
- # Compile chain map by attenuating one path at a time and seeing which
- # chain's RSSI degrades
- chain_map = []
- for test_atten in attenuators:
- # Set one attenuator to 30 dB down
- test_atten.set_atten(30, strict=False)
- # Get new RSSI
- test_rssi = get_connected_rssi(dut, 4, 0.25, 1)
- # Assign attenuator to path that has lower RSSI
- if chain0_base_rssi > -70 and chain0_base_rssi - test_rssi[
- 'chain_0_rssi']['mean'] > 10:
- chain_map.append('DUT-Chain-0')
- elif chain1_base_rssi > -70 and chain1_base_rssi - test_rssi[
- 'chain_1_rssi']['mean'] > 10:
- chain_map.append('DUT-Chain-1')
- else:
- chain_map.append(None)
- # Reset attenuator to 0
- test_atten.set_atten(0, strict=False)
- ping_future.result()
- logging.debug('Chain Map: {}'.format(chain_map))
- return chain_map
-
-
-def get_full_rf_connection_map(attenuators,
- dut,
- ping_server,
- networks,
- ping_from_dut=False):
- """Function to detect per-network connections between attenuator and DUT.
-
- This function detects the mapping between attenuator ports and DUT chains
- on all networks in its arguments. The function connects the DUT to each
- network then calls get_current_atten_dut_chain_map to get the connection
- map on the current network. The function outputs the results in two formats
- to enable easy access when users are interested in indexing by network or
- attenuator port.
-
- Args:
- attenuators: list of attenuator ports
- dut: android device object assumed connected to a wifi network.
- ping_server: ssh connection object to ping server
- networks: dict of network IDs and configs
- Returns:
- rf_map_by_network: dict of RF connections indexed by network.
- rf_map_by_atten: list of RF connections indexed by attenuator
- """
- for atten in attenuators:
- atten.set_atten(0, strict=False)
-
- rf_map_by_network = collections.OrderedDict()
- rf_map_by_atten = [[] for atten in attenuators]
- for net_id, net_config in networks.items():
- wutils.reset_wifi(dut)
- wutils.wifi_connect(dut,
- net_config,
- num_of_tries=1,
- assert_on_fail=False,
- check_connectivity=False)
- rf_map_by_network[net_id] = get_current_atten_dut_chain_map(
- attenuators, dut, ping_server, ping_from_dut)
- for idx, chain in enumerate(rf_map_by_network[net_id]):
- if chain:
- rf_map_by_atten[idx].append({
- 'network': net_id,
- 'dut_chain': chain
- })
- logging.debug('RF Map (by Network): {}'.format(rf_map_by_network))
- logging.debug('RF Map (by Atten): {}'.format(rf_map_by_atten))
-
- return rf_map_by_network, rf_map_by_atten
-
-
-# Generic device utils
-def get_dut_temperature(dut):
- """Function to get dut temperature.
-
- The function fetches and returns the reading from the temperature sensor
- used for skin temperature and thermal throttling.
-
- Args:
- dut: AndroidDevice of interest
- Returns:
- temperature: device temperature. 0 if temperature could not be read
- """
- candidate_zones = [
- '/sys/devices/virtual/thermal/tz-by-name/skin-therm/temp',
- '/sys/devices/virtual/thermal/tz-by-name/sdm-therm-monitor/temp',
- '/sys/devices/virtual/thermal/tz-by-name/sdm-therm-adc/temp',
- '/sys/devices/virtual/thermal/tz-by-name/back_therm/temp',
- '/dev/thermal/tz-by-name/quiet_therm/temp'
- ]
- for zone in candidate_zones:
- try:
- temperature = int(dut.adb.shell('cat {}'.format(zone)))
- break
- except:
- temperature = 0
- if temperature == 0:
- logging.debug('Could not check DUT temperature.')
- elif temperature > 100:
- temperature = temperature / 1000
- return temperature
-
-
-def wait_for_dut_cooldown(dut, target_temp=50, timeout=300):
- """Function to wait for a DUT to cool down.
-
- Args:
- dut: AndroidDevice of interest
- target_temp: target cooldown temperature
- timeout: maxt time to wait for cooldown
- """
- start_time = time.time()
- while time.time() - start_time < timeout:
- temperature = get_dut_temperature(dut)
- if temperature < target_temp:
- break
- time.sleep(SHORT_SLEEP)
- elapsed_time = time.time() - start_time
- logging.debug('DUT Final Temperature: {}C. Cooldown duration: {}'.format(
- temperature, elapsed_time))
-
-
-def health_check(dut, batt_thresh=5, temp_threshold=53, cooldown=1):
- """Function to check health status of a DUT.
-
- The function checks both battery levels and temperature to avoid DUT
- powering off during the test.
-
- Args:
- dut: AndroidDevice of interest
- batt_thresh: battery level threshold
- temp_threshold: temperature threshold
- cooldown: flag to wait for DUT to cool down when overheating
- Returns:
- health_check: boolean confirming device is healthy
- """
- health_check = True
- battery_level = utils.get_battery_level(dut)
- if battery_level < batt_thresh:
- logging.warning('Battery level low ({}%)'.format(battery_level))
- health_check = False
- else:
- logging.debug('Battery level = {}%'.format(battery_level))
-
- temperature = get_dut_temperature(dut)
- if temperature > temp_threshold:
- if cooldown:
- logging.warning(
- 'Waiting for DUT to cooldown. ({} C)'.format(temperature))
- wait_for_dut_cooldown(dut, target_temp=temp_threshold - 5)
- else:
- logging.warning('DUT Overheating ({} C)'.format(temperature))
- health_check = False
- else:
- logging.debug('DUT Temperature = {} C'.format(temperature))
- return health_check
-
-
-# Wifi Device utils
-def detect_wifi_platform(dut):
- ini_check = len(dut.get_file_names('/vendor/firmware/wlan/qca_cld/'))
- if ini_check:
- wifi_platform = 'qcom'
- else:
- wifi_platform = 'brcm'
- return wifi_platform
-
-
-def detect_wifi_decorator(f):
- def wrap(*args, **kwargs):
- if 'dut' in kwargs:
- dut = kwargs['dut']
- else:
- dut = next(arg for arg in args if type(arg) == AndroidDevice)
- f_decorated = '{}_{}'.format(f.__name__, detect_wifi_platform(dut))
- f_decorated = globals()[f_decorated]
- return (f_decorated(*args, **kwargs))
-
- return wrap
-
-
-# Rssi Utilities
-def empty_rssi_result():
- return collections.OrderedDict([('data', []), ('mean', None),
- ('stdev', None)])
-
-
-@detect_wifi_decorator
-def get_connected_rssi(dut,
- num_measurements=1,
- polling_frequency=SHORT_SLEEP,
- first_measurement_delay=0,
- disconnect_warning=True,
- ignore_samples=0,
- interface=None):
- """Gets all RSSI values reported for the connected access point/BSSID.
-
- Args:
- dut: android device object from which to get RSSI
- num_measurements: number of scans done, and RSSIs collected
- polling_frequency: time to wait between RSSI measurements
- disconnect_warning: boolean controlling disconnection logging messages
- ignore_samples: number of leading samples to ignore
- Returns:
- connected_rssi: dict containing the measurements results for
- all reported RSSI values (signal_poll, per chain, etc.) and their
- statistics
- """
- pass
-
-
-@nonblocking
-def get_connected_rssi_nb(dut,
- num_measurements=1,
- polling_frequency=SHORT_SLEEP,
- first_measurement_delay=0,
- disconnect_warning=True,
- ignore_samples=0,
- interface=None):
- return get_connected_rssi(dut, num_measurements, polling_frequency,
- first_measurement_delay, disconnect_warning,
- ignore_samples, interface)
-
-
-def get_connected_rssi_qcom(dut,
- num_measurements=1,
- polling_frequency=SHORT_SLEEP,
- first_measurement_delay=0,
- disconnect_warning=True,
- ignore_samples=0,
- interface=None):
- # yapf: disable
- connected_rssi = collections.OrderedDict(
- [('time_stamp', []),
- ('bssid', []), ('ssid', []), ('frequency', []),
- ('signal_poll_rssi', empty_rssi_result()),
- ('signal_poll_avg_rssi', empty_rssi_result()),
- ('chain_0_rssi', empty_rssi_result()),
- ('chain_1_rssi', empty_rssi_result())])
- # yapf: enable
- previous_bssid = 'disconnected'
- t0 = time.time()
- time.sleep(first_measurement_delay)
- for idx in range(num_measurements):
- measurement_start_time = time.time()
- connected_rssi['time_stamp'].append(measurement_start_time - t0)
- # Get signal poll RSSI
- try:
- if interface is None:
- status_output = dut.adb.shell(WPA_CLI_STATUS)
- else:
- status_output = dut.adb.shell(
- 'wpa_cli -i {} status'.format(interface))
- except:
- status_output = ''
- match = re.search('bssid=.*', status_output)
- if match:
- current_bssid = match.group(0).split('=')[1]
- connected_rssi['bssid'].append(current_bssid)
- else:
- current_bssid = 'disconnected'
- connected_rssi['bssid'].append(current_bssid)
- if disconnect_warning and previous_bssid != 'disconnected':
- logging.warning('WIFI DISCONNECT DETECTED!')
- previous_bssid = current_bssid
- match = re.search('\s+ssid=.*', status_output)
- if match:
- ssid = match.group(0).split('=')[1]
- connected_rssi['ssid'].append(ssid)
- else:
- connected_rssi['ssid'].append('disconnected')
- try:
- if interface is None:
- signal_poll_output = dut.adb.shell(SIGNAL_POLL)
- else:
- signal_poll_output = dut.adb.shell(
- 'wpa_cli -i {} signal_poll'.format(interface))
- except:
- signal_poll_output = ''
- match = re.search('FREQUENCY=.*', signal_poll_output)
- if match:
- frequency = int(match.group(0).split('=')[1])
- connected_rssi['frequency'].append(frequency)
- else:
- connected_rssi['frequency'].append(RSSI_ERROR_VAL)
- match = re.search('RSSI=.*', signal_poll_output)
- if match:
- temp_rssi = int(match.group(0).split('=')[1])
- if temp_rssi == -9999 or temp_rssi == 0:
- connected_rssi['signal_poll_rssi']['data'].append(
- RSSI_ERROR_VAL)
- else:
- connected_rssi['signal_poll_rssi']['data'].append(temp_rssi)
- else:
- connected_rssi['signal_poll_rssi']['data'].append(RSSI_ERROR_VAL)
- match = re.search('AVG_RSSI=.*', signal_poll_output)
- if match:
- connected_rssi['signal_poll_avg_rssi']['data'].append(
- int(match.group(0).split('=')[1]))
- else:
- connected_rssi['signal_poll_avg_rssi']['data'].append(
- RSSI_ERROR_VAL)
-
- # Get per chain RSSI
- try:
- if interface is None:
- per_chain_rssi = dut.adb.shell(STATION_DUMP)
- else:
- per_chain_rssi = ''
- except:
- per_chain_rssi = ''
- match = re.search('.*signal avg:.*', per_chain_rssi)
- if match:
- per_chain_rssi = per_chain_rssi[per_chain_rssi.find('[') +
- 1:per_chain_rssi.find(']')]
- per_chain_rssi = per_chain_rssi.split(', ')
- connected_rssi['chain_0_rssi']['data'].append(
- int(per_chain_rssi[0]))
- connected_rssi['chain_1_rssi']['data'].append(
- int(per_chain_rssi[1]))
- else:
- connected_rssi['chain_0_rssi']['data'].append(RSSI_ERROR_VAL)
- connected_rssi['chain_1_rssi']['data'].append(RSSI_ERROR_VAL)
- measurement_elapsed_time = time.time() - measurement_start_time
- time.sleep(max(0, polling_frequency - measurement_elapsed_time))
-
- # Compute mean RSSIs. Only average valid readings.
- # Output RSSI_ERROR_VAL if no valid connected readings found.
- for key, val in connected_rssi.copy().items():
- if 'data' not in val:
- continue
- filtered_rssi_values = [x for x in val['data'] if not math.isnan(x)]
- if len(filtered_rssi_values) > ignore_samples:
- filtered_rssi_values = filtered_rssi_values[ignore_samples:]
- if filtered_rssi_values:
- connected_rssi[key]['mean'] = statistics.mean(filtered_rssi_values)
- if len(filtered_rssi_values) > 1:
- connected_rssi[key]['stdev'] = statistics.stdev(
- filtered_rssi_values)
- else:
- connected_rssi[key]['stdev'] = 0
- else:
- connected_rssi[key]['mean'] = RSSI_ERROR_VAL
- connected_rssi[key]['stdev'] = RSSI_ERROR_VAL
- return connected_rssi
-
-
-def get_connected_rssi_brcm(dut,
- num_measurements=1,
- polling_frequency=SHORT_SLEEP,
- first_measurement_delay=0,
- disconnect_warning=True,
- ignore_samples=0,
- interface=None):
- # yapf: disable
- connected_rssi = collections.OrderedDict(
- [('time_stamp', []),
- ('bssid', []), ('ssid', []), ('frequency', []),
- ('signal_poll_rssi', empty_rssi_result()),
- ('signal_poll_avg_rssi', empty_rssi_result()),
- ('chain_0_rssi', empty_rssi_result()),
- ('chain_1_rssi', empty_rssi_result())])
-
- # yapf: enable
- previous_bssid = 'disconnected'
- t0 = time.time()
- time.sleep(first_measurement_delay)
- for idx in range(num_measurements):
- measurement_start_time = time.time()
- connected_rssi['time_stamp'].append(measurement_start_time - t0)
- # Get signal poll RSSI
- status_output = dut.adb.shell('wl assoc')
- match = re.search('BSSID:.*', status_output)
-
- if match:
- current_bssid = match.group(0).split('\t')[0]
- current_bssid = current_bssid.split(' ')[1]
- connected_rssi['bssid'].append(current_bssid)
-
- else:
- current_bssid = 'disconnected'
- connected_rssi['bssid'].append(current_bssid)
- if disconnect_warning and previous_bssid != 'disconnected':
- logging.warning('WIFI DISCONNECT DETECTED!')
-
- previous_bssid = current_bssid
- match = re.search('SSID:.*', status_output)
- if match:
- ssid = match.group(0).split(': ')[1]
- connected_rssi['ssid'].append(ssid)
- else:
- connected_rssi['ssid'].append('disconnected')
-
- #TODO: SEARCH MAP ; PICK CENTER CHANNEL
- match = re.search('Primary channel:.*', status_output)
- if match:
- frequency = int(match.group(0).split(':')[1])
- connected_rssi['frequency'].append(frequency)
- else:
- connected_rssi['frequency'].append(RSSI_ERROR_VAL)
-
- try:
- per_chain_rssi = dut.adb.shell('wl phy_rssi_ant')
- except:
- per_chain_rssi = DISCONNECTION_MESSAGE_BRCM
- if DISCONNECTION_MESSAGE_BRCM not in per_chain_rssi:
- per_chain_rssi = per_chain_rssi.split(' ')
- chain_0_rssi = int(per_chain_rssi[1])
- chain_1_rssi = int(per_chain_rssi[4])
- connected_rssi['chain_0_rssi']['data'].append(chain_0_rssi)
- connected_rssi['chain_1_rssi']['data'].append(chain_1_rssi)
- combined_rssi = math.pow(10, chain_0_rssi / 10) + math.pow(
- 10, chain_1_rssi / 10)
- combined_rssi = 10 * math.log10(combined_rssi)
- connected_rssi['signal_poll_rssi']['data'].append(combined_rssi)
- connected_rssi['signal_poll_avg_rssi']['data'].append(
- combined_rssi)
- else:
- connected_rssi['chain_0_rssi']['data'].append(RSSI_ERROR_VAL)
- connected_rssi['chain_1_rssi']['data'].append(RSSI_ERROR_VAL)
- connected_rssi['signal_poll_rssi']['data'].append(RSSI_ERROR_VAL)
- connected_rssi['signal_poll_avg_rssi']['data'].append(
- RSSI_ERROR_VAL)
- measurement_elapsed_time = time.time() - measurement_start_time
- time.sleep(max(0, polling_frequency - measurement_elapsed_time))
-
- # Statistics, Statistics
- for key, val in connected_rssi.copy().items():
- if 'data' not in val:
- continue
- filtered_rssi_values = [x for x in val['data'] if not math.isnan(x)]
- if len(filtered_rssi_values) > ignore_samples:
- filtered_rssi_values = filtered_rssi_values[ignore_samples:]
- if filtered_rssi_values:
- connected_rssi[key]['mean'] = statistics.mean(filtered_rssi_values)
- if len(filtered_rssi_values) > 1:
- connected_rssi[key]['stdev'] = statistics.stdev(
- filtered_rssi_values)
- else:
- connected_rssi[key]['stdev'] = 0
- else:
- connected_rssi[key]['mean'] = RSSI_ERROR_VAL
- connected_rssi[key]['stdev'] = RSSI_ERROR_VAL
-
- return connected_rssi
-
-
-@detect_wifi_decorator
-def get_scan_rssi(dut, tracked_bssids, num_measurements=1):
- """Gets scan RSSI for specified BSSIDs.
-
- Args:
- dut: android device object from which to get RSSI
- tracked_bssids: array of BSSIDs to gather RSSI data for
- num_measurements: number of scans done, and RSSIs collected
- Returns:
- scan_rssi: dict containing the measurement results as well as the
- statistics of the scan RSSI for all BSSIDs in tracked_bssids
- """
- pass
-
-
-@nonblocking
-def get_scan_rssi_nb(dut, tracked_bssids, num_measurements=1):
- return get_scan_rssi(dut, tracked_bssids, num_measurements)
-
-
-def get_scan_rssi_qcom(dut, tracked_bssids, num_measurements=1):
- scan_rssi = collections.OrderedDict()
- for bssid in tracked_bssids:
- scan_rssi[bssid] = empty_rssi_result()
- for idx in range(num_measurements):
- scan_output = dut.adb.shell(SCAN)
- time.sleep(MED_SLEEP)
- scan_output = dut.adb.shell(SCAN_RESULTS)
- for bssid in tracked_bssids:
- bssid_result = re.search(bssid + '.*',
- scan_output,
- flags=re.IGNORECASE)
- if bssid_result:
- bssid_result = bssid_result.group(0).split('\t')
- scan_rssi[bssid]['data'].append(int(bssid_result[2]))
- else:
- scan_rssi[bssid]['data'].append(RSSI_ERROR_VAL)
- # Compute mean RSSIs. Only average valid readings.
- # Output RSSI_ERROR_VAL if no readings found.
- for key, val in scan_rssi.items():
- filtered_rssi_values = [x for x in val['data'] if not math.isnan(x)]
- if filtered_rssi_values:
- scan_rssi[key]['mean'] = statistics.mean(filtered_rssi_values)
- if len(filtered_rssi_values) > 1:
- scan_rssi[key]['stdev'] = statistics.stdev(
- filtered_rssi_values)
- else:
- scan_rssi[key]['stdev'] = 0
- else:
- scan_rssi[key]['mean'] = RSSI_ERROR_VAL
- scan_rssi[key]['stdev'] = RSSI_ERROR_VAL
- return scan_rssi
-
-
-def get_scan_rssi_brcm(dut, tracked_bssids, num_measurements=1):
- scan_rssi = collections.OrderedDict()
- for bssid in tracked_bssids:
- scan_rssi[bssid] = empty_rssi_result()
- for idx in range(num_measurements):
- scan_output = dut.adb.shell('cmd wifi start-scan')
- time.sleep(MED_SLEEP)
- scan_output = dut.adb.shell('cmd wifi list-scan-results')
- for bssid in tracked_bssids:
- bssid_result = re.search(bssid + '.*',
- scan_output,
- flags=re.IGNORECASE)
- if bssid_result:
- bssid_result = bssid_result.group(0).split()
- print(bssid_result)
- scan_rssi[bssid]['data'].append(int(bssid_result[2]))
- else:
- scan_rssi[bssid]['data'].append(RSSI_ERROR_VAL)
- # Compute mean RSSIs. Only average valid readings.
- # Output RSSI_ERROR_VAL if no readings found.
- for key, val in scan_rssi.items():
- filtered_rssi_values = [x for x in val['data'] if not math.isnan(x)]
- if filtered_rssi_values:
- scan_rssi[key]['mean'] = statistics.mean(filtered_rssi_values)
- if len(filtered_rssi_values) > 1:
- scan_rssi[key]['stdev'] = statistics.stdev(
- filtered_rssi_values)
- else:
- scan_rssi[key]['stdev'] = 0
- else:
- scan_rssi[key]['mean'] = RSSI_ERROR_VAL
- scan_rssi[key]['stdev'] = RSSI_ERROR_VAL
- return scan_rssi
-
-
-@detect_wifi_decorator
-def get_sw_signature(dut):
- """Function that checks the signature for wifi firmware and config files.
-
- Returns:
- bdf_signature: signature consisting of last three digits of bdf cksums
- fw_signature: floating point firmware version, i.e., major.minor
- """
- pass
-
-
-def get_sw_signature_qcom(dut):
- bdf_output = dut.adb.shell('cksum /vendor/firmware/bdwlan*')
- logging.debug('BDF Checksum output: {}'.format(bdf_output))
- bdf_signature = sum(
- [int(line.split(' ')[0]) for line in bdf_output.splitlines()]) % 1000
-
- fw_output = dut.adb.shell('halutil -logger -get fw')
- logging.debug('Firmware version output: {}'.format(fw_output))
- fw_version = re.search(FW_REGEX, fw_output).group('firmware')
- fw_signature = fw_version.split('.')[-3:-1]
- fw_signature = float('.'.join(fw_signature))
- serial_hash = int(hashlib.md5(dut.serial.encode()).hexdigest(), 16) % 1000
- return {
- 'config_signature': bdf_signature,
- 'fw_signature': fw_signature,
- 'serial_hash': serial_hash
- }
-
-
-def get_sw_signature_brcm(dut):
- bdf_output = dut.adb.shell('cksum /vendor/etc/wifi/bcmdhd*')
- logging.debug('BDF Checksum output: {}'.format(bdf_output))
- bdf_signature = sum(
- [int(line.split(' ')[0]) for line in bdf_output.splitlines()]) % 1000
-
- fw_output = dut.adb.shell('getprop vendor.wlan.firmware.version')
- logging.debug('Firmware version output: {}'.format(fw_output))
- fw_version = fw_output.split('.')[-1]
- driver_output = dut.adb.shell('getprop vendor.wlan.driver.version')
- driver_version = driver_output.split('.')[-1]
- fw_signature = float('{}.{}'.format(fw_version, driver_version))
- serial_hash = int(hashlib.md5(dut.serial.encode()).hexdigest(), 16) % 1000
- return {
- 'config_signature': bdf_signature,
- 'fw_signature': fw_signature,
- 'serial_hash': serial_hash
- }
-
-
-@detect_wifi_decorator
-def push_config(dut, config_file):
- """Function to push Wifi BDF files
-
- This function checks for existing wifi bdf files and over writes them all,
- for simplicity, with the bdf file provided in the arguments. The dut is
- rebooted for the bdf file to take effect
-
- Args:
- dut: dut to push bdf file to
- config_file: path to bdf_file to push
- """
- pass
-
-
-def push_config_qcom(dut, config_file):
- config_files_list = dut.adb.shell(
- 'ls /vendor/firmware/bdwlan*').splitlines()
- for dst_file in config_files_list:
- dut.push_system_file(config_file, dst_file)
- dut.reboot()
-
-
-def push_config_brcm(dut, config_file):
- config_files_list = dut.adb.shell('ls /vendor/etc/*.cal').splitlines()
- for dst_file in config_files_list:
- dut.push_system_file(config_file, dst_file)
- dut.reboot()
-
-
-def push_firmware(dut, firmware_files):
- """Function to push Wifi firmware files
-
- Args:
- dut: dut to push bdf file to
- firmware_files: path to wlanmdsp.mbn file
- datamsc_file: path to Data.msc file
- """
- for file in firmware_files:
- dut.push_system_file(file, '/vendor/firmware/')
- dut.reboot()
-
-
-@detect_wifi_decorator
-def start_wifi_logging(dut):
- """Function to start collecting wifi-related logs"""
- pass
-
-
-def start_wifi_logging_qcom(dut):
- dut.droid.wifiEnableVerboseLogging(1)
- msg = "Failed to enable WiFi verbose logging."
- asserts.assert_equal(dut.droid.wifiGetVerboseLoggingLevel(), 1, msg)
- logging.info('Starting CNSS logs')
- dut.adb.shell("find /data/vendor/wifi/wlan_logs/ -type f -delete",
- ignore_status=True)
- dut.adb.shell_nb('cnss_diag -f -s')
-
-
-def start_wifi_logging_brcm(dut):
- pass
-
-
-@detect_wifi_decorator
-def stop_wifi_logging(dut):
- """Function to start collecting wifi-related logs"""
- pass
-
-
-def stop_wifi_logging_qcom(dut):
- logging.info('Stopping CNSS logs')
- dut.adb.shell('killall cnss_diag')
- logs = dut.get_file_names("/data/vendor/wifi/wlan_logs/")
- if logs:
- dut.log.info("Pulling cnss_diag logs %s", logs)
- log_path = os.path.join(dut.device_log_path,
- "CNSS_DIAG_%s" % dut.serial)
- os.makedirs(log_path, exist_ok=True)
- dut.pull_files(logs, log_path)
-
-
-def stop_wifi_logging_brcm(dut):
- pass
-
-
-def _set_ini_fields(ini_file_path, ini_field_dict):
- template_regex = r'^{}=[0-9,.x-]+'
- with open(ini_file_path, 'r') as f:
- ini_lines = f.read().splitlines()
- for idx, line in enumerate(ini_lines):
- for field_name, field_value in ini_field_dict.items():
- line_regex = re.compile(template_regex.format(field_name))
- if re.match(line_regex, line):
- ini_lines[idx] = '{}={}'.format(field_name, field_value)
- print(ini_lines[idx])
- with open(ini_file_path, 'w') as f:
- f.write('\n'.join(ini_lines) + '\n')
-
-
-def _edit_dut_ini(dut, ini_fields):
- """Function to edit Wifi ini files."""
- dut_ini_path = '/vendor/firmware/wlan/qca_cld/WCNSS_qcom_cfg.ini'
- local_ini_path = os.path.expanduser('~/WCNSS_qcom_cfg.ini')
- dut.pull_files(dut_ini_path, local_ini_path)
-
- _set_ini_fields(local_ini_path, ini_fields)
-
- dut.push_system_file(local_ini_path, dut_ini_path)
- dut.reboot()
-
-
-def set_ini_single_chain_mode(dut, chain):
- ini_fields = {
- 'gEnable2x2': 0,
- 'gSetTxChainmask1x1': chain + 1,
- 'gSetRxChainmask1x1': chain + 1,
- 'gDualMacFeatureDisable': 1,
- 'gDot11Mode': 0
- }
- _edit_dut_ini(dut, ini_fields)
-
-
-def set_ini_two_chain_mode(dut):
- ini_fields = {
- 'gEnable2x2': 2,
- 'gSetTxChainmask1x1': 1,
- 'gSetRxChainmask1x1': 1,
- 'gDualMacFeatureDisable': 6,
- 'gDot11Mode': 0
- }
- _edit_dut_ini(dut, ini_fields)
-
-
-def set_ini_tx_mode(dut, mode):
- TX_MODE_DICT = {
- 'Auto': 0,
- '11n': 4,
- '11ac': 9,
- '11abg': 1,
- '11b': 2,
- '11': 3,
- '11g only': 5,
- '11n only': 6,
- '11b only': 7,
- '11ac only': 8
- }
-
- ini_fields = {
- 'gEnable2x2': 2,
- 'gSetTxChainmask1x1': 1,
- 'gSetRxChainmask1x1': 1,
- 'gDualMacFeatureDisable': 6,
- 'gDot11Mode': TX_MODE_DICT[mode]
- }
- _edit_dut_ini(dut, ini_fields)
-
-
-# Link layer stats utilities
-class LinkLayerStats():
- def __new__(self, dut, llstats_enabled=True):
- if detect_wifi_platform(dut) == 'qcom':
- return LinkLayerStatsQcom(dut, llstats_enabled=True)
- else:
- return LinkLayerStatsBrcm(dut, llstats_enabled=True)
-
-
-class LinkLayerStatsQcom():
-
- LLSTATS_CMD = 'cat /d/wlan0/ll_stats'
- PEER_REGEX = 'LL_STATS_PEER_ALL'
- MCS_REGEX = re.compile(
- r'preamble: (?P<mode>\S+), nss: (?P<num_streams>\S+), bw: (?P<bw>\S+), '
- 'mcs: (?P<mcs>\S+), bitrate: (?P<rate>\S+), txmpdu: (?P<txmpdu>\S+), '
- 'rxmpdu: (?P<rxmpdu>\S+), mpdu_lost: (?P<mpdu_lost>\S+), '
- 'retries: (?P<retries>\S+), retries_short: (?P<retries_short>\S+), '
- 'retries_long: (?P<retries_long>\S+)')
- MCS_ID = collections.namedtuple(
- 'mcs_id', ['mode', 'num_streams', 'bandwidth', 'mcs', 'rate'])
- MODE_MAP = {'0': '11a/g', '1': '11b', '2': '11n', '3': '11ac'}
- BW_MAP = {'0': 20, '1': 40, '2': 80}
-
- def __init__(self, dut, llstats_enabled=True):
- self.dut = dut
- self.llstats_enabled = llstats_enabled
- self.llstats_cumulative = self._empty_llstats()
- self.llstats_incremental = self._empty_llstats()
-
- def update_stats(self):
- if self.llstats_enabled:
- try:
- llstats_output = self.dut.adb.shell(self.LLSTATS_CMD,
- timeout=0.1)
- except:
- llstats_output = ''
- else:
- llstats_output = ''
- self._update_stats(llstats_output)
-
- def reset_stats(self):
- self.llstats_cumulative = self._empty_llstats()
- self.llstats_incremental = self._empty_llstats()
-
- def _empty_llstats(self):
- return collections.OrderedDict(mcs_stats=collections.OrderedDict(),
- summary=collections.OrderedDict())
-
- def _empty_mcs_stat(self):
- return collections.OrderedDict(txmpdu=0,
- rxmpdu=0,
- mpdu_lost=0,
- retries=0,
- retries_short=0,
- retries_long=0)
-
- def _mcs_id_to_string(self, mcs_id):
- mcs_string = '{} {}MHz Nss{} MCS{} {}Mbps'.format(
- mcs_id.mode, mcs_id.bandwidth, mcs_id.num_streams, mcs_id.mcs,
- mcs_id.rate)
- return mcs_string
-
- def _parse_mcs_stats(self, llstats_output):
- llstats_dict = {}
- # Look for per-peer stats
- match = re.search(self.PEER_REGEX, llstats_output)
- if not match:
- self.reset_stats()
- return collections.OrderedDict()
- # Find and process all matches for per stream stats
- match_iter = re.finditer(self.MCS_REGEX, llstats_output)
- for match in match_iter:
- current_mcs = self.MCS_ID(self.MODE_MAP[match.group('mode')],
- int(match.group('num_streams')) + 1,
- self.BW_MAP[match.group('bw')],
- int(match.group('mcs')),
- int(match.group('rate'), 16) / 1000)
- current_stats = collections.OrderedDict(
- txmpdu=int(match.group('txmpdu')),
- rxmpdu=int(match.group('rxmpdu')),
- mpdu_lost=int(match.group('mpdu_lost')),
- retries=int(match.group('retries')),
- retries_short=int(match.group('retries_short')),
- retries_long=int(match.group('retries_long')))
- llstats_dict[self._mcs_id_to_string(current_mcs)] = current_stats
- return llstats_dict
-
- def _diff_mcs_stats(self, new_stats, old_stats):
- stats_diff = collections.OrderedDict()
- for stat_key in new_stats.keys():
- stats_diff[stat_key] = new_stats[stat_key] - old_stats[stat_key]
- return stats_diff
-
- def _generate_stats_summary(self, llstats_dict):
- llstats_summary = collections.OrderedDict(common_tx_mcs=None,
- common_tx_mcs_count=0,
- common_tx_mcs_freq=0,
- common_rx_mcs=None,
- common_rx_mcs_count=0,
- common_rx_mcs_freq=0)
- txmpdu_count = 0
- rxmpdu_count = 0
- for mcs_id, mcs_stats in llstats_dict['mcs_stats'].items():
- if mcs_stats['txmpdu'] > llstats_summary['common_tx_mcs_count']:
- llstats_summary['common_tx_mcs'] = mcs_id
- llstats_summary['common_tx_mcs_count'] = mcs_stats['txmpdu']
- if mcs_stats['rxmpdu'] > llstats_summary['common_rx_mcs_count']:
- llstats_summary['common_rx_mcs'] = mcs_id
- llstats_summary['common_rx_mcs_count'] = mcs_stats['rxmpdu']
- txmpdu_count += mcs_stats['txmpdu']
- rxmpdu_count += mcs_stats['rxmpdu']
- if txmpdu_count:
- llstats_summary['common_tx_mcs_freq'] = (
- llstats_summary['common_tx_mcs_count'] / txmpdu_count)
- if rxmpdu_count:
- llstats_summary['common_rx_mcs_freq'] = (
- llstats_summary['common_rx_mcs_count'] / rxmpdu_count)
- return llstats_summary
-
- def _update_stats(self, llstats_output):
- # Parse stats
- new_llstats = self._empty_llstats()
- new_llstats['mcs_stats'] = self._parse_mcs_stats(llstats_output)
- # Save old stats and set new cumulative stats
- old_llstats = self.llstats_cumulative.copy()
- self.llstats_cumulative = new_llstats.copy()
- # Compute difference between new and old stats
- self.llstats_incremental = self._empty_llstats()
- for mcs_id, new_mcs_stats in new_llstats['mcs_stats'].items():
- old_mcs_stats = old_llstats['mcs_stats'].get(
- mcs_id, self._empty_mcs_stat())
- self.llstats_incremental['mcs_stats'][
- mcs_id] = self._diff_mcs_stats(new_mcs_stats, old_mcs_stats)
- # Generate llstats summary
- self.llstats_incremental['summary'] = self._generate_stats_summary(
- self.llstats_incremental)
- self.llstats_cumulative['summary'] = self._generate_stats_summary(
- self.llstats_cumulative)
-
-
-class LinkLayerStatsBrcm():
- def __init__(self, dut, llstats_enabled=True):
- self.dut = dut
- self.llstats_enabled = llstats_enabled
- self.llstats_incremental = self._empty_llstats()
- self.llstats_cumulative = self.llstats_incremental
-
- def _empty_llstats(self):
- return collections.OrderedDict(mcs_stats=collections.OrderedDict(),
- summary=collections.OrderedDict())
-
- def update_stats(self):
- self.llstats_incremental = self._empty_llstats()
- self.llstats_incremental['summary'] = collections.OrderedDict(
- common_tx_mcs=None,
- common_tx_mcs_count=1,
- common_tx_mcs_freq=1,
- common_rx_mcs=None,
- common_rx_mcs_count=1,
- common_rx_mcs_freq=1)
- if self.llstats_enabled:
- try:
- rate_info = self.dut.adb.shell('wl rate_info', timeout=0.1)
- self.llstats_incremental['summary'][
- 'common_tx_mcs'] = '{} Mbps'.format(
- re.findall('\[Tx\]:'
- ' (\d+[.]*\d* Mbps)', rate_info))
- self.llstats_incremental['summary'][
- 'common_rx_mcs'] = '{} Mbps'.format(
- re.findall('\[Rx\]:'
- ' (\d+[.]*\d* Mbps)', rate_info))
- except:
- pass
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/__init__.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/__init__.py
new file mode 100644
index 0000000..4e32f1a
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/__init__.py
@@ -0,0 +1,747 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2019 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import collections
+import importlib
+import ipaddress
+import logging
+import numpy
+import re
+import time
+from acts import asserts
+from acts import utils
+from acts.controllers.android_device import AndroidDevice
+from acts.controllers.utils_lib import ssh
+from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from acts_contrib.test_utils.wifi.wifi_performance_test_utils import ping_utils
+from acts_contrib.test_utils.wifi.wifi_performance_test_utils import qcom_utils
+from acts_contrib.test_utils.wifi.wifi_performance_test_utils import brcm_utils
+
+from concurrent.futures import ThreadPoolExecutor
+
+SHORT_SLEEP = 1
+MED_SLEEP = 6
+CHANNELS_6GHz = ['6g{}'.format(4 * x + 1) for x in range(59)]
+BAND_TO_CHANNEL_MAP = {
+ '2.4GHz': list(range(1, 14)),
+ 'UNII-1': [36, 40, 44, 48],
+ 'UNII-2':
+ [52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 140],
+ 'UNII-3': [149, 153, 157, 161, 165],
+ '6GHz': CHANNELS_6GHz
+}
+CHANNEL_TO_BAND_MAP = {
+ channel: band
+ for band, channels in BAND_TO_CHANNEL_MAP.items() for channel in channels
+}
+
+
+# Decorators
+def nonblocking(f):
+ """Creates a decorator transforming function calls to non-blocking"""
+ def wrap(*args, **kwargs):
+ executor = ThreadPoolExecutor(max_workers=1)
+ thread_future = executor.submit(f, *args, **kwargs)
+ # Ensure resources are freed up when executor ruturns or raises
+ executor.shutdown(wait=False)
+ return thread_future
+
+ return wrap
+
+
+def detect_wifi_platform(dut):
+ if hasattr(dut, 'wifi_platform'):
+ return dut.wifi_platform
+ qcom_check = len(dut.get_file_names('/vendor/firmware/wlan/qca_cld/'))
+ if qcom_check:
+ dut.wifi_platform = 'qcom'
+ else:
+ dut.wifi_platform = 'brcm'
+ return dut.wifi_platform
+
+
+def detect_wifi_decorator(f):
+ def wrap(*args, **kwargs):
+ if 'dut' in kwargs:
+ dut = kwargs['dut']
+ else:
+ dut = next(arg for arg in args if type(arg) == AndroidDevice)
+ dut_package = 'acts_contrib.test_utils.wifi.wifi_performance_test_utils.{}_utils'.format(
+ detect_wifi_platform(dut))
+ dut_package = importlib.import_module(dut_package)
+ f_decorated = getattr(dut_package, f.__name__, lambda: None)
+ return (f_decorated(*args, **kwargs))
+
+ return wrap
+
+
+# JSON serializer
+def serialize_dict(input_dict):
+ """Function to serialize dicts to enable JSON output"""
+ output_dict = collections.OrderedDict()
+ for key, value in input_dict.items():
+ output_dict[_serialize_value(key)] = _serialize_value(value)
+ return output_dict
+
+
+def _serialize_value(value):
+ """Function to recursively serialize dict entries to enable JSON output"""
+ if isinstance(value, tuple):
+ return str(value)
+ if isinstance(value, numpy.int64):
+ return int(value)
+ if isinstance(value, numpy.float64):
+ return float(value)
+ if isinstance(value, list):
+ return [_serialize_value(x) for x in value]
+ if isinstance(value, numpy.ndarray):
+ return [_serialize_value(x) for x in value]
+ elif isinstance(value, dict):
+ return serialize_dict(value)
+ elif type(value) in (float, int, bool, str):
+ return value
+ else:
+ return "Non-serializable object"
+
+
+def extract_sub_dict(full_dict, fields):
+ sub_dict = collections.OrderedDict(
+ (field, full_dict[field]) for field in fields)
+ return sub_dict
+
+
+# Miscellaneous Wifi Utilities
+def check_skip_conditions(testcase_params,
+ dut,
+ access_point,
+ ota_chamber=None):
+ """Checks if test should be skipped."""
+ # Check battery level before test
+ if not health_check(dut, 10):
+ asserts.skip('DUT battery level too low.')
+ if not access_point.band_lookup_by_channel(testcase_params['channel']):
+ asserts.skip('AP does not support requested channel.')
+ if ota_chamber and CHANNEL_TO_BAND_MAP[
+ testcase_params['channel']] not in ota_chamber.SUPPORTED_BANDS:
+ asserts.skip('OTA chamber does not support requested channel.')
+ # Check if 6GHz is supported by checking capabilities in the US.
+ if not dut.droid.wifiCheckState():
+ wutils.wifi_toggle_state(dut, True)
+ iw_list = dut.adb.shell('iw list')
+ supports_6ghz = '6135 MHz' in iw_list
+ supports_160mhz = 'Supported Channel Width: 160 MHz' in iw_list
+ if testcase_params.get('bandwidth', 20) == 160 and not supports_160mhz:
+ asserts.skip('DUT does not support 160 MHz networks.')
+ if testcase_params.get('channel',
+ 6) in CHANNELS_6GHz and not supports_6ghz:
+ asserts.skip('DUT does not support 6 GHz band.')
+
+
+def validate_network(dut, ssid):
+ """Check that DUT has a valid internet connection through expected SSID
+
+ Args:
+ dut: android device of interest
+ ssid: expected ssid
+ """
+ try:
+ connected = wutils.validate_connection(dut, wait_time=3) is not None
+ current_network = dut.droid.wifiGetConnectionInfo()
+ except:
+ connected = False
+ current_network = None
+ if connected and current_network['SSID'] == ssid:
+ return True
+ else:
+ return False
+
+
+def get_server_address(ssh_connection, dut_ip, subnet_mask):
+ """Get server address on a specific subnet,
+
+ This function retrieves the LAN or WAN IP of a remote machine used in
+ testing. If subnet_mask is set to 'public' it returns a machines global ip,
+ else it returns the ip belonging to the dut local network given the dut's
+ ip and subnet mask.
+
+ Args:
+ ssh_connection: object representing server for which we want an ip
+ dut_ip: string in ip address format, i.e., xxx.xxx.xxx.xxx
+ subnet_mask: string representing subnet mask (public for global ip)
+ """
+ ifconfig_out = ssh_connection.run('ifconfig').stdout
+ ip_list = re.findall('inet (?:addr:)?(\d+.\d+.\d+.\d+)', ifconfig_out)
+ ip_list = [ipaddress.ip_address(ip) for ip in ip_list]
+
+ if subnet_mask == 'public':
+ for ip in ip_list:
+ # is_global is not used to allow for CGNAT ips in 100.x.y.z range
+ if not ip.is_private:
+ return str(ip)
+ else:
+ dut_network = ipaddress.ip_network('{}/{}'.format(dut_ip, subnet_mask),
+ strict=False)
+ for ip in ip_list:
+ if ip in dut_network:
+ return str(ip)
+ logging.error('No IP address found in requested subnet')
+
+
+# Ping utilities
+def get_ping_stats(src_device, dest_address, ping_duration, ping_interval,
+ ping_size):
+ """Run ping to or from the DUT.
+
+ The function computes either pings the DUT or pings a remote ip from
+ DUT.
+
+ Args:
+ src_device: object representing device to ping from
+ dest_address: ip address to ping
+ ping_duration: timeout to set on the ping process (in seconds)
+ ping_interval: time between pings (in seconds)
+ ping_size: size of ping packet payload
+ Returns:
+ ping_result: dict containing ping results and other meta data
+ """
+ ping_count = int(ping_duration / ping_interval)
+ ping_deadline = int(ping_count * ping_interval) + 1
+ ping_cmd_linux = 'ping -c {} -w {} -i {} -s {} -D'.format(
+ ping_count,
+ ping_deadline,
+ ping_interval,
+ ping_size,
+ )
+
+ ping_cmd_macos = 'ping -c {} -t {} -i {} -s {}'.format(
+ ping_count,
+ ping_deadline,
+ ping_interval,
+ ping_size,
+ )
+
+ if isinstance(src_device, AndroidDevice):
+ ping_cmd = '{} {}'.format(ping_cmd_linux, dest_address)
+ ping_output = src_device.adb.shell(ping_cmd,
+ timeout=ping_deadline + SHORT_SLEEP,
+ ignore_status=True)
+ elif isinstance(src_device, ssh.connection.SshConnection):
+ platform = src_device.run('uname').stdout
+ if 'linux' in platform.lower():
+ ping_cmd = 'sudo {} {}'.format(ping_cmd_linux, dest_address)
+ elif 'darwin' in platform.lower():
+ ping_cmd = "sudo {} {}| while IFS= read -r line; do printf '[%s] %s\n' \"$(gdate '+%s.%N')\" \"$line\"; done".format(
+ ping_cmd_macos, dest_address)
+ ping_output = src_device.run(ping_cmd,
+ timeout=ping_deadline + SHORT_SLEEP,
+ ignore_status=True).stdout
+ else:
+ raise TypeError('Unable to ping using src_device of type %s.' %
+ type(src_device))
+ return ping_utils.PingResult(ping_output.splitlines())
+
+
+@nonblocking
+def get_ping_stats_nb(src_device, dest_address, ping_duration, ping_interval,
+ ping_size):
+ return get_ping_stats(src_device, dest_address, ping_duration,
+ ping_interval, ping_size)
+
+
+# Iperf utilities
+@nonblocking
+def start_iperf_client_nb(iperf_client, iperf_server_address, iperf_args, tag,
+ timeout):
+ return iperf_client.start(iperf_server_address, iperf_args, tag, timeout)
+
+
+def get_iperf_arg_string(duration,
+ reverse_direction,
+ interval=1,
+ traffic_type='TCP',
+ socket_size=None,
+ num_processes=1,
+ udp_throughput='1000M',
+ ipv6=False):
+ """Function to format iperf client arguments.
+
+ This function takes in iperf client parameters and returns a properly
+ formatter iperf arg string to be used in throughput tests.
+
+ Args:
+ duration: iperf duration in seconds
+ reverse_direction: boolean controlling the -R flag for iperf clients
+ interval: iperf print interval
+ traffic_type: string specifying TCP or UDP traffic
+ socket_size: string specifying TCP window or socket buffer, e.g., 2M
+ num_processes: int specifying number of iperf processes
+ udp_throughput: string specifying TX throughput in UDP tests, e.g. 100M
+ ipv6: boolean controlling the use of IP V6
+ Returns:
+ iperf_args: string of formatted iperf args
+ """
+ iperf_args = '-i {} -t {} -J '.format(interval, duration)
+ if ipv6:
+ iperf_args = iperf_args + '-6 '
+ if traffic_type.upper() == 'UDP':
+ iperf_args = iperf_args + '-u -b {} -l 1470 -P {} '.format(
+ udp_throughput, num_processes)
+ elif traffic_type.upper() == 'TCP':
+ iperf_args = iperf_args + '-P {} '.format(num_processes)
+ if socket_size:
+ iperf_args = iperf_args + '-w {} '.format(socket_size)
+ if reverse_direction:
+ iperf_args = iperf_args + ' -R'
+ return iperf_args
+
+
+# Attenuator Utilities
+def atten_by_label(atten_list, path_label, atten_level):
+ """Attenuate signals according to their path label.
+
+ Args:
+ atten_list: list of attenuators to iterate over
+ path_label: path label on which to set desired attenuation
+ atten_level: attenuation desired on path
+ """
+ for atten in atten_list:
+ if path_label in atten.path:
+ atten.set_atten(atten_level, retry=True)
+
+
+def get_atten_for_target_rssi(target_rssi, attenuators, dut, ping_server):
+ """Function to estimate attenuation to hit a target RSSI.
+
+ This function estimates a constant attenuation setting on all atennuation
+ ports to hit a target RSSI. The estimate is not meant to be exact or
+ guaranteed.
+
+ Args:
+ target_rssi: rssi of interest
+ attenuators: list of attenuator ports
+ dut: android device object assumed connected to a wifi network.
+ ping_server: ssh connection object to ping server
+ Returns:
+ target_atten: attenuation setting to achieve target_rssi
+ """
+ logging.info('Searching attenuation for RSSI = {}dB'.format(target_rssi))
+ # Set attenuator to 0 dB
+ for atten in attenuators:
+ atten.set_atten(0, strict=False, retry=True)
+ # Start ping traffic
+ dut_ip = dut.droid.connectivityGetIPv4Addresses('wlan0')[0]
+ # Measure starting RSSI
+ ping_future = get_ping_stats_nb(src_device=ping_server,
+ dest_address=dut_ip,
+ ping_duration=1.5,
+ ping_interval=0.02,
+ ping_size=64)
+ current_rssi = get_connected_rssi(dut,
+ num_measurements=4,
+ polling_frequency=0.25,
+ first_measurement_delay=0.5,
+ disconnect_warning=1,
+ ignore_samples=1)
+ current_rssi = current_rssi['signal_poll_rssi']['mean']
+ ping_future.result()
+ target_atten = 0
+ logging.debug('RSSI @ {0:.2f}dB attenuation = {1:.2f}'.format(
+ target_atten, current_rssi))
+ within_range = 0
+ for idx in range(20):
+ atten_delta = max(min(current_rssi - target_rssi, 20), -20)
+ target_atten = int((target_atten + atten_delta) * 4) / 4
+ if target_atten < 0:
+ return 0
+ if target_atten > attenuators[0].get_max_atten():
+ return attenuators[0].get_max_atten()
+ for atten in attenuators:
+ atten.set_atten(target_atten, strict=False, retry=True)
+ ping_future = get_ping_stats_nb(src_device=ping_server,
+ dest_address=dut_ip,
+ ping_duration=1.5,
+ ping_interval=0.02,
+ ping_size=64)
+ current_rssi = get_connected_rssi(dut,
+ num_measurements=4,
+ polling_frequency=0.25,
+ first_measurement_delay=0.5,
+ disconnect_warning=1,
+ ignore_samples=1)
+ current_rssi = current_rssi['signal_poll_rssi']['mean']
+ ping_future.result()
+ logging.info('RSSI @ {0:.2f}dB attenuation = {1:.2f}'.format(
+ target_atten, current_rssi))
+ if abs(current_rssi - target_rssi) < 1:
+ if within_range:
+ logging.info(
+ 'Reached RSSI: {0:.2f}. Target RSSI: {1:.2f}.'
+ 'Attenuation: {2:.2f}, Iterations = {3:.2f}'.format(
+ current_rssi, target_rssi, target_atten, idx))
+ return target_atten
+ else:
+ within_range = True
+ else:
+ within_range = False
+ return target_atten
+
+
+def get_current_atten_dut_chain_map(attenuators,
+ dut,
+ ping_server,
+ ping_from_dut=False):
+ """Function to detect mapping between attenuator ports and DUT chains.
+
+ This function detects the mapping between attenuator ports and DUT chains
+ in cases where DUT chains are connected to only one attenuator port. The
+ function assumes the DUT is already connected to a wifi network. The
+ function starts by measuring per chain RSSI at 0 attenuation, then
+ attenuates one port at a time looking for the chain that reports a lower
+ RSSI.
+
+ Args:
+ attenuators: list of attenuator ports
+ dut: android device object assumed connected to a wifi network.
+ ping_server: ssh connection object to ping server
+ ping_from_dut: boolean controlling whether to ping from or to dut
+ Returns:
+ chain_map: list of dut chains, one entry per attenuator port
+ """
+ # Set attenuator to 0 dB
+ for atten in attenuators:
+ atten.set_atten(0, strict=False, retry=True)
+ # Start ping traffic
+ dut_ip = dut.droid.connectivityGetIPv4Addresses('wlan0')[0]
+ if ping_from_dut:
+ ping_future = get_ping_stats_nb(dut, ping_server._settings.hostname,
+ 11, 0.02, 64)
+ else:
+ ping_future = get_ping_stats_nb(ping_server, dut_ip, 11, 0.02, 64)
+ # Measure starting RSSI
+ base_rssi = get_connected_rssi(dut, 4, 0.25, 1)
+ chain0_base_rssi = base_rssi['chain_0_rssi']['mean']
+ chain1_base_rssi = base_rssi['chain_1_rssi']['mean']
+ if chain0_base_rssi < -70 or chain1_base_rssi < -70:
+ logging.warning('RSSI might be too low to get reliable chain map.')
+ # Compile chain map by attenuating one path at a time and seeing which
+ # chain's RSSI degrades
+ chain_map = []
+ for test_atten in attenuators:
+ # Set one attenuator to 30 dB down
+ test_atten.set_atten(30, strict=False, retry=True)
+ # Get new RSSI
+ test_rssi = get_connected_rssi(dut, 4, 0.25, 1)
+ # Assign attenuator to path that has lower RSSI
+ if chain0_base_rssi > -70 and chain0_base_rssi - test_rssi[
+ 'chain_0_rssi']['mean'] > 10:
+ chain_map.append('DUT-Chain-0')
+ elif chain1_base_rssi > -70 and chain1_base_rssi - test_rssi[
+ 'chain_1_rssi']['mean'] > 10:
+ chain_map.append('DUT-Chain-1')
+ else:
+ chain_map.append(None)
+ # Reset attenuator to 0
+ test_atten.set_atten(0, strict=False, retry=True)
+ ping_future.result()
+ logging.debug('Chain Map: {}'.format(chain_map))
+ return chain_map
+
+
+def get_full_rf_connection_map(attenuators,
+ dut,
+ ping_server,
+ networks,
+ ping_from_dut=False):
+ """Function to detect per-network connections between attenuator and DUT.
+
+ This function detects the mapping between attenuator ports and DUT chains
+ on all networks in its arguments. The function connects the DUT to each
+ network then calls get_current_atten_dut_chain_map to get the connection
+ map on the current network. The function outputs the results in two formats
+ to enable easy access when users are interested in indexing by network or
+ attenuator port.
+
+ Args:
+ attenuators: list of attenuator ports
+ dut: android device object assumed connected to a wifi network.
+ ping_server: ssh connection object to ping server
+ networks: dict of network IDs and configs
+ Returns:
+ rf_map_by_network: dict of RF connections indexed by network.
+ rf_map_by_atten: list of RF connections indexed by attenuator
+ """
+ for atten in attenuators:
+ atten.set_atten(0, strict=False, retry=True)
+
+ rf_map_by_network = collections.OrderedDict()
+ rf_map_by_atten = [[] for atten in attenuators]
+ for net_id, net_config in networks.items():
+ wutils.reset_wifi(dut)
+ wutils.wifi_connect(dut,
+ net_config,
+ num_of_tries=1,
+ assert_on_fail=False,
+ check_connectivity=False)
+ rf_map_by_network[net_id] = get_current_atten_dut_chain_map(
+ attenuators, dut, ping_server, ping_from_dut)
+ for idx, chain in enumerate(rf_map_by_network[net_id]):
+ if chain:
+ rf_map_by_atten[idx].append({
+ 'network': net_id,
+ 'dut_chain': chain
+ })
+ logging.debug('RF Map (by Network): {}'.format(rf_map_by_network))
+ logging.debug('RF Map (by Atten): {}'.format(rf_map_by_atten))
+
+ return rf_map_by_network, rf_map_by_atten
+
+
+# Generic device utils
+def get_dut_temperature(dut):
+ """Function to get dut temperature.
+
+ The function fetches and returns the reading from the temperature sensor
+ used for skin temperature and thermal throttling.
+
+ Args:
+ dut: AndroidDevice of interest
+ Returns:
+ temperature: device temperature. 0 if temperature could not be read
+ """
+ candidate_zones = [
+ '/sys/devices/virtual/thermal/tz-by-name/skin-therm/temp',
+ '/sys/devices/virtual/thermal/tz-by-name/sdm-therm-monitor/temp',
+ '/sys/devices/virtual/thermal/tz-by-name/sdm-therm-adc/temp',
+ '/sys/devices/virtual/thermal/tz-by-name/back_therm/temp',
+ '/dev/thermal/tz-by-name/quiet_therm/temp'
+ ]
+ for zone in candidate_zones:
+ try:
+ temperature = int(dut.adb.shell('cat {}'.format(zone)))
+ break
+ except:
+ temperature = 0
+ if temperature == 0:
+ logging.debug('Could not check DUT temperature.')
+ elif temperature > 100:
+ temperature = temperature / 1000
+ return temperature
+
+
+def wait_for_dut_cooldown(dut, target_temp=50, timeout=300):
+ """Function to wait for a DUT to cool down.
+
+ Args:
+ dut: AndroidDevice of interest
+ target_temp: target cooldown temperature
+ timeout: maxt time to wait for cooldown
+ """
+ start_time = time.time()
+ while time.time() - start_time < timeout:
+ temperature = get_dut_temperature(dut)
+ if temperature < target_temp:
+ break
+ time.sleep(SHORT_SLEEP)
+ elapsed_time = time.time() - start_time
+ logging.debug('DUT Final Temperature: {}C. Cooldown duration: {}'.format(
+ temperature, elapsed_time))
+
+
+def health_check(dut, batt_thresh=5, temp_threshold=53, cooldown=1):
+ """Function to check health status of a DUT.
+
+ The function checks both battery levels and temperature to avoid DUT
+ powering off during the test.
+
+ Args:
+ dut: AndroidDevice of interest
+ batt_thresh: battery level threshold
+ temp_threshold: temperature threshold
+ cooldown: flag to wait for DUT to cool down when overheating
+ Returns:
+ health_check: boolean confirming device is healthy
+ """
+ health_check = True
+ battery_level = utils.get_battery_level(dut)
+ if battery_level < batt_thresh:
+ logging.warning('Battery level low ({}%)'.format(battery_level))
+ health_check = False
+ else:
+ logging.debug('Battery level = {}%'.format(battery_level))
+
+ temperature = get_dut_temperature(dut)
+ if temperature > temp_threshold:
+ if cooldown:
+ logging.warning(
+ 'Waiting for DUT to cooldown. ({} C)'.format(temperature))
+ wait_for_dut_cooldown(dut, target_temp=temp_threshold - 5)
+ else:
+ logging.warning('DUT Overheating ({} C)'.format(temperature))
+ health_check = False
+ else:
+ logging.debug('DUT Temperature = {} C'.format(temperature))
+ return health_check
+
+
+# Wifi Device Utils
+def empty_rssi_result():
+ return collections.OrderedDict([('data', []), ('mean', float('nan')),
+ ('stdev', float('nan'))])
+
+
+@nonblocking
+def get_connected_rssi_nb(dut,
+ num_measurements=1,
+ polling_frequency=SHORT_SLEEP,
+ first_measurement_delay=0,
+ disconnect_warning=True,
+ ignore_samples=0,
+ interface='wlan0'):
+ return get_connected_rssi(dut, num_measurements, polling_frequency,
+ first_measurement_delay, disconnect_warning,
+ ignore_samples, interface)
+
+
+@detect_wifi_decorator
+def get_connected_rssi(dut,
+ num_measurements=1,
+ polling_frequency=SHORT_SLEEP,
+ first_measurement_delay=0,
+ disconnect_warning=True,
+ ignore_samples=0,
+ interface='wlan0'):
+ """Gets all RSSI values reported for the connected access point/BSSID.
+
+ Args:
+ dut: android device object from which to get RSSI
+ num_measurements: number of scans done, and RSSIs collected
+ polling_frequency: time to wait between RSSI measurements
+ disconnect_warning: boolean controlling disconnection logging messages
+ ignore_samples: number of leading samples to ignore
+ Returns:
+ connected_rssi: dict containing the measurements results for
+ all reported RSSI values (signal_poll, per chain, etc.) and their
+ statistics
+ """
+ pass
+
+
+@nonblocking
+def get_scan_rssi_nb(dut, tracked_bssids, num_measurements=1):
+ return get_scan_rssi(dut, tracked_bssids, num_measurements)
+
+
+@detect_wifi_decorator
+def get_scan_rssi(dut, tracked_bssids, num_measurements=1):
+ """Gets scan RSSI for specified BSSIDs.
+
+ Args:
+ dut: android device object from which to get RSSI
+ tracked_bssids: array of BSSIDs to gather RSSI data for
+ num_measurements: number of scans done, and RSSIs collected
+ Returns:
+ scan_rssi: dict containing the measurement results as well as the
+ statistics of the scan RSSI for all BSSIDs in tracked_bssids
+ """
+ pass
+
+
+@detect_wifi_decorator
+def get_sw_signature(dut):
+ """Function that checks the signature for wifi firmware and config files.
+
+ Returns:
+ bdf_signature: signature consisting of last three digits of bdf cksums
+ fw_signature: floating point firmware version, i.e., major.minor
+ """
+ pass
+
+
+@detect_wifi_decorator
+def get_country_code(dut):
+ """Function that returns the current wifi country code."""
+ pass
+
+
+@detect_wifi_decorator
+def push_config(dut, config_file):
+ """Function to push Wifi BDF files
+
+ This function checks for existing wifi bdf files and over writes them all,
+ for simplicity, with the bdf file provided in the arguments. The dut is
+ rebooted for the bdf file to take effect
+
+ Args:
+ dut: dut to push bdf file to
+ config_file: path to bdf_file to push
+ """
+ pass
+
+
+@detect_wifi_decorator
+def start_wifi_logging(dut):
+ """Function to start collecting wifi-related logs"""
+ pass
+
+
+@detect_wifi_decorator
+def stop_wifi_logging(dut):
+ """Function to start collecting wifi-related logs"""
+ pass
+
+
+@detect_wifi_decorator
+def push_firmware(dut, firmware_files):
+ """Function to push Wifi firmware files
+
+ Args:
+ dut: dut to push bdf file to
+ firmware_files: path to wlanmdsp.mbn file
+ datamsc_file: path to Data.msc file
+ """
+ pass
+
+
+@detect_wifi_decorator
+def disable_beamforming(dut):
+ """Function to disable beamforming."""
+ pass
+
+
+@detect_wifi_decorator
+def set_nss_capability(dut, nss):
+ """Function to set number of spatial streams supported."""
+ pass
+
+
+@detect_wifi_decorator
+def set_chain_mask(dut, chain_mask):
+ """Function to set DUT chain mask.
+
+ Args:
+ dut: android device
+ chain_mask: desired chain mask in [0, 1, '2x2']
+ """
+ pass
+
+
+# Link layer stats utilities
+class LinkLayerStats():
+ def __new__(self, dut, llstats_enabled=True):
+ if detect_wifi_platform(dut) == 'qcom':
+ return qcom_utils.LinkLayerStats(dut, llstats_enabled)
+ else:
+ return brcm_utils.LinkLayerStats(dut, llstats_enabled)
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/bokeh_figure.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/bokeh_figure.py
new file mode 100644
index 0000000..5a8433e
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/bokeh_figure.py
@@ -0,0 +1,361 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import bokeh, bokeh.plotting, bokeh.io
+import collections
+import itertools
+import json
+import math
+
+
+# Plotting Utilities
+class BokehFigure():
+ """Class enabling simplified Bokeh plotting."""
+
+ COLORS = [
+ 'black',
+ 'blue',
+ 'blueviolet',
+ 'brown',
+ 'burlywood',
+ 'cadetblue',
+ 'cornflowerblue',
+ 'crimson',
+ 'cyan',
+ 'darkblue',
+ 'darkgreen',
+ 'darkmagenta',
+ 'darkorange',
+ 'darkred',
+ 'deepskyblue',
+ 'goldenrod',
+ 'green',
+ 'grey',
+ 'indigo',
+ 'navy',
+ 'olive',
+ 'orange',
+ 'red',
+ 'salmon',
+ 'teal',
+ 'yellow',
+ ]
+ MARKERS = [
+ 'asterisk', 'circle', 'circle_cross', 'circle_x', 'cross', 'diamond',
+ 'diamond_cross', 'hex', 'inverted_triangle', 'square', 'square_x',
+ 'square_cross', 'triangle', 'x'
+ ]
+
+ TOOLS = ('box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save')
+
+ def __init__(self,
+ title=None,
+ x_label=None,
+ primary_y_label=None,
+ secondary_y_label=None,
+ height=700,
+ width=1100,
+ title_size='15pt',
+ axis_label_size='12pt',
+ legend_label_size='12pt',
+ axis_tick_label_size='12pt',
+ x_axis_type='auto',
+ sizing_mode='scale_both',
+ json_file=None):
+ if json_file:
+ self.load_from_json(json_file)
+ else:
+ self.figure_data = []
+ self.fig_property = {
+ 'title': title,
+ 'x_label': x_label,
+ 'primary_y_label': primary_y_label,
+ 'secondary_y_label': secondary_y_label,
+ 'num_lines': 0,
+ 'height': height,
+ 'width': width,
+ 'title_size': title_size,
+ 'axis_label_size': axis_label_size,
+ 'legend_label_size': legend_label_size,
+ 'axis_tick_label_size': axis_tick_label_size,
+ 'x_axis_type': x_axis_type,
+ 'sizing_mode': sizing_mode
+ }
+
+ def init_plot(self):
+ self.plot = bokeh.plotting.figure(
+ sizing_mode=self.fig_property['sizing_mode'],
+ plot_width=self.fig_property['width'],
+ plot_height=self.fig_property['height'],
+ title=self.fig_property['title'],
+ tools=self.TOOLS,
+ x_axis_type=self.fig_property['x_axis_type'],
+ output_backend='webgl')
+ tooltips = [
+ ('index', '$index'),
+ ('(x,y)', '($x, $y)'),
+ ]
+ hover_set = []
+ for line in self.figure_data:
+ hover_set.extend(line['hover_text'].keys())
+ hover_set = set(hover_set)
+ for item in hover_set:
+ tooltips.append((item, '@{}'.format(item)))
+ self.plot.hover.tooltips = tooltips
+ self.plot.add_tools(
+ bokeh.models.tools.WheelZoomTool(dimensions='width'))
+ self.plot.add_tools(
+ bokeh.models.tools.WheelZoomTool(dimensions='height'))
+
+ def _filter_line(self, x_data, y_data, hover_text=None):
+ """Function to remove NaN points from bokeh plots."""
+ x_data_filtered = []
+ y_data_filtered = []
+ hover_text_filtered = {}
+ for idx, xy in enumerate(
+ itertools.zip_longest(x_data, y_data, fillvalue=float('nan'))):
+ if not math.isnan(xy[1]):
+ x_data_filtered.append(xy[0])
+ y_data_filtered.append(xy[1])
+ if hover_text:
+ for key, value in hover_text.items():
+ hover_text_filtered.setdefault(key, [])
+ hover_text_filtered[key].append(
+ value[idx] if len(value) > idx else '')
+ return x_data_filtered, y_data_filtered, hover_text_filtered
+
+ def add_line(self,
+ x_data,
+ y_data,
+ legend,
+ hover_text=None,
+ color=None,
+ width=3,
+ style='solid',
+ marker=None,
+ marker_size=10,
+ shaded_region=None,
+ y_axis='default'):
+ """Function to add line to existing BokehFigure.
+
+ Args:
+ x_data: list containing x-axis values for line
+ y_data: list containing y_axis values for line
+ legend: string containing line title
+ hover_text: text to display when hovering over lines
+ color: string describing line color
+ width: integer line width
+ style: string describing line style, e.g, solid or dashed
+ marker: string specifying line marker, e.g., cross
+ shaded region: data describing shaded region to plot
+ y_axis: identifier for y-axis to plot line against
+ """
+ if y_axis not in ['default', 'secondary']:
+ raise ValueError('y_axis must be default or secondary')
+ if color == None:
+ color = self.COLORS[self.fig_property['num_lines'] %
+ len(self.COLORS)]
+ if style == 'dashed':
+ style = [5, 5]
+ if isinstance(hover_text, list):
+ hover_text = {'info': hover_text}
+ x_data_filter, y_data_filter, hover_text_filter = self._filter_line(
+ x_data, y_data, hover_text)
+ self.figure_data.append({
+ 'x_data': x_data_filter,
+ 'y_data': y_data_filter,
+ 'legend': legend,
+ 'hover_text': hover_text_filter,
+ 'color': color,
+ 'width': width,
+ 'style': style,
+ 'marker': marker,
+ 'marker_size': marker_size,
+ 'shaded_region': shaded_region,
+ 'y_axis': y_axis
+ })
+ self.fig_property['num_lines'] += 1
+
+ def add_scatter(self,
+ x_data,
+ y_data,
+ legend,
+ hover_text=None,
+ color=None,
+ marker=None,
+ marker_size=10,
+ y_axis='default'):
+ """Function to add line to existing BokehFigure.
+
+ Args:
+ x_data: list containing x-axis values for line
+ y_data: list containing y_axis values for line
+ legend: string containing line title
+ hover_text: text to display when hovering over lines
+ color: string describing line color
+ marker: string specifying marker, e.g., cross
+ y_axis: identifier for y-axis to plot line against
+ """
+ if y_axis not in ['default', 'secondary']:
+ raise ValueError('y_axis must be default or secondary')
+ if color == None:
+ color = self.COLORS[self.fig_property['num_lines'] %
+ len(self.COLORS)]
+ if marker == None:
+ marker = self.MARKERS[self.fig_property['num_lines'] %
+ len(self.MARKERS)]
+ self.figure_data.append({
+ 'x_data': x_data,
+ 'y_data': y_data,
+ 'legend': legend,
+ 'hover_text': hover_text,
+ 'color': color,
+ 'width': 0,
+ 'style': 'solid',
+ 'marker': marker,
+ 'marker_size': marker_size,
+ 'shaded_region': None,
+ 'y_axis': y_axis
+ })
+ self.fig_property['num_lines'] += 1
+
+ def generate_figure(self, output_file=None, save_json=True):
+ """Function to generate and save BokehFigure.
+
+ Args:
+ output_file: string specifying output file path
+ """
+ self.init_plot()
+ two_axes = False
+ for line in self.figure_data:
+ data_dict = {'x': line['x_data'], 'y': line['y_data']}
+ for key, value in line['hover_text'].items():
+ data_dict[key] = value
+ source = bokeh.models.ColumnDataSource(data=data_dict)
+ if line['width'] > 0:
+ self.plot.line(x='x',
+ y='y',
+ legend_label=line['legend'],
+ line_width=line['width'],
+ color=line['color'],
+ line_dash=line['style'],
+ name=line['y_axis'],
+ y_range_name=line['y_axis'],
+ source=source)
+ if line['shaded_region']:
+ band_x = line['shaded_region']['x_vector']
+ band_x.extend(line['shaded_region']['x_vector'][::-1])
+ band_y = line['shaded_region']['lower_limit']
+ band_y.extend(line['shaded_region']['upper_limit'][::-1])
+ self.plot.patch(band_x,
+ band_y,
+ color='#7570B3',
+ line_alpha=0.1,
+ fill_alpha=0.1)
+ if line['marker'] in self.MARKERS:
+ marker_func = getattr(self.plot, line['marker'])
+ marker_func(x='x',
+ y='y',
+ size=line['marker_size'],
+ legend_label=line['legend'],
+ line_color=line['color'],
+ fill_color=line['color'],
+ name=line['y_axis'],
+ y_range_name=line['y_axis'],
+ source=source)
+ if line['y_axis'] == 'secondary':
+ two_axes = True
+
+ #x-axis formatting
+ self.plot.xaxis.axis_label = self.fig_property['x_label']
+ self.plot.x_range.range_padding = 0
+ self.plot.xaxis[0].axis_label_text_font_size = self.fig_property[
+ 'axis_label_size']
+ self.plot.xaxis.major_label_text_font_size = self.fig_property[
+ 'axis_tick_label_size']
+ #y-axis formatting
+ self.plot.yaxis[0].axis_label = self.fig_property['primary_y_label']
+ self.plot.yaxis[0].axis_label_text_font_size = self.fig_property[
+ 'axis_label_size']
+ self.plot.yaxis.major_label_text_font_size = self.fig_property[
+ 'axis_tick_label_size']
+ self.plot.y_range = bokeh.models.DataRange1d(names=['default'])
+ if two_axes and 'secondary' not in self.plot.extra_y_ranges:
+ self.plot.extra_y_ranges = {
+ 'secondary': bokeh.models.DataRange1d(names=['secondary'])
+ }
+ self.plot.add_layout(
+ bokeh.models.LinearAxis(
+ y_range_name='secondary',
+ axis_label=self.fig_property['secondary_y_label'],
+ axis_label_text_font_size=self.
+ fig_property['axis_label_size']), 'right')
+ # plot formatting
+ self.plot.legend.location = 'top_right'
+ self.plot.legend.click_policy = 'hide'
+ self.plot.title.text_font_size = self.fig_property['title_size']
+ self.plot.legend.label_text_font_size = self.fig_property[
+ 'legend_label_size']
+
+ if output_file is not None:
+ self.save_figure(output_file, save_json)
+ return self.plot
+
+ def load_from_json(self, file_path):
+ with open(file_path, 'r') as json_file:
+ fig_dict = json.load(json_file)
+ self.fig_property = fig_dict['fig_property']
+ self.figure_data = fig_dict['figure_data']
+
+ def _save_figure_json(self, output_file):
+ """Function to save a json format of a figure"""
+ figure_dict = collections.OrderedDict(fig_property=self.fig_property,
+ figure_data=self.figure_data)
+ output_file = output_file.replace('.html', '_plot_data.json')
+ with open(output_file, 'w') as outfile:
+ json.dump(figure_dict, outfile, indent=4)
+
+ def save_figure(self, output_file, save_json=True):
+ """Function to save BokehFigure.
+
+ Args:
+ output_file: string specifying output file path
+ save_json: flag controlling json outputs
+ """
+ if save_json:
+ self._save_figure_json(output_file)
+ bokeh.io.output_file(output_file)
+ bokeh.io.save(self.plot)
+
+ @staticmethod
+ def save_figures(figure_array, output_file_path, save_json=True):
+ """Function to save list of BokehFigures in one file.
+
+ Args:
+ figure_array: list of BokehFigure object to be plotted
+ output_file: string specifying output file path
+ """
+ for idx, figure in enumerate(figure_array):
+ figure.generate_figure()
+ if save_json:
+ json_file_path = output_file_path.replace(
+ '.html', '{}-plot_data.json'.format(idx))
+ figure._save_figure_json(json_file_path)
+ plot_array = [figure.plot for figure in figure_array]
+ all_plots = bokeh.layouts.column(children=plot_array,
+ sizing_mode='scale_width')
+ bokeh.plotting.output_file(output_file_path)
+ bokeh.plotting.save(all_plots)
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/brcm_utils.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/brcm_utils.py
new file mode 100644
index 0000000..afa5f32
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/brcm_utils.py
@@ -0,0 +1,578 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import collections
+import hashlib
+import itertools
+import logging
+import math
+import numpy
+import re
+import statistics
+import time
+
+VERY_SHORT_SLEEP = 0.5
+SHORT_SLEEP = 1
+MED_SLEEP = 6
+DISCONNECTION_MESSAGE_BRCM = 'driver adapter not found'
+RSSI_ERROR_VAL = float('nan')
+RATE_TABLE = {
+ 'HT': {
+ 1: {
+ 20: [7.2, 14.4, 21.7, 28.9, 43.4, 57.8, 65.0, 72.2],
+ 40: [15.0, 30.0, 45.0, 60.0, 90.0, 120.0, 135.0, 150.0]
+ },
+ 2: {
+ 20: [
+ 0, 0, 0, 0, 0, 0, 0, 0, 14.4, 28.8, 43.4, 57.8, 86.8, 115.6,
+ 130, 144.4
+ ],
+ 40: [0, 0, 0, 0, 0, 0, 0, 0, 30, 60, 90, 120, 180, 240, 270, 300]
+ }
+ },
+ 'VHT': {
+ 1: {
+ 20: [
+ 7.2, 14.4, 21.7, 28.9, 43.4, 57.8, 65.0, 72.2, 86.7, 96.2,
+ 129.0, 143.4
+ ],
+ 40: [
+ 15.0, 30.0, 45.0, 60.0, 90.0, 120.0, 135.0, 150.0, 180.0,
+ 200.0, 258, 286.8
+ ],
+ 80: [
+ 32.5, 65.0, 97.5, 130.0, 195.0, 260.0, 292.5, 325.0, 390.0,
+ 433.3, 540.4, 600.4
+ ],
+ 160: [
+ 65.0, 130.0, 195.0, 260.0, 390.0, 520.0, 585.0, 650.0, 780.0,
+ 1080.8, 1200.8
+ ]
+ },
+ 2: {
+ 20: [
+ 14.4, 28.8, 43.4, 57.8, 86.8, 115.6, 130, 144.4, 173.4, 192.4,
+ 258, 286.8
+ ],
+ 40: [30, 60, 90, 120, 180, 240, 270, 300, 360, 400, 516, 573.6],
+ 80: [
+ 65, 130, 195, 260, 390, 520, 585, 650, 780, 866.6, 1080.8,
+ 1200.8
+ ],
+ 160:
+ [130, 260, 390, 520, 780, 1040, 1170, 1300, 1560, 2161.6, 2401.6]
+ },
+ },
+ 'HE': {
+ 1: {
+ 20: [
+ 8.6, 17.2, 25.8, 34.4, 51.6, 68.8, 77.4, 86.0, 103.2, 114.7,
+ 129.0, 143.4
+ ],
+ 40: [
+ 17.2, 34.4, 51.6, 68.8, 103.2, 137.6, 154.8, 172, 206.4, 229.4,
+ 258, 286.8
+ ],
+ 80: [
+ 36.0, 72.1, 108.1, 144.1, 216.2, 288.2, 324.3, 360.3, 432.4,
+ 480.4, 540.4, 600.4
+ ],
+ 160: [
+ 72, 144.2, 216.2, 288.2, 432.4, 576.4, 648.6, 720.6, 864.8,
+ 960.8, 1080.8, 1200.8
+ ]
+ },
+ 2: {
+ 20: [
+ 17.2, 34.4, 51.6, 68.8, 103.2, 137.6, 154.8, 172, 206.4, 229.4,
+ 258, 286.8
+ ],
+ 40: [
+ 34.4, 68.8, 103.2, 137.6, 206.4, 275.2, 309.6, 344, 412.8,
+ 458.8, 516, 573.6
+ ],
+ 80: [
+ 72, 144.2, 216.2, 288.2, 432.4, 576.4, 648.6, 720.6, 864.8,
+ 960.8, 1080.8, 1200.8
+ ],
+ 160: [
+ 144, 288.4, 432.4, 576.4, 864.8, 1152.8, 1297.2, 1441.2,
+ 1729.6, 1921.6, 2161.6, 2401.6
+ ]
+ },
+ },
+}
+
+
+# Rssi Utilities
+def empty_rssi_result():
+ return collections.OrderedDict([('data', []), ('mean', None),
+ ('stdev', None)])
+
+
+def get_connected_rssi(dut,
+ num_measurements=1,
+ polling_frequency=SHORT_SLEEP,
+ first_measurement_delay=0,
+ disconnect_warning=True,
+ ignore_samples=0,
+ interface='wlan0'):
+ # yapf: disable
+ connected_rssi = collections.OrderedDict(
+ [('time_stamp', []),
+ ('bssid', []), ('ssid', []), ('frequency', []),
+ ('signal_poll_rssi', empty_rssi_result()),
+ ('signal_poll_avg_rssi', empty_rssi_result()),
+ ('chain_0_rssi', empty_rssi_result()),
+ ('chain_1_rssi', empty_rssi_result())])
+
+ # yapf: enable
+ previous_bssid = 'disconnected'
+ t0 = time.time()
+ time.sleep(first_measurement_delay)
+ for idx in range(num_measurements):
+ measurement_start_time = time.time()
+ connected_rssi['time_stamp'].append(measurement_start_time - t0)
+ # Get signal poll RSSI
+ try:
+ status_output = dut.adb.shell(
+ 'wpa_cli -i {} status'.format(interface))
+ except:
+ status_output = ''
+ match = re.search('bssid=.*', status_output)
+ if match:
+ current_bssid = match.group(0).split('=')[1]
+ connected_rssi['bssid'].append(current_bssid)
+ else:
+ current_bssid = 'disconnected'
+ connected_rssi['bssid'].append(current_bssid)
+ if disconnect_warning and previous_bssid != 'disconnected':
+ logging.warning('WIFI DISCONNECT DETECTED!')
+
+ previous_bssid = current_bssid
+ match = re.search('\s+ssid=.*', status_output)
+ if match:
+ ssid = match.group(0).split('=')[1]
+ connected_rssi['ssid'].append(ssid)
+ else:
+ connected_rssi['ssid'].append('disconnected')
+
+ #TODO: SEARCH MAP ; PICK CENTER CHANNEL
+ match = re.search('\s+freq=.*', status_output)
+ if match:
+ frequency = int(match.group(0).split('=')[1])
+ connected_rssi['frequency'].append(frequency)
+ else:
+ connected_rssi['frequency'].append(RSSI_ERROR_VAL)
+
+ if interface == 'wlan0':
+ try:
+ per_chain_rssi = dut.adb.shell('wl phy_rssi_ant')
+ chain_0_rssi = re.search(
+ r'rssi\[0\]\s(?P<chain_0_rssi>[0-9\-]*)', per_chain_rssi)
+ if chain_0_rssi:
+ chain_0_rssi = int(chain_0_rssi.group('chain_0_rssi'))
+ else:
+ chain_0_rssi = -float('inf')
+ chain_1_rssi = re.search(
+ r'rssi\[1\]\s(?P<chain_1_rssi>[0-9\-]*)', per_chain_rssi)
+ if chain_1_rssi:
+ chain_1_rssi = int(chain_1_rssi.group('chain_1_rssi'))
+ else:
+ chain_1_rssi = -float('inf')
+ except:
+ chain_0_rssi = RSSI_ERROR_VAL
+ chain_1_rssi = RSSI_ERROR_VAL
+ connected_rssi['chain_0_rssi']['data'].append(chain_0_rssi)
+ connected_rssi['chain_1_rssi']['data'].append(chain_1_rssi)
+ combined_rssi = math.pow(10, chain_0_rssi / 10) + math.pow(
+ 10, chain_1_rssi / 10)
+ combined_rssi = 10 * math.log10(combined_rssi)
+ connected_rssi['signal_poll_rssi']['data'].append(combined_rssi)
+ connected_rssi['signal_poll_avg_rssi']['data'].append(
+ combined_rssi)
+ else:
+ try:
+ signal_poll_output = dut.adb.shell(
+ 'wpa_cli -i {} signal_poll'.format(interface))
+ except:
+ signal_poll_output = ''
+ match = re.search('RSSI=.*', signal_poll_output)
+ if match:
+ temp_rssi = int(match.group(0).split('=')[1])
+ if temp_rssi == -9999 or temp_rssi == 0:
+ connected_rssi['signal_poll_rssi']['data'].append(
+ RSSI_ERROR_VAL)
+ else:
+ connected_rssi['signal_poll_rssi']['data'].append(
+ temp_rssi)
+ else:
+ connected_rssi['signal_poll_rssi']['data'].append(
+ RSSI_ERROR_VAL)
+ connected_rssi['chain_0_rssi']['data'].append(RSSI_ERROR_VAL)
+ connected_rssi['chain_1_rssi']['data'].append(RSSI_ERROR_VAL)
+ measurement_elapsed_time = time.time() - measurement_start_time
+ time.sleep(max(0, polling_frequency - measurement_elapsed_time))
+
+ # Statistics, Statistics
+ for key, val in connected_rssi.copy().items():
+ if 'data' not in val:
+ continue
+ filtered_rssi_values = [x for x in val['data'] if not math.isnan(x)]
+ if len(filtered_rssi_values) > ignore_samples:
+ filtered_rssi_values = filtered_rssi_values[ignore_samples:]
+ if filtered_rssi_values:
+ connected_rssi[key]['mean'] = statistics.mean(filtered_rssi_values)
+ if len(filtered_rssi_values) > 1:
+ connected_rssi[key]['stdev'] = statistics.stdev(
+ filtered_rssi_values)
+ else:
+ connected_rssi[key]['stdev'] = 0
+ else:
+ connected_rssi[key]['mean'] = RSSI_ERROR_VAL
+ connected_rssi[key]['stdev'] = RSSI_ERROR_VAL
+
+ return connected_rssi
+
+
+def get_scan_rssi(dut, tracked_bssids, num_measurements=1):
+ scan_rssi = collections.OrderedDict()
+ for bssid in tracked_bssids:
+ scan_rssi[bssid] = empty_rssi_result()
+ for idx in range(num_measurements):
+ scan_output = dut.adb.shell('cmd wifi start-scan')
+ time.sleep(MED_SLEEP)
+ scan_output = dut.adb.shell('cmd wifi list-scan-results')
+ for bssid in tracked_bssids:
+ bssid_result = re.search(bssid + '.*',
+ scan_output,
+ flags=re.IGNORECASE)
+ if bssid_result:
+ bssid_result = bssid_result.group(0).split()
+ scan_rssi[bssid]['data'].append(int(bssid_result[2]))
+ else:
+ scan_rssi[bssid]['data'].append(RSSI_ERROR_VAL)
+ # Compute mean RSSIs. Only average valid readings.
+ # Output RSSI_ERROR_VAL if no readings found.
+ for key, val in scan_rssi.items():
+ filtered_rssi_values = [x for x in val['data'] if not math.isnan(x)]
+ if filtered_rssi_values:
+ scan_rssi[key]['mean'] = statistics.mean(filtered_rssi_values)
+ if len(filtered_rssi_values) > 1:
+ scan_rssi[key]['stdev'] = statistics.stdev(
+ filtered_rssi_values)
+ else:
+ scan_rssi[key]['stdev'] = 0
+ else:
+ scan_rssi[key]['mean'] = RSSI_ERROR_VAL
+ scan_rssi[key]['stdev'] = RSSI_ERROR_VAL
+ return scan_rssi
+
+
+def get_sw_signature(dut):
+ bdf_output = dut.adb.shell('cksum /vendor/firmware/bcmdhd*')
+ logging.debug('BDF Checksum output: {}'.format(bdf_output))
+ bdf_signature = sum(
+ [int(line.split(' ')[0]) for line in bdf_output.splitlines()]) % 1000
+
+ fw_version = dut.adb.shell('getprop vendor.wlan.firmware.version')
+ driver_version = dut.adb.shell('getprop vendor.wlan.driver.version')
+ logging.debug('Firmware version : {}. Driver version: {}'.format(
+ fw_version, driver_version))
+ fw_signature = '{}+{}'.format(fw_version, driver_version)
+ fw_signature = int(hashlib.md5(fw_signature.encode()).hexdigest(),
+ 16) % 1000
+ serial_hash = int(hashlib.md5(dut.serial.encode()).hexdigest(), 16) % 1000
+ return {
+ 'config_signature': bdf_signature,
+ 'fw_signature': fw_signature,
+ 'serial_hash': serial_hash
+ }
+
+
+def get_country_code(dut):
+ try:
+ country_code = dut.adb.shell('wl country').split(' ')[0]
+ except:
+ country_code = 'XZ'
+ if country_code == 'XZ':
+ country_code = 'WW'
+ logging.debug('Country code: {}'.format(country_code))
+ return country_code
+
+
+def push_config(dut, config_file):
+ config_files_list = dut.adb.shell('ls /vendor/etc/*.cal').splitlines()
+ for dst_file in config_files_list:
+ dut.push_system_file(config_file, dst_file)
+ dut.reboot()
+
+
+def start_wifi_logging(dut):
+ pass
+
+
+def stop_wifi_logging(dut):
+ pass
+
+
+def push_firmware(dut, firmware_files):
+ """Function to push Wifi firmware files
+
+ Args:
+ dut: dut to push bdf file to
+ firmware_files: path to wlanmdsp.mbn file
+ datamsc_file: path to Data.msc file
+ """
+ for file in firmware_files:
+ dut.push_system_file(file, '/vendor/firmware/')
+ dut.reboot()
+
+
+def disable_beamforming(dut):
+ dut.adb.shell('wl txbf 0')
+
+
+def set_nss_capability(dut, nss):
+ dut.adb.shell('wl he omi -r {} -t {}'.format(nss, nss))
+
+
+def set_chain_mask(dut, chain):
+ if chain == '2x2':
+ chain = 3
+ else:
+ chain = chain + 1
+ # Get current chain mask
+ try:
+ curr_tx_chain = int(dut.adb.shell('wl txchain'))
+ curr_rx_chain = int(dut.adb.shell('wl rxchain'))
+ except:
+ curr_tx_chain = -1
+ curr_rx_chain = -1
+ if curr_tx_chain == chain and curr_rx_chain == chain:
+ return
+ # Set chain mask if needed
+ dut.adb.shell('wl down')
+ time.sleep(VERY_SHORT_SLEEP)
+ dut.adb.shell('wl txchain 0x{}'.format(chain))
+ dut.adb.shell('wl rxchain 0x{}'.format(chain))
+ dut.adb.shell('wl up')
+
+
+class LinkLayerStats():
+
+ LLSTATS_CMD = 'wl dump ampdu; wl counters;'
+ LL_STATS_CLEAR_CMD = 'wl dump_clear ampdu; wl reset_cnts;'
+ BW_REGEX = re.compile(r'Chanspec:.+ (?P<bandwidth>[0-9]+)MHz')
+ MCS_REGEX = re.compile(r'(?P<count>[0-9]+)\((?P<percent>[0-9]+)%\)')
+ RX_REGEX = re.compile(r'RX (?P<mode>\S+)\s+:\s*(?P<nss1>[0-9, ,(,),%]*)'
+ '\n\s*:?\s*(?P<nss2>[0-9, ,(,),%]*)')
+ TX_REGEX = re.compile(r'TX (?P<mode>\S+)\s+:\s*(?P<nss1>[0-9, ,(,),%]*)'
+ '\n\s*:?\s*(?P<nss2>[0-9, ,(,),%]*)')
+ TX_PER_REGEX = re.compile(
+ r'(?P<mode>\S+) PER\s+:\s*(?P<nss1>[0-9, ,(,),%]*)'
+ '\n\s*:?\s*(?P<nss2>[0-9, ,(,),%]*)')
+ RX_FCS_REGEX = re.compile(
+ r'rxbadfcs (?P<rx_bad_fcs>[0-9]*).+\n.+goodfcs (?P<rx_good_fcs>[0-9]*)'
+ )
+ RX_AGG_REGEX = re.compile(r'rxmpduperampdu (?P<aggregation>[0-9]*)')
+ TX_AGG_REGEX = re.compile(r' mpduperampdu (?P<aggregation>[0-9]*)')
+ TX_AGG_STOP_REGEX = re.compile(
+ r'agg stop reason: tot_agg_tried (?P<agg_tried>[0-9]+) agg_txcancel (?P<agg_canceled>[0-9]+) (?P<agg_stop_reason>.+)'
+ )
+ TX_AGG_STOP_REASON_REGEX = re.compile(
+ r'(?P<reason>\w+) [0-9]+ \((?P<value>[0-9]+%)\)')
+ MCS_ID = collections.namedtuple(
+ 'mcs_id', ['mode', 'num_streams', 'bandwidth', 'mcs', 'gi'])
+ MODE_MAP = {'0': '11a/g', '1': '11b', '2': '11n', '3': '11ac'}
+ BW_MAP = {'0': 20, '1': 40, '2': 80}
+
+ def __init__(self, dut, llstats_enabled=True):
+ self.dut = dut
+ self.llstats_enabled = llstats_enabled
+ self.llstats_cumulative = self._empty_llstats()
+ self.llstats_incremental = self._empty_llstats()
+
+ def update_stats(self):
+ if self.llstats_enabled:
+ try:
+ llstats_output = self.dut.adb.shell(self.LLSTATS_CMD,
+ timeout=1)
+ self.dut.adb.shell_nb(self.LL_STATS_CLEAR_CMD)
+
+ wl_join = self.dut.adb.shell("wl status")
+ self.bandwidth = int(
+ re.search(self.BW_REGEX, wl_join).group('bandwidth'))
+ except:
+ llstats_output = ''
+ else:
+ llstats_output = ''
+ self._update_stats(llstats_output)
+
+ def reset_stats(self):
+ self.llstats_cumulative = self._empty_llstats()
+ self.llstats_incremental = self._empty_llstats()
+
+ def _empty_llstats(self):
+ return collections.OrderedDict(mcs_stats=collections.OrderedDict(),
+ mpdu_stats=collections.OrderedDict(),
+ summary=collections.OrderedDict())
+
+ def _empty_mcs_stat(self):
+ return collections.OrderedDict(txmpdu=0,
+ rxmpdu=0,
+ mpdu_lost=0,
+ retries=0,
+ retries_short=0,
+ retries_long=0)
+
+ def _mcs_id_to_string(self, mcs_id):
+ mcs_string = '{} Nss{} MCS{} GI{}'.format(mcs_id.mode,
+ mcs_id.num_streams,
+ mcs_id.mcs, mcs_id.gi)
+ return mcs_string
+
+ def _parse_mcs_stats(self, llstats_output):
+ llstats_dict = {}
+ # Look for per-peer stats
+ match = re.search(self.RX_REGEX, llstats_output)
+ if not match:
+ self.reset_stats()
+ return collections.OrderedDict()
+ # Find and process all matches for per stream stats
+ rx_match_iter = re.finditer(self.RX_REGEX, llstats_output)
+ tx_match_iter = re.finditer(self.TX_REGEX, llstats_output)
+ tx_per_match_iter = re.finditer(self.TX_PER_REGEX, llstats_output)
+ for rx_match, tx_match, tx_per_match in zip(rx_match_iter,
+ tx_match_iter,
+ tx_per_match_iter):
+ mode = rx_match.group('mode')
+ mode = 'HT' if mode == 'MCS' else mode
+ for nss in [1, 2]:
+ rx_mcs_iter = re.finditer(self.MCS_REGEX,
+ rx_match.group(nss + 1))
+ tx_mcs_iter = re.finditer(self.MCS_REGEX,
+ tx_match.group(nss + 1))
+ tx_per_iter = re.finditer(self.MCS_REGEX,
+ tx_per_match.group(nss + 1))
+ for mcs, (rx_mcs_stats, tx_mcs_stats,
+ tx_per_mcs_stats) in enumerate(
+ itertools.zip_longest(rx_mcs_iter, tx_mcs_iter,
+ tx_per_iter)):
+ current_mcs = self.MCS_ID(
+ mode, nss, self.bandwidth,
+ mcs + int(8 * (mode == 'HT') * (nss - 1)), 0)
+ current_stats = collections.OrderedDict(
+ txmpdu=int(tx_mcs_stats.group('count'))
+ if tx_mcs_stats else 0,
+ rxmpdu=int(rx_mcs_stats.group('count'))
+ if rx_mcs_stats else 0,
+ mpdu_lost=0,
+ retries=tx_per_mcs_stats.group('count')
+ if tx_per_mcs_stats else 0,
+ retries_short=0,
+ retries_long=0,
+ mcs_id=current_mcs)
+ llstats_dict[self._mcs_id_to_string(
+ current_mcs)] = current_stats
+ return llstats_dict
+
+ def _parse_mpdu_stats(self, llstats_output):
+ rx_agg_match = re.search(self.RX_AGG_REGEX, llstats_output)
+ tx_agg_match = re.search(self.TX_AGG_REGEX, llstats_output)
+ tx_agg_stop_match = re.search(self.TX_AGG_STOP_REGEX, llstats_output)
+ rx_fcs_match = re.search(self.RX_FCS_REGEX, llstats_output)
+
+ if rx_agg_match and tx_agg_match and tx_agg_stop_match and rx_fcs_match:
+ agg_stop_dict = collections.OrderedDict(
+ rx_aggregation=int(rx_agg_match.group('aggregation')),
+ tx_aggregation=int(tx_agg_match.group('aggregation')),
+ tx_agg_tried=int(tx_agg_stop_match.group('agg_tried')),
+ tx_agg_canceled=int(tx_agg_stop_match.group('agg_canceled')),
+ rx_good_fcs=int(rx_fcs_match.group('rx_good_fcs')),
+ rx_bad_fcs=int(rx_fcs_match.group('rx_bad_fcs')),
+ agg_stop_reason=collections.OrderedDict())
+ agg_reason_match = re.finditer(
+ self.TX_AGG_STOP_REASON_REGEX,
+ tx_agg_stop_match.group('agg_stop_reason'))
+ for reason_match in agg_reason_match:
+ agg_stop_dict['agg_stop_reason'][reason_match.group(
+ 'reason')] = reason_match.group('value')
+
+ else:
+ agg_stop_dict = collections.OrderedDict(rx_aggregation=0,
+ tx_aggregation=0,
+ tx_agg_tried=0,
+ tx_agg_canceled=0,
+ rx_good_fcs=0,
+ rx_bad_fcs=0,
+ agg_stop_reason=None)
+ return agg_stop_dict
+
+ def _generate_stats_summary(self, llstats_dict):
+ llstats_summary = collections.OrderedDict(common_tx_mcs=None,
+ common_tx_mcs_count=0,
+ common_tx_mcs_freq=0,
+ common_rx_mcs=None,
+ common_rx_mcs_count=0,
+ common_rx_mcs_freq=0,
+ rx_per=float('nan'))
+ mcs_ids = []
+ tx_mpdu = []
+ rx_mpdu = []
+ phy_rates = []
+ for mcs_str, mcs_stats in llstats_dict['mcs_stats'].items():
+ mcs_id = mcs_stats['mcs_id']
+ mcs_ids.append(mcs_str)
+ tx_mpdu.append(mcs_stats['txmpdu'])
+ rx_mpdu.append(mcs_stats['rxmpdu'])
+ phy_rates.append(RATE_TABLE[mcs_id.mode][mcs_id.num_streams][
+ mcs_id.bandwidth][mcs_id.mcs])
+ if len(tx_mpdu) == 0 or len(rx_mpdu) == 0:
+ return llstats_summary
+ llstats_summary['common_tx_mcs'] = mcs_ids[numpy.argmax(tx_mpdu)]
+ llstats_summary['common_tx_mcs_count'] = numpy.max(tx_mpdu)
+ llstats_summary['common_rx_mcs'] = mcs_ids[numpy.argmax(rx_mpdu)]
+ llstats_summary['common_rx_mcs_count'] = numpy.max(rx_mpdu)
+ if sum(tx_mpdu) and sum(rx_mpdu):
+ llstats_summary['mean_tx_phy_rate'] = numpy.average(
+ phy_rates, weights=tx_mpdu)
+ llstats_summary['mean_rx_phy_rate'] = numpy.average(
+ phy_rates, weights=rx_mpdu)
+ llstats_summary['common_tx_mcs_freq'] = (
+ llstats_summary['common_tx_mcs_count'] / sum(tx_mpdu))
+ llstats_summary['common_rx_mcs_freq'] = (
+ llstats_summary['common_rx_mcs_count'] / sum(rx_mpdu))
+ total_rx_frames = llstats_dict['mpdu_stats'][
+ 'rx_good_fcs'] + llstats_dict['mpdu_stats']['rx_bad_fcs']
+ if total_rx_frames:
+ llstats_summary['rx_per'] = (
+ llstats_dict['mpdu_stats']['rx_bad_fcs'] /
+ (total_rx_frames)) * 100
+ return llstats_summary
+
+ def _update_stats(self, llstats_output):
+ self.llstats_cumulative = self._empty_llstats()
+ self.llstats_incremental = self._empty_llstats()
+ self.llstats_incremental['raw_output'] = llstats_output
+ self.llstats_incremental['mcs_stats'] = self._parse_mcs_stats(
+ llstats_output)
+ self.llstats_incremental['mpdu_stats'] = self._parse_mpdu_stats(
+ llstats_output)
+ self.llstats_incremental['summary'] = self._generate_stats_summary(
+ self.llstats_incremental)
+ self.llstats_cumulative['summary'] = self._generate_stats_summary(
+ self.llstats_cumulative)
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/ping_utils.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/ping_utils.py
new file mode 100644
index 0000000..7d2e09f
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/ping_utils.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+
+RTT_REGEX = re.compile(r'^\[(?P<timestamp>\S+)\] .*? time=(?P<rtt>\S+)')
+LOSS_REGEX = re.compile(r'(?P<loss>\S+)% packet loss')
+
+
+class PingResult(object):
+ """An object that contains the results of running ping command.
+
+ Attributes:
+ connected: True if a connection was made. False otherwise.
+ packet_loss_percentage: The total percentage of packets lost.
+ transmission_times: The list of PingTransmissionTimes containing the
+ timestamps gathered for transmitted packets.
+ rtts: An list-like object enumerating all round-trip-times of
+ transmitted packets.
+ timestamps: A list-like object enumerating the beginning timestamps of
+ each packet transmission.
+ ping_interarrivals: A list-like object enumerating the amount of time
+ between the beginning of each subsequent transmission.
+ """
+ def __init__(self, ping_output):
+ self.packet_loss_percentage = 100
+ self.transmission_times = []
+
+ self.rtts = _ListWrap(self.transmission_times, lambda entry: entry.rtt)
+ self.timestamps = _ListWrap(self.transmission_times,
+ lambda entry: entry.timestamp)
+ self.ping_interarrivals = _PingInterarrivals(self.transmission_times)
+
+ self.start_time = 0
+ for line in ping_output:
+ if 'loss' in line:
+ match = re.search(LOSS_REGEX, line)
+ self.packet_loss_percentage = float(match.group('loss'))
+ if 'time=' in line:
+ match = re.search(RTT_REGEX, line)
+ if self.start_time == 0:
+ self.start_time = float(match.group('timestamp'))
+ self.transmission_times.append(
+ PingTransmissionTimes(
+ float(match.group('timestamp')) - self.start_time,
+ float(match.group('rtt'))))
+ self.connected = len(
+ ping_output) > 1 and self.packet_loss_percentage < 100
+
+ def __getitem__(self, item):
+ if item == 'rtt':
+ return self.rtts
+ if item == 'connected':
+ return self.connected
+ if item == 'packet_loss_percentage':
+ return self.packet_loss_percentage
+ raise ValueError('Invalid key. Please use an attribute instead.')
+
+ def as_dict(self):
+ return {
+ 'connected': 1 if self.connected else 0,
+ 'rtt': list(self.rtts),
+ 'time_stamp': list(self.timestamps),
+ 'ping_interarrivals': list(self.ping_interarrivals),
+ 'packet_loss_percentage': self.packet_loss_percentage
+ }
+
+
+class PingTransmissionTimes(object):
+ """A class that holds the timestamps for a packet sent via the ping command.
+
+ Attributes:
+ rtt: The round trip time for the packet sent.
+ timestamp: The timestamp the packet started its trip.
+ """
+ def __init__(self, timestamp, rtt):
+ self.rtt = rtt
+ self.timestamp = timestamp
+
+
+class _ListWrap(object):
+ """A convenient helper class for treating list iterators as native lists."""
+ def __init__(self, wrapped_list, func):
+ self.__wrapped_list = wrapped_list
+ self.__func = func
+
+ def __getitem__(self, key):
+ return self.__func(self.__wrapped_list[key])
+
+ def __iter__(self):
+ for item in self.__wrapped_list:
+ yield self.__func(item)
+
+ def __len__(self):
+ return len(self.__wrapped_list)
+
+
+class _PingInterarrivals(object):
+ """A helper class for treating ping interarrivals as a native list."""
+ def __init__(self, ping_entries):
+ self.__ping_entries = ping_entries
+
+ def __getitem__(self, key):
+ return (self.__ping_entries[key + 1].timestamp -
+ self.__ping_entries[key].timestamp)
+
+ def __iter__(self):
+ for index in range(len(self.__ping_entries) - 1):
+ yield self[index]
+
+ def __len__(self):
+ return max(0, len(self.__ping_entries) - 1)
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/qcom_utils.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/qcom_utils.py
new file mode 100644
index 0000000..53321bc
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_performance_test_utils/qcom_utils.py
@@ -0,0 +1,467 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import collections
+import hashlib
+import logging
+import math
+import os
+import re
+import statistics
+import time
+from acts import asserts
+
+SHORT_SLEEP = 1
+MED_SLEEP = 6
+STATION_DUMP = 'iw {} station dump'
+SCAN = 'wpa_cli scan'
+SCAN_RESULTS = 'wpa_cli scan_results'
+SIGNAL_POLL = 'wpa_cli signal_poll'
+WPA_CLI_STATUS = 'wpa_cli status'
+RSSI_ERROR_VAL = float('nan')
+FW_REGEX = re.compile(r'FW:(?P<firmware>\S+) HW:')
+
+
+# Rssi Utilities
+def empty_rssi_result():
+ return collections.OrderedDict([('data', []), ('mean', None),
+ ('stdev', None)])
+
+
+def get_connected_rssi(dut,
+ num_measurements=1,
+ polling_frequency=SHORT_SLEEP,
+ first_measurement_delay=0,
+ disconnect_warning=True,
+ ignore_samples=0,
+ interface='wlan0'):
+ # yapf: disable
+ connected_rssi = collections.OrderedDict(
+ [('time_stamp', []),
+ ('bssid', []), ('ssid', []), ('frequency', []),
+ ('signal_poll_rssi', empty_rssi_result()),
+ ('signal_poll_avg_rssi', empty_rssi_result()),
+ ('chain_0_rssi', empty_rssi_result()),
+ ('chain_1_rssi', empty_rssi_result())])
+ # yapf: enable
+ previous_bssid = 'disconnected'
+ t0 = time.time()
+ time.sleep(first_measurement_delay)
+ for idx in range(num_measurements):
+ measurement_start_time = time.time()
+ connected_rssi['time_stamp'].append(measurement_start_time - t0)
+ # Get signal poll RSSI
+ try:
+ status_output = dut.adb.shell(
+ 'wpa_cli -i {} status'.format(interface))
+ except:
+ status_output = ''
+ match = re.search('bssid=.*', status_output)
+ if match:
+ current_bssid = match.group(0).split('=')[1]
+ connected_rssi['bssid'].append(current_bssid)
+ else:
+ current_bssid = 'disconnected'
+ connected_rssi['bssid'].append(current_bssid)
+ if disconnect_warning and previous_bssid != 'disconnected':
+ logging.warning('WIFI DISCONNECT DETECTED!')
+ previous_bssid = current_bssid
+ match = re.search('\s+ssid=.*', status_output)
+ if match:
+ ssid = match.group(0).split('=')[1]
+ connected_rssi['ssid'].append(ssid)
+ else:
+ connected_rssi['ssid'].append('disconnected')
+ try:
+ signal_poll_output = dut.adb.shell(
+ 'wpa_cli -i {} signal_poll'.format(interface))
+ except:
+ signal_poll_output = ''
+ match = re.search('FREQUENCY=.*', signal_poll_output)
+ if match:
+ frequency = int(match.group(0).split('=')[1])
+ connected_rssi['frequency'].append(frequency)
+ else:
+ connected_rssi['frequency'].append(RSSI_ERROR_VAL)
+ match = re.search('RSSI=.*', signal_poll_output)
+ if match:
+ temp_rssi = int(match.group(0).split('=')[1])
+ if temp_rssi == -9999 or temp_rssi == 0:
+ connected_rssi['signal_poll_rssi']['data'].append(
+ RSSI_ERROR_VAL)
+ else:
+ connected_rssi['signal_poll_rssi']['data'].append(temp_rssi)
+ else:
+ connected_rssi['signal_poll_rssi']['data'].append(RSSI_ERROR_VAL)
+ match = re.search('AVG_RSSI=.*', signal_poll_output)
+ if match:
+ connected_rssi['signal_poll_avg_rssi']['data'].append(
+ int(match.group(0).split('=')[1]))
+ else:
+ connected_rssi['signal_poll_avg_rssi']['data'].append(
+ RSSI_ERROR_VAL)
+
+ # Get per chain RSSI
+ try:
+ per_chain_rssi = dut.adb.shell(STATION_DUMP.format(interface))
+ except:
+ per_chain_rssi = ''
+ match = re.search('.*signal avg:.*', per_chain_rssi)
+ if match:
+ per_chain_rssi = per_chain_rssi[per_chain_rssi.find('[') +
+ 1:per_chain_rssi.find(']')]
+ per_chain_rssi = per_chain_rssi.split(', ')
+ connected_rssi['chain_0_rssi']['data'].append(
+ int(per_chain_rssi[0]))
+ connected_rssi['chain_1_rssi']['data'].append(
+ int(per_chain_rssi[1]))
+ else:
+ connected_rssi['chain_0_rssi']['data'].append(RSSI_ERROR_VAL)
+ connected_rssi['chain_1_rssi']['data'].append(RSSI_ERROR_VAL)
+ measurement_elapsed_time = time.time() - measurement_start_time
+ time.sleep(max(0, polling_frequency - measurement_elapsed_time))
+
+ # Compute mean RSSIs. Only average valid readings.
+ # Output RSSI_ERROR_VAL if no valid connected readings found.
+ for key, val in connected_rssi.copy().items():
+ if 'data' not in val:
+ continue
+ filtered_rssi_values = [x for x in val['data'] if not math.isnan(x)]
+ if len(filtered_rssi_values) > ignore_samples:
+ filtered_rssi_values = filtered_rssi_values[ignore_samples:]
+ if filtered_rssi_values:
+ connected_rssi[key]['mean'] = statistics.mean(filtered_rssi_values)
+ if len(filtered_rssi_values) > 1:
+ connected_rssi[key]['stdev'] = statistics.stdev(
+ filtered_rssi_values)
+ else:
+ connected_rssi[key]['stdev'] = 0
+ else:
+ connected_rssi[key]['mean'] = RSSI_ERROR_VAL
+ connected_rssi[key]['stdev'] = RSSI_ERROR_VAL
+ return connected_rssi
+
+
+def get_scan_rssi(dut, tracked_bssids, num_measurements=1):
+ scan_rssi = collections.OrderedDict()
+ for bssid in tracked_bssids:
+ scan_rssi[bssid] = empty_rssi_result()
+ for idx in range(num_measurements):
+ scan_output = dut.adb.shell(SCAN)
+ time.sleep(MED_SLEEP)
+ scan_output = dut.adb.shell(SCAN_RESULTS)
+ for bssid in tracked_bssids:
+ bssid_result = re.search(bssid + '.*',
+ scan_output,
+ flags=re.IGNORECASE)
+ if bssid_result:
+ bssid_result = bssid_result.group(0).split('\t')
+ scan_rssi[bssid]['data'].append(int(bssid_result[2]))
+ else:
+ scan_rssi[bssid]['data'].append(RSSI_ERROR_VAL)
+ # Compute mean RSSIs. Only average valid readings.
+ # Output RSSI_ERROR_VAL if no readings found.
+ for key, val in scan_rssi.items():
+ filtered_rssi_values = [x for x in val['data'] if not math.isnan(x)]
+ if filtered_rssi_values:
+ scan_rssi[key]['mean'] = statistics.mean(filtered_rssi_values)
+ if len(filtered_rssi_values) > 1:
+ scan_rssi[key]['stdev'] = statistics.stdev(
+ filtered_rssi_values)
+ else:
+ scan_rssi[key]['stdev'] = 0
+ else:
+ scan_rssi[key]['mean'] = RSSI_ERROR_VAL
+ scan_rssi[key]['stdev'] = RSSI_ERROR_VAL
+ return scan_rssi
+
+
+def get_sw_signature(dut):
+ bdf_output = dut.adb.shell('cksum /vendor/firmware/bdwlan*')
+ logging.debug('BDF Checksum output: {}'.format(bdf_output))
+ bdf_signature = sum(
+ [int(line.split(' ')[0]) for line in bdf_output.splitlines()]) % 1000
+
+ fw_output = dut.adb.shell('halutil -logger -get fw')
+ logging.debug('Firmware version output: {}'.format(fw_output))
+ fw_version = re.search(FW_REGEX, fw_output).group('firmware')
+ fw_signature = fw_version.split('.')[-3:-1]
+ fw_signature = float('.'.join(fw_signature))
+ serial_hash = int(hashlib.md5(dut.serial.encode()).hexdigest(), 16) % 1000
+ return {
+ 'config_signature': bdf_signature,
+ 'fw_signature': fw_signature,
+ 'serial_hash': serial_hash
+ }
+
+
+def get_country_code(dut):
+ country_code = dut.adb.shell('iw reg get | grep country | head -1')
+ country_code = country_code.split(':')[0].split(' ')[1]
+ if country_code == '00':
+ country_code = 'WW'
+ return country_code
+
+
+def push_config(dut, config_file):
+ config_files_list = dut.adb.shell(
+ 'ls /vendor/firmware/bdwlan*').splitlines()
+ for dst_file in config_files_list:
+ dut.push_system_file(config_file, dst_file)
+ dut.reboot()
+
+
+def start_wifi_logging(dut):
+ dut.droid.wifiEnableVerboseLogging(1)
+ msg = "Failed to enable WiFi verbose logging."
+ asserts.assert_equal(dut.droid.wifiGetVerboseLoggingLevel(), 1, msg)
+ logging.info('Starting CNSS logs')
+ dut.adb.shell("find /data/vendor/wifi/wlan_logs/ -type f -delete",
+ ignore_status=True)
+ dut.adb.shell_nb('cnss_diag -f -s')
+
+
+def stop_wifi_logging(dut):
+ logging.info('Stopping CNSS logs')
+ dut.adb.shell('killall cnss_diag')
+ logs = dut.get_file_names("/data/vendor/wifi/wlan_logs/")
+ if logs:
+ dut.log.info("Pulling cnss_diag logs %s", logs)
+ log_path = os.path.join(dut.device_log_path,
+ "CNSS_DIAG_%s" % dut.serial)
+ os.makedirs(log_path, exist_ok=True)
+ dut.pull_files(logs, log_path)
+
+
+def push_firmware(dut, firmware_files):
+ """Function to push Wifi firmware files
+
+ Args:
+ dut: dut to push bdf file to
+ firmware_files: path to wlanmdsp.mbn file
+ datamsc_file: path to Data.msc file
+ """
+ for file in firmware_files:
+ dut.push_system_file(file, '/vendor/firmware/')
+ dut.reboot()
+
+
+def _set_ini_fields(ini_file_path, ini_field_dict):
+ template_regex = r'^{}=[0-9,.x-]+'
+ with open(ini_file_path, 'r') as f:
+ ini_lines = f.read().splitlines()
+ for idx, line in enumerate(ini_lines):
+ for field_name, field_value in ini_field_dict.items():
+ line_regex = re.compile(template_regex.format(field_name))
+ if re.match(line_regex, line):
+ ini_lines[idx] = '{}={}'.format(field_name, field_value)
+ print(ini_lines[idx])
+ with open(ini_file_path, 'w') as f:
+ f.write('\n'.join(ini_lines) + '\n')
+
+
+def _edit_dut_ini(dut, ini_fields):
+ """Function to edit Wifi ini files."""
+ dut_ini_path = '/vendor/firmware/wlan/qca_cld/WCNSS_qcom_cfg.ini'
+ local_ini_path = os.path.expanduser('~/WCNSS_qcom_cfg.ini')
+ dut.pull_files(dut_ini_path, local_ini_path)
+
+ _set_ini_fields(local_ini_path, ini_fields)
+
+ dut.push_system_file(local_ini_path, dut_ini_path)
+ dut.reboot()
+
+
+def set_chain_mask(dut, chain_mask):
+ curr_mask = getattr(dut, 'chain_mask', '2x2')
+ if curr_mask == chain_mask:
+ return
+ dut.chain_mask = chain_mask
+ if chain_mask == '2x2':
+ ini_fields = {
+ 'gEnable2x2': 2,
+ 'gSetTxChainmask1x1': 1,
+ 'gSetRxChainmask1x1': 1,
+ 'gDualMacFeatureDisable': 6,
+ 'gDot11Mode': 0
+ }
+ else:
+ ini_fields = {
+ 'gEnable2x2': 0,
+ 'gSetTxChainmask1x1': chain_mask + 1,
+ 'gSetRxChainmask1x1': chain_mask + 1,
+ 'gDualMacFeatureDisable': 1,
+ 'gDot11Mode': 0
+ }
+ _edit_dut_ini(dut, ini_fields)
+
+
+def set_wifi_mode(dut, mode):
+ TX_MODE_DICT = {
+ 'Auto': 0,
+ '11n': 4,
+ '11ac': 9,
+ '11abg': 1,
+ '11b': 2,
+ '11': 3,
+ '11g only': 5,
+ '11n only': 6,
+ '11b only': 7,
+ '11ac only': 8
+ }
+
+ ini_fields = {
+ 'gEnable2x2': 2,
+ 'gSetTxChainmask1x1': 1,
+ 'gSetRxChainmask1x1': 1,
+ 'gDualMacFeatureDisable': 6,
+ 'gDot11Mode': TX_MODE_DICT[mode]
+ }
+ _edit_dut_ini(dut, ini_fields)
+
+
+class LinkLayerStats():
+
+ LLSTATS_CMD = 'cat /d/wlan0/ll_stats'
+ PEER_REGEX = 'LL_STATS_PEER_ALL'
+ MCS_REGEX = re.compile(
+ r'preamble: (?P<mode>\S+), nss: (?P<num_streams>\S+), bw: (?P<bw>\S+), '
+ 'mcs: (?P<mcs>\S+), bitrate: (?P<rate>\S+), txmpdu: (?P<txmpdu>\S+), '
+ 'rxmpdu: (?P<rxmpdu>\S+), mpdu_lost: (?P<mpdu_lost>\S+), '
+ 'retries: (?P<retries>\S+), retries_short: (?P<retries_short>\S+), '
+ 'retries_long: (?P<retries_long>\S+)')
+ MCS_ID = collections.namedtuple(
+ 'mcs_id', ['mode', 'num_streams', 'bandwidth', 'mcs', 'rate'])
+ MODE_MAP = {'0': '11a/g', '1': '11b', '2': '11n', '3': '11ac'}
+ BW_MAP = {'0': 20, '1': 40, '2': 80}
+
+ def __init__(self, dut, llstats_enabled=True):
+ self.dut = dut
+ self.llstats_enabled = llstats_enabled
+ self.llstats_cumulative = self._empty_llstats()
+ self.llstats_incremental = self._empty_llstats()
+
+ def update_stats(self):
+ if self.llstats_enabled:
+ try:
+ llstats_output = self.dut.adb.shell(self.LLSTATS_CMD,
+ timeout=0.1)
+ except:
+ llstats_output = ''
+ else:
+ llstats_output = ''
+ self._update_stats(llstats_output)
+
+ def reset_stats(self):
+ self.llstats_cumulative = self._empty_llstats()
+ self.llstats_incremental = self._empty_llstats()
+
+ def _empty_llstats(self):
+ return collections.OrderedDict(mcs_stats=collections.OrderedDict(),
+ summary=collections.OrderedDict())
+
+ def _empty_mcs_stat(self):
+ return collections.OrderedDict(txmpdu=0,
+ rxmpdu=0,
+ mpdu_lost=0,
+ retries=0,
+ retries_short=0,
+ retries_long=0)
+
+ def _mcs_id_to_string(self, mcs_id):
+ mcs_string = '{} {}MHz Nss{} MCS{} {}Mbps'.format(
+ mcs_id.mode, mcs_id.bandwidth, mcs_id.num_streams, mcs_id.mcs,
+ mcs_id.rate)
+ return mcs_string
+
+ def _parse_mcs_stats(self, llstats_output):
+ llstats_dict = {}
+ # Look for per-peer stats
+ match = re.search(self.PEER_REGEX, llstats_output)
+ if not match:
+ self.reset_stats()
+ return collections.OrderedDict()
+ # Find and process all matches for per stream stats
+ match_iter = re.finditer(self.MCS_REGEX, llstats_output)
+ for match in match_iter:
+ current_mcs = self.MCS_ID(self.MODE_MAP[match.group('mode')],
+ int(match.group('num_streams')) + 1,
+ self.BW_MAP[match.group('bw')],
+ int(match.group('mcs')),
+ int(match.group('rate'), 16) / 1000)
+ current_stats = collections.OrderedDict(
+ txmpdu=int(match.group('txmpdu')),
+ rxmpdu=int(match.group('rxmpdu')),
+ mpdu_lost=int(match.group('mpdu_lost')),
+ retries=int(match.group('retries')),
+ retries_short=int(match.group('retries_short')),
+ retries_long=int(match.group('retries_long')))
+ llstats_dict[self._mcs_id_to_string(current_mcs)] = current_stats
+ return llstats_dict
+
+ def _diff_mcs_stats(self, new_stats, old_stats):
+ stats_diff = collections.OrderedDict()
+ for stat_key in new_stats.keys():
+ stats_diff[stat_key] = new_stats[stat_key] - old_stats[stat_key]
+ return stats_diff
+
+ def _generate_stats_summary(self, llstats_dict):
+ llstats_summary = collections.OrderedDict(common_tx_mcs=None,
+ common_tx_mcs_count=0,
+ common_tx_mcs_freq=0,
+ common_rx_mcs=None,
+ common_rx_mcs_count=0,
+ common_rx_mcs_freq=0,
+ rx_per=float('nan'))
+
+ txmpdu_count = 0
+ rxmpdu_count = 0
+ for mcs_id, mcs_stats in llstats_dict['mcs_stats'].items():
+ if mcs_stats['txmpdu'] > llstats_summary['common_tx_mcs_count']:
+ llstats_summary['common_tx_mcs'] = mcs_id
+ llstats_summary['common_tx_mcs_count'] = mcs_stats['txmpdu']
+ if mcs_stats['rxmpdu'] > llstats_summary['common_rx_mcs_count']:
+ llstats_summary['common_rx_mcs'] = mcs_id
+ llstats_summary['common_rx_mcs_count'] = mcs_stats['rxmpdu']
+ txmpdu_count += mcs_stats['txmpdu']
+ rxmpdu_count += mcs_stats['rxmpdu']
+ if txmpdu_count:
+ llstats_summary['common_tx_mcs_freq'] = (
+ llstats_summary['common_tx_mcs_count'] / txmpdu_count)
+ if rxmpdu_count:
+ llstats_summary['common_rx_mcs_freq'] = (
+ llstats_summary['common_rx_mcs_count'] / rxmpdu_count)
+ return llstats_summary
+
+ def _update_stats(self, llstats_output):
+ # Parse stats
+ new_llstats = self._empty_llstats()
+ new_llstats['mcs_stats'] = self._parse_mcs_stats(llstats_output)
+ # Save old stats and set new cumulative stats
+ old_llstats = self.llstats_cumulative.copy()
+ self.llstats_cumulative = new_llstats.copy()
+ # Compute difference between new and old stats
+ self.llstats_incremental = self._empty_llstats()
+ for mcs_id, new_mcs_stats in new_llstats['mcs_stats'].items():
+ old_mcs_stats = old_llstats['mcs_stats'].get(
+ mcs_id, self._empty_mcs_stat())
+ self.llstats_incremental['mcs_stats'][
+ mcs_id] = self._diff_mcs_stats(new_mcs_stats, old_mcs_stats)
+ # Generate llstats summary
+ self.llstats_incremental['summary'] = self._generate_stats_summary(
+ self.llstats_incremental)
+ self.llstats_cumulative['summary'] = self._generate_stats_summary(
+ self.llstats_cumulative)
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_power_test_utils.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_power_test_utils.py
index b1565d2..5c607ca 100644
--- a/acts_tests/acts_contrib/test_utils/wifi/wifi_power_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_power_test_utils.py
@@ -20,6 +20,7 @@
from acts.libs.proc import job
from acts.controllers.ap_lib import bridge_interface as bi
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from acts.controllers.adb_lib.error import AdbCommandError
from acts.controllers.ap_lib import hostapd_security
from acts.controllers.ap_lib import hostapd_ap_preset
@@ -41,8 +42,23 @@
gEnableModulatedDTIM: Modulated DTIM, int
gMaxLIModulatedDTIM: Maximum modulated DTIM, int
"""
- # First trying to find the ini file with DTIM settings
- ini_file_phone = ad.adb.shell('ls /vendor/firmware/wlan/*/*.ini')
+ ad.log.info('Sets dtim to {}'.format(gEnableModulatedDTIM))
+
+ # In P21 the dtim setting method changed and an AdbCommandError will take
+ # place to get ini_file_phone. Thus add try/except block for the old method.
+ # If error occurs, use change_dtim_adb method later. Otherwise, first trying
+ # to find the ini file with DTIM settings
+ try:
+ ini_file_phone = ad.adb.shell('ls /vendor/firmware/wlan/*/*.ini')
+
+ except AdbCommandError as e:
+
+ # Gets AdbCommandError, change dtim later with change_dtim_adb merthod.
+ # change_dtim_adb requires that wifi connection is on.
+ ad.log.info('Gets AdbCommandError, change dtim with change_dtim_adb.')
+ change_dtim_adb(ad, gEnableModulatedDTIM)
+ return 0
+
ini_file_local = ini_file_phone.split('/')[-1]
# Pull the file and change the DTIM to desired value
@@ -81,6 +97,59 @@
ad.log.info('DTIM updated and device back from reboot')
return 1
+def change_dtim_adb(ad, gEnableModulatedDTIM):
+ """Function to change the DTIM setting in the P21 phone.
+
+ This method should be run after connecting wifi.
+
+ Args:
+ ad: the target android device, AndroidDevice object
+ gEnableModulatedDTIM: Modulated DTIM, int
+ """
+ ad.log.info('Changes DTIM to {} with adb'.format(gEnableModulatedDTIM))
+ ad.adb.root()
+ screen_status = ad.adb.shell('dumpsys nfc | grep Screen')
+ screen_is_on = 'ON_UNLOCKED' in screen_status
+
+ # To read the dtim with 'adb shell wl bcn_li_dtim', the screen should be off
+ if screen_is_on:
+ ad.log.info('The screen is on. Set it to off before change dtim')
+ ad.droid.goToSleepNow()
+ time_limit_seconds = 60
+ _wait_screen_off(ad, time_limit_seconds)
+
+ old_dtim = ad.adb.shell('wl bcn_li_dtim')
+ ad.log.info('The dtim before change is {}'.format(old_dtim))
+ if int(old_dtim) == gEnableModulatedDTIM:
+ ad.log.info('Current DTIM is already the desired value,'
+ 'no need to reset it')
+ if screen_is_on:
+ ad.log.info('Changes the screen to the original on status')
+ ad.droid.wakeUpNow()
+ return
+ current_dtim = _set_dtim(ad, gEnableModulatedDTIM)
+ ad.log.info(
+ 'Old DTIM is {}, current DTIM is {}'.format(old_dtim, current_dtim))
+ if screen_is_on:
+ ad.log.info('Changes the screen to the original on status')
+ ad.droid.wakeUpNow()
+
+def _set_dtim(ad, gEnableModulatedDTIM):
+ ad.adb.shell("halutil -dtim_config {}".format(gEnableModulatedDTIM))
+ return ad.adb.shell('wl bcn_li_dtim')
+
+
+def _wait_screen_off(ad, time_limit_seconds):
+ while time_limit_seconds > 0:
+ screen_status = ad.adb.shell('dumpsys nfc | grep Screen')
+ if 'OFF_UNLOCKED' in screen_status:
+ ad.log.info('The screen status is {}'.format(screen_status))
+ return
+ time.sleep(1)
+ time_limit_seconds -= 1
+ raise TimeoutError('Timed out while waiting the screen off after {} '
+ 'seconds.'.format(time_limit_seconds))
+
def push_file_to_phone(ad, file_local, file_phone):
"""Function to push local file to android phone.
@@ -104,7 +173,7 @@
ad.adb.push('{} {}'.format(file_local, file_phone))
-def ap_setup(ap, network, bandwidth=80):
+def ap_setup(ap, network, bandwidth=80, dtim_period=None):
"""Set up the whirlwind AP with provided network info.
Args:
@@ -112,6 +181,7 @@
network: dict with information of the network, including ssid, password
bssid, channel etc.
bandwidth: the operation bandwidth for the AP, default 80MHz
+ dtim_period: the dtim period of access point
Returns:
brconfigs: the bridge interface configs
"""
@@ -128,6 +198,7 @@
config = hostapd_ap_preset.create_ap_preset(
channel=channel,
ssid=ssid,
+ dtim_period=dtim_period,
security=security,
bss_settings=bss_settings,
vht_bandwidth=bandwidth,
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/__init__.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/__init__.py
index 572a238..16f7a1d 100644
--- a/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/__init__.py
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/__init__.py
@@ -51,8 +51,8 @@
'package': 'netgear_r7500'
},
('Netgear', 'R7500NA'): {
- 'name': 'NetgearR7500NAAP',
- 'package': 'netgear_r7500'
+ 'name': 'NetgearR7500NAAP',
+ 'package': 'netgear_r7500'
},
('Netgear', 'R7800'): {
'name': 'NetgearR7800AP',
@@ -66,13 +66,21 @@
'name': 'NetgearRAX80AP',
'package': 'netgear_rax80'
},
+ ('Netgear', 'RAX120'): {
+ 'name': 'NetgearRAX120AP',
+ 'package': 'netgear_rax120'
+ },
('Netgear', 'RAX200'): {
'name': 'NetgearRAX200AP',
'package': 'netgear_rax200'
},
- ('Netgear', 'RAX120'): {
- 'name': 'NetgearRAX120AP',
- 'package': 'netgear_rax120'
+ ('Netgear', 'RAXE500'): {
+ 'name': 'NetgearRAXE500AP',
+ 'package': 'netgear_raxe500'
+ },
+ ('Brcm', 'Reference'): {
+ 'name': 'BrcmRefAP',
+ 'package': 'brcm_ref'
},
('Google', 'Wifi'): {
'name': 'GoogleWifiAP',
@@ -257,7 +265,8 @@
def teardown(self):
"""Function to perform destroy operations."""
- self._unlock_ap()
+ if self.ap_settings.get('lock_ap', 0):
+ self._unlock_ap()
def reset(self):
"""Function that resets AP.
@@ -316,7 +325,9 @@
Args:
region: string indicating AP region
"""
- self.log.warning('Updating region may overwrite wireless settings.')
+ if region != self.ap_settings['region']:
+ self.log.warning(
+ 'Updating region may overwrite wireless settings.')
setting_to_update = {'region': region}
self.update_ap_settings(setting_to_update)
@@ -350,7 +361,7 @@
if channel not in self.capabilities['channels'][network]:
self.log.error('Ch{} is not supported on {} interface.'.format(
channel, network))
- setting_to_update = {network: {'channel': str(channel)}}
+ setting_to_update = {network: {'channel': channel}}
self.update_ap_settings(setting_to_update)
def set_bandwidth(self, network, bandwidth):
@@ -363,10 +374,39 @@
if 'bw' in bandwidth:
bandwidth = bandwidth.replace('bw',
self.capabilities['default_mode'])
+ elif isinstance(bandwidth, int):
+ bandwidth = str(bandwidth) + self.capabilities['default_mode']
if bandwidth not in self.capabilities['modes'][network]:
self.log.error('{} mode is not supported on {} interface.'.format(
bandwidth, network))
- setting_to_update = {network: {'bandwidth': str(bandwidth)}}
+ setting_to_update = {network: {'bandwidth': bandwidth}}
+ self.update_ap_settings(setting_to_update)
+
+ def set_channel_and_bandwidth(self, network, channel, bandwidth):
+ """Function that sets network bandwidth/mode and channel.
+
+ Args:
+ network: string containing network identifier (2G, 5G_1, 5G_2)
+ channel: string containing desired channel
+ bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
+ """
+ if 'bw' in bandwidth:
+ bandwidth = bandwidth.replace('bw',
+ self.capabilities['default_mode'])
+ elif isinstance(bandwidth, int):
+ bandwidth = str(bandwidth) + self.capabilities['default_mode']
+ if bandwidth not in self.capabilities['modes'][network]:
+ self.log.error('{} mode is not supported on {} interface.'.format(
+ bandwidth, network))
+ if channel not in self.capabilities['channels'][network]:
+ self.log.error('Ch{} is not supported on {} interface.'.format(
+ channel, network))
+ setting_to_update = {
+ network: {
+ 'bandwidth': bandwidth,
+ 'channel': channel
+ }
+ }
self.update_ap_settings(setting_to_update)
def set_power(self, network, power):
@@ -379,7 +419,7 @@
if 'power' not in self.ap_settings[network].keys():
self.log.error(
'Cannot configure power on {} interface.'.format(network))
- setting_to_update = {network: {'power': str(power)}}
+ setting_to_update = {network: {'power': power}}
self.update_ap_settings(setting_to_update)
def set_security(self, network, security_type, *password):
@@ -463,12 +503,13 @@
Args:
channel: channel number to lookup
Returns:
- band: name of band which this channel belongs to on this ap
+ band: name of band which this channel belongs to on this ap, False
+ if not supported
"""
for key, value in self.capabilities['channels'].items():
if channel in value:
return key
- raise ValueError('Invalid channel passed in argument.')
+ return False
def _get_control_ip_address(self):
"""Function to get AP's Control Interface IP address."""
@@ -502,5 +543,9 @@
"""Function to unlock the AP when tests are done."""
self.log.info('Releasing AP lock.')
if hasattr(self, 'lock_file'):
- fcntl.flock(self.lock_file, fcntl.LOCK_UN)
- self.lock_file.close()
+ try:
+ fcntl.flock(self.lock_file, fcntl.LOCK_UN)
+ self.lock_file.close()
+ self.log.info('Succussfully released AP lock file.')
+ except:
+ raise RuntimeError('Error occurred while unlocking AP.')
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/brcm_ref.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/brcm_ref.py
new file mode 100644
index 0000000..1b09533
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/brcm_ref.py
@@ -0,0 +1,243 @@
+import collections
+import numpy
+import time
+from acts_contrib.test_utils.wifi.wifi_retail_ap import WifiRetailAP
+from acts_contrib.test_utils.wifi.wifi_retail_ap import BlockingBrowser
+
+BROWSER_WAIT_SHORT = 1
+BROWSER_WAIT_MED = 3
+BROWSER_WAIT_LONG = 10
+BROWSER_WAIT_EXTRA_LONG = 60
+
+
+class BrcmRefAP(WifiRetailAP):
+ """Class that implements Netgear RAX200 AP.
+
+ Since most of the class' implementation is shared with the R7000, this
+ class inherits from NetgearR7000AP and simply redefines config parameters
+ """
+ def __init__(self, ap_settings):
+ super().__init__(ap_settings)
+ self.init_gui_data()
+ # Read and update AP settings
+ self.read_ap_settings()
+ self.update_ap_settings(ap_settings)
+
+ def init_gui_data(self):
+ self.config_page = ('{protocol}://{username}:{password}@'
+ '{ip_address}:{port}/info.html').format(
+ protocol=self.ap_settings['protocol'],
+ username=self.ap_settings['admin_username'],
+ password=self.ap_settings['admin_password'],
+ ip_address=self.ap_settings['ip_address'],
+ port=self.ap_settings['port'])
+ self.config_page_nologin = (
+ '{protocol}://{ip_address}:{port}/'
+ 'wlrouter/radio.asp').format(
+ protocol=self.ap_settings['protocol'],
+ ip_address=self.ap_settings['ip_address'],
+ port=self.ap_settings['port'])
+
+ self.capabilities = {
+ 'interfaces': ['2G_5G', '6G'],
+ 'channels': {
+ '2G_5G': [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56,
+ 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136,
+ 140, 144, 149, 153, 157, 161, 165
+ ],
+ '6G': ['6g' + str(ch) for ch in numpy.arange(1, 222, 4)]
+ },
+ 'modes': {
+ '2G_5G': [
+ 'VHT20', 'VHT40', 'VHT80', 'VHT160', 'HE20', 'HE40',
+ 'HE80', 'HE160'
+ ],
+ '6G': [
+ 'VHT20', 'VHT40', 'VHT80', 'VHT160', 'HE20', 'HE40',
+ 'HE80', 'HE160'
+ ]
+ },
+ 'default_mode': 'HE'
+ }
+ self.ap_settings['region'] = 'United States'
+ for interface in self.capabilities['interfaces']:
+ self.ap_settings[interface] = {
+ 'ssid': 'BrcmAP0' if interface == '6G' else 'BrcmAP1',
+ 'security_type': 'Open',
+ 'password': '1234567890'
+ }
+ self.config_page_fields = collections.OrderedDict({
+ ('2G_5G', 'interface'): ('wl_unit', 1),
+ ('2G_5G', 'band'):
+ 'wl_nband',
+ ('2G_5G', 'bandwidth'):
+ 'wl_bw_cap',
+ ('2G_5G', 'channel'):
+ 'wl_chanspec',
+ ('6G', 'interface'): ('wl_unit', 0),
+ ('6G', 'band'):
+ 'wl_nband',
+ ('6G', 'bandwidth'):
+ 'wl_bw_cap',
+ ('6G', 'channel'):
+ 'wl_chanspec',
+ })
+
+ self.band_mode_values = {'1': '5 GHz', '2': '2.4 GHz', '4': '6 GHz'}
+
+ self.band_values = {'5 GHz': 1, '2.4 GHz': 2, '6 GHz': 4}
+
+ self.bandwidth_mode_values = {
+ '1': 'HE20',
+ '3': 'HE40',
+ '7': 'HE80',
+ '15': 'HE160'
+ }
+
+ def _decode_channel_string(self, channel_string):
+ if channel_string == '0':
+ return 'Auto'
+ if 'u' in channel_string or 'l' in channel_string:
+ channel_string = channel_string[0:-1]
+ elif len(channel_string.split('/')) > 1:
+ channel_string = channel_string.split('/')[0]
+ if '6g' in channel_string:
+ return channel_string
+ else:
+ return int(channel_string)
+
+ def _get_channel_str(self, interface, channel, bandwidth):
+ bandwidth = int(''.join([x for x in bandwidth if x.isdigit()]))
+ if bandwidth == 20:
+ channel_str = str(channel)
+ elif bandwidth in [80, 160]:
+ channel_str = str(channel) + '/' + str(bandwidth)
+ elif interface == '6G' and bandwidth == 40:
+ channel_str = str(channel) + '/' + str(bandwidth)
+ elif interface == '2G_5G' and bandwidth == 40:
+ lower_lookup = [
+ 36, 44, 52, 60, 100, 108, 116, 124, 132, 140, 149, 157
+ ]
+ if int(channel) in lower_lookup:
+ channel_str = str(channel) + 'l'
+ else:
+ channel_str = str(channel) + 'u'
+ return channel_str
+
+ def read_ap_settings(self):
+ with BlockingBrowser(self.ap_settings['headless_browser'],
+ 900) as browser:
+ # Visit URL
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page_nologin,
+ BROWSER_WAIT_MED, 10, self.config_page)
+
+ for key in self.config_page_fields.keys():
+ if 'interface' in key:
+ config_item = browser.find_by_name(
+ self.config_page_fields[key][0]).first
+ config_item.select(self.config_page_fields[key][1])
+ time.sleep(BROWSER_WAIT_SHORT)
+ else:
+ config_item = browser.find_by_name(
+ self.config_page_fields[key]).first
+ if 'band' in key:
+ self.ap_settings[key[0]][
+ key[1]] = self.band_mode_values[config_item.value]
+ elif 'bandwidth' in key:
+ self.ap_settings[key[0]][key[
+ 1]] = self.bandwidth_mode_values[config_item.value]
+ elif 'channel' in key:
+ self.ap_settings[key[0]][
+ key[1]] = self._decode_channel_string(
+ config_item.value)
+ else:
+ self.ap_settings[key[0]][key[1]] = config_item.value
+
+ def update_ap_settings(self, dict_settings={}, **named_settings):
+ """Function to update settings of existing AP.
+
+ Function copies arguments into ap_settings and calls configure_ap
+ to apply them.
+
+ Args:
+ dict_settings: single dictionary of settings to update
+ **named_settings: named settings to update
+ Note: dict and named_settings cannot contain the same settings.
+ """
+
+ settings_to_update = dict(dict_settings, **named_settings)
+ if len(settings_to_update) != len(dict_settings) + len(named_settings):
+ raise KeyError('The following keys were passed twice: {}'.format(
+ (set(dict_settings.keys()).intersection(
+ set(named_settings.keys())))))
+
+ updating_6G = '6G' in settings_to_update.keys()
+ updating_2G_5G = '2G_5G' in settings_to_update.keys()
+
+ if updating_2G_5G:
+ if 'channel' in settings_to_update['2G_5G']:
+ band = '2.4 GHz' if int(
+ settings_to_update['2G_5G']['channel']) < 13 else '5 GHz'
+ if band == '2.4 GHz':
+ settings_to_update['2G_5G']['bandwidth'] = 'HE20'
+ settings_to_update['2G_5G']['band'] = band
+ self.ap_settings, updates_requested, status_toggle_flag = self._update_settings_dict(
+ self.ap_settings, settings_to_update)
+ if updates_requested:
+ self.configure_ap(updating_2G_5G, updating_6G)
+
+ def configure_ap(self, updating_2G_5G, updating_6G):
+
+ with BlockingBrowser(self.ap_settings['headless_browser'],
+ 900) as browser:
+
+ interfaces_to_update = []
+ if updating_2G_5G:
+ interfaces_to_update.append('2G_5G')
+ if updating_6G:
+ interfaces_to_update.append('6G')
+ for interface in interfaces_to_update:
+ # Visit URL
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED,
+ 10)
+ browser.visit_persistent(self.config_page_nologin,
+ BROWSER_WAIT_MED, 10,
+ self.config_page)
+
+ config_item = browser.find_by_name(
+ self.config_page_fields[(interface, 'interface')][0]).first
+ config_item.select(self.config_page_fields[(interface,
+ 'interface')][1])
+ time.sleep(BROWSER_WAIT_SHORT)
+
+ for key, value in self.config_page_fields.items():
+ if 'interface' in key or interface not in key:
+ continue
+ config_item = browser.find_by_name(
+ self.config_page_fields[key]).first
+ if 'band' in key:
+ config_item.select(
+ self.band_values[self.ap_settings[key[0]][key[1]]])
+ elif 'bandwidth' in key:
+ config_item.select_by_text(
+ str(self.ap_settings[key[0]][key[1]])[2:] + ' MHz')
+ elif 'channel' in key:
+ channel_str = self._get_channel_str(
+ interface, self.ap_settings[interface][key[1]],
+ self.ap_settings[interface]['bandwidth'])
+ config_item.select_by_text(channel_str)
+ else:
+ self.ap_settings[key[0]][key[1]] = config_item.value
+ time.sleep(BROWSER_WAIT_SHORT)
+ # Apply
+ config_item = browser.find_by_name('action')
+ config_item.first.click()
+ time.sleep(BROWSER_WAIT_MED)
+ config_item = browser.find_by_name('action')
+ time.sleep(BROWSER_WAIT_SHORT)
+ config_item.first.click()
+ time.sleep(BROWSER_WAIT_LONG)
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_LONG,
+ 10)
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/google_wifi.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/google_wifi.py
index dd4ee9f..4023b9a 100644
--- a/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/google_wifi.py
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/google_wifi.py
@@ -93,6 +93,14 @@
'subnet': '192.168.9.0/24'
}
}
+ for setting in self.default_settings.keys():
+ if setting in self.capabilities['interfaces']:
+ continue
+ elif setting not in self.ap_settings:
+ self.log.debug(
+ '{0} {1} not found during init. Setting {0} = {1}'.format(
+ setting, self.default_settings[setting]))
+ self.ap_settings[setting] = self.default_settings[setting]
for interface in self.capabilities['interfaces']:
for setting in self.default_settings[interface].keys():
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_r7000.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_r7000.py
index e7f4e83..ac118df 100644
--- a/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_r7000.py
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_r7000.py
@@ -278,5 +278,5 @@
"""Class that implements Netgear R7000 NA AP."""
def init_gui_data(self):
"""Function to initialize data used while interacting with web GUI"""
- super.init_gui_data()
+ super().init_gui_data()
self.region_map['11'] = 'North America'
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_rax120.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_rax120.py
index e718ebd..d1420df 100644
--- a/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_rax120.py
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_rax120.py
@@ -108,6 +108,12 @@
'19': 'Russia',
'20': 'Singapore',
'21': 'Taiwan',
+ 'Australia': 'Australia',
+ 'Europe': 'Europe',
+ 'Korea': 'Korea',
+ 'Singapore': 'Singapore',
+ 'Hong Kong': 'Hong Kong',
+ 'United States': 'United States',
}
self.bw_mode_text = {
'2G': {
@@ -120,12 +126,12 @@
'5G_1': {
'HE20': 'Up to 1147 Mbps (11ax, HT20, 1024-QAM)',
'HE40': 'Up to 2294 Mbps (11ax, HT40, 1024-QAM)',
- 'HE80': 'Up to 4803 Mbps (11ax, HT80, 1024-QAM)',
- 'HE160': 'Up to 4803 Mbps (11ax, HT160, 1024-QAM)',
+ 'HE80': 'Up to 4803 Mbps (80MHz) (11ax, HT80, 1024-QAM)',
+ 'HE160': 'Up to 4803 Mbps (160MHz) (11ax, HT160, 1024-QAM)',
'VHT20': 'Up to 962 Mbps (11ac, HT20, 1024-QAM)',
'VHT40': 'Up to 2000 Mbps (11ac, HT40, 1024-QAM)',
- 'VHT80': 'Up to 4333 Mbps (11ac, HT80, 1024-QAM)',
- 'VHT160': 'Up to 4333 Mbps (11ac, HT160, 1024-QAM)'
+ 'VHT80': 'Up to 4333 Mbps (80MHz) (11ac, HT80, 1024-QAM)',
+ 'VHT160': 'Up to 4333 Mbps (160MHz) (11ac, HT160, 1024-QAM)'
}
}
self.bw_mode_values = {
@@ -146,7 +152,14 @@
'7': 'HE20',
'8': 'HE40',
'9': 'HE80',
- '10': 'HE160'
+ '10': 'HE160',
+ '54': '11g',
+ '573.5': 'HE20',
+ '1146': 'HE40',
+ '1147': 'HE20',
+ '2294': 'HE40',
+ '4803-HT80': 'HE80',
+ '4803-HT160': 'HE160'
}
}
self.security_mode_values = {
@@ -160,6 +173,55 @@
}
}
+ def _set_channel_and_bandwidth(self,
+ network,
+ channel=None,
+ bandwidth=None):
+ """Helper function that sets network bandwidth and channel.
+
+ Args:
+ network: string containing network identifier (2G, 5G_1, 5G_2)
+ channel: desired channel
+ bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
+ """
+ setting_to_update = {network: {}}
+ if channel:
+ if channel not in self.capabilities['channels'][network]:
+ self.log.error('Ch{} is not supported on {} interface.'.format(
+ channel, network))
+ setting_to_update[network]['channel'] = channel
+
+ if bandwidth is None:
+ return setting_to_update
+
+ if 'bw' in bandwidth:
+ bandwidth = bandwidth.replace('bw',
+ self.capabilities['default_mode'])
+ if bandwidth not in self.capabilities['modes'][network]:
+ self.log.error('{} mode is not supported on {} interface.'.format(
+ bandwidth, network))
+ setting_to_update[network]['bandwidth'] = str(bandwidth)
+ setting_to_update['enable_ax'] = int('HE' in bandwidth)
+ # Check if other interfaces need to be changed too
+ requested_mode = 'HE' if 'HE' in bandwidth else 'VHT'
+ for other_network in self.capabilities['interfaces']:
+ if other_network == network:
+ continue
+ other_mode = 'HE' if 'HE' in self.ap_settings[other_network][
+ 'bandwidth'] else 'VHT'
+ other_bw = ''.join([
+ x for x in self.ap_settings[other_network]['bandwidth']
+ if x.isdigit()
+ ])
+ if other_mode != requested_mode:
+ updated_mode = '{}{}'.format(requested_mode, other_bw)
+ self.log.warning('All networks must be VHT or HE. '
+ 'Updating {} to {}'.format(
+ other_network, updated_mode))
+ setting_to_update.setdefault(other_network, {})
+ setting_to_update[other_network]['bandwidth'] = updated_mode
+ return setting_to_update
+
def set_bandwidth(self, network, bandwidth):
"""Function that sets network bandwidth/mode.
@@ -167,31 +229,31 @@
network: string containing network identifier (2G, 5G_1, 5G_2)
bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
"""
- if 'bw' in bandwidth:
- bandwidth = bandwidth.replace('bw',
- self.capabilities['default_mode'])
- if bandwidth not in self.capabilities['modes'][network]:
- self.log.error('{} mode is not supported on {} interface.'.format(
- bandwidth, network))
- setting_to_update = {network: {'bandwidth': str(bandwidth)}}
- setting_to_update['enable_ax'] = int('HE' in bandwidth)
- # Check if other interfaces need to be changed too
- requested_mode = 'HE' if 'HE' in bandwidth else 'VHT'
- other_network = '2G' if '5G_1' in network else '5G_1'
- other_mode = 'HE' if 'HE' in self.ap_settings[other_network][
- 'bandwidth'] else 'VHT'
- other_bw = ''.join([
- x for x in self.ap_settings[other_network]['bandwidth']
- if x.isdigit()
- ])
- if other_mode != requested_mode:
- updated_mode = '{}{}'.format(requested_mode, other_bw)
- self.log.warning('All networks must be VHT or HE. '
- 'Updating {} to {}'.format(
- other_network, updated_mode))
- setting_to_update.setdefault(other_network, {})
- setting_to_update[other_network]['bandwidth'] = updated_mode
+ setting_to_update = self._set_channel_and_bandwidth(
+ network, bandwidth=bandwidth)
+ self.update_ap_settings(setting_to_update)
+ def set_channel(self, network, channel):
+ """Function that sets network channel.
+
+ Args:
+ network: string containing network identifier (2G, 5G_1, 5G_2)
+ channel: string or int containing channel
+ """
+ setting_to_update = self._set_channel_and_bandwidth(network,
+ channel=channel)
+ self.update_ap_settings(setting_to_update)
+
+ def set_channel_and_bandwidth(self, network, channel, bandwidth):
+ """Function that sets network bandwidth/mode.
+
+ Args:
+ network: string containing network identifier (2G, 5G_1, 5G_2)
+ channel: desired channel
+ bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
+ """
+ setting_to_update = self._set_channel_and_bandwidth(
+ network, channel=channel, bandwidth=bandwidth)
self.update_ap_settings(setting_to_update)
def read_ap_settings(self):
@@ -236,9 +298,13 @@
key[1]] = 'defaultpassword'
self.ap_settings[
key[0]]['security_type'] = 'Disable'
- elif ('channel' in key) or ('ssid' in key):
+ elif ('ssid' in key):
config_item = iframe.find_by_name(value).first
self.ap_settings[key[0]][key[1]] = config_item.value
+ elif ('channel' in key):
+ config_item = iframe.find_by_name(value).first
+ self.ap_settings[key[0]][key[1]] = int(
+ config_item.value)
return self.ap_settings.copy()
def configure_ap(self, **config_flags):
@@ -269,9 +335,13 @@
'enable_ax_chec')
action.move_to_element(ax_checkbox).click().perform()
# Update AP region. Must be done before channel setting
- config_item = iframe.find_by_name(
- self.config_page_fields['region']).first
- config_item.select_by_text(self.ap_settings['region'])
+ try:
+ config_item = iframe.find_by_name(
+ self.config_page_fields['region']).first
+ config_item.select_by_text(self.ap_settings['region'])
+ except:
+ self.log.warning('Could not set AP region to {}.'.format(
+ self.ap_settings['region']))
# Update wireless settings for each network
for key, value in self.config_page_fields.items():
if 'ssid' in key:
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_rax200.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_rax200.py
index 91c6382..d6c6fad 100644
--- a/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_rax200.py
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_rax200.py
@@ -15,7 +15,6 @@
# limitations under the License.
import collections
-import selenium
import time
from acts_contrib.test_utils.wifi.wifi_retail_ap import WifiRetailAP
from acts_contrib.test_utils.wifi.wifi_retail_ap import BlockingBrowser
@@ -119,7 +118,7 @@
'VHT20': 'Up to 433 Mbps',
'VHT40': 'Up to 1000 Mbps',
'VHT80': 'Up to 2165 Mbps',
- 'VHT160': 'Up to 4330'
+ 'VHT160': 'Up to 4330 Mbps'
},
'5G_2': {
'HE20': 'Up to 600 Mbps',
@@ -129,7 +128,7 @@
'VHT20': 'Up to 433 Mbps',
'VHT40': 'Up to 1000 Mbps',
'VHT80': 'Up to 2165 Mbps',
- 'VHT160': 'Up to 4330'
+ 'VHT160': 'Up to 4330 Mbps'
}
}
self.bw_mode_values = {
@@ -181,20 +180,34 @@
'4': '25%'
}
- def set_bandwidth(self, network, bandwidth):
- """Function that sets network bandwidth/mode.
+ def _set_channel_and_bandwidth(self,
+ network,
+ channel=None,
+ bandwidth=None):
+ """Helper function that sets network bandwidth and channel.
Args:
network: string containing network identifier (2G, 5G_1, 5G_2)
+ channel: desired channel
bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
"""
+ setting_to_update = {network: {}}
+ if channel:
+ if channel not in self.capabilities['channels'][network]:
+ self.log.error('Ch{} is not supported on {} interface.'.format(
+ channel, network))
+ setting_to_update[network]['channel'] = channel
+
+ if bandwidth is None:
+ return setting_to_update
+
if 'bw' in bandwidth:
bandwidth = bandwidth.replace('bw',
self.capabilities['default_mode'])
if bandwidth not in self.capabilities['modes'][network]:
self.log.error('{} mode is not supported on {} interface.'.format(
bandwidth, network))
- setting_to_update = {network: {'bandwidth': str(bandwidth)}}
+ setting_to_update[network]['bandwidth'] = str(bandwidth)
setting_to_update['enable_ax'] = int('HE' in bandwidth)
# Check if other interfaces need to be changed too
requested_mode = 'HE' if 'HE' in bandwidth else 'VHT'
@@ -214,7 +227,41 @@
other_network, updated_mode))
setting_to_update.setdefault(other_network, {})
setting_to_update[other_network]['bandwidth'] = updated_mode
+ return setting_to_update
+ def set_bandwidth(self, network, bandwidth):
+ """Function that sets network bandwidth/mode.
+
+ Args:
+ network: string containing network identifier (2G, 5G_1, 5G_2)
+ bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
+ """
+
+ setting_to_update = self._set_channel_and_bandwidth(
+ network, bandwidth=bandwidth)
+ self.update_ap_settings(setting_to_update)
+
+ def set_channel(self, network, channel):
+ """Function that sets network channel.
+
+ Args:
+ network: string containing network identifier (2G, 5G_1, 5G_2)
+ channel: string or int containing channel
+ """
+ setting_to_update = self._set_channel_and_bandwidth(network,
+ channel=channel)
+ self.update_ap_settings(setting_to_update)
+
+ def set_channel_and_bandwidth(self, network, channel, bandwidth):
+ """Function that sets network bandwidth/mode.
+
+ Args:
+ network: string containing network identifier (2G, 5G_1, 5G_2)
+ channel: desired channel
+ bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
+ """
+ setting_to_update = self._set_channel_and_bandwidth(
+ network, channel=channel, bandwidth=bandwidth)
self.update_ap_settings(setting_to_update)
def read_ap_settings(self):
@@ -252,6 +299,10 @@
for item in config_item:
if item.checked:
self.ap_settings[key[0]][key[1]] = item.value
+ elif 'channel' in key:
+ config_item = browser.find_by_name(value)
+ self.ap_settings[key[0]][key[1]] = int(
+ config_item.first.value)
else:
config_item = browser.find_by_name(value)
self.ap_settings[key[0]][
@@ -321,8 +372,10 @@
self.log.warning(
'Cannot select channel. Keeping AP default.')
try:
- alert = browser.get_alert()
- alert.accept()
+ for idx in range(0, 2):
+ alert = browser.get_alert()
+ alert.accept()
+ time.sleep(BROWSER_WAIT_SHORT)
except:
pass
time.sleep(BROWSER_WAIT_SHORT)
@@ -336,7 +389,6 @@
time.sleep(BROWSER_WAIT_SHORT)
browser.visit_persistent(self.config_page, BROWSER_WAIT_EXTRA_LONG,
10)
- self.validate_ap_settings()
def configure_radio_on_off(self):
"""Helper configuration function to turn radios on/off."""
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_raxe500.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_raxe500.py
new file mode 100644
index 0000000..9dc60aa
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_retail_ap/netgear_raxe500.py
@@ -0,0 +1,442 @@
+#!/usr/bin/env python3
+#
+# Copyright 2020 - 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 collections
+import numpy
+import re
+import time
+from acts_contrib.test_utils.wifi.wifi_retail_ap import WifiRetailAP
+from acts_contrib.test_utils.wifi.wifi_retail_ap import BlockingBrowser
+
+BROWSER_WAIT_SHORT = 1
+BROWSER_WAIT_MED = 3
+BROWSER_WAIT_LONG = 30
+BROWSER_WAIT_EXTRA_LONG = 60
+
+
+class NetgearRAXE500AP(WifiRetailAP):
+ """Class that implements Netgear RAXE500 AP.
+
+ Since most of the class' implementation is shared with the R7000, this
+ class inherits from NetgearR7000AP and simply redefines config parameters
+ """
+ def __init__(self, ap_settings):
+ super().__init__(ap_settings)
+ self.init_gui_data()
+ # Read and update AP settings
+ self.read_ap_firmware()
+ self.read_ap_settings()
+ self.update_ap_settings(ap_settings)
+
+ def init_gui_data(self):
+ self.config_page = (
+ '{protocol}://{username}:{password}@'
+ '{ip_address}:{port}/WLG_wireless_tri_band.htm').format(
+ protocol=self.ap_settings['protocol'],
+ username=self.ap_settings['admin_username'],
+ password=self.ap_settings['admin_password'],
+ ip_address=self.ap_settings['ip_address'],
+ port=self.ap_settings['port'])
+ self.config_page_nologin = (
+ '{protocol}://{ip_address}:{port}/'
+ 'WLG_wireless_tri_band.htm').format(
+ protocol=self.ap_settings['protocol'],
+ ip_address=self.ap_settings['ip_address'],
+ port=self.ap_settings['port'])
+ self.config_page_advanced = (
+ '{protocol}://{username}:{password}@'
+ '{ip_address}:{port}/WLG_adv_tri_band2.htm').format(
+ protocol=self.ap_settings['protocol'],
+ username=self.ap_settings['admin_username'],
+ password=self.ap_settings['admin_password'],
+ ip_address=self.ap_settings['ip_address'],
+ port=self.ap_settings['port'])
+ self.firmware_page = (
+ '{protocol}://{username}:{password}@'
+ '{ip_address}:{port}/ADVANCED_home2_tri_band.htm').format(
+ protocol=self.ap_settings['protocol'],
+ username=self.ap_settings['admin_username'],
+ password=self.ap_settings['admin_password'],
+ ip_address=self.ap_settings['ip_address'],
+ port=self.ap_settings['port'])
+ self.capabilities = {
+ 'interfaces': ['2G', '5G_1', '6G'],
+ 'channels': {
+ '2G': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
+ '5G_1': [
+ 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116,
+ 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165
+ ],
+ '6G': ['6g' + str(ch) for ch in numpy.arange(37, 222, 16)]
+ },
+ 'modes': {
+ '2G': ['VHT20', 'VHT40', 'HE20', 'HE40'],
+ '5G_1': [
+ 'VHT20', 'VHT40', 'VHT80', 'VHT160', 'HE20', 'HE40',
+ 'HE80', 'HE160'
+ ],
+ '6G': [
+ 'VHT20', 'VHT40', 'VHT80', 'VHT160', 'HE20', 'HE40',
+ 'HE80', 'HE160'
+ ]
+ },
+ 'default_mode': 'HE'
+ }
+ for interface in self.capabilities['interfaces']:
+ self.ap_settings[interface] = {}
+
+ self.region_map = {
+ '3': 'Australia',
+ '4': 'Canada',
+ '5': 'Europe',
+ '7': 'Japan',
+ '8': 'Korea',
+ '11': 'North America',
+ '16': 'China',
+ '17': 'India',
+ '21': 'Middle East(Saudi Arabia/United Arab Emirates)',
+ '23': 'Singapore',
+ '25': 'Hong Kong',
+ '26': 'Vietnam'
+ }
+
+ self.bw_mode_text = {
+ '2G': {
+ 'g and b': 'Up to 54 Mbps',
+ 'HE20': 'Up to 600 Mbps',
+ 'HE40': 'Up to 1200 Mbps',
+ 'VHT20': 'Up to 433 Mbps',
+ 'VHT40': 'Up to 1000 Mbps'
+ },
+ '5G_1': {
+ 'HE20': 'Up to 600 Mbps',
+ 'HE40': 'Up to 1200 Mbps',
+ 'HE80': 'Up to 2400 Mbps',
+ 'HE160': 'Up to 4800 Mbps',
+ 'VHT20': 'Up to 433 Mbps',
+ 'VHT40': 'Up to 1000 Mbps',
+ 'VHT80': 'Up to 2165 Mbps',
+ 'VHT160': 'Up to 4330 Mbps'
+ },
+ '6G': {
+ 'HE20': 'Up to 600 Mbps',
+ 'HE40': 'Up to 1200 Mbps',
+ 'HE80': 'Up to 2400 Mbps',
+ 'HE160': 'Up to 4800 Mbps',
+ 'VHT20': 'Up to 600 Mbps',
+ 'VHT40': 'Up to 1200 Mbps',
+ 'VHT80': 'Up to 2400 Mbps',
+ 'VHT160': 'Up to 4800 Mbps'
+ }
+ }
+ self.bw_mode_values = {
+ # first key is a boolean indicating if 11ax is enabled
+ 0: {
+ 'g and b': '11g',
+ 'HT20': 'VHT20',
+ 'HT40': 'VHT40',
+ 'HT80': 'VHT80',
+ 'HT160': 'VHT160'
+ },
+ 1: {
+ 'g and b': '11g',
+ 'HT20': 'HE20',
+ 'HT40': 'HE40',
+ 'HT80': 'HE80',
+ 'HT160': 'HE160'
+ }
+ }
+
+ # Config ordering intentional to avoid GUI bugs
+ self.config_page_fields = collections.OrderedDict([
+ ('region', 'WRegion'), ('enable_ax', 'enable_he'),
+ (('2G', 'status'), 'enable_ap'),
+ (('5G_1', 'status'), 'enable_ap_an'),
+ (('6G', 'status'), 'enable_ap_an_2'), (('2G', 'ssid'), 'ssid'),
+ (('5G_1', 'ssid'), 'ssid_an'), (('6G', 'ssid'), 'ssid_an_2'),
+ (('2G', 'channel'), 'w_channel'),
+ (('5G_1', 'channel'), 'w_channel_an'),
+ (('6G', 'channel'), 'w_channel_an_2'),
+ (('2G', 'bandwidth'), 'opmode'),
+ (('5G_1', 'bandwidth'), 'opmode_an'),
+ (('6G', 'bandwidth'), 'opmode_an_2'),
+ (('2G', 'power'), 'enable_tpc'),
+ (('5G_1', 'power'), 'enable_tpc_an'),
+ (('6G', 'security_type'), 'security_type_an_2'),
+ (('5G_1', 'security_type'), 'security_type_an'),
+ (('2G', 'security_type'), 'security_type'),
+ (('2G', 'password'), 'passphrase'),
+ (('5G_1', 'password'), 'passphrase_an'),
+ (('6G', 'password'), 'passphrase_an_2')
+ ])
+
+ self.power_mode_values = {
+ '1': '100%',
+ '2': '75%',
+ '3': '50%',
+ '4': '25%'
+ }
+
+ def _set_channel_and_bandwidth(self,
+ network,
+ channel=None,
+ bandwidth=None):
+ """Helper function that sets network bandwidth and channel.
+
+ Args:
+ network: string containing network identifier (2G, 5G_1, 5G_2)
+ channel: desired channel
+ bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
+ """
+
+ setting_to_update = {network: {}}
+ if channel:
+ if channel not in self.capabilities['channels'][network]:
+ self.log.error('Ch{} is not supported on {} interface.'.format(
+ channel, network))
+ if isinstance(channel, str) and '6g' in channel:
+ channel = int(channel[2:])
+ setting_to_update[network]['channel'] = channel
+
+ if bandwidth is None:
+ return setting_to_update
+
+ if 'bw' in bandwidth:
+ bandwidth = bandwidth.replace('bw',
+ self.capabilities['default_mode'])
+ if bandwidth not in self.capabilities['modes'][network]:
+ self.log.error('{} mode is not supported on {} interface.'.format(
+ bandwidth, network))
+ setting_to_update[network]['bandwidth'] = str(bandwidth)
+ setting_to_update['enable_ax'] = int('HE' in bandwidth)
+ # Check if other interfaces need to be changed too
+ requested_mode = 'HE' if 'HE' in bandwidth else 'VHT'
+ for other_network in self.capabilities['interfaces']:
+ if other_network == network:
+ continue
+ other_mode = 'HE' if 'HE' in self.ap_settings[other_network][
+ 'bandwidth'] else 'VHT'
+ other_bw = ''.join([
+ x for x in self.ap_settings[other_network]['bandwidth']
+ if x.isdigit()
+ ])
+ if other_mode != requested_mode:
+ updated_mode = '{}{}'.format(requested_mode, other_bw)
+ self.log.warning('All networks must be VHT or HE. '
+ 'Updating {} to {}'.format(
+ other_network, updated_mode))
+ setting_to_update.setdefault(other_network, {})
+ setting_to_update[other_network]['bandwidth'] = updated_mode
+ return setting_to_update
+
+ def set_bandwidth(self, network, bandwidth):
+ """Function that sets network bandwidth/mode.
+
+ Args:
+ network: string containing network identifier (2G, 5G_1, 5G_2)
+ bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
+ """
+
+ setting_to_update = self._set_channel_and_bandwidth(
+ network, bandwidth=bandwidth)
+ self.update_ap_settings(setting_to_update)
+
+ def set_channel(self, network, channel):
+ """Function that sets network channel.
+
+ Args:
+ network: string containing network identifier (2G, 5G_1, 5G_2)
+ channel: string or int containing channel
+ """
+ setting_to_update = self._set_channel_and_bandwidth(network,
+ channel=channel)
+ self.update_ap_settings(setting_to_update)
+
+ def set_channel_and_bandwidth(self, network, channel, bandwidth):
+ """Function that sets network bandwidth/mode.
+
+ Args:
+ network: string containing network identifier (2G, 5G_1, 5G_2)
+ channel: desired channel
+ bandwidth: string containing mode, e.g. 11g, VHT20, VHT40, VHT80.
+ """
+ setting_to_update = self._set_channel_and_bandwidth(
+ network, channel=channel, bandwidth=bandwidth)
+ self.update_ap_settings(setting_to_update)
+
+ def read_ap_firmware(self):
+ """Function to read ap settings."""
+ with BlockingBrowser(self.ap_settings['headless_browser'],
+ 900) as browser:
+
+ # Visit URL
+ browser.visit_persistent(self.firmware_page, BROWSER_WAIT_MED, 10)
+ firmware_regex = re.compile(
+ r'Firmware Version[\s\S]+V(?P<version>[0-9._]+)')
+ firmware_version = re.search(firmware_regex, browser.html)
+ if firmware_version:
+ self.ap_settings['firmware_version'] = firmware_version.group(
+ 'version')
+ else:
+ self.ap_settings['firmware_version'] = -1
+
+ def read_ap_settings(self):
+ """Function to read ap settings."""
+ with BlockingBrowser(self.ap_settings['headless_browser'],
+ 900) as browser:
+ # Visit URL
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED, 10)
+
+ for key, value in self.config_page_fields.items():
+ if 'status' in key:
+ browser.visit_persistent(self.config_page_advanced,
+ BROWSER_WAIT_MED, 10)
+ config_item = browser.find_by_name(value)
+ self.ap_settings[key[0]][key[1]] = int(
+ config_item.first.checked)
+ browser.visit_persistent(self.config_page,
+ BROWSER_WAIT_MED, 10)
+ else:
+ config_item = browser.find_by_name(value)
+ if 'enable_ax' in key:
+ self.ap_settings[key] = int(config_item.first.checked)
+ elif 'bandwidth' in key:
+ self.ap_settings[key[0]][key[1]] = self.bw_mode_values[
+ self.ap_settings['enable_ax']][
+ config_item.first.value]
+ elif 'power' in key:
+ self.ap_settings[key[0]][
+ key[1]] = self.power_mode_values[
+ config_item.first.value]
+ elif 'region' in key:
+ self.ap_settings['region'] = self.region_map[
+ config_item.first.value]
+ elif 'security_type' in key:
+ for item in config_item:
+ if item.checked:
+ self.ap_settings[key[0]][key[1]] = item.value
+ elif 'channel' in key:
+ config_item = browser.find_by_name(value)
+ self.ap_settings[key[0]][key[1]] = int(
+ config_item.first.value)
+ else:
+ config_item = browser.find_by_name(value)
+ self.ap_settings[key[0]][
+ key[1]] = config_item.first.value
+ return self.ap_settings.copy()
+
+ def configure_ap(self, **config_flags):
+ """Function to configure ap wireless settings."""
+ # Turn radios on or off
+ if config_flags['status_toggled']:
+ self.configure_radio_on_off()
+ # Configure radios
+ with BlockingBrowser(self.ap_settings['headless_browser'],
+ 900) as browser:
+ # Visit URL
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page_nologin,
+ BROWSER_WAIT_MED, 10, self.config_page)
+
+ # Update region, and power/bandwidth for each network
+ try:
+ config_item = browser.find_by_name(
+ self.config_page_fields['region']).first
+ config_item.select_by_text(self.ap_settings['region'])
+ except:
+ self.log.warning('Cannot change region.')
+ for key, value in self.config_page_fields.items():
+ if 'enable_ax' in key:
+ config_item = browser.find_by_name(value).first
+ if self.ap_settings['enable_ax']:
+ config_item.check()
+ else:
+ config_item.uncheck()
+ if 'power' in key:
+ config_item = browser.find_by_name(value).first
+ config_item.select_by_text(
+ self.ap_settings[key[0]][key[1]])
+ elif 'bandwidth' in key:
+ config_item = browser.find_by_name(value).first
+ try:
+ config_item.select_by_text(self.bw_mode_text[key[0]][
+ self.ap_settings[key[0]][key[1]]])
+ except AttributeError:
+ self.log.warning(
+ 'Cannot select bandwidth. Keeping AP default.')
+
+ # Update security settings (passwords updated only if applicable)
+ for key, value in self.config_page_fields.items():
+ if 'security_type' in key:
+ browser.choose(value, self.ap_settings[key[0]][key[1]])
+ if 'WPA' in self.ap_settings[key[0]][key[1]]:
+ config_item = browser.find_by_name(
+ self.config_page_fields[(key[0],
+ 'password')]).first
+ config_item.fill(self.ap_settings[key[0]]['password'])
+
+ for key, value in self.config_page_fields.items():
+ if 'ssid' in key:
+ config_item = browser.find_by_name(value).first
+ config_item.fill(self.ap_settings[key[0]][key[1]])
+ elif 'channel' in key:
+ config_item = browser.find_by_name(value).first
+ try:
+ config_item.select(self.ap_settings[key[0]][key[1]])
+ time.sleep(BROWSER_WAIT_SHORT)
+ except AttributeError:
+ self.log.warning(
+ 'Cannot select channel. Keeping AP default.')
+ try:
+ alert = browser.get_alert()
+ alert.accept()
+ except:
+ pass
+ time.sleep(BROWSER_WAIT_SHORT)
+ browser.find_by_name('Apply').first.click()
+ time.sleep(BROWSER_WAIT_SHORT)
+ try:
+ alert = browser.get_alert()
+ alert.accept()
+ time.sleep(BROWSER_WAIT_SHORT)
+ except:
+ time.sleep(BROWSER_WAIT_SHORT)
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_EXTRA_LONG,
+ 10)
+
+ def configure_radio_on_off(self):
+ """Helper configuration function to turn radios on/off."""
+ with BlockingBrowser(self.ap_settings['headless_browser'],
+ 900) as browser:
+ # Visit URL
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page_advanced,
+ BROWSER_WAIT_MED, 10)
+
+ # Turn radios on or off
+ for key, value in self.config_page_fields.items():
+ if 'status' in key:
+ config_item = browser.find_by_name(value).first
+ if self.ap_settings[key[0]][key[1]]:
+ config_item.check()
+ else:
+ config_item.uncheck()
+
+ time.sleep(BROWSER_WAIT_SHORT)
+ browser.find_by_name('Apply').first.click()
+ time.sleep(BROWSER_WAIT_EXTRA_LONG)
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_EXTRA_LONG,
+ 10)
diff --git a/acts_tests/acts_contrib/test_utils/wifi/wifi_test_utils.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_test_utils.py
index 420afb8..c29ce5c 100755
--- a/acts_tests/acts_contrib/test_utils/wifi/wifi_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/wifi/wifi_test_utils.py
@@ -439,6 +439,14 @@
165: 5825
}
+ channel_6G_to_freq = {4 * x + 1: 5955 + 20 * x for x in range(59)}
+
+ channel_to_freq = {
+ '2G': channel_2G_to_freq,
+ '5G': channel_5G_to_freq,
+ '6G': channel_6G_to_freq
+ }
+
class WifiChannelBase:
ALL_2G_FREQUENCIES = []
@@ -744,6 +752,7 @@
"Failed to remove these configured Wi-Fi networks: %s" % networks)
+
def toggle_airplane_mode_on_and_off(ad):
"""Turn ON and OFF Airplane mode.
@@ -909,13 +918,18 @@
True: if network_ssid is found in scan results.
False: if network_ssid is not found in scan results.
"""
+ start_time = time.time()
for num_tries in range(max_tries):
if start_wifi_connection_scan_and_return_status(ad):
scan_results = ad.droid.wifiGetScanResults()
match_results = match_networks({WifiEnums.SSID_KEY: network_ssid},
scan_results)
if len(match_results) > 0:
+ ad.log.debug("Found network in %s seconds." %
+ (time.time() - start_time))
return True
+ ad.log.debug("Did not find network in %s seconds." %
+ (time.time() - start_time))
return False
@@ -1466,11 +1480,9 @@
ad.droid.wifiStopTrackingStateChange()
-def connect_to_wifi_network(ad,
- network,
- assert_on_fail=True,
- check_connectivity=True,
- hidden=False):
+def connect_to_wifi_network(ad, network, assert_on_fail=True,
+ check_connectivity=True, hidden=False,
+ num_of_scan_tries=3, num_of_connect_tries=3):
"""Connection logic for open and psk wifi networks.
Args:
@@ -1479,16 +1491,20 @@
assert_on_fail: If true, errors from wifi_connect will raise
test failure signals.
hidden: Is the Wifi network hidden.
+ num_of_scan_tries: The number of times to try scan
+ interface before declaring failure.
+ num_of_connect_tries: The number of times to try
+ connect wifi before declaring failure.
"""
if hidden:
start_wifi_connection_scan_and_ensure_network_not_found(
- ad, network[WifiEnums.SSID_KEY])
+ ad, network[WifiEnums.SSID_KEY], max_tries=num_of_scan_tries)
else:
start_wifi_connection_scan_and_ensure_network_found(
- ad, network[WifiEnums.SSID_KEY])
+ ad, network[WifiEnums.SSID_KEY], max_tries=num_of_scan_tries)
wifi_connect(ad,
network,
- num_of_tries=3,
+ num_of_tries=num_of_connect_tries,
assert_on_fail=assert_on_fail,
check_connectivity=check_connectivity)
@@ -1705,7 +1721,8 @@
# Need a delay here because UI interaction should only start once wifi
# starts processing the request.
time.sleep(wifi_constants.NETWORK_REQUEST_CB_REGISTER_DELAY_SEC)
- _wait_for_wifi_connect_after_network_request(ad, network, key, num_of_tries)
+ _wait_for_wifi_connect_after_network_request(ad, network, key,
+ num_of_tries)
return key
@@ -1741,7 +1758,10 @@
assert_on_fail, ad, network, key, num_of_tries)
-def _wait_for_wifi_connect_after_network_request(ad, network, key, num_of_tries=3):
+def _wait_for_wifi_connect_after_network_request(ad,
+ network,
+ key,
+ num_of_tries=3):
"""
Simulate and verify the connection flow after initiating the network
request.
@@ -1793,13 +1813,11 @@
# Wait for the platform to connect to the network.
autils.wait_for_event_with_keys(
- ad, cconsts.EVENT_NETWORK_CALLBACK,
- 60,
+ ad, cconsts.EVENT_NETWORK_CALLBACK, 60,
(cconsts.NETWORK_CB_KEY_ID, key),
(cconsts.NETWORK_CB_KEY_EVENT, cconsts.NETWORK_CB_AVAILABLE))
on_capabilities_changed = autils.wait_for_event_with_keys(
- ad, cconsts.EVENT_NETWORK_CALLBACK,
- 10,
+ ad, cconsts.EVENT_NETWORK_CALLBACK, 10,
(cconsts.NETWORK_CB_KEY_ID, key),
(cconsts.NETWORK_CB_KEY_EVENT,
cconsts.NETWORK_CB_CAPABILITIES_CHANGED))
@@ -1816,8 +1834,7 @@
asserts.assert_equal(
connected_network[WifiEnums.SSID_KEY], expected_ssid,
"Connected to the wrong network."
- "Expected %s, but got %s."
- % (network, connected_network))
+ "Expected %s, but got %s." % (network, connected_network))
except Empty:
asserts.fail("Failed to connect to %s" % expected_ssid)
except Exception as error:
diff --git a/acts_tests/acts_contrib/test_utils_tests/audio_analysis_integrationtest.py b/acts_tests/acts_contrib/test_utils_tests/audio_analysis_integrationtest.py
index a00a431..eb56f20 100644
--- a/acts_tests/acts_contrib/test_utils_tests/audio_analysis_integrationtest.py
+++ b/acts_tests/acts_contrib/test_utils_tests/audio_analysis_integrationtest.py
@@ -21,11 +21,6 @@
import os
import unittest
-# TODO(markdr): Remove this after soundfile is added to setup.py
-import sys
-import mock
-sys.modules['soundfile'] = mock.Mock()
-
import acts_contrib.test_utils.audio_analysis_lib.audio_analysis as audio_analysis
import acts_contrib.test_utils.audio_analysis_lib.audio_data as audio_data
diff --git a/acts_tests/acts_contrib/test_utils_tests/audio_quality_measurement_integrationtest.py b/acts_tests/acts_contrib/test_utils_tests/audio_quality_measurement_integrationtest.py
index 396e5b8..c8b4f25 100644
--- a/acts_tests/acts_contrib/test_utils_tests/audio_quality_measurement_integrationtest.py
+++ b/acts_tests/acts_contrib/test_utils_tests/audio_quality_measurement_integrationtest.py
@@ -22,11 +22,6 @@
import numpy
import unittest
-# TODO(markdr): Remove this after soundfile is added to setup.py
-import sys
-import mock
-sys.modules['soundfile'] = mock.Mock()
-
import acts_contrib.test_utils.audio_analysis_lib.audio_quality_measurement as audio_quality_measurement
diff --git a/acts_tests/setup.py b/acts_tests/setup.py
index 592fcee..b2c3151 100755
--- a/acts_tests/setup.py
+++ b/acts_tests/setup.py
@@ -30,9 +30,20 @@
acts_tests_dir = os.path.abspath(os.path.dirname(__file__))
-install_requires = []
+install_requires = ['soundfile']
-
+if sys.version_info < (3, 6):
+ # Python <= 3.5 uses bokeh up to 1.4.x
+ install_requires.append('bokeh<1.5')
+elif sys.version_info < (3, 7):
+ # Python 3.6 uses bokeh up to 2.3.x
+ install_requires.append('bokeh<2.4')
+elif sys.version_info < (3, 8):
+ # Python 3.7+ uses bokeh up to 2.4.x
+ install_requires.append('bokeh<2.5')
+else:
+ # Python 3.8+ is support by latest bokeh
+ install_requires.append('bokeh')
def _setup_acts_framework(option, *args):
"""Locates and runs setup.py for the ACTS framework.
@@ -68,9 +79,13 @@
Otherwise, it will attempt to locate the ACTS framework from the local
repository.
"""
+
def run(self):
- super().run()
_setup_acts_framework('install')
+ # Calling install.run() directly fails to install the dependencies as
+ # listed in install_requires. Use install.do_egg_install() instead.
+ # Ref: https://stackoverflow.com/questions/21915469
+ self.do_egg_install()
class ActsContribDevelop(develop):
@@ -78,6 +93,7 @@
See ActsContribInstall for more details.
"""
+
def run(self):
super().run()
if self.uninstall:
@@ -142,8 +158,9 @@
acts_contrib_module: The acts_contrib module to uninstall.
"""
for acts_contrib_install_dir in acts_contrib_module.__path__:
- self.announce('Deleting acts_contrib from: %s'
- % acts_contrib_install_dir, log.INFO)
+ self.announce(
+ 'Deleting acts_contrib from: %s' % acts_contrib_install_dir,
+ log.INFO)
shutil.rmtree(acts_contrib_install_dir)
def run(self):
@@ -160,8 +177,9 @@
try:
import acts_contrib as acts_contrib_module
except ImportError:
- self.announce('acts_contrib is not installed, nothing to uninstall.',
- level=log.ERROR)
+ self.announce(
+ 'acts_contrib is not installed, nothing to uninstall.',
+ level=log.ERROR)
return
while acts_contrib_module:
@@ -180,7 +198,7 @@
def main():
os.chdir(acts_tests_dir)
- packages = setuptools.find_packages(include=('acts_contrib*',))
+ packages = setuptools.find_packages(include=('acts_contrib*', ))
setuptools.setup(name='acts_contrib',
version='0.9',
description='Android Comms Test Suite',
diff --git a/acts_tests/tests/OWNERS b/acts_tests/tests/OWNERS
index c38e234..3f4ab0f 100644
--- a/acts_tests/tests/OWNERS
+++ b/acts_tests/tests/OWNERS
@@ -20,12 +20,21 @@
jerrypcchen@google.com
martschneider@google.com
timhuang@google.com
+sishichen@google.com
# Fuchsia
+belgum@google.com
+chcl@google.com
+dhobsd@google.com
haydennix@google.com
jmbrenna@google.com
-#mrwifi@google.com
+nmccracken@google.com
+mnck@google.com
+nickchee@google.com
+sakuma@google.com
+silberst@google.com
tturney@google.com
+sbalana@google.com
# TechEng
abhinavjadon@google.com
diff --git a/acts_tests/tests/google/ble/api/BleAdvertiseApiTest.py b/acts_tests/tests/google/ble/api/BleAdvertiseApiTest.py
index c044b4d..877b00e 100644
--- a/acts_tests/tests/google/ble/api/BleAdvertiseApiTest.py
+++ b/acts_tests/tests/google/ble/api/BleAdvertiseApiTest.py
@@ -20,13 +20,16 @@
then other test suites utilising Ble Advertisements will also fail.
"""
+import pprint
+
from acts.controllers.sl4a_lib import rpc_client
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
-from acts_contrib.test_utils.bt.bt_test_utils import adv_fail
+from acts_contrib.test_utils.bt.bt_test_utils import adv_fail, adv_succ, scan_result
from acts_contrib.test_utils.bt.bt_test_utils import generate_ble_advertise_objects
from acts_contrib.test_utils.bt.bt_constants import ble_advertise_settings_modes
from acts_contrib.test_utils.bt.bt_constants import ble_advertise_settings_tx_powers
+# from acts_contrib.test_utils.bt.bt_constants import ble_advertise_settings_own_address_types
from acts_contrib.test_utils.bt.bt_constants import java_integer
@@ -38,6 +41,7 @@
def setup_class(self):
super().setup_class()
self.ad_dut = self.android_devices[0]
+ self.sc_dut = self.android_devices[1]
@BluetoothBaseTest.bt_test_wrap
@test_tracker_info(uuid='d6d8d0a6-7b3e-4e4b-a5d0-bcfd6e207474')
@@ -498,6 +502,149 @@
exp_is_connectable)
@BluetoothBaseTest.bt_test_wrap
+ def test_adv_settings_set_adv_own_address_type_public(self):
+ """Tests advertise settings own address type public.
+
+ This advertisement settings from "set" advertisement own address type
+ should match the corresponding "get" function.
+
+ Steps:
+ 1. Build a new advertise settings object.
+ 2. Set the advertise mode attribute to own address type public.
+ 3. Get the attributes of the advertise settings object.
+ 4. Compare the attributes found against the attributes exp.
+
+ Expected Result:
+ Found attributes should match expected attributes.
+
+ Returns:
+ True is pass
+ False if fail
+
+ TAGS: LE, Advertising
+ Priority: 1
+ """
+ self.log.debug("Step 1: Setup environment.")
+ droid = self.ad_dut.droid
+ # exp_adv_own_address_type = ble_advertise_settings_own_address_types['public']
+ exp_adv_own_address_type = 0
+ self.log.debug(
+ "Step 2: Set the filtering settings object's value to {}".format(
+ exp_adv_own_address_type))
+ return self.verify_adv_settings_own_address_type(droid, exp_adv_own_address_type)
+
+ @BluetoothBaseTest.bt_test_wrap
+ def test_adv_settings_set_adv_own_address_type_random(self):
+ """Tests advertise settings own address type random.
+
+ This advertisement settings from "set" advertisement own address type
+ should match the corresponding "get" function.
+
+ Steps:
+ 1. Build a new advertise settings object.
+ 2. Set the advertise mode attribute to own address type random.
+ 3. Get the attributes of the advertise settings object.
+ 4. Compare the attributes found against the attributes exp.
+
+ Expected Result:
+ Found attributes should match expected attributes.
+
+ Returns:
+ True is pass
+ False if fail
+
+ TAGS: LE, Advertising
+ Priority: 1
+ """
+ self.log.debug("Step 1: Setup environment.")
+ droid = self.ad_dut.droid
+ # exp_adv_own_address_type = ble_advertise_settings_own_address_types['random']
+ exp_adv_own_address_type = 1
+ self.log.debug(
+ "Step 2: Set the filtering settings object's value to {}".format(
+ exp_adv_own_address_type))
+ return self.verify_adv_settings_own_address_type(droid, exp_adv_own_address_type)
+
+ @BluetoothBaseTest.bt_test_wrap
+ def test_adv_with_multiple_own_address_types(self):
+ ad_droid = self.ad_dut.droid
+ sc_droid = self.sc_dut.droid
+ sc_ed = self.sc_dut.ed
+ adv_count = 10
+ exp_adv_own_address_types = [0, 1, 1, 0, 0, 1, 1, 1, 0, 0]
+ uuid = '01234567-89ab-cdef-0123-456789abcdef'
+ service_data = []
+
+ for i in range(3):
+ service_data.append(i)
+
+ for own_add_type in exp_adv_own_address_types:
+ result = self.verify_adv_set_address_type_start_adv(ad_droid,
+ own_add_type, uuid, service_data)
+ if result is False:
+ return False
+
+ mac_list = []
+
+ filter_list = sc_droid.bleGenFilterList()
+ scan_settings = sc_droid.bleBuildScanSetting()
+ scan_callback = sc_droid.bleGenScanCallback()
+ sc_droid.bleStartBleScan(filter_list, scan_settings,
+ scan_callback)
+ event_name = scan_result.format(scan_callback)
+ self.log.info("Scan onSuccess Event")
+
+ for _ in range(1000):
+ if len(mac_list) is adv_count:
+ break
+
+ try:
+ event = sc_ed.pop_event(event_name, 10)
+ result = event['data']['Result']
+ deviceInfo = result['deviceInfo']
+ serviceUuidList = result['serviceUuidList']
+ if uuid in serviceUuidList:
+ mac_addr = deviceInfo['address']
+ if mac_addr not in mac_list:
+ self.log.info("Found device. address: {}".format(mac_addr))
+ mac_list.append(mac_addr)
+
+ except rpc_client.Sl4aApiError:
+ self.log.info("{} event was not found.".format(event_name))
+ break
+
+ return len(mac_list) is adv_count
+
+ @BluetoothBaseTest.bt_test_wrap
+ def test_adv_settings_set_invalid_adv_own_address_type(self):
+ """Tests advertise settings invalid own address type.
+
+ This advertisement settings from "set" advertisement own address type
+ should match the corresponding "get" function.
+
+ Steps:
+ 1. Build a new advertise settings object.
+ 2. Set the advertise mode attribute to invalid own address type.
+ 3. Get the attributes of the advertise settings object.
+ 4. Compare the attributes found against the attributes exp.
+
+ Expected Result:
+ Found attributes should match expected attributes.
+
+ Returns:
+ True is pass
+ False if fail
+
+ TAGS: LE, Advertising
+ Priority: 1
+ """
+ self.log.debug("Step 1: Setup environment.")
+ droid = self.ad_dut.droid
+ exp_adv_own_address_type = -100
+ self.log.debug("Step 2: Set the filtering settings own address type to -1")
+ return self.verify_invalid_adv_settings_own_address_type(droid, exp_adv_own_address_type)
+
+ @BluetoothBaseTest.bt_test_wrap
@test_tracker_info(uuid='a770ed7e-c6cd-4533-8876-e42e68f8b4fb')
def test_adv_data_set_service_uuids_empty(self):
"""Tests advertisement data's service uuids to empty.
@@ -1095,6 +1242,55 @@
" value test Passed.".format(exp_is_connectable))
return True
+ def verify_adv_settings_own_address_type(self, droid, exp_adv_own_address_type):
+ try:
+ droid.bleSetAdvertiseSettingsOwnAddressType(exp_adv_own_address_type)
+ except BleAdvertiseVerificationError as error:
+ self.log.debug(str(error))
+ return False
+ self.log.debug("Step 3: Get a filtering settings object's index.")
+ settings_index = droid.bleBuildAdvertiseSettings()
+ self.log.debug("Step 4: Get the filtering setting's own address type.")
+ adv_own_address_type = droid.bleGetAdvertiseSettingsOwnAddressType(
+ settings_index)
+ if exp_adv_own_address_type is not adv_own_address_type:
+ self.log.debug("exp value: {}, Actual value: {}".format(
+ exp_adv_own_address_type, adv_own_address_type))
+ return False
+ self.log.debug("Advertise Setting's own address type {}"
+ " value test Passed.".format(exp_adv_own_address_type))
+ return True
+
+ def verify_adv_set_address_type_start_adv(self, droid, own_address_type, uuid, service_data):
+ try:
+ droid.bleSetAdvertiseSettingsOwnAddressType(own_address_type)
+ except BleAdvertiseVerificationError as error:
+ self.log.debug(str(error))
+ return False
+
+ droid.bleAddAdvertiseDataServiceData(
+ uuid, service_data)
+ advcallback, adv_data, adv_settings = generate_ble_advertise_objects(
+ droid)
+ droid.bleStartBleAdvertising(advcallback, adv_data, adv_settings)
+
+ adv_own_address_type = droid.bleGetAdvertiseSettingsOwnAddressType(
+ adv_settings)
+ if own_address_type is not adv_own_address_type:
+ self.log.debug("exp value: {}, Actual value: {}".format(
+ own_address_type, adv_own_address_type))
+ return False
+
+ try:
+ event = self.android_devices[0].ed.pop_event(adv_succ.format(advcallback), 10)
+ self.log.info("Ble Advertise Success Event: {}".format(event))
+ except rpc_client.Sl4aApiError:
+ self.log.info("{} event was not found.".format(
+ adv_succ.format(advcallback)))
+ return False
+
+ return True
+
def verify_adv_data_service_uuids(self, droid, exp_service_uuids):
try:
droid.bleSetAdvertiseDataSetServiceUuids(exp_service_uuids)
@@ -1227,6 +1423,20 @@
"failed successfullywith input as {}".format(exp_adv_tx_power))
return True
+ def verify_invalid_adv_settings_own_address_type(self, droid,
+ exp_adv_own_address_type):
+ try:
+ droid.bleSetAdvertiseSettingsOwnAddressType(exp_adv_own_address_type)
+ droid.bleBuildAdvertiseSettings()
+ self.log.debug("Set Advertise settings invalid own address type " +
+ " with input as {}".format(exp_adv_own_address_type))
+ return False
+ except rpc_client.Sl4aApiError:
+ self.log.debug(
+ "Set Advertise settings invalid own address type "
+ "failed successfully with input as {}".format(exp_adv_own_address_type))
+ return True
+
def verify_invalid_adv_data_service_uuids(self, droid, exp_service_uuids):
try:
droid.bleSetAdvertiseDataSetServiceUuids(exp_service_uuids)
diff --git a/acts_tests/tests/google/ble/concurrency/ConcurrentGattConnectTest.py b/acts_tests/tests/google/ble/concurrency/ConcurrentGattConnectTest.py
index 6a5b861..4162b23 100644
--- a/acts_tests/tests/google/ble/concurrency/ConcurrentGattConnectTest.py
+++ b/acts_tests/tests/google/ble/concurrency/ConcurrentGattConnectTest.py
@@ -141,14 +141,14 @@
if adv_name in item
]
devices_found.append(device[0][0].serial)
- if len(device) is not 0:
+ if len(device) != 0:
address_list_tuple = (device[0][0], mac_address)
else:
continue
result = [item for item in address_list if mac_address in item]
# if length of result is 0, it indicates that we have discovered
# new mac address.
- if len(result) is 0:
+ if len(result) == 0:
self.log.info("Found new mac address: {}".format(
address_list_tuple[1]))
address_list.append(address_list_tuple)
diff --git a/acts_tests/tests/google/ble/performance/BleRangeTest.py b/acts_tests/tests/google/ble/performance/BleRangeTest.py
new file mode 100644
index 0000000..3473cef
--- /dev/null
+++ b/acts_tests/tests/google/ble/performance/BleRangeTest.py
@@ -0,0 +1,289 @@
+#!/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.
+"""
+Test script to execute BLE connection,run data traffic and calculating RSSI value of the remote BLE device.
+"""
+
+import os
+import logging
+import pandas as pd
+import numpy as np
+import time
+import acts_contrib.test_utils.bt.bt_test_utils as btutils
+import acts_contrib.test_utils.wifi.wifi_performance_test_utils.bokeh_figure as bokeh_figure
+from acts_contrib.test_utils.bt.ble_performance_test_utils import ble_coc_connection
+from acts_contrib.test_utils.bt.ble_performance_test_utils import ble_gatt_disconnection
+from acts_contrib.test_utils.bt.ble_performance_test_utils import start_advertising_and_scanning
+from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
+from acts_contrib.test_utils.bt.bt_test_utils import cleanup_scanners_and_advertisers
+from acts_contrib.test_utils.bt.ble_performance_test_utils import establish_ble_connection
+from acts_contrib.test_utils.bt.bt_constants import l2cap_max_inactivity_delay_after_disconnect
+from acts_contrib.test_utils.bt.ble_performance_test_utils import run_ble_throughput
+from acts_contrib.test_utils.bt.ble_performance_test_utils import read_ble_rssi
+from acts_contrib.test_utils.bt.ble_performance_test_utils import read_ble_scan_rssi
+from acts_contrib.test_utils.bt.bt_test_utils import reset_bluetooth
+from acts_contrib.test_utils.power.PowerBTBaseTest import ramp_attenuation
+from acts_contrib.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
+from acts.signals import TestPass
+from acts import utils
+
+INIT_ATTEN = 0
+MAX_RSSI = 92
+
+
+class BleRangeTest(BluetoothBaseTest):
+ active_adv_callback_list = []
+ active_scan_callback_list = []
+
+ def __init__(self, configs):
+ super().__init__(configs)
+ req_params = ['attenuation_vector', 'system_path_loss']
+ #'attenuation_vector' is a dict containing: start, stop and step of
+ #attenuation changes
+ self.unpack_userparams(req_params)
+
+ def setup_class(self):
+ super().setup_class()
+ self.client_ad = self.android_devices[0]
+ # The client which is scanning will need location to be enabled in order to
+ # start scan and get scan results.
+ utils.set_location_service(self.client_ad, True)
+ self.server_ad = self.android_devices[1]
+ # Note that some tests required a third device.
+ if hasattr(self, 'attenuators'):
+ self.attenuator = self.attenuators[0]
+ self.attenuator.set_atten(INIT_ATTEN)
+ self.attenuation_range = range(self.attenuation_vector['start'],
+ self.attenuation_vector['stop'] + 1,
+ self.attenuation_vector['step'])
+ self.log_path = os.path.join(logging.log_path, 'results')
+ os.makedirs(self.log_path, exist_ok=True)
+ # BokehFigure object
+ self.plot = bokeh_figure.BokehFigure(
+ title='{}'.format(self.current_test_name),
+ x_label='Pathloss (dB)',
+ primary_y_label='BLE RSSI (dBm)',
+ secondary_y_label='DUT Tx Power (dBm)',
+ axis_label_size='16pt')
+ if len(self.android_devices) > 2:
+ self.server2_ad = self.android_devices[2]
+
+ btutils.enable_bqr(self.android_devices)
+ return setup_multiple_devices_for_bt_test(self.android_devices)
+
+ def teardown_test(self):
+ self.client_ad.droid.bluetoothSocketConnStop()
+ self.server_ad.droid.bluetoothSocketConnStop()
+ if hasattr(self, 'attenuator'):
+ self.attenuator.set_atten(INIT_ATTEN)
+ # Give sufficient time for the physical LE link to be disconnected.
+ time.sleep(l2cap_max_inactivity_delay_after_disconnect)
+ cleanup_scanners_and_advertisers(self.client_ad,
+ self.active_scan_callback_list,
+ self.server_ad,
+ self.active_adv_callback_list)
+
+ def test_ble_gatt_connection_range(self):
+ """Test GATT connection over LE and read RSSI.
+
+ Test will establish a gatt connection between a GATT server and GATT
+ client then read the RSSI for each attenuation until the BLE link get disconnect
+
+ Expected Result:
+ Verify that a connection was established and then disconnected
+ successfully. Verify that the RSSI was read correctly.
+
+ """
+ attenuation = []
+ ble_rssi = []
+ dut_pwlv = []
+ path_loss = []
+ bluetooth_gatt, gatt_callback, adv_callback, gatt_server = establish_ble_connection(
+ self.client_ad, self.server_ad)
+ for atten in self.attenuation_range:
+ ramp_attenuation(self.attenuator, atten)
+ self.log.info('Set attenuation to %d dB', atten)
+ rssi_primary, pwlv_primary = self.get_ble_rssi_and_pwlv()
+ self.log.info(
+ "Dut BLE RSSI:{} and Pwlv:{} with attenuation:{}".format(
+ rssi_primary, pwlv_primary, atten))
+ rssi = self.client_ad.droid.gattClientReadRSSI(gatt_server)
+ if type(rssi_primary) != str:
+ attenuation.append(atten)
+ ble_rssi.append(rssi_primary)
+ dut_pwlv.append(pwlv_primary)
+ path_loss.append(atten + self.system_path_loss)
+ df = pd.DataFrame({
+ 'Attenuation': attenuation,
+ 'BLE_RSSI': ble_rssi,
+ 'Dut_PwLv': dut_pwlv,
+ 'Pathloss': path_loss
+ })
+ filepath = os.path.join(
+ self.log_path, '{}.csv'.format(self.current_test_name))
+ else:
+ self.plot_ble_graph(df)
+ df.to_csv(filepath, encoding='utf-8')
+ raise TestPass('Reached BLE Max Range, BLE Gatt disconnected')
+ ble_gatt_disconnection(self.client_ad, bluetooth_gatt, gatt_callback)
+ self.plot_ble_graph(df)
+ df.to_csv(filepath, encoding='utf-8')
+ self.server_ad.droid.bleStopBleAdvertising(adv_callback)
+ return True
+
+ def test_ble_coc_throughput_range(self):
+ """Test LE CoC data transfer and read RSSI with each attenuation
+
+ Test will establish a L2CAP CoC connection between client and server
+ then start BLE date transfer and read the RSSI for each attenuation
+ until the BLE link get disconnect
+
+ Expected Result:
+ BLE data transfer successful and Read RSSi Value of the server
+
+ """
+ attenuation = []
+ ble_rssi = []
+ throughput = []
+ dut_pwlv = []
+ path_loss = []
+ self.plot_throughput = bokeh_figure.BokehFigure(
+ title='{}'.format(self.current_test_name),
+ x_label='Pathloss (dB)',
+ primary_y_label='BLE Throughput (bits per sec)',
+ axis_label_size='16pt')
+ status, gatt_callback, gatt_server, bluetooth_gatt, client_conn_id = ble_coc_connection(
+ self.server_ad, self.client_ad)
+ for atten in self.attenuation_range:
+ ramp_attenuation(self.attenuator, atten)
+ self.log.info('Set attenuation to %d dB', atten)
+ datarate = run_ble_throughput(self.client_ad, client_conn_id,
+ self.server_ad)
+ rssi_primary, pwlv_primary = self.get_ble_rssi_and_pwlv()
+ self.log.info(
+ "BLE RSSI is:{} dBm and Tx Power:{} with attenuation {} dB with throughput:{}bits per sec"
+ .format(rssi_primary, pwlv_primary, atten, datarate))
+ if type(rssi_primary) != str:
+ attenuation.append(atten)
+ ble_rssi.append(rssi_primary)
+ dut_pwlv.append(pwlv_primary)
+ throughput.append(datarate)
+ path_loss.append(atten + self.system_path_loss)
+ df = pd.DataFrame({
+ 'Attenuation': attenuation,
+ 'BLE_RSSI': ble_rssi,
+ 'Dut_PwLv': dut_pwlv,
+ 'Throughput': throughput,
+ 'Pathloss': path_loss
+ })
+ filepath = os.path.join(
+ self.log_path, '{}.csv'.format(self.current_test_name))
+ results_file_path = os.path.join(
+ self.log_path,
+ '{}_throughput.html'.format(self.current_test_name))
+ self.plot_throughput.add_line(df['Pathloss'],
+ df['Throughput'],
+ legend='BLE Throughput',
+ marker='square_x')
+ else:
+ self.plot_ble_graph(df)
+ self.plot_throughput.generate_figure()
+ bokeh_figure.BokehFigure.save_figures([self.plot_throughput],
+ results_file_path)
+ df.to_csv(filepath, encoding='utf-8')
+ raise TestPass('Reached BLE Max Range, BLE Gatt disconnected')
+ self.plot_ble_graph(df)
+ self.plot_throughput.generate_figure()
+ bokeh_figure.BokehFigure.save_figures([self.plot_throughput],
+ results_file_path)
+ df.to_csv(filepath, encoding='utf-8')
+ ble_gatt_disconnection(self.server_ad, bluetooth_gatt, gatt_callback)
+ return True
+
+ def test_ble_scan_remote_rssi(self):
+ data_points = []
+ for atten in self.attenuation_range:
+ csv_path = os.path.join(
+ self.log_path,
+ '{}_attenuation_{}.csv'.format(self.current_test_name, atten))
+ ramp_attenuation(self.attenuator, atten)
+ self.log.info('Set attenuation to %d dB', atten)
+ adv_callback, scan_callback = start_advertising_and_scanning(
+ self.client_ad, self.server_ad, Legacymode=False)
+ self.active_adv_callback_list.append(adv_callback)
+ self.active_scan_callback_list.append(scan_callback)
+ average_rssi, raw_rssi, timestamp = read_ble_scan_rssi(
+ self.client_ad, scan_callback)
+ self.log.info(
+ "Scanned rssi list of the remote device is :{}".format(
+ raw_rssi))
+ self.log.info(
+ "BLE RSSI of the remote device is:{} dBm".format(average_rssi))
+ min_rssi = min(raw_rssi)
+ max_rssi = max(raw_rssi)
+ path_loss = atten + self.system_path_loss
+ std_deviation = np.std(raw_rssi)
+ data_point = {
+ 'Attenuation': atten,
+ 'BLE_RSSI': average_rssi,
+ 'Pathloss': path_loss,
+ 'Min_RSSI': min_rssi,
+ 'Max_RSSI': max_rssi,
+ 'Standard_deviation': std_deviation
+ }
+ data_points.append(data_point)
+ df = pd.DataFrame({'timestamp': timestamp, 'raw rssi': raw_rssi})
+ df.to_csv(csv_path, encoding='utf-8', index=False)
+ try:
+ self.server_ad.droid.bleAdvSetStopAdvertisingSet(adv_callback)
+ except Exception as err:
+ self.log.warning(
+ "Failed to stop advertisement: {}".format(err))
+ reset_bluetooth([self.server_ad])
+ self.client_ad.droid.bleStopBleScan(scan_callback)
+ filepath = os.path.join(
+ self.log_path, '{}_summary.csv'.format(self.current_test_name))
+ ble_df = pd.DataFrame(data_points)
+ ble_df.to_csv(filepath, encoding='utf-8')
+ return True
+
+ def plot_ble_graph(self, df):
+ """ Plotting BLE RSSI and Throughput with Attenuation.
+
+ Args:
+ df: Summary of results contains attenuation, BLE_RSSI and Throughput
+ """
+ self.plot.add_line(df['Pathloss'],
+ df['BLE_RSSI'],
+ legend='DUT BLE RSSI (dBm)',
+ marker='circle_x')
+ self.plot.add_line(df['Pathloss'],
+ df['Dut_PwLv'],
+ legend='DUT TX Power (dBm)',
+ marker='hex',
+ y_axis='secondary')
+ results_file_path = os.path.join(
+ self.log_path, '{}.html'.format(self.current_test_name))
+ self.plot.generate_figure()
+ bokeh_figure.BokehFigure.save_figures([self.plot], results_file_path)
+
+ def get_ble_rssi_and_pwlv(self):
+ process_data_dict = btutils.get_bt_metric(self.client_ad)
+ rssi_primary = process_data_dict.get('rssi')
+ pwlv_primary = process_data_dict.get('pwlv')
+ rssi_primary = rssi_primary.get(self.client_ad.serial)
+ pwlv_primary = pwlv_primary.get(self.client_ad.serial)
+ return rssi_primary, pwlv_primary
diff --git a/acts_tests/tests/google/bt/car_bt/BtCarHfpConferenceTest.py b/acts_tests/tests/google/bt/car_bt/BtCarHfpConferenceTest.py
index edb9683..5611de3 100644
--- a/acts_tests/tests/google/bt/car_bt/BtCarHfpConferenceTest.py
+++ b/acts_tests/tests/google/bt/car_bt/BtCarHfpConferenceTest.py
@@ -26,9 +26,9 @@
from acts_contrib.test_utils.bt import bt_test_utils
from acts_contrib.test_utils.car import car_telecom_utils
from acts_contrib.test_utils.tel import tel_defines
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_ringing_call
from acts_contrib.test_utils.tel.tel_voice_utils import get_audio_route
from acts_contrib.test_utils.tel.tel_voice_utils import set_audio_route
diff --git a/acts_tests/tests/google/bt/car_bt/BtCarHfpConnectionTest.py b/acts_tests/tests/google/bt/car_bt/BtCarHfpConnectionTest.py
index bda7e88..e0ea79e 100644
--- a/acts_tests/tests/google/bt/car_bt/BtCarHfpConnectionTest.py
+++ b/acts_tests/tests/google/bt/car_bt/BtCarHfpConnectionTest.py
@@ -27,9 +27,9 @@
from acts_contrib.test_utils.car import car_bt_utils
from acts_contrib.test_utils.car import car_telecom_utils
from acts_contrib.test_utils.tel import tel_defines
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
BLUETOOTH_PKG_NAME = "com.android.bluetooth"
CALL_TYPE_OUTGOING = "CALL_TYPE_OUTGOING"
diff --git a/acts_tests/tests/google/bt/car_bt/BtCarPairedConnectDisconnectTest.py b/acts_tests/tests/google/bt/car_bt/BtCarPairedConnectDisconnectTest.py
index eb2a06c..82751af 100644
--- a/acts_tests/tests/google/bt/car_bt/BtCarPairedConnectDisconnectTest.py
+++ b/acts_tests/tests/google/bt/car_bt/BtCarPairedConnectDisconnectTest.py
@@ -79,9 +79,9 @@
self.car.droid.bluetoothHfpClientSetPriority(
self.ph.droid.bluetoothGetLocalAddress(),
BtEnum.BluetoothPriorityLevel.PRIORITY_OFF.value)
- self.ph.droid.bluetoothHspSetPriority(
+ self.ph.droid.bluetoothHspSetConnectionPolicy(
self.car.droid.bluetoothGetLocalAddress(),
- BtEnum.BluetoothPriorityLevel.PRIORITY_OFF.value)
+ BtEnum.BluetoothConnectionPolicy.CONNECTION_POLICY_FORBIDDEN.value)
addr = self.ph.droid.bluetoothGetLocalAddress()
if not bt_test_utils.connect_pri_to_sec(
self.car, self.ph,
diff --git a/acts_tests/tests/google/bt/performance/BtA2dpDynamicChannelTest.py b/acts_tests/tests/google/bt/performance/BtA2dpDynamicChannelTest.py
new file mode 100644
index 0000000..0ee137c
--- /dev/null
+++ b/acts_tests/tests/google/bt/performance/BtA2dpDynamicChannelTest.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+import time
+import os
+import logging
+import acts_contrib.test_utils.bt.bt_test_utils as btutils
+import acts_contrib.test_utils.coex.audio_test_utils as atu
+from acts import asserts
+from acts_contrib.test_utils.bt.A2dpBaseTest import A2dpBaseTest
+from acts.signals import TestFailure
+
+INIT_ATTEN = 0
+WAIT_TIME = 2
+
+
+class BtA2dpDynamicChannelTest(A2dpBaseTest):
+ def __init__(self, configs):
+ super().__init__(configs)
+ req_params = ['codecs', 'rssi_profile_params']
+ # 'rssi_profile_params' is a dict containing,a list of upper_bound,
+ # lower_bound attenuation values, Dwell time for RSSI and the test duration
+ # ex:- "rssi_profile_params": {
+ # "upper_bound": [15, 25],
+ # "RSSI_Dwell_time": [1, 1],
+ # "lower_bound": [35, 45],
+ # "test_duration": 30}
+ # 'codecs' is a list containing all codecs required in the tests
+ self.unpack_userparams(req_params)
+ self.upper_bound = self.rssi_profile_params['upper_bound']
+ self.lower_bound = self.rssi_profile_params['lower_bound']
+ self.dwell_time = self.rssi_profile_params['RSSI_Dwell_time']
+ for upper_bound, lower_bound, dwell_time in zip(
+ self.upper_bound, self.lower_bound, self.dwell_time):
+ for codec_config in self.codecs:
+ self.generate_test_case(codec_config, upper_bound, lower_bound,
+ dwell_time)
+
+ def setup_class(self):
+ super().setup_class()
+ # Enable BQR on all android devices
+ btutils.enable_bqr(self.android_devices)
+ self.log_path = os.path.join(logging.log_path, 'results')
+
+ def teardown_class(self):
+ super().teardown_class()
+
+ def generate_test_case(self, codec_config, upper_bound, lower_bound,
+ dwell_time):
+ def test_case_fn():
+ self.check_audio_quality_dynamic_rssi(upper_bound, lower_bound,
+ dwell_time)
+
+ test_case_name = 'test_bt_a2dp_Dynamic_channel_between_attenuation_{}dB_and_{}dB' \
+ '_codec_{}'.format(upper_bound, lower_bound, codec_config['codec_type'])
+ setattr(self, test_case_name, test_case_fn)
+
+ def check_audio_quality_dynamic_rssi(self, upper_bound, lower_bound,
+ dwell_time):
+ tag = 'Dynamic_RSSI'
+ self.media.play()
+ proc = self.audio_device.start()
+ self.inject_rssi_profile(upper_bound, lower_bound, dwell_time)
+ proc.kill()
+ time.sleep(WAIT_TIME)
+ proc.kill()
+ audio_captured = self.audio_device.stop()
+ self.media.stop()
+ self.log.info('Audio play and record stopped')
+ asserts.assert_true(audio_captured, 'Audio not recorded')
+ audio_result = atu.AudioCaptureResult(audio_captured,
+ self.audio_params)
+ thdn = audio_result.THDN(**self.audio_params['thdn_params'])
+ self.log.info('THDN is {}'.format(thdn[0]))
+ # Reading DUT RSSI to check the RSSI fluctuation from
+ # upper and lower bound attenuation values
+ self.attenuator.set_atten(upper_bound)
+ [
+ rssi_master, pwl_master, rssi_c0_master, rssi_c1_master,
+ txpw_c0_master, txpw_c1_master, bftx_master, divtx_master
+ ], [rssi_slave] = self._get_bt_link_metrics(tag)
+ rssi_l1 = rssi_master.get(self.dut.serial, -127)
+ pwlv_l1 = pwl_master.get(self.dut.serial, -127)
+ self.attenuator.set_atten(lower_bound)
+ [
+ rssi_master, pwl_master, rssi_c0_master, rssi_c1_master,
+ txpw_c0_master, txpw_c1_master, bftx_master, divtx_master
+ ], [rssi_slave] = self._get_bt_link_metrics(tag)
+ rssi_l2 = rssi_master.get(self.dut.serial, -127)
+ pwlv_l2 = pwl_master.get(self.dut.serial, -127)
+ self.log.info(
+ "DUT RSSI is fluctuating between {} and {} dBm with {}sec interval"
+ .format(rssi_l1, rssi_l2, dwell_time))
+ if thdn[0] > self.audio_params['thdn_threshold'] or thdn[0] == 0:
+ raise TestFailure('Observed audio glitches!')
+
+ def inject_rssi_profile(self, upper_bound, lower_bound, dwell_time):
+ end_time = time.time() + self.rssi_profile_params['test_duration']
+ self.log.info("Testing dynamic channel RSSI")
+ while time.time() < end_time:
+ self.attenuator.set_atten(upper_bound)
+ time.sleep(dwell_time)
+ self.attenuator.set_atten(lower_bound)
+ time.sleep(dwell_time)
diff --git a/acts_tests/tests/google/bt/performance/BtA2dpRangeTest.py b/acts_tests/tests/google/bt/performance/BtA2dpRangeTest.py
index 99e564c..c775dd7 100644
--- a/acts_tests/tests/google/bt/performance/BtA2dpRangeTest.py
+++ b/acts_tests/tests/google/bt/performance/BtA2dpRangeTest.py
@@ -13,23 +13,16 @@
# 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 pandas as pd
import acts_contrib.test_utils.bt.bt_test_utils as btutils
-import acts_contrib.test_utils.wifi.wifi_performance_test_utils as wifi_utils
from acts import asserts
-from acts_contrib.test_utils.bt import bt_constants
-from acts_contrib.test_utils.bt import BtEnum
from acts_contrib.test_utils.bt.A2dpBaseTest import A2dpBaseTest
-from acts_contrib.test_utils.bt.loggers import bluetooth_metric_logger as log
-from acts.test_utils.power.PowerBTBaseTest import ramp_attenuation
-from acts.signals import TestPass
+
+INIT_ATTEN = 0
class BtA2dpRangeTest(A2dpBaseTest):
def __init__(self, configs):
super().__init__(configs)
- self.bt_logger = log.BluetoothMetricLogger.for_test_case()
req_params = ['attenuation_vector', 'codecs']
#'attenuation_vector' is a dict containing: start, stop and step of
#attenuation changes
@@ -40,151 +33,30 @@
def setup_class(self):
super().setup_class()
+ opt_params = ['gain_mismatch', 'dual_chain']
+ self.unpack_userparams(opt_params, dual_chain=None, gain_mismatch=None)
# Enable BQR on all android devices
btutils.enable_bqr(self.android_devices)
+ if hasattr(self, 'dual_chain') and self.dual_chain == 1:
+ self.atten_c0 = self.attenuators[0]
+ self.atten_c1 = self.attenuators[1]
+ self.atten_c0.set_atten(INIT_ATTEN)
+ self.atten_c1.set_atten(INIT_ATTEN)
+
+ def teardown_class(self):
+ super().teardown_class()
+ if hasattr(self, 'atten_c0') and hasattr(self, 'atten_c1'):
+ self.atten_c0.set_atten(INIT_ATTEN)
+ self.atten_c1.set_atten(INIT_ATTEN)
def generate_test_case(self, codec_config):
def test_case_fn():
self.run_a2dp_to_max_range(codec_config)
- test_case_name = 'test_bt_a2dp_range_codec_{}'.format(
- codec_config['codec_type'])
- setattr(self, test_case_name, test_case_fn)
-
- def generate_proto(self, data_points, codec_type, sample_rate,
- bits_per_sample, channel_mode):
- """Generate a results protobuf.
-
- Args:
- data_points: list of dicts representing info to go into
- AudioTestDataPoint protobuffer message.
- codec_type: The codec type config to store in the proto.
- sample_rate: The sample rate config to store in the proto.
- bits_per_sample: The bits per sample config to store in the proto.
- channel_mode: The channel mode config to store in the proto.
- Returns:
- dict: Dictionary with key 'proto' mapping to serialized protobuf,
- 'proto_ascii' mapping to human readable protobuf info, and 'test'
- mapping to the test class name that generated the results.
- """
-
- # Populate protobuf
- test_case_proto = self.bt_logger.proto_module.BluetoothAudioTestResult(
- )
-
- for data_point in data_points:
- audio_data_proto = test_case_proto.data_points.add()
- log.recursive_assign(audio_data_proto, data_point)
-
- codec_proto = test_case_proto.a2dp_codec_config
- codec_proto.codec_type = bt_constants.codec_types[codec_type]
- codec_proto.sample_rate = int(sample_rate)
- codec_proto.bits_per_sample = int(bits_per_sample)
- codec_proto.channel_mode = bt_constants.channel_modes[channel_mode]
-
- self.bt_logger.add_config_data_to_proto(test_case_proto, self.dut,
- self.bt_device)
-
- self.bt_logger.add_proto_to_results(test_case_proto,
- self.__class__.__name__)
-
- proto_dict = self.bt_logger.get_proto_dict(self.__class__.__name__,
- test_case_proto)
- del proto_dict["proto_ascii"]
- return proto_dict
-
- def plot_graph(self, df):
- """ Plotting A2DP DUT RSSI, remote RSSI and TX Power with Attenuation.
-
- Args:
- df: Summary of results contains attenuation, DUT RSSI, remote RSSI and Tx Power
- """
- self.plot = wifi_utils.BokehFigure(title='{}'.format(
- self.current_test_name),
- x_label='Pathloss (dBm)',
- primary_y_label='RSSI (dBm)',
- secondary_y_label='TX Power (dBm)',
- axis_label_size='16pt')
- self.plot.add_line(df.index,
- df['rssi_primary'],
- legend='DUT RSSI (dBm)',
- marker='circle_x')
- self.plot.add_line(df.index,
- df['rssi_secondary'],
- legend='Remote RSSI (dBm)',
- marker='square_x')
- self.plot.add_line(df.index,
- df['tx_power_level_master'],
- legend='DUT TX Power (dBm)',
- marker='hex',
- y_axis='secondary')
-
- results_file_path = os.path.join(
- self.log_path, '{}.html'.format(self.current_test_name))
- self.plot.generate_figure()
- wifi_utils.BokehFigure.save_figures([self.plot], results_file_path)
-
- def run_a2dp_to_max_range(self, codec_config):
- attenuation_range = range(self.attenuation_vector['start'],
- self.attenuation_vector['stop'] + 1,
- self.attenuation_vector['step'])
-
- data_points = []
- self.file_output = os.path.join(
- self.log_path, '{}.csv'.format(self.current_test_name))
-
- # Set Codec if needed
- current_codec = self.dut.droid.bluetoothA2dpGetCurrentCodecConfig()
- current_codec_type = BtEnum.BluetoothA2dpCodecType(
- current_codec['codecType']).name
- if current_codec_type != codec_config['codec_type']:
- codec_set = btutils.set_bluetooth_codec(self.dut, **codec_config)
- asserts.assert_true(codec_set, 'Codec configuration failed.')
+ if hasattr(self, 'dual_chain') and self.dual_chain == 1:
+ test_case_name = 'test_dual_bt_a2dp_range_codec_{}_gainmimatch_{}dB'.format(
+ codec_config['codec_type'], self.gain_mismatch)
else:
- self.log.info('Current codec is {}, no need to change'.format(
- current_codec_type))
-
- #loop RSSI with the same codec setting
- for atten in attenuation_range:
- ramp_attenuation(self.attenuator, atten)
- self.log.info('Set attenuation to %d dB', atten)
-
- tag = 'codec_{}_attenuation_{}dB_'.format(
- codec_config['codec_type'], atten)
- recorded_file = self.play_and_record_audio(
- self.audio_params['duration'])
- [rssi_master, pwl_master, rssi_slave] = self._get_bt_link_metrics()
- thdns = self.run_thdn_analysis(recorded_file, tag)
- # Collect Metrics for dashboard
- data_point = {
- 'attenuation_db': int(self.attenuator.get_atten()),
- 'rssi_primary': rssi_master[self.dut.serial],
- 'tx_power_level_master': pwl_master[self.dut.serial],
- 'rssi_secondary': rssi_slave[self.bt_device_controller.serial],
- 'total_harmonic_distortion_plus_noise_percent': thdns[0] * 100
- }
- data_points.append(data_point)
- self.log.info(data_point)
- A2dpRange_df = pd.DataFrame(data_points)
-
- # Check thdn for glitches, stop if max range reached
- for thdn in thdns:
- if thdn >= self.audio_params['thdn_threshold']:
- self.log.info(
- 'Max range at attenuation {} dB'.format(atten))
- self.log.info('DUT rssi {} dBm, DUT tx power level {}, '
- 'Remote rssi {} dBm'.format(
- rssi_master, pwl_master, rssi_slave))
- proto_dict = self.generate_proto(data_points,
- **codec_config)
- A2dpRange_df.to_csv(self.file_output, index=False)
- self.plot_graph(A2dpRange_df)
- raise TestPass('Max range reached and move to next codec',
- extras=proto_dict)
- # Save Data points to csv
- A2dpRange_df.to_csv(self.file_output, index=False)
- # Plot graph
- self.plot_graph(A2dpRange_df)
- proto_dict = self.generate_proto(data_points, **codec_config)
- raise TestPass('Could not reach max range, need extra attenuation.',
- extras=proto_dict)
\ No newline at end of file
+ test_case_name = 'test_bt_a2dp_range_codec_{}'.format(
+ codec_config['codec_type'])
+ setattr(self, test_case_name, test_case_fn)
diff --git a/acts_tests/tests/google/bt/performance/BtA2dpRangeWithBleAdvTest.py b/acts_tests/tests/google/bt/performance/BtA2dpRangeWithBleAdvTest.py
new file mode 100644
index 0000000..5fe9503
--- /dev/null
+++ b/acts_tests/tests/google/bt/performance/BtA2dpRangeWithBleAdvTest.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import acts_contrib.test_utils.bt.bt_test_utils as btutils
+from acts_contrib.test_utils.bt.bt_constants import adv_succ
+from acts_contrib.test_utils.bt.A2dpBaseTest import A2dpBaseTest
+from acts_contrib.test_utils.bt.bt_constants import bt_default_timeout
+from acts_contrib.test_utils.bt.bt_constants import ble_advertise_settings_modes
+from acts_contrib.test_utils.bt.bt_constants import ble_advertise_settings_tx_powers
+from acts_contrib.test_utils.bt.bt_test_utils import BtTestUtilsError
+from queue import Empty
+from acts_contrib.test_utils.bt.bt_test_utils import generate_ble_advertise_objects
+from acts_contrib.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
+
+INIT_ATTEN = 0
+
+
+class BtA2dpRangeWithBleAdvTest(A2dpBaseTest):
+ """User can generate test case with below format.
+ test_bt_a2dp_range_codec_"Codec"_adv_mode_"Adv Mode"_adv_tx_power_"Adv Tx Power"
+
+ Below are the list of test cases:
+ test_bt_a2dp_range_codec_AAC_adv_mode_low_power_adv_tx_power_ultra_low
+ test_bt_a2dp_range_codec_AAC_adv_mode_low_power_adv_tx_power_low
+ test_bt_a2dp_range_codec_AAC_adv_mode_low_power_adv_tx_power_medium
+ test_bt_a2dp_range_codec_AAC_adv_mode_low_power_adv_tx_power_high
+ test_bt_a2dp_range_codec_AAC_adv_mode_balanced_adv_tx_power_ultra_low
+ test_bt_a2dp_range_codec_AAC_adv_mode_balanced_adv_tx_power_low
+ test_bt_a2dp_range_codec_AAC_adv_mode_balanced_adv_tx_power_medium
+ test_bt_a2dp_range_codec_AAC_adv_mode_balanced_adv_tx_power_high
+ test_bt_a2dp_range_codec_AAC_adv_mode_low_latency_adv_tx_power_ultra_low
+ test_bt_a2dp_range_codec_AAC_adv_mode_low_latency_adv_tx_power_low
+ test_bt_a2dp_range_codec_AAC_adv_mode_low_latency_adv_tx_power_medium
+ test_bt_a2dp_range_codec_AAC_adv_mode_low_latency_adv_tx_power_high
+ test_bt_a2dp_range_codec_SBC_adv_mode_low_power_adv_tx_power_ultra_low
+ test_bt_a2dp_range_codec_SBC_adv_mode_low_power_adv_tx_power_low
+ test_bt_a2dp_range_codec_SBC_adv_mode_low_power_adv_tx_power_medium
+ test_bt_a2dp_range_codec_SBC_adv_mode_low_power_adv_tx_power_high
+ test_bt_a2dp_range_codec_SBC_adv_mode_balanced_adv_tx_power_ultra_low
+ test_bt_a2dp_range_codec_SBC_adv_mode_balanced_adv_tx_power_low
+ test_bt_a2dp_range_codec_SBC_adv_mode_balanced_adv_tx_power_medium
+ test_bt_a2dp_range_codec_SBC_adv_mode_balanced_adv_tx_power_high
+ test_bt_a2dp_range_codec_SBC_adv_mode_low_latency_adv_tx_power_ultra_low
+ test_bt_a2dp_range_codec_SBC_adv_mode_low_latency_adv_tx_power_low
+ test_bt_a2dp_range_codec_SBC_adv_mode_low_latency_adv_tx_power_medium
+ test_bt_a2dp_range_codec_SBC_adv_mode_low_latency_adv_tx_power_high
+
+ """
+ def __init__(self, configs):
+ super().__init__(configs)
+ req_params = ['attenuation_vector', 'codecs']
+ #'attenuation_vector' is a dict containing: start, stop and step of
+ #attenuation changes
+ #'codecs' is a list containing all codecs required in the tests
+ self.unpack_userparams(req_params)
+ for codec_config in self.codecs:
+ # Loop all advertise modes and power levels
+ for adv_mode in ble_advertise_settings_modes.items():
+ for adv_power_level in ble_advertise_settings_tx_powers.items(
+ ):
+ self.generate_test_case(codec_config, adv_mode,
+ adv_power_level)
+
+ def setup_class(self):
+ super().setup_class()
+ opt_params = ['gain_mismatch', 'dual_chain']
+ self.unpack_userparams(opt_params, dual_chain=None, gain_mismatch=None)
+ return setup_multiple_devices_for_bt_test(self.android_devices)
+ # Enable BQR on all android devices
+ btutils.enable_bqr(self.android_devices)
+ if hasattr(self, 'dual_chain') and self.dual_chain == 1:
+ self.atten_c0 = self.attenuators[0]
+ self.atten_c1 = self.attenuators[1]
+ self.atten_c0.set_atten(INIT_ATTEN)
+ self.atten_c1.set_atten(INIT_ATTEN)
+
+ def teardown_class(self):
+ super().teardown_class()
+ if hasattr(self, 'atten_c0') and hasattr(self, 'atten_c1'):
+ self.atten_c0.set_atten(INIT_ATTEN)
+ self.atten_c1.set_atten(INIT_ATTEN)
+
+ def generate_test_case(self, codec_config, adv_mode, adv_power_level):
+ def test_case_fn():
+ adv_callback = self.start_ble_adv(adv_mode[1], adv_power_level[1])
+ self.run_a2dp_to_max_range(codec_config)
+ self.dut.droid.bleStopBleAdvertising(adv_callback)
+ self.log.info("Advertisement stopped Successfully")
+
+ if hasattr(self, 'dual_chain') and self.dual_chain == 1:
+ test_case_name = 'test_dual_bt_a2dp_range_codec_{}_gainmimatch_{}dB'.format(
+ codec_config['codec_type'], self.gain_mismatch)
+ else:
+ test_case_name = 'test_bt_a2dp_range_codec_{}_adv_mode_{}_adv_tx_power_{}'.format(
+ codec_config['codec_type'], adv_mode[0], adv_power_level[0])
+ setattr(self, test_case_name, test_case_fn)
+
+ def start_ble_adv(self, adv_mode, adv_power_level):
+ """Function to start an LE advertisement
+ Steps:
+ 1. Create a advertise data object
+ 2. Create a advertise settings object.
+ 3. Create a advertise callback object.
+ 4. Start an LE advertising using the objects created in steps 1-3.
+ 5. Find the onSuccess advertisement event.
+
+ Expected Result:
+ Advertisement is successfully advertising.
+
+ Returns:
+ Returns advertise call back"""
+
+ self.dut.droid.bleSetAdvertiseDataIncludeDeviceName(True)
+ self.dut.droid.bleSetAdvertiseSettingsAdvertiseMode(adv_mode)
+ self.dut.droid.bleSetAdvertiseSettingsIsConnectable(True)
+ self.dut.droid.bleSetAdvertiseSettingsTxPowerLevel(adv_power_level)
+ advertise_callback, advertise_data, advertise_settings = (
+ generate_ble_advertise_objects(self.dut.droid))
+ self.dut.droid.bleStartBleAdvertising(advertise_callback,
+ advertise_data,
+ advertise_settings)
+ try:
+ self.dut.ed.pop_event(adv_succ.format(advertise_callback),
+ bt_default_timeout)
+ self.log.info("Advertisement started successfully")
+ except Empty as err:
+ raise BtTestUtilsError(
+ "Advertiser did not start successfully {}".format(err))
+ return advertise_callback
diff --git a/acts_tests/tests/google/bt/performance/BtA2dpRangeWithBleScanTest.py b/acts_tests/tests/google/bt/performance/BtA2dpRangeWithBleScanTest.py
new file mode 100644
index 0000000..6020c4a
--- /dev/null
+++ b/acts_tests/tests/google/bt/performance/BtA2dpRangeWithBleScanTest.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import acts_contrib.test_utils.bt.bt_test_utils as btutils
+from acts_contrib.test_utils.bt.A2dpBaseTest import A2dpBaseTest
+from acts_contrib.test_utils.bt.bt_constants import ble_scan_settings_modes
+from acts_contrib.test_utils.bt.bt_test_utils import generate_ble_scan_objects
+from acts_contrib.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
+from acts_contrib.test_utils.bt.bt_constants import scan_result
+
+INIT_ATTEN = 0
+
+
+class BtA2dpRangeWithBleScanTest(A2dpBaseTest):
+ default_timeout = 10
+
+ def __init__(self, configs):
+ super().__init__(configs)
+ req_params = ['attenuation_vector', 'codecs']
+ #'attenuation_vector' is a dict containing: start, stop and step of
+ #attenuation changes
+ #'codecs' is a list containing all codecs required in the tests
+ self.unpack_userparams(req_params)
+ for codec_config in self.codecs:
+ # Loop all BLE Scan modes
+ for scan_mode in ble_scan_settings_modes.items():
+ self.generate_test_case(codec_config, scan_mode)
+
+ def setup_class(self):
+ super().setup_class()
+ opt_params = ['gain_mismatch', 'dual_chain']
+ self.unpack_userparams(opt_params, dual_chain=None, gain_mismatch=None)
+ return setup_multiple_devices_for_bt_test(self.android_devices)
+ # Enable BQR on all android devices
+ btutils.enable_bqr(self.android_devices)
+ if hasattr(self, 'dual_chain') and self.dual_chain == 1:
+ self.atten_c0 = self.attenuators[0]
+ self.atten_c1 = self.attenuators[1]
+ self.atten_c0.set_atten(INIT_ATTEN)
+ self.atten_c1.set_atten(INIT_ATTEN)
+
+ def teardown_class(self):
+ super().teardown_class()
+ if hasattr(self, 'atten_c0') and hasattr(self, 'atten_c1'):
+ self.atten_c0.set_atten(INIT_ATTEN)
+ self.atten_c1.set_atten(INIT_ATTEN)
+
+ def generate_test_case(self, codec_config, scan_mode):
+ """ Below are the list of test case's user can choose to run.
+ Test case list:
+ "test_bt_a2dp_range_codec_AAC_with_BLE_scan_balanced"
+ "test_bt_a2dp_range_codec_AAC_with_BLE_scan_low_latency"
+ "test_bt_a2dp_range_codec_AAC_with_BLE_scan_low_power"
+ "test_bt_a2dp_range_codec_AAC_with_BLE_scan_opportunistic"
+ "test_bt_a2dp_range_codec_SBC_with_BLE_scan_balanced"
+ "test_bt_a2dp_range_codec_SBC_with_BLE_scan_low_latency"
+ "test_bt_a2dp_range_codec_SBC_with_BLE_scan_low_power"
+ "test_bt_a2dp_range_codec_SBC_with_BLE_scan_opportunistic"
+ """
+ def test_case_fn():
+ scan_callback = self.start_ble_scan(scan_mode[1])
+ self.run_a2dp_to_max_range(codec_config)
+ self.dut.droid.bleStopBleScan(scan_callback)
+ self.log.info("BLE Scan stopped succssfully")
+
+ if hasattr(self, 'dual_chain') and self.dual_chain == 1:
+ test_case_name = 'test_dual_bt_a2dp_range_codec_{}_gainmimatch_{}dB'.format(
+ codec_config['codec_type'], self.gain_mismatch)
+ else:
+ test_case_name = 'test_bt_a2dp_range_codec_{}_with_BLE_scan_{}'.format(
+ codec_config['codec_type'], scan_mode[0])
+ setattr(self, test_case_name, test_case_fn)
+
+ def start_ble_scan(self, scan_mode):
+ """ This function will start Ble Scan with different scan mode.
+
+ Args:
+ Scan_mode: Ble scan setting modes
+
+ returns:
+ Scan_callback: Ble scan callback
+ """
+
+ self.dut.droid.bleSetScanSettingsScanMode(scan_mode)
+ filter_list, scan_settings, scan_callback = generate_ble_scan_objects(
+ self.dut.droid)
+ self.dut.droid.bleStartBleScan(filter_list, scan_settings,
+ scan_callback)
+ self.log.info("BLE Scanning started succssfully")
+ return scan_callback
diff --git a/acts_tests/tests/google/bt/performance/BtInterferenceDynamicTest.py b/acts_tests/tests/google/bt/performance/BtInterferenceDynamicTest.py
index 59721ca..ec980a2 100644
--- a/acts_tests/tests/google/bt/performance/BtInterferenceDynamicTest.py
+++ b/acts_tests/tests/google/bt/performance/BtInterferenceDynamicTest.py
@@ -261,9 +261,13 @@
ramp_attenuation(self.attenuator, bt_atten_level)
self.interference_rssi_mapping_from_attenuation(
interference_atten_level)
- [rssi_master, pwl_master, rssi_slave] = self._get_bt_link_metrics()
- tag_bt = 'bt_signal_level_{}_rssi_{}_dBm'.format(
- bt_atten_level, rssi_master)
+ [
+ rssi_master, pwl_master, rssi_c0_master, rssi_c1_master,
+ txpw_c0_master, txpw_c1_master, bftx_master, divtx_master
+ ], [rssi_slave] = self._get_bt_link_metrics()
+ rssi_primary = rssi_master.get(self.dut.serial, -127)
+ tag_bt = 'bt_signal_level_{}'.format(
+ bt_atten_level)
procs_iperf = []
for obj in self.wifi_int_pairs:
obj.iperf_server.start()
@@ -313,9 +317,13 @@
ramp_attenuation(self.attenuator, bt_atten_level)
self.interference_rssi_mapping_from_attenuation(
interference_atten_level)
- [rssi_master, pwl_master, rssi_slave] = self._get_bt_link_metrics()
- tag_bt = 'bt_signal_level_{}_rssi_{}_dBm'.format(
- bt_atten_level, rssi_master)
+ [
+ rssi_master, pwl_master, rssi_c0_master, rssi_c1_master,
+ txpw_c0_master, txpw_c1_master, bftx_master, divtx_master
+ ], [rssi_slave] = self._get_bt_link_metrics()
+ rssi_primary = rssi_master.get(self.dut.serial, -127)
+ tag_bt = 'bt_signal_level_{}'.format(
+ bt_atten_level)
procs_iperf = []
#Start IPERF on all three interference pairs
for obj in self.wifi_int_pairs:
@@ -354,4 +362,4 @@
self.log.info('THDN results are {}'.format(thdns))
for thdn in thdns:
if thdn >= self.audio_params['thdn_threshold']:
- raise TestFailure('AFH failed')
+ raise TestFailure('AFH failed')
\ No newline at end of file
diff --git a/acts_tests/tests/google/bt/performance/BtInterferenceStaticTest.py b/acts_tests/tests/google/bt/performance/BtInterferenceStaticTest.py
index bf6b0de..99218b0 100644
--- a/acts_tests/tests/google/bt/performance/BtInterferenceStaticTest.py
+++ b/acts_tests/tests/google/bt/performance/BtInterferenceStaticTest.py
@@ -15,11 +15,13 @@
# the License.
"""Stream music through connected device from phone across different
attenuations."""
-from acts.signals import TestPass
+
from acts_contrib.test_utils.bt.BtInterferenceBaseTest import BtInterferenceBaseTest
from acts.metrics.loggers.blackbox import BlackboxMetricLogger
from acts_contrib.test_utils.bt.BtInterferenceBaseTest import get_iperf_results
+from acts_contrib.test_utils.bt.BtInterferenceBaseTest import inject_static_wifi_interference
from multiprocessing import Process, Queue
+from acts.signals import TestPass
DEFAULT_THDN_THRESHOLD = 0.9
MAX_ATTENUATION = 95
@@ -33,8 +35,7 @@
self.attenuation_vector['stop'] + 1,
self.attenuation_vector['step'])
- self.iperf_duration = self.audio_params[
- 'duration'] + TIME_OVERHEAD
+ self.iperf_duration = self.audio_params['duration'] + TIME_OVERHEAD
for level in list(
self.static_wifi_interference['interference_level'].keys()):
for channels in self.static_wifi_interference['channels']:
@@ -69,44 +70,6 @@
str_channel_test))
setattr(self, test_case_name, test_case_fn)
- def inject_static_wifi_interference(self, interference_level, channels):
- """Function to inject wifi interference to bt link and read rssi.
-
- Interference of IPERF traffic is always running, by setting attenuation,
- the gate is opened to release the interference to the setup.
- Args:
- interference_level: the signal strength of wifi interference, use
- attenuation level to represent this
- channels: wifi channels where interference will
- be injected, list
- """
- all_pair = range(len(self.wifi_int_pairs))
- interference_pair_indices = self.locate_interference_pair_by_channel(
- channels)
- inactive_interference_pairs_indices = [
- item for item in all_pair if item not in interference_pair_indices
- ]
- self.log.info(
- 'WiFi interference at {} and inactive channels at {}'.format(
- interference_pair_indices,
- inactive_interference_pairs_indices))
- for i in interference_pair_indices:
- self.wifi_int_pairs[i].attenuator.set_atten(interference_level)
- self.log.info('Set attenuation {} dB on attenuator {}'.format(
- self.wifi_int_pairs[i].attenuator.get_atten(), i + 1))
- for i in inactive_interference_pairs_indices:
- self.wifi_int_pairs[i].attenuator.set_atten(MAX_ATTENUATION)
- self.log.info('Set attenuation {} dB on attenuator {}'.format(
- self.wifi_int_pairs[i].attenuator.get_atten(), i + 1))
- #Read interference RSSI
- self.get_interference_rssi()
- self.wifi_chan1_rssi_metric.metric_value = self.interference_rssi[0][
- 'rssi']
- self.wifi_chan6_rssi_metric.metric_value = self.interference_rssi[1][
- 'rssi']
- self.wifi_chan11_rssi_metric.metric_value = self.interference_rssi[2][
- 'rssi']
-
def bt_range_with_static_wifi_interference(self, interference_level,
channels):
"""Test function to measure bt range under interference.
@@ -116,12 +79,28 @@
channels: wifi interference channels
"""
#setup wifi interference by setting the correct attenuator
- self.inject_static_wifi_interference(interference_level, channels)
+ inject_static_wifi_interference(self.wifi_int_pairs,
+ interference_level, channels)
+ # Read interference RSSI
+ self.get_interference_rssi()
+ self.wifi_chan1_rssi_metric.metric_value = self.interference_rssi[0][
+ 'rssi']
+ self.wifi_chan6_rssi_metric.metric_value = self.interference_rssi[1][
+ 'rssi']
+ self.wifi_chan11_rssi_metric.metric_value = self.interference_rssi[2][
+ 'rssi']
for atten in self.bt_attenuation_range:
# Set attenuation for BT link
self.attenuator.set_atten(atten)
- [rssi_master, pwl_master, rssi_slave] = self._get_bt_link_metrics()
- tag = 'attenuation_{}dB_'.format(atten)
+ [
+ rssi_master, pwl_master, rssi_c0_master, rssi_c1_master,
+ txpw_c0_master, txpw_c1_master, bftx_master, divtx_master
+ ], [rssi_slave] = self._get_bt_link_metrics()
+ rssi_primary = rssi_master.get(self.dut.serial, -127)
+ pwl_primary = pwl_master.get(self.dut.serial, -127)
+ rssi_secondary = rssi_slave.get(self.bt_device_controller.serial,
+ -127)
+ tag = 'attenuation_{}dB'.format(atten)
self.log.info(
'BT attenuation set to {} dB and start A2DP streaming'.format(
atten))
@@ -140,8 +119,8 @@
#play a2dp streaming and run thdn analysis
queue = Queue()
- proc_bt = Process(target=self.play_and_record_audio,
- args=(self.audio_params['duration'],queue))
+ proc_bt = Process(target=self.play_and_record_audio,
+ args=(self.audio_params['duration'], queue))
for proc in procs_iperf:
proc.start()
proc_bt.start()
@@ -155,23 +134,23 @@
obj.channel, iperf_throughput))
obj.iperf_server.stop()
self.log.info('Stopped IPERF server at port {}'.format(
- obj.iperf_server.port))
+ obj.iperf_server.port))
audio_captured = queue.get()
thdns = self.run_thdn_analysis(audio_captured, tag)
- self.log.info('THDN results are {} at {} dB attenuation'
- .format(thdns, atten))
- self.log.info('master rssi {} dBm, master tx power level {}, '
- 'slave rssi {} dBm'
- .format(rssi_master, pwl_master, rssi_slave))
+ self.log.info('THDN results are {} at {} dB attenuation'.format(
+ thdns, atten))
+ self.log.info('DUT rssi {} dBm, master tx power level {}, '
+ 'RemoteDevice rssi {} dBm'.format(rssi_primary, pwl_primary,
+ rssi_secondary))
for thdn in thdns:
if thdn >= self.audio_params['thdn_threshold']:
self.log.info('Under the WiFi interference condition: '
'channel 1 RSSI: {} dBm, '
'channel 6 RSSI: {} dBm'
- 'channel 11 RSSI: {} dBm'
- .format(self.interference_rssi[0]['rssi'],
- self.interference_rssi[1]['rssi'],
- self.interference_rssi[2]['rssi']))
+ 'channel 11 RSSI: {} dBm'.format(
+ self.interference_rssi[0]['rssi'],
+ self.interference_rssi[1]['rssi'],
+ self.interference_rssi[2]['rssi']))
raise TestPass(
'Max range for this test is {}, with BT master RSSI at'
- ' {} dBm'.format(atten, rssi_master))
+ ' {} dBm'.format(atten, rssi_primary))
diff --git a/acts_tests/tests/google/bt/performance/InjectWifiInterferenceTest.py b/acts_tests/tests/google/bt/performance/InjectWifiInterferenceTest.py
new file mode 100644
index 0000000..22c2b2f
--- /dev/null
+++ b/acts_tests/tests/google/bt/performance/InjectWifiInterferenceTest.py
@@ -0,0 +1,190 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+import json
+import random
+import sys
+import logging
+import re
+from acts.base_test import BaseTestClass
+from acts_contrib.test_utils.bt.BtInterferenceBaseTest import inject_static_wifi_interference
+from acts_contrib.test_utils.bt.BtInterferenceBaseTest import unpack_custom_file
+from acts_contrib.test_utils.power.PowerBaseTest import ObjNew
+from acts_contrib.test_utils.wifi import wifi_performance_test_utils as wpeutils
+from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+import time
+
+MAX_ATTENUATION = 95
+INIT_ATTEN = 0
+SCAN = 'wpa_cli scan'
+SCAN_RESULTS = 'wpa_cli scan_results'
+
+
+class InjectWifiInterferenceTest(BaseTestClass):
+ def __init__(self, configs):
+ super().__init__(configs)
+ req_params = ['custom_files', 'wifi_networks']
+ self.unpack_userparams(req_params)
+ for file in self.custom_files:
+ if 'static_interference' in file:
+ self.static_wifi_interference = unpack_custom_file(file)
+ elif 'dynamic_interference' in file:
+ self.dynamic_wifi_interference = unpack_custom_file(file)
+
+ def setup_class(self):
+
+ self.dut = self.android_devices[0]
+ # Set attenuator to minimum attenuation
+ if hasattr(self, 'attenuators'):
+ self.attenuator = self.attenuators[0]
+ self.attenuator.set_atten(INIT_ATTEN)
+ self.wifi_int_pairs = []
+ for i in range(len(self.attenuators) - 1):
+ tmp_dict = {
+ 'attenuator': self.attenuators[i + 1],
+ 'network': self.wifi_networks[i],
+ 'channel': self.wifi_networks[i]['channel']
+ }
+ tmp_obj = ObjNew(**tmp_dict)
+ self.wifi_int_pairs.append(tmp_obj)
+ ##Setup connection between WiFi APs and Phones and get DHCP address
+ # for the interface
+ for obj in self.wifi_int_pairs:
+ obj.attenuator.set_atten(INIT_ATTEN)
+
+ def setup_test(self):
+ self.log.info("Setup test initiated")
+
+ def teardown_class(self):
+ for obj in self.wifi_int_pairs:
+ obj.attenuator.set_atten(MAX_ATTENUATION)
+
+ def teardown_test(self):
+ for obj in self.wifi_int_pairs:
+ obj.attenuator.set_atten(MAX_ATTENUATION)
+
+ def test_inject_static_wifi_interference(self):
+ condition = True
+ while condition:
+ attenuation = [
+ int(x) for x in input(
+ "Please enter 4 channel attenuation value followed by comma :\n"
+ ).split(',')
+ ]
+ self.set_atten_all_channel(attenuation)
+ # Read interference RSSI
+ self.interference_rssi = get_interference_rssi(
+ self.dut, self.wifi_int_pairs)
+ self.log.info('Under the WiFi interference condition: '
+ 'channel 1 RSSI: {} dBm, '
+ 'channel 6 RSSI: {} dBm'
+ 'channel 11 RSSI: {} dBm'.format(
+ self.interference_rssi[0]['rssi'],
+ self.interference_rssi[1]['rssi'],
+ self.interference_rssi[2]['rssi']))
+ condition = True
+ return True
+
+ def test_inject_dynamic_interface(self):
+ atten = int(input("Please enter the attenuation level for CHAN1 :"))
+ self.attenuator.set_atten(atten)
+ self.log.info("Attenuation for CHAN1 set to:{} dB".format(atten))
+ interference_rssi = None
+ self.channel_change_interval = self.dynamic_wifi_interference[
+ 'channel_change_interval_second']
+ self.wifi_int_levels = list(
+ self.dynamic_wifi_interference['interference_level'].keys())
+ for wifi_level in self.wifi_int_levels:
+ interference_atten_level = self.dynamic_wifi_interference[
+ 'interference_level'][wifi_level]
+ all_pair = range(len(self.wifi_int_pairs))
+ # Set initial WiFi interference at channel 1
+ logging.info('Start with interference at channel 1')
+ self.wifi_int_pairs[0].attenuator.set_atten(
+ interference_atten_level)
+ self.wifi_int_pairs[1].attenuator.set_atten(MAX_ATTENUATION)
+ self.wifi_int_pairs[2].attenuator.set_atten(MAX_ATTENUATION)
+ current_int_pair = [0]
+ inactive_int_pairs = [
+ item for item in all_pair if item not in current_int_pair
+ ]
+ logging.info(
+ 'Inject random changing channel (1,6,11) wifi interference'
+ 'every {} second'.format(self.channel_change_interval))
+ while True:
+ current_int_pair = [
+ random.randint(inactive_int_pairs[0],
+ inactive_int_pairs[1])
+ ]
+ inactive_int_pairs = [
+ item for item in all_pair if item not in current_int_pair
+ ]
+ self.wifi_int_pairs[current_int_pair[0]].attenuator.set_atten(
+ interference_atten_level)
+ logging.info('Current interference at channel {}'.format(
+ self.wifi_int_pairs[current_int_pair[0]].channel))
+ for i in inactive_int_pairs:
+ self.wifi_int_pairs[i].attenuator.set_atten(
+ MAX_ATTENUATION)
+ # Read interference RSSI
+ self.interference_rssi = get_interference_rssi(
+ self.dut, self.wifi_int_pairs)
+ self.log.info('Under the WiFi interference condition: '
+ 'channel 1 RSSI: {} dBm, '
+ 'channel 6 RSSI: {} dBm'
+ 'channel 11 RSSI: {} dBm'.format(
+ self.interference_rssi[0]['rssi'],
+ self.interference_rssi[1]['rssi'],
+ self.interference_rssi[2]['rssi']))
+ time.sleep(self.channel_change_interval)
+ return True
+
+ def set_atten_all_channel(self, attenuation):
+ self.attenuators[0].set_atten(attenuation[0])
+ self.attenuators[1].set_atten(attenuation[1])
+ self.attenuators[2].set_atten(attenuation[2])
+ self.attenuators[3].set_atten(attenuation[3])
+ self.log.info(
+ "Attenuation set to CHAN1:{},CHAN2:{},CHAN3:{},CHAN4:{}".format(
+ self.attenuators[0].get_atten(),
+ self.attenuators[1].get_atten(),
+ self.attenuators[2].get_atten(),
+ self.attenuators[3].get_atten()))
+
+
+def get_interference_rssi(dut, wifi_int_pairs):
+ """Function to read wifi interference RSSI level."""
+
+ bssids = []
+ interference_rssi = []
+ wutils.wifi_toggle_state(dut, True)
+ for item in wifi_int_pairs:
+ ssid = item.network['SSID']
+ bssid = item.network['bssid']
+ bssids.append(bssid)
+ interference_rssi_dict = {
+ "ssid": ssid,
+ "bssid": bssid,
+ "chan": item.channel,
+ "rssi": 0
+ }
+ interference_rssi.append(interference_rssi_dict)
+ scaned_rssi = wpeutils.get_scan_rssi(dut, bssids, num_measurements=2)
+ for item in interference_rssi:
+ item['rssi'] = scaned_rssi[item['bssid']]['mean']
+ logging.info('Interference RSSI at channel {} is {} dBm'.format(
+ item['chan'], item['rssi']))
+ wutils.wifi_toggle_state(dut, False)
+ return interference_rssi
diff --git a/acts_tests/tests/google/bt/performance/StartIperfTrafficTest.py b/acts_tests/tests/google/bt/performance/StartIperfTrafficTest.py
new file mode 100644
index 0000000..edc373f
--- /dev/null
+++ b/acts_tests/tests/google/bt/performance/StartIperfTrafficTest.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+import sys
+import time
+import acts.controllers.iperf_client as ipc
+from acts_contrib.test_utils.bt.BtInterferenceBaseTest import BtInterferenceBaseTest
+from acts_contrib.test_utils.power.PowerBaseTest import ObjNew
+from multiprocessing import Process, Queue
+from acts_contrib.test_utils.bt.BtInterferenceBaseTest import setup_ap_connection
+from acts_contrib.test_utils.wifi import wifi_power_test_utils as wputils
+from acts.signals import TestPass
+
+
+class StartIperfTrafficTest(BtInterferenceBaseTest):
+ """
+ """
+ def __init__(self, configs):
+ super().__init__(configs)
+ req_params =["IperfDuration"]
+ self.unpack_userparams(req_params)
+
+ def setup_class(self):
+ self.dut = self.android_devices[0]
+ self.wifi_int_pairs = []
+ for i in range(len(self.attenuators) - 1):
+ tmp_dict = {
+ 'dut': self.android_devices[i],
+ 'ap': self.access_points[i],
+ 'network': self.wifi_networks[i],
+ 'channel': self.wifi_networks[i]['channel'],
+ 'iperf_server': self.iperf_servers[i],
+ 'ether_int': self.packet_senders[i],
+ 'iperf_client': ipc.IPerfClientOverAdb(self.android_devices[i])
+ }
+ tmp_obj = ObjNew(**tmp_dict)
+ self.wifi_int_pairs.append(tmp_obj)
+ ##Setup connection between WiFi APs and Phones and get DHCP address
+ # for the interface
+ for obj in self.wifi_int_pairs:
+ brconfigs = setup_ap_connection(obj.dut, obj.network, obj.ap)
+ iperf_server_address = wputils.wait_for_dhcp(
+ obj.ether_int.interface)
+ setattr(obj, 'server_address', iperf_server_address)
+ setattr(obj, 'brconfigs', brconfigs)
+
+ def setup_test(self):
+ self.log.info("Setup test initiated")
+
+ def teardown_class(self):
+ for obj in self.wifi_int_pairs:
+ obj.ap.bridge.teardown(obj.brconfigs)
+ self.log.info('Stop IPERF server at port {}'.format(
+ obj.iperf_server.port))
+ obj.iperf_server.stop()
+ self.log.info('Stop IPERF process on {}'.format(obj.dut.serial))
+ #obj.dut.adb.shell('pkill -9 iperf3')
+ #only for glinux machine
+ # wputils.bring_down_interface(obj.ether_int.interface)
+ obj.ap.close()
+
+ def teardown_test(self):
+ self.log.info("Setup test initiated")
+
+ def test_start_iperf_traffic(self):
+ self.channel_change_interval = self.dynamic_wifi_interference[
+ 'channel_change_interval_second']
+ self.wifi_int_levels = list(
+ self.dynamic_wifi_interference['interference_level'].keys())
+ for wifi_level in self.wifi_int_levels:
+ interference_atten_level = self.dynamic_wifi_interference[
+ 'interference_level'][wifi_level]
+ end_time = time.time() + self.IperfDuration
+ while time.time() < end_time:
+ procs_iperf = []
+ # Start IPERF on all three interference pairs
+ for obj in self.wifi_int_pairs:
+ obj.iperf_server.start()
+ iperf_args = '-i 1 -t {} -p {} -J -R'.format(
+ self.IperfDuration, obj.iperf_server.port)
+ tag = 'chan_{}'.format(obj.channel)
+ proc_iperf = Process(target=obj.iperf_client.start,
+ args=(obj.server_address, iperf_args,
+ tag))
+ proc_iperf.start()
+ procs_iperf.append(proc_iperf)
+ for proc in procs_iperf:
+ self.log.info('Started IPERF on all three channels')
+ proc.join()
+ return True
diff --git a/acts_tests/tests/google/bt/pts/cmd_input.py b/acts_tests/tests/google/bt/pts/cmd_input.py
index 2db77a7..9a90c1d 100644
--- a/acts_tests/tests/google/bt/pts/cmd_input.py
+++ b/acts_tests/tests/google/bt/pts/cmd_input.py
@@ -1023,6 +1023,18 @@
except Exception as err:
self.log.info(FAILURE.format(cmd, err))
+ def do_bta_hfp_client_connect(self, line):
+ self.pri_dut.droid.bluetoothHfpClientConnect(self.mac_addr)
+
+ def do_bta_hfp_client_disconnect(self, line):
+ self.pri_dut.droid.bluetoothHfpClientDisconnect(self.mac_addr)
+
+ def do_bta_hfp_client_connect_audio(self, line):
+ self.pri_dut.droid.bluetoothHfpClientConnectAudio(self.mac_addr)
+
+ def do_bta_hfp_client_disconnect_audio(self, line):
+ self.pri_dut.droid.bluetoothHfpClientDisconnectAudio(self.mac_addr)
+
"""End HFP/HSP wrapper"""
"""Begin HID wrappers"""
diff --git a/acts_tests/tests/google/coex/functionality_tests/WlanWithHfpFunctionalityTest.py b/acts_tests/tests/google/coex/functionality_tests/WlanWithHfpFunctionalityTest.py
index f6aadc3..3b71537 100644
--- a/acts_tests/tests/google/coex/functionality_tests/WlanWithHfpFunctionalityTest.py
+++ b/acts_tests/tests/google/coex/functionality_tests/WlanWithHfpFunctionalityTest.py
@@ -27,8 +27,8 @@
from acts_contrib.test_utils.coex.coex_test_utils import toggle_screen_state
from acts_contrib.test_utils.coex.coex_test_utils import setup_tel_config
from acts_contrib.test_utils.coex.coex_test_utils import start_fping
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
BLUETOOTH_WAIT_TIME = 2
diff --git a/acts_tests/tests/google/coex/performance_tests/CoexBtMultiProfilePerformanceTest.py b/acts_tests/tests/google/coex/performance_tests/CoexBtMultiProfilePerformanceTest.py
index de36052..a952c1a 100644
--- a/acts_tests/tests/google/coex/performance_tests/CoexBtMultiProfilePerformanceTest.py
+++ b/acts_tests/tests/google/coex/performance_tests/CoexBtMultiProfilePerformanceTest.py
@@ -33,9 +33,9 @@
from acts_contrib.test_utils.coex.coex_test_utils import pair_and_connect_headset
from acts_contrib.test_utils.coex.coex_test_utils import setup_tel_config
from acts_contrib.test_utils.coex.coex_test_utils import connect_wlan_profile
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
class CoexBtMultiProfilePerformanceTest(CoexPerformanceBaseTest):
diff --git a/acts_tests/tests/google/coex/performance_tests/WlanWithHfpPerformanceTest.py b/acts_tests/tests/google/coex/performance_tests/WlanWithHfpPerformanceTest.py
index b56cbde..0c5b5da 100644
--- a/acts_tests/tests/google/coex/performance_tests/WlanWithHfpPerformanceTest.py
+++ b/acts_tests/tests/google/coex/performance_tests/WlanWithHfpPerformanceTest.py
@@ -22,8 +22,8 @@
from acts_contrib.test_utils.coex.coex_test_utils import initiate_disconnect_from_hf
from acts_contrib.test_utils.coex.coex_test_utils import pair_and_connect_headset
from acts_contrib.test_utils.coex.coex_test_utils import setup_tel_config
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
class WlanWithHfpPerformanceTest(CoexPerformanceBaseTest):
diff --git a/acts_tests/tests/google/coex/stress_tests/CoexHfpStressTest.py b/acts_tests/tests/google/coex/stress_tests/CoexHfpStressTest.py
index 8add009..49ee4a9 100644
--- a/acts_tests/tests/google/coex/stress_tests/CoexHfpStressTest.py
+++ b/acts_tests/tests/google/coex/stress_tests/CoexHfpStressTest.py
@@ -26,7 +26,7 @@
from acts_contrib.test_utils.tel.tel_defines import AUDIO_ROUTE_BLUETOOTH
from acts_contrib.test_utils.tel.tel_defines import AUDIO_ROUTE_SPEAKER
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
from acts_contrib.test_utils.tel.tel_voice_utils import set_audio_route
diff --git a/acts_tests/tests/google/fuchsia/bt/command_input.py b/acts_tests/tests/google/fuchsia/bt/command_input.py
index 69778c2..c993ac0 100644
--- a/acts_tests/tests/google/fuchsia/bt/command_input.py
+++ b/acts_tests/tests/google/fuchsia/bt/command_input.py
@@ -43,6 +43,9 @@
"""
+from acts_contrib.test_utils.audio_analysis_lib.check_quality import quality_analysis
+from acts_contrib.test_utils.bt.bt_constants import audio_bits_per_sample_32
+from acts_contrib.test_utils.bt.bt_constants import audio_sample_rate_48000
from acts_contrib.test_utils.abstract_devices.bluetooth_device import create_bluetooth_device
from acts_contrib.test_utils.bt.bt_constants import bt_attribute_values
from acts_contrib.test_utils.bt.bt_constants import sig_appearance_constants
@@ -2275,6 +2278,58 @@
except Exception as err:
self.log.error(FAILURE.format(cmd, err))
+ def do_audio_5_min_test(self, line):
+ """
+ Description: Capture and anlyize sine audio waves played from a Bluetooth A2DP
+ Source device.
+
+ Pre steps:
+ 1. Pair A2DP source device
+ 2. Prepare generated SOX file over preferred codec on source device.
+ Quick way to generate necessary audio files:
+ sudo apt-get install sox
+ sox -b 16 -r 48000 -c 2 -n audio_file_2k1k_5_min.wav synth 300 sine 2000 sine 3000
+
+ Usage:
+ Examples:
+ audio_5_min_test
+ """
+ cmd = "5 min audio capture test"
+ input("Press Enter once Source device is streaming audio file")
+ try:
+ result = self.pri_dut.audio_lib.startOutputSave()
+ self.log.info(result)
+ for i in range(5):
+ print("Minutes left: {}".format(10 - i))
+ time.sleep(60)
+ result = self.pri_dut.audio_lib.stopOutputSave()
+ log_time = int(time.time())
+ save_path = "{}/{}".format(self.pri_dut.log_path,
+ "{}_audio.raw".format(log_time))
+ analysis_path = "{}/{}".format(
+ self.pri_dut.log_path,
+ "{}_audio_analysis.txt".format(log_time))
+ result = self.pri_dut.audio_lib.getOutputAudio(save_path)
+
+ channels = 1
+ try:
+ quality_analysis(filename=save_path,
+ output_file=analysis_path,
+ bit_width=audio_bits_per_sample_32,
+ rate=audio_sample_rate_48000,
+ channel=channels,
+ spectral_only=False)
+
+ except Exception as err:
+ self.log.error("Failed to analyze raw audio: {}".format(err))
+ return False
+
+ self.log.info("Analysis output here: {}".format(analysis_path))
+ self.log.info("Analysis Results: {}".format(
+ open(analysis_path).readlines()))
+ except Exception as err:
+ self.log.error(FAILURE.format(cmd, err))
+
"""End Audio wrappers"""
"""Begin HFP wrappers"""
@@ -2321,7 +2376,7 @@
cmd = "Lists connected peers"
try:
result = self.pri_dut.hfp_lib.listPeers()
- self.log.info(result)
+ self.log.info(pprint.pformat(result))
except Exception as err:
self.log.error(FAILURE.format(cmd, err))
@@ -2357,7 +2412,7 @@
cmd = "Lists all calls"
try:
result = self.pri_dut.hfp_lib.listCalls()
- self.log.info(result)
+ self.log.info(pprint.pformat(result))
except Exception as err:
self.log.error(FAILURE.format(cmd, err))
@@ -2369,23 +2424,27 @@
remote: The number of the remote party on the simulated call
state: The state of the call. Must be one of "ringing", "waiting",
"dialing", "alerting", "active", "held".
+ direction: The direction of the call. Must be one of "incoming", "outgoing".
Usage:
Examples:
- hfp_new_call <remote> <state>
- hfp_new_call 14085555555 active
- hfp_new_call 14085555555 held
- hfp_new_call 14085555555 ringing
- hfp_new_call 14085555555 alerting
- hfp_new_call 14085555555 dialing
+ hfp_new_call <remote> <state> <direction>
+ hfp_new_call 14085555555 active incoming
+ hfp_new_call 14085555555 held outgoing
+ hfp_new_call 14085555555 ringing incoming
+ hfp_new_call 14085555555 waiting incoming
+ hfp_new_call 14085555555 alerting outgoing
+ hfp_new_call 14085555555 dialing outgoing
"""
cmd = "Simulates a call"
try:
info = line.strip().split()
- if len(info) != 2:
- raise ValueError("Exactly two command line arguments required: <remote> <state>")
- remote, state = info[0], info[1]
- result = self.pri_dut.hfp_lib.newCall(remote, state)
+ if len(info) != 3:
+ raise ValueError(
+ "Exactly three command line arguments required: <remote> <state> <direction>"
+ )
+ remote, state, direction = info[0], info[1], info[2]
+ result = self.pri_dut.hfp_lib.newCall(remote, state, direction)
self.log.info(result)
except Exception as err:
self.log.error(FAILURE.format(cmd, err))
@@ -2410,6 +2469,27 @@
except Exception as err:
self.log.error(FAILURE.format(cmd, err))
+ def do_hfp_waiting_call(self, line):
+ """
+ Description: Simulate an incoming call on the call manager when there is
+ an onging active call already.
+
+ Input(s):
+ remote: The number of the remote party on the incoming call
+
+ Usage:
+ Examples:
+ hfp_waiting_call <remote>
+ hfp_waiting_call 14085555555
+ """
+ cmd = "Simulates an incoming call"
+ try:
+ remote = line.strip()
+ result = self.pri_dut.hfp_lib.initiateIncomingWaitingCall(remote)
+ self.log.info(result)
+ except Exception as err:
+ self.log.error(FAILURE.format(cmd, err))
+
def do_hfp_outgoing_call(self, line):
"""
Description: Simulate an outgoing call on the call manager
@@ -2741,7 +2821,9 @@
try:
info = line.strip().split()
if len(info) != 2:
- raise ValueError("Exactly two command line arguments required: <location> <number>")
+ raise ValueError(
+ "Exactly two command line arguments required: <location> <number>"
+ )
location, number = info[0], info[1]
result = self.pri_dut.hfp_lib.setMemoryLocation(location, number)
self.log.info(result)
@@ -2784,10 +2866,12 @@
try:
info = line.strip().split()
if len(info) != 2:
- raise ValueError("Exactly two command line arguments required: <number> <status>")
+ raise ValueError(
+ "Exactly two command line arguments required: <number> <status>"
+ )
number, status = info[0], int(info[1])
result = self.pri_dut.hfp_lib.setDialResult(number, status)
- self.log.info(result)
+ self.log.info(pprint.pformat(result))
except Exception as err:
self.log.error(FAILURE.format(cmd, err))
@@ -2802,7 +2886,157 @@
cmd = "Get the call manager's state"
try:
result = self.pri_dut.hfp_lib.getState()
+ self.log.info(pprint.pformat(result))
+ except Exception as err:
+ self.log.error(FAILURE.format(cmd, err))
+
+ def do_hfp_set_connection_behavior(self, line):
+ """
+ Description: Set the Service Level Connection (SLC) behavior when a new peer connects.
+
+ Input(s):
+ autoconnect: Enable/Disable autoconnection of SLC.
+
+ Usage:
+ Examples:
+ hfp_set_connection_behavior <autoconnect>
+ hfp_set_connection_behavior true
+ hfp_set_connection_behavior false
+ """
+ cmd = "Set the Service Level Connection (SLC) behavior"
+ try:
+ autoconnect = line.strip().lower() == "true"
+ result = self.pri_dut.hfp_lib.setConnectionBehavior(autoconnect)
self.log.info(result)
except Exception as err:
self.log.error(FAILURE.format(cmd, err))
+
"""End HFP wrappers"""
+ """Begin RFCOMM wrappers"""
+
+ def do_rfcomm_init(self, line):
+ """
+ Description: Initialize the RFCOMM component services.
+
+ Usage:
+ Examples:
+ rfcomm_init
+ """
+ cmd = "Initialize RFCOMM proxy"
+ try:
+ result = self.pri_dut.rfcomm_lib.init()
+ self.log.info(result)
+ except Exception as err:
+ self.log.error(FAILURE.format(cmd, err))
+
+ def do_rfcomm_remove_service(self, line):
+ """
+ Description: Removes the RFCOMM service in use.
+
+ Usage:
+ Examples:
+ rfcomm_remove_service
+ """
+ cmd = "Remove RFCOMM service"
+ try:
+ result = self.pri_dut.rfcomm_lib.removeService()
+ self.log.info(result)
+ except Exception as err:
+ self.log.error(FAILURE.format(cmd, err))
+
+ def do_rfcomm_disconnect_session(self, line):
+ """
+ Description: Closes the RFCOMM Session.
+
+ Usage:
+ Examples:
+ rfcomm_disconnect_session
+ rfcomm_disconnect_session
+ """
+ cmd = "Disconnect the RFCOMM Session"
+ try:
+ result = self.pri_dut.rfcomm_lib.disconnectSession(
+ self.unique_mac_addr_id)
+ self.log.info(result)
+ except Exception as err:
+ self.log.error(FAILURE.format(cmd, err))
+
+ def do_rfcomm_connect_rfcomm_channel(self, line):
+ """
+ Description: Make an outgoing RFCOMM connection.
+
+ Usage:
+ Examples:
+ rfcomm_connect_rfcomm_channel <server_channel_number>
+ rfcomm_connect_rfcomm_channel 2
+ """
+ cmd = "Make an outgoing RFCOMM connection"
+ try:
+ server_channel_number = int(line.strip())
+ result = self.pri_dut.rfcomm_lib.connectRfcommChannel(
+ self.unique_mac_addr_id, server_channel_number)
+ self.log.info(result)
+ except Exception as err:
+ self.log.error(FAILURE.format(cmd, err))
+
+ def do_rfcomm_disconnect_rfcomm_channel(self, line):
+ """
+ Description: Close the RFCOMM connection with the peer
+
+ Usage:
+ Examples:
+ rfcomm_disconnect_rfcomm_channel <server_channel_number>
+ rfcomm_disconnect_rfcomm_channel 2
+ """
+ cmd = "Close the RFCOMM channel"
+ try:
+ server_channel_number = int(line.strip())
+ result = self.pri_dut.rfcomm_lib.disconnectRfcommChannel(
+ self.unique_mac_addr_id, server_channel_number)
+ self.log.info(result)
+ except Exception as err:
+ self.log.error(FAILURE.format(cmd, err))
+
+ def do_rfcomm_send_remote_line_status(self, line):
+ """
+ Description: Send a remote line status for the RFCOMM channel.
+
+ Usage:
+ Examples:
+ rfcomm_send_remote_line_status <server_channel_number>
+ rfcomm_send_remote_line_status 2
+ """
+ cmd = "Send a remote line status update for the RFCOMM channel"
+ try:
+ server_channel_number = int(line.strip())
+ result = self.pri_dut.rfcomm_lib.sendRemoteLineStatus(
+ self.unique_mac_addr_id, server_channel_number)
+ self.log.info(result)
+ except Exception as err:
+ self.log.error(FAILURE.format(cmd, err))
+
+ def do_rfcomm_write_rfcomm(self, line):
+ """
+ Description: Send data over the RFCOMM channel.
+
+ Usage:
+ Examples:
+ rfcomm_write_rfcomm <server_channel_number> <data>
+ rfcomm_write_rfcomm 2 foobar
+ """
+ cmd = "Send data using the RFCOMM channel"
+ try:
+ info = line.strip().split()
+ if len(info) != 2:
+ raise ValueError(
+ "Exactly two command line arguments required: <server_channel_number> <data>"
+ )
+ server_channel_number = int(info[0])
+ data = info[1]
+ result = self.pri_dut.rfcomm_lib.writeRfcomm(
+ self.unique_mac_addr_id, server_channel_number, data)
+ self.log.info(result)
+ except Exception as err:
+ self.log.error(FAILURE.format(cmd, err))
+
+ """End RFCOMM wrappers"""
diff --git a/acts_tests/tests/google/fuchsia/bt/ep/BtFuchsiaEPTest.py b/acts_tests/tests/google/fuchsia/bt/ep/BtFuchsiaEPTest.py
index 59da1dd..e01afd5 100644
--- a/acts_tests/tests/google/fuchsia/bt/ep/BtFuchsiaEPTest.py
+++ b/acts_tests/tests/google/fuchsia/bt/ep/BtFuchsiaEPTest.py
@@ -241,10 +241,11 @@
input_capabilities = "NONE"
output_capabilities = "NONE"
+
+ # Initialize a2dp on both devices.
self.pri_dut.avdtp_lib.init()
- self.pri_dut.control_daemon("bt-avrcp.cmx", "start")
- self.sec_dut.avdtp_lib.init(initiator_delay=2000)
- self.sec_dut.control_daemon("bt-avrcp-target.cmx", "start")
+ self.sec_dut.avdtp_lib.init()
+
self.pri_dut.bts_lib.acceptPairing(input_capabilities,
output_capabilities)
@@ -265,16 +266,9 @@
raise signals.TestFailure("Failed to connect with {}.".format(
connect_result.get("error")))
- if not verify_device_state_by_name(
- self.pri_dut, self.log, target_device_name, "CONNECTED", None):
- raise signals.TestFailure(
- "Failed to connect to device {}.".format(target_device_name))
-
- if not verify_device_state_by_name(
- self.sec_dut, self.log, source_device_name, "CONNECTED", None):
- raise signals.TestFailure(
- "Failed to connect to device {}.".format(source_device_name))
-
+ # We pair before checking the CONNECTED status because BR/EDR semantics
+ # were recently changed such that if pairing is not confirmed, then bt
+ # does not report connected = True.
security_level = "NONE"
bondable = True
transport = 1 #BREDR
@@ -285,6 +279,16 @@
raise signals.TestFailure("Failed to pair with {}.".format(
pair_result.get("error")))
+ if not verify_device_state_by_name(
+ self.pri_dut, self.log, target_device_name, "CONNECTED", None):
+ raise signals.TestFailure(
+ "Failed to connect to device {}.".format(target_device_name))
+
+ if not verify_device_state_by_name(
+ self.sec_dut, self.log, source_device_name, "CONNECTED", None):
+ raise signals.TestFailure(
+ "Failed to connect to device {}.".format(source_device_name))
+
#TODO: Validation of services and paired devices (b/175641870)
# A2DP sink: 0000110b-0000-1000-8000-00805f9b34fb
# A2DP source: 0000110a-0000-1000-8000-00805f9b34fb
diff --git a/acts_tests/tests/google/fuchsia/bt/gatt/GattServerSetupTest.py b/acts_tests/tests/google/fuchsia/bt/gatt/GattServerSetupTest.py
index 83418e4..41a4cf2 100644
--- a/acts_tests/tests/google/fuchsia/bt/gatt/GattServerSetupTest.py
+++ b/acts_tests/tests/google/fuchsia/bt/gatt/GattServerSetupTest.py
@@ -150,7 +150,7 @@
TAGS: GATT
Priority: 1
- """
+ """
self.setup_database(database.ALERT_NOTIFICATION_SERVICE)
@test_tracker_info(uuid='c42e8bc9-1ba7-4d4e-b67e-9c19cc11472c')
diff --git a/acts_tests/tests/google/fuchsia/bt/gatt/gatt_server_databases.py b/acts_tests/tests/google/fuchsia/bt/gatt/gatt_server_databases.py
index c854281..7575afd 100644
--- a/acts_tests/tests/google/fuchsia/bt/gatt/gatt_server_databases.py
+++ b/acts_tests/tests/google/fuchsia/bt/gatt/gatt_server_databases.py
@@ -13,7 +13,6 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
-
"""
GATT server dictionaries which will be setup in various tests.
"""
@@ -25,7 +24,6 @@
from acts_contrib.test_utils.bt.bt_constants import gatt_characteristic_value_format
from acts_contrib.test_utils.bt.bt_constants import gatt_char_desc_uuids
-
SINGLE_PRIMARY_SERVICE = {
'services': [{
'uuid': '00001802-0000-1000-8000-00805f9b34fb',
@@ -61,6 +59,7 @@
}
### Begin SIG defined services ###
+# yapf: disable
# TODO: Reconcile all the proper security parameters of each service.
# Some are correct, others are not.
@@ -2488,4 +2487,5 @@
}
-### End SIG defined services ###
\ No newline at end of file
+# yapf: enable
+### End SIG defined services ###
diff --git a/acts_tests/tests/google/fuchsia/dhcp/Dhcpv4InteropTest.py b/acts_tests/tests/google/fuchsia/dhcp/Dhcpv4InteropTest.py
new file mode 100644
index 0000000..3a668da
--- /dev/null
+++ b/acts_tests/tests/google/fuchsia/dhcp/Dhcpv4InteropTest.py
@@ -0,0 +1,540 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import ipaddress
+import itertools
+import random
+import time
+import re
+
+from acts import asserts
+from acts import utils
+from acts.controllers.access_point import setup_ap, AccessPoint
+from acts.controllers.ap_lib import dhcp_config
+from acts.controllers.ap_lib import hostapd_constants
+from acts.controllers.ap_lib.hostapd_security import Security
+from acts.controllers.ap_lib.hostapd_utils import generate_random_password
+from acts.controllers.utils_lib.commands import ip
+from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
+from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
+from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
+
+
+class Dhcpv4InteropFixture(AbstractDeviceWlanDeviceBaseTest):
+ """Test helpers for validating DHCPv4 Interop
+
+ Test Bed Requirement:
+ * One Android device or Fuchsia device
+ * One Access Point
+ """
+ access_point: AccessPoint
+
+ def __init__(self, controllers):
+ WifiBaseTest.__init__(self, controllers)
+
+ def setup_class(self):
+ super().setup_class()
+ if 'dut' in self.user_params:
+ if self.user_params['dut'] == 'fuchsia_devices':
+ self.dut = create_wlan_device(self.fuchsia_devices[0])
+ elif self.user_params['dut'] == 'android_devices':
+ self.dut = create_wlan_device(self.android_devices[0])
+ else:
+ raise ValueError('Invalid DUT specified in config. (%s)' %
+ self.user_params['dut'])
+ else:
+ # Default is an android device, just like the other tests
+ self.dut = create_wlan_device(self.android_devices[0])
+
+ self.access_point = self.access_points[0]
+ self.access_point.stop_all_aps()
+
+ def setup_test(self):
+ if hasattr(self, "android_devices"):
+ for ad in self.android_devices:
+ ad.droid.wakeLockAcquireBright()
+ ad.droid.wakeUpNow()
+ self.dut.wifi_toggle_state(True)
+
+ def teardown_test(self):
+ if hasattr(self, "android_devices"):
+ for ad in self.android_devices:
+ ad.droid.wakeLockRelease()
+ ad.droid.goToSleepNow()
+ self.dut.turn_location_off_and_scan_toggle_off()
+ self.dut.disconnect()
+ self.dut.reset_wifi()
+ self.access_point.stop_all_aps()
+
+ def connect(self, ap_params):
+ asserts.assert_true(
+ self.dut.associate(ap_params['ssid'],
+ target_pwd=ap_params['password'],
+ target_security=ap_params['target_security']),
+ 'Failed to connect.')
+
+ def setup_ap(self):
+ """Generates a hostapd config and sets up the AP with that config.
+ Does not run a DHCP server.
+
+ Returns: A dictionary of information about the AP.
+ """
+ ssid = utils.rand_ascii_str(20)
+ security_mode = hostapd_constants.WPA2_STRING
+ security_profile = Security(
+ security_mode=security_mode,
+ password=generate_random_password(length=20),
+ wpa_cipher='CCMP',
+ wpa2_cipher='CCMP')
+ password = security_profile.password
+ target_security = hostapd_constants.SECURITY_STRING_TO_DEFAULT_TARGET_SECURITY.get(
+ security_mode)
+
+ ap_ids = setup_ap(access_point=self.access_point,
+ profile_name='whirlwind',
+ mode=hostapd_constants.MODE_11N_MIXED,
+ channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
+ n_capabilities=[],
+ ac_capabilities=[],
+ force_wmm=True,
+ ssid=ssid,
+ security=security_profile,
+ password=password)
+
+ if len(ap_ids) > 1:
+ raise Exception("Expected only one SSID on AP")
+
+ configured_subnets = self.access_point.get_configured_subnets()
+ if len(configured_subnets) > 1:
+ raise Exception("Expected only one subnet on AP")
+ router_ip = configured_subnets[0].router
+ network = configured_subnets[0].network
+
+ self.access_point.stop_dhcp()
+
+ return {
+ 'ssid': ssid,
+ 'password': password,
+ 'target_security': target_security,
+ 'ip': router_ip,
+ 'network': network,
+ 'id': ap_ids[0],
+ }
+
+ def device_can_ping(self, dest_ip):
+ """Checks if the DUT can ping the given address.
+
+ Returns: True if can ping, False otherwise"""
+ self.log.info('Attempting to ping %s...' % dest_ip)
+ ping_result = self.dut.can_ping(dest_ip, count=2)
+ if ping_result:
+ self.log.info('Success pinging: %s' % dest_ip)
+ else:
+ self.log.info('Failure pinging: %s' % dest_ip)
+ return ping_result
+
+ def get_device_ipv4_addr(self, interface=None, timeout=20):
+ """Checks if device has an ipv4 private address. Sleeps 1 second between
+ retries.
+
+ Args:
+ interface: string, name of interface from which to get ipv4 address.
+
+ Raises:
+ ConnectionError, if DUT does not have an ipv4 address after all
+ timeout.
+
+ Returns:
+ The device's IP address
+
+ """
+ self.log.debug('Fetching updated WLAN interface list')
+ if interface is None:
+ interface = self.dut.device.wlan_client_test_interface_name
+ self.log.info(
+ 'Checking if DUT has received an ipv4 addr on iface %s. Will retry for %s '
+ 'seconds.' % (interface, timeout))
+ timeout = time.time() + timeout
+ while time.time() < timeout:
+ ip_addrs = self.dut.get_interface_ip_addresses(interface)
+
+ if len(ip_addrs['ipv4_private']) > 0:
+ ip = ip_addrs['ipv4_private'][0]
+ self.log.info('DUT has an ipv4 address: %s' % ip)
+ return ip
+ else:
+ self.log.debug(
+ 'DUT does not yet have an ipv4 address...retrying in 1 '
+ 'second.')
+ time.sleep(1)
+ else:
+ raise ConnectionError('DUT failed to get an ipv4 address.')
+
+ def run_test_case_expect_dhcp_success(self, settings):
+ """Starts the AP and DHCP server, and validates that the client
+ connects and obtains an address.
+
+ Args:
+ settings: a dictionary containing:
+ dhcp_parameters: a dictionary of DHCP parameters
+ dhcp_options: a dictionary of DHCP options
+ """
+ ap_params = self.setup_ap()
+ subnet_conf = dhcp_config.Subnet(
+ subnet=ap_params['network'],
+ router=ap_params['ip'],
+ additional_parameters=settings['dhcp_parameters'],
+ additional_options=settings['dhcp_options'])
+ dhcp_conf = dhcp_config.DhcpConfig(subnets=[subnet_conf])
+
+ self.log.debug('DHCP Configuration:\n' +
+ dhcp_conf.render_config_file() + "\n")
+
+ dhcp_logs_before = self.access_point.get_dhcp_logs()
+ self.access_point.start_dhcp(dhcp_conf=dhcp_conf)
+ self.connect(ap_params=ap_params)
+ dhcp_logs_after = self.access_point.get_dhcp_logs()
+ dhcp_logs = dhcp_logs_after.replace(dhcp_logs_before, '')
+
+ # Typical log lines look like:
+ # dhcpd[26695]: DHCPDISCOVER from f8:0f:f9:3d:ce:d1 via wlan1
+ # dhcpd[26695]: DHCPOFFER on 192.168.9.2 to f8:0f:f9:3d:ce:d1 via wlan1
+ # dhcpd[26695]: DHCPREQUEST for 192.168.9.2 (192.168.9.1) from f8:0f:f9:3d:ce:d1 via wlan1
+ # dhcpd[26695]: DHCPACK on 192.168.9.2 to f8:0f:f9:3d:ce:d1 via wlan1
+
+ try:
+ ip = self.get_device_ipv4_addr()
+ except ConnectionError:
+ self.log.warn(dhcp_logs)
+ asserts.fail(f'DUT failed to get an IP address')
+
+ expected_string = f'DHCPDISCOVER from'
+ asserts.assert_true(
+ dhcp_logs.count(expected_string) == 1,
+ f'Incorrect count of DHCP Discovers ("{expected_string}") in logs: '
+ + dhcp_logs + "\n")
+
+ expected_string = f'DHCPOFFER on {ip}'
+ asserts.assert_true(
+ dhcp_logs.count(expected_string) == 1,
+ f'Incorrect count of DHCP Offers ("{expected_string}") in logs: ' +
+ dhcp_logs + "\n")
+
+ expected_string = f'DHCPREQUEST for {ip}'
+ asserts.assert_true(
+ dhcp_logs.count(expected_string) >= 1,
+ f'Incorrect count of DHCP Requests ("{expected_string}") in logs: '
+ + dhcp_logs + "\n")
+
+ expected_string = f'DHCPACK on {ip}'
+ asserts.assert_true(
+ dhcp_logs.count(expected_string) >= 1,
+ f'Incorrect count of DHCP Acks ("{expected_string}") in logs: ' +
+ dhcp_logs + "\n")
+
+ asserts.assert_true(self.device_can_ping(ap_params['ip']),
+ f'DUT failed to ping router at {ap_params["ip"]}')
+
+
+class Dhcpv4InteropFixtureTest(Dhcpv4InteropFixture):
+ """Tests which validate the behavior of the Dhcpv4InteropFixture.
+
+ In theory, these are more similar to unit tests than ACTS tests, but
+ since they interact with hardware (specifically, the AP), we have to
+ write and run them like the rest of the ACTS tests."""
+
+ def test_invalid_options_not_accepted(self):
+ """Ensures the DHCP server doesn't accept invalid options"""
+ ap_params = self.setup_ap()
+ subnet_conf = dhcp_config.Subnet(subnet=ap_params['network'],
+ router=ap_params['ip'],
+ additional_options={'foo': 'bar'})
+ dhcp_conf = dhcp_config.DhcpConfig(subnets=[subnet_conf])
+ with asserts.assert_raises_regex(Exception, r'failed to start'):
+ self.access_point.start_dhcp(dhcp_conf=dhcp_conf)
+
+ def test_invalid_parameters_not_accepted(self):
+ """Ensures the DHCP server doesn't accept invalid parameters"""
+ ap_params = self.setup_ap()
+ subnet_conf = dhcp_config.Subnet(subnet=ap_params['network'],
+ router=ap_params['ip'],
+ additional_parameters={'foo': 'bar'})
+ dhcp_conf = dhcp_config.DhcpConfig(subnets=[subnet_conf])
+ with asserts.assert_raises_regex(Exception, r'failed to start'):
+ self.access_point.start_dhcp(dhcp_conf=dhcp_conf)
+
+ def test_no_dhcp_server_started(self):
+ """Validates that the test fixture does not start a DHCP server."""
+ ap_params = self.setup_ap()
+ self.connect(ap_params=ap_params)
+ with asserts.assert_raises(ConnectionError):
+ self.get_device_ipv4_addr()
+
+
+class Dhcpv4InteropBasicTest(Dhcpv4InteropFixture):
+ """DhcpV4 tests which validate basic DHCP client/server interactions."""
+
+ def test_basic_dhcp_assignment(self):
+ self.run_test_case_expect_dhcp_success(settings={
+ 'dhcp_options': {},
+ 'dhcp_parameters': {}
+ })
+
+ def test_pool_allows_unknown_clients(self):
+ self.run_test_case_expect_dhcp_success(settings={
+ 'dhcp_options': {},
+ 'dhcp_parameters': {
+ 'allow': 'unknown-clients'
+ }
+ })
+
+ def test_pool_disallows_unknown_clients(self):
+ ap_params = self.setup_ap()
+ subnet_conf = dhcp_config.Subnet(
+ subnet=ap_params['network'],
+ router=ap_params['ip'],
+ additional_parameters={'deny': 'unknown-clients'})
+ dhcp_conf = dhcp_config.DhcpConfig(subnets=[subnet_conf])
+ self.access_point.start_dhcp(dhcp_conf=dhcp_conf)
+
+ self.connect(ap_params=ap_params)
+ with asserts.assert_raises(ConnectionError):
+ self.get_device_ipv4_addr()
+
+ dhcp_logs = self.access_point.get_dhcp_logs()
+ asserts.assert_true(
+ re.search(r'DHCPDISCOVER from .*no free leases', dhcp_logs),
+ "Did not find expected message in dhcp logs: " + dhcp_logs + "\n")
+
+ def test_lease_renewal(self):
+ """Validates that a client renews their DHCP lease."""
+ LEASE_TIME = 30
+ ap_params = self.setup_ap()
+ subnet_conf = dhcp_config.Subnet(subnet=ap_params['network'],
+ router=ap_params['ip'])
+ dhcp_conf = dhcp_config.DhcpConfig(subnets=[subnet_conf],
+ default_lease_time=LEASE_TIME,
+ max_lease_time=LEASE_TIME)
+ self.access_point.start_dhcp(dhcp_conf=dhcp_conf)
+ self.connect(ap_params=ap_params)
+ ip = self.get_device_ipv4_addr()
+
+ dhcp_logs_before = self.access_point.get_dhcp_logs()
+ SLEEP_TIME = LEASE_TIME + 3
+ self.log.info(f'Sleeping {SLEEP_TIME}s to await DHCP renewal')
+ time.sleep(SLEEP_TIME)
+
+ dhcp_logs_after = self.access_point.get_dhcp_logs()
+ dhcp_logs = dhcp_logs_after.replace(dhcp_logs_before, '')
+ # Fuchsia renews at LEASE_TIME / 2, so there should be at least 2 DHCPREQUESTs in logs.
+ # The log lines look like:
+ # INFO dhcpd[17385]: DHCPREQUEST for 192.168.9.2 from f8:0f:f9:3d:ce:d1 via wlan1
+ # INFO dhcpd[17385]: DHCPACK on 192.168.9.2 to f8:0f:f9:3d:ce:d1 via wlan1
+ expected_string = f'DHCPREQUEST for {ip}'
+ asserts.assert_true(
+ dhcp_logs.count(expected_string) >= 2,
+ f'Not enough DHCP renewals ("{expected_string}") in logs: ' +
+ dhcp_logs + "\n")
+
+
+class Dhcpv4DuplicateAddressTest(Dhcpv4InteropFixture):
+ def setup_test(self):
+ super().setup_test()
+ self.extra_addresses = []
+ self.ap_params = self.setup_ap()
+ self.ap_ip_cmd = ip.LinuxIpCommand(self.access_point.ssh)
+
+ def teardown_test(self):
+ super().teardown_test()
+ for ip in self.extra_addresses:
+ self.ap_ip_cmd.remove_ipv4_address(self.ap_params['id'], ip)
+ pass
+
+ def test_duplicate_address_assignment(self):
+ """It's possible for a DHCP server to assign an address that already exists on the network.
+ DHCP clients are expected to perform a "gratuitous ARP" of the to-be-assigned address, and
+ refuse to assign that address. Clients should also recover by asking for a different
+ address.
+ """
+ # Modify subnet to hold fewer addresses.
+ # A '/29' has 8 addresses (6 usable excluding router / broadcast)
+ subnet = next(self.ap_params['network'].subnets(new_prefix=29))
+ subnet_conf = dhcp_config.Subnet(
+ subnet=subnet,
+ router=self.ap_params['ip'],
+ # When the DHCP server is considering dynamically allocating an IP address to a client,
+ # it first sends an ICMP Echo request (a ping) to the address being assigned. It waits
+ # for a second, and if no ICMP Echo response has been heard, it assigns the address.
+ # If a response is heard, the lease is abandoned, and the server does not respond to
+ # the client.
+ # The ping-check configuration parameter can be used to control checking - if its value
+ # is false, no ping check is done.
+ additional_parameters={'ping-check': 'false'})
+ dhcp_conf = dhcp_config.DhcpConfig(subnets=[subnet_conf])
+ self.access_point.start_dhcp(dhcp_conf=dhcp_conf)
+
+ # Add each of the usable IPs as an alias for the router's interface, such that the router
+ # will respond to any pings on it.
+ for ip in subnet.hosts():
+ self.ap_ip_cmd.add_ipv4_address(self.ap_params['id'], ip)
+ # Ensure we remove the address in self.teardown_test() even if the test fails
+ self.extra_addresses.append(ip)
+
+ self.connect(ap_params=self.ap_params)
+ with asserts.assert_raises(ConnectionError):
+ self.get_device_ipv4_addr()
+
+ # Per spec, the flow should be:
+ # Discover -> Offer -> Request -> Ack -> client optionally performs DAD
+ dhcp_logs = self.access_point.get_dhcp_logs()
+ for expected_message in [
+ r'DHCPDISCOVER from \S+',
+ r'DHCPOFFER on [0-9.]+ to \S+',
+ r'DHCPREQUEST for [0-9.]+',
+ r'DHCPACK on [0-9.]+',
+ r'DHCPDECLINE of [0-9.]+ from \S+ via .*: abandoned',
+ r'Abandoning IP address [0-9.]+: declined',
+ ]:
+ asserts.assert_true(
+ re.search(expected_message, dhcp_logs),
+ f'Did not find expected message ({expected_message}) in dhcp logs: {dhcp_logs}'
+ + "\n")
+
+ # Remove each of the IP aliases.
+ # Note: this also removes the router's address (e.g. 192.168.1.1), so pinging the
+ # router after this will not work.
+ while self.extra_addresses:
+ self.ap_ip_cmd.remove_ipv4_address(self.ap_params['id'],
+ self.extra_addresses.pop())
+
+ # Now, we should get an address successfully
+ ip = self.get_device_ipv4_addr()
+ dhcp_logs = self.access_point.get_dhcp_logs()
+
+ expected_string = f'DHCPREQUEST for {ip}'
+ asserts.assert_true(
+ dhcp_logs.count(expected_string) >= 1,
+ f'Incorrect count of DHCP Requests ("{expected_string}") in logs: '
+ + dhcp_logs + "\n")
+
+ expected_string = f'DHCPACK on {ip}'
+ asserts.assert_true(
+ dhcp_logs.count(expected_string) >= 1,
+ f'Incorrect count of DHCP Acks ("{expected_string}") in logs: ' +
+ dhcp_logs + "\n")
+
+
+class Dhcpv4InteropCombinatorialOptionsTest(Dhcpv4InteropFixture):
+ """DhcpV4 tests which validate combinations of DHCP options."""
+ OPT_NUM_DOMAIN_SEARCH = 119
+ OPT_NUM_DOMAIN_NAME = 15
+
+ def setup_class(self):
+ super().setup_class()
+ self.DHCP_OPTIONS = {
+ 'domain-name-tests': [{
+ 'domain-name':
+ '"example.invalid"',
+ 'dhcp-parameter-request-list':
+ self.OPT_NUM_DOMAIN_NAME
+ }, {
+ 'domain-name':
+ '"example.test"',
+ 'dhcp-parameter-request-list':
+ self.OPT_NUM_DOMAIN_NAME
+ }],
+ 'domain-search-tests': [{
+ 'domain-search':
+ '"example.invalid"',
+ 'dhcp-parameter-request-list':
+ self.OPT_NUM_DOMAIN_SEARCH
+ }, {
+ 'domain-search':
+ '"example.test"',
+ 'dhcp-parameter-request-list':
+ self.OPT_NUM_DOMAIN_SEARCH
+ }]
+ }
+
+ # The RFC limits DHCP payloads to 576 bytes unless the client signals it can handle larger
+ # payloads, which it does by sending DHCP option 57, "Maximum DHCP Message Size". Despite
+ # being able to accept larger payloads, clients typically don't advertise this.
+ # The test verifies that the client accepts a large message split across multiple ethernet
+ # frames.
+ # The test is created by sending many bytes of options through the domain-name-servers
+ # option, which is of unbounded length (though is compressed per RFC1035 section 4.1.4).
+ typical_ethernet_mtu = 1500
+ self.DHCP_OPTIONS['max-message-size-tests'] = []
+
+ long_dns_setting = ', '.join(
+ f'"ns{num}.example"'
+ for num in random.sample(range(100_000, 1_000_000), 250))
+ # RFC1035 compression means any shared suffix ('.example' in this case) will
+ # be deduplicated. Calculate approximate length by removing that suffix.
+ long_dns_setting_len = len(
+ long_dns_setting.replace(', ', '').replace('"', '').replace(
+ '.example', '').encode('utf-8'))
+ asserts.assert_true(
+ long_dns_setting_len > typical_ethernet_mtu,
+ "Expected to generate message greater than ethernet mtu")
+ self.DHCP_OPTIONS['max-message-size-tests'].append({
+ 'dhcp-max-message-size':
+ long_dns_setting_len * 2,
+ 'domain-search':
+ long_dns_setting,
+ 'dhcp-parameter-request-list':
+ self.OPT_NUM_DOMAIN_SEARCH
+ })
+
+ def test_domain_names(self):
+ test_list = []
+ for option_list in self.DHCP_OPTIONS['domain-name-tests']:
+ test_list.append({
+ 'dhcp_options': option_list,
+ 'dhcp_parameters': {}
+ })
+ self.run_generated_testcases(self.run_test_case_expect_dhcp_success,
+ settings=test_list)
+
+ def test_search_domains(self):
+ test_list = []
+ for option_list in self.DHCP_OPTIONS['domain-search-tests']:
+ test_list.append({
+ 'dhcp_options': option_list,
+ 'dhcp_parameters': {}
+ })
+ self.run_generated_testcases(self.run_test_case_expect_dhcp_success,
+ settings=test_list)
+
+ def test_large_messages(self):
+ test_list = []
+ for option_list in self.DHCP_OPTIONS['max-message-size-tests']:
+ test_list.append({
+ 'dhcp_options': option_list,
+ 'dhcp_parameters': {}
+ })
+ self.run_generated_testcases(self.run_test_case_expect_dhcp_success,
+ settings=test_list)
+
+ def test_dns(self):
+ pass
+
+ def test_ignored_options_singularly(self):
+ pass
+
+ def test_all_combinations(self):
+ # TODO: test all the combinations above
+ pass
diff --git a/acts_tests/tests/google/fuchsia/examples/Sl4fSanityTest.py b/acts_tests/tests/google/fuchsia/examples/Sl4fSanityTest.py
index d7491dd..91d664e 100644
--- a/acts_tests/tests/google/fuchsia/examples/Sl4fSanityTest.py
+++ b/acts_tests/tests/google/fuchsia/examples/Sl4fSanityTest.py
@@ -28,7 +28,6 @@
class Sl4fSanityTest(BaseTestClass):
-
def setup_class(self):
super().setup_class()
@@ -44,4 +43,3 @@
def test_example(self):
self.log.info("Congratulations! You've run your first test.")
return True
-
diff --git a/acts_tests/tests/google/fuchsia/flash/FlashTest.py b/acts_tests/tests/google/fuchsia/flash/FlashTest.py
new file mode 100644
index 0000000..572a431
--- /dev/null
+++ b/acts_tests/tests/google/fuchsia/flash/FlashTest.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""
+Script for to flash Fuchsia devices and reports the DUT's version of Fuchsia in
+the Sponge test result properties. Uses the built in flashing tool for
+fuchsia_devices.
+"""
+import time
+
+import acts.libs.proc.job as job
+
+from acts import signals
+from acts.base_test import BaseTestClass
+from acts.controllers.fuchsia_lib.base_lib import DeviceOffline
+from acts.utils import get_device
+
+
+class FlashTest(BaseTestClass):
+ def setup_class(self):
+ super().setup_class()
+ success_str = ("Congratulations! Fuchsia controllers have been "
+ "initialized successfully!")
+ err_str = ("Sorry, please try verifying FuchsiaDevice is in your "
+ "config file and try again.")
+ if len(self.fuchsia_devices) > 0:
+ self.log.info(success_str)
+ else:
+ raise signals.TestAbortClass("err_str")
+
+ def teardown_class(self):
+ try:
+ dut = get_device(self.fuchsia_devices, 'DUT')
+ version = dut.version()
+ self.record_data({'sponge_properties': {
+ 'DUT_VERSION': version,
+ }})
+ self.log.info("DUT version found: {}".format(version))
+ except ValueError as err:
+ self.log.warn("Failed to determine DUT: %s" % err)
+ except DeviceOffline as err:
+ self.log.warn("Failed to get DUT's version: %s" % err)
+
+ return super().teardown_class()
+
+ def test_flash_devices(self):
+ flash_retry_max = 3
+ flash_counter = 0
+ for fuchsia_device in self.fuchsia_devices:
+ while flash_counter < flash_retry_max:
+ try:
+ fuchsia_device.reboot(reboot_type='flash',
+ use_ssh=True,
+ unreachable_timeout=120,
+ ping_timeout=120)
+ flash_counter = flash_retry_max
+ except Exception as err:
+ if fuchsia_device.device_pdu_config:
+ self.log.info(
+ 'Flashing failed with error: {}'.format(err))
+ self.log.info('Hard rebooting fuchsia_device({}) and '
+ 'retrying.'.format(
+ fuchsia_device.orig_ip))
+ fuchsia_device.reboot(reboot_type='hard',
+ testbed_pdus=self.pdu_devices)
+ flash_counter = flash_counter + 1
+ if flash_counter == flash_retry_max:
+ raise err
+ time.sleep(1)
+ else:
+ raise err
+ self.log.info("fuchsia_device(%s) has been flashed." %
+ fuchsia_device.orig_ip)
+ flash_counter = 0
+
+ return True
+
+ def test_report_dut_version(self):
+ """Empty test to ensure the version of the DUT is reported in the Sponge
+ results in the case when flashing the device is not necessary.
+
+ Useful for when flashing the device is not necessary; specify ACTS to
+ only run this test from the test class.
+ """
+ pass
diff --git a/acts_tests/tests/google/fuchsia/netstack/NetstackIfaceTest.py b/acts_tests/tests/google/fuchsia/netstack/NetstackIfaceTest.py
index d360277..7033156 100644
--- a/acts_tests/tests/google/fuchsia/netstack/NetstackIfaceTest.py
+++ b/acts_tests/tests/google/fuchsia/netstack/NetstackIfaceTest.py
@@ -33,7 +33,6 @@
"NetstackFuchsiaTest Init: Not enough fuchsia devices.")
self.log.info("Running testbed setup with one fuchsia devices")
self.dut = self.fuchsia_devices[0]
- self.dut.netstack_lib.init()
def _enable_all_interfaces(self):
interfaces = self.dut.netstack_lib.netstackListInterfaces()
@@ -76,44 +75,6 @@
self.log.info("Interfaces found: {}".format(interfaces.get('result')))
raise signals.TestPass("Success")
- def test_get_interface_by_id(self):
- """Tests getting interface information by id on all interfaces.
-
- Steps:
- 1. Call ListInterfaces FIDL api.
- 2. For each interface in the list, call GetInterfaceInfo FIDL api.
-
- Expected Result:
- There were no errors in each GetInterfaceInfo call.
-
- Returns:
- signals.TestPass if no errors
- signals.TestFailure if there are any errors during the test.
-
- TAGS: Netstack
- Priority: 1
- """
- interfaces = self.dut.netstack_lib.netstackListInterfaces()
- if interfaces.get('error') is not None:
- raise signals.TestFailure("Failed with {}".format(
- interfaces.get('error')))
- for item in interfaces.get("result"):
- identifier = item.get('id')
- interface_info_result = self.dut.netstack_lib.getInterfaceInfo(
- identifier)
- if interface_info_result.get('error') is not None:
- raise signals.TestFailure(
- "Get interfaces info failed with {}".format(
- interface_info_result.get('error')))
- else:
- result = interface_info_result.get('result')
- if result is None:
- raise signals.TestFailure(
- "Interface info returned None: {}".format(result))
- self.log.info("Interface {} info: {}".format(
- identifier, result))
- raise signals.TestPass("Success")
-
def test_toggle_wlan_interface(self):
"""Test toggling the wlan interface if it exists.
@@ -131,43 +92,60 @@
Returns:
signals.TestPass if no errors
signals.TestFailure if there are any errors during the test.
+ signals.TestSkip if there are no wlan interfaces.
TAGS: Netstack
Priority: 1
"""
- interfaces = self.dut.netstack_lib.netstackListInterfaces()
- for item in interfaces.get('result'):
- # Find the WLAN interface
- if "wlan" in item.get('name'):
- identifier = item.get('id')
- # Disable the interface by ID.
- result = self.dut.netstack_lib.disableInterface(identifier)
- if result.get('error') is not None:
- raise signals.TestFailure(
- "Unable to disable wlan interface: {}".format(
- result.get('error')))
- # Check the current state of the interface.
- interface_info_result = self.dut.netstack_lib.getInterfaceInfo(
- identifier)
- interface_info = interface_info_result.get('result')
+ def get_wlan_interfaces():
+ result = self.dut.netstack_lib.netstackListInterfaces()
+ if (error := result.get('error')):
+ raise signals.TestFailure(
+ f'unable to list interfaces: {error}')
+ return [
+ interface for interface in result.get('result')
+ if 'wlan' in interface.get('name')
+ ]
- if len(interface_info.get('ipv4_addresses')) > 0:
- raise signals.TestFailure(
- "No Ipv4 Address should be present: {}".format(
- interface_info))
+ def get_ids(interfaces):
+ return [get_id(interface) for interface in interfaces]
- # TODO (35981): Verify other values when interface down.
+ wlan_interfaces = get_wlan_interfaces()
+ if not wlan_interfaces:
+ raise signals.TestSkip('no wlan interface found')
+ interface_ids = get_ids(wlan_interfaces)
- # Re-enable the interface
- result = self.dut.netstack_lib.enableInterface(identifier)
- if result.get('error') is not None:
- raise signals.TestFailure(
- "Unable to enable wlan interface: {}".format(
- result.get('error')))
+ # Disable the interfaces.
+ for identifier in interface_ids:
+ result = self.dut.netstack_lib.disableInterface(identifier)
+ if (error := result.get('error')):
+ raise signals.TestFailure(
+ f'failed to disable wlan interface {identifier}: {error}')
- # TODO (35981): Verify other values when interface up.
+ # Retrieve the interfaces again.
+ disabled_wlan_interfaces = get_wlan_interfaces()
+ disabled_interface_ids = get_ids(wlan_interfaces)
- raise signals.TestPass("Success")
+ if not disabled_interface_ids == interface_ids:
+ raise signals.TestFailure(
+ f'disabled interface IDs do not match original interface IDs: original={interface_ids} disabled={disabled_interface_ids}'
+ )
- raise signals.TestSkip("No WLAN interface found.")
+ # Check the current state of the interfaces.
+ for interface in disabled_interfaces:
+ if len(interface_info.get('ipv4_addresses')) > 0:
+ raise signals.TestFailure(
+ f'no Ipv4 Address should be present: {interface}')
+
+ # TODO (35981): Verify other values when interface down.
+
+ # Re-enable the interfaces.
+ for identifier in disabled_interface_ids:
+ result = self.dut.netstack_lib.enableInterface(identifier)
+ if (error := result.get('error')):
+ raise signals.TestFailure(
+ f'failed to enable wlan interface {identifier}: {error}')
+
+ # TODO (35981): Verify other values when interface up.
+ raise signals.TestPass("Success")
diff --git a/acts_tests/tests/google/fuchsia/netstack/NetstackIxiaTest.py b/acts_tests/tests/google/fuchsia/netstack/NetstackIxiaTest.py
index 129d28f..260928e 100644
--- a/acts_tests/tests/google/fuchsia/netstack/NetstackIxiaTest.py
+++ b/acts_tests/tests/google/fuchsia/netstack/NetstackIxiaTest.py
@@ -165,5 +165,6 @@
access_point.remove_bridge(bridge_name='ixia_bridge0')
"""Tests"""
+
def test_do_nothing(self):
return True
diff --git a/acts_tests/tests/google/fuchsia/netstack/ToggleWlanInterfaceStressTest.py b/acts_tests/tests/google/fuchsia/netstack/ToggleWlanInterfaceStressTest.py
new file mode 100644
index 0000000..9b60998
--- /dev/null
+++ b/acts_tests/tests/google/fuchsia/netstack/ToggleWlanInterfaceStressTest.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android secure 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 import signals
+import time
+from acts.base_test import BaseTestClass
+from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
+
+
+class ToggleWlanInterfaceStressTest(BaseTestClass):
+ def setup_class(self):
+ dut = self.user_params.get('dut', None)
+ if dut:
+ if dut == 'fuchsia_devices':
+ self.dut = create_wlan_device(self.fuchsia_devices[0])
+ elif dut == 'android_devices':
+ self.dut = create_wlan_device(self.android_devices[0])
+ else:
+ raise ValueError('Invalid DUT specified in config. (%s)' %
+ self.user_params['dut'])
+ else:
+ # Default is an Fuchsia device
+ self.dut = create_wlan_device(self.fuchsia_devices[0])
+
+ def test_iface_toggle_and_ping(self):
+ """Test that we don't error out when toggling WLAN interfaces.
+
+ Steps:
+ 1. Find a WLAN interface
+ 2. Destroy it
+ 3. Create a new WLAN interface
+ 4. Ping after association
+ 5. Repeat 1-4 1,000 times
+
+ Expected Result:
+ Verify there are no errors in destroying the wlan interface.
+
+ Returns:
+ signals.TestPass if no errors
+ signals.TestFailure if there are any errors during the test.
+
+ TAGS: WLAN, Stability
+ Priority: 1
+ """
+
+ # Test assumes you've already connected to some AP.
+
+ for i in range(1000):
+ wlan_interfaces = self.dut.get_wlan_interface_id_list()
+ print(wlan_interfaces)
+ if len(wlan_interfaces) < 1:
+ raise signals.TestFailure(
+ "Not enough wlan interfaces for test")
+ if not self.dut.destroy_wlan_interface(wlan_interfaces[0]):
+ raise signals.TestFailure("Failed to destroy WLAN interface")
+ # Really make sure it is dead
+ self.fuchsia_devices[0].send_command_ssh(
+ "wlan iface del {}".format(wlan_interfaces[0]))
+ # Grace period
+ time.sleep(2)
+ self.fuchsia_devices[0].send_command_ssh(
+ 'wlan iface new --phy 0 --role Client')
+ end_time = time.time() + 300
+ while time.time() < end_time:
+ time.sleep(1)
+ if self.dut.is_connected():
+ try:
+ ping_result = self.dut.ping("8.8.8.8", 10, 1000, 1000,
+ 25)
+ print(ping_result)
+ except Exception as err:
+ # TODO: Once we gain more stability, fail test when pinging fails
+ print("some err {}".format(err))
+ time.sleep(2) #give time for some traffic
+ break
+ if not self.dut.is_connected():
+ raise signals.TestFailure("Failed at iteration {}".format(i +
+ 1))
+ self.log.info("Iteration {} successful".format(i + 1))
+ raise signals.TestPass("Success")
diff --git a/acts_tests/tests/google/fuchsia/wlan/compliance/VapeInteropTest.py b/acts_tests/tests/google/fuchsia/wlan/compliance/VapeInteropTest.py
index 3cc7a74..962c1bf 100644
--- a/acts_tests/tests/google/fuchsia/wlan/compliance/VapeInteropTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/compliance/VapeInteropTest.py
@@ -32,6 +32,7 @@
* One Android or Fuchsia Device
* One Whirlwind Access Point
"""
+
def setup_class(self):
super().setup_class()
if 'dut' in self.user_params:
@@ -74,6 +75,7 @@
self.dut.turn_location_off_and_scan_toggle_off()
self.dut.disconnect()
self.dut.reset_wifi()
+ self.download_ap_logs()
self.access_point.stop_all_aps()
def on_fail(self, test_name, begin_time):
diff --git a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11ACTest.py b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11ACTest.py
index 47deadd..04adfab 100644
--- a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11ACTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11ACTest.py
@@ -115,6 +115,7 @@
* One Android device or Fuchsia device
* One Access Point
"""
+
def __init__(self, controllers):
WifiBaseTest.__init__(self, controllers)
self.tests = [
@@ -158,6 +159,7 @@
self.dut.turn_location_off_and_scan_toggle_off()
self.dut.disconnect()
self.dut.reset_wifi()
+ self.download_ap_logs()
self.access_point.stop_all_aps()
def on_fail(self, test_name, begin_time):
diff --git a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11NTest.py b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11NTest.py
index df5540f..ad0800f 100644
--- a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11NTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11NTest.py
@@ -70,6 +70,7 @@
* One Android device or Fuchsia device
* One Access Point
"""
+
def __init__(self, controllers):
WifiBaseTest.__init__(self, controllers)
self.tests = [
@@ -121,6 +122,7 @@
self.dut.turn_location_off_and_scan_toggle_off()
self.dut.disconnect()
self.dut.reset_wifi()
+ self.download_ap_logs()
self.access_point.stop_all_aps()
def on_fail(self, test_name, begin_time):
diff --git a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyComplianceABGTest.py b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyComplianceABGTest.py
index b3efacc..2d17f4b 100644
--- a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyComplianceABGTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyComplianceABGTest.py
@@ -32,6 +32,7 @@
* One Android device or Fuchsia device
* One Access Point
"""
+
def setup_class(self):
super().setup_class()
if 'dut' in self.user_params:
@@ -122,6 +123,7 @@
self.dut.turn_location_off_and_scan_toggle_off()
self.dut.disconnect()
self.dut.reset_wifi()
+ self.download_ap_logs()
self.access_point.stop_all_aps()
def on_fail(self, test_name, begin_time):
diff --git a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanSecurityComplianceABGTest.py b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanSecurityComplianceABGTest.py
index 3e72a51..a32c7c4 100644
--- a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanSecurityComplianceABGTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanSecurityComplianceABGTest.py
@@ -39,6 +39,7 @@
security_profile_generator: The function that generates the security
profile object
"""
+
@wraps(test_func)
def security_profile_generator(self, *args, **kwargs):
"""Function that looks at the name of the function and determines what
@@ -54,7 +55,7 @@
*args: args that were sent to the original test function
**kwargs: kwargs that were sent to the original test function
Returns:
- The original fuction that was called
+ The original function that was called
"""
utf8_password_2g = '2𝔤_𝔊𝔬𝔬𝔤𝔩𝔢'
utf8_password_2g_french = 'du Feÿ Château'
@@ -162,6 +163,7 @@
* One Android device or Fuchsia device
* One Access Point
"""
+
def setup_class(self):
super().setup_class()
if 'dut' in self.user_params:
@@ -199,6 +201,7 @@
self.dut.turn_location_off_and_scan_toggle_off()
self.dut.disconnect()
self.dut.reset_wifi()
+ self.download_ap_logs()
self.access_point.stop_all_aps()
def on_fail(self, test_name, begin_time):
@@ -1105,11 +1108,14 @@
password=self.client_password,
force_wmm=False)
- asserts.assert_true(
+ asserts.assert_false(
self.dut.associate(self.ssid,
target_security=self.target_security,
target_pwd=self.client_password),
- 'Failed to associate.')
+ 'Expected failure to associate. This device must support TKIP and '
+ 'PMF, which is not supported on Fuchsia. If this device is a '
+ 'mainstream device, we need to reconsider adding support for TKIP '
+ 'and PMF on Fuchsia.')
@create_security_profile
def test_associate_11a_pmf_sec_wpa2_psk_ptk_ccmp(self):
@@ -1156,11 +1162,14 @@
password=self.client_password,
force_wmm=False)
- asserts.assert_true(
+ asserts.assert_false(
self.dut.associate(self.ssid,
target_security=self.target_security,
target_pwd=self.client_password),
- 'Failed to associate.')
+ 'Expected failure to associate. This device must support TKIP and '
+ 'PMF, which is not supported on Fuchsia. If this device is a '
+ 'mainstream device, we need to reconsider adding support for TKIP '
+ 'and PMF on Fuchsia.')
@create_security_profile
def test_associate_11a_pmf_max_length_password_sec_wpa2_psk_ptk_ccmp(self):
@@ -1208,11 +1217,14 @@
password=self.client_password,
force_wmm=False)
- asserts.assert_true(
+ asserts.assert_false(
self.dut.associate(self.ssid,
target_security=self.target_security,
target_pwd=self.client_password),
- 'Failed to associate.')
+ 'Expected failure to associate. This device must support TKIP and '
+ 'PMF, which is not supported on Fuchsia. If this device is a '
+ 'mainstream device, we need to reconsider adding support for TKIP '
+ 'and PMF on Fuchsia.')
@create_security_profile
def test_associate_11a_pmf_max_length_psk_sec_wpa2_psk_ptk_ccmp(self):
@@ -1261,11 +1273,14 @@
frag_threshold=430,
force_wmm=False)
- asserts.assert_true(
+ asserts.assert_false(
self.dut.associate(self.ssid,
target_security=self.target_security,
target_pwd=self.client_password),
- 'Failed to associate.')
+ 'Expected failure to associate. This device must support TKIP and '
+ 'PMF, which is not supported on Fuchsia. If this device is a '
+ 'mainstream device, we need to reconsider adding support for TKIP '
+ 'and PMF on Fuchsia.')
@create_security_profile
def test_associate_11a_pmf_frag_430_sec_wpa2_psk_ptk_ccmp(self):
@@ -1315,11 +1330,14 @@
rts_threshold=256,
force_wmm=False)
- asserts.assert_true(
+ asserts.assert_false(
self.dut.associate(self.ssid,
target_security=self.target_security,
target_pwd=self.client_password),
- 'Failed to associate.')
+ 'Expected failure to associate. This device must support TKIP and '
+ 'PMF, which is not supported on Fuchsia. If this device is a '
+ 'mainstream device, we need to reconsider adding support for TKIP '
+ 'and PMF on Fuchsia.')
@create_security_profile
def test_associate_11a_pmf_rts_256_sec_wpa2_psk_ptk_ccmp(self):
@@ -4133,11 +4151,14 @@
password=self.client_password,
force_wmm=False)
- asserts.assert_true(
+ asserts.assert_false(
self.dut.associate(self.ssid,
target_security=self.target_security,
target_pwd=self.client_password),
- 'Failed to associate.')
+ 'Expected failure to associate. This device must support TKIP and '
+ 'PMF, which is not supported on Fuchsia. If this device is a '
+ 'mainstream device, we need to reconsider adding support for TKIP '
+ 'and PMF on Fuchsia.')
@create_security_profile
def test_associate_11bg_pmf_sec_wpa2_psk_ptk_ccmp(self):
@@ -4185,11 +4206,14 @@
password=self.client_password,
force_wmm=False)
- asserts.assert_true(
+ asserts.assert_false(
self.dut.associate(self.ssid,
target_security=self.target_security,
target_pwd=self.client_password),
- 'Failed to associate.')
+ 'Expected failure to associate. This device must support TKIP and '
+ 'PMF, which is not supported on Fuchsia. If this device is a '
+ 'mainstream device, we need to reconsider adding support for TKIP '
+ 'and PMF on Fuchsia.')
@create_security_profile
def test_associate_11bg_pmf_max_length_password_sec_wpa2_psk_ptk_ccmp(
@@ -4238,11 +4262,14 @@
password=self.client_password,
force_wmm=False)
- asserts.assert_true(
+ asserts.assert_false(
self.dut.associate(self.ssid,
target_security=self.target_security,
target_pwd=self.client_password),
- 'Failed to associate.')
+ 'Expected failure to associate. This device must support TKIP and '
+ 'PMF, which is not supported on Fuchsia. If this device is a '
+ 'mainstream device, we need to reconsider adding support for TKIP '
+ 'and PMF on Fuchsia.')
@create_security_profile
def test_associate_11bg_pmf_max_length_psk_sec_wpa2_psk_ptk_ccmp(self):
@@ -4291,11 +4318,14 @@
frag_threshold=430,
force_wmm=False)
- asserts.assert_true(
+ asserts.assert_false(
self.dut.associate(self.ssid,
target_security=self.target_security,
target_pwd=self.client_password),
- 'Failed to associate.')
+ 'Expected failure to associate. This device must support TKIP and '
+ 'PMF, which is not supported on Fuchsia. If this device is a '
+ 'mainstream device, we need to reconsider adding support for TKIP '
+ 'and PMF on Fuchsia.')
@create_security_profile
def test_associate_11bg_pmf_frag_430_sec_wpa2_psk_ptk_ccmp(self):
@@ -4345,11 +4375,14 @@
rts_threshold=256,
force_wmm=False)
- asserts.assert_true(
+ asserts.assert_false(
self.dut.associate(self.ssid,
target_security=self.target_security,
target_pwd=self.client_password),
- 'Failed to associate.')
+ 'Expected failure to associate. This device must support TKIP and '
+ 'PMF, which is not supported on Fuchsia. If this device is a '
+ 'mainstream device, we need to reconsider adding support for TKIP '
+ 'and PMF on Fuchsia.')
@create_security_profile
def test_associate_11bg_pmf_rts_256_sec_wpa2_psk_ptk_ccmp(self):
diff --git a/acts_tests/tests/google/fuchsia/wlan/facade/WlanDeprecatedConfigurationTest.py b/acts_tests/tests/google/fuchsia/wlan/facade/WlanDeprecatedConfigurationTest.py
index 574a9c9..44e6731 100644
--- a/acts_tests/tests/google/fuchsia/wlan/facade/WlanDeprecatedConfigurationTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/facade/WlanDeprecatedConfigurationTest.py
@@ -14,9 +14,10 @@
# License for the specific language governing permissions and limitations under
# the License.
-from acts.base_test import BaseTestClass
from acts import asserts
from acts import utils
+from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
+from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
AP_ROLE = 'Ap'
DEFAULT_SSID = 'testssid'
@@ -28,11 +29,11 @@
TEST_MAC_ADDR_SECONDARY = 'bc:9a:78:56:34:12'
-class WlanDeprecatedConfigurationTest(BaseTestClass):
+class WlanDeprecatedConfigurationTest(AbstractDeviceWlanDeviceBaseTest):
"""Tests for WlanDeprecatedConfigurationFacade"""
def setup_class(self):
super().setup_class()
- self.dut = self.fuchsia_devices[0]
+ self.dut = create_wlan_device(self.fuchsia_devices[0])
def setup_test(self):
self._stop_soft_aps()
@@ -40,20 +41,6 @@
def teardown_test(self):
self._stop_soft_aps()
- def on_fail(self, test_name, begin_time):
- for fd in self.fuchsia_devices:
- try:
- fd.take_bug_report(test_name, begin_time)
- fd.get_log(test_name, begin_time)
- except Exception:
- pass
-
- try:
- if fd.device.hard_reboot_on_fail:
- fd.hard_power_cycle(self.pdu_devices)
- except AttributeError:
- pass
-
def _get_ap_interface_mac_address(self):
"""Retrieves mac address from wlan interface with role ap
@@ -64,13 +51,14 @@
ConnectionError, if SL4F calls fail
AttributeError, if no interface has role 'Ap'
"""
- wlan_ifaces = self.dut.wlan_lib.wlanGetIfaceIdList()
+ wlan_ifaces = self.dut.device.wlan_lib.wlanGetIfaceIdList()
if wlan_ifaces.get('error'):
raise ConnectionError('Failed to get wlan interface IDs: %s' %
wlan_ifaces['error'])
for wlan_iface in wlan_ifaces['result']:
- iface_info = self.dut.wlan_lib.wlanQueryInterface(wlan_iface)
+ iface_info = self.dut.device.wlan_lib.wlanQueryInterface(
+ wlan_iface)
if iface_info.get('error'):
raise ConnectionError('Failed to query wlan iface: %s' %
iface_info['error'])
@@ -87,8 +75,9 @@
Raises:
ConnectionError, if SL4F call fails.
"""
- self.log.info('Starting SoftAP on Fuchsia device (%s).' % self.dut.ip)
- response = self.dut.wlan_ap_policy_lib.wlanStartAccessPoint(
+ self.log.info('Starting SoftAP on Fuchsia device (%s).' %
+ self.dut.device.ip)
+ response = self.dut.device.wlan_ap_policy_lib.wlanStartAccessPoint(
DEFAULT_SSID, DEFAULT_SECURITY, DEFAULT_PASSWORD,
DEFAULT_CONNECTIVITY_MODE, DEFAULT_OPERATING_BAND)
if response.get('error'):
@@ -102,7 +91,7 @@
ConnectionError, if SL4F call fails.
"""
self.log.info('Stopping SoftAP.')
- response = self.dut.wlan_ap_policy_lib.wlanStopAllAccessPoint()
+ response = self.dut.device.wlan_ap_policy_lib.wlanStopAllAccessPoint()
if response.get('error'):
raise ConnectionError('Failed to stop SoftAP: %s' %
response['error'])
@@ -118,8 +107,8 @@
self.log.info(
'Suggesting AP mac addr (%s) via wlan_deprecated_configuration_lib.'
% mac_addr)
- response = self.dut.wlan_deprecated_configuration_lib.wlanSuggestAccessPointMacAddress(
- mac_addr)
+ response = (self.dut.device.wlan_deprecated_configuration_lib.
+ wlanSuggestAccessPointMacAddress(mac_addr))
if response.get('error'):
asserts.fail('Failed to suggest AP mac address (%s): %s' %
(mac_addr, response['error']))
diff --git a/acts_tests/tests/google/fuchsia/wlan/facade/WlanFacadeTest.py b/acts_tests/tests/google/fuchsia/wlan/facade/WlanFacadeTest.py
index ffe86fa..9f884b6 100644
--- a/acts_tests/tests/google/fuchsia/wlan/facade/WlanFacadeTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/facade/WlanFacadeTest.py
@@ -17,34 +17,24 @@
Script for verifying that we can invoke methods of the WlanFacade.
"""
-from acts.base_test import BaseTestClass
+import array
+
from acts import asserts, signals
+from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
+from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
-class WlanFacadeTest(BaseTestClass):
+class WlanFacadeTest(AbstractDeviceWlanDeviceBaseTest):
def setup_class(self):
super().setup_class()
if len(self.fuchsia_devices) < 1:
raise signals.TestAbortClass(
"Sorry, please try verifying FuchsiaDevice is in your "
"config file and try again.")
-
- def on_fail(self, test_name, begin_time):
- for fd in self.fuchsia_devices:
- try:
- fd.take_bug_report(test_name, begin_time)
- fd.get_log(test_name, begin_time)
- except Exception:
- pass
-
- try:
- if fd.device.hard_reboot_on_fail:
- fd.hard_power_cycle(self.pdu_devices)
- except AttributeError:
- pass
+ self.dut = create_wlan_device(self.fuchsia_devices[0])
def test_get_phy_id_list(self):
- result = self.fuchsia_devices[0].wlan_lib.wlanPhyIdList()
+ result = self.dut.device.wlan_lib.wlanPhyIdList()
error = result['error']
asserts.assert_true(error is None, error)
@@ -52,7 +42,7 @@
return True
def test_get_country(self):
- wlan_lib = self.fuchsia_devices[0].wlan_lib
+ wlan_lib = self.dut.device.wlan_lib
result = wlan_lib.wlanPhyIdList()
error = result['error']
@@ -68,3 +58,19 @@
encoding='us-ascii')
self.log.info('Got country %s (%s)', country_string, country_bytes)
return True
+
+ def test_get_dev_path(self):
+ wlan_lib = self.dut.device.wlan_lib
+
+ result = wlan_lib.wlanPhyIdList()
+ error = result['error']
+ asserts.assert_true(error is None, error)
+ phy_id = result['result'][0]
+
+ result = wlan_lib.wlanGetDevPath(phy_id)
+ error = result['error']
+ asserts.assert_true(error is None, error)
+
+ dev_path = result['result']
+ self.log.info('Got device path: %s', dev_path)
+ return True
diff --git a/acts_tests/tests/google/fuchsia/wlan/facade/WlanStatusTest.py b/acts_tests/tests/google/fuchsia/wlan/facade/WlanStatusTest.py
index 0228940..10344b2 100644
--- a/acts_tests/tests/google/fuchsia/wlan/facade/WlanStatusTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/facade/WlanStatusTest.py
@@ -18,10 +18,10 @@
"""
from acts import signals
-from acts.base_test import BaseTestClass
+from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
-class WlanStatusTest(BaseTestClass):
+class WlanStatusTest(AbstractDeviceWlanDeviceBaseTest):
"""WLAN status test class.
Test Bed Requirements:
@@ -35,19 +35,9 @@
def on_fail(self, test_name, begin_time):
for fd in self.fuchsia_devices:
- try:
- fd.take_bug_report(test_name, begin_time)
- fd.get_log(test_name, begin_time)
- except Exception:
- pass
-
- try:
- if fd.device.hard_reboot_on_fail:
- fd.hard_power_cycle(self.pdu_devices)
- fd.configure_wlan(association_mechanism='policy',
- preserve_saved_networks=True)
- except AttributeError:
- pass
+ super().on_device_fail(fd, test_name, begin_time)
+ fd.configure_wlan(association_mechanism='policy',
+ preserve_saved_networks=True)
def test_wlan_stopped_client_status(self):
"""Queries WLAN status on DUTs with no WLAN ifaces.
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/BeaconLossTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/BeaconLossTest.py
index aaef98f..a2a763b 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/BeaconLossTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/BeaconLossTest.py
@@ -29,7 +29,6 @@
from acts import asserts
from acts import signals
from acts import utils
-from acts.base_test import BaseTestClass
from acts.controllers.access_point import setup_ap
from acts.controllers.ap_lib import hostapd_constants
@@ -71,7 +70,7 @@
else:
# Default is an android device, just like the other tests
self.dut = create_wlan_device(self.android_devices[0])
- self.ap = self.access_points[0]
+ self.access_point = self.access_points[0]
self.num_of_iterations = int(
self.user_params.get("beacon_loss_test_iterations",
self.num_of_iterations))
@@ -81,23 +80,25 @@
self.dut.disconnect()
self.dut.reset_wifi()
# ensure radio is on, in case the test failed while the radio was off
- self.ap.iwconfig.ap_iwconfig(self.in_use_interface, "txpower on")
- self.ap.stop_all_aps()
+ self.access_point.iwconfig.ap_iwconfig(self.in_use_interface,
+ "txpower on")
+ self.download_ap_logs()
+ self.access_point.stop_all_aps()
def on_fail(self, test_name, begin_time):
super().on_fail(test_name, begin_time)
- self.ap.stop_all_aps()
+ self.access_point.stop_all_aps()
def beacon_loss(self, channel):
- setup_ap(access_point=self.ap,
+ setup_ap(access_point=self.access_point,
profile_name='whirlwind',
channel=channel,
ssid=self.ssid)
time.sleep(self.wait_ap_startup_s)
if channel > 14:
- self.in_use_interface = self.ap.wlan_5g
+ self.in_use_interface = self.access_point.wlan_5g
else:
- self.in_use_interface = self.ap.wlan_2g
+ self.in_use_interface = self.access_point.wlan_2g
# TODO(b/144505723): [ACTS] update BeaconLossTest.py to handle client
# roaming, saved networks, etc.
@@ -111,7 +112,8 @@
for _ in range(0, self.num_of_iterations):
# Turn off AP radio
self.log.info("turning off radio")
- self.ap.iwconfig.ap_iwconfig(self.in_use_interface, "txpower off")
+ self.access_point.iwconfig.ap_iwconfig(self.in_use_interface,
+ "txpower off")
time.sleep(self.wait_after_ap_txoff_s)
# Did we disconnect from AP?
@@ -120,7 +122,8 @@
# Turn on AP radio
self.log.info("turning on radio")
- self.ap.iwconfig.ap_iwconfig(self.in_use_interface, "txpower on")
+ self.access_point.iwconfig.ap_iwconfig(self.in_use_interface,
+ "txpower on")
time.sleep(self.wait_to_connect_after_ap_txon_s)
# Tell the client to connect
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/ChannelSwitchTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/ChannelSwitchTest.py
new file mode 100644
index 0000000..be8e3ca
--- /dev/null
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/ChannelSwitchTest.py
@@ -0,0 +1,378 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""
+Tests STA handling of channel switch announcements.
+"""
+
+import random
+import time
+
+from acts import asserts
+from acts.controllers.access_point import setup_ap
+from acts.controllers.ap_lib import hostapd_constants
+from acts.utils import rand_ascii_str
+from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
+from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
+from typing import Sequence
+
+
+class ChannelSwitchTest(AbstractDeviceWlanDeviceBaseTest):
+ # Time to wait between issuing channel switches
+ WAIT_BETWEEN_CHANNEL_SWITCHES_S = 15
+
+ # For operating class 115 tests.
+ GLOBAL_OPERATING_CLASS_115_CHANNELS = [36, 40, 44, 48]
+ # A channel outside the operating class.
+ NON_GLOBAL_OPERATING_CLASS_115_CHANNEL = 52
+
+ # For operating class 124 tests.
+ GLOBAL_OPERATING_CLASS_124_CHANNELS = [149, 153, 157, 161]
+ # A channel outside the operating class.
+ NON_GLOBAL_OPERATING_CLASS_124_CHANNEL = 52
+
+ def setup_class(self) -> None:
+ super().setup_class()
+ self.ssid = rand_ascii_str(10)
+ if 'dut' in self.user_params:
+ if self.user_params['dut'] == 'fuchsia_devices':
+ self.dut = create_wlan_device(self.fuchsia_devices[0])
+ elif self.user_params['dut'] == 'android_devices':
+ self.dut = create_wlan_device(self.android_devices[0])
+ else:
+ raise ValueError('Invalid DUT specified in config. (%s)' %
+ self.user_params['dut'])
+ else:
+ # Default is an android device, just like the other tests
+ self.dut = create_wlan_device(self.android_devices[0])
+ self.access_point = self.access_points[0]
+ self._stop_all_soft_aps()
+ self.in_use_interface = None
+
+ def teardown_test(self) -> None:
+ self.dut.disconnect()
+ self.dut.reset_wifi()
+ self.download_ap_logs()
+ self.access_point.stop_all_aps()
+
+ # TODO(fxbug.dev/85738): Change band type to an enum.
+ def channel_switch(self,
+ band: str,
+ starting_channel: int,
+ channel_switches: Sequence[int],
+ test_with_soft_ap: bool = False) -> None:
+ """Setup and run a channel switch test with the given parameters.
+
+ Creates an AP, associates to it, and then issues channel switches
+ through the provided channels. After each channel switch, the test
+ checks that the DUT is connected for a period of time before considering
+ the channel switch successful. If directed to start a SoftAP, the test
+ will also check that the SoftAP is on the expected channel after each
+ channel switch.
+
+ Args:
+ band: band that AP will use, must be a valid band (e.g.
+ hostapd_constants.BAND_2G)
+ starting_channel: channel number that AP will use at startup
+ channel_switches: ordered list of channels that the test will
+ attempt to switch to
+ test_with_soft_ap: whether to start a SoftAP before beginning the
+ channel switches (default is False); note that if a SoftAP is
+ started, the test will also check that the SoftAP handles
+ channel switches correctly
+ """
+ asserts.assert_true(
+ band in [hostapd_constants.BAND_2G, hostapd_constants.BAND_5G],
+ 'Failed to setup AP, invalid band {}'.format(band))
+
+ self.current_channel_num = starting_channel
+ if band == hostapd_constants.BAND_5G:
+ self.in_use_interface = self.access_point.wlan_5g
+ elif band == hostapd_constants.BAND_2G:
+ self.in_use_interface = self.access_point.wlan_2g
+ asserts.assert_true(
+ self._channels_valid_for_band([self.current_channel_num], band),
+ 'starting channel {} not a valid channel for band {}'.format(
+ self.current_channel_num, band))
+
+ setup_ap(access_point=self.access_point,
+ profile_name='whirlwind',
+ channel=self.current_channel_num,
+ ssid=self.ssid)
+ if test_with_soft_ap:
+ self._start_soft_ap()
+ self.log.info('sending associate command for ssid %s', self.ssid)
+ self.dut.associate(target_ssid=self.ssid)
+ asserts.assert_true(self.dut.is_connected(), 'Failed to connect.')
+
+ asserts.assert_true(channel_switches,
+ 'Cannot run test, no channels to switch to')
+ asserts.assert_true(
+ self._channels_valid_for_band(channel_switches, band),
+ 'channel_switches {} includes invalid channels for band {}'.format(
+ channel_switches, band))
+
+ for channel_num in channel_switches:
+ if channel_num == self.current_channel_num:
+ continue
+ self.log.info('channel switch: {} -> {}'.format(
+ self.current_channel_num, channel_num))
+ self.access_point.channel_switch(self.in_use_interface,
+ channel_num)
+ channel_num_after_switch = self.access_point.get_current_channel(
+ self.in_use_interface)
+ asserts.assert_true(channel_num_after_switch == channel_num,
+ 'AP failed to channel switch')
+ self.current_channel_num = channel_num
+
+ # Check periodically to see if DUT stays connected. Sometimes
+ # CSA-induced disconnects occur seconds after last channel switch.
+ for _ in range(self.WAIT_BETWEEN_CHANNEL_SWITCHES_S):
+ asserts.assert_true(
+ self.dut.is_connected(),
+ 'Failed to stay connected after channel switch.')
+ client_channel = self._client_channel()
+ asserts.assert_equal(
+ client_channel, channel_num,
+ 'Client interface on wrong channel ({})'.format(
+ client_channel))
+ if test_with_soft_ap:
+ soft_ap_channel = self._soft_ap_channel()
+ asserts.assert_equal(
+ soft_ap_channel, channel_num,
+ 'SoftAP interface on wrong channel ({})'.format(
+ soft_ap_channel))
+ time.sleep(1)
+
+ def test_channel_switch_2g(self) -> None:
+ """Channel switch through all (US only) channels in the 2 GHz band."""
+ self.channel_switch(
+ band=hostapd_constants.BAND_2G,
+ starting_channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
+ channel_switches=hostapd_constants.US_CHANNELS_2G)
+
+ def test_channel_switch_2g_with_soft_ap(self) -> None:
+ """Channel switch through (US only) 2 Ghz channels with SoftAP up."""
+ self.channel_switch(
+ band=hostapd_constants.BAND_2G,
+ starting_channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
+ channel_switches=hostapd_constants.US_CHANNELS_2G,
+ test_with_soft_ap=True)
+
+ def test_channel_switch_2g_shuffled_with_soft_ap(self) -> None:
+ """Switch through shuffled (US only) 2 Ghz channels with SoftAP up."""
+ channels = hostapd_constants.US_CHANNELS_2G
+ random.shuffle(channels)
+ self.log.info('Shuffled channel switch sequence: {}'.format(channels))
+ self.channel_switch(
+ band=hostapd_constants.BAND_2G,
+ starting_channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
+ channel_switches=channels,
+ test_with_soft_ap=True)
+
+ # TODO(fxbug.dev/84777): This test fails.
+ def test_channel_switch_5g(self) -> None:
+ """Channel switch through all (US only) channels in the 5 GHz band."""
+ self.channel_switch(
+ band=hostapd_constants.BAND_5G,
+ starting_channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
+ channel_switches=hostapd_constants.US_CHANNELS_5G)
+
+ # TODO(fxbug.dev/84777): This test fails.
+ def test_channel_switch_5g_with_soft_ap(self) -> None:
+ """Channel switch through (US only) 5 GHz channels with SoftAP up."""
+ self.channel_switch(
+ band=hostapd_constants.BAND_5G,
+ starting_channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
+ channel_switches=hostapd_constants.US_CHANNELS_5G,
+ test_with_soft_ap=True)
+
+ def test_channel_switch_5g_shuffled_with_soft_ap(self) -> None:
+ """Switch through shuffled (US only) 5 Ghz channels with SoftAP up."""
+ channels = hostapd_constants.US_CHANNELS_5G
+ random.shuffle(channels)
+ self.log.info('Shuffled channel switch sequence: {}'.format(channels))
+ self.channel_switch(
+ band=hostapd_constants.BAND_5G,
+ starting_channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
+ channel_switches=channels,
+ test_with_soft_ap=True)
+
+ # TODO(fxbug.dev/84777): This test fails.
+ def test_channel_switch_regression_global_operating_class_115(
+ self) -> None:
+ """Channel switch into, through, and out of global op. class 115 channels.
+
+ Global operating class 115 is described in IEEE 802.11-2016 Table E-4.
+ Regression test for fxbug.dev/84777.
+ """
+ channels = self.GLOBAL_OPERATING_CLASS_115_CHANNELS + [
+ self.NON_GLOBAL_OPERATING_CLASS_115_CHANNEL
+ ]
+ self.channel_switch(
+ band=hostapd_constants.BAND_5G,
+ starting_channel=self.NON_GLOBAL_OPERATING_CLASS_115_CHANNEL,
+ channel_switches=channels)
+
+ # TODO(fxbug.dev/84777): This test fails.
+ def test_channel_switch_regression_global_operating_class_115_with_soft_ap(
+ self) -> None:
+ """Test global operating class 124 channel switches, with SoftAP.
+
+ Regression test for fxbug.dev/84777.
+ """
+ channels = self.GLOBAL_OPERATING_CLASS_115_CHANNELS + [
+ self.NON_GLOBAL_OPERATING_CLASS_115_CHANNEL
+ ]
+ self.channel_switch(
+ band=hostapd_constants.BAND_5G,
+ starting_channel=self.NON_GLOBAL_OPERATING_CLASS_115_CHANNEL,
+ channel_switches=channels,
+ test_with_soft_ap=True)
+
+ # TODO(fxbug.dev/84777): This test fails.
+ def test_channel_switch_regression_global_operating_class_124(
+ self) -> None:
+ """Switch into, through, and out of global op. class 124 channels.
+
+ Global operating class 124 is described in IEEE 802.11-2016 Table E-4.
+ Regression test for fxbug.dev/64279.
+ """
+ channels = self.GLOBAL_OPERATING_CLASS_124_CHANNELS + [
+ self.NON_GLOBAL_OPERATING_CLASS_124_CHANNEL
+ ]
+ self.channel_switch(
+ band=hostapd_constants.BAND_5G,
+ starting_channel=self.NON_GLOBAL_OPERATING_CLASS_124_CHANNEL,
+ channel_switches=channels)
+
+ # TODO(fxbug.dev/84777): This test fails.
+ def test_channel_switch_regression_global_operating_class_124_with_soft_ap(
+ self) -> None:
+ """Test global operating class 124 channel switches, with SoftAP.
+
+ Regression test for fxbug.dev/64279.
+ """
+ channels = self.GLOBAL_OPERATING_CLASS_124_CHANNELS + [
+ self.NON_GLOBAL_OPERATING_CLASS_124_CHANNEL
+ ]
+ self.channel_switch(
+ band=hostapd_constants.BAND_5G,
+ starting_channel=self.NON_GLOBAL_OPERATING_CLASS_124_CHANNEL,
+ channel_switches=channels,
+ test_with_soft_ap=True)
+
+ def _channels_valid_for_band(self, channels: Sequence[int],
+ band: str) -> bool:
+ """Determine if the channels are valid for the band (US only).
+
+ Args:
+ channels: channel numbers
+ band: a valid band (e.g. hostapd_constants.BAND_2G)
+ """
+ if band == hostapd_constants.BAND_2G:
+ band_channels = frozenset(hostapd_constants.US_CHANNELS_2G)
+ elif band == hostapd_constants.BAND_5G:
+ band_channels = frozenset(hostapd_constants.US_CHANNELS_5G)
+ else:
+ asserts.fail('Invalid band {}'.format(band))
+ channels_set = frozenset(channels)
+ if channels_set <= band_channels:
+ return True
+ return False
+
+ def _start_soft_ap(self) -> None:
+ """Start a SoftAP on the DUT.
+
+ Raises:
+ EnvironmentError: if the SoftAP does not start
+ """
+ ssid = rand_ascii_str(10)
+ security_type = 'none'
+ password = ''
+ connectivity_mode = 'local_only'
+ operating_band = 'any'
+
+ self.log.info('Starting SoftAP on DUT')
+
+ response = self.dut.device.wlan_ap_policy_lib.wlanStartAccessPoint(
+ ssid, security_type, password, connectivity_mode, operating_band)
+ if response.get('error'):
+ raise EnvironmentError('SL4F: Failed to setup SoftAP. Err: %s' %
+ response['error'])
+ self.log.info('SoftAp network (%s) is up.' % ssid)
+
+ def _stop_all_soft_aps(self) -> None:
+ """Stops all SoftAPs on Fuchsia Device.
+
+ Raises:
+ EnvironmentError: if SoftAP stop call fails
+ """
+ response = self.dut.device.wlan_ap_policy_lib.wlanStopAllAccessPoint()
+ if response.get('error'):
+ raise EnvironmentError(
+ 'SL4F: Failed to stop all SoftAPs. Err: %s' %
+ response['error'])
+
+ def _client_channel(self) -> int:
+ """Determine the channel of the DUT client interface.
+
+ If the interface is not connected, the method will assert a test
+ failure.
+
+ Returns: channel number
+
+ Raises:
+ EnvironmentError: if client interface channel cannot be
+ determined
+ """
+ status = self.dut.status()
+ if status['error']:
+ raise EnvironmentError('Could not determine client channel')
+
+ result = status['result']
+ if isinstance(result, dict):
+ if result.get('Connected'):
+ return result['Connected']['channel']['primary']
+ asserts.fail('Client interface not connected')
+ raise EnvironmentError('Could not determine client channel')
+
+ def _soft_ap_channel(self) -> int:
+ """Determine the channel of the DUT SoftAP interface.
+
+ If the interface is not connected, the method will assert a test
+ failure.
+
+ Returns: channel number
+
+ Raises:
+ EnvironmentError: if SoftAP interface channel cannot be determined.
+ """
+ iface_ids = self.dut.get_wlan_interface_id_list()
+ for iface_id in iface_ids:
+ query = self.dut.device.wlan_lib.wlanQueryInterface(iface_id)
+ if query['error']:
+ continue
+ query_result = query['result']
+ if type(query_result) is dict and query_result.get('role') == 'Ap':
+ status = self.dut.device.wlan_lib.wlanStatus(iface_id)
+ if status['error']:
+ continue
+ status_result = status['result']
+ if isinstance(status_result, dict):
+ if status_result.get('Connected'):
+ return status_result['Connected']['channel']['primary']
+ asserts.fail('SoftAP interface not connected')
+ raise EnvironmentError('Could not determine SoftAP channel')
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/ConnectionStressTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/ConnectionStressTest.py
index 20e187d..64fc144 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/ConnectionStressTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/ConnectionStressTest.py
@@ -17,7 +17,6 @@
Script for testing WiFi connection and disconnection in a loop
"""
-from acts.base_test import BaseTestClass
import os
import uuid
@@ -47,7 +46,7 @@
self.ssid = rand_ascii_str(10)
self.fd = self.fuchsia_devices[0]
self.dut = create_wlan_device(self.fd)
- self.ap = self.access_points[0]
+ self.access_point = self.access_points[0]
self.num_of_iterations = int(
self.user_params.get("connection_stress_test_iterations",
self.num_of_iterations))
@@ -55,11 +54,12 @@
def teardown_test(self):
self.dut.reset_wifi()
- self.ap.stop_all_aps()
+ self.download_ap_logs()
+ self.access_point.stop_all_aps()
def on_fail(self, test_name, begin_time):
super().on_fail(test_name, begin_time)
- self.ap.stop_all_aps()
+ self.access_point.stop_all_aps()
def start_ap(self, profile, channel, security=None):
"""Starts an Access Point
@@ -69,7 +69,7 @@
channel: Channel to operate on
"""
self.log.info('Profile: %s, Channel: %d' % (profile, channel))
- setup_ap(access_point=self.ap,
+ setup_ap(access_point=self.access_point,
profile_name=profile,
channel=channel,
ssid=self.ssid,
@@ -132,7 +132,7 @@
time.sleep(1)
# Stop AP
- self.ap.stop_all_aps()
+ self.access_point.stop_all_aps()
if failed:
raise signals.TestFailure(
'One or more association attempt failed.')
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/DownloadStressTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/DownloadStressTest.py
index df83af3..5ec6290 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/DownloadStressTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/DownloadStressTest.py
@@ -21,17 +21,17 @@
import threading
import uuid
-from acts.base_test import BaseTestClass
from acts import signals
from acts.controllers.access_point import setup_ap
from acts.controllers.ap_lib import hostapd_constants
from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
+from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
from acts_contrib.test_utils.fuchsia import utils
from acts_contrib.test_utils.tel.tel_test_utils import setup_droid_properties
from acts.utils import rand_ascii_str
-class DownloadStressTest(BaseTestClass):
+class DownloadStressTest(AbstractDeviceWlanDeviceBaseTest):
# Default number of test iterations here.
# Override using parameter in config file.
# Eg: "download_stress_test_iterations": "10"
@@ -55,24 +55,24 @@
def setup_class(self):
super().setup_class()
self.ssid = rand_ascii_str(10)
- self.fd = self.fuchsia_devices[0]
- self.wlan_device = create_wlan_device(self.fd)
- self.ap = self.access_points[0]
+ self.dut = create_wlan_device(self.fuchsia_devices[0])
+ self.access_point = self.access_points[0]
self.num_of_iterations = int(
self.user_params.get("download_stress_test_iterations",
self.num_of_iterations))
- setup_ap(access_point=self.ap,
+ setup_ap(access_point=self.access_point,
profile_name='whirlwind',
channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
ssid=self.ssid)
- self.wlan_device.associate(self.ssid)
+ self.dut.associate(self.ssid)
def teardown_test(self):
self.download_threads_result.clear()
- self.wlan_device.disconnect()
- self.wlan_device.reset_wifi()
- self.ap.stop_all_aps()
+ self.dut.disconnect()
+ self.dut.reset_wifi()
+ self.download_ap_logs()
+ self.access_point.stop_all_aps()
def test_download_small(self):
self.log.info("Downloading small file")
@@ -90,7 +90,7 @@
def download_file(self, url):
self.log.info("Start downloading: %s" % url)
return utils.http_file_download_by_curl(
- self.fd,
+ self.dut.device,
url,
additional_args='--max-time %d --silent' % self.download_timeout_s)
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/PingStressTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/PingStressTest.py
index 8c31e65..5f8addc 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/PingStressTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/PingStressTest.py
@@ -17,7 +17,6 @@
Script for exercising various ping scenarios
"""
-from acts.base_test import BaseTestClass
import os
import threading
@@ -27,12 +26,13 @@
from acts.controllers.access_point import setup_ap
from acts.controllers.ap_lib import hostapd_constants
from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
+from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
from acts_contrib.test_utils.tel.tel_test_utils import setup_droid_properties
from acts_contrib.test_utils.fuchsia import utils
from acts.utils import rand_ascii_str
-class PingStressTest(BaseTestClass):
+class PingStressTest(AbstractDeviceWlanDeviceBaseTest):
# Timeout for ping thread in seconds
ping_thread_timeout_s = 60 * 5
@@ -47,20 +47,20 @@
super().setup_class()
self.ssid = rand_ascii_str(10)
- self.fd = self.fuchsia_devices[0]
- self.wlan_device = create_wlan_device(self.fd)
- self.ap = self.access_points[0]
- setup_ap(access_point=self.ap,
+ self.dut = create_wlan_device(self.fuchsia_devices[0])
+ self.access_point = self.access_points[0]
+ setup_ap(access_point=self.access_point,
profile_name='whirlwind',
channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
ssid=self.ssid,
setup_bridge=True)
- self.wlan_device.associate(self.ssid)
+ self.dut.associate(self.ssid)
def teardown_class(self):
- self.wlan_device.disconnect()
- self.wlan_device.reset_wifi()
- self.ap.stop_all_aps()
+ self.dut.disconnect()
+ self.dut.reset_wifi()
+ self.download_ap_logs()
+ self.access_point.stop_all_aps()
def send_ping(self,
dest_ip,
@@ -69,8 +69,8 @@
timeout=1000,
size=25):
self.log.info('Attempting to ping %s...' % dest_ip)
- ping_result = self.wlan_device.can_ping(dest_ip, count, interval,
- timeout, size)
+ ping_result = self.dut.can_ping(dest_ip, count, interval, timeout,
+ size)
if ping_result:
self.log.info('Ping was successful.')
else:
@@ -83,7 +83,7 @@
def ping_thread(self, dest_ip):
self.log.info('Attempting to ping %s...' % dest_ip)
- ping_result = self.wlan_device.can_ping(dest_ip, count=10, size=50)
+ ping_result = self.dut.can_ping(dest_ip, count=10, size=50)
if ping_result:
self.log.info('Success pinging: %s' % dest_ip)
else:
@@ -98,7 +98,7 @@
return self.send_ping('127.0.0.1')
def test_ping_AP(self):
- return self.send_ping(self.ap.ssh_settings.hostname)
+ return self.send_ping(self.access_point.ssh_settings.hostname)
def test_ping_with_params(self):
return self.send_ping(self.google_dns_1,
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/SoftApTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/SoftApTest.py
index 4f29672..ec74992 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/SoftApTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/SoftApTest.py
@@ -21,16 +21,15 @@
from acts import utils
from acts import asserts
-from acts.base_test import BaseTestClass
from acts.controllers import iperf_server
from acts.controllers import iperf_client
-from acts.controllers.access_point import setup_ap
+from acts.controllers.access_point import setup_ap, AccessPoint
from acts.controllers.ap_lib import hostapd_constants
from acts.controllers.ap_lib import hostapd_security
from acts.controllers.ap_lib.hostapd_utils import generate_random_password
from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
+from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
-ANDROID_DEFAULT_WLAN_INTERFACE = 'wlan0'
CONNECTIVITY_MODE_LOCAL = 'local_only'
CONNECTIVITY_MODE_UNRESTRICTED = 'unrestricted'
DEFAULT_AP_PROFILE = 'whirlwind'
@@ -41,7 +40,6 @@
DEFAULT_NO_ADDR_EXPECTED_TIMEOUT = 5
INTERFACE_ROLE_AP = 'Ap'
INTERFACE_ROLE_CLIENT = 'Client'
-INTERFACE_ROLES = {INTERFACE_ROLE_AP, INTERFACE_ROLE_CLIENT}
OPERATING_BAND_2G = 'only_2_4_ghz'
OPERATING_BAND_5G = 'only_5_ghz'
OPERATING_BAND_ANY = 'any'
@@ -134,26 +132,13 @@
pass
-class SoftApClient(object):
- def __init__(self, device):
- self.w_device = create_wlan_device(device)
- self.ip_client = iperf_client.IPerfClientOverAdb(device.serial)
-
-
-class WlanInterface(object):
- def __init__(self):
- self.name = None
- self.mac_addr = None
- self.ipv4 = None
-
-
-class SoftApTest(BaseTestClass):
+class SoftApTest(AbstractDeviceWlanDeviceBaseTest):
"""Tests for Fuchsia SoftAP
Testbed requirement:
* One Fuchsia device
- * At least one dlient (Android) device
- * For multi-client tests, at least two dlient (Android) devices are
+ * At least one client (Android) device
+ * For multi-client tests, at least two client (Android) devices are
required. Test will be skipped if less than two client devices are
present.
* For any tests that exercise client-mode (e.g. toggle tests, simultaneous
@@ -164,14 +149,19 @@
self.soft_ap_test_params = self.user_params.get(
'soft_ap_test_params', {})
self.dut = create_wlan_device(self.fuchsia_devices[0])
- self.dut.device.netstack_lib.init()
# TODO(fxb/51313): Add in device agnosticity for clients
+ # Create a wlan device and iperf client for each Android client
self.clients = []
+ self.iperf_clients_map = {}
for device in self.android_devices:
- self.clients.append(SoftApClient(device))
+ client_wlan_device = create_wlan_device(device)
+ self.clients.append(client_wlan_device)
+ self.iperf_clients_map[
+ client_wlan_device] = client_wlan_device.create_iperf_client()
self.primary_client = self.clients[0]
+ # Create an iperf server on the DUT, which will be used for any streaming.
self.iperf_server_config = {
'user': self.dut.device.ssh_username,
'host': self.dut.device.ip,
@@ -181,13 +171,17 @@
self.iperf_server_config, DEFAULT_IPERF_PORT, use_killall=True)
self.iperf_server.start()
+ # Attempt to create an ap iperf server. AP is only required for tests
+ # that use client mode.
try:
self.access_point = self.access_points[0]
+ self.ap_iperf_client = iperf_client.IPerfClientOverSsh(
+ self.user_params['AccessPoint'][0]['ssh_config'])
except AttributeError:
self.access_point = None
+ self.ap_iperf_client = None
- self.ap_iperf_client = iperf_client.IPerfClientOverSsh(
- self.user_params['AccessPoint'][0]['ssh_config'])
+ self.iperf_clients_map[self.access_point] = self.ap_iperf_client
def teardown_class(self):
# Because this is using killall, it will stop all iperf processes
@@ -198,9 +192,9 @@
ad.droid.wakeLockAcquireBright()
ad.droid.wakeUpNow()
for client in self.clients:
- client.w_device.disconnect()
- client.w_device.reset_wifi()
- client.w_device.wifi_toggle_state(True)
+ client.disconnect()
+ client.reset_wifi()
+ client.wifi_toggle_state(True)
self.stop_all_soft_aps()
if self.access_point:
self.access_point.stop_all_aps()
@@ -208,19 +202,16 @@
def teardown_test(self):
for client in self.clients:
- client.w_device.disconnect()
+ client.disconnect()
for ad in self.android_devices:
ad.droid.wakeLockRelease()
ad.droid.goToSleepNow()
self.stop_all_soft_aps()
if self.access_point:
+ self.download_ap_logs()
self.access_point.stop_all_aps()
self.dut.disconnect()
- def on_fail(self, test_name, begin_time):
- self.dut.take_bug_report(test_name, begin_time)
- self.dut.get_log(test_name, begin_time)
-
def start_soft_ap(self, settings):
"""Starts a softAP on Fuchsia device.
@@ -283,11 +274,11 @@
'SL4F: Failed to stop all SoftAPs. Err: %s' %
response['error'])
- def associate_with_soft_ap(self, w_device, settings):
+ def associate_with_soft_ap(self, device, soft_ap_settings):
"""Associates client device with softAP on Fuchsia device.
Args:
- w_device: wlan_device to associate with the softAP
+ device: wlan_device to associate with the softAP
settings: a dict containing softAP config params (see start_soft_ap)
for details
@@ -296,16 +287,16 @@
"""
self.log.info(
'Attempting to associate client %s with SoftAP on FuchsiaDevice '
- '(%s).' % (w_device.device.serial, self.dut.device.ip))
+ '(%s).' % (device.identifier, self.dut.identifier))
- check_connectivity = settings[
+ check_connectivity = soft_ap_settings[
'connectivity_mode'] == CONNECTIVITY_MODE_UNRESTRICTED
- associated = w_device.associate(
- settings['ssid'],
- target_pwd=settings.get('password'),
+ associated = device.associate(
+ soft_ap_settings['ssid'],
+ target_pwd=soft_ap_settings.get('password'),
target_security=hostapd_constants.
SECURITY_STRING_TO_DEFAULT_TARGET_SECURITY.get(
- settings['security_type'], None),
+ soft_ap_settings['security_type'], None),
check_connectivity=check_connectivity)
if not associated:
@@ -315,144 +306,87 @@
self.log.info('Client successfully associated with SoftAP.')
return True
- def disconnect_from_soft_ap(self, w_device):
+ def disconnect_from_soft_ap(self, device):
"""Disconnects client device from SoftAP.
Args:
- w_device: wlan_device to disconnect from SoftAP
+ device: wlan_device to disconnect from SoftAP
"""
self.log.info('Disconnecting device %s from SoftAP.' %
- w_device.device.serial)
- w_device.disconnect()
+ device.identifier)
+ device.disconnect()
- def get_dut_interface_by_role(self,
- role,
- wait_for_addr_timeout=DEFAULT_TIMEOUT):
- """Retrieves interface information from the FuchsiaDevice DUT based
- on the role.
+ def get_device_test_interface(self, device, role=None, channel=None):
+ """Retrieves test interface from a provided device, which can be the
+ FuchsiaDevice DUT, the AccessPoint, or an AndroidClient.
Args:
- role: string, the role of the interface to seek (e.g. Client or Ap)
-
- Raises:
- ConnectionError, if SL4F calls fail
- AttributeError, if device does not have an interface matching role
+ device: the device do get the test interface from. Either
+ FuchsiaDevice (DUT), Android client, or AccessPoint.
+ role: str, either "client" or "ap". Required for FuchsiaDevice (DUT)
+ channel: int, channel of the ap network. Required for AccessPoint.
Returns:
- WlanInterface object representing the interface matching role
+ String, name of test interface on given device.
"""
- if not role in INTERFACE_ROLES:
- raise ValueError('Unsupported interface role %s' % role)
- interface = WlanInterface()
-
- # Determine WLAN interface with role
- wlan_ifaces = self.dut.device.wlan_lib.wlanGetIfaceIdList()
- if wlan_ifaces.get('error'):
- raise ConnectionError('Failed to get wlan interface IDs: %s' %
- wlan_ifaces['error'])
-
- for wlan_iface in wlan_ifaces['result']:
- iface_info = self.dut.device.wlan_lib.wlanQueryInterface(
- wlan_iface)
- if iface_info.get('error'):
- raise ConnectionError('Failed to query wlan iface: %s' %
- iface_info['error'])
-
- if iface_info['result']['role'] == role:
- interface.mac_addr = iface_info['result']['mac_addr']
- break
+ if device is self.dut:
+ device.device.wlan_controller.update_wlan_interfaces()
+ if role == INTERFACE_ROLE_CLIENT:
+ return device.device.wlan_client_test_interface_name
+ elif role == INTERFACE_ROLE_AP:
+ return device.device.wlan_ap_test_interface_name
+ else:
+ raise ValueError('Unsupported interface role: %s' % role)
+ elif isinstance(device, AccessPoint):
+ if not channel:
+ raise ValueError(
+ 'Must provide a channel to get AccessPoint interface')
+ if channel < 36:
+ return device.wlan_2g
+ else:
+ return device.wlan_5g
else:
- raise LookupError('Failed to find a %s interface.' % role)
-
- # Retrieve interface info from netstack
- netstack_ifaces = self.dut.device.netstack_lib.netstackListInterfaces()
- if netstack_ifaces.get('error'):
- raise ConnectionError('Failed to get netstack ifaces: %s' %
- netstack_ifaces['error'])
-
- # TODO(fxb/51315): Once subnet information is available in
- # netstackListInterfaces store it to verify the clients ip address.
- for netstack_iface in netstack_ifaces['result']:
- if netstack_iface['mac'] == interface.mac_addr:
- interface.name = netstack_iface['name']
- if len(netstack_iface['ipv4_addresses']) > 0:
- interface.ipv4 = '.'.join(
- str(byte)
- for byte in netstack_iface['ipv4_addresses'][0])
- else:
- interface.ipv4 = self.wait_for_ipv4_address(
- self.dut,
- interface.name,
- timeout=wait_for_addr_timeout)
- self.log.info('DUT %s interface: %s. Has ipv4 address %s' %
- (role, interface.name, interface.ipv4))
- return interface
+ return device.get_default_wlan_test_interface()
def wait_for_ipv4_address(self,
- w_device,
+ device,
interface_name,
timeout=DEFAULT_TIMEOUT):
- # TODO(fxb/51315): Once subnet information is available in netstack, add a
- # subnet verification here.
""" Waits for interface on a wlan_device to get an ipv4 address.
Args:
- w_device: wlan_device to check interface
+ device: wlan_device or AccessPoint to check interface
interface_name: name of the interface to check
timeout: seconds to wait before raising an error
Raises:
ValueError, if interface does not have an ipv4 address after timeout
"""
-
+ if isinstance(device, AccessPoint):
+ comm_channel = device.ssh
+ else:
+ comm_channel = device.device
end_time = time.time() + timeout
while time.time() < end_time:
- ips = w_device.get_interface_ip_addresses(interface_name)
+ ips = utils.get_interface_ip_addresses(comm_channel,
+ interface_name)
if len(ips['ipv4_private']) > 0:
self.log.info('Device %s interface %s has ipv4 address %s' %
- (w_device.device.serial, interface_name,
+ (device.identifier, interface_name,
ips['ipv4_private'][0]))
return ips['ipv4_private'][0]
else:
time.sleep(1)
raise ConnectionError(
'After %s seconds, device %s still does not have an ipv4 address '
- 'on interface %s.' %
- (timeout, w_device.device.serial, interface_name))
+ 'on interface %s.' % (timeout, device.identifier, interface_name))
- def get_ap_ipv4_address(self, channel, timeout=DEFAULT_TIMEOUT):
- """Get APs ipv4 address (actual AP, not soft ap on DUT)
-
- Args:
- channel: int, channel of the network used to determine
- which interface to use
- """
- lowest_5ghz_channel = 36
- if channel < lowest_5ghz_channel:
- ap_interface = self.access_point.wlan_2g
- else:
- ap_interface = self.access_point.wlan_5g
- end_time = time.time() + timeout
- while time.time() < end_time:
- ap_ipv4_addresses = utils.get_interface_ip_addresses(
- self.access_point.ssh, ap_interface)['ipv4_private']
- if len(ap_ipv4_addresses) > 0:
- return ap_ipv4_addresses[0]
- else:
- self.log.debug(
- 'Access point does not have an ipv4 address on interface '
- '%s. Retrying in 1 second.' % ap_interface)
- else:
- raise ConnectionError(
- 'Access point never had an ipv4 address on interface %s.' %
- ap_interface)
-
- def device_can_ping_addr(self, w_device, dest_ip, timeout=DEFAULT_TIMEOUT):
+ def device_can_ping_addr(self, device, dest_ip, timeout=DEFAULT_TIMEOUT):
""" Verify wlan_device can ping a destination ip.
Args:
- w_device: wlan_device to initiate ping
+ device: wlan_device to initiate ping
dest_ip: ip to ping from wlan_device
Raises:
@@ -461,20 +395,20 @@
end_time = time.time() + timeout
while time.time() < end_time:
with utils.SuppressLogOutput():
- ping_result = w_device.can_ping(dest_ip)
+ ping_result = device.can_ping(dest_ip)
if ping_result:
self.log.info('Ping successful from device %s to dest ip %s.' %
- (w_device.identifier, dest_ip))
+ (device.identifier, dest_ip))
return True
else:
self.log.debug(
'Device %s could not ping dest ip %s. Retrying in 1 second.'
- % (w_device.identifier, dest_ip))
+ % (device.identifier, dest_ip))
time.sleep(1)
else:
self.log.info('Failed to ping from device %s to dest ip %s.' %
- (w_device.identifier, dest_ip))
+ (device.identifier, dest_ip))
return False
def run_iperf_traffic(self, ip_client, server_address, server_port=5201):
@@ -556,107 +490,69 @@
ip_client: iperf client to grab identifier from
"""
if type(ip_client) == iperf_client.IPerfClientOverAdb:
- return ip_client._android_device_or_serial
+ return ip_client._android_device_or_serial.serial
return ip_client._ssh_settings.hostname
- def dut_is_connected_as_client(self,
- channel,
- check_traffic=False,
- wait_for_addr_timeout=DEFAULT_TIMEOUT):
- """Checks if DUT is successfully connected to AP.
+ def device_is_connected_to_ap(self,
+ client,
+ ap,
+ channel=None,
+ check_traffic=False,
+ timeout=DEFAULT_TIMEOUT):
+ """ Returns whether client device can ping (and optionally pass traffic)
+ to the ap device.
Args:
- channel: int, channel of the AP network (to retrieve interfaces)
- check_traffic: bool, if true, verifies traffic between DUT and AP,
- else just checks ping.
- wait_for_addr_timeout: int, time, in seconds, to wait when getting
- DUT and AP addresses
-
- Returns:
- True, if connected correctly
- False, otherwise
+ client: device that should be associated. Either FuchsiaDevice (DUT)
+ or Android client
+ ap: device acting as AP. Either FuchsiaDevice (DUT) or AccessPoint.
+ channel: int, channel the AP is using. Required if ap is an
+ AccessPoint object.
+ check_traffic: bool, whether to attempt to pass traffic between
+ client and ap devices.
+ timeout: int, time in seconds to wait for devices to have ipv4
+ addresses
"""
try:
- dut_client_interface = self.get_dut_interface_by_role(
- INTERFACE_ROLE_CLIENT,
- wait_for_addr_timeout=wait_for_addr_timeout)
- ap_ipv4 = self.get_ap_ipv4_address(channel,
- timeout=wait_for_addr_timeout)
+ # Get interfaces
+ client_interface = self.get_device_test_interface(
+ client, INTERFACE_ROLE_CLIENT)
+ ap_interface = self.get_device_test_interface(
+ ap, role=INTERFACE_ROLE_AP, channel=channel)
+
+ # Get addresses
+ client_ipv4 = self.wait_for_ipv4_address(client,
+ client_interface,
+ timeout=timeout)
+ ap_ipv4 = self.wait_for_ipv4_address(ap,
+ ap_interface,
+ timeout=timeout)
except ConnectionError as err:
self.log.error(
'Failed to retrieve interfaces and addresses. Err: %s' % err)
return False
- if not self.device_can_ping_addr(self.dut, ap_ipv4):
- self.log.error('Failed to ping from DUT to AP.')
+ if not self.device_can_ping_addr(client, ap_ipv4):
+ self.log.error('Failed to ping from client to ap.')
return False
- if not self.device_can_ping_addr(self.access_point,
- dut_client_interface.ipv4):
- self.log.error('Failed to ping from AP to DUT.')
+ if not self.device_can_ping_addr(ap, client_ipv4):
+ self.log.error('Failed to ping from ap to client.')
return False
if check_traffic:
try:
- self.run_iperf_traffic(self.ap_iperf_client,
- dut_client_interface.ipv4)
+ if client is self.dut:
+ self.run_iperf_traffic(self.iperf_clients_map[ap],
+ client_ipv4)
+ else:
+ self.run_iperf_traffic(self.iperf_clients_map[client],
+ ap_ipv4)
except ConnectionError as err:
self.log.error('Failed to run traffic between DUT and AP.')
return False
return True
- def client_is_connected_to_soft_ap(
- self,
- client,
- client_interface=ANDROID_DEFAULT_WLAN_INTERFACE,
- check_traffic=False,
- wait_for_addr_timeout=DEFAULT_TIMEOUT):
- """Checks if client is successfully connected to DUT SoftAP.
-
- Args:
- client: SoftApClient to check
- client_interface: string, wlan interface name of client
- check_traffic: bool, if true, verifies traffic between client and
- DUT, else just checks ping.
- wait_for_addr_timeout: int, time, in seconds, to wait when getting
- DUT and client addresses
-
- Returns:
- True, if connected correctly
- False, otherwise
- """
-
- try:
- dut_ap_interface = self.get_dut_interface_by_role(
- INTERFACE_ROLE_AP, wait_for_addr_timeout=wait_for_addr_timeout)
- client_ipv4 = self.wait_for_ipv4_address(
- client.w_device,
- client_interface,
- timeout=wait_for_addr_timeout)
- except ConnectionError as err:
- self.log.error(
- 'Failed to retrieve interfaces and addresses. Err: %s' % err)
- return False
-
- if not self.device_can_ping_addr(self.dut, client_ipv4):
- self.log.error('Failed to ping client (%s) from DUT.' %
- client_ipv4)
- return False
- if not self.device_can_ping_addr(client.w_device,
- dut_ap_interface.ipv4):
- self.log.error('Failed to ping DUT from client (%s)' % client_ipv4)
- return False
-
- if check_traffic:
- try:
- self.run_iperf_traffic(client.ip_client, dut_ap_interface.ipv4)
- except ConnectionError as err:
- self.log.error(
- 'Failed to pass traffic between client (%s) and DUT.' %
- client_ipv4)
- return False
- return True
-
def verify_soft_ap_connectivity_from_state(self, state, client):
"""Verifies SoftAP state based on a client connection.
@@ -665,13 +561,14 @@
client: SoftApClient, to verify connectivity (or lack therof)
"""
if state == STATE_UP:
- return self.client_is_connected_to_soft_ap(client)
+ return self.device_is_connected_to_ap(client, self.dut)
else:
with utils.SuppressLogOutput():
try:
- return not self.client_is_connected_to_soft_ap(
+ return not self.device_is_connected_to_ap(
client,
- wait_for_addr_timeout=DEFAULT_NO_ADDR_EXPECTED_TIMEOUT)
+ self.dut,
+ timeout=DEFAULT_NO_ADDR_EXPECTED_TIMEOUT)
# Allow a failed to find ap interface error
except LookupError as err:
self.log.debug('Hit expected LookupError: %s' % err)
@@ -685,13 +582,17 @@
channel: int, channel of the APs network
"""
if state == STATE_UP:
- return self.dut_is_connected_as_client(channel)
+ return self.device_is_connected_to_ap(self.dut,
+ self.access_point,
+ channel=channel)
else:
with utils.SuppressLogOutput():
try:
- return not self.dut_is_connected_as_client(
- channel,
- wait_for_addr_timeout=DEFAULT_NO_ADDR_EXPECTED_TIMEOUT)
+ return not self.device_is_connected_to_ap(
+ self.dut,
+ self.access_point,
+ channel=channel,
+ timeout=DEFAULT_NO_ADDR_EXPECTED_TIMEOUT)
# Allow a failed to find client interface error
except LookupError as err:
self.log.debug('Hit expected LookupError: %s' % err)
@@ -699,18 +600,19 @@
# Test Types
- def verify_soft_ap_associate_only(self, client, settings):
- if not self.associate_with_soft_ap(client.w_device, settings):
+ def verify_soft_ap_associate_only(self, client, soft_ap_settings):
+ if not self.associate_with_soft_ap(client, soft_ap_settings):
asserts.fail('Failed to associate client with SoftAP.')
- def verify_soft_ap_associate_and_ping(self, client, settings):
- self.verify_soft_ap_associate_only(client, settings)
- if not self.client_is_connected_to_soft_ap(client):
+ def verify_soft_ap_associate_and_ping(self, client, soft_ap_settings):
+ self.verify_soft_ap_associate_only(client, soft_ap_settings)
+ if not self.device_is_connected_to_ap(client, self.dut):
asserts.fail('Client and SoftAP could not ping eachother.')
def verify_soft_ap_associate_and_pass_traffic(self, client, settings):
self.verify_soft_ap_associate_only(client, settings)
- if not self.client_is_connected_to_soft_ap(client, check_traffic=True):
+ if not self.device_is_connected_to_ap(
+ client, self.dut, check_traffic=True):
asserts.fail(
'Client and SoftAP not responding to pings and passing traffic '
'as expected.')
@@ -784,7 +686,6 @@
"""
iterations = settings['iterations']
pass_count = 0
- client = self.primary_client
current_soft_ap_state = STATE_DOWN
current_client_mode_state = STATE_DOWN
@@ -792,7 +693,8 @@
for iteration in range(iterations):
passes = True
- # Attempt to toggle SoftAP on, then off
+ # Attempt to toggle SoftAP on, then off. If the first toggle fails
+ # to occur, exit early.
for _ in range(2):
(current_soft_ap_state, err) = self.run_toggle_iteration_func(
self.soft_ap_toggle_test_iteration, settings,
@@ -804,7 +706,8 @@
if current_soft_ap_state == STATE_DOWN:
break
- # Attempt to toggle Client mode on, then off
+ # Attempt to toggle Client mode on, then off. If the first toggle,
+ # fails to occur, exit early.
for _ in range(2):
(current_client_mode_state,
err) = self.run_toggle_iteration_func(
@@ -919,8 +822,7 @@
soft_ap_params['ssid'] = utils.rand_ascii_str(
hostapd_constants.AP_SSID_LENGTH_2G)
self.start_soft_ap(soft_ap_params)
- associated = self.associate_with_soft_ap(client.w_device,
- soft_ap_params)
+ associated = self.associate_with_soft_ap(client, soft_ap_params)
if not associated:
raise StressTestIterationFailure(
'Failed to associated client to DUT SoftAP. '
@@ -1049,7 +951,9 @@
profile_name=ap_profile,
**ap_params)
# Confirms AP assigned itself an address
- self.get_ap_ipv4_address(ap_channel)
+ ap_interface = self.get_device_test_interface(self.access_point,
+ channel=ap_channel)
+ self.wait_for_ipv4_address(self.access_point, ap_interface)
def client_mode_toggle_test_iteration(self, settings, current_state):
"""Runs a single iteration of client mode toggle stress test
@@ -1064,7 +968,6 @@
functioning correctly.
EnvironmentError, if toggle fails to occur at all
"""
- # TODO(b/168054673): Use client connections and policy connect
ap_params = settings['ap_params']
self.log.info('Toggling client mode %s' %
('off' if current_state else 'on'))
@@ -1114,7 +1017,8 @@
ap_params = settings['ap_params']
ap_channel = ap_params['channel']
self.soft_ap_toggle_test_iteration(settings, current_state)
- if not self.dut_is_connected_as_client(ap_channel):
+ if not self.device_is_connected_to_ap(
+ self.dut, self.access_point, channel=ap_channel):
raise StressTestIterationFailure(
'DUT client mode is no longer functional after SoftAP toggle.')
@@ -1153,7 +1057,7 @@
EnvironmentError, if toggle fails to occur at all
"""
self.client_mode_toggle_test_iteration(settings, current_state)
- if not self.client_is_connected_to_soft_ap(self.primary_client):
+ if not self.device_is_connected_to_ap(self.primary_client, self.dut):
raise StressTestIterationFailure(
'SoftAP is no longer functional after client mode toggle.')
@@ -1596,7 +1500,6 @@
}
}
"""
- # TODO(fxb/59335): Validate clients on network can reach eachother.
asserts.skip_if(
len(self.clients) < 2, 'Test requires at least 2 SoftAPClients')
@@ -1607,55 +1510,67 @@
self.start_soft_ap(soft_ap_params)
- dut_ap_interface = self.get_dut_interface_by_role(INTERFACE_ROLE_AP)
associated = []
for client in self.clients:
# Associate new client
self.verify_soft_ap_associate_and_ping(client, soft_ap_params)
- client_ipv4 = self.wait_for_ipv4_address(
- client.w_device, ANDROID_DEFAULT_WLAN_INTERFACE)
# Verify previously associated clients still behave as expected
- for client_map in associated:
- associated_client = client_map['client']
- associated_client_ipv4 = client_map['ipv4']
+ for associated_client in associated:
self.log.info(
'Verifying previously associated client %s still functions correctly.'
- % associated_client.w_device.device.serial)
- if not self.client_is_connected_to_soft_ap(associated_client,
- check_traffic=True):
+ % associated_client['device'].identifier)
+ if not self.device_is_connected_to_ap(
+ associated_client['device'], self.dut,
+ check_traffic=True):
asserts.fail(
'Previously associated client %s failed checks after '
'client %s associated.' %
- (associated_client.w_device.device.serial,
- client.w_device.device.serial))
+ (associated_client['device'].identifier,
+ client.identifier))
- associated.append({'client': client, 'ipv4': client_ipv4})
+ client_interface = self.get_device_test_interface(client)
+ client_ipv4 = self.wait_for_ipv4_address(client, client_interface)
+ associated.append({"device": client, "address": client_ipv4})
+
+ self.log.info('All devices successfully associated.')
+
+ self.log.info('Verifying all associated clients can ping eachother.')
+ for transmitter in associated:
+ for receiver in associated:
+ if transmitter != receiver:
+ if not transmitter['device'].can_ping(receiver['address']):
+ asserts.fail(
+ 'Could not ping from one associated client (%s) to another (%s).'
+ % (transmitter['address'], receiver['address']))
+ else:
+ self.log.info(
+ 'Successfully pinged from associated client (%s) to another (%s)'
+ % (transmitter['address'], receiver['address']))
self.log.info(
- 'All devices successfully associated. Beginning disassociations.')
+ 'All associated clients can ping eachother. Beginning disassociations.'
+ )
while len(associated) > 0:
# Disassociate client
- client = associated.pop()['client']
- self.disconnect_from_soft_ap(client.w_device)
+ client = associated.pop()['device']
+ self.disconnect_from_soft_ap(client)
# Verify still connected clients still behave as expected
- for client_map in associated:
- associated_client = client_map['client']
- associated_client_ipv4 = client_map['ipv4']
-
+ for associated_client in associated:
self.log.info(
'Verifying still associated client %s still functions '
- 'correctly.' % associated_client.w_device.device.serial)
- if not self.client_is_connected_to_soft_ap(associated_client,
- check_traffic=True):
+ 'correctly.' % associated_client['device'].identifier)
+ if not self.device_is_connected_to_ap(
+ associated_client['device'], self.dut,
+ check_traffic=True):
asserts.fail(
'Previously associated client %s failed checks after'
' client %s disassociated.' %
- (associated_client.w_device.device.serial,
- client.w_device.device.serial))
+ (associated_client['device'].identifier,
+ client.identifier))
self.log.info('All disassociations occurred smoothly.')
@@ -1669,7 +1584,6 @@
TestFailure: if DUT fails to pass traffic as either a client or an
AP
"""
- # TODO(fxb/59306): Fix flakey parallel streams.
asserts.skip_if(not self.access_point, 'No access point provided.')
self.log.info('Setting up AP using hostapd.')
@@ -1696,10 +1610,16 @@
self.start_soft_ap_and_verify_connected(self.primary_client,
soft_ap_params)
- # Get FuchsiaDevice's AP interface info
- dut_ap_interface = self.get_dut_interface_by_role(INTERFACE_ROLE_AP)
- dut_client_interface = self.get_dut_interface_by_role(
- INTERFACE_ROLE_CLIENT)
+ # Get FuchsiaDevice test interfaces
+ dut_ap_interface = self.get_device_test_interface(
+ self.dut, role=INTERFACE_ROLE_AP)
+ dut_client_interface = self.get_device_test_interface(
+ self.dut, role=INTERFACE_ROLE_CLIENT)
+
+ # Get FuchsiaDevice addresses
+ dut_ap_ipv4 = self.wait_for_ipv4_address(self.dut, dut_ap_interface)
+ dut_client_ipv4 = self.wait_for_ipv4_address(self.dut,
+ dut_client_interface)
# Set up secondary iperf server of FuchsiaDevice
self.log.info('Setting up second iperf server on FuchsiaDevice DUT.')
@@ -1719,13 +1639,13 @@
iperf_soft_ap = mp.Process(
target=self.run_iperf_traffic_parallel_process,
args=[
- self.primary_client.ip_client, dut_ap_interface.ipv4,
+ self.iperf_clients_map[self.primary_client], dut_ap_ipv4,
process_errors
])
iperf_fuchsia_client = mp.Process(
target=self.run_iperf_traffic_parallel_process,
- args=[ap_iperf_client, dut_client_interface.ipv4, process_errors],
+ args=[ap_iperf_client, dut_client_ipv4, process_errors],
kwargs={'server_port': 5202})
# Run iperf processes simultaneously
@@ -1793,11 +1713,19 @@
iterations = config_settings.get('iterations',
DEFAULT_STRESS_TEST_ITERATIONS)
test_settings = {
- 'test_name': config_settings['test_name'],
- 'client': self.primary_client,
- 'soft_ap_params': soft_ap_params,
- 'test_type': test_type,
- 'iterations': iterations
+ 'test_name':
+ config_settings.get(
+ 'test_name',
+ 'test_soft_ap_association_stress_%s_iterations' %
+ iterations),
+ 'client':
+ self.primary_client,
+ 'soft_ap_params':
+ soft_ap_params,
+ 'test_type':
+ test_type,
+ 'iterations':
+ iterations
}
test_settings_list.append(test_settings)
@@ -1854,10 +1782,17 @@
DEFAULT_STRESS_TEST_ITERATIONS)
test_settings = {
- 'test_name': config_settings['test_name'],
- 'iterations': iterations,
- 'soft_ap_params': soft_ap_params,
- 'ap_params': ap_params,
+ 'test_name':
+ config_settings.get(
+ 'test_name',
+ 'test_soft_ap_and_client_mode_alternating_stress_%s_iterations'
+ % iterations),
+ 'iterations':
+ iterations,
+ 'soft_ap_params':
+ soft_ap_params,
+ 'ap_params':
+ ap_params,
}
test_settings_list.append(test_settings)
@@ -1901,10 +1836,16 @@
iterations = config_settings.get('iterations',
DEFAULT_STRESS_TEST_ITERATIONS)
test_settings = {
- 'test_name': config_settings['test_name'],
- 'test_runner_func': self.soft_ap_toggle_test_iteration,
- 'soft_ap_params': soft_ap_params,
- 'iterations': iterations
+ 'test_name':
+ config_settings.get(
+ 'test_name',
+ 'test_soft_ap_toggle_stress_%s_iterations' % iterations),
+ 'test_runner_func':
+ self.soft_ap_toggle_test_iteration,
+ 'soft_ap_params':
+ soft_ap_params,
+ 'iterations':
+ iterations
}
test_settings_list.append(test_settings)
@@ -1948,11 +1889,19 @@
iterations = config_settings.get('iterations',
DEFAULT_STRESS_TEST_ITERATIONS)
test_settings = {
- 'test_name': config_settings['test_name'],
- 'test_runner_func': self.client_mode_toggle_test_iteration,
- 'pre_test_func': self.client_mode_toggle_pre_test,
- 'ap_params': ap_params,
- 'iterations': iterations
+ 'test_name':
+ config_settings.get(
+ 'test_name',
+ 'test_client_mode_toggle_stress_%s_iterations' %
+ iterations),
+ 'test_runner_func':
+ self.client_mode_toggle_test_iteration,
+ 'pre_test_func':
+ self.client_mode_toggle_pre_test,
+ 'ap_params':
+ ap_params,
+ 'iterations':
+ iterations
}
test_settings_list.append(test_settings)
self.run_generated_testcases(self.run_toggle_stress_test,
@@ -1978,13 +1927,21 @@
iterations = config_settings.get('iterations',
DEFAULT_STRESS_TEST_ITERATIONS)
test_settings = {
- 'test_name': config_settings['test_name'],
+ 'test_name':
+ config_settings.get(
+ 'test_name',
+ 'test_soft_ap_toggle_stress_with_client_mode_%s_iterations'
+ % iterations),
'test_runner_func':
self.soft_ap_toggle_with_client_mode_iteration,
- 'pre_test_func': self.soft_ap_toggle_with_client_mode_pre_test,
- 'soft_ap_params': soft_ap_params,
- 'ap_params': ap_params,
- 'iterations': iterations
+ 'pre_test_func':
+ self.soft_ap_toggle_with_client_mode_pre_test,
+ 'soft_ap_params':
+ soft_ap_params,
+ 'ap_params':
+ ap_params,
+ 'iterations':
+ iterations
}
test_settings_list.append(test_settings)
self.run_generated_testcases(self.run_toggle_stress_test,
@@ -2010,13 +1967,21 @@
iterations = config_settings.get('iterations',
DEFAULT_STRESS_TEST_ITERATIONS)
test_settings = {
- 'test_name': config_settings['test_name'],
+ 'test_name':
+ config_settings.get(
+ 'test_name',
+ 'test_client_mode_toggle_stress_with_soft_ap_%s_iterations'
+ % iterations),
'test_runner_func':
self.client_mode_toggle_with_soft_ap_iteration,
- 'pre_test_func': self.client_mode_toggle_with_soft_ap_pre_test,
- 'soft_ap_params': soft_ap_params,
- 'ap_params': ap_params,
- 'iterations': iterations
+ 'pre_test_func':
+ self.client_mode_toggle_with_soft_ap_pre_test,
+ 'soft_ap_params':
+ soft_ap_params,
+ 'ap_params':
+ ap_params,
+ 'iterations':
+ iterations
}
test_settings_list.append(test_settings)
self.run_generated_testcases(self.run_toggle_stress_test,
@@ -2044,10 +2009,17 @@
iterations = config_settings.get('iterations',
DEFAULT_STRESS_TEST_ITERATIONS)
test_settings = {
- 'test_name': config_settings['test_name'],
- 'soft_ap_params': soft_ap_params,
- 'ap_params': ap_params,
- 'iterations': iterations
+ 'test_name':
+ config_settings.get(
+ 'test_name',
+ 'test_soft_ap_and_client_mode_random_toggle_stress_%s_iterations'
+ % iterations),
+ 'soft_ap_params':
+ soft_ap_params,
+ 'ap_params':
+ ap_params,
+ 'iterations':
+ iterations
}
test_settings_list.append(test_settings)
self.run_generated_testcases(
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/WlanRebootTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/WlanRebootTest.py
index 59060bd..8d365a7 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/WlanRebootTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/WlanRebootTest.py
@@ -35,6 +35,7 @@
from acts.controllers.ap_lib.radvd_config import RadvdConfig
from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
+from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
# Constants, for readibility
AP = 'ap'
@@ -100,7 +101,7 @@
return settings['test_name']
-class WlanRebootTest(WifiBaseTest):
+class WlanRebootTest(AbstractDeviceWlanDeviceBaseTest):
"""Tests wlan reconnects in different reboot scenarios.
Testbed Requirement:
@@ -143,9 +144,9 @@
self.iperf_server_on_ap = None
self.iperf_client_on_dut = None
if not self.skip_iperf:
- try:
+ if hasattr(self, "iperf_clients") and self.iperf_clients:
self.iperf_client_on_dut = self.iperf_clients[0]
- except AttributeError:
+ else:
self.iperf_client_on_dut = self.dut.create_iperf_client()
else:
self.log.info(
@@ -167,8 +168,14 @@
self.ssid = utils.rand_ascii_str(hostapd_constants.AP_SSID_LENGTH_2G)
def teardown_test(self):
+ self.download_ap_logs()
self.access_point.stop_all_aps()
if self.router_adv_daemon:
+ output_path = context.get_current_context().get_base_output_path()
+ full_output_path = os.path.join(output_path, "radvd_log.txt")
+ radvd_log_file = open(full_output_path, 'w')
+ radvd_log_file.write(self.router_adv_daemon.pull_logs())
+ radvd_log_file.close()
self.router_adv_daemon.stop()
self.router_adv_daemon = None
self.dut.disconnect()
@@ -178,10 +185,6 @@
self.dut.turn_location_off_and_scan_toggle_off()
self.dut.reset_wifi()
- def on_fail(self, test_name, begin_time):
- self.dut.take_bug_report(test_name, begin_time)
- self.dut.get_log(test_name, begin_time)
-
def setup_ap(self,
ssid,
band,
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/WlanScanTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/WlanScanTest.py
index dda04a5..6133f0b 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/WlanScanTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/WlanScanTest.py
@@ -24,7 +24,6 @@
import pprint
import time
-import acts.base_test
import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
from acts import signals
@@ -32,10 +31,10 @@
from acts.controllers.ap_lib import hostapd_bss_settings
from acts.controllers.ap_lib import hostapd_constants
from acts.controllers.ap_lib import hostapd_security
-from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
+from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
-class WlanScanTest(WifiBaseTest):
+class WlanScanTest(AbstractDeviceWlanDeviceBaseTest):
"""WLAN scan test class.
Test Bed Requirement:
@@ -46,6 +45,7 @@
def setup_class(self):
super().setup_class()
+ self.access_point = self.access_points[0]
self.start_access_point = False
for fd in self.fuchsia_devices:
fd.configure_wlan(association_mechanism='drivers')
@@ -85,14 +85,14 @@
security_mode=self.wpa2_network_5g["security"],
password=self.wpa2_network_5g["password"])))
self.ap_2g = hostapd_ap_preset.create_ap_preset(
- iface_wlan_2g=self.access_points[0].wlan_2g,
- iface_wlan_5g=self.access_points[0].wlan_5g,
+ iface_wlan_2g=self.access_point.wlan_2g,
+ iface_wlan_5g=self.access_point.wlan_5g,
channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
ssid=self.open_network_2g['SSID'],
bss_settings=bss_settings_2g)
self.ap_5g = hostapd_ap_preset.create_ap_preset(
- iface_wlan_2g=self.access_points[0].wlan_2g,
- iface_wlan_5g=self.access_points[0].wlan_5g,
+ iface_wlan_2g=self.access_point.wlan_2g,
+ iface_wlan_5g=self.access_point.wlan_5g,
channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
ssid=self.open_network_5g['SSID'],
bss_settings=bss_settings_5g)
@@ -134,10 +134,10 @@
# previously saved ssid on the device.
if self.start_access_point_2g:
self.start_access_point = True
- self.access_points[0].start_ap(hostapd_config=self.ap_2g)
+ self.access_point.start_ap(hostapd_config=self.ap_2g)
if self.start_access_point_5g:
self.start_access_point = True
- self.access_points[0].start_ap(hostapd_config=self.ap_5g)
+ self.access_point.start_ap(hostapd_config=self.ap_5g)
def setup_test(self):
for fd in self.fuchsia_devices:
@@ -150,7 +150,13 @@
def teardown_class(self):
if self.start_access_point:
- self.access_points[0].stop_all_aps()
+ self.download_ap_logs()
+ self.access_point.stop_all_aps()
+
+ def on_fail(self, test_name, begin_time):
+ for fd in self.fuchsia_devices:
+ super().on_device_fail(fd, test_name, begin_time)
+ fd.configure_wlan(association_mechanism='drivers')
"""Helper Functions"""
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/WlanTargetSecurityTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/WlanTargetSecurityTest.py
index a8d44f4..2debf65 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/WlanTargetSecurityTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/WlanTargetSecurityTest.py
@@ -16,16 +16,16 @@
from acts import asserts
from acts import utils
-from acts.base_test import BaseTestClass
from acts.controllers.access_point import setup_ap
from acts.controllers.ap_lib import hostapd_constants
from acts.controllers.ap_lib.hostapd_security import Security
from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
+from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
# TODO(fxb/68956): Add security protocol check to mixed mode tests when info is
# available.
-class WlanTargetSecurityTest(BaseTestClass):
+class WlanTargetSecurityTest(AbstractDeviceWlanDeviceBaseTest):
"""Tests Fuchsia's target security concept and security upgrading
Testbed Requirements:
@@ -49,8 +49,9 @@
self.dut.disconnect()
self.access_point.stop_all_aps()
- def setup_test(self):
+ def teardown_test(self):
self.dut.disconnect()
+ self.download_ap_logs()
self.access_point.stop_all_aps()
def on_fail(self, test_name, begin_time):
@@ -288,10 +289,14 @@
def test_associate_wpa3_ap_with_wpa_target_security(self):
ssid, password = self.setup_ap(hostapd_constants.WPA3_STRING)
- asserts.assert_true(
+ asserts.assert_false(
self.dut.associate(ssid,
target_security=hostapd_constants.WPA_STRING,
- target_pwd=password), 'Failed to associate.')
+ target_pwd=password),
+ 'Expected failure to associate. WPA credentials for WPA3 was '
+ 'temporarily disabled, see https://fxbug.dev/85817 for context. '
+ 'If this feature was reenabled, please update this test\'s '
+ 'expectation.')
def test_associate_wpa3_ap_with_wpa2_target_security(self):
ssid, password = self.setup_ap(hostapd_constants.WPA3_STRING)
@@ -325,10 +330,14 @@
def test_associate_wpa2_wpa3_ap_with_wpa_target_security(self):
ssid, password = self.setup_ap(
hostapd_constants.WPA2_WPA3_MIXED_STRING)
- asserts.assert_true(
+ asserts.assert_false(
self.dut.associate(ssid,
target_security=hostapd_constants.WPA_STRING,
- target_pwd=password), 'Failed to associate.')
+ target_pwd=password),
+ 'Expected failure to associate. WPA credentials for WPA3 was '
+ 'temporarily disabled, see https://fxbug.dev/85817 for context. '
+ 'If this feature was reenabled, please update this test\'s '
+ 'expectation.')
def test_associate_wpa2_wpa3_ap_with_wpa2_target_security(self):
ssid, password = self.setup_ap(
diff --git a/acts_tests/tests/google/fuchsia/wlan/misc/WlanInterfaceTest.py b/acts_tests/tests/google/fuchsia/wlan/misc/WlanInterfaceTest.py
index 4994dd2..3e2b707 100644
--- a/acts_tests/tests/google/fuchsia/wlan/misc/WlanInterfaceTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/misc/WlanInterfaceTest.py
@@ -16,7 +16,6 @@
from acts import signals
-from acts.base_test import BaseTestClass
from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
@@ -37,9 +36,6 @@
# Default is an Fuchsia device
self.dut = create_wlan_device(self.fuchsia_devices[0])
- def on_fail(self, test_name, begin_time):
- super().on_fail(test_name, begin_time)
-
def test_destroy_iface(self):
"""Test that we don't error out when destroying the WLAN interface.
diff --git a/acts_tests/tests/google/fuchsia/wlan/misc/WlanMiscScenarioTest.py b/acts_tests/tests/google/fuchsia/wlan/misc/WlanMiscScenarioTest.py
index 24b62dd..950015d 100644
--- a/acts_tests/tests/google/fuchsia/wlan/misc/WlanMiscScenarioTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/misc/WlanMiscScenarioTest.py
@@ -29,6 +29,7 @@
fit into a specific test category, but should still be run in CI to catch
regressions.
"""
+
def setup_class(self):
super().setup_class()
dut = self.user_params.get('dut', None)
@@ -49,8 +50,9 @@
self.dut.disconnect()
self.access_point.stop_all_aps()
- def setup_test(self):
+ def teardown_test(self):
self.dut.disconnect()
+ self.download_ap_logs()
self.access_point.stop_all_aps()
def on_fail(self, test_name, begin_time):
diff --git a/acts_tests/tests/google/fuchsia/wlan/performance/ChannelSweepTest.py b/acts_tests/tests/google/fuchsia/wlan/performance/ChannelSweepTest.py
index b9f26bf..8ea7891 100644
--- a/acts_tests/tests/google/fuchsia/wlan/performance/ChannelSweepTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/performance/ChannelSweepTest.py
@@ -35,6 +35,7 @@
from acts.controllers.ap_lib.hostapd_security import Security
from acts.controllers.iperf_server import IPerfResult
from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
+from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
N_CAPABILITIES_DEFAULT = [
@@ -75,7 +76,7 @@
return settings.get('test_name')
-class ChannelSweepTest(WifiBaseTest):
+class ChannelSweepTest(AbstractDeviceWlanDeviceBaseTest):
"""Tests channel performance and regulatory compliance..
Testbed Requirement:
@@ -124,11 +125,16 @@
try:
self.iperf_server = self.iperf_servers[0]
self.iperf_server.start()
- self.iperf_client = self.iperf_clients[0]
except AttributeError:
self.log.warn(
'Missing iperf config. Throughput cannot be measured, so only '
'association will be tested.')
+
+ if hasattr(self, "iperf_clients") and self.iperf_clients:
+ self.iperf_client = self.iperf_clients[0]
+ else:
+ self.iperf_client = self.dut.create_iperf_client()
+
self.regulatory_results = "====CountryCode,Channel,Frequency,ChannelBandwith,Connected/Not-Connected====\n"
def teardown_class(self):
@@ -169,12 +175,9 @@
ad.droid.goToSleepNow()
self.dut.turn_location_off_and_scan_toggle_off()
self.dut.disconnect()
+ self.download_ap_logs()
self.access_point.stop_all_aps()
- def on_fail(self, test_name, begin_time):
- self.dut.take_bug_report(test_name, begin_time)
- self.dut.get_log(test_name, begin_time)
-
def set_dut_country_code(self, country_code):
"""Set the country code on the DUT. Then verify that the country
code was set successfully
diff --git a/acts_tests/tests/google/fuchsia/wlan/performance/WlanRvrTest.py b/acts_tests/tests/google/fuchsia/wlan/performance/WlanRvrTest.py
index 0147b7b..545bbc5 100644
--- a/acts_tests/tests/google/fuchsia/wlan/performance/WlanRvrTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/performance/WlanRvrTest.py
@@ -13,6 +13,7 @@
# 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 time
from acts import asserts
@@ -41,6 +42,8 @@
RVR_GRAPH_SUMMARY_FILE = 'rvr_summary.html'
+DAD_TIMEOUT_SEC = 30
+
def create_rvr_graph(test_name, graph_path, graph_data):
"""Creates the RvR graphs
@@ -107,6 +110,7 @@
* One attenuator
* One Linux iPerf Server
"""
+
def __init__(self, controllers):
WifiBaseTest.__init__(self, controllers)
self.rvr_graph_summary = []
@@ -157,7 +161,6 @@
'debug_post_traffic_cmd', None))
self.router_adv_daemon = None
- self.check_if_has_private_local_ipv6_address = True
if self.ending_attn == 'auto':
self.use_auto_end = True
@@ -176,7 +179,11 @@
self.attenuators, 'attenuator_ports_wifi_5g')
self.iperf_server = self.iperf_servers[0]
- self.dut_iperf_client = self.iperf_clients[0]
+
+ if hasattr(self, "iperf_clients") and self.iperf_clients:
+ self.dut_iperf_client = self.iperf_clients[0]
+ else:
+ self.dut_iperf_client = self.dut.create_iperf_client()
self.access_point.stop_all_aps()
@@ -207,6 +214,8 @@
'to Exception')
self.log.info(e)
+ super().teardown_class()
+
def on_fail(self, test_name, begin_time):
super().on_fail(test_name, begin_time)
self.cleanup_tests()
@@ -218,6 +227,11 @@
"""
if self.router_adv_daemon:
+ output_path = context.get_current_context().get_base_output_path()
+ full_output_path = os.path.join(output_path, "radvd_log.txt")
+ radvd_log_file = open(full_output_path, 'w')
+ radvd_log_file.write(self.router_adv_daemon.pull_logs())
+ radvd_log_file.close()
self.router_adv_daemon.stop()
if hasattr(self, "android_devices"):
for ad in self.android_devices:
@@ -228,8 +242,87 @@
self.dut.turn_location_off_and_scan_toggle_off()
self.dut.disconnect()
self.dut.reset_wifi()
+ self.download_ap_logs()
self.access_point.stop_all_aps()
+ def _wait_for_ipv4_addrs(self):
+ """Wait for an IPv4 addresses to become available on the DUT and iperf
+ server.
+
+ Returns:
+ A string containing the private IPv4 address of the iperf server.
+
+ Raises:
+ TestFailure: If unable to acquire a IPv4 address.
+ """
+ ip_address_checker_counter = 0
+ ip_address_checker_max_attempts = 3
+ while ip_address_checker_counter < ip_address_checker_max_attempts:
+ self.iperf_server.renew_test_interface_ip_address()
+ iperf_server_ip_addresses = (
+ self.iperf_server.get_interface_ip_addresses(
+ self.iperf_server.test_interface))
+ dut_ip_addresses = self.dut.get_interface_ip_addresses(
+ self.dut_iperf_client.test_interface)
+
+ self.log.info(
+ 'IPerf server IP info: {}'.format(iperf_server_ip_addresses))
+ self.log.info('DUT IP info: {}'.format(dut_ip_addresses))
+
+ if not iperf_server_ip_addresses['ipv4_private']:
+ self.log.warn('Unable to get the iperf server IPv4 '
+ 'address. Retrying...')
+ ip_address_checker_counter += 1
+ time.sleep(1)
+ continue
+
+ if dut_ip_addresses['ipv4_private']:
+ return iperf_server_ip_addresses['ipv4_private'][0]
+
+ self.log.warn('Unable to get the DUT IPv4 address starting at '
+ 'attenuation "{}". Retrying...'.format(
+ self.starting_attn))
+ ip_address_checker_counter += 1
+ time.sleep(1)
+
+ asserts.fail(
+ 'IPv4 addresses are not available on both the DUT and iperf server.'
+ )
+
+ def _wait_for_dad(self, device, test_interface):
+ """Wait for Duplicate Address Detection to resolve so that an
+ private-local IPv6 address is available for test.
+
+ Args:
+ device: implementor of get_interface_ip_addresses
+ test_interface: name of interface that DAD is operating on
+
+ Returns:
+ A string containing the private-local IPv6 address of the device.
+
+ Raises:
+ TestFailure: If unable to acquire an IPv6 address.
+ """
+ now = time.time()
+ start = now
+ elapsed = now - start
+
+ while elapsed < DAD_TIMEOUT_SEC:
+ addrs = device.get_interface_ip_addresses(test_interface)
+ now = time.time()
+ elapsed = now - start
+ if addrs['ipv6_private_local']:
+ # DAD has completed
+ addr = addrs['ipv6_private_local'][0]
+ self.log.info('DAD resolved with "{}" after {}s'.format(
+ addr, elapsed))
+ return addr
+ time.sleep(1)
+ else:
+ asserts.fail(
+ 'Unable to acquire a private-local IPv6 address for testing '
+ 'after {}s'.format(elapsed))
+
def run_rvr(self,
ssid,
security_mode=None,
@@ -251,7 +344,6 @@
"""
throughput = []
relative_attn = []
- self.check_if_has_private_local_ipv6_address = True
if band == '2g':
rvr_attenuators = self.attenuators_2g
elif band == '5g':
@@ -259,7 +351,7 @@
else:
raise ValueError('Invalid WLAN band specified: %s' % band)
if ip_version == 6:
- ravdvd_config = RadvdConfig(
+ radvd_config = RadvdConfig(
prefix=RADVD_PREFIX,
adv_send_advert=radvd_constants.ADV_SEND_ADVERT_ON,
adv_on_link=radvd_constants.ADV_ON_LINK_ON,
@@ -267,7 +359,7 @@
self.router_adv_daemon = Radvd(
self.access_point.ssh,
self.access_point.interfaces.get_bridge_interface()[0])
- self.router_adv_daemon.start(ravdvd_config)
+ self.router_adv_daemon.start(radvd_config)
for rvr_loop_counter in range(0, self.debug_loop_count):
for rvr_attenuator in rvr_attenuators:
@@ -286,66 +378,27 @@
break
else:
associate_counter += 1
- if associate_counter == associate_max_attempts:
+ else:
asserts.fail('Unable to associate at starting '
'attenuation: %s' % self.starting_attn)
- ip_address_checker_counter = 0
- ip_address_checker_max_attempts = 3
- while ip_address_checker_counter < ip_address_checker_max_attempts:
+ if ip_version == 4:
+ iperf_server_ip_address = self._wait_for_ipv4_addrs()
+ elif ip_version == 6:
self.iperf_server.renew_test_interface_ip_address()
- iperf_server_ip_addresses = (
- self.iperf_server.get_interface_ip_addresses(
- self.iperf_server.test_interface))
- dut_ip_addresses = self.dut.get_interface_ip_addresses(
- self.dut_iperf_client.test_interface)
- self.log.info('IPerf server IP info: %s' %
- iperf_server_ip_addresses)
- self.log.info('DUT IP info: %s' % dut_ip_addresses)
- if ip_version == 4:
- if iperf_server_ip_addresses['ipv4_private']:
- iperf_server_ip_address = (
- iperf_server_ip_addresses['ipv4_private'][0])
- if not dut_ip_addresses['ipv4_private']:
- self.log.warn('Unable to get IPv4 address at starting '
- 'attenuation: %s Retrying.' %
- self.starting_attn)
- ip_address_checker_counter += 1
- time.sleep(1)
- else:
- break
- elif ip_version == 6:
- if iperf_server_ip_addresses['ipv6_private_local']:
- iperf_server_ip_address = (
- iperf_server_ip_addresses['ipv6_private_local'][0])
- else:
- self.check_if_has_private_local_ipv6_address = False
- iperf_server_ip_address = (
- '%s%%%s' %
- (iperf_server_ip_addresses['ipv6_link_local'][0],
- self.dut_iperf_client.test_interface))
- if self.check_if_has_private_local_ipv6_address:
- if not dut_ip_addresses['ipv6_private_local']:
- self.log.warn('Unable to get IPv6 address at '
- 'starting attenuation: %s' %
- self.starting_attn)
- ip_address_checker_counter += 1
- time.sleep(1)
- else:
- break
- else:
- break
- else:
- raise ValueError('Invalid IP version: %s' % ip_version)
- if ip_address_checker_counter == ip_address_checker_max_attempts:
- if self.dut.can_ping(iperf_server_ip_address):
- self.log.error('IPerf server is pingable. Continuing with '
- 'test. The missing IP address information '
- 'should be marked as a bug.')
- else:
- asserts.fail('DUT was unable to get IPv%s address and '
- 'could not ping the IPerf server.' %
- str(ip_version))
+ self.log.info('Waiting for iperf server to complete Duplicate '
+ 'Address Detection...')
+ iperf_server_ip_address = self._wait_for_dad(
+ self.iperf_server, self.iperf_server.test_interface)
+
+ self.log.info('Waiting for DUT to complete Duplicate Address '
+ 'Detection for "{}"...'.format(
+ self.dut_iperf_client.test_interface))
+ _ = self._wait_for_dad(self.dut,
+ self.dut_iperf_client.test_interface)
+ else:
+ raise ValueError('Invalid IP version: {}'.format(ip_version))
+
throughput, relative_attn = (self.rvr_loop(
traffic_dir,
rvr_attenuators,
@@ -472,19 +525,13 @@
self.log.info('DUT has the following IPv4 address: "%s"' %
dut_ip_addresses['ipv4_private'][0])
elif ip_version == 6:
- if self.check_if_has_private_local_ipv6_address:
- if not dut_ip_addresses['ipv6_private_local']:
- self.log.info(
- 'DUT does not have an IPv6 address. '
- 'Traffic attempt to be run if the server '
- 'is pingable.')
- else:
- self.log.info(
- 'DUT has the following IPv6 address: "%s"' %
- dut_ip_addresses['ipv6_private_local'][0])
+ if not dut_ip_addresses['ipv6_private_local']:
+ self.log.info('DUT does not have an IPv6 address. '
+ 'Traffic attempt to be run if the server '
+ 'is pingable.')
else:
self.log.info('DUT has the following IPv6 address: "%s"' %
- dut_ip_addresses['ipv6_link_local'][0])
+ dut_ip_addresses['ipv6_private_local'][0])
server_pingable = self.dut.can_ping(iperf_server_ip_address)
if not server_pingable:
self.log.info('Iperf server "%s" is not pingable. Marking '
diff --git a/acts_tests/tests/google/fuchsia/wlan/performance/WlanWmmTest.py b/acts_tests/tests/google/fuchsia/wlan/performance/WlanWmmTest.py
index 64e5431..adbb5f6 100644
--- a/acts_tests/tests/google/fuchsia/wlan/performance/WlanWmmTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/performance/WlanWmmTest.py
@@ -190,14 +190,17 @@
tc.wlan_device.disconnect()
tc.wlan_device.reset_wifi()
if tc.access_point:
+ self.download_ap_logs()
tc.access_point.stop_all_aps()
def teardown_class(self):
for tc in self.wmm_transceivers:
tc.destroy_resources()
+ super().teardown_class()
def on_fail(self, test_name, begin_time):
- super().on_fail(test_name, begin_time)
+ for wlan_device in self.wlan_devices:
+ super().on_device_fail(wlan_device.device, test_name, begin_time)
def start_ap_with_wmm_params(self, ap_parameters, wmm_parameters):
"""Sets up WMM network on AP.
diff --git a/acts_tests/tests/google/fuchsia/wlan_policy/HiddenNetworksTest.py b/acts_tests/tests/google/fuchsia/wlan_policy/HiddenNetworksTest.py
index 98d8a19..7d294d2 100644
--- a/acts_tests/tests/google/fuchsia/wlan_policy/HiddenNetworksTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan_policy/HiddenNetworksTest.py
@@ -41,6 +41,7 @@
* One or more Fuchsia devices
* One Access Point
"""
+
def setup_class(self):
super().setup_class()
# Start an AP with a hidden network
diff --git a/acts_tests/tests/google/fuchsia/wlan_policy/PolicyScanTest.py b/acts_tests/tests/google/fuchsia/wlan_policy/PolicyScanTest.py
index c174bc7..efd8729 100644
--- a/acts_tests/tests/google/fuchsia/wlan_policy/PolicyScanTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan_policy/PolicyScanTest.py
@@ -31,6 +31,7 @@
* One or more Fuchsia devices
* One Whirlwind Access Point
"""
+
def setup_class(self):
super().setup_class()
if len(self.fuchsia_devices) < 1:
diff --git a/acts_tests/tests/google/fuchsia/wlan_policy/RegulatoryRecoveryTest.py b/acts_tests/tests/google/fuchsia/wlan_policy/RegulatoryRecoveryTest.py
index 5cf9ad7..9cfaf84 100644
--- a/acts_tests/tests/google/fuchsia/wlan_policy/RegulatoryRecoveryTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan_policy/RegulatoryRecoveryTest.py
@@ -32,6 +32,7 @@
If no configuration information is provided, the test will default to
toggling between WW and US.
"""
+
def setup_class(self):
super().setup_class()
if len(self.fuchsia_devices) < 1:
@@ -40,13 +41,16 @@
self.config_test_params = self.user_params.get(
"regulatory_recovery_test_params", {})
self.country_code = self.config_test_params.get("country_code", "US")
+ self.negative_test = self.config_test_params.get(
+ "negative_test", False)
for fd in self.fuchsia_devices:
fd.configure_wlan(association_mechanism='policy')
def teardown_class(self):
- for fd in self.fuchsia_devices:
- fd.wlan_controller.set_country_code(self.country_code)
+ if not self.negative_test:
+ for fd in self.fuchsia_devices:
+ fd.wlan_controller.set_country_code(self.country_code)
super().teardown_class()
@@ -66,6 +70,27 @@
fd.wlan_policy_controller.stop_client_connections()
fd.wlan_ap_policy_lib.wlanStopAllAccessPoint()
+ def set_country_code(self, fd):
+ try:
+ fd.wlan_controller.set_country_code(self.country_code)
+ except EnvironmentError as e:
+ if self.negative_test:
+ # In the negative case, setting the country code for an
+ # invalid country should fail.
+ pass
+ else:
+ # If this is not a negative test case, re-raise the
+ # exception.
+ raise e
+ else:
+ # The negative test case should have failed to set the country
+ # code and the positive test case should succeed.
+ if self.negative_test:
+ raise EnvironmentError(
+ "Setting invalid country code succeeded.")
+ else:
+ pass
+
def test_interfaces_not_recreated_when_initially_disabled(self):
"""This test ensures that after a new regulatory region is applied
while client connections and access points are disabled, no new
@@ -73,7 +98,7 @@
"""
for fd in self.fuchsia_devices:
# Set the region code.
- fd.wlan_controller.set_country_code(self.country_code)
+ self.set_country_code(fd)
# Reset the listeners and verify the current state.
fd.wlan_policy_lib.wlanSetNewListener()
@@ -116,7 +141,7 @@
"local_only", "any")
# Set the country code.
- fd.wlan_controller.set_country_code(self.country_code)
+ self.set_country_code(fd)
# Reset the listeners and verify the current state.
fd.wlan_policy_lib.wlanSetNewListener()
diff --git a/acts_tests/tests/google/fuchsia/wlan_policy/SavedNetworksTest.py b/acts_tests/tests/google/fuchsia/wlan_policy/SavedNetworksTest.py
index 8b256c3..b9d9721 100644
--- a/acts_tests/tests/google/fuchsia/wlan_policy/SavedNetworksTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan_policy/SavedNetworksTest.py
@@ -55,6 +55,7 @@
* One or more Fuchsia devices
* One Access Point
"""
+
def setup_class(self):
super().setup_class()
# Keep track of whether we have started an access point in a test
@@ -86,8 +87,9 @@
password: The password to save for the network. Empty string represents
no password, and PSK should be provided as 64 character hex string.
"""
- if not fd.wlan_policy_controller.save_network(
- ssid, security_type, password=password):
+ if fd.wlan_policy_controller.save_network(ssid,
+ security_type,
+ password=password):
self.log.info(
"Attempting to save bad network config %s did not give an error"
% ssid)
diff --git a/acts_tests/tests/google/fuchsia/wlan_policy/StartStopClientConnectionsTest.py b/acts_tests/tests/google/fuchsia/wlan_policy/StartStopClientConnectionsTest.py
index 3f585a2..7643a05 100644
--- a/acts_tests/tests/google/fuchsia/wlan_policy/StartStopClientConnectionsTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan_policy/StartStopClientConnectionsTest.py
@@ -20,12 +20,14 @@
from acts.controllers.ap_lib import hostapd_security
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
from acts.utils import rand_ascii_str
+import time
DISCONNECTED = "Disconnected"
CONNECTION_STOPPED = "ConnectionStopped"
CONNECTIONS_ENABLED = "ConnectionsEnabled"
CONNECTIONS_DISABLED = "ConnectionsDisabled"
WPA2 = "wpa2"
+UPDATE_TIMEOUT_SEC = 5
class StartStopClientConnectionsTest(WifiBaseTest):
@@ -36,6 +38,7 @@
* One or more Fuchsia devices
* One Access Point
"""
+
def setup_class(self):
super().setup_class()
# Start an AP with a hidden network
@@ -88,6 +91,42 @@
raise signals.TestFailure(
"Failed to get expected connect response")
+ def await_state_update(self, fd, desired_state, timeout):
+ """ This function polls the policy client state until it converges to
+ the caller's desired state.
+
+ Args:
+ fd: A FuchsiaDevice
+ desired_state: The expected client policy state.
+ timeout: Number of seconds to wait for the policy state to become
+ the desired_state.
+ Returns:
+ None assuming the desired state has been reached.
+ Raises:
+ TestFailure if the desired state is not reached by the timeout.
+ """
+ start_time = time.time()
+ curr_state = None
+ while time.time() < start_time + timeout:
+ fd.wlan_policy_lib.wlanSetNewListener()
+ curr_state = fd.wlan_policy_lib.wlanGetUpdate()
+ if curr_state.get("error"):
+ self.log.error("Error occurred getting status update: %s" %
+ curr_state.get("error"))
+ raise EnvironmentError("Failed to get update")
+
+ if curr_state.get("result") and curr_state.get(
+ "result") == desired_state:
+ return
+
+ time.sleep(1)
+
+ self.log.error(
+ "Client state did not converge to the expected state in %s "
+ "seconds. Expected update: %s Actual update: %s" %
+ (timeout, desired_state, curr_state))
+ raise signals.TestFailure("Client policy layer is in unexpected state")
+
def test_stop_client_connections_update(self):
for fd in self.fuchsia_devices:
if not fd.wlan_policy_controller.stop_client_connections():
@@ -95,21 +134,8 @@
# Check that the most recent update says that the device is not
# connected to anything and client connections are disabled
- fd.wlan_policy_lib.wlanSetNewListener()
- result_update = fd.wlan_policy_lib.wlanGetUpdate()
- if result_update.get("error") != None:
- self.log.error("Error occurred getting status update: %s" %
- result_update.get("error"))
- raise EnvironmentError("Failed to get update")
-
expected_update = {"networks": [], "state": CONNECTIONS_DISABLED}
- if result_update.get("result") != expected_update:
- self.log.error(
- "Most recent status update does not indicate client "
- "connections have stopped. Expected update: %s Actual update: %s"
- % (expected_update, result_update.get('result')))
- raise signals.TestFailure(
- "Incorrect update after stopping client connections")
+ self.await_state_update(fd, expected_update, UPDATE_TIMEOUT_SEC)
def test_start_client_connections_update(self):
for fd in self.fuchsia_devices:
@@ -118,21 +144,8 @@
# Check that the most recent update says that the device is not
# connected to anything and client connections are disabled
- fd.wlan_policy_lib.wlanSetNewListener()
- result_update = fd.wlan_policy_lib.wlanGetUpdate()
- if result_update.get("error") != None:
- self.log.error("Error occurred getting status update: %s" %
- result_update.get("error"))
- raise EnvironmentError("Failed to get update")
-
expected_update = {"networks": [], "state": CONNECTIONS_ENABLED}
- if result_update.get("result") != expected_update:
- self.log.error(
- "Most recent status update does not indicate client "
- "connections are enabled. Expected update: %s\nActual update:"
- % (expected_update, result_update))
- raise signals.TestFailure(
- "Incorrect update after starting client connections")
+ self.await_state_update(fd, expected_update, UPDATE_TIMEOUT_SEC)
def test_stop_client_connections_rejects_connections(self):
# Test that if we turn client connections off, our requests to connect
diff --git a/acts_tests/tests/google/gnss/FlpTtffTest.py b/acts_tests/tests/google/gnss/FlpTtffTest.py
index 59b19b5..0a30fe8 100644
--- a/acts_tests/tests/google/gnss/FlpTtffTest.py
+++ b/acts_tests/tests/google/gnss/FlpTtffTest.py
@@ -14,20 +14,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from acts import utils
from acts import asserts
from acts import signals
from acts.base_test import BaseTestClass
from acts.test_decorators import test_tracker_info
from acts.utils import get_current_epoch_time
from acts_contrib.test_utils.wifi.wifi_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_logger
-from acts_contrib.test_utils.tel.tel_test_utils import stop_qxdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import stop_qxdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import start_adb_tcpdump
+from acts_contrib.test_utils.tel.tel_logging_utils import stop_adb_tcpdump
+from acts_contrib.test_utils.tel.tel_logging_utils import get_tcpdump_log
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import abort_all_tests
from acts_contrib.test_utils.gnss.gnss_test_utils import get_baseband_and_gms_version
from acts_contrib.test_utils.gnss.gnss_test_utils import _init_device
-from acts_contrib.test_utils.gnss.gnss_test_utils import check_location_service
from acts_contrib.test_utils.gnss.gnss_test_utils import clear_logd_gnss_qxdm_log
from acts_contrib.test_utils.gnss.gnss_test_utils import set_mobile_data
from acts_contrib.test_utils.gnss.gnss_test_utils import get_gnss_qxdm_log
@@ -40,9 +40,6 @@
from acts_contrib.test_utils.gnss.gnss_test_utils import connect_to_wifi_network
from acts_contrib.test_utils.gnss.gnss_test_utils import gnss_tracking_via_gtw_gpstool
from acts_contrib.test_utils.gnss.gnss_test_utils import parse_gtw_gpstool_log
-from acts_contrib.test_utils.tel.tel_test_utils import start_adb_tcpdump
-from acts_contrib.test_utils.tel.tel_test_utils import stop_adb_tcpdump
-from acts_contrib.test_utils.tel.tel_test_utils import get_tcpdump_log
class FlpTtffTest(BaseTestClass):
diff --git a/acts_tests/tests/google/gnss/GnssBlankingThTest.py b/acts_tests/tests/google/gnss/GnssBlankingThTest.py
new file mode 100644
index 0000000..e625171
--- /dev/null
+++ b/acts_tests/tests/google/gnss/GnssBlankingThTest.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from acts_contrib.test_utils.gnss.GnssBlankingBase import GnssBlankingBase
+
+
+class GnssBlankingThTest(GnssBlankingBase):
+ """ LAB GNSS Cellular Coex Tx Power Sweep TTFF/FFPE Tests"""
+
+ def gnss_wwan_blanking_sweep_base(self):
+ """
+ GNSS WWAN blanking cellular power sweep base function
+ """
+ # Get parameters from user params.
+ first_wait = self.user_params.get('first_wait', 300)
+
+ # Start the test item with gnss_init_power_setting.
+ if self.gnss_init_power_setting(first_wait):
+ self.log.info('Successfully set the GNSS power level to %d' %
+ self.sa_sensitivity)
+ self.log.info('Start searching for cellular power level threshold')
+ # After the GNSS power initialization is done, start the cellular power sweep.
+ self.result_cell_pwr = self.cell_power_sweep()
+
+ def test_gnss_gsm850_sweep(self):
+ """
+ GNSS WWAN blanking cellular power sweep GSM850, Ch190.
+ """
+ self.eecoex_func = 'CELLR,2,850,190,1,1,{}'
+ self.start_pwr = self.gsm_sweep_params[0]
+ self.stop_pwr = self.gsm_sweep_params[1]
+ self.offset = self.gsm_sweep_params[2]
+ self.gnss_wwan_blanking_sweep_base()
+
+ def test_gnss_gsm900_sweep(self):
+ """
+ GNSS WWAN blanking cellular power sweep GSM900, Ch20.
+ """
+ self.eecoex_func = 'CELLR,2,900,20,1,1,{}'
+ self.start_pwr = self.gsm_sweep_params[0]
+ self.stop_pwr = self.gsm_sweep_params[1]
+ self.offset = self.gsm_sweep_params[2]
+ self.gnss_wwan_blanking_sweep_base()
+
+ def test_gnss_gsm1800_sweep(self):
+ """
+ GNSS WWAN blanking cellular power sweep GSM1800, Ch699.
+ """
+ self.eecoex_func = 'CELLR,2,1800,699,1,1,{}'
+ self.start_pwr = self.gsm_sweep_params[0]
+ self.stop_pwr = self.gsm_sweep_params[1]
+ self.offset = self.gsm_sweep_params[2]
+ self.gnss_wwan_blanking_sweep_base()
+
+ def test_gnss_gsm1900_sweep(self):
+ """
+ GNSS WWAN blanking cellular power sweep GSM1900, Ch661.
+ """
+ self.eecoex_func = 'CELLR,2,1900,661,1,1,{}'
+ self.start_pwr = self.gsm_sweep_params[0]
+ self.stop_pwr = self.gsm_sweep_params[1]
+ self.offset = self.gsm_sweep_params[2]
+ self.gnss_wwan_blanking_sweep_base()
+
+ def test_gnss_lte_b38_sweep(self):
+ """
+ GNSS WWAN blanking cellular power sweep LTE-TDD, B38, 10M, 12RB@0, Ch38000.
+ """
+ self.eecoex_func = 'CELLR,5,38,38000,true,PRIMARY,{},10MHz,0,12'
+ self.start_pwr = self.lte_tdd_pc3_sweep_params[0]
+ self.stop_pwr = self.lte_tdd_pc3_sweep_params[1]
+ self.offset = self.lte_tdd_pc3_sweep_params[2]
+ self.gnss_wwan_blanking_sweep_base()
+
+ def test_gnss_lte_b39_sweep(self):
+ """
+ GNSS WWAN blanking cellular power sweep LTE-TDD, B39, 10M, 12RB@0, Ch38450.
+ """
+ self.eecoex_func = 'CELLR,5,39,38450,true,PRIMARY,{},10MHz,0,12'
+ self.start_pwr = self.lte_tdd_pc3_sweep_params[0]
+ self.stop_pwr = self.lte_tdd_pc3_sweep_params[1]
+ self.offset = self.lte_tdd_pc3_sweep_params[2]
+ self.gnss_wwan_blanking_sweep_base()
+
+ def test_gnss_lte_b40_sweep(self):
+ """
+ GNSS WWAN blanking cellular power sweep LTE-TDD, B40, 10M, 12RB@0, Ch39150.
+ """
+ self.eecoex_func = 'CELLR,5,40,39150,true,PRIMARY,{},10MHz,0,12'
+ self.start_pwr = self.lte_tdd_pc3_sweep_params[0]
+ self.stop_pwr = self.lte_tdd_pc3_sweep_params[1]
+ self.offset = self.lte_tdd_pc3_sweep_params[2]
+ self.gnss_wwan_blanking_sweep_base()
+
+ def test_gnss_lte_b41_sweep(self):
+ """
+ GNSS WWAN blanking cellular power sweep LTE-TDD, B41, 10M, 12RB@0, Ch40620.
+ """
+ self.eecoex_func = 'CELLR,5,41,40620,true,PRIMARY,{},10MHz,0,12'
+ self.start_pwr = self.lte_tdd_pc3_sweep_params[0]
+ self.stop_pwr = self.lte_tdd_pc3_sweep_params[1]
+ self.offset = self.lte_tdd_pc3_sweep_params[2]
+ self.gnss_wwan_blanking_sweep_base()
+
+ def test_gnss_lte_b42_sweep(self):
+ """
+ GNSS WWAN blanking cellular power sweep LTE-TDD, B42, 10M, 12RB@0, Ch42590.
+ """
+ self.eecoex_func = 'CELLR,5,42,42590,true,PRIMARY,{},10MHz,0,12'
+ self.start_pwr = self.lte_tdd_pc3_sweep_params[0]
+ self.stop_pwr = self.lte_tdd_pc3_sweep_params[1]
+ self.offset = self.lte_tdd_pc3_sweep_params[2]
+ self.gnss_wwan_blanking_sweep_base()
+
+ def test_gnss_lte_b48_sweep(self):
+ """
+ GNSS WWAN blanking cellular power sweep LTE-TDD, B48, 10M, 12RB@0, Ch55990.
+ """
+ self.eecoex_func = 'CELLR,5,48,55990,true,PRIMARY,{},10MHz,0,12'
+ self.start_pwr = self.lte_tdd_pc3_sweep_params[0]
+ self.stop_pwr = self.lte_tdd_pc3_sweep_params[1]
+ self.offset = self.lte_tdd_pc3_sweep_params[2]
+ self.gnss_wwan_blanking_sweep_base()
+
+ def test_gnss_stand_alone_gnss(self):
+ """
+ GNSS stand alone test item.
+ """
+ self.eecoex_func = ''
+ self.start_pwr = 0
+ self.stop_pwr = 0
+ self.offset = 0
+ self.gnss_wwan_blanking_sweep_base()
diff --git a/acts_tests/tests/google/gnss/GnssConcurrencyTest.py b/acts_tests/tests/google/gnss/GnssConcurrencyTest.py
index 0eb714d..9169f4e 100644
--- a/acts_tests/tests/google/gnss/GnssConcurrencyTest.py
+++ b/acts_tests/tests/google/gnss/GnssConcurrencyTest.py
@@ -16,14 +16,15 @@
import time
import datetime
+import re
from acts import utils
-from acts import asserts
from acts import signals
from acts.base_test import BaseTestClass
from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.tel_logging_utils import start_adb_tcpdump
+from acts_contrib.test_utils.tel.tel_logging_utils import stop_adb_tcpdump
+from acts_contrib.test_utils.tel.tel_logging_utils import get_tcpdump_log
from acts_contrib.test_utils.gnss import gnss_test_utils as gutils
-from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
-from acts_contrib.test_utils.tel import tel_test_utils as tutils
CONCURRENCY_TYPE = {
"gnss": "GNSS location received",
@@ -40,14 +41,19 @@
self.ad = self.android_devices[0]
req_params = [
"standalone_cs_criteria", "chre_tolerate_rate", "qdsp6m_path",
- "outlier_criteria", "max_outliers"
+ "outlier_criteria", "max_outliers", "pixel_lab_location",
+ "max_interval", "onchip_interval"
]
self.unpack_userparams(req_param_names=req_params)
gutils._init_device(self.ad)
+ self.ad.adb.shell("setprop persist.vendor.radio.adb_log_on 0")
+ self.ad.adb.shell("sync")
+ gutils.reboot(self.ad)
def setup_test(self):
+ gutils.clear_logd_gnss_qxdm_log(self.ad)
gutils.start_pixel_logger(self.ad)
- tutils.start_adb_tcpdump(self.ad)
+ start_adb_tcpdump(self.ad)
# related properties
gutils.check_location_service(self.ad)
gutils.get_baseband_and_gms_version(self.ad)
@@ -55,12 +61,17 @@
def teardown_test(self):
gutils.stop_pixel_logger(self.ad)
- tutils.stop_adb_tcpdump(self.ad)
+ stop_adb_tcpdump(self.ad)
def on_fail(self, test_name, begin_time):
self.ad.take_bug_report(test_name, begin_time)
gutils.get_gnss_qxdm_log(self.ad, self.qdsp6m_path)
- tutils.get_tcpdump_log(self.ad, test_name, begin_time)
+ get_tcpdump_log(self.ad, test_name, begin_time)
+
+ def is_brcm_test(self):
+ """ Check the test is for BRCM and skip if not. """
+ if gutils.check_chipset_vendor_by_qualcomm(self.ad):
+ raise signals.TestSkip("Not BRCM chipset. Skip the test.")
def load_chre_nanoapp(self):
""" Load CHRE nanoapp to target Android Device. """
@@ -77,7 +88,7 @@
else:
raise signals.TestError("Failed to load CHRE nanoapp")
- def enable_gnss_concurrency(self, freq):
+ def enable_chre(self, freq):
""" Enable or disable gnss concurrency via nanoapp.
Args:
@@ -91,32 +102,14 @@
if "ap" not in type:
self.ad.adb.shell(" ".join([cmd, type, option]))
- def run_concurrency_test(self, ap_freq, chre_freq, test_time):
- """ Run the concurrency test with specific sequence.
-
- Args:
- ap_freq: int for AP side location request frequency.
- chre_freq: int forCHRE side location request frequency.
- test_time: int for test duration.
- Return: test begin time.
- """
- gutils.process_gnss_by_gtw_gpstool(self.ad, self.standalone_cs_criteria)
- begin_time = utils.get_current_epoch_time()
- gutils.start_gnss_by_gtw_gpstool(self.ad, True, freq=ap_freq)
- self.enable_gnss_concurrency(chre_freq)
- time.sleep(test_time)
- self.enable_gnss_concurrency(0)
- gutils.start_gnss_by_gtw_gpstool(self.ad, False)
- return begin_time
-
def parse_concurrency_result(self, begin_time, type, criteria):
""" Parse the test result with given time and criteria.
Args:
begin_time: test begin time.
type: str for location request type.
- criteria: int for test criteria.
- Return: List for the failure and outlier loops.
+ criteria: dictionary for test criteria.
+ Return: List for the failure and outlier loops and results.
"""
results = []
failures = []
@@ -126,6 +119,9 @@
start_time = utils.epoch_to_human_time(begin_time)
start_time = datetime.datetime.strptime(start_time,
"%m-%d-%Y %H:%M:%S ")
+ if not search_results:
+ raise signals.TestFailure(f"No log entry found for keyword:"
+ f"{CONCURRENCY_TYPE[type]}")
results.append(
(search_results[0]["datetime_obj"] - start_time).total_seconds())
samples = len(search_results) - 1
@@ -152,53 +148,193 @@
self.ad.log.info("TestResult %s_max_time %.2f" %
(type, max(results[1:])))
- return outliers, failures
+ return outliers, failures, results
- def execute_gnss_concurrency_test(self, criteria, test_duration):
+ def run_gnss_concurrency_test(self, criteria, test_duration):
""" Execute GNSS concurrency test steps.
Args:
criteria: int for test criteria.
test_duration: int for test duration.
"""
- failures = {}
- outliers = {}
- begin_time = self.run_concurrency_test(criteria["ap_location"],
- criteria["gnss"], test_duration)
- for type in CONCURRENCY_TYPE.keys():
- self.ad.log.info("Starting process %s result" % type)
- outliers[type], failures[type] = self.parse_concurrency_result(
- begin_time, type, criteria[type])
- for type in CONCURRENCY_TYPE.keys():
- if len(failures[type]) > 0:
- raise signals.TestFailure("Test exceeds criteria: %.2f" %
- criteria[type])
- elif len(outliers[type]) > self.max_outliers:
- raise signals.TestFailure("Outliers excceds max amount: %d" %
- len(outliers[type]))
+ begin_time = utils.get_current_epoch_time()
+ self.ad.log.info("Tests Start at %s" %
+ utils.epoch_to_human_time(begin_time))
+ gutils.start_gnss_by_gtw_gpstool(
+ self.ad, True, freq=criteria["ap_location"])
+ self.enable_chre(criteria["gnss"])
+ time.sleep(test_duration)
+ self.enable_chre(0)
+ gutils.start_gnss_by_gtw_gpstool(self.ad, False)
+ self.validate_location_test_result(begin_time, criteria)
- # Test Cases
+ def run_chre_only_test(self, criteria, test_duration):
+ """ Execute CHRE only test steps.
+
+ Args:
+ criteria: int for test criteria.
+ test_duration: int for test duration.
+ """
+ begin_time = utils.get_current_epoch_time()
+ self.ad.log.info("Tests Start at %s" %
+ utils.epoch_to_human_time(begin_time))
+ self.enable_chre(criteria["gnss"])
+ time.sleep(test_duration)
+ self.enable_chre(0)
+ self.validate_location_test_result(begin_time, criteria)
+
+ def validate_location_test_result(self, begin_time, request):
+ """ Validate GNSS concurrency/CHRE test results.
+
+ Args:
+ begin_time: epoc of test begin time
+ request: int for test criteria.
+ """
+ results = {}
+ outliers = {}
+ failures = {}
+ failure_log = ""
+ for request_type, criteria in request.items():
+ criteria = criteria if criteria > 1 else 1
+ self.ad.log.info("Starting process %s result" % request_type)
+ outliers[request_type], failures[request_type], results[
+ request_type] = self.parse_concurrency_result(
+ begin_time, request_type, criteria)
+ if not results[request_type]:
+ failure_log += "[%s] Fail to find location report.\n" % request_type
+ if len(failures[request_type]) > 0:
+ failure_log += "[%s] Test exceeds criteria: %.2f\n" % (
+ request_type, criteria)
+ if len(outliers[request_type]) > self.max_outliers:
+ failure_log += "[%s] Outliers excceds max amount: %d\n" % (
+ request_type, len(outliers[request_type]))
+
+ if failure_log:
+ raise signals.TestFailure(failure_log)
+
+ def run_engine_switching_test(self, freq):
+ """ Conduct engine switching test with given frequency.
+
+ Args:
+ freq: a list identify source1/2 frequency [freq1, freq2]
+ """
+ request = {"ap_location": self.max_interval}
+ begin_time = utils.get_current_epoch_time()
+ self.ad.droid.startLocating(freq[0] * 1000, 0)
+ time.sleep(10)
+ for i in range(5):
+ gutils.start_gnss_by_gtw_gpstool(self.ad, True, freq=freq[1])
+ time.sleep(10)
+ gutils.start_gnss_by_gtw_gpstool(self.ad, False)
+ self.ad.droid.stopLocating()
+ self.calculate_position_error(begin_time)
+ self.validate_location_test_result(begin_time, request)
+
+ def calculate_position_error(self, begin_time):
+ """ Calculate the position error for the logcat search results.
+
+ Args:
+ begin_time: test begin time
+ """
+ position_errors = []
+ search_results = self.ad.search_logcat("reportLocation", begin_time)
+ for result in search_results:
+ # search for location like 25.000717,121.455163
+ regex = r"(-?\d{1,5}\.\d{1,10}),\s*(-?\d{1,5}\.\d{1,10})"
+ result = re.search(regex, result["log_message"])
+ if not result:
+ raise ValueError("lat/lon does not found. "
+ f"original text: {result['log_message']}")
+ lat = float(result.group(1))
+ lon = float(result.group(2))
+ pe = gutils.calculate_position_error(lat, lon,
+ self.pixel_lab_location)
+ position_errors.append(pe)
+ self.ad.log.info("TestResult max_position_error %.2f" %
+ max(position_errors))
+
+ # Concurrency Test Cases
+ @test_tracker_info(uuid="9b0daebf-461e-4005-9773-d5d10aaeaaa4")
def test_gnss_concurrency_ct1(self):
test_duration = 15
criteria = {"ap_location": 1, "gnss": 1, "gnss_meas": 1}
- self.execute_gnss_concurrency_test(criteria, test_duration)
+ self.run_gnss_concurrency_test(criteria, test_duration)
+ @test_tracker_info(uuid="f423db2f-12a0-4858-b66f-99e7ca6010c3")
def test_gnss_concurrency_ct2(self):
test_duration = 30
criteria = {"ap_location": 1, "gnss": 8, "gnss_meas": 8}
- self.execute_gnss_concurrency_test(criteria, test_duration)
+ self.run_gnss_concurrency_test(criteria, test_duration)
+ @test_tracker_info(uuid="f72d2df0-f70a-4a11-9f68-2a38f6974454")
def test_gnss_concurrency_ct3(self):
test_duration = 60
criteria = {"ap_location": 15, "gnss": 8, "gnss_meas": 8}
- self.execute_gnss_concurrency_test(criteria, test_duration)
+ self.run_gnss_concurrency_test(criteria, test_duration)
+ @test_tracker_info(uuid="8e5563fd-afcd-40d3-9392-7fc0d10f49da")
def test_gnss_concurrency_aoc1(self):
test_duration = 120
criteria = {"ap_location": 61, "gnss": 1, "gnss_meas": 1}
- self.execute_gnss_concurrency_test(criteria, test_duration)
+ self.run_gnss_concurrency_test(criteria, test_duration)
+ @test_tracker_info(uuid="fb258565-6ac8-4bf7-a554-01d63fc4ef54")
def test_gnss_concurrency_aoc2(self):
test_duration = 120
criteria = {"ap_location": 61, "gnss": 10, "gnss_meas": 10}
- self.execute_gnss_concurrency_test(criteria, test_duration)
+ self.run_gnss_concurrency_test(criteria, test_duration)
+
+ # CHRE Only Test Cases
+ @test_tracker_info(uuid="cb85fa60-9f1a-4957-b5e3-0f2e5db70b47")
+ def test_gnss_chre1(self):
+ test_duration = 15
+ criteria = {"gnss": 1, "gnss_meas": 1}
+ self.run_chre_only_test(criteria, test_duration)
+
+ @test_tracker_info(uuid="6ab17866-0d0e-4d9e-b3af-441d9db0e324")
+ def test_gnss_chre2(self):
+ test_duration = 30
+ criteria = {"gnss": 8, "gnss_meas": 8}
+ self.run_chre_only_test(criteria, test_duration)
+
+ # Interval tests
+ @test_tracker_info(uuid="53b161e5-335e-44a7-ae2e-eae7464a2b37")
+ def test_variable_interval_via_chre(self):
+ test_duration = 10
+ intervals = [{
+ "gnss": 0.1,
+ "gnss_meas": 0.1
+ }, {
+ "gnss": 0.5,
+ "gnss_meas": 0.5
+ }, {
+ "gnss": 1.5,
+ "gnss_meas": 1.5
+ }]
+ for interval in intervals:
+ self.run_chre_only_test(interval, test_duration)
+
+ @test_tracker_info(uuid="ee0a46fe-aa5f-4dfd-9cb7-d4924f9e9cea")
+ def test_variable_interval_via_framework(self):
+ test_duration = 10
+ intervals = [0, 0.5, 1.5]
+ for interval in intervals:
+ begin_time = utils.get_current_epoch_time()
+ self.ad.droid.startLocating(interval * 1000, 0)
+ time.sleep(test_duration)
+ self.ad.droid.stopLocating()
+ criteria = interval if interval > 1 else 1
+ self.parse_concurrency_result(begin_time, "ap_location", criteria)
+
+ # Engine switching test
+ @test_tracker_info(uuid="8b42bcb2-cb8c-4ef9-bd98-4fb74a521224")
+ def test_gps_engine_switching_host_to_onchip(self):
+ self.is_brcm_test()
+ freq = [1, self.onchip_interval]
+ self.run_engine_switching_test(freq)
+
+ @test_tracker_info(uuid="636041dc-2bd6-4854-aa5d-61c87943d99c")
+ def test_gps_engine_switching_onchip_to_host(self):
+ self.is_brcm_test()
+ freq = [self.onchip_interval, 1]
+ self.run_engine_switching_test(freq)
diff --git a/acts_tests/tests/google/gnss/GnssFunctionTest.py b/acts_tests/tests/google/gnss/GnssFunctionTest.py
index 1c48601..d45a997 100644
--- a/acts_tests/tests/google/gnss/GnssFunctionTest.py
+++ b/acts_tests/tests/google/gnss/GnssFunctionTest.py
@@ -19,7 +19,6 @@
import fnmatch
from multiprocessing import Process
-from acts import utils
from acts import asserts
from acts import signals
from acts.base_test import BaseTestClass
@@ -29,18 +28,13 @@
from acts_contrib.test_utils.gnss import gnss_test_utils as gutils
from acts.utils import get_current_epoch_time
from acts.utils import unzip_maintain_permissions
-from acts.utils import force_airplane_mode
from acts_contrib.test_utils.wifi.wifi_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_test_utils import flash_radio
+from acts_contrib.test_utils.tel.tel_bootloader_utils import flash_radio
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import abort_all_tests
-from acts_contrib.test_utils.tel.tel_test_utils import stop_qxdm_logger
from acts_contrib.test_utils.tel.tel_test_utils import check_call_state_connected_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import http_file_download_by_sl4a
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_logger
-from acts_contrib.test_utils.tel.tel_test_utils import trigger_modem_crash
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_data_utils import http_file_download_by_sl4a
from acts_contrib.test_utils.gnss.gnss_test_utils import get_baseband_and_gms_version
from acts_contrib.test_utils.gnss.gnss_test_utils import set_attenuator_gnss_signal
from acts_contrib.test_utils.gnss.gnss_test_utils import _init_device
@@ -63,7 +57,6 @@
from acts_contrib.test_utils.gnss.gnss_test_utils import check_ttff_data
from acts_contrib.test_utils.gnss.gnss_test_utils import start_youtube_video
from acts_contrib.test_utils.gnss.gnss_test_utils import fastboot_factory_reset
-from acts_contrib.test_utils.gnss.gnss_test_utils import gnss_trigger_modem_ssr_by_adb
from acts_contrib.test_utils.gnss.gnss_test_utils import gnss_trigger_modem_ssr_by_mds
from acts_contrib.test_utils.gnss.gnss_test_utils import disable_supl_mode
from acts_contrib.test_utils.gnss.gnss_test_utils import connect_to_wifi_network
@@ -73,9 +66,13 @@
from acts_contrib.test_utils.gnss.gnss_test_utils import enable_supl_mode
from acts_contrib.test_utils.gnss.gnss_test_utils import start_toggle_gnss_by_gtw_gpstool
from acts_contrib.test_utils.gnss.gnss_test_utils import grant_location_permission
-from acts_contrib.test_utils.tel.tel_test_utils import start_adb_tcpdump
-from acts_contrib.test_utils.tel.tel_test_utils import stop_adb_tcpdump
-from acts_contrib.test_utils.tel.tel_test_utils import get_tcpdump_log
+from acts_contrib.test_utils.gnss.gnss_test_utils import is_mobile_data_on
+from acts_contrib.test_utils.gnss.gnss_test_utils import is_wearable_btwifi
+from acts_contrib.test_utils.gnss.gnss_test_utils import delete_lto_file
+from acts_contrib.test_utils.gnss.gnss_test_utils import is_device_wearable
+from acts_contrib.test_utils.tel.tel_logging_utils import start_adb_tcpdump
+from acts_contrib.test_utils.tel.tel_logging_utils import stop_adb_tcpdump
+from acts_contrib.test_utils.tel.tel_logging_utils import get_tcpdump_log
class GnssFunctionTest(BaseTestClass):
@@ -94,13 +91,14 @@
"weak_signal_xtra_cs_criteria",
"weak_signal_xtra_ws_criteria",
"weak_signal_xtra_hs_criteria",
+ "wearable_reboot_hs_criteria",
"default_gnss_signal_attenuation",
"weak_gnss_signal_attenuation",
"no_gnss_signal_attenuation", "gnss_init_error_list",
"gnss_init_error_allowlist", "pixel_lab_location",
- "legacy_wifi_xtra_cs_criteria", "legacy_projects",
"qdsp6m_path", "supl_capabilities", "ttff_test_cycle",
- "collect_logs", "dpo_threshold"]
+ "collect_logs", "dpo_threshold",
+ "brcm_error_log_allowlist"]
self.unpack_userparams(req_param_names=req_params)
# create hashmap for SSID
self.ssid_map = {}
@@ -109,11 +107,8 @@
self.ssid_map[SSID] = network
self.ttff_mode = {"cs": "Cold Start",
"ws": "Warm Start",
- "hs": "Hot Start"}
- if self.ad.model in self.legacy_projects:
- self.wifi_xtra_cs_criteria = self.legacy_wifi_xtra_cs_criteria
- else:
- self.wifi_xtra_cs_criteria = self.xtra_cs_criteria
+ "hs": "Hot Start",
+ "csa": "CSWith Assist"}
if self.collect_logs and \
gutils.check_chipset_vendor_by_qualcomm(self.ad):
self.flash_new_radio_or_mbn()
@@ -126,6 +121,11 @@
clear_logd_gnss_qxdm_log(self.ad)
set_attenuator_gnss_signal(self.ad, self.attenuators,
self.default_gnss_signal_attenuation)
+ # TODO (b/202101058:chenstanley): Need to double check how to disable wifi successfully in wearable projects.
+ if is_wearable_btwifi(self.ad):
+ wifi_toggle_state(self.ad, True)
+ connect_to_wifi_network(
+ self.ad, self.ssid_map[self.pixel_lab_network[0]["SSID"]])
if not verify_internet_connection(self.ad.log, self.ad, retries=3,
expected_state=True):
raise signals.TestFailure("Fail to connect to LTE network.")
@@ -136,18 +136,23 @@
stop_adb_tcpdump(self.ad)
set_attenuator_gnss_signal(self.ad, self.attenuators,
self.default_gnss_signal_attenuation)
- if check_call_state_connected_by_adb(self.ad):
- hangup_call(self.ad.log, self.ad)
- if int(self.ad.adb.shell("settings get global airplane_mode_on")) != 0:
+ # TODO(chenstanley): sim structure issue
+ if not is_device_wearable(self.ad):
+ if check_call_state_connected_by_adb(self.ad):
+ hangup_call(self.ad.log, self.ad)
+ if self.ad.droid.connectivityCheckAirplaneMode():
self.ad.log.info("Force airplane mode off")
- force_airplane_mode(self.ad, False)
- if self.ad.droid.wifiCheckState():
+ self.ad.droid.connectivityToggleAirplaneMode(False)
+ if not is_wearable_btwifi and self.ad.droid.wifiCheckState():
wifi_toggle_state(self.ad, False)
- if int(self.ad.adb.shell("settings get global mobile_data")) != 1:
+ if not is_mobile_data_on(self.ad):
set_mobile_data(self.ad, True)
if int(self.ad.adb.shell(
"settings get global wifi_scan_always_enabled")) != 1:
set_wifi_and_bt_scanning(self.ad, True)
+ if not verify_internet_connection(self.ad.log, self.ad, retries=3,
+ expected_state=True):
+ raise signals.TestFailure("Fail to connect to LTE network.")
def on_fail(self, test_name, begin_time):
if self.collect_logs:
@@ -287,7 +292,7 @@
"""
self.start_qxdm_and_tcpdump_log()
self.ad.log.info("Turn airplane mode on")
- force_airplane_mode(self.ad, True)
+ self.ad.droid.connectivityToggleAirplaneMode(True)
self.run_ttff_via_gtw_gpstool(mode, criteria)
def supl_ttff_weak_gnss_signal(self, mode, criteria):
@@ -337,12 +342,37 @@
disable_supl_mode(self.ad)
self.start_qxdm_and_tcpdump_log()
self.ad.log.info("Turn airplane mode on")
- force_airplane_mode(self.ad, True)
+ self.ad.droid.connectivityToggleAirplaneMode(True)
wifi_toggle_state(self.ad, True)
connect_to_wifi_network(
self.ad, self.ssid_map[self.pixel_lab_network[0]["SSID"]])
self.run_ttff_via_gtw_gpstool(mode, criteria)
+ def ttff_with_assist(self, mode, criteria):
+ """Verify CS/WS TTFF functionality with Assist data.
+
+ Args:
+ mode: "csa" or "ws"
+ criteria: Criteria for the test.
+ """
+ disable_supl_mode(self.ad)
+ begin_time = get_current_epoch_time()
+ process_gnss_by_gtw_gpstool(
+ self.ad, self.standalone_cs_criteria)
+ check_xtra_download(self.ad, begin_time)
+ self.ad.log.info("Turn airplane mode on")
+ self.ad.droid.connectivityToggleAirplaneMode(True)
+ start_gnss_by_gtw_gpstool(self.ad, True)
+ start_ttff_by_gtw_gpstool(
+ self.ad, mode, iteration=self.ttff_test_cycle)
+ ttff_data = process_ttff_by_gtw_gpstool(
+ self.ad, begin_time, self.pixel_lab_location)
+ result = check_ttff_data(
+ self.ad, ttff_data, mode, criteria)
+ asserts.assert_true(
+ result, "TTFF %s fails to reach designated criteria of %d "
+ "seconds." % (self.ttff_mode.get(mode), criteria))
+
""" Test Cases """
@test_tracker_info(uuid="ab859f2a-2c95-4d15-bb7f-bd0e3278340f")
@@ -383,26 +413,14 @@
type="gnss",
testtime=tracking_minutes,
meas_flag=True)
- dpo_results = self.ad.search_logcat("HardwareClockDiscontinuityCount",
- dpo_begin_time)
- if not dpo_results:
- raise signals.TestError(
- "No \"HardwareClockDiscontinuityCount\" is found in logs.")
- self.ad.log.info(dpo_results[0]["log_message"])
- self.ad.log.info(dpo_results[-1]["log_message"])
- first_dpo_count = int(dpo_results[0]["log_message"].split()[-1])
- final_dpo_count = int(dpo_results[-1]["log_message"].split()[-1])
- dpo_rate = ((final_dpo_count - first_dpo_count)/(tracking_minutes * 60))
- dpo_engage_rate = "{percent:.2%}".format(percent=dpo_rate)
- self.ad.log.info("DPO is ON for %d seconds during %d minutes test." % (
- final_dpo_count - first_dpo_count, tracking_minutes))
- self.ad.log.info("TestResult DPO_Engage_Rate " + dpo_engage_rate)
- threshold = "{percent:.0%}".format(percent=self.dpo_threshold / 100)
- asserts.assert_true(dpo_rate * 100 > self.dpo_threshold,
- "DPO only engaged %s in %d minutes test with "
- "threshold %s." % (dpo_engage_rate,
- tracking_minutes,
- threshold))
+ if gutils.check_chipset_vendor_by_qualcomm(self.ad):
+ gutils.check_dpo_rate_via_gnss_meas(self.ad,
+ dpo_begin_time,
+ self.dpo_threshold)
+ else:
+ gutils.check_dpo_rate_via_brcm_log(self.ad,
+ self.dpo_threshold,
+ self.brcm_error_log_allowlist)
@test_tracker_info(uuid="499d2091-640a-4735-9c58-de67370e4421")
def test_gnss_init_error(self):
@@ -936,7 +954,7 @@
All SUPL TTFF Cold Start results should be within supl_cs_criteria.
"""
for times in range(1, 4):
- fastboot_factory_reset(self.ad)
+ fastboot_factory_reset(self.ad, True)
self.ad.unlock_screen(password=None)
_init_device(self.ad)
begin_time = get_current_epoch_time()
@@ -1052,9 +1070,9 @@
Expected Results:
XTRA/LTO TTFF Cold Start results should be within
- wifi_xtra_cs_criteria.
+ xtra_cs_criteria.
"""
- self.xtra_ttff_wifi("cs", self.wifi_xtra_cs_criteria)
+ self.xtra_ttff_wifi("cs", self.xtra_cs_criteria)
@test_tracker_info(uuid="f6e79b31-99d5-49ca-974f-4543957ea449")
def test_xtra_ttff_ws_wifi(self):
@@ -1171,7 +1189,7 @@
disable_supl_mode(self.ad)
self.start_qxdm_and_tcpdump_log()
self.ad.log.info("Turn airplane mode on")
- force_airplane_mode(self.ad, True)
+ self.ad.droid.connectivityToggleAirplaneMode(True)
wifi_toggle_state(self.ad, True)
connect_to_wifi_network(
self.ad, self.ssid_map[self.pixel_lab_network[0]["SSID"]])
@@ -1283,12 +1301,80 @@
start_gnss_by_gtw_gpstool(self.ad, False)
for test_loop in range(1, 11):
reboot(self.ad)
- test_result = process_gnss_by_gtw_gpstool(
- self.ad, self.supl_hs_criteria, clear_data=False)
+ self.start_qxdm_and_tcpdump_log()
+ if is_device_wearable(self.ad):
+ test_result = process_gnss_by_gtw_gpstool(
+ self.ad, self.wearable_reboot_hs_criteria, clear_data=False)
+ else:
+ test_result = process_gnss_by_gtw_gpstool(
+ self.ad, self.supl_hs_criteria, clear_data=False)
start_gnss_by_gtw_gpstool(self.ad, False)
self.ad.log.info("Iteration %d => %s" % (test_loop, test_result))
overall_test_result.append(test_result)
+ gutils.stop_pixel_logger(self.ad)
+ stop_adb_tcpdump(self.ad)
pass_rate = overall_test_result.count(True)/len(overall_test_result)
self.ad.log.info("TestResult Pass_rate %s" % format(pass_rate, ".0%"))
asserts.assert_true(all(overall_test_result),
"GNSS init fail after reboot.")
+
+ @test_tracker_info(uuid="2c62183a-4354-4efc-92f2-84580cbd3398")
+ def test_lto_download_after_reboot(self):
+ """Verify LTO data could be downloaded and injected after device reboot.
+
+ Steps:
+ 1. Reboot device.
+ 2. Verify whether LTO is auto downloaded and injected without trigger GPS.
+ 3. Repeat Step 1 to Step 2 for 5 times.
+
+ Expected Results:
+ LTO data is properly downloaded and injected at the first time tether to phone.
+ """
+ reboot_lto_test_results_all = []
+ disable_supl_mode(self.ad)
+ for times in range(1, 6):
+ delete_lto_file(self.ad)
+ reboot(self.ad)
+ self.start_qxdm_and_tcpdump_log()
+ # Wait 20 seconds for boot busy and lto auto-download time
+ time.sleep(20)
+ begin_time = get_current_epoch_time()
+ reboot_lto_test_result = gutils.check_xtra_download(self.ad, begin_time)
+ self.ad.log.info("Iteration %d => %s" % (times, reboot_lto_test_result))
+ reboot_lto_test_results_all.append(reboot_lto_test_result)
+ gutils.stop_pixel_logger(self.ad)
+ tutils.stop_adb_tcpdump(self.ad)
+ asserts.assert_true(all(reboot_lto_test_results_all),
+ "Fail to Download and Inject LTO File.")
+
+ @test_tracker_info(uuid="a7048a4f-8a40-40a4-bb6c-7fc90e8227bd")
+ def test_ws_with_assist(self):
+ """Verify Warm Start functionality with existed LTO data.
+
+ Steps:
+ 1. Disable SUPL mode.
+ 2. Make LTO is downloaded.
+ 3. Turn on AirPlane mode to make sure there's no network connection.
+ 4. TTFF Warm Start with Assist for 10 iteration.
+
+ Expected Results:
+ All TTFF Warm Start with Assist results should be within
+ xtra_ws_criteria.
+ """
+ self.ttff_with_assist("ws", self.xtra_ws_criteria)
+
+ @test_tracker_info(uuid="c5fb9519-63b0-42bd-bd79-fce7593604ea")
+ def test_cs_with_assist(self):
+ """Verify Cold Start functionality with existed LTO data.
+
+ Steps:
+ 1. Disable SUPL mode.
+ 2. Make sure LTO is downloaded.
+ 3. Turn on AirPlane mode to make sure there's no network connection.
+ 4. TTFF Cold Start with Assist for 10 iteration.
+
+ Expected Results:
+ All TTFF Cold Start with Assist results should be within
+ standalone_cs_criteria.
+ """
+ self.ttff_with_assist("csa", self.standalone_cs_criteria)
diff --git a/acts_tests/tests/google/gnss/GnssHsSenTest.py b/acts_tests/tests/google/gnss/GnssHsSenTest.py
new file mode 100644
index 0000000..5269ae0
--- /dev/null
+++ b/acts_tests/tests/google/gnss/GnssHsSenTest.py
@@ -0,0 +1,180 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+from acts_contrib.test_utils.gnss.GnssBlankingBase import GnssBlankingBase
+from acts_contrib.test_utils.gnss.dut_log_test_utils import get_gpstool_logs
+from acts_contrib.test_utils.gnss.gnss_test_utils import excute_eecoexer_function
+
+
+class GnssHsSenTest(GnssBlankingBase):
+ """ LAB GNSS Cellular coex hot start sensitivity search"""
+
+ def __init__(self, controllers):
+ super().__init__(controllers)
+ self.gnss_simulator_power_level = -130
+ self.sa_sensitivity = -150
+ self.gnss_pwr_lvl_offset = 5
+
+ def gnss_hot_start_sensitivity_search_base(self, cellular_enable=False):
+ """
+ Perform GNSS hot start sensitivity search.
+
+ Args:
+ cellular_enable: argument to identify if Tx cellular signal is required or not.
+ Type, bool.
+ Default, False.
+ """
+ # Get parameters from user_params.
+ first_wait = self.user_params.get('first_wait', 300)
+ wait_between_pwr = self.user_params.get('wait_between_pwr', 60)
+ gnss_pwr_sweep = self.user_params.get('gnss_pwr_sweep')
+ gnss_init_pwr = gnss_pwr_sweep.get('init')
+ self.gnss_simulator_power_level = gnss_init_pwr[0]
+ self.sa_sensitivity = gnss_init_pwr[1]
+ self.gnss_pwr_lvl_offset = gnss_init_pwr[2]
+ gnss_pwr_fine_sweep = gnss_pwr_sweep.get('fine_sweep')
+ ttft_iteration = self.user_params.get('ttff_iteration', 25)
+
+ # Start the test item with gnss_init_power_setting.
+ if self.gnss_init_power_setting(first_wait):
+ self.log.info('Successfully set the GNSS power level to %d' %
+ self.sa_sensitivity)
+ # Create gnss log folders for init and cellular sweep
+ gnss_init_log_dir = os.path.join(self.gnss_log_path, 'GNSS_init')
+
+ # Pull all exist GPStool logs into GNSS_init folder
+ get_gpstool_logs(self.dut, gnss_init_log_dir, False)
+
+ if cellular_enable:
+ self.log.info('Start cellular coexistence test.')
+ # Set cellular Tx power level.
+ eecoex_cmd = self.eecoex_func.format('Infinity')
+ eecoex_cmd_file_str = eecoex_cmd.replace(',', '_')
+ excute_eecoexer_function(self.dut, eecoex_cmd)
+ else:
+ self.log.info('Start stand alone test.')
+ eecoex_cmd_file_str = 'Stand_alone'
+
+ for i, gnss_pwr in enumerate(gnss_pwr_fine_sweep):
+ self.log.info('Start fine GNSS power level sweep part %d' %
+ (i + 1))
+ sweep_start = gnss_pwr[0]
+ sweep_stop = gnss_pwr[1]
+ sweep_offset = gnss_pwr[2]
+ self.log.info(
+ 'The GNSS simulator (start, stop, offset): (%.1f, %.1f, %.1f)'
+ % (sweep_start, sweep_stop, sweep_offset))
+ result, sensitivity = self.hot_start_gnss_power_sweep(
+ sweep_start, sweep_stop, sweep_offset, wait_between_pwr,
+ ttft_iteration, True, eecoex_cmd_file_str)
+ if not result:
+ break
+ self.log.info('The sensitivity level is: %.1f' % sensitivity)
+
+ def test_hot_start_sensitivity_search(self):
+ """
+ GNSS hot start stand alone sensitivity search.
+ """
+ self.gnss_hot_start_sensitivity_search_base(False)
+
+ def test_hot_start_sensitivity_search_gsm850(self):
+ """
+ GNSS hot start GSM850 Ch190 coexistence sensitivity search.
+ """
+ self.eecoex_func = 'CELLR,2,850,190,1,1,{}'
+ self.log.info('Running GSM850 and GNSS coexistence sensitivity search.')
+ self.gnss_hot_start_sensitivity_search_base(True)
+
+ def test_hot_start_sensitivity_search_gsm900(self):
+ """
+ GNSS hot start GSM900 Ch20 coexistence sensitivity search.
+ """
+ self.eecoex_func = 'CELLR,2,900,20,1,1,{}'
+ self.log.info('Running GSM900 and GNSS coexistence sensitivity search.')
+ self.gnss_hot_start_sensitivity_search_base(True)
+
+ def test_hot_start_sensitivity_search_gsm1800(self):
+ """
+ GNSS hot start GSM1800 Ch699 coexistence sensitivity search.
+ """
+ self.eecoex_func = 'CELLR,2,1800,699,1,1,{}'
+ self.log.info(
+ 'Running GSM1800 and GNSS coexistence sensitivity search.')
+ self.gnss_hot_start_sensitivity_search_base(True)
+
+ def test_hot_start_sensitivity_search_gsm1900(self):
+ """
+ GNSS hot start GSM1900 Ch661 coexistence sensitivity search.
+ """
+ self.eecoex_func = 'CELLR,2,1900,661,1,1,{}'
+ self.log.info(
+ 'Running GSM1900 and GNSS coexistence sensitivity search.')
+ self.gnss_hot_start_sensitivity_search_base(True)
+
+ def test_hot_start_sensitivity_search_lte_b38(self):
+ """
+ GNSS hot start LTE B38 Ch38000 coexistence sensitivity search.
+ """
+ self.eecoex_func = 'CELLR,5,38,38000,true,PRIMARY,{},10MHz,0,12'
+ self.log.info(
+ 'Running LTE B38 and GNSS coexistence sensitivity search.')
+ self.gnss_hot_start_sensitivity_search_base(True)
+
+ def test_hot_start_sensitivity_search_lte_b39(self):
+ """
+ GNSS hot start LTE B39 Ch38450 coexistence sensitivity search.
+ """
+ self.eecoex_func = 'CELLR,5,39,38450,true,PRIMARY,{},10MHz,0,12'
+ self.log.info(
+ 'Running LTE B38 and GNSS coexistence sensitivity search.')
+ self.gnss_hot_start_sensitivity_search_base(True)
+
+ def test_hot_start_sensitivity_search_lte_b40(self):
+ """
+ GNSS hot start LTE B40 Ch39150 coexistence sensitivity search.
+ """
+ self.eecoex_func = 'CELLR,5,40,39150,true,PRIMARY,{},10MHz,0,12'
+ self.log.info(
+ 'Running LTE B38 and GNSS coexistence sensitivity search.')
+ self.gnss_hot_start_sensitivity_search_base(True)
+
+ def test_hot_start_sensitivity_search_lte_b41(self):
+ """
+ GNSS hot start LTE B41 Ch40620 coexistence sensitivity search.
+ """
+ self.eecoex_func = 'CELLR,5,41,40620,true,PRIMARY,{},10MHz,0,12'
+ self.log.info(
+ 'Running LTE B41 and GNSS coexistence sensitivity search.')
+ self.gnss_hot_start_sensitivity_search_base(True)
+
+ def test_hot_start_sensitivity_search_lte_b42(self):
+ """
+ GNSS hot start LTE B42 Ch42590 coexistence sensitivity search.
+ """
+ self.eecoex_func = 'CELLR,5,42,42590,true,PRIMARY,{},10MHz,0,12'
+ self.log.info(
+ 'Running LTE B42 and GNSS coexistence sensitivity search.')
+ self.gnss_hot_start_sensitivity_search_base(True)
+
+ def test_hot_start_sensitivity_search_lte_b48(self):
+ """
+ GNSS hot start LTE B48 Ch55990 coexistence sensitivity search.
+ """
+ self.eecoex_func = 'CELLR,5,48,55990,true,PRIMARY,{},10MHz,0,12'
+ self.log.info(
+ 'Running LTE B48 and GNSS coexistence sensitivity search.')
+ self.gnss_hot_start_sensitivity_search_base(True)
diff --git a/acts_tests/tests/google/gnss/GnssPowerAGPSTest.py b/acts_tests/tests/google/gnss/GnssPowerAGPSTest.py
index df52d64..15ec3c2 100644
--- a/acts_tests/tests/google/gnss/GnssPowerAGPSTest.py
+++ b/acts_tests/tests/google/gnss/GnssPowerAGPSTest.py
@@ -36,16 +36,17 @@
self.set_cell_only()
self.start_gnss_tracking_with_power_data()
- def test_cell_strong_cn_long(self):
- self.set_cell_only()
- self.start_gnss_tracking_with_power_data()
-
- def test_cell_weak_cn_long(self):
- self.set_attenuation(self.atten_level['weak_signal'])
- self.set_cell_only()
- self.start_gnss_tracking_with_power_data()
-
def test_cell_no_signal(self):
self.set_attenuation(self.atten_level['no_signal'])
self.set_cell_only()
self.start_gnss_tracking_with_power_data(is_signal=False)
+
+ # Long Interval tests
+ def test_cell_strong_cn_long(self):
+ self.set_cell_only()
+ self.start_gnss_tracking_with_power_data(freq=self.interval)
+
+ def test_cell_weak_cn_long(self):
+ self.set_attenuation(self.atten_level['weak_signal'])
+ self.set_cell_only()
+ self.start_gnss_tracking_with_power_data(freq=self.interval)
diff --git a/acts_tests/tests/google/gnss/GnssPowerBasicTest.py b/acts_tests/tests/google/gnss/GnssPowerBasicTest.py
index b74aa96..d4ee545 100644
--- a/acts_tests/tests/google/gnss/GnssPowerBasicTest.py
+++ b/acts_tests/tests/google/gnss/GnssPowerBasicTest.py
@@ -46,7 +46,7 @@
self.start_gnss_tracking_with_power_data()
# Long Interval tests
- def test_standalone_DPO_long_strong_cn(self):
+ def test_standalone_DPO_strong_cn_long(self):
self.start_gnss_tracking_with_power_data(freq=self.interval)
def test_standalone_NDPO_strong_cn_long(self):
diff --git a/acts_tests/tests/google/gnss/GnssPowerFrequecyTest.py b/acts_tests/tests/google/gnss/GnssPowerFrequecyTest.py
new file mode 100644
index 0000000..e24845e
--- /dev/null
+++ b/acts_tests/tests/google/gnss/GnssPowerFrequecyTest.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from acts import utils
+from acts_contrib.test_utils.power.PowerGTWGnssBaseTest import PowerGTWGnssBaseTest
+
+
+class GnssPowerFrequencyTest(PowerGTWGnssBaseTest):
+ """Gnss Power Low Power Mode Test"""
+
+ # Test cases
+ # L1 only test cases
+ def test_L1_only_strong(self):
+ self.ad.adb.shell('settings put secure location_mode 3')
+ self.set_attenuation(self.atten_level['l1_strong_signal'])
+ self.start_gnss_tracking_with_power_data()
+
+ def test_L1_only_weak(self):
+ self.ad.adb.shell('settings put secure location_mode 3')
+ self.set_attenuation(self.atten_level['l1_weak_signal'])
+ self.start_gnss_tracking_with_power_data()
+
+ # L5 tests
+ def test_L1L5_strong(self):
+ self.ad.adb.shell('settings put secure location_mode 3')
+ self.set_attenuation(self.atten_level['l1l5_strong_signal'])
+ self.start_gnss_tracking_with_power_data()
+
+ def test_L1L5_weak(self):
+ self.ad.adb.shell('settings put secure location_mode 3')
+ self.set_attenuation(self.atten_level['l1l5_weak_signal'])
+ self.start_gnss_tracking_with_power_data()
+
+ def test_L1_weak_L5_strong(self):
+ self.ad.adb.shell('settings put secure location_mode 3')
+ self.set_attenuation(self.atten_level['l1_w_l5_s_signal'])
+ self.start_gnss_tracking_with_power_data()
+
+ def test_L1_strong_L5_weak(self):
+ self.ad.adb.shell('settings put secure location_mode 3')
+ self.set_attenuation(self.atten_level['l1_s_l5_w_signal'])
+ self.start_gnss_tracking_with_power_data()
diff --git a/acts_tests/tests/google/gnss/GnssPowerMeasurementTest.py b/acts_tests/tests/google/gnss/GnssPowerMeasurementTest.py
index 3125263..affd322 100644
--- a/acts_tests/tests/google/gnss/GnssPowerMeasurementTest.py
+++ b/acts_tests/tests/google/gnss/GnssPowerMeasurementTest.py
@@ -31,6 +31,7 @@
self.start_gnss_tracking_with_power_data(
mode='standalone', freq=self.meas_interval, meas=True)
+ # Long Interval tests
def test_measurement_DPO_long(self):
self.start_gnss_tracking_with_power_data(
mode='standalone', freq=self.interval, meas=True)
diff --git a/acts_tests/tests/google/gnss/GnssSimInventoryTest.py b/acts_tests/tests/google/gnss/GnssSimInventoryTest.py
index cabd82d..801aa85 100644
--- a/acts_tests/tests/google/gnss/GnssSimInventoryTest.py
+++ b/acts_tests/tests/google/gnss/GnssSimInventoryTest.py
@@ -1,6 +1,6 @@
import time
import os
-import tempfile
+import re
from acts import utils
from acts import signals
@@ -15,8 +15,6 @@
def setup_class(self):
super().setup_class()
self.ad = self.android_devices[0]
- req_params = ["sim_inventory_recipient", "sim_inventory_ldap"]
- self.unpack_userparams(req_param_names=req_params)
def check_device_status(self):
if int(self.ad.adb.shell("settings get global airplane_mode_on")) != 0:
@@ -27,34 +25,32 @@
def get_imsi(self):
self.ad.log.info("Get imsi from netpolicy.xml")
- tmp_path = tempfile.mkdtemp()
- self.ad.pull_files("/data/system/netpolicy.xml", tmp_path)
- netpolicy_path = os.path.join(tmp_path, "netpolicy.xml")
- with open(netpolicy_path, "r", encoding="utf-8") as file:
- for line in file.readlines():
- if "subscriberId" in line:
- imsi = line.split(" ")[2].split("=")[-1].strip('"')
- return imsi
- raise signals.TestFailure("Fail to get imsi")
+ try:
+ tmp_imsi = self.ad.adb.shell("cat /data/system/netpolicy.xml")
+ imsi = re.compile(r'(\d{15})').search(tmp_imsi).group(1)
+ return imsi
+ except Exception as e:
+ raise signals.TestFailure("Fail to get imsi : %s" % e)
def get_iccid(self):
iccid = str(get_iccid_by_adb(self.ad))
if not isinstance(iccid, int):
self.ad.log.info("Unable to get iccid via adb. Changed to isub.")
- iccid = str(self.ad.adb.shell(
- "dumpsys isub | grep iccid")).split(" ")[4].strip(",")
+ tmp_iccid = self.ad.adb.shell("dumpsys isub | grep iccid")
+ iccid = re.compile(r'(\d{20})').search(tmp_iccid).group(1)
return iccid
raise signals.TestFailure("Fail to get iccid")
def test_gnss_sim_inventory(self):
+ sim_inventory_recipient = "0958787507"
self.check_device_status()
sms_message = "imsi: %s, iccid: %s, ldap: %s, model: %s, sn: %s" % (
- self.get_imsi(), self.get_iccid(), self.sim_inventory_ldap,
- self.ad.model, self.ad.serial)
+ self.get_imsi(), self.get_iccid(), os.getlogin(), self.ad.model,
+ self.ad.serial)
self.ad.log.info(sms_message)
try:
self.ad.log.info("Send SMS by SL4A.")
- self.ad.droid.smsSendTextMessage(self.sim_inventory_recipient,
+ self.ad.droid.smsSendTextMessage(sim_inventory_recipient,
sms_message, True)
self.ad.ed.pop_event(EventSmsSentSuccess, 10)
except Exception as e:
diff --git a/acts_tests/tests/google/gnss/GnssUserBuildBroadcomConfigurationTest.py b/acts_tests/tests/google/gnss/GnssUserBuildBroadcomConfigurationTest.py
new file mode 100644
index 0000000..9f3ccfd
--- /dev/null
+++ b/acts_tests/tests/google/gnss/GnssUserBuildBroadcomConfigurationTest.py
@@ -0,0 +1,419 @@
+"""Make sure the user build configuration is working as expected.
+
+Although we can assume the features should be the same between user and user_debug build,
+the configuration difference between this two build are not tested.
+
+In this test suite, we modify the gps configuration to be the same as user build
+and check if the setting is working.
+For more details, please refer to : go/p22_user_build_verification
+"""
+import os
+import shutil
+import tempfile
+import time
+
+from acts import asserts
+from acts import signals
+from acts.base_test import BaseTestClass
+from acts.controllers.adb_lib.error import AdbCommandError
+from acts.libs.proc.job import TimeoutError
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.gnss import gnss_test_utils as gutils
+
+
+class GpsConfig:
+ def __init__(self, ad, name) -> None:
+ self.ad = ad
+ self.name = name
+ self.folder = "/vendor/etc/gnss"
+ self.full_path = os.path.join(self.folder, self.name)
+ self.logenabled = "LogEnabled"
+ self._log_enable = "true"
+ self._log_disable = "false"
+
+ def _change_file_content(self, pattern, target):
+ """Modify file via sed command
+
+ command will be sed -i 's/<pattern>/<target>/g' <file_path>
+ Args:
+ pattern: a string will be used as search pattern
+ target: string that will overwrite the matched result
+ """
+ self.ad.adb.remount()
+ command = f"sed -i s/{pattern}/{target}/g {self.full_path}"
+ self.ad.adb.shell(command)
+
+ def _get_setting_value(self, key):
+ """Get setting value from config file
+
+ command is grep <key> self.full_path
+ Args:
+ key: a string will be used as search pattern
+ Returns:
+ string: grep result ("" for no grep result)
+ """
+ command = f"grep {key} {self.full_path}"
+ result = self.ad.adb.shell(command)
+ return result
+
+ def _adjust_log_enable_setting(self, key, enable):
+ """Enable / Disable in self.full_path by setting key = true / false
+ Args:
+ key: The target will be changed
+ enable: True to enable / False to disable
+ """
+ src = self._log_disable if enable else self._log_enable
+ target = self._log_enable if enable else self._log_disable
+ pattern = f"{key}={src}"
+ target = f"{key}={target}"
+ self._change_file_content(pattern, target)
+ result = self._get_setting_value(key)
+ self.ad.log.debug("%s setting: %s", self.name, result)
+
+ def _check_file_exist(self, file_pattern):
+ """use command ls to check if file/dir exists
+ command ls <file_pattern>
+ Args:
+ file_pattern: A string represents the file or dir
+ Returns:
+ bool: True -> file exists / False -> file doesn't exist
+ """
+ command = f"ls {file_pattern}"
+ try:
+ self.ad.adb.shell(command)
+ result = True
+ except AdbCommandError as e:
+ result = False
+ return result
+
+ def enable_diagnostic_log(self):
+ """Set LogEnabled=true in config file
+ In gps.xml it will be LogEnabled=\"true\"
+ """
+ self.ad.log.info("Enable diagnostic log in %s", self.name)
+ self._adjust_log_enable_setting(key=self.logenabled, enable=True)
+
+ def disable_diagnostic_log(self):
+ """Set LogEnabled=false in config file
+ In gps.xml it will be LogEnabled=\"false\"
+ """
+ self.ad.log.info("Disable diagnostic log in %s", self.name)
+ self._adjust_log_enable_setting(key=self.logenabled, enable=False)
+
+
+class ScdConf(GpsConfig):
+ def __init__(self, ad) -> None:
+ super().__init__(ad, "scd.conf")
+
+
+class GpsXml(GpsConfig):
+ def __init__(self, ad) -> None:
+ super().__init__(ad, "gps.xml")
+ self.supllogenable = "SuplLogEnable"
+ self.supl_log = "/data/vendor/gps/suplflow.txt"
+ self._log_enable = "\\\"true\\\""
+ self._log_disable = "\\\"false\\\""
+
+ def enable_supl_log(self):
+ """Set SuplLogEnable=\"true\" in gps.xml"""
+ self.ad.log.info("Enable SUPL logs")
+ self._adjust_log_enable_setting(key=self.supllogenable, enable=True)
+
+ def disable_supl_log(self):
+ """Set SuplLogEnable=\"false\" in gps.xml"""
+ self.ad.log.info("Disable SUPL log")
+ self._adjust_log_enable_setting(key=self.supllogenable, enable=False)
+
+ def remove_supl_logs(self):
+ """Remove /data/vendor/gps/suplflow.txt"""
+ self.ad.log.info("Remove SUPL logs")
+ command = f"rm -f {self.supl_log}"
+ self.ad.adb.shell(command)
+
+ def is_supl_log_file_exist(self):
+ """Check if /data/vendor/gps/suplflow.txt exist
+ Returns:
+ bool: True -> supl log exists / False -> supl log doesn't exist
+ """
+ result = self._check_file_exist(self.supl_log)
+ self.ad.log.debug("Supl file exists?: %s", result)
+ return result
+
+
+class LhdConf(GpsConfig):
+ def __init__(self, ad) -> None:
+ super().__init__(ad, "lhd.conf")
+ self.lhefailsafe = "LheFailSafe"
+ self.lheconsole = "LheConsole"
+ self.lheconsole_hub = self.get_lheconsole_value()
+ self.esw_crash_dump_pattern = self.get_esw_crash_dump_pattern()
+ self.ad.log.info(f"here is {self.esw_crash_dump_pattern}")
+
+ def _adjust_lhe_setting(self, key, enable):
+ """Set lhe setting.
+ Enable - uncomment out the setting
+ Dissable - comment out the setting
+ Args:
+ key: A string will be used as search pattern
+ enable: bool True to enable / False to disable
+ """
+ pattern = f"#\ {key}" if enable else key
+ target = key if enable else f"#\ {key}"
+ self._change_file_content(pattern, target)
+
+ def enable_lhefailsafe(self):
+ """Uncomment out LheFailSafe"""
+ self.ad.log.info("Enable %s", self.lhefailsafe)
+ self._adjust_lhe_setting(key=self.lhefailsafe, enable=True)
+
+ def disable_lhefailsafe(self):
+ """Comment out LheFailSafe"""
+ self.ad.log.info("Disable %s", self.lhefailsafe)
+ self._adjust_lhe_setting(key=self.lhefailsafe, enable=False)
+
+ def enable_lheconsole(self):
+ """Uncomment out LheConsole"""
+ self.ad.log.info("Enable %s", self.lheconsole)
+ self._adjust_lhe_setting(key=self.lheconsole, enable=True)
+
+ def disable_lheconsole(self):
+ """Comment out LheConsole"""
+ self.ad.log.info("Disable %s", self.lheconsole)
+ self._adjust_lhe_setting(key=self.lheconsole, enable=False)
+
+ def get_lhefailsafe_value(self):
+ """Get the LheFailSafe value
+
+ Returns:
+ string: the LheFailSafe value in config
+ Raises:
+ ValueError: No LheFailSafe value
+ """
+ result = self._get_setting_value(self.lhefailsafe)
+ if not result:
+ raise ValueError(("%s should exists in %s", self.lhefailsafe, self.name))
+ result = result.split("=")[1]
+ self.ad.log.debug("%s is %s", self.lhefailsafe, result)
+ return result
+
+ def get_lheconsole_value(self):
+ """Get the LheConsole value
+
+ Returns:
+ string: the LheConsole value in config
+ Raises:
+ ValueError: No LheConsole value
+ """
+ result = self._get_setting_value(self.lheconsole)
+ if not result:
+ raise ValueError(("%s should exists in %s", self.lheconsole, self.name))
+ result = result.split("=")[1]
+ self.ad.log.debug("%s is %s", self.lheconsole, result)
+ return result
+
+ def get_esw_crash_dump_pattern(self):
+ """Get the esw crash dump file pattern
+ The value is set in LheFailSafe, but we need to add wildcard.
+ Returns:
+ string: esw crash dump pattern
+ Raises:
+ ValueError: No LheFailSafe value
+ """
+ value = self.get_lhefailsafe_value()
+ value = value.replace(".txt", "*.txt")
+ self.ad.log.debug("Dump file pattern is %s", value)
+ return value
+
+ def remove_esw_crash_dump_file(self):
+ """Remove crash dump file"""
+ self.ad.log.info("Remove esw crash file")
+ command = f"rm -f {self.esw_crash_dump_pattern}"
+ self.ad.adb.shell(command)
+
+ def trigger_firmware_crash(self):
+ """Send command to LheConsole to trigger firmware crash"""
+ self.ad.log.info("Trigger firmware crash")
+ command = f"echo Lhe:write=0xFFFFFFFF,4 > {self.lheconsole_hub}.toAsic"
+ self.ad.adb.shell(command, timeout=10)
+
+ def is_esw_crash_dump_file_exist(self):
+ """Check if esw_crash_dump_pattern exists
+ Will try 3 times, 1 second interval for each attempt
+ Returns:
+ bool: True -> file exists / False -> file doesn't exist
+ """
+ for attempt in range(1, 4):
+ result = self._check_file_exist(self.esw_crash_dump_pattern)
+ self.ad.log.debug("(Attempt %s)esw dump file exists?: %s", attempt, result)
+ if result:
+ return result
+ time.sleep(1)
+ return False
+
+
+class GnssUserBuildBroadcomConfigurationTest(BaseTestClass):
+ """ GNSS user build configuration Tests on Broadcom device."""
+ def setup_class(self):
+ super().setup_class()
+ self.ad = self.android_devices[0]
+
+ if not gutils.check_chipset_vendor_by_qualcomm(self.ad):
+ gutils._init_device(self.ad)
+ self.gps_config_path = tempfile.mkdtemp()
+ self.gps_xml = GpsXml(self.ad)
+ self.lhd_conf = LhdConf(self.ad)
+ self.scd_conf = ScdConf(self.ad)
+ self.enable_testing_setting()
+ self.backup_gps_config()
+
+ def teardown_class(self):
+ if hasattr(self, "gps_config_path") and os.path.isdir(self.gps_config_path):
+ shutil.rmtree(self.gps_config_path)
+
+ def setup_test(self):
+ if gutils.check_chipset_vendor_by_qualcomm(self.ad):
+ raise signals.TestSkip("Device is Qualcomm, skip the test")
+ gutils.clear_logd_gnss_qxdm_log(self.ad)
+
+ def teardown_test(self):
+ if not gutils.check_chipset_vendor_by_qualcomm(self.ad):
+ self.revert_gps_config()
+ self.ad.reboot()
+
+ def on_fail(self, test_name, begin_time):
+ self.ad.take_bug_report(test_name, begin_time)
+ gutils.get_gnss_qxdm_log(self.ad)
+
+ def enable_testing_setting(self):
+ """Enable setting to the testing target
+ Before backing up config, enable all the testing target
+ To ensure the teardown_test can bring the device back to the desired state
+ """
+ self.set_gps_logenabled(enable=True)
+ self.gps_xml.enable_supl_log()
+ self.lhd_conf.enable_lheconsole()
+ self.lhd_conf.enable_lhefailsafe()
+
+ def backup_gps_config(self):
+ """Copy the gps config
+
+ config file will be copied: gps.xml / lhd.conf / scd.conf
+ """
+ for conf in [self.gps_xml, self.scd_conf, self.lhd_conf]:
+ self.ad.log.debug("Backup %s", conf.full_path)
+ self.ad.adb.pull(conf.full_path, self.gps_config_path)
+
+ def revert_gps_config(self):
+ """Revert the gps config from the one we backup in the setup_class
+
+ config file will be reverted: gps.xml / lhd.conf / scd.conf
+ """
+ self.ad.adb.remount()
+ for conf in [self.gps_xml, self.scd_conf, self.lhd_conf]:
+ file_path = os.path.join(self.gps_config_path, conf.name)
+ self.ad.log.debug("Revert %s", conf.full_path)
+ self.ad.adb.push(file_path, conf.full_path)
+
+ def run_gps_and_capture_log(self):
+ """Enable GPS via gps tool for 15s and capture pixel log"""
+ gutils.start_pixel_logger(self.ad)
+ gutils.start_gnss_by_gtw_gpstool(self.ad, state=True)
+ time.sleep(15)
+ gutils.start_gnss_by_gtw_gpstool(self.ad, state=False)
+ gutils.stop_pixel_logger(self.ad)
+
+ def set_gps_logenabled(self, enable):
+ """Set LogEnabled in gps.xml / lhd.conf / scd.conf
+
+ Args:
+ enable: True to enable / False to disable
+ """
+ if enable:
+ self.gps_xml.enable_diagnostic_log()
+ self.scd_conf.enable_diagnostic_log()
+ self.lhd_conf.enable_diagnostic_log()
+ else:
+ self.gps_xml.disable_diagnostic_log()
+ self.scd_conf.disable_diagnostic_log()
+ self.lhd_conf.disable_diagnostic_log()
+
+ @test_tracker_info(uuid="1dd68d9c-38b0-4fbc-8635-1228c72872ff")
+ def test_gps_logenabled_setting(self):
+ """Verify the LogEnabled setting in gps.xml / scd.conf / lhd.conf
+ Steps:
+ 1. default setting is on in user_debug build
+ 2. enable gps for 15s
+ 3. assert gps log pattern "slog :" in pixel logger
+ 4. disable LogEnabled in all the gps conf
+ 5. enable gps for 15s
+ 6. assert gps log pattern "slog :" in pixel logger
+ """
+ self.run_gps_and_capture_log()
+ result, _ = gutils.parse_brcm_nmea_log(self.ad, "slog :", [])
+ asserts.assert_true(bool(result), "LogEnabled is set to true, but no gps log was found")
+
+ self.set_gps_logenabled(enable=False)
+ gutils.clear_logd_gnss_qxdm_log(self.ad)
+
+ self.run_gps_and_capture_log()
+ result, _ = gutils.parse_brcm_nmea_log(self.ad, "slog :", [])
+ asserts.assert_false(bool(result), ("LogEnabled is set to False but still found %d slog",
+ len(result)))
+
+ @test_tracker_info(uuid="152a12e0-7957-47e0-9ea7-14725254fd1d")
+ def test_gps_supllogenable_setting(self):
+ """Verify SuplLogEnable in gps.xml
+ Steps:
+ 1. default setting is on in user_debug build
+ 2. remove existing supl log
+ 3. enable gps for 15s
+ 4. supl log should exist
+ 5. disable SuplLogEnable in gps.xml
+ 6. remove existing supl log
+ 7. enable gps for 15s
+ 8. supl log should not exist
+ """
+ def is_supl_log_exist_after_supl_request():
+ self.gps_xml.remove_supl_logs()
+ self.run_gps_and_capture_log()
+ return self.gps_xml.is_supl_log_file_exist()
+
+ result = is_supl_log_exist_after_supl_request()
+ asserts.assert_true(result, "SuplLogEnable is enable, should find supl log file")
+
+ self.gps_xml.disable_supl_log()
+ self.ad.reboot()
+
+ result = is_supl_log_exist_after_supl_request()
+ asserts.assert_false(result, "SuplLogEnable is disable, should not find supl log file")
+
+ @test_tracker_info(uuid="892d0037-8c0c-45b6-bd0f-9e4073d37232")
+ def test_lhe_setting(self):
+ """Verify lhefailsafe / lheconsole setting in lhd.conf
+ Steps:
+ 1. both setting is enabled
+ 2. trigger firmware crash and check if dump file exist
+ 3. disable lhefailsafe
+ 4. trigger firmware crash and check if dump file exist
+ 5. disable lheconsle
+ 6. trigger firmware crash and check if command timeout
+ """
+ def is_dump_file_exist_after_firmware_crash():
+ self.lhd_conf.remove_esw_crash_dump_file()
+ self.lhd_conf.trigger_firmware_crash()
+ return self.lhd_conf.is_esw_crash_dump_file_exist()
+
+ result = is_dump_file_exist_after_firmware_crash()
+ asserts.assert_true(result, "LheFailSafe is enabled, but no crash file was found")
+
+ self.lhd_conf.disable_lhefailsafe()
+ self.ad.reboot()
+
+ result = is_dump_file_exist_after_firmware_crash()
+ asserts.assert_false(result, "LheFailSafe is disabled, but still found crash file")
+
+ self.lhd_conf.disable_lheconsole()
+ self.ad.reboot()
+
+ with asserts.assert_raises(TimeoutError):
+ self.lhd_conf.trigger_firmware_crash()
diff --git a/acts_tests/tests/google/gnss/GnssWearableTetherFunctionTest.py b/acts_tests/tests/google/gnss/GnssWearableTetherFunctionTest.py
new file mode 100644
index 0000000..87a233d
--- /dev/null
+++ b/acts_tests/tests/google/gnss/GnssWearableTetherFunctionTest.py
@@ -0,0 +1,272 @@
+#!/usr/bin/env python3
+#
+# Copyright 2020 - 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
+import os
+
+from acts import asserts
+from acts import signals
+from acts.base_test import BaseTestClass
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.gnss import gnss_test_utils as gutils
+from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from acts_contrib.test_utils.tel import tel_logging_utils as tutils
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts.utils import get_current_epoch_time
+from acts_contrib.test_utils.gnss.gnss_test_utils import delete_lto_file, pair_to_wearable
+from acts_contrib.test_utils.gnss.gnss_test_utils import process_gnss_by_gtw_gpstool
+from acts_contrib.test_utils.gnss.gnss_test_utils import start_gnss_by_gtw_gpstool
+from acts_contrib.test_utils.gnss.gnss_test_utils import check_tracking_file
+from uiautomator import Device
+
+
+class GnssWearableTetherFunctionTest(BaseTestClass):
+ """ GNSS Wearable Tether Function Tests"""
+ def setup_class(self):
+ super().setup_class()
+ self.watch = self.android_devices[0]
+ self.phone = self.android_devices[1]
+ self.phone.uia = Device(self.phone.serial)
+ req_params = ["pixel_lab_network", "standalone_cs_criteria",
+ "flp_ttff_max_threshold", "pixel_lab_location",
+ "flp_ttff_cycle", "default_gnss_signal_attenuation",
+ "flp_waiting_time", "tracking_test_time",
+ "fast_start_criteria" ]
+ self.unpack_userparams(req_param_names=req_params)
+ # create hashmap for SSID
+ self.ssid_map = {}
+ for network in self.pixel_lab_network:
+ SSID = network["SSID"]
+ self.ssid_map[SSID] = network
+ self.ttff_mode = {"cs": "Cold Start",
+ "ws": "Warm Start",
+ "hs": "Hot Start"}
+ gutils._init_device(self.watch)
+ pair_to_wearable(self.watch, self.phone)
+
+ def setup_test(self):
+ gutils.get_baseband_and_gms_version(self.watch)
+ gutils.clear_logd_gnss_qxdm_log(self.watch)
+ gutils.clear_logd_gnss_qxdm_log(self.phone)
+ gutils.set_attenuator_gnss_signal(self.watch, self.attenuators,
+ self.default_gnss_signal_attenuation)
+ if not gutils.is_mobile_data_on(self.watch):
+ gutils.set_mobile_data(self.watch, True)
+ # TODO (b/202101058:chenstanley): Need to double check how to disable wifi successfully in wearable projects.
+ if gutils.is_wearable_btwifi(self.watch):
+ wutils.wifi_toggle_state(self.watch, True)
+ gutils.connect_to_wifi_network(
+ self.watch, self.ssid_map[self.pixel_lab_network[0]["SSID"]])
+ if not verify_internet_connection(self.watch.log, self.watch, retries=3,
+ expected_state=True):
+ raise signals.TestFailure("Fail to connect to LTE or WiFi network.")
+ if not gutils.is_bluetooth_connected(self.watch, self.phone):
+ gutils.pair_to_wearable(self.phone, self.watch)
+
+ def teardown_test(self):
+ gutils.stop_pixel_logger(self.watch)
+ tutils.stop_adb_tcpdump(self.watch)
+ gutils.set_attenuator_gnss_signal(self.watch, self.attenuators,
+ self.default_gnss_signal_attenuation)
+
+ def on_fail(self, test_name, begin_time):
+ self.watch.take_bug_report(test_name, begin_time)
+ gutils.get_gnss_qxdm_log(self.watch)
+ tutils.get_tcpdump_log(self.watch, test_name, begin_time)
+
+ def start_qxdm_and_tcpdump_log(self):
+ """Start QXDM and adb tcpdump if collect_logs is True."""
+ gutils.start_pixel_logger(self.watch)
+ tutils.start_adb_tcpdump(self.watch)
+
+ def flp_ttff(self, mode, criteria, location):
+ self.start_qxdm_and_tcpdump_log()
+ start_gnss_by_gtw_gpstool(self.phone, True, type="FLP")
+ time.sleep(self.flp_waiting_time)
+ self.watch.unlock_screen(password=None)
+ begin_time = get_current_epoch_time()
+ process_gnss_by_gtw_gpstool(
+ self.watch, self.standalone_cs_criteria, type="flp")
+ gutils.start_ttff_by_gtw_gpstool(
+ self.watch, mode, iteration=self.flp_ttff_cycle)
+ results = gutils.process_ttff_by_gtw_gpstool(
+ self.watch, begin_time, location, type="flp")
+ gutils.check_ttff_data(self.watch, results, mode, criteria)
+ self.check_location_from_phone()
+ start_gnss_by_gtw_gpstool(self.phone, False, type="FLP")
+
+ def check_location_from_phone(self):
+ watch_file = check_tracking_file(self.watch)
+ phone_file = check_tracking_file(self.phone)
+ return gutils.compare_watch_phone_location(self, watch_file, phone_file)
+
+ """ Test Cases """
+
+ @test_tracker_info(uuid="2c62183a-4354-4efc-92f2-84580cbd3398")
+ def test_lto_download_after_reboot(self):
+ """Verify LTO data could be downloaded and injected after device reboot.
+
+ Steps:
+ 1. Reboot device.
+ 2. Verify whether LTO is auto downloaded and injected without trigger GPS.
+ 3. Repeat Step 1 to Step 2 for 5 times.
+
+ Expected Results:
+ LTO data is properly downloaded and injected at the first time tether to phone.
+ """
+ reboot_lto_test_results_all = []
+ gutils.disable_supl_mode(self.watch)
+ for times in range(1, 6):
+ delete_lto_file(self.watch)
+ gutils.reboot(self.watch)
+ self.start_qxdm_and_tcpdump_log()
+ # Wait 20 seconds for boot busy and lto auto-download time
+ time.sleep(20)
+ begin_time = get_current_epoch_time()
+ reboot_lto_test_result = gutils.check_xtra_download(self.watch, begin_time)
+ self.watch.log.info("Iteration %d => %s" % (times, reboot_lto_test_result))
+ reboot_lto_test_results_all.append(reboot_lto_test_result)
+ gutils.stop_pixel_logger(self.watch)
+ tutils.stop_adb_tcpdump(self.watch)
+ asserts.assert_true(all(reboot_lto_test_results_all),
+ "Fail to Download and Inject LTO File.")
+
+ @test_tracker_info(uuid="7ed596df-df71-42ca-bdb3-69a3cad81963")
+ def test_flp_ttff_cs(self):
+ """Verify FLP TTFF Cold Start while tether with phone.
+
+ Steps:
+ 1. Pair with phone via Bluetooth.
+ 2. FLP TTFF Cold Start for 10 iteration.
+ 3. Check location source is from Phone.
+
+ Expected Results:
+ 1. FLP TTFF Cold Start results should be within
+ flp_ttff_max_threshold.
+ 2. Watch uses phone's FLP location.
+ """
+ self.flp_ttff("cs", self.flp_ttff_max_threshold, self.pixel_lab_location)
+
+ @test_tracker_info(uuid="de19617c-1f03-4077-99af-542b300ab4ed")
+ def test_flp_ttff_ws(self):
+ """Verify FLP TTFF Warm Start while tether with phone.
+
+ Steps:
+ 1. Pair with phone via Bluetooth.
+ 2. FLP TTFF Warm Start for 10 iteration.
+ 3. Check location source is from Phone.
+
+ Expected Results:
+ 1. FLP TTFF Warm Start results should be within
+ flp_ttff_max_threshold.
+ 2. Watch uses phone's FLP location.
+ """
+ self.flp_ttff("ws", self.flp_ttff_max_threshold, self.pixel_lab_location)
+
+ @test_tracker_info(uuid="c58c90ae-9f4a-4619-a9f8-f2f98c930008")
+ def test_flp_ttff_hs(self):
+ """Verify FLP TTFF Hot Start while tether with phone.
+
+ Steps:
+ 1. Pair with phone via Bluetooth.
+ 2. FLP TTFF Hot Start for 10 iteration.
+ 3. Check location source is from Phone.
+
+ Expected Results:
+ 1. FLP TTFF Hot Start results should be within
+ flp_ttff_max_threshold.
+ 2. Watch uses phone's FLP location.
+ """
+ self.flp_ttff("hs", self.flp_ttff_max_threshold, self.pixel_lab_location)
+
+ @test_tracker_info(uuid="ca955ad3-e2eb-4fde-af2b-3e19abe47792")
+ def test_tracking_during_bt_disconnect_resume(self):
+ """Verify tracking is correct during Bluetooth disconnect and resume.
+
+ Steps:
+ 1. Make sure watch Bluetooth is on and in paired status.
+ 2. Do 1 min tracking.
+ 3. After 1 min tracking, check location source is using phone's FLP.
+ 4. Turn off watch Bluetooth, and do 1 min tracking.
+ 5. After 1 min tracking, check tracking results.
+ 6. Repeat Step 1 to Step 5 for 5 times.
+
+ Expected Results:
+ 1. Watch uses phone's FLP location in Bluetooth connect state.
+ 2. Tracking results should be within pixel_lab_location criteria.
+ """
+ self.start_qxdm_and_tcpdump_log()
+ for i in range(1, 6):
+ if not self.watch.droid.bluetoothCheckState():
+ self.watch.droid.bluetoothToggleState(True)
+ self.watch.log.info("Turn Bluetooth on")
+ self.watch.log.info("Wait 1 min for Bluetooth auto re-connect")
+ time.sleep(60)
+ if not gutils.is_bluetooth_connect(self.watch, self.phone):
+ raise signals.TestFailure("Fail to connect to device via Bluetooth.")
+ start_gnss_by_gtw_gpstool(self.phone, True, type="FLP")
+ time.sleep(self.flp_waiting_time)
+ start_gnss_by_gtw_gpstool(self.watch, True, type="FLP")
+ time.sleep(self.flp_waiting_time)
+ self.watch.log.info("Wait 1 min for tracking")
+ time.sleep(self.tracking_test_time)
+ if not self.check_location_from_phone():
+ raise signals.TestFailure("Watch is not using phone location")
+ self.watch.droid.bluetoothToggleState(False)
+ self.watch.log.info("Turn off Watch Bluetooth")
+ self.watch.log.info("Wait 1 min for tracking")
+ time.sleep(self.tracking_test_time)
+ if self.check_location_from_phone():
+ raise signals.TestError("Watch should not use phone location")
+ gutils.parse_gtw_gpstool_log(self.watch, self.pixel_lab_location, type="FLP")
+ start_gnss_by_gtw_gpstool(self.phone, False, type="FLP")
+
+ @test_tracker_info(uuid="654a8f1b-f9c6-433e-a21f-59224cce822e")
+ def test_fast_start_first_fix_and_ttff(self):
+ """Verify first fix and TTFF of Fast Start (Warm Start v4) within the criteria
+
+ Steps:
+ 1. Pair watch to phone during OOBE.
+ 2. Ensure LTO file download in watch.
+ 3. Ensure UTC time inject in watch.
+ 4. Enable AirPlane mode to untether to phone.
+ 5. Open GPSTool to get first fix in LTO and UTC time injected.
+ 6. Repeat Step1 ~ Step5 for 5 times.
+ 7. After Step6, Warm Start TTFF for 10 iterations.
+
+ Expected Results:
+ 1. First fix should be within fast_start_threshold.
+ 2. TTFF should be within fast_start_threshold.
+ """
+ for i in range(1,6):
+ self.watch.log.info("First fix of Fast Start - attempts %s" % i)
+ pair_to_wearable(self.watch, self.phone)
+ gutils.enable_framework_log(self.watch)
+ self.start_qxdm_and_tcpdump_log()
+ begin_time = get_current_epoch_time()
+ gutils.check_xtra_download(self.watch, begin_time)
+ gutils.check_inject_time(self.watch)
+ self.watch.log.info("Turn airplane mode on")
+ self.watch.droid.connectivityToggleAirplaneMode(True)
+ self.watch.unlock_screen(password=None)
+ gutils.process_gnss_by_gtw_gpstool(
+ self.watch, self.fast_start_criteria, clear_data=False)
+ gutils.start_ttff_by_gtw_gpstool(
+ self.watch, ttff_mode="ws", iteration=self.ttff_test_cycle)
+ ttff_data = gutils.process_ttff_by_gtw_gpstool(self.watch, begin_time,
+ self.pixel_lab_location)
+ result = gutils.check_ttff_data(self.watch, ttff_data, self.ttff_mode.get("ws"),
+ criteria=self.fast_start_criteria)
+ asserts.assert_true(result, "TTFF fails to reach designated criteria")
diff --git a/acts_tests/tests/google/gnss/LabTtffGeneralCoexTest.py b/acts_tests/tests/google/gnss/LabTtffGeneralCoexTest.py
new file mode 100644
index 0000000..24da4d3
--- /dev/null
+++ b/acts_tests/tests/google/gnss/LabTtffGeneralCoexTest.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+## Licensed under the Apache License, Version 2.0 (the 'License');
+## you may not use this file except in compliance with the License.
+## You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an 'AS IS' BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+
+from acts_contrib.test_utils.gnss import LabTtffTestBase as lttb
+from acts_contrib.test_utils.gnss.gnss_test_utils import launch_eecoexer
+from acts_contrib.test_utils.gnss.gnss_test_utils import excute_eecoexer_function
+
+
+class LabTtffGeneralCoexTest(lttb.LabTtffTestBase):
+ """Lab stand alone GNSS general coex TTFF/FFPE test"""
+
+ def setup_class(self):
+ super().setup_class()
+ req_params = ['coex_testcase_ls']
+ self.unpack_userparams(req_param_names=req_params)
+
+ def setup_test(self):
+ super().setup_test()
+ launch_eecoexer(self.dut)
+ # Set DUT temperature the limit to 60 degree
+ self.dut.adb.shell(
+ 'setprop persist.com.google.eecoexer.cellular.temperature_limit 60')
+
+ def exe_eecoexer_loop_cmd(self, cmd_list=list()):
+ """
+ Function for execute EECoexer command list
+ Args:
+ cmd_list: a list of EECoexer function command.
+ Type, list.
+ """
+ for cmd in cmd_list:
+ self.log.info('Execute EEcoexer Command: {}'.format(cmd))
+ excute_eecoexer_function(self.dut, cmd)
+
+ def gnss_ttff_ffpe_coex_base(self, mode):
+ """
+ TTFF and FFPE general coex base test function
+
+ Args:
+ mode: Set the TTFF mode for testing. Definitions are as below.
+ cs(cold start), ws(warm start), hs(hot start)
+ """
+ # Loop all test case in coex_testcase_ls
+ for test_item in self.coex_testcase_ls:
+
+ # get test_log_path from coex_testcase_ls['test_name']
+ test_log_path = test_item['test_name']
+
+ # get test_cmd from coex_testcase_ls['test_cmd']
+ test_cmd = test_item['test_cmd']
+
+ # get stop_cmd from coex_testcase_ls['stop_cmd']
+ stop_cmd = test_item['stop_cmd']
+
+ # Start aggressor Tx by EEcoexer
+ self.exe_eecoexer_loop_cmd(test_cmd)
+
+ # Start GNSS TTFF FFPE testing
+ self.gnss_ttff_ffpe(mode, test_log_path)
+
+ # Stop aggressor Tx by EEcoexer
+ self.exe_eecoexer_loop_cmd(stop_cmd)
+
+ # Clear GTW GPSTool log. Need to clean the log every round of the test.
+ self.clear_gps_log()
+
+ def test_gnss_cold_ttff_ffpe_coex(self):
+ """
+ Cold start TTFF and FFPE GNSS general coex testing
+ """
+ self.gnss_ttff_ffpe_coex_base('cs')
+
+ def test_gnss_warm_ttff_ffpe_coex(self):
+ """
+ Warm start TTFF and FFPE GNSS general coex testing
+ """
+ self.gnss_ttff_ffpe_coex_base('ws')
+
+ def test_gnss_hot_ttff_ffpe_coex(self):
+ """
+ Hot start TTFF and FFPE GNSS general coex testing
+ """
+ self.gnss_ttff_ffpe_coex_base('hs')
diff --git a/acts_tests/tests/google/gnss/LabTtffTest.py b/acts_tests/tests/google/gnss/LabTtffTest.py
index 5c05fa9..374b570 100644
--- a/acts_tests/tests/google/gnss/LabTtffTest.py
+++ b/acts_tests/tests/google/gnss/LabTtffTest.py
@@ -14,284 +14,29 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import os
-import time
-import glob
-import errno
+from acts_contrib.test_utils.gnss import LabTtffTestBase as lttb
-from acts import utils
-from acts import asserts
-from acts import signals
-from acts import base_test
-from pandas import DataFrame
-from collections import namedtuple
-from acts.controllers.spectracom_lib import gsg6
-from acts.test_utils.gnss import dut_log_test_utils as diaglog
-from acts_contrib.test_utils.gnss import gnss_test_utils as gutils
-from acts_contrib.test_utils.gnss import gnss_testlog_utils as glogutils
-DEVICE_GPSLOG_FOLDER = '/sdcard/Android/data/com.android.gpstool/files/'
-GPS_PKG_NAME = 'com.android.gpstool'
-
-class LabTtffTest(base_test.BaseTestClass):
-
- """ LAB TTFF Tests"""
- GTW_GPSTOOL_APP = 'gtw_gpstool_apk'
- SPECTRACOM_IP_KEY = 'spectracom_ip'
- SPECTRACOM_PORT_KEY = 'spectracom_port'
- SPECTRACOM_FILES_KEY = 'spectracom_files'
- SPECTRACOM_POWER_KEY = 'spectracom_power_level'
- SPIRENT_IP_KEY = 'spirent_ip'
- SPIRENT_SCENARIO = 'sprient_scenario'
- CUSTOM_FILES_KEY = 'custom_files'
- CSTTFF_CRITERIA = 'cs_criteria'
- HSTTFF_CRITERIA = 'hs_criteria'
- WSTTFF_CRITERIA = 'ws_criteria'
- CSTTFF_PECRITERIA = 'cs_ttff_pecriteria'
- HSTTFF_PECRITERIA = 'hs_ttff_pecriteria'
- WSTTFF_PECRITERIA = 'ws_ttff_pecriteria'
- TTFF_ITERATION = 'ttff_iteration'
- SIMULATOR_LOCATION = 'simulator_location'
- DIAG_OPTION = 'diag_option'
-
- def __init__(self, controllers):
- """ Initializes class attributes. """
-
- super().__init__(controllers)
-
- self.dut = None
- self.spectracom = None
-
- def setup_class(self):
- super().setup_class()
-
- req_params = [
- self.SPECTRACOM_IP_KEY, self.SPECTRACOM_PORT_KEY,
- self.SPECTRACOM_FILES_KEY, self.SPECTRACOM_POWER_KEY,
- self.CSTTFF_CRITERIA, self.HSTTFF_CRITERIA,
- self.WSTTFF_CRITERIA, self.TTFF_ITERATION,
- self.SIMULATOR_LOCATION, self.DIAG_OPTION
- ]
-
- for param in req_params:
- if param not in self.user_params:
- self.log.error('Required parameter {} is missing in config '
- 'file.'.format(param))
- raise signals.TestAbortClass(
- 'Required parameter {} is missing in config '
- 'file.'.format(param))
- self.dut = self.android_devices[0]
- self.spectracom_ip = self.user_params[self.SPECTRACOM_IP_KEY]
- self.spectracom_port = self.user_params[self.SPECTRACOM_PORT_KEY]
- self.spectracom_file = self.user_params[self.SPECTRACOM_FILES_KEY]
- self.spectracom_power = self.user_params[self.SPECTRACOM_POWER_KEY]
- self.gtw_gpstool_app = self.user_params[self.GTW_GPSTOOL_APP]
- custom_files = self.user_params.get(self.CUSTOM_FILES_KEY, [])
- self.cs_ttff_criteria = self.user_params.get(self.CSTTFF_CRITERIA, [])
- self.hs_ttff_criteria = self.user_params.get(self.HSTTFF_CRITERIA, [])
- self.ws_ttff_criteria = self.user_params.get(self.WSTTFF_CRITERIA, [])
- self.cs_ttff_pecriteria = self.user_params.get(
- self.CSTTFF_PECRITERIA, [])
- self.hs_ttff_pecriteria = self.user_params.get(
- self.HSTTFF_PECRITERIA, [])
- self.ws_ttff_pecriteria = self.user_params.get(
- self.WSTTFF_PECRITERIA, [])
- self.ttff_iteration = self.user_params.get(self.TTFF_ITERATION, [])
- self.simulator_location = self.user_params.get(
- self.SIMULATOR_LOCATION, [])
- self.diag_option = self.user_params.get(self.DIAG_OPTION, [])
-
- test_type = namedtuple('Type', ['command', 'criteria'])
- self.test_types = {
- 'cs': test_type('Cold Start', self.cs_ttff_criteria),
- 'ws': test_type('Warm Start', self.ws_ttff_criteria),
- 'hs': test_type('Hot Start', self.hs_ttff_criteria)
- }
-
- # Unpack the rockbottom script or fail class setup if it can't be found
- for file in custom_files:
- if 'rockbottom_' + self.dut.model in file:
- self.rockbottom_script = file
- break
- else:
- raise signals.TestAbortClass(
- 'Required rockbottom script is missing.')
-
- def setup_test(self):
-
- self.clear_gps_log()
- self.spectracom = gsg6.GSG6(self.spectracom_ip, self.spectracom_port)
-
- self.spectracom.stop_scenario()
- time.sleep(10)
- self.spectracom.close()
-
- self.dut_rockbottom()
- utils.set_location_service(self.dut, True)
- gutils.reinstall_package_apk(self.dut, GPS_PKG_NAME,
- self.gtw_gpstool_app)
- self.spectracom = gsg6.GSG6(self.spectracom_ip, self.spectracom_port)
- self.spectracom.connect()
-
- def dut_rockbottom(self):
- """
- Set the dut to rockbottom state
-
- """
- # The rockbottom script might include a device reboot, so it is
- # necessary to stop SL4A during its execution.
- self.dut.stop_services()
- self.log.info('Executing rockbottom script for ' + self.dut.model)
- os.chmod(self.rockbottom_script, 0o777)
- os.system('{} {}'.format(self.rockbottom_script, self.dut.serial))
- # Make sure the DUT is in root mode after coming back
- self.dut.root_adb()
- # Restart SL4A
- self.dut.start_services()
-
- def teardown_class(self):
- """ Executed after completing all selected test cases."""
- self.clear_gps_log()
- if self.spectracom:
- self.spectracom.stop_scenario()
- time.sleep(10)
- self.spectracom.close()
-
- def start_and_set_spectracom_power(self):
- """
- Start spectracom secnario and set power level.
-
- """
-
- self.spectracom.start_scenario(self.spectracom_file)
- time.sleep(25)
- self.spectracom.set_power(self.spectracom_power)
-
- def get_and_verify_ttff(self, mode):
- """Retrieve ttff with designate mode.
-
- Args:
- mode: A string for identify gnss test mode.
- """
- if mode not in self.test_types:
- raise signals.TestError('Unrecognized mode %s' % mode)
- test_type = self.test_types.get(mode)
-
- gutils.process_gnss_by_gtw_gpstool(self.dut,
- self.test_types['cs'].criteria)
- begin_time = gutils.get_current_epoch_time()
- gutils.start_ttff_by_gtw_gpstool(
- self.dut, ttff_mode=mode,
- iteration=self.ttff_iteration, aid_data=True)
- ttff_data = gutils.process_ttff_by_gtw_gpstool(self.dut, begin_time,
- self.simulator_location)
-
- gps_log_path = os.path.join(self.log_path, 'GPSLogs')
- self.dut.adb.pull("{} {}".format(DEVICE_GPSLOG_FOLDER, gps_log_path))
-
- gps_api_log = glob.glob(gps_log_path + '/GPS_API_*.txt')
- ttff_loop_log = glob.glob(gps_log_path + '/GPS_{}_*.txt'.
- format(mode.upper()))
-
- if not gps_api_log and ttff_loop_log:
- raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT),
- gps_log_path)
-
- df = DataFrame(glogutils.parse_gpstool_ttfflog_to_df(gps_api_log[0]))
-
- ttff_dict = {}
- for i in ttff_data:
- d = ttff_data[i]._asdict()
- ttff_dict[i] = dict(d)
-
- ttff_time =[]
- ttff_pe = []
- for i, k in ttff_dict.items():
- ttff_time.append(ttff_dict[i]['ttff_time'])
- ttff_pe.append(ttff_dict[i]['ttff_pe'])
- df['ttff_time'] = ttff_time
- df['ttff_pe'] = ttff_pe
- df.to_json(gps_log_path + '/gps_log.json', orient='table')
- result = gutils.check_ttff_data(
- self.dut,
- ttff_data,
- ttff_mode=test_type.command,
- criteria=test_type.criteria)
- if not result:
- raise signals.TestFailure('%s TTFF fails to reach '
- 'designated criteria'
- % test_type.command)
- return ttff_data
-
- def verify_pe(self, mode):
- """
- Verify ttff Position Error with designate mode.
-
- Args:
- mode: A string for identify gnss test mode.
- """
-
- ffpe_type = namedtuple('Type', ['command', 'pecriteria'])
- ffpe_types = {
- 'cs': ffpe_type('Cold Start', self.cs_ttff_pecriteria),
- 'ws': ffpe_type('Warm Start', self.ws_ttff_pecriteria),
- 'hs': ffpe_type('Hot Start', self.hs_ttff_pecriteria)
- }
-
- if mode not in self.test_types:
- raise signals.TestError('Unrecognized mode %s' % mode)
- test_type = self.test_types.get(mode)
-
- ttff_data = self.get_and_verify_ttff(mode)
- result = gutils.check_ttff_pe(
- self.dut,
- ttff_data,
- ttff_mode=test_type.command,
- pecriteria=test_type.pecriteria
- )
- if not result:
- raise signals.TestFailure('%s TTFF fails to reach '
- 'designated criteria'
- % test_type.command)
- return ttff_data
-
- def clear_gps_log(self):
- """
- Delete the existing GPS GTW Log from DUT.
-
- """
- self.dut.adb.shell("rm -rf {}".format(DEVICE_GPSLOG_FOLDER))
+class LabTtffTest(lttb.LabTtffTestBase):
+ """ LAB Stand Alone TTFF Tests"""
def test_gnss_cold_ttff_ffpe(self):
-
- self.start_and_set_spectracom_power()
- if self.diag_option is "QCOM":
- diaglog.start_diagmdlog_background(self.dut, maskfile=self.maskfile)
- else:
- #start_tbdlog() yet to add for Broadcom
- pass
- self.verify_pe('cs')
- diaglog.stop_background_diagmdlog(self.dut, self.qxdm_log_path, keep_logs=False)
+ """
+ Cold start TTFF and FFPE Testing
+ """
+ mode = 'cs'
+ self.gnss_ttff_ffpe(mode)
def test_gnss_warm_ttff_ffpe(self):
-
- self.start_and_set_spectracom_power()
- if self.diag_option is "QCOM":
- diaglog.start_diagmdlog_background(self.dut, maskfile=self.maskfile)
- else:
- #start_tbdlog() yet to add for Broadcom
- pass
- self.verify_pe('ws')
- diaglog.stop_background_diagmdlog(self.dut, self.qxdm_log_path, keep_logs=False)
+ """
+ Warm start TTFF and FFPE Testing
+ """
+ mode = 'ws'
+ self.gnss_ttff_ffpe(mode)
def test_gnss_hot_ttff_ffpe(self):
-
- self.start_and_set_spectracom_power()
- if self.diag_option is "QCOM":
- diaglog.start_diagmdlog_background(self.dut, maskfile=self.maskfile)
- else:
- #start_tbdlog() yet to add for Broadcom
- pass
- self.verify_pe('hs')
- diaglog.stop_background_diagmdlog(self.dut, self.qxdm_log_path, keep_logs=False)
-
+ """
+ Hot start TTFF and FFPE Testing
+ """
+ mode = 'hs'
+ self.gnss_ttff_ffpe(mode)
diff --git a/acts_tests/tests/google/gnss/LocationPlatinumTest.py b/acts_tests/tests/google/gnss/LocationPlatinumTest.py
index 110748f..6f4c253 100644
--- a/acts_tests/tests/google/gnss/LocationPlatinumTest.py
+++ b/acts_tests/tests/google/gnss/LocationPlatinumTest.py
@@ -22,10 +22,9 @@
from acts.base_test import BaseTestClass
from acts_contrib.test_utils.gnss import gnss_test_utils as gutils
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
-from acts_contrib.test_utils.tel import tel_test_utils as tutils
BACKGROUND_LOCATION_PERMISSION = 'android.permission.ACCESS_BACKGROUND_LOCATION'
-APP_CLEAN_UP_TIME = 60
+APP_CLEAN_UP_TIME = 10
class LocationPlatinumTest(BaseTestClass):
"""Location Platinum Tests"""
@@ -45,9 +44,7 @@
# Hot Start Criteria, a int to define the criteria.
'hs_criteria',
# NetworkLocationProvide Criteria, a int to define the criteria.
- 'nlp_criteria',
- # A list to identify QXDM log path.
- 'qdsp6m_path'
+ 'nlp_criteria'
]
self.unpack_userparams(req_param_names=req_params)
@@ -58,31 +55,19 @@
'ws': test_type('Warm Start', self.ws_criteria),
'hs': test_type('Hot Start', self.hs_criteria)
}
- gutils._init_device(self.ad)
- self.begin_time = utils.get_current_epoch_time()
- gutils.clear_logd_gnss_qxdm_log(self.ad)
- tutils.start_qxdm_logger(self.ad, self.begin_time)
- tutils.start_adb_tcpdump(self.ad)
+ self._init(self.ad)
+
+ def _init(self, ad):
+ gutils.enable_gnss_verbose_logging(ad)
+ if gutils.check_chipset_vendor_by_qualcomm(ad):
+ gutils.disable_xtra_throttle(ad)
def setup_test(self):
"""Prepare device with mobile data, wifi and gps ready for test """
- if int(self.ad.adb.shell('settings get secure location_mode')) != 3:
- self.ad.adb.shell('settings put secure location_mode 3')
+ gutils.check_location_service(self.ad)
if not self.ad.droid.wifiCheckState():
wutils.wifi_toggle_state(self.ad, True)
gutils.connect_to_wifi_network(self.ad, self.wifi_network)
- if int(self.ad.adb.shell('settings get global mobile_data')) != 1:
- gutils.set_mobile_data(self.ad, True)
- gutils.grant_location_permission(self.ad, True)
- self.ad.adb.shell('pm grant com.android.gpstool %s' %
- BACKGROUND_LOCATION_PERMISSION)
-
- def teardown_class(self):
- tutils.stop_qxdm_logger(self.ad)
- gutils.get_gnss_qxdm_log(self.ad, self.qdsp6m_path)
- tutils.stop_adb_tcpdump(self.ad)
- tutils.get_tcpdump_log(self.ad, 'location_platinum', self.begin_time)
- self.ad.take_bug_report('location_platinum', self.begin_time)
def get_and_verify_ttff(self, mode):
"""Retrieve ttff with designate mode.
@@ -112,28 +97,28 @@
'%s TTFF fails to reach designated criteria' % test_type.command)
# Test cases
- def test_gnss_cold_ttff(self):
+ def test_gnss_cs_ttff(self):
"""
1. Send intent to GPSTool for cold start test.
2. Retrieve ttff and validate with target criteria.
"""
self.get_and_verify_ttff('cs')
- def test_gnss_warm_ttff(self):
+ def test_gnss_ws_ttff(self):
"""
1. Send intent to GPSTool for warm start test.
2. Retrieve ttff and validate with target criteria.
"""
self.get_and_verify_ttff('ws')
- def test_gnss_hot_ttff(self):
+ def test_gnss_hs_ttff(self):
"""
1. Send intent to GPSTool for hot start test.
2. Retrieve ttff and validate with target criteria.
"""
self.get_and_verify_ttff('hs')
- def test_nlp_available_by_wifi(self):
+ def test_nlp_by_wifi(self):
"""
1. Disable mobile data.
2. Send intent to GPSTool for NLP.
@@ -145,7 +130,7 @@
self.ad, 1, 'wifi', self.nlp_criteria),
'Fail to get NLP from wifi')
- def test_nlp_available_by_cell(self):
+ def test_nlp_by_cell(self):
"""
1. Disable wifi.
2. Send intent to GPSTool for NLP.
@@ -157,7 +142,7 @@
self.ad, 1, 'cell', self.nlp_criteria),
'Fail to get NLP from cell')
- def test_toggle_location_setting_off_on_report_location(self):
+ def test_toggle_location_setting_off_on(self):
"""
1. Toggle location setting off on.
2. Open Google Map and ask for location.
@@ -170,7 +155,7 @@
gutils.check_location_api(self.ad, retries=1),
'DUT failed to receive location fix')
- def test_toggle_location_setting_off_not_report_location(self):
+ def test_location_setting_off(self):
"""
1. Toggle location setting off.
2. Open Google Map and ask for location.
@@ -195,7 +180,7 @@
gutils.check_location_api(self.ad, retries=1),
'DUT fail to receive location fix')
- def test_toggle_location_permission_off(self):
+ def test_location_permission_off(self):
"""
1. Toggle Google Map location permission off.
2. Open Google Map and ask for location.
diff --git a/acts_tests/tests/google/net/ApfCountersTest.py b/acts_tests/tests/google/net/ApfCountersTest.py
index 84e96c0..4d602b2 100755
--- a/acts_tests/tests/google/net/ApfCountersTest.py
+++ b/acts_tests/tests/google/net/ApfCountersTest.py
@@ -35,12 +35,11 @@
WifiEnums = wutils.WifiEnums
RA_SCRIPT = 'sendra.py'
-SCAPY = 'scapy-2.2.0.tar.gz'
-SCAPY_INSTALL_COMMAND = 'sudo python setup.py install'
PROC_NET_SNMP6 = '/proc/net/snmp6'
LIFETIME_FRACTION = 6
LIFETIME = 180
INTERVAL = 2
+WLAN0= "wlan0"
class ApfCountersTest(WifiBaseTest):
@@ -54,8 +53,8 @@
super().setup_class()
self.dut = self.android_devices[0]
wutils.wifi_test_device_init(self.dut)
- req_params = []
- opt_param = ["reference_networks", ]
+ req_params = ["scapy"]
+ opt_param = ["reference_networks"]
self.unpack_userparams(
req_param_names=req_params, opt_param_names=opt_param)
@@ -74,13 +73,12 @@
# install scapy
current_dir = os.path.dirname(os.path.realpath(__file__))
send_ra = os.path.join(current_dir, RA_SCRIPT)
- send_scapy = os.path.join(current_dir, SCAPY)
- self.access_points[0].install_scapy(send_scapy, send_ra)
+ self.access_points[0].install_scapy(self.scapy[0], send_ra)
self.tcpdump_pid = None
def setup_test(self):
if 'RTT' not in self.test_name:
- self.tcpdump_pid = start_tcpdump(self.dut, self.test_name)
+ self.tcpdump_pid = start_tcpdump(self.dut, self.test_name, WLAN0)
def teardown_test(self):
if 'RTT' not in self.test_name:
@@ -95,6 +93,7 @@
del self.user_params["reference_networks"]
self.access_points[0].cleanup_scapy()
wutils.reset_wifi(self.dut)
+ self.dut.adb.shell("settings put global stay_on_while_plugged_in 7")
""" Helper methods """
@@ -164,6 +163,8 @@
ra_count_latest = self._get_icmp6intype134()
asserts.assert_true(ra_count_latest == ra_count + 1,
"Device dropped the first RA in sequence")
+ self.dut.adb.shell("settings put global stay_on_while_plugged_in 0")
+ self.dut.droid.goToSleepNow()
# Generate and send 'x' number of duplicate RAs, for 1/6th of the the
# lifetime of the original RA. Test assumes that the original RA has a
@@ -213,7 +214,7 @@
ra_count = self._get_icmp6intype134()
# start tcpdump on the device
- tcpdump_pid = start_tcpdump(self.dut, self.test_name)
+ tcpdump_pid = start_tcpdump(self.dut, self.test_name, WLAN0)
# send RA with differnt re-trans time
for rtt in rtt_list:
diff --git a/acts_tests/tests/google/net/BluetoothTetheringTest.py b/acts_tests/tests/google/net/BluetoothTetheringTest.py
index e4d3c67..318ed53 100644
--- a/acts_tests/tests/google/net/BluetoothTetheringTest.py
+++ b/acts_tests/tests/google/net/BluetoothTetheringTest.py
@@ -22,7 +22,7 @@
from acts_contrib.test_utils.bt.bt_test_utils import orchestrate_and_verify_pan_connection
from acts_contrib.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test
from acts_contrib.test_utils.net import net_test_utils as nutils
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
DEFAULT_PING_URL = "https://www.google.com/robots.txt"
diff --git a/acts_tests/tests/google/net/CaptivePortalTest.py b/acts_tests/tests/google/net/CaptivePortalTest.py
index eaafa25..c44ff9b 100644
--- a/acts_tests/tests/google/net/CaptivePortalTest.py
+++ b/acts_tests/tests/google/net/CaptivePortalTest.py
@@ -16,7 +16,7 @@
import time
from acts import asserts
-from acts import base_test
+from acts.controllers.openwrt_ap import MOBLY_CONTROLLER_CONFIG_NAME as OPENWRT
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.net import connectivity_const as cconst
from acts_contrib.test_utils.net import connectivity_test_utils as cutils
@@ -31,10 +31,11 @@
ACCEPT_CONTINUE = "Accept and Continue"
CONNECTED = "Connected"
SIGN_IN_NOTIFICATION = "Sign in to network"
+FAS_FDQN = "netsplashpage.net"
-class CaptivePortalTest(base_test.BaseTestClass):
- """Tests for Captive portal."""
+class CaptivePortalTest(WifiBaseTest):
+ """Check device can access the network after pass captive portal check."""
def setup_class(self):
"""Setup devices for tests and unpack params.
@@ -48,10 +49,20 @@
4. uic_zip: Zip file location of UICD application
"""
self.dut = self.android_devices[0]
- req_params = ["rk_captive_portal", "gg_captive_portal"]
- self.unpack_userparams(req_param_names=req_params,)
+ opt_params = ["rk_captive_portal", "gg_captive_portal",
+ "configure_OpenWrt", "wifi_network"]
+ self.unpack_userparams(opt_param_names=opt_params,)
wutils.wifi_test_device_init(self.dut)
+ if OPENWRT in self.user_params:
+ self.openwrt = self.access_points[0]
+ if hasattr(self, "configure_OpenWrt") and self.configure_OpenWrt == "skip":
+ self.dut.log.info("Skip configure Wifi interface due to config setup.")
+ else:
+ self.configure_openwrt_ap_and_start(wpa_network=True)
+ self.wifi_network = self.openwrt.get_wifi_network()
+ self.openwrt.network_setting.setup_captive_portal(FAS_FDQN)
+
def teardown_class(self):
"""Reset devices."""
cutils.set_private_dns(self.dut, cconst.PRIVATE_DNS_MODE_OPPORTUNISTIC)
@@ -76,7 +87,11 @@
uutils.has_element(self.dut, text="Network & internet"),
"Failed to find 'Network & internet' icon")
uutils.wait_and_click(self.dut, text="Network & internet")
- uutils.wait_and_click(self.dut, text="Not connected")
+ android_version = self.dut.adb.getprop("ro.build.version.release")
+ if int(android_version) < 12:
+ uutils.wait_and_click(self.dut, text="Wi‑Fi")
+ else:
+ uutils.wait_and_click(self.dut, text="Internet")
def _verify_sign_in_notification(self):
"""Verify sign in notification shows for captive portal."""
@@ -91,7 +106,9 @@
return
asserts.fail("Failed to get sign in notification")
- def _verify_captive_portal(self, network, click_accept=ACCEPT_CONTINUE):
+ def _verify_captive_portal(self, network, user="username",
+ mail="user@example.net",
+ click_accept=ACCEPT_CONTINUE):
"""Connect to captive portal network using uicd workflow.
Steps:
@@ -101,15 +118,24 @@
Args:
network: captive portal network to connect to
+ user: Option for captive portal login in
+ mail: Option for captive portal login in
click_accept: Notification to select to accept captive portal
"""
# connect to captive portal wifi network
wutils.connect_to_wifi_network(
self.dut, network, check_connectivity=False)
-
+ # Wait for captive portal detection.
+ time.sleep(10)
# run ui automator
self._verify_sign_in_notification()
uutils.wait_and_click(self.dut, text="%s" % network["SSID"])
+ if uutils.has_element(self.dut, class_name="android.widget.EditText"):
+ uutils.wait_and_click(self.dut, class_name="android.widget.EditText")
+ self.dut.adb.shell("input text %s" % user)
+ self.dut.adb.shell("input keyevent 20")
+ self.dut.adb.shell("input text %s" % mail)
+ uutils.wait_and_click(self.dut, text="Accept Terms of Service")
if uutils.has_element(self.dut, text="%s" % click_accept):
uutils.wait_and_click(self.dut, text="%s" % click_accept)
@@ -174,7 +200,7 @@
# set private dns to strict mode
cutils.set_private_dns(self.dut,
cconst.PRIVATE_DNS_MODE_STRICT,
- cconst.DNS_GOOGLE)
+ cconst.DNS_GOOGLE_HOSTNAME)
# verify connection to captive portal network
self._verify_captive_portal(self.rk_captive_portal)
@@ -221,7 +247,50 @@
# set private dns to strict mode
cutils.set_private_dns(self.dut,
cconst.PRIVATE_DNS_MODE_STRICT,
- cconst.DNS_GOOGLE)
+ cconst.DNS_GOOGLE_HOSTNAME)
# verify connection to captive portal network
self._verify_captive_portal(self.gg_captive_portal)
+
+ @test_tracker_info(uuid="c25a1be7-f202-41c4-ac95-bed1720833ab")
+ def test_openwrt_captive_portal_default(self):
+ """Verify captive portal network.
+
+ Steps:
+ 1. Set default private dns mode
+ 2. Connect to openwrt captive portal network
+ 3. Verify connectivity
+ """
+ cutils.set_private_dns(self.dut, cconst.PRIVATE_DNS_MODE_OPPORTUNISTIC)
+ self.openwrt.network_setting.service_manager.restart("opennds")
+ self._verify_captive_portal(self.wifi_network, click_accept="Continue")
+
+ @test_tracker_info(uuid="1419e36d-0303-44ba-bc60-4d707b45ef48")
+ def test_openwrt_captive_portal_private_dns_off(self):
+ """Verify captive portal network.
+
+ Steps:
+ 1. Turn off private dns mode
+ 2. Connect to openwrt captive portal network
+ 3. Verify connectivity
+ """
+ cutils.set_private_dns(self.dut, cconst.PRIVATE_DNS_MODE_OFF)
+ self.openwrt.network_setting.service_manager.restart("opennds")
+ self._verify_captive_portal(self.wifi_network, click_accept="Continue")
+
+ @test_tracker_info(uuid="5aae44ee-fa62-47b9-9b3d-8121f9f92da1")
+ def test_openwrt_captive_portal_private_dns_strict(self):
+ """Verify captive portal network.
+
+ Steps:
+ 1. Set strict private dns mode
+ 2. Connect to openwrt captive portal network
+ 3. Verify connectivity
+ """
+ cutils.set_private_dns(self.dut,
+ cconst.PRIVATE_DNS_MODE_STRICT,
+ cconst.DNS_GOOGLE_HOSTNAME)
+ self.openwrt.network_setting.service_manager.restart("opennds")
+ self._verify_captive_portal(self.wifi_network, click_accept="Continue")
+
+
diff --git a/acts_tests/tests/google/net/DNSTest.py b/acts_tests/tests/google/net/DNSTest.py
new file mode 100644
index 0000000..f4e23ec
--- /dev/null
+++ b/acts_tests/tests/google/net/DNSTest.py
@@ -0,0 +1,181 @@
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import random
+
+from acts import asserts
+from acts.controllers.openwrt_ap import MOBLY_CONTROLLER_CONFIG_NAME as OPENWRT
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.net import connectivity_const as cconst
+from acts_contrib.test_utils.net import connectivity_test_utils as cutils
+from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
+from scapy.all import rdpcap, DNSRR, DNSQR, IP, IPv6
+
+
+WLAN = "wlan0"
+PING_ADDR = "google.com"
+
+
+class DNSTest(WifiBaseTest):
+ """DNS related test for Android."""
+
+ def setup_class(self):
+ self.dut = self.android_devices[0]
+ wutils.wifi_test_device_init(self.dut)
+
+ req_params = []
+ opt_param = ["wifi_network", "configure_OpenWrt"]
+ self.unpack_userparams(
+ req_param_names=req_params, opt_param_names=opt_param)
+
+ asserts.assert_true(OPENWRT in self.user_params,
+ "OpenWrtAP is not in testbed.")
+ self.openwrt = self.access_points[0]
+ if hasattr(self, "configure_OpenWrt") and self.configure_OpenWrt == "skip":
+ self.dut.log.info("Skip configure Wifi interface due to config setup.")
+ else:
+ self.configure_openwrt_ap_and_start(wpa_network=True)
+ self.wifi_network = self.openwrt.get_wifi_network()
+
+ asserts.assert_true(self.openwrt.verify_wifi_status(),
+ "OpenWrt Wifi interface is not ready.")
+
+ def teardown_class(self):
+ """Reset wifi to make sure VPN tears down cleanly."""
+ wutils.reset_wifi(self.dut)
+
+ def teardown_test(self):
+ """Reset wifi to make sure VPN tears down cleanly."""
+ wutils.reset_wifi(self.dut)
+
+ def ping(self, addr, ignore_status=True, timeout=60):
+ """Start a ping from DUT and return ping result.
+
+ Args:
+ addr: Address to ping.
+ ignore_status: ignore non zero return.
+ timeout: cmd timeout.
+ Returns:
+ Boolean for ping result.
+ """
+ return "100%" not in self.dut.adb.shell("ping -c 1 %s" % addr,
+ ignore_status=ignore_status,
+ timeout=timeout)
+
+ def generate_query_qname(self):
+ """Return a random query name."""
+ return "%s-ds.metric.gstatic.com" % random.randint(0, 99999999)
+
+ def _block_dns_response_and_ping(self, test_qname):
+ """Block the DNS response and ping
+
+ Args:
+ test_qname: Address to ping
+ Returns:
+ Packets for the ping result
+ """
+ # Start tcpdump on OpenWrt
+ remote_pcap_path = \
+ self.openwrt.network_setting.start_tcpdump(self.test_name)
+ self.dut.log.info("Test query name = %s" % test_qname)
+ # Block the DNS response only before sending the DNS query
+ self.openwrt.network_setting.block_dns_response()
+ # Start send a query
+ self.ping(test_qname)
+ # Un-block the DNS response right after DNS query
+ self.openwrt.network_setting.unblock_dns_response()
+ local_pcap_path = self.openwrt.network_setting.stop_tcpdump(
+ remote_pcap_path, self.dut.device_log_path)
+ self.dut.log.info("pcap file path : %s" % local_pcap_path)
+ # Check DNSQR.qname in tcpdump to verify device retransmit the query
+ packets = rdpcap(local_pcap_path)
+ return packets
+
+ def _get_dnsqr_packets(self, packets, layer, qname):
+ """Filter the DNSQR packets with specific layer
+
+ Args:
+ packets: Packets that came from rdpcap function
+ layer: Keep the packets that contains this layer
+ qname: Keep the packets that related to this qname
+ Returns:
+ List of filtered packets
+ """
+ filtered_packets = []
+ for pkt in packets:
+ if not pkt.haslayer(DNSQR):
+ continue
+ if pkt[DNSQR].qname.decode().strip(".") != qname:
+ continue
+ if pkt.haslayer(layer):
+ filtered_packets.append(pkt)
+ return filtered_packets
+
+ @test_tracker_info(uuid="dd7b8c92-c0f4-4403-a0ae-57a703162d83")
+ def test_dns_query(self):
+ # Setup environment
+ wutils.connect_to_wifi_network(self.dut, self.wifi_network)
+ # Start tcpdump on OpenWrt
+ remote_pcap_path = self.openwrt.network_setting.start_tcpdump(self.test_name)
+ # Generate query name
+ test_qname = self.generate_query_qname()
+ self.dut.log.info("Test query name = %s" % test_qname)
+ # Start send a query
+ ping_result = self.ping(test_qname)
+ local_pcap_path = self.openwrt.network_setting.stop_tcpdump(remote_pcap_path,
+ self.dut.device_log_path)
+ # Check DNSRR.rrname in tcpdump to verify DNS response
+ packets = rdpcap(local_pcap_path)
+ self.dut.log.info("pcap file path : %s" % local_pcap_path)
+ pkt_count = 0
+ for pkt in packets:
+ if pkt.haslayer(DNSRR) and pkt[DNSRR].rrname.decode().strip(".") == test_qname:
+ pkt_count = pkt_count + 1
+ self.dut.log.info("DNS query response count : %s" % pkt_count)
+ if not ping_result:
+ asserts.assert_true(pkt_count > 0,
+ "Did not find match standard query response in tcpdump.")
+ asserts.assert_true(ping_result, "Device ping fail.")
+
+ @test_tracker_info(uuid="cd20c6e7-9c2e-4286-b08e-c8e40e413da5")
+ def test_dns_query_retransmit(self):
+ # Setup environment
+ wutils.connect_to_wifi_network(self.dut, self.wifi_network)
+ test_qname = self.generate_query_qname()
+ packets = self._block_dns_response_and_ping(test_qname)
+ pkts = self._get_dnsqr_packets(packets, IP, test_qname)
+ pkts6 = self._get_dnsqr_packets(packets, IPv6, test_qname)
+ self.dut.log.info("IPv4 DNS query count : %s" % len(pkts))
+ self.dut.log.info("IPv6 DNS query count : %s" % len(pkts6))
+ asserts.assert_true(len(pkts) >= 2 or len(pkts6) >= 2,
+ "Did not find match standard query in tcpdump.")
+
+ @test_tracker_info(uuid="5f58775d-ee7b-4d2e-8e77-77d41e821415")
+ def test_private_dns_query_retransmit(self):
+ # set private DNS mode
+ cutils.set_private_dns(self.dut, cconst.PRIVATE_DNS_MODE_STRICT)
+
+ # Setup environment
+ wutils.connect_to_wifi_network(self.dut, self.wifi_network)
+ test_qname = self.generate_query_qname()
+ packets = self._block_dns_response_and_ping(test_qname)
+ pkts = self._get_dnsqr_packets(packets, IP, test_qname)
+ pkts6 = self._get_dnsqr_packets(packets, IPv6, test_qname)
+ self.dut.log.info("IPv4 DNS query count : %s" % len(pkts))
+ self.dut.log.info("IPv6 DNS query count : %s" % len(pkts6))
+ asserts.assert_true(len(pkts) >= 2 or len(pkts6) >= 2,
+ "Did not find match standard query in tcpdump.")
+
diff --git a/acts_tests/tests/google/net/DataCostTest.py b/acts_tests/tests/google/net/DataCostTest.py
index 6174009..c8089d9 100644
--- a/acts_tests/tests/google/net/DataCostTest.py
+++ b/acts_tests/tests/google/net/DataCostTest.py
@@ -1,5 +1,5 @@
#
-# Copyright 2018 - The Android Open Source Project
+# Copyright 2022 - 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.
@@ -28,7 +28,7 @@
from acts.controllers import adb
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.net import net_test_utils as nutils
-from acts_contrib.test_utils.tel.tel_test_utils import _check_file_existance
+from acts_contrib.test_utils.tel.tel_test_utils import _check_file_existence
from acts_contrib.test_utils.tel.tel_test_utils import _generate_file_directory_and_file_name
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from acts_contrib.test_utils.net.connectivity_const import MULTIPATH_PREFERENCE_NONE as NONE
@@ -252,7 +252,7 @@
self.download_file, DOWNLOAD_PATH)
file_path = os.path.join(file_folder, file_name)
self.log.info("File path: %s" % file_path)
- if _check_file_existance(ad, file_path):
+ if _check_file_existence(ad, file_path):
self.log.info("File exists. Removing file %s" % file_name)
ad.adb.shell("rm -rf %s%s" % (DOWNLOAD_PATH, file_name))
diff --git a/acts_tests/tests/google/net/DataUsageTest.py b/acts_tests/tests/google/net/DataUsageTest.py
index 1582886..e6b3fca 100644
--- a/acts_tests/tests/google/net/DataUsageTest.py
+++ b/acts_tests/tests/google/net/DataUsageTest.py
@@ -1,5 +1,5 @@
#
-# Copyright 2018 - The Android Open Source Project
+# Copyright 2022 - 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.
@@ -30,7 +30,7 @@
from acts_contrib.test_utils.net.net_test_utils import stop_tcpdump
from acts_contrib.test_utils.tel import tel_test_utils as ttutils
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_test_utils import http_file_download_by_chrome
+from acts_contrib.test_utils.tel.tel_data_utils import http_file_download_by_chrome
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
import queue
from queue import Empty
@@ -143,7 +143,7 @@
download_status = False
end_time = time.time() + TIMEOUT
while time.time() < end_time:
- download_status = ttutils._check_file_existance(
+ download_status = ttutils._check_file_existence(
ad, self.file_path, self.file_size * BYTE_TO_MB)
if download_status:
self.log.info("Delete file: %s", self.file_path)
diff --git a/acts_tests/tests/google/net/DhcpTest.py b/acts_tests/tests/google/net/DhcpTest.py
new file mode 100644
index 0000000..08aa983
--- /dev/null
+++ b/acts_tests/tests/google/net/DhcpTest.py
@@ -0,0 +1,153 @@
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import time
+
+from acts import asserts
+from acts.controllers.openwrt_ap import MOBLY_CONTROLLER_CONFIG_NAME as OPENWRT
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
+from scapy.all import rdpcap, DHCP
+
+WLAN = "wlan0"
+PING_ADDR = "google.com"
+RAPID_COMMIT_OPTION = (80, b'')
+
+class DhcpTest(WifiBaseTest):
+ """DHCP related test for Android."""
+
+ def setup_class(self):
+ self.dut = self.android_devices[0]
+
+ wutils.wifi_test_device_init(self.dut)
+ req_params = []
+ opt_param = ["wifi_network", "configure_OpenWrt"]
+ self.unpack_userparams(
+ req_param_names=req_params, opt_param_names=opt_param)
+ asserts.assert_true(OPENWRT in self.user_params,
+ "OpenWrtAP is not in testbed.")
+
+ self.openwrt = self.access_points[0]
+ if hasattr(self, "configure_OpenWrt") and self.configure_OpenWrt == "skip":
+ self.dut.log.info("Skip configure Wifi interface due to config setup.")
+ else:
+ self.configure_openwrt_ap_and_start(wpa_network=True)
+ self.wifi_network = self.openwrt.get_wifi_network()
+ self.openwrt.network_setting.setup_ipv6_bridge()
+ asserts.assert_true(self.openwrt.verify_wifi_status(),
+ "OpenWrt Wifi interface is not ready.")
+
+ def teardown_class(self):
+ """Reset wifi and stop tcpdump cleanly."""
+ wutils.reset_wifi(self.dut)
+ self.openwrt.network_setting.clear_tcpdump()
+
+ def teardown_test(self):
+ """Reset wifi to make sure DUT tears down cleanly."""
+ wutils.reset_wifi(self.dut)
+
+ def _verify_ping(self, option="", dest=PING_ADDR):
+ try:
+ out = self.dut.adb.shell("ping%s -c1 %s" % (option, dest))
+ return "100%" not in out
+ except Exception as e:
+ self.dut.log.debug(e)
+ return False
+
+ def _verify_device_address(self, ipv4=True, ipv6=True, timeout=15):
+ """Verify device get assign address on wireless interface."""
+ current_time = time.time()
+ while time.time() < current_time + timeout:
+ try:
+ if ipv4:
+ ipv4_addr = self.dut.droid.connectivityGetIPv4Addresses(WLAN)[0]
+ self.dut.log.info("ipv4_address is %s" % ipv4_addr)
+ if ipv6:
+ ipv6_addr = self.dut.droid.connectivityGetIPv6Addresses(WLAN)[0]
+ self.dut.log.info("ipv6_address is %s" % ipv6_addr)
+ return True
+ except:
+ time.sleep(1)
+ return False
+
+ def verify_dhcp_packet(self, packets, support_rapid_commit):
+ for pkt in packets:
+ if pkt.haslayer(DHCP):
+ if pkt[DHCP].options[0][1]==1:
+ send_option = RAPID_COMMIT_OPTION in pkt[DHCP].options
+ asserts.assert_true(send_option == support_rapid_commit,
+ "Unexpected result in DHCP DISCOVER.")
+ elif pkt[DHCP].options[0][1]==2:
+ asserts.assert_true( not support_rapid_commit,
+ "Should not find DHCP OFFER when RAPID_COMMIT_OPTION supported.")
+ elif pkt[DHCP].options[0][1]==3:
+ asserts.assert_true( not support_rapid_commit,
+ "Should not find DHCP REQUEST when RAPID_COMMIT_OPTION supported.")
+ elif pkt[DHCP].options[0][1]==5:
+ send_option = RAPID_COMMIT_OPTION in pkt[DHCP].options
+ asserts.assert_true(send_option == support_rapid_commit,
+ "Unexpected result in DHCP ACK.")
+
+ @test_tracker_info(uuid="01148659-6a3d-4a74-88b6-04b19c4acaaa")
+ def test_ipv4_ipv6_network(self):
+ """Verify device can get both ipv4 ipv6 address."""
+ wutils.connect_to_wifi_network(self.dut, self.wifi_network)
+
+ asserts.assert_true(self._verify_device_address(),
+ "Fail to get ipv4/ipv6 address.")
+ asserts.assert_true(self._verify_ping(), "Fail to ping on ipv4.")
+ asserts.assert_true(self._verify_ping("6"), "Fail to ping on ipv6.")
+
+ @test_tracker_info(uuid="d3f37ba7-504e-48fc-95be-6eca9a148e4a")
+ def test_ipv6_only_prefer_option(self):
+ """Verify DUT can only get ipv6 address and ping out."""
+ self.openwrt.network_setting.add_ipv6_prefer_option()
+ wutils.connect_to_wifi_network(self.dut, self.wifi_network)
+
+ asserts.assert_true(self._verify_device_address(ipv4=False),
+ "Fail to get ipv6 address.")
+ asserts.assert_false(self._verify_ping(),
+ "Should not ping on success on ipv4.")
+ asserts.assert_true(self._verify_ping("6"),
+ "Fail to ping on ipv6.")
+ self.openwrt.network_setting.remove_ipv6_prefer_option()
+
+ @test_tracker_info(uuid="a16f2a3c-e3ca-4fca-b3ee-bccb5cf34bab")
+ def test_dhcp_rapid_commit(self):
+ """Verify DUT can run with rapid commit on IPv4."""
+ self.dut.adb.shell("device_config put connectivity dhcp_rapid_commit_version 1")
+ self.openwrt.network_setting.add_dhcp_rapid_commit()
+ remote_pcap_path = \
+ self.openwrt.network_setting.start_tcpdump(self.test_name)
+ wutils.connect_to_wifi_network(self.dut, self.wifi_network)
+ local_pcap_path = self.openwrt.network_setting.stop_tcpdump(
+ remote_pcap_path, self.dut.device_log_path)
+ self.dut.log.info("pcap file path : %s" % local_pcap_path)
+ packets = rdpcap(local_pcap_path)
+ self.verify_dhcp_packet(packets, True)
+ self.openwrt.network_setting.remove_dhcp_rapid_commit()
+
+ @test_tracker_info(uuid="cddb3d33-e5ef-4efd-8ae5-1325010a05c8")
+ def test_dhcp_4_way_handshake(self):
+ """Verify DUT can run with rapid commit on IPv4."""
+ self.dut.adb.shell("device_config put connectivity dhcp_rapid_commit_version 0")
+ remote_pcap_path = \
+ self.openwrt.network_setting.start_tcpdump(self.test_name)
+ wutils.connect_to_wifi_network(self.dut, self.wifi_network)
+ local_pcap_path = self.openwrt.network_setting.stop_tcpdump(
+ remote_pcap_path, self.dut.device_log_path)
+ self.dut.log.info("pcap file path : %s" % local_pcap_path)
+ packets = rdpcap(local_pcap_path)
+ self.verify_dhcp_packet(packets, False)
diff --git a/acts_tests/tests/google/net/DnsOverHttpsTest.py b/acts_tests/tests/google/net/DnsOverHttpsTest.py
new file mode 100644
index 0000000..56f3792
--- /dev/null
+++ b/acts_tests/tests/google/net/DnsOverHttpsTest.py
@@ -0,0 +1,295 @@
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import time
+
+from acts import asserts
+from acts.controllers.openwrt_ap import MOBLY_CONTROLLER_CONFIG_NAME as OPENWRT
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.net import connectivity_const as cconst
+from acts_contrib.test_utils.net import connectivity_test_utils as cutils
+from acts_contrib.test_utils.net.net_test_utils import start_tcpdump
+from acts_contrib.test_utils.net.net_test_utils import stop_tcpdump
+from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
+from scapy.all import rdpcap
+from scapy.all import Scapy_Exception
+from scapy.all import TCP
+from scapy.all import UDP
+
+
+DEFAULT_DNS_TIMEOUT = 5
+
+
+class DnsOverHttpsTest(WifiBaseTest):
+ """Tests for DnsoverHttps feature."""
+
+ def setup_class(self):
+ """Setup devices and OpenWrt for DnsoverHttps test and unpack params."""
+
+ self.dut = self.android_devices[0]
+ if len(self.android_devices) > 1:
+ self.dut_b = self.android_devices[1]
+ for ad in self.android_devices:
+ wutils.reset_wifi(ad)
+ ad.droid.setPrivateDnsMode(True)
+ req_params = ("ping_hosts",)
+ opt_params = ("wifi_network", "configure_OpenWrt",
+ "ipv4_only_network", "ipv4_ipv6_network")
+ self.unpack_userparams(req_param_names=req_params,
+ opt_param_names=opt_params)
+ if OPENWRT in self.user_params:
+ self.openwrt = self.access_points[0]
+ if hasattr(self, "configure_OpenWrt") and self.configure_OpenWrt == "skip":
+ self.dut.log.info("Skip configure Wifi interface due to config setup.")
+ else:
+ self.configure_openwrt_ap_and_start(wpa_network=True)
+ self.tcpdump_pid = None
+ self.default_dns = None
+ self.default_dns_v6 = None
+ self._setup_doh(self.dut, self.get_wifi_network())
+
+ def teardown_test(self):
+ wutils.reset_wifi(self.dut)
+ if OPENWRT in self.user_params:
+ self.openwrt.network_setting.del_default_dns(self.default_dns)
+ self.default_dns = None
+ self.default_dns_v6 = None
+
+ def teardown_class(self):
+ for ad in self.android_devices:
+ ad.droid.setPrivateDnsMode(True)
+ self._setup_doh(ad, self.get_wifi_network(), enable=False)
+
+ def on_fail(self, test_name, begin_time):
+ self.dut.take_bug_report(test_name, begin_time)
+
+ def get_wifi_network(self, ipv6_supported=False):
+ """Return fit network for conditions.
+
+ Args:
+ ipv6_supported: Boolean for select network.
+ Returns:
+ A dict for network object for connect wifi.
+ """
+ if OPENWRT in self.user_params:
+ if ipv6_supported:
+ self.openwrt.network_setting.enable_ipv6()
+ self.openwrt.network_setting.setup_ipv6_bridge()
+ else:
+ self.openwrt.network_setting.disable_ipv6()
+ self.openwrt.network_setting.remove_ipv6_bridge()
+ if self.default_dns:
+ self.openwrt.network_setting.add_default_dns(self.default_dns)
+ if self.default_dns_v6:
+ for ipv6_dns in self.default_dns_v6:
+ self.openwrt.network_setting.add_default_v6_dns(ipv6_dns)
+ if hasattr(self, "configure_OpenWrt") and self.configure_OpenWrt == "skip":
+ return self.wifi_network
+ return self.openwrt.get_wifi_network()
+ if ipv6_supported:
+ return self.ipv4_ipv6_network
+ return self.ipv4_only_network
+
+ def _verify_doh_queries(self, pcap_file, over_https):
+ """Verify if DNS queries were over https or not.
+
+ Args:
+ pcap_file: tcpdump file
+ over_https: True if excepted all dns go through doh.
+ """
+ try:
+ packets = rdpcap(pcap_file)
+ except Scapy_Exception:
+ asserts.fail("Not a valid pcap file")
+
+ for pkt in packets:
+ summary = "%s" % pkt.summary()
+ for host in self.ping_hosts:
+ host = host.split(".")[-2]
+ if UDP in pkt and pkt[UDP].sport == 53 and host in summary:
+ if over_https:
+ asserts.fail("Found query to port 53: %s" % summary)
+ else:
+ self.dut.log.info("Found query to port 53: %s" % summary)
+ if TCP in pkt and pkt[TCP].sport == 853:
+ asserts.fail("Found query to port 853: %s" % summary)
+
+ def _test_public_doh_mode(self, ad, net, dns_mode, hostname=None):
+ """Test step for DoH.
+
+ Args:
+ ad: android device object.
+ net: wifi network to connect to, LTE network if None.
+ dns_mode: private DNS mode.
+ hostname: private DNS hostname to set to.
+ """
+
+ # set private dns mode
+ if dns_mode:
+ cutils.set_private_dns(self.dut, dns_mode, hostname)
+ # connect to wifi
+ wutils.start_wifi_connection_scan_and_ensure_network_found(
+ self.dut, net[wutils.WifiEnums.SSID_KEY])
+ wutils.wifi_connect(self.dut, net)
+ self._verify_tls_completed()
+
+ # start tcpdump on the device
+ self.tcpdump_pid = start_tcpdump(self.dut, self.test_name)
+
+ # ping hosts should pass
+ for host in self.ping_hosts:
+ self.log.info("Pinging %s" % host)
+ status = wutils.validate_connection(self.dut, host)
+ asserts.assert_true(status, "Failed to ping host %s" % host)
+ self.log.info("Ping successful")
+
+ # stop tcpdump
+ pcap_file = stop_tcpdump(self.dut, self.tcpdump_pid, self.test_name)
+
+ # verify DNS queries
+ overhttps = dns_mode != cconst.PRIVATE_DNS_MODE_OFF
+ self._verify_doh_queries(pcap_file, overhttps)
+
+ # reset wifi
+ wutils.reset_wifi(self.dut)
+
+ def _verify_tls_completed(self, retry_count=5):
+ """Verify tls finish verification process.
+
+ Expect all private dns server status, should be
+ "success", or "fail".
+
+ Args:
+ retry_count: int for retry times.
+ Raises:
+ TimeoutError: if TLS verification stuck in processing.
+ """
+ for attempt in range(retry_count):
+ out = self.dut.adb.shell("dumpsys dnsresolver")
+ if "status{in_process}" in out:
+ if attempt + 1 < retry_count:
+ self.dut.log.info("DoT still validating, retrying...")
+ time.sleep(DEFAULT_DNS_TIMEOUT)
+ else:
+ return
+ raise TimeoutError("Fail to completed TLS verification.")
+
+ def _setup_doh(self, ad, net, enable=True):
+ """Enable/Disable DoH option.
+
+ Args:
+ ad: android devies.
+ net: network as wifi.
+ enable: if True, sets the 'doh' experiment flag.
+ """
+ if enable:
+ ad.adb.shell("setprop persist.device_config.netd_native.doh 1")
+ else:
+ ad.adb.shell("setprop persist.device_config.netd_native.doh 0")
+ wutils.wifi_connect(ad, net)
+ wutils.reset_wifi(ad)
+ out = ad.adb.shell("dumpsys dnsresolver |grep doh")
+ ad.log.debug(out)
+
+ def test_mix_server_ipv4_only_wifi_network_with_dns_strict_mode(self):
+ """Test doh flag with below situation.
+
+ - Android device in strict mode
+ - DNS server supporting both Dns, DoT and DoH protocols
+ - IPv4-only network
+ """
+ self._test_public_doh_mode(self.dut, self.get_wifi_network(),
+ cconst.PRIVATE_DNS_MODE_STRICT,
+ hostname=cconst.DNS_GOOGLE_HOSTNAME)
+
+ def test_mix_server_ipv4_ipv6_wifi_network_with_dns_strict_mode(self):
+ """Test doh flag with below situation.
+
+ - Android device in strict mode
+ - DNS server supporting both Dns, DoT and DoH protocols
+ - IPv4-IPv6 network
+ """
+ self._test_public_doh_mode(self.dut, self.get_wifi_network(),
+ cconst.PRIVATE_DNS_MODE_STRICT,
+ hostname=cconst.DNS_GOOGLE_HOSTNAME)
+
+ def test_pure_server_ipv4_only_wifi_network_with_dns_strict_mode(self):
+ """Test doh flag with below situation.
+
+ - Android device in strict mode
+ - DNS server only supporting DoH protocols
+ - IPv4-only network
+ """
+ self._test_public_doh_mode(self.dut, self.get_wifi_network(),
+ cconst.PRIVATE_DNS_MODE_STRICT,
+ hostname=cconst.DOH_CLOUDFLARE_HOSTNAME)
+
+ def test_pure_server_ipv4_ipv6_wifi_network_with_dns_strict_mode(self):
+ """Test doh flag with below situation.
+
+ - Android device in strict mode
+ - DNS server only supporting DoH protocols
+ - IPv4-IPv6 network
+ """
+ self._test_public_doh_mode(self.dut, self.get_wifi_network(),
+ cconst.PRIVATE_DNS_MODE_STRICT,
+ hostname=cconst.DOH_CLOUDFLARE_HOSTNAME)
+
+ def test_mix_server_ipv4_only_wifi_network_with_dns_opportunistic_mode(self):
+ """Test doh flag with below situation.
+
+ - Android device in opportunistic mode
+ - DNS server supporting both Dns, DoT and DoH protocols
+ - IPv4-only network
+ """
+ self.default_dns = cconst.DNS_GOOGLE_ADDR_V4
+ self._test_public_doh_mode(self.dut, self.get_wifi_network(),
+ cconst.PRIVATE_DNS_MODE_OPPORTUNISTIC)
+
+ def test_mix_server_ipv4_ipv6_wifi_network_with_dns_opportunistic_mode(self):
+ """Test doh flag with below situation.
+
+ - Android device in opportunistic mode
+ - DNS server supporting both Dns, DoT and DoH protocols
+ - IPv4-IPv6 network
+ """
+ self.default_dns = cconst.DNS_GOOGLE_ADDR_V4
+ self.default_dns_v6 = cconst.DNS_GOOGLE_ADDR_V6
+ self._test_public_doh_mode(self.dut, self.get_wifi_network(),
+ cconst.PRIVATE_DNS_MODE_OPPORTUNISTIC)
+
+ def test_mix_server_ipv4_only_wifi_network_with_dns_off_mode(self):
+ """Test doh with below situation.
+
+ - Android device in dns off mode
+ - DNS server supporting both Dns, DoT and DoH protocols
+ - IPv4-only network
+ """
+ self.default_dns = cconst.DNS_GOOGLE_ADDR_V4
+ self._test_public_doh_mode(self.dut, self.get_wifi_network(),
+ cconst.PRIVATE_DNS_MODE_OFF)
+
+ def test_mix_server_ipv4_ipv6_wifi_network_with_dns_off_mode(self):
+ """Test doh with below situation.
+
+ - Android device in dns off mode
+ - DNS server supporting both Dns, DoT and DoH protocols
+ - IPv4-IPv6 network
+ """
+ self.default_dns = cconst.DNS_GOOGLE_ADDR_V4
+ self.default_dns_v6 = cconst.DNS_GOOGLE_ADDR_V6
+ self._test_public_doh_mode(self.dut, self.get_wifi_network(),
+ cconst.PRIVATE_DNS_MODE_OFF)
diff --git a/acts_tests/tests/google/net/DnsOverTlsTest.py b/acts_tests/tests/google/net/DnsOverTlsTest.py
index 13d8fe1..0bb1e28 100644
--- a/acts_tests/tests/google/net/DnsOverTlsTest.py
+++ b/acts_tests/tests/google/net/DnsOverTlsTest.py
@@ -21,11 +21,11 @@
from acts_contrib.test_utils.net import connectivity_const as cconst
from acts_contrib.test_utils.net import connectivity_test_utils as cutils
from acts_contrib.test_utils.net import net_test_utils as nutils
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
from acts_contrib.test_utils.net.net_test_utils import start_tcpdump
from acts_contrib.test_utils.net.net_test_utils import stop_tcpdump
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
from scapy.all import rdpcap
@@ -37,6 +37,7 @@
RST = 0x04
SSID = wutils.WifiEnums.SSID_KEY
+
class DnsOverTlsTest(WifiBaseTest):
"""Tests for DNS-over-TLS."""
@@ -48,22 +49,28 @@
self.dut_b = self.android_devices[1]
for ad in self.android_devices:
ad.droid.setPrivateDnsMode(True)
- nutils.verify_lte_data_and_tethering_supported(ad)
+ if OPENWRT not in self.user_params:
+ nutils.verify_lte_data_and_tethering_supported(ad)
set_wfc_mode(self.log, ad, WFC_MODE_DISABLED)
req_params = ("ping_hosts",)
- opt_params = ("ipv4_only_network", "ipv4_ipv6_network", "dns_name")
+ opt_params = ("ipv4_only_network", "ipv4_ipv6_network",
+ "dns_name", "configure_OpenWrt", "wifi_network")
self.unpack_userparams(req_param_names=req_params,
opt_param_names=opt_params)
if OPENWRT in self.user_params:
self.openwrt = self.access_points[0]
+ if hasattr(self, "configure_OpenWrt") and self.configure_OpenWrt == "skip":
+ self.dut.log.info("Skip configure Wifi interface due to config setup.")
+ else:
+ self.configure_openwrt_ap_and_start(wpa_network=True)
+ self.wifi_network = self.openwrt.get_wifi_network()
self.private_dns_servers = [self.dns_name]
- self.configure_openwrt_ap_and_start(wpa_network=True)
self.openwrt.network_setting.setup_dns_server(self.dns_name)
else:
- self.private_dns_servers = [cconst.DNS_GOOGLE,
- cconst.DNS_QUAD9,
- cconst.DNS_CLOUDFLARE]
+ self.private_dns_servers = [cconst.DNS_GOOGLE_HOSTNAME,
+ cconst.DNS_QUAD9_HOSTNAME,
+ cconst.DNS_CLOUDFLARE_HOSTNAME]
self.tcpdump_pid = None
def teardown_test(self):
@@ -179,6 +186,42 @@
# reset wifi
wutils.reset_wifi(self.dut)
+ def _test_invalid_private_dns(self, net, dns_mode, dns_hostname):
+ """Test private DNS with invalid hostname, which should failed the ping.
+
+ :param net: Wi-Fi network to connect to
+ :param dns_mode: private DNS mode
+ :param dns_hostname: private DNS hostname
+ :return:
+ """
+
+ cutils.set_private_dns(self.dut, dns_mode, dns_hostname)
+ if net:
+ wutils.start_wifi_connection_scan_and_ensure_network_found(
+ self.dut, net[SSID])
+ wutils.wifi_connect(
+ self.dut, net, assert_on_fail=False, check_connectivity=False)
+
+ self._start_tcp_dump(self.dut)
+
+ # ping hosts should NOT pass
+ ping_result = False
+ for host in self.ping_hosts:
+ self.log.info("Pinging %s" % host)
+ try:
+ ping_result = self.dut.droid.httpPing(host)
+ except:
+ pass
+ # Ping result should keep negative with invalid DNS,
+ # so once it's positive we should break, and the test should fail
+ if ping_result:
+ break
+
+ pcap_file = self._stop_tcp_dump(self.dut)
+ self._verify_dns_queries_over_tls(pcap_file, True)
+ wutils.reset_wifi(self.dut)
+ return ping_result
+
@test_tracker_info(uuid="2957e61c-d333-45fb-9ff9-2250c9c8535a")
def test_private_dns_mode_off_wifi_ipv4_only_network(self):
"""Verify private dns mode off on ipv4 only network.
@@ -477,7 +520,7 @@
# set private DNS to strict mode
cutils.set_private_dns(
- self.dut, cconst.PRIVATE_DNS_MODE_STRICT, cconst.DNS_GOOGLE)
+ self.dut, cconst.PRIVATE_DNS_MODE_STRICT, cconst.DNS_GOOGLE_HOSTNAME)
# connect DUT to wifi network
wutils.start_wifi_connection_scan_and_ensure_network_found(
@@ -506,9 +549,9 @@
pcap_file = self._stop_tcp_dump(self.dut)
# Verify DNS server in link properties
- asserts.assert_true(cconst.DNS_GOOGLE in wifi_dns_servers,
+ asserts.assert_true(cconst.DNS_GOOGLE_HOSTNAME in wifi_dns_servers,
"Hostname not in link properties - wifi network")
- asserts.assert_true(cconst.DNS_GOOGLE in lte_dns_servers,
+ asserts.assert_true(cconst.DNS_GOOGLE_HOSTNAME in lte_dns_servers,
"Hostname not in link properites - cell network")
@test_tracker_info(uuid="525a6f2d-9751-474e-a004-52441091e427")
@@ -532,6 +575,7 @@
for host in self.ping_hosts:
wutils.validate_connection(self.dut, host)
+
# stop tcpdump on device
pcap_file = self._stop_tcp_dump(self.dut)
@@ -540,18 +584,17 @@
@test_tracker_info(uuid="af6e34f1-3ad5-4ab0-b3b9-53008aa08294")
def test_private_dns_mode_strict_invalid_hostnames(self):
- """Verify that invalid hostnames are not saved for strict mode.
+ """Verify that invalid hostnames are not able to ping for strict mode.
Steps:
1. Set private DNS to strict mode with invalid hostname
2. Verify that invalid hostname is not saved
"""
invalid_hostnames = ["!%@&!*", "12093478129", "9.9.9.9", "sdkfjhasdf"]
- for hostname in invalid_hostnames:
- cutils.set_private_dns(
- self.dut, cconst.PRIVATE_DNS_MODE_STRICT, hostname)
- mode = self.dut.droid.getPrivateDnsMode()
- specifier = self.dut.droid.getPrivateDnsSpecifier()
- asserts.assert_true(
- mode == cconst.PRIVATE_DNS_MODE_STRICT and specifier != hostname,
- "Able to set invalid private DNS strict mode")
+ for dns_hostname in invalid_hostnames:
+ ping_result = self._test_invalid_private_dns(
+ self.get_wifi_network(False),
+ cconst.PRIVATE_DNS_MODE_STRICT,
+ dns_hostname)
+ asserts.assert_false(ping_result, "Ping success with invalid DNS.")
+
diff --git a/acts_tests/tests/google/net/IKEv2VpnOverWifiTest.py b/acts_tests/tests/google/net/IKEv2VpnOverWifiTest.py
index 6196f61..22fa780 100644
--- a/acts_tests/tests/google/net/IKEv2VpnOverWifiTest.py
+++ b/acts_tests/tests/google/net/IKEv2VpnOverWifiTest.py
@@ -13,39 +13,69 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import time
-from acts import base_test
+from acts.controllers.openwrt_ap import MOBLY_CONTROLLER_CONFIG_NAME as OPENWRT
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.net import connectivity_const
from acts_contrib.test_utils.net import net_test_utils as nutils
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
+
VPN_CONST = connectivity_const.VpnProfile
VPN_TYPE = connectivity_const.VpnProfileType
VPN_PARAMS = connectivity_const.VpnReqParams
-class IKEv2VpnOverWifiTest(base_test.BaseTestClass):
+class IKEv2VpnOverWifiTest(WifiBaseTest):
"""IKEv2 VPN tests."""
def setup_class(self):
+ """Setup wi-fi connection and unpack params."""
self.dut = self.android_devices[0]
-
- required_params = dir(VPN_PARAMS)
- required_params = [x for x in required_params if not x.startswith("__")]
- self.unpack_userparams(req_param_names=required_params)
- self.vpn_params = {
- "vpn_username": self.vpn_username,
- "vpn_password": self.vpn_password,
- "psk_secret": self.psk_secret,
- "client_pkcs_file_name": self.client_pkcs_file_name,
- "cert_path_vpnserver": self.cert_path_vpnserver,
- "cert_password": self.cert_password,
- "vpn_identity": self.vpn_identity,
- }
+ req_params = dir(VPN_PARAMS)
+ req_params = [
+ x for x in req_params if not x.startswith("__")
+ ]
+ opt_params = ["wifi_network", "vpn_cert_country",
+ "vpn_cert_org", "configure_OpenWrt"]
+ self.unpack_userparams(req_param_names=req_params,
+ opt_param_names=opt_params)
wutils.wifi_test_device_init(self.dut)
- wutils.connect_to_wifi_network(self.dut, self.wifi_network)
+ wutils.wifi_toggle_state(self.dut, True)
+ if OPENWRT in self.user_params:
+ self.openwrt = self.access_points[0]
+ if hasattr(self, "configure_OpenWrt") and self.configure_OpenWrt == "skip":
+ self.dut.log.info("Skip configure Wifi interface due to config setup.")
+ else:
+ self.configure_openwrt_ap_and_start(wpa_network=True)
+ self.wifi_network = self.openwrt.get_wifi_network()
+ # Wait for OpenWrt statement update
+ time.sleep(10)
+ self.openwrt.network_setting.setup_vpn_l2tp_server(
+ self.vpn_server_hostname,
+ self.vpn_verify_addresses["IKEV2_IPSEC_RSA"][0],
+ self.vpn_username,
+ self.vpn_password,
+ self.vpn_identity,
+ "ikev2-server",
+ self.vpn_cert_country,
+ self.vpn_cert_org
+ )
+ wutils.start_wifi_connection_scan_and_ensure_network_found(
+ self.dut, self.wifi_network["SSID"])
+ wutils.wifi_connect(self.dut, self.wifi_network)
+ time.sleep(3)
+
+ self.vpn_params = {"vpn_username": self.vpn_username,
+ "vpn_password": self.vpn_password,
+ "psk_secret": self.psk_secret,
+ "client_pkcs_file_name": self.client_pkcs_file_name,
+ "cert_path_vpnserver": self.cert_path_vpnserver,
+ "cert_password": self.cert_password,
+ "vpn_identity": self.vpn_identity}
def teardown_class(self):
wutils.reset_wifi(self.dut)
@@ -54,6 +84,7 @@
self.dut.take_bug_report(test_name, begin_time)
### Helper methods ###
+
def _test_ikev2_vpn(self, vpn, hostname=None):
"""Verify IKEv2 VPN connection.
@@ -86,7 +117,8 @@
@test_tracker_info(uuid="bdd8a967-8dac-4e48-87b7-2ce9f7d32158")
def test_ikev2_psk_vpn_wifi_with_hostname(self):
- self._test_ikev2_vpn(VPN_TYPE.IKEV2_IPSEC_PSK, self.vpn_server_hostname)
+ self._test_ikev2_vpn(VPN_TYPE.IKEV2_IPSEC_PSK,
+ self.vpn_server_hostname)
@test_tracker_info(uuid="19692520-c123-4b42-8549-08dda9c4873e")
def test_ikev2_mschapv2_vpn_wifi_with_hostname(self):
@@ -95,4 +127,5 @@
@test_tracker_info(uuid="bdaaf6e3-6671-4533-baba-2951009c7d69")
def test_ikev2_rsa_vpn_wifi_with_hostname(self):
- self._test_ikev2_vpn(VPN_TYPE.IKEV2_IPSEC_RSA, self.vpn_server_hostname)
+ self._test_ikev2_vpn(VPN_TYPE.IKEV2_IPSEC_RSA,
+ self.vpn_server_hostname)
diff --git a/acts_tests/tests/google/net/LegacyVpnTest.py b/acts_tests/tests/google/net/LegacyVpnTest.py
index 6e9710b..4003a2f 100644
--- a/acts_tests/tests/google/net/LegacyVpnTest.py
+++ b/acts_tests/tests/google/net/LegacyVpnTest.py
@@ -43,7 +43,8 @@
req_params = [
x for x in req_params if not x.startswith("__")
]
- opt_params = ["wifi_network", "vpn_cert_country", "vpn_cert_org"]
+ opt_params = ["wifi_network", "vpn_cert_country",
+ "vpn_cert_org", "configure_OpenWrt"]
self.unpack_userparams(req_param_names=req_params,
opt_param_names=opt_params)
@@ -51,8 +52,12 @@
wutils.wifi_toggle_state(self.dut, True)
if OPENWRT in self.user_params:
self.openwrt = self.access_points[0]
- self.configure_openwrt_ap_and_start(wpa_network=True)
- self.wifi_network = self.openwrt.get_wifi_network()
+ if hasattr(self, "configure_OpenWrt") and self.configure_OpenWrt == "skip":
+ self.dut.log.info("Skip configure Wifi interface due to config setup.")
+ else:
+ self.configure_openwrt_ap_and_start(wpa_network=True)
+ self.wifi_network = self.openwrt.get_wifi_network()
+
# Wait for OpenWrt statement update
time.sleep(10)
self.openwrt.network_setting.setup_vpn_pptp_server(
diff --git a/acts_tests/tests/google/net/MutlicastDNSTest.py b/acts_tests/tests/google/net/MutlicastDNSTest.py
new file mode 100644
index 0000000..475ad45
--- /dev/null
+++ b/acts_tests/tests/google/net/MutlicastDNSTest.py
@@ -0,0 +1,79 @@
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+from acts import asserts
+from acts.controllers.openwrt_ap import MOBLY_CONTROLLER_CONFIG_NAME as OPENWRT
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
+
+
+class MulticastDNSTest(WifiBaseTest):
+ """Verify Multicast DNS can work on Android devices."""
+
+ def setup_class(self):
+ """Setup Openwrt and unpack params for mDNS test."""
+ self.dut = self.android_devices[0]
+ req_params = []
+ opt_params = ["configure_OpenWrt", "wifi_network"]
+ self.unpack_userparams(req_params, opt_params)
+ if OPENWRT in self.user_params:
+ self.openwrt = self.access_points[0]
+ if hasattr(self, "configure_OpenWrt") and self.configure_OpenWrt == "skip":
+ self.dut.log.info("Skip configure Wifi interface due to config setup.")
+ else:
+ self.configure_openwrt_ap_and_start(wpa_network=True)
+ self.wifi_network = self.openwrt.get_wifi_network()
+
+ def on_fail(self, test_name, begin_time):
+ """Take bugreport if test failed."""
+ self.dut.take_bug_report(test_name, begin_time)
+
+ def teardown_test(self):
+ """Reset wifi settings after test case."""
+ wutils.reset_wifi(self.dut)
+
+ def verify_ping(self, hostname, expect_ping_pass=True):
+ """Verify if result of the ping as excepted.
+
+ Args:
+ hostname: ping address.
+ expect_ping_pass: excepted ping result is True or False.
+ Returns:
+ Boolean if ping result work as expected.
+ """
+ out = self.dut.adb.shell("ping -c 1 %s" % hostname)
+ result = ("100%" not in out) == expect_ping_pass
+ if not result:
+ self.dut.log.info(out)
+ return result
+
+ def test_mdns_query_ipv4_only(self):
+ """Verify mdns query work in ipv4 only network."""
+ self.openwrt.network_setting.disable_ipv6()
+ self.openwrt.network_setting.setup_mdns()
+ wutils.wifi_connect(self.dut, self.wifi_network)
+ asserts.assert_true(self.verify_ping("openwrt.local"),
+ "Fail to ping openwrt.local.")
+
+ def test_mdns_query_ipv4_ipv6(self):
+ """Verify mdns query work in ipv4 & ipv6 network."""
+ self.openwrt.network_setting.enable_ipv6()
+ self.openwrt.network_setting.setup_mdns()
+ wutils.wifi_connect(self.dut, self.wifi_network)
+ asserts.assert_true(self.verify_ping("openwrt.local"),
+ "Fail to ping openwrt.local.")
+
diff --git a/acts_tests/tests/google/net/UsbTetheringTest.py b/acts_tests/tests/google/net/UsbTetheringTest.py
index e02611e..1f1d4cf 100644
--- a/acts_tests/tests/google/net/UsbTetheringTest.py
+++ b/acts_tests/tests/google/net/UsbTetheringTest.py
@@ -3,25 +3,47 @@
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.net import net_test_utils as nutils
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
-from scapy.all import get_if_list
from scapy.all import get_if_raw_hwaddr
+from scapy.layers.dns import DNS, DNSQR
+from scapy.layers.inet import IP, ICMP, UDP, TCP, RandShort, sr1
+from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest
DUMSYS_CMD = "dumpsys connectivity tethering"
UPSTREAM_WANTED_STRING = "Upstream wanted"
CURRENT_UPSTREAM_STRING = "Current upstream interface"
SSID = wutils.WifiEnums.SSID_KEY
+GOOGLE_DNS_IP_ADDRESS = "8.8.8.8"
+DEFAULT_DOMAIN_NAME = "www.google.com"
+DEFAULT_DOMAIN_NAME_IPV4 = "ipv4.google.com"
+DEFAULT_DOMAIN_NAME_IPV6 = "ipv6.google.com"
class UsbTetheringTest(base_test.BaseTestClass):
- """Tests for tethering."""
+ """Tests for USB tethering.
+
+ Prerequisite:
+ 1. Android phone should connect to the desktop with USB cable
+ 2. DUT should be able to connect to cellular network and Wi-Fi network
+ 3. Set the CAP_NET_RAW capability before run the test.
+ e.g., `sudo setcap cap_net_raw=eip /usr/local/bin/act.py`
+ """
def setup_class(self):
self.dut = self.android_devices[0]
self.USB_TETHERED = False
nutils.verify_lte_data_and_tethering_supported(self.dut)
+ nutils.set_cap_net_raw_capability()
req_params = ("wifi_network",)
self.unpack_userparams(req_params)
+ # Enable USB tethering and get the USB network interface
+ iflist_before = nutils.get_if_list()
+ serial = self.dut.device_info['serial']
+ nutils.start_usb_tethering(self.dut)
+ self.dut.recreate_services(serial)
+ self.iface = nutils.wait_for_new_iface(iflist_before)
+ if not self.check_upstream_ready():
+ raise asserts.fail("Upstream interface is not active.")
def teardown_class(self):
nutils.stop_usb_tethering(self.dut)
@@ -31,14 +53,112 @@
def on_fail(self, test_name, begin_time):
self.dut.take_bug_report(test_name, begin_time)
- @test_tracker_info(uuid="140a064b-1ab0-4a92-8bdb-e52dde03d5b8")
- def test_usb_tethering_over_wifi(self):
- """Tests USB tethering over wifi.
+ @test_tracker_info(uuid="d4da7695-4342-4564-b7b0-0a30895f23eb")
+ def test_icmp_connectivity(self):
+ """Tests connectivity under ICMP.
Steps:
- 1. Connects to a wifi network
- 2. Enables USB tethering
- 3. Verifies wifi is preferred upstream over data connection
+ 1. Enable USB tethering on Android devices
+ 2. Generate ICMP packet and send to target IP address
+ 3. Verify that the response contains an ICMP layer
+ """
+ icmp = IP(dst=GOOGLE_DNS_IP_ADDRESS)/ICMP()
+ resp = sr1(icmp, timeout=2, iface=self.iface)
+ asserts.assert_true(
+ resp and resp.haslayer(ICMP),
+ "Failed to send ICMP: " + resp.show(dump=True) if resp else "null")
+
+ @test_tracker_info(uuid="0dc7d049-11bf-42f9-918a-263f4470a7e8")
+ def test_icmpv6_connectivity(self):
+ """Tests connectivity under ICMPv6.
+
+ Steps:
+ 1. Enable USB tethering on Android devices
+ 2. Generate ICMPv6 echo request packet and send to target URL
+ 3. Verify that the response contains an IPv6 layer
+ """
+ icmpv6 = IPv6(dst=DEFAULT_DOMAIN_NAME_IPV6)/ICMPv6EchoRequest()
+ resp = sr1(icmpv6, timeout=2, iface=self.iface)
+ asserts.assert_true(
+ resp and resp.haslayer(IPv6),
+ "Failed to send ICMPv6: " + resp.show(dump=True) if resp else "null")
+
+ @test_tracker_info(uuid="34aaffb8-8dd4-4a1f-a158-2732b8df5e59")
+ def test_dns_query_connectivity(self):
+ """Tests connectivity of DNS query.
+
+ Steps:
+ 1. Enable USB tethering on Android devices
+ 2. Generate DNS query and send to target DNS server
+ 3. Verify that the response contains a DNS layer
+ """
+ dnsqr = IP(dst=GOOGLE_DNS_IP_ADDRESS) \
+ /UDP(sport=RandShort(), dport=53) \
+ /DNS(rd=1, qd=DNSQR(qname=DEFAULT_DOMAIN_NAME))
+ resp = sr1(dnsqr, timeout=2, iface=self.iface)
+ asserts.assert_true(
+ resp and resp.haslayer(DNS),
+ "Failed to send DNS query: " + resp.show(dump=True) if resp else "null")
+
+ @test_tracker_info(uuid="b9bed0fa-3178-4456-92e0-736b3a8cc181")
+ def test_tcp_connectivity(self):
+ """Tests connectivity under TCP.
+
+ Steps:
+ 1. Enable USB tethering on Android devices
+ 2. Generate TCP packet and send to target URL
+ 3. Verify that the response contains a TCP layer
+ """
+ tcp = IP(dst=DEFAULT_DOMAIN_NAME)/TCP(dport=[80, 443])
+ resp = sr1(tcp, timeout=2, iface=self.iface)
+ asserts.assert_true(
+ resp and resp.haslayer(TCP),
+ "Failed to send TCP packet:" + resp.show(dump=True) if resp else "null")
+
+ @test_tracker_info(uuid="5e2f31f4-0b18-44be-a1ba-d82bf9050996")
+ def test_tcp_ipv6_connectivity(self):
+ """Tests connectivity under IPv6.
+
+ Steps:
+ 1. Enable USB tethering on Android devices
+ 2. Generate IPv6 packet and send to target URL (e.g., ipv6.google.com)
+ 3. Verify that the response contains an IPv6 layer
+ """
+ tcp_ipv6 = IPv6(dst=DEFAULT_DOMAIN_NAME_IPV6)/TCP(dport=[80, 443])
+ resp = sr1(tcp_ipv6, timeout=2, iface=self.iface)
+ asserts.assert_true(
+ resp and resp.haslayer(IPv6),
+ "Failed to send TCP packet over IPv6, resp: " +
+ resp.show(dump=True) if resp else "null")
+
+ @test_tracker_info(uuid="96115afb-e0d3-40a8-8f04-b64cedc6588f")
+ def test_http_connectivity(self):
+ """Tests connectivity under HTTP.
+
+ Steps:
+ 1. Enable USB tethering on Android devices
+ 2. Implement TCP 3-way handshake to simulate HTTP GET
+ 3. Verify that the 3-way handshake works and response contains a TCP layer
+ """
+ syn_ack = sr1(IP(dst=DEFAULT_DOMAIN_NAME)
+ / TCP(dport=80, flags="S"), timeout=2, iface=self.iface)
+ get_str = "GET / HTTP/1.1\r\nHost: " + DEFAULT_DOMAIN_NAME + "\r\n\r\n"
+ req = IP(dst=DEFAULT_DOMAIN_NAME)/TCP(dport=80, sport=syn_ack[TCP].dport,
+ seq=syn_ack[TCP].ack, ack=syn_ack[TCP].seq + 1, flags="A")/get_str
+ resp = sr1(req, timeout=2, iface=self.iface)
+ asserts.assert_true(
+ resp and resp.haslayer(TCP),
+ "Failed to send HTTP request, resp: " +
+ resp.show(dump=True) if resp else "null")
+
+ @test_tracker_info(uuid="140a064b-1ab0-4a92-8bdb-e52dde03d5b8")
+ def test_usb_tethering_over_wifi(self):
+ """Tests connectivity over Wi-Fi.
+
+ Steps:
+ 1. Connects to a Wi-Fi network
+ 2. Enable USB tethering
+ 3. Verifies Wi-Fi is preferred upstream over data connection
"""
wutils.start_wifi_connection_scan_and_ensure_network_found(
@@ -47,10 +167,7 @@
wifi_network = self.dut.droid.connectivityGetActiveNetwork()
self.log.info("wifi network %s" % wifi_network)
- iflist_before = get_if_list()
- nutils.start_usb_tethering(self.dut)
self.USB_TETHERED = True
- self.iface = nutils.wait_for_new_iface(iflist_before)
self.real_hwaddr = get_if_raw_hwaddr(self.iface)
output = self.dut.adb.shell(DUMSYS_CMD)
@@ -63,3 +180,17 @@
"interface")
self.log.info("WiFi is the upstream interface")
+ def check_upstream_ready(self, retry=3):
+ """Check the upstream is activated
+
+ Check the upstream is activated with retry
+ """
+ for i in range(0, retry):
+ output = self.dut.adb.shell(DUMSYS_CMD)
+ for line in output.split("\n"):
+ if UPSTREAM_WANTED_STRING in line:
+ if "true" in line:
+ self.log.info("Upstream interface is active")
+ elif i == retry:
+ return False
+ return True
diff --git a/acts_tests/tests/google/net/scapy-2.2.0.tar.gz b/acts_tests/tests/google/net/scapy-2.2.0.tar.gz
deleted file mode 100644
index 47ac039..0000000
--- a/acts_tests/tests/google/net/scapy-2.2.0.tar.gz
+++ /dev/null
Binary files differ
diff --git a/acts_tests/tests/google/nr/cbr/CellBroadcastInitializationTest.py b/acts_tests/tests/google/nr/cbr/CellBroadcastInitializationTest.py
new file mode 100644
index 0000000..ed3ea6a
--- /dev/null
+++ b/acts_tests/tests/google/nr/cbr/CellBroadcastInitializationTest.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2022 - 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 CellBroadcast initialization Test
+"""
+
+import time
+import os
+
+
+from acts.logger import epoch_to_log_line_timestamp
+from acts.keys import Config
+from acts.base_test import BaseTestClass
+from acts.test_decorators import test_tracker_info
+from acts.utils import load_config
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
+from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
+
+
+class CellBroadcastInitializationTest(BaseTestClass):
+ def setup_test(self):
+ super().setup_class()
+ self.number_of_devices = 1
+ self.cbr_init_iteration = self.user_params.get("cbr_init_iteration", 50)
+
+ def teardown_class(self):
+ super().teardown_class(self)
+
+ def _get_current_time_in_secs(self, ad):
+ try:
+ c_time = get_device_epoch_time(ad)
+ c_time = epoch_to_log_line_timestamp(c_time).split()[1].split('.')[0]
+ return self._convert_formatted_time_to_secs(c_time)
+ except Exception as e:
+ ad.log.error(e)
+
+ def _convert_formatted_time_to_secs(self, formatted_time):
+ try:
+ time_list = formatted_time.split(":")
+ return int(time_list[0]) * 3600 + int(time_list[1]) * 60 + int(time_list[2])
+ except Exception as e:
+ self.log.error(e)
+
+ def _verify_channel_config_4400(self, ad):
+ #TODO add all channel checks as constants in tel_defines
+ channel_4400__log = 'SmsBroadcastConfigInfo: Id \\[4400'
+ return ad.search_logcat(channel_4400__log)
+
+ @test_tracker_info(uuid="30f30fa4-f57a-40bd-a37a-141a8efb5a04")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_reboot_stress(self):
+ """ Verifies channel 4400 is set correctly after device boot up
+ only applicable to US carriers
+ after every boot up, search logcat to verify channel 4400 is set
+ default iterations is 50
+ config param : cbr_init_iteration
+
+ """
+ ad = self.android_devices[0]
+
+ current_cbr_version = ad.get_apk_version('com.google.android.cellbroadcast')
+ ad.log.info("Current cbr apk version is %s.", current_cbr_version)
+
+ failure_count = 0
+ begin_time = self._get_current_time_in_secs(ad)
+ for iteration in range(1, self.cbr_init_iteration + 1):
+ msg = "Stress CBR reboot initialization test Iteration: <%s>/<%s>" % (iteration, self.cbr_init_iteration)
+ self.log.info(msg)
+ ad.reboot()
+ ad.wait_for_boot_completion()
+ self.log.info("Rebooted")
+ #TODO make sleep time a constant in tel_defines WAIT_TIME_CBR_INIT_AFTER_REBOOT
+ time.sleep(40)
+ if not self._verify_channel_config_4400(ad):
+ failure_count += 1
+ self.log.error('Iteration failed at %d ' % iteration)
+ end_time = self._get_current_time_in_secs(ad)
+ self.log.debug('Test completed from %s to %s' % (begin_time, end_time))
+ result = True
+ if failure_count > 0:
+ result = False
+ self.log.error('CBR reboot init stress test: <%s> failures in %s iterations',
+ failure_count, self.cbr_init_iteration)
+ return result
+
diff --git a/acts_tests/tests/google/nr/cbr/CellBroadcastTest.py b/acts_tests/tests/google/nr/cbr/CellBroadcastTest.py
index d5264ca..4086f2a 100644
--- a/acts_tests/tests/google/nr/cbr/CellBroadcastTest.py
+++ b/acts_tests/tests/google/nr/cbr/CellBroadcastTest.py
@@ -19,24 +19,39 @@
import xml.etree.ElementTree as ET
import time
+import random
+import os
from acts import signals
+from acts.logger import epoch_to_log_line_timestamp
+from acts.keys import Config
from acts.test_decorators import test_tracker_info
from acts.utils import load_config
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import CARRIER_TEST_CONF_XML_PATH
+from acts_contrib.test_utils.tel.tel_defines import CARRIER_TEST_CONF_XML_PATH, GERMANY_TELEKOM, QATAR_VODAFONE
+from acts_contrib.test_utils.tel.tel_defines import CLEAR_NOTIFICATION_BAR
+from acts_contrib.test_utils.tel.tel_defines import DEFAULT_ALERT_TYPE
+from acts_contrib.test_utils.tel.tel_defines import EXPAND_NOTIFICATION_BAR
+from acts_contrib.test_utils.tel.tel_defines import COLLAPSE_NOTIFICATION_BAR
from acts_contrib.test_utils.tel.tel_defines import UAE
from acts_contrib.test_utils.tel.tel_defines import JAPAN_KDDI
from acts_contrib.test_utils.tel.tel_defines import NEWZEALAND
from acts_contrib.test_utils.tel.tel_defines import HONGKONG
-from acts_contrib.test_utils.tel.tel_defines import CHILE
-from acts_contrib.test_utils.tel.tel_defines import PERU
+from acts_contrib.test_utils.tel.tel_defines import CHILE_ENTEL
+from acts_contrib.test_utils.tel.tel_defines import CHILE_TELEFONICA
+from acts_contrib.test_utils.tel.tel_defines import MEXICO_TELEFONICA
+from acts_contrib.test_utils.tel.tel_defines import ELSALVADOR_TELEFONICA
+from acts_contrib.test_utils.tel.tel_defines import PERU_TELEFONICA
+from acts_contrib.test_utils.tel.tel_defines import PERU_ENTEL
from acts_contrib.test_utils.tel.tel_defines import KOREA
from acts_contrib.test_utils.tel.tel_defines import TAIWAN
from acts_contrib.test_utils.tel.tel_defines import CANADA
+from acts_contrib.test_utils.tel.tel_defines import AUSTRALIA
from acts_contrib.test_utils.tel.tel_defines import BRAZIL
from acts_contrib.test_utils.tel.tel_defines import COLUMBIA
-from acts_contrib.test_utils.tel.tel_defines import EQUADOR
+from acts_contrib.test_utils.tel.tel_defines import ECUADOR_TELEFONICA
+from acts_contrib.test_utils.tel.tel_defines import ECUADOR_CLARO
+from acts_contrib.test_utils.tel.tel_defines import FRANCE
from acts_contrib.test_utils.tel.tel_defines import PUERTORICO
from acts_contrib.test_utils.tel.tel_defines import NETHERLANDS
from acts_contrib.test_utils.tel.tel_defines import ROMANIA
@@ -47,12 +62,16 @@
from acts_contrib.test_utils.tel.tel_defines import ITALY
from acts_contrib.test_utils.tel.tel_defines import SOUTHAFRICA
from acts_contrib.test_utils.tel.tel_defines import UK
+from acts_contrib.test_utils.tel.tel_defines import US_VZW
+from acts_contrib.test_utils.tel.tel_defines import US_ATT
+from acts_contrib.test_utils.tel.tel_defines import US_TMO
from acts_contrib.test_utils.tel.tel_defines import ISRAEL
from acts_contrib.test_utils.tel.tel_defines import OMAN
from acts_contrib.test_utils.tel.tel_defines import JAPAN_SOFTBANK
from acts_contrib.test_utils.tel.tel_defines import SAUDIARABIA
from acts_contrib.test_utils.tel.tel_defines import MAIN_ACTIVITY
from acts_contrib.test_utils.tel.tel_defines import CBR_PACKAGE
+from acts_contrib.test_utils.tel.tel_defines import SYSUI_PACKAGE
from acts_contrib.test_utils.tel.tel_defines import CBR_ACTIVITY
from acts_contrib.test_utils.tel.tel_defines import CBR_TEST_APK
from acts_contrib.test_utils.tel.tel_defines import MCC_MNC
@@ -61,19 +80,94 @@
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_ALERTS_TO_POPULATE
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_UI
from acts_contrib.test_utils.tel.tel_defines import SCROLL_DOWN
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_ALERT_TO_RECEIVE
+from acts_contrib.test_utils.tel.tel_defines import EXIT_ALERT_LIST
+from acts_contrib.test_utils.tel.tel_defines import CMD_DND_OFF
+from acts_contrib.test_utils.tel.tel_defines import DUMPSYS_VIBRATION
+from acts_contrib.test_utils.tel.tel_defines import DEFAULT_SOUND_TIME
+from acts_contrib.test_utils.tel.tel_defines import DEFAULT_VIBRATION_TIME
+from acts_contrib.test_utils.tel.tel_defines import DEFAULT_OFFSET
+from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_DATA_SUB_CHANGE
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
+from acts_contrib.test_utils.tel.tel_defines import GEN_5G
+from acts_contrib.test_utils.tel.tel_defines import GEN_4G
+from acts_contrib.test_utils.tel.tel_defines import GEN_3G
+from acts_contrib.test_utils.tel.tel_logging_utils import log_screen_shot
+from acts_contrib.test_utils.tel.tel_logging_utils import get_screen_shot_log
from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
-from acts_contrib.test_utils.tel.tel_test_utils import log_screen_shot
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_log
+from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_data_connection
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
from acts_contrib.test_utils.net import ui_utils as uutils
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_data_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from test_utils.tel.tel_ims_utils import set_wfc_mode_for_subscription
+from test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
class CellBroadcastTest(TelephonyBaseTest):
def setup_class(self):
super().setup_class()
- self.region_plmn_list_conf = self.user_params.get("region_plmn_list")
- self.emergency_alert_settings_conf = self.user_params.get("emergency_alert_settings")
- self.region_plmn_dict = load_config(self.region_plmn_list_conf)
- self.emergency_alert_settings_dict = load_config(self.emergency_alert_settings_conf)
+ req_param = ["region_plmn_list", "emergency_alert_settings", "emergency_alert_channels", "carrier_test_conf"]
+ self.unpack_userparams(req_param_names=req_param)
+ if hasattr(self, "region_plmn_list"):
+ if isinstance(self.region_plmn_list, list):
+ self.region_plmn_list = self.region_plmn_list[0]
+ if not os.path.isfile(self.region_plmn_list):
+ self.region_plmn_list = os.path.join(
+ self.user_params[Config.key_config_path.value],
+ self.region_plmn_list)
+ if hasattr(self, "emergency_alert_settings"):
+ if isinstance(self.emergency_alert_settings, list):
+ self.emergency_alert_settings = self.emergency_alert_settings[0]
+ if not os.path.isfile(self.emergency_alert_settings):
+ self.emergency_alert_settings = os.path.join(
+ self.user_params[Config.key_config_path.value],
+ self.emergency_alert_settings)
+ if hasattr(self, "emergency_alert_channels"):
+ if isinstance(self.emergency_alert_channels, list):
+ self.emergency_alert_channels = self.emergency_alert_channels[0]
+ if not os.path.isfile(self.emergency_alert_channels):
+ self.emergency_alert_channels = os.path.join(
+ self.user_params[Config.key_config_path.value],
+ self.emergency_alert_channels)
+
+ subInfo = self.android_devices[0].droid.subscriptionGetAllSubInfoList()
+ self.slot_sub_id_list = {}
+ for info in subInfo:
+ if info["simSlotIndex"] >= 0:
+ self.slot_sub_id_list[info["subscriptionId"]] = info["simSlotIndex"]
+ if len(subInfo) > 1:
+ self.android_devices[0].log.info("device is operated at DSDS!")
+ else:
+ self.android_devices[0].log.info("device is operated at single SIM!")
+ self.current_sub_id = self.android_devices[0].droid.subscriptionGetDefaultVoiceSubId()
+
+ self.android_devices[0].log.info("Active slot: %d, active voice subscription id: %d",
+ self.slot_sub_id_list[self.current_sub_id], self.current_sub_id)
+
+ if hasattr(self, "carrier_test_conf"):
+ if isinstance(self.carrier_test_conf, list):
+ self.carrier_test_conf = self.carrier_test_conf[self.slot_sub_id_list[self.current_sub_id]]
+ if not os.path.isfile(self.carrier_test_conf):
+ self.carrier_test_conf = os.path.join(
+ self.user_params[Config.key_config_path.value],
+ self.carrier_test_conf)
+ self.verify_vibration = self.user_params.get("verify_vibration", True)
+ self._disable_vibration_check_for_11()
+ self.verify_sound = self.user_params.get("verify_sound", True)
+ self.region_plmn_dict = load_config(self.region_plmn_list)
+ self.emergency_alert_settings_dict = load_config(self.emergency_alert_settings)
+ self.emergency_alert_channels_dict = load_config(self.emergency_alert_channels)
self._verify_cbr_test_apk_install(self.android_devices[0])
def setup_test(self):
@@ -94,7 +188,9 @@
def _verify_device_in_specific_region(self, ad, region=None):
mccmnc = self.region_plmn_dict[region][MCC_MNC]
- current_plmn = ad.adb.getprop(PLMN_ADB_PROPERTY)
+ plmns = ad.adb.getprop(PLMN_ADB_PROPERTY)
+ plmn_list = plmns.split(",")
+ current_plmn = plmn_list[self.slot_sub_id_list[self.current_sub_id]]
if current_plmn == mccmnc:
ad.log.info("device in %s region", region.upper())
return True
@@ -102,18 +198,35 @@
ad.log.info("device not in %s region", region.upper())
return False
+ def _disable_vibration_check_for_11(self):
+ if self.android_devices[0].adb.getprop("ro.build.version.release") in ("11", "R"):
+ self.verify_vibration = False
def _get_toggle_value(self, ad, alert_text=None):
- node = uutils.wait_and_get_xml_node(ad, timeout=30, text=alert_text)
+ if alert_text == "Alerts":
+ node = uutils.wait_and_get_xml_node(ad, timeout=30, matching_node=2, text=alert_text)
+ else:
+ node = uutils.wait_and_get_xml_node(ad, timeout=30, text=alert_text)
return node.parentNode.nextSibling.firstChild.attributes['checked'].value
+ def _wait_and_click(self, ad, alert_text=None):
+ if alert_text == "Alerts":
+ uutils.wait_and_click(ad, text=alert_text, matching_node=2)
+ else:
+ uutils.wait_and_click(ad, text=alert_text)
+
+ def _has_element(self, ad, alert_text=None):
+ if alert_text == "Alerts":
+ return uutils.has_element(ad, text=alert_text, matching_node=2)
+ else:
+ return uutils.has_element(ad, text=alert_text)
def _open_wea_settings_page(self, ad):
ad.adb.shell("am start -a %s -n %s/%s" % (MAIN_ACTIVITY, CBR_PACKAGE, CBR_ACTIVITY))
def _close_wea_settings_page(self, ad):
- pid = ad.adb.shell("pidof %s" % CBR_PACKAGE)
+ pid = ad.adb.shell("pidof %s" % CBR_PACKAGE, ignore_status=True)
ad.adb.shell("kill -9 %s" % pid, ignore_status=True)
@@ -130,15 +243,15 @@
region.upper(), mccmnc, imsi)
# update carrier xml file
- carrier_test_conf = self.user_params.get("carrier_test_conf")
- tree = ET.parse(carrier_test_conf)
+ tree = ET.parse(self.carrier_test_conf)
root = tree.getroot()
root[1].attrib['value'] = mccmnc
root[2].attrib['value'] = imsi
- tree.write(carrier_test_conf)
+ tree.write(self.carrier_test_conf)
# push carrier xml to device
- ad.adb.push("%s %s" % (carrier_test_conf, CARRIER_TEST_CONF_XML_PATH))
+ ad.log.info("push %s to %s" % (self.carrier_test_conf, CARRIER_TEST_CONF_XML_PATH))
+ ad.adb.push("%s %s" % (self.carrier_test_conf, CARRIER_TEST_CONF_XML_PATH))
# reboot device
reboot_device(ad)
@@ -157,10 +270,10 @@
alert_value = value["default_value"]
self._open_wea_settings_page(ad)
# scroll till bottom
- if not uutils.has_element(ad, text=alert_text):
+ if not self._has_element(ad, alert_text):
for _ in range(3):
ad.adb.shell(SCROLL_DOWN)
- if not uutils.has_element(ad, text=alert_text):
+ if not self._has_element(ad, alert_text):
ad.log.error("UI - %s missing", alert_text)
result = False
continue
@@ -182,26 +295,26 @@
alert_toggle = value["toggle_avail"]
if alert_toggle == "true":
self._open_wea_settings_page(ad)
- if not uutils.has_element(ad, text=alert_text):
+ if not self._has_element(ad, alert_text):
for _ in range(3):
ad.adb.shell(SCROLL_DOWN)
- if not uutils.has_element(ad, text=alert_text):
+ if not self._has_element(ad, alert_text):
ad.log.error("UI - %s missing", alert_text)
result = False
continue
before_toggle = self._get_toggle_value(ad, alert_text)
- uutils.wait_and_click(ad, text=alert_text)
+ self._wait_and_click(ad, alert_text)
after_toggle = self._get_toggle_value(ad, alert_text)
if before_toggle == after_toggle:
for _ in range(3):
ad.adb.shell(SCROLL_DOWN)
- uutils.wait_and_click(ad, text=alert_text)
+ self._wait_and_click(ad, alert_text)
after_toggle = self._get_toggle_value(ad, alert_text)
if before_toggle == after_toggle:
ad.log.error("UI - fail to toggle %s", alert_text)
result = False
else:
- uutils.wait_and_click(ad, text=alert_text)
+ self._wait_and_click(ad, alert_text)
reset_toggle = self._get_toggle_value(ad, alert_text)
if reset_toggle != before_toggle:
ad.log.error("UI - fail to reset toggle %s", alert_text)
@@ -211,6 +324,232 @@
return result
+ def _convert_formatted_time_to_secs(self, formatted_time):
+ try:
+ time_list = formatted_time.split(":")
+ return int(time_list[0]) * 3600 + int(time_list[1]) * 60 + int(time_list[2])
+ except Exception as e:
+ self.log.error(e)
+
+
+ def _get_current_time_in_secs(self, ad):
+ try:
+ c_time = get_device_epoch_time(ad)
+ c_time = epoch_to_log_line_timestamp(c_time).split()[1].split('.')[0]
+ return self._convert_formatted_time_to_secs(c_time)
+ except Exception as e:
+ ad.log.error(e)
+
+
+ def _verify_flashlight(self, ad):
+ count = 0
+ while(count < 10):
+ status = ad.adb.shell("settings get secure flashlight_available")
+ if status == "1":
+ ad.log.info("LED lights OK")
+ return True
+ ad.log.error("LED lights not OK")
+ return False
+
+
+
+ def _verify_vibration(self, ad, begintime, expectedtime, offset):
+ if not self.verify_vibration:
+ return True
+ out = ad.adb.shell(DUMPSYS_VIBRATION)
+ if out:
+ try:
+ starttime = out.split()[2].split('.')[0]
+ endtime = out.split()[5].split('.')[0]
+ starttime = self._convert_formatted_time_to_secs(starttime)
+ endtime = self._convert_formatted_time_to_secs(endtime)
+ vibration_time = endtime - starttime
+ if (starttime < begintime):
+ ad.log.error("vibration: actualtime:%s logtime:%s Not OK", begintime, starttime)
+ return False
+ if not vibration_time in range(expectedtime - offset, expectedtime + offset + 1):
+ ad.log.error("vibration: %d secs Not OK", vibration_time)
+ return False
+ ad.log.info("vibration: %d secs OK", vibration_time)
+ return True
+ except Exception as e:
+ ad.log.error("vibration parsing is broken %s", e)
+ return False
+ return False
+
+
+ def _verify_sound(self, ad, begintime, expectedtime, offset, calling_package=CBR_PACKAGE):
+ if not self.verify_sound:
+ return True
+ cbr_pid = ad.adb.shell("pidof %s" % calling_package)
+ DUMPSYS_START_AUDIO = "dumpsys audio | grep %s | grep requestAudioFocus | tail -1" % cbr_pid
+ DUMPSYS_END_AUDIO = "dumpsys audio | grep %s | grep abandonAudioFocus | tail -1" % cbr_pid
+ start_audio = ad.adb.shell(DUMPSYS_START_AUDIO)
+ end_audio = ad.adb.shell(DUMPSYS_END_AUDIO)
+ if start_audio and end_audio:
+ try:
+ starttime = start_audio.split()[1]
+ endtime = end_audio.split()[1]
+ starttime = self._convert_formatted_time_to_secs(starttime)
+ endtime = self._convert_formatted_time_to_secs(endtime)
+ sound_time = endtime - starttime
+ if (starttime < begintime):
+ ad.log.error("sound: actualtime:%s logtime:%s Not OK", begintime, starttime)
+ return False
+ if not sound_time in range(expectedtime - offset, expectedtime + offset + 1):
+ ad.log.error("sound: %d secs Not OK", sound_time)
+ return False
+ ad.log.info("sound: %d secs OK", sound_time)
+ return True
+ except Exception as e:
+ ad.log.error("sound parsing is broken %s", e)
+ return False
+ return False
+
+
+ def _exit_alert_pop_up(self, ad):
+ for text in EXIT_ALERT_LIST:
+ try:
+ uutils.wait_and_click(ad, text_contains=text, timeout=1)
+ except Exception:
+ continue
+
+
+ def _verify_text_present_on_ui(self, ad, alert_text):
+ if uutils.has_element(ad, text=alert_text, timeout=5):
+ return True
+ elif uutils.has_element(ad, text_contains=alert_text, timeout=5):
+ return True
+ else:
+ return False
+
+
+ def _log_and_screenshot_alert_fail(self, ad, state, region, channel):
+ ad.log.error("Fail for alert: %s for %s: %s", state, region, channel)
+ log_screen_shot(ad, "alert_%s_for_%s_%s" % (state, region, channel))
+
+
+ def _show_statusbar_notifications(self, ad):
+ ad.adb.shell(EXPAND_NOTIFICATION_BAR)
+
+
+ def _hide_statusbar_notifications(self, ad):
+ ad.adb.shell(COLLAPSE_NOTIFICATION_BAR)
+
+
+ def _clear_statusbar_notifications(self, ad):
+ ad.adb.shell(CLEAR_NOTIFICATION_BAR)
+
+
+ def _popup_alert_in_statusbar_notifications(self, ad, alert_text):
+ alert_in_notification = False
+ # Open status bar notifications.
+ self._show_statusbar_notifications(ad)
+ # Wait for status bar notifications showing.
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ if self._verify_text_present_on_ui(ad, alert_text):
+ # Found alert in notifications, display it.
+ uutils.wait_and_click(ad, text=alert_text)
+ alert_in_notification = True
+ else:
+ # Close status bar notifications
+ self._hide_statusbar_notifications(ad)
+ return alert_in_notification
+
+
+ def _verify_send_receive_wea_alerts(self, ad, region=None, call=False, call_direction=DIRECTION_MOBILE_ORIGINATED):
+ result = True
+ # Always clear notifications in the status bar before testing to find alert notification easily.
+ self._clear_statusbar_notifications(ad)
+ for key, value in self.emergency_alert_channels_dict[region].items():
+
+ if call:
+ if not self._setup_voice_call(self.log,
+ self.android_devices,
+ call_direction=call_direction):
+ self.log("Fail to set up voice call!")
+ return False
+
+ # Configs
+ iteration_result = True
+ channel = int(key)
+ alert_text = value["title"]
+ alert_expected = value["default_value"]
+ wait_for_alert = value.get("alert_time", WAIT_TIME_FOR_ALERT_TO_RECEIVE)
+ vibration_time = value.get("vibration_time", DEFAULT_VIBRATION_TIME)
+ sound_time = value.get("sound_time", DEFAULT_SOUND_TIME)
+ offset = value.get("offset", DEFAULT_OFFSET)
+ alert_type = value.get("alert_type", DEFAULT_ALERT_TYPE)
+
+ # Begin Iteration
+ begintime = self._get_current_time_in_secs(ad)
+ sequence_num = random.randrange(10000, 40000)
+ ad.log.info("Iteration: %s for %s: %s", alert_text, region, channel)
+
+ # Send Alert
+ ad.droid.cbrSendTestAlert(sequence_num, channel)
+ if region == NEWZEALAND:
+ if not self._verify_flashlight(ad):
+ iteration_result = False
+
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ if call:
+ hangup_call(self.log, ad)
+
+ time.sleep(wait_for_alert)
+
+ # Receive Alert
+ if not self._verify_text_present_on_ui(ad, alert_text):
+ alert_in_notification = False
+ # Check if alert message is expected to be in the notification drawer
+ if alert_expected == "true" and alert_type == "notification":
+ # Verify expected notification in notification drawer and open the message
+ if self._popup_alert_in_statusbar_notifications(ad, alert_text):
+ ad.log.info("Found alert channel %d in status bar notifications, pop it up.", channel)
+ # Verify alert text in message.
+ alert_in_notification = self._verify_text_present_on_ui(ad, alert_text)
+ if alert_in_notification:
+ # Verify vibration and notification sound.
+ # We check sound generated by com.android.systemui package.
+ # For the reason of offset + 1, refer to b/199565843
+ # TODO: The notification sound is initiated by system
+ # rather than CellBroadcastReceiver. In case there are
+ # any non-emergency notifications coming during testing, we
+ # should consider to validate notification id instead of
+ # com.android.systemui package. b/199565843
+ if not (self._verify_vibration(ad, begintime, vibration_time, offset) and
+ self._verify_sound(ad, begintime, sound_time, offset+1, SYSUI_PACKAGE)):
+ iteration_result = False
+ if alert_expected == "true" and not alert_in_notification:
+ iteration_result = False
+ self._log_and_screenshot_alert_fail(ad, "missing", region, channel)
+ else:
+ if alert_expected == "true":
+ ad.log.info("Alert received OK")
+ self._exit_alert_pop_up(ad)
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+
+ # Vibration and Sound
+ if not self._verify_text_present_on_ui(ad, alert_text):
+ ad.log.info("Alert exited OK")
+ if not (self._verify_vibration(ad, begintime, vibration_time, offset) and
+ self._verify_sound(ad, begintime, sound_time, offset)):
+ iteration_result = False
+ else:
+ iteration_result = False
+ self._log_and_screenshot_alert_fail(ad, "present", region, channel)
+ else:
+ iteration_result = False
+ self._log_and_screenshot_alert_fail(ad, "present", region, channel)
+ if iteration_result:
+ ad.log.info("Success alert: %s for %s: %s", alert_text, region, channel)
+ else:
+ ad.log.error("Failure alert: %s for %s: %s", alert_text, region, channel)
+ result = iteration_result
+ self._exit_alert_pop_up(ad)
+ return result
+
+
def _settings_test_flow(self, region):
ad = self.android_devices[0]
result = True
@@ -218,16 +557,89 @@
time.sleep(WAIT_TIME_FOR_UI)
if not self._verify_wea_default_settings(ad, region):
result = False
- log_screen_shot(ad, "default_settings_for_%s" % region)
+ log_screen_shot(ad, "default_settings_%s" % region)
self._close_wea_settings_page(ad)
+ # Here close wea setting UI and then immediately open the UI that sometimes causes
+ # failing to open the wea setting UI. So we just delay 1 sec after closing
+ # the wea setting UI.
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
if not self._verify_wea_toggle_settings(ad, region):
- log_screen_shot(ad, "toggle_settings_for_%s" % region)
+ log_screen_shot(ad, "toggle_settings_%s" % region)
result = False
get_screen_shot_log(ad)
self._close_wea_settings_page(ad)
return result
+ def _send_receive_test_flow(self, region):
+ ad = self.android_devices[0]
+ result = True
+ self._set_device_to_specific_region(ad, region)
+ time.sleep(WAIT_TIME_FOR_UI)
+ ad.log.info("disable DND: %s", CMD_DND_OFF)
+ ad.adb.shell(CMD_DND_OFF)
+ if not self._verify_send_receive_wea_alerts(ad, region):
+ result = False
+ get_screen_shot_log(ad)
+ return result
+
+
+ def _setup_receive_test_flow_wifi(self, region, gen, data):
+ """ Setup send/receive WEA with wifi enabled and various RAT."""
+ ad = self.android_devices[0]
+ self._set_device_to_specific_region(ad, region)
+ time.sleep(WAIT_TIME_FOR_UI)
+ ad.log.info("disable DND: %s", CMD_DND_OFF)
+ ad.adb.shell(CMD_DND_OFF)
+ if gen == GEN_5G:
+ if not provision_device_for_5g(self.log, ad):
+ return False
+ else:
+ phone_setup_data_for_subscription(ad.log,
+ ad,
+ get_default_data_sub_id(ad),
+ gen)
+ if data:
+ ad.log.info("Enable data network!")
+ else:
+ ad.log.info("Disable data network!")
+ ad.droid.telephonyToggleDataConnection(data)
+ if not wait_for_data_connection(ad.log, ad, data,
+ MAX_WAIT_TIME_DATA_SUB_CHANGE):
+ if data:
+ ad.log.error("Failed to enable data network!")
+ else:
+ ad.log.error("Failed to disable data network!")
+ return False
+
+ wifi_toggle_state(ad.log, ad, True)
+ if not ensure_wifi_connected(ad.log, ad,
+ self.wifi_network_ssid,
+ self.wifi_network_pass):
+ ad.log.error("WiFi connect fail.")
+ return False
+ return True
+
+ def _setup_voice_call(self, log, ads, call_direction=DIRECTION_MOBILE_ORIGINATED):
+ if call_direction == DIRECTION_MOBILE_ORIGINATED:
+ ad_caller = ads[0]
+ ad_callee = ads[1]
+ else:
+ ad_caller = ads[1]
+ ad_callee = ads[0]
+ return call_setup_teardown(log, ad_caller, ad_callee, wait_time_in_call=0)
+
+ def _setup_wfc_mode(self, ad):
+ if not set_wfc_mode_for_subscription(ad,
+ WFC_MODE_WIFI_ONLY,
+ get_default_data_sub_id(ad)):
+ ad.log.error("Unable to set WFC mode to %s.", WFC_MODE_WIFI_ONLY)
+ return False
+
+ if not wait_for_wfc_enabled(ad.log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
+ ad.log.error("WFC is not enabled")
+ return False
+ return True
""" Tests Begin """
@@ -246,6 +658,36 @@
return self._settings_test_flow(UAE)
+ @test_tracker_info(uuid="ac4639ca-b77e-4200-b3f0-9079e2783f60")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_default_alert_settings_australia(self):
+ """ Verifies Wireless Emergency Alert settings for Australia
+
+ configures the device to Australia
+ verifies alert names and its default values
+ toggles the alert twice if available
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._settings_test_flow(AUSTRALIA)
+
+
+ @test_tracker_info(uuid="d0255023-d9bb-45c5-bede-446d720e619a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_default_alert_settings_france(self):
+ """ Verifies Wireless Emergency Alert settings for France
+
+ configures the device to France
+ verifies alert names and its default values
+ toggles the alert twice if available
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._settings_test_flow(FRANCE)
+
+
@test_tracker_info(uuid="fd461335-21c0-470c-aca7-74c8ebb67711")
@TelephonyBaseTest.tel_test_wrap
def test_default_alert_settings_japan_kddi(self):
@@ -293,32 +735,92 @@
@test_tracker_info(uuid="d9e2dca2-4965-48d5-9d79-352c4ccf9e0f")
@TelephonyBaseTest.tel_test_wrap
- def test_default_alert_settings_chile(self):
- """ Verifies Wireless Emergency Alert settings for Chile
+ def test_default_alert_settings_chile_entel(self):
+ """ Verifies Wireless Emergency Alert settings for Chile_Entel
- configures the device to Chile
+ configures the device to Chile_Entel
verifies alert names and its default values
toggles the alert twice if available
Returns:
True if pass; False if fail and collects screenshot
"""
- return self._settings_test_flow(CHILE)
+ return self._settings_test_flow(CHILE_ENTEL)
+
+
+ @test_tracker_info(uuid="2a045a0e-145c-4677-b454-b0b63a69ea10")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_default_alert_settings_chile_telefonica(self):
+ """ Verifies Wireless Emergency Alert settings for Chile_Telefonica
+
+ configures the device to Chile_Telefonica
+ verifies alert names and its default values
+ toggles the alert twice if available
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._settings_test_flow(CHILE_TELEFONICA)
@test_tracker_info(uuid="77cff297-fe3b-4b4c-b502-5324b4e91506")
@TelephonyBaseTest.tel_test_wrap
- def test_default_alert_settings_peru(self):
- """ Verifies Wireless Emergency Alert settings for Peru
+ def test_default_alert_settings_peru_entel(self):
+ """ Verifies Wireless Emergency Alert settings for Peru_Entel
- configures the device to Peru
+ configures the device to Peru_Entel
verifies alert names and its default values
toggles the alert twice if available
Returns:
True if pass; False if fail and collects screenshot
"""
- return self._settings_test_flow(PERU)
+ return self._settings_test_flow(PERU_ENTEL)
+
+
+ @test_tracker_info(uuid="8b683505-288f-4587-95f2-9a8705476f09")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_default_alert_settings_peru_telefonica(self):
+ """ Verifies Wireless Emergency Alert settings for Peru_Telefonica
+
+ configures the device to Peru_Telefonica
+ verifies alert names and its default values
+ toggles the alert twice if available
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._settings_test_flow(PERU_TELEFONICA)
+
+
+ @test_tracker_info(uuid="cc0e0f64-2c77-4e20-b55e-6f555f7ecb97")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_default_alert_settings_elsalvador_telefonica(self):
+ """ Verifies Wireless Emergency Alert settings for Elsalvador_Telefonica
+
+ configures the device to Elsalvador_Telefonica
+ verifies alert names and its default values
+ toggles the alert twice if available
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._settings_test_flow(ELSALVADOR_TELEFONICA)
+
+
+ @test_tracker_info(uuid="339be9ef-7e0e-463a-ad45-12b7e74bb1c4")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_default_alert_settings_mexico_telefonica(self):
+ """ Verifies Wireless Emergency Alert settings for Mexico_Telefonica
+
+ configures the device to Mexico_Telefonica
+ verifies alert names and its default values
+ toggles the alert twice if available
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._settings_test_flow(MEXICO_TELEFONICA)
@test_tracker_info(uuid="4c3c4e65-c624-4eba-9a81-263f4ee01e12")
@@ -398,17 +900,32 @@
@test_tracker_info(uuid="2ebfc05b-3512-4eff-9c09-5d8f49fe0b5e")
@TelephonyBaseTest.tel_test_wrap
- def test_default_alert_settings_equador(self):
- """ Verifies Wireless Emergency Alert settings for Equador
+ def test_default_alert_settings_ecuador_telefonica(self):
+ """ Verifies Wireless Emergency Alert settings for Ecuador Telefonica
- configures the device to Equador
+ configures the device to Ecuador Telefonica
verifies alert names and its default values
toggles the alert twice if available
Returns:
True if pass; False if fail and collects screenshot
"""
- return self._settings_test_flow(EQUADOR)
+ return self._settings_test_flow(ECUADOR_TELEFONICA)
+
+
+ @test_tracker_info(uuid="694bf8f6-9e6e-46b4-98df-c7ab1a9a3ec8")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_default_alert_settings_ecuador_claro(self):
+ """ Verifies Wireless Emergency Alert settings for Ecuador Claro
+
+ configures the device to Ecuador Claro
+ verifies alert names and its default values
+ toggles the alert twice if available
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._settings_test_flow(ECUADOR_CLARO)
@test_tracker_info(uuid="96628975-a23f-47f7-ab18-1aa7a7dc08b5")
@@ -619,3 +1136,1055 @@
True if pass; False if fail and collects screenshot
"""
return self._settings_test_flow(SAUDIARABIA)
+
+
+ @test_tracker_info(uuid="a5f232c4-e0fa-4ce6-aa00-c838f0d86272")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_default_alert_settings_us_att(self):
+ """ Verifies Wireless Emergency Alert settings for US ATT
+
+ configures the device to US ATT
+ verifies alert names and its default values
+ toggles the alert twice if available
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._settings_test_flow(US_ATT)
+
+
+ @test_tracker_info(uuid="a712c136-8ce9-4bc2-9dda-05ecdd11e8ad")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_default_alert_settings_us_tmo(self):
+ """ Verifies Wireless Emergency Alert settings for US TMO
+
+ configures the device to US TMO
+ verifies alert names and its default values
+ toggles the alert twice if available
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._settings_test_flow(US_TMO)
+
+
+ @test_tracker_info(uuid="20403705-f627-42d7-9dc2-4e820273a622")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_default_alert_settings_us_vzw(self):
+ """ Verifies Wireless Emergency Alert settings for US VZW
+
+ configures the device to US VZW
+ verifies alert names and its default values
+ toggles the alert twice if available
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._settings_test_flow(US_VZW)
+
+
+ @test_tracker_info(uuid="fb4cda9e-7b4c-469e-a480-670bfb9dc6d7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_default_alert_settings_germany_telekom(self):
+ """ Verifies Wireless Emergency Alert settings for Germany telecom
+
+ configures the device to Germany telecom
+ verifies alert names and its default values
+ toggles the alert twice if available
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._settings_test_flow(GERMANY_TELEKOM)
+
+
+ @test_tracker_info(uuid="f4afbef9-c1d7-4fab-ad0f-e03bc961a689")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_default_alert_settings_qatar_vodafone(self):
+ """ Verifies Wireless Emergency Alert settings for Qatar vodafone
+
+ configures the device to Qatar vodafone
+ verifies alert names and its default values
+ toggles the alert twice if available
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._settings_test_flow(QATAR_VODAFONE)
+
+
+ @test_tracker_info(uuid="f3a99475-a23f-427c-a371-d2a46d357d75")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_australia(self):
+ """ Verifies Wireless Emergency Alerts for AUSTRALIA
+
+ configures the device to AUSTRALIA
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(AUSTRALIA)
+
+
+ @test_tracker_info(uuid="73c98624-2935-46ea-bf7c-43c431177ebd")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_brazil(self):
+ """ Verifies Wireless Emergency Alerts for BRAZIL
+
+ configures the device to BRAZIL
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(BRAZIL)
+
+
+ @test_tracker_info(uuid="8c2e16f8-9b7f-4733-a65e-f087d2480e92")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_canada(self):
+ """ Verifies Wireless Emergency Alerts for CANADA
+
+ configures the device to CANADA
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(CANADA)
+
+
+ @test_tracker_info(uuid="feea4e42-99cc-4075-bd78-15b149cb2e4c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_chile_entel(self):
+ """ Verifies Wireless Emergency Alerts for CHILE_ENTEL
+
+ configures the device to CHILE_ENTEL
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(CHILE_ENTEL)
+
+
+ @test_tracker_info(uuid="d2ec84ad-7f9a-4aa2-97e8-ca9ffa6c58a7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_chile_telefonica(self):
+ """ Verifies Wireless Emergency Alerts for CHILE_TELEFONICA
+
+ configures the device to CHILE_TELEFONICA
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(CHILE_TELEFONICA)
+
+
+ @test_tracker_info(uuid="4af30b94-50ea-4e19-8866-31fd3573a059")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_columbia(self):
+ """ Verifies Wireless Emergency Alerts for COLUMBIA
+
+ configures the device to COLUMBIA
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(COLUMBIA)
+
+
+ @test_tracker_info(uuid="2378b651-2097-48e6-b409-885bde9f4586")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_ecuador_telefonica(self):
+ """ Verifies Wireless Emergency Alerts for ECUADOR Telefonica
+
+ configures the device to ECUADOR Telefonica
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(ECUADOR_TELEFONICA)
+
+
+ @test_tracker_info(uuid="cd064259-6cb2-460b-8225-de613f6cf967")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_ecuador_claro(self):
+ """ Verifies Wireless Emergency Alerts for ECUADOR Claro
+
+ configures the device to ECUADOR Claro
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(ECUADOR_CLARO)
+
+
+ @test_tracker_info(uuid="b11d1dd7-2090-463a-ba3a-39703db7f376")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_elsalvador_telefonica(self):
+ """ Verifies Wireless Emergency Alerts for ELSALVADOR telefonica
+
+ configures the device to ELSALVADOR telefonica
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(ELSALVADOR_TELEFONICA)
+
+
+ @test_tracker_info(uuid="46d6c612-21df-476e-a41b-3baa621b52f0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_estonia(self):
+ """ Verifies Wireless Emergency Alerts for ESTONIA
+
+ configures the device to ESTONIA
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(ESTONIA)
+
+
+ @test_tracker_info(uuid="6de32af0-9545-4143-b327-146e4d0af28c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_france(self):
+ """ Verifies Wireless Emergency Alerts for FRANCE
+
+ configures the device to FRANCE
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(FRANCE)
+
+
+ @test_tracker_info(uuid="9c5826db-0457-4c6f-9d06-6973b5f77e3f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_greece(self):
+ """ Verifies Wireless Emergency Alerts for GREECE
+
+ configures the device to GREECE
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(GREECE)
+
+
+ @test_tracker_info(uuid="57dd9a79-6ac2-41c7-b7eb-3afb01f35bd2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_hongkong(self):
+ """ Verifies Wireless Emergency Alerts for Japan HONGKONG
+
+ configures the device to HONGKONG
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(HONGKONG)
+
+
+ @test_tracker_info(uuid="8ffdfaf8-5925-4e66-be22-e1ac25165784")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_israel(self):
+ """ Verifies Wireless Emergency Alerts for ISRAEL
+
+ configures the device to ISRAEL
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(ISRAEL)
+
+
+ @test_tracker_info(uuid="f38e289c-4c7d-48a7-9b21-f7d872e3eb98")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_italy(self):
+ """ Verifies Wireless Emergency Alerts for ITALY
+
+ configures the device to ITALY
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(ITALY)
+
+
+ @test_tracker_info(uuid="d434dbf8-72e8-44a7-ab15-d418133088c6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_japan_kddi(self):
+ """ Verifies Wireless Emergency Alerts for JAPAN_KDDI
+
+ configures the device to JAPAN_KDDI
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(JAPAN_KDDI)
+
+
+ @test_tracker_info(uuid="c597995f-8937-4987-91db-7f83a0f5f4ec")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_japan_softbank(self):
+ """ Verifies Wireless Emergency Alerts for JAPAN_SOFTBANK
+
+ configures the device to JAPAN_SOFTBANK
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(JAPAN_SOFTBANK)
+
+
+ @test_tracker_info(uuid="b159d6b2-b900-4329-9b77-c9ba9e83dddc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_korea(self):
+ """ Verifies Wireless Emergency Alerts for KOREA
+
+ configures the device to KOREA
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(KOREA)
+
+
+ @test_tracker_info(uuid="9b59c594-179a-44d6-9dbf-68adc43aa820")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_latvia(self):
+ """ Verifies Wireless Emergency Alerts for LATVIA
+
+ configures the device to LATVIA
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(LATVIA)
+
+
+ @test_tracker_info(uuid="af7d916b-42f0-4420-8a1c-b39d3f184953")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_lithuania(self):
+ """ Verifies Wireless Emergency Alerts for LITHUANIA
+
+ configures the device to LITHUANIA
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(LITHUANIA)
+
+
+ @test_tracker_info(uuid="061cd0f3-cefa-4e5d-a1aa-f6125ccf9347")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_mexico_telefonica(self):
+ """ Verifies Wireless Emergency Alerts for MEXICO telefonica
+
+ configures the device to MEXICO telefonica
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(MEXICO_TELEFONICA)
+
+
+ @test_tracker_info(uuid="a9c7cdbe-5a9e-49fb-af60-953e8c1547c0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_netherlands(self):
+ """ Verifies Wireless Emergency Alerts for NETHERLANDS
+
+ configures the device to NETHERLANDS
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(NETHERLANDS)
+
+
+ @test_tracker_info(uuid="23db0b77-1a1c-494c-bcc6-1355fb037a6f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_newzealand(self):
+ """ Verifies Wireless Emergency Alerts for NEWZEALAND
+
+ configures the device to NEWZEALAND
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(NEWZEALAND)
+
+
+ @test_tracker_info(uuid="a4216cbb-4ed7-4e72-98e7-2ebebe904956")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_oman(self):
+ """ Verifies Wireless Emergency Alerts for OMAN
+
+ configures the device to OMAN
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(OMAN)
+
+
+ @test_tracker_info(uuid="35f0f156-1555-4bf1-98b1-b5848d8e2d39")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_peru_entel(self):
+ """ Verifies Wireless Emergency Alerts for PERU_ENTEL
+
+ configures the device to PERU_ENTEL
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(PERU_ENTEL)
+
+
+ @test_tracker_info(uuid="4708c783-ca89-498d-b74c-a6bc9df3fb32")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_peru_telefonica(self):
+ """ Verifies Wireless Emergency Alerts for PERU_TELEFONICA
+
+ configures the device to PERU_TELEFONICA
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(PERU_TELEFONICA)
+
+
+ @test_tracker_info(uuid="fefb293a-5c22-45b2-9323-ccb355245c9a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_puertorico(self):
+ """ Verifies Wireless Emergency Alerts for PUERTORICO
+
+ configures the device to PUERTORICO
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(PUERTORICO)
+
+
+ @test_tracker_info(uuid="7df5a2fd-fc20-46a1-8a57-c7690daf97ff")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_romania(self):
+ """ Verifies Wireless Emergency Alerts for ROMANIA
+
+ configures the device to ROMANIA
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(ROMANIA)
+
+
+ @test_tracker_info(uuid="cb1a2e92-eddb-4d8a-8b8d-96a0b8c558dd")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_saudiarabia(self):
+ """ Verifies Wireless Emergency Alerts for SAUDIARABIA
+
+ configures the device to SAUDIARABIA
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(SAUDIARABIA)
+
+
+ @test_tracker_info(uuid="0bf0196a-e456-4fa8-a735-b8d6d014ce7f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_southafrica(self):
+ """ Verifies Wireless Emergency Alerts for SOUTHAFRICA
+
+ configures the device to SOUTHAFRICA
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(SOUTHAFRICA)
+
+
+ @test_tracker_info(uuid="513c7d24-4957-49a4-98a2-f8a9444124ae")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_taiwan(self):
+ """ Verifies Wireless Emergency Alerts for TAIWAN
+
+ configures the device to TAIWAN
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(TAIWAN)
+
+
+ @test_tracker_info(uuid="43d54588-95e2-4e8a-b322-f6c99b9d3fbb")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_uae(self):
+ """ Verifies Wireless Emergency Alerts for UAE
+
+ configures the device to UAE
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(UAE)
+
+
+ @test_tracker_info(uuid="b44425c3-0d5b-498a-8322-86cc03eefd7d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_uk(self):
+ """ Verifies Wireless Emergency Alerts for UK
+
+ configures the device to UK
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(UK)
+
+
+ @test_tracker_info(uuid="b3e73b61-6232-44f0-9507-9954387ab25b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_us_att(self):
+ """ Verifies Wireless Emergency Alerts for US ATT
+
+ configures the device to US ATT
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(US_ATT)
+
+
+ @test_tracker_info(uuid="f993d21d-c240-4196-8015-ea8f5967fdb3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_us_tmo(self):
+ """ Verifies Wireless Emergency Alerts for US TMO
+
+ configures the device to US TMO
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(US_TMO)
+
+
+ @test_tracker_info(uuid="173293f2-4876-4891-ad2c-2b0d5269b2e0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_us_vzw(self):
+ """ Verifies Wireless Emergency Alerts for US Verizon
+
+ configures the device to US Verizon
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(US_VZW)
+
+
+ @test_tracker_info(uuid="b94cc715-d2e2-47a4-91cd-acb47d64e6b2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_germany_telekom(self):
+ """ Verifies Wireless Emergency Alerts for Germany telekom
+
+ configures the device to Germany telekom
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(GERMANY_TELEKOM)
+
+
+ @test_tracker_info(uuid="f0b0cdbf-32c4-4dfd-b8fb-03d8b6169fd1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_qatar_vodafone(self):
+ """ Verifies Wireless Emergency Alerts for Qatar vodafone.
+
+ configures the device to Qatar vodafone
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ return self._send_receive_test_flow(QATAR_VODAFONE)
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_5g_wifi_us_vzw(self):
+ """ Verifies WEA with WiFi and 5G NSA data network enabled for US Verizon.
+
+ configures the device to US Verizon
+ enables WiFi and 5G NSA data network.
+ connects to internet via WiFi.
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ result = True
+ if not self._setup_receive_test_flow_wifi(US_VZW, GEN_5G, True):
+ result = False
+ if result:
+ if not self._verify_send_receive_wea_alerts(self.android_devices[0], US_VZW):
+ result = False
+
+ get_screen_shot_log(self.android_devices[0])
+ return result
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_4g_wifi_us_vzw(self):
+ """ Verifies WEA with WiFi and 4G data network enabled for US Verizon.
+
+ configures the device to US Verizon
+ enables WiFi and 4G data network.
+ connects to internet via WiFi.
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ result = True
+ if not self._setup_receive_test_flow_wifi(US_VZW, GEN_4G, True):
+ result = False
+ if result:
+ if not self._verify_send_receive_wea_alerts(self.android_devices[0], US_VZW):
+ result = False
+
+ get_screen_shot_log(self.android_devices[0])
+ return result
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_3g_wifi_us_vzw(self):
+ """ Verifies WEA with WiFi and 3G data network enabled for US Verizon.
+
+ configures the device to US Verizon
+ enables WiFi and 3G data network.
+ connects to internet via WiFi.
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ result = True
+ if not self._setup_receive_test_flow_wifi(US_VZW, GEN_3G, True):
+ result = False
+ if result:
+ if not self._verify_send_receive_wea_alerts(self.android_devices[0], US_VZW):
+ result = False
+
+ get_screen_shot_log(self.android_devices[0])
+ return result
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_5g_wifi_only_us_vzw(self):
+ """ Verifies WEA with WiFi enabled and 5G NSA data network disabled for US Verizon.
+
+ configures the device to US Verizon
+ enables WiFi and disable 5G NSA data network.
+ connects to internet via WiFi.
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ result = True
+ if not self._setup_receive_test_flow_wifi(US_VZW, GEN_5G, False):
+ result = False
+ if result:
+ if not self._verify_send_receive_wea_alerts(self.android_devices[0], US_VZW):
+ result = False
+
+ get_screen_shot_log(self.android_devices[0])
+ return result
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_4g_wifi_only_us_vzw(self):
+ """ Verifies WEA with WiFi enabled and 4G data network disabled for US Verizon.
+
+ configures the device to US Verizon
+ enables WiFi and disable 4G data network.
+ connects to internet via WiFi.
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ result = True
+ if not self._setup_receive_test_flow_wifi(US_VZW, GEN_4G, False):
+ result = False
+ if result:
+ if not self._verify_send_receive_wea_alerts(self.android_devices[0], US_VZW):
+ result = False
+
+ get_screen_shot_log(self.android_devices[0])
+ return result
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_3g_wifi_only_us_vzw(self):
+ """ Verifies WEA with WiFi enabled and 3G data network disabled for US Verizon.
+
+ configures the device to US Verizon
+ enables WiFi and disable 3G data network.
+ connects to internet via WiFi.
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ result = True
+ if not self._setup_receive_test_flow_wifi(US_VZW, GEN_3G, False):
+ result = False
+ if result:
+ if not self._verify_send_receive_wea_alerts(self.android_devices[0], US_VZW):
+ result = False
+
+ get_screen_shot_log(self.android_devices[0])
+ return result
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_5g_wfc_wifi_only_us_vzw(self):
+ """ Verifies WEA with WFC mode and 5G NSA data network disabled for US Verizon.
+
+ configures the device to US Verizon
+ enables WFC mode and disable 5G NSA data network.
+ connects to internet via WiFi.
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ result = True
+ if not self._setup_receive_test_flow_wifi(US_VZW, GEN_5G, False)\
+ or not self._setup_wfc_mode(self.android_devices[0]):
+ result = False
+
+ if result:
+ if not self._verify_send_receive_wea_alerts(self.android_devices[0], US_VZW):
+ result = False
+
+ get_screen_shot_log(self.android_devices[0])
+ return result
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_4g_wfc_wifi_only_us_vzw(self):
+ """ Verifies WEA with WFC mode and 4G data network disabled for US Verizon.
+
+ configures the device to US Verizon
+ enables WFC mode and disable 4G data network.
+ connects to internet via WiFi.
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ result = True
+ if not self._setup_receive_test_flow_wifi(US_VZW, GEN_4G, False)\
+ or not self._setup_wfc_mode(self.android_devices[0]):
+ result = False
+
+ if result:
+ if not self._verify_send_receive_wea_alerts(self.android_devices[0], US_VZW):
+ result = False
+
+ get_screen_shot_log(self.android_devices[0])
+ return True
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_3g_wfc_wifi_only_us_vzw(self):
+ """ Verifies WEA with WFC mode and 3G data network disabled for US Verizon.
+
+ configures the device to US Verizon
+ enables WFC mode and disable 3G data network.
+ connects to internet via WiFi.
+ send alerts across all channels,
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ result = True
+ if not self._setup_receive_test_flow_wifi(US_VZW, GEN_3G, False)\
+ or not self._setup_wfc_mode(self.android_devices[0]):
+ result = False
+
+ if result:
+ if not self._verify_send_receive_wea_alerts(self.android_devices[0], US_VZW):
+ result = False
+
+ get_screen_shot_log(self.android_devices[0])
+ return True
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_5g_epdg_mo_wfc_wifi_only_us_vzw(self):
+ """ Verifies WEA during VoWiFi call for US Verizon.
+
+ configures the device to US Verizon
+ enables WFC mode and disable 5G NSA data network.
+ connects to internet via WiFi.
+ sends alerts across all channels and initiates mo VoWiFi call respectively.
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ result = True
+ if not self._setup_receive_test_flow_wifi(US_VZW, GEN_5G, False)\
+ or not self._setup_wfc_mode(self.android_devices[0]):
+ result = False
+
+ phone_setup_voice_general(self.log, self.android_devices[1] )
+
+ if result:
+ if not self._verify_send_receive_wea_alerts(self.android_devices[0], US_VZW, call=True):
+ result = False
+
+ get_screen_shot_log(self.android_devices[0])
+ return result
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_4g_epdg_mo_wfc_wifi_only_us_vzw(self):
+ """ Verifies WEA during VoWiFi call for US Verizon.
+
+ configures the device to US Verizon
+ enables WFC mode and disable 5G NSA data network.
+ connects to internet via WiFi.
+ sends alerts across all channels and initiates mo VoWiFi call respectively.
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ result = True
+ if not self._setup_receive_test_flow_wifi(US_VZW, GEN_4G, False)\
+ or not self._setup_wfc_mode(self.android_devices[0]):
+ result = False
+
+ phone_setup_voice_general(self.log, self.android_devices[1] )
+
+ if result:
+ if not self._verify_send_receive_wea_alerts(self.android_devices[0], US_VZW, call=True):
+ result = False
+
+ get_screen_shot_log(self.android_devices[0])
+ return result
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_send_receive_alerts_3g_epdg_mo_wfc_wifi_only_us_vzw(self):
+ """ Verifies WEA during VoWiFi call for US Verizon.
+
+ configures the device to US Verizon
+ enables WFC mode and disable 5G NSA data network.
+ connects to internet via WiFi.
+ sends alerts across all channels and initiates mo VoWiFi call respectively.
+ verify if alert is received correctly
+ verify sound and vibration timing
+ click on OK/exit alert and verify text
+
+ Returns:
+ True if pass; False if fail and collects screenshot
+ """
+ result = True
+ if not self._setup_receive_test_flow_wifi(US_VZW, GEN_3G, False)\
+ or not self._setup_wfc_mode(self.android_devices[0]):
+ result = False
+
+ phone_setup_voice_general(self.log, self.android_devices[1] )
+
+ if result:
+ if not self._verify_send_receive_wea_alerts(self.android_devices[0], US_VZW, call=True):
+ result = False
+
+ get_screen_shot_log(self.android_devices[0])
+ return result
+
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gActivationTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gActivationTest.py
index 87e7856..eab184d 100755
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gActivationTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gActivationTest.py
@@ -21,18 +21,9 @@
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import GEN_4G
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_WCDMA_ONLY
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
-from acts_contrib.test_utils.tel.tel_test_utils import get_current_override_network_type
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa
-from acts_contrib.test_utils.tel.tel_5g_test_utils import set_preferred_mode_for_5g
+from acts_contrib.test_utils.tel.tel_test_utils import cycle_airplane_mode
+from acts_contrib.test_utils.tel.tel_5g_test_utils import test_activation_by_condition
class Nsa5gActivationTest(TelephonyBaseTest):
@@ -63,29 +54,10 @@
Returns:
True if pass; False if fail.
"""
- ad = self.android_devices[0]
- wifi_toggle_state(ad.log, ad, False)
- set_preferred_mode_for_5g(ad)
- for iteration in range(3):
- ad.log.info("Attempt %d", iteration + 1)
- # APM toggle
- toggle_airplane_mode(ad.log, ad, True)
- toggle_airplane_mode(ad.log, ad, False)
- # LTE attach
- if not wait_for_network_generation(
- ad.log, ad, GEN_4G, voice_or_data=NETWORK_SERVICE_DATA):
- ad.log.error("Fail to ensure initial data in 4G")
- # 5G attach
- ad.log.info("Waiting for 5g NSA attach for 60 secs")
- if is_current_network_5g_nsa(ad, timeout=60):
- ad.log.info("Success! attached on 5g NSA")
- return True
- else:
- ad.log.error("Failure - expected NR_NSA, current %s",
- get_current_override_network_type(ad))
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- ad.log.info("nsa5g attach test FAIL for all 3 iterations")
- return False
+
+ return test_activation_by_condition(self.android_devices[0],
+ nr_type='nsa',
+ precond_func=lambda: cycle_airplane_mode(self.android_devices[0]))
@test_tracker_info(uuid="d4f5f0c5-cc58-4531-96dd-32eed9121b95")
@@ -101,29 +73,10 @@
Returns:
True if pass; False if fail.
"""
- ad = self.android_devices[0]
- wifi_toggle_state(ad.log, ad, False)
- toggle_airplane_mode(ad.log, ad, False)
- set_preferred_mode_for_5g(ad)
- for iteration in range(3):
- ad.log.info("Attempt %d", iteration + 1)
- # Reboot phone
- reboot_device(ad)
- # LTE attach
- if not wait_for_network_generation(
- ad.log, ad, GEN_4G, voice_or_data=NETWORK_SERVICE_DATA):
- ad.log.error("Fail to ensure initial data in 4G")
- # 5G attach
- ad.log.info("Waiting for 5g NSA attach for 60 secs")
- if is_current_network_5g_nsa(ad, timeout=60):
- ad.log.info("Success! attached on 5g NSA")
- return True
- else:
- ad.log.error("Failure - expected NR_NSA, current %s",
- get_current_override_network_type(ad))
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- ad.log.info("nsa5g reboot test FAIL for all 3 iterations")
- return False
+
+ return test_activation_by_condition(self.android_devices[0],
+ nr_type='nsa',
+ precond_func=lambda: reboot_device(self.android_devices[0]))
@test_tracker_info(uuid="1ceda4b5-4a6a-43fa-8976-67cbfb7eab5b")
@@ -140,32 +93,9 @@
Returns:
True if pass; False if fail.
"""
- ad = self.android_devices[0]
- sub_id = ad.droid.subscriptionGetDefaultSubId()
- wifi_toggle_state(ad.log, ad, False)
- toggle_airplane_mode(ad.log, ad, False)
- for iteration in range(3):
- ad.log.info("Attempt %d", iteration + 1)
- # Set mode pref to 3G
- set_preferred_network_mode_pref(ad.log, ad, sub_id,
- NETWORK_MODE_WCDMA_ONLY)
- time.sleep(15)
- # Set mode pref to 5G
- set_preferred_mode_for_5g(ad)
- # LTE attach
- if not wait_for_network_generation(
- ad.log, ad, GEN_4G, voice_or_data=NETWORK_SERVICE_DATA):
- ad.log.error("Fail to ensure initial data in 4G")
- # 5G attach
- ad.log.info("Waiting for 5g NSA attach for 60 secs")
- if is_current_network_5g_nsa(ad, timeout=60):
- ad.log.info("Success! attached on 5g NSA")
- return True
- else:
- ad.log.error("Failure - expected NR_NSA, current %s",
- get_current_override_network_type(ad))
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- ad.log.info("nsa5g mode pref from 3G test FAIL for all 3 iterations")
- return False
+
+ return test_activation_by_condition(self.android_devices[0],
+ from_3g=True,
+ nr_type='nsa')
""" Tests End """
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSDDSSwitchTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSDDSSwitchTest.py
new file mode 100644
index 0000000..9c2ddce
--- /dev/null
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSDDSSwitchTest.py
@@ -0,0 +1,427 @@
+#!/usr/bin/env python3
+#
+# Copyright 2020 - 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.
+
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
+from acts_contrib.test_utils.tel.tel_dsds_utils import dds_switch_during_data_transfer_test
+from acts_contrib.test_utils.tel.tel_dsds_utils import dsds_dds_swap_call_streaming_test
+from acts_contrib.test_utils.tel.tel_dsds_utils import dsds_dds_swap_message_streaming_test
+from acts_contrib.test_utils.tel.tel_defines import YOUTUBE_PACKAGE_NAME
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+
+class Nsa5gDSDSDDSSwitchTest(TelephonyBaseTest):
+ def setup_class(self):
+ TelephonyBaseTest.setup_class(self)
+ self.message_lengths = (50, 160, 180)
+ self.tel_logger = TelephonyMetricLogger.for_test_case()
+
+ def teardown_test(self):
+ self.android_devices[0].force_stop_apk(YOUTUBE_PACKAGE_NAME)
+ ensure_phones_idle(self.log, self.android_devices)
+
+ @test_tracker_info(uuid="0514be56-48b1-4ae9-967f-2326939ef386")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_sms_dds_psim_5g_nsa_volte_esim_5g_nsa_volte(self):
+ """ 5G NSA DDS swap SMS test(Initial DDS is on SIM1).
+
+ 1. Make MO/MT SMS via SIM1 when DDS is on SIM1 and idle.
+ 2. Switch DDS to SIM2.
+ 3. Make MO/MT SMS via SIM2 when DDS is on SIM2 and idle.
+ 4. Switch DDS to SIM1, make sure data works fine.
+
+ After Make/Receive SMS will check the dds slot if is attach to the
+ network with assigned RAT successfully and data works fine.
+ """
+ return dsds_dds_swap_message_streaming_test(
+ self.log,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=[0, 1],
+ init_dds=0,
+ msg_type="SMS",
+ direction="mt",
+ streaming=False)
+
+ @test_tracker_info(uuid="d04fca02-881c-4089-bfdf-b1d84c301ff1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_sms_non_dds_psim_5g_nsa_volte_esim_5g_nsa_volte(self):
+ """ 5G NSA DDS swap SMS test(Initial DDS is on SIM1).
+
+ 1. Make MO/MT SMS via SIM2 when DDS is on SIM1 and idle.
+ 2. Switch DDS to SIM2.
+ 3. Make MO/MT SMS via SIM1 when DDS is on SIM2 and idle.
+ 4. Switch DDS to SIM1, make sure data works fine.
+
+ After Make/Receive SMS will check the dds slot if is attach to the
+ network with assigned RAT successfully and data works fine.
+ """
+ return dsds_dds_swap_message_streaming_test(
+ self.log,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=[1, 0],
+ init_dds=0,
+ msg_type="SMS",
+ direction="mt",
+ streaming=False)
+
+ @test_tracker_info(uuid="e5562a55-788a-4c33-9b97-8eeb8e412052")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_sms_dds_psim_5g_nsa_volte_esim_5g_nsa_volte(self):
+ """ 5G NSA DDS swap SMS test(Initial DDS is on SIM1).
+
+ 1. Start Youtube streaming.
+ 2. Make MO/MT SMS via SIM1 when DDS is on SIM1 and idle.
+ 3. Stop Youtube streaming.
+ 4. Switch DDS to SIM2.
+ 5. Start Youtube streaming.
+ 6. Make MO/MT SMS via SIM2 when DDS is on SIM2 and idle.
+ 7. Stop Youtube streaming.
+ 8. Switch DDS to SIM1, make sure data works fine.
+
+ After Make/Receive SMS will check the dds slot if is attach to the
+ network with assigned RAT successfully and data works fine.
+ """
+ return dsds_dds_swap_message_streaming_test(
+ self.log,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=[0, 1],
+ init_dds=0,
+ msg_type="SMS",
+ direction="mt",
+ streaming=True)
+
+ @test_tracker_info(uuid="71fb524f-4777-4aa5-aa94-28d6d46dc253")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_sms_non_dds_psim_5g_nsa_volte_esim_5g_nsa_volte(self):
+ """ 5G NSA DDS swap SMS test(Initial DDS is on SIM1).
+
+ 1. Start Youtube streaming.
+ 2. Make MO/MT SMS via SIM2 when DDS is on SIM1 and idle.
+ 3. Stop Youtube streaming.
+ 4. Switch DDS to SIM2.
+ 5. Start Youtube streaming.
+ 6. Make MO/MT SMS via SIM1 when DDS is on SIM2 and idle.
+ 7. Stop Youtube streaming.
+ 8. Switch DDS to SIM1, make sure data works fine.
+
+ After Make/Receive SMS will check the dds slot if is attach to the
+ network with assigned RAT successfully and data works fine.
+ """
+ return dsds_dds_swap_message_streaming_test(
+ self.log,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=[1, 0],
+ init_dds=0,
+ msg_type="SMS",
+ direction="mt",
+ streaming=True)
+
+ @test_tracker_info(uuid="3f7cf6ff-a3ec-471b-8a13-e3035dd791c6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_mms_dds_psim_5g_nsa_volte_esim_5g_nsa_volte(self):
+ """ 5G NSA DDS swap MMS test(Initial DDS is on SIM1).
+
+ 1. Make MO/MT MMS via SIM1 when DDS is on SIM1 and idle.
+ 2. Switch DDS to SIM2.
+ 3. Make MO/MT MMS via SIM2 when DDS is on SIM2 and idle.
+ 4. Switch DDS to SIM1, make sure data works fine.
+
+ After Make/Receive MMS will check the dds slot if is attach to the
+ network with assigned RAT successfully and data works fine.
+ """
+ return dsds_dds_swap_message_streaming_test(
+ self.log,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=[0, 1],
+ init_dds=0,
+ msg_type="MMS",
+ direction="mt",
+ streaming=False)
+
+ @test_tracker_info(uuid="311205dd-f484-407c-bd4a-93c25a78b02a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_mms_non_dds_psim_5g_nsa_volte_esim_5g_nsa_volte(self):
+ """ 5G NSA DDS swap MMS test(Initial DDS is on SIM1).
+
+ 1. Make MO/MT MMS via SIM2 when DDS is on SIM1 and idle.
+ 2. Switch DDS to SIM2.
+ 3. Make MO/MT MMS via SIM1 when DDS is on SIM2 and idle.
+ 4. Switch DDS to SIM1, make sure data works fine.
+
+ After Make/Receive MMS will check the dds slot if is attach to the
+ network with assigned RAT successfully and data works fine.
+ """
+ return dsds_dds_swap_message_streaming_test(
+ self.log,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=[1, 0],
+ init_dds=0,
+ msg_type="MMS",
+ direction="mt",
+ streaming=False)
+
+ @test_tracker_info(uuid="d817ee1d-8825-4614-abb1-f813c5f4c7de")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_mms_dds_psim_5g_nsa_volte_esim_5g_nsa_volte(self):
+ """ 5G NSA DDS swap MMS test(Initial DDS is on SIM1).
+
+ 1. Start Youtube streaming.
+ 2. Make MO/MT MMS via SIM1 when DDS is on SIM1 and idle.
+ 3. Stop Youtube streaming.
+ 4. Switch DDS to SIM2.
+ 5. Start Youtube streaming.
+ 6. Make MO/MT MMS via SIM2 when DDS is on SIM2 and idle.
+ 7. Stop Youtube streaming.
+ 8. Switch DDS to SIM1, make sure data works fine.
+
+ After Make/Receive MMS will check the dds slot if is attach to the
+ network with assigned RAT successfully and data works fine.
+ """
+ return dsds_dds_swap_message_streaming_test(
+ self.log,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=[0, 1],
+ init_dds=0,
+ msg_type="MMS",
+ direction="mt",
+ streaming=True)
+
+ @test_tracker_info(uuid="131f68c6-e0b6-41cb-85c5-a2df125e01b3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_mms_non_dds_psim_5g_nsa_volte_esim_5g_nsa_volte(self):
+ """ 5G NSA DDS swap MMS test(Initial DDS is on SIM1).
+
+ 1. Start Youtube streaming.
+ 2. Make MO/MT MMS via SIM2 when DDS is on SIM1 and idle.
+ 3. Stop Youtube streaming.
+ 4. Switch DDS to SIM2.
+ 5. Start Youtube streaming.
+ 6. Make MO/MT MMS via SIM1 when DDS is on SIM2 and idle.
+ 7. Stop Youtube streaming.
+ 8. Switch DDS to SIM1, make sure data works fine.
+
+ After Make/Receive MMS will check the dds slot if is attach to the
+ network with assigned RAT successfully and data works fine.
+ """
+ return dsds_dds_swap_message_streaming_test(
+ self.log,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=[1, 0],
+ init_dds=0,
+ msg_type="MMS",
+ direction="mt",
+ streaming=True)
+
+ @test_tracker_info(uuid="1c3ba14c-d7f6-4737-8ac2-f55fa3b6cc46")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_voice_psim_mo_5g_nsa_volte_esim_5g_nsa_volte(self):
+ """ 5G NSA DDS swap call test(Initial DDS is on SIM1).
+
+ 1. Make MO call via SIM1 when DDS is on SIM1 and idle.
+ 2. Switch DDS to SIM2.
+ 3. Make MO call via SIM1 when DDS is on SIM2 and idle.
+ 4. Switch DDS to SIM1, make sure data works fine.
+
+ After call end will check the dds slot if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_dds_swap_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=[0, 0],
+ init_dds=0,
+ direction="mo",
+ duration=30,
+ streaming=False)
+
+ @test_tracker_info(uuid="55c3fbd0-0b8b-4275-81a0-1e1715b66ec1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_voice_psim_mt_5g_nsa_volte_esim_5g_nsa_volte(self):
+ """ 5G NSA DDS swap call test(Initial DDS is on SIM1).
+
+ 1. Receive MT call via SIM1 when DDS is on SIM1 and idle.
+ 2. Switch DDS to SIM2.
+ 3. Receive MT call via SIM1 when DDS is on SIM2 and idle.
+ 4. Switch DDS to SIM1, make sure data works fine.
+
+ After call end will check the dds slot if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_dds_swap_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=[0, 0],
+ init_dds=0,
+ direction="mt",
+ duration=30,
+ streaming=False)
+
+ @test_tracker_info(uuid="1359b4a9-7e3e-4b34-b512-4638ab4ab4a7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_voice_esim_mo_5g_nsa_volte_psim_5g_nsa_volte(self):
+ """ 5G NSA DDS swap call test(Initial DDS is on SIM1).
+
+ 1. Make MO call via SIM2 when DDS is on SIM1 and idle.
+ 2. Switch DDS to SIM2.
+ 3. Make MO call via SIM2 when DDS is on SIM2 and idle.
+ 4. Switch DDS to SIM1, make sure data works fine.
+
+ After call end will check the dds slot if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_dds_swap_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=[1, 1],
+ init_dds=0,
+ direction="mo",
+ duration=30,
+ streaming=False)
+
+ @test_tracker_info(uuid="f4a290dc-3a8b-4364-8b6e-35275a6b8f92")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_voice_esim_mt_5g_nsa_volte_psim_5g_nsa_volte(self):
+ """ 5G NSA DDS swap call test(Initial DDS is on SIM1).
+
+ 1. Receive MT call via SIM2 when DDS is on SIM1 and idle.
+ 2. Switch DDS to SIM2.
+ 3. Receive MT call via SIM2 when DDS is on SIM2 and idle.
+ 4. Switch DDS to SIM1, make sure data works fine.
+
+ After call end will check the dds slot if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_dds_swap_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=[1, 1],
+ init_dds=0,
+ direction="mt",
+ duration=30,
+ streaming=False)
+
+ @test_tracker_info(uuid="727a75ef-7277-42fe-8a4b-7b2debe666d9")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_psim_5g_nsa_volte_esim_5g_nsa_volte(self):
+ return dds_switch_during_data_transfer_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ nw_rat=["5g_volte", "5g_volte"])
+
+ @test_tracker_info(uuid="4ef4626a-11b3-4a09-ac98-2e3d94e54bf7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_and_voice_mo_psim_5g_nsa_volte_esim_5g_nsa_volte(self):
+ return dds_switch_during_data_transfer_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ nw_rat=["5g_volte", "5g_volte"],
+ call_slot=0,
+ call_direction="mo")
+
+ @test_tracker_info(uuid="ef3bc49f-e94f-432b-bb51-4b6008359313")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_and_voice_mt_psim_5g_nsa_volte_esim_5g_nsa_volte(self):
+ return dds_switch_during_data_transfer_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ nw_rat=["5g_volte", "5g_volte"],
+ call_slot=0,
+ call_direction="mt")
+
+ @test_tracker_info(uuid="6d913c58-dde5-453d-b9a9-30e76cdac554")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_and_voice_mo_esim_5g_nsa_volte_psim_5g_nsa_volte(self):
+ return dds_switch_during_data_transfer_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ nw_rat=["5g_volte", "5g_volte"],
+ call_slot=1,
+ call_direction="mo")
+
+ @test_tracker_info(uuid="df91d2ce-ef5e-4d38-a642-6470ade625c6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_and_voice_mt_esim_5g_nsa_volte_psim_5g_nsa_volte(self):
+ return dds_switch_during_data_transfer_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ nw_rat=["5g_volte", "5g_volte"],
+ call_slot=1,
+ call_direction="mt")
+
+ @test_tracker_info(uuid="4ba86f3c-1de6-4888-a2e5-a5e6079c3886")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_and_voice_mo_psim_5g_nsa_csfb_esim_5g_nsa_csfb(self):
+ return dds_switch_during_data_transfer_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ nw_rat=["5g_csfb", "5g_csfb"],
+ call_slot=0,
+ call_direction="mo")
+
+ @test_tracker_info(uuid="aa426eb2-dc7b-4ffe-aaa2-a3204251c131")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_and_voice_mt_psim_5g_nsa_csfb_esim_5g_nsa_csfb(self):
+ return dds_switch_during_data_transfer_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ nw_rat=["5g_csfb", "5g_csfb"],
+ call_slot=0,
+ call_direction="mt")
+
+ @test_tracker_info(uuid="854634e8-7a2a-4d14-8269-8f4f463f8f56")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_and_voice_mo_esim_5g_nsa_csfb_psim_5g_nsa_csfb(self):
+ return dds_switch_during_data_transfer_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ nw_rat=["5g_csfb", "5g_csfb"],
+ call_slot=1,
+ call_direction="mo")
+
+ @test_tracker_info(uuid="02478b9e-6bf6-4148-bbc4-0cbdf59f1625")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch_youtube_and_voice_mt_esim_5g_nsa_csfb_psim_5g_nsa_csfb(self):
+ return dds_switch_during_data_transfer_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ nw_rat=["5g_csfb", "5g_csfb"],
+ call_slot=1,
+ call_direction="mt")
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSMessageTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSMessageTest.py
new file mode 100644
index 0000000..a21cde3
--- /dev/null
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSMessageTest.py
@@ -0,0 +1,801 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
+from acts_contrib.test_utils.tel.tel_defines import YOUTUBE_PACKAGE_NAME
+from acts_contrib.test_utils.tel.tel_dsds_utils import dsds_message_test
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+
+CallResult = TelephonyVoiceTestResult.CallResult.Value
+
+class Nsa5gDSDSMessageTest(TelephonyBaseTest):
+ def setup_class(self):
+ TelephonyBaseTest.setup_class(self)
+ self.tel_logger = TelephonyMetricLogger.for_test_case()
+
+ def teardown_test(self):
+ ensure_phones_idle(self.log, self.android_devices)
+
+ @test_tracker_info(uuid="123a50bc-f0a0-4129-9377-cc63c76d5727")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mo_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 0, mo_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="5dcf76bc-369f-4d47-b3ec-318559a95843")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mt_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 0, mt_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="245a6148-cd45-4b82-bf4c-5679ebe15e29")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mo_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 1, mo_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="5a93d377-d9bc-477c-bfab-2496064e3522")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mt_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 1, mt_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="dd4a9fb5-b0fe-492b-ad24-61e022d13a22")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mo_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 0, mo_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="09100a8f-b7ed-41a0-9f04-e716115cabb8")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mt_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 0, mt_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="b5971c57-bbe9-4e87-a6f2-9953fa770a15")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mo_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 1, mo_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="142b11d4-b593-4a09-8fc6-35e310739244")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mt_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 1, mt_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="87759475-0208-4d9b-b5b9-814fdb97f09c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mo_psim_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 0, mo_rat=["5g_volte", "volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="2f14e81d-330f-4cdd-837c-1168185ffec4")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mt_psim_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 0, mt_rat=["5g_volte", "volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="38f01127-54bf-4c55-b7d8-d8f41352b399")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mo_psim_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 1, mo_rat=["5g_volte", "volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="4e0c9692-a758-4169-85fe-c33bd2651525")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mt_psim_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 1, mt_rat=["5g_volte", "volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="9cc45474-1fca-4008-8499-87829d6516ea")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mo_esim_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 0, mo_rat=["5g_volte", "volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="341786de-5b23-438a-a91b-97cf420ef5fd")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mt_esim_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 0, mt_rat=["5g_volte", "volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="527e8629-6e0d-4742-98c0-5cbc868c430e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mo_esim_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 1, mo_rat=["5g_volte", "volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="66277aa0-0a9a-4a25-828f-b0315ae7fd0e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mt_esim_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 1, mt_rat=["5g_volte", "volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="a4d797b6-2699-48de-b36b-b10a1901305b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mo_psim_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 0, mo_rat=["volte", "5g_volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="371286ba-f1da-4459-a7e8-0368d0fae147")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mt_psim_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 0, mt_rat=["volte", "5g_volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="183cda35-45aa-485d-b3d4-975d78f7d361")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mo_psim_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 1, mo_rat=["volte", "5g_volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="d9cb69ce-c462-4fd4-b716-bfb1fd2ed86a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mt_psim_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 1, mt_rat=["volte", "5g_volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="dfe54cea-8396-4af4-8aee-9dadad602e5b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mo_esim_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 0, mo_rat=["volte", "5g_volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="fd4ae44c-3527-4b90-8d33-face10e160a6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mt_esim_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 0, mt_rat=["volte", "5g_volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="51d5e05d-66e7-4369-91e0-6cdc573d9a59")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mo_esim_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 1, mo_rat=["volte", "5g_volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="38271a0f-2efb-4991-9f24-6da9f003ddd4")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_sms_mt_esim_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 1, mt_rat=["volte", "5g_volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="dde1e900-abcd-4a5f-8872-02456ea248ee")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mo_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 0, mo_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="5a8ad6dc-687a-498e-8b99-119f3cbb781c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mt_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 0, mt_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="765443f4-d4a0-45fe-8c97-763feb4b588b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mo_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 1, mo_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="026b9e8f-400e-4b59-b40d-d4e741838be0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mt_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 1, mt_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="468536c1-de6e-48e7-b59e-11f17389ac12")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mo_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 0, mo_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="c4ae7f6b-bc20-4cb2-8e41-8a02171aec6f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mt_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 0, mt_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="2d70443e-b442-48e0-9c1f-ce1409184ff8")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mo_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 1, mo_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="47fbc6c0-ca76-44c0-a166-d8c99d16b6ac")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mt_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 1, mt_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="39684fbc-73d1-48cb-af3f-07a366a6b190")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mo_psim_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 0, mo_rat=["5g_volte", "volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="6adf4163-4969-4129-bbac-4ebdac4c4cf5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mt_psim_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 0, mt_rat=["5g_volte", "volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="7b636038-5b0c-4844-ba2a-2e76ed787f72")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mo_psim_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 1, mo_rat=["5g_volte", "volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="b5008ad4-372d-4849-b47b-583be6aa080a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mt_psim_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 1, mt_rat=["5g_volte", "volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="fd6b33b6-c654-4ec0-becc-2fd7ec10c291")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mo_esim_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 0, mo_rat=["5g_volte", "volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="0267c4e8-e5b8-4001-912f-76c387a15f79")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mt_esim_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 0, mt_rat=["5g_volte", "volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="a54caa16-dfc6-46e1-a376-b4b585e2e840")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mo_esim_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 1, mo_rat=["5g_volte", "volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="f6af184a-933b-467e-81a7-44ef48b56540")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mt_esim_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 1, mt_rat=["5g_volte", "volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="2e89f125-aacc-4c36-a1c2-308cd83b0e22")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mo_psim_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 0, mo_rat=["volte", "5g_volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="03c23c94-3cc5-4ecf-9b87-273c815b9f53")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mt_psim_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 0, mt_rat=["volte", "5g_volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="d2af382a-0f87-46c0-b2de-84f5a549e32c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mo_psim_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 1, mo_rat=["volte", "5g_volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="bf788d99-954b-47e2-b465-8565bb30e907")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mt_psim_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 1, mt_rat=["volte", "5g_volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="f0b1d46b-6ddc-4625-b653-38e323e542ad")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mo_esim_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 0, mo_rat=["volte", "5g_volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="b17a4943-1f69-428a-bd63-13144b2bc592")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mt_esim_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 0, mt_rat=["volte", "5g_volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="98d7b7b8-0bd3-4362-957b-56c8b19ac3d4")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mo_esim_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 1, mo_rat=["volte", "5g_volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="5f0f4174-548d-43ab-b520-5e2211fdaacc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_mms_mt_esim_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 1, mt_rat=["volte", "5g_volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="09cd2c80-5c94-4b97-badd-b9d23712cbad")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mo_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 0, mo_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mo", streaming=True)
+
+ @test_tracker_info(uuid="deed7037-932e-4c08-bbf0-989144a51193")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mt_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 0, mt_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mt", streaming=True)
+
+ @test_tracker_info(uuid="14fe5ef1-e6aa-4615-887a-ac26043c2dfc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mo_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 1, mo_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mo", streaming=True)
+
+ @test_tracker_info(uuid="1f07d373-dc81-42f4-a5c5-461304f1e7bf")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mt_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 1, mt_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mt", streaming=True)
+
+ @test_tracker_info(uuid="a9f066d3-a5db-4319-a5c9-f7a20f84cd6e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mo_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 0, mo_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mo", streaming=True)
+
+ @test_tracker_info(uuid="688485af-cdc7-43b7-af01-baf6bc695b70")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mt_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 0, mt_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mt", streaming=True)
+
+ @test_tracker_info(uuid="7fef6173-1f37-45d3-be94-60fea340444c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mo_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 1, mo_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mo", streaming=True)
+
+ @test_tracker_info(uuid="71b15942-6c8f-41b3-8dc9-5a1dea64aad4")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mt_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 1, mt_rat=["5g_volte", "5g_volte"], msg="SMS", direction="mt", streaming=True)
+
+ @test_tracker_info(uuid="6cbc50e7-e135-405d-bf69-ab074d345d80")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mo_psim_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 0, mo_rat=["5g_volte", "volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="d976560a-1ea1-421a-9c2d-906cbfb7654e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mt_psim_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 0, mt_rat=["5g_volte", "volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="0e3a10b2-2351-49a2-9282-99aae1372bf0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mo_psim_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 1, mo_rat=["5g_volte", "volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="e713c430-0bfa-4d25-91f3-1b6fec84b3a5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mt_psim_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 1, mt_rat=["5g_volte", "volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="770bec4d-c1c9-4936-8683-3fb796827eba")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mo_esim_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 0, mo_rat=["5g_volte", "volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="3f34328b-9295-4740-a48b-3ffadbab3fb5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mt_esim_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 0, mt_rat=["5g_volte", "volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="eeaeb58a-7566-498e-a4d1-ce1cbd82f362")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mo_esim_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 1, mo_rat=["5g_volte", "volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="7550ef0b-b0d3-4932-95d3-119abdad53ad")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mt_esim_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 1, mt_rat=["5g_volte", "volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="6dd693f4-6c61-4048-9027-02c17874dbd0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mo_psim_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 0, mo_rat=["volte", "5g_volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="976d5c30-63af-4e49-952e-2cd4147b7c8d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mt_psim_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 0, mt_rat=["volte", "5g_volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="b2c94d26-c806-417d-a751-618491dce246")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mo_psim_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 1, mo_rat=["volte", "5g_volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="02739364-2848-4242-bb6e-41a03ec358ed")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mt_psim_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 1, mt_rat=["volte", "5g_volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="811880fd-c422-4548-8dfb-cddbfb1dc6c0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mo_esim_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 0, mo_rat=["volte", "5g_volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="9e02ade7-c2b6-4b7e-ab15-b42c119f4141")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mt_esim_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 0, mt_rat=["volte", "5g_volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="ba2ce2de-a0a6-4abe-adb8-110541e60cb1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mo_esim_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 1, mo_rat=["volte", "5g_volte"], msg="SMS", direction="mo")
+
+ @test_tracker_info(uuid="46e1397c-7296-4aac-8e0f-7049d04427bc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_sms_mt_esim_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 1, mt_rat=["volte", "5g_volte"], msg="SMS", direction="mt")
+
+ @test_tracker_info(uuid="181c1ac9-625e-450d-b566-834e20ecd59d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mo_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 0, mo_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mo", streaming=True)
+
+ @test_tracker_info(uuid="b37aceed-7f67-4ae3-aba8-0f94d24d81e2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mt_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 0, mt_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mt", streaming=True)
+
+ @test_tracker_info(uuid="0fb13f48-bfd7-4019-8a33-e229677b3357")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mo_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 1, mo_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mo", streaming=True)
+
+ @test_tracker_info(uuid="016369fa-3420-45f5-9ed2-3776816f4e4b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mt_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 1, mt_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mt", streaming=True)
+
+ @test_tracker_info(uuid="65fdbecf-9ea5-4881-9e99-4a1ed90b76cc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mo_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 0, mo_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mo", streaming=True)
+
+ @test_tracker_info(uuid="3e6b4bcf-30cd-4502-8811-2a5a7a9142a5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mt_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 0, mt_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mt", streaming=True)
+
+ @test_tracker_info(uuid="a49b7a91-8811-403b-b8ed-ac0edad69c2c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mo_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 1, mo_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mo", streaming=True)
+
+ @test_tracker_info(uuid="961db859-ad50-4b13-8555-e523843d3e0c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mt_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 1, mt_rat=["5g_volte", "5g_volte"], msg="MMS", direction="mt", streaming=True)
+
+ @test_tracker_info(uuid="398fea0a-4ef4-4a6d-bea0-76ab0b2e2c34")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mo_psim_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 0, mo_rat=["5g_volte", "volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="06503954-caff-47ba-8ed3-7793fca4e94a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mt_psim_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 0, mt_rat=["5g_volte", "volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="bc43d539-7bbd-4b12-b88a-ecf0229f1ed5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mo_psim_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 1, mo_rat=["5g_volte", "volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="d558a53b-396e-4a9e-aec1-929f41f8ad2a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mt_psim_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 1, mt_rat=["5g_volte", "volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="74afcd0a-e121-4028-99c6-48cad25b18b8")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mo_esim_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 0, mo_rat=["5g_volte", "volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="5042ec42-f1b3-466a-8e06-6e1c3de2dffb")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mt_esim_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 0, mt_rat=["5g_volte", "volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="6f286c93-004b-4360-9afa-78f15a0a5549")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mo_esim_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 1, mo_rat=["5g_volte", "volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="0313548b-653b-44ea-bb63-76b69b67e456")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mt_esim_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 1, mt_rat=["5g_volte", "volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="4c1e4667-2b0d-4f4d-a419-c349ef767dbc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mo_psim_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 0, mo_rat=["volte", "5g_volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="f82650db-d0d9-4990-a3c6-b918eabeddc6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mt_psim_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 0, mt_rat=["volte", "5g_volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="76dca39c-8ead-435b-8b5f-8b167946a18e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mo_psim_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 0, None, 1, mo_rat=["volte", "5g_volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="29d8ffec-be68-4d12-b2ad-b2e8f95347c1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mt_psim_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 0, 1, mt_rat=["volte", "5g_volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="625bc42e-c9c7-442e-8464-72aab6055ef8")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mo_esim_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 0, mo_rat=["volte", "5g_volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="18f852da-0877-4624-bbcd-d59a168780dc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mt_esim_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 0, mt_rat=["volte", "5g_volte"], msg="MMS", direction="mt")
+
+ @test_tracker_info(uuid="cac044ec-176d-4eef-885d-ba419ab634eb")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mo_esim_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ 1, None, 1, mo_rat=["volte", "5g_volte"], msg="MMS", direction="mo")
+
+ @test_tracker_info(uuid="245ee61e-f768-403c-9005-7eed90deedd7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_youtube_and_mms_mt_esim_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
+ None, 1, 1, mt_rat=["volte", "5g_volte"], msg="MMS", direction="mt")
\ No newline at end of file
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSSupplementaryServiceTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSSupplementaryServiceTest.py
new file mode 100644
index 0000000..2b06b2c
--- /dev/null
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSSupplementaryServiceTest.py
@@ -0,0 +1,1257 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+from acts import signals
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_CONFERENCE
+from acts_contrib.test_utils.tel.tel_dsds_utils import erase_call_forwarding
+from acts_contrib.test_utils.tel.tel_dsds_utils import msim_call_forwarding
+from acts_contrib.test_utils.tel.tel_dsds_utils import msim_call_voice_conf
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_ss_utils import set_call_waiting
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
+from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
+
+
+class Nsa5gDSDSSupplementaryServiceTest(TelephonyBaseTest):
+ def setup_class(self):
+ TelephonyBaseTest.setup_class(self)
+ self.message_lengths = (50, 160, 180)
+ self.tel_logger = TelephonyMetricLogger.for_test_case()
+ erase_call_forwarding(self.log, self.android_devices[0])
+ if not get_capability_for_subscription(
+ self.android_devices[0],
+ CAPABILITY_CONFERENCE,
+ get_outgoing_voice_sub_id(self.android_devices[0])):
+ self.android_devices[0].log.error(
+ "Conference call is not supported, abort test.")
+ raise signals.TestAbortClass(
+ "Conference call is not supported, abort test.")
+
+ def teardown_test(self):
+ ensure_phones_idle(self.log, self.android_devices)
+ erase_call_forwarding(self.log, self.android_devices[0])
+ set_call_waiting(self.log, self.android_devices[0], enable=1)
+
+ # psim 5g nsa volte & esim 5g nsa volte & dds slot 0
+ @test_tracker_info(uuid="d1a50121-a245-4e51-a6aa-7836878339aa")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_callee_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ """Call forwarding unconditional test on pSIM of the primary device.
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CFU on pSIM of the primary device.
+ 2. Let the 2nd device call the pSIM of the primary device. The
+ call should be forwarded to the 3rd device. Answer and then
+ hang up the call.
+ 3. Disable CFU on pSIM of the primary device.
+ 4. Let the 2nd device call the pSIM of the primary device. The
+ call should NOT be forwarded to the primary device. Answer
+ and then hang up the call.
+ 5. Disable and erase CFU on the primary device.
+ """
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ None,
+ 0,
+ callee_rat=["5g_volte", "5g_volte"],
+ call_forwarding_type="unconditional")
+
+ @test_tracker_info(uuid="c268fee2-6f09-48c2-98d8-97cc06de0e61")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_callee_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ """Call forwarding unconditional test on eSIM of the primary device.
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CFU on eSIM of the primary device.
+ 2. Let the 2nd device call the eSIM of the primary device. The
+ call should be forwarded to the 3rd device. Answer and then
+ hang up the call.
+ 3. Disable CFU on eSIM of the primary device.
+ 4. Let the 2nd device call the eSIM of the primary device. The
+ call should NOT be forwarded to the primary device. Answer
+ and then hang up the call.
+ 5. Disable and erase CFU on the primary device.
+ """
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ None,
+ 0,
+ callee_rat=["5g_volte", "5g_volte"],
+ call_forwarding_type="unconditional")
+
+ # psim 5g nsa volte & esim 5g nsa volte & dds slot 1
+ @test_tracker_info(uuid="df98b0d6-3643-4e01-b9c5-d41b40d95146")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_callee_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ """Call forwarding unconditional test on pSIM of the primary device.
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CFU on pSIM of the primary device.
+ 2. Let the 2nd device call the pSIM of the primary device. The
+ call should be forwarded to the 3rd device. Answer and then
+ hang up the call.
+ 3. Disable CFU on pSIM of the primary device.
+ 4. Let the 2nd device call the pSIM of the primary device. The
+ call should NOT be forwarded to the primary device. Answer
+ and then hang up the call.
+ 5. Disable and erase CFU on the primary device.
+ """
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ None,
+ 1,
+ callee_rat=["5g_volte", "5g_volte"],
+ call_forwarding_type="unconditional")
+
+ @test_tracker_info(uuid="99a61d4e-f0fa-4f65-b3bd-67d2a90cdfe2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_callee_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ """Call forwarding unconditional test on eSIM of the primary device.
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CFU on eSIM of the primary device.
+ 2. Let the 2nd device call the eSIM of the primary device. The
+ call should be forwarded to the 3rd device. Answer and then
+ hang up the call.
+ 3. Disable CFU on eSIM of the primary device.
+ 4. Let the 2nd device call the eSIM of the primary device. The
+ call should NOT be forwarded to the primary device. Answer
+ and then hang up the call.
+ 5. Disable and erase CFU on the primary device.
+ """
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ None,
+ 1,
+ callee_rat=["5g_volte", "5g_volte"],
+ call_forwarding_type="unconditional")
+
+ # psim 5g nsa volte & esim 4g volte & dds slot 0
+ @test_tracker_info(uuid="9fb2da2e-00f6-4d0f-a921-49786ffbb758")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_callee_psim_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ """Call forwarding unconditional test on pSIM of the primary device.
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CFU on pSIM of the primary device.
+ 2. Let the 2nd device call the pSIM of the primary device. The
+ call should be forwarded to the 3rd device. Answer and then
+ hang up the call.
+ 3. Disable CFU on pSIM of the primary device.
+ 4. Let the 2nd device call the pSIM of the primary device. The
+ call should NOT be forwarded to the primary device. Answer
+ and then hang up the call.
+ 5. Disable and erase CFU on the primary device.
+ """
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ None,
+ 0,
+ callee_rat=["5g_volte", "volte"],
+ call_forwarding_type="unconditional")
+
+ @test_tracker_info(uuid="da42b577-30a6-417d-a545-629ccbfaebb2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_callee_esim_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ """Call forwarding unconditional test on eSIM of the primary device.
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CFU on eSIM of the primary device.
+ 2. Let the 2nd device call the eSIM of the primary device. The
+ call should be forwarded to the 3rd device. Answer and then
+ hang up the call.
+ 3. Disable CFU on eSIM of the primary device.
+ 4. Let the 2nd device call the eSIM of the primary device. The
+ call should NOT be forwarded to the primary device. Answer
+ and then hang up the call.
+ 5. Disable and erase CFU on the primary device.
+ """
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ None,
+ 0,
+ callee_rat=["5g_volte", "volte"],
+ call_forwarding_type="unconditional")
+
+ # psim 5g nsa volte & esim 4g volte & dds slot 1
+ @test_tracker_info(uuid="e9ab2c2f-8b2c-4f26-879d-b872947ee3a1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_callee_psim_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ """Call forwarding unconditional test on pSIM of the primary device.
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CFU on pSIM of the primary device.
+ 2. Let the 2nd device call the pSIM of the primary device. The
+ call should be forwarded to the 3rd device. Answer and then
+ hang up the call.
+ 3. Disable CFU on pSIM of the primary device.
+ 4. Let the 2nd device call the pSIM of the primary device. The
+ call should NOT be forwarded to the primary device. Answer
+ and then hang up the call.
+ 5. Disable and erase CFU on the primary device.
+ """
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ None,
+ 1,
+ callee_rat=["5g_volte", "volte"],
+ call_forwarding_type="unconditional")
+
+ @test_tracker_info(uuid="080e6cf2-7bb1-4ce8-9f15-c082cbb0fd8c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_callee_esim_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ """Call forwarding unconditional test on eSIM of the primary device.
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CFU on eSIM of the primary device.
+ 2. Let the 2nd device call the eSIM of the primary device. The
+ call should be forwarded to the 3rd device. Answer and then
+ hang up the call.
+ 3. Disable CFU on eSIM of the primary device.
+ 4. Let the 2nd device call the eSIM of the primary device. The
+ call should NOT be forwarded to the primary device. Answer
+ and then hang up the call.
+ 5. Disable and erase CFU on the primary device.
+ """
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ None,
+ 1,
+ callee_rat=["5g_volte", "volte"],
+ call_forwarding_type="unconditional")
+
+ # psim 4g volte & esim 5g nsa volte & dds slot 0
+ @test_tracker_info(uuid="0da6f8e9-dfea-408b-91d9-e10fb6dad086")
+ def test_msim_cfu_callee_psim_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ """Call forwarding unconditional test on pSIM of the primary device.
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CFU on pSIM of the primary device.
+ 2. Let the 2nd device call the pSIM of the primary device. The
+ call should be forwarded to the 3rd device. Answer and then
+ hang up the call.
+ 3. Disable CFU on pSIM of the primary device.
+ 4. Let the 2nd device call the pSIM of the primary device. The
+ call should NOT be forwarded to the primary device. Answer
+ and then hang up the call.
+ 5. Disable and erase CFU on the primary device.
+ """
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ None,
+ 0,
+ callee_rat=["volte", "5g_volte"],
+ call_forwarding_type="unconditional")
+
+ @test_tracker_info(uuid="dadde63d-4a4d-4fe7-82bd-25ecff856900")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_callee_esim_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ """Call forwarding unconditional test on eSIM of the primary device.
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CFU on eSIM of the primary device.
+ 2. Let the 2nd device call the eSIM of the primary device. The
+ call should be forwarded to the 3rd device. Answer and then
+ hang up the call.
+ 3. Disable CFU on eSIM of the primary device.
+ 4. Let the 2nd device call the eSIM of the primary device. The
+ call should NOT be forwarded to the primary device. Answer
+ and then hang up the call.
+ 5. Disable and erase CFU on the primary device.
+ """
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ None,
+ 0,
+ callee_rat=["volte", "5g_volte"],
+ call_forwarding_type="unconditional")
+
+ # psim 4g volte & esim 5g nsa volte & dds slot 1
+ @test_tracker_info(uuid="0e951ee2-4a38-4b97-8a79-f6b3c66bf4d5")
+ def test_msim_cfu_callee_psim_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ """Call forwarding unconditional test on pSIM of the primary device.
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CFU on pSIM of the primary device.
+ 2. Let the 2nd device call the pSIM of the primary device. The
+ call should be forwarded to the 3rd device. Answer and then
+ hang up the call.
+ 3. Disable CFU on pSIM of the primary device.
+ 4. Let the 2nd device call the pSIM of the primary device. The
+ call should NOT be forwarded to the primary device. Answer
+ and then hang up the call.
+ 5. Disable and erase CFU on the primary device.
+ """
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ None,
+ 1,
+ callee_rat=["volte", "5g_volte"],
+ call_forwarding_type="unconditional")
+
+ @test_tracker_info(uuid="0f15a135-aa30-46fb-956a-99b5b1109783")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_callee_esim_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ """Call forwarding unconditional test on eSIM of the primary device.
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CFU on eSIM of the primary device.
+ 2. Let the 2nd device call the eSIM of the primary device. The
+ call should be forwarded to the 3rd device. Answer and then
+ hang up the call.
+ 3. Disable CFU on eSIM of the primary device.
+ 4. Let the 2nd device call the eSIM of the primary device. The
+ call should NOT be forwarded to the primary device. Answer
+ and then hang up the call.
+ 5. Disable and erase CFU on the primary device.
+ """
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ None,
+ 1,
+ callee_rat=["volte", "5g_volte"],
+ call_forwarding_type="unconditional")
+
+ # psim 5g nsa volte & esim 5g nsa volte & dds slot 0
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="edfbc065-7a1d-4ac8-94fe-58106bd5f0a0")
+ def test_msim_conf_call_host_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ """Conference call test on pSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CW on pSIM of the primary device.
+ 2. Let the pSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the pSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Merge 2 active calls.
+ """
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0, None, None, 0, host_rat=["5g_volte", "5g_volte"])
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="fbae3ef2-6ecc-48fb-b21c-155b2b4fd5d6")
+ def test_msim_conf_call_host_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ """Conference call test on eSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CW on eSIM of the primary device.
+ 2. Let the eSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the eSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Merge 2 active calls.
+ """
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1, None, None, 0, host_rat=["5g_volte", "5g_volte"])
+
+ # psim 5g nsa volte & esim 5g nsa volte & dds slot 1
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="404b7bf8-0706-4d27-a1ff-231ea6d5c34b")
+ def test_msim_conf_call_host_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ """Conference call test on pSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CW on pSIM of the primary device.
+ 2. Let the pSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the pSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Merge 2 active calls.
+ """
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0, None, None, 1, host_rat=["5g_volte", "5g_volte"])
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="cd74af3e-ced5-4275-990c-0561bfeee81d")
+ def test_msim_conf_call_host_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ """Conference call test on eSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CW on eSIM of the primary device.
+ 2. Let the eSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the eSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Merge 2 active calls.
+ """
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1, None, None, 1, host_rat=["5g_volte", "5g_volte"])
+
+ # psim 5g nsa volte & esim 4g volte & dds slot 0
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="ff107828-0b09-47fb-ba85-b0e13b89970f")
+ def test_msim_conf_call_host_psim_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ """Conference call test on pSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CW on pSIM of the primary device.
+ 2. Let the pSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the pSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Merge 2 active calls.
+ """
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0, None, None, 0, host_rat=["5g_volte", "volte"])
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="4a3152e2-8cc6-477d-9dd6-55f3ac35681e")
+ def test_msim_conf_call_host_esim_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ """Conference call test on eSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CW on eSIM of the primary device.
+ 2. Let the eSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the eSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Merge 2 active calls.
+ """
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1, None, None, 0, host_rat=["5g_volte", "volte"])
+
+ # psim 5g nsa volte & esim 4g volte & dds slot 1
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="4aa8e15a-16b5-4173-b0d7-1a6cf00cf240")
+ def test_msim_conf_call_host_psim_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ """Conference call test on pSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CW on pSIM of the primary device.
+ 2. Let the pSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the pSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Merge 2 active calls.
+ """
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0, None, None, 1, host_rat=["5g_volte", "volte"])
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="82d9ca6c-8c3d-4a54-ae85-c3d52aab8bc4")
+ def test_msim_conf_call_host_esim_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ """Conference call test on eSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CW on eSIM of the primary device.
+ 2. Let the eSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the eSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Merge 2 active calls.
+ """
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1, None, None, 1, host_rat=["5g_volte", "volte"])
+
+ # psim 4g volte & esim 5g nsa volte & dds slot 0
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="d8dc0e1b-bfad-4040-ab44-91b15160dd86")
+ def test_msim_conf_call_host_psim_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ """Conference call test on pSIM of the primary device
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CW on pSIM of the primary device.
+ 2. Let the pSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the pSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Merge 2 active calls.
+ """
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0, None, None, 0, host_rat=["volte", "5g_volte"])
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="8d8d1050-9e73-4ec9-a9dd-7f68ccd11483")
+ def test_msim_conf_call_host_esim_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ """Conference call test on eSIM of the primary device
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CW on eSIM of the primary device.
+ 2. Let the eSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the eSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Merge 2 active calls.
+ """
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1, None, None, 0, host_rat=["volte", "5g_volte"])
+
+ # psim 4g volte & esim 5g nsa volte & dds slot 1
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="8f46e57c-c7a2-49e9-9e4c-1f83ab67cd5e")
+ def test_msim_conf_call_host_psim_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ """Conference call test on pSIM of the primary device
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+
+ Test steps:
+ 1. Enable CW on pSIM of the primary device.
+ 2. Let the pSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the pSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Merge 2 active calls.
+ """
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0, None, None, 1, host_rat=["volte", "5g_volte"])
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="7975fc5b-4146-4370-9f1b-1ad1987a14f3")
+ def test_msim_conf_call_host_esim_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ """Conference call test on eSIM of the primary device
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+
+ Test steps:
+ 1. Enable CW on eSIM of the primary device.
+ 2. Let the eSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the eSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Merge 2 active calls.
+ """
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1, None, None, 1, host_rat=["volte", "5g_volte"])
+
+ # psim 5g nsa volte & esim 5g nsa volte & dds slot 0
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="1050ee12-d1aa-47c9-ad3a-589ad6c6b695")
+ def test_msim_cw_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ """Call waiting test on pSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CW on pSIM of the primary device.
+ 2. Let the pSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the pSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Hang up 2 calls from the 2nd and 3rd devices.
+ 6. Disable CW on pSIM of the primary device.
+ 7. Repeat step 2 & 3. In the step 3 the primary device should
+ not receive the incoming call.
+ """
+ result = True
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ None,
+ 0,
+ host_rat=["5g_volte", "5g_volte"],
+ merge=False, disable_cw=False):
+ result = False
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ None,
+ 0,
+ host_rat=["5g_volte", "5g_volte"],
+ merge=False,
+ disable_cw=True):
+ result = False
+ return result
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="74ae2673-fefb-459c-a415-366a12477956")
+ def test_msim_cw_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ """Call waiting test on eSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CW on eSIM of the primary device.
+ 2. Let the eSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the eSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Hang up 2 calls from the 2nd and 3rd devices.
+ 6. Disable CW on eSIM of the primary device.
+ 7. Repeat step 2 & 3. In the step 3 the primary device should
+ not receive the incoming call.
+ """
+ result = True
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ None,
+ 0,
+ host_rat=["5g_volte", "5g_volte"],
+ merge=False, disable_cw=False):
+ result = False
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ None,
+ 0,
+ host_rat=["5g_volte", "5g_volte"],
+ merge=False,
+ disable_cw=True):
+ result = False
+ return result
+
+ # psim 5g nsa volte & esim 5g nsa volte & dds slot 1
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="73b26c81-8080-4df0-a491-875e1290b5aa")
+ def test_msim_cw_psim_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ """Call waiting test on pSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+
+ Test steps:
+ 1. Enable CW on pSIM of the primary device.
+ 2. Let the pSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the pSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Hang up 2 calls from the 2nd and 3rd devices.
+ 6. Disable CW on pSIM of the primary device.
+ 7. Repeat step 2 & 3. In the step 3 the primary device should
+ not receive the incoming call.
+ """
+ result = True
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ None,
+ 1,
+ host_rat=["5g_volte", "5g_volte"],
+ merge=False, disable_cw=False):
+ result = False
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ None,
+ 1,
+ host_rat=["5g_volte", "5g_volte"],
+ merge=False,
+ disable_cw=True):
+ result = False
+ return result
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="32804d38-7def-4507-921d-f906d1cf9dfa")
+ def test_msim_cw_esim_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ """Call waiting test on eSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+
+ Test steps:
+ 1. Enable CW on eSIM of the primary device.
+ 2. Let the eSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the eSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Hang up 2 calls from the 2nd and 3rd devices.
+ 6. Disable CW on eSIM of the primary device.
+ 7. Repeat step 2 & 3. In the step 3 the primary device should
+ not receive the incoming call.
+ """
+ result = True
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ None,
+ 1,
+ host_rat=["5g_volte", "5g_volte"],
+ merge=False, disable_cw=False):
+ result = False
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ None,
+ 1,
+ host_rat=["5g_volte", "5g_volte"],
+ merge=False,
+ disable_cw=True):
+ result = False
+ return result
+
+ # psim 5g nsa volte & esim 4g volte & dds slot 0
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="753a8651-8230-4714-aa5c-32ed7e7d7c04")
+ def test_msim_cw_psim_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ """Call waiting test on pSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CW on pSIM of the primary device.
+ 2. Let the pSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the pSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Hang up 2 calls from the 2nd and 3rd devices.
+ 6. Disable CW on pSIM of the primary device.
+ 7. Repeat step 2 & 3. In the step 3 the primary device should
+ not receive the incoming call.
+ """
+ result = True
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ None,
+ 0,
+ host_rat=["5g_volte", "volte"],
+ merge=False, disable_cw=False):
+ result = False
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ None,
+ 0,
+ host_rat=["5g_volte", "volte"],
+ merge=False,
+ disable_cw=True):
+ result = False
+ return result
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="fc92c004-5862-4035-98b4-5ea3d3c2c5e9")
+ def test_msim_cw_esim_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ """Call waiting test on eSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CW on eSIM of the primary device.
+ 2. Let the eSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the eSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Hang up 2 calls from the 2nd and 3rd devices.
+ 6. Disable CW on eSIM of the primary device.
+ 7. Repeat step 2 & 3. In the step 3 the primary device should
+ not receive the incoming call.
+ """
+ result = True
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ None,
+ 0,
+ host_rat=["5g_volte", "volte"],
+ merge=False, disable_cw=False):
+ result = False
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ None,
+ 0,
+ host_rat=["5g_volte", "volte"],
+ merge=False,
+ disable_cw=True):
+ result = False
+ return result
+
+ # psim 5g nsa volte & esim 4g volte & dds slot 1
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="753a8651-8230-4714-aa5c-32ed7e7d7c04")
+ def test_msim_cw_psim_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ """Call waiting test on pSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CW on pSIM of the primary device.
+ 2. Let the pSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the pSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Hang up 2 calls from the 2nd and 3rd devices.
+ 6. Disable CW on pSIM of the primary device.
+ 7. Repeat step 2 & 3. In the step 3 the primary device should
+ not receive the incoming call.
+ """
+ result = True
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ None,
+ 1,
+ host_rat=["5g_volte", "volte"],
+ merge=False, disable_cw=False):
+ result = False
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ None,
+ 1,
+ host_rat=["5g_volte", "volte"],
+ merge=False,
+ disable_cw=True):
+ result = False
+ return result
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="fc92c004-5862-4035-98b4-5ea3d3c2c5e9")
+ def test_msim_cw_esim_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ """Call waiting test on eSIM of the primary device
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CW on eSIM of the primary device.
+ 2. Let the eSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the eSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Hang up 2 calls from the 2nd and 3rd devices.
+ 6. Disable CW on eSIM of the primary device.
+ 7. Repeat step 2 & 3. In the step 3 the primary device should
+ not receive the incoming call.
+ """
+ result = True
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ None,
+ 1,
+ host_rat=["5g_volte", "volte"],
+ merge=False, disable_cw=False):
+ result = False
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ None,
+ 1,
+ host_rat=["5g_volte", "volte"],
+ merge=False,
+ disable_cw=True):
+ result = False
+ return result
+
+ # psim 4g volte & esim 5g nsa volte & dds slot 0
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="4c02fc60-b838-40a1-879f-675d8c4b91af")
+ def test_msim_cw_psim_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ """Call waiting test on pSIM of the primary device
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CW on pSIM of the primary device.
+ 2. Let the pSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the pSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Hang up 2 calls from the 2nd and 3rd devices.
+ 6. Disable CW on pSIM of the primary device.
+ 7. Repeat step 2 & 3. In the step 3 the primary device should
+ not receive the incoming call.
+ """
+ result = True
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ None,
+ 0,
+ host_rat=["volte", "5g_volte"],
+ merge=False,
+ disable_cw=False):
+ result = False
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ None,
+ 0,
+ host_rat=["volte", "5g_volte"],
+ merge=False,
+ disable_cw=True):
+ result = False
+ return result
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="cbe58062-bd7f-48b5-aab1-84355a3fcf55")
+ def test_msim_cw_esim_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ """Call waiting test on eSIM of the primary device
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Test steps:
+ 1. Enable CW on eSIM of the primary device.
+ 2. Let the eSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the eSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Hang up 2 calls from the 2nd and 3rd devices.
+ 6. Disable CW on eSIM of the primary device.
+ 7. Repeat step 2 & 3. In the step 3 the primary device should
+ not receive the incoming call.
+ """
+ result = True
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ None,
+ 0,
+ host_rat=["volte", "5g_volte"],
+ merge=False,
+ disable_cw=False):
+ result = False
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ None,
+ 0,
+ host_rat=["volte", "5g_volte"],
+ merge=False,
+ disable_cw=True):
+ result = False
+ return result
+
+ # psim 4g volte & esim 5g nsa volte & dds slot 1
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="80c7e356-9419-484f-9b34-65ca5544bc39")
+ def test_msim_cw_psim_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ """Call waiting test on pSIM of the primary device
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CW on pSIM of the primary device.
+ 2. Let the pSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the pSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Hang up 2 calls from the 2nd and 3rd devices.
+ 6. Disable CW on pSIM of the primary device.
+ 7. Repeat step 2 & 3. In the step 3 the primary device should
+ not receive the incoming call.
+ """
+ result = True
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ None,
+ 1,
+ host_rat=["volte", "5g_volte"],
+ merge=False,
+ disable_cw=False):
+ result = False
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ None,
+ 1,
+ host_rat=["volte", "5g_volte"],
+ merge=False,
+ disable_cw=True):
+ result = False
+ return result
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="6cd6b062-d68a-4b1b-b6ca-92af72ebe3b9")
+ def test_msim_cw_esim_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ """Call waiting test on eSIM of the primary device
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+
+ Test steps:
+ 1. Enable CW on eSIM of the primary device.
+ 2. Let the eSIM of primary device call the 2nd device. Keep the
+ call active.
+ 3. Let the 3rd device call the eSIM of the primary device. Keep
+ both calls active.
+ 4. Swap the call twice.
+ 5. Hang up 2 calls from the 2nd and 3rd devices.
+ 6. Disable CW on eSIM of the primary device.
+ 7. Repeat step 2 & 3. In the step 3 the primary device should
+ not receive the incoming call.
+ """
+ result = True
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ None,
+ 1,
+ host_rat=["volte", "5g_volte"],
+ merge=False,
+ disable_cw=False):
+ result = False
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ None,
+ 1,
+ host_rat=["volte", "5g_volte"],
+ merge=False,
+ disable_cw=True):
+ result = False
+ return result
\ No newline at end of file
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSVoiceTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSVoiceTest.py
new file mode 100644
index 0000000..3544b8d
--- /dev/null
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSVoiceTest.py
@@ -0,0 +1,2857 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_dsds_utils import dsds_long_call_streaming_test
+from acts_contrib.test_utils.tel.tel_dsds_utils import dsds_voice_call_test
+from acts_contrib.test_utils.tel.tel_dsds_utils import enable_slot_after_voice_call_test
+from acts_contrib.test_utils.tel.tel_dsds_utils import enable_slot_after_data_call_test
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+
+
+class Nsa5gDSDSVoiceTest(TelephonyBaseTest):
+ def setup_class(self):
+ TelephonyBaseTest.setup_class(self)
+ self.tel_logger = TelephonyMetricLogger.for_test_case()
+
+ def teardown_test(self):
+ ensure_phones_idle(self.log, self.android_devices)
+
+ # psim 5g nsa volte & esim 5g nsa volte & dds slot 0
+ @test_tracker_info(uuid="8a8c3f42-f5d7-4299-8d84-64ac5377788f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ """A MO VoLTE call dialed at pSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 0,
+ mo_rat=["5g_volte", "5g_volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="b05b6aea-7c48-4412-b0b1-f57192fc786c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_volte_esim_5g_nsa_volte_dds_0(self):
+ """A MT VoLTE call received at pSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 0,
+ mt_rat=["5g_volte", "5g_volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="213d5e6f-97df-4c2a-9745-4e40a704853a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ """A MO VoLTE call dialed at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 0,
+ mo_rat=["5g_volte", "5g_volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="48a06a2f-b3d0-4b0e-85e5-2d439ee3147b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ """A MT VoLTE call received at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 0,
+ mt_rat=["5g_volte", "5g_volte"],
+ call_direction="mt")
+
+ # psim 5g nsa volte & esim 5g nsa volte & dds slot 1
+ @test_tracker_info(uuid="406bd5e5-b549-470d-b15a-20b4bb5ff3db")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ """A MO VoLTE call dialed at pSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 1,
+ mo_rat=["5g_volte", "5g_volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="a1e52cee-78ab-4d6e-859b-faf542b8056b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ """A MT VoLTE call received at pSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 1,
+ mt_rat=["5g_volte", "5g_volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="3b9d796c-b658-4bff-aae0-1243ce8c3d54")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ """A MO VoLTE call dialed at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 1,
+ mo_rat=["5g_volte", "5g_volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="e3edd065-72e1-4067-901c-1454706e9f43")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_volte_psim_5g_nsa_volte_dds_1(self):
+ """A MT VoLTE call received at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 1,
+ mt_rat=["5g_volte", "5g_volte"],
+ call_direction="mt")
+
+ # psim 5g nsa volte & esim 4g volte & dds slot 0
+ @test_tracker_info(uuid="2890827d-deb2-42ea-921d-3b45f7645d61")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ """A MO VoLTE call dialed at pSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 0,
+ mo_rat=["5g_volte", "volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="83d9b127-25da-4c19-a3a0-470a5ced020b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_volte_esim_4g_volte_dds_0(self):
+ """A MT VoLTE call received at pSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 0,
+ mt_rat=["5g_volte", "volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="14c29c79-d100-4f03-b3df-f2ae4a172cc5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ """A MO VoLTE call dialed at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 0,
+ mo_rat=["5g_volte", "volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="12a59cc1-8c1e-44a0-836b-0d842c0746a3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_4g_volte_psim_5g_nsa_volte_dds_0(self):
+ """A MT VoLTE call received at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 0,
+ mt_rat=["5g_volte", "volte"],
+ call_direction="mt")
+
+ # psim 5g nsa volte & esim 4g volte & dds slot 1
+ @test_tracker_info(uuid="9dfa66cc-f464-4964-9e5a-07e01d3e263e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ """A MO VoLTE call dialed at pSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 1,
+ mo_rat=["5g_volte", "volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="97e9ecc0-e377-46a8-9b13-ecedcb98922b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_volte_esim_4g_volte_dds_1(self):
+ """A MT VoLTE call received at pSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 1,
+ mt_rat=["5g_volte", "volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="5814cd18-e33b-45c5-b129-bec7e3992d8e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ """A MO VoLTE call dialed at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 1,
+ mo_rat=["5g_volte", "volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="457dd160-f7b1-4cfd-920f-1f5ab64f6d78")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_4g_volte_psim_5g_nsa_volte_dds_1(self):
+ """A MT VoLTE call received at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 1,
+ mt_rat=["5g_volte", "volte"],
+ call_direction="mt")
+
+ # psim 4g volte & esim 5g nsa volte & dds slot 0
+ @test_tracker_info(uuid="db5fca13-bcd8-420b-9953-256186efa290")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ """A MO VoLTE call dialed at pSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 0,
+ mo_rat=["volte", "5g_volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="2fe76eda-20b2-46ab-a1f4-c2c2bc501f38")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_4g_volte_esim_5g_nsa_volte_dds_0(self):
+ """A MT VoLTE call received at pSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 0,
+ mt_rat=["volte", "5g_volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="90005074-e21f-47c3-9965-54b513214600")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ """A MO VoLTE call dialed at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 0,
+ mo_rat=["volte", "5g_volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="eaf94a45-66d0-41d0-8cb2-153fa3f751f9")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_volte_psim_4g_volte_dds_0(self):
+ """A MT VoLTE call received at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 0)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 0,
+ mt_rat=["volte", "5g_volte"],
+ call_direction="mt")
+
+ # psim 4g volte & esim 5g nsa volte & dds slot 1
+ @test_tracker_info(uuid="8ee47ad7-24b6-4cd3-9443-6ab677695eb7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ """A MO VoLTE call dialed at pSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 1,
+ mo_rat=["volte", "5g_volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="8795b95d-a138-45cd-b45c-41ad4021589a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_4g_volte_esim_5g_nsa_volte_dds_1(self):
+ """A MT VoLTE call received at pSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 1,
+ mt_rat=["volte", "5g_volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="33f2fa73-de7b-4b68-b9b8-aa08f6511e1a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ """A MO VoLTE call dialed at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 1,
+ mo_rat=["volte", "5g_volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="b1ae55f1-dfd4-4e50-a0e3-df3b3ae29c68")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_volte_psim_4g_volte_dds_1(self):
+ """A MT VoLTE call received at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 1,
+ mt_rat=["volte", "5g_volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="f94d5fd2-79ac-426a-9a0d-1ba72e070b19")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_volte_psim_5g_nsa_volte_disable_psim(self):
+ """Disable/enable pSIM with MO voice call
+ Test step:
+ 1. Set the RAT to 5G at both slots.
+ 2. Disable pSIM.
+ 3. Switch DDS to eSIM.
+ 4. Verify RAT at slot 1 (eSIM) and also internet connection.
+ 5. Make a MO voice call.
+ 6. Enable pSIM.
+ 7. Switch DDS to pSIM.
+ 8. Verify RAT at slot 0 (pSIM) and also internet connection.
+ """
+ return enable_slot_after_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 0,
+ mo_rat=["5g_volte", "5g_volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="3b58146a-72d2-4544-b50b-f685d10da20a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_volte_psim_5g_nsa_volte_disable_psim(self):
+ """Disable/enable pSIM with MT voice call
+ Test step:
+ 1. Set the RAT to 5G at both slots.
+ 2. Disable pSIM.
+ 3. Switch DDS to eSIM.
+ 4. Verify RAT at slot 1 (eSIM) and also internet connection.
+ 5. Make a MT voice call.
+ 6. Enable pSIM.
+ 7. Switch DDS to pSIM.
+ 8. Verify RAT at slot 0 (pSIM) and also internet connection.
+ """
+ return enable_slot_after_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 0,
+ mt_rat=["5g_volte", "5g_volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="6b7fde1b-d51a-49df-b7d4-bf5e3d091895")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_data_esim_5g_nsa_volte_psim_5g_nsa_volte_disable_psim(self):
+ """Disable/enable pSIM with data call
+ Test step:
+ 1. Set the RAT to 5G at both slots.
+ 2. Disable pSIM.
+ 3. Switch DDS to eSIM.
+ 4. Verify RAT at slot 1 (eSIM) and also internet connection.
+ 5. Make a data call by http download.
+ 6. Enable pSIM.
+ 7. Switch DDS to pSIM.
+ 8. Verify RAT at slot 0 (pSIM) and also internet connection.
+ """
+ return enable_slot_after_data_call_test(
+ self.log,
+ self.android_devices[0],
+ 0,
+ rat=["5g_volte", "5g_volte"])
+
+ @test_tracker_info(uuid="dc490360-66b6-4796-a649-73bb09ce0cc1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_volte_esim_5g_nsa_volte_disable_esim(self):
+ """Disable/enable eSIM with MO voice call
+ Test step:
+ 1. Set the RAT to 5G at both slots.
+ 2. Disable eSIM.
+ 3. Switch DDS to pSIM.
+ 4. Verify RAT at slot 0 (pSIM) and also internet connection.
+ 5. Make a MO voice call.
+ 6. Enable eSIM.
+ 7. Switch DDS to eSIM.
+ 8. Verify RAT at slot 1 (eSIM) and also internet connection.
+ """
+ return enable_slot_after_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 1,
+ mo_rat=["5g_volte", "5g_volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="63f57c95-75be-4a51-83c6-609356bb301b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_volte_esim_5g_nsa_volte_disable_esim(self):
+ """Disable/enable eSIM with MT voice call
+ Test step:
+ 1. Set the RAT to 5G at both slots.
+ 2. Disable eSIM.
+ 3. Switch DDS to pSIM.
+ 4. Verify RAT at slot 0 (pSIM) and also internet connection.
+ 5. Make a MT voice call.
+ 6. Enable eSIM.
+ 7. Switch DDS to eSIM.
+ 8. Verify RAT at slot 1 (eSIM) and also internet connection.
+ """
+ return enable_slot_after_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 1,
+ mt_rat=["5g_volte", "5g_volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="7ad9e84a-dfa0-44e2-adde-390ae521b50b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_data_psim_5g_nsa_volte_esim_5g_nsa_volte_disable_esim(self):
+ """Disable/enable eSIM with data call
+ Test step:
+ 1. Set the RAT to 5G at both slots.
+ 2. Disable eSIM.
+ 3. Switch DDS to pSIM.
+ 4. Verify RAT at slot 0 (pSIM) and also internet connection.
+ 5. Make a data call by http download.
+ 6. Enable eSIM.
+ 7. Switch DDS to eSIM.
+ 8. Verify RAT at slot 1 (eSIM) and also internet connection.
+ """
+ return enable_slot_after_data_call_test(
+ self.log,
+ self.android_devices[0],
+ 1,
+ rat=["5g_volte", "5g_volte"])
+
+ @test_tracker_info(uuid="b1b02578-6e75-4a96-b3f3-c724fafbae2a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_volte_psim_4g_volte_disable_psim(self):
+ """Disable/enable pSIM with MO voice call
+ Test step:
+ 1. Set the RAT to LTE at slot 0 and 5G at slot 1.
+ 2. Disable pSIM.
+ 3. Switch DDS to eSIM.
+ 4. Verify RAT at slot 1 (eSIM) and also internet connection.
+ 5. Make a MO voice call.
+ 6. Enable pSIM.
+ 7. Switch DDS to pSIM.
+ 8. Verify RAT at slot 0 (pSIM) and also internet connection.
+ """
+ return enable_slot_after_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 0,
+ mo_rat=["volte", "5g_volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="15bb2fdd-ec38-47dc-a2f0-3251c8d19e3c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_volte_psim_4g_volte_disable_psim(self):
+ """Disable/enable pSIM with MT voice call
+ Test step:
+ 1. Set the RAT to LTE at slot 0 and 5G at slot 1.
+ 2. Disable pSIM.
+ 3. Switch DDS to eSIM.
+ 4. Verify RAT at slot 1 (eSIM) and also internet connection.
+ 5. Make a MT voice call.
+ 6. Enable pSIM.
+ 7. Switch DDS to pSIM.
+ 8. Verify RAT at slot 0 (pSIM) and also internet connection.
+ """
+ return enable_slot_after_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 0,
+ mt_rat=["volte", "5g_volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="37d5e72b-723f-4a26-87e9-cf54726476a6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_data_esim_5g_nsa_volte_psim_4g_volte_disable_psim(self):
+ """Disable/enable pSIM with data call
+ Test step:
+ 1. Set the RAT to LTE at slot 0 and 5G at slot 1.
+ 2. Disable pSIM.
+ 3. Switch DDS to eSIM.
+ 4. Verify RAT at slot 1 (eSIM) and also internet connection.
+ 5. Make a data call by http download.
+ 6. Enable pSIM.
+ 7. Switch DDS to pSIM.
+ 8. Verify RAT at slot 0 (pSIM) and also internet connection.
+ """
+ return enable_slot_after_data_call_test(
+ self.log,
+ self.android_devices[0],
+ 0,
+ rat=["volte", "5g_volte"])
+
+ @test_tracker_info(uuid="bc0dea98-cfe7-4cdd-8dd9-84eda4212fd4")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_4g_volte_esim_5g_nsa_volte_disable_esim(self):
+ """Disable/enable eSIM with MO voice call
+ Test step:
+ 1. Set the RAT to LTE at slot 0 and 5G at slot 1.
+ 2. Disable eSIM.
+ 3. Switch DDS to pSIM.
+ 4. Verify RAT at slot 0 (pSIM) and also internet connection.
+ 5. Make a MO voice call.
+ 6. Enable eSIM.
+ 7. Switch DDS to eSIM.
+ 8. Verify RAT at slot 1 (eSIM) and also internet connection.
+ """
+ return enable_slot_after_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 1,
+ mo_rat=["volte", "5g_volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="cfb8b670-6049-46fd-88ff-b9565ab2b582")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_4g_volte_esim_5g_nsa_volte_disable_esim(self):
+ """Disable/enable eSIM with MT voice call
+ Test step:
+ 1. Set the RAT to LTE at slot 0 and 5G at slot 1.
+ 2. Disable eSIM.
+ 3. Switch DDS to pSIM.
+ 4. Verify RAT at slot 0 (pSIM) and also internet connection.
+ 5. Make a MT voice call.
+ 6. Enable eSIM.
+ 7. Switch DDS to eSIM.
+ 8. Verify RAT at slot 1 (eSIM) and also internet connection.
+ """
+ return enable_slot_after_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 1,
+ mt_rat=["volte", "5g_volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="e2a18907-d9a4-491b-82c4-11ca86fc7129")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_data_psim_4g_volte_esim_5g_nsa_volte_disable_esim(self):
+ """Disable/enable eSIM with data call
+ Test step:
+ 1. Set the RAT to LTE at slot 0 and 5G at slot 1.
+ 2. Disable eSIM.
+ 3. Switch DDS to pSIM.
+ 4. Verify RAT at slot 0 (pSIM) and also internet connection.
+ 5. Make a data call by http download.
+ 6. Enable eSIM.
+ 7. Switch DDS to eSIM.
+ 8. Verify RAT at slot 1 (eSIM) and also internet connection.
+ """
+ return enable_slot_after_data_call_test(
+ self.log,
+ self.android_devices[0],
+ 1,
+ rat=["volte", "5g_volte"])
+
+ @test_tracker_info(uuid="13220595-9774-4f62-b1fb-3b6b98b51df3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_4g_volte_psim_5g_nsa_volte_disable_psim(self):
+ """Disable/enable pSIM with MO voice call
+ Test step:
+ 1. Set the RAT to 5G at slot 0 and LTE at slot 1.
+ 2. Disable pSIM.
+ 3. Switch DDS to eSIM.
+ 4. Verify RAT at slot 1 (eSIM) and also internet connection.
+ 5. Make a MO voice call.
+ 6. Enable pSIM.
+ 7. Switch DDS to pSIM.
+ 8. Verify RAT at slot 0 (pSIM) and also internet connection.
+ """
+ return enable_slot_after_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 0,
+ mo_rat=["5g_volte", "volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="57e3e643-26a9-4e32-ac55-a0f7e4a72148")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_4g_volte_psim_5g_nsa_volte_disable_psim(self):
+ """Disable/enable pSIM with MT voice call
+ Test step:
+ 1. Set the RAT to 5G at slot 0 and LTE at slot 1.
+ 2. Disable pSIM.
+ 3. Switch DDS to eSIM.
+ 4. Verify RAT at slot 1 (eSIM) and also internet connection.
+ 5. Make a MT voice call.
+ 6. Enable pSIM.
+ 7. Switch DDS to pSIM.
+ 8. Verify RAT at slot 0 (pSIM) and also internet connection.
+ """
+ return enable_slot_after_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 0,
+ mt_rat=["5g_volte", "volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="3d809e0d-e75e-4ccd-af38-80d465d14eb7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_data_esim_4g_volte_psim_5g_nsa_volte_disable_psim(self):
+ """Disable/enable pSIM with data call
+ Test step:
+ 1. Set the RAT to 5G at slot 0 and LTE at slot 1.
+ 2. Disable pSIM.
+ 3. Switch DDS to eSIM.
+ 4. Verify RAT at slot 1 (eSIM) and also internet connection.
+ 5. Make a data call by http download.
+ 6. Enable pSIM.
+ 7. Switch DDS to pSIM.
+ 8. Verify RAT at slot 0 (pSIM) and also internet connection.
+ """
+ return enable_slot_after_data_call_test(
+ self.log,
+ self.android_devices[0],
+ 0,
+ rat=["5g_volte", "volte"])
+
+ @test_tracker_info(uuid="c54ab348-367f-43c9-9aae-fa2c3d3badec")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_volte_esim_4g_volte_disable_esim(self):
+ """Disable/enable eSIM with MO voice call
+ Test step:
+ 1. Set the RAT to 5G at slot 0 and LTE at slot 1.
+ 2. Disable eSIM.
+ 3. Switch DDS to pSIM.
+ 4. Verify RAT at slot 0 (pSIM) and also internet connection.
+ 5. Make a MO voice call.
+ 6. Enable eSIM.
+ 7. Switch DDS to eSIM.
+ 8. Verify RAT at slot 1 (eSIM) and also internet connection.
+ """
+ return enable_slot_after_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 1,
+ mo_rat=["5g_volte", "volte"],
+ call_direction="mo")
+
+ @test_tracker_info(uuid="db8e5cdc-c34f-48d4-8ebe-2a71e03c159f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_volte_esim_4g_volte_disable_esim(self):
+ """Disable/enable eSIM with MT voice call
+ Test step:
+ 1. Set the RAT to 5G at slot 0 and LTE at slot 1.
+ 2. Disable eSIM.
+ 3. Switch DDS to pSIM.
+ 4. Verify RAT at slot 0 (pSIM) and also internet connection.
+ 5. Make a MT voice call.
+ 6. Enable eSIM.
+ 7. Switch DDS to eSIM.
+ 8. Verify RAT at slot 1 (eSIM) and also internet connection.
+ """
+ return enable_slot_after_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 1,
+ mt_rat=["5g_volte", "volte"],
+ call_direction="mt")
+
+ @test_tracker_info(uuid="a271d5f2-4449-4961-8417-14943fa96144")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_data_psim_5g_nsa_volte_esim_4g_volte_disable_esim(self):
+ """Disable/enable eSIM with data call
+ Test step:
+ 1. Set the RAT to 5G at slot 0 and LTE at slot 1.
+ 2. Disable eSIM.
+ 3. Switch DDS to pSIM.
+ 4. Verify RAT at slot 0 (pSIM) and also internet connection.
+ 5. Make a data call by http download.
+ 6. Enable eSIM.
+ 7. Switch DDS to eSIM.
+ 8. Verify RAT at slot 1 (eSIM) and also internet connection.
+ """
+ return enable_slot_after_data_call_test(
+ self.log,
+ self.android_devices[0],
+ 1,
+ rat=["5g_volte", "volte"])
+
+ @test_tracker_info(uuid="f86faed8-5259-4e5d-9e49-40618ad41670")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_wfc_wifi_preferred_esim_5g_nsa_volte_dds_0(self):
+ """ A MO vowifi call at pSIM, where
+ - pSIM 5G WFC in Wi-Fi preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 0,
+ mo_rat=["5g_wfc", "5g_volte"],
+ call_direction="mo",
+ wfc_mode = [WFC_MODE_WIFI_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="1e13a8be-7ddd-4177-89cb-720d305d766e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_wfc_wifi_preferred_esim_5g_nsa_volte_dds_0(self):
+ """ A MT vowifi call at pSIM, where
+ - pSIM 5G WFC in Wi-Fi preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 0,
+ mt_rat=["5g_wfc", "5g_volte"],
+ call_direction="mt",
+ wfc_mode = [WFC_MODE_WIFI_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="d32696a1-6e6d-48ca-8612-06e24645cfc6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_wfc_wifi_preferred_psim_5g_nsa_volte_dds_0(self):
+ """ A MO vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G WFC in Wi-Fi preferred mode
+ - DDS at pSIM (slot 0)
+
+ Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 0,
+ mo_rat=["5g_volte", "5g_wfc"],
+ call_direction="mo",
+ wfc_mode = [None, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="9ed35291-ae87-469a-a12f-8df2c17daa6e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_wfc_wifi_preferred_psim_5g_nsa_volte_dds_0(self):
+ """ A MT vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G WFC in Wi-Fi preferred mode
+ - DDS at pSIM (slot 0)
+
+ Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 0,
+ mt_rat=["5g_volte", "5g_wfc"],
+ call_direction="mt",
+ wfc_mode = [None, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="a44352d0-8ded-4e42-bd77-59c9f5801954")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_wfc_wifi_preferred_esim_5g_nsa_volte_dds_1(self):
+ """ A MO vowifi call at pSIM, where
+ - pSIM 5G WFC in Wi-Fi preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+
+ Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 1,
+ mo_rat=["5g_wfc", "5g_volte"],
+ call_direction="mo",
+ wfc_mode = [WFC_MODE_WIFI_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="6e99a297-6deb-4674-90e1-1f703971501a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_wfc_wifi_preferred_esim_5g_nsa_volte_dds_1(self):
+ """ A MT vowifi call at pSIM, where
+ - pSIM 5G WFC in Wi-Fi preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+
+ Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 1,
+ mt_rat=["5g_wfc", "5g_volte"],
+ call_direction="mt",
+ wfc_mode = [WFC_MODE_WIFI_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="119f71a5-9d5d-4c66-b958-684672a95a87")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_wfc_wifi_preferred_psim_5g_nsa_volte_dds_1(self):
+ """ A MO vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G WFC in Wi-Fi preferred mode
+ - DDS at eSIM (slot 1)
+
+ Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 1,
+ mo_rat=["5g_volte", "5g_wfc"],
+ call_direction="mo",
+ wfc_mode = [None, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="55e651d2-4112-4fe9-a70d-f448287b078b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_wfc_wifi_preferred_psim_5g_nsa_volte_dds_1(self):
+ """ A MT vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G WFC in Wi-Fi preferred mode
+ - DDS at eSIM (slot 1)
+
+ Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 1,
+ mt_rat=["5g_volte", "5g_wfc"],
+ call_direction="mt",
+ wfc_mode = [None, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="10ce825e-8ed8-4bc8-a70f-e0822d391066")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_4g_wfc_wifi_preferred_esim_5g_nsa_volte_dds_0(self):
+ """ A MO vowifi call at pSIM, where
+ - pSIM 4G WFC in Wi-Fi preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 0,
+ mo_rat=["wfc", "5g_volte"],
+ call_direction="mo",
+ wfc_mode = [WFC_MODE_WIFI_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="39cb207c-10e5-4f6a-8ee4-0f26634070cb")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_4g_wfc_wifi_preferred_esim_5g_nsa_volte_dds_0(self):
+ """ A MT vowifi call at pSIM, where
+ - pSIM 4G WFC in Wi-Fi preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 0,
+ mt_rat=["wfc", "5g_volte"],
+ call_direction="mt",
+ wfc_mode = [WFC_MODE_WIFI_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="a2245d31-c3ca-42bf-a6ca-72f3d3dc32e9")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_wfc_wifi_preferred_psim_4g_volte_dds_0(self):
+ """ A MO vowifi call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G WFC in Wi-Fi preferred mode
+ - DDS at pSIM (slot 0)
+
+ Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 0,
+ mo_rat=["volte", "5g_wfc"],
+ call_direction="mo",
+ wfc_mode = [None, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="2d683601-b604-4dba-b5b8-8aec86d70f95")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_wfc_wifi_preferred_psim_4g_volte_dds_0(self):
+ """ A MT vowifi call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G WFC in Wi-Fi preferred mode
+ - DDS at pSIM (slot 0)
+
+ Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 0,
+ mt_rat=["volte", "5g_wfc"],
+ call_direction="mt",
+ wfc_mode = [None, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="7c79782e-e273-43a4-9176-48a7b5a8cb85")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_4g_wfc_wifi_preferred_esim_5g_nsa_volte_dds_1(self):
+ """ A MO vowifi call at pSIM, where
+ - pSIM 4G WFC in Wi-Fi preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+
+ Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 1,
+ mo_rat=["wfc", "5g_volte"],
+ call_direction="mo",
+ wfc_mode = [WFC_MODE_WIFI_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="1b9c6b37-2345-46af-a6eb-48ebd962c953")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_4g_wfc_wifi_preferred_esim_5g_nsa_volte_dds_1(self):
+ """ A MT vowifi call at pSIM, where
+ - pSIM 4G WFC in Wi-Fi preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+
+ Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 1,
+ mt_rat=["wfc", "5g_volte"],
+ call_direction="mt",
+ wfc_mode = [WFC_MODE_WIFI_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="ce37ebda-f83b-4482-9214-74e82e04ae7f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_wfc_wifi_preferred_psim_4g_volte_dds_1(self):
+ """ A MO vowifi call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G WFC in Wi-Fi preferred mode
+ - DDS at eSIM (slot 1)
+
+ Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 1,
+ mo_rat=["volte", "5g_wfc"],
+ call_direction="mo",
+ wfc_mode = [None, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="3ba071ba-bf6f-4c27-ae82-557dabb60291")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_wfc_wifi_preferred_psim_4g_volte_dds_1(self):
+ """ A MT vowifi call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G WFC in Wi-Fi preferred mode
+ - DDS at eSIM (slot 1)
+
+ Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 1,
+ mt_rat=["volte", "5g_wfc"],
+ call_direction="mt",
+ wfc_mode = [None, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="1385939f-272e-4ba7-ba5d-de1bff60ad01")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_wfc_wifi_preferred_esim_4g_volte_dds_0(self):
+ """ A MO vowifi call at pSIM, where
+ - pSIM 5G WFC in Wi-Fi preferred mode
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+
+ Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 0,
+ mo_rat=["5g_wfc", "volte"],
+ call_direction="mo",
+ wfc_mode = [WFC_MODE_WIFI_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="79d24164-bbcc-49c6-a538-99b39b65749b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_wfc_wifi_preferred_esim_4g_volte_dds_0(self):
+ """ A MT vowifi call at pSIM, where
+ - pSIM 5G WFC in Wi-Fi preferred mode
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+
+ Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 0,
+ mt_rat=["5g_wfc", "volte"],
+ call_direction="mt",
+ wfc_mode = [WFC_MODE_WIFI_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="837186d2-fe35-4d4a-900d-0bc5b71829b7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_4g_wfc_wifi_preferred_psim_5g_nsa_volte_dds_0(self):
+ """ A MO vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G WFC in Wi-Fi preferred mode
+ - DDS at pSIM (slot 0)
+
+ Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 0,
+ mo_rat=["5g_volte", "wfc"],
+ call_direction="mo",
+ wfc_mode = [None, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="ace4d07a-07ba-4868-bfa1-c82a81bce4c9")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_4g_wfc_wifi_preferred_psim_5g_nsa_volte_dds_0(self):
+ """ A MT vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G WFC in Wi-Fi preferred mode
+ - DDS at pSIM (slot 0)
+
+ Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 0,
+ mt_rat=["5g_volte", "wfc"],
+ call_direction="mt",
+ wfc_mode = [None, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="17306fd2-842e-47d9-bd83-e5a34fce1d5a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_wfc_wifi_preferred_esim_4g_volte_dds_1(self):
+ """ A MO vowifi call at pSIM, where
+ - pSIM 5G WFC in Wi-Fi preferred mode
+ - eSIM 4G VoLTE
+ - DDS at eSIM (slot 1)
+
+ Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 1,
+ mo_rat=["5g_wfc", "volte"],
+ call_direction="mo",
+ wfc_mode = [WFC_MODE_WIFI_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="352b0f73-f89a-45cf-9810-147e8a1b1522")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_wfc_wifi_preferred_esim_4g_volte_dds_1(self):
+ """ A MT vowifi call at pSIM, where
+ - pSIM 5G WFC in Wi-Fi preferred mode
+ - eSIM 4G VoLTE
+ - DDS at eSIM (slot 1)
+
+ Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 1,
+ mt_rat=["5g_wfc", "volte"],
+ call_direction="mt",
+ wfc_mode = [WFC_MODE_WIFI_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="4a574fee-dc59-45a6-99a6-18098053adf3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_4g_wfc_wifi_preferred_psim_5g_nsa_volte_dds_1(self):
+ """ A MO vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G WFC in Wi-Fi preferred mode
+ - DDS at eSIM (slot 1)
+
+ Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 1,
+ mo_rat=["5g_volte", "wfc"],
+ call_direction="mo",
+ wfc_mode = [None, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="c70a2aa8-5567-4f74-9a2c-a24214d6af74")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_4g_wfc_wifi_preferred_psim_5g_nsa_volte_dds_1(self):
+ """ A MT vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G WFC in Wi-Fi preferred mode
+ - DDS at eSIM (slot 1)
+
+ Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 1,
+ mt_rat=["5g_volte", "wfc"],
+ call_direction="mt",
+ wfc_mode = [None, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True)
+
+ @test_tracker_info(uuid="1f5f9721-0dbb-443d-b54f-2e4acdc2e1a6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_wfc_cellular_preferred_esim_5g_nsa_volte_dds_0(self):
+ """ A MO vowifi call at pSIM, where
+ - pSIM 5G WFC in cellular preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 0,
+ mo_rat=["5g_wfc", "5g_volte"],
+ call_direction="mo",
+ is_airplane_mode=True,
+ wfc_mode = [WFC_MODE_CELLULAR_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="00723b82-3fa5-4263-b56f-a27ba76f24bd")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_wfc_cellular_preferred_esim_5g_nsa_volte_dds_0(self):
+ """ A MT vowifi call at pSIM, where
+ - pSIM 5G WFC in cellular preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 0,
+ mt_rat=["5g_wfc", "5g_volte"],
+ call_direction="mt",
+ is_airplane_mode=True,
+ wfc_mode = [WFC_MODE_CELLULAR_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="5d024b1c-e345-45e8-9759-9f8729799a05")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_wfc_cellular_preferred_psim_5g_nsa_volte_dds_0(self):
+ """ A MO vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G WFC in cellular preferred mode
+ - DDS at pSIM (slot 0)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 0,
+ mo_rat=["5g_volte", "5g_wfc"],
+ call_direction="mo",
+ is_airplane_mode=True,
+ wfc_mode = [None, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="9627755c-3dea-4296-8140-eac0037c4f17")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_wfc_cellular_preferred_psim_5g_nsa_volte_dds_0(self):
+ """ A MT vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G WFC in cellular preferred mode
+ - DDS at pSIM (slot 0)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 0,
+ mt_rat=["5g_volte", "5g_wfc"],
+ call_direction="mt",
+ is_airplane_mode=True,
+ wfc_mode = [None, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="aeddb446-8ec1-4692-9b6c-417aa89205eb")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_wfc_cellular_preferred_esim_5g_nsa_volte_dds_1(self):
+ """ A MO vowifi call at pSIM, where
+ - pSIM 5G WFC in cellular preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 1,
+ mo_rat=["5g_wfc", "5g_volte"],
+ call_direction="mo",
+ is_airplane_mode=True,
+ wfc_mode = [WFC_MODE_CELLULAR_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="4e56a128-0706-4f48-a031-93c77faa5e5a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_wfc_cellular_preferred_esim_5g_nsa_volte_dds_1(self):
+ """ A MT vowifi call at pSIM, where
+ - pSIM 5G WFC in cellular preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 1,
+ mt_rat=["5g_wfc", "5g_volte"],
+ call_direction="mt",
+ is_airplane_mode=True,
+ wfc_mode = [WFC_MODE_CELLULAR_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="8adbe013-4f93-4778-8f82-f7db3be8c318")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_wfc_cellular_preferred_psim_5g_nsa_volte_dds_1(self):
+ """ A MO vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G WFC in cellular preferred mode
+ - DDS at eSIM (slot 1)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 1,
+ mo_rat=["5g_volte", "5g_wfc"],
+ call_direction="mo",
+ is_airplane_mode=True,
+ wfc_mode = [None, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="75fe4f90-8945-4886-92ad-29d0d536163d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_wfc_cellular_preferred_psim_5g_nsa_volte_dds_1(self):
+ """ A MT vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G WFC in cellular preferred mode
+ - DDS at eSIM (slot 1)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 1,
+ mt_rat=["5g_volte", "5g_wfc"],
+ call_direction="mt",
+ is_airplane_mode=True,
+ wfc_mode = [None, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="25716018-d4cc-4b62-ac00-77d34b3920e1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_4g_wfc_cellular_preferred_esim_5g_nsa_volte_dds_0(self):
+ """ A MO vowifi call at pSIM, where
+ - pSIM 4G WFC in cellular preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 0,
+ mo_rat=["wfc", "5g_volte"],
+ call_direction="mo",
+ is_airplane_mode=True,
+ wfc_mode = [WFC_MODE_CELLULAR_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="ae7a19bb-f257-4853-83ff-25dd70696d76")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_4g_wfc_cellular_preferred_esim_5g_nsa_volte_dds_0(self):
+ """ A MT vowifi call at pSIM, where
+ - pSIM 4G WFC in cellular preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 0,
+ mt_rat=["wfc", "5g_volte"],
+ call_direction="mt",
+ is_airplane_mode=True,
+ wfc_mode = [WFC_MODE_CELLULAR_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="c498a7fc-8c5d-4b5d-bd9e-47bd77032765")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_wfc_cellular_preferred_psim_4g_volte_dds_0(self):
+ """ A MO vowifi call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G WFC in cellular preferred mode
+ - DDS at pSIM (slot 0)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 0,
+ mo_rat=["volte", "5g_wfc"],
+ call_direction="mo",
+ is_airplane_mode=True,
+ wfc_mode = [None, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="ce7b23af-41f1-4977-a140-6e1a456487dc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_wfc_cellular_preferred_psim_4g_volte_dds_0(self):
+ """ A MT vowifi call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G WFC in cellular preferred mode
+ - DDS at pSIM (slot 0)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 0,
+ mt_rat=["volte", "5g_wfc"],
+ call_direction="mt",
+ is_airplane_mode=True,
+ wfc_mode = [None, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="808fab1e-1fe7-406a-b479-8e9e6a5c2ef5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_4g_wfc_cellular_preferred_esim_5g_nsa_volte_dds_1(self):
+ """ A MO vowifi call at pSIM, where
+ - pSIM 4G WFC in cellular preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 1,
+ mo_rat=["wfc", "5g_volte"],
+ call_direction="mo",
+ is_airplane_mode=True,
+ wfc_mode = [WFC_MODE_CELLULAR_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="4b0f73a8-a508-4e77-aca2-0155b54b4e2c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_4g_wfc_cellular_preferred_esim_5g_nsa_volte_dds_1(self):
+ """ A MT vowifi call at pSIM, where
+ - pSIM 4G WFC in cellular preferred mode
+ - eSIM 5G NSA VoLTE
+ - DDS at eSIM (slot 1)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 1,
+ mt_rat=["wfc", "5g_volte"],
+ call_direction="mt",
+ is_airplane_mode=True,
+ wfc_mode = [WFC_MODE_CELLULAR_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="4a73fdb3-abf3-4094-9317-74b758991c0a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_5g_nsa_wfc_cellular_preferred_psim_4g_volte_dds_1(self):
+ """ A MO vowifi call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G WFC in cellular preferred mode
+ - DDS at eSIM (slot 1)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 1,
+ mo_rat=["volte", "5g_wfc"],
+ call_direction="mo",
+ is_airplane_mode=True,
+ wfc_mode = [None, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="5247d0dc-2d60-4760-8c27-a9b358992849")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_5g_nsa_wfc_cellular_preferred_psim_4g_volte_dds_1(self):
+ """ A MT vowifi call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G WFC in cellular preferred mode
+ - DDS at eSIM (slot 1)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 1,
+ mt_rat=["volte", "5g_wfc"],
+ call_direction="mt",
+ is_airplane_mode=True,
+ wfc_mode = [None, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="df037a28-c130-4d00-ba2e-28723af26128")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_wfc_cellular_preferred_esim_4g_volte_dds_0(self):
+ """ A MO vowifi call at pSIM, where
+ - pSIM 5G WFC in cellular preferred mode
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 0,
+ mo_rat=["5g_wfc", "volte"],
+ call_direction="mo",
+ is_airplane_mode=True,
+ wfc_mode = [WFC_MODE_CELLULAR_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="900a7a74-064b-43df-b40a-8257ea9a1598")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_wfc_cellular_preferred_esim_4g_volte_dds_0(self):
+ """ A MT vowifi call at pSIM, where
+ - pSIM 5G WFC in cellular preferred mode
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 0,
+ mt_rat=["5g_wfc", "volte"],
+ call_direction="mt",
+ is_airplane_mode=True,
+ wfc_mode = [WFC_MODE_CELLULAR_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="08057239-a1de-42e5-8ff2-560d6a7a7e35")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_4g_wfc_cellular_preferred_psim_5g_nsa_volte_dds_0(self):
+ """ A MO vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G WFC in cellular preferred mode
+ - DDS at pSIM (slot 0)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 0,
+ mo_rat=["5g_volte", "wfc"],
+ call_direction="mo",
+ is_airplane_mode=True,
+ wfc_mode = [None, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="edd15dd4-4abe-4de0-905e-6dd2aebf2697")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_4g_wfc_cellular_preferred_psim_5g_nsa_volte_dds_0(self):
+ """ A MT vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G WFC in cellular preferred mode
+ - DDS at pSIM (slot 0)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 0,
+ mt_rat=["5g_volte", "wfc"],
+ call_direction="mt",
+ is_airplane_mode=True,
+ wfc_mode = [None, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="c230b98b-fbe2-4fc5-b0a0-cc91c5613ade")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mo_5g_nsa_wfc_cellular_preferred_esim_4g_volte_dds_1(self):
+ """ A MO vowifi call at pSIM, where
+ - pSIM 5G WFC in cellular preferred mode
+ - eSIM 4G VoLTE
+ - DDS at eSIM (slot 1)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ 1,
+ mo_rat=["5g_wfc", "volte"],
+ call_direction="mo",
+ is_airplane_mode=True,
+ wfc_mode = [WFC_MODE_CELLULAR_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="1e0eb29c-4850-4f42-b83f-d831305eeaa7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_psim_mt_5g_nsa_wfc_cellular_preferred_esim_4g_volte_dds_1(self):
+ """ A MT vowifi call at pSIM, where
+ - pSIM 5G WFC in cellular preferred mode
+ - eSIM 4G VoLTE
+ - DDS at eSIM (slot 1)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the pSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 0,
+ 1,
+ mt_rat=["5g_wfc", "volte"],
+ call_direction="mt",
+ is_airplane_mode=True,
+ wfc_mode = [WFC_MODE_CELLULAR_PREFERRED, None],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="2fd7d04f-1ce7-40d0-86f1-ebf042dfad8b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mo_4g_wfc_cellular_preferred_psim_5g_nsa_volte_dds_1(self):
+ """ A MO vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G WFC in cellular preferred mode
+ - DDS at eSIM (slot 1)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ 1,
+ mo_rat=["5g_volte", "wfc"],
+ call_direction="mo",
+ is_airplane_mode=True,
+ wfc_mode = [None, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="fd3bace9-f9ce-4870-8818-74f9b1605716")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_voice_esim_mt_4g_wfc_cellular_preferred_psim_5g_nsa_volte_dds_1(self):
+ """ A MT vowifi call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G WFC in cellular preferred mode
+ - DDS at eSIM (slot 1)
+ - Airplane mode
+
+ Airplane mode and Wi-Fi will be turned off in the end to ensure the eSIM will attach to
+ the network with assigned RAT successfully.
+ """
+ return dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ None,
+ 1,
+ 1,
+ mt_rat=["5g_volte", "wfc"],
+ call_direction="mt",
+ is_airplane_mode=True,
+ wfc_mode = [None, WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass,
+ turn_off_wifi_in_the_end=True,
+ turn_off_airplane_mode_in_the_end=True)
+
+ @test_tracker_info(uuid="f07a4924-0752-41fd-8e52-e75c3c78c538")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_esim_mo_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ """ A MO VoLTE long call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mo",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="cac09fa6-5db1-4523-910a-7fe9918a04ac")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_esim_mt_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ """ A MT VoLTE long call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mt",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="a0039ac0-9d3d-4acf-801b-4b0d01971153")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_esim_mo_volte_psim_5g_nsa_volte_dds_0(self):
+ """ A MO VoLTE long call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mo",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="9cf03491-df27-4eda-9e3d-7782a44c0674")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_esim_mt_volte_psim_5g_nsa_volte_dds_0(self):
+ """ A MT VoLTE long call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mt",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="6c8c7e67-3bec-49b4-8164-963e488df14f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_esim_mo_5g_nsa_volte_psim_volte_dds_0(self):
+ """ A MO VoLTE long call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "5g_volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mo",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="9a2bc9a2-18a2-471f-9b21-fd0aea1b126b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_esim_mt_5g_nsa_volte_psim_volte_dds_0(self):
+ """ A MT VoLTE long call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "5g_volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mt",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="c88a0ed6-f8b6-4033-93db-b160c29d4b9e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_psim_mo_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ """ A MO VoLTE long call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mo",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="b4aa294d-679d-4a0e-8cc9-9261bfe8b392")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_psim_mt_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ """ A MT VoLTE long call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mt",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="2e20f05f-9434-410f-a40a-a01c0303d1a0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_psim_mo_5g_nsa_volte_esim_volte_dds_1(self):
+ """ A MO VoLTE long call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mo",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="3f89b354-0cdc-4522-8a67-76773219e5af")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_psim_mt_5g_nsa_volte_esim_volte_dds_1(self):
+ """ A MT VoLTE long call at eSIM, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mt",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="f18c61c5-3c3b-4645-90eb-e7bdef9b7c74")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_psim_mo_volte_esim_5g_nsa_volte_dds_1(self):
+ """ A MO VoLTE long call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "5g_volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mo",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="8324ffe2-1332-47fc-af92-a3ed7be9b629")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_psim_mt_volte_esim_5g_nsa_volte_dds_1(self):
+ """ A MT VoLTE long call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "5g_volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mt",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="e6760078-2a5e-4182-8ba1-57788fc607f1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_esim_mo_volte_psim_volte_dds_0(self):
+ """ A MO VoLTE long call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mo",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="c736e4f0-8dbc-480a-8da6-68453cc13d07")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_esim_mt_volte_psim_volte_dds_0(self):
+ """ A MO VoLTE long call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mt",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="19dc55b5-b989-481d-a980-fcd0ff56abc2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_psim_mo_volte_esim_volte_dds_1(self):
+ """ A MO VoLTE long call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mo",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="494e9c90-6c56-4fa1-9fac-ac8f2b1c0dba")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_psim_mt_volte_esim_volte_dds_1(self):
+ """ A MT VoLTE long call at eSIM, where
+ - pSIM 4G VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mt",
+ duration=360,
+ streaming=False)
+
+ @test_tracker_info(uuid="d253553d-7dc9-4e38-8e20-0839326c20aa")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_esim_mo_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ """ A MO VoLTE long call at eSIM during streaming, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mo",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="80a201c5-0bfe-4d7f-b08b-52b7c53b6468")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_esim_mt_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+ """ A MT VoLTE long call at eSIM during streaming, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mt",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="8938575b-2544-4075-9cf9-3d938ad4d9cb")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_esim_mo_volte_psim_5g_nsa_volte_dds_0(self):
+ """ A MO VoLTE long call at eSIM during streaming, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mo",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="200c7cce-aba2-40f8-a274-9b05177d00e0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_esim_mt_volte_psim_5g_nsa_volte_dds_0(self):
+ """ A MT VoLTE long call at eSIM during streaming, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 0)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mt",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="26bb9415-44f4-43df-b2e6-abbdfacf33c2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_esim_mo_5g_nsa_volte_psim_volte_dds_0(self):
+ """ A MO VoLTE long call at eSIM during streaming, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "5g_volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mo",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="8a8dc1ca-6a85-4dc8-9e34-e17abe61f7b8")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_esim_mt_5g_nsa_volte_psim_volte_dds_0(self):
+ """ A MT VoLTE long call at eSIM during streaming, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 0)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "5g_volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mt",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="903a2813-6b27-4020-aaf2-b5ab8b29fa13")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_psim_mo_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ """ A MO VoLTE long call at eSIM during streaming, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mo",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="33d8ba2c-fa45-4ec0-aef5-b191b6ddd9a6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_psim_mt_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+ """ A MT VoLTE long call at eSIM during streaming, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "5g_volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mt",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="6db23c84-13d9-47fa-b8f1-45c56e2d6428")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_psim_mo_5g_nsa_volte_esim_volte_dds_1(self):
+ """ A MO VoLTE long call at eSIM during streaming, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mo",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="3a77b38f-c327-4c43-addf-48832bca7148")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_psim_mt_5g_nsa_volte_esim_volte_dds_1(self):
+ """ A MT VoLTE long call at eSIM during streaming, where
+ - pSIM 5G NSA VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["5g_volte", "volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mt",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="2898eb67-3dfe-4322-8c69-817e0a95dfda")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_psim_mo_volte_esim_5g_nsa_volte_dds_1(self):
+ """ A MO VoLTE long call at eSIM during streaming, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "5g_volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mo",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="780e8187-2068-4eca-a9de-e5f2f3491403")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_psim_mt_volte_esim_5g_nsa_volte_dds_1(self):
+ """ A MT VoLTE long call at eSIM during streaming, where
+ - pSIM 4G VoLTE
+ - eSIM 5G NSA VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "5g_volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mt",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="9b84bd00-fae3-45c0-9e44-dd57d1719bb9")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_esim_mo_volte_psim_volte_dds_0(self):
+ """ A MO VoLTE long call at eSIM during streaming, where
+ - pSIM 4G VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mo",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="813c6059-bcef-42d3-b70b-9b0ba67ffc20")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_esim_mt_volte_psim_volte_dds_0(self):
+ """ A MO VoLTE long call at eSIM during streaming, where
+ - pSIM 4G VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "volte"],
+ test_slot=1,
+ dds_slot=0,
+ direction="mt",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="970b1d31-195b-4599-80bc-bc46ede43a90")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_psim_mo_volte_esim_volte_dds_1(self):
+ """ A MO VoLTE long call at eSIM during streaming, where
+ - pSIM 4G VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mo",
+ duration=360,
+ streaming=True)
+
+ @test_tracker_info(uuid="62843f60-5d1c-44ed-9936-e10d2691e787")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_long_voice_streaming_psim_mt_volte_esim_volte_dds_1(self):
+ """ A MT VoLTE long call at eSIM during streaming, where
+ - pSIM 4G VoLTE
+ - eSIM 4G VoLTE
+ - DDS at pSIM (slot 1)
+
+ After call end will check the eSIM if is attach to the network
+ with assigned RAT successfully and data works fine.
+ """
+ return dsds_long_call_streaming_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ test_rat=["volte", "volte"],
+ test_slot=0,
+ dds_slot=1,
+ direction="mt",
+ duration=360,
+ streaming=True)
\ No newline at end of file
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSWfcSupplementaryServiceTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSWfcSupplementaryServiceTest.py
new file mode 100644
index 0000000..de31b45
--- /dev/null
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSWfcSupplementaryServiceTest.py
@@ -0,0 +1,318 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+from acts import signals
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_CONFERENCE
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_dsds_utils import erase_call_forwarding
+from acts_contrib.test_utils.tel.tel_dsds_utils import msim_volte_wfc_call_forwarding
+from acts_contrib.test_utils.tel.tel_dsds_utils import msim_volte_wfc_call_voice_conf
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
+from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_wifi_utils import set_wifi_to_default
+
+
+class Nsa5gDSDSWfcSupplementaryServiceTest(TelephonyBaseTest):
+ def setup_class(self):
+ TelephonyBaseTest.setup_class(self)
+ self.tel_logger = TelephonyMetricLogger.for_test_case()
+ toggle_airplane_mode(self.log, self.android_devices[0], False)
+ erase_call_forwarding(self.log, self.android_devices[0])
+ if not get_capability_for_subscription(
+ self.android_devices[0],
+ CAPABILITY_CONFERENCE,
+ get_outgoing_voice_sub_id(self.android_devices[0])):
+ self.android_devices[0].log.error(
+ "Conference call is not supported, abort test.")
+ raise signals.TestAbortClass(
+ "Conference call is not supported, abort test.")
+
+ def teardown_test(self):
+ toggle_airplane_mode(self.log, self.android_devices[0], False)
+ ensure_phones_idle(self.log, self.android_devices)
+ erase_call_forwarding(self.log, self.android_devices[0])
+ set_wifi_to_default(self.log, self.android_devices[0])
+
+ @test_tracker_info(uuid="53169ee2-eb70-423e-bbe0-3112f34d2d73")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_psim_5g_nsa_wfc_wifi_preferred_apm_off_dds_0(self):
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ 0,
+ callee_rat=['5g_wfc', 'general'],
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="f0b1c9ce-a386-4b25-8a44-8ca4897fc650")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_psim_5g_nsa_wfc_wifi_preferred_apm_off_dds_1(self):
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ 1,
+ callee_rat=['5g_wfc', 'general'],
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="c952fe28-823d-412d-a3ac-797bd6e2dc09")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_psim_5g_nsa_volte_cellular_preferred_wifi_on_dds_0(self):
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ 0,
+ callee_rat=["5g_volte", "general"],
+ is_wifi_connected=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="d9e58366-46ea-454a-a1b1-466ec91112ef")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_esim_5g_nsa_wfc_wifi_preferred_apm_off_dds_0(self):
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ 0,
+ callee_rat=['general', '5g_wfc'],
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="18ce70a6-972c-4723-8e65-0c9814d14e76")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_esim_5g_nsa_wfc_wifi_preferred_apm_off_dds_1(self):
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ 1,
+ callee_rat=['general', '5g_wfc'],
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="d843d4cd-c562-47f1-b35b-57a84896314e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cfu_esim_5g_nsa_volte_cellular_preferred_wifi_on_dds_0(self):
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ 0,
+ callee_rat=["general", "5g_volte"],
+ is_wifi_connected=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="556a0737-f2c2-44c4-acfd-4eeb57e4c15e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cw_hold_swap_psim_5g_nsa_wfc_wifi_preferred_apm_off_dds_0(self):
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ 0,
+ host_rat=['5g_wfc', 'general'],
+ merge=False,
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="d86de799-73ed-432e-b9b8-e762df459ad0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cw_hold_swap_psim_5g_nsa_wfc_wifi_preferred_apm_off_dds_1(self):
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ 1,
+ host_rat=['5g_wfc', 'general'],
+ merge=False,
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="9b9a9cd0-218f-4694-b5b7-ec2818abad48")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cw_hold_swap_psim_5g_nsa_volte_cellular_preferred_wifi_on_dds_0(self):
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ 0,
+ host_rat=["5g_volte", "general"],
+ merge=False,
+ is_airplane_mode=False,
+ is_wifi_connected=True,
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="02dd5686-0a55-497f-8b0c-9f624b6d7af5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cw_hold_swap_esim_5g_nsa_wfc_wifi_preferred_apm_off_dds_0(self):
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ 0,
+ host_rat=['general', '5g_wfc'],
+ merge=False,
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="1527f060-8226-4507-a502-09e55096da0a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cw_hold_swap_esim_5g_nsa_wfc_wifi_preferred_apm_off_dds_1(self):
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ 1,
+ host_rat=['general', '5g_wfc'],
+ merge=False,
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="e6db2878-8d64-4566-95f9-e8cbf28723e8")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_cw_hold_swap_esim_5g_nsa_volte_cellular_preferred_wifi_on_dds_0(self):
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ 0,
+ host_rat=["general", "5g_volte"],
+ merge=False,
+ is_airplane_mode=False,
+ is_wifi_connected=True,
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="5dfb45b7-2706-418f-a5c1-2f8ca9602a29")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_conf_psim_5g_nsa_wfc_wifi_preferred_apm_off_dds_0(self):
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ 0,
+ host_rat=['5g_wfc', 'general'],
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="3b520d38-e1f4-46dd-90a7-90d91766e290")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_conf_psim_5g_nsa_wfc_wifi_preferred_apm_off_dds_1(self):
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ 1,
+ host_rat=['5g_wfc', 'general'],
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="f3f09280-bd34-46dc-b813-e017d671ddba")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_conf_psim_5g_nsa_volte_cellular_preferred_wifi_on_dds_0(self):
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ 0,
+ host_rat=["5g_volte", "general"],
+ is_wifi_connected=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="f157ba39-b4ae-464a-840a-56e94ba62736")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_conf_esim_5g_wfc_wifi_preferred_apm_off_dds_0(self):
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ 0,
+ host_rat=['general', '5g_wfc'],
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="872413fa-ae9c-4482-9e87-a3a4a2738bab")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_conf_esim_5g_nsa_wfc_wifi_preferred_apm_off_dds_1(self):
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ 1,
+ host_rat=['general', '5g_wfc'],
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="18023ab7-fa96-4dda-a9ed-dd7562a0d185")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_msim_conf_esim_5g_nsa_volte_cellular_preferred_wifi_on_dds_0(self):
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ 0,
+ host_rat=["general", "5g_volte"],
+ is_wifi_connected=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
\ No newline at end of file
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gDataTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gDataTest.py
index 905225b..8dfc5a6 100755
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gDataTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gDataTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2020 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -25,14 +25,22 @@
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_USER_PLANE_DATA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_NR_LTE_GSM_WCDMA
from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackCapabilitiesChanged
-from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackLost
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
+from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_detection
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_recovery
+from acts_contrib.test_utils.tel.tel_data_utils import check_network_validation_fail
+from acts_contrib.test_utils.tel.tel_data_utils import data_connectivity_single_bearer
+from acts_contrib.test_utils.tel.tel_data_utils import test_data_connectivity_multi_bearer
+from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_connect_disconnect
+from acts_contrib.test_utils.tel.tel_data_utils import verify_for_network_callback
+from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
+from acts_contrib.test_utils.tel.tel_data_utils import airplane_mode_test
+from acts_contrib.test_utils.tel.tel_data_utils import reboot_test
+from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
from acts_contrib.test_utils.tel.tel_test_utils import break_internet_except_sl4a_port
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_detection
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_recovery
-from acts_contrib.test_utils.tel.tel_test_utils import check_network_validation_fail
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
from acts_contrib.test_utils.tel.tel_test_utils import get_current_override_network_type
from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
from acts_contrib.test_utils.tel.tel_test_utils import iperf_test_by_adb
@@ -43,30 +51,21 @@
from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_success_using_sl4a
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_reset
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
-from acts_contrib.test_utils.tel.tel_data_utils import data_connectivity_single_bearer
-from acts_contrib.test_utils.tel.tel_data_utils import test_data_connectivity_multi_bearer
-from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_connect_disconnect
-from acts_contrib.test_utils.tel.tel_data_utils import verify_for_network_callback
-from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
-from acts_contrib.test_utils.tel.tel_data_utils import airplane_mode_test
-from acts_contrib.test_utils.tel.tel_data_utils import reboot_test
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
-from acts_contrib.test_utils.tel.tel_5g_test_utils import set_preferred_mode_for_5g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_reset
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
class Nsa5gDataTest(TelephonyBaseTest):
def setup_class(self):
super().setup_class()
self.iperf_server_ip = self.user_params.get("iperf_server", '0.0.0.0')
- self.iperf_tcp_port = self.user_params.get("iperf_tcp_port", 0)
- self.iperf_udp_port = self.user_params.get("iperf_udp_port", 0)
- self.iperf_duration = self.user_params.get("iperf_duration", 60)
+ self.iperf_tcp_port = int(
+ self.user_params.get("iperf_tcp_port", 0))
+ self.iperf_udp_port = int(
+ self.user_params.get("iperf_udp_port", 0))
+ self.iperf_duration = int(
+ self.user_params.get("iperf_duration", 60))
def setup_test(self):
TelephonyBaseTest.setup_test(self)
@@ -100,7 +99,7 @@
return False
ad.log.info("Set network mode to NSA successfully")
ad.log.info("Waiting for 5g NSA attach for 60 secs")
- if is_current_network_5g_nsa(ad, timeout=60):
+ if is_current_network_5g(ad, nr_type = 'nsa', timeout=60):
ad.log.info("Success! attached on 5g NSA")
else:
ad.log.error("Failure - expected NR_NSA, current %s",
@@ -147,7 +146,7 @@
wifi_toggle_state(ad.log, ad, False)
toggle_airplane_mode(ad.log, ad, False)
- if not provision_device_for_5g(ad.log, ad):
+ if not provision_device_for_5g(ad.log, ad, nr_type='nsa'):
return False
cmd = ('ss -l -p -n | grep "tcp.*droid_script" | tr -s " " '
@@ -204,7 +203,7 @@
try:
wifi_toggle_state(ad.log, ad, False)
toggle_airplane_mode(ad.log, ad, False)
- if not provision_device_for_5g(ad.log, ad):
+ if not provision_device_for_5g(ad.log, ad, nr_type='nsa'):
return False
return verify_for_network_callback(ad.log, ad,
@@ -229,7 +228,7 @@
ad = self.android_devices[0]
try:
toggle_airplane_mode(ad.log, ad, False)
- if not provision_device_for_5g(ad.log, ad):
+ if not provision_device_for_5g(ad.log, ad, nr_type='nsa'):
return False
wifi_toggle_state(ad.log, ad, True)
if not ensure_wifi_connected(ad.log, ad,
@@ -261,7 +260,7 @@
ad = self.android_devices[0]
try:
toggle_airplane_mode(ad.log, ad, False)
- if not provision_device_for_5g(ad.log, ad):
+ if not provision_device_for_5g(ad.log, ad, nr_type='nsa'):
return False
wifi_toggle_state(ad.log, ad, False)
return iperf_udp_test_by_adb(ad.log,
@@ -290,7 +289,7 @@
ad = self.android_devices[0]
try:
toggle_airplane_mode(ad.log, ad, False)
- if not provision_device_for_5g(ad.log, ad):
+ if not provision_device_for_5g(ad.log, ad, nr_type='nsa'):
return False
wifi_toggle_state(ad.log, ad, False)
return iperf_test_by_adb(ad.log,
@@ -319,7 +318,7 @@
ad = self.android_devices[0]
try:
toggle_airplane_mode(ad.log, ad, False)
- if not provision_device_for_5g(ad.log, ad):
+ if not provision_device_for_5g(ad.log, ad, nr_type='nsa'):
return False
wifi_toggle_state(ad.log, ad, False)
return iperf_udp_test_by_adb(ad.log,
@@ -334,20 +333,6 @@
ad.log.error(e)
return False
-
- @test_tracker_info(uuid="cd1429e8-94d7-44de-ae48-68cf42f3246b")
- @TelephonyBaseTest.tel_test_wrap
- def test_5g_nsa_browsing(self):
- ad = self.android_devices[0]
- ad.log.info("Connect to NR and verify internet connection.")
- if not provision_device_for_5g(ad.log, ad):
- return False
- if not verify_internet_connection(ad.log, ad):
- return False
-
- return browsing_test(ad.log, ad)
-
-
@test_tracker_info(uuid="7179f0f1-f0ca-4496-8f4a-7eebc616a41a")
@TelephonyBaseTest.tel_test_wrap
def test_5g_nsa_wifi_switching(self):
@@ -365,7 +350,7 @@
"""
ad = self.android_devices[0]
return wifi_cell_switching(ad.log, ad, GEN_5G, self.wifi_network_ssid,
- self.wifi_network_pass)
+ self.wifi_network_pass, nr_type='nsa')
@test_tracker_info(uuid="75066e0a-0e2e-4346-a253-6ed11d1c4d23")
@@ -388,12 +373,12 @@
if not phone_setup_volte(ads[0].log, ads[0]):
ads[0].log.error("Failed to setup VoLTE")
return False
- return test_data_connectivity_multi_bearer(self.log, ads, GEN_5G)
+ return test_data_connectivity_multi_bearer(self.log, ads, GEN_5G, nr_type='nsa')
@test_tracker_info(uuid="e88b226e-3842-4c45-a33e-d4fee7d8f6f0")
@TelephonyBaseTest.tel_test_wrap
- def test_5g_nsa(self):
+ def test_5g_nsa_data_connectivity(self):
"""Test data connection in nsa5g.
Turn off airplane mode, disable WiFi, enable Cellular Data.
@@ -409,7 +394,7 @@
ad = self.android_devices[0]
wifi_reset(ad.log, ad)
wifi_toggle_state(ad.log, ad, False)
- return data_connectivity_single_bearer(ad.log, ad, GEN_5G)
+ return data_connectivity_single_bearer(ad.log, ad, GEN_5G, nr_type='nsa')
@test_tracker_info(uuid="4c70e09d-f215-4c5b-8c61-f9e9def43d30")
@@ -431,7 +416,7 @@
wifi_reset(ad.log, ad)
wifi_toggle_state(ad.log, ad, False)
wifi_toggle_state(ad.log, ad, True)
- return data_connectivity_single_bearer(ad.log, ad, GEN_5G)
+ return data_connectivity_single_bearer(ad.log, ad, GEN_5G, nr_type='nsa')
@test_tracker_info(uuid="8308bf40-7f1b-443f-bde6-19d9ff97e471")
@@ -453,7 +438,7 @@
True if success.
False if failed.
"""
- if not provision_device_for_5g(self.log, self.provider):
+ if not provision_device_for_5g(self.log, self.provider, nr_type='nsa'):
return False
return test_wifi_connect_disconnect(self.log, self.provider, self.wifi_network_ssid, self.wifi_network_pass)
@@ -472,15 +457,24 @@
Returns:
True if pass; False if fail.
"""
- if not provision_device_for_5g(self.log, self.android_devices[0]):
+ if not provision_device_for_5g(self.log, self.android_devices[0], nr_type='nsa'):
return False
return airplane_mode_test(self.log, self.android_devices[0])
@test_tracker_info(uuid="091cde37-0bac-4399-83aa-cbd5a83b07a1")
@TelephonyBaseTest.tel_test_wrap
def test_5g_nsa_reboot(self):
- """Test 5G NSA service availability after reboot."""
- if not provision_device_for_5g(self.log, self.android_devices[0]):
+ """Test 5G NSA service availability after reboot.
+
+ Ensure phone is on 5G NSA.
+ Ensure phone attach, data on, WiFi off and verify Internet.
+ Reboot Device.
+ Verify Network Connection.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ if not provision_device_for_5g(self.log, self.android_devices[0], nr_type='nsa'):
return False
if not verify_internet_connection(self.log, self.android_devices[0]):
return False
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gDsdsMessageTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gDsdsMessageTest.py
deleted file mode 100644
index 01888cf..0000000
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gDsdsMessageTest.py
+++ /dev/null
@@ -1,357 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright 2021 - 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.
-
-import time
-
-from acts import asserts
-from acts import signals
-from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
-from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
-from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
-from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
-from acts_contrib.test_utils.tel.tel_defines import GEN_5G
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_message_subid
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_data
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import sms_send_receive_verify_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import sms_in_collision_send_receive_verify_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import sms_rx_power_off_multiple_send_receive_verify_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import voice_call_in_collision_with_mt_sms_msim
-from acts_contrib.test_utils.tel.tel_test_utils import mms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import log_messaging_screen_shot
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import get_slot_index_from_subid
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_on_rat
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat
-from acts.utils import rand_ascii_str
-
-CallResult = TelephonyVoiceTestResult.CallResult.Value
-
-class Nsa5gDsdsMessageTest(TelephonyBaseTest):
- def setup_class(self):
- TelephonyBaseTest.setup_class(self)
- self.message_lengths = (50, 160, 180)
- self.tel_logger = TelephonyMetricLogger.for_test_case()
-
- def teardown_test(self):
- ensure_phones_idle(self.log, self.android_devices)
-
- def _msim_message_test(
- self,
- ad_mo,
- ad_mt,
- mo_sub_id,
- mt_sub_id, msg="SMS",
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
- expected_result=True):
- """Make MO/MT SMS/MMS at specific slot.
-
- Args:
- ad_mo: Android object of the device sending SMS/MMS
- ad_mt: Android object of the device receiving SMS/MMS
- mo_sub_id: Sub ID of MO device
- mt_sub_id: Sub ID of MT device
- max_wait_time: Max wait time before SMS/MMS is received.
- expected_result: True for successful sending/receiving and False on
- the contrary
-
- Returns:
- True if the result matches expected_result and False on the
- contrary.
- """
-
- if msg == "SMS":
- for length in self.message_lengths:
- message_array = [rand_ascii_str(length)]
- if not sms_send_receive_verify_for_subscription(
- self.log,
- ad_mo,
- ad_mt,
- mo_sub_id,
- mt_sub_id,
- message_array,
- max_wait_time):
- ad_mo.log.warning(
- "%s of length %s test failed", msg, length)
- return False
- else:
- ad_mo.log.info(
- "%s of length %s test succeeded", msg, length)
- self.log.info("%s test of length %s characters succeeded.",
- msg, self.message_lengths)
-
- elif msg == "MMS":
- for length in self.message_lengths:
- message_array = [("Test Message", rand_ascii_str(length), None)]
-
- if not mms_send_receive_verify(
- self.log,
- ad_mo,
- ad_mt,
- message_array,
- max_wait_time,
- expected_result):
- self.log.warning("%s of body length %s test failed",
- msg, length)
- return False
- else:
- self.log.info(
- "%s of body length %s test succeeded", msg, length)
- self.log.info("%s test of body lengths %s succeeded",
- msg, self.message_lengths)
- return True
-
- def _test_msim_message(
- self,
- mo_slot,
- mt_slot,
- dds_slot,
- msg="SMS",
- mo_rat=["", ""],
- mt_rat=["", ""],
- direction="mo",
- expected_result=True):
- """Make MO/MT SMS/MMS at specific slot in specific RAT with DDS at
- specific slot.
-
- Test step:
- 1. Get sub IDs of specific slots of both MO and MT devices.
- 2. Switch DDS to specific slot.
- 3. Check HTTP connection after DDS switch.
- 4. Set up phones in desired RAT.
- 5. Send SMS/MMS.
-
- Args:
- mo_slot: Slot sending MO SMS (0 or 1)
- mt_slot: Slot receiving MT SMS (0 or 1)
- dds_slot: Preferred data slot
- mo_rat: RAT for both slots of MO device
- mt_rat: RAT for both slots of MT device
- direction: "mo" or "mt"
- expected_result: True of False
-
- Returns:
- TestFailure if failed.
- """
- ads = self.android_devices
-
- if direction == "mo":
- ad_mo = ads[0]
- ad_mt = ads[1]
- else:
- ad_mo = ads[1]
- ad_mt = ads[0]
-
- if mo_slot is not None:
- mo_sub_id = get_subid_from_slot_index(self.log, ad_mo, mo_slot)
- if mo_sub_id == INVALID_SUB_ID:
- ad_mo.log.warning("Failed to get sub ID at slot %s.", mo_slot)
- return False
- mo_other_sub_id = get_subid_from_slot_index(
- self.log, ad_mo, 1-mo_slot)
- set_message_subid(ad_mo, mo_sub_id)
- else:
- _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(
- ads, type="sms")
- if mo_sub_id == INVALID_SUB_ID:
- ad_mo.log.warning("Failed to get sub ID at slot %s.", mo_slot)
- return False
- mo_slot = "auto"
- set_message_subid(ad_mo, mo_sub_id)
- if msg == "MMS":
- set_subid_for_data(ad_mo, mo_sub_id)
- ad_mo.droid.telephonyToggleDataConnection(True)
- ad_mo.log.info("Sub ID for outgoing %s at slot %s: %s", msg, mo_slot,
- get_outgoing_message_sub_id(ad_mo))
-
- if mt_slot is not None:
- mt_sub_id = get_subid_from_slot_index(self.log, ad_mt, mt_slot)
- if mt_sub_id == INVALID_SUB_ID:
- ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
- return False
- mt_other_sub_id = get_subid_from_slot_index(
- self.log, ad_mt, 1-mt_slot)
- set_message_subid(ad_mt, mt_sub_id)
- else:
- _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
- ads, type="sms")
- if mt_sub_id == INVALID_SUB_ID:
- ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
- return False
- mt_slot = "auto"
- set_message_subid(ad_mt, mt_sub_id)
- if msg == "MMS":
- set_subid_for_data(ad_mt, mt_sub_id)
- ad_mt.droid.telephonyToggleDataConnection(True)
- ad_mt.log.info("Sub ID for incoming %s at slot %s: %s", msg, mt_slot,
- get_outgoing_message_sub_id(ad_mt))
-
- self.log.info("Step 1: Switch DDS.")
- if dds_slot:
- if not set_dds_on_slot_1(ads[0]):
- self.log.warning(
- "Failed to set DDS at eSIM on %s", ads[0].serial)
- return False
- else:
- if not set_dds_on_slot_0(ads[0]):
- self.log.warning(
- "Failed to set DDS at pSIM on %s", ads[0].serial)
- return False
-
- self.log.info("Step 2: Check HTTP connection after DDS switch.")
- if not verify_http_connection(self.log,
- ads[0],
- url="https://www.google.com",
- retry=5,
- retry_interval=15,
- expected_state=True):
-
- self.log.error("Failed to verify http connection.")
- return False
- else:
- self.log.info("Verify http connection successfully.")
-
- mo_phone_setup_func_argv = (self.log, ad_mo, mo_sub_id)
- mt_phone_setup_func_argv = (self.log, ad_mt, mt_sub_id)
-
- if mo_slot in (0, 1):
- # set up the rat on mo side another slot which not to be test(primary device)
- phone_setup_on_rat(self.log, ad_mo, mo_rat[1-mo_slot], mo_other_sub_id)
- # get phone setup function and required argument of primary device
- if '5g' in mo_rat[mo_slot].lower():
- mo_phone_setup_func_argv = (self.log, ad_mo, mo_sub_id, GEN_5G)
- mo_phone_setup_func = phone_setup_on_rat(
- self.log,
- ad_mo,
- mo_rat[mo_slot],
- only_return_fn=True)
- else:
- # set up the rat and get phone setup function on mo side(non-primary device)
- phone_setup_on_rat(self.log, ad_mo, 'general', sub_id_type='sms')
- mo_phone_setup_func = phone_setup_voice_general_for_subscription
-
- if mt_slot in (0, 1):
- # set up the rat on mt side another slot which not to be test(primary device)
- phone_setup_on_rat(self.log, ad_mt, mt_rat[1-mt_slot], mt_other_sub_id)
- # get phone setup function and required argument of primary device
- if '5g' in mt_rat[mt_slot].lower():
- mt_phone_setup_func_argv = (self.log, ad_mt, mt_sub_id, GEN_5G)
- mt_phone_setup_func = phone_setup_on_rat(
- self.log,
- ad_mt,
- mt_rat[mt_slot],
- only_return_fn=True)
- else:
- # set up the rat and get phone setup function on mt side(non-primary device)
- phone_setup_on_rat(self.log, ad_mt, 'general', sub_id_type='sms')
- mt_phone_setup_func = phone_setup_voice_general_for_subscription
-
- self.log.info("Step 3: Set up phones in desired RAT.")
- tasks = [(mo_phone_setup_func, mo_phone_setup_func_argv),
- (mt_phone_setup_func, mt_phone_setup_func_argv)]
- 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("Step 4: Send %s.", msg)
-
- if msg == "MMS":
- for ad, current_data_sub_id, current_msg_sub_id in [
- [ ads[0],
- get_default_data_sub_id(ads[0]),
- get_outgoing_message_sub_id(ads[0]) ],
- [ ads[1],
- get_default_data_sub_id(ads[1]),
- get_outgoing_message_sub_id(ads[1]) ]]:
- if current_data_sub_id != current_msg_sub_id:
- ad.log.warning(
- "Current data sub ID (%s) does not match message"
- " sub ID (%s). MMS should NOT be sent.",
- current_data_sub_id,
- current_msg_sub_id)
- expected_result = False
-
- result = self._msim_message_test(ad_mo, ad_mt, mo_sub_id, mt_sub_id,
- msg=msg, expected_result=expected_result)
-
- if not result:
- log_messaging_screen_shot(ad_mo, test_name="%s_tx" % msg)
- log_messaging_screen_shot(ad_mt, test_name="%s_rx" % msg)
-
- return result
-
- @test_tracker_info(uuid="183cda35-45aa-485d-b3d4-975d78f7d361")
- @TelephonyBaseTest.tel_test_wrap
- def test_msim_sms_mo_psim_volte_esim_nsa_5g_volte_dds_1(self):
- return self._test_msim_message(
- 0, None, 1, mo_rat=["volte", "5g_volte"], msg="SMS", direction="mo")
-
- @test_tracker_info(uuid="d9cb69ce-c462-4fd4-b716-bfb1fd2ed86a")
- @TelephonyBaseTest.tel_test_wrap
- def test_msim_sms_mt_psim_volte_esim_nsa_5g_volte_dds_1(self):
- return self._test_msim_message(
- None, 0, 1, mt_rat=["volte", "5g_volte"], msg="SMS", direction="mt")
-
- @test_tracker_info(uuid="51d5e05d-66e7-4369-91e0-6cdc573d9a59")
- @TelephonyBaseTest.tel_test_wrap
- def test_msim_sms_mo_esim_nsa_5g_volte_psim_volte_dds_1(self):
- return self._test_msim_message(
- 1, None, 1, mo_rat=["volte", "5g_volte"], msg="SMS", direction="mo")
-
- @test_tracker_info(uuid="38271a0f-2efb-4991-9f24-6da9f003ddd4")
- @TelephonyBaseTest.tel_test_wrap
- def test_msim_sms_mt_esim_nsa_5g_volte_psim_volte_dds_1(self):
- return self._test_msim_message(
- None, 1, 1, mt_rat=["volte", "5g_volte"], msg="SMS", direction="mt")
-
- @test_tracker_info(uuid="87759475-0208-4d9b-b5b9-814fdb97f09c")
- @TelephonyBaseTest.tel_test_wrap
- def test_msim_sms_mo_psim_nsa_5g_volte_esim_volte_dds_0(self):
- return self._test_msim_message(
- 0, None, 0, mo_rat=["5g_volte", "volte"], msg="SMS", direction="mo")
-
- @test_tracker_info(uuid="2f14e81d-330f-4cdd-837c-1168185ffec4")
- @TelephonyBaseTest.tel_test_wrap
- def test_msim_sms_mt_psim_nsa_5g_volte_esim_volte_dds_0(self):
- return self._test_msim_message(
- None, 0, 0, mt_rat=["5g_volte", "volte"], msg="SMS", direction="mt")
-
- @test_tracker_info(uuid="9cc45474-1fca-4008-8499-87829d6516ea")
- @TelephonyBaseTest.tel_test_wrap
- def test_msim_sms_mo_esim_volte_psim_nsa_5g_volte_dds_0(self):
- return self._test_msim_message(
- 1, None, 0, mo_rat=["5g_volte", "volte"], msg="SMS", direction="mo")
-
- @test_tracker_info(uuid="341786de-5b23-438a-a91b-97cf420ef5fd")
- @TelephonyBaseTest.tel_test_wrap
- def test_msim_sms_mt_esim_volte_psim_nsa_5g_volte_dds_0(self):
- return self._test_msim_message(
- None, 1, 0, mt_rat=["5g_volte", "volte"], msg="SMS", direction="mt")
-
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gImsSettingsTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gImsSettingsTest.py
index 6e2b143..127942e 100644
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gImsSettingsTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gImsSettingsTest.py
@@ -17,26 +17,19 @@
Test Script for 5G IMS Settings scenarios
"""
-import time
-
from acts import signals
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import CarrierConfigs
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
from acts_contrib.test_utils.tel.tel_defines import RAT_NR
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_on_rat
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
from acts_contrib.test_utils.tel.tel_test_utils import dumpsys_carrier_config
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
-from acts_contrib.test_utils.tel.tel_5g_test_utils import set_preferred_mode_for_5g
-from acts_contrib.test_utils.tel.tel_ims_utils import change_ims_setting
+from acts_contrib.test_utils.tel.tel_voice_utils import change_ims_setting
class Nsa5gImsSettingsTest(TelephonyBaseTest):
@@ -82,11 +75,8 @@
4. DUT WiFi Calling feature bit return False, network rat is not iwlan.
"""
- if not phone_setup_volte(self.log, self.dut):
- self.log.error("Failed to setup VoLTE")
- return False
-
- if not provision_device_for_5g(self.log, self.dut):
+ if not phone_setup_on_rat(self.log, self.dut, rat='5g_volte'):
+ self.log.error("Phone Failed to setup Properly")
return False
if not change_ims_setting(log=self.log,
@@ -151,13 +141,10 @@
4. DUT WiFi Calling feature bit return False, network rat is not iwlan.
"""
- if not phone_setup_csfb(self.log, self.dut):
+ if not phone_setup_on_rat(self.log, self.dut, rat='5g_csfb'):
self.log.error("Phone Failed to setup Properly")
return False
- if not provision_device_for_5g(self.log, self.dut):
- return False
-
if not change_ims_setting(log=self.log,
ad=self.dut,
dut_client= self.dut_client,
@@ -217,12 +204,8 @@
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.
"""
- if not phone_setup_volte(self.log, self.dut):
- self.log.error("Failed to setup VoLTE")
- return False
-
- ads = self.android_devices
- if not provision_device_for_5g(self.log, ads):
+ if not phone_setup_on_rat(self.log, self.dut, rat='5g_volte'):
+ self.log.error("Phone Failed to setup Properly")
return False
if not change_ims_setting(log=self.log,
@@ -284,11 +267,8 @@
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.
"""
- if not phone_setup_csfb(self.log, self.dut):
- self.log.error("Failed to setup CSFB")
- return False
-
- if not provision_device_for_5g(self.log, self.dut):
+ if not phone_setup_on_rat(self.log, self.dut, rat='5g_csfb'):
+ self.log.error("Phone Failed to setup Properly")
return False
if not change_ims_setting(log=self.log,
@@ -356,11 +336,8 @@
3. DUT WiFi Calling feature bit return True, network rat is iwlan.
4. DUT WiFi Calling feature bit return True, network rat is iwlan.
"""
- if not phone_setup_volte(self.log, self.dut):
- self.dut.log.error("Phone Failed to setup properly")
- return False
-
- if not provision_device_for_5g(self.log, self.dut):
+ if not phone_setup_on_rat(self.log, self.dut, rat='5g_volte'):
+ self.log.error("Phone Failed to setup Properly")
return False
if not change_ims_setting(log=self.log,
@@ -429,11 +406,8 @@
raise signals.TestSkip(
"WFC_MODE_CELLULAR_PREFERRED is not supported")
- if not phone_setup_volte(self.log, self.dut):
- self.dut.log.error("Phone Failed to setup properly.")
- return False
-
- if not provision_device_for_5g(self.log, self.dut):
+ if not phone_setup_on_rat(self.log, self.dut, rat='5g_volte'):
+ self.log.error("Phone Failed to setup Properly")
return False
if not change_ims_setting(log=self.log,
@@ -488,11 +462,8 @@
raise signals.TestSkip(
"WFC_MODE_CELLULAR_PREFERRED is not supported")
- if not phone_setup_csfb(self.log, self.dut):
- self.dut.log.error("Failed to setup properly")
- return False
-
- if not provision_device_for_5g(self.log, self.dut):
+ if not phone_setup_on_rat(self.log, self.dut, rat='5g_csfb'):
+ self.log.error("Phone Failed to setup Properly")
return False
if not change_ims_setting(log=self.log,
@@ -547,11 +518,8 @@
if WFC_MODE_CELLULAR_PREFERRED not in self.dut_wfc_modes:
raise signals.TestSkip(
"WFC_MODE_CELLULAR_PREFERRED is not supported")
- if not phone_setup_volte(self.log, self.dut):
- self.dut.log.error("Phone Failed to setup properly")
- return False
-
- if not provision_device_for_5g(self.log, self.dut):
+ if not phone_setup_on_rat(self.log, self.dut, rat='5g_volte'):
+ self.log.error("Phone Failed to setup Properly")
return False
if not change_ims_setting(log=self.log,
@@ -606,11 +574,8 @@
raise signals.TestSkip(
"WFC_MODE_CELLULAR_PREFERRED is not supported")
- if not phone_setup_csfb(self.log, self.dut):
- self.dut.log.error("Phone Failed to setup properly")
- return False
-
- if not provision_device_for_5g(self.log, self.dut):
+ if not phone_setup_on_rat(self.log, self.dut, rat='5g_csfb'):
+ self.log.error("Phone Failed to setup Properly")
return False
if not change_ims_setting(log=self.log,
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gMmsTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gMmsTest.py
index 22c8842..e7bcb5a 100755
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gMmsTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gMmsTest.py
@@ -21,49 +21,31 @@
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
-from acts_contrib.test_utils.tel.tel_defines import SMS_OVER_WIFI_PROVIDERS
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
-from acts_contrib.test_utils.tel.tel_5g_test_utils import connect_both_devices_to_wifi
-from acts_contrib.test_utils.tel.tel_5g_test_utils import disable_apm_mode_both_devices
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_message_utils import message_test
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_task
+from acts_contrib.test_utils.tel.tel_test_utils import install_message_apk
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_both_devices_for_volte
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_both_devices_for_wfc_cell_pref
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_both_devices_for_wfc_wifi_pref
-from acts_contrib.test_utils.tel.tel_5g_test_utils import verify_5g_attach_for_both_devices
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_both_devices_for_csfb
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa
-from acts_contrib.test_utils.tel.tel_mms_utils import _mms_test_mo
-from acts_contrib.test_utils.tel.tel_mms_utils import _mms_test_mt
-from acts_contrib.test_utils.tel.tel_mms_utils import _long_mms_test_mo
-from acts_contrib.test_utils.tel.tel_mms_utils import test_mms_mo_in_call
+from acts.libs.utils.multithread import run_multithread_func
class Nsa5gMmsTest(TelephonyBaseTest):
def setup_class(self):
super().setup_class()
- self.number_of_devices = 2
- self.message_lengths = (50, 160, 180)
- is_roaming = False
- for ad in self.android_devices:
- ad.sms_over_wifi = False
- # verizon supports sms over wifi. will add more carriers later
- for sub in ad.telephony["subscription"].values():
- if sub["operator"] in SMS_OVER_WIFI_PROVIDERS:
- ad.sms_over_wifi = True
- if getattr(ad, 'roaming', False):
- is_roaming = True
- if is_roaming:
- # roaming device does not allow message of length 180
- self.message_lengths = (50, 160)
+ self.message_util = self.user_params.get("message_apk", None)
+ if isinstance(self.message_util, list):
+ self.message_util = self.message_util[0]
+
+ if self.message_util:
+ ads = self.android_devices
+ for ad in ads:
+ install_message_apk(ad, self.message_util)
def setup_test(self):
TelephonyBaseTest.setup_test(self)
@@ -73,8 +55,6 @@
""" Tests Begin """
-
-
@test_tracker_info(uuid="bc484c2c-8086-42db-94cd-a1e4a35f35cf")
@TelephonyBaseTest.tel_test_wrap
def test_5g_nsa_mms_mo_mt(self):
@@ -88,19 +68,55 @@
True if success.
False if failed.
"""
- ads = self.android_devices
- if not provision_device_for_5g(self.log, ads):
- return False
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g',
+ mt_rat='5g',
+ msg_type='mms')
- if not _mms_test_mo(self.log, ads):
- return False
+ @test_tracker_info(uuid="88bd6658-30fa-41b1-b5d9-0f9dadd83219")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mo_general(self):
+ """Test MO MMS for 1 phone in 5g NSA. The other phone in any network
- if not verify_5g_attach_for_both_devices(self.log, ads):
- return False
+ Provision PhoneA in 5g NSA
+ Send and Verify MMS from PhoneA to PhoneB
+ Verify phoneA is still on 5g NSA
- self.log.info("PASS - mms test over 5g nsa validated")
- return True
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g',
+ mt_rat='default',
+ msg_type='mms')
+ @test_tracker_info(uuid="11f2e2c8-bb63-43fa-b279-e7bb32f80596")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mt_general(self):
+ """Test MT MMS for 1 phone in 5g NSA. The other phone in any network
+
+ Provision PhoneA in 5g NSA
+ Send and Verify MMS from PhoneB to PhoneA
+ Verify phoneA is still on 5g NSA
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g',
+ msg_type='mms')
@test_tracker_info(uuid="51d42104-cb87-4c9b-9a16-302e246a21dc")
@TelephonyBaseTest.tel_test_wrap
@@ -116,23 +132,13 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
- if not provision_both_devices_for_volte(self.log, ads):
- return False
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- if not _mms_test_mo(self.log, ads):
- return False
-
- if not verify_5g_attach_for_both_devices(self.log, ads):
- return False
-
- self.log.info("PASS - volte mms test over 5g nsa validated")
- return True
-
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_volte',
+ mt_rat='5g_volte',
+ msg_type='mms')
@test_tracker_info(uuid="97d6b071-aef2-40c1-8245-7be6c31870a6")
@TelephonyBaseTest.tel_test_wrap
@@ -148,31 +154,14 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
- if not provision_both_devices_for_volte(self.log, ads):
- return False
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- self.log.info("Begin Incall mms test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_volte,
- verify_callee_func=None):
- return False
-
- if not _mms_test_mo(self.log, ads):
- return False
-
- if not verify_5g_attach_for_both_devices(self.log, ads):
- return False
- self.log.info("PASS - Incall volte mms test over 5g nsa validated")
- return True
-
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_volte',
+ mt_rat='5g_volte',
+ msg_type='mms',
+ msg_in_call=True)
@test_tracker_info(uuid="bbb4b80c-fc1b-4377-b3c7-eeed642c5980")
@TelephonyBaseTest.tel_test_wrap
@@ -188,28 +177,18 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
- if not disable_apm_mode_both_devices(self.log, ads):
- return False
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- if not provision_both_devices_for_wfc_cell_pref(self.log,
- ads,
- self.wifi_network_ssid,
- self.wifi_network_pass,
- apm_mode=True):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- if not _mms_test_mo(self.log, ads):
- return False
-
- self.log.info("PASS - iwlan mms test over 5g nsa validated")
- return True
-
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_wfc',
+ mt_rat='5g_wfc',
+ msg_type='mms',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="d36d95dc-0973-4711-bb08-c29ce23495e4")
@TelephonyBaseTest.tel_test_wrap
@@ -225,31 +204,17 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
- if not disable_apm_mode_both_devices(self.log, ads):
- return False
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- if not provision_both_devices_for_wfc_wifi_pref(self.log,
- ads,
- self.wifi_network_ssid,
- self.wifi_network_pass,
- apm_mode=False):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- if not _mms_test_mo(self.log, ads):
- self.log.error("Failed to send receive sms over 5g nsa")
- return False
- self.log.info("PASS - iwlan mms test over 5g nsa validated")
-
- if not verify_5g_attach_for_both_devices(self.log, ads):
- return False
- return True
-
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_wfc',
+ mt_rat='5g_wfc',
+ msg_type='mms',
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="74ffb79e-f1e9-4087-a9d2-e07878e47869")
@TelephonyBaseTest.tel_test_wrap
@@ -265,35 +230,19 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
-
- if not disable_apm_mode_both_devices(self.log, ads):
- return False
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- if not provision_both_devices_for_wfc_wifi_pref(self.log,
- ads,
- self.wifi_network_ssid,
- self.wifi_network_pass,
- apm_mode=True):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- self.log.info("Begin Incall mms test")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_iwlan,
- verify_callee_func=None):
- return False
-
- return _mms_test_mo(self.log, ads)
-
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_wfc',
+ mt_rat='5g_wfc',
+ msg_type='mms',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="68c8e0ca-bea4-45e4-92cf-19424ee47ca4")
@TelephonyBaseTest.tel_test_wrap
@@ -309,36 +258,16 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
- if not provision_both_devices_for_volte(self.log, ads):
- return False
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- if not connect_both_devices_to_wifi(self.log,
- ads,
- self.wifi_network_ssid,
- self.wifi_network_pass):
- return False
-
- self.log.info("Begin In Call MMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_volte,
- verify_callee_func=None):
- return False
-
- if not _mms_test_mo(self.log, ads):
- return False
-
- if not verify_5g_attach_for_both_devices(self.log, ads):
- return False
- return True
-
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_volte',
+ mt_rat='5g_volte',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="8c795c3a-59d4-408c-9b99-5287e79ba00b")
@TelephonyBaseTest.tel_test_wrap
@@ -353,17 +282,14 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- if not disable_apm_mode_both_devices(self.log, ads):
- return False
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- return _long_mms_test_mo(self.log, ads)
-
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g',
+ mt_rat='5g',
+ msg_type='mms',
+ long_msg=True)
@test_tracker_info(uuid="e09b82ab-69a9-4eae-8cbe-b6f2cff993ad")
@TelephonyBaseTest.tel_test_wrap
@@ -379,20 +305,15 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- if not disable_apm_mode_both_devices(self.log, ads):
- return False
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
-
- return _mms_test_mo(self.log, ads)
-
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g',
+ mt_rat='general',
+ msg_type='mms',
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="fedae24f-2577-4f84-9d76-53bbbe109d48")
@TelephonyBaseTest.tel_test_wrap
@@ -408,20 +329,15 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- if not disable_apm_mode_both_devices(self.log, ads):
- return False
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
-
- return _mms_test_mt(self.log, ads)
-
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='5g',
+ msg_type='mms',
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="156bf832-acc2-4729-a69d-b471cd5cfbde")
@TelephonyBaseTest.tel_test_wrap
@@ -439,85 +355,516 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_csfb',
+ mt_rat='5g_csfb',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
- if not disable_apm_mode_both_devices(self.log, ads):
- return False
-
- if not provision_both_devices_for_csfb(self.log, ads):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- if not provision_both_devices_for_5g(self.log, ads):
- return False
-
- if not connect_both_devices_to_wifi(self.log,
- ads,
- self.wifi_network_ssid,
- self.wifi_network_pass):
- return False
- if not test_mms_mo_in_call(self.log,
- ads,
- wifi=True,
- caller_func=is_phone_in_call_csfb):
- return False
-
-
- @test_tracker_info(uuid="88bd6658-30fa-41b1-b5d9-0f9dadd83219")
+ @test_tracker_info(uuid="a76e4adc-ce37-47d4-9925-4ebe175f7b9c")
@TelephonyBaseTest.tel_test_wrap
- def test_5g_nsa_mms_mo_general(self):
- """Test MO MMS for 1 phone in 5g NSA. The other phone in any network
+ def test_5g_nsa_mms_mo_volte(self):
+ """Test MO MMS for 1 phone with VoLTE on 5G NSA
+ Provision PhoneA on VoLTE
Provision PhoneA in 5g NSA
Send and Verify MMS from PhoneA to PhoneB
- Verify phoneA is still on 5g NSA
+ Verify PhoneA is still on 5g NSA
Returns:
True if success.
False if failed.
"""
- ads = self.android_devices
- tasks = [(provision_device_for_5g, (self.log, ads[0])),
- (ensure_phone_default_state, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- return Fals
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_volte',
+ mt_rat='default',
+ msg_type='mms')
- if not _mms_test_mo(self.log, ads):
- return False
-
- if not is_current_network_5g_nsa(ads[0]):
- return False
-
- self.log.info("PASS - MO mms test over 5g nsa validated")
- return True
-
-
- @test_tracker_info(uuid="11f2e2c8-bb63-43fa-b279-e7bb32f80596")
+ @test_tracker_info(uuid="c2282b01-e89f-49db-8925-79d38b63a373")
@TelephonyBaseTest.tel_test_wrap
- def test_5g_nsa_mms_mt_general(self):
- """Test MT MMS for 1 phone in 5g NSA. The other phone in any network
+ def test_5g_nsa_mms_mt_volte(self):
+ """Test MT MMS for 1 phone with VoLTE on 5G NSA
+ Provision PhoneA on VoLTE
Provision PhoneA in 5g NSA
Send and Verify MMS from PhoneB to PhoneA
- Verify phoneA is still on 5g NSA
+ Verify PhoneA is still on 5g NSA
Returns:
True if success.
False if failed.
"""
- ads = self.android_devices
- tasks = [(provision_device_for_5g, (self.log, ads[0])),
- (ensure_phone_default_state, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_volte',
+ msg_type='mms')
+
+ @test_tracker_info(uuid="fd9bc699-940f-4a4a-abf1-31080e54ab56")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mo_in_call_volte(self):
+ """ Test MO MMS during a VoLTE call over 5G NSA.
+
+ Provision PhoneA on VoLTE
+ Provision PhoneA in 5g NSA
+ Make a Voice call from PhoneA to PhoneB
+ Send and Verify MMS from PhoneA to PhoneB
+ Verify PhoneA is still on 5g NSA
+
+ Returns:
+ True if pass; False if fail.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_volte',
+ mt_rat='default',
+ msg_type='mms',
+ msg_in_call=True)
+
+ @test_tracker_info(uuid="cfbae1e0-842a-470a-914a-a3a25a18dc81")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mt_in_call_volte(self):
+ """ Test MT MMS during a VoLTE call over 5G NSA.
+
+ Provision PhoneA on VoLTE
+ Provision PhoneA in 5g NSA
+ Make a Voice call from PhoneB to PhoneA
+ Send and Verify MMS from PhoneB to PhoneA
+ Verify PhoneA is still on 5g NSA
+
+ Returns:
+ True if pass; False if fail.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_volte',
+ msg_type='mms',
+ msg_in_call=True)
+
+ @test_tracker_info(uuid="fc8a996b-04b5-40e0-be25-cbbabf4d7957")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mo_iwlan(self):
+ """ Test MO MMS text function for 1 phone in APM,
+ WiFi connected, WFC Cell Preferred mode.
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA
+ Provision PhoneA for WFC Cell Pref with APM ON
+ Send and Verify MMS from PhoneA to PhoneB
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_wfc',
+ mt_rat='default',
+ msg_type='mms',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="7f354997-38b5-49cd-8bee-12d0589e0380")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mt_iwlan(self):
+ """ Test MT MMS text function for 1 phone in APM,
+ WiFi connected, WFC Cell Preferred mode.
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA
+ Provision PhoneA for WFC Cell Pref with APM ON
+ Send and Verify MMS from PhoneB to PhoneA
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_wfc',
+ msg_type='mms',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="592ea897-cba1-4ab5-a4ed-54ac1f8d3039")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mo_iwlan_apm_off(self):
+ """ Test MO MMS, Phone in APM off, WiFi connected, WFC WiFi Pref Mode
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA
+ Provision PhoneA for WFC Wifi Pref with APM OFF
+ Send and Verify MMS from PhoneA to PhoneB
+ Verify 5g NSA attach for PhoneA
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_wfc',
+ mt_rat='default',
+ msg_type='mms',
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="3824205d-6a36-420f-a448-51ebb30948c2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mt_iwlan_apm_off(self):
+ """ Test MT MMS, Phone in APM off, WiFi connected, WFC WiFi Pref Mode
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA
+ Provision PhoneA for WFC Wifi Pref with APM OFF
+ Send and Verify MMS from PhoneB to PhoneA
+ Verify 5g NSA attach for PhoneA
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_wfc',
+ msg_type='mms',
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="91da5493-c810-4b1e-84f0-9d292a7b23eb")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mo_in_call_iwlan(self):
+ """ Test MO MMS, Phone in APM, WiFi connected, WFC WiFi Pref mode
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA
+ Provision PhoneA for WFC Wifi Pref with APM ON
+ Make a Voice call from PhoneA to PhoneB
+ Send and Verify MMS from PhoneA to PhoneB
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_wfc',
+ mt_rat='default',
+ msg_type='mms',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="3e6a6700-1fcb-4db1-a757-e80801032605")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mt_in_call_iwlan(self):
+ """ Test MT MMS, Phone in APM, WiFi connected, WFC WiFi Pref mode
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA
+ Provision PhoneA for WFC Wifi Pref with APM ON
+ Make a Voice call from PhoneB to PhoneA
+ Send and Verify MMS from PhoneB to PhoneA
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_wfc',
+ msg_type='mms',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="dc483cc-d7c7-4cdd-9500-4bfc4f1b5bab")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mo_in_call_volte_wifi(self):
+ """ Test MO MMS during VoLTE call and WiFi connected
+
+ Make sure PhoneA is in 5G NSA (with VoLTE).
+ Make sure PhoneA is able to make call.
+ Connect PhoneA to Wifi.
+ Call from PhoneA to PhoneB, accept on PhoneB, send MMS on PhoneA.
+ Make sure PhoneA is in 5G NSA.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_volte',
+ mt_rat='default',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="95472ce7-0947-4199-bb6a-8fbb189f3c5c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mt_in_call_volte_wifi(self):
+ """ Test MT MMS during VoLTE call and WiFi connected
+
+ Make sure PhoneA is in 5G NSA (with VoLTE).
+ Make sure PhoneA is able to receive call.
+ Connect PhoneA to Wifi.
+ Call from PhoneB to PhoneA, accept on PhoneA, send MMS on PhoneB.
+ Make sure PhoneA is in 5G NSA.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_volte',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="738e2d29-c82d-4a4a-9f4b-e8f8688151ee")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_long_message_mo(self):
+ """Test MO long MMS basic function for 1 phone in nsa 5G network.
+
+ Airplane mode is off. PhoneA in nsa 5G.
+ Send long MMS from PhoneA to PhoneB.
+ Verify received message on PhoneB is correct.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g',
+ mt_rat='default',
+ msg_type='mms',
+ long_msg=True)
+
+ @test_tracker_info(uuid="68f4f0d6-b798-4d0b-9500-ce49f009b61a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_long_message_mt(self):
+ """Test MT long MMS basic function for 1 phone in nsa 5G network.
+
+ Airplane mode is off. PhoneA in nsa 5G.
+ Send long MMS from PhoneB to PhoneA.
+ Verify received message on PhoneA is correct.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g',
+ msg_type='mms',
+ long_msg=True)
+
+ @test_tracker_info(uuid="a379fac4-1aa6-46e0-8cef-6d2452702e04")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mo_in_call_csfb_wifi(self):
+ """ Test MO MMS during a MO csfb call and device connects to Wifi.
+
+ Disable APM on PhoneA
+ Set up PhoneA in CSFB mode.
+ Provision PhoneA in 5g NSA.
+ Make sure PhoneA is able to make call.
+ Connect PhoneA to Wifi.
+ Call from PhoneA to PhoneB, accept on PhoneB, send MMS on PhoneA,
+ receive MMS on B.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_csfb',
+ mt_rat='default',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="1a6543b1-b7d6-4260-8276-88aee649c4b2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_mt_in_call_csfb_wifi(self):
+ """ Test MT MMS during a MT csfb call and device connects to Wifi.
+
+ Disable APM on PhoneA
+ Set up PhoneA is CSFB mode.
+ Provision PhoneA in 5g NSA.
+ Make sure PhoneA is able to receive call.
+ Connect PhoneA to Wifi.
+ Call from PhoneB to PhoneA, accept on PhoneA, send MMS on PhoneB,
+ receive MMS on A.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_csfb',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+ @test_tracker_info(uuid="536c8e25-2d72-46a6-89e1-03f70c5a28a3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_multiple_pdns_mo(self):
+ """Test 5G NSA for multiple pdns
+
+ Steps:
+ (1) UE supports EN-DC option 3.
+ (2) SIM with 5G service.
+ (3) UE is provisioned for 5G service and powered off.
+ (4) NR cell (Cell 2) that is within the coverage of LTE cell (Cell 1).
+ (5) UE is in near cell coverage for LTE (Cell 1) and NR (Cell 2).
+ (6) Power on the UE.
+ (7) Initiate data transfer while UE is in idle mode.
+ (8) During data transferring, send a MO MMS.
+ (9) End the data transfer
+
+ Returns:
+ True if pass; False if fail.
+ """
+ cell_1 = self.android_devices[0]
+ cell_2 = self.android_devices[1]
+ if not phone_setup_volte(self.log, cell_1):
+ cell_1.log.error("Failed to setup on VoLTE")
return False
- if not _mms_test_mt(self.log, ads):
+ if not verify_internet_connection(self.log, cell_1):
+ return False
+ if not provision_device_for_5g(self.log, cell_2, nr_type='nsa'):
+ cell_2.log.error("Failed to setup on 5G NSA")
+ return False
+ if not verify_internet_connection(self.log, cell_2):
+ return False
+ if not active_file_download_task(self.log, cell_2):
+ return False
+ download_task = active_file_download_task(self.log, cell_2, "10MB")
+ message_task = (message_test, (self.log, cell_2, cell_1,
+ '5g', 'volte', 'mms'))
+ results = run_multithread_func(self.log, [download_task, message_task])
+
+ if ((results[0]) & (results[1])):
+ self.log.info("PASS - MO MMS test validated over active data transfer")
+ elif ((results[0] == False) & (results[1] == True)):
+ self.log.error("FAIL - Data Transfer failed")
+ elif ((results[0] == True) & (results[1] == False)):
+ self.log.error("FAIL - Sending MMS failed")
+ else:
+ self.log.error("FAILED - MO MMS test over active data transfer")
+
+ return results
+
+ @test_tracker_info(uuid="10212ab7-a03f-4e11-889e-236b8d1d8afc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mms_multiple_pdns_mt(self):
+ """Test 5G NSA for multiple pdns
+
+ Steps:
+ (1) UE supports EN-DC option 3.
+ (2) SIM with 5G service.
+ (3) UE is provisioned for 5G service and powered off.
+ (4) NR cell (Cell 2) that is within the coverage of LTE cell (Cell 1).
+ (5) UE is in near cell coverage for LTE (Cell 1) and NR (Cell 2).
+ (6) Power on the UE.
+ (7) Initiate data transfer while UE is in idle mode.
+ (8) During data transferring, send a MT MMS.
+ (9) End the data transfer.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ cell_1 = self.android_devices[0]
+ cell_2 = self.android_devices[1]
+
+ if not phone_setup_volte(self.log, cell_1):
+ cell_1.log.error("Failed to setup on VoLTE")
+ return False
+ if not verify_internet_connection(self.log, cell_1):
+ return False
+ if not provision_device_for_5g(self.log, cell_2, nr_type='nsa'):
+ cell_2.log.error("Failed to setup on 5G NSA")
+ return False
+ if not verify_internet_connection(self.log, cell_2):
+ return False
+ if not active_file_download_task(self.log, cell_2):
return False
- if not is_current_network_5g_nsa(ads[0]):
- return False
+ download_task = active_file_download_task(self.log, cell_2, "10MB")
+ message_task = (message_test, (self.log, cell_1, cell_2,
+ 'volte', '5g', 'mms'))
+ results = run_multithread_func(self.log, [download_task, message_task])
- self.log.info("PASS - MT mms test over 5g nsa validated")
- return True
+ if ((results[0]) & (results[1])):
+ self.log.info("PASS - MT MMS test validated over active data transfer")
+ elif ((results[0] == False) & (results[1] == True)):
+ self.log.error("FAIL - Data Transfer failed")
+ elif ((results[0] == True) & (results[1] == False)):
+ self.log.error("FAIL - Sending MMS failed")
+ else:
+ self.log.error("FAILED - MT MMS test over active data transfer")
+
+ return results
""" Tests End """
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gSmsTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gSmsTest.py
index 26ab60a..f1df4f4 100755
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gSmsTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gSmsTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2020 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,41 +18,35 @@
"""
import time
-from acts.utils import rand_ascii_str
+
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_5g_test_utils import disable_apm_mode_both_devices
from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_both_devices_for_volte
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_both_devices_for_wfc_cell_pref
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_both_devices_for_wfc_wifi_pref
-from acts_contrib.test_utils.tel.tel_5g_test_utils import verify_5g_attach_for_both_devices
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_both_devices_for_csfb
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g_nsa
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa
-from acts_contrib.test_utils.tel.tel_sms_utils import _sms_test_mo
-from acts_contrib.test_utils.tel.tel_sms_utils import _sms_test_mt
-from acts_contrib.test_utils.tel.tel_sms_utils import _long_sms_test_mo
-from acts_contrib.test_utils.tel.tel_sms_utils import test_sms_mo_in_call
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_task
+from acts_contrib.test_utils.tel.tel_message_utils import message_test
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_test_utils import install_message_apk
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts.libs.utils.multithread import run_multithread_func
class Nsa5gSmsTest(TelephonyBaseTest):
def setup_class(self):
super().setup_class()
+ self.message_util = self.user_params.get("message_apk", None)
+ if isinstance(self.message_util, list):
+ self.message_util = self.message_util[0]
+
+ if self.message_util:
+ ads = self.android_devices
+ for ad in ads:
+ install_message_apk(ad, self.message_util)
+
def setup_test(self):
TelephonyBaseTest.setup_test(self)
@@ -61,8 +55,6 @@
""" Tests Begin """
-
-
@test_tracker_info(uuid="4a64a262-7433-4a7f-b5c6-a36ff60aeaa2")
@TelephonyBaseTest.tel_test_wrap
def test_5g_nsa_sms_mo_mt(self):
@@ -76,19 +68,12 @@
True if success.
False if failed.
"""
- ads = self.android_devices
- if not provision_device_for_5g(self.log, ads):
- return False
-
- if not _sms_test_mo(self.log, ads):
- return False
-
- if not verify_5g_attach_for_both_devices(self.log, ads):
- return False
-
- self.log.info("PASS - SMS test over 5G NSA validated")
- return True
-
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g',
+ mt_rat='5g')
@test_tracker_info(uuid="52b16764-0c9e-45c0-910f-a39d17c7cf7e")
@TelephonyBaseTest.tel_test_wrap
@@ -103,22 +88,12 @@
True if success.
False if failed.
"""
- ads = self.android_devices
-
- tasks = [(provision_device_for_5g, (self.log, ads[0])),
- (ensure_phone_default_state, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- return False
-
- if not _sms_test_mo(self.log, ads):
- return False
-
- if not is_current_network_5g_nsa(ads[0]):
- return False
-
- self.log.info("PASS - MO SMS test over 5G NSA validated")
- return True
-
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g',
+ mt_rat='default')
@test_tracker_info(uuid="e9b2494a-0e40-449c-b877-1e4ddc78c536")
@TelephonyBaseTest.tel_test_wrap
@@ -133,22 +108,12 @@
True if success.
False if failed.
"""
- ads = self.android_devices
-
- tasks = [(provision_device_for_5g, (self.log, ads[0])),
- (ensure_phone_default_state, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- return False
-
- if not _sms_test_mt(self.log, ads):
- return False
-
- if not is_current_network_5g_nsa(ads[0]):
- return False
-
- self.log.info("PASS - MT SMS test over 5G NSA validated")
- return True
-
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g')
@test_tracker_info(uuid="2ce809d4-cbf6-4233-81ad-43f91107b201")
@TelephonyBaseTest.tel_test_wrap
@@ -164,27 +129,12 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
- if not provision_both_devices_for_volte(self.log, ads):
- return False
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- if not _sms_test_mo(self.log, ads):
- return False
-
- if not hangup_call(self.log, ads[0]):
- ads[0].log.info("Failed to hang up call.!")
- return False
-
- if not verify_5g_attach_for_both_devices(self.log, ads):
- return False
-
- self.log.info("PASS - VoLTE SMS test over 5G NSA validated")
- return True
-
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_volte',
+ mt_rat='5g_volte')
@test_tracker_info(uuid="e51f3dbb-bb16-4400-b2be-f9422f511087")
@TelephonyBaseTest.tel_test_wrap
@@ -200,25 +150,12 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
- if not phone_setup_volte(self.log, ads[0]):
- return False
-
- tasks = [(provision_device_for_5g, (self.log, ads[0])),
- (ensure_phone_default_state, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- return False
-
- if not _sms_test_mo(self.log, ads):
- return False
-
- if not is_current_network_5g_nsa(ads[0]):
- return False
-
- self.log.info("PASS - MO VoLTE SMS test over 5G NSA validated")
- return True
-
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_volte',
+ mt_rat='default')
@test_tracker_info(uuid="5217d427-04a2-4b2b-9ed8-28951e71fc21")
@TelephonyBaseTest.tel_test_wrap
@@ -234,25 +171,12 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
- if not phone_setup_volte(self.log, ads[0]):
- return False
-
- tasks = [(provision_device_for_5g, (self.log, ads[0])),
- (ensure_phone_default_state, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- return False
-
- if not _sms_test_mt(self.log, ads):
- return False
-
- if not is_current_network_5g_nsa(ads[0]):
- return False
-
- self.log.info("PASS - MT VoLTE SMS test over 5G NSA validated")
- return True
-
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_volte')
@test_tracker_info(uuid="49bfb4b3-a6ec-45d4-ad96-09282fb07d1d")
@TelephonyBaseTest.tel_test_wrap
@@ -268,23 +192,13 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
- if not provision_both_devices_for_volte(self.log, ads):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- if not test_sms_mo_in_call(self.log,
- ads,
- caller_func=is_phone_in_call_volte):
- return False
-
- if not verify_5g_attach_for_both_devices(self.log, ads):
- return False
- return True
-
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_volte',
+ mt_rat='5g_volte',
+ msg_in_call=True)
@test_tracker_info(uuid="3d5c8f60-1eaa-4f4a-b539-c529fa36db91")
@TelephonyBaseTest.tel_test_wrap
@@ -300,25 +214,13 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
- if not phone_setup_volte(self.log, ads[0]):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- tasks = [(provision_device_for_5g, (self.log, ads[0])),
- (ensure_phone_default_state, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- return False
-
- if not test_sms_mo_in_call(self.log,
- ads,
- caller_func=is_phone_in_call_volte):
- return False
-
- if not is_current_network_5g_nsa(ads[0]):
- return False
- return True
-
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_volte',
+ mt_rat='default',
+ msg_in_call=True)
@test_tracker_info(uuid="c71813f3-bb04-4115-8519-e23046349689")
@TelephonyBaseTest.tel_test_wrap
@@ -334,25 +236,13 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
- if not phone_setup_volte(self.log, ads[0]):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- tasks = [(provision_device_for_5g, (self.log, ads[0])),
- (ensure_phone_default_state, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- return False
-
- if not test_sms_mo_in_call(self.log,
- [ads[1], ads[0]],
- callee_func=is_phone_in_call_volte):
- return False
-
- if not is_current_network_5g_nsa(ads[0]):
- return False
- return True
-
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_volte',
+ msg_in_call=True)
@test_tracker_info(uuid="1f914d5c-ac24-4794-9fcb-cb28e483d69a")
@TelephonyBaseTest.tel_test_wrap
@@ -368,28 +258,69 @@
Returns:
True if pass; False if fail.
"""
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_wfc',
+ mt_rat='5g_wfc',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
- ads = self.android_devices
- if not disable_apm_mode_both_devices(self.log, ads):
- return False
+ @test_tracker_info(uuid="2d375f20-a785-42e0-b5a1-968d19bc693d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_sms_mo_iwlan(self):
+ """ Test MO SMS for 1 phone in APM,
+ WiFi connected, WFC Cell Preferred mode.
- if not provision_device_for_5g(self.log, ads):
- return False
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA
+ Provision PhoneA for WFC Cell Pref with APM ON
+ Send and Verify SMS from PhoneA to PhoneB
- if not provision_both_devices_for_wfc_cell_pref(self.log,
- ads,
- self.wifi_network_ssid,
- self.wifi_network_pass,
- apm_mode=True):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_wfc',
+ mt_rat='general',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
- if not _sms_test_mo(self.log, ads):
- return False
+ @test_tracker_info(uuid="db8b2b5b-bf9e-4a99-9fdb-dbd028567705")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_sms_mt_iwlan(self):
+ """ Test MT SMS for 1 phone in APM,
+ WiFi connected, WFC Cell Preferred mode.
- self.log.info("PASS - iwlan sms test over 5g nsa validated")
- return True
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA
+ Provision PhoneA for WFC Cell Pref with APM ON
+ Send and Verify SMS from PhoneB to PhoneA
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='5g_wfc',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="7274be32-b9dd-4ce3-83d1-f32ab14ce05e")
@TelephonyBaseTest.tel_test_wrap
@@ -405,31 +336,68 @@
Returns:
True if pass; False if fail.
"""
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_wfc',
+ mt_rat='5g_wfc',
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
- ads = self.android_devices
- if not disable_apm_mode_both_devices(self.log, ads):
- return False
+ @test_tracker_info(uuid="5997a618-efee-478f-8fa9-6cf8ba9cfc58")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_sms_mo_iwlan_apm_off(self):
+ """ Test MO SMS for 1 Phone in APM off, WiFi connected,
+ WFC WiFi Preferred mode.
- if not provision_device_for_5g(self.log, ads):
- return False
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA
+ Provision PhoneA for WFC Wifi Pref with APM OFF
+ Send and Verify SMS from PhoneA to PhoneB
+ Verify 5g NSA attach for PhoneA
- if not provision_both_devices_for_wfc_wifi_pref(self.log,
- ads,
- self.wifi_network_ssid,
- self.wifi_network_pass,
- apm_mode=False):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_wfc',
+ mt_rat='general',
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
- if not _sms_test_mo(self.log, ads):
- self.log.error("failed to send receive sms over 5g nsa")
- return False
- self.log.info("PASS - iwlan sms test over 5g nsa validated")
+ @test_tracker_info(uuid="352ca023-2cd1-4b08-877c-20c5d50cc265")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_sms_mt_iwlan_apm_off(self):
+ """ Test MT SMS for 1 Phone in APM off, WiFi connected,
+ WFC WiFi Preferred mode.
- if not verify_5g_attach_for_both_devices(self.log, ads):
- return False
- return True
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA
+ Provision PhoneA for WFC Wifi Pref with APM OFF
+ Send and Verify SMS from PhoneB to PhoneA
+ Verify 5g NSA attach for PhoneA
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='5g_wfc',
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="2d1787f2-d6fe-4b41-b389-2a8f817594e4")
@TelephonyBaseTest.tel_test_wrap
@@ -445,27 +413,18 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
-
- if not disable_apm_mode_both_devices(self.log, ads):
- return False
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- if not provision_both_devices_for_wfc_wifi_pref(self.log,
- ads,
- self.wifi_network_ssid,
- self.wifi_network_pass,
- apm_mode=True):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- return test_sms_mo_in_call(self.log,
- ads,
- caller_func=is_phone_in_call_iwlan)
-
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_wfc',
+ mt_rat='5g_wfc',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="784062e8-02a4-49ce-8fc1-5359ab40bbdd")
@TelephonyBaseTest.tel_test_wrap
@@ -480,17 +439,13 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- if not disable_apm_mode_both_devices(self.log, ads):
- return False
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- return _long_sms_test_mo(self.log, ads)
-
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g',
+ mt_rat='5g',
+ long_msg=True)
@test_tracker_info(uuid="45dbd61a-6a90-473e-9cfa-03e2408d5f15")
@TelephonyBaseTest.tel_test_wrap
@@ -507,188 +462,259 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_csfb',
+ mt_rat='5g_csfb',
+ msg_in_call=True)
- if not disable_apm_mode_both_devices(self.log, ads):
- return False
-
- if not provision_both_devices_for_csfb(self.log, ads):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- if not provision_device_for_5g_nsa(self.log, ads):
- return False
-
- return test_sms_mo_in_call(self.log,
- ads,
- caller_func=is_phone_in_call_csfb)
-
-
- @test_tracker_info(uuid="2d375f20-a785-42e0-b5a1-968d19bc693d")
+ @test_tracker_info(uuid="709d5322-3da3-4c77-9180-281bc54ad78e")
@TelephonyBaseTest.tel_test_wrap
- def test_5g_nsa_sms_mo_iwlan(self):
- """ Test MO SMS for 1 phone in APM,
- WiFi connected, WFC Cell Preferred mode.
+ def test_5g_nsa_sms_mo_in_call_iwlan(self):
+ """ Test MO SMS for 1 Phone in APM, WiFi connected,
+ WFC WiFi Preferred mode.
- Disable APM on PhoneA
+ Disable APM on both devices
Provision PhoneA in 5g NSA
- Provision PhoneA for WFC Cell Pref with APM ON
+ Provision PhoneA for WFC Wifi Pref with APM ON
+ Make a Voice call from PhoneA to PhoneB
Send and Verify SMS from PhoneA to PhoneB
Returns:
True if pass; False if fail.
"""
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_wfc',
+ mt_rat='default',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
- ads = self.android_devices
- if not toggle_airplane_mode(self.log, ads[0], False):
- return False
-
- tasks = [(provision_device_for_5g, (self.log, ads[0])),
- (ensure_phone_default_state, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- return False
-
- if not phone_setup_iwlan(self.log,
- ads[0],
- True,
- WFC_MODE_CELLULAR_PREFERRED,
- self.wifi_network_ssid,
- self.wifi_network_pass):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- if not _sms_test_mo(self.log, ads):
- return False
-
- self.log.info("PASS - iwlan mo sms test over 5g nsa validated")
- return True
-
-
- @test_tracker_info(uuid="db8b2b5b-bf9e-4a99-9fdb-dbd028567705")
+ @test_tracker_info(uuid="6af38572-bbf7-4c11-8f0c-ab2f9b25ac49")
@TelephonyBaseTest.tel_test_wrap
- def test_5g_nsa_sms_mt_iwlan(self):
- """ Test MT SMS for 1 phone in APM,
- WiFi connected, WFC Cell Preferred mode.
+ def test_5g_nsa_sms_mt_in_call_iwlan(self):
+ """ Test MT SMS for 1 Phone in APM, WiFi connected,
+ WFC WiFi Preferred mode.
- Disable APM on PhoneA
+ Disable APM on both devices
Provision PhoneA in 5g NSA
- Provision PhoneA for WFC Cell Pref with APM ON
+ Provision PhoneA for WFC Wifi Pref with APM ON
+ Make a Voice call from PhoneB to PhoneA
Send and Verify SMS from PhoneB to PhoneA
Returns:
True if pass; False if fail.
"""
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_wfc',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
- ads = self.android_devices
- if not toggle_airplane_mode(self.log, ads[0], False):
- return False
-
- tasks = [(provision_device_for_5g, (self.log, ads[0])),
- (ensure_phone_default_state, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- return False
-
- if not phone_setup_iwlan(self.log,
- ads[0],
- True,
- WFC_MODE_CELLULAR_PREFERRED,
- self.wifi_network_ssid,
- self.wifi_network_pass):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- if not _sms_test_mo(self.log, [ads[1], ads[0]]):
- return False
-
- self.log.info("PASS - iwlan mt sms test over 5g nsa validated")
- return True
-
-
- @test_tracker_info(uuid="5997a618-efee-478f-8fa9-6cf8ba9cfc58")
+ @test_tracker_info(uuid="1437adb8-dfb0-49fb-8ecc-b456f60d7f64")
@TelephonyBaseTest.tel_test_wrap
- def test_5g_nsa_sms_mo_iwlan_apm_off(self):
- """ Test MO SMS for 1 Phone in APM off, WiFi connected,
- WFC WiFi Preferred mode.
+ def test_5g_nsa_sms_long_message_mo(self):
+ """Test MO long SMS function for 1 phone in nsa 5G network.
Disable APM on PhoneA
Provision PhoneA in 5g NSA
- Provision PhoneA for WFC Wifi Pref with APM OFF
- Send and Verify SMS from PhoneA to PhoneB
- Verify 5g NSA attach for PhoneA
+ Send SMS from PhoneA to PhoneB
+ Verify received message on PhoneB is correct
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g',
+ mt_rat='default',
+ long_msg=True)
+
+ @test_tracker_info(uuid="d34a4840-d1fa-46f1-885b-f67456225f50")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_sms_long_message_mt(self):
+ """Test MT long SMS function for 1 phone in nsa 5G network.
+
+ Disable APM on PhoneA
+ Provision PhoneA in 5g NSA
+ Send SMS from PhoneB to PhoneA
+ Verify received message on PhoneA is correct
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g',
+ long_msg=True)
+
+ @test_tracker_info(uuid="84e40f15-1d02-44b0-8103-f25f73dae7a1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_sms_mo_in_call_csfb(self):
+ """ Test MO SMS during a MO csfb call over 5G NSA.
+
+ Disable APM on PhoneA
+ Set up PhoneA are in CSFB mode.
+ Provision PhoneA in 5g NSA.
+ Make sure PhoneA is able to make call.
+ Call from PhoneA to PhoneB, accept on PhoneB, send SMS on PhoneA,
+ receive SMS on PhoneB.
Returns:
True if pass; False if fail.
"""
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_csfb',
+ mt_rat='default',
+ msg_in_call=True)
- ads = self.android_devices
- if not toggle_airplane_mode(self.log, ads[0], False):
- return False
-
- tasks = [(provision_device_for_5g, (self.log, ads[0])),
- (ensure_phone_default_state, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- return False
-
- if not phone_setup_iwlan(self.log,
- ads[0],
- False,
- WFC_MODE_WIFI_PREFERRED,
- self.wifi_network_ssid,
- self.wifi_network_pass):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- if not _sms_test_mo(self.log, ads):
- self.log.error("failed to send receive sms over 5g nsa")
- return False
- self.log.info("PASS - iwlan MO sms test over 5g nsa validated")
-
- if not is_current_network_5g_nsa(ads[0]):
- return False
- return True
-
-
- @test_tracker_info(uuid="352ca023-2cd1-4b08-877c-20c5d50cc265")
+ @test_tracker_info(uuid="259ccd94-2d70-450e-adf4-949889096cce")
@TelephonyBaseTest.tel_test_wrap
- def test_5g_nsa_sms_mt_iwlan_apm_off(self):
- """ Test MT SMS for 1 Phone in APM off, WiFi connected,
- WFC WiFi Preferred mode.
+ def test_5g_nsa_sms_mt_in_call_csfb(self):
+ """ Test MT SMS during a MT csfb call over 5G NSA.
Disable APM on PhoneA
- Provision PhoneA in 5g NSA
- Provision PhoneA for WFC Wifi Pref with APM OFF
- Send and Verify SMS from PhoneB to PhoneA
- Verify 5g NSA attach for PhoneA
+ Set up PhoneA are in CSFB mode.
+ Provision PhoneA in 5g NSA.
+ Make sure PhoneA is able to receive call.
+ Call from PhoneB to PhoneA, accept on PhoneA, send SMS on PhoneB,
+ receive SMS on PhoneA.
Returns:
True if pass; False if fail.
"""
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_csfb',
+ msg_in_call=True)
- ads = self.android_devices
- if not toggle_airplane_mode(self.log, ads[0], False):
+ @test_tracker_info(uuid="303d5c2f-15bd-4608-96b8-37d16341004e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_sms_multiple_pdns_mo(self):
+ """Test 5G NSA for multiple pdns
+
+ Steps:
+ (1) UE supports EN-DC option 3.
+ (2) SIM with 5G service.
+ (3) UE is provisioned for 5G service and powered off.
+ (4) NR cell (Cell 2) that is within the coverage of LTE cell (Cell 1).
+ (5) UE is in near cell coverage for LTE (Cell 1) and NR (Cell 2).
+ (6) Power on the UE.
+ (7) Initiate data transfer while UE is in idle mode.
+ (8) During data transferring, send a MO SMS.
+ (9) End the data transfer
+
+ Returns:
+ True if pass; False if fail.
+ """
+ cell_1 = self.android_devices[0]
+ cell_2 = self.android_devices[1]
+ if not phone_setup_volte(self.log, cell_1):
+ cell_1.log.error("Failed to setup on VoLTE")
return False
- tasks = [(provision_device_for_5g, (self.log, ads[0])),
- (ensure_phone_default_state, (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
+ if not verify_internet_connection(self.log, cell_1):
+ return False
+ if not provision_device_for_5g(self.log, cell_2, nr_type='nsa'):
+ cell_2.log.error("Failed to setup on 5G NSA")
+ return False
+ if not verify_internet_connection(self.log, cell_2):
+ return False
+ if not active_file_download_task(self.log, cell_2):
+ return False
+ download_task = active_file_download_task(self.log, cell_2, "10MB")
+ message_task = (message_test, (self.log, cell_2, cell_1,
+ '5g', 'volte', 'sms'))
+ results = run_multithread_func(self.log, [download_task, message_task])
+
+ if ((results[0]) & (results[1])):
+ self.log.info("PASS - MO SMS test validated over active data transfer")
+ elif ((results[0] == False) & (results[1] == True)):
+ self.log.error("FAIL - Data Transfer failed")
+ elif ((results[0] == True) & (results[1] == False)):
+ self.log.error("FAIL - Sending SMS failed")
+ else:
+ self.log.error("FAILED - MO SMS test over active data transfer")
+
+ return results
+
+ @test_tracker_info(uuid="cc9d2b46-80cc-47a8-926b-3ccf8095cefb")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_sms_multiple_pdns_mt(self):
+ """Test 5G NSA for multiple pdns
+
+ Steps:
+ (1) UE supports EN-DC option 3.
+ (2) SIM with 5G service.
+ (3) UE is provisioned for 5G service and powered off.
+ (4) NR cell (Cell 2) that is within the coverage of LTE cell (Cell 1).
+ (5) UE is in near cell coverage for LTE (Cell 1) and NR (Cell 2).
+ (6) Power on the UE.
+ (7) Initiate data transfer while UE is in idle mode.
+ (8) During data transferring, send a MT SMS.
+ (9) End the data transfer.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ cell_1 = self.android_devices[0]
+ cell_2 = self.android_devices[1]
+
+ if not phone_setup_volte(self.log, cell_1):
+ cell_1.log.error("Failed to setup on VoLTE")
+ return False
+ if not verify_internet_connection(self.log, cell_1):
+ return False
+ if not provision_device_for_5g(self.log, cell_2, nr_type='nsa'):
+ cell_2.log.error("Failed to setup on 5G NSA")
+ return False
+ if not verify_internet_connection(self.log, cell_2):
+ return False
+ if not active_file_download_task(self.log, cell_2):
return False
- if not phone_setup_iwlan(self.log,
- ads[0],
- False,
- WFC_MODE_WIFI_PREFERRED,
- self.wifi_network_ssid,
- self.wifi_network_pass):
- return False
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ download_task = active_file_download_task(self.log, cell_2, "10MB")
+ message_task = (message_test, (self.log, cell_1, cell_2,
+ 'volte', '5g', 'sms'))
+ results = run_multithread_func(self.log, [download_task, message_task])
- if not _sms_test_mt(self.log, ads):
- self.log.error("failed to send receive sms over 5g nsa")
- return False
- self.log.info("PASS - iwlan MT sms test over 5g nsa validated")
+ if ((results[0]) & (results[1])):
+ self.log.info("PASS - MT SMS test validated over active data transfer")
+ elif ((results[0] == False) & (results[1] == True)):
+ self.log.error("FAIL - Data Transfer failed")
+ elif ((results[0] == True) & (results[1] == False)):
+ self.log.error("FAIL - Sending SMS failed")
+ else:
+ self.log.error("FAILED - MT SMS test over active data transfer")
- if not is_current_network_5g_nsa(ads[0]):
- return False
- return True
+ return results
""" Tests End """
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gTetheringTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gTetheringTest.py
index 2558d89..4f43881 100755
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gTetheringTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gTetheringTest.py
@@ -20,8 +20,6 @@
import time
from acts.utils import rand_ascii_str
-from acts.utils import enable_doze
-from acts.utils import disable_doze
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
@@ -32,15 +30,15 @@
from acts_contrib.test_utils.tel.tel_defines import TETHERING_PASSWORD_HAS_ESCAPE
from acts_contrib.test_utils.tel.tel_defines import TETHERING_SPECIAL_SSID_LIST
from acts_contrib.test_utils.tel.tel_defines import TETHERING_SPECIAL_PASSWORD_LIST
-from acts_contrib.test_utils.tel.tel_defines import \
- WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_bt_utils import verify_bluetooth_tethering_connection
from acts_contrib.test_utils.tel.tel_data_utils import run_stress_test
from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_tethering
from acts_contrib.test_utils.tel.tel_data_utils import test_setup_tethering
from acts_contrib.test_utils.tel.tel_data_utils import test_start_wifi_tethering_connect_teardown
from acts_contrib.test_utils.tel.tel_data_utils import test_tethering_wifi_and_voice_call
from acts_contrib.test_utils.tel.tel_data_utils import tethering_check_internet_connection
-from acts_contrib.test_utils.tel.tel_data_utils import verify_bluetooth_tethering_connection
from acts_contrib.test_utils.tel.tel_data_utils import verify_toggle_apm_tethering_internet_connection
from acts_contrib.test_utils.tel.tel_data_utils import verify_tethering_entitlement_check
from acts_contrib.test_utils.tel.tel_data_utils import wifi_tethering_cleanup
@@ -51,19 +49,18 @@
from acts_contrib.test_utils.tel.tel_data_utils import setup_device_internet_connection_then_reboot
from acts_contrib.test_utils.tel.tel_data_utils import verify_internet_connection_in_doze_mode
from acts_contrib.test_utils.tel.tel_data_utils import verify_toggle_data_during_wifi_tethering
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_default_state
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_reset
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_reset
class Nsa5gTetheringTest(TelephonyBaseTest):
@@ -104,7 +101,8 @@
RAT_5G,
WIFI_CONFIG_APBAND_5G,
check_interval=10,
- check_iteration=10)
+ check_iteration=10,
+ nr_type= 'nsa')
@test_tracker_info(uuid="0af10a6b-7c01-41fd-95ce-d839a787aa98")
@@ -128,7 +126,8 @@
RAT_5G,
WIFI_CONFIG_APBAND_2G,
check_interval=10,
- check_iteration=10)
+ check_iteration=10,
+ nr_type= 'nsa')
@test_tracker_info(uuid="d7ab31d5-5f96-4b48-aa92-810e6cfcf845")
@@ -158,7 +157,8 @@
check_interval=10,
check_iteration=2,
do_cleanup=False,
- ssid=ssid):
+ ssid=ssid,
+ nr_type= 'nsa'):
self.log.error("WiFi Tethering failed.")
return False
@@ -191,7 +191,8 @@
if not verify_toggle_data_during_wifi_tethering(self.log,
self.provider,
self.clients,
- new_gen=RAT_5G):
+ new_gen=RAT_5G,
+ nr_type= 'nsa'):
return False
return True
@@ -206,7 +207,7 @@
True if entitlement check returns True.
"""
- if not provision_device_for_5g(self.log, self.provider):
+ if not provision_device_for_5g(self.log, self.provider, nr_type= 'nsa'):
return False
return verify_tethering_entitlement_check(self.log,
self.provider)
@@ -235,7 +236,8 @@
RAT_5G,
WIFI_CONFIG_APBAND_2G,
check_interval=10,
- check_iteration=10)
+ check_iteration=10,
+ nr_type= 'nsa')
return run_stress_test(self.log, self.stress_test_number, precondition, test_case)
@@ -263,7 +265,8 @@
WIFI_CONFIG_APBAND_2G,
check_interval=10,
check_iteration=10,
- ssid=ssid)
+ ssid=ssid,
+ nr_type= 'nsa')
@test_tracker_info(uuid="678c6b04-6733-41e1-bb0c-af8c9d1183cb")
@@ -292,7 +295,8 @@
WIFI_CONFIG_APBAND_2G,
check_interval=10,
check_iteration=10,
- password=password)
+ password=password,
+ nr_type= 'nsa')
@test_tracker_info(uuid="eacc5412-fe75-400b-aba9-c0c38bdfff71")
@@ -307,7 +311,11 @@
True if WiFi tethering succeed on all SSIDs.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ nr_type='nsa'):
self.log.error("Setup Failed.")
return False
ssid_list = TETHERING_SPECIAL_SSID_LIST
@@ -342,7 +350,11 @@
True if WiFi tethering succeed on all passwords.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ nr_type='nsa'):
self.log.error("Setup Failed.")
return False
password_list = TETHERING_SPECIAL_PASSWORD_LIST
@@ -381,11 +393,17 @@
True if success.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ nr_type='nsa'):
self.log.error("Verify 5G Internet access failed.")
return False
- return verify_bluetooth_tethering_connection(self.log, self.provider, self.clients)
+ return verify_bluetooth_tethering_connection(self.log,
+ self.provider,
+ self.clients)
@test_tracker_info(uuid="db70c6ec-5edc-44c2-b61b-1c39516a7475")
@@ -404,12 +422,20 @@
True if success.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ nr_type='nsa'):
self.log.error("Verify 5G Internet access failed.")
return False
- return verify_bluetooth_tethering_connection(self.log, self.provider, self.clients,
- toggle_tethering=False, toggle_bluetooth=False, voice_call=True)
+ return verify_bluetooth_tethering_connection(self.log,
+ self.provider,
+ self.clients,
+ toggle_tethering=False,
+ toggle_bluetooth=False,
+ voice_call=True)
@test_tracker_info(uuid="12efb94f-7466-40e9-9a79-59b4074ab4dd")
@@ -428,12 +454,20 @@
True if success.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ nr_type='nsa'):
self.log.error("Verify 5G Internet access failed.")
return False
- return verify_bluetooth_tethering_connection(self.log, self.provider, self.clients,
- toggle_tethering=False, toggle_bluetooth=False, toggle_data=True)
+ return verify_bluetooth_tethering_connection(self.log,
+ self.provider,
+ self.clients,
+ toggle_tethering=False,
+ toggle_bluetooth=False,
+ toggle_data=True)
@test_tracker_info(uuid="475b485a-1228-4f18-b9f2-593f96850165")
@@ -452,12 +486,20 @@
True if success.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ nr_type='nsa'):
self.log.error("Verify 5G Internet access failed.")
return False
- return verify_bluetooth_tethering_connection(self.log, self.provider, self.clients,
- toggle_tethering=True, toggle_bluetooth=False, toggle_data=False)
+ return verify_bluetooth_tethering_connection(self.log,
+ self.provider,
+ self.clients,
+ toggle_tethering=True,
+ toggle_bluetooth=False,
+ toggle_data=False)
@test_tracker_info(uuid="07f8e523-b471-4156-b057-558123973a5b")
@@ -476,15 +518,21 @@
True if success.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ nr_type='nsa'):
self.log.error("Verify 5G Internet access failed.")
return False
- return verify_bluetooth_tethering_connection(self.log, self.provider, self.clients,
- toggle_tethering=False,
- toggle_bluetooth=False,
- toggle_data=False,
- change_rat=RAT_4G)
+ return verify_bluetooth_tethering_connection(self.log,
+ self.provider,
+ self.clients,
+ toggle_tethering=False,
+ toggle_bluetooth=False,
+ toggle_data=False,
+ change_rat=RAT_4G)
@test_tracker_info(uuid="93040a69-fa85-431f-ac9d-80091c6c8223")
@@ -503,15 +551,21 @@
True if success.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ nr_type='nsa'):
self.log.error("Verify 5G Internet access failed.")
return False
- return verify_bluetooth_tethering_connection(self.log, self.provider, self.clients,
- toggle_tethering=False,
- toggle_bluetooth=False,
- toggle_data=False,
- change_rat=RAT_3G)
+ return verify_bluetooth_tethering_connection(self.log,
+ self.provider,
+ self.clients,
+ toggle_tethering=False,
+ toggle_bluetooth=False,
+ toggle_data=False,
+ change_rat=RAT_3G)
@test_tracker_info(uuid="6cc17fc7-13a0-4493-9673-920952a16fcc")
@@ -530,15 +584,21 @@
True if success.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ nr_type='nsa'):
self.log.error("Verify 5G Internet access failed.")
return False
- return verify_bluetooth_tethering_connection(self.log, self.provider, self.clients,
- toggle_tethering=False,
- toggle_bluetooth=False,
- toggle_data=False,
- change_rat=RAT_2G)
+ return verify_bluetooth_tethering_connection(self.log,
+ self.provider,
+ self.clients,
+ toggle_tethering=False,
+ toggle_bluetooth=False,
+ toggle_data=False,
+ change_rat=RAT_2G)
# Invalid Live Test. Can't rely on the result of this test with live network.
@@ -560,7 +620,11 @@
True if success.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ nr_type='nsa'):
self.log.error("Verify 5G Internet access failed.")
return False
try:
@@ -623,7 +687,10 @@
True if success.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_3G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_3G):
self.log.error("Verify 3G Internet access failed.")
return False
try:
@@ -650,7 +717,9 @@
toggle_apm_after_setting=False):
self.log.error("Provider failed to reselect to LTE")
return False
- if not provision_device_for_5g(self.log, self.provider):
+ if not provision_device_for_5g(self.log,
+ self.provider,
+ nr_type='nsa'):
self.log.error("Provider failed to reselect to nsa 5G")
return False
time.sleep(WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING)
@@ -688,7 +757,11 @@
True if success.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ nr_type='nsa'):
self.log.error("Verify 5G Internet access failed.")
return False
try:
@@ -751,7 +824,10 @@
True if success.
False if failed.
"""
- if not test_setup_tethering(self.log, self.provider, self.clients, RAT_4G):
+ if not test_setup_tethering(self.log,
+ self.provider,
+ self.clients,
+ RAT_4G):
self.log.error("Verify 4G Internet access failed.")
return False
try:
@@ -778,7 +854,9 @@
toggle_apm_after_setting=False):
self.log.error("Provider failed to reselect to LTE")
return False
- if not provision_device_for_5g(self.log, self.provider):
+ if not provision_device_for_5g(self.log,
+ self.provider,
+ nr_type='nsa'):
self.log.error("Provider failed to reselect to nsa 5G")
return False
time.sleep(WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING)
@@ -812,8 +890,13 @@
True if success.
False if failed.
"""
- return test_tethering_wifi_and_voice_call(self.log, self.provider, self.clients,
- RAT_5G, phone_setup_volte, is_phone_in_call_volte)
+ return test_tethering_wifi_and_voice_call(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ phone_setup_volte,
+ is_phone_in_call_volte,
+ nr_type='nsa')
@test_tracker_info(uuid="f4b96666-ac71-49f2-89db-a792da7bb88c")
@TelephonyBaseTest.tel_test_wrap
@@ -830,8 +913,13 @@
True if success.
False if failed.
"""
- return test_tethering_wifi_and_voice_call(self.log, self.provider, self.clients,
- RAT_5G, phone_setup_csfb, is_phone_in_call_csfb)
+ return test_tethering_wifi_and_voice_call(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ phone_setup_csfb,
+ is_phone_in_call_csfb,
+ nr_type='nsa')
@test_tracker_info(uuid="8cfa6ab6-6dcd-4ee5-97f2-db3b0f52ae17")
@TelephonyBaseTest.tel_test_wrap
@@ -848,8 +936,13 @@
True if success.
False if failed.
"""
- return test_tethering_wifi_and_voice_call(self.log, self.provider, self.clients,
- RAT_5G, phone_setup_voice_3g, is_phone_in_call_3g)
+ return test_tethering_wifi_and_voice_call(self.log,
+ self.provider,
+ self.clients,
+ RAT_5G,
+ phone_setup_voice_3g,
+ is_phone_in_call_3g,
+ nr_type='nsa')
@test_tracker_info(uuid="ff1f71d7-142c-4e0d-94be-cadbc30828fd")
@TelephonyBaseTest.tel_test_wrap
@@ -873,7 +966,8 @@
WIFI_CONFIG_APBAND_2G,
check_interval=10,
check_iteration=10,
- password="")
+ password="",
+ nr_type='nsa')
@test_tracker_info(uuid="fd6daa93-2ecb-4a23-8f29-6d2db3b940c4")
@TelephonyBaseTest.tel_test_wrap
@@ -900,7 +994,8 @@
WIFI_CONFIG_APBAND_2G,
check_interval=10,
check_iteration=2,
- do_cleanup=False):
+ do_cleanup=False,
+ nr_type='nsa'):
return False
if not verify_wifi_tethering_when_reboot(self.log,
@@ -955,7 +1050,8 @@
check_interval=10,
check_iteration=2,
do_cleanup=False,
- pre_teardown_func=setup_provider_internet_connection):
+ pre_teardown_func=setup_provider_internet_connection,
+ nr_type='nsa'):
return False
if not verify_wifi_tethering_when_reboot(self.log,
@@ -1002,7 +1098,8 @@
WIFI_CONFIG_APBAND_2G,
check_interval=10,
check_iteration=2,
- pre_teardown_func=setup_provider_internet_connect_then_reboot)
+ pre_teardown_func=setup_provider_internet_connect_then_reboot,
+ nr_type='nsa')
@test_tracker_info(uuid="70f20bcf-8064-49e3-a3f0-ff151374d1ac")
@TelephonyBaseTest.tel_test_wrap
@@ -1032,7 +1129,8 @@
WIFI_CONFIG_APBAND_2G,
check_interval=10,
check_iteration=2,
- do_cleanup=False):
+ do_cleanup=False,
+ nr_type='nsa'):
return False
if not verify_internet_connection_in_doze_mode(self.log,
self.provider,
@@ -1078,7 +1176,8 @@
WIFI_CONFIG_APBAND_2G,
check_interval=10,
check_iteration=2,
- pre_teardown_func=setup_provider_internet_connection):
+ pre_teardown_func=setup_provider_internet_connection,
+ nr_type='nsa'):
return False
if not wait_and_verify_device_internet_connection(self.log, self.provider):
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gVoiceConfTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gVoiceConfTest.py
index bbe738b..b4bbbd0 100644
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gVoiceConfTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gVoiceConfTest.py
@@ -22,32 +22,32 @@
import time
from acts import signals
from acts.test_decorators import test_tracker_info
+from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_ACTIVE
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_CONFERENCE
+from acts_contrib.test_utils.tel.tel_defines import GEN_5G
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_ss_utils import three_phone_call_forwarding_short_seq
+from acts_contrib.test_utils.tel.tel_ss_utils import three_phone_call_waiting_short_seq
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import install_dialer_apk
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_wcdma
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _get_expected_call_state
-from acts_contrib.test_utils.tel.tel_voice_conf_utils import \
- _test_ims_conference_merge_drop_first_call_from_host
-from acts_contrib.test_utils.tel.tel_voice_conf_utils import \
- _test_ims_conference_merge_drop_first_call_from_participant
-from acts_contrib.test_utils.tel.tel_voice_conf_utils import \
- _test_ims_conference_merge_drop_second_call_from_host
-from acts_contrib.test_utils.tel.tel_voice_conf_utils import \
- _test_ims_conference_merge_drop_second_call_from_participant
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_ims_conference_merge_drop_first_call_from_host
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_ims_conference_merge_drop_first_call_from_participant
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_ims_conference_merge_drop_second_call_from_host
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_ims_conference_merge_drop_second_call_from_participant
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_call_mo_mo_add_swap_x
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_call_mo_mt_add_swap_x
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_call_mt_mt_add_swap_x
-from acts_contrib.test_utils.tel.tel_voice_conf_utils import \
- _three_phone_hangup_call_verify_call_state
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _three_phone_hangup_call_verify_call_state
class Nsa5gVoiceConfTest(TelephonyBaseTest):
@@ -62,6 +62,15 @@
raise signals.TestAbortClass(
"Conference call is not supported, abort test.")
+ self.dialer_util = self.user_params.get("dialer_apk", None)
+ if isinstance(self.dialer_util, list):
+ self.dialer_util = self.dialer_util[0]
+
+ if self.dialer_util:
+ ads = self.android_devices
+ for ad in ads:
+ install_dialer_apk(ad, self.dialer_util)
+
def teardown_test(self):
ensure_phones_idle(self.log, self.android_devices)
@@ -2429,3 +2438,325 @@
call_state=_get_expected_call_state(ads[0]),
ads_active=[ads[0], ads[2]])
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="f4990e20-4a40-4238-9a2a-a75d9be3d354")
+ def test_5g_nsa_volte_call_forwarding_unconditional(self):
+
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0], GEN_5G)),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_forwarding_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_forwarding_type="unconditional")
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="26b85c3f-5a38-465a-a6e3-dfd03c6ea315")
+ def test_5g_nsa_volte_call_forwarding_busy(self):
+
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0], GEN_5G)),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_forwarding_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_forwarding_type="busy")
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="96638a39-efe2-40e2-afb6-6a97f87c4af5")
+ def test_5g_nsa_volte_call_forwarding_not_answered(self):
+
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0], GEN_5G)),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_forwarding_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_forwarding_type="not_answered")
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="a13e586a-3345-49d8-9e84-ca33bd3fbd7d")
+ def test_5g_nsa_volte_call_forwarding_not_reachable(self):
+
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0], GEN_5G)),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_forwarding_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_forwarding_type="not_reachable")
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="e9a6027b-7dd1-4dca-a700-e4d42c9c947d")
+ def test_call_waiting_scenario_1(self):
+ """ Call waiting scenario 1: 1st call ended first by caller1 during 2nd
+ call incoming. 2nd call ended by caller2.
+ """
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0], GEN_5G)),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_waiting_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_waiting=True,
+ scenario=1)
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="3fe02cb7-68d7-4762-882a-02bff8ce32f9")
+ def test_call_waiting_scenario_2(self):
+ """ Call waiting scenario 2: 1st call ended first by caller1 during 2nd
+ call incoming. 2nd call ended by callee.
+ """
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0], GEN_5G)),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_waiting_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_waiting=True,
+ scenario=2)
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="bf5eb9ad-1fa2-468d-99dc-3cbcee8c89f8")
+ def test_call_waiting_scenario_3(self):
+ """ Call waiting scenario 3: 1st call ended first by callee during 2nd
+ call incoming. 2nd call ended by caller2.
+ """
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0], GEN_5G)),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_waiting_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_waiting=True,
+ scenario=3)
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="f2e4b6a9-6a6f-466c-884c-c0ef79d6ff01")
+ def test_call_waiting_scenario_4(self):
+ """Call waiting scenario 4: 1st call ended first by callee during 2nd
+ call incoming. 2nd call ended by callee.
+ """
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0], GEN_5G)),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_waiting_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_waiting=True,
+ scenario=4)
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="f2d36f45-63f6-4e01-9844-6fa53c26def7")
+ def test_call_waiting_scenario_5(self):
+ """ Call waiting scenario 5: 1st call ended by caller1. 2nd call ended
+ by caller2.
+ """
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0], GEN_5G)),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_waiting_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_waiting=True,
+ scenario=5)
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="7eb2a89d-30ad-4a34-8e63-87d0181b91aa")
+ def test_call_waiting_scenario_6(self):
+ """Call waiting scenario 6: 1st call ended by caller1. 2nd call ended by
+ callee.
+ """
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0], GEN_5G)),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_waiting_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_waiting=True,
+ scenario=6)
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="c63882e5-5b72-4ca6-8e36-260c50f42028")
+ def test_call_waiting_scenario_7(self):
+ """ Call waiting scenario 7: 1st call ended by callee. 2nd call ended by
+ caller2.
+ """
+ ads = self.android_devices
+
+ tasks = [(phone_setup_voice_general, (self.log, ads[0])),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_waiting_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_waiting=True,
+ scenario=7)
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="f9be652f-a307-4fa5-9b30-ea78404110bd")
+ def test_call_waiting_scenario_8(self):
+ """Call waiting scenario 8: 1st call ended by callee. 2nd call ended by
+ callee.
+ """
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0], GEN_5G)),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_waiting_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_waiting=True,
+ scenario=8)
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="b2e816b5-8e8f-4863-981c-47847d9527e0")
+ def test_call_waiting_deactivated(self):
+
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0], GEN_5G)),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_waiting_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_waiting=False)
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gVoiceTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gVoiceTest.py
index eff3227..38cbe45 100644
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gVoiceTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gVoiceTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2020 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,10 +17,9 @@
Test Script for 5G Voice scenarios
"""
-import time
-
from acts import signals
-from acts.utils import adb_shell_ping
+from acts.libs.utils.multithread import multithread_func
+from acts.libs.utils.multithread import run_multithread_func
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
@@ -29,51 +28,51 @@
from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_TERMINATED
from acts_contrib.test_utils.tel.tel_defines import GEN_5G
from acts_contrib.test_utils.tel.tel_defines import TOTAL_LONG_CALL_DURATION
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL_FOR_IMS
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import \
- call_voicemail_erase_all_pending_voicemail
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import get_mobile_data_usage
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call_active
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import remove_mobile_data_usage_limit
-from acts_contrib.test_utils.tel.tel_test_utils import set_mobile_data_usage_limit
+from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_both_devices_for_volte
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_5g_test_utils import verify_5g_attach_for_both_devices
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_task
+from acts_contrib.test_utils.tel.tel_data_utils import call_epdg_to_epdg_wfc
+from acts_contrib.test_utils.tel.tel_data_utils import get_mobile_data_usage
+from acts_contrib.test_utils.tel.tel_data_utils import remove_mobile_data_usage_limit
+from acts_contrib.test_utils.tel.tel_data_utils import set_mobile_data_usage_limit
+from acts_contrib.test_utils.tel.tel_data_utils import test_call_setup_in_active_data_transfer
+from acts_contrib.test_utils.tel.tel_data_utils import test_call_setup_in_active_youtube_video
+from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
+from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_cell_switching_in_call
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_test_utils import install_dialer_apk
from acts_contrib.test_utils.tel.tel_voice_utils import _test_call_long_duration
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_volte
from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_call_hold_unhold_test
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import call_voicemail_erase_all_pending_voicemail
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_active
from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_leave_voice_mail
from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_long_seq
from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_short_seq
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_both_devices_for_volte
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
-from acts_contrib.test_utils.tel.tel_5g_test_utils import set_preferred_mode_for_5g
-from acts_contrib.test_utils.tel.tel_5g_test_utils import verify_5g_attach_for_both_devices
-from acts_contrib.test_utils.tel.tel_5g_test_utils import disable_apm_mode_both_devices
-from acts_contrib.test_utils.tel.tel_data_utils import call_epdg_to_epdg_wfc
-from acts_contrib.test_utils.tel.tel_data_utils import test_call_setup_in_active_data_transfer
-from acts_contrib.test_utils.tel.tel_data_utils import test_call_setup_in_active_youtube_video
-from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
-from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_cell_switching_in_call
+from acts_contrib.test_utils.tel.tel_ops_utils import initiate_call_verify_operation
+
+
CallResult = TelephonyVoiceTestResult.CallResult.Value
@@ -88,6 +87,15 @@
"long_call_duration",
TOTAL_LONG_CALL_DURATION)
+ self.dialer_util = self.user_params.get("dialer_apk", None)
+ if isinstance(self.dialer_util, list):
+ self.dialer_util = self.dialer_util[0]
+
+ if self.dialer_util:
+ ads = self.android_devices
+ for ad in ads:
+ install_dialer_apk(ad, self.dialer_util)
+
def setup_test(self):
TelephonyBaseTest.setup_test(self)
@@ -114,7 +122,7 @@
if not provision_both_devices_for_volte(self.log, ads):
return False
- if not provision_device_for_5g(self.log, ads):
+ if not provision_device_for_5g(self.log, ads, nr_type='nsa'):
return False
# VoLTE calls
@@ -126,7 +134,7 @@
self.log.error("Failure is volte call during 5g nsa")
return False
- if not verify_5g_attach_for_both_devices(self.log, ads):
+ if not verify_5g_attach_for_both_devices(self.log, ads, nr_type='nsa'):
return False
self.log.info("PASS - volte test over 5g nsa validated")
@@ -155,7 +163,7 @@
self.log.error("Phone failed to set up in volte/3g")
return False
- if not provision_device_for_5g(self.log, ads[0]):
+ if not provision_device_for_5g(self.log, ads[0], nr_type='nsa'):
return False
# VoLTE to 3G
@@ -168,7 +176,7 @@
return False
# Attach nsa5g
- if not is_current_network_5g_nsa(ads[0]):
+ if not is_current_network_5g(ads[0], nr_type = 'nsa'):
ads[0].log.error("Phone not attached on 5g nsa after call end.")
return False
@@ -195,7 +203,7 @@
if not provision_both_devices_for_volte(self.log, ads):
return False
- if not provision_device_for_5g(self.log, ads):
+ if not provision_device_for_5g(self.log, ads, nr_type='nsa'):
return False
if not phone_setup_call_hold_unhold_test(self.log,
@@ -204,7 +212,7 @@
caller_func=is_phone_in_call_volte):
return False
- if not verify_5g_attach_for_both_devices(self.log, ads):
+ if not verify_5g_attach_for_both_devices(self.log, ads, nr_type='nsa'):
return False
return True
@@ -227,7 +235,7 @@
if not provision_both_devices_for_volte(self.log, ads):
return False
- if not provision_device_for_5g(self.log, ads):
+ if not provision_device_for_5g(self.log, ads, nr_type='nsa'):
return False
if not phone_setup_call_hold_unhold_test(self.log,
@@ -236,7 +244,7 @@
callee_func=is_phone_in_call_volte):
return False
- if not verify_5g_attach_for_both_devices(self.log, ads):
+ if not verify_5g_attach_for_both_devices(self.log, ads, nr_type='nsa'):
return False
return True
@@ -297,67 +305,6 @@
DIRECTION_MOBILE_TERMINATED)
- @test_tracker_info(uuid="3a607dee-7e92-4567-8ca0-05099590b773")
- @TelephonyBaseTest.tel_test_wrap
- def test_5g_nsa_volte_in_call_wifi_toggling(self):
- """ Test data connection network switching during VoLTE call in 5G NSA.
-
- 1. Make Sure PhoneA in VoLTE.
- 2. Make Sure PhoneB in VoLTE.
- 3. Make sure Phones are in 5G NSA
- 4. Call from PhoneA to PhoneB.
- 5. Toggling Wifi connection in call.
- 6. Verify call is active.
- 7. Hung up the call on PhoneA
- 8. Make sure Phones are in 5G NSA
-
- Returns:
- True if pass; False if fail.
- """
- ads = self.android_devices
- result = True
- if not provision_both_devices_for_volte(self.log, ads):
- return False
-
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- if not provision_device_for_5g(self.log, ads):
- return False
-
- if not verify_5g_attach_for_both_devices(self.log, ads):
- self.log.error("Phone not attached on 5G NSA before call.")
- return False
-
- if not call_setup_teardown(self.log, ads[0], ads[1], None, None, None,
- 5):
- self.log.error("Call setup failed")
- return False
- else:
- self.log.info("Call setup succeed")
-
- if not wifi_cell_switching(self.log, ads[0], None, self.wifi_network_ssid,
- self.wifi_network_pass):
- ads[0].log.error("Failed to do WIFI and Cell switch in call")
- result = False
-
- if not is_phone_in_call_active(ads[0]):
- return False
- else:
- if not ads[0].droid.telecomCallGetAudioState():
- ads[0].log.error("Audio is not on call")
- result = False
- else:
- ads[0].log.info("Audio is on call")
- hangup_call(self.log, ads[0])
-
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-
- if not verify_5g_attach_for_both_devices(self.log, ads):
- self.log.error("Phone not attached on 5G NSA after call.")
- return False
- return result
-
-
@test_tracker_info(uuid="96b7d8c9-d32a-4abf-8326-6b060d116ac2")
@TelephonyBaseTest.tel_test_wrap
def test_5g_nsa_call_epdg_to_epdg_wfc_wifi_preferred(self):
@@ -522,7 +469,7 @@
"Failed to setup iwlan with APM off and WIFI and WFC on")
return False
- if not provision_device_for_5g(self.log, ads[0]):
+ if not provision_device_for_5g(self.log, ads[0], nr_type='nsa'):
return False
if not phone_setup_call_hold_unhold_test(self.log,
@@ -531,7 +478,7 @@
caller_func=is_phone_in_call_iwlan):
return False
- if not is_current_network_5g_nsa(ads[0]):
+ if not is_current_network_5g(ads[0], nr_type = 'nsa'):
ads[0].log.error("Phone not attached on 5G NSA after call.")
return False
return True
@@ -561,7 +508,7 @@
"Failed to setup iwlan with APM off and WIFI and WFC on")
return False
- if not provision_device_for_5g(self.log, ads[0]):
+ if not provision_device_for_5g(self.log, ads[0], nr_type='nsa'):
return False
if not phone_setup_call_hold_unhold_test(self.log,
@@ -570,7 +517,7 @@
callee_func=is_phone_in_call_iwlan):
return False
- if not is_current_network_5g_nsa(ads[0]):
+ if not is_current_network_5g(ads[0], nr_type = 'nsa'):
ads[0].log.error("Phone not attached on 5G NSA after call.")
return False
return True
@@ -597,7 +544,7 @@
self.log.error("Phone failed to set up in VoLTE/CSFB")
return False
- if not provision_device_for_5g(self.log, ads[0]):
+ if not provision_device_for_5g(self.log, ads[0], nr_type='nsa'):
return False
result = two_phone_call_short_seq(
@@ -630,7 +577,7 @@
self.log.error("Phone failed to set up in VoLTE/2G")
return False
- if not provision_device_for_5g(self.log, ads[0]):
+ if not provision_device_for_5g(self.log, ads[0], nr_type='nsa'):
return False
result = two_phone_call_short_seq(
@@ -665,7 +612,7 @@
self.log.error("Phone failed to set up in VoLTE")
return False
- if not provision_device_for_5g(self.log, ads[1]):
+ if not provision_device_for_5g(self.log, ads[1], nr_type='nsa'):
return False
result = two_phone_call_short_seq(
@@ -701,7 +648,7 @@
self.log.error("Phone failed to set up in VoLTE")
return False
- if not provision_device_for_5g(self.log, ads[1]):
+ if not provision_device_for_5g(self.log, ads[1], nr_type='nsa'):
return False
result = two_phone_call_short_seq(
@@ -737,7 +684,7 @@
self.log.error("Phone failed to set up in VoLTE")
return False
- if not provision_device_for_5g(self.log, ads[1]):
+ if not provision_device_for_5g(self.log, ads[1], nr_type='nsa'):
return False
result = two_phone_call_short_seq(
@@ -769,7 +716,7 @@
if not provision_both_devices_for_volte(self.log, ads):
return False
- if not provision_device_for_5g(self.log, ads[1]):
+ if not provision_device_for_5g(self.log, ads[1], nr_type='nsa'):
return False
result = two_phone_call_long_seq(
@@ -805,7 +752,7 @@
if not provision_both_devices_for_volte(self.log, ads):
return False
- if not provision_device_for_5g(self.log, ads[1]):
+ if not provision_device_for_5g(self.log, ads[1], nr_type='nsa'):
return False
success_count = 0
@@ -859,7 +806,7 @@
self.log.error("Phone Failed to Set Up Properly.")
return False
- if not provision_device_for_5g(self.log, ads[0]):
+ if not provision_device_for_5g(self.log, ads[0], nr_type='nsa'):
return False
if not call_voicemail_erase_all_pending_voicemail(self.log, ads[0]):
@@ -895,7 +842,7 @@
self.log.error("Phone Failed to Set Up Properly.")
return False
- if not provision_device_for_5g(self.log, ads[0]):
+ if not provision_device_for_5g(self.log, ads[0], nr_type='nsa'):
return False
return _test_call_long_duration(self.log, ads,
@@ -922,7 +869,7 @@
data_usage = get_mobile_data_usage(ads[0], subscriber_id)
set_mobile_data_usage_limit(ads[0], data_usage, subscriber_id)
- if not provision_device_for_5g(self.log, ads):
+ if not provision_device_for_5g(self.log, ads, nr_type='nsa'):
self.log.error("Phone Failed to Set Up Properly.")
self.tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
raise signals.TestFailure("Failed",
@@ -959,7 +906,7 @@
ads = self.android_devices
result = True
- if not provision_device_for_5g(self.log, ads):
+ if not provision_device_for_5g(self.log, ads, nr_type='nsa'):
self.log.error("Phone Failed to Set Up Properly.")
self.tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
raise signals.TestFailure("Failed",
@@ -1052,7 +999,7 @@
True if success.
False if failed.
"""
- if not provision_device_for_5g(self.log, self.android_devices[0]):
+ if not provision_device_for_5g(self.log, self.android_devices[0], nr_type='nsa'):
self.android_devices[0].log.error("Phone not attached on 5G NSA before call.")
return False
@@ -1082,7 +1029,7 @@
True if success.
False if failed.
"""
- if not provision_device_for_5g(self.log, self.android_devices[0]):
+ if not provision_device_for_5g(self.log, self.android_devices[0], nr_type='nsa'):
self.android_devices[0].log.error("Phone not attached on 5G NSA before call.")
return False
@@ -1111,7 +1058,7 @@
True if success.
False if failed.
"""
- if not provision_device_for_5g(self.log, self.android_devices[0]):
+ if not provision_device_for_5g(self.log, self.android_devices[0], nr_type='nsa'):
self.android_devices[0].log.error("Phone not attached on 5G NSA before call.")
return False
@@ -1140,7 +1087,7 @@
True if success.
False if failed.
"""
- if not provision_device_for_5g(self.log, self.android_devices[0]):
+ if not provision_device_for_5g(self.log, self.android_devices[0], nr_type='nsa'):
self.android_devices[0].log.error("Phone not attached on 5G NSA before call.")
return False
@@ -1174,7 +1121,7 @@
ads = self.android_devices
- if not provision_device_for_5g(self.log, ads):
+ if not provision_device_for_5g(self.log, ads, nr_type='nsa'):
return False
tasks = [(phone_setup_iwlan,
(self.log, ads[0], False, WFC_MODE_WIFI_PREFERRED,
@@ -1189,4 +1136,109 @@
self.wifi_network_ssid,
self.wifi_network_pass)
+ @test_tracker_info(uuid="e42cb2bc-db0b-4053-a052-7d95e55bc815")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_volte_call_during_data_idle_and_transfer_mo(self):
+ """Test 5G NSA for VoLTE call during data idle and data transfer.
+
+ Steps:
+ (1) Provision both devices on 5G NSA.
+ (2) Initiate MO VoLTE call during data idle.
+ (3) End call.
+ (4) Initiate a MO VoLTE call and start a download.
+ (5) Start another download and initiate MO VoLTE call during data transferring.
+ (6) End call.
+ (7) Initiate a MO VoLTE call and start a download.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ cell_1 = self.android_devices[0]
+ cell_2 = self.android_devices[1]
+
+ if not provision_device_for_5g(self.log, [cell_1, cell_2], nr_type='nsa'):
+ cell_1.log.error("Failed to setup on 5G NSA")
+ return False
+
+ # Initiate call during data idle and end call
+ if not initiate_call_verify_operation(self.log, cell_1, cell_2):
+ cell_1.log.error("Phone was unable to initate a call")
+ return False
+
+ # Initiate call and start a download
+ if not initiate_call_verify_operation(self.log, cell_1, cell_2, True):
+ cell_1.log.error("Phone was unable to initate a call and verify download")
+ return False
+
+ download_task = active_file_download_task(self.log, cell_1, "10MB")
+ call_task = (initiate_call_verify_operation, (self.log, cell_1, cell_2))
+
+ results = run_multithread_func(self.log, [download_task, call_task])
+
+ if ((results[0]) & (results[1])):
+ self.log.info("PASS - Validate VoLTE call during data transferring")
+ elif ((results[0] == False) & (results[1] == True)):
+ self.log.error("FAIL - Data Transfer failed")
+ elif ((results[0] == True) & (results[1] == False)):
+ self.log.error("FAIL - Call Initiation failed")
+ else:
+ self.log.error("FAILED - Validate VoLTE call during data transferring")
+
+ if not initiate_call_verify_operation(self.log, cell_1, cell_2, True):
+ cell_1.log.error("Phone was unable to initate a call and verify download")
+ return False
+
+
+ @test_tracker_info(uuid="c69ec37d-133f-42c5-babd-91f763dd5b21")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_volte_call_during_data_idle_and_transfer_mt(self):
+ """Test 5G NSA for VoLTE call during data idle and data transfer.
+
+ Steps:
+ (1) Provision both devices on 5G NSA.
+ (2) Initiate MT VoLTE call during data idle.
+ (3) End call.
+ (4) Initiate a MO VoLTE call and start a download.
+ (5) Start another download and initiate MT VoLTE call during data transferring.
+ (6) End call.
+ (7) Initiate a MO VoLTE call and start a download.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ cell_1 = self.android_devices[0]
+ cell_2 = self.android_devices[1]
+
+ if not provision_device_for_5g(self.log, [cell_1, cell_2], nr_type='nsa'):
+ cell_1.log.error("Failed to setup on 5G NSA")
+ return False
+
+ # Initiate call during data idle and end call
+ if not initiate_call_verify_operation(self.log, cell_2, cell_1):
+ cell_2.log.error("Phone was unable to initate a call")
+ return False
+
+ # Initiate call and start a download
+ if not initiate_call_verify_operation(self.log, cell_1, cell_2, True):
+ cell_1.log.error("Phone was unable to initate a call and verify download")
+ return False
+
+ download_task = active_file_download_task(self.log, cell_2, "10MB")
+ call_task = (initiate_call_verify_operation, (self.log, cell_2, cell_1))
+
+ results = run_multithread_func(self.log, [download_task, call_task])
+
+ if ((results[0]) & (results[1])):
+ self.log.info("PASS - Validate MT VoLTE call during data transferring")
+ elif ((results[0] == False) & (results[1] == True)):
+ self.log.error("FAIL - Data Transfer failed")
+ elif ((results[0] == True) & (results[1] == False)):
+ self.log.error("FAIL - Call Initiation failed")
+ else:
+ self.log.error("FAILED - Validate MT VoLTE call during data transferring")
+
+ if not initiate_call_verify_operation(self.log, cell_1, cell_2, True):
+ cell_1.log.error("Phone was unable to initate a call and verify download")
+ return False
+
""" Tests End """
diff --git a/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwActivationTest.py b/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwActivationTest.py
new file mode 100644
index 0000000..fde9540
--- /dev/null
+++ b/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwActivationTest.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2021 - 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 5G MSA mmWave Activation scenarios
+"""
+
+import time
+
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
+from acts_contrib.test_utils.tel.tel_test_utils import cycle_airplane_mode
+from acts_contrib.test_utils.tel.tel_5g_test_utils import test_activation_by_condition
+from acts_contrib.test_utils.tel.tel_test_utils import set_phone_silent_mode
+
+
+class Nsa5gMmwActivationTest(TelephonyBaseTest):
+ def setup_class(self):
+ super().setup_class()
+ for ad in self.android_devices:
+ set_phone_silent_mode(self.log, ad, True)
+
+ def setup_test(self):
+ TelephonyBaseTest.setup_test(self)
+ self.number_of_devices = 1
+
+ def teardown_class(self):
+ TelephonyBaseTest.teardown_class(self)
+
+ """ Tests Begin """
+
+ @test_tracker_info(uuid="6831cf7f-349e-43ae-9a89-5e183a755671")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_activation_from_apm(self):
+ """ Verifies 5G NSA mmWave activation from Airplane Mode
+
+ Toggle Airplane mode on and off
+ Ensure phone attach, data on, LTE attach
+ Wait for 120 secs for ENDC attach
+ Verify is data network type is NR_NSA
+
+ Returns:
+ True if pass; False if fail.
+ """
+
+ return test_activation_by_condition(self.android_devices[0],
+ nr_type='mmwave',
+ precond_func=lambda: cycle_airplane_mode(self.android_devices[0]))
+
+ @test_tracker_info(uuid="21fb9b5c-40e8-4804-b05b-017395bb2e79")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_activation_from_reboot(self):
+ """ Verifies 5G NSA mmWave activation from Reboot
+
+ Reboot device
+ Ensure phone attach, data on, LTE attach
+ Wait for 120 secs for ENDC attach
+ Verify is data network type is NR_NSA
+
+ Returns:
+ True if pass; False if fail.
+ """
+
+ return test_activation_by_condition(self.android_devices[0],
+ nr_type='mmwave',
+ precond_func=lambda: reboot_device(self.android_devices[0]))
+
+ @test_tracker_info(uuid="2cef7ec0-ea74-458f-a98e-143d0be71f31")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_activation_from_3g(self):
+ """ Verifies 5G NSA mmWave activation from 3G Mode Pref
+
+ Change Mode to 3G and wait for 15 secs
+ Change Mode back to 5G
+ Ensure phone attach, data on, LTE attach
+ Wait for 120 secs for ENDC attach
+ Verify is data network type is NR_NSA
+
+ Returns:
+ True if pass; False if fail.
+ """
+
+ return test_activation_by_condition(self.android_devices[0],
+ from_3g=True,
+ nr_type='mmwave')
+
+ """ Tests End """
+
diff --git a/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwDataTest.py b/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwDataTest.py
new file mode 100755
index 0000000..5f54d59
--- /dev/null
+++ b/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwDataTest.py
@@ -0,0 +1,372 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2022 - 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 5G NSA MMWAVE Data scenarios
+"""
+
+import time
+
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_defines import GEN_5G
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_USER_PLANE_DATA
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_NR_LTE_GSM_WCDMA
+from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackCapabilitiesChanged
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_5g_test_utils import set_preferred_mode_for_5g
+from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
+from acts_contrib.test_utils.tel.tel_data_utils import airplane_mode_test
+from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_detection
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_recovery
+from acts_contrib.test_utils.tel.tel_data_utils import check_network_validation_fail
+from acts_contrib.test_utils.tel.tel_data_utils import data_connectivity_single_bearer
+from acts_contrib.test_utils.tel.tel_data_utils import reboot_test
+from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_connect_disconnect
+from acts_contrib.test_utils.tel.tel_data_utils import verify_for_network_callback
+from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
+from acts_contrib.test_utils.tel.tel_test_utils import break_internet_except_sl4a_port
+from acts_contrib.test_utils.tel.tel_test_utils import get_current_override_network_type
+from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
+from acts_contrib.test_utils.tel.tel_test_utils import resume_internet_with_sl4a_port
+from acts_contrib.test_utils.tel.tel_test_utils import set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_failure_using_sl4a
+from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_success_using_sl4a
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_reset
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
+
+
+class Nsa5gMmwDataTest(TelephonyBaseTest):
+ def setup_class(self):
+ super().setup_class()
+ self.iperf_server_ip = self.user_params.get("iperf_server", '0.0.0.0')
+ self.iperf_tcp_port = self.user_params.get("iperf_tcp_port", 0)
+ self.iperf_udp_port = self.user_params.get("iperf_udp_port", 0)
+ self.iperf_duration = self.user_params.get("iperf_duration", 60)
+ for ad in self.android_devices:
+ set_phone_silent_mode(self.log, ad, True)
+
+ def setup_test(self):
+ TelephonyBaseTest.setup_test(self)
+ self.provider = self.android_devices[0]
+ self.clients = self.android_devices[1:]
+
+ def teardown_class(self):
+ TelephonyBaseTest.teardown_class(self)
+
+
+ """ Tests Begin """
+
+
+ @test_tracker_info(uuid="069d05c0-1fa0-4fd4-a4df-a0eff753b38d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_data_browsing(self):
+ """ Verifying connectivity of internet and browsing websites on 5G NSA MMW network.
+
+ Ensure
+ 1. ping to IP of websites is successful.
+ 2. http ping to IP of websites is successful.
+ 3. browsing websites is successful.
+ Returns:
+ True if pass; False if fail.
+ """
+ ad = self.android_devices[0]
+ wifi_toggle_state(ad.log, ad, False)
+ sub_id = ad.droid.subscriptionGetDefaultSubId()
+ if not set_preferred_mode_for_5g(ad, sub_id,
+ NETWORK_MODE_NR_LTE_GSM_WCDMA):
+ ad.log.error("Failed to set network mode to NSA")
+ return False
+ ad.log.info("Set network mode to NSA successfully")
+ ad.log.info("Waiting for 5G NSA MMW attach for 60 secs")
+ if is_current_network_5g(ad, nr_type = 'mmwave', timeout=60):
+ ad.log.info("Success! attached on 5G NSA MMW")
+ else:
+ ad.log.error("Failure - expected NR_NSA MMW, current %s",
+ get_current_override_network_type(ad))
+ # Can't attach 5G NSA MMW, exit test!
+ return False
+ for iteration in range(3):
+ connectivity = False
+ browsing = False
+ ad.log.info("Attempt %d", iteration + 1)
+ if not verify_internet_connection(self.log, ad):
+ ad.log.error("Failed to connect to internet!")
+ else:
+ ad.log.info("Connect to internet successfully!")
+ connectivity = True
+ if not browsing_test(ad.log, ad):
+ ad.log.error("Failed to browse websites!")
+ else:
+ ad.log.info("Successful to browse websites!")
+ browsing = True
+ if connectivity and browsing:
+ return True
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ ad.log.error("5G NSA MMW Connectivity and Data Browsing test FAIL for all 3 iterations")
+ return False
+
+
+ @test_tracker_info(uuid="f1638e11-c686-4431-8b6c-4dc7cbff6406")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_data_stall_recovery(self):
+ """ Verifies 5G NSA MMW data stall
+
+ Set Mode to 5G NSA MMW
+ Wait for 5G attached on NSA MMW
+ Browse websites for success
+ Trigger data stall and verify browsing fails
+ Resume data and verify browsing success
+
+ Returns:
+ True if pass; False if fail.
+ """
+ ad = self.android_devices[0]
+ result = True
+ wifi_toggle_state(ad.log, ad, False)
+ toggle_airplane_mode(ad.log, ad, False)
+
+ if not provision_device_for_5g(ad.log, ad, nr_type='mmwave'):
+ return False
+
+ cmd = ('ss -l -p -n | grep "tcp.*droid_script" | tr -s " " '
+ '| cut -d " " -f 5 | sed s/.*://g')
+ sl4a_port = ad.adb.shell(cmd)
+
+ if not test_data_browsing_success_using_sl4a(ad.log, ad):
+ ad.log.error("Browsing failed before the test, aborting!")
+ return False
+
+ begin_time = get_device_epoch_time(ad)
+ break_internet_except_sl4a_port(ad, sl4a_port)
+
+ if not test_data_browsing_failure_using_sl4a(ad.log, ad):
+ ad.log.error("Browsing after breaking the internet, aborting!")
+ result = False
+
+ if not check_data_stall_detection(ad):
+ ad.log.warning("NetworkMonitor unable to detect Data Stall")
+
+ if not check_network_validation_fail(ad, begin_time):
+ ad.log.warning("Unable to detect NW validation fail")
+
+ if not check_data_stall_recovery(ad, begin_time):
+ ad.log.error("Recovery was not triggered")
+ result = False
+
+ resume_internet_with_sl4a_port(ad, sl4a_port)
+ time.sleep(MAX_WAIT_TIME_USER_PLANE_DATA)
+ if not test_data_browsing_success_using_sl4a(ad.log, ad):
+ ad.log.error("Browsing failed after resuming internet")
+ result = False
+ if result:
+ ad.log.info("PASS - data stall over 5G NSA MMW")
+ else:
+ ad.log.error("FAIL - data stall over 5G NSA MMW")
+ return result
+
+
+ @test_tracker_info(uuid="38fd987d-2a9a-44d5-bea4-e524359390c6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_metered_cellular(self):
+ """ Verifies 5G NSA MMW Meteredness API
+
+ Set Mode to 5G NSA MMW
+ Wait for 5G attached on NSA NSA MMW
+ Register for Connectivity callback
+ Verify value of metered flag
+
+ Returns:
+ True if pass; False if fail.
+ """
+ ad = self.android_devices[0]
+ try:
+ wifi_toggle_state(ad.log, ad, False)
+ toggle_airplane_mode(ad.log, ad, False)
+ if not provision_device_for_5g(ad.log, ad, nr_type='mmwave'):
+ return False
+
+ return verify_for_network_callback(ad.log, ad,
+ NetworkCallbackCapabilitiesChanged, apm_mode=False)
+ except Exception as e:
+ ad.log.error(e)
+ return False
+
+
+ @test_tracker_info(uuid="8d4ce840-6261-4395-bf7b-e1f6cdf4d9a9")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_metered_wifi(self):
+ """ Verifies 5G NSA MMW Meteredness API
+
+ Set Mode to 5G NSA MMW, Wifi Connected
+ Register for Connectivity callback
+ Verify value of metered flag
+
+ Returns:
+ True if pass; False if fail.
+ """
+ ad = self.android_devices[0]
+ try:
+ toggle_airplane_mode(ad.log, ad, False)
+ if not provision_device_for_5g(ad.log, ad, nr_type='mmwave'):
+ return False
+ wifi_toggle_state(ad.log, ad, True)
+ if not ensure_wifi_connected(ad.log, ad,
+ self.wifi_network_ssid,
+ self.wifi_network_pass):
+ ad.log.error("WiFi connect fail.")
+ return False
+ return verify_for_network_callback(ad.log, ad,
+ NetworkCallbackCapabilitiesChanged)
+ except Exception as e:
+ ad.log.error(e)
+ return False
+ finally:
+ wifi_toggle_state(ad.log, ad, False)
+
+
+ @test_tracker_info(uuid="1661cd40-0eed-43f0-bd2a-8e02392af3b1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_switching(self):
+ """Test data connection network switching when phone camped on 5G NSA MMW.
+
+ Ensure phone is camped on 5G NSA MMW
+ Ensure WiFi can connect to live network,
+ Airplane mode is off, data connection is on, WiFi is on.
+ Turn off WiFi, verify data is on cell and browse to google.com is OK.
+ Turn on WiFi, verify data is on WiFi and browse to google.com is OK.
+ Turn off WiFi, verify data is on cell and browse to google.com is OK.
+
+ Returns:
+ True if pass.
+ """
+ ad = self.android_devices[0]
+ return wifi_cell_switching(ad.log, ad, GEN_5G, self.wifi_network_ssid,
+ self.wifi_network_pass, nr_type='mmwave')
+
+
+ @test_tracker_info(uuid="8033a359-1b92-45ff-b766-bb0010132eb7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_data_connectivity(self):
+ """Test data connection in 5g NSA MMW.
+
+ Turn off airplane mode, disable WiFi, enable Cellular Data.
+ Ensure phone data generation is 5g NSA MMW.
+ Verify Internet.
+ Disable Cellular Data, verify Internet is inaccessible.
+ Enable Cellular Data, verify Internet.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ ad = self.android_devices[0]
+ wifi_reset(ad.log, ad)
+ wifi_toggle_state(ad.log, ad, False)
+ return data_connectivity_single_bearer(ad.log, ad, GEN_5G, nr_type='mmwave')
+
+
+ @test_tracker_info(uuid="633526fa-9e58-47a4-8957-bb0a95eef4ab")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_not_associated(self):
+ """Test data connection in 5g NSA MMW.
+
+ Turn off airplane mode, enable WiFi (but not connected), enable Cellular Data.
+ Ensure phone data generation is 5g MMW.
+ Verify Internet.
+ Disable Cellular Data, verify Internet is inaccessible.
+ Enable Cellular Data, verify Internet.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ ad = self.android_devices[0]
+ wifi_reset(ad.log, ad)
+ wifi_toggle_state(ad.log, ad, False)
+ wifi_toggle_state(ad.log, ad, True)
+ return data_connectivity_single_bearer(ad.log, ad, GEN_5G, nr_type='mmwave')
+
+
+ @test_tracker_info(uuid="c56324a2-5eda-4027-9068-7e120d2b178e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_connect_disconnect(self):
+ """Perform multiple connects and disconnects from WiFi and verify that
+ data switches between WiFi and Cell.
+
+ Steps:
+ 1. DUT Cellular Data is on 5G NSA MMW. Reset Wifi on DUT
+ 2. Connect DUT to a WiFi AP
+ 3. Repeat steps 1-2, alternately disconnecting and disabling wifi
+
+ Expected Results:
+ 1. Verify Data on Cell
+ 2. Verify Data on Wifi
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not provision_device_for_5g(self.log, self.provider, nr_type='mmwave'):
+ return False
+
+ return test_wifi_connect_disconnect(self.log, self.provider, self.wifi_network_ssid, self.wifi_network_pass)
+
+
+ @test_tracker_info(uuid="88cd3f68-08c3-4635-94ce-a1dffc3ffbf2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_airplane_mode(self):
+ """Test airplane mode basic on Phone and Live SIM on 5G NSA MMW.
+
+ Ensure phone is on 5G NSA MMW.
+ Ensure phone attach, data on, WiFi off and verify Internet.
+ Turn on airplane mode to make sure detach.
+ Turn off airplane mode to make sure attach.
+ Verify Internet connection.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ if not provision_device_for_5g(self.log, self.android_devices[0], nr_type='mmwave'):
+ return False
+ return airplane_mode_test(self.log, self.android_devices[0])
+
+
+ @test_tracker_info(uuid="b99967b9-96da-4f1b-90cb-6dbd6578236b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_reboot(self):
+ """Test 5G NSA MMWAVE service availability after reboot.
+
+ Ensure phone is on 5G NSA MMWAVE.
+ Ensure phone attach, data on, WiFi off and verify Internet.
+ Reboot Device.
+ Verify Network Connection.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ if not provision_device_for_5g(self.log, self.android_devices[0], nr_type='mmwave'):
+ return False
+ if not verify_internet_connection(self.log, self.android_devices[0]):
+ return False
+ return reboot_test(self.log, self.android_devices[0])
+
+
+ """ Tests End """
diff --git a/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwMmsTest.py b/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwMmsTest.py
new file mode 100755
index 0000000..d865e8f
--- /dev/null
+++ b/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwMmsTest.py
@@ -0,0 +1,388 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2021 - 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 5G NSA MMWAVE MMS scenarios
+"""
+
+import time
+
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_message_utils import message_test
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_test_utils import set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+
+
+class Nsa5gMmwMmsTest(TelephonyBaseTest):
+ def setup_class(self):
+ super().setup_class()
+ for ad in self.android_devices:
+ set_phone_silent_mode(self.log, ad, True)
+
+ def setup_test(self):
+ TelephonyBaseTest.setup_test(self)
+
+ def teardown_test(self):
+ ensure_phones_idle(self.log, self.android_devices)
+
+
+ """ Tests Begin """
+
+
+ @test_tracker_info(uuid="c6f7483f-6007-4a3b-a02d-5e6ab2b9a742")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_mo_mt(self):
+ """Test MMS between two phones in 5g NSA MMW
+
+ Provision devices in 5g NSA MMW
+ Send and Verify MMS from PhoneA to PhoneB
+ Verify both devices are still on 5g NSA MMW
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmwave',
+ mt_rat='5g_nsa_mmwave',
+ msg_type='mms')
+
+
+ @test_tracker_info(uuid="8e6ed681-d5b8-4503-8262-a16739c66bdb")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_mo_general(self):
+ """Test MO MMS for 1 phone in 5g NSA MMW. The other phone in any network
+
+ Provision PhoneA in 5g NSA MMW
+ Send and Verify MMS from PhoneA to PhoneB
+ Verify phoneA is still on 5g NSA MMW
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmwave',
+ mt_rat='default',
+ msg_type='mms')
+
+
+ @test_tracker_info(uuid="d22ea7fd-6c07-4eb2-a1bf-10b03cab3201")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_mt_general(self):
+ """Test MT MMS for 1 phone in 5g NSA MMW. The other phone in any network
+
+ Provision PhoneA in 5g NSA MMW
+ Send and Verify MMS from PhoneB to PhoneA
+ Verify phoneA is still on 5g NSA MMW
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_nsa_mmwave',
+ msg_type='mms')
+
+
+ @test_tracker_info(uuid="897eb961-236d-4b8f-8a84-42f2010c6621")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_mo_volte(self):
+ """Test MO MMS for 1 phone with VoLTE on 5G NSA MMW
+
+ Provision PhoneA on VoLTE
+ Provision PhoneA in 5g NSA MMW
+ Send and Verify MMS from PhoneA to PhoneB
+ Verify PhoneA is still on 5g NSA MMW
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmw_volte',
+ mt_rat='default',
+ msg_type='mms')
+
+
+ @test_tracker_info(uuid="6e185efe-b876-4dcf-9fc2-915039826dbe")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_mt_volte(self):
+ """Test MT MMS for 1 phone with VoLTE on 5G NSA MMW
+
+ Provision PhoneA on VoLTE
+ Provision PhoneA in 5g NSA MMW
+ Send and Verify MMS from PhoneB to PhoneA
+ Verify PhoneA is still on 5g NSA MMW
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_nsa_mmw_volte',
+ msg_type='mms')
+
+
+ @test_tracker_info(uuid="900d9913-b35d-4d75-859b-12bb28a35b73")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_mo_iwlan(self):
+ """ Test MO MMS text function for 1 phone in APM,
+ WiFi connected, WFC Cell Preferred mode.
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA MMW
+ Provision PhoneA for WFC Cell Pref with APM ON
+ Send and Verify MMS from PhoneA to PhoneB
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmw_wfc',
+ mt_rat='default',
+ msg_type='mms',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+
+ @test_tracker_info(uuid="939a1ec5-1004-4527-b11e-eacbcfe0f632")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_mt_iwlan(self):
+ """ Test MT MMS text function for 1 phone in APM,
+ WiFi connected, WFC Cell Preferred mode.
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA MMW
+ Provision PhoneA for WFC Cell Pref with APM ON
+ Send and Verify MMS from PhoneB to PhoneA
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_nsa_mmw_wfc',
+ msg_type='mms',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+
+ @test_tracker_info(uuid="253e4966-dd1c-487b-87fc-85b675140b24")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_mo_iwlan_apm_off(self):
+ """ Test MO MMS, Phone in APM off, WiFi connected, WFC WiFi Pref Mode
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA MMW
+ Provision PhoneA for WFC Wifi Pref with APM OFF
+ Send and Verify MMS from PhoneA to PhoneB
+ Verify 5g NSA MMW attach for PhoneA
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmw_wfc',
+ mt_rat='default',
+ msg_type='mms',
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+
+ @test_tracker_info(uuid="884435c5-47d8-4db9-b89e-087fc344a8b9")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_mt_iwlan_apm_off(self):
+ """ Test MT MMS, Phone in APM off, WiFi connected, WFC WiFi Pref Mode
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA MMW
+ Provision PhoneA for WFC Wifi Pref with APM OFF
+ Send and Verify MMS from PhoneB to PhoneA
+ Verify 5g NSA MMW attach for PhoneA
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_nsa_mmw_wfc',
+ msg_type='mms',
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+
+ @test_tracker_info(uuid="d0085f8f-bb18-4801-8bba-c5d2466922f2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_long_message_mo_mt(self):
+ """Test MMS basic function between two phone. Phones in 5G NSA MMW network.
+
+ Airplane mode is off. Phone in 5G NSA MMW.
+ Send MMS from PhoneA to PhoneB.
+ Verify received message on PhoneB is correct.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmwave',
+ mt_rat='5g_nsa_mmwave',
+ msg_type='mms',
+ long_msg=True)
+
+
+ @test_tracker_info(uuid="f43760c6-b040-46ba-9613-fde4192bf2db")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_long_message_mo(self):
+ """Test MO long MMS basic function for 1 phone in 5G NSA MMW network.
+
+ Airplane mode is off. PhoneA in 5G NSA MMW.
+ Send long MMS from PhoneA to PhoneB.
+ Verify received message on PhoneB is correct.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmwave',
+ mt_rat='default',
+ msg_type='mms',
+ long_msg=True)
+
+
+ @test_tracker_info(uuid="dc17e5d2-e022-47af-9b21-cf4e11911e17")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_long_message_mt(self):
+ """Test MT long MMS basic function for 1 phone in 5G NSA MMW network.
+
+ Airplane mode is off. PhoneA in nsa 5G NSA MMW.
+ Send long MMS from PhoneB to PhoneA.
+ Verify received message on PhoneA is correct.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_nsa_mmwave',
+ msg_type='mms',
+ long_msg=True)
+
+
+ @test_tracker_info(uuid="2a73b511-988c-4a49-857c-5692f6d6cdd6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_mo_wifi(self):
+ """Test MMS basic function between two phone. Phones in nsa 5g network.
+
+ Airplane mode is off. Phone in 5G NSA MMW.
+ Connect to Wifi.
+ Send MMS from PhoneA to PhoneB.
+ Verify received message on PhoneB is correct.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmwave',
+ mt_rat='general',
+ msg_type='mms',
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+
+ @test_tracker_info(uuid="58414ce6-851a-4527-8243-502f5a8cfa7a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_mms_mt_wifi(self):
+ """Test MMS basic function between two phone. Phones in nsa 5g network.
+
+ Airplane mode is off. Phone in 5G NSA MMW.
+ Connect to Wifi.
+ Send MMS from PhoneB to PhoneA.
+ Verify received message on PhoneA is correct.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='5g_nsa_mmwave',
+ msg_type='mms',
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+ """ Tests End """
diff --git a/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwSmsTest.py b/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwSmsTest.py
new file mode 100755
index 0000000..aeaac3b
--- /dev/null
+++ b/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwSmsTest.py
@@ -0,0 +1,351 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2021 - 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 5G NSA MMWAVE SMS scenarios
+"""
+
+import time
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_message_utils import message_test
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_test_utils import set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+
+
+class Nsa5gMmwSmsTest(TelephonyBaseTest):
+ def setup_class(self):
+ super().setup_class()
+ for ad in self.android_devices:
+ set_phone_silent_mode(self.log, ad, True)
+
+ def setup_test(self):
+ TelephonyBaseTest.setup_test(self)
+
+ def teardown_test(self):
+ ensure_phones_idle(self.log, self.android_devices)
+
+
+ """ Tests Begin """
+
+
+ @test_tracker_info(uuid="fb333cd5-2eaa-4d63-be26-fdf1e67d01b0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_mo_mt(self):
+ """Test SMS between two phones in 5g NSA MMW
+
+ Provision devices in 5g NSA MMW
+ Send and Verify SMS from PhoneA to PhoneB
+ Verify both devices are still on 5g NSA MMW
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmwave',
+ mt_rat='5g_nsa_mmwave')
+
+
+ @test_tracker_info(uuid="3afc92e8-69f7-4ead-a416-4df9753da27a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_mo_general(self):
+ """Test MO SMS for 1 phone in 5g NSA MMW. The other phone in any network
+
+ Provision PhoneA in 5g NSA MMW
+ Send and Verify SMS from PhoneA to PhoneB
+ Verify phoneA is still on 5g NSA MMW
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmwave',
+ mt_rat='default')
+
+
+ @test_tracker_info(uuid="ee57da72-8e30-42ad-a7b3-d05bb4762724")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_mt_general(self):
+ """Test MT SMS for 1 phone in 5g NSA MMW. The other phone in any network
+
+ Provision PhoneB in 5g NSA MMW
+ Send and Verify SMS from PhoneB to PhoneA
+ Verify phoneA is still on 5g NSA MMW
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_nsa_mmwave')
+
+
+ @test_tracker_info(uuid="1f75e117-f0f5-45fe-8896-91e0d2e61e9c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_mo_mt_volte(self):
+ """Test SMS between two phones with VoLTE on 5g NSA MMW
+
+ Provision devices on VoLTE
+ Provision devices in 5g NSA MMW
+ Send and Verify SMS from PhoneA to PhoneB
+ Verify both devices are still on 5g NSA MMW
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmw_volte',
+ mt_rat='5g_nsa_mmw_volte')
+
+
+ @test_tracker_info(uuid="f58fe4ed-77e0-40ff-8599-27d95cb27e14")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_mo_volte(self):
+ """Test MO SMS with VoLTE on 5g NSA MMW. The other phone in any network
+
+ Provision PhoneA on VoLTE
+ Provision PhoneA in 5g NSA MMW
+ Send and Verify SMS from PhoneA to PhoneB
+ Verify PhoneA is still on 5g NSA MMW
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmw_volte',
+ mt_rat='default')
+
+
+ @test_tracker_info(uuid="f60ac2b0-0feb-441e-9048-fe1b2878f8b6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_mt_volte(self):
+ """Test MT SMS with VoLTE on 5g NSA MMW. The other phone in any network
+
+ Provision PhoneA on VoLTE
+ Provision PhoneA in 5g NSA MMW
+ Send and Verify SMS from PhoneB to PhoneA
+ Verify phoneA is still on 5g NSA MMW
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_nsa_mmw_volte')
+
+
+ @test_tracker_info(uuid="6b27d804-abcd-4558-894d-545428a5dff4")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_mo_iwlan(self):
+ """ Test MO SMS for 1 phone in APM,
+ WiFi connected, WFC Cell Preferred mode.
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA MMW
+ Provision PhoneA for WFC Cell Pref with APM ON
+ Send and Verify SMS from PhoneA to PhoneB
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmw_wfc',
+ mt_rat='general',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+
+ @test_tracker_info(uuid="0b848508-a1e8-4652-9e13-74749a7ccd2e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_mt_iwlan(self):
+ """ Test MT SMS for 1 phone in APM,
+ WiFi connected, WFC Cell Preferred mode.
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA MMW
+ Provision PhoneA for WFC Cell Pref with APM ON
+ Send and Verify SMS from PhoneB to PhoneA
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='5g_nsa_mmw_wfc',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+
+ @test_tracker_info(uuid="9fc07594-6dbf-4b7a-b5a5-f4c06032fa35")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_mo_iwlan_apm_off(self):
+ """ Test MO SMS for 1 Phone in APM off, WiFi connected,
+ WFC WiFi Preferred mode.
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA MMW
+ Provision PhoneA for WFC Wifi Pref with APM OFF
+ Send and Verify SMS from PhoneA to PhoneB
+ Verify 5g NSA MMW attach for PhoneA
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmw_wfc',
+ mt_rat='general',
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+
+ @test_tracker_info(uuid="b76c0eaf-6e6b-4da7-87a0-26895f93a554")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_mt_iwlan_apm_off(self):
+ """ Test MT SMS for 1 Phone in APM off, WiFi connected,
+ WFC WiFi Preferred mode.
+
+ Disable APM on both devices
+ Provision PhoneA in 5g NSA MMW
+ Provision PhoneA for WFC Wifi Pref with APM OFF
+ Send and Verify SMS from PhoneB to PhoneA
+ Verify 5g NSA MMW attach for PhoneA
+
+ Returns:
+ True if pass; False if fail.
+ """
+ apm_mode = [toggle_airplane_mode(self.log, ad, False) for ad in self.android_devices]
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='5g_nsa_mmw_wfc',
+ wfc_mode=WFC_MODE_WIFI_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
+
+
+ @test_tracker_info(uuid="43694343-e6f0-4430-972f-53f61c7b51b0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_long_message_mo_mt(self):
+ """Test SMS basic function between two phone. Phones in 5G NSA MMW network.
+
+ Airplane mode is off.
+ Send SMS from PhoneA to PhoneB.
+ Verify received message on PhoneB is correct.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmwave',
+ mt_rat='5g_nsa_mmwave',
+ long_msg=True)
+
+
+ @test_tracker_info(uuid="846dcf2d-911f-46a0-adb1-e32667b8ebd3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_long_message_mo(self):
+ """Test MO long SMS function for 1 phone in 5G NSA MMW network.
+
+ Disable APM on PhoneA
+ Provision PhoneA in 5g NSA MMW
+ Send SMS from PhoneA to PhoneB
+ Verify received message on PhoneB is correct
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='5g_nsa_mmwave',
+ mt_rat='default',
+ long_msg=True)
+
+
+ @test_tracker_info(uuid="4d2951c3-d80c-4860-8dd9-9709cb7dfaa8")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_sms_long_message_mt(self):
+ """Test MT long SMS function for 1 phone in 5G NSA MMW network.
+
+ Disable APM on PhoneA
+ Provision PhoneA in 5g NSA MMW
+ Send SMS from PhoneB to PhoneA
+ Verify received message on PhoneA is correct
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='5g_nsa_mmwave',
+ long_msg=True)
+
+ """ Tests End """
diff --git a/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwTetheringTest.py b/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwTetheringTest.py
new file mode 100755
index 0000000..4f94bb1
--- /dev/null
+++ b/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwTetheringTest.py
@@ -0,0 +1,657 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2021 - 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 5G NSA MMWAVE Tethering scenarios
+"""
+
+import time
+
+from acts.utils import rand_ascii_str
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
+from acts_contrib.test_utils.tel.tel_defines import RAT_3G
+from acts_contrib.test_utils.tel.tel_defines import RAT_4G
+from acts_contrib.test_utils.tel.tel_defines import RAT_5G
+from acts_contrib.test_utils.tel.tel_defines import TETHERING_PASSWORD_HAS_ESCAPE
+from acts_contrib.test_utils.tel.tel_defines import TETHERING_SPECIAL_SSID_LIST
+from acts_contrib.test_utils.tel.tel_defines import TETHERING_SPECIAL_PASSWORD_LIST
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_tethering
+from acts_contrib.test_utils.tel.tel_data_utils import test_setup_tethering
+from acts_contrib.test_utils.tel.tel_data_utils import test_start_wifi_tethering_connect_teardown
+from acts_contrib.test_utils.tel.tel_data_utils import tethering_check_internet_connection
+from acts_contrib.test_utils.tel.tel_data_utils import verify_toggle_apm_tethering_internet_connection
+from acts_contrib.test_utils.tel.tel_data_utils import verify_tethering_entitlement_check
+from acts_contrib.test_utils.tel.tel_data_utils import wifi_tethering_cleanup
+from acts_contrib.test_utils.tel.tel_data_utils import wifi_tethering_setup_teardown
+from acts_contrib.test_utils.tel.tel_data_utils import wait_and_verify_device_internet_connection
+from acts_contrib.test_utils.tel.tel_data_utils import setup_device_internet_connection
+from acts_contrib.test_utils.tel.tel_data_utils import verify_toggle_data_during_wifi_tethering
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_test_utils import set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_reset
+
+
+class Nsa5gMmwTetheringTest(TelephonyBaseTest):
+ def setup_class(self):
+ super().setup_class()
+ self.stress_test_number = self.get_stress_test_number()
+ self.provider = self.android_devices[0]
+ self.clients = self.android_devices[1:]
+ for ad in self.android_devices:
+ set_phone_silent_mode(self.log, ad, True)
+
+ def setup_test(self):
+ TelephonyBaseTest.setup_test(self)
+ self.number_of_devices = 1
+
+ def teardown_class(self):
+ TelephonyBaseTest.teardown_class(self)
+
+
+ """ Tests Begin """
+
+
+ @test_tracker_info(uuid="ae6c4a14-0474-448c-ad18-dcedfee7fa5a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_to_5gwifi(self):
+ """WiFi Tethering test: 5G NSA MMW to WiFI 5G Tethering
+
+ 1. DUT in 5G NSA MMW mode, attached.
+ 2. DUT start 5G WiFi Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return test_wifi_tethering(self.log,
+ self.provider,
+ self.clients,
+ self.clients,
+ RAT_5G,
+ WIFI_CONFIG_APBAND_5G,
+ check_interval=10,
+ check_iteration=10,
+ nr_type= 'mmwave')
+
+
+ @test_tracker_info(uuid="bf6ed593-4fe3-417c-9d04-ad71a8d3095e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_to_2gwifi(self):
+ """WiFi Tethering test: 5G NSA MMW to WiFI 2G Tethering
+
+ 1. DUT in 5G NSA MMW mode, attached.
+ 2. DUT start 2.4G WiFi Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return test_wifi_tethering(self.log,
+ self.provider,
+ self.clients,
+ self.clients,
+ RAT_5G,
+ WIFI_CONFIG_APBAND_2G,
+ check_interval=10,
+ check_iteration=10,
+ nr_type= 'mmwave')
+
+
+ @test_tracker_info(uuid="96c4bc30-6dd1-4f14-bdbd-bf40b8b24701")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_toggle_apm(self):
+ """WiFi Tethering test: Toggle APM during active WiFi 2.4G Tethering from 5G NSA MMW
+
+ 1. DUT in 5G NSA MMW mode, idle.
+ 2. DUT start 2.4G WiFi Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. DUT toggle APM on, verify WiFi tethering stopped, PhoneB lost WiFi connection.
+ 6. DUT toggle APM off, verify PhoneA have cellular data and Internet connection.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ try:
+ ssid = rand_ascii_str(10)
+ if not test_wifi_tethering(self.log,
+ self.provider,
+ self.clients,
+ [self.clients[0]],
+ RAT_5G,
+ WIFI_CONFIG_APBAND_2G,
+ check_interval=10,
+ check_iteration=2,
+ do_cleanup=False,
+ ssid=ssid,
+ nr_type= 'mmwave'):
+ self.log.error("WiFi Tethering failed.")
+ return False
+
+ if not verify_toggle_apm_tethering_internet_connection(self.log,
+ self.provider,
+ self.clients,
+ ssid):
+ return False
+ finally:
+ self.clients[0].droid.telephonyToggleDataConnection(True)
+ wifi_reset(self.log, self.clients[0])
+ return True
+
+
+ @test_tracker_info(uuid="e4f7deaa-a2be-4543-9364-17d704b2bf44")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_toggle_data(self):
+ """WiFi Tethering test: Toggle Data during active WiFi Tethering from 5G NSA MMW
+
+ 1. DUT is on 5G NSA MMW, DUT data connection is on and idle.
+ 2. DUT start 2.4G WiFi Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Disable Data on DUT, verify PhoneB still connected to WiFi, but no Internet access.
+ 6. Enable Data on DUT, verify PhoneB still connected to WiFi and have Internet access.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not verify_toggle_data_during_wifi_tethering(self.log,
+ self.provider,
+ self.clients,
+ new_gen=RAT_5G,
+ nr_type= 'mmwave'):
+ return False
+ return True
+
+
+ @test_tracker_info(uuid="e6c30776-c245-42aa-a211-77dbd76c5217")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_entitlement_check(self):
+ """5G NSA MMW Tethering Entitlement Check Test
+
+ Get tethering entitlement check result.
+
+ Returns:
+ True if entitlement check returns True.
+ """
+
+ if not provision_device_for_5g(self.log, self.provider, nr_type= 'mmwave'):
+ return False
+ return verify_tethering_entitlement_check(self.log,
+ self.provider)
+
+
+ @test_tracker_info(uuid="a73ca034-c90c-4579-96dd-9518d74c2a6c")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_ssid_quotes(self):
+ """WiFi Tethering test: 5G NSA MMW wifi tethering SSID name have quotes.
+ 1. Set SSID name have double quotes.
+ 2. Start LTE to WiFi (2.4G) tethering.
+ 3. Verify tethering.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ ssid = "\"" + rand_ascii_str(10) + "\""
+ self.log.info(
+ "Starting WiFi Tethering test with ssid: {}".format(ssid))
+
+ return test_wifi_tethering(self.log,
+ self.provider,
+ self.clients,
+ self.clients,
+ RAT_5G,
+ WIFI_CONFIG_APBAND_2G,
+ check_interval=10,
+ check_iteration=10,
+ ssid=ssid,
+ nr_type= 'mmwave')
+
+
+ @test_tracker_info(uuid="6702831b-f656-4410-a922-d47fae138d68")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_password_escaping_characters(self):
+ """WiFi Tethering test: 5G NSA MMW wifi tethering password have escaping characters.
+ 1. Set password have escaping characters.
+ e.g.: '"DQ=/{Yqq;M=(^_3HzRvhOiL8S%`]w&l<Qp8qH)bs<4E9v_q=HLr^)}w$blA0Kg'
+ 2. Start LTE to WiFi (2.4G) tethering.
+ 3. Verify tethering.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+
+ password = TETHERING_PASSWORD_HAS_ESCAPE
+ self.log.info(
+ "Starting WiFi Tethering test with password: {}".format(password))
+
+ return test_wifi_tethering(self.log,
+ self.provider,
+ self.clients,
+ self.clients,
+ RAT_5G,
+ WIFI_CONFIG_APBAND_2G,
+ check_interval=10,
+ check_iteration=10,
+ password=password,
+ nr_type= 'mmwave')
+
+
+ @test_tracker_info(uuid="93cf9aa2-740f-42a4-92a8-c506ceb5d448")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_ssid(self):
+ """WiFi Tethering test: start 5G NSA MMW WiFi tethering with all kinds of SSIDs.
+
+ For each listed SSID, start WiFi tethering on DUT, client connect WiFi,
+ then tear down WiFi tethering.
+
+ Returns:
+ True if WiFi tethering succeed on all SSIDs.
+ False if failed.
+ """
+ if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G, nr_type= 'mmwave'):
+ self.log.error("Setup Failed.")
+ return False
+ ssid_list = TETHERING_SPECIAL_SSID_LIST
+ fail_list = {}
+ self.number_of_devices = 2
+ for ssid in ssid_list:
+ password = rand_ascii_str(8)
+ self.log.info("SSID: <{}>, Password: <{}>".format(ssid, password))
+ if not test_start_wifi_tethering_connect_teardown(self.log,
+ self.provider,
+ self.clients[0],
+ ssid,
+ password):
+ fail_list[ssid] = password
+
+ if len(fail_list) > 0:
+ self.log.error("Failed cases: {}".format(fail_list))
+ return False
+ else:
+ return True
+
+
+ @test_tracker_info(uuid="ed73ed58-781b-4fe4-991e-fa0cc2726b0d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_password(self):
+ """WiFi Tethering test: start 5G NSA MMW WiFi tethering with all kinds of passwords.
+
+ For each listed password, start WiFi tethering on DUT, client connect WiFi,
+ then tear down WiFi tethering.
+
+ Returns:
+ True if WiFi tethering succeed on all passwords.
+ False if failed.
+ """
+ if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G, nr_type= 'mmwave'):
+ self.log.error("Setup Failed.")
+ return False
+ password_list = TETHERING_SPECIAL_PASSWORD_LIST
+ fail_list = {}
+ self.number_of_devices = 2
+ for password in password_list:
+ ssid = rand_ascii_str(8)
+ self.log.info("SSID: <{}>, Password: <{}>".format(ssid, password))
+ if not test_start_wifi_tethering_connect_teardown(self.log,
+ self.provider,
+ self.clients[0],
+ ssid,
+ password):
+ fail_list[ssid] = password
+
+ if len(fail_list) > 0:
+ self.log.error("Failed cases: {}".format(fail_list))
+ return False
+ else:
+ return True
+
+
+ # Invalid Live Test. Can't rely on the result of this test with live network.
+ # Network may decide not to change the RAT when data connection is active.
+ @test_tracker_info(uuid="ac18159b-ebfb-42d1-b97b-ff25c5cb7b9e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_from_5g_nsa_mmw_to_3g(self):
+ """WiFi Tethering test: Change Cellular Data RAT generation from 5G NSA MMW to 3G,
+ during active WiFi Tethering.
+
+ 1. DUT in 5G NSA MMW mode, idle.
+ 2. DUT start 2.4G WiFi Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verily Internet access on DUT and PhoneB
+ 5. Change DUT Cellular Data RAT generation from 5G NSA MMW to 3G.
+ 6. Verify both DUT and PhoneB have Internet access.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G, nr_type= 'mmwave'):
+ self.log.error("Verify 5G Internet access failed.")
+ return False
+ try:
+ if not wifi_tethering_setup_teardown(
+ self.log,
+ self.provider, [self.clients[0]],
+ ap_band=WIFI_CONFIG_APBAND_2G,
+ check_interval=10,
+ check_iteration=2,
+ do_cleanup=False):
+ self.log.error("WiFi Tethering failed.")
+ return False
+
+ if not self.provider.droid.wifiIsApEnabled():
+ self.provider.log.error("Provider WiFi tethering stopped.")
+ return False
+
+ self.log.info("Provider change RAT from 5G NSA MMW to 3G.")
+ if not ensure_network_generation(
+ self.log,
+ self.provider,
+ RAT_3G,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ toggle_apm_after_setting=False):
+ self.provider.log.error("Provider failed to reselect to 3G.")
+ return False
+ time.sleep(WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING)
+ if not verify_internet_connection(self.log, self.provider):
+ self.provider.log.error("Data not available on Provider.")
+ return False
+ if not self.provider.droid.wifiIsApEnabled():
+ self.provider.log.error("Provider WiFi tethering stopped.")
+ return False
+ if not tethering_check_internet_connection(
+ self.log, self.provider, [self.clients[0]], 10, 5):
+ return False
+ finally:
+ if not wifi_tethering_cleanup(self.log, self.provider,
+ self.clients):
+ return False
+ return True
+
+
+ # Invalid Live Test. Can't rely on the result of this test with live network.
+ # Network may decide not to change the RAT when data connection is active.
+ @test_tracker_info(uuid="5a2dc4f4-f6ea-4162-b034-4919997161ac")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_from_3g_to_5g_nsa_mmw(self):
+ """WiFi Tethering test: Change Cellular Data RAT generation from 3G to 5G NSA MMW,
+ during active WiFi Tethering.
+
+ 1. DUT in 3G mode, idle.
+ 2. DUT start 2.4G WiFi Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verily Internet access on DUT and PhoneB
+ 5. Change DUT Cellular Data RAT generation from 3G to nsa5G.
+ 6. Verify both DUT and PhoneB have Internet access.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not test_setup_tethering(self.log, self.provider, self.clients, RAT_3G):
+ self.log.error("Verify 3G Internet access failed.")
+ return False
+ try:
+ if not wifi_tethering_setup_teardown(
+ self.log,
+ self.provider, [self.clients[0]],
+ ap_band=WIFI_CONFIG_APBAND_2G,
+ check_interval=10,
+ check_iteration=2,
+ do_cleanup=False):
+ self.log.error("WiFi Tethering failed.")
+ return False
+
+ if not self.provider.droid.wifiIsApEnabled():
+ self.log.error("Provider WiFi tethering stopped.")
+ return False
+
+ self.log.info("Provider change RAT from 3G to 5G NSA MMW.")
+ if not ensure_network_generation(
+ self.log,
+ self.provider,
+ RAT_5G,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ toggle_apm_after_setting=False,
+ nr_type= 'mmwave'):
+ self.log.error("Provider failed to reselect to 5G NSA MMW")
+ return False
+
+ time.sleep(WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING)
+ if not verify_internet_connection(self.log, self.provider):
+ self.provider.log.error("Data not available on Provider.")
+ return False
+ if not self.provider.droid.wifiIsApEnabled():
+ self.provider.log.error("Provider WiFi tethering stopped.")
+ return False
+ if not tethering_check_internet_connection(
+ self.log, self.provider, [self.clients[0]], 10, 5):
+ return False
+ finally:
+ if not wifi_tethering_cleanup(self.log, self.provider, [self.clients[0]]):
+ return False
+ return True
+
+
+ # Invalid Live Test. Can't rely on the result of this test with live network.
+ # Network may decide not to change the RAT when data connection is active.
+ @test_tracker_info(uuid="ac0a5f75-3f08-40fb-83ca-3312019680b9")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_from_5g_nsa_mmw_to_4g(self):
+ """WiFi Tethering test: Change Cellular Data RAT generation from 5G NSA MMW to 4G,
+ during active WiFi Tethering.
+
+ 1. DUT in 5G NSA MMW mode, idle.
+ 2. DUT start 2.4G WiFi Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verily Internet access on DUT and PhoneB
+ 5. Change DUT Cellular Data RAT generation from 5G NSA MMW to LTE.
+ 6. Verify both DUT and PhoneB have Internet access.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not test_setup_tethering(self.log, self.provider, self.clients, RAT_5G, nr_type= 'mmwave'):
+ self.log.error("Verify 5G Internet access failed.")
+ return False
+ try:
+ if not wifi_tethering_setup_teardown(
+ self.log,
+ self.provider, [self.clients[0]],
+ ap_band=WIFI_CONFIG_APBAND_2G,
+ check_interval=10,
+ check_iteration=2,
+ do_cleanup=False):
+ self.log.error("WiFi Tethering failed.")
+ return False
+
+ if not self.provider.droid.wifiIsApEnabled():
+ self.provider.log.error("Provider WiFi tethering stopped.")
+ return False
+
+ self.log.info("Provider change RAT from 5G to LTE.")
+ if not ensure_network_generation(
+ self.log,
+ self.provider,
+ RAT_4G,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ toggle_apm_after_setting=False):
+ self.provider.log.error("Provider failed to reselect to 4G.")
+ return False
+ time.sleep(WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING)
+ if not verify_internet_connection(self.log, self.provider):
+ self.provider.log.error("Data not available on Provider.")
+ return False
+ if not self.provider.droid.wifiIsApEnabled():
+ self.provider.log.error("Provider WiFi tethering stopped.")
+ return False
+ if not tethering_check_internet_connection(
+ self.log, self.provider, [self.clients[0]], 10, 5):
+ return False
+ finally:
+ if not wifi_tethering_cleanup(self.log, self.provider,
+ self.clients):
+ return False
+ return True
+
+
+ # Invalid Live Test. Can't rely on the result of this test with live network.
+ # Network may decide not to change the RAT when data connection is active.
+ @test_tracker_info(uuid="9335bfdc-d0df-4c5e-99fd-6492a2ce2947")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_from_4g_to_5g_nsa_mmw(self):
+ """WiFi Tethering test: Change Cellular Data RAT generation from 4G to 5G NSA MMW,
+ during active WiFi Tethering.
+
+ 1. DUT in 4G mode, idle.
+ 2. DUT start 2.4G WiFi Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verily Internet access on DUT and PhoneB
+ 5. Change DUT Cellular Data RAT generation from 4G to 5G NSA MMW.
+ 6. Verify both DUT and PhoneB have Internet access.
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ if not test_setup_tethering(self.log, self.provider, self.clients, RAT_4G):
+ self.log.error("Verify 4G Internet access failed.")
+ return False
+ try:
+ if not wifi_tethering_setup_teardown(
+ self.log,
+ self.provider, [self.clients[0]],
+ ap_band=WIFI_CONFIG_APBAND_2G,
+ check_interval=10,
+ check_iteration=2,
+ do_cleanup=False):
+ self.log.error("WiFi Tethering failed.")
+ return False
+
+ if not self.provider.droid.wifiIsApEnabled():
+ self.log.error("Provider WiFi tethering stopped.")
+ return False
+
+ self.log.info("Provider change RAT from 4G to 5G.")
+ if not ensure_network_generation(
+ self.log,
+ self.provider,
+ RAT_5G,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ toggle_apm_after_setting=False,
+ nr_type= 'mmwave'):
+ self.log.error("Provider failed to reselect to 5G NSA MMW")
+ return False
+
+ time.sleep(WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING)
+ if not verify_internet_connection(self.log, self.provider):
+ self.provider.log.error("Data not available on Provider.")
+ return False
+ if not self.provider.droid.wifiIsApEnabled():
+ self.provider.log.error("Provider WiFi tethering stopped.")
+ return False
+ if not tethering_check_internet_connection(
+ self.log, self.provider, [self.clients[0]], 10, 5):
+ return False
+ finally:
+ if not wifi_tethering_cleanup(self.log, self.provider, [self.clients[0]]):
+ return False
+ return True
+
+
+ @test_tracker_info(uuid="7956472e-962c-4bbe-a08d-37901935c9ac")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_no_password(self):
+ """WiFi Tethering test: Start 5G NSA MMW WiFi tethering with no password
+
+ 1. DUT is idle.
+ 2. DUT start 2.4G WiFi Tethering, with no WiFi password.
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return test_wifi_tethering(self.log,
+ self.provider,
+ self.clients,
+ [self.clients[0]],
+ RAT_5G,
+ WIFI_CONFIG_APBAND_2G,
+ check_interval=10,
+ check_iteration=10,
+ password="",
+ nr_type= 'mmwave')
+
+
+ @test_tracker_info(uuid="39e73f91-79c7-4cc0-9fa0-a737f88889e8")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_nsa_mmw_wifi_tethering_disable_resume_wifi(self):
+ """WiFi Tethering test: WiFI connected to 2.4G network,
+ start (LTE) 2.4G WiFi tethering, then stop tethering over 5G NSA MMW
+
+ 1. DUT in data connected, idle. WiFi connected to 2.4G Network
+ 2. DUT start 2.4G WiFi Tethering
+ 3. PhoneB disable data, connect to DUT's softAP
+ 4. Verify Internet access on DUT and PhoneB
+ 5. Disable WiFi Tethering on DUT.
+ 6. Verify DUT automatically connect to previous WiFI network
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ # Ensure provider connecting to wifi network.
+ def setup_provider_internet_connection():
+ return setup_device_internet_connection(self.log,
+ self.provider,
+ self.wifi_network_ssid,
+ self.wifi_network_pass)
+
+ if not test_wifi_tethering(self.log,
+ self.provider,
+ self.clients,
+ [self.clients[0]],
+ RAT_5G,
+ WIFI_CONFIG_APBAND_2G,
+ check_interval=10,
+ check_iteration=2,
+ pre_teardown_func=setup_provider_internet_connection,
+ nr_type= 'mmwave'):
+ return False
+
+ if not wait_and_verify_device_internet_connection(self.log, self.provider):
+ return False
+ return True
+
+
+ """ Tests End """
diff --git a/acts_tests/tests/google/nr/sa5g/Sa5gDataTest.py b/acts_tests/tests/google/nr/sa5g/Sa5gDataTest.py
index 80fe585..9212968 100755
--- a/acts_tests/tests/google/nr/sa5g/Sa5gDataTest.py
+++ b/acts_tests/tests/google/nr/sa5g/Sa5gDataTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2021 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -25,10 +25,17 @@
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_USER_PLANE_DATA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_NR_ONLY
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
+from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_detection
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_recovery
+from acts_contrib.test_utils.tel.tel_data_utils import check_network_validation_fail
+from acts_contrib.test_utils.tel.tel_data_utils import data_connectivity_single_bearer
+from acts_contrib.test_utils.tel.tel_data_utils import reboot_test
+from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_connect_disconnect
+from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
from acts_contrib.test_utils.tel.tel_test_utils import break_internet_except_sl4a_port
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_detection
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_recovery
-from acts_contrib.test_utils.tel.tel_test_utils import check_network_validation_fail
from acts_contrib.test_utils.tel.tel_test_utils import get_current_override_network_type
from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
from acts_contrib.test_utils.tel.tel_test_utils import resume_internet_with_sl4a_port
@@ -37,14 +44,8 @@
from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_success_using_sl4a
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_reset
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
-from acts_contrib.test_utils.tel.tel_data_utils import data_connectivity_single_bearer
-from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_connect_disconnect
-from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_sa
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_reset
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
class Sa5gDataTest(TelephonyBaseTest):
@@ -83,7 +84,7 @@
return False
ad.log.info("Set network mode to SA successfully")
ad.log.info("Waiting for 5g SA attach for 60 secs")
- if is_current_network_5g_sa(ad):
+ if is_current_network_5g(ad, nr_type = 'sa'):
ad.log.info("Success! attached on 5g SA")
else:
ad.log.error("Failure - expected NR, current %s",
@@ -129,7 +130,7 @@
wifi_toggle_state(ad.log, ad, False)
toggle_airplane_mode(ad.log, ad, False)
- if not provision_device_for_5g(ad.log, ad, sa_5g=True):
+ if not provision_device_for_5g(ad.log, ad, nr_type= 'sa'):
return False
cmd = ('ss -l -p -n | grep "tcp.*droid_script" | tr -s " " '
@@ -188,7 +189,7 @@
True if success.
False if failed.
"""
- if not provision_device_for_5g(self.log, self.provider, sa_5g=True):
+ if not provision_device_for_5g(self.log, self.provider, nr_type= 'sa'):
return False
return test_wifi_connect_disconnect(self.log, self.provider, self.wifi_network_ssid, self.wifi_network_pass)
@@ -211,7 +212,7 @@
"""
ad = self.android_devices[0]
return wifi_cell_switching(ad.log, ad, GEN_5G, self.wifi_network_ssid,
- self.wifi_network_pass, sa_5g=True)
+ self.wifi_network_pass, nr_type= 'sa')
@test_tracker_info(uuid="8df1b65c-197e-40b3-83a4-6da1f0a51b97")
@@ -233,6 +234,26 @@
wifi_reset(ad.log, ad)
wifi_toggle_state(ad.log, ad, False)
wifi_toggle_state(ad.log, ad, True)
- return data_connectivity_single_bearer(ad.log, ad, GEN_5G, sa_5g=True)
+ return data_connectivity_single_bearer(ad.log, ad, GEN_5G, nr_type= 'sa')
+
+
+ @test_tracker_info(uuid="6c1ec0a6-223e-4bcd-b958-b85f5eb03943")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_5g_sa_reboot(self):
+ """Test 5G SA service availability after reboot.
+
+ Ensure phone is on 5G SA.
+ Ensure phone attach, data on, WiFi off and verify Internet.
+ Reboot Device.
+ Verify Network Connection.
+
+ Returns:
+ True if pass; False if fail.
+ """
+ if not provision_device_for_5g(self.log, self.android_devices[0], nr_type='sa'):
+ return False
+ if not verify_internet_connection(self.log, self.android_devices[0]):
+ return False
+ return reboot_test(self.log, self.android_devices[0])
""" Tests End """
diff --git a/acts_tests/tests/google/nr/sa5g/Sa5gMmsTest.py b/acts_tests/tests/google/nr/sa5g/Sa5gMmsTest.py
index 43d5028..b3be0b4 100755
--- a/acts_tests/tests/google/nr/sa5g/Sa5gMmsTest.py
+++ b/acts_tests/tests/google/nr/sa5g/Sa5gMmsTest.py
@@ -21,13 +21,13 @@
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.tel_5g_test_utils import disable_apm_mode_both_devices
from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
from acts_contrib.test_utils.tel.tel_5g_test_utils import verify_5g_attach_for_both_devices
from acts_contrib.test_utils.tel.tel_mms_utils import _mms_test_mo
from acts_contrib.test_utils.tel.tel_mms_utils import _long_mms_test_mo
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
class Sa5gMmsTest(TelephonyBaseTest):
@@ -59,13 +59,13 @@
False if failed.
"""
ads = self.android_devices
- if not provision_device_for_5g(self.log, ads, sa_5g=True):
+ if not provision_device_for_5g(self.log, ads, nr_type='sa'):
return False
if not _mms_test_mo(self.log, ads):
return False
- if not verify_5g_attach_for_both_devices(self.log, ads, True):
+ if not verify_5g_attach_for_both_devices(self.log, ads, nr_type='sa'):
return False
self.log.info("PASS - mms test over 5g sa validated")
@@ -91,7 +91,7 @@
if not disable_apm_mode_both_devices(self.log, ads):
return False
- if not provision_device_for_5g(self.log, ads, sa_5g=True):
+ if not provision_device_for_5g(self.log, ads, nr_type='sa'):
return False
return _long_mms_test_mo(self.log, ads)
@@ -117,7 +117,7 @@
if not disable_apm_mode_both_devices(self.log, ads):
return False
- if not provision_device_for_5g(self.log, ads, sa_5g=True):
+ if not provision_device_for_5g(self.log, ads, nr_type='sa'):
return False
ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
diff --git a/acts_tests/tests/google/nr/sa5g/Sa5gSmsTest.py b/acts_tests/tests/google/nr/sa5g/Sa5gSmsTest.py
index 011062f..fd84637 100755
--- a/acts_tests/tests/google/nr/sa5g/Sa5gSmsTest.py
+++ b/acts_tests/tests/google/nr/sa5g/Sa5gSmsTest.py
@@ -20,7 +20,7 @@
import time
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.tel_5g_test_utils import disable_apm_mode_both_devices
from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_both_devices_for_volte
@@ -57,13 +57,13 @@
False if failed.
"""
ads = self.android_devices
- if not provision_device_for_5g(self.log, ads, sa_5g=True):
+ if not provision_device_for_5g(self.log, ads, nr_type='sa'):
return False
if not _sms_test_mo(self.log, ads):
return False
- if not verify_5g_attach_for_both_devices(self.log, ads, True):
+ if not verify_5g_attach_for_both_devices(self.log, ads, nr_type='sa'):
return False
self.log.info("PASS - SMS test over 5G SA validated")
@@ -90,7 +90,7 @@
if not disable_apm_mode_both_devices(self.log, ads):
return False
- if not provision_device_for_5g(self.log, ads, sa_5g=True):
+ if not provision_device_for_5g(self.log, ads, nr_type='sa'):
return False
return _long_sms_test_mo(self.log, ads)
diff --git a/acts_tests/tests/google/power/bt/PowerBTa2dpTest.py b/acts_tests/tests/google/power/bt/PowerBTa2dpTest.py
index 2d0bc9d..419c418 100644
--- a/acts_tests/tests/google/power/bt/PowerBTa2dpTest.py
+++ b/acts_tests/tests/google/power/bt/PowerBTa2dpTest.py
@@ -19,9 +19,17 @@
import acts_contrib.test_utils.power.PowerBTBaseTest as PBtBT
from acts import asserts
from acts_contrib.test_utils.bt import BtEnum
+from acts.libs.proc import job
+DEFAULT_ADB_TIMEOUT = 60
EXTRA_PLAY_TIME = 10
-
+GET_PROPERTY_HARDWARE_PLATFORM = 'getprop ro.boot.hardware.platform'
+PL_MAP = {
+ '10': 'EPA_BF',
+ '9': 'EPA_DIV',
+ '8': 'IPA_BF',
+ '7': 'IPA_DIV',
+}
class PowerBTa2dpTest(PBtBT.PowerBTBaseTest):
def __init__(self, configs):
@@ -45,10 +53,32 @@
def test_case_fn():
self.measure_a2dp_power(codec_config, tpl)
- test_case_name = ('test_BTa2dp_{}_codec_at_PL{}'.format(
- codec_config['codec_type'], tpl))
+ power_level = 'PL{}'.format(tpl)
+
+ # If the device is P21 and later, generate tests with different name.
+ platform = self._get_hardware_platform_at_init_stage()
+ self.log.info('Hardware Platform is: {}'.format(platform))
+ if platform.startswith('gs'):
+ power_level = PL_MAP[str(tpl)]
+ self.log.info('The device is P21 or later, use name {}'.format(
+ power_level))
+
+ test_case_name = ('test_BTa2dp_{}_codec_at_{}'.format(
+ codec_config['codec_type'], power_level))
setattr(self, test_case_name, test_case_fn)
+ def _get_hardware_platform_at_init_stage(self):
+
+ # At __init__ stage the android devices are not registered. Thus, run
+ # adb command with device sn directly.
+ sn = self.controller_configs['AndroidDevice'][0]
+ cmd = 'adb -s {} shell {}'.format(sn, GET_PROPERTY_HARDWARE_PLATFORM)
+ result = job.run(cmd, ignore_status=True, timeout=DEFAULT_ADB_TIMEOUT)
+ ret, out, err = result.exit_status, result.stdout, result.stderr
+ self.log.info('get platform ret: {}, out: {}, err: {}'.format(
+ ret, out, err))
+ return out
+
def measure_a2dp_power(self, codec_config, tpl):
current_codec = self.dut.droid.bluetoothA2dpGetCurrentCodecConfig()
diff --git a/acts_tests/tests/google/power/bt/PowerBTcalibrationTest.py b/acts_tests/tests/google/power/bt/PowerBTcalibrationTest.py
index 13b3f39..c0bac23 100644
--- a/acts_tests/tests/google/power/bt/PowerBTcalibrationTest.py
+++ b/acts_tests/tests/google/power/bt/PowerBTcalibrationTest.py
@@ -21,6 +21,7 @@
import acts_contrib.test_utils.power.PowerBTBaseTest as PBtBT
EXTRA_PLAY_TIME = 30
+GET_PROPERTY_HARDWARE_PLATFORM = 'getprop ro.boot.hardware.platform'
class PowerBTcalibrationTest(PBtBT.PowerBTBaseTest):
@@ -50,20 +51,23 @@
self.media.play()
time.sleep(EXTRA_PLAY_TIME)
- # Loop through attenuation in 1 dB step until reaching at PL10
+ # Loop through attenuation in 1 dB step
self.log.info('Starting Calibration Process')
- pl10_count = 0
for i in range(int(self.attenuator.get_max_atten())):
-
- self.attenuator.set_atten(i)
- bt_metrics_dict = btutils.get_bt_metric(self.dut)
- pwl = bt_metrics_dict['pwlv'][self.dut.serial]
- self.log.info('Reach PW {} at attenuation {} dB'.format(pwl, i))
- self.cal_matrix.append([i, pwl])
- if pwl == 10:
- pl10_count += 1
- if pl10_count > 5:
- break
+ try:
+ self.attenuator.set_atten(i)
+ bt_metrics_dict = btutils.get_bt_metric(self.dut)
+ pwl = bt_metrics_dict['pwlv'][self.dut.serial]
+ rssi = bt_metrics_dict['rssi'][self.dut.serial]
+ bftx = bt_metrics_dict['bftx'][self.dut.serial]
+ self.log.info(
+ 'Reach PW {}, RSSI {}, BFTX {} at attenuation {} dB'.format(
+ pwl, rssi, bftx, i))
+ except Exception as e:
+ self.log.warning('Get Exception {} at attenuation {} dB'.format(
+ str(e), i))
+ continue
+ self.cal_matrix.append([i, pwl, rssi, bftx])
# Write cal results to csv
with open(self.log_file, 'w', newline='') as f:
diff --git a/acts_tests/tests/google/power/tel/PowerTelMac_McsSweep_Test.py b/acts_tests/tests/google/power/tel/PowerTelMac_McsSweep_Test.py
new file mode 100644
index 0000000..d787234
--- /dev/null
+++ b/acts_tests/tests/google/power/tel/PowerTelMac_McsSweep_Test.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import acts_contrib.test_utils.power.cellular.cellular_pdcch_power_test as cppt
+
+
+class PowerTelMac_McsSweep_Test(cppt.PowerTelPDCCHTest):
+
+ def test_lte_mac_dl_4_ul_4(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_11_ul_4(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_21_ul_4(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_28_ul_4(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_4_ul_11(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_4_ul_21(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_4_ul_28(self):
+ self.power_pdcch_test()
\ No newline at end of file
diff --git a/acts_tests/tests/google/power/tel/PowerTelMac_MimoSweep_Test.py b/acts_tests/tests/google/power/tel/PowerTelMac_MimoSweep_Test.py
new file mode 100644
index 0000000..9e84867
--- /dev/null
+++ b/acts_tests/tests/google/power/tel/PowerTelMac_MimoSweep_Test.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import acts_contrib.test_utils.power.cellular.cellular_pdcch_power_test as cppt
+
+
+class PowerTelMac_MimoSweep_Test(cppt.PowerTelPDCCHTest):
+
+ def test_lte_mac_1x1(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_2x2(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_4x4(self):
+ self.power_pdcch_test()
diff --git a/acts_tests/tests/google/power/tel/PowerTelMac_RbSweep_Test.py b/acts_tests/tests/google/power/tel/PowerTelMac_RbSweep_Test.py
new file mode 100644
index 0000000..154d07d
--- /dev/null
+++ b/acts_tests/tests/google/power/tel/PowerTelMac_RbSweep_Test.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import acts_contrib.test_utils.power.cellular.cellular_pdcch_power_test as cppt
+
+
+class PowerTelMac_RbSweep_Test(cppt.PowerTelPDCCHTest):
+
+ def test_lte_mac_dl_4_ul_1(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_24_ul_1(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_52_ul_1(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_76_ul_1(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_100_ul_1(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_4_ul_25(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_4_ul_50(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_4_ul_75(self):
+ self.power_pdcch_test()
+
+ def test_lte_mac_dl_4_ul_100(self):
+ self.power_pdcch_test()
\ No newline at end of file
diff --git a/acts_tests/tests/google/power/tel/PowerTelTraffic_RbSweep_Test.py b/acts_tests/tests/google/power/tel/PowerTelTraffic_RbSweep_Test.py
new file mode 100644
index 0000000..a081b87
--- /dev/null
+++ b/acts_tests/tests/google/power/tel/PowerTelTraffic_RbSweep_Test.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import acts_contrib.test_utils.power.cellular.cellular_traffic_power_test as ctpt
+
+
+class PowerTelTraffic_RbSweep_Test(ctpt.PowerTelTrafficTest):
+
+ def test_lte_direction_dl_8(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_direction_dl_24(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_direction_dl_52(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_direction_dl_76(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_direction_dl_100(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_direction_ul_8(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_direction_ul_25(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_direction_ul_50(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_direction_ul_75(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_direction_ul_100(self):
+ self.power_tel_traffic_test()
diff --git a/acts_tests/tests/google/power/tel/PowerTestPdcch_BandwidthSweep_Test.py b/acts_tests/tests/google/power/tel/PowerTestPdcch_BandwidthSweep_Test.py
new file mode 100644
index 0000000..41086f1
--- /dev/null
+++ b/acts_tests/tests/google/power/tel/PowerTestPdcch_BandwidthSweep_Test.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import acts_contrib.test_utils.power.cellular.cellular_pdcch_power_test as cppt
+
+
+class PowerTelPdcch_BandwidthSweep_Test(cppt.PowerTelPDCCHTest):
+
+ def test_lte_pdcch_b4_20(self):
+ self.power_pdcch_test()
+
+ def test_lte_pdcch_b4_15(self):
+ self.power_pdcch_test()
+
+ def test_lte_pdcch_b4_10(self):
+ self.power_pdcch_test()
+
+ def test_lte_pdcch_b4_5(self):
+ self.power_pdcch_test()
diff --git a/acts_tests/tests/google/power/tel/PowerTestPdcch_FddBandSweep_Test.py b/acts_tests/tests/google/power/tel/PowerTestPdcch_FddBandSweep_Test.py
new file mode 100644
index 0000000..4d6353b
--- /dev/null
+++ b/acts_tests/tests/google/power/tel/PowerTestPdcch_FddBandSweep_Test.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import acts_contrib.test_utils.power.cellular.cellular_pdcch_power_test as cppt
+
+
+class PowerTelPdcch_FddBandSweep_Test(cppt.PowerTelPDCCHTest):
+
+ def test_lte_pdcch_b1(self):
+ self.power_pdcch_test()
+
+ def test_lte_pdcch_b2(self):
+ self.power_pdcch_test()
+
+ def test_lte_pdcch_b3(self):
+ self.power_pdcch_test()
+
+ def test_lte_pdcch_b4(self):
+ self.power_pdcch_test()
+
+ def test_lte_pdcch_b5(self):
+ self.power_pdcch_test()
+
+ def test_lte_pdcch_b7(self):
+ self.power_pdcch_test()
+
+ def test_lte_pdcch_b8(self):
+ self.power_pdcch_test()
+
+ def test_lte_pdcch_b11(self):
+ self.power_pdcch_test()
+
+ def test_lte_pdcch_b12(self):
+ self.power_pdcch_test()
+
+ def test_lte_pdcch_b13(self):
+ self.power_pdcch_test()
diff --git a/acts_tests/tests/google/power/wifi/PowerWiFiHotspotTest.py b/acts_tests/tests/google/power/wifi/PowerWiFiHotspotTest.py
index 74106c9..7e7c3b8 100644
--- a/acts_tests/tests/google/power/wifi/PowerWiFiHotspotTest.py
+++ b/acts_tests/tests/google/power/wifi/PowerWiFiHotspotTest.py
@@ -17,8 +17,8 @@
import time
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.power import PowerWiFiBaseTest as PWBT
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from acts_contrib.test_utils.wifi import wifi_power_test_utils as wputils
from acts_contrib.test_utils.power.IperfHelper import IperfHelper
diff --git a/acts_tests/tests/google/power/wifi/PowerWiFidtimTest.py b/acts_tests/tests/google/power/wifi/PowerWiFidtimTest.py
index 2d6eec1..bb68233 100644
--- a/acts_tests/tests/google/power/wifi/PowerWiFidtimTest.py
+++ b/acts_tests/tests/google/power/wifi/PowerWiFidtimTest.py
@@ -18,6 +18,7 @@
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.power import PowerWiFiBaseTest as PWBT
from acts_contrib.test_utils.wifi import wifi_power_test_utils as wputils
+from acts.controllers.adb_lib.error import AdbCommandError
class PowerWiFidtimTest(PWBT.PowerWiFiBaseTest):
@@ -33,17 +34,34 @@
attrs = ['screen_status', 'wifi_band', 'dtim']
indices = [2, 4, 6]
self.decode_test_configs(attrs, indices)
- # Initialize the dut to rock-bottom state
- rebooted = wputils.change_dtim(
- self.dut,
- gEnableModulatedDTIM=int(self.test_configs.dtim),
- gMaxLIModulatedDTIM=dtim_max)
- if rebooted:
- self.dut_rockbottom()
- self.dut.log.info('DTIM value of the phone is now {}'.format(
- self.test_configs.dtim))
- self.setup_ap_connection(
- self.main_network[self.test_configs.wifi_band])
+
+ # Starts from P21 device, the dtim setting method is changed to use adb.
+ # If no file match '/vendor/firmware/wlan/*/*.ini', use adb to change
+ # the dtim.
+ change_dtim_with_adb = False
+ try:
+ self.dut.adb.shell('ls /vendor/firmware/wlan/*/*.ini')
+ except AdbCommandError as e:
+ change_dtim_with_adb = True
+
+ if not change_dtim_with_adb:
+ # Initialize the dut to rock-bottom state
+ rebooted = wputils.change_dtim(
+ self.dut,
+ gEnableModulatedDTIM=int(self.test_configs.dtim),
+ gMaxLIModulatedDTIM=dtim_max)
+ if rebooted:
+ self.dut_rockbottom()
+ self.dut.log.info('DTIM value of the phone is now {}'.format(
+ self.test_configs.dtim))
+ self.setup_ap_connection(self.main_network[self.test_configs.wifi_band])
+
+ if change_dtim_with_adb:
+ self.dut.log.info('No ini file for dtim, change dtim with adb')
+ wputils.change_dtim_adb(
+ self.dut,
+ gEnableModulatedDTIM=int(self.test_configs.dtim))
+
if self.test_configs.screen_status == 'OFF':
self.dut.droid.goToSleepNow()
self.dut.log.info('Screen is OFF')
@@ -56,7 +74,10 @@
self.dtim_test_func()
@test_tracker_info(uuid='384d3b0f-4335-4b00-8363-308ec27a150c')
- def test_screen_ON_band_2g_dtim_1(self):
+ def test_screen_OFF_band_2g_dtim_8(self):
+ self.dtim_test_func()
+
+ def test_screen_OFF_band_2g_dtim_9(self):
self.dtim_test_func()
@test_tracker_info(uuid='017f57c3-e133-461d-80be-d025d1491d8a')
@@ -64,5 +85,8 @@
self.dtim_test_func()
@test_tracker_info(uuid='327af44d-d9e7-49e0-9bda-accad6241dc7')
- def test_screen_ON_band_5g_dtim_1(self):
+ def test_screen_OFF_band_5g_dtim_8(self):
+ self.dtim_test_func()
+
+ def test_screen_OFF_band_5g_dtim_9(self):
self.dtim_test_func()
diff --git a/acts_tests/tests/google/power/wifi/PowerWiFimulticastTest.py b/acts_tests/tests/google/power/wifi/PowerWiFimulticastTest.py
index 8b7e063..f0559e4 100644
--- a/acts_tests/tests/google/power/wifi/PowerWiFimulticastTest.py
+++ b/acts_tests/tests/google/power/wifi/PowerWiFimulticastTest.py
@@ -19,6 +19,7 @@
from acts_contrib.test_utils.power import PowerWiFiBaseTest as PWBT
from acts_contrib.test_utils.wifi import wifi_power_test_utils as wputils
from acts.controllers import packet_sender as pkt_utils
+from acts.controllers.adb_lib.error import AdbCommandError
RA_SHORT_LIFETIME = 3
RA_LONG_LIFETIME = 1000
@@ -54,18 +55,35 @@
indices = [2, 4]
self.decode_test_configs(attrs, indices)
# Change DTIMx1 on the phone to receive all Multicast packets
- rebooted = wputils.change_dtim(self.dut,
- gEnableModulatedDTIM=1,
- gMaxLIModulatedDTIM=10)
- self.dut.log.info('DTIM value of the phone is now DTIMx1')
- if rebooted:
- self.dut_rockbottom()
+
+ # Starts from P21 device, the dtim setting method is changed to use adb.
+ # If no file match '/vendor/firmware/wlan/*/*.ini', use adb to change
+ # the dtim.
+ change_dtim_with_adb = False
+ try:
+ self.dut.adb.shell('ls /vendor/firmware/wlan/*/*.ini')
+ except AdbCommandError as e:
+ change_dtim_with_adb = True
+
+ if not change_dtim_with_adb:
+ # Initialize the dut to rock-bottom state
+ rebooted = wputils.change_dtim(
+ self.dut,
+ gEnableModulatedDTIM=1,
+ gMaxLIModulatedDTIM=10)
+ if rebooted:
+ self.dut_rockbottom()
+ self.dut.log.info('DTIM value of the phone is now DTIMx1')
self.setup_ap_connection(
self.main_network[self.test_configs.wifi_band])
# Wait for DHCP with timeout of 60 seconds
wputils.wait_for_dhcp(self.pkt_sender.interface)
+ if change_dtim_with_adb:
+ self.dut.log.info('No ini file for dtim, change dtim with adb')
+ wputils.change_dtim_adb(self.dut, gEnableModulatedDTIM=1)
+
# Set the desired screen status
if self.test_configs.screen_status == 'OFF':
self.dut.droid.goToSleepNow()
diff --git a/acts_tests/tests/google/tel/etc/manage_sim.py b/acts_tests/tests/google/tel/etc/manage_sim.py
index 91a3887..d848350 100755
--- a/acts_tests/tests/google/tel/etc/manage_sim.py
+++ b/acts_tests/tests/google/tel/etc/manage_sim.py
@@ -67,9 +67,9 @@
'operator'] = tel_lookup_tables.operator_name_from_plmn_id(
plmn_id)
except KeyError:
- if vebose_warnings:
+ if verbose_warnings:
print('Unknown Operator {}'.format(
- droid.telephonyGetSimOperator()))
+ droid.telephonyGetSimOperatorForSubscription(sub_id)))
current['operator'] = ''
# TODO: add actual capability determination to replace the defaults
@@ -83,8 +83,17 @@
iccid))
current['phone_num'] = ''
else:
- current['phone_num'] = tel_test_utils.phone_number_formatter(
- phone_num, tel_defines.PHONE_NUMBER_STRING_FORMAT_11_DIGIT)
+ # No need to set phone number formatter for South Korea carriers
+ if (current['operator'] == tel_defines.CARRIER_SKT or
+ current['operator'] == tel_defines.CARRIER_KT or
+ current['operator'] == tel_defines.CARRIER_LG_UPLUS):
+ current['phone_num'] = \
+ tel_test_utils.phone_number_formatter(phone_num)
+ else:
+ current['phone_num'] = \
+ tel_test_utils.phone_number_formatter(
+ phone_num,
+ tel_defines.PHONE_NUMBER_STRING_FORMAT_11_DIGIT)
return active_list
diff --git a/acts_tests/tests/google/tel/lab/TelLabCmasTest.py b/acts_tests/tests/google/tel/lab/TelLabCmasTest.py
index 4292c87..052adb8 100644
--- a/acts_tests/tests/google/tel/lab/TelLabCmasTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabCmasTest.py
@@ -57,10 +57,10 @@
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_UMTS
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.test_decorators import test_tracker_info
diff --git a/acts_tests/tests/google/tel/lab/TelLabDataRoamingTest.py b/acts_tests/tests/google/tel/lab/TelLabDataRoamingTest.py
index af4ca6c..73e610c 100644
--- a/acts_tests/tests/google/tel/lab/TelLabDataRoamingTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabDataRoamingTest.py
@@ -29,12 +29,12 @@
from acts_contrib.test_utils.tel.anritsu_utils import set_post_sim_params
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import toggle_cell_data_roaming
from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_apn_by_adb
-from acts_contrib.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
diff --git a/acts_tests/tests/google/tel/lab/TelLabDataTest.py b/acts_tests/tests/google/tel/lab/TelLabDataTest.py
index 9a1355d..7481799 100644
--- a/acts_tests/tests/google/tel/lab/TelLabDataTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabDataTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2016 - The Android Open Source Project
+# Copyright 2022 - 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.
@@ -18,7 +18,6 @@
"""
import time
-import json
import logging
import os
@@ -26,23 +25,13 @@
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.controllers.anritsu_lib.md8475a import VirtualPhoneStatus
from acts_contrib.test_utils.tel.anritsu_utils import cb_serial_number
-from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_1x
-from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_gsm
from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_lte
-from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_lte_wcdma
-from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_wcdma
-from acts_contrib.test_utils.tel.anritsu_utils import sms_mo_send
-from acts_contrib.test_utils.tel.anritsu_utils import sms_mt_receive_verify
from acts_contrib.test_utils.tel.anritsu_utils import set_usim_parameters
from acts_contrib.test_utils.tel.anritsu_utils import set_post_sim_params
-from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
-from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_TERMINATED
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_CDMA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_ONLY
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_UMTS
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_CDMA_EVDO
from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
from acts_contrib.test_utils.tel.tel_defines import RAT_GSM
@@ -52,33 +41,24 @@
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_UMTS
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
-from acts_contrib.test_utils.tel.tel_defines import GEN_4G
from acts_contrib.test_utils.tel.tel_defines import POWER_LEVEL_OUT_OF_SERVICE
from acts_contrib.test_utils.tel.tel_defines import POWER_LEVEL_FULL_SERVICE
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_detection
+from acts_contrib.test_utils.tel.tel_data_utils import check_network_validation_fail
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_recovery
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.tel_test_utils import get_host_ip_address
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import iperf_test_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
-from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_detection
-from acts_contrib.test_utils.tel.tel_test_utils import check_network_validation_fail
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_recovery
from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
from acts_contrib.test_utils.tel.tel_test_utils import break_internet_except_sl4a_port
from acts_contrib.test_utils.tel.tel_test_utils import resume_internet_with_sl4a_port
-from acts_contrib.test_utils.tel.tel_test_utils import \
- test_data_browsing_success_using_sl4a
-from acts_contrib.test_utils.tel.tel_test_utils import \
- test_data_browsing_failure_using_sl4a
+from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_success_using_sl4a
+from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_failure_using_sl4a
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.utils import adb_shell_ping
-from acts.utils import rand_ascii_str
-from acts.controllers import iperf_server
-from acts.utils import exe_cmd
DEFAULT_PING_DURATION = 30
diff --git a/acts_tests/tests/google/tel/lab/TelLabEmergencyCallTest.py b/acts_tests/tests/google/tel/lab/TelLabEmergencyCallTest.py
index d83faa3..9042aeb 100644
--- a/acts_tests/tests/google/tel/lab/TelLabEmergencyCallTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabEmergencyCallTest.py
@@ -22,7 +22,6 @@
from acts.controllers.anritsu_lib.md8475a import CsfbType
from acts.controllers.anritsu_lib.md8475a import MD8475A
from acts.controllers.anritsu_lib.md8475a import VirtualPhoneAutoAnswer
-from acts.controllers.anritsu_lib.md8475a import VirtualPhoneStatus
from acts_contrib.test_utils.tel.anritsu_utils import WAIT_TIME_ANRITSU_REG_AND_CALL
from acts_contrib.test_utils.tel.anritsu_utils import call_mo_setup_teardown
from acts_contrib.test_utils.tel.anritsu_utils import ims_call_cs_teardown
@@ -53,16 +52,15 @@
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL_FOR_IMS
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_volte
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte
from acts_contrib.test_utils.tel.tel_test_utils import check_apm_mode_on_by_serial
from acts_contrib.test_utils.tel.tel_test_utils import set_apm_mode_on_by_serial
from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_apn_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_volte
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.test_decorators import test_tracker_info
from acts.utils import exe_cmd
diff --git a/acts_tests/tests/google/tel/lab/TelLabEtwsTest.py b/acts_tests/tests/google/tel/lab/TelLabEtwsTest.py
index 3683173..b3a566c 100644
--- a/acts_tests/tests/google/tel/lab/TelLabEtwsTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabEtwsTest.py
@@ -43,10 +43,10 @@
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_UMTS
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.test_decorators import test_tracker_info
diff --git a/acts_tests/tests/google/tel/lab/TelLabGFTAirplaneModeTest.py b/acts_tests/tests/google/tel/lab/TelLabGFTAirplaneModeTest.py
new file mode 100644
index 0000000..4dcf75c
--- /dev/null
+++ b/acts_tests/tests/google/tel/lab/TelLabGFTAirplaneModeTest.py
@@ -0,0 +1,422 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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 signals
+from acts.test_decorators import test_tracker_info
+from acts.libs.utils.multithread import multithread_func
+
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.GFTInOutBaseTest import GFTInOutBaseTest
+from acts_contrib.test_utils.tel.gft_inout_defines import VOICE_CALL
+from acts_contrib.test_utils.tel.gft_inout_utils import check_no_service_time
+from acts_contrib.test_utils.tel.gft_inout_utils import check_back_to_service_time
+from acts_contrib.test_utils.tel.gft_inout_utils import mo_voice_call
+from acts_contrib.test_utils.tel.tel_defines import RAT_3G
+from acts_contrib.test_utils.tel.tel_defines import RAT_4G
+from acts_contrib.test_utils.tel.tel_defines import RAT_5G
+from acts_contrib.test_utils.tel.tel_defines import GEN_3G
+from acts_contrib.test_utils.tel.tel_defines import GEN_4G
+from acts_contrib.test_utils.tel.tel_defines import GEN_5G
+from acts_contrib.test_utils.tel.tel_defines import YOUTUBE_PACKAGE_NAME
+from acts_contrib.test_utils.tel.tel_data_utils import start_youtube_video
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
+
+AIRPLANE_MODE_ON_TIME = 60
+AIRPLANE_MODE_OFF_TIME = 60
+MOBILE_DATA_ON_OFF_CASE = 1
+DATA_TRANSFER_CASE = 2
+WIFI_HOTSPOT_CASE = 3
+IN_CALL_CASE = 4
+
+class TelLabGFTAirplaneModeTest(GFTInOutBaseTest):
+ def __init__(self, controllers):
+ GFTInOutBaseTest.__init__(self, controllers)
+
+
+ def setup_test(self):
+ for ad in self.android_devices:
+ ensure_phone_default_state(self.log, ad)
+ GFTInOutBaseTest.setup_test(self)
+ self.my_error_msg = ""
+
+ def teardown_test(self):
+ for ad in self.android_devices:
+ ad.force_stop_apk(YOUTUBE_PACKAGE_NAME)
+ ensure_phones_idle(self.log, self.android_devices)
+
+ @test_tracker_info(uuid="c5d2e9b3-478c-4f86-86e5-c8341944d222")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_airplane_mode_mobile_data_off_3g(self):
+ '''
+ 1.9.5 - 3G Airplane mode on/off - Mobile data off
+
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(self._airplane_mode_helper, (ad, MOBILE_DATA_ON_OFF_CASE, RAT_3G))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("_airplane_mode_data_on_off failure: %s"
+ %(self.my_error_msg))
+ return True
+
+ @test_tracker_info(uuid="22956c54-ab2a-4031-8dfc-95fdb69fb3a6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_airplane_mode_mobile_data_off_4g(self):
+ '''
+ 1.13.5 - 4G Airplane mode on/off - Mobile data off
+
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(self._airplane_mode_helper, (ad, MOBILE_DATA_ON_OFF_CASE, RAT_4G))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("_airplane_mode_data_on_off failure: %s"
+ %(self.my_error_msg))
+ return True
+
+
+ @test_tracker_info(uuid="9ab8e183-6864-4543-855e-4d9a6cb74e42")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_airplane_mode_mobile_data_off_5g(self):
+ '''
+ 1.14.5 - 5G [NSA/SA] Airplane mode on/off - Mobile data off
+
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(self._airplane_mode_helper, (ad, MOBILE_DATA_ON_OFF_CASE, RAT_5G))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("_airplane_mode_data_on_off failure: %s"
+ %(self.my_error_msg))
+ return True
+
+
+ @test_tracker_info(uuid="114afeb6-4c60-4da3-957f-b4b0005223be")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_airplane_mode_voice_call_3g(self):
+ '''
+ 3G 1.9.2 - Airplane mode on/off - Active call
+
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(self._airplane_mode_helper, (ad, IN_CALL_CASE, GEN_3G))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("_airplane_mode_voice_call failure: %s"
+ %(self.my_error_msg))
+ return True
+
+
+ @test_tracker_info(uuid="0e00ca1a-f896-4a18-a3c8-05514975ecd6")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_airplane_mode_voice_call_4g(self):
+ '''
+ 4G 1.13.2 - Airplane mode on/off - Active call
+
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(self._airplane_mode_helper, (ad, IN_CALL_CASE, GEN_4G))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("_airplane_mode_voice_call failure: %s"
+ %(self.my_error_msg))
+ return True
+
+ @test_tracker_info(uuid="cb228d48-78b4-48b4-9996-26ac252a9486")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_airplane_mode_voice_call_5g(self):
+ '''
+ 5G 1.14.2 - [NSA/SA] Airplane mode on/off - Active call
+ For NSA, call goes through IMS over LTE (VoLTE).
+ For SA, call goes through IMS over LTE/NR (EPSFB or VoNR)
+ depends on carrier's implementation.
+
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(self._airplane_mode_helper, (ad, IN_CALL_CASE, GEN_5G))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("_airplane_mode_voice_call failure: %s"
+ %(self.my_error_msg))
+ return True
+
+ def _airplane_mode_mobile_data_off(self, ad):
+ """ Mobile data on/off and airplane mode on/off.
+
+ Args:
+ ad: android_device object.
+
+ Returns:
+ result: True if operation succeed. False if error happens.
+ """
+ # Repeat for 3 cycles.
+ for x in range (3):
+ ad.log.info("Turn off mobile data")
+ ad.droid.telephonyToggleDataConnection(False)
+ if not wait_for_cell_data_connection(self.log, ad, False):
+ self.my_error_msg += "fail to turn off mobile data"
+ return False
+ if not self._airplane_mode_on_off(ad):
+ return False
+ ad.log.info("Turn on mobile data")
+ ad.droid.telephonyToggleDataConnection(True)
+ #If True, it will wait for status to be DATA_STATE_CONNECTED
+ if not wait_for_cell_data_connection(self.log, ad, True):
+ self.my_error_msg += "fail to turn on mobile data"
+ return False
+ # UE turn airplane mode on then off.
+ if not self._airplane_mode_on_off(ad):
+ return False
+ return True
+
+
+ def _airplane_mode_on_off(self, ad):
+ """ Toggle airplane mode on/off.
+
+ Args:
+ ad: android_device object.
+
+ Returns:
+ result: True if operation succeed. False if error happens.
+ """
+ ad.log.info("Turn on airplane mode")
+ if not toggle_airplane_mode(self.log, ad, True):
+ self.my_error_msg += "Fail to enable airplane mode on. "
+ return False
+ time.sleep(AIRPLANE_MODE_ON_TIME)
+ ad.log.info("Turn off airplane mode")
+ if not toggle_airplane_mode(self.log, ad, False):
+ self.my_error_msg += "Fail to enable airplane mode off. "
+ return False
+ time.sleep(AIRPLANE_MODE_OFF_TIME)
+ return True
+
+
+ def _airplane_mode_voice_call(self, ad):
+ """ Airplane mode on/off while in-call.
+
+ Args:
+ ad: android_device object.
+
+ Returns:
+ result: True if operation succeed. False if error happens.
+ """
+ # Repeat for 3 cycles.
+ for x in range (3):
+ ad.log.info("Make a MO call.")
+ if not mo_voice_call(self.log, ad, VOICE_CALL, False):
+ return False
+ self.log.info("turn airplane mode on then off during in call")
+ if not self._airplane_mode_on_off(ad):
+ return False
+ return True
+
+ def _airplane_mode_data_transfer(self, ad):
+ """ Airplane mode on/off while data transfer.
+
+ Args:
+ ad: android_device object.
+
+ Returns:
+ result: True if operation succeed. False if error happens.
+ """
+ # Repeat for 3 cycles.
+ for x in range (3):
+ ad.log.info("Perform a data transferring. Start streaming")
+ if not start_youtube_video(ad):
+ ad.log.warning("Fail to bring up youtube video")
+ self.my_error_msg += "Fail to bring up youtube video. "
+ return False
+ self.log.info("turn airplane mode on then off during data transferring")
+ if not self._airplane_mode_on_off(ad):
+ return False
+ return True
+
+
+ def _airplane_mode_wifi_hotspot(self, ad):
+ """ Airplane mode on/off Wi-Fi hotspot enabled
+
+ Args:
+ ad: android_device object.
+
+ Returns:
+ result: True if operation succeed. False if error happens.
+ """
+ # Repeat for 3 cycles.
+ for x in range (3):
+ ad.log.info("Enable Wi-Fi Hotspot on UE")
+ #if not start_youtube_video(ad):
+ # return False
+ self.log.info("turn airplane mode on then off")
+ if not self._airplane_mode_on_off(ad):
+ return False
+ return True
+
+ def _airplane_mode_helper(self, ad, case= MOBILE_DATA_ON_OFF_CASE, rat=GEN_4G, loop=1):
+ self.log.info("Lock network mode to %s." , rat)
+ if not ensure_network_generation(self.log, ad, rat):
+ raise signals.TestFailure("device fail to register at %s"
+ %(rat))
+
+ for x in range(self.user_params.get("apm_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name,x+1, loop))
+ if case == MOBILE_DATA_ON_OFF_CASE:
+ if not self._airplane_mode_mobile_data_off(ad):
+ return False
+ elif case == DATA_TRANSFER_CASE:
+ if not self._airplane_mode_data_transfer(ad):
+ return False
+ elif case == WIFI_HOTSPOT_CASE:
+ if not self._airplane_mode_wifi_hotspot(ad):
+ return False
+ elif case == IN_CALL_CASE:
+ if not self._airplane_mode_voice_call(ad):
+ return False
+ #check radio function
+ tasks = [(self.verify_device_status, (ad, VOICE_CALL))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("verify_device_status failure: %s"
+ %(self.my_error_msg))
+ return True
+
+ @test_tracker_info(uuid="0205ec77-36c1-478f-9d05-c8a72fffdd03")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_airplane_mode_data_transfer_5g(self):
+ '''
+ 5G - [NSA/SA] Airplane mode on/off - transfer
+ For NSA, call goes through IMS over LTE (VoLTE).
+ For SA, call goes through IMS over LTE/NR (EPSFB or VoNR)
+ depends on carrier's implementation.
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(self._airplane_mode_helper, (ad, DATA_TRANSFER_CASE, GEN_5G))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("_airplane_mode_data_transfer failure: %s"
+ %(self.my_error_msg))
+ return True
+
+ @test_tracker_info(uuid="c76a1154-29c0-4259-bd4c-05279d80537b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_airplane_mode_data_transfer_4g(self):
+ '''
+ 4G - Airplane mode on/off - Data transferring
+
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(self._airplane_mode_helper, (ad, DATA_TRANSFER_CASE, GEN_4G))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("_airplane_mode_data_transfer failure: %s"
+ %(self.my_error_msg))
+ return True
+
+ @test_tracker_info(uuid="c16ea0bb-0155-4f5f-97a8-22c7e0e6e2f5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_airplane_mode_data_transfer_3g(self):
+ '''
+ 3G - Airplane mode on/off - Data transferring
+
+ Raises:
+ TestFailure if not success.
+
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(self._airplane_mode_helper, (ad, DATA_TRANSFER_CASE, GEN_3G))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("_airplane_mode_data_transfer failure: %s"
+ %(self.my_error_msg))
+ return True
+
+ @test_tracker_info(uuid="b1db4e3b-ea0b-4b61-9f2c-4b8fc251c71a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_airplane_mode_wifi_hotspot_5g(self):
+ '''
+ 5G -[NSA/SA] Airplane mode off/on - Wi-Fi Hotspot enabled
+ For NSA, call goes through IMS over LTE (VoLTE).
+ For SA, call goes through IMS over LTE/NR (EPSFB or VoNR)
+ depends on carrier's implementation.
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(self._airplane_mode_helper, (ad, WIFI_HOTSPOT_CASE, GEN_5G))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("_airplane_mode_wifi_hotspot failure: %s"
+ %(self.my_error_msg))
+ return True
+
+ @test_tracker_info(uuid="f21f4554-7755-4019-b8a2-6f86d1ebd57a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_airplane_mode_wifi_hotspot_4g(self):
+ '''
+ 4G - Airplane mode off/on - Wi-Fi Hotspot enabled
+
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(self._airplane_mode_helper, (ad, WIFI_HOTSPOT_CASE, GEN_4G))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("_airplane_mode_wifi_hotspot failure: %s"
+ %(self.my_error_msg))
+ return True
+
+ @test_tracker_info(uuid="8cf3c617-4534-4b08-b31f-f702c5f8bb8b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_airplane_mode_wifi_hotspot_3g(self):
+ '''
+ 3G - Airplane mode off/on - Wi-Fi Hotspot enabled
+
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(self._airplane_mode_helper, (ad, WIFI_HOTSPOT_CASE, GEN_3G))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("_airplane_mode_wifi_hotspot failure: %s"
+ %(self.my_error_msg))
+ return True
\ No newline at end of file
diff --git a/acts_tests/tests/google/tel/lab/TelLabGFTDSDSInOutServiceTest.py b/acts_tests/tests/google/tel/lab/TelLabGFTDSDSInOutServiceTest.py
new file mode 100644
index 0000000..a4529eb
--- /dev/null
+++ b/acts_tests/tests/google/tel/lab/TelLabGFTDSDSInOutServiceTest.py
@@ -0,0 +1,907 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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
+import datetime
+from acts import asserts
+from acts.test_decorators import test_tracker_info
+from acts.libs.utils.multithread import multithread_func
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.GFTInOutBaseTest import GFTInOutBaseTest
+from acts_contrib.test_utils.tel.gft_inout_utils import mo_voice_call
+from acts_contrib.test_utils.tel.tel_test_utils import wait_for_ims_registered
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
+
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_message_subid
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_voice_sub_id
+
+from acts_contrib.test_utils.tel.gft_inout_defines import VOICE_CALL
+from acts_contrib.test_utils.tel.gft_inout_defines import VOLTE_CALL
+from acts_contrib.test_utils.tel.gft_inout_defines import CSFB_CALL
+from acts_contrib.test_utils.tel.gft_inout_defines import WFC_CALL
+from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_POWER_LEVEL
+from acts_contrib.test_utils.tel.gft_inout_defines import IN_SERVICE_POWER_LEVEL
+from acts_contrib.test_utils.tel.gft_inout_utils import check_ims_state
+from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_service
+
+IDLE_CASE = 1
+DATA_TRANSFER_CASE = 2
+DATA_OFF_CASE = 3
+IN_CALL_CASE = 4
+CALL_DATA_CASE = 5
+_VOLTE = "volte"
+
+class TelLabGFTDSDSInOutServiceTest(GFTInOutBaseTest):
+ def __init__(self, controllers):
+ GFTInOutBaseTest.__init__(self, controllers)
+ self.my_error_msg = ""
+
+ def teardown_test(self):
+ GFTInOutBaseTest.teardown_class(self)
+ ensure_phones_idle(self.log, self.android_devices)
+
+ def _dsds_in_out_service_test(self, case=IDLE_CASE, loop=1, idle_time=60, dds_slot=0,
+ voice_slot=0, sms_slot=0, psim_rat=_VOLTE , esim_rat=_VOLTE):
+ '''
+ b/201599180
+ Move UE from coverage area to no service area and UE shows no service
+ Wait for a period of time, then re-enter coverage area
+
+ Args:
+ case: include IDLE_CAS, DATA_TRANSFER_CASE, DATA_OFF_CASE,
+ IN_CALL_CASE, CALL_DATA_CASE
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ dds_slot: Preferred data slot
+ voice_slot: Preferred voice slot
+ sms_slot: Preferred SMS slot
+ psim_rat: RAT on psim
+ esim_rat: RAT on esim
+ Returns:
+ True if pass; False if fail
+ Raises:
+ TestFailure if not success.
+ '''
+ tasks = [(set_dds_on_slot, (ad, dds_slot )) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ asserts.skip("Fail to to set up DDS")
+ for ad in self.android_devices:
+ voice_sub_id = get_subid_from_slot_index(self.log, ad, voice_slot)
+ if voice_sub_id == INVALID_SUB_ID:
+ asserts.skip("Failed to get sub ID ar slot %s.", voice_slot)
+ else:
+ ad.log.info("get_subid_from_slot_index voice_slot=%s. voice_sub_id=%s"
+ , voice_slot, voice_sub_id)
+ if not set_voice_sub_id(ad, voice_sub_id):
+ ad.log.info("Fail to to set voice to slot %s" , voice_sub_id)
+ else:
+ ad.log.info("set voice to slot %s" , voice_sub_id)
+ tasks = [(set_message_subid, (ad, sms_slot )) for ad in self.android_devices]
+ if multithread_func(self.log, tasks):
+ asserts.skip("Fail to to set up sms to slot %s" , sms_slot)
+ else:
+ ad.log.info("set up sms to slot %s" , sms_slot)
+
+ for x in range (loop):
+ self.log.info("%s loop: %s/%s" , self.current_test_name, x+1, loop))
+ if case == IDLE_CASE:
+ asserts.assert_true(self._dsds_in_out_service_idle_test(idle_time),
+ "Fail: %s." %("_dsds_in_out_service_idle_test failure"),
+ extras={"failure_cause": self.my_error_msg})
+ elif case == DATA_TRANSFER_CASE:
+ asserts.assert_true(self._dsds_in_out_service_data_transfer_test(idle_time),
+ "Fail: %s." %("_dsds_in_out_service_data_transfer_test failure"),
+ extras={"failure_cause": self.my_error_msg})
+ elif case == DATA_OFF_CASE:
+ asserts.assert_true(self._dsds_in_out_service_data_off_test(idle_time),
+ "Fail: %s." %("_dsds_in_out_service_data_off_test failure"),
+ extras={"failure_cause": self.my_error_msg})
+ elif case == IN_CALL_CASE:
+ asserts.assert_true(self._dsds_in_out_service_in_call_test(idle_time),
+ "Fail: %s." %("_dsds_in_out_service_in_call_test failure"),
+ extras={"failure_cause": self.my_error_msg})
+ elif case == CALL_DATA_CASE:
+ asserts.assert_true(self._dsds_in_out_service_in_call_transfer_test(idle_time),
+ "Fail: %s." %("_dsds_in_out_service_in_call_transfer_test failure"),
+ extras={"failure_cause": self.my_error_msg})
+
+ tasks = [(wait_for_network_service, (self.log, ad, ))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ asserts.assert_true(False, "Fail: %s." %("wait_for_network_service failure"),
+ extras={"failure_cause": self.my_error_msg})
+ tasks = [(self.verify_device_status, (ad, VOICE_CALL))
+ for ad in self.android_devices]
+ asserts.assert_true(multithread_func(self.log, tasks),
+ "Fail: %s." %("verify_device_status failure"),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+ def _dsds_in_out_service_idle_test(self, idle_time=60):
+ '''
+ (1) UE is in idle
+ (2) Move UE from coverage area to no service area and UE shows no service
+ (3) Wait for a period of time, then re-enter coverage area
+
+ Args:
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ return self._in_out_service_idle(idle_time)
+
+
+ def _dsds_in_out_service_in_call_transfer_test(self, idle_time=60):
+ '''
+ (1) UE is performing data transfer (E.g. Use FTP or browse tools)
+ (2) UE makes a MO call
+ (3) Move UE from coverage area to no service area and UE shows no service
+ (4) Wait for a period of time, then re-enter coverage area
+
+ Args:
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ error_msg = ""
+ tasks_a = [(active_file_download_test, (self.log, ad, )) for ad in self.android_devices]
+ tasks_b= [(mo_voice_call, (self.log, ad, VOICE_CALL, False)) for ad in self.android_devices]
+ tasks_b.extend(tasks_a)
+ if not multithread_func(self.log, tasks_b):
+ error_msg = "fail to perfrom data transfer/voice call"
+ self.my_error_msg += error_msg
+ return False
+ self._in_out_service_idle(idle_time)
+ return True
+
+ def _dsds_in_out_service_in_call_test(self, idle_time=60):
+ '''
+ (1) UE is in call
+ (2) Move UE from coverage area to no service area and UE shows no service
+ (3) Wait for a period of time, then re-enter coverage area
+
+ Args:
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ error_msg = ""
+ tasks = [(mo_voice_call, (self.log, ad, VOICE_CALL, False)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ error_msg = "MO voice call fail"
+ self.my_error_msg += error_msg
+ self.log.error(error_msg)
+ return False
+ return self._in_out_service_idle(idle_time)
+
+ def _dsds_in_out_service_data_off_test(self, idle_time=60):
+ '''
+ (1) Disable UE mobile data
+ (2) Move UE from coverage area to no service area and UE shows no service
+ (3) Wait for a period of time, then re-enter coverage area
+
+ Args:
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ for ad in self.android_devices:
+ ad.log.info("Turn off mobile data")
+ ad.droid.telephonyToggleDataConnection(False)
+ if not wait_for_cell_data_connection(self.log, ad, False):
+ self.my_error_msg += "fail to turn off mobile data"
+ return False
+ self._in_out_service_idle(idle_time)
+ for ad in self.android_devices:
+ ad.log.info("Turn on mobile data")
+ ad.droid.telephonyToggleDataConnection(True)
+ #If True, it will wait for status to be DATA_STATE_CONNECTED
+ if not wait_for_cell_data_connection(self.log, ad, True):
+ self.my_error_msg += "fail to turn on mobile data"
+ return False
+ return True
+
+ def _dsds_in_out_service_data_transfer_test(self, idle_time=60, file_name="10MB"):
+ '''
+ (1) UE is performing data transfer (E.g. Use FTP or browse tools)
+ (2) Move UE from coverage area to no service area and UE shows no service
+ (3) Wait for 1 min, then re-enter coverage area
+
+ Args:
+ idle_time: idle time at no service area
+ file_name:
+ Returns:
+ True if pass; False if fail
+ Raises:
+ TestFailure if not success.
+ '''
+ tasks_a = [(self._in_out_service_idle, (idle_time))]
+ tasks_b = [(active_file_download_test, (self.log, ad, file_name))
+ for ad in self.android_devices]
+ tasks_b.extend(tasks_a)
+ if not multithread_func(self.log, tasks_b):
+ error_msg = " data transfer fail. "
+ self.my_error_msg += error_msg
+ self.log.error(error_msg)
+ tasks = [(self.verify_device_status, (ad, VOICE_CALL))
+ for ad in self.android_devices]
+ asserts.assert_true(multithread_func(self.log, tasks), "Fail: %s."
+ %("verify_device_status failure"), extras={"failure_cause":
+ self.my_error_msg})
+ return True
+
+ def _in_out_service_idle(self, idle_time):
+ '''
+ adjust cellular signal
+
+ Args:
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(idle_time)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ return True
+
+
+
+ @test_tracker_info(uuid="053465d8-a682-404c-a0fb-8e79f6ca581d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_idle_msim_4g_esim_4g_dds_sim1_1min(self, loop=50, idle_time=60):
+ '''
+ 1.8.17 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary idle mode - 1 min
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IDLE_CASE, loop, idle_time, 0)
+
+
+ @test_tracker_info(uuid="1ba35ced-41d1-456d-84e2-a40a0d7402b2")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_idle_msim_4g_esim_4g_dds_sim2_1min(self, loop=50, idle_time=60):
+ '''
+ 1.8.18 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary idle mode - 1 min
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IDLE_CASE, loop, idle_time, 1)
+
+ @test_tracker_info(uuid="53697dd9-a2f6-4eb5-8b2c-5c9f2a5417ad")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_idle_msim_4g_esim_4g_dds_sim1_2min(self, loop=1,
+ idle_time=120):
+ '''
+ 1.8.19 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service
+ Stationary idle mode - 2 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IDLE_CASE, loop, idle_time, 0)
+
+ @test_tracker_info(uuid="f329bb22-c74f-4688-9983-eaf88131a630")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_idle_msim_4g_esim_4g_dds_sim2_2min(self, loop=1,
+ idle_time=120):
+ '''
+ 1.8.20 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary idle mode - 2 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IDLE_CASE, loop, idle_time, 1)
+
+ @test_tracker_info(uuid="4d8cba59-921b-441c-94dc-8c43a12593ea")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_idle_msim_4g_esim_4g_dds_sim1_5min(self, loop=1,
+ idle_time=300):
+ '''
+ 1.8.21 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary idle mode - 5 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IDLE_CASE, loop, idle_time, 0)
+
+ @test_tracker_info(uuid="dfb3646f-b21f-41f4-a70b-f7ca93ff56ec")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_idle_msim_4g_esim_4g_dds_sim2_5min(self, loop=1,
+ idle_time=300):
+ '''
+ 1.8.22 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary idle mode - 5 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IDLE_CASE, loop, idle_time, 1)
+
+
+ @test_tracker_info(uuid="95e026e1-8f3e-4b9e-8d13-96a2d3be2d23")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_idle_msim_4g_esim_4g_dds_sim1_10min(self, loop=1,
+ idle_time=600):
+ '''
+ 1.8.23 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary idle mode - 10 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IDLE_CASE, loop, idle_time, 0)
+
+ @test_tracker_info(uuid="935ed9be-94ef-4f46-b742-4bfac16b876d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_idle_msim_4g_esim_4g_dds_sim2_10min(self, loop=1,
+ idle_time=600):
+ '''
+ 1.8.24 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary idle mode - 10 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IDLE_CASE, loop, idle_time, 1)
+
+
+ @test_tracker_info(uuid="919e478e-6ea4-4bdc-b7d8-0252c7fa1510")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_4g_esim_4g_dds_sim1_1min(
+ self, loop=20, idle_time=60):
+ '''
+ 1.8.25 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary data transfer - 1 min
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(DATA_TRANSFER_CASE, loop, idle_time, 0)
+
+ @test_tracker_info(uuid="0826b234-7619-4ad9-b1e9-81d4d7e51be4")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_4g_esim_4g_dds_sim2_1min(
+ self, loop=20, idle_time=60):
+ '''
+ 1.8.26 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary data transfer - 1 min
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(DATA_TRANSFER_CASE, loop, idle_time, 1)
+
+
+ @test_tracker_info(uuid="baf5a72d-2a44-416b-b50d-80a4e6d75373")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_4g_esim_4g_dds_sim1_2min(
+ self, loop=20, idle_time=120):
+ '''
+ 1.8.27 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary data transfer - 2 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(DATA_TRANSFER_CASE, loop, idle_time, 0)
+
+
+ @test_tracker_info(uuid="e74bbe30-6ced-4122-8088-3f7f7bcd35d1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_4g_esim_4g_dds_sim2_2min(
+ self, loop=20, idle_time=120):
+ '''
+ 1.8.28 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary data transfer - 2 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(DATA_TRANSFER_CASE, loop, idle_time, 1)
+
+
+ @test_tracker_info(uuid="d605bdc1-c262-424b-aa05-dd64db0f150d")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_4g_esim_4g_dds_sim1_5min(
+ self, loop=20, idle_time=300):
+ '''
+ 1.8.29 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary data transfer - 5 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(DATA_TRANSFER_CASE, loop, idle_time, 0)
+
+
+ @test_tracker_info(uuid="590f6292-c19e-44f9-9050-8e4ad6ef0047")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_4g_esim_4g_dds_sim2_5min(
+ self, loop=20, idle_time=300):
+ '''
+ 1.8.30 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary data transfer - 5 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(DATA_TRANSFER_CASE, loop, idle_time, 1)
+
+
+ @test_tracker_info(uuid="6d4c631d-d4b1-4974-bcf5-f63d655a43d8")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_4g_esim_4g_dds_sim1_10min(
+ self, loop=20, idle_time=600):
+ '''
+ 1.8.31 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary data transfer - 10 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(DATA_TRANSFER_CASE, loop, idle_time, 0)
+
+ @test_tracker_info(uuid="ec4c4b08-d306-4d95-af07-485953afe741")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_4g_esim_4g_dds_sim2_10min(
+ self, loop=20, idle_time=600):
+ '''
+ 1.8.32 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary data transfer - 10 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(DATA_TRANSFER_CASE, loop, idle_time, 1)
+
+
+
+ @test_tracker_info(uuid="9a3827bd-132b-42de-968d-802b7e2e22cc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_off_msim_4g_esim_4g_dds_sim1_1min(self, loop=50, idle_time=60):
+ '''
+ 1.8.33 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary data off - 1 min
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(DATA_OFF_CASE, loop, idle_time, 0)
+
+ @test_tracker_info(uuid="4c42e33b-188c-4c62-8def-f47c46a07555")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_off_msim_4g_esim_4g_dds_sim1_2min(self, loop=50, idle_time=120):
+ '''
+ 1.8.34 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary data off - 2 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(DATA_OFF_CASE, loop, idle_time, 0)
+
+ @test_tracker_info(uuid="d40ee1cb-0e63-43f4-8b45-6a3a9bc1fcaa")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_off_msim_4g_esim_4g_dds_sim1_5min(self, loop=10, idle_time=300):
+ '''
+ 1.8.35 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary data off - 5 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(DATA_OFF_CASE, loop, idle_time, dds_slot=0)
+
+
+ @test_tracker_info(uuid="a0bb09bf-36c2-45cc-91d3-5441fd90a2ee")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_off_msim_4g_esim_4g_dds_sim1_10min(self, loop=10, idle_time=600):
+ '''
+ 1.8.36 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary data off - 10 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(DATA_OFF_CASE, loop, idle_time, dds_slot=0)
+
+
+ @test_tracker_info(uuid="d267f0bb-427a-4bed-9d78-20dbc193588f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_in_call_msim_4g_esim_4g_dds_sim1_call_sim1_1min(self, loop=10, idle_time=60):
+ '''
+ 1.8.37 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall - 1 min
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IN_CALL_CASE, loop, idle_time, dds_slot=0,
+ voice_slot=0, sms_slot=0)
+
+ @test_tracker_info(uuid="f0fcfc8f-4867-4b3c-94b8-4b406fa4ce8f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_in_call_msim_4g_esim_4g_dds_sim2_call_sim2_1min(self, loop=10, idle_time=60):
+ '''
+ 1.8.38 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall - 1 min
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IN_CALL_CASE, loop, idle_time,
+ dds_slot=1, voice_slot=1, sms_slot=1)
+
+ @test_tracker_info(uuid="5f96c891-fdb3-4367-afba-539eeb57ff0f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_in_call_msim_4g_esim_4g_dds_sim1_call_sim1_2min(self, loop=10, idle_time=120):
+ '''
+ 1.8.39 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall - 2 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IN_CALL_CASE, loop, idle_time,
+ dds_slot=0, voice_slot=0, sms_slot=0)
+
+
+ @test_tracker_info(uuid="3920a8b7-492b-4bc4-9b3d-6d7df9861934")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_in_call_msim_4g_esim_4g_dds_sim2_call_sim2_2min(self, loop=10, idle_time=120):
+ '''
+ 1.8.40 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall - 2 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IN_CALL_CASE, loop, idle_time,
+ dds_slot=1, voice_slot=1, sms_slot=1)
+
+
+ @test_tracker_info(uuid="b8fac57b-fdf8-48e6-a51f-349a512d2df7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_in_call_msim_4g_esim_4g_dds_sim1_call_sim1_5min(self, loop=10, idle_time=300):
+ '''
+ 1.8.41 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall - 5 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IN_CALL_CASE, loop, idle_time,
+ dds_slot=0, voice_slot=0, sms_slot=0)
+
+ @test_tracker_info(uuid="0f0f7749-5cf8-4030-aae5-d28cb3a26d9b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_in_call_msim_4g_esim_4g_dds_sim2_call_sim2_5min(self, loop=10,
+ idle_time=300):
+ '''
+ 1.8.42 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall - 5 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IN_CALL_CASE, loop, idle_time,
+ dds_slot=1, voice_slot=1, sms_slot=1)
+
+
+ @test_tracker_info(uuid="53c8bc90-b9a6-46c7-a412-fe5b9f8df3c3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_in_call_msim_4g_esim_4g_dds_sim1_call_sim1_10min(self, loop=10,
+ idle_time=600):
+ '''
+ 1.8.43 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall - 10 mins
+ (1) SIM1 (pSIM): Carrier1, VoLTE
+ (2) SIM2 (eSIM): Carrier2, VoLTE
+ (3) DDS (Data preferred) on SIM1
+ (4) Call/SMS Preference: on SIM1
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IN_CALL_CASE, loop, idle_time,
+ dds_slot=0, voice_slot=0, sms_slot=0)
+
+ @test_tracker_info(uuid="cff1893e-ea14-4e32-83ae-9116ffd96da4")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_in_call_msim_4g_esim_4g_dds_sim2_call_sim2_10min(self, loop=10,
+ idle_time=600):
+ '''
+ 1.8.44 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall - 10 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(IN_CALL_CASE, loop, idle_time,
+ dds_slot=1, voice_slot=1, sms_slot=1)
+
+
+ @test_tracker_info(uuid="a73d70d2-d5dd-4901-8cfe-6e54bdd4ddc3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_call_data_msim_4g_esim_4g_dds_sim1_call_sim1_1min(self, loop=10,
+ idle_time=60):
+ '''
+ 1.8.45 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall + data transfer - 1 min
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(CALL_DATA_CASE, loop, idle_time,
+ dds_slot=0, voice_slot=0, sms_slot=0)
+
+
+ @test_tracker_info(uuid="6d331e0e-368d-4752-810c-ad497ccb0001")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_call_data_msim_4g_esim_4g_dds_sim2_call_sim2_1min(self, loop=10, idle_time=60):
+ '''
+ 1.8.46 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall + data transfer - 1 min
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(CALL_DATA_CASE, loop, idle_time,
+ dds_slot=1, voice_slot=1, sms_slot=1)
+
+
+
+ @test_tracker_info(uuid="2b4c5912-f654-45ad-8195-284c602c194f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_call_data_msim_4g_esim_4g_dds_sim1_call_sim1_2min(self, loop=10,
+ idle_time=120):
+ '''
+ 1.8.47 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall + data transfer - 2 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(CALL_DATA_CASE, loop, idle_time,
+ dds_slot=0, voice_slot=0, sms_slot=0)
+
+
+ @test_tracker_info(uuid="d0428b18-6c5b-42d9-96fd-423a0512b95e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_call_data_msim_4g_esim_4g_dds_sim2_call_sim2_2min(self, loop=10,
+ idle_time=120):
+ '''
+ 1.8.48 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall + data transfer - 2 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(CALL_DATA_CASE, loop, idle_time,
+ dds_slot=1, voice_slot=1, sms_slot=1)
+
+
+
+ @test_tracker_info(uuid="66b2ec18-d2f8-46b3-8626-0688f4f7c0dc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_call_data_msim_4g_esim_4g_dds_sim1_call_sim1_5min(self, loop=10,
+ idle_time=300):
+ '''
+ 1.8.49 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall + data transfer - 5 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(CALL_DATA_CASE, loop, idle_time,
+ dds_slot=0, voice_slot=0, sms_slot=0)
+
+
+ @test_tracker_info(uuid="4634689f-3ab5-4826-9057-668b0fe15402")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_call_data_msim_4g_esim_4g_dds_sim2_call_sim2_5min(self, loop=10,
+ idle_time=300):
+ '''
+ 1.8.50 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall + data transfer - 5 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(CALL_DATA_CASE, loop, idle_time,
+ dds_slot=1, voice_slot=1, sms_slot=1)
+
+
+ @test_tracker_info(uuid="5a097f66-dbd4-49d4-957c-d0e9584de36b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_call_data_msim_4g_esim_4g_dds_sim1_call_sim1_10min(self, loop=10,
+ idle_time=600):
+ '''
+ 1.8.51 - [DDS:SIM1][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall + data transfer - 10 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(CALL_DATA_CASE, loop, idle_time,
+ dds_slot=0, voice_slot=0, sms_slot=0)
+
+
+ @test_tracker_info(uuid="d99c0700-27b1-4b0c-881b-ccf908a70287")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_call_data_msim_4g_esim_4g_dds_sim2_call_sim2_10min(self, loop=10,
+ idle_time=600):
+ '''
+ 1.8.52 - [DDS:SIM2][SIM1:VoLTE, SIM2:VoLTE] In/Out service -
+ Stationary incall + data transfer - 10 mins
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: idle time at no service area
+ Returns:
+ True if pass; False if fail
+ '''
+ loop = self.user_params.get("4g_dsds_io_cycle", 1)
+ return self._dsds_in_out_service_test(CALL_DATA_CASE, loop, idle_time,
+ dds_slot=1, voice_slot=1, sms_slot=1)
\ No newline at end of file
diff --git a/acts_tests/tests/google/tel/lab/TelLabGFTDSDSTest.py b/acts_tests/tests/google/tel/lab/TelLabGFTDSDSTest.py
new file mode 100644
index 0000000..a0f0d3b
--- /dev/null
+++ b/acts_tests/tests/google/tel/lab/TelLabGFTDSDSTest.py
@@ -0,0 +1,465 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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
+import datetime
+from acts import asserts
+from acts.test_decorators import test_tracker_info
+
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.GFTInOutBaseTest import GFTInOutBaseTest
+from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_POWER_LEVEL
+from acts_contrib.test_utils.tel.gft_inout_defines import IN_SERVICE_POWER_LEVEL
+from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
+from acts_contrib.test_utils.tel.tel_data_utils import start_youtube_video
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_dsds_utils import dsds_voice_call_test
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
+
+
+_5G_VOLTE = "5g_volte"
+_VOLTE = "volte"
+_NO_SERVICE_TIME = 30
+_ERROR_MSG_DATA_TRANSFER_FAILURE = "_test_in_out_service_data_transfer failure"
+_ERROR_MSG_IDLE_FAILURE = "_test_in_out_service_idle failure"
+
+class TelLabGFTDSDSTest(GFTInOutBaseTest):
+ def __init__(self, controllers):
+ # requirs 2 android devices to run DSDS test
+ GFTInOutBaseTest.__init__(self, controllers)
+ self.tel_logger = TelephonyMetricLogger.for_test_case()
+ self.my_error_msg = ""
+
+ def teardown_test(self):
+ GFTInOutBaseTest.teardown_class(self)
+ ensure_phones_idle(self.log, self.android_devices)
+
+ @test_tracker_info(uuid="90ef8e20-64bb-4bf8-81b6-431de524f2af")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_msim_5g_esim_5g_dds_sim1(self, loop=1):
+ '''
+ 1.7.19 - [SA/NSA][DDS:SIM1][SIM1:5G, SIM2:5G]
+ Attach to 5G after in/out service during idle
+ SIM1 (pSIM) : Carrier 1 with 5G SIM.
+ SIM2 (eSIM) : Carrier 2 with 5G SIM.
+ DDS (Data preferred) on SIM1 and this slot has the 5G capability.
+
+ (1) Moves to no service area during data idle.
+ (2) Moves to service area.
+ (3) Makes a MOMT voice/VT call on SIM1.
+ (4) Makes a MOMT voice/VT call on SIM2.
+ (5) Starts streaming.
+ Args:
+ loop: repeat this test cases for how many times
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("dsds_io_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ asserts.assert_true(
+ self._test_in_out_service_idle(_5G_VOLTE, _5G_VOLTE, 0),
+ "[Fail]%s" % (_ERROR_MSG_IDLE_FAILURE),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+
+ @test_tracker_info(uuid="21b3ff34-e42a-4d42-ba98-87c510e83967")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_msim_5g_esim_5g_dds_sim2(self, loop=1):
+ '''
+ 1.7.20 [SA/NSA][DDS:SIM2][SIM1:5G, SIM2:5G]
+ Attach to 5G after in/out service during idle.
+ SIM1 (pSIM) : Carrier 1 with 5G SIM.
+ SIM2 (eSIM) : Carrier 2 with 5G SIM.
+ DDS (Data preferred) on SIM2
+
+ (1) Moves to no service area during data idle.
+ (2) Moves to service area.
+ (3) Makes a MOMT voice/VT call on SIM2.
+ (4) Makes a MOMT voice/VT call on SIM1.
+ (5) Starts streaming.
+
+ Args:
+ loop: repeat this test cases for how many times
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("dsds_io_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ asserts.assert_true(
+ self._test_in_out_service_idle(_5G_VOLTE, _5G_VOLTE, 1),
+ "[Fail]%s" % (_ERROR_MSG_IDLE_FAILURE),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+
+ @test_tracker_info(uuid="f1311823-e6e4-478e-a38d-2344389698b7")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_msim_4g_esim_5g_dds_sim1(self, loop=1):
+ '''
+ 1.7.21 - [SA/NSA][DDS:SIM1][SIM1:VoLTE, SIM2:5G]
+ Attach to 5G after in/out service during idle
+ SIM1 (pSIM) : Carrier 1 with 4G SIM or 5G SIM locks in 4G.
+ SIM2 (eSIM) : Carrier 2 with 5G SIM.
+ DDS (Data preferred) on SIM1.
+
+ (1) Move to no service area during data idle.
+ (2) Moves to service area.
+ (3) Makes a MOMT voice/VT call on SIM1.
+ (4) Makes a MOMT voice/VT call on SIM2.
+ (5) Starts streaming.
+
+ Args:
+ loop: repeat this test cases for how many times
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("dsds_io_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ asserts.assert_true(
+ self._test_in_out_service_idle(_VOLTE, _5G_VOLTE, 0),
+ "[Fail]%s" % (_ERROR_MSG_IDLE_FAILURE),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+
+ @test_tracker_info(uuid="7dc38fd5-741f-42b0-a476-3aa51610d184")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_msim_4g_esim_5g_dds_sim2(self, loop=1):
+ '''
+ 1.7.22 - [SA/NSA][DDS:SIM2][SIM1:VoLTE, SIM2:5G]
+ Attach to 5G after in/out service during idle
+ SIM1 (pSIM) : Carrier 1 with 4G SIM or 5G SIM locks in 4G.
+ SIM2 (eSIM) : Carrier 2 with 5G SIM.
+ DDS (Data preferred) on SIM2.
+
+ (1) Moves to no service area during data idle.
+ (2) Moves to service area.
+ (3) Makes a MOMT voice/VT call on SIM2.
+ (4) Makes a MOMT voice/VT call on SIM1.
+ (5) Starts streaming.
+
+ Args:
+ loop: repeat this test cases for how many times
+ Returns:
+ True if pass; False if fail
+ Raises:
+ TestFailure if not success.
+ '''
+ for x in range(self.user_params.get("dsds_io_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ asserts.assert_true(
+ self._test_in_out_service_idle(_VOLTE, _5G_VOLTE, 1),
+ "[Fail]%s" % (_ERROR_MSG_IDLE_FAILURE),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+ @test_tracker_info(uuid="a47cdaf6-87b6-416e-a0e4-ebdd2ec5f3f1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_msim_5g_esim_4g_dds_sim1(self, loop=1):
+ '''
+ 1.7.23 - [SA/NSA][DDS:SIM1][SIM1:5G, SIM2:VoLTE]
+ Attach to 5G after in/out service during idle
+ SIM1 (pSIM) : Carrier 1 with 5G SIM.
+ SIM2 (eSIM) : Carrier 2 with 4G SIM
+ DDS (Data preferred) on SIM1.
+
+ (1) Moves to no service area during data idle.
+ (2) Moves to service area.
+ (3) Makes a MOMT voice/VT call on SIM1.
+ (4) Makes a MOMT voice/VT call on SIM2.
+ (5) Starts streaming.
+
+ Args:
+ loop: repeat this test cases for how many times
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("dsds_io_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ asserts.assert_true(
+ self._test_in_out_service_idle(_5G_VOLTE, _VOLTE, 0),
+ "[Fail]%s" % (_ERROR_MSG_IDLE_FAILURE),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+
+ @test_tracker_info(uuid="5e2e3ce2-6d37-48dd-9007-6aa3f593150b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_msim_5g_esim_4g_dds_sim2(self, loop=1):
+ '''
+ 1.7.24 - [SA/NSA][DDS:SIM2][SIM1:5G, SIM2:VoLTE]
+ Attach to 5G after in/out service during idle
+ SIM1 (pSIM) : Carrier 1 with 5G SIM.
+ SIM2 (eSIM) : Carrier 2 with 4G SIM
+ DDS (Data preferred) on SIM1.
+
+ (1) Moves to no service area during data idle.
+ (2) Moves to service area.
+ (3) Makes a MOMT voice/VT call on SIM1.
+ (4) Makes a MOMT voice/VT call on SIM2.
+ (5) Starts streaming.
+
+ Args:
+ loop: repeat this test cases for how many times
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("dsds_io_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ asserts.assert_true(
+ self._test_in_out_service_idle(_5G_VOLTE, _VOLTE, 1),
+ "[Fail]%s" % (_ERROR_MSG_IDLE_FAILURE),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+
+ @test_tracker_info(uuid="51f291f0-af5f-400c-9678-4f129695bb68")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_5g_esim_5g_dds_sim1(self, loop=1):
+ '''
+ 1.7.25 - [SA/NSA][DDS:SIM1][SIM1:5G, SIM2:5G]
+ Attach to 5G after in/out service during data transferring
+ SIM1 (pSIM) : Carrier 1 with 5G SIM.
+ SIM2 (eSIM) : Carrier 2 with 5G SIM
+ DDS (Data preferred) on SIM1.
+
+ (1) Moves to no service area during data transferring..
+ (2) Moves to service area.
+ (3) Makes a MOMT voice/VT call on SIM1.
+ (4) Makes a MOMT voice/VT call on SIM2.
+ (5) Starts streaming.
+
+ Args:
+ loop: repeat this test cases for how many times
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("dsds_io_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ asserts.assert_true(
+ self._test_in_out_service_data_transfer(_5G_VOLTE, _5G_VOLTE, 0),
+ "[Fail]%s" % (_ERROR_MSG_DATA_TRANSFER_FAILURE),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+
+ @test_tracker_info(uuid="d0b134c5-380f-4c74-8ab9-8322de1c59e9")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_5g_esim_5g_dds_sim2(self, loop=1):
+ '''
+ 1.7.26 - [SA/NSA][DDS:SIM2][SIM1:5G, SIM2:5G]
+ Attach to 5G after in/out service during data transferring
+ SIM1 (pSIM) : Carrier 1 with 5G SIM.
+ SIM2 (eSIM) : Carrier 2 with 5G SIM
+ DDS (Data preferred) on SIM2.
+
+ (1) Moves to no service area during data transferring..
+ (2) Moves to service area.
+ (3) Makes a MOMT voice/VT call on SIM1.
+ (4) Makes a MOMT voice/VT call on SIM2.
+ (5) Starts streaming.
+
+ Args:
+ loop: repeat this test cases for how many times
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("dsds_io_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ asserts.assert_true(
+ self._test_in_out_service_data_transfer(_VOLTE, _5G_VOLTE, 1),
+ "[Fail]%s" % (_ERROR_MSG_DATA_TRANSFER_FAILURE),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+
+ @test_tracker_info(uuid="c28a9ea5-28a8-4d21-ba25-cb38aca30170")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_4g_esim_5g_dds_sim1(self, loop=1):
+ '''
+ 1.7.27 - [SA/NSA][DDS:SIM1][SIM1:VoLTE, SIM2:5G]
+ Attach to 5G after in/out service during data transferring
+ SIM1 (pSIM) : Carrier 1 with 4G SIM.
+ SIM2 (eSIM) : Carrier 2 with 5G SIM
+ DDS (Data preferred) on SIM1.
+
+ (1) Moves to no service area during data transferring..
+ (2) Moves to service area.
+ (3) Makes a MOMT voice/VT call on SIM1.
+ (4) Makes a MOMT voice/VT call on SIM2.
+ (5) Starts streaming.
+
+ Args:
+ loop: repeat this test cases for how many times
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("dsds_io_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ asserts.assert_true(
+ self._test_in_out_service_data_transfer(_VOLTE, _5G_VOLTE, 0),
+ "[Fail]%s" % (_ERROR_MSG_DATA_TRANSFER_FAILURE),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+
+ @test_tracker_info(uuid="c28a9ea5-28a8-4d21-ba25-cb38aca30170")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_4g_esim_5g_dds_sim2(self, loop=1):
+ '''
+ 1.7.28 - [SA/NSA][DDS:SIM2][SIM1:VoLTE, SIM2:5G]
+ Attach to 5G after in/out service during data transferring
+ SIM1 (pSIM) : Carrier 1 with 4G SIM.
+ SIM2 (eSIM) : Carrier 2 with 5G SIM
+ DDS (Data preferred) on SIM2.
+
+ (1) Moves to no service area during data transferring..
+ (2) Moves to service area.
+ (3) Makes a MOMT voice/VT call on SIM1.
+ (4) Makes a MOMT voice/VT call on SIM2.
+ (5) Start a download via speedtest lab mode.
+
+ Args:
+ loop: repeat this test cases for how many times
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("dsds_io_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ asserts.assert_true(
+ self._test_in_out_service_data_transfer(_VOLTE, _5G_VOLTE, 1),
+ "[Fail]%s" % (_ERROR_MSG_DATA_TRANSFER_FAILURE),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+ @test_tracker_info(uuid="7d6a85c0-0194-4705-8a80-49f21cebc4ed")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_5g_esim_4g_dds_sim1(self, loop=1):
+ '''
+ 1.7.29 - [SA/NSA][DDS:SIM1][SIM1:5G, SIM2:VoLTE]
+ Attach to 5G after in/out service during data transferring
+ SIM1 (pSIM) : Carrier 1 with 5G SIM.
+ SIM2 (eSIM) : Carrier 2 with 4G SIM
+ DDS (Data preferred) on SIM1.
+
+ (1) Move to no service area during data transferring..
+ (2) Move to service area.
+ (3) Make a MOMT voice/VT call on SIM1.
+ (4) Makes a MOMT voice/VT call on SIM2.
+ (5) Starts streaming.
+
+ Args:
+ loop: repeat this test cases for how many times
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("dsds_io_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ asserts.assert_true(
+ self._test_in_out_service_data_transfer(_5G_VOLTE, _VOLTE, 0),
+ "[Fail]%s" % (_ERROR_MSG_DATA_TRANSFER_FAILURE),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+
+ @test_tracker_info(uuid="43cd405f-d510-4193-9bff-795db12dbb30")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_data_transfer_msim_5g_esim_4g_dds_sim2(self, loop=1):
+ '''
+ 1.7.30 - [SA/NSA][DDS:SIM2][SIM1:5G, SIM2:VoLTE]
+ Attach to 5G after in/out service during data transferring
+ SIM1 (pSIM) : Carrier 1 with 5G SIM.
+ SIM2 (eSIM) : Carrier 2 with 4G SIM
+ DDS (Data preferred) on SIM2.
+
+ (1) Move to no service area during data transferring..
+ (2) Move to service area.
+ (3) Make a MOMT voice/VT call on SIM1.
+ (4) Make a MOMT voice/VT call on SIM2.
+ (5) start streaming.
+
+ Args:
+ loop: repeat this test cases for how many times
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("dsds_io_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ asserts.assert_true(
+ self._test_in_out_service_data_transfer(_5G_VOLTE, _VOLTE, 1),
+ "[Fail]%s" % (_ERROR_MSG_DATA_TRANSFER_FAILURE),
+ extras={"failure_cause": self.my_error_msg})
+ return True
+
+
+ def _test_in_out_service_idle(self, psim_rat=_5G_VOLTE , esim_rat=_5G_VOLTE,
+ dds_slot=0, momt_direction="mo"):
+ ad = self.android_devices[0]
+ set_dds_on_slot(ad, dds_slot)
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(_NO_SERVICE_TIME)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ return self._test_mo_voice_call(psim_rat, esim_rat, dds_slot, momt_direction)
+
+
+ def _test_in_out_service_data_transfer(self, psim_rat=_5G_VOLTE , esim_rat=_5G_VOLTE,
+ dds_slot=0, momt_direction="mo"):
+ ad = self.android_devices[0]
+ set_dds_on_slot(ad, dds_slot)
+ # start streaming
+ if not start_youtube_video(ad):
+ ad.log.warning("Fail to bring up youtube video")
+ time.sleep(10)
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(_NO_SERVICE_TIME)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ return self._test_mo_voice_call(psim_rat, esim_rat, dds_slot, momt_direction)
+
+ def _test_mo_voice_call(self, psim_rat=_5G_VOLTE , esim_rat=_5G_VOLTE,
+ dds_slot =0, momt_direction="mo"):
+ ad = self.android_devices[0]
+ # Make a MOMT voice on SIM1
+ test_result = dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 0,
+ None,
+ dds_slot,
+ mo_rat=[psim_rat, esim_rat],
+ call_direction=momt_direction)
+ ensure_phones_idle(self.log, self.android_devices)
+ # Make a MOMT voice on SIM2
+ test_result = dsds_voice_call_test(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
+ 1,
+ None,
+ dds_slot,
+ mo_rat=[psim_rat, esim_rat],
+ call_direction=momt_direction)
+ # start streaming
+ if not start_youtube_video(ad):
+ ad.log.warning("Fail to bring up youtube video")
+ time.sleep(10)
+ return test_result
\ No newline at end of file
diff --git a/acts_tests/tests/google/tel/lab/TelLabGFTInOutServiceTest.py b/acts_tests/tests/google/tel/lab/TelLabGFTInOutServiceTest.py
index 5f04fff..9694749 100644
--- a/acts_tests/tests/google/tel/lab/TelLabGFTInOutServiceTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabGFTInOutServiceTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2021 - The Android Open Source Project
+# Copyright 2022 - 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.
@@ -13,57 +13,27 @@
# 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
-import datetime
-import logging
-
from acts import asserts
-from acts.test_decorators import test_info
from acts.test_decorators import test_tracker_info
-
-from acts.base_test import BaseTestClass
+from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.GFTInOutBaseTest import GFTInOutBaseTest
-
-from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import run_multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_log
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_logs
-from acts_contrib.test_utils.tel.tel_test_utils import log_screen_shot
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
-
-from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
-from acts_contrib.test_utils.tel.gft_inout_utils import check_no_service_time
-from acts_contrib.test_utils.tel.gft_inout_utils import check_back_to_service_time
-from acts_contrib.test_utils.tel.gft_inout_utils import mo_voice_call
-from acts_contrib.test_utils.tel.gft_inout_utils import get_voice_call_type
-
-from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
-from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_DISCONNECTED
-from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_EMERGENCY_ONLY
-from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
-from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_UNKNOWN
-from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_OUT_OF_SERVICE
-from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_POWER_OFF
-
from acts_contrib.test_utils.tel.gft_inout_defines import VOICE_CALL
from acts_contrib.test_utils.tel.gft_inout_defines import VOLTE_CALL
from acts_contrib.test_utils.tel.gft_inout_defines import CSFB_CALL
-from acts_contrib.test_utils.tel.gft_inout_defines import WFC_CALL
from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_POWER_LEVEL
from acts_contrib.test_utils.tel.gft_inout_defines import IN_SERVICE_POWER_LEVEL
-from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_AREA
-from acts_contrib.test_utils.tel.gft_inout_defines import IN_SERVICE_AREA
-from acts_contrib.test_utils.tel.gft_inout_defines import WIFI_AREA
-from acts_contrib.test_utils.tel.gft_inout_defines import NO_WIFI_AREA
-from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_TIME
-from acts_contrib.test_utils.tel.gft_inout_defines import WAIT_FOR_SERVICE_TIME
-
+from acts_contrib.test_utils.tel.gft_inout_utils import check_no_service_time
+from acts_contrib.test_utils.tel.gft_inout_utils import check_back_to_service_time
+from acts_contrib.test_utils.tel.gft_inout_utils import mo_voice_call
+from acts_contrib.test_utils.tel.gft_inout_utils import check_ims_state
+from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
IDLE_CASE = 1
DATA_TRANSFER_CASE = 2
@@ -71,29 +41,30 @@
IN_CALL_CASE = 4
CALL_DATA_CASE = 5
+
class TelLabGFTInOutServiceTest(GFTInOutBaseTest):
def __init__(self, controllers):
GFTInOutBaseTest.__init__(self, controllers)
self.my_error_msg = ""
def setup_test(self):
+ self.check_network()
self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ for ad in self.android_devices:
+ ad.droid.wifiToggleState(False)
GFTInOutBaseTest.setup_test(self)
self.check_network()
self.my_error_msg = ""
-
@test_tracker_info(uuid="c602e556-8273-4c75-b8fa-4d51ba514654")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_no_service_idle_1min(self, idle_time=60):
""" UE is in idle
Move UE from coverage area to no service area and UE shows no service
Wait for 1 min, then re-enter coverage area
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
@@ -105,49 +76,38 @@
""" UE is in idle
Move UE from coverage area to no service area and UE shows no service
Wait for 2 min, then re-enter coverage area
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time)
-
-
@test_tracker_info(uuid="1d437482-caff-4695-9f3f-f3daf6793540")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_no_service_idle_5min(self, idle_time=300):
""" UE is in idle
Move UE from coverage area to no service area and UE shows no service
Wait for 5 min, then re-enter coverage area
-
Args:
loop: cycle
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time)
-
@test_tracker_info(uuid="339b4bf5-57a1-48f0-b26a-83a7db21b08b")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_no_service_idle_10min(self, idle_time=600):
""" UE is in idle
Move UE from coverage area to no service area and UE shows no service
Wait for 10 min, then re-enter coverage area
-
Args:
loop: cycle
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time)
-
-
@test_tracker_info(uuid="65ebac02-8d5a-48c2-bd26-6d931d6048f1")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_no_service_data_transfer_1min(self, idle_time=60):
@@ -155,171 +115,125 @@
UE is performing data transfer (E.g. Use FTP or browse tools)
move UE from coverage area to no service area and UE shows no service
Wait for 1 min, then re-enter coverage area
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, DATA_TRANSFER_CASE)
-
-
@test_tracker_info(uuid="ec3e7de4-bcf6-4a8a-ae04-868bd7925191")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_no_service_data_transfer_2min(self, idle_time=120):
""" In/Out service - Stationary data transfer - 2 min
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, DATA_TRANSFER_CASE)
-
-
@test_tracker_info(uuid="8bd7017d-0a88-4423-a94b-1e37060bba1d")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_no_service_data_transfer_5min(self, idle_time=300):
""" In/Out service - Stationary data transfer - 5 min
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, DATA_TRANSFER_CASE)
-
-
@test_tracker_info(uuid="c3b9c52d-41d3-449c-99ff-4bb830ca0219")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_no_service_data_transfer_10min(self, idle_time=600):
""" In/Out service - Stationary data transfer - 10 min
-
Args:
idle_time: idle time in service area
file_name: download filename
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, DATA_TRANSFER_CASE)
-
-
@test_tracker_info(uuid="86a6b3b3-e754-4bde-b418-d4273b1ad907")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_service_incall_1min(self, idle_time=60):
""" In/Out service - Stationary incall - 1 min
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, IN_CALL_CASE)
-
-
@test_tracker_info(uuid="0f8772cd-6f86-48eb-b583-4cbaf80a21a9")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_service_incall_2min(self, idle_time=120):
""" In/Out service - Stationary incall - 2 min
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, IN_CALL_CASE)
-
-
@test_tracker_info(uuid="11f24c0f-db33-4eb3-b847-9aed447eb820")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_service_incall_5min(self, idle_time=300):
""" In/Out service - Stationary incall - 5 min
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, IN_CALL_CASE)
-
-
@test_tracker_info(uuid="e318921b-de6b-428b-b2c4-3db7786d7558")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_service_incall_10min(self, idle_time=600):
""" In/Out service - Stationary incall - 10 min
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, IN_CALL_CASE)
-
-
@test_tracker_info(uuid="f6cf0019-e123-4ebd-990b-0fa5b236840c")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_service_call_date_1min(self, idle_time=60):
""" In/Out service - Stationary incall + data transfer - 1 mins
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, CALL_DATA_CASE)
-
-
@test_tracker_info(uuid="2f49a9de-0383-4ec6-a8ee-c62f52ea0cf2")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_service_call_date_2min(self, idle_time=120):
""" In/Out service - Stationary incall + data transfer - 2 mins
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, CALL_DATA_CASE)
-
-
@test_tracker_info(uuid="73a6eedb-791f-4486-b815-8067a95efd5c")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_service_call_date_5min(self, idle_time=300):
""" In/Out service - Stationary incall + data transfer - 5 mins
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, CALL_DATA_CASE)
-
@test_tracker_info(uuid="5cfbc90a-97e1-43e9-a69e-4ce2815c544d")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_service_call_date_10min(self, idle_time=600):
""" In/Out service - Stationary incall + data transfer - 10 mins
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, CALL_DATA_CASE)
-
@test_tracker_info(uuid="c70180c9-5a36-4dc5-9ccc-3e6c0b5e6d37")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_service_pdp_off_1min(self, idle_time=60):
@@ -327,59 +241,43 @@
Disable UE mobile data
Move UE from coverage area to no service area and UE shows no service
Wait for 1 min, then re-enter coverage area
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, PDP_OFF_CASE)
-
@test_tracker_info(uuid="50cc8e73-d96f-45a6-91cd-bf51de5241d2")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_service_pdp_off_2min(self, idle_time=120):
""" In/Out service - Stationary data off - 2 min
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, PDP_OFF_CASE)
-
-
@test_tracker_info(uuid="1f25d40c-1bfe-4d18-b57c-d7be69664f0d")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_service_pdp_off_5min(self, idle_time=300):
""" In/Out service - Stationary data off - 5 min
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, PDP_OFF_CASE)
-
-
@test_tracker_info(uuid="b076b0d0-a105-4be9-aa0b-db0d782f70f2")
@TelephonyBaseTest.tel_test_wrap
def test_in_out_service_pdp_off_10min(self, idle_time=600):
""" In/Out service - Stationary data off - 10 min
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
return self._test_in_out_service_idle(idle_time, PDP_OFF_CASE)
-
-
-
def _test_in_out_service_idle(self, idle_time, case= IDLE_CASE, loop=1):
""" UE is in idle
Move UE from coverage area to no service area and UE shows no service
@@ -394,7 +292,6 @@
test_result = True
if 'autoio_cycle' in self.user_params:
loop = self.user_params.get('autoio_cycle')
-
for x in range (loop):
self.log.info("%s loop: %s/%s" %(self.current_test_name,x+1, loop))
if case == IDLE_CASE:
@@ -416,22 +313,23 @@
extras={"failure_cause": self.my_error_msg})
return test_result
-
def _in_out_service_idle_only(self, no_service_time=60, check_back_to_service=True,
check_no_service=True):
""" Move UE from coverage area to no service area and UE shows no service
Wait for no_service_time sec , then re-enter coverage area
-
Args:
no_service_time: stay at no service area time in sec
check_back_to_service: check device is back to service flag
check_no_service: check device is no service flag
-
Returns:
True if pass; False if fail.
"""
test_result = True
error_msg = ""
+ if 'check_no_service' in self.user_params:
+ loop = self.user_params.get('check_no_service')
+ if 'check_back_to_service' in self.user_params:
+ loop = self.user_params.get('check_back_to_service')
for ad in self.android_devices:
network_type = ad.droid.telephonyGetNetworkType()
service_state = get_service_state_by_adb(self.log,ad)
@@ -442,10 +340,8 @@
ad.log.info("Device is not ready for test. Service_state=%s." %(service_state))
self.my_error_msg += error_msg
return False
-
self.log.info("Move UE from coverage area to no service area")
self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
-
if check_no_service:
tasks = [(check_no_service_time, (ad, )) for ad in self.android_devices]
if not multithread_func(self.log, tasks):
@@ -465,11 +361,9 @@
def _data_transfer_mode(self, idle_time, file_name="10MB"):
""" Download file and in/out service
-
Args:
idle_time: stay at no service area time in sec
file_name: file to be download
-
Returns:
True if pass; False if fail.
"""
@@ -482,7 +376,6 @@
error_msg = " data transfer fail. "
self.my_error_msg += error_msg
self.log.info(error_msg)
- return False
return self._check_after_no_service()
def _in_out_service_pdp_off(self, idle_time):
@@ -491,10 +384,8 @@
Move UE from coverage area to no/limited service area
enable UE mobile data
After UE show no service, re-enter coverage area
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
@@ -505,10 +396,8 @@
if not wait_for_cell_data_connection(self.log, ad, False):
self.my_error_msg += "fail to turn off mobile data"
return False
-
if not self._in_out_service_idle_only(idle_time, False):
return False
-
for ad in self.android_devices:
ad.log.info("Turn on mobile data")
ad.droid.telephonyToggleDataConnection(True)
@@ -522,10 +411,8 @@
""" UE is in call
Move UE from coverage area to no/limited service area
After UE show no service, re-enter coverage area
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
@@ -536,7 +423,6 @@
self.my_error_msg += error_msg
self.log.info(error_msg)
return False
-
if not self._in_out_service_idle_only(idle_time, False):
return False
return self._check_after_no_service()
@@ -546,10 +432,8 @@
UE makes a MO call
Move UE from coverage area to no/limited service area
After UE show no service, re-enter coverage area
-
Args:
idle_time: idle time in service area
-
Returns:
True if pass; False if fail.
"""
@@ -560,14 +444,12 @@
error_msg = "fail to perfrom data transfer/voice call"
self.my_error_msg += error_msg
return False
-
if not self._in_out_service_idle_only(idle_time, False):
return False
return self._check_after_no_service()
def _check_after_no_service(self):
""" check device is back to service or not
-
Returns:
True if pass; False if fail.
"""
@@ -578,3 +460,283 @@
self.log.info(error_msg)
return False
return True
+
+
+ @test_tracker_info(uuid="4b8fee71-0d9b-4355-b175-84ea3c2a222a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_ID_1_1_5_ims_on_off(self, loop=1):
+ '''
+ 1.1.5 - In/Out service - IMS on -> no service
+ -> service area -> IMS off
+
+ Args:
+ loop: repeat this test cases for how many times
+
+ Returns:
+ True if pass; False if fail
+ Raises:
+ TestFailure if not success.
+ '''
+ error_msg = ""
+ test_result = True
+ if 'ims_cycle' in self.user_params:
+ loop = self.user_params.get('ims_cycle')
+
+ for x in range (loop):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.my_error_msg += "cylce%s: " %(x+1)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+
+ self.log.info("Turn on IMS")
+ tasks = [(toggle_volte, (self.log, ad, True)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("fail to toggle volte, ")
+ return False
+
+ tasks = [(check_ims_state, (ad, )) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("ims is not register, ")
+ return False
+
+ self.log.info("Move to no service area")
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(60)
+
+ self.log.info("Turn off IMS")
+ tasks = [(toggle_volte, (self.log, ad, False)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("fail to toggle volte, ")
+ return False
+ self.log.info("Move back to service area and verify device status")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ tasks = [(self.verify_device_status, (ad, VOICE_CALL))
+ for ad in self.android_devices]
+ test_result = multithread_func(self.log, tasks)
+ if not test_result:
+ self._on_fail("verify_device_status fail, ")
+ return False
+ if not test_result:
+ asserts.assert_true(test_result, "[Fail]%s" %(error_msg),
+ extras={"failure_cause": error_msg})
+ return test_result
+
+
+ @test_tracker_info(uuid="6b963676-fd28-4626-ad54-e1aa04274a37")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_ID_1_1_6_ims_on_off(self, loop=1):
+ '''
+ 1.1.6 - In/Out service - IMS on -> Enter no service area
+ -> service area -> IMS off
+
+ Args:
+ loop: repeat this test cases for how many times
+
+ Returns:
+ True if pass; False if fail
+ '''
+ error_msg = ""
+ test_result = True
+ if 'ims_cycle' in self.user_params:
+ loop = self.user_params.get('ims_cylce')
+
+ for x in range (loop):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.my_error_msg += "cylce%s: " %(x+1)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+
+ tasks = [(check_ims_state, (ad, )) for ad in self.android_devices]
+ multithread_func(self.log, tasks)
+
+ self.log.info("Turn on IMS")
+ tasks = [(toggle_volte, (self.log, ad, True)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("fail to toggle volte, ")
+ return False
+
+ tasks = [(check_ims_state, (ad, )) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("ims is not register, ")
+ return False
+
+ self.log.info("Move to no service area")
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(60)
+
+ self.log.info("Move back to service area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.log.info("Turn off IMS")
+ tasks = [(toggle_volte, (self.log, ad, False)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("fail to toggle volte, ")
+ return False
+ tasks = [(self.verify_device_status, (ad, VOICE_CALL))
+ for ad in self.android_devices]
+ test_result = multithread_func(self.log, tasks)
+ if not test_result:
+ self._on_fail( "verify_device_status fail, ")
+ return False
+ return test_result
+
+ @test_tracker_info(uuid="640db83f-6ba8-4df5-9c8c-dcf52a1904a1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_ID_1_1_7_ims_on_off(self, loop=1):
+ '''
+ 1.1.7 - In/Out service - IMS off
+ -> IMS on under no service area -> Back service area
+
+ Args:
+ loop: repeat this test cases for how many times
+
+ Returns:
+ True if pass; False if fail
+ '''
+ error_msg = ""
+ test_result = True
+ if 'ims_cycle' in self.user_params:
+ loop = self.user_params.get('ims_cylce')
+
+ for x in range (loop):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.my_error_msg += "cylce%s: " %(x+1)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+
+ tasks = [(check_ims_state, (ad, )) for ad in self.android_devices]
+ multithread_func(self.log, tasks)
+
+ self.log.info("Turn off IMS")
+ tasks = [(toggle_volte, (self.log, ad, False)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("fail to toggle volte, ")
+ return False
+
+ tasks = [(check_ims_state, (ad, )) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("ims is not register, ")
+ return False
+
+ self.log.info("CSFB call in service area")
+ tasks = [(mo_voice_call, (self.log, ad, CSFB_CALL, True, 30))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("csfb_call_fail, ")
+ return False
+
+ self.log.info("Move to no service area then turn on IMS")
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(60)
+ tasks = [(toggle_volte, (self.log, ad, True)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("fail to toggle volte, ")
+ return False
+
+ self.log.info("Move back to service area and verify device status, VOLTE call")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ tasks = [(self.verify_device_status, (ad, VOLTE_CALL))
+ for ad in self.android_devices]
+ test_result = multithread_func(self.log, tasks)
+ if not test_result:
+ self._on_fail( "verify_device_status fail, ")
+ return False
+ return test_result
+
+
+ @test_tracker_info(uuid="fcb72af6-b9d0-4911-9819-79abc58d5213")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_ID_1_1_8_ims_on_off(self, loop=1, sleepTimer=15):
+ '''
+ 1.1.8 - In/Out service - IMS off -> Enter no service area
+ -> service area -> IMS on
+
+ Args:
+ loop: repeat this test cases for how many times
+
+ Returns:
+ True if pass; False if fail
+ Raises:
+ TestFailure if not success.
+ '''
+ error_msg = ""
+ test_result = True
+ if 'ims_cycle' in self.user_params:
+ loop = self.user_params.get('ims_cylce')
+
+ for x in range (loop):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.my_error_msg += "cylce%s: " %(x+1)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+
+ tasks = [(check_ims_state, (ad, )) for ad in self.android_devices]
+ multithread_func(self.log, tasks)
+
+ self.log.info("Turn off IMS")
+ tasks = [(toggle_volte, (self.log, ad, False)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("fail to toggle volte ")
+ return False
+
+ tasks = [(check_ims_state, (ad, )) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("ims is not register, ")
+ return False
+
+ self.log.info("CSFB call in service area")
+ tasks = [(mo_voice_call, (self.log, ad, CSFB_CALL, true, 30))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("csfb_call_fail, ")
+ return False
+
+ self.log.info("Move to no service area")
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(60)
+ self.log.info("Move back to service area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.log.info("Turn on ims")
+ tasks = [(toggle_volte, (self.log, ad, True)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self._on_fail("fail to toggle volte ")
+ return False
+ self.log.info("Verify device status, VOLTE call")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ tasks = [(self.verify_device_status, (ad, VOLTE_CALL))
+ for ad in self.android_devices]
+ test_result = multithread_func(self.log, tasks)
+ if not test_result:
+ self._on_fail("verify_device_status fail, ")
+ return False
+ return test_result
+
+
+ @test_tracker_info(uuid="36250121-fe44-4953-ba9f-b806d7bb0e28")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_ID_1_1_49_in_out_service_dialing(self, loop=1):
+ '''
+ 1.1.49 - In/Out service - Stationary dialing stage
+
+ Args:
+ loop: repeat this test cases for how many times
+
+ Returns:
+ True if pass; False if fail
+ '''
+ error_msg = ""
+ test_result = True
+ if 'autoio_cycle' in self.user_params:
+ loop = self.user_params.get('autoio_cycle')
+
+ for x in range (loop):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.my_error_msg += "cylce%s: " %(x+1)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ for ad in self.android_devices:
+ ad.log.info("initiate voice call to %s " %(ad.mt_phone_number))
+ ad.droid.telecomCallNumber(ad.mt_phone_number)
+ self.log.info("Move to no service area")
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(30)
+ tasks = [(hangup_call, (self.log, ad)) for ad in self.android_devices]
+ multithread_func(self.log, tasks)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ if not self._check_after_no_service():
+ return False
+ return test_result
diff --git a/acts_tests/tests/google/tel/lab/TelLabGFTModemConnectivityHelperTest.py b/acts_tests/tests/google/tel/lab/TelLabGFTModemConnectivityHelperTest.py
index 295590a..8c51b34 100644
--- a/acts_tests/tests/google/tel/lab/TelLabGFTModemConnectivityHelperTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabGFTModemConnectivityHelperTest.py
@@ -33,15 +33,14 @@
from acts_contrib.test_utils.tel.GFTInOutBaseTest import GFTInOutBaseTest
from acts.controllers.android_device import DEFAULT_QXDM_LOG_PATH
from acts.controllers.android_device import DEFAULT_SDM_LOG_PATH
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import run_multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
from acts.test_decorators import test_tracker_info
from acts.logger import epoch_to_log_line_timestamp
from acts.utils import get_current_epoch_time
+from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_POWER_LEVEL
from acts_contrib.test_utils.tel.gft_inout_defines import IN_SERVICE_POWER_LEVEL
diff --git a/acts_tests/tests/google/tel/lab/TelLabGFTVoWifiStressTest.py b/acts_tests/tests/google/tel/lab/TelLabGFTVoWifiStressTest.py
new file mode 100644
index 0000000..db02fa2
--- /dev/null
+++ b/acts_tests/tests/google/tel/lab/TelLabGFTVoWifiStressTest.py
@@ -0,0 +1,375 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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 collections
+import time
+import random
+import logging
+from acts import asserts
+from acts import signals
+from acts.test_decorators import test_tracker_info
+from acts.libs.utils.multithread import multithread_func
+from acts.utils import get_current_epoch_time
+
+from acts_contrib.test_utils.tel.tel_atten_utils import set_rssi
+from acts_contrib.test_utils.tel.tel_defines import SignalStrengthContainer
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.GFTInOutBaseTest import GFTInOutBaseTest
+from acts_contrib.test_utils.tel.gft_inout_defines import VOLTE_CALL
+from acts_contrib.test_utils.tel.gft_inout_defines import WFC_CALL
+from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_POWER_LEVEL
+from acts_contrib.test_utils.tel.gft_inout_defines import IN_SERVICE_POWER_LEVEL
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.wifi import wifi_power_test_utils as wputils
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_ims_registered
+from acts_contrib.test_utils.tel.tel_logging_utils import log_screen_shot
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_logging_utils import start_sdm_loggers
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc
+from acts_contrib.test_utils.tel.tel_ims_utils import is_wfc_enabled
+from acts_contrib.test_utils.tel.gft_inout_utils import mo_voice_call
+
+WAIT_TIME_AT_NO_SERVICE_AREA = 300
+
+
+class TelLabGFTVoWifiStressTest(GFTInOutBaseTest):
+
+ def __init__(self, controllers):
+ GFTInOutBaseTest.__init__(self, controllers)
+ self.wifi_ssid = self.user_params.get('wifi_network_ssid')
+ self.wifi_pw = self.user_params.get('wifi_network_pw')
+ self.my_error_msg = ""
+ self.rssi = ""
+ logging.info("wifi_ssid = %s" %self.wifi_ssid)
+ logging.info("wifi_pw = %s" %self.wifi_pw )
+
+ def setup_test(self):
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ GFTInOutBaseTest.setup_test(self)
+ for ad in self.android_devices:
+ ad.droid.wifiToggleState(True)
+ ad.droid.telephonyStartTrackingSignalStrengthChange()
+ # Ensure IMS on
+ self.log.info("Turn on ims")
+ tasks = [(phone_setup_volte, (self.log, ad, )) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ for ad in self.android_devices:
+ log_screen_shot(ad, self.test_name)
+ error_msg = "fail to setup volte"
+ self.log.error(error_msg)
+ # ensure WFC is enabled
+ tasks = [(toggle_wfc, (self.log, ad,True)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ for ad in self.android_devices:
+ log_screen_shot(ad, self.test_name)
+ error_msg = "device does not support WFC!"
+ self.log.error(error_msg)
+
+
+ def teardown_test(self):
+ super().teardown_test()
+ tasks = [(toggle_airplane_mode, (self.log, ad, False))
+ for ad in self.android_devices]
+ multithread_func(self.log, tasks)
+ for ad in self.android_devices:
+ ad.droid.telephonyStopTrackingSignalStrengthChange()
+
+ def _check_signal_strength(self):
+ """
+ check cellular signal strength
+ """
+ for ad in self.android_devices:
+ # SIGNAL_STRENGTH_LTE = "lteSignalStrength"
+ # SIGNAL_STRENGTH_LTE_DBM = "lteDbm"
+ # SIGNAL_STRENGTH_LTE_LEVEL = "lteLevel"
+ result = ad.droid.telephonyGetSignalStrength()
+ ad.log.info("lteDbm: {}".format(result[SignalStrengthContainer.
+ SIGNAL_STRENGTH_LTE_DBM]))
+ ad.log.info("lteSignalStrength: {}".format(result[SignalStrengthContainer.
+ SIGNAL_STRENGTH_LTE]))
+ ad.log.info("ltelevel: {}".format(result[SignalStrengthContainer.
+ SIGNAL_STRENGTH_LTE_LEVEL]))
+
+ @TelephonyBaseTest.tel_test_wrap
+ def test_wifi_cellular_signal(self, wfc_mode=WFC_MODE_WIFI_PREFERRED):
+ """
+ check WiFi and cellular signal
+
+ Args:
+ wfc_mode: wfc mode
+
+ Returns:
+ True if pass; False if fail
+ """
+ tasks = [(phone_setup_iwlan, (self.log, ad, False, wfc_mode,
+ self.wifi_ssid)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ error_msg = "fail to setup WFC mode to %s" %(wfc_mode)
+ self.log.error(error_msg)
+ cellular_power_level = 0
+ wifi_power_level = 0
+ for x in range(20):
+ self.adjust_cellular_signal(cellular_power_level)
+ self.adjust_wifi_signal(wifi_power_level)
+ time.sleep(5)
+ for ad in self.android_devices:
+ log_screen_shot(ad)
+ wifi_rssi = wputils.get_wifi_rssi(ad)
+ ad.log.info("wifi_power_level to %s , wifi_rssi=%s"
+ %(wifi_power_level, wifi_rssi))
+ cellular_power_level += 5
+ wifi_power_level += 5
+ self._check_signal_strength()
+ return True
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="176a0230-c35d-454d-a1f7-c706f71c5dbd")
+ def test_wfc_marginal_area_random_stress(self, wfc_mode=WFC_MODE_WIFI_PREFERRED):
+ """
+ b/213907614 marginal area with random
+ Adjusts WiFi and cellular signal randomly
+
+ Args:
+ wfc_mode: wfc mode
+
+ Returns:
+ True if pass; False if fail
+ """
+ fail_count = collections.defaultdict(int)
+ loop = self.user_params.get("marginal_cycle", 5)
+ error_msg = ""
+ self.log.info("Start test at cellular and wifi area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ self.check_network()
+ tasks = [(phone_setup_iwlan, (self.log, ad, False, wfc_mode,
+ self.wifi_ssid)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ error_msg = "fail to setup WFC mode to %s" %(wfc_mode)
+ fail_count["fail_to_setup_WFC_mode"] += 1
+ iteration_result = False
+ self.log.error(error_msg)
+
+ for i in range(1, loop + 1):
+ msg = "Stress Test %s Iteration: <%s> / <%s>" % (
+ self.test_name, i, loop)
+ begin_time = get_current_epoch_time()
+ self.log.info(msg)
+ iteration_result = True
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, i, loop))
+
+ self.log.info("Randomly adjust wifi and cellular signal")
+ for x in range (1):
+ cellular_power_level = random.randint(30, 50)
+ wifi_power_level = random.randint(5, 30)
+ self.log.info("adjust wifi power level to %s"%wifi_power_level )
+ self.log.info("adjust cellular power level to %s" %cellular_power_level)
+ self.adjust_wifi_signal(wifi_power_level)
+ self.adjust_cellular_signal(cellular_power_level)
+ time.sleep(10)
+ self._check_signal_strength()
+ for ad in self.android_devices:
+ log_screen_shot(ad)
+ wifi_rssi = wputils.get_wifi_rssi(ad)
+ ad.log.info("wifi_power_level to %s , wifi_rssi=%s"
+ %(wifi_power_level, wifi_rssi))
+ self.log.info("check ims status")
+ tasks = [(wait_for_ims_registered, (self.log, ad, ))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ error_msg = "Fail: IMS is not registered"
+ fail_count["IMS_is_not_registered"] += 1
+ iteration_result = False
+ self.log.error("%s:%s", msg, error_msg)
+ tasks = [(is_wfc_enabled, (self.log, ad, ))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.log.info("WiFi Calling feature bit is False.")
+ self.log.info("Set call_type to VOLTE_CALL")
+ call_type = VOLTE_CALL
+ else:
+ self.log.info("Set call_type to WFC_CALL")
+ call_type = WFC_CALL
+ if not self._voice_call(self.android_devices, call_type, end_call=True):
+ self.log.info("voice call failure")
+ tasks = [(self.verify_device_status, (ad, call_type, True,
+ 30, True, True)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ error_msg = "Verify_device_status fail"
+ fail_count["verify_device_status_fail"] += 1
+ iteration_result = False
+ self.log.error("%s:%s", msg, error_msg)
+ self.log.info("%s %s", msg, iteration_result)
+
+ if not iteration_result:
+ self._take_bug_report("%s_No_%s" % (self.test_name, i), begin_time)
+ if self.sdm_log:
+ start_sdm_loggers(self.log, self.android_devices)
+ else:
+ start_qxdm_loggers(self.log, self.android_devices)
+ test_result = True
+ for failure, count in fail_count.items():
+ if count:
+ self.log.error("%s: %s %s failures in %s iterations",
+ self.test_name, count, failure, loop)
+ test_result = False
+ return test_result
+
+
+ @TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="111d5810-bc44-4873-b18c-265afa283d34")
+ def test_wfc_marginal_area_cellcular_good_stress(self,
+ wfc_mode=WFC_MODE_WIFI_PREFERRED):
+ """
+ b/213907614
+ Keeps cellular signal good and adjust WiFi signal slowly
+
+ Args:
+ wfc_mode: wfc mode
+ Returns:
+ True if pass; False if fail
+ """
+ loop = self.user_params.get("marginal_cycle", 5)
+ fail_count = collections.defaultdict(int)
+ error_msg = ""
+
+ self.log.info("Start test at cellular and wifi area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ self.check_network()
+ tasks = [(phone_setup_iwlan, (self.log, ad, False, wfc_mode,
+ self.wifi_ssid)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ error_msg = "fail to setup WFC mode to %s" %(wfc_mode)
+ fail_count["fail_to_setup_WFC_mode"] += 1
+ iteration_result = False
+ # self.log.error("%s:%s", msg, error_msg)
+ self.log.error(error_msg)
+
+ for i in range(1, loop + 1):
+ msg = "Stress Test %s Iteration: <%s> / <%s>" % (
+ self.test_name, i, loop)
+ begin_time = get_current_epoch_time()
+ self.log.info(msg)
+ iteration_result = True
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, i, loop))
+
+ self.log.info("Move to poor wifi area slowly")
+ wifi_power_level = 5
+ for x in range (5):
+ self.log.info("adjust wifi power level to %s" %wifi_power_level)
+ self.adjust_wifi_signal(wifi_power_level)
+ time.sleep(5)
+ self._check_signal_strength()
+ self.log.info("check ims status")
+ tasks = [(wait_for_ims_registered, (self.log, ad, ))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ error_msg = "Fail: IMS is not registered"
+ fail_count["IMS_is_not_registered"] += 1
+ iteration_result = False
+ self.log.error("%s:%s", msg, error_msg)
+ tasks = [(is_wfc_enabled, (self.log, ad, ))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.log.info("WiFi Calling feature bit is False.")
+ self.log.info("Set call_type tp VOLTE_CALL")
+ call_type = VOLTE_CALL
+ else:
+ self.log.info("Set call_type to WFC_CALL")
+ call_type = WFC_CALL
+ if not self._voice_call(self.android_devices, call_type, end_call=True):
+ error_msg = "Fail: voice call failure"
+ fail_count["voice_call_failure"] += 1
+ iteration_result = False
+ self.log.error("%s:%s", msg, error_msg)
+ wifi_power_level += 5
+ self.log.info("Move back to wifi area slowly")
+ for x in range (5):
+ self.log.info("adjust wifi power level to %s" %wifi_power_level)
+ self.adjust_wifi_signal(wifi_power_level)
+ time.sleep(5)
+ self._check_signal_strength()
+ for ad in self.android_devices:
+ wifi_rssi = wputils.get_wifi_rssi(ad)
+ ad.log.info("wifi_power_level to %s , wifi_rssi=%s"
+ %(wifi_power_level, wifi_rssi))
+ self.log.info("check ims status")
+ tasks = [(wait_for_ims_registered, (self.log, ad, ))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ error_msg = "Fail: IMS is not registered"
+ fail_count["IMS_is_not_registered"] += 1
+ iteration_result = False
+ self.log.error("%s:%s", msg, error_msg)
+ tasks = [(is_wfc_enabled, (self.log, ad, ))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.log.info("WiFi Calling feature bit is False.")
+ self.log.info("Set call_type to VOLTE_CALL")
+ call_type = VOLTE_CALL
+ else:
+ self.log.info("Set call_type to WFC_CALL")
+ call_type = WFC_CALL
+ if not self._voice_call(self.android_devices, call_type,
+ end_call=True):
+ error_msg = "voice call failure"
+ fail_count["voice_call_failure"] += 1
+ iteration_result = False
+ self.log.error("%s:%s", msg, error_msg)
+ wifi_power_level -=5
+
+ self.log.info("%s %s", msg, iteration_result)
+ if not iteration_result:
+ self._take_bug_report("%s_No_%s" % (self.test_name, i), begin_time)
+ if self.sdm_log:
+ start_sdm_loggers(self.log, self.android_devices)
+ else:
+ start_qxdm_loggers(self.log, self.android_devices)
+ test_result = True
+ for failure, count in fail_count.items():
+ if count:
+ self.log.error("%s: %s %s failures in %s iterations",
+ self.test_name, count, failure, loop)
+ test_result = False
+ return test_result
+
+
+ def _voice_call(self, ads, call_type, end_call=True, talk_time=15):
+ """ Enable Wi-Fi calling in Wi-Fi Preferred mode and connect to a
+ valid Wi-Fi AP.
+ Args:
+ ads: android devices
+ call_type: WFC call, VOLTE call. CSFB call, voice call
+ end_call: hangup call after voice call flag
+ talk_time: in call duration in sec
+ Returns:
+ True if pass; False if fail.
+ """
+ tasks = [(mo_voice_call, (self.log, ad, call_type, end_call, talk_time))
+ for ad in ads]
+ if not multithread_func(self.log, tasks):
+ error_msg = "%s failure" %(call_type)
+ self.log.error(error_msg)
+ self.my_error_msg += error_msg
+ return False
+ return True
\ No newline at end of file
diff --git a/acts_tests/tests/google/tel/lab/TelLabGFTVoWifiTest.py b/acts_tests/tests/google/tel/lab/TelLabGFTVoWifiTest.py
index ae5cb21..35305a0 100644
--- a/acts_tests/tests/google/tel/lab/TelLabGFTVoWifiTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabGFTVoWifiTest.py
@@ -14,107 +14,116 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import sys
-import collections
-import random
+
+
import time
-import datetime
-import os
import logging
-import json
-import subprocess
-import math
-import re
-
from acts import asserts
+from acts import signals
from acts.test_decorators import test_tracker_info
-
-from acts.base_test import BaseTestClass
+from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.GFTInOutBaseTest import GFTInOutBaseTest
-
-
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_wfc
-
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import run_multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_log
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_logs
-from acts_contrib.test_utils.tel.tel_test_utils import log_screen_shot
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-
-from acts_contrib.test_utils.tel.gft_inout_utils import check_no_service_time
-from acts_contrib.test_utils.tel.gft_inout_utils import check_back_to_service_time
-from acts_contrib.test_utils.tel.gft_inout_utils import mo_voice_call
-from acts_contrib.test_utils.tel.gft_inout_utils import get_voice_call_type
-
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
-
+from acts_contrib.test_utils.tel.tel_atten_utils import set_rssi
from acts_contrib.test_utils.tel.gft_inout_defines import VOICE_CALL
from acts_contrib.test_utils.tel.gft_inout_defines import VOLTE_CALL
from acts_contrib.test_utils.tel.gft_inout_defines import CSFB_CALL
from acts_contrib.test_utils.tel.gft_inout_defines import WFC_CALL
+from acts_contrib.test_utils.tel.gft_inout_defines import NO_VOICE_CALL
from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_POWER_LEVEL
from acts_contrib.test_utils.tel.gft_inout_defines import IN_SERVICE_POWER_LEVEL
-from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_AREA
-from acts_contrib.test_utils.tel.gft_inout_defines import IN_SERVICE_AREA
-from acts_contrib.test_utils.tel.gft_inout_defines import WIFI_AREA
-from acts_contrib.test_utils.tel.gft_inout_defines import NO_WIFI_AREA
from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_TIME
from acts_contrib.test_utils.tel.gft_inout_defines import WAIT_FOR_SERVICE_TIME
+from acts_contrib.test_utils.tel.gft_inout_utils import check_back_to_service_time
+from acts_contrib.test_utils.tel.gft_inout_utils import mo_voice_call
+from acts_contrib.test_utils.tel.gft_inout_utils import get_voice_call_type
+from acts_contrib.test_utils.tel.gft_inout_utils import browsing_test_ping_retry
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
+from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_ACTIVE
+from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_HOLDING
+from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_ims_registered
+from acts_contrib.test_utils.tel.tel_logging_utils import log_screen_shot
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.gft_inout_utils import verify_data_connection
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
WAIT_TIME_AT_NO_SERVICE_AREA = 300
+
class TelLabGFTVoWifiTest(GFTInOutBaseTest):
+
def __init__(self, controllers):
GFTInOutBaseTest.__init__(self, controllers)
self.wifi_ssid = self.user_params.get('wifi_network_ssid')
self.wifi_pw = self.user_params.get('wifi_network_pw')
+ self.my_error_msg = ""
+ self.rssi = ""
+ logging.info("wifi_ssid = %s" %self.wifi_ssid)
+ logging.info("wifi_pw = %s" %self.wifi_pw )
def setup_test(self):
self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
GFTInOutBaseTest.setup_test(self)
+ for ad in self.android_devices:
+ ad.droid.wifiToggleState(True)
+ # Ensure IMS on
+ self.log.info("Turn on ims")
+ tasks = [(phone_setup_volte, (self.log, ad, )) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ for ad in self.android_devices:
+ log_screen_shot(ad, self.test_name)
+ error_msg = "fail to setup volte"
+ self.log.error(error_msg)
+ asserts.assert_true(False, "Fail: %s." %(error_msg),
+ extras={"failure_cause": self.my_error_msg})
+ asserts.skip(error_msg)
+ # ensure WFC is enabled
tasks = [(toggle_wfc, (self.log, ad,True)) for ad in self.android_devices]
if not multithread_func(self.log, tasks):
- msg = "device does not support WFC! Skip test"
- self.log.info(msg)
- asserts.skip(msg)
- for ad in self.android_devices:
- log_screen_shot(ad, self.test_name)
+ for ad in self.android_devices:
+ log_screen_shot(ad, self.test_name)
+ error_msg = "device does not support WFC! Skip test"
+ asserts.skip(error_msg)
- @test_tracker_info(uuid="c0e74803-44ac-4a6b-be7e-2d1337ee4521")
+
+ def teardown_test(self):
+ super().teardown_test()
+ tasks = [(toggle_airplane_mode, (self.log, ad, False))
+ for ad in self.android_devices]
+ multithread_func(self.log, tasks)
+
+
+ @test_tracker_info(uuid="21ec1aff-a161-4dc9-9682-91e0dd8a13a7")
@TelephonyBaseTest.tel_test_wrap
def test_wfc_in_out_wifi(self, loop=1, wfc_mode=WFC_MODE_WIFI_PREFERRED):
"""
Enable Wi-Fi calling in Wi-Fi Preferred mode and connect to a
valid Wi-Fi AP. Test VoWiFi call under WiFi and cellular area
-> move to WiFi only area -> move to Cellular only area
-
Args:
loop: repeat this test cases for how many times
wfc_mode: wfc mode
-
Returns:
True if pass; False if fail
"""
test_result = True
- if 'wfc_cycle' in self.user_params:
- loop = self.user_params.get('wfc_cycle')
-
- for x in range (loop):
+ for x in range(self.user_params.get("wfc_cycle", 1)):
self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
self.log.info("Start test at cellular and wifi area")
self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
self.check_network()
if self._enable_wifi_calling(wfc_mode):
- if not self._voice_call(self.android_devices, WFC_CALL, False):
+ if not self._voice_call(self.android_devices, WFC_CALL, end_call=True):
self.log.info("VoWiFi call failure")
return False
self.log.info("Move to no service area and wifi area")
@@ -126,6 +135,12 @@
self.log.info("Move back to service area and no wifi area")
self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
self.adjust_wifi_signal(NO_SERVICE_POWER_LEVEL)
+ self.log.info("check cellular data")
+ # self._data_retry_mechanism()
+ tasks = [(verify_data_connection, (ad, 3))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.log.info("verify_data_connection failure")
self.log.info("Verify device state after in-out service")
tasks = [(check_back_to_service_time, (ad,)) for ad in self.android_devices]
test_result = multithread_func(self.log, tasks)
@@ -135,42 +150,1200 @@
self.log.info("device is not back to service")
return test_result
- def _enable_wifi_calling(self, wfc_mode):
+ def _enable_wifi_calling(self, wfc_mode, call_type=NO_VOICE_CALL,
+ end_call=True, is_airplane_mode=False, talk_time=30):
""" Enable Wi-Fi calling in Wi-Fi Preferred mode and connect to a
valid Wi-Fi AP.
Args:
wfc_mode: wfc mode
+ call_type: None would not make any calls
+ end_call: hang up call
+ is_airplane_mode: toggle airplane mode on or off
+ talk_time: call duration
Returns:
True if pass; False if fail.
"""
- self.log.info("Move in WiFi area and set WFC mode to %s" %(wfc_mode))
+ self.log.info("Move in WiFi area and set WFC mode to %s, airplane mode=%s"
+ %(wfc_mode, is_airplane_mode))
self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
time.sleep(10)
- tasks = [(set_wfc_mode, (self.log, ad, wfc_mode)) for ad in self.android_devices]
+ tasks = [(phone_setup_iwlan, (self.log, ad, is_airplane_mode, wfc_mode,
+ self.wifi_ssid))
+ for ad in self.android_devices]
if not multithread_func(self.log, tasks):
- self.log.error("fail to setup WFC mode %s" %(wfc_mode))
- return False
- tasks = [(ensure_wifi_connected, (self.log, ad, self.wifi_ssid,
- self.wifi_pw)) for ad in self.android_devices]
- if not multithread_func(self.log, tasks):
- self.log.error("phone failed to connect to wifi.")
- return False
+ self.my_error_msg += "fail to setup WFC mode to %s, " %(wfc_mode)
+ raise signals.TestFailure(self.my_error_msg)
+ if call_type != NO_VOICE_CALL:
+ if not self._voice_call(self.android_devices, call_type, end_call, talk_time):
+ self.log.error("%s failuer" %call_type)
+ return False
return True
- def _voice_call(self, ads, call_type, end_call=True, talk_time=30):
+ def _voice_call(self, ads, call_type, end_call=True, talk_time=15):
""" Enable Wi-Fi calling in Wi-Fi Preferred mode and connect to a
valid Wi-Fi AP.
-
Args:
ads: android devices
call_type: WFC call, VOLTE call. CSFB call, voice call
end_call: hangup call after voice call flag
talk_time: in call duration in sec
-
Returns:
True if pass; False if fail.
"""
- tasks = [(mo_voice_call, (self.log, ad, call_type, end_call, talk_time)) for ad in self.android_devices]
- return multithread_func(self.log, tasks)
\ No newline at end of file
+ tasks = [(mo_voice_call, (self.log, ad, call_type, end_call, talk_time))
+ for ad in ads]
+ if not multithread_func(self.log, tasks):
+ error_msg = "%s failure" %(call_type)
+ self.log.error(error_msg)
+ self.my_error_msg += error_msg
+ return False
+ return True
+
+ @test_tracker_info(uuid="3ca05651-a6c9-4b6b-84c0-a5d761757061")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_idle_wifi_preferred(self, wfc_mode=WFC_MODE_WIFI_PREFERRED):
+ ''' In/Out Service - Idle + VoWiFi registered in Wi-Fi Preferred mode
+ Enable Wi-Fi calling in Wi-Fi Preferred mode and connect to a valid Wi-Fi AP.
+ Idle in service area.
+ Move to no service area for 1 minute when idle.
+ Move back to service area and verfiy device status.
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wfc mode
+
+ Returns:
+ True if pass; False if fail
+ Raises:
+ TestFailure if not success.
+ '''
+ return self._in_out_wifi_wfc_mode(1, wfc_mode)
+
+
+ @test_tracker_info(uuid="b06121de-f458-4fc0-b9ef-efac02e46181")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_idle_cellular_preferred(self, loop=1,wfc_mode=WFC_MODE_CELLULAR_PREFERRED):
+ ''' In/Out Service - Idle + VoLTE registered in Cellular preferred mode
+ Enable Wi-Fi calling in Cellular preferred mode and connect to a valid Wi-Fi AP.
+ Idle in service area.
+ Move to no service area for 1 minute when idle.
+ Move back to service area and verify device status
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wfc mode
+
+ Returns:
+ True if pass; False if fail
+ Raises:
+ TestFailure if not success.
+ '''
+ asserts.assert_true(self._in_out_wifi_wfc_mode(1, WFC_MODE_CELLULAR_PREFERRED),
+ "Fail: %s." %(self.my_error_msg), extras={"failure_cause": self.my_error_msg})
+
+ def _in_out_wifi_wfc_mode(self, loop=1, wfc_mode=WFC_MODE_CELLULAR_PREFERRED):
+ error_msg = ""
+ test_result = True
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.my_error_msg += "cylce%s: " %(x+1)
+ self.log.info("Move in Wi-Fi area and set to %s" %(wfc_mode))
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ if not self._enable_wifi_calling(wfc_mode):
+ error_msg = "Fail to setup WFC mode"
+ self.log.info(error_msg)
+ self.my_error_msg += error_msg
+ return False
+ self.log.info("Idle in service area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.check_network()
+
+ self.log.info("Move to no service area in idle mode for 1 min")
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(NO_SERVICE_TIME)
+
+ self.log.info("Move back to service area and verify device status")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.log.info("Verify device status after in-out service")
+ tasks = [(check_back_to_service_time, (ad,)) for ad in self.android_devices]
+ test_result = multithread_func(self.log, tasks)
+ if test_result:
+ tasks = [(self.verify_device_status, (ad, VOICE_CALL))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ error_msg = "verify_device_status fail, "
+ self.log.info(error_msg)
+ else:
+ error_msg = "device is not back to service, "
+ self.log.info(error_msg)
+ self.my_error_msg += error_msg
+ return test_result
+
+ @test_tracker_info(uuid="95bf5006-4ff6-4e7e-a02d-156e6b43f129")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_wifi_apm_on(self):
+ '''
+ 1.1.4 In/Out Service - Idle + VoWiFi registered in Airplane on
+ + Wi-Fi on in default mode
+
+ Returns:
+ True if pass; False if fail
+ Raises:
+ TestFailure if not success.
+ '''
+ asserts.assert_true(self._ID_1_1_4_in_out_vowifi(1, 180), "Fail: %s."
+ %(self.my_error_msg), extras={"failure_cause": self.my_error_msg})
+ asserts.assert_true(self._ID_1_1_4_in_out_vowifi(1, 60), "Fail: %s."
+ %(self.my_error_msg), extras={"failure_cause": self.my_error_msg})
+ return True
+
+ def _ID_1_1_4_in_out_vowifi(self, loop=1, idle_time=60):
+ '''
+ 1.1.4 In/Out Service - Idle + VoWiFi registered in Airplane on
+ + Wi-Fi on in default mode
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: at no service area
+
+ Returns:
+ True if pass; False if fail
+ '''
+ error_msg = ""
+ test_result = True
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.my_error_msg += "cylce%s: " %(x+1)
+ self.log.info("Enable Wi-Fi calling in Airplane on")
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+
+ ad = self.android_devices[0]
+ wfc_mode = ad.droid.imsGetWfcMode()
+ tasks = [(phone_setup_iwlan, (self.log, ad, True, wfc_mode, self.wifi_ssid))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.my_error_msg += "fail to setup WFC mode to %s, " %(wfc_mode)
+ raise signals.TestFailure(self.my_error_msg)
+ self.log.info("idle in service area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ time.sleep(10)
+ self.log.info("Move to no service area for %s sec" %(idle_time))
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(idle_time)
+
+ self.log.info("Move back to service area and verify device status")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.log.info("Verify device status after in-out service")
+ tasks = [(check_back_to_service_time, (ad,)) for ad in self.android_devices]
+ test_result = multithread_func(self.log, tasks)
+ if test_result:
+ tasks = [(self.verify_device_status, (ad, VOICE_CALL))
+ for ad in self.android_devices]
+ test_result = multithread_func(self.log, tasks)
+ if not test_result:
+ error_msg = "verify_device_status fail, "
+ else:
+ error_msg = "device is not back to service, "
+ self.log.info(error_msg)
+ return test_result
+
+
+ def _device_status_check(self, call_type=None, end_call=True,
+ talk_time=30, verify_data=True, verify_voice=True):
+ '''
+ Check device status
+ Args:
+ ad: android device
+ call_type: WFC call, VOLTE call. CSFB call, voice call
+ end_call: hangup call after voice call flag
+ talk_time: in call duration in sec
+ verify_data: flag to check data connection
+ verify_voice: flag to check voice
+ Returns:
+ True if pass; False if fail
+ '''
+ tasks = [(check_back_to_service_time, (ad,))
+ for ad in self.android_devices]
+ if multithread_func(self.log, tasks):
+ tasks = [(self.verify_device_status, (ad, call_type, end_call,
+ talk_time, verify_data, verify_voice)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.my_error_msg += "Verify_device_status fail, "
+ return False
+ else:
+ self.my_error_msg += "device is not back to service, "
+ return False
+ return True
+
+ def _move_in_out_wifi_cellular_area(self, cellular_power_level,
+ wifi_power_level, hangup=False):
+ '''
+ Moves in out wifi/cellular area
+
+ Args:
+ cellular_power_level: cellular power level
+ wifi_power_level: wifi power level
+
+ Raises:
+ TestFailure if not success.
+
+ Returns:
+ True if pass; False if fail
+ '''
+ self.adjust_cellular_signal(cellular_power_level)
+ self.adjust_wifi_signal(wifi_power_level)
+ time.sleep(WAIT_FOR_SERVICE_TIME)
+ tasks = [(wait_for_ims_registered, (self.log, ad, ))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ return False
+ if hangup:
+ for ad in self.android_devices:
+ hangup_call(self.log, ad)
+ time.sleep(3)
+ return True
+
+ @test_tracker_info(uuid="7d308a3e-dc01-4bc1-b986-14f6adc9d2ed")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_hand_in_out_vowifi_incall (self, loop=1, wfc_mode = WFC_MODE_WIFI_PREFERRED):
+ '''1.2.17 - [Wi-Fi Preferred] Hand In/Out while VoWiFi incall
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wfc mode
+
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ test_result = True
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Start test at wifi area and no service area")
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ if not self._enable_wifi_calling(wfc_mode, call_type=WFC_CALL,
+ end_call=False):
+ self.log.info("WFC call failure")
+ test_result = False
+ self.log.info("Move out Wi-Fi area to VoLTE area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(WAIT_FOR_SERVICE_TIME)
+ self.log.info("check cellular data")
+ # self._data_retry_mechanism()
+ tasks = [(verify_data_connection, (ad, 3))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.log.info("verify_data_connection failure")
+ for ad in self.android_devices:
+ hangup_call(self.log, ad)
+ # Make a MO VoLTE call and verify data connection
+ if not self._voice_call(self.android_devices, VOLTE_CALL, False):
+ self.log.info("VOLTE call failure")
+ test_result = False
+ #Move back to Wi-Fi area during incall.
+ self.log.info("Move back to Wi-Fi area during incall.")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ time.sleep(WAIT_FOR_SERVICE_TIME)
+ for ad in self.android_devices:
+ hangup_call(self.log, ad)
+ # check device status
+ test_result = self._device_status_check()
+ return test_result
+
+
+ @test_tracker_info(uuid="9dda069f-068c-47c8-b9e1-2b1a0f3a6bdd")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_hand_in_out_vowifi_incall_stress_ims_on(self, loop=1,
+ wfc_mode=WFC_MODE_WIFI_PREFERRED):
+ '''
+ 1.2.18 - [Wi-Fi Preferred] Hand In/Out while VoWiFi incall
+ - Stress, IMS on
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wfc mode
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ test_result = True
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Start test at wifi area and service area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ if not self._enable_wifi_calling(wfc_mode, call_type=WFC_CALL,
+ end_call=False):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+ # Move out Wi-Fi area to VoLTE area during incall.
+ self.log.info("Move out Wi-Fi area to VoLTE area")
+ if not self._move_in_out_wifi_cellular_area(
+ IN_SERVICE_POWER_LEVEL,NO_SERVICE_POWER_LEVEL):
+ raise signals.TestFailure("ims is not registered: %s"
+ %(self.my_error_msg))
+ self.log.info("Move back to Wi-Fi area")
+ if not self._move_in_out_wifi_cellular_area(
+ IN_SERVICE_POWER_LEVEL, IN_SERVICE_POWER_LEVEL, True):
+ raise signals.TestFailure("ims is not registered: %s"
+ %(self.my_error_msg))
+ if not self._device_status_check():
+ raise signals.TestFailure(self.my_error_msg)
+ return test_result
+
+
+ @test_tracker_info(uuid="e3633a6b-425a-4e4f-a58c-2d6aea56ec96")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_hand_in_out_vowifi_incall_stress_ims_off(self, loop=1,
+ wfc_mode = WFC_MODE_WIFI_PREFERRED):
+ '''
+ [Wi-Fi Preferred] Hand In/Out while VoWiFi incall -
+ Hand In/Out stress, IMS on - Hand In/Out, IMS off
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wfc mode
+
+ Raises:
+ TestFailure if not success.
+
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ tasks = [(toggle_volte, (self.log, ad, False))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("fail to turn off IMS: %s"
+ %(self.my_error_msg))
+ self.log.info("Start test at wifi area and service area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ if not self._enable_wifi_calling(wfc_mode, call_type=WFC_CALL,
+ end_call=False):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+ #Move out Wi-Fi area to VoLTE area during incall.
+ self.log.info("Move out Wi-Fi area to VoLTE area")
+ self._move_in_out_wifi_cellular_area(
+ IN_SERVICE_POWER_LEVEL, IN_SERVICE_POWER_LEVEL)
+ time.sleep(3)
+ #Make a MO CSFB call "
+ if not self._voice_call(self.android_devices, CSFB_CALL, False):
+ raise signals.TestFailure("CSFB call failure: %s"
+ %(self.my_error_msg))
+ #Move back to Wi-Fi area during incall.
+ self.log.info("Move to WiFi only area and no VoLTE area")
+ self._move_in_out_wifi_cellular_area(NO_SERVICE_POWER_LEVEL,
+ IN_SERVICE_POWER_LEVEL, True)
+ if not self._device_status_check():
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+
+
+ @test_tracker_info(uuid="1f0697e5-6798-4cb1-af3f-c246cac59a40")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_rove_in_out_ims_on_cellular_preferred(self, loop=1,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED):
+ '''
+ [Cellular Preferred] Rove In/Out when idle - IMS on
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wfc mode
+
+ Raises:
+ TestFailure if not success.
+
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("roveinout_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Move in Wi-Fi area in cellular preferred mode")
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ time.sleep(10)
+ if not self._enable_wifi_calling(wfc_mode, call_type=VOLTE_CALL,
+ end_call=False):
+ raise signals.TestFailure("VoLTE call failure: %s"
+ %(self.my_error_msg))
+
+ self.log.info("Move out Wi-Fi area to VoLTE area")
+ self.adjust_wifi_signal(NO_SERVICE_POWER_LEVEL)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ time.sleep(WAIT_FOR_SERVICE_TIME)
+ self.log.info("check cellular data")
+ # self._data_retry_mechanism()
+ tasks = [(verify_data_connection, (ad, 3))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.log.info("verify_data_connection failure")
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ tasks = [(wait_for_ims_registered, (self.log, ad, )) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("IMS is not registered: %s"
+ %(self.my_error_msg))
+ if not self._device_status_check():
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+
+ @test_tracker_info(uuid="89690d28-e21e-4baf-88cf-be04675b764b")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_rove_in_out_ims_on_wifi_preferred(self, loop=1, wfc_mode=WFC_MODE_WIFI_PREFERRED):
+ ''' 1.2.154 - [Wi-Fi Preferred] Rove In/Out when idle - IMS on
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wfc mode
+
+ Raises:
+ TestFailure if not success.
+
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("roveinout_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Move in Wi-Fi area in wifi preferred mode")
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ time.sleep(10)
+ if not self._enable_wifi_calling(wfc_mode, call_type=WFC_CALL,
+ end_call=False):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+
+ self.log.info("Move out Wi-Fi area to VoLTE area when idle.")
+ self.adjust_wifi_signal(NO_SERVICE_POWER_LEVEL)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+
+ tasks = [(wait_for_ims_registered, (self.log, ad, ))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("IMS is not registered: %s"
+ %(self.my_error_msg))
+ self.log.info("check cellular data")
+ # self._data_retry_mechanism()
+ tasks = [(verify_data_connection, (ad, 3))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.log.info("verify_data_connection failure")
+ self.log.info("Move back to Wi-Fi area when idle.")
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+
+ tasks = [(wait_for_ims_registered, (self.log, ad, ))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("IMS is not registered: %s"
+ %(self.my_error_msg))
+ if not self._device_status_check():
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+
+ @test_tracker_info(uuid="cd453193-4769-4fa5-809c-a6afb1d833c3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_rove_in_out_ims_off_wifi_preferred(self, loop=1, wfc_mode=WFC_MODE_WIFI_PREFERRED):
+ ''' [Wi-Fi Preferred] Rove In/Out when idle - IMS off
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wfc mode
+
+ Raises:
+ TestFailure if not success.
+
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("roveinout_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Turn off IMS")
+ tasks = [(toggle_volte, (self.log, ad, False))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("fail to turn off IMS: %s"
+ %(self.my_error_msg))
+ self.log.info("Move in Wi-Fi area in wifi preferred mode")
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ time.sleep(10)
+ if not self._enable_wifi_calling(wfc_mode, call_type=WFC_CALL,
+ end_call=False):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+
+ self.log.info("Move out Wi-Fi area to VoLTE area when idle.")
+ self.adjust_wifi_signal(NO_SERVICE_POWER_LEVEL)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+
+ tasks = [(wait_for_ims_registered, (self.log, ad, ))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("IMS is not registered: %s"
+ %(self.my_error_msg))
+ self.log.info("check cellular data")
+ # self._data_retry_mechanism()
+ tasks = [(verify_data_connection, (ad, 3))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.log.info("verify_data_connection failure")
+ self.log.info("Move back to Wi-Fi area when idle.")
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+
+ tasks = [(wait_for_ims_registered, (self.log, ad, ))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("IMS is not registered: %s"
+ %(self.my_error_msg))
+ if not self._device_status_check():
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+
+ @test_tracker_info(uuid="2632e594-3715-477b-b905-405ac8e490a9")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_vowifi_airplane_mode_on(self):
+ '''
+ Enable Wi-Fi calling in Airplane on + Wi-Fi on in default mode and
+ connect to a valid Wi-Fi AP.
+ Make a MO VoWiFi call in service area.
+ Move to no service area for 1 minute during incall.
+ Move back to service area
+
+ Returns:
+ True if pass; False if fail
+ Raises:
+ TestFailure if not success.
+ '''
+ asserts.assert_true(self._ID_1_1_11_vowifi_airplane_mode_on(1, 60),
+ "Fail: %s." %(self.my_error_msg), extras={"failure_cause": self.my_error_msg})
+ asserts.assert_true(self._ID_1_1_11_vowifi_airplane_mode_on(1, 180),
+ "Fail: %s." %(self.my_error_msg), extras={"failure_cause": self.my_error_msg})
+ return True
+
+ def _ID_1_1_11_vowifi_airplane_mode_on(self, loop=1, idle_time=60):
+ '''
+ 1.1.11 - In/Out Service - VoWiFi incall in Airplane on + Wi-Fi on in default mode
+
+ Args:
+ loop: repeat this test cases for how many times
+ idle_time: at no service area
+
+ Returns:
+ True if pass; False if fail
+ '''
+ error_msg = ""
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.my_error_msg += "cylce%s: " %(x+1)
+ self.log.info("idle in service area")
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ # Make a MO VoWiFi call in service area.
+ self.log.info("Enable Wi-Fi calling in Airplane on")
+ ad = self.android_devices[0]
+ wfc_mode = ad.droid.imsGetWfcMode()
+ tasks = [(phone_setup_iwlan, (self.log, ad, True, wfc_mode, self.wifi_ssid))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.my_error_msg += "fail to setup WFC mode to %s, " %(wfc_mode)
+ raise signals.TestFailure(self.my_error_msg)
+ self.log.info("Move to no service area for %s sec" %(idle_time))
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(idle_time)
+ self.log.info("Move back to service area and verify device status")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ if not self._device_status_check():
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+
+ @test_tracker_info(uuid="2b1f19c5-1214-41bd-895f-86987f1cf2b5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_vowifi_call_wifi_preferred(self, loop=1 ,wfc_mode=WFC_MODE_WIFI_PREFERRED):
+ '''
+ In/Out Service - VoWiFi incall in Wi-Fi Preferred mode
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wifi prefer mode
+
+ Returns:
+ True if pass; False if fail
+ Raises:
+ TestFailure if not success.
+ '''
+ for x in range(self.user_params.get("roveinout_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Start test at cellular and wifi area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ self.check_network()
+ if not self._enable_wifi_calling(wfc_mode, call_type=WFC_CALL,
+ end_call=False):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(WAIT_FOR_SERVICE_TIME)
+ # check call status
+ for ad in self.android_devices:
+ get_voice_call_type(ad)
+ self.log.info("Move back to service area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.log.info("Verify device state after in-out service")
+ if not self._device_status_check():
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+
+
+ @test_tracker_info(uuid="63dfa017-8bdb-4c61-a29e-7c347982a5ac")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_volte_call_cellular_preferred(self, loop=1, wfc_mode=WFC_MODE_CELLULAR_PREFERRED):
+ '''
+ In/Out Service - VoLTE incall in Cellular preferred mode
+ Make sure that MO/MT VoWiFi call can be made after In/Out service
+ in Wi-Fi Preferred mode and Airplane on + Wi-Fi on and MO/MT
+ VoLTE call can be made in Cellular preferred mode.
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wifi prefer mode
+
+ Returns:
+ True if pass; False if fail
+ Raises:
+ TestFailure if not success.
+ '''
+ for x in range(self.user_params.get("roveinout_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Start test at cellular and wifi area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ self.check_network()
+
+ if not self._enable_wifi_calling(wfc_mode, call_type=WFC_CALL,
+ end_call=False):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+ self.log.info(" Move to no service area for 1 minute during incall.")
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(WAIT_FOR_SERVICE_TIME)
+ # check call status
+ for ad in self.android_devices:
+ get_voice_call_type(ad)
+ self.log.info("Move back to service area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.log.info("Verify device state after in-out service")
+ if not self._device_status_check(call_type=VOLTE_CALL):
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+
+ @test_tracker_info(uuid="4f196186-b163-4c78-bdd9-d8fd7dc79dac")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_wfc_in_out_wifi_disabled(self, loop=1, wfc_mode=WFC_MODE_DISABLED):
+ """
+ [LAB][Wi-Fi Preferred/Cellular Preferred] In/Out Wi-Fi only area with
+ Wi-Fi calling disabled - Idle -> Make sure that radio function can work
+ after in/out Wi-Fi only area when Wi-Fi calling disabled.
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wfc mode
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ """
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Start test at cellular and wifi area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ if not self._enable_wifi_calling(wfc_mode, ):
+ raise signals.TestFailure("_enable_wifi_calling failure: %s"
+ %(self.my_error_msg))
+ self.log.info("Move out cellular area to Wi-Fi only area")
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(WAIT_TIME_AT_NO_SERVICE_AREA)
+ self.log.info("Move back to service area and no wifi area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(NO_SERVICE_POWER_LEVEL)
+
+ self.log.info("Verify device state after in-out service")
+ if not self._device_status_check(call_type=VOICE_CALL):
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+ @test_tracker_info(uuid="d597a694-fae9-426b-ba5e-97a9844cba4f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_wifi_browsing_wifi_preferred(self, loop=1, wfc_mode=WFC_MODE_WIFI_PREFERRED):
+ '''
+ [LAB][Wi-Fi Preferred] In/Out Wi-Fi only area with Wi-Fi calling enabled
+ Browsing -> Make sure that radio function can work after in/out Wi-Fi
+ only area in Wi-Fi preferred mode.
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wfc mode
+
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Start test at cellular and wifi area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ self.check_network()
+ if not self._enable_wifi_calling(wfc_mode, call_type=WFC_CALL,
+ end_call=False):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+ #Keep browsing then move out cellular area to Wi-Fi only area
+ tasks_a = [(self._in_out_browse, ())]
+ tasks_b = [(browsing_test_ping_retry, (ad, )) for ad in self.android_devices]
+ tasks_b.extend(tasks_a)
+ if not multithread_func(self.log, tasks_b):
+ raise signals.TestFailure("in/out browsing failure: %s"
+ %(self.my_error_msg))
+ self.log.info("Verify device state after in-out service")
+ if not self._device_status_check(call_type=VOICE_CALL):
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+ @test_tracker_info(uuid="c7d3dc90-c0ed-48f8-b674-6d5b1efea3cc")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_in_out_wifi_browsing_wfc_disabled(self, loop=1, wfc_mode=WFC_MODE_DISABLED):
+ '''
+ [LAB][Wi-Fi Preferred/Cellular Preferred] In/Out Wi-Fi only area
+ with Wi-Fi calling disabled - Browsing
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wfc mode
+
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Start test at cellular and wifi area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ if not self._enable_wifi_calling(wfc_mode, call_type=WFC_CALL,
+ end_call=False):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+ # Keep browsing then move out cellular area to Wi-Fi only area
+ tasks_a = [(self._in_out_browse, ())]
+ tasks_b = [(browsing_test_ping_retry, (ad, )) for ad in self.android_devices]
+ tasks_b.extend(tasks_a)
+ if not multithread_func(self.log, tasks_b):
+ for ad in self.android_devices:
+ log_screen_shot(ad, "browsing_failure")
+ raise signals.TestFailure("in/out browsing failure: %s"
+ %(self.my_error_msg))
+ if not self._device_status_check(call_type=VOICE_CALL):
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+ def _in_out_browse(self):
+ '''
+ Move out cellular area to Wi-Fi only area and
+ move back to service area and no wifi area
+ '''
+ self.log.info("Move out cellular area to Wi-Fi only area")
+ self.adjust_cellular_signal(NO_SERVICE_POWER_LEVEL)
+ # browsing at no service area
+ time.sleep(WAIT_TIME_AT_NO_SERVICE_AREA)
+ self.log.info("Move back to service area and no wifi area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(NO_SERVICE_POWER_LEVEL)
+ return True
+
+ @test_tracker_info(uuid="9029f3bb-3aca-42be-9241-ed21aab418ff")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_hand_in_out_vowifi_incall_data_transfer(self, loop=1,
+ wfc_mode=WFC_MODE_WIFI_PREFERRED):
+ '''
+ [Wi-Fi Preferred] Hand In/Out while VoWiFi incall -
+ Data transferring -> Make sure that IMS can register between Wi-Fi
+ and LTE NW and no call dropped during data transferring after
+ hand in/out in Wi-Fi Preferred mode.
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode: wfc mode
+
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Start test at cellular and wifi area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ self.check_network()
+ if not self._enable_wifi_calling(wfc_mode, call_type=WFC_CALL,
+ end_call=False):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+ #Download a large file in the background then make a MO VoWiFi call.
+ if not self._voice_call(self.android_devices, WFC_CALL, False,):
+ error_msg = "VoWiFi call failure, "
+ self.log.info(error_msg)
+ self._on_failure(error_msg)
+ self.log.info("Move out Wi-Fi area to VoLTE area during incall + data transferring.")
+ self.adjust_wifi_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(WAIT_FOR_SERVICE_TIME)
+ for ad in self.android_devices:
+ hangup_call(self.log, ad)
+ if not self._device_status_check(call_type=VOLTE_CALL):
+ raise signals.TestFailure(self.my_error_msg)
+ # Download a file in the background then make a MO VoLTE call.
+ self.log.info("Move back to Wi-Fi area during incall + data transferring.")
+ # Move back to Wi-Fi area during incall + data transferring.
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ time.sleep(160)
+ for ad in self.android_devices:
+ hangup_call(self.log, ad)
+ if not self._device_status_check(call_type=VOICE_CALL):
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+
+ @test_tracker_info(uuid="45c1f623-5eeb-4ee4-8739-2b0ebcd5f19f")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_rove_in_out_ims_on_airplane_mode(self, loop=1,):
+ '''
+ [Wi-Fi Calling+Airplane On] Rove In/Out when idle - IMS on ->
+ Make sure that IMS can register between Wi-Fi and LTE NW and
+ VoWiFi call can be made after rove in/out.
+
+ Args:
+ loop: repeat this test cases for how many times
+
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.my_error_msg += "cylce%s: " %(x+1)
+
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.log.info("Enable Wi-Fi calling in Airplane on")
+ ad = self.android_devices[0]
+ wfc_mode = ad.droid.imsGetWfcMode()
+ tasks = [(phone_setup_iwlan, (self.log, ad, True, wfc_mode, self.wifi_ssid))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.my_error_msg += "fail to setup WFC mode to %s, " %(wfc_mode)
+ raise signals.TestFailure(self.my_error_msg)
+
+ self.log.info("Make a MO VoWiFi call in service area")
+ if not self._voice_call(self.android_devices, WFC_CALL, False):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+
+ self.log.info("Move out Wi-Fi area to VoLTE area when idle.")
+ self.adjust_wifi_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(WAIT_FOR_SERVICE_TIME)
+ # if not self._device_status_check(call_type=VOICE_CALL):
+ # raise signals.TestFailure(self.my_error_msg)
+ self.log.info("Move back to Wi-Fi area when idle.")
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ self.log.info("Verify device status after in-out service")
+ self.log.info("Wait for maximum to 160 sec before IMS switched")
+ tasks = [(wait_for_ims_registered, (self.log, ad, 160))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ asserts.assert_true(False, "Fail: %s." %("wait_for_ims_registered failure"),
+ extras={"failure_cause": self.my_error_msg})
+ # turn off APM
+ self.log.info("Turn off airplande mode")
+ tasks = [(toggle_airplane_mode, (self.log, ad, False))
+ for ad in self.android_devices]
+ multithread_func(self.log, tasks)
+ return True
+
+
+ @test_tracker_info(uuid="fb431706-737d-4020-b3d1-347dc4d7ce03")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_wifi_rove_out_wfc(self,loop=1, wfc_mode=WFC_MODE_WIFI_PREFERRED, idle_time=180):
+ '''
+ [Wi-Fi Preferred] Rove In/Out when idle for 1 hours - Wi-Fi calling enabled
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode:
+ idle_time: how long device will be idle
+
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Start test at cellular and wifi area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ if not self._enable_wifi_calling(wfc_mode, call_type=WFC_CALL,
+ end_call=False):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+
+ if not self._voice_call(self.android_devices, WFC_CALL, ):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+ time.sleep(idle_time)
+
+ self.log.info("Move out Wi-Fi area to VoLTE area when idle.")
+ self.adjust_wifi_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(30)
+ self.log.info("check cellular data")
+ # self._data_retry_mechanism()
+ tasks = [(verify_data_connection, (ad, 3))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.log.info("verify_data_connection failure")
+ if not self._voice_call(self.android_devices, VOLTE_CALL, ):
+ raise signals.TestFailure("VOLTE call failure: %s"
+ %(self.my_error_msg))
+ self.log.info("Move back to Wi-Fi area when idle.")
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ if not self._device_status_check(call_type=WFC_CALL):
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+
+ @test_tracker_info(uuid="fb431706-737d-4020-b3d1-347dc4d7ce03")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_wifi_rove_out_no_wfc(self,loop=1, wfc_mode=WFC_MODE_DISABLED,
+ idle_time=180):
+ '''
+ [Wi-Fi Preferred] Rove In/Out when idle for 1 hours
+ Wi-Fi calling disabled. Make sure that IMS can register between
+ Wi-Fi and LTE NW and VoWiFi call can be made after rove in/out.
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode:
+ idle_time: how long device will be idle
+
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Start test at cellular and wifi area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ self.check_network()
+ if not self._enable_wifi_calling(wfc_mode):
+ raise signals.TestFailure("_enable_wifi_calling failure: %s"
+ %(self.my_error_msg))
+
+ if not self._voice_call(self.android_devices, VOLTE_CALL, ):
+ raise signals.TestFailure("VOLTE call failure: %s"
+ %(self.my_error_msg))
+ time.sleep(idle_time)
+
+ self.log.info("Move out Wi-Fi area to VoLTE area when idle.")
+ self.adjust_wifi_signal(NO_SERVICE_POWER_LEVEL)
+ time.sleep(30)
+ self.log.info("check cellular data")
+ # self._data_retry_mechanism()
+ tasks = [(verify_data_connection, (ad, 3))
+ for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ self.log.info("verify_data_connection failure")
+ if not self._voice_call(self.android_devices, VOLTE_CALL, ):
+ raise signals.TestFailure("VOLTE call failure: %s"
+ %(self.my_error_msg))
+ self.log.info("Move back to Wi-Fi area when idle.")
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ # Enable Wi-Fi calling in Wi-Fi Preferred mode
+ if not self._enable_wifi_calling(WFC_MODE_WIFI_PREFERRED):
+ raise signals.TestFailure("_enable_wifi_calling failure: %s"
+ %(self.my_error_msg))
+ # check device status
+ if not self._device_status_check(call_type=WFC_CALL):
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+
+ @test_tracker_info(uuid="5ddfa906-7756-42b4-b1c4-2ac507211547")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_hand_in_out_vowifi_incall_call_hold(self,loop=1,
+ wfc_mode=WFC_MODE_WIFI_PREFERRED, idle_time=180):
+ '''
+ [NSA/SA][Wi-Fi Preferred] Hand In/Out while VoWiFi incall - Hold
+ Ensure IMS can register between Wi-Fi and LTE/NR NW and no call dropped
+ during incall with hold on after hand in/out in Wi-Fi Preferred mode.
+
+ Args:
+ loop: repeat this test cases for how many times
+ wfc_mode:
+ idle_time: how long device will be idle
+
+ Raises:
+ TestFailure if not success.
+ Returns:
+ True if pass; False if fail
+ '''
+ for x in range(self.user_params.get("wfc_cycle", 1)):
+ self.log.info("%s loop: %s/%s" %(self.current_test_name, x+1, loop))
+ self.log.info("Start test at wifi area and service area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ #Make a MO VoWiFi call and hold the call.
+ if not self._enable_wifi_calling(wfc_mode, call_type=WFC_CALL,
+ end_call=False):
+ raise signals.TestFailure("VoWiFi call failure: %s"
+ %(self.my_error_msg))
+ tasks = [(self._call_hold, (ad,)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("fail to hold call: %s"
+ %(self.my_error_msg))
+
+ # Move out Wi-Fi area to 4G area during incall
+ self.log.info("Move out Wi-Fi area to VoLTE area")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(NO_SERVICE_POWER_LEVEL)
+ # Unhold the call
+ tasks = [(self._call_unhold, (ad,)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("fail to unhold call: %s"
+ %(self.my_error_msg))
+ time.sleep(30)
+ for ad in self.android_devices:
+ hangup_call(self.log, ad)
+
+ # Make a MO VoLTE call and hold the call.
+ if not self._voice_call(self.android_devices, VOLTE_CALL, False):
+ raise signals.TestFailure("VoLTE call failure: %s"
+ %(self.my_error_msg))
+ tasks = [(self._call_hold, (ad,)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("fail to hold call: %s"
+ %(self.my_error_msg))
+
+ #Move back to Wi-Fi area during incall.
+ self.log.info("Move back to Wi-Fi area during incall.")
+ self.adjust_cellular_signal(IN_SERVICE_POWER_LEVEL)
+ self.adjust_wifi_signal(IN_SERVICE_POWER_LEVEL)
+ tasks = [(self._call_unhold, (ad,)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ raise signals.TestFailure("fail to unhold call: %s"
+ %(self.my_error_msg))
+ time.sleep(30)
+ for ad in self.android_devices:
+ hangup_call(self.log, ad)
+ # check device status
+ if not self._device_status_check(call_type=WFC_CALL):
+ raise signals.TestFailure(self.my_error_msg)
+ return True
+
+
+ def _call_hold(self, ad, wait_time=WAIT_TIME_IN_CALL):
+ '''
+ Press call hold
+
+ Args:
+ ad: android device
+ wait_time: wait time after press hold/unhold in sec
+
+ Returns:
+ True if pass; False if fail
+ '''
+ if ad.droid.telecomIsInCall():
+ ad.droid.telecomShowInCallScreen()
+ call_list = ad.droid.telecomCallGetCallIds()
+ ad.log.info("Calls in PhoneA %s", call_list)
+ call_id = call_list[0]
+ call_state = ad.droid.telecomCallGetCallState(call_id)
+ if call_state != CALL_STATE_ACTIVE:
+ ad.log.error("Call_id:%s, state:%s, expected: STATE_ACTIVE",
+ call_id,
+ ad.droid.telecomCallGetCallState(call_id))
+ return False
+ ad.log.info("Hold call_id %s on PhoneA", call_id)
+ log_screen_shot(ad, "before_call_hold")
+ ad.droid.telecomCallHold(call_id)
+ time.sleep(wait_time)
+
+ call_state = ad.droid.telecomCallGetCallState(call_id)
+ log_screen_shot(ad, "after_call_hold")
+ if call_state != CALL_STATE_HOLDING:
+ ad.log.error("Call_id:%s, state:%s, expected: STATE_HOLDING",
+ call_id,
+ ad.droid.telecomCallGetCallState(call_id))
+ log_screen_shot(ad, "hold_failure")
+ return False
+ else:
+ ad.log.info("device is not in call")
+ return False
+ return True
+
+ def _call_unhold(self, ad, wait_time=WAIT_TIME_IN_CALL):
+ '''
+ Press call unhold
+
+ Args:
+ ad: android device
+ wait_time: wait time after press hold/unhold in sec
+
+ Returns:
+ True if pass; False if fail
+ '''
+ if ad.droid.telecomIsInCall():
+ ad.droid.telecomShowInCallScreen()
+ call_list = ad.droid.telecomCallGetCallIds()
+ ad.log.info("Calls in PhoneA %s", call_list)
+ call_id = call_list[0]
+ call_state = ad.droid.telecomCallGetCallState(call_id)
+ if call_state != CALL_STATE_HOLDING:
+ ad.log.error("Call_id:%s, state:%s, expected: STATE_HOLDING",
+ call_id,
+ ad.droid.telecomCallGetCallState(call_id))
+ return False
+ ad.log.info("Unhold call_id %s on PhoneA", call_id)
+ log_screen_shot(ad, "before_unhold")
+ ad.droid.telecomCallUnhold(call_id)
+ time.sleep(wait_time)
+ call_state = ad.droid.telecomCallGetCallState(call_id)
+ log_screen_shot(ad, "after_unhold")
+ if call_state != CALL_STATE_ACTIVE:
+ ad.log.error("Call_id:%s, state:%s, expected: STATE_ACTIVE",
+ call_id,
+ call_state)
+ log_screen_shot(ad, "_unhold_failure")
+ return False
+ else:
+ ad.log.info("device is not in call")
+ return False
+ return True
+
diff --git a/acts_tests/tests/google/tel/lab/TelLabMobilityTest.py b/acts_tests/tests/google/tel/lab/TelLabMobilityTest.py
index aba648b..ccfdf78 100644
--- a/acts_tests/tests/google/tel/lab/TelLabMobilityTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabMobilityTest.py
@@ -28,9 +28,6 @@
from acts_contrib.test_utils.tel.anritsu_utils import tear_down_call
from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_lte_lte
from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_lte_wcdma
-from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_lte_gsm
-from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_lte_1x
-from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_lte_evdo
from acts_contrib.test_utils.tel.anritsu_utils import set_usim_parameters
from acts_contrib.test_utils.tel.anritsu_utils import set_post_sim_params
from acts_contrib.test_utils.tel.tel_defines import CALL_TEARDOWN_PHONE
@@ -38,7 +35,6 @@
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_UMTS
-from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_CDMA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_ONLY
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_UMTS
@@ -46,22 +42,17 @@
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL_FOR_IMS
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_rat
from acts_contrib.test_utils.tel.tel_test_utils import get_host_ip_address
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte
-from acts_contrib.test_utils.tel.tel_test_utils import run_multithread_func
from acts_contrib.test_utils.tel.tel_test_utils import iperf_test_by_adb
from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_apn_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_volte
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.utils import adb_shell_ping
-from acts.utils import rand_ascii_str
-from acts.controllers import iperf_server
-from acts.utils import exe_cmd
+from acts.libs.utils.multithread import run_multithread_func
DEFAULT_CALL_NUMBER = "+11234567891"
DEFAULT_PING_DURATION = 5
diff --git a/acts_tests/tests/google/tel/lab/TelLabNeighborCellTest.py b/acts_tests/tests/google/tel/lab/TelLabNeighborCellTest.py
index 8690ae7..ae26d91 100644
--- a/acts_tests/tests/google/tel/lab/TelLabNeighborCellTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabNeighborCellTest.py
@@ -44,8 +44,8 @@
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_UMTS
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts.controllers.anritsu_lib.cell_configurations import \
diff --git a/acts_tests/tests/google/tel/lab/TelLabProjectFiTest.py b/acts_tests/tests/google/tel/lab/TelLabProjectFiTest.py
index 4208689..c151811 100644
--- a/acts_tests/tests/google/tel/lab/TelLabProjectFiTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabProjectFiTest.py
@@ -14,22 +14,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""
-Fi Switching Methods
+Fi Switching Methods
"""
import time
+from acts.libs.utils.multithread import multithread_func
from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError
-from acts.controllers.anritsu_lib.md8475a import CBCHSetup
-from acts.controllers.anritsu_lib.md8475a import CTCHSetup
from acts.controllers.anritsu_lib.md8475a import MD8475A
from acts_contrib.test_utils.tel.anritsu_utils import cb_serial_number
from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_lte
from acts_contrib.test_utils.tel.anritsu_utils import set_usim_parameters
from acts_contrib.test_utils.tel.anritsu_utils import set_post_sim_params
-from acts_contrib.test_utils.tel.tel_test_utils import \
- ensure_preferred_network_type_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
@@ -38,20 +32,23 @@
from acts_contrib.test_utils.tel.tel_defines import CARRIER_SPT
from acts_contrib.test_utils.tel.tel_defines import CARRIER_TMO
from acts_contrib.test_utils.tel.tel_defines import CARRIER_USCC
+from acts_contrib.test_utils.tel.tel_logging_utils import log_screen_shot
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
from acts_contrib.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_preferred_network_type_for_subscription
from acts_contrib.test_utils.tel.tel_test_utils import abort_all_tests
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
from acts_contrib.test_utils.tel.tel_test_utils import is_sim_ready
-from acts_contrib.test_utils.tel.tel_test_utils import log_screen_shot
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
from acts_contrib.test_utils.tel.tel_test_utils import refresh_droid_config
from acts_contrib.test_utils.tel.tel_test_utils import send_dialer_secret_code
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
from acts_contrib.test_utils.tel.tel_test_utils import add_google_account
from acts_contrib.test_utils.tel.tel_test_utils import remove_google_account
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
WAIT_TIME_BETWEEN_REG_AND_MSG = 15 # default 15 sec
CARRIER = None
diff --git a/acts_tests/tests/google/tel/lab/TelLabPwsTest.py b/acts_tests/tests/google/tel/lab/TelLabPwsTest.py
new file mode 100644
index 0000000..188783a
--- /dev/null
+++ b/acts_tests/tests/google/tel/lab/TelLabPwsTest.py
@@ -0,0 +1,373 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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.
+
+import datetime
+import enum
+import logging
+import time
+from typing import Callable
+
+from acts import asserts
+from acts.controllers.amarisoft_lib import amarisoft_client
+from acts.controllers.amarisoft_lib import config_utils
+from acts.controllers.amarisoft_lib import ssh_utils
+from acts.controllers.amarisoft_lib import ims
+from acts.controllers.amarisoft_lib import mme
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel import tel_defines
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts.libs.proc import job
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+
+PWS_ALERT_4370 = 4370
+PWS_ALERT_4371 = 4371
+PWS_ALERT_4380 = 4380
+PWS_ALERT_911 = 911
+PWS_ALERT_4383 = 4383
+PWS_ALERT_4384 = 4384
+PWS_ALERT_4393 = 4393
+PWS_ALERT_919 = 919
+
+PREFERENCES_XML_FILENAME = '/data/user_de/0/com.google.android.cellbroadcastreceiver/shared_prefs/com.google.android.cellbroadcastreceiver_preferences.xml'
+ENABLE_TEST_ALERT_CMD = (
+ "sed -i 's/"
+ "enable_test_alerts\\\" value=\\\"false/"
+ "enable_test_alerts\\\" value=\\\"true/"
+ f"' {PREFERENCES_XML_FILENAME}")
+PWS_DUPLICATE_DETECTION_OFF = (
+ 'am broadcast -a '
+ 'com.android.cellbroadcastservice.action.DUPLICATE_DETECTION '
+ '--ez enable false')
+
+IN_CALL_DURATION = datetime.timedelta(seconds=10)
+CHECK_INTERVAL = datetime.timedelta(seconds=1)
+SERVICE_RESTART_TIME_OUT = datetime.timedelta(seconds=10)
+REGISTRATION_TIMEOUT = datetime.timedelta(seconds=120)
+WAIT_CALL_STATE_TIMEOUT = datetime.timedelta(seconds=30)
+PWS_START_END_INTERVAL = datetime.timedelta(seconds=15)
+
+
+class TestScenario(enum.Enum):
+ """Test scenario for PWS test."""
+ PS = 0
+ CS = 1
+ IDLE = 2
+
+
+class CallState(enum.Enum):
+ """Telephony call state."""
+ IDLE = 0
+ RINGING = 1
+ OFFHOOK = 2
+
+
+def wait_until(condition: Callable[..., bool], interval: datetime.timedelta,
+ timeout: datetime.timedelta, ret: bool, *argv) -> bool:
+ """Waits for the condition to occur.
+
+ Args:
+ condition: Function to check specific event occur or not.
+ interval: Time period during each check.
+ timeout: A timer which wait for event occur.
+ ret: Expected result of condition.
+ *argv: Parameters used by condition.
+
+ Returns:
+ True if condition match ret, False otherwise.
+ """
+ start_time = datetime.datetime.now()
+ while datetime.datetime.now() - start_time < timeout:
+ if condition(*argv) == ret:
+ return True
+ time.sleep(interval.total_seconds())
+ return False
+
+
+def is_in_service(ad) -> bool:
+ """Checks radio service state of android device .
+
+ Args:
+ ad: Mobly's Android controller objects.
+
+ Returns:
+ True if device is in service, False otherwise.
+ """
+ service_state = ad.droid.telephonyGetServiceState()
+ if service_state is None:
+ return False
+ return service_state.get('serviceState') == 'IN_SERVICE'
+
+
+class TelLabPwsTest(TelephonyBaseTest):
+
+ def setup_class(self):
+ super().setup_class()
+ self.ad = self.android_devices[0]
+ self.ad.info = self.user_params.get('AndroidDevice')[0]
+ self.amarisoft_ip_address = self.user_params.get('amarisoft_ip_address')
+ self.amarisoft_username = self.user_params.get('amarisoft_username')
+ self.amarisoft_pw = self.user_params.get('amarisoft_pw')
+ self.amarisoft_call_num = self.user_params.get('amarisoft_call_num')
+ self.remote = amarisoft_client.AmariSoftClient(self.amarisoft_ip_address,
+ self.amarisoft_username,
+ self.amarisoft_pw)
+ self.remote.connect()
+ self.config = config_utils.ConfigUtils(self.remote)
+ self.mme = mme.MmeFunctions(self.remote)
+ self.ims = ims.ImsFunctions(self.remote)
+ self._amarisoft_preset()
+ self._android_device_preset()
+
+ def _amarisoft_preset(self) -> None:
+ """Sets Amarisoft test network."""
+
+ if not self.remote.ssh_is_connected():
+ raise ssh_utils.NotConnectedError(
+ 'amarisoft_preset: amarisoft is not connected.')
+ self.remote.lte_service_start()
+
+ asserts.skip_if(
+ not self.config.upload_enb_template(config_utils.EnbCfg.ENB_GENERIC),
+ 'amarisoft_preset: Failed to upload enb configuration.')
+ asserts.skip_if(
+ not self.config.upload_mme_template(config_utils.MmeCfg.MME_GENERIC),
+ 'amarisoft_preset: Failed to upload mme configuration.')
+ asserts.skip_if(
+ not self.config.enb_set_plmn('46697'),
+ 'amarisoft_preset: Failed to set ENB PLMN.')
+ asserts.skip_if(
+ not self.config.mme_set_plmn('46697'),
+ 'amarisoft_preset: Failed to set MME PLMN.')
+ asserts.skip_if(
+ not self.config.enb_set_spectrum_tech(config_utils.SpecTech.FDD.value),
+ 'amarisoft_preset: Failed to set ENB spectrum technique.')
+ asserts.skip_if(
+ not self.config.enb_set_fdd_arfcn(275),
+ 'amarisoft_preset: Failed to set ENB FDD ARFCN.')
+
+ self.remote.lte_service_restart()
+ start_time = datetime.datetime.now()
+ while not self.remote.lte_service_is_active():
+ if datetime.datetime.now() - start_time > SERVICE_RESTART_TIME_OUT:
+ asserts.fail('amarisoft_preset: Amarisoft service restart failed.')
+ else:
+ time.sleep(CHECK_INTERVAL)
+ self.log.info('Amarisoft preset completed.')
+
+ def _android_device_preset(self)->None:
+ """Presets the device before the test starts."""
+
+ self.log.info('Android device preset start.')
+ self.ad.droid.connectivityToggleAirplaneMode(False)
+ asserts.skip_if(
+ not wait_until(is_in_service, CHECK_INTERVAL, REGISTRATION_TIMEOUT,
+ True, self.ad), 'android_device_preset: '
+ f'{self.ad.serial} is still out of service after airplane mode off.')
+ self.ad.droid.toggleRingerSilentMode(False)
+ self.ad.adb.shell(ENABLE_TEST_ALERT_CMD)
+ self.ad.reboot()
+ self.ad.droid.setMediaVolume(3)
+ self.ad.droid.setRingerVolume(3)
+ self.ad.droid.setVoiceCallVolume(3)
+ self.ad.droid.setAlarmVolume(3)
+ asserts.assert_true(
+ phone_setup_volte(self.log, self.ad),
+ 'android_device_preset: Failed to set up VoLTE.')
+ self.log.info('Android device preset completed.')
+
+ def mo_call_to_amarisoft(self) -> None:
+ """Executes a MO call process including checking the call status during the MO call.
+
+ The method focus on if any issue found on MO side with below steps:
+ (1) Make a voice call from MO side to MT side(Amarisoft).
+ (2) MT side accepts the call.
+ (3) Check if the call is connect.
+ (4) Monitor the in-call status for MO side during in-call duration.
+ (5) End the call on MO side.
+ """
+ if not self.ad.droid.telephonyIsImsRegistered():
+ asserts.skip(
+ 'mo_call_process: No IMS registered, cannot perform VoLTE call test.')
+ self.ad.log.info('Dial a Call to callbox.')
+ self.ad.droid.telecomCallNumber(self.amarisoft_call_num, False)
+ asserts.assert_true(
+ wait_until(self.ad.droid.telecomGetCallState, CHECK_INTERVAL,
+ WAIT_CALL_STATE_TIMEOUT, CallState.OFFHOOK.name),
+ 'mo_call_process: The call is not connected.')
+ asserts.assert_false(
+ wait_until(self.ad.droid.telecomIsInCall, CHECK_INTERVAL,
+ IN_CALL_DURATION, False),
+ 'mo_call_process: UE drop call before end call.')
+ self.ad.droid.telecomEndCall()
+ asserts.assert_true(
+ wait_until(self.ad.droid.telecomGetCallState, CHECK_INTERVAL,
+ WAIT_CALL_STATE_TIMEOUT, CallState.IDLE.name),
+ 'mo_call_process: UE is still in-call after hanging up the call.')
+
+ def pws_action(self, msg: str, test_scenario: int) -> None:
+ """Performs a PWS broadcast and check android device receives PWS message.
+
+ (1) Device idle or perform mo call/ping test according to test scenario.
+ (2) Broadcast a specific PWS message.
+ (3) Wait 15 seconds for device receive PWS message.
+ (4) Stop broadcast PWS message.
+ (5) Verify android device receive PWS message by check keywords in logcat.
+ (6) Perform mo call/ping test according to test scenario.
+
+ Args:
+ msg: The PWS parameter to be broadcast.
+ test_scenario: The parameters of the test scenario to be executed.
+ """
+ if test_scenario == TestScenario.PS:
+ job.run(f'adb -s {self.ad.serial} shell ping -c 5 8.8.8.8')
+ elif test_scenario == TestScenario.CS:
+ self.mo_call_to_amarisoft()
+
+ logging.info('Broadcast PWS: %s', msg)
+ # Advance the start time by one second to avoid loss of logs
+ # due to time differences between test device and mobileharness.
+ start_time = datetime.datetime.now() - datetime.timedelta(seconds=1)
+ self.mme.pws_write(msg)
+ time.sleep(PWS_START_END_INTERVAL.seconds)
+ self.mme.pws_kill(msg)
+
+ asserts.assert_true(
+ self.ad.search_logcat(
+ f'CBChannelManager: isEmergencyMessage: true, message id = {msg}',
+ start_time), f'{msg} not received.')
+ asserts.assert_false(
+ self.ad.search_logcat('Failed to play alert sound', start_time),
+ f'{msg} failed to play alert sound.')
+
+ if msg in [PWS_ALERT_911, PWS_ALERT_919]:
+ asserts.assert_true(
+ self.ad.search_logcat('playAlertTone: alertType=INFO', start_time),
+ f'{msg} alertType not match expected (alertType=INFO).')
+ else:
+ asserts.assert_true(
+ self.ad.search_logcat('playAlertTone: alertType=DEFAULT', start_time),
+ f'{msg} alertType not match expected (alertType=DEFAULT).')
+
+ if test_scenario == TestScenario.PS:
+ job.run(f'adb -s {self.ad.serial} shell ping -c 5 8.8.8.8')
+ elif test_scenario == TestScenario.CS:
+ self.mo_call_to_amarisoft()
+
+ def teardown_test(self):
+ self.ad.adb.shell(PWS_DUPLICATE_DETECTION_OFF)
+ super().teardown_test()
+
+ def teardown_class(self):
+ self.ad.droid.connectivityToggleAirplaneMode(True)
+ super().teardown_class()
+
+ @test_tracker_info(uuid="f8971b34-fcaa-4915-ba05-36c754378987")
+ def test_pws_idle_4370(self):
+ self.pws_action(PWS_ALERT_4370, TestScenario.IDLE)
+
+ @test_tracker_info(uuid="ed925410-646f-475a-8765-44ea1631cc6a")
+ def test_pws_idle_4371(self):
+ self.pws_action(PWS_ALERT_4371, TestScenario.IDLE)
+
+ @test_tracker_info(uuid="253f2e2e-8262-43b5-a66e-65b2bc73df58")
+ def test_pws_idle_4380(self):
+ self.pws_action(PWS_ALERT_4380, TestScenario.IDLE)
+
+ @test_tracker_info(uuid="95ed6407-3c5b-4f58-9fd9-e5021972f03c")
+ def test_pws_idle_911(self):
+ self.pws_action(PWS_ALERT_911, TestScenario.IDLE)
+
+ @test_tracker_info(uuid="a6f76e03-b808-4194-b286-54a2ca02cb7f")
+ def test_pws_idle_4383(self):
+ self.pws_action(PWS_ALERT_4383, TestScenario.IDLE)
+
+ @test_tracker_info(uuid="8db4be15-2e2c-4616-8f7f-a6b8062d7265")
+ def test_pws_idle_4384(self):
+ self.pws_action(PWS_ALERT_4384, TestScenario.IDLE)
+
+ @test_tracker_info(uuid="79ba63d7-8ffb-48d3-b27e-a8b152ee5a25")
+ def test_pws_idle_4393(self):
+ self.pws_action(PWS_ALERT_4393, TestScenario.IDLE)
+
+ @test_tracker_info(uuid="a07b1c14-dd3f-4818-bc8d-120d006dcea5")
+ def test_pws_idle_919(self):
+ self.pws_action(PWS_ALERT_919, TestScenario.IDLE)
+
+ @test_tracker_info(uuid="00b607a9-e75c-4342-9c7f-9528704ae3bd")
+ def test_pws_ps_4370(self):
+ self.pws_action(PWS_ALERT_4370, TestScenario.PS)
+
+ @test_tracker_info(uuid="feff8d7a-52fe-46f0-abe5-0da698fc985c")
+ def test_pws_ps_4371(self):
+ self.pws_action(PWS_ALERT_4371, TestScenario.PS)
+
+ @test_tracker_info(uuid="22afaaa1-7738-4499-a378-eabb9ae19fa6")
+ def test_pws_ps_4380(self):
+ self.pws_action(PWS_ALERT_4380, TestScenario.PS)
+
+ @test_tracker_info(uuid="d6fb35fa-9058-4c90-ac8d-bc49d6be1070")
+ def test_pws_ps_911(self):
+ self.pws_action(PWS_ALERT_911, TestScenario.PS)
+
+ @test_tracker_info(uuid="9937c39f-4b47-47f4-904a-108123919716")
+ def test_pws_ps_4383(self):
+ self.pws_action(PWS_ALERT_4383, TestScenario.PS)
+
+ @test_tracker_info(uuid="01faa5bb-e02a-42a3-bf08-30e422c684f4")
+ def test_pws_ps_4384(self):
+ self.pws_action(PWS_ALERT_4384, TestScenario.PS)
+
+ @test_tracker_info(uuid="71d02b4a-a1a3-44e1-a28a-aea3a62f758f")
+ def test_pws_ps_4393(self):
+ self.pws_action(PWS_ALERT_4393, TestScenario.PS)
+
+ @test_tracker_info(uuid="f5e7801c-80e0-4cbe-b4b1-133fa88fa4a3")
+ def test_pws_ps_919(self):
+ self.pws_action(PWS_ALERT_919, TestScenario.PS)
+
+ @test_tracker_info(uuid="b68e5593-1748-434c-be2a-e684791f2ca8")
+ def test_pws_cs_4370(self):
+ self.pws_action(PWS_ALERT_4370, TestScenario.CS)
+
+ @test_tracker_info(uuid="a04f433d-bbf0-4a09-b958-719ec8df9991")
+ def test_pws_cs_4371(self):
+ self.pws_action(PWS_ALERT_4371, TestScenario.CS)
+
+ @test_tracker_info(uuid="48432d8d-847a-44e3-aa24-32ae704e15de")
+ def test_pws_cs_4380(self):
+ self.pws_action(PWS_ALERT_4380, TestScenario.CS)
+
+ @test_tracker_info(uuid="9fde76b2-e568-4aa5-a627-9d682ba9e1fb")
+ def test_pws_cs_911(self):
+ self.pws_action(PWS_ALERT_911, TestScenario.CS)
+
+ @test_tracker_info(uuid="fa1f0c6a-22af-4daf-ab32-a508b06de165")
+ def test_pws_cs_4383(self):
+ self.pws_action(PWS_ALERT_4383, TestScenario.CS)
+
+ @test_tracker_info(uuid="45d924be-e204-497d-b598-e18a8c668492")
+ def test_pws_cs_4384(self):
+ self.pws_action(PWS_ALERT_4384, TestScenario.CS)
+
+ @test_tracker_info(uuid="ff4f0e6e-2bda-4047-a69c-7b103868e2d5")
+ def test_pws_cs_4393(self):
+ self.pws_action(PWS_ALERT_4393, TestScenario.CS)
+
+ @test_tracker_info(uuid="ab2bd166-c5e0-4505-ba37-6192bf53226f")
+ def test_pws_cs_919(self):
+ self.pws_action(PWS_ALERT_919, TestScenario.CS)
+
+
diff --git a/acts_tests/tests/google/tel/lab/TelLabSmsTest.py b/acts_tests/tests/google/tel/lab/TelLabSmsTest.py
index 2f2bc68..3ecb101 100644
--- a/acts_tests/tests/google/tel/lab/TelLabSmsTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabSmsTest.py
@@ -44,10 +44,10 @@
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_UMTS
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte
from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_apn_by_adb
from acts_contrib.test_utils.tel.tel_defines import CALL_TEARDOWN_PHONE
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_CDMA2000
diff --git a/acts_tests/tests/google/tel/lab/TelLabUeIdentityTest.py b/acts_tests/tests/google/tel/lab/TelLabUeIdentityTest.py
index e7858ce..031c33b 100644
--- a/acts_tests/tests/google/tel/lab/TelLabUeIdentityTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabUeIdentityTest.py
@@ -37,8 +37,8 @@
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_UMTS
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
diff --git a/acts_tests/tests/google/tel/lab/TelLabVoiceTest.py b/acts_tests/tests/google/tel/lab/TelLabVoiceTest.py
index f2417dd..ac0b6a2 100644
--- a/acts_tests/tests/google/tel/lab/TelLabVoiceTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabVoiceTest.py
@@ -23,11 +23,9 @@
from acts.controllers.anritsu_lib.md8475a import CsfbType
from acts.controllers.anritsu_lib.md8475a import MD8475A
from acts.controllers.anritsu_lib.md8475a import VirtualPhoneAutoAnswer
-from acts.controllers.anritsu_lib.md8475a import VirtualPhoneStatus
from acts_contrib.test_utils.tel.anritsu_utils import WAIT_TIME_ANRITSU_REG_AND_CALL
from acts_contrib.test_utils.tel.anritsu_utils import call_mo_setup_teardown
from acts_contrib.test_utils.tel.anritsu_utils import ims_call_cs_teardown
-from acts_contrib.test_utils.tel.anritsu_utils import call_mt_setup_teardown
from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_1x
from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_1x_evdo
from acts_contrib.test_utils.tel.anritsu_utils import set_system_model_gsm
@@ -43,7 +41,6 @@
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_UMTS
-from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_CDMA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_ONLY
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_UMTS
@@ -52,13 +49,12 @@
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL_FOR_IMS
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_rat
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte
from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_apn_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_volte
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
DEFAULT_CALL_NUMBER = "0123456789"
diff --git a/acts_tests/tests/google/tel/live/TelLiveCBRSTest.py b/acts_tests/tests/google/tel/live/TelLiveCBRSTest.py
index 7b63288..9cd049b 100644
--- a/acts_tests/tests/google/tel/live/TelLiveCBRSTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveCBRSTest.py
@@ -30,14 +30,21 @@
from acts_contrib.test_utils.tel.tel_defines import EventActiveDataSubIdChanged
from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackAvailable
from acts_contrib.test_utils.tel.tel_defines import EventNetworkCallback
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import is_phone_not_in_call
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_not_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_cdma
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_2g
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_cbrs_and_default_sub_id
from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_not_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
from acts_contrib.test_utils.tel.tel_test_utils import load_scone_cat_simulate_data
from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_success_using_sl4a
from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_failure_using_sl4a
@@ -46,27 +53,18 @@
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import STORY_LINE
from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_logger
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call_by_adb
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_not_iwlan
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_cdma
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_not_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_volte
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_operatorname_from_slot_index
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_cbrs_and_default_sub_id
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
from acts.utils import get_current_epoch_time
from queue import Empty
@@ -74,6 +72,7 @@
WAIT_TIME_BETWEEN_HANDOVER = 10
TIME_PERMITTED_FOR_CBRS_SWITCH = 2
+
class TelLiveCBRSTest(TelephonyBaseTest):
def setup_class(self):
super().setup_class()
diff --git a/acts_tests/tests/google/tel/live/TelLiveCellInfoTest.py b/acts_tests/tests/google/tel/live/TelLiveCellInfoTest.py
index 5895d10..3f7bdc9 100644
--- a/acts_tests/tests/google/tel/live/TelLiveCellInfoTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveCellInfoTest.py
@@ -19,8 +19,8 @@
import time
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected, \
- toggle_airplane_mode, ensure_phones_idle, start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
from acts_contrib.test_utils.wifi import wifi_test_utils
from acts.utils import disable_usb_charging, enable_usb_charging
diff --git a/acts_tests/tests/google/tel/live/TelLiveConnectivityMonitorBaseTest.py b/acts_tests/tests/google/tel/live/TelLiveConnectivityMonitorBaseTest.py
index 5ec5ddb..79035cb 100644
--- a/acts_tests/tests/google/tel/live/TelLiveConnectivityMonitorBaseTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveConnectivityMonitorBaseTest.py
@@ -29,38 +29,37 @@
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
+from acts_contrib.test_utils.tel.tel_bootloader_utils import fastboot_wipe
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
from acts_contrib.test_utils.tel.tel_test_utils import bring_up_connectivity_monitor
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import fastboot_wipe
from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
from acts_contrib.test_utils.tel.tel_test_utils import get_model_name
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
from acts_contrib.test_utils.tel.tel_test_utils import get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import last_call_drop_reason
from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_wfc
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
from acts_contrib.test_utils.tel.tel_test_utils import trigger_modem_crash
from acts_contrib.test_utils.tel.tel_test_utils import trigger_modem_crash_by_modem
+from acts_contrib.test_utils.tel.tel_video_utils import video_call_setup_teardown
+from acts_contrib.test_utils.tel.tel_video_utils import phone_setup_video
+from acts_contrib.test_utils.tel.tel_video_utils import is_phone_in_call_video_bidirectional
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_video_utils import video_call_setup_teardown
-from acts_contrib.test_utils.tel.tel_video_utils import phone_setup_video
-from acts_contrib.test_utils.tel.tel_video_utils import \
- is_phone_in_call_video_bidirectional
+from acts_contrib.test_utils.tel.tel_voice_utils import last_call_drop_reason
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
CALL_DROP_CODE_MAPPING = {
373: "Radio Internal Error",
diff --git a/acts_tests/tests/google/tel/live/TelLiveConnectivityMonitorMobilityTest.py b/acts_tests/tests/google/tel/live/TelLiveConnectivityMonitorMobilityTest.py
index fd76813..03fbc55 100644
--- a/acts_tests/tests/google/tel/live/TelLiveConnectivityMonitorMobilityTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveConnectivityMonitorMobilityTest.py
@@ -28,15 +28,14 @@
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_WIFI_RSSI_CALIBRATION_SCREEN_ON
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_WIFI_RSSI_CALIBRATION_WIFI_CONNECTED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WIFI_WEAK_RSSI_VALUE
from acts_contrib.test_utils.tel.tel_defines import SignalStrengthContainer
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_wifi_data_connection
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_subscription
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
from TelLiveConnectivityMonitorBaseTest import TelLiveConnectivityMonitorBaseTest
# Attenuator name
diff --git a/acts_tests/tests/google/tel/live/TelLiveDSDSVoiceTest.py b/acts_tests/tests/google/tel/live/TelLiveDSDSVoiceTest.py
index 4a711ce..78bd320 100644
--- a/acts_tests/tests/google/tel/live/TelLiveDSDSVoiceTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveDSDSVoiceTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2019 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -21,105 +21,56 @@
import random
import collections
-from queue import Empty
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_TERMINATED
-from acts_contrib.test_utils.tel.tel_defines import GEN_3G
-from acts_contrib.test_utils.tel.tel_defines import GEN_4G
-from acts_contrib.test_utils.tel.tel_defines import INVALID_WIFI_RSSI
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_DROP
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
-from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_BACKGROUND
-from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_FOREGROUND
-from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_RINGING
-from acts_contrib.test_utils.tel.tel_defines import RAT_LTE
-from acts_contrib.test_utils.tel.tel_defines import RAT_IWLAN
-from acts_contrib.test_utils.tel.tel_defines import RAT_WCDMA
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_REG_AND_CALL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_WIFI_RSSI_CALIBRATION_SCREEN_ON
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_WIFI_RSSI_CALIBRATION_WIFI_CONNECTED
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import WIFI_WEAK_RSSI_VALUE
-from acts_contrib.test_utils.tel.tel_defines import EventNetworkCallback
-from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackAvailable
-from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackLost
-from acts_contrib.test_utils.tel.tel_defines import SignalStrengthContainer
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_DATA_SUB_ID
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
-from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_network_call_back_event_match
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_not_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_droid_not_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_disabled
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
-from acts_contrib.test_utils.tel.tel_test_utils import get_lte_rsrp
-from acts_contrib.test_utils.tel.tel_test_utils import get_wifi_signal_strength
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_logger
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
-from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_success_using_sl4a
-from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_failure_using_sl4a
-from acts_contrib.test_utils.tel.tel_test_utils import sms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import mms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_not_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_3g_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_not_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_2g
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_logger
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import is_phone_not_in_call
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_3g_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_not_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_volte
from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_outgoing_call
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_incoming_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
from acts_contrib.test_utils.tel.tel_subscription_utils import get_operatorname_from_slot_index
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import perform_dds_switch
from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_data
from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_message
from acts_contrib.test_utils.tel.tel_subscription_utils import set_always_allow_mms_data
+from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
+from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
+from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_success_using_sl4a
+from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_failure_using_sl4a
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call_by_adb
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_not_iwlan
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
from acts.utils import get_current_epoch_time
from acts.utils import rand_ascii_str
diff --git a/acts_tests/tests/google/tel/live/TelLiveDataTest.py b/acts_tests/tests/google/tel/live/TelLiveDataTest.py
index 7881a8c..cd297ba 100755
--- a/acts_tests/tests/google/tel/live/TelLiveDataTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveDataTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2016 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -23,13 +23,8 @@
import os
from acts import signals
-from acts.utils import disable_doze
-from acts.utils import enable_doze
from acts.utils import rand_ascii_str
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_subid_from_slot_index
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_data
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_TERMINATED
@@ -48,25 +43,30 @@
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK
from acts_contrib.test_utils.tel.tel_defines import TETHERING_MODE_WIFI
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_AFTER_REBOOT
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
-from acts_contrib.test_utils.tel.tel_defines import \
- WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_TETHERING_AFTER_REBOOT
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING
from acts_contrib.test_utils.tel.tel_defines import TETHERING_PASSWORD_HAS_ESCAPE
from acts_contrib.test_utils.tel.tel_defines import TETHERING_SPECIAL_SSID_LIST
from acts_contrib.test_utils.tel.tel_defines import TETHERING_SPECIAL_PASSWORD_LIST
+from acts_contrib.test_utils.tel.tel_bt_utils import verify_bluetooth_tethering_connection
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
from acts_contrib.test_utils.tel.tel_data_utils import airplane_mode_test
from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
+from acts_contrib.test_utils.tel.tel_data_utils import get_mobile_data_usage
from acts_contrib.test_utils.tel.tel_data_utils import reboot_test
from acts_contrib.test_utils.tel.tel_data_utils import change_data_sim_and_verify_data
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_detection
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_recovery
+from acts_contrib.test_utils.tel.tel_data_utils import check_network_validation_fail
from acts_contrib.test_utils.tel.tel_data_utils import data_connectivity_single_bearer
+from acts_contrib.test_utils.tel.tel_data_utils import remove_mobile_data_usage_limit
+from acts_contrib.test_utils.tel.tel_data_utils import set_mobile_data_usage_limit
from acts_contrib.test_utils.tel.tel_data_utils import tethering_check_internet_connection
from acts_contrib.test_utils.tel.tel_data_utils import test_data_connectivity_multi_bearer
from acts_contrib.test_utils.tel.tel_data_utils import test_setup_tethering
from acts_contrib.test_utils.tel.tel_data_utils import test_tethering_wifi_and_voice_call
from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_connect_disconnect
-from acts_contrib.test_utils.tel.tel_data_utils import verify_bluetooth_tethering_connection
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_wifi_data_connection
from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
from acts_contrib.test_utils.tel.tel_data_utils import wifi_tethering_cleanup
from acts_contrib.test_utils.tel.tel_data_utils import verify_toggle_apm_tethering_internet_connection
@@ -81,53 +81,38 @@
from acts_contrib.test_utils.tel.tel_data_utils import setup_device_internet_connection_then_reboot
from acts_contrib.test_utils.tel.tel_data_utils import verify_internet_connection_in_doze_mode
from acts_contrib.test_utils.tel.tel_data_utils import verify_toggle_data_during_wifi_tethering
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import check_is_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import \
- ensure_network_generation_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import get_mobile_data_usage
-from acts_contrib.test_utils.tel.tel_test_utils import get_slot_index_from_subid
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import remove_mobile_data_usage_limit
-from acts_contrib.test_utils.tel.tel_test_utils import set_mobile_data_usage_limit
-from acts_contrib.test_utils.tel.tel_test_utils import stop_wifi_tethering
-from acts_contrib.test_utils.tel.tel_test_utils import start_wifi_tethering
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_data
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_4g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation_for_subscription
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import \
- wait_for_data_attach_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_reset
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_SSID_KEY
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_detection
-from acts_contrib.test_utils.tel.tel_test_utils import check_network_validation_fail
+from acts_contrib.test_utils.tel.tel_test_utils import wait_for_data_attach_for_subscription
from acts_contrib.test_utils.tel.tel_test_utils import break_internet_except_sl4a_port
from acts_contrib.test_utils.tel.tel_test_utils import resume_internet_with_sl4a_port
from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_recovery
-from acts_contrib.test_utils.tel.tel_test_utils import \
- test_data_browsing_success_using_sl4a
-from acts_contrib.test_utils.tel.tel_test_utils import \
- test_data_browsing_failure_using_sl4a
+from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_success_using_sl4a
+from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_failure_using_sl4a
from acts_contrib.test_utils.tel.tel_test_utils import set_time_sync_from_network
from acts_contrib.test_utils.tel.tel_test_utils import datetime_handle
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_4g
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import stop_wifi_tethering
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_reset
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
class TelLiveDataTest(TelephonyBaseTest):
@@ -140,7 +125,7 @@
def setup_test(self):
TelephonyBaseTest.setup_test(self)
- self.number_of_devices = 1
+ self.number_of_devices = 2
def teardown_class(self):
TelephonyBaseTest.teardown_class(self)
@@ -162,10 +147,13 @@
"""
ad = self.android_devices[0]
wifi_toggle_state(ad.log, ad, False)
+ self.number_of_devices = 1
+
for iteration in range(3):
ad.log.info("Attempt %d", iteration + 1)
if test_data_browsing_success_using_sl4a(ad.log, ad):
- ad.log.info("Call test PASS in iteration %d", iteration + 1)
+ ad.log.info("Data Browsing test PASS in iteration %d",
+ iteration + 1)
return True
time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
ad.log.info("Data Browsing test FAIL for all 3 iterations")
@@ -185,6 +173,8 @@
"""
ad = self.android_devices[0]
wifi_toggle_state(ad.log, ad, True)
+ self.number_of_devices = 1
+
if not ensure_wifi_connected(ad.log, ad, self.wifi_network_ssid,
self.wifi_network_pass):
ad.log.error("WiFi connect fail.")
@@ -192,7 +182,8 @@
for iteration in range(3):
ad.log.info("Attempt %d", iteration + 1)
if test_data_browsing_success_using_sl4a(ad.log, ad):
- ad.log.info("Call test PASS in iteration %d", iteration + 1)
+ ad.log.info("Data Browsing test PASS in iteration %d",
+ iteration + 1)
wifi_toggle_state(ad.log, ad, False)
return True
time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
@@ -214,6 +205,8 @@
Returns:
True if pass; False if fail.
"""
+ self.number_of_devices = 1
+
return airplane_mode_test(self.log, self.android_devices[0])
@test_tracker_info(uuid="47430f01-583f-4efb-923a-285a51b75d50")
@@ -231,6 +224,8 @@
Returns:
True if pass.
"""
+ self.number_of_devices = 1
+
return wifi_cell_switching(self.log, self.android_devices[0], GEN_4G,
self.wifi_network_ssid,
self.wifi_network_pass)
@@ -249,6 +244,7 @@
success_count = 0
fail_count = 0
self.stress_test_number = 10
+ self.number_of_devices = 1
for i in range(1, self.stress_test_number + 1):
ensure_phones_default_state(
@@ -289,6 +285,8 @@
Returns:
True if pass.
"""
+ self.number_of_devices = 1
+
return wifi_cell_switching(self.log, self.android_devices[0], GEN_3G,
self.wifi_network_ssid,
self.wifi_network_pass)
@@ -308,6 +306,8 @@
Returns:
True if pass.
"""
+ self.number_of_devices = 1
+
return wifi_cell_switching(self.log, self.android_devices[0], GEN_2G,
self.wifi_network_ssid,
self.wifi_network_pass)
@@ -330,6 +330,8 @@
False if failed.
"""
ads = self.android_devices
+ self.number_of_devices = 1
+
if not phone_setup_volte(self.log, self.android_devices[0]):
self.log.error("Failed to setup VoLTE")
return False
@@ -405,7 +407,6 @@
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):
@@ -486,6 +487,8 @@
True if success.
False if failed.
"""
+ self.number_of_devices = 1
+
wifi_reset(self.log, self.android_devices[0])
wifi_toggle_state(self.log, self.android_devices[0], False)
return data_connectivity_single_bearer(self.log,
@@ -506,6 +509,8 @@
True if success.
False if failed.
"""
+ self.number_of_devices = 1
+
wifi_reset(self.log, self.android_devices[0])
wifi_toggle_state(self.log, self.android_devices[0], False)
wifi_toggle_state(self.log, self.android_devices[0], True)
@@ -527,6 +532,8 @@
True if success.
False if failed.
"""
+ self.number_of_devices = 1
+
wifi_reset(self.log, self.android_devices[0])
wifi_toggle_state(self.log, self.android_devices[0], False)
return data_connectivity_single_bearer(self.log,
@@ -547,6 +554,8 @@
True if success.
False if failed.
"""
+ self.number_of_devices = 1
+
wifi_reset(self.log, self.android_devices[0])
wifi_toggle_state(self.log, self.android_devices[0], False)
wifi_toggle_state(self.log, self.android_devices[0], True)
@@ -568,6 +577,8 @@
True if success.
False if failed.
"""
+ self.number_of_devices = 1
+
wifi_reset(self.log, self.android_devices[0])
wifi_toggle_state(self.log, self.android_devices[0], False)
return data_connectivity_single_bearer(self.log,
@@ -588,6 +599,8 @@
True if success.
False if failed.
"""
+ self.number_of_devices = 1
+
wifi_reset(self.log, self.android_devices[0])
wifi_toggle_state(self.log, self.android_devices[0], False)
wifi_toggle_state(self.log, self.android_devices[0], True)
@@ -609,6 +622,7 @@
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):
@@ -1463,6 +1477,8 @@
Returns:
True if entitlement check returns True.
"""
+ self.number_of_devices = 1
+
return verify_tethering_entitlement_check(self.log,
self.provider)
@@ -1565,7 +1581,7 @@
return False
ssid_list = TETHERING_SPECIAL_SSID_LIST
fail_list = {}
- self.number_of_devices = 2
+
for ssid in ssid_list:
password = rand_ascii_str(8)
self.log.info("SSID: <{}>, Password: <{}>".format(ssid, password))
@@ -1599,7 +1615,7 @@
return False
password_list = TETHERING_SPECIAL_PASSWORD_LIST
fail_list = {}
- self.number_of_devices = 2
+
for password in password_list:
ssid = rand_ascii_str(8)
self.log.info("SSID: <{}>, Password: <{}>".format(ssid, password))
@@ -1887,9 +1903,10 @@
False if failed.
"""
ad = self.android_devices[0]
+ self.number_of_devices = 1
current_data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
current_sim_slot_index = get_slot_index_from_subid(
- self.log, ad, current_data_sub_id)
+ ad, current_data_sub_id)
if current_sim_slot_index == SIM1_SLOT_INDEX:
next_sim_slot_index = SIM2_SLOT_INDEX
else:
@@ -1950,6 +1967,8 @@
"""
ad = self.android_devices[0]
+ self.number_of_devices = 1
+
if not ensure_network_generation_for_subscription(
self.log, ad, ad.droid.subscriptionGetDefaultDataSubId(),
GEN_4G, MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
@@ -1979,6 +1998,8 @@
"""
ad = self.android_devices[0]
+ self.number_of_devices = 1
+
if not ensure_network_generation_for_subscription(
self.log, ad, ad.droid.subscriptionGetDefaultDataSubId(),
GEN_3G, MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
@@ -2007,6 +2028,8 @@
False if failed.
"""
ad = self.android_devices[0]
+ self.number_of_devices = 1
+
if not ensure_network_generation_for_subscription(
self.log, ad, ad.droid.subscriptionGetDefaultDataSubId(),
GEN_2G, MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
@@ -2181,7 +2204,7 @@
current_data_sub_id = self.provider.droid.subscriptionGetDefaultDataSubId(
)
current_sim_slot_index = get_slot_index_from_subid(
- self.log, self.provider, current_data_sub_id)
+ self.provider, current_data_sub_id)
self.provider.log.info("Current Data is on subId: %s, SIM slot: %s",
current_data_sub_id, current_sim_slot_index)
if not test_setup_tethering(self.log, self.provider, self.clients, None):
@@ -2240,9 +2263,11 @@
False if failed.
"""
ad = self.android_devices[0]
+ self.number_of_devices = 1
+
current_data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
current_sim_slot_index = get_slot_index_from_subid(
- self.log, ad, current_data_sub_id)
+ ad, current_data_sub_id)
if current_sim_slot_index == SIM1_SLOT_INDEX:
next_sim_slot_index = SIM2_SLOT_INDEX
else:
@@ -2298,6 +2323,8 @@
@TelephonyBaseTest.tel_test_wrap
def test_vzw_embms_services(self):
ad = self.android_devices[0]
+ self.number_of_devices = 1
+
# Install App and Push config
self.log.info("Pushing embms config and apk to the Android device.")
android_embms_path = "/sdcard/mobitv"
@@ -2391,9 +2418,10 @@
False if failed.
"""
ad = self.android_devices[0]
+ self.number_of_devices = 1
current_data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
current_sim_slot_index = get_slot_index_from_subid(
- self.log, ad, current_data_sub_id)
+ ad, current_data_sub_id)
if current_sim_slot_index == SIM1_SLOT_INDEX:
non_active_sim_slot_index = SIM2_SLOT_INDEX
else:
@@ -2440,6 +2468,7 @@
total_count = 0
self.result_info = collections.defaultdict(int)
dut = self.android_devices[0]
+ self.number_of_devices = 1
self.max_sleep_time = int(self.user_params.get("max_sleep_time", 1200))
#file_names = ["5MB", "10MB", "20MB", "50MB", "200MB", "512MB", "1GB"]
file_names = ["5MB", "10MB", "20MB", "50MB", "200MB", "512MB"]
@@ -2499,6 +2528,7 @@
"""
dut = self.android_devices[0]
+ self.number_of_devices = 1
ensure_phones_default_state(self.log, [dut])
subscriber_id = dut.droid.telephonyGetSubscriberId()
old_data_usage = get_mobile_data_usage(dut, subscriber_id)
@@ -2538,6 +2568,8 @@
def _test_data_stall_detection_recovery(self, nw_type="cellular",
validation_type="detection"):
dut = self.android_devices[0]
+ self.number_of_devices = 1
+
try:
cmd = ('ss -l -p -n | grep "tcp.*droid_script" | tr -s " " '
'| cut -d " " -f 5 | sed s/.*://g')
@@ -2585,6 +2617,7 @@
def _test_airplane_mode_stress(self):
ad = self.android_devices[0]
+ self.number_of_devices = 1
total_iteration = self.stress_test_number
fail_count = collections.defaultdict(int)
current_iteration = 1
@@ -2668,6 +2701,8 @@
@TelephonyBaseTest.tel_test_wrap
def test_browsing_4g(self):
ad = self.android_devices[0]
+ self.number_of_devices = 1
+
self.log.info("Connect to LTE and verify internet connection.")
if not phone_setup_4g(self.log, ad):
return False
@@ -2680,6 +2715,8 @@
@TelephonyBaseTest.tel_test_wrap
def test_browsing_wifi(self):
ad = self.android_devices[0]
+ self.number_of_devices = 1
+
self.log.info("Connect to Wi-Fi and verify internet connection.")
if not ensure_wifi_connected(self.log, ad, self.wifi_network_ssid,
self.wifi_network_pass):
@@ -2754,6 +2791,8 @@
"""
ad = self.android_devices[0]
+ self.number_of_devices = 1
+
wifi_toggle_state(ad.log, ad, False)
return self._test_sync_time_from_network(ad)
@@ -2770,6 +2809,8 @@
"""
ad = self.android_devices[0]
+ self.number_of_devices = 1
+
wifi_toggle_state(ad.log, ad, False)
return self._test_sync_time_from_network(ad, data_on=False)
@@ -2777,6 +2818,8 @@
@TelephonyBaseTest.tel_test_wrap
def test_reboot_4g(self):
ad = self.android_devices[0]
+ self.number_of_devices = 1
+
self.log.info("Connect to LTE and verify internet connection.")
if not phone_setup_4g(self.log, ad):
return False
@@ -2789,6 +2832,8 @@
@TelephonyBaseTest.tel_test_wrap
def test_reboot_3g(self):
ad = self.android_devices[0]
+ self.number_of_devices = 1
+
self.log.info("Connect to 3G and verify internet connection.")
if not phone_setup_3g(self.log, ad):
return False
@@ -2801,6 +2846,8 @@
@TelephonyBaseTest.tel_test_wrap
def test_reboot_wifi(self):
ad = self.android_devices[0]
+ self.number_of_devices = 1
+
self.log.info("Connect to Wi-Fi and verify internet connection.")
if not ensure_wifi_connected(self.log, ad, self.wifi_network_ssid,
self.wifi_network_pass):
diff --git a/acts_tests/tests/google/tel/live/TelLiveEmergencyBase.py b/acts_tests/tests/google/tel/live/TelLiveEmergencyBase.py
index edb8b39..eb60081 100644
--- a/acts_tests/tests/google/tel/live/TelLiveEmergencyBase.py
+++ b/acts_tests/tests/google/tel/live/TelLiveEmergencyBase.py
@@ -20,38 +20,26 @@
import re
import time
from acts import signals
-from acts.test_decorators import test_tracker_info
+from acts.utils import get_current_epoch_time
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
-from acts_contrib.test_utils.tel.tel_defines import DEFAULT_DEVICE_PASSWORD
-from acts_contrib.test_utils.tel.tel_defines import PHONE_TYPE_CDMA
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_lookup_tables import operator_capabilities
+from acts_contrib.test_utils.tel.tel_bootloader_utils import reset_device_password
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_default_state
from acts_contrib.test_utils.tel.tel_test_utils import abort_all_tests
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import dumpsys_last_call_info
-from acts_contrib.test_utils.tel.tel_test_utils import dumpsys_last_call_number
-from acts_contrib.test_utils.tel.tel_test_utils import dumpsys_new_call_info
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_default_state
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import fastboot_wipe
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
from acts_contrib.test_utils.tel.tel_test_utils import is_sim_lock_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_emergency_dialer_call_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import last_call_drop_reason
-from acts_contrib.test_utils.tel.tel_test_utils import reset_device_password
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
from acts_contrib.test_utils.tel.tel_test_utils import unlock_sim
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_sim_ready_by_adb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts.utils import get_current_epoch_time
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import dumpsys_last_call_info
+from acts_contrib.test_utils.tel.tel_voice_utils import dumpsys_last_call_number
+from acts_contrib.test_utils.tel.tel_voice_utils import dumpsys_new_call_info
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call_by_adb
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_emergency_dialer_call_by_adb
+from acts_contrib.test_utils.tel.tel_voice_utils import last_call_drop_reason
CARRIER_OVERRIDE_CMD = (
"am broadcast -a com.google.android.carrier.action.LOCAL_OVERRIDE -n "
diff --git a/acts_tests/tests/google/tel/live/TelLiveEmergencyTest.py b/acts_tests/tests/google/tel/live/TelLiveEmergencyTest.py
index e29ed7a..9f078b3 100644
--- a/acts_tests/tests/google/tel/live/TelLiveEmergencyTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveEmergencyTest.py
@@ -23,15 +23,15 @@
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
from acts_contrib.test_utils.tel.tel_defines import DEFAULT_DEVICE_PASSWORD
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_bootloader_utils import fastboot_wipe
+from acts_contrib.test_utils.tel.tel_bootloader_utils import reset_device_password
from acts_contrib.test_utils.tel.tel_lookup_tables import operator_capabilities
-from acts_contrib.test_utils.tel.tel_test_utils import fastboot_wipe
-from acts_contrib.test_utils.tel.tel_test_utils import reset_device_password
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_2g
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_sim_ready_by_adb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
from TelLiveEmergencyBase import TelLiveEmergencyBase
diff --git a/acts_tests/tests/google/tel/live/TelLiveGFTDSDSDDSSwitchTest.py b/acts_tests/tests/google/tel/live/TelLiveGFTDSDSDDSSwitchTest.py
index 2734fed..b762af0 100644
--- a/acts_tests/tests/google/tel/live/TelLiveGFTDSDSDDSSwitchTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveGFTDSDSDDSSwitchTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2020 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,64 +14,54 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import re
import time
-from acts import asserts
from acts import signals
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import \
- TelephonyVoiceTestResult
-from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import \
- TelephonyMetricLogger
+from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts_contrib.test_utils.tel.tel_data_utils import reboot_test
+from acts_contrib.test_utils.tel.tel_data_utils import start_youtube_video
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection_for_subscription
+from acts_contrib.test_utils.tel.tel_ims_utils import is_volte_enabled
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode_for_subscription
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte_for_subscription
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc_for_subscription
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify_for_subscription
+from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_message_utils import log_messaging_screen_shot
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_on_rat
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
from acts_contrib.test_utils.tel.tel_subscription_utils import set_message_subid
from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_data
from acts_contrib.test_utils.tel.tel_subscription_utils import set_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_subid_on_same_network_of_host_ad
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import start_youtube_video
-from acts_contrib.test_utils.tel.tel_test_utils import \
- wait_for_cell_data_connection_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_wfc_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import \
- sms_send_receive_verify_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import mms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import log_messaging_screen_shot
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import get_slot_index_from_subid
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import is_volte_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import check_is_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_enabled
-from acts_contrib.test_utils.tel.tel_voice_utils import \
- phone_setup_volte_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_on_rat
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat
from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_msim_for_slot
+from acts_contrib.test_utils.tel.tel_wifi_utils import check_is_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
from acts.utils import rand_ascii_str
CallResult = TelephonyVoiceTestResult.CallResult.Value
+
class TelLiveGFTDSDSDDSSwitchTest(TelephonyBaseTest):
def setup_class(self):
TelephonyBaseTest.setup_class(self)
@@ -335,10 +325,8 @@
if call_or_sms_or_mms == "call":
self.log.info("Step 4: Make voice call.")
- mo_slot = get_slot_index_from_subid(
- self.log, ad_mo, mo_sub_id)
- mt_slot = get_slot_index_from_subid(
- self.log, ad_mt, mt_sub_id)
+ mo_slot = get_slot_index_from_subid(ad_mo, mo_sub_id)
+ mt_slot = get_slot_index_from_subid(ad_mt, mt_sub_id)
result = two_phone_call_msim_for_slot(
self.log,
ad_mo,
@@ -668,8 +656,8 @@
return False
self.log.info("Step 6: Make voice call.")
- mo_slot = get_slot_index_from_subid(self.log, ad_mo, mo_sub_id)
- mt_slot = get_slot_index_from_subid(self.log, ad_mt, mt_sub_id)
+ mo_slot = get_slot_index_from_subid(ad_mo, mo_sub_id)
+ mt_slot = get_slot_index_from_subid(ad_mt, mt_sub_id)
result = two_phone_call_msim_for_slot(
self.log,
ad_mo,
diff --git a/acts_tests/tests/google/tel/live/TelLiveGFTDSDSMessageTest.py b/acts_tests/tests/google/tel/live/TelLiveGFTDSDSMessageTest.py
index b735184..344da22 100644
--- a/acts_tests/tests/google/tel/live/TelLiveGFTDSDSMessageTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveGFTDSDSMessageTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2020 - Google
+# Copyright 2021 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,51 +14,31 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import time
-
-from acts import asserts
from acts import signals
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import \
- TelephonyVoiceTestResult
-from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import \
- TelephonyMetricLogger
+from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_incoming_voice_sub_id
+from acts_contrib.test_utils.tel.tel_dsds_utils import dsds_message_test
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_on_rat
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_outgoing_message_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
from acts_contrib.test_utils.tel.tel_subscription_utils import set_message_subid
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_data
from acts_contrib.test_utils.tel.tel_subscription_utils import set_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_subid_on_same_network_of_host_ad
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import \
- sms_send_receive_verify_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import \
- sms_in_collision_send_receive_verify_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import \
- sms_rx_power_off_multiple_send_receive_verify_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import \
- voice_call_in_collision_with_mt_sms_msim
-from acts_contrib.test_utils.tel.tel_test_utils import mms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot
+from acts_contrib.test_utils.tel.tel_message_utils import log_messaging_screen_shot
+from acts_contrib.test_utils.tel.tel_message_utils import sms_in_collision_send_receive_verify_for_subscription
+from acts_contrib.test_utils.tel.tel_message_utils import sms_rx_power_off_multiple_send_receive_verify_for_subscription
+from acts_contrib.test_utils.tel.tel_message_utils import voice_call_in_collision_with_mt_sms_msim
from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import log_messaging_screen_shot
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import get_slot_index_from_subid
-from acts_contrib.test_utils.tel.tel_voice_utils import \
- phone_setup_voice_general_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_on_rat
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat
from acts.utils import rand_ascii_str
+from acts.libs.utils.multithread import multithread_func
CallResult = TelephonyVoiceTestResult.CallResult.Value
@@ -71,71 +51,6 @@
def teardown_test(self):
ensure_phones_idle(self.log, self.android_devices)
- def _msim_message_test(
- self,
- ad_mo,
- ad_mt,
- mo_sub_id,
- mt_sub_id, msg="SMS",
- max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
- expected_result=True):
- """Make MO/MT SMS/MMS at specific slot.
-
- Args:
- ad_mo: Android object of the device sending SMS/MMS
- ad_mt: Android object of the device receiving SMS/MMS
- mo_sub_id: Sub ID of MO device
- mt_sub_id: Sub ID of MT device
- max_wait_time: Max wait time before SMS/MMS is received.
- expected_result: True for successful sending/receiving and False on
- the contrary
-
- Returns:
- True if the result matches expected_result and False on the
- contrary.
- """
-
- if msg == "SMS":
- for length in self.message_lengths:
- message_array = [rand_ascii_str(length)]
- if not sms_send_receive_verify_for_subscription(
- self.log,
- ad_mo,
- ad_mt,
- mo_sub_id,
- mt_sub_id,
- message_array,
- max_wait_time):
- ad_mo.log.warning(
- "%s of length %s test failed", msg, length)
- return False
- else:
- ad_mo.log.info(
- "%s of length %s test succeeded", msg, length)
- self.log.info("%s test of length %s characters succeeded.",
- msg, self.message_lengths)
-
- elif msg == "MMS":
- for length in self.message_lengths:
- message_array = [("Test Message", rand_ascii_str(length), None)]
-
- if not mms_send_receive_verify(
- self.log,
- ad_mo,
- ad_mt,
- message_array,
- max_wait_time,
- expected_result):
- self.log.warning("%s of body length %s test failed",
- msg, length)
- return False
- else:
- self.log.info(
- "%s of body length %s test succeeded", msg, length)
- self.log.info("%s test of body lengths %s succeeded",
- msg, self.message_lengths)
- return True
-
def _msim_sms_collision_test(
self,
ad_mo,
@@ -245,181 +160,6 @@
"off succeeded.", self.message_lengths)
return True
-
- def _test_msim_message(
- self,
- mo_slot,
- mt_slot,
- dds_slot,
- msg="SMS",
- mo_rat=["", ""],
- mt_rat=["", ""],
- direction="mo",
- expected_result=True):
- """Make MO/MT SMS/MMS at specific slot in specific RAT with DDS at
- specific slot.
-
- Test step:
- 1. Get sub IDs of specific slots of both MO and MT devices.
- 2. Switch DDS to specific slot.
- 3. Check HTTP connection after DDS switch.
- 4. Set up phones in desired RAT.
- 5. Send SMS/MMS.
-
- Args:
- mo_slot: Slot sending MO SMS (0 or 1)
- mt_slot: Slot receiving MT SMS (0 or 1)
- dds_slot: Preferred data slot
- mo_rat: RAT for both slots of MO device
- mt_rat: RAT for both slots of MT device
- direction: "mo" or "mt"
- expected_result: True of False
-
- Returns:
- TestFailure if failed.
- """
- ads = self.android_devices
-
- if direction == "mo":
- ad_mo = ads[0]
- ad_mt = ads[1]
- else:
- ad_mo = ads[1]
- ad_mt = ads[0]
-
- if mo_slot is not None:
- mo_sub_id = get_subid_from_slot_index(self.log, ad_mo, mo_slot)
- if mo_sub_id == INVALID_SUB_ID:
- ad_mo.log.warning("Failed to get sub ID at slot %s.", mo_slot)
- return False
- mo_other_sub_id = get_subid_from_slot_index(
- self.log, ad_mo, 1-mo_slot)
- set_message_subid(ad_mo, mo_sub_id)
- else:
- _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(
- ads, type="sms")
- if mo_sub_id == INVALID_SUB_ID:
- ad_mo.log.warning("Failed to get sub ID at slot %s.", mo_slot)
- return False
- mo_slot = "auto"
- set_message_subid(ad_mo, mo_sub_id)
- if msg == "MMS":
- set_subid_for_data(ad_mo, mo_sub_id)
- ad_mo.droid.telephonyToggleDataConnection(True)
- ad_mo.log.info("Sub ID for outgoing %s at slot %s: %s", msg, mo_slot,
- get_outgoing_message_sub_id(ad_mo))
-
- if mt_slot is not None:
- mt_sub_id = get_subid_from_slot_index(self.log, ad_mt, mt_slot)
- if mt_sub_id == INVALID_SUB_ID:
- ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
- return False
- mt_other_sub_id = get_subid_from_slot_index(
- self.log, ad_mt, 1-mt_slot)
- set_message_subid(ad_mt, mt_sub_id)
- else:
- _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
- ads, type="sms")
- if mt_sub_id == INVALID_SUB_ID:
- ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
- return False
- mt_slot = "auto"
- set_message_subid(ad_mt, mt_sub_id)
- if msg == "MMS":
- set_subid_for_data(ad_mt, mt_sub_id)
- ad_mt.droid.telephonyToggleDataConnection(True)
- ad_mt.log.info("Sub ID for incoming %s at slot %s: %s", msg, mt_slot,
- get_outgoing_message_sub_id(ad_mt))
-
- self.log.info("Step 1: Switch DDS.")
- if dds_slot:
- if not set_dds_on_slot_1(ads[0]):
- self.log.warning(
- "Failed to set DDS at eSIM on %s", ads[0].serial)
- return False
- else:
- if not set_dds_on_slot_0(ads[0]):
- self.log.warning(
- "Failed to set DDS at pSIM on %s", ads[0].serial)
- return False
-
- self.log.info("Step 2: Check HTTP connection after DDS switch.")
- if not verify_http_connection(self.log,
- ads[0],
- url="https://www.google.com",
- retry=5,
- retry_interval=15,
- expected_state=True):
-
- self.log.error("Failed to verify http connection.")
- return False
- else:
- self.log.info("Verify http connection successfully.")
-
- if mo_slot == 0 or mo_slot == 1:
- phone_setup_on_rat(self.log, ad_mo, mo_rat[1-mo_slot], mo_other_sub_id)
- else:
- phone_setup_on_rat(self.log, ad_mo, 'general', sub_id_type='sms')
-
- if mt_slot == 0 or mt_slot == 1:
- phone_setup_on_rat(self.log, ad_mt, mt_rat[1-mt_slot], mt_other_sub_id)
- else:
- phone_setup_on_rat(self.log, ad_mt, 'general', sub_id_type='sms')
-
- if mo_slot == 0 or mo_slot == 1:
- mo_phone_setup_func = phone_setup_on_rat(
- self.log,
- ad_mo,
- mo_rat[mo_slot],
- only_return_fn=True)
- else:
- mo_phone_setup_func = phone_setup_voice_general_for_subscription
-
- if mt_slot == 0 or mt_slot == 1:
- mt_phone_setup_func = phone_setup_on_rat(
- self.log,
- ad_mt,
- mt_rat[mt_slot],
- only_return_fn=True)
- else:
- mt_phone_setup_func = phone_setup_voice_general_for_subscription
-
- self.log.info("Step 3: Set up phones in desired RAT.")
- tasks = [(mo_phone_setup_func, (self.log, ad_mo, mo_sub_id)),
- (mt_phone_setup_func, (self.log, ad_mt, mt_sub_id))]
- 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("Step 4: Send %s.", msg)
-
- if msg == "MMS":
- for ad, current_data_sub_id, current_msg_sub_id in [
- [ ads[0],
- get_default_data_sub_id(ads[0]),
- get_outgoing_message_sub_id(ads[0]) ],
- [ ads[1],
- get_default_data_sub_id(ads[1]),
- get_outgoing_message_sub_id(ads[1]) ]]:
- if current_data_sub_id != current_msg_sub_id:
- ad.log.warning(
- "Current data sub ID (%s) does not match message"
- " sub ID (%s). MMS should NOT be sent.",
- current_data_sub_id,
- current_msg_sub_id)
- expected_result = False
-
- result = self._msim_message_test(ad_mo, ad_mt, mo_sub_id, mt_sub_id,
- msg=msg, expected_result=expected_result)
-
- if not result:
- log_messaging_screen_shot(ad_mo, test_name="%s_tx" % msg)
- log_messaging_screen_shot(ad_mt, test_name="%s_rx" % msg)
-
- return result
-
-
def _test_msim_voice_call_in_collision_with_mt_sms(
self,
mo_voice_slot,
@@ -456,21 +196,17 @@
_, mt_voice_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
set_voice_sub_id(ad_mt_voice, mt_voice_sub_id)
ad_mt_voice.log.info("Sub ID for incoming call at slot %s: %s",
- get_slot_index_from_subid(self.log, ad_mt_voice, mt_voice_sub_id),
+ get_slot_index_from_subid(ad_mt_voice, mt_voice_sub_id),
get_incoming_voice_sub_id(ad_mt_voice))
set_message_subid(
ad, get_subid_from_slot_index(self.log, ad, mt_sms_slot))
self.log.info("Step 1: Switch DDS.")
- if dds_slot:
- if not set_dds_on_slot_1(ads[0]):
- ads[0].log.warning("Failed to set DDS at eSIM.")
- return False
- else:
- if not set_dds_on_slot_0(ads[0]):
- ads[0].log.warning("Failed to set DDS at pSIM.")
- return False
+ if not set_dds_on_slot(ads[0], dds_slot):
+ ads[0].log.error(
+ "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
+ return False
self.log.info("Step 2: Check HTTP connection after DDS switch.")
if not verify_http_connection(self.log,
@@ -548,7 +284,7 @@
mo_voice_slot,
ad_mt_voice.serial,
get_slot_index_from_subid(
- self.log, ad_mt_voice, mt_voice_sub_id))
+ ad_mt_voice, mt_voice_sub_id))
extras = {"call_fail_reason": str(result.result_value)}
if not sms_result or not call_result:
@@ -661,865 +397,1153 @@
@test_tracker_info(uuid="4ae61fdf-2078-4e50-ae03-cb2e9299ce8d")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_volte_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["volte", "volte"], msg="SMS", direction="mo")
@test_tracker_info(uuid="0e8801f8-7203-45ba-aff3-cb667fd538e1")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_volte_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["volte", "volte"], msg="SMS", direction="mo")
@test_tracker_info(uuid="d54c2b4e-2e32-49f0-9536-879eb6f6577e")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_volte_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["volte", "volte"], msg="SMS", direction="mt")
@test_tracker_info(uuid="feed9119-df31-46f7-afd8-addf4052422a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_volte_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["volte", "volte"], msg="SMS", direction="mt")
@test_tracker_info(uuid="1da9965c-c863-4e6e-9374-a082fa16d6fd")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_volte_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["volte", "volte"], msg="SMS", direction="mo")
@test_tracker_info(uuid="64aec600-851f-4bde-b66c-130c69d1d5b6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_volte_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["volte", "volte"], msg="SMS", direction="mo")
@test_tracker_info(uuid="9ce40c2c-3a59-4612-a0cc-4fcba887856c")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_volte_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["volte", "volte"], msg="SMS", direction="mt")
@test_tracker_info(uuid="4e46081d-733d-47d9-be4d-9e492de38bcd")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_volte_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["volte", "volte"], msg="SMS", direction="mt")
@test_tracker_info(uuid="5ede96ed-78b5-4cfb-94a3-44c34d610bef")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_volte_csfb_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["volte", "csfb"], msg="SMS", direction="mo")
@test_tracker_info(uuid="ae681d36-e450-4453-88a8-e9abf4bdf723")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_volte_csfb_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["volte", "csfb"], msg="SMS", direction="mo")
@test_tracker_info(uuid="6490abf9-7fc9-4168-ba20-7da0cb18d96e")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_volte_csfb_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["volte", "csfb"], msg="SMS", direction="mt")
@test_tracker_info(uuid="71590c9e-add0-4cbb-a530-07f58d26d954")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_volte_csfb_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["volte", "csfb"], msg="SMS", direction="mt")
@test_tracker_info(uuid="1b033914-8a26-48e0-829a-c85b5a93ce42")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_volte_csfb_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["volte", "csfb"], msg="SMS", direction="mo")
@test_tracker_info(uuid="15ebac40-5dc3-47ee-a787-ae6f9d71aff6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_volte_csfb_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["volte", "csfb"], msg="SMS", direction="mo")
@test_tracker_info(uuid="b38390d2-b5ab-414b-9c61-2324395a56a6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_volte_csfb_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["volte", "csfb"], msg="SMS", direction="mt")
@test_tracker_info(uuid="1c4a3a34-800a-4117-8c32-b6ec7d58a5cb")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_volte_csfb_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["volte", "csfb"], msg="SMS", direction="mt")
@test_tracker_info(uuid="c7645032-8006-448e-ae3e-86c9223482cf")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_csfb_volte_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["csfb", "volte"], msg="SMS", direction="mo")
@test_tracker_info(uuid="a4455da1-6314-4d2e-a6eb-c7e063a5fd10")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_csfb_volte_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["csfb", "volte"], msg="SMS", direction="mo")
@test_tracker_info(uuid="60828bcc-0111-4d97-ac01-b43ff9c33b11")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_csfb_volte_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["csfb", "volte"], msg="SMS", direction="mt")
@test_tracker_info(uuid="d0f04ab9-c1fe-41b1-8ffc-7bf7cbb408ea")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_csfb_volte_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["csfb", "volte"], msg="SMS", direction="mt")
@test_tracker_info(uuid="97ad2e6f-8b71-49d4-870c-2f4438351880")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_csfb_volte_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["csfb", "volte"], msg="SMS", direction="mo")
@test_tracker_info(uuid="8353bce2-a800-440c-9822-a922343d0ff5")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_csfb_volte_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["csfb", "volte"], msg="SMS", direction="mo")
@test_tracker_info(uuid="7659d23d-8cf4-4ace-8e53-b26fc2fca38c")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_csfb_volte_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["csfb", "volte"], msg="SMS", direction="mt")
@test_tracker_info(uuid="91577f12-4a0e-4743-82bc-1b7581a6940d")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_csfb_volte_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["csfb", "volte"], msg="SMS", direction="mt")
@test_tracker_info(uuid="a5f2c1b0-5ae7-4187-ad63-4782dc47f62b")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_volte_3g_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["volte", "3g"], msg="SMS", direction="mo")
@test_tracker_info(uuid="0c983462-5372-4aae-a484-53da4d2b9553")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_volte_3g_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["volte", "3g"], msg="SMS", direction="mo")
@test_tracker_info(uuid="8266aaac-9d67-42c3-9260-d80c377b1ef9")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_volte_3g_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["volte", "3g"], msg="SMS", direction="mt")
@test_tracker_info(uuid="d6ae749b-5e69-489e-8fda-fcb38aaa6cb0")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_volte_3g_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["volte", "3g"], msg="SMS", direction="mt")
@test_tracker_info(uuid="f4985e53-d530-491c-94cd-51ba22a34eff")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_volte_3g_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["volte", "3g"], msg="SMS", direction="mo")
@test_tracker_info(uuid="b4fc2379-6937-404a-a659-249c1ccf9dd0")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_volte_3g_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["volte", "3g"], msg="SMS", direction="mo")
@test_tracker_info(uuid="e1027a25-b19f-4fb7-bfb9-79919e380c25")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_volte_3g_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["volte", "3g"], msg="SMS", direction="mt")
@test_tracker_info(uuid="7cf99f83-0542-42c8-8e72-1653e381aa6c")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_volte_3g_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["volte", "3g"], msg="SMS", direction="mt")
@test_tracker_info(uuid="c1084606-a63b-41da-a0cb-2db972b6a8ce")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_3g_volte_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["3g", "volte"], msg="SMS", direction="mo")
@test_tracker_info(uuid="4806716c-047a-4a33-a317-97d3cce5d2ca")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_3g_volte_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["3g", "volte"], msg="SMS", direction="mo")
@test_tracker_info(uuid="2877ff0b-d567-4683-baa3-20e254ed025c")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_3g_volte_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["3g", "volte"], msg="SMS", direction="mt")
@test_tracker_info(uuid="6bf3ea1b-e75c-4844-a311-5a18b1b7a1b8")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_3g_volte_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["3g", "volte"], msg="SMS", direction="mt")
@test_tracker_info(uuid="fb7bf8b2-fa44-4e05-a0ab-16e7b1907e6b")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_3g_volte_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["3g", "volte"], msg="SMS", direction="mo")
@test_tracker_info(uuid="d9090125-61cb-4ef5-97de-06c2ec8529bd")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_3g_volte_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["3g", "volte"], msg="SMS", direction="mo")
@test_tracker_info(uuid="d764c5ea-a34a-4b29-ab50-63bd63ebe5c4")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_3g_volte_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["3g", "volte"], msg="SMS", direction="mt")
@test_tracker_info(uuid="fe7d2f8c-eeb6-4ae9-a57d-1636d3153d2b")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_3g_volte_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["3g", "volte"], msg="SMS", direction="mt")
@test_tracker_info(uuid="b9a5cb40-4986-4811-90e7-628d1729ccb2")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_csfb_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["csfb", "csfb"], msg="SMS", direction="mo")
@test_tracker_info(uuid="220665c1-4c63-4450-b8bb-17fc6df24498")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_csfb_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["csfb", "csfb"], msg="SMS", direction="mo")
@test_tracker_info(uuid="968217a6-320f-41f0-b401-7c377309d983")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_csfb_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["csfb", "csfb"], msg="SMS", direction="mt")
@test_tracker_info(uuid="c6a5bf63-af40-4619-a0eb-0d1835fde36c")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_csfb_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["csfb", "csfb"], msg="SMS", direction="mt")
@test_tracker_info(uuid="ea9f4e72-0dea-4f5f-b5ff-4a0bad0d29a0")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_csfb_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["csfb", "csfb"], msg="SMS", direction="mo")
@test_tracker_info(uuid="4eb935f0-2b11-4b2d-8faa-9a022e36813a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_csfb_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["csfb", "csfb"], msg="SMS", direction="mo")
@test_tracker_info(uuid="765e31fd-b412-43a8-a6a8-5d3ae66cab18")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_csfb_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["csfb", "csfb"], msg="SMS", direction="mt")
@test_tracker_info(uuid="bc6ada03-6a5e-4fe7-80c4-3aebc9fa426f")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_csfb_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["csfb", "csfb"], msg="SMS", direction="mt")
@test_tracker_info(uuid="a42994d0-bdb3-487e-98f2-665899d3edba")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_csfb_3g_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["csfb", "3g"], msg="SMS", direction="mo")
@test_tracker_info(uuid="d8ef0ac8-9cb1-4f32-8211-84dee563af00")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_csfb_3g_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["csfb", "3g"], msg="SMS", direction="mo")
@test_tracker_info(uuid="f4eb2254-5148-4cf9-b53f-56d8665de645")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_csfb_3g_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["csfb", "3g"], msg="SMS", direction="mt")
@test_tracker_info(uuid="fd546290-f7e7-47ff-b165-a9bb01e91c64")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_csfb_3g_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["csfb", "3g"], msg="SMS", direction="mt")
@test_tracker_info(uuid="d6994024-e845-48e2-9cd6-d72e97480a8a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_csfb_3g_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["csfb", "3g"], msg="SMS", direction="mo")
@test_tracker_info(uuid="c816165e-49d8-4d0a-8bb5-e64ad910a55a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_csfb_3g_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["csfb", "3g"], msg="SMS", direction="mo")
@test_tracker_info(uuid="647d546f-b325-4b91-be84-0bedf5a33210")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_csfb_3g_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["csfb", "3g"], msg="SMS", direction="mt")
@test_tracker_info(uuid="98b7e161-4953-4566-a96c-21545bf05e51")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_csfb_3g_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["csfb", "3g"], msg="SMS", direction="mt")
@test_tracker_info(uuid="9a3d1330-e70e-4ac0-a8bc-fec5710a8dcd")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_3g_csfb_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["3g", "csfb"], msg="SMS", direction="mo")
@test_tracker_info(uuid="51b4edd3-a867-409e-b367-2fd8cf0eb4a6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_3g_csfb_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["3g", "csfb"], msg="SMS", direction="mo")
@test_tracker_info(uuid="dba9cb2b-84bd-47db-a5a6-826e54a1bbeb")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_3g_csfb_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["3g", "csfb"], msg="SMS", direction="mt")
@test_tracker_info(uuid="263494aa-f3c4-450e-b5bf-b9331d9c9dd8")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_3g_csfb_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["3g", "csfb"], msg="SMS", direction="mt")
@test_tracker_info(uuid="7ba231b8-edc9-4f64-ba7e-5f0360c4eed5")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_3g_csfb_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["3g", "csfb"], msg="SMS", direction="mo")
@test_tracker_info(uuid="ca1e9c35-07f2-4e32-8a59-61efc37f11a4")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_3g_csfb_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["3g", "csfb"], msg="SMS", direction="mo")
@test_tracker_info(uuid="f19252c0-8ff6-4267-adcd-f676407333e6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_3g_csfb_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["3g", "csfb"], msg="SMS", direction="mt")
@test_tracker_info(uuid="34ef2001-d80d-4818-b458-1e8a9556e5cd")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_3g_csfb_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["3g", "csfb"], msg="SMS", direction="mt")
@test_tracker_info(uuid="947ceba7-9aeb-402c-ba36-4856bc4352eb")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_3g_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["3g", "3g"], msg="SMS", direction="mo")
@test_tracker_info(uuid="9f9677e1-1215-49ed-a671-22e7779659a9")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_3g_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["3g", "3g"], msg="SMS", direction="mo")
@test_tracker_info(uuid="f77112c8-85e8-4584-a0b7-bba11c23be7d")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_3g_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["3g", "3g"], msg="SMS", direction="mt")
@test_tracker_info(uuid="facc19fd-7846-488e-9cf1-755f81d0fee2")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_3g_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["3g", "3g"], msg="SMS", direction="mt")
@test_tracker_info(uuid="5a26f35e-c038-409e-8941-7e0b475ebda8")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_3g_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["3g", "3g"], msg="SMS", direction="mo")
@test_tracker_info(uuid="c303aa26-0fd0-44d7-b2fc-32782deaf5ea")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mo_3g_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["3g", "3g"], msg="SMS", direction="mo")
@test_tracker_info(uuid="45cbddd3-889d-46ab-8d7f-9dd971287155")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_3g_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["3g", "3g"], msg="SMS", direction="mt")
@test_tracker_info(uuid="7dacd6b2-9d21-4c4d-bec4-fdfe685cdce8")
@TelephonyBaseTest.tel_test_wrap
def test_msim_sms_mt_3g_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["3g", "3g"], msg="SMS", direction="mt")
@test_tracker_info(uuid="24268e9f-b047-4c67-92f9-22e0bd8b3a11")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_volte_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["volte", "volte"], msg="MMS", direction="mo")
@test_tracker_info(uuid="1d72b01d-5ca7-4899-ae57-ecbeff09bc39")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_volte_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["volte", "volte"], msg="MMS", direction="mo")
@test_tracker_info(uuid="ca2ad510-7f5e-49e4-861e-d433f86c2237")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_volte_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["volte", "volte"], msg="MMS", direction="mt")
@test_tracker_info(uuid="63a0480a-18dd-43e5-82e9-45e008346ea9")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_volte_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["volte", "volte"], msg="MMS", direction="mt")
@test_tracker_info(uuid="5e51f0d9-f1b6-4bfe-88ab-f28ebaa6ee55")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_volte_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["volte", "volte"], msg="MMS", direction="mo")
@test_tracker_info(uuid="fcc7e8aa-41a4-48a1-9586-d6080c77a79b")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_volte_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["volte", "volte"], msg="MMS", direction="mo")
@test_tracker_info(uuid="f633bf56-2d15-462b-994d-e9294d87ca23")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_volte_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["volte", "volte"], msg="MMS", direction="mt")
@test_tracker_info(uuid="3c336061-32cf-4e9a-bb1e-b54e3357e644")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_volte_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["volte", "volte"], msg="MMS", direction="mt")
@test_tracker_info(uuid="50ee8103-0196-4194-b982-9d07c68e57e4")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_volte_csfb_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["volte", "csfb"], msg="MMS", direction="mo")
@test_tracker_info(uuid="ec09405d-b12d-405c-9bfd-ba3eb20eb752")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_volte_csfb_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["volte", "csfb"], msg="MMS", direction="mo")
@test_tracker_info(uuid="26bea731-b653-4e9f-98d1-1b290b959bfc")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_volte_csfb_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["volte", "csfb"], msg="MMS", direction="mt")
@test_tracker_info(uuid="ecc010da-1798-4da3-b041-13e2b2547548")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_volte_csfb_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["volte", "csfb"], msg="MMS", direction="mt")
@test_tracker_info(uuid="cf4c5bd0-525a-497a-a0f8-17acd9dbeabd")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_volte_csfb_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["volte", "csfb"], msg="MMS", direction="mo")
@test_tracker_info(uuid="603f22db-913b-4ad3-b148-7c6d3624bc09")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_volte_csfb_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["volte", "csfb"], msg="MMS", direction="mo")
@test_tracker_info(uuid="561efaf1-7fe4-4196-991e-d03eee28fb4e")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_volte_csfb_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["volte", "csfb"], msg="MMS", direction="mt")
@test_tracker_info(uuid="6f383ef0-d99a-4a3d-b137-e24fa03306b9")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_volte_csfb_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["volte", "csfb"], msg="MMS", direction="mt")
@test_tracker_info(uuid="eeaa1262-c2a0-4f47-baa5-7435fa9e9315")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_csfb_volte_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["csfb", "volte"], msg="MMS", direction="mo")
@test_tracker_info(uuid="478f5497-cc21-4634-8b97-df70dbe286c0")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_csfb_volte_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["csfb", "volte"], msg="MMS", direction="mo")
@test_tracker_info(uuid="1c4af9c6-87d6-438c-aba7-70d8bb4b357e")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_csfb_volte_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["csfb", "volte"], msg="MMS", direction="mt")
@test_tracker_info(uuid="825daee3-db6c-404a-a454-cea98182bf5a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_csfb_volte_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["csfb", "volte"], msg="MMS", direction="mt")
@test_tracker_info(uuid="50fe9f3e-eae1-4a01-8655-02340f85037a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_csfb_volte_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["csfb", "volte"], msg="MMS", direction="mo")
@test_tracker_info(uuid="bae89139-f73f-4a06-bb65-a0bae385fae9")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_csfb_volte_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["csfb", "volte"], msg="MMS", direction="mo")
@test_tracker_info(uuid="42e897e3-4411-45a0-bf62-3ea6f59c2617")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_csfb_volte_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["csfb", "volte"], msg="MMS", direction="mt")
@test_tracker_info(uuid="9847b0c8-517e-42ea-9306-8a4a1cd46cd8")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_csfb_volte_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["csfb", "volte"], msg="MMS", direction="mt")
@test_tracker_info(uuid="5057f8e4-19e7-42c0-bc63-1678d8ce1504")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_volte_3g_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["volte", "3g"], msg="MMS", direction="mo")
@test_tracker_info(uuid="52bb44ae-0263-4415-8a61-337a8f990f8b")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_volte_3g_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["volte", "3g"], msg="MMS", direction="mo")
@test_tracker_info(uuid="deb00e73-b63a-4ed8-8b7f-953704b5d783")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_volte_3g_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["volte", "3g"], msg="MMS", direction="mt")
@test_tracker_info(uuid="e0aa9846-2c02-4ba1-aeef-08a673c497ae")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_volte_3g_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["volte", "3g"], msg="MMS", direction="mt")
@test_tracker_info(uuid="ef06ae23-6f52-4c3b-b228-5c95ed780cd2")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_volte_3g_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["volte", "3g"], msg="MMS", direction="mo")
@test_tracker_info(uuid="69a62cd6-290b-4e58-81ff-0b35ac82262c")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_volte_3g_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["volte", "3g"], msg="MMS", direction="mo")
@test_tracker_info(uuid="645cef41-ddf8-49b4-8a58-2da019883f32")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_volte_3g_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["volte", "3g"], msg="MMS", direction="mt")
@test_tracker_info(uuid="b0b8aac3-cc85-47d9-828a-8016138fe466")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_volte_3g_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["volte", "3g"], msg="MMS", direction="mt")
@test_tracker_info(uuid="1dcebefb-3338-4550-96fa-07b64493db1c")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_3g_volte_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["3g", "volte"], msg="MMS", direction="mo")
@test_tracker_info(uuid="3d06854e-5b86-46fb-9ca2-a217b026733d")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_3g_volte_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["3g", "volte"], msg="MMS", direction="mo")
@test_tracker_info(uuid="0c0f72bc-4076-411d-8a8d-fc6ae414a73a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_3g_volte_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["3g", "volte"], msg="MMS", direction="mt")
@test_tracker_info(uuid="b63211fa-baf0-4dff-bd18-d7f80e85e551")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_3g_volte_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["3g", "volte"], msg="MMS", direction="mt")
@test_tracker_info(uuid="80c2fe4d-e87a-45d7-9b83-23863e75cd94")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_3g_volte_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["3g", "volte"], msg="MMS", direction="mo")
@test_tracker_info(uuid="84be29a1-0b29-4785-baaa-6cf84c503fa6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_3g_volte_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["3g", "volte"], msg="MMS", direction="mo")
@test_tracker_info(uuid="591d2948-2257-4a46-8ccb-5c628d85fc43")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_3g_volte_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["3g", "volte"], msg="MMS", direction="mt")
@test_tracker_info(uuid="67e4dae5-8ca5-475f-af0e-f91b89df68ed")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_3g_volte_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["3g", "volte"], msg="MMS", direction="mt")
@test_tracker_info(uuid="35d33d3e-f618-4ce1-8b40-3dac0ef2731a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_csfb_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["csfb", "csfb"], msg="MMS", direction="mo")
@test_tracker_info(uuid="179e49c7-7066-4285-9b5b-3ef639d8c5e4")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_csfb_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["csfb", "csfb"], msg="MMS", direction="mo")
@test_tracker_info(uuid="09d6954f-d760-47e5-8667-3ed317fdbfbc")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_csfb_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["csfb", "csfb"], msg="MMS", direction="mt")
@test_tracker_info(uuid="80f8c18f-2bd6-4310-be39-472d7a24e08a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_csfb_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["csfb", "csfb"], msg="MMS", direction="mt")
@test_tracker_info(uuid="b700d261-7616-4226-95cc-59ec54cc2678")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_csfb_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["csfb", "csfb"], msg="MMS", direction="mo")
@test_tracker_info(uuid="5cb2cc81-bf3e-4025-b85b-2bf1a4797e41")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_csfb_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["csfb", "csfb"], msg="MMS", direction="mo")
@test_tracker_info(uuid="1af2ac12-4d2d-4a36-8c46-8b3013eadab2")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_csfb_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["csfb", "csfb"], msg="MMS", direction="mt")
@test_tracker_info(uuid="66d8108e-8dd9-42e3-b2cd-49a538beecf6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_csfb_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["csfb", "csfb"], msg="MMS", direction="mt")
@test_tracker_info(uuid="a35df875-72eb-43d7-874c-a7b3f0aea2a9")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_csfb_3g_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["csfb", "3g"], msg="MMS", direction="mo")
@test_tracker_info(uuid="cf718bda-75d6-4906-a33e-110610b01d4d")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_csfb_3g_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["csfb", "3g"], msg="MMS", direction="mo")
@test_tracker_info(uuid="342cbc1a-7151-425c-9bd6-81808a5eb7e6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_csfb_3g_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["csfb", "3g"], msg="MMS", direction="mt")
@test_tracker_info(uuid="01e33aa4-27a9-48fd-b9e8-313980d06b0d")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_csfb_3g_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["csfb", "3g"], msg="MMS", direction="mt")
@test_tracker_info(uuid="fe527335-731e-49a5-a07e-f4999c536153")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_csfb_3g_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["csfb", "3g"], msg="MMS", direction="mo")
@test_tracker_info(uuid="1c56f866-3b3c-45c0-9c13-face44246aca")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_csfb_3g_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["csfb", "3g"], msg="MMS", direction="mo")
@test_tracker_info(uuid="4affd77a-afdc-4ac9-ba8a-a3599efe1e96")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_csfb_3g_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["csfb", "3g"], msg="MMS", direction="mt")
@test_tracker_info(uuid="8440c05e-28d9-45c7-b32e-127f240d12f0")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_csfb_3g_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["csfb", "3g"], msg="MMS", direction="mt")
@test_tracker_info(uuid="a53ebb84-945e-4068-a78a-fd78362e8073")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_3g_csfb_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["3g", "csfb"], msg="MMS", direction="mo")
@test_tracker_info(uuid="23bedcbc-7c09-430d-a162-04de75244fd8")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_3g_csfb_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["3g", "csfb"], msg="MMS", direction="mo")
@test_tracker_info(uuid="e1e1ef53-d91b-4b10-9bd6-e065ca48ab94")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_3g_csfb_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["3g", "csfb"], msg="MMS", direction="mt")
@test_tracker_info(uuid="e813ae3b-b875-43f6-a055-d2119cec9786")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_3g_csfb_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["3g", "csfb"], msg="MMS", direction="mt")
@test_tracker_info(uuid="d5863aab-a46a-4363-8bf8-5dcfc29a9055")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_3g_csfb_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["3g", "csfb"], msg="MMS", direction="mo")
@test_tracker_info(uuid="79a0bd58-0de0-471e-9e53-9cc655700428")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_3g_csfb_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["3g", "csfb"], msg="MMS", direction="mo")
@test_tracker_info(uuid="e9a340f4-22a7-4786-bb5b-370295324d5a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_3g_csfb_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["3g", "csfb"], msg="MMS", direction="mt")
@test_tracker_info(uuid="8a261b43-2532-4c47-ac0c-3a5dd0d51b69")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_3g_csfb_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["3g", "csfb"], msg="MMS", direction="mt")
@test_tracker_info(uuid="2efdf7da-d2ec-4580-a164-5f7b740f9ac6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_3g_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 0, mo_rat=["3g", "3g"], msg="MMS", direction="mo")
@test_tracker_info(uuid="459e9b40-ad4e-4a89-ac89-f3c8ec472d3f")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_3g_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
0, None, 1, mo_rat=["3g", "3g"], msg="MMS", direction="mo")
@test_tracker_info(uuid="130a0e85-1653-4ddf-81b9-dadd26dde1e3")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_3g_psim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 0, mt_rat=["3g", "3g"], msg="MMS", direction="mt")
@test_tracker_info(uuid="e81f0b33-38b3-4a4d-9e05-fb44a689230b")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_3g_psim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 0, 1, mt_rat=["3g", "3g"], msg="MMS", direction="mt")
@test_tracker_info(uuid="61894370-93b5-4ab5-80c7-d50948d38471")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_3g_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 0, mo_rat=["3g", "3g"], msg="MMS", direction="mo")
@test_tracker_info(uuid="8d41ee9a-fed9-4472-ada7-007e56690c67")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mo_3g_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
1, None, 1, mo_rat=["3g", "3g"], msg="MMS", direction="mo")
@test_tracker_info(uuid="6aa41641-2619-48f6-8c5f-1c06260f0e28")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_3g_esim_dds_slot_0(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 0, mt_rat=["3g", "3g"], msg="MMS", direction="mt")
@test_tracker_info(uuid="94d8e05d-eb99-4a71-be00-e725cbd05cae")
@TelephonyBaseTest.tel_test_wrap
def test_msim_mms_mt_3g_esim_dds_slot_1(self):
- return self._test_msim_message(
+ return dsds_message_test(
+ self.log,
+ self.android_devices,
None, 1, 1, mt_rat=["3g", "3g"], msg="MMS", direction="mt")
@test_tracker_info(uuid="207a23b7-17f1-4e27-892d-6c276f463b07")
diff --git a/acts_tests/tests/google/tel/live/TelLiveGFTDSDSSupplementaryServiceTest.py b/acts_tests/tests/google/tel/live/TelLiveGFTDSDSSupplementaryServiceTest.py
index aae30c3..683d747 100644
--- a/acts_tests/tests/google/tel/live/TelLiveGFTDSDSSupplementaryServiceTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveGFTDSDSSupplementaryServiceTest.py
@@ -14,64 +14,26 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import re
-import time
-
-from acts import asserts
from acts import signals
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import \
- TelephonyVoiceTestResult
-from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import \
- TelephonyMetricLogger
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import CALL_CAPABILITY_MANAGE_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import CALL_PROPERTY_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_ACTIVE
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
-from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_incoming_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_subid_on_same_network_of_host_ad
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
-from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
+from acts_contrib.test_utils.tel.tel_dsds_utils import erase_call_forwarding
+from acts_contrib.test_utils.tel.tel_dsds_utils import msim_call_forwarding
+from acts_contrib.test_utils.tel.tel_dsds_utils import msim_call_voice_conf
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_ss_utils import set_call_waiting
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import set_call_waiting
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import \
- wait_and_reject_call_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import erase_call_forwarding_by_mmi
-from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_voice_utils import get_cep_conference_call_id
-from acts_contrib.test_utils.tel.tel_voice_utils import \
- three_phone_call_forwarding_short_seq
-from acts_contrib.test_utils.tel.tel_voice_utils import \
- three_phone_call_waiting_short_seq
-from acts_contrib.test_utils.tel.tel_voice_utils import swap_calls
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_on_rat
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat
-CallResult = TelephonyVoiceTestResult.CallResult.Value
class TelLiveGFTDSDSSupplementaryServiceTest(TelephonyBaseTest):
def setup_class(self):
TelephonyBaseTest.setup_class(self)
self.message_lengths = (50, 160, 180)
self.tel_logger = TelephonyMetricLogger.for_test_case()
- self.erase_call_forwarding(self.log, self.android_devices[0])
+ erase_call_forwarding(self.log, self.android_devices[0])
if not get_capability_for_subscription(
self.android_devices[0],
CAPABILITY_CONFERENCE,
@@ -83,842 +45,16 @@
def teardown_test(self):
ensure_phones_idle(self.log, self.android_devices)
- self.erase_call_forwarding(self.log, self.android_devices[0])
+ erase_call_forwarding(self.log, self.android_devices[0])
set_call_waiting(self.log, self.android_devices[0], enable=1)
- def _hangup_call(self, ad, device_description='Device'):
- if not hangup_call(self.log, ad):
- ad.log.error("Failed to hang up on %s", device_description)
- return False
- return True
-
- def erase_call_forwarding(self, log, ad):
- slot0_sub_id = get_subid_from_slot_index(log, ad, 0)
- slot1_sub_id = get_subid_from_slot_index(log, ad, 1)
- current_voice_sub_id = get_incoming_voice_sub_id(ad)
- for sub_id in (slot0_sub_id, slot1_sub_id):
- set_voice_sub_id(ad, sub_id)
- get_operator_name(log, ad, sub_id)
- erase_call_forwarding_by_mmi(log, ad)
- set_voice_sub_id(ad, current_voice_sub_id)
-
- def _three_phone_call_mo_add_mt(
- self,
- ads,
- phone_setups,
- verify_funcs,
- reject_once=False):
- """Use 3 phones to make MO call and MT call.
-
- Call from PhoneA to PhoneB, accept on PhoneB.
- Call from PhoneC to PhoneA, accept on PhoneA.
-
- Args:
- ads: list of ad object.
- The list should have three objects.
- phone_setups: list of phone setup functions.
- The list should have three objects.
- verify_funcs: list of phone call verify functions.
- The list should have three objects.
-
- Returns:
- If success, return 'call_AB' id in PhoneA.
- if fail, return None.
- """
-
- class _CallException(Exception):
- pass
-
- try:
- verify_func_a, verify_func_b, verify_func_c = verify_funcs
- tasks = []
- for ad, setup_func in zip(ads, phone_setups):
- if setup_func is not None:
- tasks.append((setup_func, (self.log, ad, get_incoming_voice_sub_id(ad))))
- if tasks != [] and not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- raise _CallException("Setup failed.")
- for ad in ads:
- ad.droid.telecomCallClearCallList()
- if num_active_calls(self.log, ad) != 0:
- ad.log.error("Phone Call List is not empty.")
- raise _CallException("Clear call list failed.")
-
- self.log.info("Step1: Call From PhoneA to PhoneB.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=verify_func_a,
- verify_callee_func=verify_func_b):
- raise _CallException("PhoneA call PhoneB failed.")
-
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
- if num_active_calls(self.log, ads[0]) != 1:
- raise _CallException("Call list verify failed.")
- call_ab_id = calls[0]
-
- self.log.info("Step2: Call From PhoneC to PhoneA.")
- if reject_once:
- self.log.info("Step2-1: Reject incoming call once.")
- if not initiate_call(
- self.log,
- ads[2],
- ads[0].telephony['subscription'][get_incoming_voice_sub_id(
- ads[0])]['phone_num']):
- ads[2].log.error("Initiate call failed.")
- raise _CallException("Failed to initiate call.")
-
- if not wait_and_reject_call_for_subscription(
- self.log,
- ads[0],
- get_incoming_voice_sub_id(ads[0]),
- incoming_number= \
- ads[2].telephony['subscription'][
- get_incoming_voice_sub_id(
- ads[2])]['phone_num']):
- ads[0].log.error("Reject call fail.")
- raise _CallException("Failed to reject call.")
-
- self._hangup_call(ads[2], "PhoneC")
- time.sleep(15)
-
- if not call_setup_teardown(
- self.log,
- ads[2],
- ads[0],
- ad_hangup=None,
- verify_caller_func=verify_func_c,
- verify_callee_func=verify_func_a):
- raise _CallException("PhoneA call PhoneC failed.")
- if not verify_incall_state(self.log, [ads[0], ads[1], ads[2]],
- True):
- raise _CallException("Not All phones are in-call.")
-
- except Exception as e:
- self.log.error(e)
- setattr(ads[0], "exception", e)
- return None
-
- return call_ab_id
-
- def _test_ims_conference_merge_drop_second_call_from_participant(
- self, call_ab_id, call_ac_id):
- """Test conference merge and drop in IMS (VoLTE or WiFi Calling) call.
- (supporting both cases of CEP enabled and disabled).
-
- PhoneA in IMS (VoLTE or WiFi Calling) call with PhoneB.
- PhoneA in IMS (VoLTE or WiFi Calling) call with PhoneC.
- Merge calls to conference on PhoneA.
- Hangup on PhoneC, check call continues between AB.
- Hangup on PhoneB, check A ends.
-
- Args:
- call_ab_id: call id for call_AB on PhoneA.
- call_ac_id: call id for call_AC on PhoneA.
-
- Returns:
- True if succeed;
- False if failed.
- """
- ads = self.android_devices
-
- call_conf_id = self._merge_ims_conference_call(call_ab_id, call_ac_id)
- if call_conf_id is None:
- return False
-
- self.log.info("Step5: End call on PhoneC and verify call continues.")
- if not self._hangup_call(ads[2], "PhoneC"):
- return False
- time.sleep(WAIT_TIME_IN_CALL)
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
- if not verify_incall_state(self.log, [ads[0], ads[1]], True):
- return False
- if not verify_incall_state(self.log, [ads[2]], False):
- return False
-
- self.log.info("Step6: End call on PhoneB and verify PhoneA end.")
- if not self._hangup_call(ads[1], "PhoneB"):
- return False
- time.sleep(WAIT_TIME_IN_CALL)
- if not verify_incall_state(self.log, [ads[0], ads[1], ads[2]], False):
- return False
- return True
-
- def _merge_ims_conference_call(self, call_ab_id, call_ac_id):
- """Merge IMS conference call for both cases of CEP enabled and disabled.
-
- PhoneA in IMS (VoLTE or WiFi Calling) call with PhoneB.
- PhoneA in IMS (VoLTE or WiFi Calling) call with PhoneC.
- Merge calls to conference on PhoneA.
-
- Args:
- call_ab_id: call id for call_AB on PhoneA.
- call_ac_id: call id for call_AC on PhoneA.
-
- Returns:
- call_id for conference
- """
- ads = self.android_devices
- 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)
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
-
- call_conf_id = None
- if num_active_calls(self.log, ads[0]) != 1:
- ads[0].log.info("Total number of call ids is not 1.")
- call_conf_id = get_cep_conference_call_id(ads[0])
- if call_conf_id is not None:
- self.log.info("New conference call id is found. CEP enabled.")
- calls.remove(call_conf_id)
- if (set(ads[0].droid.telecomCallGetCallChildren(
- call_conf_id)) != set(calls)):
- ads[0].log.error(
- "Children list %s for conference call is not correct.",
- ads[0].droid.telecomCallGetCallChildren(call_conf_id))
- return None
-
- if (CALL_PROPERTY_CONFERENCE not in ads[0]
- .droid.telecomCallGetProperties(call_conf_id)):
- ads[0].log.error(
- "Conf call id % properties wrong: %s", call_conf_id,
- ads[0].droid.telecomCallGetProperties(call_conf_id))
- return None
-
- if (CALL_CAPABILITY_MANAGE_CONFERENCE not in ads[0]
- .droid.telecomCallGetCapabilities(call_conf_id)):
- ads[0].log.error(
- "Conf call id %s capabilities wrong: %s", call_conf_id,
- ads[0].droid.telecomCallGetCapabilities(call_conf_id))
- return None
-
- if (call_ab_id in calls) or (call_ac_id in calls):
- self.log.error("Previous call ids should not in new call"
- " list after merge.")
- return None
- else:
- for call_id in calls:
- if call_id != call_ab_id and call_id != call_ac_id:
- call_conf_id = call_id
- self.log.info("CEP not enabled.")
-
- if not call_conf_id:
- self.log.error("Merge call fail, no new conference call id.")
- raise signals.TestFailure(
- "Calls were not merged. Failed to merge calls.",
- extras={"fail_reason": "Calls were not merged."
- " Failed to merge calls."})
- if not verify_incall_state(self.log, [ads[0], ads[1], ads[2]], True):
- return False
-
- if ads[0].droid.telecomCallGetCallState(
- call_conf_id) != CALL_STATE_ACTIVE:
- ads[0].log.error(
- "Call_ID: %s, state: %s, expected: STATE_ACTIVE", call_conf_id,
- ads[0].droid.telecomCallGetCallState(call_conf_id))
- return None
-
- return call_conf_id
-
- def _test_wcdma_conference_merge_drop(self, call_ab_id, call_ac_id):
- """Test conference merge and drop in WCDMA/CSFB_WCDMA call.
-
- PhoneA in WCDMA (or CSFB_WCDMA) call with PhoneB.
- PhoneA in WCDMA (or CSFB_WCDMA) call with PhoneC.
- Merge calls to conference on PhoneA.
- Hangup on PhoneC, check call continues between AB.
- Hangup on PhoneB, check A ends.
-
- Args:
- call_ab_id: call id for call_AB on PhoneA.
- call_ac_id: call id for call_AC on PhoneA.
-
- Returns:
- True if succeed;
- False if failed.
- """
- ads = self.android_devices
-
- 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)
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
- num_calls = num_active_calls(self.log, ads[0])
- if num_calls != 3:
- ads[0].log.error("Total number of call ids is not 3.")
- if num_calls == 2:
- if call_ab_id in calls and call_ac_id in calls:
- ads[0].log.error("Calls were not merged."
- " Failed to merge calls.")
- raise signals.TestFailure(
- "Calls were not merged. Failed to merge calls.",
- extras={"fail_reason": "Calls were not merged."
- " Failed to merge calls."})
- return False
- call_conf_id = None
- for call_id in calls:
- if call_id != call_ab_id and call_id != call_ac_id:
- call_conf_id = call_id
- if not call_conf_id:
- self.log.error("Merge call fail, no new conference call id.")
- return False
- if not verify_incall_state(self.log, [ads[0], ads[1], ads[2]], True):
- return False
-
- if ads[0].droid.telecomCallGetCallState(
- call_conf_id) != CALL_STATE_ACTIVE:
- ads[0].log.error(
- "Call_id: %s, state: %s, expected: STATE_ACTIVE", call_conf_id,
- ads[0].droid.telecomCallGetCallState(call_conf_id))
- return False
-
- self.log.info("Step5: End call on PhoneC and verify call continues.")
- if not self._hangup_call(ads[2], "PhoneC"):
- return False
- time.sleep(WAIT_TIME_IN_CALL)
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
- if num_active_calls(self.log, ads[0]) != 1:
- return False
- if not verify_incall_state(self.log, [ads[0], ads[1]], True):
- return False
- if not verify_incall_state(self.log, [ads[2]], False):
- return False
-
- self.log.info("Step6: End call on PhoneB and verify PhoneA end.")
- if not self._hangup_call(ads[1], "PhoneB"):
- return False
- time.sleep(WAIT_TIME_IN_CALL)
- if not verify_incall_state(self.log, [ads[0], ads[1], ads[2]], False):
- return False
- return True
-
- def _test_msim_call_forwarding(
- self,
- caller_slot,
- callee_slot,
- forwarded_callee_slot,
- dds_slot,
- caller_rat=["", ""],
- callee_rat=["", ""],
- forwarded_callee_rat=["", ""],
- call_forwarding_type="unconditional"):
- """Make MO voice call to the primary device at specific slot in specific
- RAT with DDS at specific slot, and then forwarded to 3rd device with
- specific call forwarding type.
-
- Test step:
- 1. Get sub IDs of specific slots of both MO and MT devices.
- 2. Switch DDS to specific slot.
- 3. Check HTTP connection after DDS switch.
- 4. Set up phones in desired RAT.
- 5. Register and enable call forwarding with specifc type.
- 5. Make voice call to the primary device and wait for being forwarded
- to 3rd device.
-
- Args:
- caller_slot: Slot of 2nd device making MO call (0 or 1)
- callee_slot: Slot of primary device receiving and forwarding MT call
- (0 or 1)
- forwarded_callee_slot: Slot of 3rd device receiving forwarded call.
- dds_slot: Preferred data slot
- caller_rat: RAT for both slots of the 2nd device
- callee_rat: RAT for both slots of the primary device
- forwarded_callee_rat: RAT for both slots of the 3rd device
- call_forwarding_type:
- "unconditional"
- "busy"
- "not_answered"
- "not_reachable"
-
- Returns:
- True or False
- """
- ads = self.android_devices
-
- ad_caller = ads[1]
- ad_callee = ads[0]
- ad_forwarded_callee = ads[2]
-
- if callee_slot is not None:
- callee_sub_id = get_subid_from_slot_index(
- self.log, ad_callee, callee_slot)
- if callee_sub_id == INVALID_SUB_ID:
- ad_callee.log.warning(
- "Failed to get sub ID at slot %s.", callee_slot)
- return False
- callee_other_sub_id = get_subid_from_slot_index(
- self.log, ad_callee, 1-callee_slot)
- set_voice_sub_id(ad_callee, callee_sub_id)
- else:
- callee_sub_id, _, _ = get_subid_on_same_network_of_host_ad(ads)
- if callee_sub_id == INVALID_SUB_ID:
- ad_callee.log.warning(
- "Failed to get sub ID at slot %s.", callee_slot)
- return False
- callee_slot = "auto"
- set_voice_sub_id(ad_callee, callee_sub_id)
- ad_callee.log.info(
- "Sub ID for incoming call at slot %s: %s",
- callee_slot, get_incoming_voice_sub_id(ad_callee))
-
- if caller_slot is not None:
- caller_sub_id = get_subid_from_slot_index(
- self.log, ad_caller, caller_slot)
- if caller_sub_id == INVALID_SUB_ID:
- ad_caller.log.warning(
- "Failed to get sub ID at slot %s.", caller_slot)
- return False
- caller_other_sub_id = get_subid_from_slot_index(
- self.log, ad_caller, 1-caller_slot)
- set_voice_sub_id(ad_caller, caller_sub_id)
- else:
- _, caller_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
- if caller_sub_id == INVALID_SUB_ID:
- ad_caller.log.warning(
- "Failed to get sub ID at slot %s.", caller_slot)
- return False
- caller_slot = "auto"
- set_voice_sub_id(ad_caller, caller_sub_id)
- ad_caller.log.info(
- "Sub ID for outgoing call at slot %s: %s",
- caller_slot, get_outgoing_voice_sub_id(ad_caller))
-
- if forwarded_callee_slot is not None:
- forwarded_callee_sub_id = get_subid_from_slot_index(
- self.log, ad_forwarded_callee, forwarded_callee_slot)
- if forwarded_callee_sub_id == INVALID_SUB_ID:
- ad_forwarded_callee.log.warning(
- "Failed to get sub ID at slot %s.", forwarded_callee_slot)
- return False
- forwarded_callee_other_sub_id = get_subid_from_slot_index(
- self.log, ad_forwarded_callee, 1-forwarded_callee_slot)
- set_voice_sub_id(
- ad_forwarded_callee, forwarded_callee_sub_id)
- else:
- _, _, forwarded_callee_sub_id = \
- get_subid_on_same_network_of_host_ad(ads)
- if forwarded_callee_sub_id == INVALID_SUB_ID:
- ad_forwarded_callee.log.warning(
- "Failed to get sub ID at slot %s.", forwarded_callee_slot)
- return False
- forwarded_callee_slot = "auto"
- set_voice_sub_id(
- ad_forwarded_callee, forwarded_callee_sub_id)
- ad_forwarded_callee.log.info(
- "Sub ID for incoming call at slot %s: %s",
- forwarded_callee_slot,
- get_incoming_voice_sub_id(ad_forwarded_callee))
-
- self.log.info("Step 1: Switch DDS.")
- if dds_slot:
- if not set_dds_on_slot_1(ads[0]):
- self.log.warning(
- "Failed to set DDS at eSIM on %s", ads[0].serial)
- return False
- else:
- if not set_dds_on_slot_0(ads[0]):
- self.log.warning(
- "Failed to set DDS at pSIM on %s", ads[0].serial)
- return False
-
- self.log.info("Step 2: Check HTTP connection after DDS switch.")
- if not verify_http_connection(self.log,
- ads[0],
- url="https://www.google.com",
- retry=5,
- retry_interval=15,
- expected_state=True):
-
- self.log.error("Failed to verify http connection.")
- return False
- else:
- self.log.info("Verify http connection successfully.")
-
- if caller_slot == 1:
- phone_setup_on_rat(
- self.log,
- ad_caller,
- caller_rat[0],
- caller_other_sub_id)
-
- elif caller_slot == 0:
- phone_setup_on_rat(
- self.log,
- ad_caller,
- caller_rat[1],
- caller_other_sub_id)
- else:
- phone_setup_on_rat(
- self.log,
- ad_caller,
- 'general')
-
- if callee_slot == 1:
- phone_setup_on_rat(
- self.log,
- ad_callee,
- callee_rat[0],
- callee_other_sub_id)
-
- elif callee_slot == 0:
- phone_setup_on_rat(
- self.log,
- ad_callee,
- callee_rat[1],
- callee_other_sub_id)
- else:
- phone_setup_on_rat(
- self.log,
- ad_callee,
- 'general')
-
- if forwarded_callee_slot == 1:
- phone_setup_on_rat(
- self.log,
- ad_forwarded_callee,
- forwarded_callee_rat[0],
- forwarded_callee_other_sub_id)
-
- elif forwarded_callee_slot == 0:
- phone_setup_on_rat(
- self.log,
- ad_forwarded_callee,
- forwarded_callee_rat[1],
- forwarded_callee_other_sub_id)
- else:
- phone_setup_on_rat(
- self.log,
- ad_forwarded_callee,
- 'general')
-
- if caller_slot == 0 or caller_slot == 1:
- caller_phone_setup_func = phone_setup_on_rat(
- self.log, ad_caller, caller_rat[caller_slot], only_return_fn=True)
- else:
- caller_phone_setup_func = phone_setup_on_rat(
- self.log, ad_caller, 'general', only_return_fn=True)
-
- callee_phone_setup_func = phone_setup_on_rat(
- self.log, ad_callee, callee_rat[callee_slot], only_return_fn=True)
-
- if forwarded_callee_slot == 0 or forwarded_callee_slot == 1:
- forwarded_callee_phone_setup_func = phone_setup_on_rat(
- self.log,
- ad_forwarded_callee,
- forwarded_callee_rat[forwarded_callee_slot],
- only_return_fn=True)
- else:
- forwarded_callee_phone_setup_func = phone_setup_on_rat(
- self.log,
- ad_forwarded_callee,
- 'general',
- only_return_fn=True)
-
- self.log.info("Step 3: Set up phones in desired RAT.")
- tasks = [(caller_phone_setup_func, (self.log, ad_caller, caller_sub_id)),
- (callee_phone_setup_func, (self.log, ad_callee, callee_sub_id)),
- (forwarded_callee_phone_setup_func,
- (self.log, ad_forwarded_callee, forwarded_callee_sub_id))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- self.tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
- raise signals.TestFailure("Failed",
- extras={"fail_reason": "Phone Failed to Set Up Properly."})
-
- is_callee_in_call = is_phone_in_call_on_rat(
- self.log, ad_callee, callee_rat[callee_slot], only_return_fn=True)
-
- is_call_waiting = re.search(
- "call_waiting (True (\d)|False)", call_forwarding_type, re.I)
- if is_call_waiting:
- if is_call_waiting.group(1) == "False":
- call_waiting = False
- scenario = None
- else:
- call_waiting = True
- scenario = int(is_call_waiting.group(2))
-
- self.log.info(
- "Step 4: Make voice call with call waiting enabled = %s.",
- call_waiting)
- result = three_phone_call_waiting_short_seq(
- self.log,
- ads[0],
- None,
- is_callee_in_call,
- ads[1],
- ads[2],
- call_waiting=call_waiting, scenario=scenario)
- else:
- self.log.info(
- "Step 4: Make voice call with call forwarding %s.",
- call_forwarding_type)
- result = three_phone_call_forwarding_short_seq(
- self.log,
- ads[0],
- None,
- is_callee_in_call,
- ads[1],
- ads[2],
- call_forwarding_type=call_forwarding_type)
-
- if not result:
- if is_call_waiting:
- pass
- else:
- self.log.error(
- "Failed to make MO call from %s slot %s to %s slot %s"
- " and forward to %s slot %s",
- ad_caller.serial,
- caller_slot,
- ad_callee.serial,
- callee_slot,
- ad_forwarded_callee.serial,
- forwarded_callee_slot)
-
- return result
-
- def _test_msim_call_voice_conf(
- self,
- host_slot,
- p1_slot,
- p2_slot,
- dds_slot,
- host_rat=["volte", "volte"],
- p1_rat="",
- p2_rat="",
- merge=True,
- disable_cw=False):
- """Make a voice conference call at specific slot in specific RAT with
- DDS at specific slot.
-
- Test step:
- 1. Get sub IDs of specific slots of both MO and MT devices.
- 2. Switch DDS to specific slot.
- 3. Check HTTP connection after DDS switch.
- 4. Set up phones in desired RAT and make 3-way voice call.
- 5. Swap calls.
- 6. Merge calls.
-
- Args:
- host_slot: Slot on the primary device to host the comference call.
- 0 or 1 (0 for pSIM or 1 for eSIM)
- p1_slot: Slot on the participant device for the call
- p2_slot: Slot on another participant device for the call
- dds_slot: Preferred data slot
- host_rat: RAT for both slots of the primary device
- p1_rat: RAT for both slots of the participant device
- p2_rat: RAT for both slots of another participant device
- merge: True for merging 2 calls into the conference call. False for
- not merging 2 separated call.
- disable_cw: True for disabling call waiting and False on the
- contrary.
-
- Returns:
- True of False
- """
- ads = self.android_devices
- ad_host = ads[0]
- ad_p1 = ads[1]
- ad_p2 = ads[2]
-
- if host_slot is not None:
- host_sub_id = get_subid_from_slot_index(
- self.log, ad_host, host_slot)
- if host_sub_id == INVALID_SUB_ID:
- ad_host.log.warning("Failed to get sub ID at slot.", host_slot)
- return False
- host_other_sub_id = get_subid_from_slot_index(
- self.log, ad_host, 1-host_slot)
- set_voice_sub_id(ad_host, host_sub_id)
- else:
- host_sub_id, _, _ = get_subid_on_same_network_of_host_ad(ads)
- if host_sub_id == INVALID_SUB_ID:
- ad_host.log.warning("Failed to get sub ID at slot.", host_slot)
- return False
- host_slot = "auto"
- set_voice_sub_id(ad_host, host_sub_id)
-
- ad_host.log.info("Sub ID for outgoing call at slot %s: %s",
- host_slot, get_outgoing_voice_sub_id(ad_host))
-
- if p1_slot is not None:
- p1_sub_id = get_subid_from_slot_index(self.log, ad_p1, p1_slot)
- if p1_sub_id == INVALID_SUB_ID:
- ad_p1.log.warning("Failed to get sub ID at slot %s.", p1_slot)
- return False
- set_voice_sub_id(ad_p1, p1_sub_id)
- else:
- _, p1_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
- if p1_sub_id == INVALID_SUB_ID:
- ad_p1.log.warning("Failed to get sub ID at slot %s.", p1_slot)
- return False
- p1_slot = "auto"
- set_voice_sub_id(ad_p1, p1_sub_id)
- ad_p1.log.info("Sub ID for incoming call at slot %s: %s",
- p1_slot, get_incoming_voice_sub_id(ad_p1))
-
- if p2_slot is not None:
- p2_sub_id = get_subid_from_slot_index(self.log, ad_p2, p2_slot)
- if p2_sub_id == INVALID_SUB_ID:
- ad_p2.log.warning("Failed to get sub ID at slot %s.", p2_slot)
- return False
- set_voice_sub_id(ad_p2, p2_sub_id)
- else:
- _, _, p2_sub_id = get_subid_on_same_network_of_host_ad(ads)
- if p2_sub_id == INVALID_SUB_ID:
- ad_p2.log.warning("Failed to get sub ID at slot %s.", p2_slot)
- return False
- p2_slot = "auto"
- set_voice_sub_id(ad_p2, p2_sub_id)
- ad_p2.log.info("Sub ID for incoming call at slot %s: %s",
- p2_slot, get_incoming_voice_sub_id(ad_p2))
-
- self.log.info("Step 1: Switch DDS.")
- if dds_slot:
- if not set_dds_on_slot_1(ads[0]):
- self.log.warning(
- "Failed to set DDS at eSIM on %s", ads[0].serial)
- return False
- else:
- if not set_dds_on_slot_0(ads[0]):
- self.log.warning(
- "Failed to set DDS at pSIM on %s", ads[0].serial)
- return False
-
- self.log.info("Step 2: Check HTTP connection after DDS switch.")
- if not verify_http_connection(self.log,
- ads[0],
- url="https://www.google.com",
- retry=5,
- retry_interval=15,
- expected_state=True):
-
- self.log.error("Failed to verify http connection.")
- return False
- else:
- self.log.info("Verify http connection successfully.")
-
- if disable_cw:
- if not set_call_waiting(self.log, ad_host, enable=0):
- return False
- else:
- if not set_call_waiting(self.log, ad_host, enable=1):
- return False
-
- if host_slot == 1:
- phone_setup_on_rat(
- self.log,
- ad_host,
- host_rat[0],
- host_other_sub_id)
-
- elif host_slot == 0:
- phone_setup_on_rat(
- self.log,
- ad_host,
- host_rat[1],
- host_other_sub_id)
-
- host_phone_setup_func = phone_setup_on_rat(
- self.log, ad_host, host_rat[host_slot], only_return_fn=True)
-
- is_host_in_call = is_phone_in_call_on_rat(
- self.log, ad_host, host_rat[host_slot], only_return_fn=True)
-
- if p1_rat:
- p1_phone_setup_func = phone_setup_on_rat(
- self.log, ad_p1, p1_rat, only_return_fn=True)
- is_p1_in_call = is_phone_in_call_on_rat(
- self.log, ad_p1, p1_rat, only_return_fn=True)
- else:
- p1_phone_setup_func = phone_setup_on_rat(
- self.log, ad_p1, 'general', only_return_fn=True)
- is_p1_in_call = is_phone_in_call_on_rat(
- self.log, ad_p1, 'general', only_return_fn=True)
-
- if p2_rat:
- p2_phone_setup_func = phone_setup_on_rat(
- self.log, ad_p2, p2_rat, only_return_fn=True)
- is_p2_in_call = is_phone_in_call_on_rat(
- self.log, ad_p2, p2_rat, only_return_fn=True)
- else:
- p2_phone_setup_func = phone_setup_on_rat(
- self.log, ad_p2, 'general', only_return_fn=True)
- is_p2_in_call = is_phone_in_call_on_rat(
- self.log, ad_p2, 'general', only_return_fn=True)
-
- self.log.info("Step 3: Set up phone in desired RAT and make 3-way"
- " voice call.")
- call_ab_id = self._three_phone_call_mo_add_mt(
- [ad_host, ad_p1, ad_p2],
- [host_phone_setup_func, p1_phone_setup_func, p2_phone_setup_func], [
- is_host_in_call, is_p1_in_call,
- is_p2_in_call
- ])
-
- if call_ab_id is None:
- if disable_cw:
- set_call_waiting(self.log, ad_host, enable=1)
- if str(getattr(ad_host, "exception", None)) == \
- "PhoneA call PhoneC failed.":
- ads[0].log.info("PhoneA failed to call PhoneC due to call"
- " waiting being disabled.")
- delattr(ad_host, "exception")
- return True
- self.log.error("Failed to get call_ab_id")
- return False
- else:
- if disable_cw:
- return False
-
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
- if num_active_calls(self.log, ads[0]) != 2:
- return False
- if calls[0] == call_ab_id:
- call_ac_id = calls[1]
- else:
- call_ac_id = calls[0]
-
- if call_ac_id is None:
- self.log.error("Failed to get call_ac_id")
- return False
-
- num_swaps = 2
- self.log.info("Step 4: Begin Swap x%s test.", num_swaps)
- if not swap_calls(self.log, ads, call_ab_id, call_ac_id,
- num_swaps):
- self.log.error("Swap test failed.")
- return False
-
- if not merge:
- result = True
- if not self._hangup_call(ads[1], "PhoneB"):
- result = False
- if not self._hangup_call(ads[2], "PhoneC"):
- result = False
- return result
- else:
- self.log.info("Step 5: Merge calls.")
- if host_rat[host_slot] == "volte":
- return self._test_ims_conference_merge_drop_second_call_from_participant(
- call_ab_id, call_ac_id)
- else:
- return self._test_wcdma_conference_merge_drop(
- call_ab_id, call_ac_id)
-
@test_tracker_info(uuid="ccaeff83-4b8c-488a-8c7f-6bb019528bf8")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_volte_psim_dds_slot_0(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
0,
None,
@@ -929,7 +65,10 @@
@test_tracker_info(uuid="a132bfa6-d545-4970-9a39-55aea7477f8c")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_volte_psim_dds_slot_1(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
0,
None,
@@ -940,7 +79,10 @@
@test_tracker_info(uuid="71a4db8a-d20f-4fcb-ac5f-5fe6b9fa36f5")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_volte_esim_dds_slot_0(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
1,
None,
@@ -951,7 +93,10 @@
@test_tracker_info(uuid="50b064e7-4bf6-4bb3-aed1-e4d78b0b6195")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_volte_esim_dds_slot_1(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
1,
None,
@@ -964,7 +109,10 @@
@test_tracker_info(uuid="b1cfe07f-f4bf-49c4-95f1-f0973f32940e")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_volte_csfb_psim_dds_slot_0(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
0,
None,
@@ -975,7 +123,10 @@
@test_tracker_info(uuid="668bd2c6-beee-4c38-a9e5-8b0cc5937c28")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_volte_csfb_psim_dds_slot_1(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
0,
None,
@@ -986,7 +137,10 @@
@test_tracker_info(uuid="d69e86f3-f279-4cc8-8c1f-8a9dce0acfdf")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_volte_csfb_esim_dds_slot_0(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
1,
None,
@@ -997,7 +151,10 @@
@test_tracker_info(uuid="6156c374-7b07-473b-84f7-45de633f9681")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_volte_csfb_esim_dds_slot_1(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
1,
None,
@@ -1005,12 +162,13 @@
callee_rat=["volte", "csfb"],
call_forwarding_type="unconditional")
-
-
@test_tracker_info(uuid="29e36a21-9c94-418b-8628-e601e56fb168")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_csfb_volte_psim_dds_slot_0(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
0,
None,
@@ -1021,7 +179,10 @@
@test_tracker_info(uuid="36ebf549-e64e-4093-bebf-c9ca56289477")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_csfb_volte_psim_dds_slot_1(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
0,
None,
@@ -1032,7 +193,10 @@
@test_tracker_info(uuid="cfb973d7-aa3b-4e59-9f00-501e42c99947")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_csfb_volte_esim_dds_slot_0(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
1,
None,
@@ -1043,7 +207,10 @@
@test_tracker_info(uuid="a347c3db-e128-4deb-9009-c8b8e8145f67")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_csfb_volte_esim_dds_slot_1(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
1,
None,
@@ -1056,7 +223,10 @@
@test_tracker_info(uuid="7040e929-eb1d-4dc6-a404-2c185dc8a0a0")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_csfb_psim_dds_slot_0(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
0,
None,
@@ -1067,7 +237,10 @@
@test_tracker_info(uuid="b88a2ce3-74c7-41df-8114-71b6c3d0b050")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_csfb_psim_dds_slot_1(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
0,
None,
@@ -1078,7 +251,10 @@
@test_tracker_info(uuid="0ffd2391-ec5a-4a48-b0a8-fceba0c922d3")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_csfb_esim_dds_slot_0(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
1,
None,
@@ -1089,7 +265,10 @@
@test_tracker_info(uuid="44937439-2d0a-4aea-bb4d-263e5ed634b4")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_csfb_esim_dds_slot_1(self):
- return self._test_msim_call_forwarding(
+ return msim_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
None,
1,
None,
@@ -1097,117 +276,158 @@
callee_rat=["csfb", "csfb"],
call_forwarding_type="unconditional")
-
-
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="73ac948b-5260-44f1-a0a6-e4a410cb3283")
def test_msim_voice_conf_call_host_volte_psim_dds_slot_0(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0, None, None, 0, host_rat=["volte", "volte"])
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="75d7fb2c-aa62-4b4f-9e70-8f6b1647f816")
def test_msim_voice_conf_call_host_volte_psim_dds_slot_1(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0, None, None, 1, host_rat=["volte", "volte"])
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="2343369e-0240-4adc-bc01-7c08f9327737")
def test_msim_voice_conf_call_host_volte_esim_dds_slot_0(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1, None, None, 0, host_rat=["volte", "volte"])
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="3a28e621-1d47-432c-a7e8-20d2d9f82588")
def test_msim_voice_conf_call_host_volte_esim_dds_slot_1(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1, None, None, 1, host_rat=["volte", "volte"])
-
-
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="378f24cf-bb96-45e1-8150-02f08d7417b6")
def test_msim_voice_conf_call_host_volte_csfb_psim_dds_slot_0(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0, None, None, 0, host_rat=["volte", "csfb"])
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="e3fdf5ec-eafe-4825-acd3-5d4ff03df1d2")
def test_msim_voice_conf_call_host_volte_csfb_psim_dds_slot_1(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0, None, None, 1, host_rat=["volte", "csfb"])
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="221da988-e8c7-43e5-ae3a-414e8f01e872")
def test_msim_voice_conf_call_host_volte_csfb_esim_dds_slot_0(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1, None, None, 0, host_rat=["volte", "csfb"])
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="ea5f0254-59b8-4f63-8a4a-6f0ecb55ddbf")
def test_msim_voice_conf_call_host_volte_csfb_esim_dds_slot_1(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1, None, None, 1, host_rat=["volte", "csfb"])
-
-
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="90abbc8a-d492-45f9-9919-fae7e44c877a")
def test_msim_voice_conf_call_host_csfb_volte_psim_dds_slot_0(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0, None, None, 0, host_rat=["csfb", "volte"])
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="da98268a-a94a-4fc7-8fb9-8e8573baed50")
def test_msim_voice_conf_call_host_csfb_volte_psim_dds_slot_1(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0, None, None, 1, host_rat=["csfb", "volte"])
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="df46bcf5-48a3-466f-ba37-9519f5a671cf")
def test_msim_voice_conf_call_host_csfb_volte_esim_dds_slot_0(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1, None, None, 0, host_rat=["csfb", "volte"])
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="f0c82ae0-c659-45e3-9a00-419e2da55739")
def test_msim_voice_conf_call_host_csfb_volte_esim_dds_slot_1(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1, None, None, 1, host_rat=["csfb", "volte"])
-
-
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="4831c07a-9a38-4ccd-8fa0-beaf52a2751e")
def test_msim_voice_conf_call_host_csfb_psim_dds_slot_0(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0, None, None, 0, host_rat=["csfb", "csfb"])
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="79cbf768-88ea-4d03-b798-2097789ee456")
def test_msim_voice_conf_call_host_csfb_psim_dds_slot_1(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0, None, None, 1, host_rat=["csfb", "csfb"])
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="68b0a15f-62e4-419d-948a-d74d763a736c")
def test_msim_voice_conf_call_host_csfb_esim_dds_slot_0(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1, None, None, 0, host_rat=["csfb", "csfb"])
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="a93af289-98a8-4d4b-bdbd-54478f273fea")
def test_msim_voice_conf_call_host_csfb_esim_dds_slot_1(self):
- return self._test_msim_call_voice_conf(
+ return msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1, None, None, 1, host_rat=["csfb", "csfb"])
-
-
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="43e450c8-8a0b-4dfc-8c59-d0865c4c6399")
def test_msim_call_waiting_volte_psim_dds_slot_0(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1215,7 +435,10 @@
host_rat=["volte", "volte"],
merge=False, disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1230,7 +453,10 @@
@test_tracker_info(uuid="7d05525e-8fcf-4630-9248-22803a14209d")
def test_msim_call_waiting_volte_psim_dds_slot_1(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1239,7 +465,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1254,7 +483,10 @@
@test_tracker_info(uuid="caec880c-948a-4fcd-b57e-e64fd3048b08")
def test_msim_call_waiting_volte_esim_dds_slot_0(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1263,7 +495,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1278,7 +513,10 @@
@test_tracker_info(uuid="72ec685d-6c36-40cd-81fd-dd97e32b1e48")
def test_msim_call_waiting_volte_esim_dds_slot_1(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1287,7 +525,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1298,13 +539,14 @@
result = False
return result
-
-
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="3cef5c80-b15f-45fa-8376-5252e61d7849")
def test_msim_call_waiting_volte_csfb_psim_dds_slot_0(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1313,7 +555,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1328,7 +573,10 @@
@test_tracker_info(uuid="5da5c799-5349-4cf3-b683-c7372aadfdfa")
def test_msim_call_waiting_volte_csfb_psim_dds_slot_1(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1337,7 +585,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1352,7 +603,10 @@
@test_tracker_info(uuid="30c06bb3-a62f-4dba-90c2-1b00c515034a")
def test_msim_call_waiting_volte_csfb_esim_dds_slot_0(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1361,7 +615,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1376,7 +633,10 @@
@test_tracker_info(uuid="d2b0fdb1-5ea6-4958-a34f-6f701801e3c9")
def test_msim_call_waiting_volte_csfb_esim_dds_slot_1(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1385,7 +645,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1396,13 +659,14 @@
result = False
return result
-
-
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="b239d4be-9a36-4791-84df-ecebae645c84")
def test_msim_call_waiting_csfb_volte_psim_dds_slot_0(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1411,7 +675,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1426,7 +693,10 @@
@test_tracker_info(uuid="51a368e6-83d8-46af-8a85-56aaed787f9f")
def test_msim_call_waiting_csfb_volte_psim_dds_slot_1(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1435,7 +705,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1450,7 +723,10 @@
@test_tracker_info(uuid="73646014-1ead-4bd9-bd8f-2c21da3d596a")
def test_msim_call_waiting_csfb_volte_esim_dds_slot_0(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1459,7 +735,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1474,7 +753,10 @@
@test_tracker_info(uuid="0d520b78-20b8-4be7-833a-40179114cbce")
def test_msim_call_waiting_csfb_volte_esim_dds_slot_1(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1483,7 +765,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1498,7 +783,10 @@
@test_tracker_info(uuid="0544abec-7a59-4de0-be45-0b9b9d706b17")
def test_msim_call_waiting_csfb_psim_dds_slot_0(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1507,7 +795,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1522,7 +813,10 @@
@test_tracker_info(uuid="4329319b-0503-4c51-8792-2f36090b8071")
def test_msim_call_waiting_csfb_psim_dds_slot_1(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1531,7 +825,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
None,
None,
@@ -1546,7 +843,10 @@
@test_tracker_info(uuid="d612ce5c-b4cd-490c-bc6c-7f67c25264aa")
def test_msim_call_waiting_csfb_esim_dds_slot_0(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1555,7 +855,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1570,7 +873,10 @@
@test_tracker_info(uuid="fb4869da-a346-4275-a742-d2c653bfc39a")
def test_msim_call_waiting_csfb_esim_dds_slot_1(self):
result = True
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
@@ -1579,7 +885,10 @@
merge=False,
disable_cw=False):
result = False
- if not self._test_msim_call_voice_conf(
+ if not msim_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
None,
None,
diff --git a/acts_tests/tests/google/tel/live/TelLiveGFTDSDSVoiceTest.py b/acts_tests/tests/google/tel/live/TelLiveGFTDSDSVoiceTest.py
index f984ed7..c51e078 100644
--- a/acts_tests/tests/google/tel/live/TelLiveGFTDSDSVoiceTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveGFTDSDSVoiceTest.py
@@ -14,40 +14,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from acts import asserts
-from acts import signals
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import \
- TelephonyVoiceTestResult
-from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import \
- TelephonyMetricLogger
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_incoming_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_subid_on_same_network_of_host_ad
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import get_slot_index_from_subid
-from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_voice_utils import \
- phone_setup_voice_general_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_on_rat
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat
-from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_msim_for_slot
+from acts_contrib.test_utils.tel.tel_dsds_utils import dsds_voice_call_test
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
-CallResult = TelephonyVoiceTestResult.CallResult.Value
class TelLiveGFTDSDSVoiceTest(TelephonyBaseTest):
def setup_class(self):
@@ -57,597 +29,506 @@
def teardown_test(self):
ensure_phones_idle(self.log, self.android_devices)
- def _hangup_call(self, ad, device_description='Device'):
- if not hangup_call(self.log, ad):
- ad.log.error("Failed to hang up on %s", device_description)
- return False
- return True
-
- def _test_msim_call_voice(
- self,
- mo_slot,
- mt_slot,
- dds_slot,
- mo_rat=["", ""],
- mt_rat=["", ""],
- call_direction="mo"):
- """Make MO/MT voice call at specific slot in specific RAT with DDS at
- specific slot.
-
- Test step:
- 1. Get sub IDs of specific slots of both MO and MT devices.
- 2. Switch DDS to specific slot.
- 3. Check HTTP connection after DDS switch.
- 4. Set up phones in desired RAT.
- 5. Make voice call.
-
- Args:
- mo_slot: Slot making MO call (0 or 1)
- mt_slot: Slot receiving MT call (0 or 1)
- dds_slot: Preferred data slot
- mo_rat: RAT for both slots of MO device
- mt_rat: RAT for both slots of MT device
- call_direction: "mo" or "mt"
-
- Returns:
- TestFailure if failed.
- """
- ads = self.android_devices
-
- if call_direction == "mo":
- ad_mo = ads[0]
- ad_mt = ads[1]
- else:
- ad_mo = ads[1]
- ad_mt = ads[0]
-
- if mo_slot is not None:
- mo_sub_id = get_subid_from_slot_index(self.log, ad_mo, mo_slot)
- if mo_sub_id == INVALID_SUB_ID:
- ad_mo.log.warning("Failed to get sub ID ar slot %s.", mo_slot)
- return False
- mo_other_sub_id = get_subid_from_slot_index(
- self.log, ad_mo, 1-mo_slot)
- set_voice_sub_id(ad_mo, mo_sub_id)
- else:
- _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
- if mo_sub_id == INVALID_SUB_ID:
- ad_mo.log.warning("Failed to get sub ID ar slot %s.", mo_slot)
- return False
- mo_slot = "auto"
- set_voice_sub_id(ad_mo, mo_sub_id)
- ad_mo.log.info("Sub ID for outgoing call at slot %s: %s",
- mo_slot, get_outgoing_voice_sub_id(ad_mo))
-
- if mt_slot is not None:
- mt_sub_id = get_subid_from_slot_index(self.log, ad_mt, mt_slot)
- if mt_sub_id == INVALID_SUB_ID:
- ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
- return False
- mt_other_sub_id = get_subid_from_slot_index(
- self.log, ad_mt, 1-mt_slot)
- set_voice_sub_id(ad_mt, mt_sub_id)
- else:
- _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
- if mt_sub_id == INVALID_SUB_ID:
- ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
- return False
- mt_slot = "auto"
- set_voice_sub_id(ad_mt, mt_sub_id)
- ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot,
- get_incoming_voice_sub_id(ad_mt))
-
- self.log.info("Step 1: Switch DDS.")
- if dds_slot:
- if not set_dds_on_slot_1(ads[0]):
- ads[0].log.warning("Failed to set DDS at eSIM.")
- return False
- else:
- if not set_dds_on_slot_0(ads[0]):
- ads[0].log.warning("Failed to set DDS at pSIM.")
- return False
-
- self.log.info("Step 2: Check HTTP connection after DDS switch.")
- if not verify_http_connection(self.log,
- ads[0],
- url="https://www.google.com",
- retry=5,
- retry_interval=15,
- expected_state=True):
-
- self.log.error("Failed to verify http connection.")
- return False
- else:
- self.log.info("Verify http connection successfully.")
-
- if mo_slot == 0 or mo_slot == 1:
- phone_setup_on_rat(self.log, ad_mo, mo_rat[1-mo_slot], mo_other_sub_id)
- mo_phone_setup_func = phone_setup_on_rat(
- self.log,
- ad_mo,
- mo_rat[mo_slot],
- only_return_fn=True)
- is_mo_in_call = is_phone_in_call_on_rat(
- self.log, ad_mo, mo_rat[mo_slot], only_return_fn=True)
- else:
- phone_setup_on_rat(self.log, ad_mo, 'general')
- mo_phone_setup_func = phone_setup_voice_general_for_subscription
- is_mo_in_call = is_phone_in_call_on_rat(
- self.log, ad_mo, 'general', only_return_fn=True)
-
- if mt_slot == 0 or mt_slot == 1:
- phone_setup_on_rat(self.log, ad_mt, mt_rat[1-mt_slot], mt_other_sub_id)
- mt_phone_setup_func = phone_setup_on_rat(
- self.log,
- ad_mt,
- mt_rat[mt_slot],
- only_return_fn=True)
- is_mt_in_call = is_phone_in_call_on_rat(
- self.log, ad_mt, mt_rat[mt_slot], only_return_fn=True)
- else:
- phone_setup_on_rat(self.log, ad_mt, 'general')
- mt_phone_setup_func = phone_setup_voice_general_for_subscription
- is_mt_in_call = is_phone_in_call_on_rat(
- self.log, ad_mt, 'general', only_return_fn=True)
-
- self.log.info("Step 3: Set up phones in desired RAT.")
- tasks = [(mo_phone_setup_func, (self.log, ad_mo, mo_sub_id)),
- (mt_phone_setup_func, (self.log, ad_mt, mt_sub_id))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- self.tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
- raise signals.TestFailure("Failed",
- extras={"fail_reason": "Phone Failed to Set Up Properly."})
-
- self.log.info("Step 4: Make voice call.")
- result = two_phone_call_msim_for_slot(
- self.log,
- ad_mo,
- get_slot_index_from_subid(self.log, ad_mo, mo_sub_id),
- None,
- is_mo_in_call,
- ad_mt,
- get_slot_index_from_subid(self.log, ad_mt, mt_sub_id),
- None,
- is_mt_in_call)
- self.tel_logger.set_result(result.result_value)
-
- if not result:
- self.log.error(
- "Failed to make MO call from %s slot %s to %s slot %s",
- ad_mo.serial, mo_slot, ad_mt.serial, mt_slot)
- raise signals.TestFailure("Failed",
- extras={"fail_reason": str(result.result_value)})
-
-
@test_tracker_info(uuid="e252aa07-c377-4e12-8f06-ed1dc8f2b6a6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_volte_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 0, mo_rat=["volte", "volte"], call_direction="mo")
@test_tracker_info(uuid="7631b805-48b6-4b91-99a3-eef392e5b0fc")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_volte_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 1, mo_rat=["volte", "volte"], call_direction="mo")
@test_tracker_info(uuid="4771e517-08cf-4169-afe7-fe3e41f05c45")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_volte_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 0, mt_rat=["volte", "volte"], call_direction="mt")
@test_tracker_info(uuid="e8f914df-cada-4187-ab53-734624c9c941")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_volte_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 1, mt_rat=["volte", "volte"], call_direction="mt")
@test_tracker_info(uuid="967a665a-9614-4fe4-b293-e20b66637802")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_volte_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 0, mo_rat=["volte", "volte"], call_direction="mo")
@test_tracker_info(uuid="901c7fa3-039f-4888-90eb-82af587fa8dd")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_volte_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 1, mo_rat=["volte", "volte"], call_direction="mo")
@test_tracker_info(uuid="a78f2808-a6c6-4483-b7f5-ad1ec925dd52")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_volte_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 0, mt_rat=["volte", "volte"], call_direction="mt")
@test_tracker_info(uuid="f6994dbd-c5a0-42c7-a43d-67227f5dfb88")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_volte_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 1, mt_rat=["volte", "volte"], call_direction="mt")
@test_tracker_info(uuid="0786d7d3-d272-4233-83dd-0667e844094d")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_volte_csfb_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 0, mo_rat=["volte", "csfb"], call_direction="mo")
@test_tracker_info(uuid="b9dfd46c-752c-4424-83b1-b5749a7018af")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_volte_csfb_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 1, mo_rat=["volte", "csfb"], call_direction="mo")
@test_tracker_info(uuid="8bc57654-a5d9-4c82-b11a-62e76ece9b43")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_volte_csfb_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 0, mt_rat=["volte", "csfb"], call_direction="mt")
@test_tracker_info(uuid="dbe44bf1-4638-4490-a06f-406205681ca5")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_volte_csfb_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 1, mt_rat=["volte", "csfb"], call_direction="mt")
@test_tracker_info(uuid="ffd82db7-eaaa-4f96-9e3b-e0e15d054e62")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_volte_csfb_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 0, mo_rat=["volte", "csfb"], call_direction="mo")
@test_tracker_info(uuid="f7f3f28b-eecf-42e5-ba28-168a38337c80")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_volte_csfb_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 1, mo_rat=["volte", "csfb"], call_direction="mo")
@test_tracker_info(uuid="eb6ae70a-3251-4642-8268-b91b593cecfd")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_volte_csfb_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 0, mt_rat=["volte", "csfb"], call_direction="mt")
@test_tracker_info(uuid="1d927140-34d2-4fc7-8fe4-b23a303fd190")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_volte_csfb_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 1, mt_rat=["volte", "csfb"], call_direction="mt")
@test_tracker_info(uuid="f15f6696-6e11-414b-8e28-9c16793b66b0")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_csfb_volte_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 0, mo_rat=["csfb", "volte"], call_direction="mo")
@test_tracker_info(uuid="ca99d987-0bdb-4034-892f-cc0b1d22f381")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_csfb_volte_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 1, mo_rat=["csfb", "volte"], call_direction="mo")
@test_tracker_info(uuid="692bd3d0-05be-4597-afab-2f837a3f9bd4")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_csfb_volte_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 0, mt_rat=["csfb", "volte"], call_direction="mt")
@test_tracker_info(uuid="87a5fae2-f32c-4b4d-8028-d065b582b117")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_csfb_volte_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 1, mt_rat=["csfb", "volte"], call_direction="mt")
@test_tracker_info(uuid="f6375034-5ecb-4872-bab2-cf9529f20fda")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_csfb_volte_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 0, mo_rat=["csfb", "volte"], call_direction="mo")
@test_tracker_info(uuid="6185bc28-1703-4ca2-a617-171d81adfe9a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_csfb_volte_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 1, mo_rat=["csfb", "volte"], call_direction="mo")
@test_tracker_info(uuid="06bad228-27af-47b4-9b74-aacba81f9da7")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_csfb_volte_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 0, mt_rat=["csfb", "volte"], call_direction="mt")
@test_tracker_info(uuid="5a5f2178-2ac6-4d21-bf6f-b9d8455365f1")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_csfb_volte_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 1, mt_rat=["csfb", "volte"], call_direction="mt")
@test_tracker_info(uuid="216f8569-8120-43c4-a9c5-da3081d168db")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_volte_3g_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 0, mo_rat=["volte", "3g"], call_direction="mo")
@test_tracker_info(uuid="8d15524a-f7f9-4321-a962-b455bfdf4ec9")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_volte_3g_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 1, mo_rat=["volte", "3g"], call_direction="mo")
@test_tracker_info(uuid="c6aa5975-9ea6-4367-a59e-a248fde2c8be")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_volte_3g_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 0, mt_rat=["volte", "3g"], call_direction="mt")
@test_tracker_info(uuid="a99a54e0-46ea-4d35-a3c1-d825c546cc21")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_volte_3g_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 1, mt_rat=["volte", "3g"], call_direction="mt")
@test_tracker_info(uuid="6d128732-8a8e-488b-bb38-fbb764d228dd")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_volte_3g_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 0, mo_rat=["volte", "3g"], call_direction="mo")
@test_tracker_info(uuid="29517d00-5edf-4617-9d29-226d56426abf")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_volte_3g_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 1, mo_rat=["volte", "3g"], call_direction="mo")
@test_tracker_info(uuid="d18ec79e-3bc3-4c7e-89fd-d03519b2e2a6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_volte_3g_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 0, mt_rat=["volte", "3g"], call_direction="mt")
@test_tracker_info(uuid="6442b85a-b116-4987-b6d5-2d2b9bac7fd5")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_volte_3g_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 1, mt_rat=["volte", "3g"], call_direction="mt")
@test_tracker_info(uuid="82e6f955-5156-4ad3-885d-d1d5ff0526cb")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_3g_volte_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 0, mo_rat=["3g", "volte"], call_direction="mo")
@test_tracker_info(uuid="ffdafbac-026d-4d7d-a1dc-f639c01db818")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_3g_volte_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 1, mo_rat=["3g", "volte"], call_direction="mo")
@test_tracker_info(uuid="b18dc6a7-e4a1-4409-a4aa-4e4add2fee13")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_3g_volte_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 0, mt_rat=["3g", "volte"], call_direction="mt")
@test_tracker_info(uuid="ea6fc855-31b8-4680-b306-51228277e0d3")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_3g_volte_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 1, mt_rat=["3g", "volte"], call_direction="mt")
@test_tracker_info(uuid="fdf9f4ea-a6f6-4434-a912-13711bb33a72")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_3g_volte_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 0, mo_rat=["3g", "volte"], call_direction="mo")
@test_tracker_info(uuid="deb8e2f6-e097-451e-9f19-aadaf1820fea")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_3g_volte_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 1, mo_rat=["3g", "volte"], call_direction="mo")
@test_tracker_info(uuid="6a636c5d-5da9-4916-9751-435ab39aaa00")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_3g_volte_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 0, mt_rat=["3g", "volte"], call_direction="mt")
@test_tracker_info(uuid="0b9d9d5c-e5e7-4c9d-ab8a-0658fadbf450")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_3g_volte_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 1, mt_rat=["3g", "volte"], call_direction="mt")
@test_tracker_info(uuid="fce99df9-8931-4a34-9285-121145fb9b2f")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_csfb_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 0, mo_rat=["csfb", "csfb"], call_direction="mo")
@test_tracker_info(uuid="81d9a087-e494-40e4-a0fb-7e4ef62e566c")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_csfb_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 1, mo_rat=["csfb", "csfb"], call_direction="mo")
@test_tracker_info(uuid="d4520000-9cd1-4aff-9862-bfb6832d51ce")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_csfb_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 0, mt_rat=["csfb", "csfb"], call_direction="mt")
@test_tracker_info(uuid="0eaf1e67-6aec-4a39-8f06-4e49009400e0")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_csfb_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 1, mt_rat=["csfb", "csfb"], call_direction="mt")
@test_tracker_info(uuid="0e6bc15a-e510-4b56-826c-96e0add6b20a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_csfb_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 0, mo_rat=["csfb", "csfb"], call_direction="mo")
@test_tracker_info(uuid="ecead288-424d-4579-bf6a-10a1a78600d5")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_csfb_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 1, mo_rat=["csfb", "csfb"], call_direction="mo")
@test_tracker_info(uuid="3a76076d-808e-45f8-b99c-95b82f2f07de")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_csfb_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 0, mt_rat=["csfb", "csfb"], call_direction="mt")
@test_tracker_info(uuid="af638c75-c0e1-4ac1-83f5-bc0e6cdd913c")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_csfb_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 1, mt_rat=["csfb", "csfb"], call_direction="mt")
@test_tracker_info(uuid="0bf59f38-ddbc-4a88-bc8a-d6985e7d7567")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_csfb_3g_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 0, mo_rat=["csfb", "3g"], call_direction="mo")
@test_tracker_info(uuid="59f5a14a-c7e5-4bca-82dd-cb90b9a7a0e1")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_csfb_3g_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 1, mo_rat=["csfb", "3g"], call_direction="mo")
@test_tracker_info(uuid="79fc4d6f-0915-4717-80ae-db656cf3a82c")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_csfb_3g_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 0, mt_rat=["csfb", "3g"], call_direction="mt")
@test_tracker_info(uuid="b4927ebb-ae36-4ca7-a0b7-ea011b271122")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_csfb_3g_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 1, mt_rat=["csfb", "3g"], call_direction="mt")
@test_tracker_info(uuid="620be8d5-40b7-45f2-abfd-f788c8ce1977")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_csfb_3g_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 0, mo_rat=["csfb", "3g"], call_direction="mo")
@test_tracker_info(uuid="e277e0db-2dfb-4cfc-8d13-7c699f397b9b")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_csfb_3g_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 1, mo_rat=["csfb", "3g"], call_direction="mo")
@test_tracker_info(uuid="f7822fca-a22d-4989-bca8-506e9652cee1")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_csfb_3g_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 0, mt_rat=["csfb", "3g"], call_direction="mt")
@test_tracker_info(uuid="60e5f5cd-a2e1-4a6a-b76b-25a8ce2b037d")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_csfb_3g_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 1, mt_rat=["csfb", "3g"], call_direction="mt")
@test_tracker_info(uuid="ef4b5c61-e9c9-4a29-8ff1-f9920ec9f4dd")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_3g_csfb_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 0, mo_rat=["3g", "csfb"], call_direction="mo")
@test_tracker_info(uuid="0e82934d-391d-46af-9609-f59522140ea9")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_3g_csfb_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 1, mo_rat=["3g", "csfb"], call_direction="mo")
@test_tracker_info(uuid="dab9ea2d-5370-4438-b0ee-67c68ebda024")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_3g_csfb_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 0, mt_rat=["3g", "csfb"], call_direction="mt")
@test_tracker_info(uuid="3ba5816e-11fe-4a39-968d-2e9853e8f47a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_3g_csfb_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 1, mt_rat=["3g", "csfb"], call_direction="mt")
@test_tracker_info(uuid="e8246c60-031d-4362-94c6-ad0882511d21")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_3g_csfb_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 0, mo_rat=["3g", "csfb"], call_direction="mo")
@test_tracker_info(uuid="db66ecb2-b09d-44be-991b-8025c6fab26a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_3g_csfb_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 1, mo_rat=["3g", "csfb"], call_direction="mo")
@test_tracker_info(uuid="008e990c-94e4-4adc-abaa-e328d84079a5")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_3g_csfb_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 0, mt_rat=["3g", "csfb"], call_direction="mt")
@test_tracker_info(uuid="0a87cbb1-96d9-4eed-b92c-745432dc4ba4")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_3g_csfb_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 1, mt_rat=["3g", "csfb"], call_direction="mt")
@test_tracker_info(uuid="5620c3c8-e847-42c1-ae4e-b3370a0b6f98")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_3g_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 0, mo_rat=["3g", "3g"], call_direction="mo")
@test_tracker_info(uuid="a4415a1e-cd91-4a74-8f49-6c8ea428fe8f")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_3g_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
0, None, 1, mo_rat=["3g", "3g"], call_direction="mo")
@test_tracker_info(uuid="35a73981-15d7-491f-bade-42642cabbf76")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_3g_psim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 0, mt_rat=["3g", "3g"], call_direction="mt")
@test_tracker_info(uuid="e38de6bd-8f6b-4a95-8c0f-e685abc3e7ef")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_3g_psim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 0, 1, mt_rat=["3g", "3g"], call_direction="mt")
@test_tracker_info(uuid="1c86a1cb-5bd6-404a-a38f-4619a4b641a2")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_3g_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 0, mo_rat=["3g", "3g"], call_direction="mo")
@test_tracker_info(uuid="665736ff-206f-4c02-ae81-26f2e25d5988")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mo_3g_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
1, None, 1, mo_rat=["3g", "3g"], call_direction="mo")
@test_tracker_info(uuid="5e5c8f33-60e5-44be-bf69-56c7715ead41")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_3g_esim_dds_slot_0(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 0, mt_rat=["3g", "3g"], call_direction="mt")
@test_tracker_info(uuid="2250b4d5-7b34-45cb-8ec2-300f4a4fbc2b")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_call_mt_3g_esim_dds_slot_1(self):
- return self._test_msim_call_voice(
+ return dsds_voice_call_test(
+ self.log, self.tel_logger, self.android_devices,
None, 1, 1, mt_rat=["3g", "3g"], call_direction="mt")
\ No newline at end of file
diff --git a/acts_tests/tests/google/tel/live/TelLiveGFTDSDSWfcSupplementaryServiceTest.py b/acts_tests/tests/google/tel/live/TelLiveGFTDSDSWfcSupplementaryServiceTest.py
index acdb8eb..f88661a 100644
--- a/acts_tests/tests/google/tel/live/TelLiveGFTDSDSWfcSupplementaryServiceTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveGFTDSDSWfcSupplementaryServiceTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2020 - Google
+# Copyright 2021 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,90 +14,32 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import re
-import time
-from acts import asserts
from acts import signals
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import \
- TelephonyVoiceTestResult
-from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import \
- TelephonyMetricLogger
+from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import CALL_CAPABILITY_MANAGE_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import CALL_PROPERTY_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_ACTIVE
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
-from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_incoming_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
-from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_subid_on_same_network_of_host_ad
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
-from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_wfc_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode_for_subscription
+from acts_contrib.test_utils.tel.tel_dsds_utils import erase_call_forwarding
+from acts_contrib.test_utils.tel.tel_dsds_utils import msim_volte_wfc_call_forwarding
+from acts_contrib.test_utils.tel.tel_dsds_utils import msim_volte_wfc_call_voice_conf
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import set_call_forwarding_by_mmi
-from acts_contrib.test_utils.tel.tel_test_utils import erase_call_forwarding_by_mmi
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import set_call_waiting
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import \
- wait_and_reject_call_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_voice_utils import get_cep_conference_call_id
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import \
- phone_setup_csfb_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import \
- phone_setup_voice_3g_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general
-from acts_contrib.test_utils.tel.tel_voice_utils import \
- phone_setup_voice_general_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import \
- phone_setup_volte_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils import \
- three_phone_call_forwarding_short_seq
-from acts_contrib.test_utils.tel.tel_voice_utils import \
- three_phone_call_waiting_short_seq
-from acts_contrib.test_utils.tel.tel_voice_utils import swap_calls
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_on_rat
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat
CallResult = TelephonyVoiceTestResult.CallResult.Value
+
class TelLiveGFTDSDSWfcSupplementaryServiceTest(TelephonyBaseTest):
def setup_class(self):
TelephonyBaseTest.setup_class(self)
self.message_lengths = (50, 160, 180)
self.tel_logger = TelephonyMetricLogger.for_test_case()
toggle_airplane_mode(self.log, self.android_devices[0], False)
- self.erase_call_forwarding(self.log, self.android_devices[0])
+ erase_call_forwarding(self.log, self.android_devices[0])
if not get_capability_for_subscription(
self.android_devices[0],
CAPABILITY_CONFERENCE,
@@ -110,1106 +52,446 @@
def teardown_test(self):
toggle_airplane_mode(self.log, self.android_devices[0], False)
ensure_phones_idle(self.log, self.android_devices)
- self.erase_call_forwarding(self.log, self.android_devices[0])
-
-
- def _hangup_call(self, ad, device_description='Device'):
- if not hangup_call(self.log, ad):
- ad.log.error("Failed to hang up on %s", device_description)
- return False
- return True
-
- def erase_call_forwarding(self, log, ad):
- slot0_sub_id = get_subid_from_slot_index(log, ad, 0)
- slot1_sub_id = get_subid_from_slot_index(log, ad, 1)
- current_voice_sub_id = get_incoming_voice_sub_id(ad)
- for sub_id in (slot0_sub_id, slot1_sub_id):
- set_voice_sub_id(ad, sub_id)
- get_operator_name(log, ad, sub_id)
- erase_call_forwarding_by_mmi(log, ad)
- set_voice_sub_id(ad, current_voice_sub_id)
-
- def _three_phone_call_mo_add_mt(
- self,
- ads,
- phone_setups,
- verify_funcs,
- reject_once=False):
- """Use 3 phones to make MO call and MT call.
-
- Call from PhoneA to PhoneB, accept on PhoneB.
- Call from PhoneC to PhoneA, accept on PhoneA.
-
- Args:
- ads: list of ad object.
- The list should have three objects.
- phone_setups: list of phone setup functions.
- The list should have three objects.
- verify_funcs: list of phone call verify functions.
- The list should have three objects.
-
- Returns:
- If success, return 'call_AB' id in PhoneA.
- if fail, return None.
- """
-
- class _CallException(Exception):
- pass
-
- try:
- verify_func_a, verify_func_b, verify_func_c = verify_funcs
- tasks = []
- for ad, setup_func in zip(ads, phone_setups):
- if setup_func is not None:
- tasks.append((setup_func, (self.log, ad)))
- if tasks != [] and not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- raise _CallException("Setup failed.")
- for ad in ads:
- ad.droid.telecomCallClearCallList()
- if num_active_calls(self.log, ad) != 0:
- ad.log.error("Phone Call List is not empty.")
- raise _CallException("Clear call list failed.")
-
- self.log.info("Step1: Call From PhoneA to PhoneB.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=verify_func_a,
- verify_callee_func=verify_func_b):
- raise _CallException("PhoneA call PhoneB failed.")
-
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
- if num_active_calls(self.log, ads[0]) != 1:
- raise _CallException("Call list verify failed.")
- call_ab_id = calls[0]
-
- self.log.info("Step2: Call From PhoneC to PhoneA.")
- if reject_once:
- self.log.info("Step2-1: Reject incoming call once.")
- if not initiate_call(
- self.log,
- ads[2],
- ads[0].telephony['subscription'][get_incoming_voice_sub_id(
- ads[0])]['phone_num']):
- ads[2].log.error("Initiate call failed.")
- raise _CallException("Failed to initiate call.")
-
- if not wait_and_reject_call_for_subscription(
- self.log,
- ads[0],
- get_incoming_voice_sub_id(ads[0]),
- incoming_number= \
- ads[2].telephony['subscription'][
- get_incoming_voice_sub_id(
- ads[2])]['phone_num']):
- ads[0].log.error("Reject call fail.")
- raise _CallException("Failed to reject call.")
-
- self._hangup_call(ads[2], "PhoneC")
- time.sleep(15)
-
- if not call_setup_teardown(
- self.log,
- ads[2],
- ads[0],
- ad_hangup=None,
- verify_caller_func=verify_func_c,
- verify_callee_func=verify_func_a):
- raise _CallException("PhoneA call PhoneC failed.")
- if not verify_incall_state(self.log, [ads[0], ads[1], ads[2]],
- True):
- raise _CallException("Not All phones are in-call.")
-
- except Exception as e:
- self.log.error(e)
- setattr(ads[0], "exception", e)
- return None
-
- return call_ab_id
-
- def _test_ims_conference_merge_drop_second_call_from_participant(
- self, call_ab_id, call_ac_id):
- """Test conference merge and drop in IMS (VoLTE or WiFi Calling) call.
- (supporting both cases of CEP enabled and disabled).
-
- PhoneA in IMS (VoLTE or WiFi Calling) call with PhoneB.
- PhoneA in IMS (VoLTE or WiFi Calling) call with PhoneC.
- Merge calls to conference on PhoneA.
- Hangup on PhoneC, check call continues between AB.
- Hangup on PhoneB, check A ends.
-
- Args:
- call_ab_id: call id for call_AB on PhoneA.
- call_ac_id: call id for call_AC on PhoneA.
-
- Returns:
- True if succeed;
- False if failed.
- """
- ads = self.android_devices
-
- call_conf_id = self._merge_ims_conference_call(call_ab_id, call_ac_id)
- if call_conf_id is None:
- return False
-
- self.log.info("Step5: End call on PhoneC and verify call continues.")
- if not self._hangup_call(ads[2], "PhoneC"):
- return False
- time.sleep(WAIT_TIME_IN_CALL)
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
- if not verify_incall_state(self.log, [ads[0], ads[1]], True):
- return False
- if not verify_incall_state(self.log, [ads[2]], False):
- return False
-
- self.log.info("Step6: End call on PhoneB and verify PhoneA end.")
- if not self._hangup_call(ads[1], "PhoneB"):
- return False
- time.sleep(WAIT_TIME_IN_CALL)
- if not verify_incall_state(self.log, [ads[0], ads[1], ads[2]], False):
- return False
- return True
-
-
- def _merge_ims_conference_call(self, call_ab_id, call_ac_id):
- """Merge IMS conference call for both cases of CEP enabled and disabled.
-
- PhoneA in IMS (VoLTE or WiFi Calling) call with PhoneB.
- PhoneA in IMS (VoLTE or WiFi Calling) call with PhoneC.
- Merge calls to conference on PhoneA.
-
- Args:
- call_ab_id: call id for call_AB on PhoneA.
- call_ac_id: call id for call_AC on PhoneA.
-
- Returns:
- call_id for conference
- """
- ads = self.android_devices
- 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)
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
-
- call_conf_id = None
- if num_active_calls(self.log, ads[0]) != 1:
- ads[0].log.info("Total number of call ids is not 1.")
- call_conf_id = get_cep_conference_call_id(ads[0])
- if call_conf_id is not None:
- self.log.info("New conference call id is found. CEP enabled.")
- calls.remove(call_conf_id)
- if (set(ads[0].droid.telecomCallGetCallChildren(
- call_conf_id)) != set(calls)):
- ads[0].log.error(
- "Children list %s for conference call is not correct.",
- ads[0].droid.telecomCallGetCallChildren(call_conf_id))
- return None
-
- if (CALL_PROPERTY_CONFERENCE not in ads[0]
- .droid.telecomCallGetProperties(call_conf_id)):
- ads[0].log.error(
- "Conf call id % properties wrong: %s", call_conf_id,
- ads[0].droid.telecomCallGetProperties(call_conf_id))
- return None
-
- if (CALL_CAPABILITY_MANAGE_CONFERENCE not in ads[0]
- .droid.telecomCallGetCapabilities(call_conf_id)):
- ads[0].log.error(
- "Conf call id %s capabilities wrong: %s", call_conf_id,
- ads[0].droid.telecomCallGetCapabilities(call_conf_id))
- return None
-
- if (call_ab_id in calls) or (call_ac_id in calls):
- self.log.error("Previous call ids should not in new call"
- " list after merge.")
- return None
- else:
- for call_id in calls:
- if call_id != call_ab_id and call_id != call_ac_id:
- call_conf_id = call_id
- self.log.info("CEP not enabled.")
-
- if not call_conf_id:
- self.log.error("Merge call fail, no new conference call id.")
- raise signals.TestFailure(
- "Calls were not merged. Failed to merge calls.",
- extras={"fail_reason": "Calls were not merged."
- " Failed to merge calls."})
- if not verify_incall_state(self.log, [ads[0], ads[1], ads[2]], True):
- return False
-
- # Check if Conf Call is currently active
- if ads[0].droid.telecomCallGetCallState(
- call_conf_id) != CALL_STATE_ACTIVE:
- ads[0].log.error(
- "Call_ID: %s, state: %s, expected: STATE_ACTIVE", call_conf_id,
- ads[0].droid.telecomCallGetCallState(call_conf_id))
- return None
-
- return call_conf_id
-
-
- def _test_wcdma_conference_merge_drop(self, call_ab_id, call_ac_id):
- """Test conference merge and drop in WCDMA/CSFB_WCDMA call.
-
- PhoneA in WCDMA (or CSFB_WCDMA) call with PhoneB.
- PhoneA in WCDMA (or CSFB_WCDMA) call with PhoneC.
- Merge calls to conference on PhoneA.
- Hangup on PhoneC, check call continues between AB.
- Hangup on PhoneB, check A ends.
-
- Args:
- call_ab_id: call id for call_AB on PhoneA.
- call_ac_id: call id for call_AC on PhoneA.
-
- Returns:
- True if succeed;
- False if failed.
- """
- ads = self.android_devices
-
- 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)
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
- num_calls = num_active_calls(self.log, ads[0])
- if num_calls != 3:
- ads[0].log.error("Total number of call ids is not 3.")
- if num_calls == 2:
- if call_ab_id in calls and call_ac_id in calls:
- ads[0].log.error("Calls were not merged."
- " Failed to merge calls.")
- raise signals.TestFailure(
- "Calls were not merged. Failed to merge calls.",
- extras={"fail_reason": "Calls were not merged."
- " Failed to merge calls."})
- return False
- call_conf_id = None
- for call_id in calls:
- if call_id != call_ab_id and call_id != call_ac_id:
- call_conf_id = call_id
- if not call_conf_id:
- self.log.error("Merge call fail, no new conference call id.")
- return False
- if not verify_incall_state(self.log, [ads[0], ads[1], ads[2]], True):
- return False
-
- # Check if Conf Call is currently active
- if ads[0].droid.telecomCallGetCallState(
- call_conf_id) != CALL_STATE_ACTIVE:
- ads[0].log.error(
- "Call_id: %s, state: %s, expected: STATE_ACTIVE", call_conf_id,
- ads[0].droid.telecomCallGetCallState(call_conf_id))
- return False
-
- self.log.info("Step5: End call on PhoneC and verify call continues.")
- if not self._hangup_call(ads[2], "PhoneC"):
- return False
- time.sleep(WAIT_TIME_IN_CALL)
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
- if num_active_calls(self.log, ads[0]) != 1:
- return False
- if not verify_incall_state(self.log, [ads[0], ads[1]], True):
- return False
- if not verify_incall_state(self.log, [ads[2]], False):
- return False
-
- self.log.info("Step6: End call on PhoneB and verify PhoneA end.")
- if not self._hangup_call(ads[1], "PhoneB"):
- return False
- time.sleep(WAIT_TIME_IN_CALL)
- if not verify_incall_state(self.log, [ads[0], ads[1], ads[2]], False):
- return False
- return True
-
-
- def _test_msim_volte_wfc_call_forwarding(
- self,
- callee_slot,
- dds_slot,
- callee_rat=["wfc", "wfc"],
- call_forwarding_type="unconditional",
- enable_volte=[True, True],
- enable_wfc=[True, True],
- is_airplane_mode=False,
- is_wifi_connected=False,
- wfc_mode=[
- WFC_MODE_CELLULAR_PREFERRED,
- WFC_MODE_CELLULAR_PREFERRED]):
- """Make VoLTE/WFC call to the primary device at specific slot with DDS
- at specific slot, and then forwarded to 3rd device with specific call
- forwarding type.
-
- Test step:
- 1. Get sub IDs of specific slots of both MO and MT devices.
- 2. Set up phones in desired RAT.
- 3. Enable VoLTE/WFC.
- 4. Switch DDS to specific slot.
- 5. Check HTTP connection after DDS switch.
- 6. Register and enable call forwarding with specifc type.
- 7. Make VoLTE/WFC call to the primary device and wait for being
- forwarded to 3rd device.
-
- Args:
- callee_slot: Slot of primary device receiving and forwarding MT call
- (0 or 1)
- dds_slot: Preferred data slot
- callee_rat: RAT for both slots of the primary device
- call_forwarding_type:
- "unconditional"
- "busy"
- "not_answered"
- "not_reachable"
- enable_volte: True for enabling and False for disabling VoLTE for
- each slot on the primary device
- enable_wfc: True for enabling and False for disabling WFC for
- each slot on the primary device
- is_airplane_mode: True of False for WFC setup
- wfc_mode: Cellular preferred or Wi-Fi preferred.
-
- Returns:
- True or False
- """
- ads = self.android_devices
- ad_caller = ads[1]
- ad_callee = ads[0]
- ad_forwarded_callee = ads[2]
- slot_0_subid = get_subid_from_slot_index(self.log, ad_callee, 0)
- slot_1_subid = get_subid_from_slot_index(self.log, ad_callee, 1)
-
- if not toggle_airplane_mode(self.log, ad_callee, False):
- ad_callee.log.error("Failed to disable airplane mode.")
- return False
-
- # Set up callee (primary device)
- callee_sub_id = get_subid_from_slot_index(
- self.log, ad_callee, callee_slot)
- if callee_sub_id == INVALID_SUB_ID:
- self.log.warning(
- "Failed to get sub ID at slot %s.", callee_slot)
- return
- callee_other_sub_id = get_subid_from_slot_index(
- self.log, ad_callee, 1-callee_slot)
- set_voice_sub_id(ad_callee, callee_sub_id)
- ad_callee.log.info(
- "Sub ID for incoming call at slot %s: %s",
- callee_slot, get_incoming_voice_sub_id(ad_callee))
-
- # Set up caller
- _, caller_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
- if caller_sub_id == INVALID_SUB_ID:
- ad_caller.log.warning("Failed to get proper sub ID of the caller")
- return
- set_voice_sub_id(ad_caller, caller_sub_id)
- ad_caller.log.info(
- "Sub ID for outgoing call of the caller: %s",
- get_outgoing_voice_sub_id(ad_caller))
-
- # Set up forwarded callee
- _, _, forwarded_callee_sub_id = get_subid_on_same_network_of_host_ad(
- ads)
- if forwarded_callee_sub_id == INVALID_SUB_ID:
- ad_forwarded_callee.log.warning(
- "Failed to get proper sub ID of the forwarded callee.")
- return
- set_voice_sub_id(ad_forwarded_callee, forwarded_callee_sub_id)
- ad_forwarded_callee.log.info(
- "Sub ID for incoming call of the forwarded callee: %s",
- get_incoming_voice_sub_id(ad_forwarded_callee))
-
- set_call_forwarding_by_mmi(self.log, ad_callee, ad_forwarded_callee)
-
- ad_callee.log.info("Step 0: Set up phones in desired RAT.")
-
- if callee_slot == 1:
- phone_setup_on_rat(
- self.log,
- ad_callee,
- callee_rat[0],
- callee_other_sub_id,
- is_airplane_mode,
- wfc_mode[0],
- self.wifi_network_ssid,
- self.wifi_network_pass)
-
- elif callee_slot == 0:
- phone_setup_on_rat(
- self.log,
- ad_callee,
- callee_rat[1],
- callee_other_sub_id,
- is_airplane_mode,
- wfc_mode[1],
- self.wifi_network_ssid,
- self.wifi_network_pass)
-
- callee_phone_setup_func = phone_setup_on_rat(
- self.log, ad_callee, callee_rat[callee_slot], only_return_fn=True)
-
- if callee_rat[callee_slot] == 'wfc':
- argv = (
- self.log,
- ad_callee,
- callee_sub_id,
- is_airplane_mode,
- wfc_mode[callee_slot],
- self.wifi_network_ssid,
- self.wifi_network_pass)
- else:
- argv = (self.log, ad_callee, callee_sub_id)
-
- tasks = [(phone_setup_voice_general, (self.log, ad_caller)),
- (callee_phone_setup_func, argv),
- (phone_setup_voice_general, (self.log, ad_forwarded_callee))]
-
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- self.tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
- raise signals.TestFailure("Failed",
- extras={"fail_reason": "Phone Failed to Set Up Properly."})
-
- if is_wifi_connected:
- if not ensure_wifi_connected(
- self.log,
- ad_callee,
- self.wifi_network_ssid,
- self.wifi_network_pass,
- apm=is_airplane_mode):
- return False
- time.sleep(5)
-
- ad_callee.log.info("Step 1: Enable/disable VoLTE and WFC.")
- for sub_id, volte in zip([slot_0_subid, slot_1_subid], enable_volte):
- if not toggle_volte_for_subscription(
- self.log,
- ad_callee,
- new_state=volte,
- sub_id=sub_id):
- return False
-
- for sub_id, wfc, mode in \
- zip([slot_0_subid, slot_1_subid], enable_wfc, wfc_mode):
- if not toggle_wfc_for_subscription(
- self.log,
- ad_callee,
- new_state=wfc,
- sub_id=sub_id):
- return False
- if not set_wfc_mode_for_subscription(ad_callee, mode, sub_id=sub_id):
- return False
-
- ad_callee.log.info("Step 2: Switch DDS.")
- if dds_slot:
- if not set_dds_on_slot_1(ad_callee):
- ad_callee.log.warning(
- "Failed to set DDS at eSIM on %s", ad_callee.serial)
- return
- else:
- if not set_dds_on_slot_0(ad_callee):
- ad_callee.log.warning(
- "Failed to set DDS at pSIM on %s", ad_callee.serial)
- return
-
- ad_callee.log.info("Step 3: Check HTTP connection after DDS switch.")
- if not verify_http_connection(self.log, ad_callee):
- ad_callee.log.error("Failed to verify http connection.")
- return False
- else:
- ad_callee.log.info("Verify http connection successfully.")
-
- is_callee_in_call = is_phone_in_call_on_rat(
- self.log, ad_callee, callee_rat[callee_slot], only_return_fn=True)
-
- is_call_waiting = re.search(
- "call_waiting (True (\d)|False)", call_forwarding_type, re.I)
- if is_call_waiting:
- if is_call_waiting.group(1) == "False":
- call_waiting = False
- scenario = None
- else:
- call_waiting = True
- scenario = int(is_call_waiting.group(2))
-
- self.log.info(
- "Step 4: Make voice call with call waiting enabled = %s.",
- call_waiting)
-
- result = three_phone_call_waiting_short_seq(
- self.log,
- ad_callee,
- None,
- is_callee_in_call,
- ad_caller,
- ad_forwarded_callee,
- call_waiting=call_waiting,
- scenario=scenario)
- else:
- self.log.info(
- "Step 4: Make voice call with call forwarding %s.",
- call_forwarding_type)
- result = three_phone_call_forwarding_short_seq(
- self.log,
- ad_callee,
- None,
- is_callee_in_call,
- ad_caller,
- ad_forwarded_callee,
- call_forwarding_type=call_forwarding_type)
-
- if not result:
- if is_call_waiting:
- pass
- else:
- self.log.error(
- "Failed to make MO call from %s to %s slot %s and forward"
- " to %s.",
- ad_caller.serial,
- ad_callee.serial,
- callee_slot,
- ad_forwarded_callee.serial)
- return result
-
-
- def _test_msim_volte_wfc_call_voice_conf(
- self,
- host_slot,
- dds_slot,
- host_rat=["wfc", "wfc"],
- merge=True,
- disable_cw=False,
- enable_volte=[True, True],
- enable_wfc=[True, True],
- is_airplane_mode=False,
- is_wifi_connected=False,
- wfc_mode=[WFC_MODE_CELLULAR_PREFERRED, WFC_MODE_CELLULAR_PREFERRED],
- reject_once=False):
- """Make a VoLTE/WFC conference call at specific slot with DDS at
- specific slot.
-
- Test step:
- 1. Get sub IDs of specific slots of both MO and MT devices.
- 2. Set up phones in desired RAT
- 3. Enable VoLTE/WFC.
- 4. Switch DDS to specific slot.
- 5. Check HTTP connection after DDS switch.
- 6. Make 3-way VoLTE/WFC call.
- 7. Swap calls.
- 8. Merge calls.
-
- Args:
- host_slot: Slot on the primary device to host the comference call.
- 0 or 1 (0 for pSIM or 1 for eSIM)call
- dds_slot: Preferred data slot
- host_rat: RAT for both slots of the primary devicevice
- merge: True for merging 2 calls into the conference call. False for
- not merging 2 separated call.
- disable_cw: True for disabling call waiting and False on the
- contrary.
- enable_volte: True for enabling and False for disabling VoLTE for
- each slot on the primary device
- enable_wfc: True for enabling and False for disabling WFC for
- each slot on the primary device
- is_airplane_mode: True of False for WFC setup
- wfc_mode: Cellular preferred or Wi-Fi preferred.
- reject_once: True for rejecting the 2nd call once from the 3rd
- device (Phone C) to the primary device (Phone A).
-
- Returns:
- True of False
- """
-
- ads = self.android_devices
- ad_host = ads[0]
- ad_p1 = ads[1]
- ad_p2 = ads[2]
- slot_0_subid = get_subid_from_slot_index(ad_host.log, ad_host, 0)
- slot_1_subid = get_subid_from_slot_index(ad_host.log, ad_host, 1)
-
- host_sub_id = get_subid_from_slot_index(self.log, ad_host, host_slot)
- if host_sub_id == INVALID_SUB_ID:
- ad_host.log.warning("Failed to get sub ID at slot.", host_slot)
- return
- host_other_sub_id = get_subid_from_slot_index(
- self.log, ad_host, 1-host_slot)
- set_voice_sub_id(ad_host, host_sub_id)
- ad_host.log.info(
- "Sub ID for outgoing call at slot %s: %s",
- host_slot, get_outgoing_voice_sub_id(ad_host))
-
- _, p1_sub_id, p2_sub_id = get_subid_on_same_network_of_host_ad(ads)
-
- if p1_sub_id == INVALID_SUB_ID:
- ad_p1.log.warning("Failed to get proper sub ID.")
- return
- set_voice_sub_id(ad_p1, p1_sub_id)
- ad_p1.log.info(
- "Sub ID for incoming call: %s",
- get_incoming_voice_sub_id(ad_p1))
-
- if p2_sub_id == INVALID_SUB_ID:
- ad_p2.log.warning("Failed to get proper sub ID.")
- return
- set_voice_sub_id(ad_p2, p2_sub_id)
- ad_p2.log.info(
- "Sub ID for incoming call: %s", get_incoming_voice_sub_id(ad_p2))
-
- ad_host.log.info("Step 0: Set up phones in desired RAT.")
-
- if disable_cw:
- if not set_call_waiting(self.log, ad_host, enable=0):
- return False
-
- if host_slot == 1:
- phone_setup_on_rat(
- self.log,
- ad_host,
- host_rat[0],
- host_other_sub_id,
- is_airplane_mode,
- wfc_mode[0],
- self.wifi_network_ssid,
- self.wifi_network_pass)
-
- elif host_slot == 0:
- phone_setup_on_rat(
- self.log,
- ad_host,
- host_rat[1],
- host_other_sub_id,
- is_airplane_mode,
- wfc_mode[1],
- self.wifi_network_ssid,
- self.wifi_network_pass)
-
- host_phone_setup_func = phone_setup_on_rat(
- self.log, ad_host, host_rat[host_slot], only_return_fn=True)
-
- if host_rat[host_slot].lower() == 'wfc':
- argv = (
- self.log,
- ad_host,
- host_sub_id,
- is_airplane_mode,
- wfc_mode[host_slot],
- self.wifi_network_ssid,
- self.wifi_network_pass)
- else:
- argv = (self.log, ad_host, host_sub_id)
-
- tasks = [(phone_setup_voice_general, (self.log, ad_p1)),
- (host_phone_setup_func, argv),
- (phone_setup_voice_general, (self.log, ad_p2))]
-
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- self.tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
- raise signals.TestFailure("Failed",
- extras={"fail_reason": "Phone Failed to Set Up Properly."})
-
- if is_wifi_connected:
- if not ensure_wifi_connected(
- self.log,
- ad_host,
- self.wifi_network_ssid,
- self.wifi_network_pass,
- apm=is_airplane_mode):
- return False
- time.sleep(5)
-
- ad_host.log.info("Step 1: Enable/disable VoLTE and WFC.")
- for sub_id, volte in zip([slot_0_subid, slot_1_subid], enable_volte):
- if not toggle_volte_for_subscription(
- self.log,
- ad_host,
- new_state=volte,
- sub_id=sub_id):
- return False
-
- for sub_id, wfc, mode in \
- zip([slot_0_subid, slot_1_subid], enable_wfc, wfc_mode):
- if not toggle_wfc_for_subscription(
- self.log,
- ad_host,
- new_state=wfc,
- sub_id=sub_id):
- return False
- if not set_wfc_mode_for_subscription(ad_host, mode, sub_id=sub_id):
- return False
-
- ad_host.log.info("Step 2: Switch DDS.")
- if dds_slot:
- if not set_dds_on_slot_1(ad_host):
- ad_host.log.warning(
- "Failed to set DDS at eSIM on %s", ad_host.serial)
- return
- else:
- if not set_dds_on_slot_0(ad_host):
- ad_host.log.warning(
- "Failed to set DDS at pSIM on %s", ad_host.serial)
- return
-
- ad_host.log.info("Step 3: Check HTTP connection after DDS switch.")
- if not verify_http_connection(self.log, ads[0]):
- ad_host.log.error("Failed to verify http connection.")
- return False
- else:
- ad_host.log.info("Verify http connection successfully.")
-
- self.log.info("Step 4: Make 3-way voice call.")
- is_host_in_call = is_phone_in_call_on_rat(
- self.log, ad_host, host_rat[host_slot], only_return_fn=True)
- call_ab_id = self._three_phone_call_mo_add_mt(
- [ad_host, ad_p1, ad_p2],
- [None, None, None],
- [is_host_in_call, None, None],
- reject_once=reject_once)
-
- if call_ab_id is None:
- if disable_cw:
- set_call_waiting(self.log, ad_host, enable=1)
- if str(getattr(ad_host, "exception", None)) == \
- "PhoneA call PhoneC failed.":
- ads[0].log.info("PhoneA failed to call PhoneC due to call"
- " waiting being disabled.")
- delattr(ad_host, "exception")
- return True
- self.log.error("Failed to get call_ab_id")
- return False
- else:
- if disable_cw:
- set_call_waiting(self.log, ad_host, enable=0)
- return False
-
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
- if num_active_calls(self.log, ads[0]) != 2:
- return False
- if calls[0] == call_ab_id:
- call_ac_id = calls[1]
- else:
- call_ac_id = calls[0]
-
- if call_ac_id is None:
- self.log.error("Failed to get call_ac_id")
- return False
-
- num_swaps = 2
- ad_host.log.info("Step 5: Begin Swap x%s test.", num_swaps)
- if not swap_calls(self.log, ads, call_ab_id, call_ac_id,
- num_swaps):
- ad_host.log.error("Swap test failed.")
- return False
-
- if not merge:
- result = True
- if not self._hangup_call(ads[1], "PhoneB"):
- result = False
- if not self._hangup_call(ads[2], "PhoneC"):
- result = False
- return result
- else:
- ad_host.log.info("Step 6: Merge calls.")
- if host_rat[host_slot] == "volte" or host_rat[host_slot] == "wfc":
- return self._test_ims_conference_merge_drop_second_call_from_participant(
- call_ab_id, call_ac_id)
- else:
- return self._test_wcdma_conference_merge_drop(
- call_ab_id, call_ac_id)
+ erase_call_forwarding(self.log, self.android_devices[0])
@test_tracker_info(uuid="3d328dd0-acb6-48be-9cb2-ffffb15bf2cd")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_wfc_psim_cellular_preferred_apm_on_with_volte_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_forwarding(
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
0,
callee_rat=['wfc', 'general'],
- is_airplane_mode=True)
+ is_airplane_mode=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="aac41970-4fdb-4f22-bf33-2092ce14db6e")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_wfc_psim_wifi_preferred_apm_off_with_volte_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_forwarding(
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
0,
callee_rat=['wfc', 'general'],
- wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED])
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="716a795a-529f-450a-800d-80c1dd7c0e3f")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_wfc_psim_cellular_preferred_apm_on_with_volte_on_dds_slot_1(self):
- return self._test_msim_volte_wfc_call_forwarding(
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
1,
callee_rat=['wfc', 'general'],
- is_airplane_mode=True)
+ is_airplane_mode=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="0743331b-78a4-4721-91e7-4c6b894b4b61")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_wfc_psim_wifi_preferred_apm_off_with_volte_on_dds_slot_1(self):
- return self._test_msim_volte_wfc_call_forwarding(
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
1,
callee_rat=['wfc', 'general'],
- wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED])
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="65e8192f-c8af-454e-a142-0ba95f801fb4")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_volte_psim_cellular_preferred_wifi_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_forwarding(
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
0,
callee_rat=["volte", "general"],
- is_wifi_connected=True)
+ is_wifi_connected=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="29175f3c-0f7b-4baf-8399-a37cc92acce0")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_wfc_esim_cellular_preferred_apm_on_with_volte_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_forwarding(
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
0,
callee_rat=['general', 'wfc'],
- is_airplane_mode=True)
+ is_airplane_mode=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="a652a973-7445-4b3d-83cf-7b3ff2e1b47d")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_wfc_esim_wifi_preferred_apm_off_with_volte_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_forwarding(
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
0,
callee_rat=['general', 'wfc'],
- wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED])
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="8ff9bc8f-8740-4198-b437-19994f07758b")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_wfc_esim_cellular_preferred_apm_on_with_volte_on_dds_slot_1(self):
- return self._test_msim_volte_wfc_call_forwarding(
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
1,
callee_rat=['general', 'wfc'],
- is_airplane_mode=True)
+ is_airplane_mode=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="3341cfec-4720-4c20-97c2-29409c727fab")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_wfc_esim_wifi_preferred_apm_off_with_volte_on_dds_slot_1(self):
- return self._test_msim_volte_wfc_call_forwarding(
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
1,
callee_rat=['general', 'wfc'],
- wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED])
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="7cfea32a-6de2-4285-99b1-1219efaf542b")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_forwarding_unconditional_volte_esim_cellular_preferred_wifi_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_forwarding(
+ return msim_volte_wfc_call_forwarding(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
0,
callee_rat=["general", "volte"],
- is_wifi_connected=True)
+ is_wifi_connected=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="27422851-620c-4009-8e2a-730a97d88cb0")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_waiting_hold_swap_wfc_psim_cellular_preferred_apm_on_with_volte_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
0,
host_rat=['wfc', 'general'],
merge=False,
is_airplane_mode=True,
- reject_once=True)
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="f741f336-7eee-473e-b68f-c3505dbab935")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_waiting_hold_swap_wfc_psim_wifi_preferred_apm_off_with_volte_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
0,
host_rat=['wfc', 'general'],
merge=False,
wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
- reject_once=True)
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="4c2c9896-1cfd-4d4c-9594-97c600ac3f50")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_waiting_hold_swap_wfc_psim_cellular_preferred_apm_on_with_volte_on_dds_slot_1(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
1,
host_rat=['wfc', 'general'],
merge=False,
is_airplane_mode=True,
- reject_once=True)
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="74491391-8ea5-4bad-868b-332218a8b015")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_waiting_hold_swap_wfc_psim_wifi_preferred_apm_off_with_volte_on_dds_slot_1(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
1,
host_rat=['wfc', 'general'],
merge=False,
wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
- reject_once=True)
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="40185d6d-e127-4696-9ed8-53dbe355b1c3")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_waiting_hold_swap_volte_psim_cellular_preferred_wifi_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
0,
host_rat=["volte", "general"],
merge=False,
is_airplane_mode=False,
is_wifi_connected=True,
- reject_once=True)
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="b07a6693-3d1c-496a-b2fc-90711b2bf4f6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_waiting_hold_swap_wfc_esim_cellular_preferred_apm_on_with_volte_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
0,
host_rat=['general', 'wfc'],
merge=False,
is_airplane_mode=True,
- reject_once=True)
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="c4461963-5d99-4c6a-b2f6-92de2437e0e7")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_waiting_hold_swap_wfc_esim_wifi_preferred_apm_off_with_volte_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
0,
host_rat=['general', 'wfc'],
merge=False,
wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
- reject_once=True)
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="cece707d-fa13-4748-a777-873eaaa27bca")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_waiting_hold_swap_wfc_esim_cellular_preferred_apm_on_with_volte_on_dds_slot_1(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
1,
host_rat=['general', 'wfc'],
merge=False,
is_airplane_mode=True,
- reject_once=True)
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="bae04c51-99eb-43a5-9f30-f16ac369bb71")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_waiting_hold_swap_wfc_esim_wifi_preferred_apm_off_with_volte_on_dds_slot_1(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
1,
host_rat=['general', 'wfc'],
merge=False,
wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
- reject_once=True)
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="c1d2c088-8782-45cd-b320-effecf6838b4")
@TelephonyBaseTest.tel_test_wrap
def test_msim_call_waiting_hold_swap_volte_esim_cellular_preferred_wifi_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
0,
host_rat=["general", "volte"],
merge=False,
is_airplane_mode=False,
is_wifi_connected=True,
- reject_once=True)
+ reject_once=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="bb4119c9-f5bc-4ef1-acbd-e8f4099f2ba9")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_conf_call_wfc_psim_cellular_preferred_apm_on_with_volte_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
0,
host_rat=['wfc', 'general'],
- is_airplane_mode=True)
+ is_airplane_mode=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="2e48ad65-bfa9-43d3-aa3a-62f412d931cc")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_conf_call_wfc_psim_wifi_preferred_apm_off_with_volte_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
0,
host_rat=['wfc', 'general'],
- wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED])
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="39a9c791-16d0-4476-94e9-fc04e9f5f65a")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_conf_call_wfc_psim_cellular_preferred_apm_on_with_volte_on_dds_slot_1(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
1,
host_rat=['wfc', 'general'],
- is_airplane_mode=True)
+ is_airplane_mode=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="daba5874-0aaa-4f47-9548-e484dd72a8c6")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_conf_call_wfc_psim_wifi_preferred_apm_off_with_volte_on_dds_slot_1(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
1,
host_rat=['wfc', 'general'],
- wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED])
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="ef96a46b-8898-4d5e-a494-31b8047fc986")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_conf_call_volte_psim_cellular_preferred_wifi_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
0,
0,
host_rat=["volte", "general"],
- is_wifi_connected=True)
+ is_wifi_connected=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="c565b2af-512c-4097-a4f7-7d920ea78373")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_conf_call_wfc_esim_cellular_preferred_apm_on_with_volte_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
0,
- host_rat=['general', 'wfc'], is_airplane_mode=True)
+ host_rat=['general', 'wfc'],
+ is_airplane_mode=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="078db8f5-eaf9-409c-878b-70c13be18802")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_conf_call_wfc_esim_wifi_preferred_apm_off_with_volte_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
0,
host_rat=['general', 'wfc'],
- wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED])
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="77c70690-6206-43a5-9789-e9ff39235d42")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_conf_call_wfc_esim_cellular_preferred_apm_on_with_volte_on_dds_slot_1(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
1,
- host_rat=['general', 'wfc'], is_airplane_mode=True)
+ host_rat=['general', 'wfc'],
+ is_airplane_mode=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="b48138dd-5c03-4592-a96d-f63833456197")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_conf_call_wfc_esim_wifi_preferred_apm_off_with_volte_on_dds_slot_1(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
1,
host_rat=['general', 'wfc'],
- wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED])
+ wfc_mode=[WFC_MODE_WIFI_PREFERRED, WFC_MODE_WIFI_PREFERRED],
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
@test_tracker_info(uuid="c2e3ff0e-6112-4b79-92e2-2fabeaf87b1f")
@TelephonyBaseTest.tel_test_wrap
def test_msim_voice_conf_call_volte_esim_cellular_preferred_wifi_on_dds_slot_0(self):
- return self._test_msim_volte_wfc_call_voice_conf(
+ return msim_volte_wfc_call_voice_conf(
+ self.log,
+ self.tel_logger,
+ self.android_devices,
1,
0,
host_rat=["general", "volte"],
- is_wifi_connected=True)
\ No newline at end of file
+ is_wifi_connected=True,
+ wifi_network_ssid=self.wifi_network_ssid,
+ wifi_network_pass=self.wifi_network_pass)
\ No newline at end of file
diff --git a/acts_tests/tests/google/tel/live/TelLiveImsSettingsTest.py b/acts_tests/tests/google/tel/live/TelLiveImsSettingsTest.py
index 0e78f40..23b2e0c 100644
--- a/acts_tests/tests/google/tel/live/TelLiveImsSettingsTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveImsSettingsTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2018 - Google
+# Copyright 2021 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -34,31 +34,30 @@
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_bootloader_utils import fastboot_wipe
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_wifi_data_connection
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_ims_registered
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_not_network_rat
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
from acts_contrib.test_utils.tel.tel_test_utils import dumpsys_carrier_config
-from acts_contrib.test_utils.tel.tel_test_utils import fastboot_wipe
from acts_contrib.test_utils.tel.tel_test_utils import is_droid_in_rat_family
from acts_contrib.test_utils.tel.tel_test_utils import revert_default_telephony_setting
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_wfc
from acts_contrib.test_utils.tel.tel_test_utils import verify_default_telephony_setting
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_ims_registered
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_not_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_reset
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_SSID_KEY
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_PWD_KEY
-from acts_contrib.test_utils.tel.tel_ims_utils import change_ims_setting
-from acts_contrib.test_utils.tel.tel_ims_utils import verify_default_ims_setting
+from acts_contrib.test_utils.tel.tel_voice_utils import change_ims_setting
+from acts_contrib.test_utils.tel.tel_voice_utils import verify_default_ims_setting
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_SSID_KEY
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_PWD_KEY
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_reset
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
class TelLiveImsSettingsTest(TelephonyBaseTest):
diff --git a/acts_tests/tests/google/tel/live/TelLiveLockedSimTest.py b/acts_tests/tests/google/tel/live/TelLiveLockedSimTest.py
index 83c192a..fd4418b 100644
--- a/acts_tests/tests/google/tel/live/TelLiveLockedSimTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveLockedSimTest.py
@@ -26,18 +26,17 @@
from acts_contrib.test_utils.tel.tel_defines import GEN_3G
from acts_contrib.test_utils.tel.tel_defines import GEN_4G
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_lookup_tables import \
- network_preference_for_generation
+from acts_contrib.test_utils.tel.tel_bootloader_utils import fastboot_wipe
+from acts_contrib.test_utils.tel.tel_bootloader_utils import reset_device_password
+from acts_contrib.test_utils.tel.tel_lookup_tables import network_preference_for_generation
from acts_contrib.test_utils.tel.tel_lookup_tables import operator_capabilities
-from acts_contrib.test_utils.tel.tel_test_utils import fastboot_wipe
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
from acts_contrib.test_utils.tel.tel_test_utils import get_sim_state
from acts_contrib.test_utils.tel.tel_test_utils import is_sim_lock_enabled
from acts_contrib.test_utils.tel.tel_test_utils import is_sim_locked
from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
-from acts_contrib.test_utils.tel.tel_test_utils import reset_device_password
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
from acts_contrib.test_utils.tel.tel_test_utils import unlock_sim
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
from TelLiveEmergencyBase import TelLiveEmergencyBase
EXPECTED_CALL_TEST_RESULT = False
diff --git a/acts_tests/tests/google/tel/live/TelLiveMobilityStressTest.py b/acts_tests/tests/google/tel/live/TelLiveMobilityStressTest.py
index 0319763..b608584 100644
--- a/acts_tests/tests/google/tel/live/TelLiveMobilityStressTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveMobilityStressTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2017 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -26,42 +26,21 @@
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_atten_utils import set_rssi
from acts_contrib.test_utils.tel.tel_defines import CELL_WEAK_RSSI_VALUE
-from acts_contrib.test_utils.tel.tel_defines import CELL_STRONG_RSSI_VALUE
from acts_contrib.test_utils.tel.tel_defines import MAX_RSSI_RESERVED_VALUE
from acts_contrib.test_utils.tel.tel_defines import MIN_RSSI_RESERVED_VALUE
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import WIFI_WEAK_RSSI_VALUE
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_voice_attached
-from acts_contrib.test_utils.tel.tel_test_utils import run_multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode
-from acts_contrib.test_utils.tel.tel_test_utils import sms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
-from acts_contrib.test_utils.tel.tel_test_utils import mms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
from acts_contrib.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.libs.utils.multithread import run_multithread_func
from TelWifiVoiceTest import TelWifiVoiceTest
from TelWifiVoiceTest import ATTEN_NAME_FOR_WIFI_2G
@@ -69,13 +48,11 @@
from TelWifiVoiceTest import ATTEN_NAME_FOR_CELL_3G
from TelWifiVoiceTest import ATTEN_NAME_FOR_CELL_4G
-import socket
from acts.controllers.sl4a_lib.rpc_client import Sl4aProtocolError
IGNORE_EXCEPTIONS = (BrokenPipeError, Sl4aProtocolError)
EXCEPTION_TOLERANCE = 20
-
class TelLiveMobilityStressTest(TelWifiVoiceTest):
def setup_class(self):
super().setup_class()
diff --git a/acts_tests/tests/google/tel/live/TelLiveNoQXDMLogTest.py b/acts_tests/tests/google/tel/live/TelLiveNoQXDMLogTest.py
index 3bafb61..c51b779 100644
--- a/acts_tests/tests/google/tel/live/TelLiveNoQXDMLogTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveNoQXDMLogTest.py
@@ -43,8 +43,11 @@
from acts_contrib.test_utils.tel.tel_defines import CARRIER_ID_METADATA_URL_P
from acts_contrib.test_utils.tel.tel_defines import CARRIER_ID_CONTENT_URL_P
from acts_contrib.test_utils.tel.tel_defines import CARRIER_ID_VERSION_P
+from acts_contrib.test_utils.tel.tel_bootloader_utils import fastboot_wipe
from acts_contrib.test_utils.tel.tel_lookup_tables import device_capabilities
from acts_contrib.test_utils.tel.tel_lookup_tables import operator_capabilities
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_cbrs_and_default_sub_id
from acts_contrib.test_utils.tel.tel_test_utils import lock_lte_band_by_mds
from acts_contrib.test_utils.tel.tel_test_utils import get_model_name
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
@@ -52,7 +55,6 @@
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import trigger_modem_crash_by_modem
from acts_contrib.test_utils.tel.tel_test_utils import bring_up_sl4a
-from acts_contrib.test_utils.tel.tel_test_utils import fastboot_wipe
from acts_contrib.test_utils.tel.tel_test_utils import get_carrier_config_version
from acts_contrib.test_utils.tel.tel_test_utils import get_carrier_id_version
from acts_contrib.test_utils.tel.tel_test_utils import get_er_db_id_version
@@ -61,15 +63,14 @@
from acts_contrib.test_utils.tel.tel_test_utils import add_whitelisted_account
from acts_contrib.test_utils.tel.tel_test_utils import adb_disable_verity
from acts_contrib.test_utils.tel.tel_test_utils import install_carriersettings_apk
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
from acts_contrib.test_utils.tel.tel_test_utils import cleanup_configupdater
from acts_contrib.test_utils.tel.tel_test_utils import pull_carrier_id_files
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_cbrs_and_default_sub_id
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
from acts.utils import get_current_epoch_time
from acts.keys import Config
+
class TelLiveNoQXDMLogTest(TelephonyBaseTest):
def setup_class(self):
super().setup_class()
diff --git a/acts_tests/tests/google/tel/live/TelLiveNoSimTest.py b/acts_tests/tests/google/tel/live/TelLiveNoSimTest.py
index 9e4cc07..60bd7ac 100644
--- a/acts_tests/tests/google/tel/live/TelLiveNoSimTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveNoSimTest.py
@@ -26,11 +26,10 @@
from acts_contrib.test_utils.tel.tel_defines import GEN_4G
from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_ABSENT
from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_UNKNOWN
-from acts_contrib.test_utils.tel.tel_test_utils import fastboot_wipe
+from acts_contrib.test_utils.tel.tel_bootloader_utils import fastboot_wipe
+from acts_contrib.test_utils.tel.tel_bootloader_utils import reset_device_password
+from acts_contrib.test_utils.tel.tel_lookup_tables import network_preference_for_generation
from acts_contrib.test_utils.tel.tel_test_utils import get_sim_state
-from acts_contrib.test_utils.tel.tel_lookup_tables import \
- network_preference_for_generation
-from acts_contrib.test_utils.tel.tel_test_utils import reset_device_password
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
from TelLiveEmergencyBase import TelLiveEmergencyBase
diff --git a/acts_tests/tests/google/tel/live/TelLivePreflightTest.py b/acts_tests/tests/google/tel/live/TelLivePreflightTest.py
index 134255e..17dd7f6 100644
--- a/acts_tests/tests/google/tel/live/TelLivePreflightTest.py
+++ b/acts_tests/tests/google/tel/live/TelLivePreflightTest.py
@@ -23,29 +23,29 @@
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.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WLAN
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_wifi_data_connection
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan_cellular_preferred
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_rat
from acts_contrib.test_utils.tel.tel_test_utils import abort_all_tests
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
from acts_contrib.test_utils.tel.tel_test_utils import get_user_config_profile
from acts_contrib.test_utils.tel.tel_test_utils import is_sim_locked
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
from acts_contrib.test_utils.tel.tel_test_utils import unlock_sim
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan_cellular_preferred
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
class TelLivePreflightTest(TelephonyBaseTest):
diff --git a/acts_tests/tests/google/tel/live/TelLiveProjectFiTest.py b/acts_tests/tests/google/tel/live/TelLiveProjectFiTest.py
index 5bf765e..950b0fc 100644
--- a/acts_tests/tests/google/tel/live/TelLiveProjectFiTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveProjectFiTest.py
@@ -20,17 +20,16 @@
import time
from acts.test_decorators import test_tracker_info
+from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import CARRIER_SPT
from acts_contrib.test_utils.tel.tel_defines import CARRIER_TMO
from acts_contrib.test_utils.tel.tel_defines import CARRIER_USCC
+from acts_contrib.test_utils.tel.tel_logging_utils import log_screen_shot
from acts_contrib.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_subscription
from acts_contrib.test_utils.tel.tel_test_utils import abort_all_tests
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
from acts_contrib.test_utils.tel.tel_test_utils import is_sim_ready
-from acts_contrib.test_utils.tel.tel_test_utils import log_screen_shot
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
from acts_contrib.test_utils.tel.tel_test_utils import refresh_droid_config
from acts_contrib.test_utils.tel.tel_test_utils import send_dialer_secret_code
@@ -38,6 +37,7 @@
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
from acts_contrib.test_utils.tel.tel_test_utils import add_google_account
from acts_contrib.test_utils.tel.tel_test_utils import remove_google_account
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
CARRIER_AUTO = "auto"
diff --git a/acts_tests/tests/google/tel/live/TelLiveRcsTest.py b/acts_tests/tests/google/tel/live/TelLiveRcsTest.py
new file mode 100644
index 0000000..fab619c
--- /dev/null
+++ b/acts_tests/tests/google/tel/live/TelLiveRcsTest.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2016 - 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 RCS.
+"""
+from time import sleep
+
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+
+
+class TelLiveRcsTest(TelephonyBaseTest):
+ def setup_class(self):
+ super().setup_class()
+
+ def setup_test(self):
+ TelephonyBaseTest.setup_test(self)
+
+ def teardown_class(self):
+ TelephonyBaseTest.teardown_class(self)
+
+ def test_verify_provisioning(self):
+ ad = self.android_devices[0]
+ ad.log.info("Start RCS provisioning")
+ ad.droid.startRCSProvisioning("UP_1.0", "6.0", "Goog", "RCSAndrd-1.0")
+ sleep(20)
+ isRcsVolteSingleRegistrationCapable = ad.droid.isRcsVolteSingleRegistrationCapable()
+ configXml = ad.droid.getRCSConfigXml()
+ ad.log.info("isRcsVolteSingleRegistrationCapable: %r", isRcsVolteSingleRegistrationCapable)
+ ad.log.info("RCS Config XML: %s", configXml)
+ result = configXml.find("<parm name=\"rcsVolteSingleRegistration\" value=\"1\"/>")
+ return result != -1
+
+ def test_is_single_reg_capable(self, ad):
+ """ Test single registration provisioning.
+
+ """
+
+ return ad.droid.isRcsVolteSingleRegistrationCapable()
+
+ def test_unregister(self):
+ ad = self.android_devices[0]
+ return ad.droid.unregister()
+
diff --git a/acts_tests/tests/google/tel/live/TelLiveRebootStressTest.py b/acts_tests/tests/google/tel/live/TelLiveRebootStressTest.py
index 4d90bdb..2071ef7 100644
--- a/acts_tests/tests/google/tel/live/TelLiveRebootStressTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveRebootStressTest.py
@@ -39,42 +39,40 @@
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_subscription
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_wifi_data_connection
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_generation
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_rat
from acts_contrib.test_utils.tel.tel_test_utils import get_model_name
from acts_contrib.test_utils.tel.tel_test_utils import get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import get_slot_index_from_subid
from acts_contrib.test_utils.tel.tel_test_utils import is_droid_in_network_generation
from acts_contrib.test_utils.tel.tel_test_utils import is_sim_locked
-from acts_contrib.test_utils.tel.tel_test_utils import mms_send_receive_verify
from acts_contrib.test_utils.tel.tel_test_utils import power_off_sim
from acts_contrib.test_utils.tel.tel_test_utils import power_on_sim
from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
-from acts_contrib.test_utils.tel.tel_test_utils import sms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import trigger_modem_crash
from acts_contrib.test_utils.tel.tel_test_utils import trigger_modem_crash_by_modem
from acts_contrib.test_utils.tel.tel_test_utils import unlock_sim
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
from acts_contrib.test_utils.tel.tel_video_utils import video_call_setup_teardown
from acts_contrib.test_utils.tel.tel_video_utils import phone_setup_video
-from acts_contrib.test_utils.tel.tel_video_utils import \
- is_phone_in_call_video_bidirectional
+from acts_contrib.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
@@ -577,7 +575,7 @@
self.dut.log.info("======== Power cycle SIM slot ========")
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)
+ slot_index = get_slot_index_from_subid(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")
diff --git a/acts_tests/tests/google/tel/live/TelLiveRilDataKpiTest.py b/acts_tests/tests/google/tel/live/TelLiveRilDataKpiTest.py
new file mode 100644
index 0000000..ce6e6fa
--- /dev/null
+++ b/acts_tests/tests/google/tel/live/TelLiveRilDataKpiTest.py
@@ -0,0 +1,388 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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.
+
+import time
+from datetime import datetime, timedelta
+
+from acts import signals
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_data_utils import activate_and_verify_cellular_data
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_data_utils import deactivate_and_verify_cellular_data
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_disabled
+from acts_contrib.test_utils.tel.tel_parse_utils import print_nested_dict
+from acts_contrib.test_utils.tel.tel_parse_utils import parse_setup_data_call
+from acts_contrib.test_utils.tel.tel_parse_utils import parse_deactivate_data_call
+from acts_contrib.test_utils.tel.tel_parse_utils import parse_setup_data_call_on_iwlan
+from acts_contrib.test_utils.tel.tel_parse_utils import parse_deactivate_data_call_on_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_4g_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_data_sub_id
+from acts.utils import get_current_epoch_time
+from acts.libs.utils.multithread import multithread_func
+
+CALCULATE_EVERY_N_CYCLES = 10
+
+
+class TelLiveRilDataKpiTest(TelephonyBaseTest):
+ def setup_class(self):
+ TelephonyBaseTest.setup_class(self)
+ self.cycle_cellular_data_cycle = self.user_params.get(
+ "cycle_cellular_data_cycle", 1)
+ self.cycle_wfc_cycle = self.user_params.get("cycle_wfc_cycle", 1)
+ self.dds_switch_test_cycle = self.user_params.get(
+ "dds_switch_test_cycle", 1)
+ self.http_download_duration = self.user_params.get(
+ "http_download_duration", 3600)
+
+ def cycle_cellular_data(self, ad):
+ """ Toggle off and then toggle on again cellular data.
+
+ Args:
+ ad: Android object
+
+ Returns:
+ True if cellular data is cycled successfully. Otherwise False.
+ """
+ if not deactivate_and_verify_cellular_data(self.log, ad):
+ return False
+
+ if not activate_and_verify_cellular_data(self.log, ad):
+ return False
+
+ return True
+
+ def cycle_wfc(self, ad):
+ """ Toggle off and then toggle on again WFC.
+
+ Args:
+ ad: Android object
+
+ Returns:
+ True if WFC is cycled successfully. Otherwise False.
+ """
+ if not toggle_wfc(self.log, ad, new_state=False):
+ return False
+
+ if not wait_for_wfc_disabled(self.log, ad):
+ return False
+
+ if not toggle_wfc(self.log, ad, new_state=True):
+ return False
+
+ if not wait_for_wfc_enabled(self.log, ad):
+ return False
+
+ return True
+
+ def switch_dds(self, ad):
+ """Switch DDS to the other sub ID.
+
+ Args:
+ ad: Android object
+
+ Returns:
+ True if DDS is switched successfully. Otherwise False.
+ """
+ current_dds_slot = get_slot_index_from_data_sub_id(ad)
+
+ if current_dds_slot == 0:
+ if set_dds_on_slot_1(ad):
+ return True
+ else:
+ if set_dds_on_slot_0(ad):
+ return True
+
+ return False
+
+ @test_tracker_info(uuid="27424b59-efa9-47c3-89b4-4b5415003a58")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_cycle_cellular_data_4g(self):
+ """Cycle cellular data on LTE to measure data call setup time,
+ deactivate time and LTE validation time.
+
+ Test steps:
+ 1. Set up UE on LTE and ensure cellular data is connected.
+ 2. Cycle cellular data.
+ 3. Parse logcat to calculate data call setup time, deactivate time
+ and LTE validation time.
+ """
+ ad = self.android_devices[0]
+
+ cycle = self.cycle_cellular_data_cycle
+
+ tasks = [(
+ phone_setup_4g_for_subscription,
+ (self.log, ad, get_default_data_sub_id(ad)))]
+ 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)
+
+ cycle_cellular_data_summary = []
+ for attempt in range(cycle):
+ ad.log.info(
+ '======> Cycling cellular data %s/%s <======',
+ attempt+1, cycle)
+ res = self.cycle_cellular_data(ad)
+ cycle_cellular_data_summary.append(res)
+ if not res:
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+
+ if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or attempt == cycle - 1:
+ (
+ res,
+ lst,
+ avg_data_call_setup_time,
+ avg_validation_time_on_lte) = parse_setup_data_call(ad)
+
+ ad.log.info('====== Setup data call list ======')
+ print_nested_dict(ad, res)
+
+ ad.log.info('====== Data call setup time list ======')
+ for item in lst:
+ print_nested_dict(ad, item)
+ ad.log.info('------------------')
+
+ (
+ res,
+ lst,
+ avg_deactivate_data_call_time) = parse_deactivate_data_call(ad)
+
+ ad.log.info('====== Deactivate data call list ======')
+ print_nested_dict(ad, res)
+
+ ad.log.info('====== Data call deactivate time list ======')
+ for item in lst:
+ print_nested_dict(ad, item)
+ ad.log.info('------------------')
+
+ ad.log.info(
+ 'Average data call setup time on LTE: %.2f sec.',
+ avg_data_call_setup_time)
+ ad.log.info(
+ 'Average validation time on LTE: %.2f sec.',
+ avg_validation_time_on_lte)
+ ad.log.info(
+ 'Average deactivate data call time on LTE: %.2f sec.',
+ avg_deactivate_data_call_time)
+
+ try:
+ fail_rate = cycle_cellular_data_summary.count(False)/len(
+ cycle_cellular_data_summary)
+ self.log.info(
+ 'Fail rate of cycling cellular data on LTE: %s/%s (%.2f)',
+ cycle_cellular_data_summary.count(False),
+ len(cycle_cellular_data_summary),
+ fail_rate)
+ except Exception as e:
+ self.log.error(
+ 'Fail rate of cycling cellular data on LTE: ERROR (%s)',
+ e)
+
+ @test_tracker_info(uuid="9f4ab929-176d-4f26-8e14-12bd6c25e80a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_cycle_wfc(self):
+ """Cycle WFC to measure data call setup time and deactivate time on
+ iwlan.
+
+ Test steps:
+ 1. Set up UE on iwlan and ensure WFC is registered in Wi-Fi-preferred
+ mode.
+ 2. Cycle WFC.
+ 3. Parse logcat to calculate data call setup time and deactivate time
+ on iwlan.
+ """
+ ad = self.android_devices[0]
+
+ cycle = self.cycle_wfc_cycle
+
+ tasks = [(phone_setup_iwlan, (
+ self.log,
+ ad,
+ 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
+
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+
+ cycle_wfc_summary = []
+ for attempt in range(cycle):
+ ad.log.info(
+ '==================> Cycling WFC %s/%s <==================',
+ attempt+1, cycle)
+ res = self.cycle_wfc(ad)
+ cycle_wfc_summary.append(res)
+ if not res:
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+
+ if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or attempt == cycle - 1:
+ (
+ res,
+ lst,
+ avg_data_call_setup_time) = parse_setup_data_call_on_iwlan(ad)
+
+ ad.log.info('====== Setup data call list ======')
+ print_nested_dict(ad, res)
+
+ ad.log.info('====== Data call setup time list ======')
+ for item in lst:
+ print_nested_dict(ad, item)
+ ad.log.info('------------------')
+
+ (
+ res,
+ lst,
+ avg_deactivate_data_call_time) = parse_deactivate_data_call_on_iwlan(ad)
+
+ ad.log.info('====== Deactivate data call list ======')
+ print_nested_dict(ad, res)
+
+ ad.log.info('====== Data call deactivate time list ======')
+ for item in lst:
+ print_nested_dict(ad, item)
+ ad.log.info('------------------')
+
+ ad.log.info(
+ 'Average WFC data call setup time: %.2f sec.',
+ avg_data_call_setup_time)
+ ad.log.info(
+ 'Average WFC deactivate data call time: %.2f sec.',
+ avg_deactivate_data_call_time)
+
+ try:
+ fail_rate = cycle_wfc_summary.count(False)/len(
+ cycle_wfc_summary)
+ self.log.info(
+ 'Fail rate of cycling WFC: %s/%s (%.2f)',
+ cycle_wfc_summary.count(False),
+ len(cycle_wfc_summary),
+ fail_rate)
+ except Exception as e:
+ self.log.error('Fail rate of cycling WFC: ERROR (%s)', e)
+
+ @test_tracker_info(uuid="77388597-d764-4db3-be6f-656e56dc253a")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_dds_switch(self):
+ """ Switch DDS to measure DDS switch time and LTE validation time.
+
+ Test steps:
+ 1. Switch DDS.
+ 2. Parse logcat to calculate DDS switch time and LTE validation time.
+ """
+ ad = self.android_devices[0]
+ cycle = self.dds_switch_test_cycle
+
+ if not getattr(ad, 'dsds', False):
+ raise signals.TestSkip("UE is in single mode. Test will be skipped.")
+
+ dds_switch_summary = []
+ for attempt in range(cycle):
+ self.log.info(
+ '======> DDS switch on LTE %s/%s <======',
+ attempt+1,
+ cycle)
+ if self.switch_dds(ad):
+ dds_switch_summary.append(True)
+ else:
+ dds_switch_summary.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+
+ if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or attempt == cycle - 1:
+ (
+ res,
+ lst,
+ avg_data_call_setup_time,
+ avg_validation_time_on_lte) = parse_setup_data_call(
+ ad, dds_switch=True)
+
+ ad.log.info('====== Setup data call list ======')
+ print_nested_dict(ad, res)
+
+ ad.log.info('====== Data call setup time list ======')
+ for item in lst:
+ print_nested_dict(ad, item)
+ ad.log.info('------------------')
+
+ try:
+ ad.log.info(
+ 'Average data call setup time on LTE: %.2f sec.',
+ avg_data_call_setup_time)
+ except Exception as e:
+ ad.log.error(
+ 'Average data call setup time on LTE: ERROR (%s)', e)
+
+ try:
+ ad.log.info(
+ 'Average validation time on LTE: %.2f sec.',
+ avg_validation_time_on_lte)
+ except Exception as e:
+ ad.log.error('Average validation tim on LTE: ERROR (%s)', e)
+
+ try:
+ fail_rate = dds_switch_summary.count(False)/len(dds_switch_summary)
+ self.log.info(
+ 'Fail rate of cycling cellular data on LTE: %s/%s (%.2f)',
+ dds_switch_summary.count(False),
+ len(dds_switch_summary),
+ fail_rate)
+ except Exception as e:
+ self.log.error(
+ 'Fail rate of cycling cellular data on LTE: ERROR (%s)',
+ e)
+
+ @test_tracker_info(uuid="ac0b6541-d900-4413-8ccb-839ae998804e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_http_download(self, method='sl4a'):
+ """HTTP download large file for a long time to ensure there is no issue
+ related to the stability.
+
+ Test steps:
+ 1. HTTP download a large file (e.g., 512MB) for a long time
+
+ Returns:
+ False if the download is interrupted. Otherwise True.
+ """
+ ad = self.android_devices[0]
+
+ duration = self.http_download_duration
+
+ start_time = datetime.now()
+
+ result = True
+ while datetime.now() - start_time <= timedelta(seconds=duration):
+ if not active_file_download_test(
+ self.log, ad, file_name='512MB', method=method):
+ result = False
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ return result
\ No newline at end of file
diff --git a/acts_tests/tests/google/tel/live/TelLiveRilImsKpiTest.py b/acts_tests/tests/google/tel/live/TelLiveRilImsKpiTest.py
new file mode 100644
index 0000000..f7bb1ca
--- /dev/null
+++ b/acts_tests/tests/google/tel/live/TelLiveRilImsKpiTest.py
@@ -0,0 +1,1355 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - 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.
+
+import time
+from datetime import datetime
+
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_data_utils import airplane_mode_test
+from acts_contrib.test_utils.tel.tel_data_utils import reboot_test
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_network_service
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WIFI_CONNECTION
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
+from acts_contrib.test_utils.tel.tel_logging_utils import start_pixellogger_always_on_logging
+from acts_contrib.test_utils.tel.tel_logging_utils import wait_for_log
+from acts_contrib.test_utils.tel.tel_parse_utils import print_nested_dict
+from acts_contrib.test_utils.tel.tel_parse_utils import parse_ims_reg
+from acts_contrib.test_utils.tel.tel_parse_utils import ON_IMS_MM_TEL_CONNECTED_4G_SLOT0
+from acts_contrib.test_utils.tel.tel_parse_utils import ON_IMS_MM_TEL_CONNECTED_4G_SLOT1
+from acts_contrib.test_utils.tel.tel_parse_utils import ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT0
+from acts_contrib.test_utils.tel.tel_parse_utils import ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT1
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_voice_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_all_sub_id
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
+from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_short_seq
+from acts_contrib.test_utils.tel.tel_wifi_utils import check_is_wifi_connected
+from acts.utils import get_current_epoch_time
+
+SETUP_PHONE_FAIL = 'SETUP_PHONE_FAIL'
+VERIFY_NETWORK_FAIL = 'VERIFY_NETWORK_FAIL'
+VERIFY_INTERNET_FAIL = 'VERIFY_INTERNET_FAIL'
+TOGGLE_OFF_APM_FAIL = 'TOGGLE_OFF_APM_FAIL'
+
+CALCULATE_EVERY_N_CYCLES = 10
+
+
+def test_result(result_list, cycle, min_fail=0, failrate=0):
+ failure_count = len(list(filter(lambda x: (x != True), result_list)))
+ if failure_count >= min_fail:
+ if failure_count >= cycle * failrate:
+ return False
+ return True
+
+def wait_for_wifi_disconnected(ad, wifi_ssid):
+ """Wait until Wifi is disconnected.
+
+ Args:
+ ad: Android object
+ wifi_ssid: to specify the Wifi AP which should be disconnected.
+
+ Returns:
+ True if Wifi is disconnected before time-out. Otherwise False.
+ """
+ wait_time = 0
+ while wait_time < MAX_WAIT_TIME_WIFI_CONNECTION:
+ if check_is_wifi_connected(ad.log, ad, wifi_ssid):
+ ad.droid.wifiToggleState(False)
+ time.sleep(3)
+ wait_time = wait_time + 3
+ else:
+ ad.log.info('Wifi is disconnected.')
+ return True
+
+ if check_is_wifi_connected(ad.log, ad, wifi_ssid):
+ ad.log.error('Wifi still is connected to %s.', wifi_ssid)
+ return False
+ else:
+ ad.log.info('Wifi is disconnected.')
+ return True
+
+class TelLiveRilImsKpiTest(TelephonyBaseTest):
+ def setup_class(self):
+ TelephonyBaseTest.setup_class(self)
+ start_pixellogger_always_on_logging(self.android_devices[0])
+ self.tel_logger = TelephonyMetricLogger.for_test_case()
+ self.user_params["telephony_auto_rerun"] = 0
+ self.reboot_4g_test_cycle = self.user_params.get(
+ 'reboot_4g_test_cycle', 1)
+ self.reboot_iwlan_test_cycle = self.user_params.get(
+ 'reboot_iwlan_test_cycle', 1)
+ self.cycle_apm_4g_test_cycle = self.user_params.get(
+ 'cycle_apm_4g_test_cycle', 1)
+ self.cycle_wifi_in_apm_mode_test_cycle = self.user_params.get(
+ 'cycle_wifi_in_apm_mode_test_cycle', 1)
+ self.ims_handover_4g_to_iwlan_with_voice_call_wfc_wifi_preferred_test_cycle = self.user_params.get(
+ 'ims_handover_4g_to_iwlan_with_voice_call_wfc_wifi_preferred_test_cycle', 1)
+ self.ims_handover_4g_to_iwlan_wfc_wifi_preferred_test_cycle = self.user_params.get(
+ 'ims_handover_4g_to_iwlan_wfc_wifi_preferred_test_cycle', 1)
+ self.ims_handover_iwlan_to_4g_wfc_wifi_preferred_test_cycle = self.user_params.get(
+ 'ims_handover_iwlan_to_4g_wfc_wifi_preferred_test_cycle', 1)
+ self.ims_handover_iwlan_to_4g_with_voice_call_wfc_wifi_preferred_test_cycle = self.user_params.get(
+ 'ims_handover_iwlan_to_4g_with_voice_call_wfc_wifi_preferred_test_cycle', 1)
+ self.ims_handover_iwlan_to_4g_wfc_cellular_preferred_test_cycle = self.user_params.get(
+ 'ims_handover_iwlan_to_4g_wfc_cellular_preferred_test_cycle', 1)
+ self.ims_handover_iwlan_to_4g_with_voice_call_wfc_cellular_preferred_test_cycle = self.user_params.get(
+ 'ims_handover_iwlan_to_4g_with_voice_call_wfc_cellular_preferred_test_cycle', 1)
+
+ def teardown_test(self):
+ for ad in self.android_devices:
+ toggle_airplane_mode(self.log, ad, False)
+
+ @test_tracker_info(uuid="d6a59a3c-2bbc-4ed3-a41e-4492b4ab8a50")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_reboot_4g(self):
+ """Reboot UE and measure bootup IMS registration time on LTE.
+
+ Test steps:
+ 1. Enable VoLTE at all slots and ensure IMS is registered over LTE
+ cellular network at all slots.
+ 2. Reboot UE.
+ 3. Parse logcat to calculate IMS registration time on LTE after
+ bootup.
+ """
+ ad = self.android_devices[0]
+ cycle = self.reboot_4g_test_cycle
+ voice_slot = get_slot_index_from_voice_sub_id(ad)
+
+ if getattr(ad, 'dsds', False):
+ the_other_slot = 1 - voice_slot
+ else:
+ the_other_slot = None
+
+ result = []
+ search_intervals = []
+ exit_due_to_high_fail_rate = False
+ for attempt in range(cycle):
+ _continue = True
+ self.log.info(
+ '==================> Reboot on LTE %s/%s <==================',
+ attempt+1,
+ cycle)
+
+ sub_id_list = get_all_sub_id(ad)
+ for sub_id in sub_id_list:
+ if not phone_setup_volte_for_subscription(self.log, ad, sub_id):
+ result.append(SETUP_PHONE_FAIL)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if not wait_for_network_service(self.log, ad):
+ result.append(VERIFY_NETWORK_FAIL)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ begin_time = datetime.now()
+ if reboot_test(self.log, ad):
+ result.append(True)
+ else:
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ end_time = datetime.now()
+ search_intervals.append([begin_time, end_time])
+
+ if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or (
+ attempt == cycle - 1) or exit_due_to_high_fail_rate:
+
+ ad.log.info(
+ '====== Test result of IMS bootup registration at slot %s '
+ '======',
+ voice_slot)
+ ad.log.info(result)
+
+ for slot in [voice_slot, the_other_slot]:
+ if slot is None:
+ continue
+
+ ims_reg, parsing_fail, avg_ims_reg_duration = parse_ims_reg(
+ ad, search_intervals, '4g', 'reboot', slot=slot)
+ ad.log.info(
+ '====== IMS bootup registration at slot %s ======', slot)
+ for msg in ims_reg:
+ print_nested_dict(ad, msg)
+
+ ad.log.info(
+ '====== Attempt of parsing fail at slot %s ======' % slot)
+ for msg in parsing_fail:
+ ad.log.info(msg)
+
+ ad.log.warning('====== Summary ======')
+ ad.log.warning(
+ '%s/%s cycles failed.',
+ (len(result) - result.count(True)),
+ len(result))
+ for attempt, value in enumerate(result):
+ if value is not True:
+ ad.log.warning('Cycle %s: %s', attempt+1, value)
+ try:
+ fail_rate = (
+ len(result) - result.count(True))/len(result)
+ ad.log.info(
+ 'Fail rate of IMS bootup registration at slot %s: %s',
+ slot,
+ fail_rate)
+ except Exception as e:
+ ad.log.error(
+ 'Fail rate of IMS bootup registration at slot %s: '
+ 'ERROR (%s)',
+ slot,
+ e)
+
+ ad.log.info(
+ 'Number of trials with valid parsed logs: %s',
+ len(ims_reg))
+ ad.log.info(
+ 'Average IMS bootup registration time at slot %s: %s',
+ slot,
+ avg_ims_reg_duration)
+
+ if exit_due_to_high_fail_rate:
+ break
+
+ return test_result(result, cycle)
+
+ @test_tracker_info(uuid="c97dd2f2-9e8a-43d4-9352-b53abe5ac6a4")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_reboot_iwlan(self):
+ """Reboot UE and measure bootup IMS registration time over iwlan.
+
+ Test steps:
+ 1. Enable VoLTE at all slots; enable WFC and set WFC mode to
+ Wi-Fi-preferred mode; connect Wi-Fi and ensure IMS is registered
+ at all slots over iwlan.
+ 2. Reboot UE.
+ 3. Parse logcat to calculate IMS registration time over iwlan after
+ bootup.
+ """
+ ad = self.android_devices[0]
+ cycle = self.reboot_iwlan_test_cycle
+ voice_slot = get_slot_index_from_voice_sub_id(ad)
+
+ if getattr(ad, 'dsds', False):
+ the_other_slot = 1 - voice_slot
+ else:
+ the_other_slot = None
+
+ result = []
+ search_intervals = []
+ exit_due_to_high_fail_rate = False
+ for attempt in range(cycle):
+ _continue = True
+ self.log.info(
+ '==================> Reboot on iwlan %s/%s <==================',
+ attempt+1,
+ cycle)
+
+ sub_id_list = get_all_sub_id(ad)
+ for sub_id in sub_id_list:
+ if not phone_setup_iwlan_for_subscription(
+ self.log,
+ ad,
+ sub_id,
+ False,
+ WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass):
+
+ result.append(SETUP_PHONE_FAIL)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ wait_for_wifi_disconnected(ad, self.wifi_network_ssid)
+
+ if _continue:
+ if not verify_internet_connection(self.log, ad):
+ result.append(VERIFY_INTERNET_FAIL)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ begin_time = datetime.now()
+ if reboot_test(self.log, ad, wifi_ssid=self.wifi_network_ssid):
+ result.append(True)
+ else:
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ end_time = datetime.now()
+ search_intervals.append([begin_time, end_time])
+
+ if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or (
+ attempt == cycle - 1) or exit_due_to_high_fail_rate:
+
+ ad.log.info(
+ '====== Test result of IMS bootup registration at slot %s '
+ '======',
+ voice_slot)
+ ad.log.info(result)
+
+ for slot in [voice_slot, the_other_slot]:
+ if slot is None:
+ continue
+
+ ims_reg, parsing_fail, avg_ims_reg_duration = parse_ims_reg(
+ ad, search_intervals, 'iwlan', 'reboot', slot=slot)
+ ad.log.info(
+ '====== IMS bootup registration at slot %s ======', slot)
+ for msg in ims_reg:
+ print_nested_dict(ad, msg)
+
+ ad.log.info(
+ '====== Attempt of parsing fail at slot %s ======' % slot)
+ for msg in parsing_fail:
+ ad.log.info(msg)
+
+ ad.log.warning('====== Summary ======')
+ ad.log.warning(
+ '%s/%s cycles failed.',
+ (len(result) - result.count(True)),
+ len(result))
+ for attempt, value in enumerate(result):
+ if value is not True:
+ ad.log.warning('Cycle %s: %s', attempt+1, value)
+
+ try:
+ fail_rate = (
+ len(result) - result.count(True))/len(result)
+ ad.log.info(
+ 'Fail rate of IMS bootup registration at slot %s: %s',
+ slot,
+ fail_rate)
+ except Exception as e:
+ ad.log.error(
+ 'Fail rate of IMS bootup registration at slot %s: '
+ 'ERROR (%s)',
+ slot,
+ e)
+
+ ad.log.info(
+ 'Number of trials with valid parsed logs: %s',
+ len(ims_reg))
+ ad.log.info(
+ 'Average IMS bootup registration time at slot %s: %s',
+ slot, avg_ims_reg_duration)
+ if exit_due_to_high_fail_rate:
+ break
+
+ return test_result(result, cycle)
+
+ @test_tracker_info(uuid="45ed4572-7de9-4e1b-b2ec-58dea722fa3e")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_cycle_airplane_mode_4g(self):
+ """Cycle airplane mode and measure IMS registration time on LTE
+
+ Test steps:
+ 1. Enable VoLTE at all slots and ensure IMS is registered on LTE at
+ all slots.
+ 2. Cycle airplane mode.
+ 3. Parse logcat to calculate IMS registration time right after
+ recovery of cellular service.
+ """
+ ad = self.android_devices[0]
+ cycle = self.cycle_apm_4g_test_cycle
+ voice_slot = get_slot_index_from_voice_sub_id(ad)
+
+ if getattr(ad, 'dsds', False):
+ the_other_slot = 1 - voice_slot
+ else:
+ the_other_slot = None
+
+ result = []
+ search_intervals = []
+ exit_due_to_high_fail_rate = False
+ for attempt in range(cycle):
+ _continue = True
+ self.log.info(
+ '============> Cycle airplane mode on LTE %s/%s <============',
+ attempt+1,
+ cycle)
+
+ sub_id_list = get_all_sub_id(ad)
+ for sub_id in sub_id_list:
+ if not phone_setup_volte_for_subscription(self.log, ad, sub_id):
+ result.append(SETUP_PHONE_FAIL)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if not wait_for_network_service(self.log, ad):
+ result.append(VERIFY_NETWORK_FAIL)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ begin_time = datetime.now()
+ if airplane_mode_test(self.log, ad):
+ result.append(True)
+ else:
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ end_time = datetime.now()
+ search_intervals.append([begin_time, end_time])
+
+ if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or (
+ attempt == cycle - 1) or exit_due_to_high_fail_rate:
+
+ ad.log.info(
+ '====== Test result of IMS registration at slot %s ======',
+ voice_slot)
+ ad.log.info(result)
+
+ for slot in [voice_slot, the_other_slot]:
+ if slot is None:
+ continue
+
+ ims_reg, parsing_fail, avg_ims_reg_duration = parse_ims_reg(
+ ad, search_intervals, '4g', 'apm', slot=slot)
+ ad.log.info(
+ '====== IMS registration at slot %s ======', slot)
+ for msg in ims_reg:
+ print_nested_dict(ad, msg)
+
+ ad.log.info(
+ '====== Attempt of parsing fail at slot %s ======' % slot)
+ for msg in parsing_fail:
+ ad.log.info(msg)
+
+ ad.log.warning('====== Summary ======')
+ ad.log.warning('%s/%s cycles failed.', (len(result) - result.count(True)), len(result))
+ for attempt, value in enumerate(result):
+ if value is not True:
+ ad.log.warning('Cycle %s: %s', attempt+1, value)
+
+ try:
+ fail_rate = (
+ len(result) - result.count(True))/len(result)
+ ad.log.info(
+ 'Fail rate of IMS registration at slot %s: %s',
+ slot,
+ fail_rate)
+ except Exception as e:
+ ad.log.error(
+ 'Fail rate of IMS registration at slot %s: '
+ 'ERROR (%s)',
+ slot,
+ e)
+
+ ad.log.info(
+ 'Number of trials with valid parsed logs: %s',
+ len(ims_reg))
+ ad.log.info(
+ 'Average IMS registration time at slot %s: %s',
+ slot, avg_ims_reg_duration)
+
+ if exit_due_to_high_fail_rate:
+ break
+
+ return test_result(result, cycle)
+
+ @test_tracker_info(uuid="915c9403-8bbc-45c7-be53-8b0de4191716")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_cycle_wifi_in_apm_mode(self):
+ """Cycle Wi-Fi in airplane mode and measure IMS registration time over
+ iwlan.
+
+ Test steps:
+ 1. Enable VoLTE; enable WFC and set WFC mode to Wi-Fi-preferred mode;
+ turn on airplane mode and connect Wi-Fi to ensure IMS is
+ registered over iwlan.
+ 2. Cycle Wi-Fi.
+ 3. Parse logcat to calculate IMS registration time right after
+ recovery of Wi-Fi connection in airplane mode.
+ """
+ ad = self.android_devices[0]
+ cycle = self.cycle_wifi_in_apm_mode_test_cycle
+ voice_slot = get_slot_index_from_voice_sub_id(ad)
+
+ result = []
+ search_intervals = []
+ exit_due_to_high_fail_rate = False
+ for attempt in range(cycle):
+ _continue = True
+ self.log.info(
+ '============> Cycle WiFi in airplane mode %s/%s <============',
+ attempt+1,
+ cycle)
+
+ begin_time = datetime.now()
+
+ if not wait_for_wifi_disconnected(ad, self.wifi_network_ssid):
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if not phone_setup_iwlan(
+ self.log,
+ ad,
+ True,
+ WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass):
+
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if not verify_internet_connection(self.log, ad):
+ result.append(VERIFY_INTERNET_FAIL)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if not wait_for_wifi_disconnected(
+ ad, self.wifi_network_ssid):
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ result.append(True)
+ end_time = datetime.now()
+ search_intervals.append([begin_time, end_time])
+
+ if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or (
+ attempt == cycle - 1) or exit_due_to_high_fail_rate:
+
+ ad.log.info(
+ '====== Test result of IMS registration at slot %s ======',
+ voice_slot)
+ ad.log.info(result)
+
+ ims_reg, parsing_fail, avg_ims_reg_duration = parse_ims_reg(
+ ad, search_intervals, 'iwlan', 'apm')
+ ad.log.info(
+ '====== IMS registration at slot %s ======', voice_slot)
+ for msg in ims_reg:
+ ad.log.info(msg)
+
+ ad.log.info(
+ '====== Attempt of parsing fail at slot %s ======' % voice_slot)
+ for msg in parsing_fail:
+ ad.log.info(msg)
+
+ ad.log.warning('====== Summary ======')
+ ad.log.warning(
+ '%s/%s cycles failed.',
+ (len(result) - result.count(True)),
+ len(result))
+ for attempt, value in enumerate(result):
+ if value is not True:
+ ad.log.warning('Cycle %s: %s', attempt+1, value)
+
+ try:
+ fail_rate = (len(result) - result.count(True))/len(result)
+ ad.log.info(
+ 'Fail rate of IMS registration at slot %s: %s',
+ voice_slot,
+ fail_rate)
+ except Exception as e:
+ ad.log.error(
+ 'Fail rate of IMS registration at slot %s: ERROR (%s)',
+ voice_slot,
+ e)
+
+ ad.log.info(
+ 'Number of trials with valid parsed logs: %s', len(ims_reg))
+ ad.log.info(
+ 'Average IMS registration time at slot %s: %s',
+ voice_slot, avg_ims_reg_duration)
+
+ if exit_due_to_high_fail_rate:
+ break
+ toggle_airplane_mode(self.log, ad, False)
+ return test_result(result, cycle)
+
+ def ims_handover_4g_to_iwlan_wfc_wifi_preferred(self, voice_call=False):
+ """Connect WFC to make IMS registration hand over from LTE to iwlan in
+ Wi-Fi-preferred mode. Measure IMS handover time.
+
+ Test steps:
+ 1. Enable WFC and set WFC mode to Wi-Fi-preferred mode.
+ 2. Ensure Wi-Fi are disconnected and all cellular services are
+ available.
+ 3. (Optional) Make a VoLTE call and keep the call active.
+ 4. Connect Wi-Fi. The IMS registration should hand over from LTE
+ to iwlan.
+ 5. Parse logcat to calculate the IMS handover time.
+
+ Args:
+ voice_call: True if an active VoLTE call is desired in the background
+ during IMS handover procedure. Otherwise False.
+ """
+ ad = self.android_devices[0]
+ if voice_call:
+ cycle = self.ims_handover_4g_to_iwlan_with_voice_call_wfc_wifi_preferred_test_cycle
+ else:
+ cycle = self.ims_handover_4g_to_iwlan_wfc_wifi_preferred_test_cycle
+
+ voice_slot = get_slot_index_from_voice_sub_id(ad)
+
+ result = []
+ search_intervals = []
+ exit_due_to_high_fail_rate = False
+
+ if not set_wfc_mode(self.log, ad, WFC_MODE_WIFI_PREFERRED):
+ return False
+
+ for attempt in range(cycle):
+ _continue = True
+ self.log.info(
+ '======> IMS handover from LTE to iwlan in WFC wifi-preferred '
+ 'mode %s/%s <======',
+ attempt+1,
+ cycle)
+
+ begin_time = datetime.now()
+
+ if not wait_for_wifi_disconnected(ad, self.wifi_network_ssid):
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if not wait_for_network_service(
+ self.log,
+ ad,
+ wifi_connected=False,
+ ims_reg=True):
+
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if voice_call:
+ ad_mt = self.android_devices[1]
+ call_params = [(
+ ad,
+ ad_mt,
+ None,
+ is_phone_in_call_volte,
+ None)]
+ call_result = two_phone_call_short_seq(
+ self.log,
+ ad,
+ phone_idle_volte,
+ is_phone_in_call_volte,
+ ad_mt,
+ None,
+ None,
+ wait_time_in_call=30,
+ call_params=call_params)
+ self.tel_logger.set_result(call_result.result_value)
+ if not call_result:
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if not phone_setup_iwlan(
+ self.log,
+ ad,
+ False,
+ WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass):
+
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if voice_slot == 0:
+ ims_pattern = ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT0
+ else:
+ ims_pattern = ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT1
+
+ if wait_for_log(ad, ims_pattern, begin_time=begin_time):
+ ad.log.info(
+ 'IMS registration is handed over from LTE to iwlan.')
+ else:
+ ad.log.error(
+ 'IMS registration is NOT yet handed over from LTE to '
+ 'iwlan.')
+
+ if voice_call:
+ hangup_call(self.log, ad)
+
+ if _continue:
+ if not verify_internet_connection(self.log, ad):
+ result.append(VERIFY_INTERNET_FAIL)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if not wait_for_wifi_disconnected(
+ ad, self.wifi_network_ssid):
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if voice_slot == 0:
+ ims_pattern = ON_IMS_MM_TEL_CONNECTED_4G_SLOT0
+ else:
+ ims_pattern = ON_IMS_MM_TEL_CONNECTED_4G_SLOT1
+
+ if wait_for_log(ad, ims_pattern, begin_time=begin_time):
+ ad.log.info(
+ 'IMS registration is handed over from iwlan to LTE.')
+ else:
+ ad.log.error(
+ 'IMS registration is NOT yet handed over from iwlan to '
+ 'LTE.')
+
+ if _continue:
+ result.append(True)
+ end_time = datetime.now()
+ search_intervals.append([begin_time, end_time])
+
+ if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or (
+ attempt == cycle - 1) or exit_due_to_high_fail_rate:
+
+ ad.log.info(
+ '====== Test result of IMS registration at slot %s ======',
+ voice_slot)
+ ad.log.info(result)
+
+ ims_reg, parsing_fail, avg_ims_reg_duration = parse_ims_reg(
+ ad, search_intervals, 'iwlan', 'apm')
+ ad.log.info(
+ '====== IMS registration at slot %s ======', voice_slot)
+ for msg in ims_reg:
+ ad.log.info(msg)
+
+ ad.log.info(
+ '====== Attempt of parsing fail at slot %s ======' % voice_slot)
+ for msg in parsing_fail:
+ ad.log.info(msg)
+
+ ad.log.warning('====== Summary ======')
+ ad.log.warning(
+ '%s/%s cycles failed.',
+ (len(result) - result.count(True)),
+ len(result))
+ for attempt, value in enumerate(result):
+ if value is not True:
+ ad.log.warning('Cycle %s: %s', attempt+1, value)
+
+ try:
+ fail_rate = (len(result) - result.count(True))/len(result)
+ ad.log.info(
+ 'Fail rate of IMS registration at slot %s: %s',
+ voice_slot,
+ fail_rate)
+ except Exception as e:
+ ad.log.error(
+ 'Fail rate of IMS registration at slot %s: ERROR (%s)',
+ voice_slot,
+ e)
+
+ ad.log.info(
+ 'Number of trials with valid parsed logs: %s',len(ims_reg))
+ ad.log.info(
+ 'Average IMS registration time at slot %s: %s',
+ voice_slot, avg_ims_reg_duration)
+
+ if exit_due_to_high_fail_rate:
+ break
+
+ return test_result(result, cycle)
+
+ @test_tracker_info(uuid="e3d1aaa8-f673-4a2b-adb1-cfa525a4edbd")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_ims_handover_4g_to_iwlan_with_voice_call_wfc_wifi_preferred(self):
+ """Connect WFC to make IMS registration hand over from LTE to iwlan in
+ Wi-Fi-preferred mode. Measure IMS handover time.
+
+ Test steps:
+ 1. Enable WFC and set WFC mode to Wi-Fi-preferred mode.
+ 2. Ensure Wi-Fi are disconnected and all cellular services are
+ available.
+ 3. Make a VoLTE call and keep the call active.
+ 4. Connect Wi-Fi. The IMS registration should hand over from LTE
+ to iwlan.
+ 5. Parse logcat to calculate the IMS handover time.
+ """
+ return self.ims_handover_4g_to_iwlan_wfc_wifi_preferred(True)
+
+ @test_tracker_info(uuid="bd86fb46-04bd-4642-923a-747e6c9d4282")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_ims_handover_4g_to_iwlan_wfc_wifi_preferred(self):
+ """Connect WFC to make IMS registration hand over from LTE to iwlan in
+ Wi-Fi-preferred mode. Measure IMS handover time.
+
+ Test steps:
+ 1. Enable WFC and set WFC mode to Wi-Fi-preferred mode.
+ 2. Ensure Wi-Fi are disconnected and all cellular services are
+ available.
+ 3. Connect Wi-Fi. The IMS registration should hand over from LTE
+ to iwlan.
+ 4. Parse logcat to calculate the IMS handover time.
+ """
+ return self.ims_handover_4g_to_iwlan_wfc_wifi_preferred(False)
+
+ def ims_handover_iwlan_to_4g_wfc_wifi_preferred(self, voice_call=False):
+ """Disconnect Wi-Fi to make IMS registration hand over from iwlan to LTE
+ in Wi-Fi-preferred mode. Measure IMS handover time.
+
+ Test steps:
+ 1. Enable WFC, set WFC mode to Wi-Fi-preferred mode, and then
+ connect Wi-Fi to let IMS register over iwlan.
+ 2. (Optional) Make a WFC call and keep the call active.
+ 3. Disconnect Wi-Fi. The IMS registration should hand over from iwlan
+ to LTE.
+ 4. Parse logcat to calculate the IMS handover time.
+
+ Args:
+ voice_call: True if an active WFC call is desired in the background
+ during IMS handover procedure. Otherwise False.
+ """
+ ad = self.android_devices[0]
+ if voice_call:
+ cycle = self.ims_handover_iwlan_to_4g_with_voice_call_wfc_wifi_preferred_test_cycle
+ else:
+ cycle = self.ims_handover_iwlan_to_4g_wfc_wifi_preferred_test_cycle
+ voice_slot = get_slot_index_from_voice_sub_id(ad)
+
+ result = []
+ search_intervals = []
+ exit_due_to_high_fail_rate = False
+ for attempt in range(cycle):
+ _continue = True
+ self.log.info(
+ '======> IMS handover from iwlan to LTE in WFC wifi-preferred '
+ 'mode %s/%s <======',
+ attempt+1,
+ cycle)
+
+ begin_time = datetime.now()
+
+ if not phone_setup_iwlan(
+ self.log,
+ ad,
+ False,
+ WFC_MODE_WIFI_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass):
+
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ wait_for_wifi_disconnected(ad, self.wifi_network_ssid)
+
+ if _continue:
+ if voice_slot == 0:
+ ims_pattern = ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT0
+ else:
+ ims_pattern = ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT1
+
+ if wait_for_log(ad, ims_pattern, begin_time=begin_time):
+ ad.log.info(
+ 'IMS registration is handed over from LTE to iwlan.')
+ else:
+ ad.log.error(
+ 'IMS registration is NOT yet handed over from LTE to '
+ 'iwlan.')
+
+ if _continue:
+ if not verify_internet_connection(self.log, ad):
+ result.append(VERIFY_INTERNET_FAIL)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if voice_call:
+ ad_mt = self.android_devices[1]
+ call_params = [(
+ ad,
+ ad_mt,
+ None,
+ is_phone_in_call_iwlan,
+ None)]
+ call_result = two_phone_call_short_seq(
+ self.log,
+ ad,
+ phone_idle_iwlan,
+ is_phone_in_call_iwlan,
+ ad_mt,
+ None,
+ None,
+ wait_time_in_call=30,
+ call_params=call_params)
+ self.tel_logger.set_result(call_result.result_value)
+ if not call_result:
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if not wait_for_wifi_disconnected(
+ ad, self.wifi_network_ssid):
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if voice_slot == 0:
+ ims_pattern = ON_IMS_MM_TEL_CONNECTED_4G_SLOT0
+ else:
+ ims_pattern = ON_IMS_MM_TEL_CONNECTED_4G_SLOT1
+
+ if wait_for_log(ad, ims_pattern, begin_time=begin_time):
+ ad.log.info(
+ 'IMS registration is handed over from iwlan to LTE.')
+ else:
+ ad.log.error(
+ 'IMS registration is NOT yet handed over from iwlan to '
+ 'LTE.')
+
+ if voice_call:
+ hangup_call(self.log, ad)
+
+ if _continue:
+ if not wait_for_network_service(
+ self.log,
+ ad,
+ wifi_connected=False,
+ ims_reg=True):
+
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ result.append(True)
+ end_time = datetime.now()
+ search_intervals.append([begin_time, end_time])
+
+ if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or (
+ attempt == cycle - 1) or exit_due_to_high_fail_rate:
+
+ ad.log.info(
+ '====== Test result of IMS registration at slot %s ======',
+ voice_slot)
+ ad.log.info(result)
+
+ ims_reg, parsing_fail, avg_ims_reg_duration = parse_ims_reg(
+ ad, search_intervals, '4g', 'wifi_off')
+ ad.log.info(
+ '====== IMS registration at slot %s ======', voice_slot)
+ for msg in ims_reg:
+ ad.log.info(msg)
+
+ ad.log.info(
+ '====== Attempt of parsing fail at slot %s ======' % voice_slot)
+ for msg in parsing_fail:
+ ad.log.info(msg)
+
+ ad.log.warning('====== Summary ======')
+ ad.log.warning(
+ '%s/%s cycles failed.',
+ (len(result) - result.count(True)),
+ len(result))
+ for attempt, value in enumerate(result):
+ if value is not True:
+ ad.log.warning('Cycle %s: %s', attempt+1, value)
+
+ try:
+ fail_rate = (len(result) - result.count(True))/len(result)
+ ad.log.info(
+ 'Fail rate of IMS registration at slot %s: %s',
+ voice_slot,
+ fail_rate)
+ except Exception as e:
+ ad.log.error(
+ 'Fail rate of IMS registration at slot %s: ERROR (%s)',
+ voice_slot,
+ e)
+
+ ad.log.info(
+ 'Number of trials with valid parsed logs: %s', len(ims_reg))
+ ad.log.info(
+ 'Average IMS registration time at slot %s: %s',
+ voice_slot, avg_ims_reg_duration)
+
+ if exit_due_to_high_fail_rate:
+ break
+
+ return test_result(result, cycle)
+
+ @test_tracker_info(uuid="6ce623a6-7ef9-42db-8099-d5c449e70bff")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_ims_handover_iwlan_to_4g_wfc_wifi_preferred(self):
+ """Disconnect Wi-Fi to make IMS registration hand over from iwlan to LTE
+ in Wi-Fi-preferred mode. Measure IMS handover time.
+
+ Test steps:
+ 1. Enable WFC, set WFC mode to Wi-Fi-preferred mode, and then
+ connect Wi-Fi to let IMS register over iwlan.
+ 2. Disconnect Wi-Fi. The IMS registration should hand over from iwlan
+ to LTE.
+ 3. Parse logcat to calculate the IMS handover time.
+ """
+ return self.ims_handover_iwlan_to_4g_wfc_wifi_preferred(False)
+
+ @test_tracker_info(uuid="b965ab09-d8b1-423f-bb98-2cdd43babbe3")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_ims_handover_iwlan_to_4g_with_voice_call_wfc_wifi_preferred(self):
+ """Disconnect Wi-Fi to make IMS registration hand over from iwlan to LTE
+ in Wi-Fi-preferred mode. Measure IMS handover time.
+
+ Test steps:
+ 1. Enable WFC, set WFC mode to Wi-Fi-preferred mode, and then
+ connect Wi-Fi to let IMS register over iwlan.
+ 2. Make a WFC call and keep the call active.
+ 3. Disconnect Wi-Fi. The IMS registration should hand over from iwlan
+ to LTE.
+ 4. Parse logcat to calculate the IMS handover time.
+ """
+ return self.ims_handover_iwlan_to_4g_wfc_wifi_preferred(True)
+
+ def ims_handover_iwlan_to_4g_wfc_cellular_preferred(self, voice_call=False):
+ """Turn off airplane mode to make IMS registration hand over from iwlan to LTE
+ in WFC cellular-preferred mode. Measure IMS handover time.
+
+ Test steps:
+ 1. Enable WFC, set WFC mode to cellular-preferred mode, turn on
+ airplane mode and then connect Wi-Fi to let IMS register over
+ iwlan.
+ 2. (Optional) Make a WFC call and keep the call active.
+ 3. Turn off airplane mode. The IMS registration should hand over
+ from iwlan to LTE.
+ 4. Parse logcat to calculate the IMS handover time.
+
+ Args:
+ voice_call: True if an active WFC call is desired in the background
+ during IMS handover procedure. Otherwise False.
+ """
+ ad = self.android_devices[0]
+ if voice_call:
+ cycle = self.ims_handover_iwlan_to_4g_with_voice_call_wfc_cellular_preferred_test_cycle
+ else:
+ cycle = self.ims_handover_iwlan_to_4g_wfc_cellular_preferred_test_cycle
+
+ voice_slot = get_slot_index_from_voice_sub_id(ad)
+
+ result = []
+ search_intervals = []
+ exit_due_to_high_fail_rate = False
+ for attempt in range(cycle):
+ _continue = True
+
+ self.log.info(
+ '======> IMS handover from iwlan to LTE in WFC '
+ 'cellular-preferred mode %s/%s <======',
+ attempt+1,
+ cycle)
+
+ begin_time = datetime.now()
+
+ if not phone_setup_iwlan(
+ self.log,
+ ad,
+ True,
+ WFC_MODE_CELLULAR_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass):
+
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ toggle_airplane_mode(self.log, ad, False)
+
+ if _continue:
+ if voice_slot == 0:
+ ims_pattern = ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT0
+ else:
+ ims_pattern = ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT1
+
+ if wait_for_log(ad, ims_pattern, begin_time=begin_time):
+ ad.log.info(
+ 'IMS registration is handed over from LTE to iwlan.')
+ else:
+ ad.log.error(
+ 'IMS registration is NOT yet handed over from LTE to '
+ 'iwlan.')
+
+ if _continue:
+ if not verify_internet_connection(self.log, ad):
+ result.append(VERIFY_INTERNET_FAIL)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if voice_call:
+ ad_mt = self.android_devices[1]
+ call_params = [(
+ ad,
+ ad_mt,
+ None,
+ is_phone_in_call_iwlan,
+ None)]
+ call_result = two_phone_call_short_seq(
+ self.log,
+ ad,
+ phone_idle_iwlan,
+ is_phone_in_call_iwlan,
+ ad_mt,
+ None,
+ None,
+ wait_time_in_call=30,
+ call_params=call_params)
+ self.tel_logger.set_result(call_result.result_value)
+ if not call_result:
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if not toggle_airplane_mode(self.log, ad, False):
+ result.append(TOGGLE_OFF_APM_FAIL)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ if voice_slot == 0:
+ ims_pattern = ON_IMS_MM_TEL_CONNECTED_4G_SLOT0
+ else:
+ ims_pattern = ON_IMS_MM_TEL_CONNECTED_4G_SLOT1
+
+ if wait_for_log(ad, ims_pattern, begin_time=begin_time):
+ ad.log.info(
+ 'IMS registration is handed over from iwlan to LTE.')
+ else:
+ ad.log.error(
+ 'IMS registration is NOT yet handed over from iwlan to '
+ 'LTE.')
+
+ if voice_call:
+ hangup_call(self.log, ad)
+
+ if _continue:
+ if not wait_for_network_service(
+ self.log,
+ ad,
+ wifi_connected=True,
+ wifi_ssid=self.wifi_network_ssid,
+ ims_reg=True):
+
+ result.append(False)
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ _continue = False
+ if not test_result(result, cycle, 10, 0.1):
+ exit_due_to_high_fail_rate = True
+
+ if _continue:
+ result.append(True)
+ end_time = datetime.now()
+ search_intervals.append([begin_time, end_time])
+
+ if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or (
+ attempt == cycle - 1) or exit_due_to_high_fail_rate:
+
+ ad.log.info(
+ '====== Test result of IMS registration at slot %s ======',
+ voice_slot)
+ ad.log.info(result)
+
+ ims_reg, parsing_fail, avg_ims_reg_duration = parse_ims_reg(
+ ad, search_intervals, '4g', 'apm')
+ ad.log.info(
+ '====== IMS registration at slot %s ======', voice_slot)
+ for msg in ims_reg:
+ ad.log.info(msg)
+
+ ad.log.info(
+ '====== Attempt of parsing fail at slot %s ======' % voice_slot)
+ for msg in parsing_fail:
+ ad.log.info(msg)
+
+ ad.log.warning('====== Summary ======')
+ ad.log.warning(
+ '%s/%s cycles failed.',
+ (len(result) - result.count(True)),
+ len(result))
+ for attempt, value in enumerate(result):
+ if value is not True:
+ ad.log.warning('Cycle %s: %s', attempt+1, value)
+
+ try:
+ fail_rate = (len(result) - result.count(True))/len(result)
+ ad.log.info(
+ 'Fail rate of IMS registration at slot %s: %s',
+ voice_slot,
+ fail_rate)
+ except Exception as e:
+ ad.log.error(
+ 'Fail rate of IMS registration at slot %s: ERROR (%s)',
+ voice_slot,
+ e)
+
+ ad.log.info(
+ 'Number of trials with valid parsed logs: %s', len(ims_reg))
+ ad.log.info(
+ 'Average IMS registration time at slot %s: %s',
+ voice_slot, avg_ims_reg_duration)
+
+ if exit_due_to_high_fail_rate:
+ break
+
+ return test_result(result, cycle)
+
+ @test_tracker_info(uuid="ce69fac3-931b-4177-82ea-dbae50b2b310")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_ims_handover_iwlan_to_4g_wfc_cellular_preferred(self):
+ """Turn off airplane mode to make IMS registration hand over from iwlan to LTE
+ in WFC cellular-preferred mode. Measure IMS handover time.
+
+ Test steps:
+ 1. Enable WFC, set WFC mode to cellular-preferred mode, turn on
+ airplane mode and then connect Wi-Fi to let IMS register over
+ iwlan.
+ 2. Turn off airplane mode. The IMS registration should hand over
+ from iwlan to LTE.
+ 3. Parse logcat to calculate the IMS handover time.
+ """
+ return self.ims_handover_iwlan_to_4g_wfc_cellular_preferred(False)
+
+ @test_tracker_info(uuid="0ac7d43e-34e6-4ea3-92f4-e413e90a8bc1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_ims_handover_iwlan_to_4g_with_voice_call_wfc_cellular_preferred(self):
+ """Turn off airplane mode to make IMS registration hand over from iwlan to LTE
+ in WFC cellular-preferred mode. Measure IMS handover time.
+
+ Test steps:
+ 1. Enable WFC, set WFC mode to cellular-preferred mode, turn on
+ airplane mode and then connect Wi-Fi to let IMS register over
+ iwlan.
+ 2. Make a WFC call and keep the call active.
+ 3. Turn off airplane mode. The IMS registration should hand over
+ from iwlan to LTE.
+ 4. Parse logcat to calculate the IMS handover time.
+ """
+ return self.ims_handover_iwlan_to_4g_wfc_cellular_preferred(True)
\ No newline at end of file
diff --git a/acts_tests/tests/google/tel/live/TelLiveRilMessageKpiTest.py b/acts_tests/tests/google/tel/live/TelLiveRilMessageKpiTest.py
new file mode 100644
index 0000000..aa1c5d3
--- /dev/null
+++ b/acts_tests/tests/google/tel/live/TelLiveRilMessageKpiTest.py
@@ -0,0 +1,442 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - 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.
+
+import random
+import time
+
+from acts.libs.utils.multithread import multithread_func
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
+from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_parse_utils import parse_mms
+from acts_contrib.test_utils.tel.tel_parse_utils import parse_sms_delivery_time
+from acts_contrib.test_utils.tel.tel_parse_utils import print_nested_dict
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan_for_subscription
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_message_subid
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
+from acts.utils import get_current_epoch_time
+from acts.utils import rand_ascii_str
+
+CALCULATE_EVERY_N_CYCLES = 10
+MAX_FAIL_COUNT = 10
+
+
+class TelLiveRilMessageKpiTest(TelephonyBaseTest):
+ def setup_class(self):
+ TelephonyBaseTest.setup_class(self)
+ self.sms_4g_over_sgs_test_cycle = self.user_params.get(
+ 'sms_4g_over_sgs_test_cycle', 1)
+ self.sms_4g_over_ims_test_cycle = self.user_params.get(
+ 'sms_4g_over_ims_test_cycle', 1)
+ self.sms_iwlan_test_cycle = self.user_params.get(
+ 'sms_iwlan_test_cycle', 1)
+ self.mms_4g_test_cycle = self.user_params.get('mms_4g_test_cycle', 1)
+ self.mms_iwlan_test_cycle = self.user_params.get(
+ 'mms_iwlan_test_cycle', 1)
+
+ def sms_test(self, ads):
+ """Send and receive a short SMS with random length and content between
+ two UEs.
+
+ Args:
+ ads: list containing Android objects
+
+ Returns:
+ True if both sending and receiving are successful. Otherwise False.
+ """
+ msg_length = random.randint(5, 160)
+ msg_body = rand_ascii_str(msg_length)
+
+ if not sms_send_receive_verify(self.log, ads[0], ads[1], [msg_body]):
+ ads[0].log.warning('SMS of length %s test failed', msg_length)
+ return False
+ else:
+ ads[0].log.info('SMS of length %s test succeeded', msg_length)
+ return True
+
+ def mms_test(self, ads, expected_result=True):
+ """Send and receive a MMS with random text length and content between
+ two UEs.
+
+ Args:
+ ads: list containing Android objects
+ expected_result: True to expect successful MMS sending and reception.
+ Otherwise False.
+
+ Returns:
+ True if both sending and reception are successful. Otherwise False.
+ """
+ message_length = random.randint(5, 160)
+ message_array = [('Test Message', rand_ascii_str(message_length), None)]
+ if not mms_send_receive_verify(
+ self.log,
+ ads[0],
+ ads[1],
+ message_array,
+ expected_result=expected_result):
+ self.log.warning('MMS of body length %s test failed', message_length)
+ return False
+ else:
+ self.log.info('MMS of body length %s test succeeded', message_length)
+ self.log.info('MMS test of body lengths %s succeeded', message_length)
+ return True
+
+
+ def _test_sms_4g(self, over_iwlan=False, over_ims=False):
+ """ Send/receive SMS over SGs/IMS to measure MO SMS setup time and SMS
+ delivery time.
+
+ Test steps:
+ 1. Enable VoLTE when over IMS. Otherwise disable VoLTE.
+ 2. Send a SMS from MO UE and receive it by MT UE.
+ 3. Parse logcat of both MO and MT UEs to calculate MO SMS setup time
+ and SMS delivery time.
+
+ Args:
+ over_iwlan: True for over Wi-Fi and False for over cellular network
+ over_ims: True for over IMS and False for over SGs
+
+ Returns:
+ True if both sending and reception are successful. Otherwise False.
+ """
+ ad_mo = self.android_devices[0]
+ ad_mt = self.android_devices[1]
+
+ mo_sub_id, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
+ [ad_mo, ad_mt],
+ host_sub_id=None,
+ type="sms")
+ set_message_subid(ad_mt, mt_sub_id)
+
+ cycle = self.sms_4g_over_sgs_test_cycle
+ phone_setup_func = phone_setup_csfb_for_subscription
+ mo_param = (self.log, ad_mo, mo_sub_id)
+ mt_param = (self.log, ad_mt, mt_sub_id)
+ wording = "SGs"
+ parsing = '4g'
+ if over_ims:
+ cycle = self.sms_4g_over_ims_test_cycle
+ phone_setup_func = phone_setup_volte_for_subscription
+ wording = "IMS"
+ parsing = 'iwlan'
+
+ if over_iwlan:
+ cycle = self.sms_iwlan_test_cycle
+ phone_setup_func = phone_setup_iwlan_for_subscription
+
+ mo_param = (
+ self.log,
+ ad_mo,
+ mo_sub_id,
+ True,
+ WFC_MODE_CELLULAR_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass)
+
+ mt_param = (
+ self.log,
+ ad_mt,
+ mt_sub_id,
+ True,
+ WFC_MODE_CELLULAR_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass)
+
+ wording = 'iwlan'
+ parsing = 'iwlan'
+
+ tasks = [
+ (phone_setup_func, mo_param),
+ (phone_setup_func, mt_param)]
+ 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)
+
+ sms_test_summary = []
+ result = True
+ continuous_fail = 0
+ for attempt in range(cycle):
+ self.log.info(
+ '======> MO/MT SMS over %s %s/%s <======',
+ wording,
+ attempt+1,
+ cycle)
+ res = self.sms_test([ad_mo, ad_mt])
+ sms_test_summary.append(res)
+
+ if not res:
+ continuous_fail += 1
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ else:
+ time.sleep(random.randint(3,10))
+
+ if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or (
+ attempt == cycle - 1) or continuous_fail >= MAX_FAIL_COUNT:
+ parse_sms_delivery_time(self.log, ad_mo, ad_mt, rat=parsing)
+ try:
+ sms_test_fail_rate = sms_test_summary.count(
+ False)/len(sms_test_summary)
+ self.log.info(
+ 'Fail rate of SMS test over %s: %s/%s (%.2f)',
+ wording,
+ sms_test_summary.count(False),
+ len(sms_test_summary),
+ sms_test_fail_rate)
+ except Exception as e:
+ self.log.error(
+ 'Fail rate of SMS test over %s: ERROR (%s)',
+ wording,
+ e)
+
+ if continuous_fail >= MAX_FAIL_COUNT:
+ self.log.error(
+ 'Failed more than %s times in succession. Test is terminated '
+ 'forcedly.',
+ MAX_FAIL_COUNT)
+ break
+
+ return result
+
+
+ @test_tracker_info(uuid="13d1a53b-66be-4ac1-b5ee-dfe4c5e4e4e1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_sms_4g_over_sgs(self):
+ """ Send/receive SMS over SGs to measure MO SMS setup time and SMS
+ delivery time.
+
+ Test steps:
+ 1. Disable VoLTE.
+ 2. Send a SMS from MO UE and receive it by MT UE.
+ 3. Parse logcat of both MO and MT UEs to calculate MO SMS setup time
+ and SMS delivery time.
+ """
+ return self._test_sms_4g()
+
+
+ @test_tracker_info(uuid="293e2955-b38b-4329-b686-fb31d9e46868")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_sms_4g_over_ims(self):
+ """ Send/receive SMS over IMS to measure MO SMS setup time and SMS
+ delivery time.
+
+ Test steps:
+ 1. Enable VoLTE.
+ 2. Send a SMS from MO UE and receive it by MT UE.
+ 3. Parse logcat of both MO and MT UEs to calculate MO SMS setup time
+ and SMS delivery time.
+ """
+ return self._test_sms_4g(over_ims=True)
+
+
+ @test_tracker_info(uuid="862fec2d-8e23-482e-b45c-a42cad134022")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_sms_iwlan(self):
+ """ Send/receive SMS on iwlan to measure MO SMS setup time and SMS
+ delivery time.
+
+ Test steps:
+ 1. Send a SMS from MO UE and receive it by MT UE.
+ 2. Parse logcat of both MO and MT UEs to calculate MO SMS setup time
+ and SMS delivery time.
+ """
+ return self._test_sms_4g(over_iwlan=True, over_ims=True)
+
+
+ def _test_mms_4g(self, over_iwlan=False):
+ """ Send/receive MMS on LTE to measure MO and MT MMS setup time
+
+ Test steps:
+ 1. Enable VoLTE when over Wi-Fi (iwlan). Otherwise disable VoLTE.
+ 2. Send a MMS from MO UE and receive it by MT UE.
+ 3. Parse logcat of both MO and MT UEs to calculate MO and MT MMS
+ setup time.
+
+ Args:
+ over_iwlan: True for over Wi-Fi and False for over cellular network
+
+ Returns:
+ True if both sending and reception are successful. Otherwise False.
+ """
+ ad_mo = self.android_devices[0]
+ ad_mt = self.android_devices[1]
+
+ mo_sub_id, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
+ [ad_mo, ad_mt],
+ host_sub_id=None,
+ type="sms")
+ set_message_subid(ad_mt, mt_sub_id)
+
+ cycle = self.mms_4g_test_cycle
+ phone_setup_func = phone_setup_csfb_for_subscription
+ mo_param = (self.log, ad_mo, mo_sub_id)
+ mt_param = (self.log, ad_mt, mt_sub_id)
+ wording = "LTE"
+ if over_iwlan:
+ cycle = self.mms_iwlan_test_cycle
+ phone_setup_func = phone_setup_iwlan_for_subscription
+ wording = "iwlan"
+
+ mo_param = (
+ self.log,
+ ad_mo,
+ mo_sub_id,
+ True,
+ WFC_MODE_CELLULAR_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass)
+
+ mt_param = (
+ self.log,
+ ad_mt,
+ mt_sub_id,
+ True,
+ WFC_MODE_CELLULAR_PREFERRED,
+ self.wifi_network_ssid,
+ self.wifi_network_pass)
+
+ phone_setup_tasks = [
+ (phone_setup_func, mo_param),
+ (phone_setup_func, mt_param)]
+ if not multithread_func(self.log, phone_setup_tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ if not over_iwlan:
+ wait_for_cell_data_connection_tasks = [
+ (wait_for_cell_data_connection, (self.log, ad_mo, True)),
+ (wait_for_cell_data_connection, (self.log, ad_mt, True))]
+ if not multithread_func(self.log, wait_for_cell_data_connection_tasks):
+ return False
+
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+
+ mms_test_summary = []
+ result = True
+ continuous_fail = 0
+ for attempt in range(cycle):
+ self.log.info(
+ '==================> MO/MT MMS on %s %s/%s <==================',
+ wording,
+ attempt+1,
+ cycle)
+ res = self.mms_test([ad_mo, ad_mt])
+ mms_test_summary.append(res)
+
+ if not res:
+ continuous_fail += 1
+ if not multithread_func(self.log, phone_setup_tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ result = False
+ break
+
+ if not over_iwlan:
+ if not multithread_func(
+ self.log, wait_for_cell_data_connection_tasks):
+ result = False
+ break
+ self._take_bug_report(
+ self.test_name, begin_time=get_current_epoch_time())
+ else:
+ time.sleep(random.randint(3,10))
+
+ if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or (
+ attempt == cycle - 1) or continuous_fail >= MAX_FAIL_COUNT:
+ (
+ mo_res,
+ mo_avg_setup_time,
+ mt_res, mt_avg_setup_time) = parse_mms(ad_mo, ad_mt)
+
+ ad_mo.log.info('================== Sent MMS ==================')
+ print_nested_dict(ad_mo, mo_res)
+ ad_mt.log.info('================== Received MMS ==================')
+ print_nested_dict(ad_mt, mt_res)
+
+ try:
+ ad_mo.log.info(
+ 'Average setup time of MO MMS on %s: %.2f sec.',
+ wording, mo_avg_setup_time)
+ except Exception as e:
+ ad_mo.log.error(
+ 'Average setup time of MO MMS on %s: ERROR (%s)',
+ wording, e)
+
+ try:
+ ad_mt.log.info(
+ 'Average setup time of MT MMS on %s: %.2f sec.',
+ wording, mt_avg_setup_time)
+ except Exception as e:
+ ad_mt.log.error(
+ 'Average setup time of MT MMS on %s: ERROR (%s)',
+ wording, e)
+
+ try:
+ mms_test_fail_rate = mms_test_summary.count(
+ False)/len(mms_test_summary)
+ self.log.info(
+ 'Fail rate of MMS test on LTE: %s/%s (%.2f)',
+ mms_test_summary.count(False),
+ len(mms_test_summary),
+ mms_test_fail_rate)
+ except Exception as e:
+ self.log.error(
+ 'Fail rate of MMS test on %s: ERROR (%s)', wording, e)
+
+ if continuous_fail >= MAX_FAIL_COUNT:
+ self.log.error(
+ 'Failed more than %s times in succession. Test is terminated '
+ 'forcedly.',
+ MAX_FAIL_COUNT)
+ break
+
+ return result
+
+
+ @test_tracker_info(uuid="33d11da8-71f1-40d7-8fc7-86fdc83ce266")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_mms_4g(self):
+ """ Send/receive MMS on LTE to measure MO and MT MMS setup time
+
+ Test steps:
+ 1. Send a MMS from MO UE and receive it by MT UE.
+ 2. Parse logcat of both MO and MT UEs to calculate MO and MT MMS
+ setup time.
+ """
+ return self._test_mms_4g()
+
+
+ @test_tracker_info(uuid="b8a8affa-6559-41d8-9de7-f74406da9ed5")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_mms_iwlan(self):
+ """ Send/receive MMS on iwlan to measure MO and MT MMS setup time
+
+ Test steps:
+ 1. Send a MMS from MO UE and receive it by MT UE.
+ 2. Parse logcat of both MO and MT UEs to calculate MO and MT MMS
+ setup time.
+ """
+ return self._test_mms_4g(over_iwlan=True)
\ No newline at end of file
diff --git a/acts_tests/tests/google/tel/live/TelLiveSettingsTest.py b/acts_tests/tests/google/tel/live/TelLiveSettingsTest.py
index 879353e..6f60282 100644
--- a/acts_tests/tests/google/tel/live/TelLiveSettingsTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveSettingsTest.py
@@ -26,22 +26,22 @@
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
+from acts_contrib.test_utils.tel.tel_bootloader_utils import flash_radio
+from acts_contrib.test_utils.tel.tel_logging_utils import set_qxdm_logger_command
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_subscription
from acts_contrib.test_utils.tel.tel_test_utils import dumpsys_carrier_config
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import flash_radio
from acts_contrib.test_utils.tel.tel_test_utils import get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import get_slot_index_from_subid
from acts_contrib.test_utils.tel.tel_test_utils import is_sim_locked
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
from acts_contrib.test_utils.tel.tel_test_utils import power_off_sim
from acts_contrib.test_utils.tel.tel_test_utils import power_on_sim
from acts_contrib.test_utils.tel.tel_test_utils import print_radio_info
from acts_contrib.test_utils.tel.tel_test_utils import revert_default_telephony_setting
-from acts_contrib.test_utils.tel.tel_test_utils import set_qxdm_logger_command
from acts_contrib.test_utils.tel.tel_test_utils import system_file_push
from acts_contrib.test_utils.tel.tel_test_utils import unlock_sim
from acts_contrib.test_utils.tel.tel_test_utils import verify_default_telephony_setting
from acts.utils import set_mobile_data_always_on
+from acts.libs.utils.multithread import multithread_func
class TelLiveSettingsTest(TelephonyBaseTest):
@@ -258,7 +258,7 @@
old_carrier_id, old_carrier_name)
self.dut.log.info(self.result_detail)
sub_id = get_outgoing_voice_sub_id(self.dut)
- slot_index = get_slot_index_from_subid(self.log, self.dut, sub_id)
+ slot_index = get_slot_index_from_subid(self.dut, sub_id)
if self.dut.model in ("angler", "bullhead", "marlin", "sailfish"):
msg = "Power off SIM slot is not supported"
diff --git a/acts_tests/tests/google/tel/live/TelLiveSmokeTest.py b/acts_tests/tests/google/tel/live/TelLiveSmokeTest.py
index 0b8ce5d..5b9263b 100644
--- a/acts_tests/tests/google/tel/live/TelLiveSmokeTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveSmokeTest.py
@@ -30,25 +30,25 @@
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL_FOR_IMS
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts_contrib.test_utils.tel.tel_lookup_tables import is_rat_svd_capable
-from acts_contrib.test_utils.tel.tel_test_utils import stop_wifi_tethering
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_default_state
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_default_state
from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import sms_send_receive_verify
from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import stop_wifi_tethering
from acts.utils import rand_ascii_str
+from acts.libs.utils.multithread import multithread_func
SKIP = 'Skip'
diff --git a/acts_tests/tests/google/tel/live/TelLiveSmsTest.py b/acts_tests/tests/google/tel/live/TelLiveSmsTest.py
index b9ce084..d03d42a 100644
--- a/acts_tests/tests/google/tel/live/TelLiveSmsTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveSmsTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2016 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -21,246 +21,57 @@
from acts import signals
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import PHONE_TYPE_GSM
-from acts_contrib.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
+from acts_contrib.test_utils.tel.tel_defines import CARRIER_VZW
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import SMS_OVER_WIFI_PROVIDERS
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import get_mobile_data_usage
+from acts_contrib.test_utils.tel.tel_data_utils import get_mobile_data_usage
+from acts_contrib.test_utils.tel.tel_data_utils import remove_mobile_data_usage_limit
+from acts_contrib.test_utils.tel.tel_data_utils import set_mobile_data_usage_limit
+from acts_contrib.test_utils.tel.tel_message_utils import sms_in_collision_send_receive_verify
+from acts_contrib.test_utils.tel.tel_message_utils import sms_rx_power_off_multiple_send_receive_verify
+from acts_contrib.test_utils.tel.tel_message_utils import message_test
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_test_utils import remove_mobile_data_usage_limit
-from acts_contrib.test_utils.tel.tel_test_utils import mms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import mms_receive_verify_after_call_hangup
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import set_mobile_data_usage_limit
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode
-from acts_contrib.test_utils.tel.tel_test_utils import \
- sms_in_collision_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import \
- sms_rx_power_off_multiple_send_receive_verify
-from acts_contrib.test_utils.tel.tel_video_utils import phone_setup_video
-from acts_contrib.test_utils.tel.tel_video_utils import is_phone_in_call_video_bidirectional
-from acts_contrib.test_utils.tel.tel_video_utils import video_call_setup_teardown
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_not_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan_cellular_preferred
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general
-from acts_contrib.test_utils.tel.tel_sms_utils import _sms_test_mo
-from acts_contrib.test_utils.tel.tel_sms_utils import _sms_test_mt
-from acts_contrib.test_utils.tel.tel_sms_utils import _long_sms_test_mo
-from acts_contrib.test_utils.tel.tel_sms_utils import _long_sms_test_mt
-from acts_contrib.test_utils.tel.tel_mms_utils import _mms_test_mo
-from acts_contrib.test_utils.tel.tel_mms_utils import _mms_test_mt
-from acts_contrib.test_utils.tel.tel_mms_utils import _long_mms_test_mo
-from acts_contrib.test_utils.tel.tel_mms_utils import _long_mms_test_mt
-from acts_contrib.test_utils.tel.tel_mms_utils import _mms_test_mo_after_call_hangup
-from acts_contrib.test_utils.tel.tel_mms_utils import _mms_test_mt_after_call_hangup
-from acts_contrib.test_utils.tel.tel_mms_utils import test_mms_mo_in_call
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_both_devices_for_volte
+from acts_contrib.test_utils.tel.tel_test_utils import install_message_apk
from acts.utils import rand_ascii_str
-
+from acts.libs.utils.multithread import multithread_func
class TelLiveSmsTest(TelephonyBaseTest):
def setup_class(self):
TelephonyBaseTest.setup_class(self)
-
- # Try to put SMS and call on different help device
- # If it is a three phone test bed, use the first one as dut,
- # 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]
- self.callee = self.android_devices[1]
self.message_lengths = (50, 160, 180)
- is_roaming = False
- for ad in self.android_devices:
- ad.sms_over_wifi = False
- # verizon supports sms over wifi. will add more carriers later
- for sub in ad.telephony["subscription"].values():
- if sub["operator"] in SMS_OVER_WIFI_PROVIDERS:
- ad.sms_over_wifi = True
- if getattr(ad, 'roaming', False):
- is_roaming = True
- if is_roaming:
- # roaming device does not allow message of length 180
- self.message_lengths = (50, 160)
+ self.message_util = self.user_params.get("message_apk", None)
+ if isinstance(self.message_util, list):
+ self.message_util = self.message_util[0]
+
+ if self.message_util:
+ ads = self.android_devices
+ for ad in ads:
+ install_message_apk(ad, self.message_util)
def teardown_test(self):
ensure_phones_idle(self.log, self.android_devices)
- def _mo_sms_in_3g_call(self, ads):
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- self.caller,
- self.callee,
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_3g,
- verify_callee_func=None):
- return False
-
- if not _sms_test_mo(self.log, ads):
- self.log.error("SMS test fail.")
- return False
-
- return True
-
- def _mt_sms_in_3g_call(self, ads):
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- self.caller,
- self.callee,
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_3g,
- verify_callee_func=None):
- return False
-
- if not _sms_test_mt(self.log, ads):
- self.log.error("SMS test fail.")
- return False
-
- return True
-
- def _mo_mms_in_3g_call(self, ads, wifi=False):
- return test_mms_mo_in_call(self.log, ads, wifi=wifi, caller_func=is_phone_in_call_3g)
-
- def _mt_mms_in_3g_call(self, ads, wifi=False):
- self.log.info("Begin In Call MMS Test.")
- if not call_setup_teardown(
- self.log,
- self.caller,
- self.callee,
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_3g,
- verify_callee_func=None):
- return False
-
- if ads[0].sms_over_wifi and wifi:
- return _mms_test_mt(self.log, ads)
+ def _get_wfc_mode(self, ad):
+ # Verizon doesn't supports wfc mode as WFC_MODE_WIFI_PREFERRED
+ carrier = ad.adb.getprop("gsm.sim.operator.alpha")
+ if carrier == CARRIER_VZW:
+ wfc = WFC_MODE_CELLULAR_PREFERRED
else:
- return _mms_test_mt_after_call_hangup(self.log, ads)
+ wfc = WFC_MODE_WIFI_PREFERRED
+ return wfc
- def _mo_sms_in_2g_call(self, ads):
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- self.caller,
- self.callee,
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_2g,
- verify_callee_func=None):
- return False
+ def check_band_support(self,ad):
+ carrier = ad.adb.getprop("gsm.sim.operator.alpha")
- if not _sms_test_mo(self.log, ads):
- self.log.error("SMS test fail.")
- return False
-
- return True
-
- def _mt_sms_in_2g_call(self, ads):
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- self.caller,
- self.callee,
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_2g,
- verify_callee_func=None):
- return False
-
- if not _sms_test_mt(self.log, ads):
- self.log.error("SMS test fail.")
- return False
-
- return True
-
- def _mo_mms_in_2g_call(self, ads, wifi=False):
- return test_mms_mo_in_call(self.log, ads, wifi=wifi, caller_func=is_phone_in_call_2g)
-
- def _mt_mms_in_2g_call(self, ads, wifi=False):
- self.log.info("Begin In Call MMS Test.")
- if not call_setup_teardown(
- self.log,
- self.caller,
- self.callee,
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_2g,
- verify_callee_func=None):
- return False
-
- if ads[0].sms_over_wifi and wifi:
- return _mms_test_mt(self.log, ads)
- else:
- return _mms_test_mt_after_call_hangup(self.log, ads)
-
- def _mo_sms_in_csfb_call(self, ads):
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- self.caller,
- self.callee,
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_csfb,
- verify_callee_func=None):
- return False
-
- if not _sms_test_mo(self.log, ads):
- self.log.error("SMS test fail.")
- return False
-
- return True
-
- def _mt_sms_in_csfb_call(self, ads):
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- self.caller,
- self.callee,
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_csfb,
- verify_callee_func=None):
- return False
-
- if not _sms_test_mt(self.log, ads):
- self.log.error("SMS test fail.")
- return False
-
- return True
-
- def _mo_mms_in_csfb_call(self, ads, wifi=False):
- return test_mms_mo_in_call(self.log, ads, wifi, caller_func=is_phone_in_call_csfb)
-
- def _mt_mms_in_csfb_call(self, ads, wifi=False):
- self.log.info("Begin In Call MMS Test.")
- if not call_setup_teardown(
- self.log,
- self.caller,
- self.callee,
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_csfb,
- verify_callee_func=None):
- return False
-
- if ads[0].sms_over_wifi and wifi:
- return _mms_test_mt(self.log, ads)
- else:
- return _mms_test_mt_after_call_hangup(self.log, ads)
+ if int(ad.adb.getprop("ro.product.first_api_level")) > 30 and (
+ carrier == CARRIER_VZW):
+ raise signals.TestSkip(
+ "Device Doesn't Support 2g/3G Band.")
def _sms_in_collision_test(self, ads):
for length in self.message_lengths:
@@ -326,16 +137,12 @@
True if success.
False if failed.
"""
- ads = self.android_devices
-
- tasks = [(ensure_phone_default_state, (self.log, ads[0])),
- (ensure_phone_default_state, (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 _sms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='default',
+ mt_rat='default')
@test_tracker_info(uuid="aa87fe73-8236-44c7-865c-3fe3b733eeb4")
@TelephonyBaseTest.tel_test_wrap
@@ -350,15 +157,12 @@
True if success.
False if failed.
"""
- ads = self.android_devices
-
- tasks = [(ensure_phone_default_state, (self.log, ads[0])),
- (ensure_phone_default_state, (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 _sms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='default')
@test_tracker_info(uuid="bb8e1a06-a4b5-4f9b-9ab2-408ace9a1deb")
@TelephonyBaseTest.tel_test_wrap
@@ -373,16 +177,13 @@
True if success.
False if failed.
"""
- ads = self.android_devices
-
- tasks = [(ensure_phone_default_state, (self.log, ads[0])),
- (ensure_phone_default_state, (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 _mms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='default',
+ mt_rat='default',
+ msg_type='mms')
@test_tracker_info(uuid="f2779e1e-7d09-43f0-8b5c-87eae5d146be")
@TelephonyBaseTest.tel_test_wrap
@@ -397,15 +198,13 @@
True if success.
False if failed.
"""
- ads = self.android_devices
-
- tasks = [(ensure_phone_default_state, (self.log, ads[0])),
- (ensure_phone_default_state, (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 _mms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='default',
+ mt_rat='default',
+ msg_type='mms')
@test_tracker_info(uuid="2c229a4b-c954-4ba3-94ba-178dc7784d03")
@TelephonyBaseTest.tel_test_wrap
@@ -420,16 +219,13 @@
True if success.
False if failed.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_voice_2g, (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 _sms_test_mo(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='2g',
+ mt_rat='general')
@test_tracker_info(uuid="17fafc41-7e12-47ab-a4cc-fb9bd94e79b9")
@TelephonyBaseTest.tel_test_wrap
@@ -444,16 +240,13 @@
True if success.
False if failed.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_voice_2g, (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 _sms_test_mt(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='2g')
@test_tracker_info(uuid="b4919317-18b5-483c-82f4-ced37a04f28d")
@TelephonyBaseTest.tel_test_wrap
@@ -468,16 +261,14 @@
True if success.
False if failed.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_voice_2g, (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 _mms_test_mo(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='2g',
+ mt_rat='general',
+ msg_type='mms')
@test_tracker_info(uuid="cd56bb8a-0794-404d-95bd-c5fd00f4b35a")
@TelephonyBaseTest.tel_test_wrap
@@ -492,16 +283,14 @@
True if success.
False if failed.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_voice_2g, (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 _mms_test_mt(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='2g',
+ msg_type='mms')
@test_tracker_info(uuid="b39fbc30-9cc2-4d86-a9f4-6f0c1dd0a905")
@TelephonyBaseTest.tel_test_wrap
@@ -517,16 +306,16 @@
True if success.
False if failed.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_voice_2g, (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 2G.")
- return False
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
- return _mms_test_mo(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='2g',
+ mt_rat='general',
+ msg_type='mms',
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="b158a0a7-9697-4b3b-8d5b-f9b6b6bc1c03")
@TelephonyBaseTest.tel_test_wrap
@@ -542,17 +331,16 @@
True if success.
False if failed.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_voice_2g, (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 2G.")
- return False
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
-
- return _mms_test_mt(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='2g',
+ msg_type='mms',
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="f094e3da-2523-4f92-a1f3-7cf9edcff850")
@TelephonyBaseTest.tel_test_wrap
@@ -567,16 +355,13 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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 _sms_test_mo(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='3g',
+ mt_rat='general')
@test_tracker_info(uuid="2186e152-bf83-4d6e-93eb-b4bf9ae2d76e")
@TelephonyBaseTest.tel_test_wrap
@@ -591,17 +376,13 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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 _sms_test_mt(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='3g')
@test_tracker_info(uuid="e716c678-eee9-4a0d-a9cd-ca9eae4fea51")
@TelephonyBaseTest.tel_test_wrap
@@ -616,17 +397,14 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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 _mms_test_mo(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='3g',
+ mt_rat='general',
+ msg_type='mms')
@test_tracker_info(uuid="e864a99e-d935-4bd9-95f6-8183cdd3d760")
@TelephonyBaseTest.tel_test_wrap
@@ -641,17 +419,14 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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 _mms_test_mt(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='3g',
+ msg_type='mms')
@test_tracker_info(uuid="07cdfe26-9021-4af3-8bf6-1abd0cb9e932")
@TelephonyBaseTest.tel_test_wrap
@@ -666,16 +441,14 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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 _long_sms_test_mo(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='3g',
+ mt_rat='general',
+ long_msg=True)
@test_tracker_info(uuid="740efe0d-fef9-42bc-a732-fe79a3485426")
@TelephonyBaseTest.tel_test_wrap
@@ -690,17 +463,14 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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 _long_sms_test_mt(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='3g',
+ long_msg=True)
@test_tracker_info(uuid="b0d27de3-1a98-48da-a9c9-c20c8587f256")
@TelephonyBaseTest.tel_test_wrap
@@ -715,17 +485,15 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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 _long_mms_test_mo(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='3g',
+ mt_rat='general',
+ msg_type='mms',
+ long_msg=True)
@test_tracker_info(uuid="fd5a1583-94d2-4b3a-b613-a0a9745daa25")
@TelephonyBaseTest.tel_test_wrap
@@ -740,17 +508,15 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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 _long_mms_test_mt(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='3g',
+ msg_type='mms',
+ long_msg=True)
@test_tracker_info(uuid="c6cfba55-6cde-41cd-93bb-667c317a0127")
@TelephonyBaseTest.tel_test_wrap
@@ -766,18 +532,16 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
-
- return _mms_test_mo(self.log, ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='3g',
+ mt_rat='general',
+ msg_type='mms',
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="83c5dd99-f2fe-433d-9775-80a36d0d493b")
@TelephonyBaseTest.tel_test_wrap
@@ -793,19 +557,16 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (self.log, ads[0])), (phone_setup_3g,
- (self.log, ads[1]))]
- if not multithread_func(self.log, tasks):
- self.log.error("Phone Failed to Set Up Properly.")
- return False
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
-
- return _mms_test_mt(self.log, ads)
-
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='3g',
+ msg_type='mms',
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="54a68d6a-dae7-4fe6-b2bb-7c73151a4a73")
@TelephonyBaseTest.tel_test_wrap
@@ -820,17 +581,12 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_volte, (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 _sms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='volte',
+ mt_rat='general')
@test_tracker_info(uuid="d0adcd69-37fc-49d1-8dd3-c03dd163fb25")
@TelephonyBaseTest.tel_test_wrap
@@ -845,17 +601,12 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_volte, (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 _sms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='volte')
@test_tracker_info(uuid="8d454a25-a1e5-4872-8193-d435a84d54fa")
@TelephonyBaseTest.tel_test_wrap
@@ -870,17 +621,13 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_volte, (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 _mms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='volte',
+ mt_rat='general',
+ msg_type='mms')
@test_tracker_info(uuid="79b8239e-9e6a-4781-942b-2df5b060718d")
@TelephonyBaseTest.tel_test_wrap
@@ -895,17 +642,13 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_volte, (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 _mms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='volte',
+ msg_type='mms')
@test_tracker_info(uuid="5b9e1195-1e42-4405-890f-631e8c58d0c2")
@TelephonyBaseTest.tel_test_wrap
@@ -920,17 +663,13 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_volte, (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 _long_sms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='volte',
+ mt_rat='general',
+ long_msg=True)
@test_tracker_info(uuid="c328cbe7-1899-4ca8-af1c-5eb05683a322")
@TelephonyBaseTest.tel_test_wrap
@@ -945,17 +684,13 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_volte, (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 _long_sms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='volte',
+ long_msg=True)
@test_tracker_info(uuid="a843c2f7-e4de-4b99-b3a9-f05ecda5fe73")
@TelephonyBaseTest.tel_test_wrap
@@ -970,17 +705,14 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_volte, (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 _long_mms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='volte',
+ mt_rat='general',
+ msg_type='mms',
+ long_msg=True)
@test_tracker_info(uuid="26dcba4d-7ddb-438d-84e7-0e754178b5ef")
@TelephonyBaseTest.tel_test_wrap
@@ -995,17 +727,14 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_volte, (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 _long_mms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='volte',
+ msg_type='mms',
+ long_msg=True)
@test_tracker_info(uuid="c97687e2-155a-4cf3-9f51-22543b89d53e")
@TelephonyBaseTest.tel_test_wrap
@@ -1020,16 +749,12 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
- tasks = [(phone_setup_csfb, (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 _sms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='csfb',
+ mt_rat='general')
@test_tracker_info(uuid="e2e01a47-2b51-4d00-a7b2-dbd3c8ffa6ae")
@TelephonyBaseTest.tel_test_wrap
@@ -1044,15 +769,12 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
- tasks = [(phone_setup_csfb, (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
-
- return _sms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='csfb')
@test_tracker_info(uuid="90fc6775-de19-49d1-8b8e-e3bc9384c733")
@TelephonyBaseTest.tel_test_wrap
@@ -1067,17 +789,13 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_csfb, (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 _mms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='csfb',
+ mt_rat='general',
+ msg_type='mms')
@test_tracker_info(uuid="274572bb-ec9f-4c30-aab4-1f4c3f16b372")
@TelephonyBaseTest.tel_test_wrap
@@ -1092,17 +810,13 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_csfb, (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 _mms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='csfb',
+ msg_type='mms')
@test_tracker_info(uuid="44392814-98dd-406a-ae82-5c39e2d082f3")
@TelephonyBaseTest.tel_test_wrap
@@ -1117,16 +831,13 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
- tasks = [(phone_setup_csfb, (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 _long_sms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='csfb',
+ mt_rat='general',
+ long_msg=True)
@test_tracker_info(uuid="0f8358a5-a7d5-4dfa-abe0-99fb8b10d48d")
@TelephonyBaseTest.tel_test_wrap
@@ -1141,15 +852,13 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
- tasks = [(phone_setup_csfb, (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
-
- return _long_sms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='csfb',
+ long_msg=True)
@test_tracker_info(uuid="18edde2b-7db9-40f4-96c4-3286a56d090b")
@TelephonyBaseTest.tel_test_wrap
@@ -1164,17 +873,14 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_csfb, (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 _long_mms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='csfb',
+ mt_rat='general',
+ msg_type='mms',
+ long_msg=True)
@test_tracker_info(uuid="49805d08-6f1f-4c90-9bf4-e9acd6f63640")
@TelephonyBaseTest.tel_test_wrap
@@ -1189,17 +895,14 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_csfb, (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 _long_mms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='csfb',
+ msg_type='mms',
+ long_msg=True)
@test_tracker_info(uuid="c7349fdf-a376-4846-b466-1f329bd1557f")
@TelephonyBaseTest.tel_test_wrap
@@ -1215,18 +918,15 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_csfb, (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)
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
- return _mms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='csfb',
+ mt_rat='general',
+ msg_type='mms',
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="1affab34-e03c-49dd-9062-e9ed8eac406b")
@TelephonyBaseTest.tel_test_wrap
@@ -1242,19 +942,15 @@
True if success.
False if failed.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_csfb, (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)
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
-
- return _mms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='csfb',
+ msg_type='mms',
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="7ee57edb-2962-4d20-b6eb-79cebce91fff")
@TelephonyBaseTest.tel_test_wrap
@@ -1268,27 +964,13 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- if not provision_both_devices_for_volte(self.log, ads):
- return False
-
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_volte,
- verify_callee_func=None):
- return False
-
- if not _sms_test_mo(self.log, ads):
- self.log.error("SMS test fail.")
- return False
-
- return True
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='volte',
+ mt_rat='general',
+ msg_in_call=True)
@test_tracker_info(uuid="5576276b-4ca1-41cc-bb74-31ccd71f9f96")
@TelephonyBaseTest.tel_test_wrap
@@ -1302,26 +984,13 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- if not provision_both_devices_for_volte(self.log, ads):
- return False
-
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_volte,
- verify_callee_func=None):
- return False
-
- if not _sms_test_mt(self.log, ads):
- self.log.error("SMS test fail.")
- return False
- return True
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='volte',
+ msg_in_call=True)
@test_tracker_info(uuid="3bf8ff74-baa6-4dc6-86eb-c13816fa9bc8")
@TelephonyBaseTest.tel_test_wrap
@@ -1335,27 +1004,14 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- if not provision_both_devices_for_volte(self.log, ads):
- return False
-
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_volte,
- verify_callee_func=None):
- return False
-
- if not _mms_test_mo(self.log, ads):
- self.log.error("MMS test fail.")
- return False
-
- return True
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='volte',
+ mt_rat='general',
+ msg_type='mms',
+ msg_in_call=True)
@test_tracker_info(uuid="289e6516-5f66-403a-b292-50d067151730")
@TelephonyBaseTest.tel_test_wrap
@@ -1369,27 +1025,14 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- if not provision_both_devices_for_volte(self.log, ads):
- return False
-
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- self.log.info("Begin In Call MMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_volte,
- verify_callee_func=None):
- return False
-
- if not _mms_test_mt(self.log, ads):
- self.log.error("MMS test fail.")
- return False
-
- return True
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='volte',
+ msg_type='mms',
+ msg_in_call=True)
@test_tracker_info(uuid="5654d974-3c32-4cce-9d07-0c96213dacc5")
@TelephonyBaseTest.tel_test_wrap
@@ -1404,29 +1047,16 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- if not provision_both_devices_for_volte(self.log, ads):
- 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.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_volte,
- verify_callee_func=None):
- return False
-
- if not _mms_test_mo(self.log, ads):
- self.log.error("MMS test fail.")
- return False
-
- return True
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='volte',
+ mt_rat='general',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="cbd5ab3d-d76a-4ece-ac09-62efeead7550")
@TelephonyBaseTest.tel_test_wrap
@@ -1441,29 +1071,16 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- if not provision_both_devices_for_volte(self.log, ads):
- 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.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_volte,
- verify_callee_func=None):
- return False
-
- if not _mms_test_mt(self.log, ads):
- self.log.error("MMS test fail.")
- return False
-
- return True
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='volte',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="b6e9ce80-8577-48e5-baa7-92780932f278")
@TelephonyBaseTest.tel_test_wrap
@@ -1477,16 +1094,13 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_csfb, (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._mo_sms_in_csfb_call(ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='csfb',
+ mt_rat='general',
+ msg_in_call=True)
@test_tracker_info(uuid="93f0b58a-01e9-4bc9-944f-729d455597dd")
@TelephonyBaseTest.tel_test_wrap
@@ -1500,16 +1114,13 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_csfb, (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._mt_sms_in_csfb_call(ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='csfb',
+ msg_in_call=True)
@test_tracker_info(uuid="bd8e9e80-1955-429f-b122-96b127771bbb")
@TelephonyBaseTest.tel_test_wrap
@@ -1523,16 +1134,14 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_csfb, (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._mo_mms_in_csfb_call(ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='csfb',
+ mt_rat='general',
+ msg_type='mms',
+ msg_in_call=True)
@test_tracker_info(uuid="89d65fd2-fc75-4fc5-a018-2d05a4364304")
@TelephonyBaseTest.tel_test_wrap
@@ -1546,16 +1155,14 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_csfb, (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._mt_mms_in_csfb_call(ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='csfb',
+ msg_type='mms',
+ msg_in_call=True)
@test_tracker_info(uuid="9c542b5d-3b8f-4d4a-80de-fb804f066c3d")
@TelephonyBaseTest.tel_test_wrap
@@ -1570,18 +1177,16 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_csfb, (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)
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
-
- return self._mo_mms_in_csfb_call(ads, wifi=True)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='csfb',
+ mt_rat='general',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="c1bed6f5-f65c-4f4d-aa06-0e9f5c867819")
@TelephonyBaseTest.tel_test_wrap
@@ -1596,18 +1201,16 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_csfb, (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)
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
-
- return self._mt_mms_in_csfb_call(ads, wifi=True)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='csfb',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="60996028-b4b2-4a16-9e4b-eb6ef80179a7")
@TelephonyBaseTest.tel_test_wrap
@@ -1621,16 +1224,14 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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._mo_sms_in_3g_call(ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='3g',
+ mt_rat='general',
+ msg_in_call=True)
@test_tracker_info(uuid="6b352aac-9b4e-4062-8980-3b1c0e61015b")
@TelephonyBaseTest.tel_test_wrap
@@ -1644,16 +1245,14 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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._mt_sms_in_3g_call(ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='3g',
+ msg_in_call=True)
@test_tracker_info(uuid="cfae3613-c490-4ce0-b00b-c13286d85027")
@TelephonyBaseTest.tel_test_wrap
@@ -1668,16 +1267,15 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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._mo_mms_in_3g_call(ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='3g',
+ mt_rat='general',
+ msg_type='mms',
+ msg_in_call=True)
@test_tracker_info(uuid="42fc8c16-4a30-4f63-9728-2639f2b79c4c")
@TelephonyBaseTest.tel_test_wrap
@@ -1691,16 +1289,15 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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._mt_mms_in_3g_call(ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='3g',
+ msg_type='mms',
+ msg_in_call=True)
@test_tracker_info(uuid="18093f87-aab5-4d86-b178-8085a1651828")
@TelephonyBaseTest.tel_test_wrap
@@ -1715,18 +1312,17 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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)
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
-
- return self._mo_mms_in_3g_call(ads, wifi=True)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='3g',
+ mt_rat='general',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="8fe3359a-0857-401f-a043-c47a2a2acb47")
@TelephonyBaseTest.tel_test_wrap
@@ -1740,25 +1336,24 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_3g, (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)
- 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)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='3g',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="ed720013-e366-448b-8901-bb09d26cea05")
@TelephonyBaseTest.tel_test_wrap
def test_sms_mo_iwlan(self):
""" Test MO SMS, Phone in APM, WiFi connected, WFC Cell Preferred mode.
- Make sure PhoneA APM, WiFi connected, WFC Cell preferred mode.
+ Make sure PhoneA APM, WiFi connected, WFC cellular preferred mode.
Make sure PhoneA report iwlan as data rat.
Make sure PhoneB is able to make/receive call/sms.
Send SMS on PhoneA.
@@ -1766,26 +1361,23 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], True, WFC_MODE_CELLULAR_PREFERRED,
- 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 _sms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='wfc',
+ mt_rat='general',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="4d4b0b7b-bf00-44f6-a0ed-23b438c30fc2")
@TelephonyBaseTest.tel_test_wrap
def test_sms_mt_iwlan(self):
""" Test MT SMS, Phone in APM, WiFi connected, WFC Cell Preferred mode.
- Make sure PhoneA APM, WiFi connected, WFC WiFi preferred mode.
+ Make sure PhoneA APM, WiFi connected, WFC cellular preferred mode.
Make sure PhoneA report iwlan as data rat.
Make sure PhoneB is able to make/receive call/sms.
Receive SMS on PhoneA.
@@ -1793,19 +1385,16 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], True, WFC_MODE_CELLULAR_PREFERRED,
- 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 _sms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='wfc',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="264e2557-e18c-41c0-8d99-49cee3fe6f07")
@TelephonyBaseTest.tel_test_wrap
@@ -1820,19 +1409,17 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], True, WFC_MODE_CELLULAR_PREFERRED,
- 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 _mms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='wfc',
+ mt_rat='general',
+ msg_type='mms',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="330db618-f074-4bfc-bf5e-78939fbee532")
@TelephonyBaseTest.tel_test_wrap
@@ -1847,19 +1434,17 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_iwlan,
- (self.log, ads[0], True, WFC_MODE_CELLULAR_PREFERRED,
- 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 _mms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='wfc',
+ msg_type='mms',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="875ce520-7a09-4032-8e88-965ce143c1f5")
@TelephonyBaseTest.tel_test_wrap
@@ -1874,19 +1459,18 @@
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_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 _long_sms_test_mo(self.log, ads)
+ _wfc_mode = self._get_wfc_mode(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='wfc',
+ mt_rat='general',
+ long_msg=True,
+ is_airplane_mode=True,
+ wfc_mode=_wfc_mode,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="a317a1b3-16c8-4c2d-bbfd-aebcc0897499")
@TelephonyBaseTest.tel_test_wrap
@@ -1901,19 +1485,18 @@
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_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 _long_sms_test_mt(self.log, ads)
+ _wfc_mode = self._get_wfc_mode(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='wfc',
+ long_msg=True,
+ is_airplane_mode=True,
+ wfc_mode=_wfc_mode,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="d692c439-6e96-45a6-be0f-1ff81226416c")
@TelephonyBaseTest.tel_test_wrap
@@ -1928,19 +1511,19 @@
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_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 _long_mms_test_mo(self.log, ads)
+ _wfc_mode = self._get_wfc_mode(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='wfc',
+ mt_rat='general',
+ msg_type='mms',
+ long_msg=True,
+ is_airplane_mode=True,
+ wfc_mode=_wfc_mode,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="a0958a1b-23ea-4353-9af6-7bc5d6a0a3d2")
@TelephonyBaseTest.tel_test_wrap
@@ -1955,19 +1538,19 @@
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_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 _long_mms_test_mt(self.log, ads)
+ _wfc_mode = self._get_wfc_mode(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='wfc',
+ msg_type='mms',
+ long_msg=True,
+ is_airplane_mode=True,
+ wfc_mode=_wfc_mode,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="94bb8297-f646-4793-9d97-6f82a706127a")
@TelephonyBaseTest.tel_test_wrap
@@ -1982,19 +1565,16 @@
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_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 _sms_test_mo(self.log, ads)
+ _wfc_mode = self._get_wfc_mode(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='wfc',
+ mt_rat='general',
+ wfc_mode=_wfc_mode,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="e4acce6a-75ae-45c1-be85-d3a2eb2da7c2")
@TelephonyBaseTest.tel_test_wrap
@@ -2009,19 +1589,16 @@
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_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 _sms_test_mt(self.log, ads)
+ _wfc_mode = self._get_wfc_mode(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='wfc',
+ wfc_mode=_wfc_mode,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="6c003c28-5712-4456-89cb-64d417ab2ce4")
@TelephonyBaseTest.tel_test_wrap
@@ -2036,19 +1613,17 @@
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_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 _mms_test_mo(self.log, ads)
+ _wfc_mode = self._get_wfc_mode(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='wfc',
+ mt_rat='general',
+ msg_type='mms',
+ wfc_mode=_wfc_mode,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="0ac5c8ff-83e5-49f2-ba71-ebb283feed9e")
@TelephonyBaseTest.tel_test_wrap
@@ -2063,18 +1638,17 @@
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_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 _mms_test_mt(self.log, ads)
+ _wfc_mode = self._get_wfc_mode(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='wfc',
+ msg_type='mms',
+ wfc_mode=_wfc_mode,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="075933a2-df7f-4374-a405-92f96bcc7770")
@TelephonyBaseTest.tel_test_wrap
@@ -2088,21 +1662,16 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
- if not set_wfc_mode(self.log, ads[0], WFC_MODE_DISABLED):
- return False
- phone_setup_voice_general(self.log, ads[0])
- tasks = [(ensure_wifi_connected,
- (self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass, 3, True)), (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 _sms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='wfc',
+ mt_rat='general',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_DISABLED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="637af228-29fc-4b74-a963-883f66ddf080")
@TelephonyBaseTest.tel_test_wrap
@@ -2116,21 +1685,16 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
- if not set_wfc_mode(self.log, ads[0], WFC_MODE_DISABLED):
- return False
- phone_setup_voice_general(self.log, ads[0])
- tasks = [(ensure_wifi_connected,
- (self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass, 3, True)), (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 _sms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='wfc',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_DISABLED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="502aba0d-8895-4807-b394-50a44208ecf7")
@TelephonyBaseTest.tel_test_wrap
@@ -2144,21 +1708,17 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
- if not set_wfc_mode(self.log, ads[0], WFC_MODE_DISABLED):
- return False
- phone_setup_voice_general(self.log, ads[0])
- tasks = [(ensure_wifi_connected,
- (self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass, 3, True)), (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 _mms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='wfc',
+ mt_rat='general',
+ msg_type='mms',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_DISABLED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="235bfdbf-4275-4d89-99f5-41b5b7de8345")
@TelephonyBaseTest.tel_test_wrap
@@ -2172,20 +1732,17 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
- if not set_wfc_mode(self.log, ads[0], WFC_MODE_DISABLED):
- return False
- phone_setup_voice_general(self.log, ads[0])
- tasks = [(ensure_wifi_connected,
- (self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass, 3, True)), (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 _mms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='wfc',
+ msg_type='mms',
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_DISABLED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="e5a31b94-1cb6-4770-a2bc-5a0ddba51502")
@TelephonyBaseTest.tel_test_wrap
@@ -2201,29 +1758,18 @@
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_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)
-
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_iwlan,
- verify_callee_func=None):
- return False
-
- return _sms_test_mo(self.log, ads)
+ _wfc_mode = self._get_wfc_mode(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='wfc',
+ mt_rat='general',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=_wfc_mode,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="d6d30cc5-f75b-42df-b517-401456ee8466")
@TelephonyBaseTest.tel_test_wrap
@@ -2239,29 +1785,18 @@
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_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)
-
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_iwlan,
- verify_callee_func=None):
- return False
-
- return _sms_test_mt(self.log, ads)
+ _wfc_mode = self._get_wfc_mode(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='wfc',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=_wfc_mode,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="a98a5a97-3864-4ff8-9085-995212eada20")
@TelephonyBaseTest.tel_test_wrap
@@ -2277,29 +1812,19 @@
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_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)
-
- self.log.info("Begin In Call MMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_iwlan,
- verify_callee_func=None):
- return False
-
- return _mms_test_mo(self.log, ads)
+ _wfc_mode = self._get_wfc_mode(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='wfc',
+ mt_rat='general',
+ msg_type='mms',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=_wfc_mode,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="0464a87b-d45b-4b03-9895-17ece360a796")
@TelephonyBaseTest.tel_test_wrap
@@ -2315,29 +1840,19 @@
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_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)
-
- self.log.info("Begin In Call MMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_iwlan,
- verify_callee_func=None):
- return False
-
- return _mms_test_mt(self.log, ads)
+ _wfc_mode = self._get_wfc_mode(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='wfc',
+ msg_type='mms',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=_wfc_mode,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="029e05cd-df6b-4a82-8402-77fc6eadf66f")
@TelephonyBaseTest.tel_test_wrap
@@ -2353,29 +1868,17 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_iwlan_cellular_preferred,
- (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)
-
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_not_iwlan,
- verify_callee_func=None):
- return False
-
- return _sms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='wfc',
+ mt_rat='general',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="c3c47a68-a839-4470-87f6-e85496cfab23")
@TelephonyBaseTest.tel_test_wrap
@@ -2391,29 +1894,17 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_iwlan_cellular_preferred,
- (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)
-
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_not_iwlan,
- verify_callee_func=None):
- return False
-
- return _sms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='wfc',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="4c6cd913-4aca-4f2b-b33b-1efe0a7dc11d")
@TelephonyBaseTest.tel_test_wrap
@@ -2429,29 +1920,18 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_iwlan_cellular_preferred,
- (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)
-
- self.log.info("Begin In Call MMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_not_iwlan,
- verify_callee_func=None):
- return False
-
- return _mms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='wfc',
+ mt_rat='general',
+ msg_type='mms',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="5b667ca1-cafd-47d4-86dc-8b87232ddcfa")
@TelephonyBaseTest.tel_test_wrap
@@ -2467,29 +1947,18 @@
Returns:
True if pass; False if fail.
"""
-
- ads = self.android_devices
-
- tasks = [(phone_setup_iwlan_cellular_preferred,
- (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)
-
- self.log.info("Begin In Call MMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_not_iwlan,
- verify_callee_func=None):
- return False
-
- return _mms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='wfc',
+ msg_type='mms',
+ msg_in_call=True,
+ is_airplane_mode=True,
+ wfc_mode=WFC_MODE_CELLULAR_PREFERRED,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="9f1933bb-c4cb-4655-8655-327c1f38e8ee")
@TelephonyBaseTest.tel_test_wrap
@@ -2503,27 +1972,14 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
- (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)
-
- if not video_call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- None,
- video_state=VT_STATE_BIDIRECTIONAL,
- verify_caller_func=is_phone_in_call_video_bidirectional,
- verify_callee_func=is_phone_in_call_video_bidirectional):
- self.log.error("Failed to setup a call")
- return False
-
- return _sms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='volte',
+ mt_rat='volte',
+ msg_in_call=True,
+ video_or_voice='video')
@test_tracker_info(uuid="0a07e737-4862-4492-9b48-8d94799eab91")
@TelephonyBaseTest.tel_test_wrap
@@ -2537,27 +1993,14 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
- (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)
-
- if not video_call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- None,
- video_state=VT_STATE_BIDIRECTIONAL,
- verify_caller_func=is_phone_in_call_video_bidirectional,
- verify_callee_func=is_phone_in_call_video_bidirectional):
- self.log.error("Failed to setup a call")
- return False
-
- return _sms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='volte',
+ mt_rat='volte',
+ msg_in_call=True,
+ video_or_voice='video')
@test_tracker_info(uuid="55d70548-6aee-40e9-b94d-d10de84fb50f")
@TelephonyBaseTest.tel_test_wrap
@@ -2571,27 +2014,15 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
- (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)
-
- if not video_call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- None,
- video_state=VT_STATE_BIDIRECTIONAL,
- verify_caller_func=is_phone_in_call_video_bidirectional,
- verify_callee_func=is_phone_in_call_video_bidirectional):
- self.log.error("Failed to setup a call")
- return False
-
- return _mms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='volte',
+ mt_rat='volte',
+ msg_type='mms',
+ msg_in_call=True,
+ video_or_voice='video')
@test_tracker_info(uuid="75f97c9a-4397-42f1-bb00-8fc6d04fdf6d")
@TelephonyBaseTest.tel_test_wrap
@@ -2605,27 +2036,15 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
-
- tasks = [(phone_setup_video, (self.log, ads[0])), (phone_setup_video,
- (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)
-
- if not video_call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- None,
- video_state=VT_STATE_BIDIRECTIONAL,
- verify_caller_func=is_phone_in_call_video_bidirectional,
- verify_callee_func=is_phone_in_call_video_bidirectional):
- self.log.error("Failed to setup a call")
- return False
-
- return _mms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='volte',
+ mt_rat='volte',
+ msg_type='mms',
+ msg_in_call=True,
+ video_or_voice='video')
@test_tracker_info(uuid="2a72ecc6-702d-4add-a7a2-8c1001628bb6")
@TelephonyBaseTest.tel_test_wrap
@@ -2639,33 +2058,14 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
- # Make sure PhoneA is GSM phone before proceed.
- if (ads[0].droid.telephonyGetPhoneType() != PHONE_TYPE_GSM):
- raise signals.TestSkip("Not GSM phone, abort this GSM SMS test.")
-
- tasks = [(phone_setup_voice_2g, (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)
-
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_2g,
- verify_callee_func=None):
- return False
-
- if not _sms_test_mo(self.log, ads):
- self.log.error("SMS test fail.")
- return False
-
- return True
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='2g',
+ mt_rat='general',
+ msg_in_call=True)
@test_tracker_info(uuid="facd1814-8d69-42a2-9f80-b6a28cc0c9d2")
@TelephonyBaseTest.tel_test_wrap
@@ -2679,33 +2079,14 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
- # Make sure PhoneA is GSM phone before proceed.
- if (ads[0].droid.telephonyGetPhoneType() != PHONE_TYPE_GSM):
- raise signals.TestSkip("Not GSM phone, abort this GSM SMS test.")
-
- tasks = [(phone_setup_voice_2g, (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)
-
- self.log.info("Begin In Call SMS Test.")
- if not call_setup_teardown(
- self.log,
- ads[0],
- ads[1],
- ad_hangup=None,
- verify_caller_func=is_phone_in_call_2g,
- verify_callee_func=None):
- return False
-
- if not _sms_test_mt(self.log, ads):
- self.log.error("SMS test fail.")
- return False
-
- return True
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='2g',
+ msg_in_call=True)
@test_tracker_info(uuid="2bd94d69-3621-4b94-abc7-bd24c4325485")
@TelephonyBaseTest.tel_test_wrap
@@ -2719,19 +2100,15 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
- # Make sure PhoneA is GSM phone before proceed.
- if (ads[0].droid.telephonyGetPhoneType() != PHONE_TYPE_GSM):
- raise signals.TestSkip("Not GSM phone, abort this GSM SMS test.")
-
- tasks = [(phone_setup_voice_2g, (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._mo_mms_in_2g_call(ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='2g',
+ mt_rat='general',
+ msg_type='mms',
+ msg_in_call=True)
@test_tracker_info(uuid="e20be70d-99d6-4344-a742-f69581b66d8f")
@TelephonyBaseTest.tel_test_wrap
@@ -2745,19 +2122,15 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
- # Make sure PhoneA is GSM phone before proceed.
- if (ads[0].droid.telephonyGetPhoneType() != PHONE_TYPE_GSM):
- raise signals.TestSkip("Not GSM phone, abort this GSM MMS test.")
-
- tasks = [(phone_setup_voice_2g, (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._mt_mms_in_2g_call(ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='2g',
+ msg_type='mms',
+ msg_in_call=True)
@test_tracker_info(uuid="3510d368-4b16-4716-92a3-9dd01842ba79")
@TelephonyBaseTest.tel_test_wrap
@@ -2771,21 +2144,17 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
- # Make sure PhoneA is GSM phone before proceed.
- if (ads[0].droid.telephonyGetPhoneType() != PHONE_TYPE_GSM):
- raise signals.TestSkip("Not GSM phone, abort this GSM MMS test.")
-
- tasks = [(phone_setup_voice_2g, (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)
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
-
- return self._mo_mms_in_2g_call(ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[0],
+ self.android_devices[1],
+ mo_rat='2g',
+ mt_rat='general',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="060def89-01bd-4b44-a49b-a4536fe39165")
@TelephonyBaseTest.tel_test_wrap
@@ -2799,21 +2168,17 @@
Returns:
True if pass; False if fail.
"""
- ads = self.android_devices
- # Make sure PhoneA is GSM phone before proceed.
- if (ads[0].droid.telephonyGetPhoneType() != PHONE_TYPE_GSM):
- raise signals.TestSkip("Not GSM phone, abort this GSM MMS test.")
-
- tasks = [(phone_setup_voice_2g, (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)
- ensure_wifi_connected(self.log, ads[0], self.wifi_network_ssid,
- self.wifi_network_pass)
-
- return self._mt_mms_in_2g_call(ads)
+ self.check_band_support(self.android_devices[0])
+ return message_test(
+ self.log,
+ self.android_devices[1],
+ self.android_devices[0],
+ mo_rat='general',
+ mt_rat='2g',
+ msg_type='mms',
+ msg_in_call=True,
+ wifi_ssid=self.wifi_network_ssid,
+ wifi_pwd=self.wifi_network_pass)
@test_tracker_info(uuid="7de95a56-8055-4c0c-9438-f249403c6078")
@TelephonyBaseTest.tel_test_wrap
@@ -2835,13 +2200,10 @@
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 _sms_test_mo(self.log, ads)
+ return message_test(
+ self.log,
+ ads[0],
+ ads[1])
finally:
remove_mobile_data_usage_limit(ads[0], subscriber_id)
@@ -2865,13 +2227,10 @@
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 _sms_test_mt(self.log, ads)
+ return message_test(
+ self.log,
+ ads[1],
+ ads[0])
finally:
remove_mobile_data_usage_limit(ads[0], subscriber_id)
@@ -2896,17 +2255,19 @@
ads[0].log.info("Expected Result is %s", expected_result)
try:
- 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
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)
log_msg = "expecting successful mms receive" if (
expected_result) else "expecting mms receive failure"
- if not _mms_test_mo(self.log, ads, expected_result=expected_result):
+
+ if not message_test(
+ self.log,
+ ads[0],
+ ads[1],
+ msg_type='mms',
+ mms_expected_result=expected_result):
+
ads[0].log.error("Mms test failed, %s", log_msg)
return False
else:
@@ -2933,18 +2294,22 @@
expected_result = False
if get_operator_name(self.log, ads[0]) in ["vzw", "Verizon", "att", "AT&T"]:
expected_result = True
+ ads[0].log.info("Expected Result is %s", expected_result)
+
try:
- 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
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)
log_msg = "expecting successful mms receive" if (
expected_result) else "expecting mms receive failure"
- if not _mms_test_mt(self.log, ads, expected_result=expected_result):
+
+ if not message_test(
+ self.log,
+ ads[1],
+ ads[0],
+ msg_type='mms',
+ mms_expected_result=expected_result):
+
ads[0].log.error("Mms test failed, %s", log_msg)
return False
else:
@@ -3004,4 +2369,3 @@
time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
return self._sms_in_collision_when_power_off_test(ads)
-
diff --git a/acts_tests/tests/google/tel/live/TelLiveStressCallTest.py b/acts_tests/tests/google/tel/live/TelLiveStressCallTest.py
index dc7a62e..573ca60 100644
--- a/acts_tests/tests/google/tel/live/TelLiveStressCallTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveStressCallTest.py
@@ -22,38 +22,35 @@
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import last_call_drop_reason
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode
-from acts_contrib.test_utils.tel.tel_test_utils import sms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_logging_utils import start_sdm_loggers
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_video_utils import phone_setup_video
+from acts_contrib.test_utils.tel.tel_video_utils import video_call_setup
+from acts_contrib.test_utils.tel.tel_video_utils import is_phone_in_call_video_bidirectional
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_iwlan
-from acts_contrib.test_utils.tel.tel_video_utils import phone_setup_video
-from acts_contrib.test_utils.tel.tel_video_utils import video_call_setup
-from acts_contrib.test_utils.tel.tel_video_utils import \
- is_phone_in_call_video_bidirectional
-from acts.logger import epoch_to_log_line_timestamp
+from acts_contrib.test_utils.tel.tel_voice_utils import last_call_drop_reason
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
from acts.utils import get_current_epoch_time
from acts.utils import rand_ascii_str
+from acts.libs.utils.multithread import multithread_func
class TelLiveStressCallTest(TelephonyBaseTest):
@@ -237,7 +234,10 @@
if not iteration_result:
self._take_bug_report("%s_CallNo_%s" % (self.test_name, i),
begin_time)
- start_qxdm_loggers(self.log, self.android_devices)
+ if self.sdm_log:
+ start_sdm_loggers(self.log, self.android_devices)
+ else:
+ start_qxdm_loggers(self.log, self.android_devices)
if self.sleep_time_between_test_iterations:
self.caller.droid.goToSleepNow()
diff --git a/acts_tests/tests/google/tel/live/TelLiveStressDataTest.py b/acts_tests/tests/google/tel/live/TelLiveStressDataTest.py
index 81e3ece..3eb9d91 100644
--- a/acts_tests/tests/google/tel/live/TelLiveStressDataTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveStressDataTest.py
@@ -16,10 +16,15 @@
"""
Test Script for Telephony Stress data Test
"""
+import collections
+import time
+
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_test_utils import iperf_test_by_adb
from acts_contrib.test_utils.tel.tel_test_utils import iperf_udp_test_by_adb
+from acts.logger import epoch_to_log_line_timestamp
+from acts.utils import get_current_epoch_time
class TelLiveStressDataTest(TelephonyBaseTest):
@@ -28,13 +33,126 @@
self.ad = self.android_devices[0]
self.iperf_server_address = self.user_params.get("iperf_server",
'0.0.0.0')
- self.iperf_srv_tcp_port = self.user_params.get("iperf_server_tcp_port",
- 0)
- self.iperf_srv_udp_port = self.user_params.get("iperf_server_udp_port",
- 0)
- self.test_duration = self.user_params.get("data_stress_duration", 60)
+ self.iperf_tcp_port = int(
+ self.user_params.get("iperf_tcp_port", 0))
+ self.iperf_udp_port = int(
+ self.user_params.get("iperf_udp_port", 0))
+ self.iperf_duration = int(
+ self.user_params.get("iperf_duration", 60))
+ self.iperf_iteration = int(
+ self.user_params.get("iperf_iteration", 10))
+ self.sleep_time_between_iperf_iterations = int(
+ self.user_params.get("sleep_time_between_iperf_iterations", 2))
- return True
+ def stress_test_upload(self, test_tcp=True):
+ """Start the upload iperf stress test.
+
+ Args:
+ test_tcp: True for using TCP, using UDP otherwise.
+
+ Returns:
+ True if success, False if fail.
+ """
+ fail_count = collections.defaultdict(int)
+ for i in range(1, self.iperf_iteration + 1):
+ msg = "Stress Throughput Test %s Iteration: <%s> / <%s>" % (
+ self.test_name, i, self.iperf_iteration)
+ begin_time = get_current_epoch_time()
+ self.log.info(msg)
+ iteration_result = True
+ if test_tcp:
+ if not iperf_test_by_adb(self.log,
+ self.ad,
+ self.iperf_server_address,
+ self.iperf_tcp_port,
+ False,
+ self.iperf_duration):
+ fail_count["upload"] += 1
+ iteration_result = False
+ self.log.error("%s upload failure.", msg)
+ else:
+ if not iperf_udp_test_by_adb(self.log,
+ self.ad,
+ self.iperf_server_address,
+ self.iperf_udp_port,
+ False,
+ self.iperf_duration):
+ fail_count["upload"] += 1
+ iteration_result = False
+ self.log.error("%s upload failure.", msg)
+
+ self.log.info("%s %s", msg, iteration_result)
+ if not iteration_result:
+ self._take_bug_report("%s_UploadNo_%s" % (self.test_name, i),
+ begin_time)
+
+ if self.sleep_time_between_iperf_iterations:
+ self.ad.droid.goToSleepNow()
+ time.sleep(self.sleep_time_between_iperf_iterations)
+
+ test_result = True
+ for failure, count in fail_count.items():
+ if count:
+ self.log.error("%s: %s %s failures in %s iterations",
+ self.test_name, count, failure,
+ self.iperf_iteration)
+ test_result = False
+ return test_result
+
+ def stress_test_download(self, test_tcp=True):
+ """Start the download iperf stress test.
+
+ Args:
+ test_tcp: True for using TCP, using UDP otherwise.
+
+ Returns:
+ True if success, False if fail.
+ """
+ fail_count = collections.defaultdict(int)
+ for i in range(1, self.iperf_iteration + 1):
+ msg = "Stress Throughput Test %s Iteration: <%s> / <%s>" % (
+ self.test_name, i, self.iperf_iteration)
+ begin_time = get_current_epoch_time()
+ self.log.info(msg)
+ iteration_result = True
+ if test_tcp:
+ if not iperf_test_by_adb(self.log,
+ self.ad,
+ self.iperf_server_address,
+ self.iperf_tcp_port,
+ True,
+ self.iperf_duration):
+ fail_count["download"] += 1
+ iteration_result = False
+ self.log.error("%s download failure.", msg)
+ else:
+ if not iperf_udp_test_by_adb(self.log,
+ self.ad,
+ self.iperf_server_address,
+ self.iperf_udp_port,
+ True,
+ self.iperf_duration):
+ fail_count["download"] += 1
+ iteration_result = False
+ self.log.error("%s download failure.", msg)
+
+ self.log.info("%s %s", msg, iteration_result)
+ if not iteration_result:
+ self._take_bug_report("%s_DownloadNo_%s" % (self.test_name, i),
+ begin_time)
+
+ if self.sleep_time_between_iperf_iterations:
+ self.ad.droid.goToSleepNow()
+ time.sleep(self.sleep_time_between_iperf_iterations)
+
+ test_result = True
+ for failure, count in fail_count.items():
+ if count:
+ self.log.error("%s: %s %s failures in %s iterations",
+ self.test_name, count, failure,
+ self.iperf_iteration)
+ test_result = False
+ return test_result
@test_tracker_info(uuid="190fdeb1-541e-455f-9f37-762a8e55c07f")
@TelephonyBaseTest.tel_test_wrap
@@ -42,9 +160,9 @@
return iperf_test_by_adb(self.log,
self.ad,
self.iperf_server_address,
- self.iperf_srv_tcp_port,
+ self.iperf_tcp_port,
False,
- self.test_duration)
+ self.iperf_duration)
@test_tracker_info(uuid="af9805f8-6ed5-4e05-823e-d88dcef45637")
@TelephonyBaseTest.tel_test_wrap
@@ -52,9 +170,9 @@
return iperf_test_by_adb(self.log,
self.ad,
self.iperf_server_address,
- self.iperf_srv_tcp_port,
+ self.iperf_tcp_port,
True,
- self.test_duration)
+ self.iperf_duration)
@test_tracker_info(uuid="55bf5e09-dc7b-40bc-843f-31fed076ffe4")
@TelephonyBaseTest.tel_test_wrap
@@ -62,9 +180,9 @@
return iperf_udp_test_by_adb(self.log,
self.ad,
self.iperf_server_address,
- self.iperf_srv_udp_port,
+ self.iperf_udp_port,
False,
- self.test_duration)
+ self.iperf_duration)
@test_tracker_info(uuid="02ae88b2-d597-45df-ab5a-d701d1125a0f")
@TelephonyBaseTest.tel_test_wrap
@@ -72,6 +190,26 @@
return iperf_udp_test_by_adb(self.log,
self.ad,
self.iperf_server_address,
- self.iperf_srv_udp_port,
+ self.iperf_udp_port,
True,
- self.test_duration)
+ self.iperf_duration)
+
+ @test_tracker_info(uuid="79aaa7ec-5046-4ffe-b27a-ca93e404e9e0")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tcp_upload_data_stress(self):
+ return self.stress_test_upload()
+
+ @test_tracker_info(uuid="6a1e5032-9498-4d23-8ae9-db36f1a238c1")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_tcp_download_data_stress(self):
+ return self.stress_test_download()
+
+ @test_tracker_info(uuid="22400c16-dbbb-41c9-afd0-86b525a0bcee")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_udp_upload_data_stress(self):
+ return self.stress_test_upload(test_tcp=False)
+
+ @test_tracker_info(uuid="9f3b2818-5265-422e-9e6f-9ee08dfcc696")
+ @TelephonyBaseTest.tel_test_wrap
+ def test_udp_download_data_stress(self):
+ return self.stress_test_download(test_tcp=False)
\ No newline at end of file
diff --git a/acts_tests/tests/google/tel/live/TelLiveStressFdrTest.py b/acts_tests/tests/google/tel/live/TelLiveStressFdrTest.py
index 46bef20..91e1332 100644
--- a/acts_tests/tests/google/tel/live/TelLiveStressFdrTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveStressFdrTest.py
@@ -25,31 +25,29 @@
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_data_utils import wifi_tethering_setup_teardown
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE
-from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_OMADM
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts_contrib.test_utils.tel.tel_defines import GEN_4G
from acts_contrib.test_utils.tel.tel_defines import TETHERING_MODE_WIFI
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_AFTER_FDR
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import get_model_name
+from acts_contrib.test_utils.tel.tel_bootloader_utils import fastboot_wipe
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_generation
from acts_contrib.test_utils.tel.tel_test_utils import get_outgoing_voice_sub_id
from acts_contrib.test_utils.tel.tel_test_utils import is_droid_in_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import mms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import fastboot_wipe
-from acts_contrib.test_utils.tel.tel_test_utils import sms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_generation
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
from acts.utils import get_current_epoch_time
from acts.utils import rand_ascii_str
@@ -59,6 +57,7 @@
def setup_class(self):
TelephonyBaseTest.setup_class(self)
+ self.user_params["telephony_auto_rerun"] = 0
self.stress_test_number = int(
self.user_params.get("stress_test_number", 100))
self.skip_reset_between_cases = False
diff --git a/acts_tests/tests/google/tel/live/TelLiveStressSmsTest.py b/acts_tests/tests/google/tel/live/TelLiveStressSmsTest.py
index 5813657..249446a 100644
--- a/acts_tests/tests/google/tel/live/TelLiveStressSmsTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveStressSmsTest.py
@@ -16,23 +16,18 @@
import random
import time
-from acts import signals
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
-from acts_contrib.test_utils.tel.tel_subscription_utils \
- import set_message_subid
-from acts_contrib.test_utils.tel.tel_subscription_utils \
- import get_subid_on_same_network_of_host_ad
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import sms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_voice_utils \
- import phone_setup_volte_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils \
- import phone_setup_csfb_for_subscription
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_on_rat
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb_for_subscription
+from acts_contrib.test_utils.tel.tel_subscription_utils import set_message_subid
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
+from acts_contrib.test_utils.tel.tel_test_utils import install_message_apk
from acts.utils import rand_ascii_str
+from acts.libs.utils.multithread import multithread_func
class TelLiveStressSmsTest(TelephonyBaseTest):
def setup_class(self):
@@ -46,6 +41,15 @@
self.long_sms_ims_cycle = \
self.user_params.get("long_sms_ims_cycle", 1)
+ self.message_util = self.user_params.get("message_apk", None)
+ if isinstance(self.message_util, list):
+ self.message_util = self.message_util[0]
+
+ if self.message_util:
+ ads = self.android_devices
+ for ad in ads:
+ install_message_apk(ad, self.message_util)
+
def teardown_test(self):
ensure_phones_idle(self.log, self.android_devices)
diff --git a/acts_tests/tests/google/tel/live/TelLiveStressTest.py b/acts_tests/tests/google/tel/live/TelLiveStressTest.py
index 9351210..e04ba6a 100644
--- a/acts_tests/tests/google/tel/live/TelLiveStressTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveStressTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2017 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -28,9 +28,8 @@
from acts.libs.proc import job
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
+from acts_contrib.test_utils.tel.loggers.telephony_stress_metric_logger import TelephonyStressMetricLogger
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE
-from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
from acts_contrib.test_utils.tel.tel_defines import GEN_3G
from acts_contrib.test_utils.tel.tel_defines import GEN_4G
from acts_contrib.test_utils.tel.tel_defines import GOOGLE_CBRS_CARRIER_ID
@@ -47,53 +46,25 @@
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_MESSAGE_SUB_ID
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_VOICE_SUB_ID
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_CBRS_DATA_SWITCH
-from acts_contrib.test_utils.tel.tel_defines import CARRIER_SING
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
+from acts_contrib.test_utils.tel.tel_logging_utils import extract_test_log
+from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
+from acts_contrib.test_utils.tel.tel_logging_utils import start_sdm_loggers
+from acts_contrib.test_utils.tel.tel_logging_utils import start_adb_tcpdump
from acts_contrib.test_utils.tel.tel_lookup_tables import is_rat_svd_capable
-from acts_contrib.test_utils.tel.tel_test_utils import STORY_LINE
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import extract_test_log
-from acts_contrib.test_utils.tel.tel_test_utils import force_connectivity_metrics_upload
-from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
-from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import last_call_drop_reason
-from acts_contrib.test_utils.tel.tel_test_utils import run_multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode
-from acts_contrib.test_utils.tel.tel_test_utils import sms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import start_qxdm_loggers
-from acts_contrib.test_utils.tel.tel_test_utils import start_sdm_loggers
-from acts_contrib.test_utils.tel.tel_test_utils import start_adb_tcpdump
-from acts_contrib.test_utils.tel.tel_test_utils import synchronize_device_time
-from acts_contrib.test_utils.tel.tel_test_utils import mms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
-from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection_by_ping
-from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_call_id_clearing
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_in_call_active
-from acts_contrib.test_utils.tel.tel_test_utils import is_current_data_on_cbrs
-from acts_contrib.test_utils.tel.tel_test_utils import check_voice_network_type
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import get_current_voice_rat
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_volte
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
from acts_contrib.test_utils.tel.tel_subscription_utils import get_operatorname_from_slot_index
from acts_contrib.test_utils.tel.tel_subscription_utils import get_carrierid_from_slot_index
@@ -102,13 +73,53 @@
from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_message
from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_outgoing_call
from acts_contrib.test_utils.tel.tel_subscription_utils import set_always_allow_mms_data
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_test_utils import STORY_LINE
+from acts_contrib.test_utils.tel.tel_test_utils import force_connectivity_metrics_upload
+from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
+from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
+from acts_contrib.test_utils.tel.tel_test_utils import synchronize_device_time
+from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection_by_ping
+from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_data_connection
+from acts_contrib.test_utils.tel.tel_test_utils import is_current_data_on_cbrs
+from acts_contrib.test_utils.tel.tel_test_utils import check_voice_network_type
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call_by_adb
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
+from acts_contrib.test_utils.tel.tel_voice_utils import last_call_drop_reason
+from acts_contrib.test_utils.tel.tel_voice_utils import get_current_voice_rat
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_call_id_clearing
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_in_call_active
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
from acts.utils import get_current_epoch_time
from acts.utils import rand_ascii_str
+from acts.libs.utils.multithread import run_multithread_func
EXCEPTION_TOLERANCE = 5
BINDER_LOGS = ["/sys/kernel/debug/binder"]
DEFAULT_FILE_DOWNLOADS = ["1MB", "5MB", "10MB", "20MB", "50MB"]
+RESULTS_LIST = {-2: "UNAVAILABLE_NETWORK_TYPE",
+ -1: "CALL_SETUP_FAILURE",
+ 0: "SUCCESS",
+ 1: "INITIATE_FAILED",
+ 2: "NO_RING_EVENT_OR_ANSWER_FAILED",
+ 3: "NO_CALL_ID_FOUND",
+ 4: "CALL_STATE_NOT_ACTIVE_DURING_ESTABLISHMENT",
+ 5: "AUDIO_STATE_NOT_INCALL_DURING_ESTABLISHMENT",
+ 6: "AUDIO_STATE_NOT_INCALL_AFTER_CONNECTED",
+ 7: "CALL_DROP_OR_WRONG_STATE_DURING_ESTABLISHMENT",
+ 8: "CALL_DROP_OR_WRONG_STATE_AFTER_CONNECTED",
+ 9: "CALL_HANGUP_FAIL",
+ 10: "CALL_ID_CLEANUP_FAIL"}
class TelLiveStressTest(TelephonyBaseTest):
@@ -182,6 +193,7 @@
"CALL_ID_CLEANUP_FAIL": 0 }
self.call_stats_check = self.user_params.get("call_stats_check", False)
self.nsa_5g_for_stress = self.user_params.get("nsa_5g_for_stress", False)
+ self.nr_type = self.user_params.get("nr_type", 'nsa')
return True
def setup_test(self):
@@ -466,8 +478,7 @@
incall_ui_display=INCALL_UI_DISPLAY_BACKGROUND,
call_stats_check=self.call_stats_check,
voice_type_init=voice_type_init,
- result_info = self.result_info,
- nsa_5g_for_stress=self.nsa_5g_for_stress
+ result_info = self.result_info
) and wait_for_in_call_active(self.dut, 60, 3)
else:
call_setup_result = call_setup_teardown(
@@ -482,8 +493,7 @@
slot_id_callee=slot_id_callee,
call_stats_check=self.call_stats_check,
voice_type_init=voice_type_init,
- result_info = self.result_info,
- nsa_5g_for_stress=self.nsa_5g_for_stress)
+ result_info = self.result_info)
self.result_collection[RESULTS_LIST[call_setup_result.result_value]] += 1
if not call_setup_result:
@@ -550,6 +560,11 @@
if not hangup_call(self.log, ads[0]):
failure_reasons.add("Teardown")
result = False
+ else:
+ if self.nsa_5g_for_stress:
+ for ad in (ads[0], ads[1]):
+ if not is_current_network_5g(ad, self.nr_type):
+ ad.log.error("Phone not attached on 5G")
for ad in ads:
if not wait_for_call_id_clearing(ad,
[]) or ad.droid.telecomIsInCall():
@@ -791,6 +806,7 @@
self.log.error("Too many exception errors, quit test")
return False
self.log.info("%s", dict(self.result_info))
+ self.tel_logger.set_result(self.result_collection)
if any([
self.result_info["Call Setup Failure"],
self.result_info["Call Maintenance Failure"],
diff --git a/acts_tests/tests/google/tel/live/TelLiveVideoDataTest.py b/acts_tests/tests/google/tel/live/TelLiveVideoDataTest.py
index 8f86f9f..fb0ef06 100644
--- a/acts_tests/tests/google/tel/live/TelLiveVideoDataTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveVideoDataTest.py
@@ -16,15 +16,14 @@
"""
Test Script for VT Data test
"""
+from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_video_utils import \
- is_phone_in_call_video_bidirectional
+from acts_contrib.test_utils.tel.tel_video_utils import is_phone_in_call_video_bidirectional
from acts_contrib.test_utils.tel.tel_video_utils import phone_setup_video
from acts_contrib.test_utils.tel.tel_video_utils import video_call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
class TelLiveVideoDataTest(TelephonyBaseTest):
diff --git a/acts_tests/tests/google/tel/live/TelLiveVideoTest.py b/acts_tests/tests/google/tel/live/TelLiveVideoTest.py
index de2e85a..2f80ef8 100644
--- a/acts_tests/tests/google/tel/live/TelLiveVideoTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveVideoTest.py
@@ -21,14 +21,13 @@
from queue import Empty
from acts import signals
from acts.test_decorators import test_tracker_info
+from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import AUDIO_ROUTE_EARPIECE
from acts_contrib.test_utils.tel.tel_defines import AUDIO_ROUTE_SPEAKER
from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_ACTIVE
from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_HOLDING
from acts_contrib.test_utils.tel.tel_defines import CALL_CAPABILITY_MANAGE_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import CALL_CAPABILITY_MERGE_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import CALL_CAPABILITY_SWAP_CONFERENCE
from acts_contrib.test_utils.tel.tel_defines import CALL_PROPERTY_CONFERENCE
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VT
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VIDEO_SESSION_EVENT
@@ -45,34 +44,28 @@
from acts_contrib.test_utils.tel.tel_defines import EventTelecomVideoCallSessionEvent
from acts_contrib.test_utils.tel.tel_defines import SESSION_EVENT_RX_PAUSE
from acts_contrib.test_utils.tel.tel_defines import SESSION_EVENT_RX_RESUME
-from acts_contrib.test_utils.tel.tel_lookup_tables import operator_capabilities
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_video_enabled
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import disconnect_call_by_id
-from acts_contrib.test_utils.tel.tel_test_utils import get_model_name
-from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_video_enabled
from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
from acts_contrib.test_utils.tel.tel_video_utils import get_call_id_in_video_state
-from acts_contrib.test_utils.tel.tel_video_utils import \
- is_phone_in_call_video_bidirectional
+from acts_contrib.test_utils.tel.tel_video_utils import is_phone_in_call_video_bidirectional
from acts_contrib.test_utils.tel.tel_video_utils import is_phone_in_call_voice_hd
from acts_contrib.test_utils.tel.tel_video_utils import phone_setup_video
-from acts_contrib.test_utils.tel.tel_video_utils import \
- verify_video_call_in_expected_state
+from acts_contrib.test_utils.tel.tel_video_utils import verify_video_call_in_expected_state
from acts_contrib.test_utils.tel.tel_video_utils import video_call_downgrade
from acts_contrib.test_utils.tel.tel_video_utils import video_call_modify_video
from acts_contrib.test_utils.tel.tel_video_utils import video_call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import disconnect_call_by_id
from acts_contrib.test_utils.tel.tel_voice_utils import get_audio_route
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import set_audio_route
from acts_contrib.test_utils.tel.tel_voice_utils import get_cep_conference_call_id
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
+from acts_contrib.test_utils.tel.tel_voice_utils import set_audio_route
DEFAULT_LONG_DURATION_CALL_TOTAL_DURATION = 1 * 60 * 60 # default 1 hour
diff --git a/acts_tests/tests/google/tel/live/TelLiveVoiceConfTest.py b/acts_tests/tests/google/tel/live/TelLiveVoiceConfTest.py
index 02088ee..8e53ea7 100644
--- a/acts_tests/tests/google/tel/live/TelLiveVoiceConfTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveVoiceConfTest.py
@@ -20,28 +20,34 @@
import time
from acts import signals
from acts.test_decorators import test_tracker_info
+from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_defines import CALL_CAPABILITY_MERGE_CONFERENCE
from acts_contrib.test_utils.tel.tel_defines import CALL_CAPABILITY_SWAP_CONFERENCE
from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_ACTIVE
-from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_HOLDING
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_CONFERENCE
from acts_contrib.test_utils.tel.tel_defines import PHONE_TYPE_CDMA
-from acts_contrib.test_utils.tel.tel_defines import PHONE_TYPE_GSM
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_ss_utils import three_phone_call_forwarding_short_seq
+from acts_contrib.test_utils.tel.tel_ss_utils import three_phone_call_waiting_short_seq
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import call_reject
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
+from acts_contrib.test_utils.tel.tel_test_utils import install_dialer_apk
from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_voice_utils import call_reject
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_1x
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
@@ -49,34 +55,21 @@
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_wcdma
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
from acts_contrib.test_utils.tel.tel_voice_utils import swap_calls
-from acts_contrib.test_utils.tel.tel_voice_utils import three_phone_call_forwarding_short_seq
-from acts_contrib.test_utils.tel.tel_voice_utils import three_phone_call_waiting_short_seq
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _get_expected_call_state
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _hangup_call
-from acts_contrib.test_utils.tel.tel_voice_conf_utils import \
- _test_ims_conference_merge_drop_first_call_from_host
-from acts_contrib.test_utils.tel.tel_voice_conf_utils import \
- _test_ims_conference_merge_drop_first_call_from_participant
-from acts_contrib.test_utils.tel.tel_voice_conf_utils import \
- _test_ims_conference_merge_drop_second_call_from_host
-from acts_contrib.test_utils.tel.tel_voice_conf_utils import \
- _test_ims_conference_merge_drop_second_call_from_participant
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_ims_conference_merge_drop_first_call_from_host
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_ims_conference_merge_drop_first_call_from_participant
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_ims_conference_merge_drop_second_call_from_host
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_ims_conference_merge_drop_second_call_from_participant
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_call_mo_mo_add_swap_x
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_call_mo_mt_add_swap_x
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_call_mt_mt_add_swap_x
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _three_phone_call_mo_add_mo
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _three_phone_call_mo_add_mt
-from acts_contrib.test_utils.tel.tel_voice_conf_utils import _three_phone_call_mt_add_mt
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _three_phone_hangup_call_verify_call_state
-
+from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_wcdma_conference_merge_drop
class TelLiveVoiceConfTest(TelephonyBaseTest):
def setup_class(self):
@@ -90,6 +83,15 @@
raise signals.TestAbortClass(
"Conference call is not supported, abort test.")
+ self.dialer_util = self.user_params.get("dialer_apk", None)
+ if isinstance(self.dialer_util, list):
+ self.dialer_util = self.dialer_util[0]
+
+ if self.dialer_util:
+ ads = self.android_devices
+ for ad in ads:
+ install_dialer_apk(ad, self.dialer_util)
+
def teardown_test(self):
ensure_phones_idle(self.log, self.android_devices)
@@ -437,78 +439,7 @@
return False
return True
-
- def _test_wcdma_conference_merge_drop(self, call_ab_id, call_ac_id):
- """Test conference merge and drop in WCDMA/CSFB_WCDMA call.
-
- PhoneA in WCDMA (or CSFB_WCDMA) call with PhoneB.
- PhoneA in WCDMA (or CSFB_WCDMA) call with PhoneC.
- Merge calls to conference on PhoneA.
- Hangup on PhoneC, check call continues between AB.
- Hangup on PhoneB, check A ends.
-
- Args:
- call_ab_id: call id for call_AB on PhoneA.
- call_ac_id: call id for call_AC on PhoneA.
-
- Returns:
- True if succeed;
- False if failed.
- """
- ads = self.android_devices
-
- 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)
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
- if num_active_calls(self.log, ads[0]) != 3:
- ads[0].log.error("Total number of call ids is not 3.")
- return False
- call_conf_id = None
- for call_id in calls:
- if call_id != call_ab_id and call_id != call_ac_id:
- call_conf_id = call_id
- if not call_conf_id:
- self.log.error("Merge call fail, no new conference call id.")
- return False
- if not verify_incall_state(self.log, [ads[0], ads[1], ads[2]], True):
- return False
-
- # Check if Conf Call is currently active
- if ads[0].droid.telecomCallGetCallState(
- call_conf_id) != CALL_STATE_ACTIVE:
- ads[0].log.error(
- "Call_id: %s, state: %s, expected: STATE_ACTIVE", call_conf_id,
- ads[0].droid.telecomCallGetCallState(call_conf_id))
- return False
-
- self.log.info("Step5: End call on PhoneC and verify call continues.")
- if not _hangup_call(self.log, ads[2], "PhoneC"):
- return False
- time.sleep(WAIT_TIME_IN_CALL)
- calls = ads[0].droid.telecomCallGetCallIds()
- ads[0].log.info("Calls in PhoneA %s", calls)
- if num_active_calls(self.log, ads[0]) != 1:
- return False
- if not verify_incall_state(self.log, [ads[0], ads[1]], True):
- return False
- if not verify_incall_state(self.log, [ads[2]], False):
- return False
-
- self.log.info("Step6: End call on PhoneB and verify PhoneA end.")
- if not _hangup_call(self.log, ads[1], "PhoneB"):
- return False
- time.sleep(WAIT_TIME_IN_CALL)
- if not verify_incall_state(self.log, [ads[0], ads[1], ads[2]], False):
- return False
- return True
-
-
-
""" Tests Begin """
-
-
@TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="3cd45972-3862-4956-9504-7fefacdd5ca6")
def test_wcdma_mo_mo_add_merge_drop(self):
@@ -537,7 +468,7 @@
if call_ab_id is None or call_ac_id is None:
return False
- return self._test_wcdma_conference_merge_drop(call_ab_id, call_ac_id)
+ return _test_wcdma_conference_merge_drop(self.log, ads, call_ab_id, call_ac_id)
@TelephonyBaseTest.tel_test_wrap
@@ -568,7 +499,7 @@
if call_ab_id is None or call_ac_id is None:
return False
- return self._test_wcdma_conference_merge_drop(call_ab_id, call_ac_id)
+ return _test_wcdma_conference_merge_drop(self.log, ads, call_ab_id, call_ac_id)
@TelephonyBaseTest.tel_test_wrap
@@ -6641,7 +6572,7 @@
if call_ab_id is None or call_ac_id is None:
return False
- return self._test_wcdma_conference_merge_drop(call_ab_id, call_ac_id)
+ return _test_wcdma_conference_merge_drop(self.log, ads, call_ab_id, call_ac_id)
@TelephonyBaseTest.tel_test_wrap
@@ -6671,7 +6602,7 @@
if call_ab_id is None or call_ac_id is None:
return False
- return self._test_wcdma_conference_merge_drop(call_ab_id, call_ac_id)
+ return _test_wcdma_conference_merge_drop(self.log, ads, call_ab_id, call_ac_id)
@TelephonyBaseTest.tel_test_wrap
@@ -6700,7 +6631,7 @@
if call_ab_id is None or call_ac_id is None:
return False
- return self._test_wcdma_conference_merge_drop(call_ab_id, call_ac_id)
+ return _test_wcdma_conference_merge_drop(self.log, ads, call_ab_id, call_ac_id)
@TelephonyBaseTest.tel_test_wrap
@@ -6730,7 +6661,7 @@
if call_ab_id is None or call_ac_id is None:
return False
- return self._test_wcdma_conference_merge_drop(call_ab_id, call_ac_id)
+ return _test_wcdma_conference_merge_drop(self.log, ads, call_ab_id, call_ac_id)
@TelephonyBaseTest.tel_test_wrap
@@ -6759,7 +6690,7 @@
if call_ab_id is None or call_ac_id is None:
return False
- return self._test_wcdma_conference_merge_drop(call_ab_id, call_ac_id)
+ return _test_wcdma_conference_merge_drop(self.log, ads, call_ab_id, call_ac_id)
@TelephonyBaseTest.tel_test_wrap
@@ -6789,7 +6720,7 @@
if call_ab_id is None or call_ac_id is None:
return False
- return self._test_wcdma_conference_merge_drop(call_ab_id, call_ac_id)
+ return _test_wcdma_conference_merge_drop(self.log, ads, call_ab_id, call_ac_id)
@TelephonyBaseTest.tel_test_wrap
@@ -6819,7 +6750,7 @@
if call_ab_id is None or call_ac_id is None:
return False
- return self._test_wcdma_conference_merge_drop(call_ab_id, call_ac_id)
+ return _test_wcdma_conference_merge_drop(self.log, ads, call_ab_id, call_ac_id)
@TelephonyBaseTest.tel_test_wrap
@@ -6849,7 +6780,7 @@
if call_ab_id is None or call_ac_id is None:
return False
- return self._test_wcdma_conference_merge_drop(call_ab_id, call_ac_id)
+ return _test_wcdma_conference_merge_drop(self.log, ads, call_ab_id, call_ac_id)
@TelephonyBaseTest.tel_test_wrap
@@ -6878,7 +6809,7 @@
if call_ab_id is None or call_ac_id is None:
return False
- return self._test_wcdma_conference_merge_drop(call_ab_id, call_ac_id)
+ return _test_wcdma_conference_merge_drop(self.log, ads, call_ab_id, call_ac_id)
@TelephonyBaseTest.tel_test_wrap
@@ -6908,7 +6839,7 @@
if call_ab_id is None or call_ac_id is None:
return False
- return self._test_wcdma_conference_merge_drop(call_ab_id, call_ac_id)
+ return _test_wcdma_conference_merge_drop(self.log, ads, call_ab_id, call_ac_id)
@TelephonyBaseTest.tel_test_wrap
@@ -11415,6 +11346,29 @@
@TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="f4990e20-4a40-4238-9a2a-a75d9be3d354")
+ def test_volte_call_forwarding_unconditional(self):
+
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0])),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_forwarding_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_forwarding_type="unconditional")
+
+
+ @TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="26b85c3f-5a38-465a-a6e3-dfd03c6ea315")
def test_call_forwarding_busy(self):
@@ -11438,6 +11392,29 @@
@TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="26b85c3f-5a38-465a-a6e3-dfd03c6ea315")
+ def test_volte_call_forwarding_busy(self):
+
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0])),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_forwarding_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_forwarding_type="busy")
+
+
+ @TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="96638a39-efe2-40e2-afb6-6a97f87c4af5")
def test_call_forwarding_not_answered(self):
@@ -11461,6 +11438,29 @@
@TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="96638a39-efe2-40e2-afb6-6a97f87c4af5")
+ def test_volte_call_forwarding_not_answered(self):
+
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0])),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_forwarding_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_forwarding_type="not_answered")
+
+
+ @TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="a13e586a-3345-49d8-9e84-ca33bd3fbd7d")
def test_call_forwarding_not_reachable(self):
@@ -11484,6 +11484,29 @@
@TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="a13e586a-3345-49d8-9e84-ca33bd3fbd7d")
+ def test_volte_call_forwarding_not_reachable(self):
+
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0])),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_forwarding_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_forwarding_type="not_reachable")
+
+
+ @TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="e9a6027b-7dd1-4dca-a700-e4d42c9c947d")
def test_call_waiting_scenario_1(self):
""" Call waiting scenario 1: 1st call ended first by caller1 during 2nd
@@ -11510,6 +11533,50 @@
@TelephonyBaseTest.tel_test_wrap
+ @test_tracker_info(uuid="e9a6027b-7dd1-4dca-a700-e4d42c9c947d")
+ def test_volte_call_waiting_scenario_1(self):
+ """Tests that the call waiting function is workable by scenario 1.
+
+ Initial Condition:
+ (1) Network Type:
+ - DUT: LTE, VoLTE ON.
+ - Caller1: LTE/3G.
+
+ Execution Criteria:
+ (1) Enable call waiting on DUT.
+ (2) Let caller1 make the first MO call to DUT and let DUT answer the
+ call.
+ (3) Let caller2 make the second MO call to DUT. Do NOT answer the
+ call and keep the call alerting.
+ (4) End the first call by caller1.
+ (5) Let DUT answer the second call.
+ (6) End the second call by caller2.
+
+ Pass Criteria:
+ (2)(5) All the call can be made/answered correctly.
+ (4)(6) All the call can be released correctly.
+ """
+ ads = self.android_devices
+
+ tasks = [(phone_setup_volte, (self.log, ads[0])),
+ (phone_setup_voice_general, (self.log, ads[1])),
+ (phone_setup_voice_general, (self.log, ads[2]))]
+ if not multithread_func(self.log, tasks):
+ self.log.error("Phone Failed to Set Up Properly.")
+ return False
+
+ return three_phone_call_waiting_short_seq(
+ self.log,
+ ads[0],
+ None,
+ None,
+ ads[1],
+ ads[2],
+ call_waiting=True,
+ scenario=1)
+
+
+ @TelephonyBaseTest.tel_test_wrap
@test_tracker_info(uuid="3fe02cb7-68d7-4762-882a-02bff8ce32f9")
def test_call_waiting_scenario_2(self):
""" Call waiting scenario 2: 1st call ended first by caller1 during 2nd
diff --git a/acts_tests/tests/google/tel/live/TelLiveVoiceTest.py b/acts_tests/tests/google/tel/live/TelLiveVoiceTest.py
index a5f0117..2d055ea 100644
--- a/acts_tests/tests/google/tel/live/TelLiveVoiceTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveVoiceTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2016 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -24,11 +24,14 @@
from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
+from acts_contrib.test_utils.tel.tel_data_utils import get_mobile_data_usage
+from acts_contrib.test_utils.tel.tel_data_utils import remove_mobile_data_usage_limit
+from acts_contrib.test_utils.tel.tel_data_utils import set_mobile_data_usage_limit
from acts_contrib.test_utils.tel.tel_data_utils import test_call_setup_in_active_data_transfer
from acts_contrib.test_utils.tel.tel_data_utils import test_call_setup_in_active_youtube_video
from acts_contrib.test_utils.tel.tel_data_utils import call_epdg_to_epdg_wfc
from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_cell_switching_in_call
+from acts_contrib.test_utils.tel.tel_defines import CARRIER_VZW
from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_TERMINATED
from acts_contrib.test_utils.tel.tel_defines import GEN_2G
@@ -43,28 +46,27 @@
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_incoming_voice_sub_id
-from acts_contrib.test_utils.tel.tel_subscription_utils import \
- get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import \
- call_voicemail_erase_all_pending_voicemail
-from acts.utils import adb_shell_ping
-from acts_contrib.test_utils.tel.tel_test_utils import get_mobile_data_usage
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call_active
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan_cellular_preferred
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
+from acts_contrib.test_utils.tel.tel_test_utils import install_dialer_apk
from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
-from acts_contrib.test_utils.tel.tel_test_utils import remove_mobile_data_usage_limit
-from acts_contrib.test_utils.tel.tel_test_utils import run_multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import set_mobile_data_usage_limit
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_ringing_call
-from acts_contrib.test_utils.tel.tel_test_utils import set_wifi_to_default
from acts_contrib.test_utils.tel.tel_test_utils import STORY_LINE
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_in_call_active
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hold_unhold_test
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_1x
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
@@ -74,29 +76,21 @@
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_wcdma
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
from acts_contrib.test_utils.tel.tel_voice_utils import _test_call_long_duration
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import \
- phone_setup_iwlan_cellular_preferred
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_volte
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import call_voicemail_erase_all_pending_voicemail
from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_leave_voice_mail
from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_long_seq
from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_short_seq
-from acts_contrib.test_utils.tel.tel_voice_utils import hold_unhold_test
-
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_in_call_active
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_ringing_call
+from acts_contrib.test_utils.tel.tel_wifi_utils import set_wifi_to_default
+from acts.libs.utils.multithread import multithread_func
DEFAULT_PING_DURATION = 120 # in seconds
CallResult = TelephonyVoiceTestResult.CallResult.Value
+
class TelLiveVoiceTest(TelephonyBaseTest):
def setup_class(self):
super().setup_class()
@@ -109,6 +103,25 @@
self.call_server_number = self.user_params.get(
"call_server_number", STORY_LINE)
self.tel_logger = TelephonyMetricLogger.for_test_case()
+ self.dialer_util = self.user_params.get("dialer_apk", None)
+ if isinstance(self.dialer_util, list):
+ self.dialer_util = self.dialer_util[0]
+
+ if self.dialer_util:
+ ads = self.android_devices
+ for ad in ads:
+ install_dialer_apk(ad, self.dialer_util)
+
+ def get_carrier_name(self, ad):
+ return ad.adb.getprop("gsm.sim.operator.alpha")
+
+ def check_band_support(self,ad):
+ carrier = ad.adb.getprop("gsm.sim.operator.alpha")
+
+ if int(ad.adb.getprop("ro.product.first_api_level")) > 30 and (
+ carrier == CARRIER_VZW):
+ raise signals.TestSkip(
+ "Device Doesn't Support 2g/3G Band.")
""" Tests Begin """
@@ -389,6 +402,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
tasks = [(phone_setup_volte, (self.log, ads[0])), (phone_setup_csfb,
(self.log, ads[1]))]
@@ -420,6 +434,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
tasks = [(phone_setup_volte, (self.log, ads[0])), (phone_setup_csfb,
(self.log, ads[1]))]
@@ -531,6 +546,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
tasks = [(phone_setup_volte, (self.log, ads[0])),
(phone_setup_voice_3g, (self.log, ads[1]))]
@@ -564,6 +580,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Make Sure PhoneB is CDMA phone.
if ads[1].droid.telephonyGetPhoneType() != PHONE_TYPE_CDMA:
self.log.error("PhoneB not cdma phone, can not 3g 1x. Stop test.")
@@ -603,6 +620,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Make Sure PhoneB is GSM phone.
if ads[1].droid.telephonyGetPhoneType() != PHONE_TYPE_GSM:
self.log.error(
@@ -641,6 +659,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
tasks = [(phone_setup_volte, (self.log, ads[0])),
(phone_setup_voice_2g, (self.log, ads[1]))]
@@ -938,6 +957,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Turn OFF WiFi for Phone B
set_wifi_to_default(self.log, ads[1])
tasks = [(phone_setup_iwlan,
@@ -972,6 +992,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Turn OFF WiFi for Phone B
set_wifi_to_default(self.log, ads[1])
tasks = [(phone_setup_iwlan,
@@ -1006,6 +1027,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Turn OFF WiFi for Phone B
set_wifi_to_default(self.log, ads[1])
tasks = [(phone_setup_iwlan,
@@ -1040,6 +1062,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Turn OFF WiFi for Phone B
set_wifi_to_default(self.log, ads[1])
tasks = [(phone_setup_iwlan,
@@ -1074,6 +1097,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Turn OFF WiFi for Phone B
set_wifi_to_default(self.log, ads[1])
tasks = [(phone_setup_iwlan,
@@ -1108,6 +1132,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Turn OFF WiFi for Phone B
set_wifi_to_default(self.log, ads[1])
tasks = [(phone_setup_iwlan,
@@ -1142,6 +1167,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Turn OFF WiFi for Phone B
set_wifi_to_default(self.log, ads[1])
tasks = [(phone_setup_iwlan,
@@ -1176,6 +1202,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Turn OFF WiFi for Phone B
set_wifi_to_default(self.log, ads[1])
tasks = [(phone_setup_iwlan,
@@ -1210,6 +1237,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Turn OFF WiFi for Phone B
set_wifi_to_default(self.log, ads[1])
tasks = [(phone_setup_csfb, (self.log, ads[0])), (phone_setup_csfb,
@@ -1242,6 +1270,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Turn OFF WiFi for Phone B
set_wifi_to_default(self.log, ads[1])
tasks = [(phone_setup_voice_3g, (self.log, ads[0])),
@@ -1462,6 +1491,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Turn OFF WiFi for Phone B
set_wifi_to_default(self.log, ads[1])
tasks = [(phone_setup_csfb, (self.log, ads[0])), (phone_setup_csfb,
@@ -1496,6 +1526,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# Turn OFF WiFi for Phone B
set_wifi_to_default(self.log, ads[1])
tasks = [(phone_setup_voice_3g, (self.log, ads[0])),
@@ -1825,6 +1856,7 @@
# TODO: b/26338422 Make this a parameter
MINIMUM_SUCCESS_RATE = .95
ads = self.android_devices
+ self.check_band_support(ads[0])
tasks = [(phone_setup_csfb, (self.log, ads[0])), (phone_setup_csfb,
(self.log, ads[1]))]
@@ -1878,6 +1910,7 @@
# TODO: b/26338422 Make this a parameter
MINIMUM_SUCCESS_RATE = .95
ads = self.android_devices
+ self.check_band_support(ads[0])
tasks = [(phone_setup_voice_3g, (self.log, ads[0])),
(phone_setup_voice_3g, (self.log, ads[1]))]
@@ -2397,6 +2430,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# make sure PhoneA is GSM phone before proceed.
if (ads[0].droid.telephonyGetPhoneType() != PHONE_TYPE_GSM):
ads[0].log.error(
@@ -2449,6 +2483,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# make sure PhoneA is GSM phone before proceed.
if (ads[0].droid.telephonyGetPhoneType() != PHONE_TYPE_GSM):
ads[0].log.error(
@@ -2690,6 +2725,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
tasks = [(phone_setup_voice_3g, (self.log, ads[0])),
(phone_setup_voice_general, (self.log, ads[1]))]
@@ -2718,6 +2754,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
tasks = [(phone_setup_voice_general, (self.log, ads[1])),
(phone_setup_voice_2g, (self.log, ads[0]))]
@@ -2805,6 +2842,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
tasks = [(phone_setup_voice_2g, (self.log, ads[0])),
(phone_setup_voice_2g, (self.log, ads[1]))]
@@ -2838,6 +2876,7 @@
TestFailure if not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
tasks = [(phone_setup_voice_2g, (self.log, ads[0])),
(phone_setup_voice_2g, (self.log, ads[1]))]
@@ -2867,6 +2906,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# make sure PhoneA is GSM phone before proceed.
if (ads[0].droid.telephonyGetPhoneType() != PHONE_TYPE_GSM):
raise signals.TestSkip(
@@ -2912,6 +2952,7 @@
True if pass; False if fail.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
# make sure PhoneA is GSM phone before proceed.
if (ads[0].droid.telephonyGetPhoneType() != PHONE_TYPE_GSM):
self.log.error("Not GSM phone, abort this wcdma hold/unhold test.")
@@ -3020,6 +3061,7 @@
Otherwise True.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
tasks = [(phone_setup_voice_3g, (self.log, ads[0])),
(phone_setup_voice_general, (self.log, ads[1]))]
@@ -3274,6 +3316,7 @@
True if success.
False if failed.
"""
+ self.check_band_support(self.android_devices[0])
if not phone_setup_voice_3g(self.log, self.android_devices[0]):
self.android_devices[0].log.error("Failed to setup 3G")
return False
@@ -3301,6 +3344,7 @@
True if success.
False if failed.
"""
+ self.check_band_support(self.android_devices[0])
if not phone_setup_voice_3g(self.log, self.android_devices[0]):
self.android_devices[0].log.error("Failed to setup 3G")
return False
@@ -3328,6 +3372,7 @@
True if success.
False if failed.
"""
+ self.check_band_support(self.android_devices[0])
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
@@ -3355,6 +3400,7 @@
True if success.
False if failed.
"""
+ self.check_band_support(self.android_devices[0])
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
@@ -3430,8 +3476,13 @@
True if success.
False if failed.
"""
+ carrier = self.get_carrier_name(self.android_devices[0])
+ if carrier == CARRIER_VZW:
+ wfc = WFC_MODE_CELLULAR_PREFERRED
+ else:
+ wfc = WFC_MODE_WIFI_PREFERRED
if not phone_setup_iwlan(self.log, self.android_devices[0], True,
- WFC_MODE_WIFI_PREFERRED,
+ wfc,
self.wifi_network_ssid,
self.wifi_network_pass):
self.android_devices[0].log.error(
@@ -3456,8 +3507,13 @@
True if success.
False if failed.
"""
+ carrier = self.get_carrier_name(self.android_devices[0])
+ if carrier == CARRIER_VZW:
+ wfc = WFC_MODE_CELLULAR_PREFERRED
+ else:
+ wfc = WFC_MODE_WIFI_PREFERRED
if not phone_setup_iwlan(self.log, self.android_devices[0], True,
- WFC_MODE_WIFI_PREFERRED,
+ wfc,
self.wifi_network_ssid,
self.wifi_network_pass):
self.android_devices[0].log.error(
@@ -3482,8 +3538,10 @@
True if success.
False if failed.
"""
- if not phone_setup_iwlan_cellular_preferred(self.log,
+ if not phone_setup_iwlan(self.log,
self.android_devices[0],
+ True,
+ WFC_MODE_CELLULAR_PREFERRED,
self.wifi_network_ssid,
self.wifi_network_pass):
self.android_devices[0].log.error(
@@ -3508,8 +3566,10 @@
True if success.
False if failed.
"""
- if not phone_setup_iwlan_cellular_preferred(self.log,
+ if not phone_setup_iwlan(self.log,
self.android_devices[0],
+ True,
+ WFC_MODE_CELLULAR_PREFERRED,
self.wifi_network_ssid,
self.wifi_network_pass):
self.android_devices[0].log.error(
@@ -3662,6 +3722,7 @@
True if success.
False if failed.
"""
+ self.check_band_support(self.android_devices[0])
if not phone_setup_voice_3g(self.log, self.android_devices[0]):
self.android_devices[0].log.error("Failed to setup 3G")
return False
@@ -3685,6 +3746,7 @@
True if success.
False if failed.
"""
+ self.check_band_support(self.android_devices[0])
if not phone_setup_voice_3g(self.log, self.android_devices[0]):
self.android_devices[0].log.error("Failed to setup 3G")
return False
@@ -3708,6 +3770,7 @@
True if success.
False if failed.
"""
+ self.check_band_support(self.android_devices[0])
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
@@ -3731,6 +3794,7 @@
True if success.
False if failed.
"""
+ self.check_band_support(self.android_devices[0])
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
@@ -3803,8 +3867,13 @@
True if success.
False if failed.
"""
+ carrier = self.get_carrier_name(self.android_devices[0])
+ if carrier == CARRIER_VZW:
+ wfc = WFC_MODE_CELLULAR_PREFERRED
+ else:
+ wfc = WFC_MODE_WIFI_PREFERRED
if not phone_setup_iwlan(self.log, self.android_devices[0], True,
- WFC_MODE_WIFI_PREFERRED,
+ wfc,
self.wifi_network_ssid,
self.wifi_network_pass):
self.android_devices[0].log.error(
@@ -3828,8 +3897,13 @@
True if success.
False if failed.
"""
+ carrier = self.get_carrier_name(self.android_devices[0])
+ if carrier == CARRIER_VZW:
+ wfc = WFC_MODE_CELLULAR_PREFERRED
+ else:
+ wfc = WFC_MODE_WIFI_PREFERRED
if not phone_setup_iwlan(self.log, self.android_devices[0], True,
- WFC_MODE_WIFI_PREFERRED,
+ wfc,
self.wifi_network_ssid,
self.wifi_network_pass):
self.android_devices[0].log.error(
@@ -3903,8 +3977,10 @@
True if success.
False if failed.
"""
- if not phone_setup_iwlan_cellular_preferred(self.log,
+ if not phone_setup_iwlan(self.log,
self.android_devices[0],
+ True,
+ WFC_MODE_CELLULAR_PREFERRED,
self.wifi_network_ssid,
self.wifi_network_pass):
self.android_devices[0].log.error(
@@ -3928,8 +4004,10 @@
True if success.
False if failed.
"""
- if not phone_setup_iwlan_cellular_preferred(self.log,
+ if not phone_setup_iwlan(self.log,
self.android_devices[0],
+ True,
+ WFC_MODE_CELLULAR_PREFERRED,
self.wifi_network_ssid,
self.wifi_network_pass):
self.android_devices[0].log.error(
@@ -3956,6 +4034,7 @@
TestFailure is not success.
"""
ads = self.android_devices
+ self.check_band_support(ads[0])
try:
subscriber_id = ads[0].droid.telephonyGetSubscriberId()
data_usage = get_mobile_data_usage(ads[0], subscriber_id)
diff --git a/acts_tests/tests/google/tel/live/TelWifiDataTest.py b/acts_tests/tests/google/tel/live/TelWifiDataTest.py
index 4672feb..9582405 100644
--- a/acts_tests/tests/google/tel/live/TelWifiDataTest.py
+++ b/acts_tests/tests/google/tel/live/TelWifiDataTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2016 - The Android Open Source Project
+# Copyright 2022 - 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.
@@ -24,18 +24,18 @@
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts_contrib.test_utils.tel.tel_defines import GEN_4G
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_wifi_data_connection
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import run_multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
-from acts_contrib.test_utils.tel.tel_test_utils import get_wifi_signal_strength
from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import get_wifi_signal_strength
from acts.utils import adb_shell_ping
+from acts.libs.utils.multithread import run_multithread_func
# Attenuator name
ATTEN_NAME_FOR_WIFI_2G = 'wifi0'
diff --git a/acts_tests/tests/google/tel/live/TelWifiVideoTest.py b/acts_tests/tests/google/tel/live/TelWifiVideoTest.py
index 8f32038..692a96e 100644
--- a/acts_tests/tests/google/tel/live/TelWifiVideoTest.py
+++ b/acts_tests/tests/google/tel/live/TelWifiVideoTest.py
@@ -17,59 +17,14 @@
Test Script for ViWiFi live call test
"""
-import time
-from queue import Empty
from acts.test_decorators import test_tracker_info
+from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_defines import AUDIO_ROUTE_EARPIECE
-from acts_contrib.test_utils.tel.tel_defines import AUDIO_ROUTE_SPEAKER
-from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_ACTIVE
-from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_HOLDING
-from acts_contrib.test_utils.tel.tel_defines import CALL_CAPABILITY_MANAGE_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import CALL_CAPABILITY_MERGE_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import CALL_CAPABILITY_SWAP_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import CALL_PROPERTY_CONFERENCE
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VIDEO_SESSION_EVENT
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOLTE_ENABLED
-from acts_contrib.test_utils.tel.tel_defines import VT_STATE_AUDIO_ONLY
from acts_contrib.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
-from acts_contrib.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL_PAUSED
-from acts_contrib.test_utils.tel.tel_defines import VT_VIDEO_QUALITY_DEFAULT
-from acts_contrib.test_utils.tel.tel_defines import VT_STATE_RX_ENABLED
-from acts_contrib.test_utils.tel.tel_defines import VT_STATE_TX_ENABLED
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
-from acts_contrib.test_utils.tel.tel_defines import EVENT_VIDEO_SESSION_EVENT
-from acts_contrib.test_utils.tel.tel_defines import EventTelecomVideoCallSessionEvent
-from acts_contrib.test_utils.tel.tel_defines import SESSION_EVENT_RX_PAUSE
-from acts_contrib.test_utils.tel.tel_defines import SESSION_EVENT_RX_RESUME
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import disconnect_call_by_id
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
-from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
-from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_video_enabled
-from acts_contrib.test_utils.tel.tel_video_utils import get_call_id_in_video_state
-from acts_contrib.test_utils.tel.tel_video_utils import \
- is_phone_in_call_video_bidirectional
-from acts_contrib.test_utils.tel.tel_video_utils import \
- is_phone_in_call_viwifi_bidirectional
-from acts_contrib.test_utils.tel.tel_video_utils import is_phone_in_call_voice_hd
-from acts_contrib.test_utils.tel.tel_video_utils import phone_setup_video
-from acts_contrib.test_utils.tel.tel_video_utils import \
- verify_video_call_in_expected_state
-from acts_contrib.test_utils.tel.tel_video_utils import video_call_downgrade
-from acts_contrib.test_utils.tel.tel_video_utils import video_call_modify_video
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_video_utils import is_phone_in_call_viwifi_bidirectional
from acts_contrib.test_utils.tel.tel_video_utils import video_call_setup_teardown
-from acts_contrib.test_utils.tel.tel_voice_utils import get_audio_route
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import set_audio_route
-from acts_contrib.test_utils.tel.tel_voice_utils import get_cep_conference_call_id
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
DEFAULT_LONG_DURATION_CALL_TOTAL_DURATION = 1 * 60 * 60 # default 1 hour
diff --git a/acts_tests/tests/google/tel/live/TelWifiVoiceTest.py b/acts_tests/tests/google/tel/live/TelWifiVoiceTest.py
index 1b177836..4fc7c4b 100644
--- a/acts_tests/tests/google/tel/live/TelWifiVoiceTest.py
+++ b/acts_tests/tests/google/tel/live/TelWifiVoiceTest.py
@@ -22,7 +22,7 @@
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
from acts_contrib.test_utils.tel.tel_atten_utils import set_rssi
-from acts_contrib.test_utils.tel.tel_defines import CELL_STRONG_RSSI_VALUE
+from acts_contrib.test_utils.tel.tel_defines import ATTEN_MIN_VALUE
from acts_contrib.test_utils.tel.tel_defines import CELL_WEAK_RSSI_VALUE
from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_TERMINATED
@@ -35,12 +35,8 @@
from acts_contrib.test_utils.tel.tel_defines import MIN_RSSI_RESERVED_VALUE
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
-from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_BACKGROUND
-from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_FOREGROUND
-from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_RINGING
from acts_contrib.test_utils.tel.tel_defines import RAT_LTE
from acts_contrib.test_utils.tel.tel_defines import RAT_IWLAN
-from acts_contrib.test_utils.tel.tel_defines import RAT_WCDMA
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_REG_AND_CALL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_WIFI_RSSI_CALIBRATION_SCREEN_ON
@@ -54,41 +50,41 @@
from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackAvailable
from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackLost
from acts_contrib.test_utils.tel.tel_defines import SignalStrengthContainer
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_wifi_data_connection
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_disabled
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import is_phone_not_in_call
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_3g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_not_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_droid_not_in_call
from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat
from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
from acts_contrib.test_utils.tel.tel_test_utils import is_network_call_back_event_match
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_not_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import set_wfc_mode
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_volte
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_droid_not_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_disabled
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wfc_enabled
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
-from acts_contrib.test_utils.tel.tel_test_utils import get_wifi_signal_strength
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_not_iwlan
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_3g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_csfb
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_not_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_volte
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import get_wifi_signal_strength
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
# Attenuator name
ATTEN_NAME_FOR_WIFI_2G = 'wifi0'
@@ -122,7 +118,7 @@
self.attens = {}
for atten in self.attenuators:
self.attens[atten.path] = atten
- atten.set_atten(atten.get_max_atten()) # Default all attens to max
+ atten.set_atten(ATTEN_MIN_VALUE, retry=True) # Default all attens to min
self.log.info("WFC phone: <{}> <{}>".format(
self.android_devices[0].serial,
@@ -207,13 +203,13 @@
super().teardown_test()
set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
- MAX_RSSI_RESERVED_VALUE)
+ MIN_RSSI_RESERVED_VALUE)
set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
- MAX_RSSI_RESERVED_VALUE)
+ MIN_RSSI_RESERVED_VALUE)
set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
- MAX_RSSI_RESERVED_VALUE)
+ MIN_RSSI_RESERVED_VALUE)
set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
- MAX_RSSI_RESERVED_VALUE)
+ MIN_RSSI_RESERVED_VALUE)
return True
def _wfc_call_sequence(self, ads, mo_mt, initial_wifi_cellular_setup_func,
@@ -3205,16 +3201,20 @@
"""
# Increase LTE RSRP to MAX_RSSI_RESERVED_VALUE
time.sleep(30)
- set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
- MAX_RSSI_RESERVED_VALUE)
- set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
- MAX_RSSI_RESERVED_VALUE)
+ if not set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+ MAX_RSSI_RESERVED_VALUE):
+ return False
+ if not set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
+ MAX_RSSI_RESERVED_VALUE):
+ return False
time.sleep(30)
# Decrease WiFi RSSI to MIN_RSSI_RESERVED_VALUE
- set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
- MIN_RSSI_RESERVED_VALUE, 5, 1)
- set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
- MIN_RSSI_RESERVED_VALUE, 5, 1)
+ if not set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
+ MIN_RSSI_RESERVED_VALUE, 5, 1):
+ return False
+ if not set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
+ MIN_RSSI_RESERVED_VALUE, 5, 1):
+ return False
# Make sure phone hand-out, not drop call
if not self._phone_wait_for_not_wfc():
self.log.error("Phone should hand out to LTE.")
@@ -3257,8 +3257,10 @@
Increase Cellular RSSI to MAX_RSSI_RESERVED_VALUE
PhoneA should still be in call. PhoneA should hand-out to LTE.
"""
- self._decrease_cellular_rssi_check_phone_hand_out()
- self._increase_lte_decrease_wifi_rssi_check_phone_hand_out()
+ if not self._decrease_cellular_rssi_check_phone_hand_out():
+ return False
+ if not self._increase_lte_decrease_wifi_rssi_check_phone_hand_out():
+ return False
return True
@@ -3528,10 +3530,12 @@
"""
time.sleep(60)
# Decrease Cellular RSSI to MIN_RSSI_RESERVED_VALUE
- set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
- MIN_RSSI_RESERVED_VALUE, 5, 1)
- set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
- MIN_RSSI_RESERVED_VALUE, 5, 1)
+ if not set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+ MIN_RSSI_RESERVED_VALUE, 5, 1):
+ return False
+ if not set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
+ MIN_RSSI_RESERVED_VALUE, 5, 1):
+ return False
# 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.")
diff --git a/acts_tests/tests/google/tel/live/msim/TelLiveMSIMSmsTest.py b/acts_tests/tests/google/tel/live/msim/TelLiveMSIMSmsTest.py
index ad6e713..83ac659 100644
--- a/acts_tests/tests/google/tel/live/msim/TelLiveMSIMSmsTest.py
+++ b/acts_tests/tests/google/tel/live/msim/TelLiveMSIMSmsTest.py
@@ -15,17 +15,14 @@
# limitations under the License.
import time
-from acts_contrib.test_utils.tel.tel_test_utils \
- import sms_send_receive_verify, multithread_func
-from acts.utils import rand_ascii_str
-from acts_contrib.test_utils.tel.tel_subscription_utils \
- import get_subid_from_slot_index, set_subid_for_message
-from acts_contrib.test_utils.tel.tel_defines \
- import MULTI_SIM_CONFIG, WAIT_TIME_ANDROID_STATE_SETTLING
-from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_voice_utils \
- import phone_setup_voice_general_for_slot
+from acts_contrib.test_utils.tel.tel_defines import MULTI_SIM_CONFIG, WAIT_TIME_ANDROID_STATE_SETTLING
+from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general_for_slot
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index, set_subid_for_message
+from acts.libs.utils.multithread import multithread_func
+from acts.test_decorators import test_tracker_info
+from acts.utils import rand_ascii_str
class TelLiveMSIMSmsTest(TelephonyBaseTest):
diff --git a/acts_tests/tests/google/tel/live/msim/TelLiveMSIMVoiceTest.py b/acts_tests/tests/google/tel/live/msim/TelLiveMSIMVoiceTest.py
index 501b0d6..f8c3237 100644
--- a/acts_tests/tests/google/tel/live/msim/TelLiveMSIMVoiceTest.py
+++ b/acts_tests/tests/google/tel/live/msim/TelLiveMSIMVoiceTest.py
@@ -14,12 +14,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from acts_contrib.test_utils.tel.tel_voice_utils \
- import two_phone_call_msim_short_seq, phone_setup_voice_general_for_slot
from acts.test_decorators import test_tracker_info
+from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_test_utils import multithread_func
from acts_contrib.test_utils.tel.tel_defines import MULTI_SIM_CONFIG
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general_for_slot
+from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_msim_short_seq
class TelLiveMSIMVoiceTest(TelephonyBaseTest):
diff --git a/acts_tests/tests/google/usb/UsbTetheringFunctionsTest.py b/acts_tests/tests/google/usb/UsbTetheringFunctionsTest.py
index 14eb381..be84075 100644
--- a/acts_tests/tests/google/usb/UsbTetheringFunctionsTest.py
+++ b/acts_tests/tests/google/usb/UsbTetheringFunctionsTest.py
@@ -28,6 +28,7 @@
from acts_contrib.test_utils.tel import tel_defines
from acts_contrib.test_utils.tel.anritsu_utils import wait_for_sms_sent_success
from acts_contrib.test_utils.tel.tel_defines import EventMmsSentSuccess
+from acts_contrib.test_utils.tel.tel_bootloader_utils import fastboot_wipe
# Time it takes for the usb tethering IP to
# show up in ifconfig and function waiting.
@@ -407,7 +408,7 @@
5. Run ping test through usb tethering interface.
"""
self.enable_usb_tethering()
- tutils.fastboot_wipe(self.dut)
+ fastboot_wipe(self.dut)
time.sleep(DEFAULT_SETTLE_TIME)
# Skip setup wizard after wipe.
self.dut.adb.shell(
diff --git a/acts_tests/tests/google/wifi/WifiAutoUpdateTest.py b/acts_tests/tests/google/wifi/WifiAutoUpdateTest.py
index 743a155..c50cef7 100755
--- a/acts_tests/tests/google/wifi/WifiAutoUpdateTest.py
+++ b/acts_tests/tests/google/wifi/WifiAutoUpdateTest.py
@@ -20,7 +20,7 @@
from acts.libs.ota import ota_updater
import acts.signals as signals
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
import acts.utils as utils
diff --git a/acts_tests/tests/google/wifi/WifiConnectedMacRandomizationTest.py b/acts_tests/tests/google/wifi/WifiConnectedMacRandomizationTest.py
index 8165c72..28dc90e 100644
--- a/acts_tests/tests/google/wifi/WifiConnectedMacRandomizationTest.py
+++ b/acts_tests/tests/google/wifi/WifiConnectedMacRandomizationTest.py
@@ -21,7 +21,7 @@
import acts.base_test
import acts.signals as signals
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
import acts.utils as utils
diff --git a/acts_tests/tests/google/wifi/WifiCrashStressTest.py b/acts_tests/tests/google/wifi/WifiCrashStressTest.py
index 90e546f..9982cd8 100644
--- a/acts_tests/tests/google/wifi/WifiCrashStressTest.py
+++ b/acts_tests/tests/google/wifi/WifiCrashStressTest.py
@@ -21,7 +21,7 @@
from acts import utils
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
-from acts_contrib.test_utils.tel.tel_test_utils import disable_qxdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import disable_qxdm_logger
WifiEnums = wutils.WifiEnums
diff --git a/acts_tests/tests/google/wifi/WifiMacRandomizationTest.py b/acts_tests/tests/google/wifi/WifiMacRandomizationTest.py
index e7fd9fa..d83460d 100644
--- a/acts_tests/tests/google/wifi/WifiMacRandomizationTest.py
+++ b/acts_tests/tests/google/wifi/WifiMacRandomizationTest.py
@@ -27,8 +27,8 @@
from acts import asserts
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
from scapy.all import *
from acts.controllers.ap_lib import hostapd_constants
diff --git a/acts_tests/tests/google/wifi/WifiManagerTest.py b/acts_tests/tests/google/wifi/WifiManagerTest.py
index 902272c..d2a07dc 100644
--- a/acts_tests/tests/google/wifi/WifiManagerTest.py
+++ b/acts_tests/tests/google/wifi/WifiManagerTest.py
@@ -205,8 +205,8 @@
" match. \nBefore reboot = %s \n After reboot = %s" %
(networks, network_info))
raise signals.TestFailure(msg)
- current_count = 0
# For each network, check if it exists in configured list after reboot
+ current_ssids = set()
for network in networks:
exists = wutils.match_networks({
WifiEnums.SSID_KEY: network[WifiEnums.SSID_KEY]
@@ -218,10 +218,10 @@
# Get the new network id for each network after reboot.
network[WifiEnums.NETID_KEY] = exists[0]['networkId']
if exists[0]['status'] == 'CURRENT':
- current_count += 1
+ current_ssids.add(network[WifiEnums.SSID_KEY])
# At any given point, there can only be one currently active
# network, defined with 'status':'CURRENT'
- if current_count > 1:
+ if len(current_ssids) > 1:
raise signals.TestFailure("More than one network showing"
"as 'CURRENT' after reboot")
diff --git a/acts_tests/tests/google/wifi/WifiPingTest.py b/acts_tests/tests/google/wifi/WifiPingTest.py
index 4d25f26..096a935 100644
--- a/acts_tests/tests/google/wifi/WifiPingTest.py
+++ b/acts_tests/tests/google/wifi/WifiPingTest.py
@@ -29,6 +29,7 @@
from acts_contrib.test_utils.wifi import ota_chamber
from acts_contrib.test_utils.wifi import ota_sniffer
from acts_contrib.test_utils.wifi import wifi_performance_test_utils as wputils
+from acts_contrib.test_utils.wifi.wifi_performance_test_utils.bokeh_figure import BokehFigure
from acts_contrib.test_utils.wifi import wifi_retail_ap as retail_ap
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from functools import partial
@@ -79,7 +80,11 @@
self.access_point = retail_ap.create(self.RetailAccessPoints)[0]
if hasattr(self,
'OTASniffer') and self.testbed_params['sniffer_enable']:
- self.sniffer = ota_sniffer.create(self.OTASniffer)[0]
+ try:
+ self.sniffer = ota_sniffer.create(self.OTASniffer)[0]
+ except:
+ self.log.warning('Could not start sniffer. Disabling sniffs.')
+ self.testbed_params['sniffer_enable'] = 0
self.log.info('Access Point Configuration: {}'.format(
self.access_point.ap_settings))
self.log_path = os.path.join(logging.log_path, 'results')
@@ -98,9 +103,13 @@
self.user_params['retry_tests'] = [self.__class__.__name__]
def teardown_class(self):
+ for attenuator in self.attenuators:
+ attenuator.set_atten(0, strict=False, retry=True)
# Turn WiFi OFF and reset AP
+ self.access_point.teardown()
for dev in self.android_devices:
wutils.wifi_toggle_state(dev, False)
+ dev.go_to_sleep()
self.process_testclass_results()
def setup_test(self):
@@ -132,7 +141,9 @@
results_file_path = os.path.join(self.log_path,
'testclass_summary.json')
with open(results_file_path, 'w') as results_file:
- json.dump(testclass_summary, results_file, indent=4)
+ json.dump(wputils.serialize_dict(testclass_summary),
+ results_file,
+ indent=4)
def pass_fail_check_ping_rtt(self, result):
"""Check the test result and decide if it passed or failed.
@@ -232,6 +243,10 @@
range_index]
ping_range_result['peak_throughput_pct'] = 100 - min(
ping_loss_over_att)
+ ping_range_result['total_attenuation'] = [
+ ping_range_result['fixed_attenuation'] + att
+ for att in testcase_params['atten_range']
+ ]
ping_range_result['range'] = (ping_range_result['atten_at_range'] +
ping_range_result['fixed_attenuation'])
ping_range_result['llstats_at_range'] = (
@@ -248,14 +263,15 @@
results_file_path = os.path.join(
self.log_path, '{}.json'.format(self.current_test_name))
with open(results_file_path, 'w') as results_file:
- json.dump(ping_range_result, results_file, indent=4)
+ json.dump(wputils.serialize_dict(ping_range_result),
+ results_file,
+ indent=4)
# Plot results
- if 'range' not in self.current_test_name:
- figure = wputils.BokehFigure(
- self.current_test_name,
- x_label='Timestamp (s)',
- primary_y_label='Round Trip Time (ms)')
+ if 'rtt' in self.current_test_name:
+ figure = BokehFigure(self.current_test_name,
+ x_label='Timestamp (s)',
+ primary_y_label='Round Trip Time (ms)')
for idx, result in enumerate(ping_range_result['ping_results']):
if len(result['rtt']) > 1:
x_data = [
@@ -298,50 +314,86 @@
if self.testbed_params['sniffer_enable']:
self.sniffer.start_capture(
testcase_params['test_network'],
- chan=int(testcase_params['channel']),
+ chan=testcase_params['channel'],
bw=testcase_params['bandwidth'],
duration=testcase_params['ping_duration'] *
len(testcase_params['atten_range']) + self.TEST_TIMEOUT)
# Run ping and sweep attenuation as needed
zero_counter = 0
+ pending_first_ping = 1
for atten in testcase_params['atten_range']:
for attenuator in self.attenuators:
- attenuator.set_atten(atten, strict=False)
- rssi_future = wputils.get_connected_rssi_nb(
- self.dut,
- int(testcase_params['ping_duration'] / 2 /
- self.RSSI_POLL_INTERVAL), self.RSSI_POLL_INTERVAL,
- testcase_params['ping_duration'] / 2)
+ attenuator.set_atten(atten, strict=False, retry=True)
+ if self.testclass_params.get('monitor_rssi', 1):
+ rssi_future = wputils.get_connected_rssi_nb(
+ self.dut,
+ int(testcase_params['ping_duration'] / 2 /
+ self.RSSI_POLL_INTERVAL), self.RSSI_POLL_INTERVAL,
+ testcase_params['ping_duration'] / 2)
# Refresh link layer stats
llstats_obj.update_stats()
- current_ping_stats = wputils.get_ping_stats(
- self.ping_server, self.dut_ip,
- testcase_params['ping_duration'],
- testcase_params['ping_interval'], testcase_params['ping_size'])
- current_rssi = rssi_future.result()
+ if testcase_params.get('ping_from_dut', False):
+ current_ping_stats = wputils.get_ping_stats(
+ self.dut,
+ wputils.get_server_address(self.ping_server, self.dut_ip,
+ '255.255.255.0'),
+ testcase_params['ping_duration'],
+ testcase_params['ping_interval'],
+ testcase_params['ping_size'])
+ else:
+ current_ping_stats = wputils.get_ping_stats(
+ self.ping_server, self.dut_ip,
+ testcase_params['ping_duration'],
+ testcase_params['ping_interval'],
+ testcase_params['ping_size'])
+ if self.testclass_params.get('monitor_rssi', 1):
+ current_rssi = rssi_future.result()
+ else:
+ current_rssi = collections.OrderedDict([
+ ('time_stamp', []), ('bssid', []), ('ssid', []),
+ ('frequency', []),
+ ('signal_poll_rssi', wputils.empty_rssi_result()),
+ ('signal_poll_avg_rssi', wputils.empty_rssi_result()),
+ ('chain_0_rssi', wputils.empty_rssi_result()),
+ ('chain_1_rssi', wputils.empty_rssi_result())
+ ])
test_result['rssi_results'].append(current_rssi)
llstats_obj.update_stats()
curr_llstats = llstats_obj.llstats_incremental.copy()
test_result['llstats'].append(curr_llstats)
if current_ping_stats['connected']:
+ llstats_str = 'TX MCS = {0} ({1:.1f}%). RX MCS = {2} ({3:.1f}%)'.format(
+ curr_llstats['summary']['common_tx_mcs'],
+ curr_llstats['summary']['common_tx_mcs_freq'] * 100,
+ curr_llstats['summary']['common_rx_mcs'],
+ curr_llstats['summary']['common_rx_mcs_freq'] * 100)
self.log.info(
- 'Attenuation = {0}dB\tPacket Loss = {1}%\t'
- 'Avg RTT = {2:.2f}ms\tRSSI = {3} [{4},{5}]\t'.format(
- atten, current_ping_stats['packet_loss_percentage'],
- statistics.mean(current_ping_stats['rtt']),
- current_rssi['signal_poll_rssi']['mean'],
- current_rssi['chain_0_rssi']['mean'],
- current_rssi['chain_1_rssi']['mean']))
+ 'Attenuation = {0}dB\tPacket Loss = {1:.1f}%\t'
+ 'Avg RTT = {2:.2f}ms\tRSSI = {3:.1f} [{4:.1f},{5:.1f}]\t{6}\t'
+ .format(atten,
+ current_ping_stats['packet_loss_percentage'],
+ statistics.mean(current_ping_stats['rtt']),
+ current_rssi['signal_poll_rssi']['mean'],
+ current_rssi['chain_0_rssi']['mean'],
+ current_rssi['chain_1_rssi']['mean'], llstats_str))
if current_ping_stats['packet_loss_percentage'] == 100:
zero_counter = zero_counter + 1
else:
zero_counter = 0
+ pending_first_ping = 0
else:
self.log.info(
'Attenuation = {}dB. Disconnected.'.format(atten))
zero_counter = zero_counter + 1
test_result['ping_results'].append(current_ping_stats.as_dict())
- if zero_counter == self.MAX_CONSECUTIVE_ZEROS:
+ # Test ends when ping loss stable at 0. If test has successfully
+ # started, test ends on MAX_CONSECUTIVE_ZEROS. In case of a restry
+ # extra zeros are allowed to ensure a test properly starts.
+ if self.retry_flag and pending_first_ping:
+ allowable_zeros = self.MAX_CONSECUTIVE_ZEROS**2
+ else:
+ allowable_zeros = self.MAX_CONSECUTIVE_ZEROS
+ if zero_counter == allowable_zeros:
self.log.info('Ping loss stable at 100%. Stopping test now.')
for idx in range(
len(testcase_params['atten_range']) -
@@ -349,6 +401,11 @@
test_result['ping_results'].append(
self.DISCONNECTED_PING_RESULT)
break
+ # Set attenuator to initial setting
+ for attenuator in self.attenuators:
+ attenuator.set_atten(testcase_params['atten_range'][0],
+ strict=False,
+ retry=True)
if self.testbed_params['sniffer_enable']:
self.sniffer.stop_capture()
return test_result
@@ -361,12 +418,16 @@
"""
band = self.access_point.band_lookup_by_channel(
testcase_params['channel'])
- if '2G' in band:
- frequency = wutils.WifiEnums.channel_2G_to_freq[
- testcase_params['channel']]
+ if '6G' in band:
+ frequency = wutils.WifiEnums.channel_6G_to_freq[int(
+ testcase_params['channel'].strip('6g'))]
else:
- frequency = wutils.WifiEnums.channel_5G_to_freq[
- testcase_params['channel']]
+ if testcase_params['channel'] < 13:
+ frequency = wutils.WifiEnums.channel_2G_to_freq[
+ testcase_params['channel']]
+ else:
+ frequency = wutils.WifiEnums.channel_5G_to_freq[
+ testcase_params['channel']]
if frequency in wutils.WifiEnums.DFS_5G_FREQUENCIES:
self.access_point.set_region(self.testbed_params['DFS_region'])
else:
@@ -380,30 +441,47 @@
self.log.info('Access Point Configuration: {}'.format(
self.access_point.ap_settings))
- def setup_dut(self, testcase_params):
- """Sets up the DUT in the configuration required by the test.
-
- Args:
- testcase_params: dict containing AP and other test params
- """
- # Check battery level before test
- if not wputils.health_check(self.dut, 10):
- asserts.skip('Battery level too low. Skipping test.')
- # Turn screen off to preserve battery
- self.dut.go_to_sleep()
+ def validate_and_connect(self, testcase_params):
if wputils.validate_network(self.dut,
testcase_params['test_network']['SSID']):
self.log.info('Already connected to desired network')
else:
- wutils.reset_wifi(self.dut)
- wutils.set_wifi_country_code(self.dut,
- self.testclass_params['country_code'])
+ current_country = wputils.get_country_code(self.dut)
+ if current_country != self.testclass_params['country_code']:
+ self.log.warning(
+ 'Requested CC: {}, Current CC: {}. Resetting WiFi'.format(
+ self.testclass_params['country_code'],
+ current_country))
+ wutils.wifi_toggle_state(self.dut, False)
+ wutils.set_wifi_country_code(
+ self.dut, self.testclass_params['country_code'])
+ wutils.wifi_toggle_state(self.dut, True)
+ wutils.reset_wifi(self.dut)
+ wutils.set_wifi_country_code(
+ self.dut, self.testclass_params['country_code'])
+ if self.testbed_params.get('txbf_off', False):
+ wputils.disable_beamforming(self.dut)
testcase_params['test_network']['channel'] = testcase_params[
'channel']
wutils.wifi_connect(self.dut,
testcase_params['test_network'],
num_of_tries=5,
check_connectivity=True)
+
+ def setup_dut(self, testcase_params):
+ """Sets up the DUT in the configuration required by the test.
+
+ Args:
+ testcase_params: dict containing AP and other test params
+ """
+ # Turn screen off to preserve battery
+ if self.testbed_params.get('screen_on',
+ False) or self.testclass_params.get(
+ 'screen_on', False):
+ self.dut.droid.wakeLockAcquireDim()
+ else:
+ self.dut.go_to_sleep()
+ self.validate_and_connect(testcase_params)
self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses('wlan0')[0]
if testcase_params['channel'] not in self.atten_dut_chain_map.keys():
self.atten_dut_chain_map[testcase_params[
@@ -428,7 +506,9 @@
self.setup_ap(testcase_params)
# Set attenuator to 0 dB
for attenuator in self.attenuators:
- attenuator.set_atten(0, strict=False)
+ attenuator.set_atten(testcase_params['atten_range'][0],
+ strict=False,
+ retry=True)
# Reset, configure, and connect DUT
self.setup_dut(testcase_params)
@@ -446,6 +526,11 @@
return self.testclass_params['range_atten_start']
def compile_test_params(self, testcase_params):
+ # Check if test should be skipped.
+ wputils.check_skip_conditions(testcase_params, self.dut,
+ self.access_point,
+ getattr(self, 'ota_chamber', None))
+
band = self.access_point.band_lookup_by_channel(
testcase_params['channel'])
testcase_params['test_network'] = self.main_network[band]
@@ -516,11 +601,11 @@
allowed_configs = {
20: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 64, 100,
- 116, 132, 140, 149, 153, 157, 161
+ 116, 132, 140, 149, 153, 157, 161, '6g37', '6g117', '6g213'
],
- 40: [36, 44, 100, 149, 157],
- 80: [36, 100, 149],
- 160: [36]
+ 40: [36, 44, 100, 149, 157, '6g37', '6g117', '6g213'],
+ 80: [36, 100, 149, '6g37', '6g117', '6g213'],
+ 160: [36, '6g37', '6g117', '6g213']
}
for channel, mode, chain, test_type in itertools.product(
@@ -545,25 +630,33 @@
class WifiPing_TwoChain_Test(WifiPingTest):
def __init__(self, controllers):
super().__init__(controllers)
- self.tests = self.generate_test_cases(
- ap_power='standard',
- channels=[1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
- modes=['bw20', 'bw40', 'bw80'],
- test_types=[
- 'test_ping_range', 'test_fast_ping_rtt', 'test_slow_ping_rtt'
- ],
- chain_mask=['2x2'])
+ self.tests = self.generate_test_cases(ap_power='standard',
+ channels=[
+ 1, 6, 11, 36, 40, 44, 48,
+ 149, 153, 157, 161, '6g37',
+ '6g117', '6g213'
+ ],
+ modes=['bw20', 'bw40', 'bw80'],
+ test_types=[
+ 'test_ping_range',
+ 'test_fast_ping_rtt',
+ 'test_slow_ping_rtt'
+ ],
+ chain_mask=['2x2'])
class WifiPing_PerChainRange_Test(WifiPingTest):
def __init__(self, controllers):
super().__init__(controllers)
- self.tests = self.generate_test_cases(
- ap_power='standard',
- chain_mask=['0', '1', '2x2'],
- channels=[1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
- modes=['bw20', 'bw40', 'bw80'],
- test_types=['test_ping_range'])
+ self.tests = self.generate_test_cases(ap_power='standard',
+ chain_mask=['0', '1', '2x2'],
+ channels=[
+ 1, 6, 11, 36, 40, 44, 48,
+ 149, 153, 157, 161, '6g37',
+ '6g117', '6g213'
+ ],
+ modes=['bw20', 'bw40', 'bw80'],
+ test_types=['test_ping_range'])
class WifiPing_LowPowerAP_Test(WifiPingTest):
@@ -610,21 +703,24 @@
range_vs_angle = collections.OrderedDict()
for test in self.testclass_results:
curr_params = test['testcase_params']
- curr_config = curr_params['channel']
- if curr_config in range_vs_angle:
- if curr_params['position'] not in range_vs_angle[curr_config][
- 'position']:
- range_vs_angle[curr_config]['position'].append(
+ curr_config = wputils.extract_sub_dict(
+ curr_params, ['channel', 'mode', 'chain_mask'])
+ curr_config_id = tuple(curr_config.items())
+ if curr_config_id in range_vs_angle:
+ if curr_params['position'] not in range_vs_angle[
+ curr_config_id]['position']:
+ range_vs_angle[curr_config_id]['position'].append(
curr_params['position'])
- range_vs_angle[curr_config]['range'].append(test['range'])
- range_vs_angle[curr_config]['llstats_at_range'].append(
+ range_vs_angle[curr_config_id]['range'].append(
+ test['range'])
+ range_vs_angle[curr_config_id]['llstats_at_range'].append(
test['llstats_at_range'])
else:
- range_vs_angle[curr_config]['range'][-1] = test['range']
- range_vs_angle[curr_config]['llstats_at_range'][-1] = test[
- 'llstats_at_range']
+ range_vs_angle[curr_config_id]['range'][-1] = test['range']
+ range_vs_angle[curr_config_id]['llstats_at_range'][
+ -1] = test['llstats_at_range']
else:
- range_vs_angle[curr_config] = {
+ range_vs_angle[curr_config_id] = {
'position': [curr_params['position']],
'range': [test['range']],
'llstats_at_range': [test['llstats_at_range']]
@@ -635,21 +731,24 @@
x_label = 'Angle (deg)'
elif chamber_mode == 'stepped stirrers':
x_label = 'Position Index'
- figure = wputils.BokehFigure(
+ figure = BokehFigure(
title='Range vs. Position',
x_label=x_label,
primary_y_label='Range (dB)',
)
- for channel, channel_data in range_vs_angle.items():
- figure.add_line(x_data=channel_data['position'],
- y_data=channel_data['range'],
- hover_text=channel_data['llstats_at_range'],
- legend='Channel {}'.format(channel))
- average_range = sum(channel_data['range']) / len(
- channel_data['range'])
- self.log.info('Average range for Channel {} is: {}dB'.format(
- channel, average_range))
- metric_name = 'ota_summary_ch{}.avg_range'.format(channel)
+ for curr_config_id, curr_config_data in range_vs_angle.items():
+ curr_config = collections.OrderedDict(curr_config_id)
+ figure.add_line(x_data=curr_config_data['position'],
+ y_data=curr_config_data['range'],
+ hover_text=curr_config_data['llstats_at_range'],
+ legend='{}'.format(curr_config_id))
+ average_range = sum(curr_config_data['range']) / len(
+ curr_config_data['range'])
+ self.log.info('Average range for {} is: {}dB'.format(
+ curr_config_id, average_range))
+ metric_name = 'ota_summary_ch{}_{}_ch{}.avg_range'.format(
+ curr_config['channel'], curr_config['mode'],
+ curr_config['chain_mask'])
self.testclass_metric_logger.add_metric(metric_name, average_range)
current_context = context.get_current_context().get_full_output_path()
plot_file_path = os.path.join(current_context, 'results.html')
@@ -659,20 +758,35 @@
results_file_path = os.path.join(current_context,
'testclass_summary.json')
with open(results_file_path, 'w') as results_file:
- json.dump(range_vs_angle, results_file, indent=4)
+ json.dump(wputils.serialize_dict(range_vs_angle),
+ results_file,
+ indent=4)
+
+ def setup_dut(self, testcase_params):
+ """Sets up the DUT in the configuration required by the test.
+
+ Args:
+ testcase_params: dict containing AP and other test params
+ """
+ wputils.set_chain_mask(self.dut, testcase_params['chain_mask'])
+ # Turn screen off to preserve battery
+ if self.testbed_params.get('screen_on',
+ False) or self.testclass_params.get(
+ 'screen_on', False):
+ self.dut.droid.wakeLockAcquireDim()
+ else:
+ self.dut.go_to_sleep()
+ self.validate_and_connect(testcase_params)
+ self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses('wlan0')[0]
def setup_ping_test(self, testcase_params):
- WifiPingTest.setup_ping_test(self, testcase_params)
# Setup turntable
if testcase_params['chamber_mode'] == 'orientation':
self.ota_chamber.set_orientation(testcase_params['position'])
elif testcase_params['chamber_mode'] == 'stepped stirrers':
self.ota_chamber.step_stirrers(testcase_params['total_positions'])
-
- def extract_test_id(self, testcase_params, id_fields):
- test_id = collections.OrderedDict(
- (param, testcase_params[param]) for param in id_fields)
- return test_id
+ # Continue setting up ping test
+ WifiPingTest.setup_ping_test(self, testcase_params)
def get_range_start_atten(self, testcase_params):
"""Gets the starting attenuation for this ping test.
@@ -690,12 +804,12 @@
return self.testclass_params['range_atten_start']
# Get the current and reference test config. The reference test is the
# one performed at the current MCS+1
- ref_test_params = self.extract_test_id(testcase_params,
- ['channel', 'mode'])
+ ref_test_params = wputils.extract_sub_dict(
+ testcase_params, ['channel', 'mode', 'chain_mask'])
# Check if reference test has been run and set attenuation accordingly
previous_params = [
- self.extract_test_id(result['testcase_params'],
- ['channel', 'mode'])
+ wputils.extract_sub_dict(result['testcase_params'],
+ ['channel', 'mode', 'chain_mask'])
for result in self.testclass_results
]
try:
@@ -711,32 +825,32 @@
start_atten = self.testclass_params['range_atten_start']
return start_atten
- def generate_test_cases(self, ap_power, channels, modes, chamber_mode,
- positions):
+ def generate_test_cases(self, ap_power, channels, modes, chain_masks,
+ chamber_mode, positions):
test_cases = []
allowed_configs = {
20: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 64, 100,
- 116, 132, 140, 149, 153, 157, 161
+ 116, 132, 140, 149, 153, 157, 161, '6g37', '6g117', '6g213'
],
- 40: [36, 44, 100, 149, 157],
- 80: [36, 100, 149],
- 160: [36]
+ 40: [36, 44, 100, 149, 157, '6g37', '6g117', '6g213'],
+ 80: [36, 100, 149, '6g37', '6g117', '6g213'],
+ 160: [36, '6g37', '6g117', '6g213']
}
- for channel, mode, position in itertools.product(
- channels, modes, positions):
+ for channel, mode, chain_mask, position in itertools.product(
+ channels, modes, chain_masks, positions):
bandwidth = int(''.join([x for x in mode if x.isdigit()]))
if channel not in allowed_configs[bandwidth]:
continue
- testcase_name = 'test_ping_range_ch{}_{}_pos{}'.format(
- channel, mode, position)
+ testcase_name = 'test_ping_range_ch{}_{}_ch{}_pos{}'.format(
+ channel, mode, chain_mask, position)
testcase_params = collections.OrderedDict(
test_type='test_ping_range',
ap_power=ap_power,
channel=channel,
mode=mode,
bandwidth=bandwidth,
- chain_mask='2x2',
+ chain_mask=chain_mask,
chamber_mode=chamber_mode,
total_positions=len(positions),
position=position)
@@ -749,23 +863,29 @@
class WifiOtaPing_TenDegree_Test(WifiOtaPingTest):
def __init__(self, controllers):
WifiOtaPingTest.__init__(self, controllers)
- self.tests = self.generate_test_cases(ap_power='standard',
- channels=[6, 36, 149],
- modes=['bw20'],
- chamber_mode='orientation',
- positions=list(range(0, 360,
- 10)))
+ self.tests = self.generate_test_cases(
+ ap_power='standard',
+ channels=[6, 36, 149, '6g37', '6g117', '6g213'],
+ modes=['bw20'],
+ chain_masks=['2x2'],
+ chamber_mode='orientation',
+ positions=list(range(0, 360, 10)))
class WifiOtaPing_45Degree_Test(WifiOtaPingTest):
def __init__(self, controllers):
WifiOtaPingTest.__init__(self, controllers)
- self.tests = self.generate_test_cases(
- ap_power='standard',
- channels=[1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
- modes=['bw20'],
- chamber_mode='orientation',
- positions=list(range(0, 360, 45)))
+ self.tests = self.generate_test_cases(ap_power='standard',
+ channels=[
+ 1, 6, 11, 36, 40, 44, 48,
+ 149, 153, 157, 161, '6g37',
+ '6g117', '6g213'
+ ],
+ modes=['bw20'],
+ chain_masks=['2x2'],
+ chamber_mode='orientation',
+ positions=list(range(0, 360,
+ 45)))
class WifiOtaPing_SteppedStirrers_Test(WifiOtaPingTest):
@@ -774,6 +894,7 @@
self.tests = self.generate_test_cases(ap_power='standard',
channels=[6, 36, 149],
modes=['bw20'],
+ chain_masks=['2x2'],
chamber_mode='stepped stirrers',
positions=list(range(100)))
@@ -784,6 +905,7 @@
self.tests = self.generate_test_cases(ap_power='low_power',
channels=[6, 36, 149],
modes=['bw20'],
+ chain_masks=['2x2'],
chamber_mode='orientation',
positions=list(range(0, 360,
10)))
@@ -796,6 +918,7 @@
ap_power='low_power',
channels=[1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
modes=['bw20'],
+ chain_masks=['2x2'],
chamber_mode='orientation',
positions=list(range(0, 360, 45)))
@@ -806,5 +929,30 @@
self.tests = self.generate_test_cases(ap_power='low_power',
channels=[6, 36, 149],
modes=['bw20'],
+ chain_masks=['2x2'],
chamber_mode='stepped stirrers',
- positions=list(range(100)))
\ No newline at end of file
+ positions=list(range(100)))
+
+
+class WifiOtaPing_LowPowerAP_PerChain_TenDegree_Test(WifiOtaPingTest):
+ def __init__(self, controllers):
+ WifiOtaPingTest.__init__(self, controllers)
+ self.tests = self.generate_test_cases(ap_power='low_power',
+ channels=[6, 36, 149],
+ modes=['bw20'],
+ chain_masks=[0, 1, '2x2'],
+ chamber_mode='orientation',
+ positions=list(range(0, 360,
+ 10)))
+
+
+class WifiOtaPing_PerChain_TenDegree_Test(WifiOtaPingTest):
+ def __init__(self, controllers):
+ WifiOtaPingTest.__init__(self, controllers)
+ self.tests = self.generate_test_cases(
+ ap_power='standard',
+ channels=[6, 36, 149, '6g37', '6g117', '6g213'],
+ modes=['bw20'],
+ chain_masks=[0, 1, '2x2'],
+ chamber_mode='orientation',
+ positions=list(range(0, 360, 10)))
diff --git a/acts_tests/tests/google/wifi/WifiRoamingPerformanceTest.py b/acts_tests/tests/google/wifi/WifiRoamingPerformanceTest.py
index db42e2e..2c739c6 100644
--- a/acts_tests/tests/google/wifi/WifiRoamingPerformanceTest.py
+++ b/acts_tests/tests/google/wifi/WifiRoamingPerformanceTest.py
@@ -28,6 +28,7 @@
from acts.controllers.utils_lib import ssh
from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
from acts_contrib.test_utils.wifi import wifi_performance_test_utils as wputils
+from acts_contrib.test_utils.wifi.wifi_performance_test_utils.bokeh_figure import BokehFigure
from acts_contrib.test_utils.wifi import wifi_retail_ap as retail_ap
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
@@ -221,7 +222,7 @@
roam_stats = collections.OrderedDict()
current_context = context.get_current_context().get_full_output_path()
for secondary_atten, results_list in results_dict.items():
- figure = wputils.BokehFigure(title=self.current_test_name,
+ figure = BokehFigure(title=self.current_test_name,
x_label='Time (ms)',
primary_y_label=primary_y_axis,
secondary_y_label='RSSI (dBm)')
@@ -383,7 +384,7 @@
output_file_path: optional path to output file
"""
if not figure:
- figure = wputils.BokehFigure(title=self.current_test_name,
+ figure = BokehFigure(title=self.current_test_name,
x_label='Time (ms)',
primary_y_label='RTT (ms)',
secondary_y_label='RSSI (dBm)')
@@ -418,7 +419,7 @@
output_file_path: optional path to output file
"""
if not figure:
- figure = wputils.BokehFigure(title=self.current_test_name,
+ figure = BokehFigure(title=self.current_test_name,
x_label='Time (s)',
primary_y_label='Throughput (Mbps)',
secondary_y_label='RSSI (dBm)')
diff --git a/acts_tests/tests/google/wifi/WifiRoamingTest.py b/acts_tests/tests/google/wifi/WifiRoamingTest.py
index 2af178b..2da901c 100644
--- a/acts_tests/tests/google/wifi/WifiRoamingTest.py
+++ b/acts_tests/tests/google/wifi/WifiRoamingTest.py
@@ -276,7 +276,7 @@
"""
for ad in self.android_devices:
wutils.set_wifi_country_code(
- ad, wutils.WifiEnums.CountryCode.AUSTRALIA)
+ ad, wutils.WifiEnums.CountryCode.AUSTRALIA)
if "OpenWrtAP" in self.user_params:
self.configure_openwrt_ap_and_start(open_network=True,
ap_count=2,
@@ -292,9 +292,9 @@
# start softap on 2G and verify the channel is 6.
sap_config = {
- WifiEnums.SSID_KEY: "hotspot_%s" % utils.rand_ascii_str(6),
- WifiEnums.PWD_KEY: "pass_%s" % utils.rand_ascii_str(6),
- WifiEnums.AP_BAND_KEY: WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G}
+ WifiEnums.SSID_KEY: "hotspot_%s" % utils.rand_ascii_str(6),
+ WifiEnums.PWD_KEY: "pass_%s" % utils.rand_ascii_str(6),
+ WifiEnums.AP_BAND_KEY: WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G}
asserts.assert_true(
self.dut.droid.wifiSetWifiApConfiguration(sap_config),
"Failed to set WifiAp Configuration")
@@ -678,7 +678,7 @@
# Configure AP1 to enable capable PMF.
self.configure_openwrt_ap_and_start(wpa_network=True,
- ieee80211w=1)
+ ieee80211w=1)
ap1_network = self.reference_networks[0]["5g"]
ap1_network["bssid"] = self.bssid_map[0]["5g"][ap1_network["SSID"]]
@@ -1047,15 +1047,16 @@
self.roaming_from_AP1_and_AP2(ap1_network, ap2_network)
@test_tracker_info(uuid="e875233f-d242-4ddd-b357-8e3e215af050")
- def test_roaming_fail_between_psk_to_sae_5g(self):
+ def test_roaming_between_psk_to_sae_5g(self):
"""Verify fail with diff security type after roaming with OpenWrtAP
+ This test will pass after design change but this is not seamless roaming.
Steps:
1. Configure 2 APs security type to sae
2. Configure AP1 security type to psk
3. Connect DUT to AP1
4. Roam to AP2
- 5. Verify the DUT can't connect to AP2 after roaming
+ 5. Verify the DUT connect to AP2 after roaming
"""
# Use OpenWrt as Wi-Fi AP when it's available in testbed.
asserts.skip_if("OpenWrtAP" not in self.user_params, "OpenWrtAP not in user_params")
@@ -1081,15 +1082,10 @@
ap2_network["SSID"] = ap1_network["SSID"]
ap2_network["password"] = ap1_network["password"]
- try:
- # DUT roaming from AP1 to AP2 with diff security type.
- self.dut.log.info("Roaming via WPA2 AP1 to SAE AP2 [{}]"
- .format(ap2_network["bssid"]))
- self.roaming_from_AP1_and_AP2(ap1_network, ap2_network)
- except:
- self.dut.log.info("Failed roaming to AP2 with diff security type")
- else:
- raise signals.TestFailure("DUT unexpectedly connect to Wi-Fi.")
+ # DUT roaming from AP1 to AP2 with diff security type.
+ # Expect device disconnect from AP1 and connect to AP2 due to
+ # saved network contain AP2.
+ self.roaming_from_AP1_and_AP2(ap1_network, ap2_network)
@test_tracker_info(uuid="76098016-56a4-4b92-8c13-7333a21c9a1b")
def test_roaming_between_psk_to_saemixed_2g(self):
diff --git a/acts_tests/tests/google/wifi/WifiRssiTest.py b/acts_tests/tests/google/wifi/WifiRssiTest.py
index 1c0c6df..06eed43 100644
--- a/acts_tests/tests/google/wifi/WifiRssiTest.py
+++ b/acts_tests/tests/google/wifi/WifiRssiTest.py
@@ -31,6 +31,7 @@
from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
from acts_contrib.test_utils.wifi import ota_chamber
from acts_contrib.test_utils.wifi import wifi_performance_test_utils as wputils
+from acts_contrib.test_utils.wifi.wifi_performance_test_utils.bokeh_figure import BokehFigure
from acts_contrib.test_utils.wifi import wifi_retail_ap as retail_ap
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from concurrent.futures import ThreadPoolExecutor
@@ -90,6 +91,13 @@
def teardown_test(self):
self.iperf_server.stop()
+ def teardown_class(self):
+ # Turn WiFi OFF and reset AP
+ self.access_point.teardown()
+ for dev in self.android_devices:
+ wutils.wifi_toggle_state(dev, False)
+ dev.go_to_sleep()
+
def pass_fail_check_rssi_stability(self, testcase_params,
postprocessed_results):
"""Check the test result and decide if it passed or failed.
@@ -220,7 +228,9 @@
# Save output as text file
results_file_path = os.path.join(self.log_path, self.current_test_name)
with open(results_file_path, 'w') as results_file:
- json.dump(rssi_result, results_file, indent=4)
+ json.dump(wputils.serialize_dict(rssi_result),
+ results_file,
+ indent=4)
# Compile results into arrays of RSSIs suitable for plotting
# yapf: disable
postprocessed_results = collections.OrderedDict(
@@ -291,9 +301,9 @@
Args:
postprocessed_results: compiled arrays of RSSI data.
"""
- figure = wputils.BokehFigure(self.current_test_name,
- x_label='Attenuation (dB)',
- primary_y_label='RSSI (dBm)')
+ figure = BokehFigure(self.current_test_name,
+ x_label='Attenuation (dB)',
+ primary_y_label='RSSI (dBm)')
figure.add_line(postprocessed_results['total_attenuation'],
postprocessed_results['signal_poll_rssi']['mean'],
'Signal Poll RSSI',
@@ -329,7 +339,7 @@
center_curvers: boolean indicating whether to shift curves to align
them with predicted RSSIs
"""
- figure = wputils.BokehFigure(
+ figure = BokehFigure(
self.current_test_name,
x_label='Time (s)',
primary_y_label=center_curves * 'Centered' + 'RSSI (dBm)',
@@ -405,10 +415,10 @@
cum_prob += prob
rssi_dist[rssi_key]['rssi_cdf'].append(cum_prob)
- figure = wputils.BokehFigure(self.current_test_name,
- x_label='RSSI (dBm)',
- primary_y_label='p(RSSI = x)',
- secondary_y_label='p(RSSI <= x)')
+ figure = BokehFigure(self.current_test_name,
+ x_label='RSSI (dBm)',
+ primary_y_label='p(RSSI = x)',
+ secondary_y_label='p(RSSI <= x)')
for rssi_key, rssi_data in rssi_dist.items():
figure.add_line(x_data=rssi_data['rssi_values'],
y_data=rssi_data['rssi_pdf'],
@@ -522,12 +532,18 @@
Args:
testcase_params: dict containing test-specific parameters
"""
- if '2G' in testcase_params['band']:
- frequency = wutils.WifiEnums.channel_2G_to_freq[
- testcase_params['channel']]
+ band = self.access_point.band_lookup_by_channel(
+ testcase_params['channel'])
+ if '6G' in band:
+ frequency = wutils.WifiEnums.channel_6G_to_freq[int(
+ testcase_params['channel'].strip('6g'))]
else:
- frequency = wutils.WifiEnums.channel_5G_to_freq[
- testcase_params['channel']]
+ if testcase_params['channel'] < 13:
+ frequency = wutils.WifiEnums.channel_2G_to_freq[
+ testcase_params['channel']]
+ else:
+ frequency = wutils.WifiEnums.channel_5G_to_freq[
+ testcase_params['channel']]
if frequency in wutils.WifiEnums.DFS_5G_FREQUENCIES:
self.access_point.set_region(self.testbed_params['DFS_region'])
else:
@@ -541,11 +557,13 @@
def setup_dut(self, testcase_params):
"""Sets up the DUT in the configuration required by the test."""
- # Check battery level before test
- if not wputils.health_check(self.dut, 10):
- asserts.skip('Battery level too low. Skipping test.')
# Turn screen off to preserve battery
- self.dut.go_to_sleep()
+ if self.testbed_params.get('screen_on',
+ False) or self.testclass_params.get(
+ 'screen_on', False):
+ self.dut.droid.wakeLockAcquireDim()
+ else:
+ self.dut.go_to_sleep()
if wputils.validate_network(self.dut,
testcase_params['test_network']['SSID']):
self.log.info('Already connected to desired network')
@@ -556,6 +574,8 @@
'channel'] = testcase_params['channel']
wutils.set_wifi_country_code(self.dut,
self.testclass_params['country_code'])
+ if self.testbed_params.get('txbf_off', False):
+ wputils.disable_beamforming(self.dut)
wutils.wifi_connect(self.dut,
self.main_network[testcase_params['band']],
num_of_tries=5)
@@ -603,6 +623,11 @@
Args:
testcase_params: dict containing test-specific parameters
"""
+ # Check if test should be skipped.
+ wputils.check_skip_conditions(testcase_params, self.dut,
+ self.access_point,
+ getattr(self, 'ota_chamber', None))
+
testcase_params.update(
connected_measurements=self.
testclass_params['rssi_vs_atten_connected_measurements'],
@@ -621,14 +646,11 @@
'BSSID', '00:00:00:00')
]
- num_atten_steps = int((self.testclass_params['rssi_vs_atten_stop'] -
- self.testclass_params['rssi_vs_atten_start']) /
- self.testclass_params['rssi_vs_atten_step'])
- testcase_params['rssi_atten_range'] = [
- self.testclass_params['rssi_vs_atten_start'] +
- x * self.testclass_params['rssi_vs_atten_step']
- for x in range(0, num_atten_steps)
- ]
+ testcase_params['rssi_atten_range'] = numpy.arange(
+ self.testclass_params['rssi_vs_atten_start'],
+ self.testclass_params['rssi_vs_atten_stop'],
+ self.testclass_params['rssi_vs_atten_step']).tolist()
+
testcase_params['traffic_timeout'] = self.get_traffic_timeout(
testcase_params)
@@ -646,6 +668,10 @@
Args:
testcase_params: dict containing test-specific parameters
"""
+ # Check if test should be skipped.
+ wputils.check_skip_conditions(testcase_params, self.dut,
+ self.access_point,
+ getattr(self, 'ota_chamber', None))
testcase_params.update(
connected_measurements=int(
self.testclass_params['rssi_stability_duration'] /
@@ -678,6 +704,11 @@
Args:
testcase_params: dict containing test-specific parameters
"""
+ # Check if test should be skipped.
+ wputils.check_skip_conditions(testcase_params, self.dut,
+ self.access_point,
+ getattr(self, 'ota_chamber', None))
+
testcase_params.update(connected_measurements=int(
1 / self.testclass_params['polling_frequency']),
scan_measurements=0,
@@ -787,11 +818,11 @@
allowed_configs = {
20: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 64, 100,
- 116, 132, 140, 149, 153, 157, 161
+ 116, 132, 140, 149, 153, 157, 161, '6g37', '6g117', '6g213'
],
- 40: [36, 44, 100, 149, 157],
- 80: [36, 100, 149],
- 160: [36]
+ 40: [36, 44, 100, 149, 157, '6g37', '6g117', '6g213'],
+ 80: [36, 100, 149, '6g37', '6g117', '6g213'],
+ 160: [36, '6g37', '6g117', '6g213']
}
for channel, mode, traffic_mode, test_type in itertools.product(
@@ -835,9 +866,10 @@
def __init__(self, controllers):
super().__init__(controllers)
self.tests = self.generate_test_cases(
- ['test_rssi_stability', 'test_rssi_vs_atten'],
- [1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
- ['bw20', 'bw40', 'bw80'], ['ActiveTraffic'])
+ ['test_rssi_stability', 'test_rssi_vs_atten'], [
+ 1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161, '6g37', '6g117',
+ '6g213'
+ ], ['bw20', 'bw40', 'bw80', 'bw160'], ['ActiveTraffic'])
class WifiRssi_SampleChannels_NoTraffic_Test(WifiRssiTest):
@@ -879,6 +911,7 @@
self.user_params['OTAChamber'])[0]
def teardown_class(self):
+ WifiRssiTest.teardown_class(self)
self.ota_chamber.reset_chamber()
self.process_testclass_results()
@@ -937,7 +970,7 @@
return
plots = []
for channel, channel_data in testclass_data.items():
- current_plot = wputils.BokehFigure(
+ current_plot = BokehFigure(
title='Channel {} - Rssi vs. Position'.format(channel),
x_label=x_label,
primary_y_label='RSSI (dBm)',
@@ -950,7 +983,7 @@
plots.append(current_plot)
current_context = context.get_current_context().get_full_output_path()
plot_file_path = os.path.join(current_context, 'results.html')
- wputils.BokehFigure.save_figures(plots, plot_file_path)
+ BokehFigure.save_figures(plots, plot_file_path)
def setup_rssi_test(self, testcase_params):
# Test setup
@@ -966,22 +999,36 @@
Args:
testcase_params: dict containing test-specific parameters
"""
+ # Check if test should be skipped.
+ wputils.check_skip_conditions(testcase_params, self.dut,
+ self.access_point,
+ getattr(self, 'ota_chamber', None))
+
if 'rssi_over_orientation' in self.test_name:
rssi_test_duration = self.testclass_params[
'rssi_over_orientation_duration']
+ rssi_ota_test_attenuation = [
+ self.testclass_params['rssi_ota_test_attenuation']
+ ]
elif 'rssi_variation' in self.test_name:
rssi_test_duration = self.testclass_params[
'rssi_variation_duration']
-
- testcase_params.update(
- connected_measurements=int(
- rssi_test_duration /
- self.testclass_params['polling_frequency']),
- scan_measurements=0,
- first_measurement_delay=MED_SLEEP,
- rssi_atten_range=[
+ rssi_ota_test_attenuation = [
self.testclass_params['rssi_ota_test_attenuation']
- ])
+ ]
+ elif 'rssi_vs_atten' in self.test_name:
+ rssi_test_duration = self.testclass_params[
+ 'rssi_over_orientation_duration']
+ rssi_ota_test_attenuation = numpy.arange(
+ self.testclass_params['rssi_vs_atten_start'],
+ self.testclass_params['rssi_vs_atten_stop'],
+ self.testclass_params['rssi_vs_atten_step']).tolist()
+
+ testcase_params.update(connected_measurements=int(
+ rssi_test_duration / self.testclass_params['polling_frequency']),
+ scan_measurements=0,
+ first_measurement_delay=MED_SLEEP,
+ rssi_atten_range=rssi_ota_test_attenuation)
testcase_params['band'] = self.access_point.band_lookup_by_channel(
testcase_params['channel'])
testcase_params['test_network'] = self.main_network[
@@ -1011,7 +1058,10 @@
self.testclass_results.append(rssi_result)
self.plot_rssi_vs_time(rssi_result,
rssi_result['postprocessed_results'], 1)
- self.plot_rssi_distribution(rssi_result['postprocessed_results'])
+ if 'rssi_vs_atten' in self.test_name:
+ self.plot_rssi_vs_attenuation(rssi_result['postprocessed_results'])
+ elif 'rssi_variation' in self.test_name:
+ self.plot_rssi_distribution(rssi_result['postprocessed_results'])
def generate_test_cases(self, test_types, channels, modes, traffic_modes,
chamber_modes, orientations):
@@ -1019,11 +1069,11 @@
allowed_configs = {
20: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 64, 100,
- 116, 132, 140, 149, 153, 157, 161
+ 116, 132, 140, 149, 153, 157, 161, '6g37', '6g117', '6g213'
],
- 40: [36, 44, 100, 149, 157],
- 80: [36, 100, 149],
- 160: [36]
+ 40: [36, 44, 100, 149, 157, '6g37', '6g117', '6g213'],
+ 80: [36, 100, 149, '6g37', '6g117', '6g213'],
+ 160: [36, '6g37', '6g117', '6g213']
}
for (channel, mode, traffic, chamber_mode, orientation,
@@ -1053,7 +1103,7 @@
def __init__(self, controllers):
super().__init__(controllers)
self.tests = self.generate_test_cases(['test_rssi_vs_atten'],
- [6, 36, 149], ['bw20'],
+ [6, 36, 149, '6g37'], ['bw20'],
['ActiveTraffic'],
['orientation'],
list(range(0, 360, 45)))
@@ -1063,7 +1113,7 @@
def __init__(self, controllers):
WifiRssiTest.__init__(self, controllers)
self.tests = self.generate_test_cases(['test_rssi_variation'],
- [6, 36, 149], ['bw20'],
+ [6, 36, 149, '6g37'], ['bw20'],
['ActiveTraffic'],
['StirrersOn'], [0])
@@ -1072,7 +1122,7 @@
def __init__(self, controllers):
WifiRssiTest.__init__(self, controllers)
self.tests = self.generate_test_cases(['test_rssi_over_orientation'],
- [6, 36, 149], ['bw20'],
+ [6, 36, 149, '6g37'], ['bw20'],
['ActiveTraffic'],
['orientation'],
list(range(0, 360, 10)))
diff --git a/acts_tests/tests/google/wifi/WifiRvrTest.py b/acts_tests/tests/google/wifi/WifiRvrTest.py
index 7131d80..ffa52d5 100644
--- a/acts_tests/tests/google/wifi/WifiRvrTest.py
+++ b/acts_tests/tests/google/wifi/WifiRvrTest.py
@@ -30,6 +30,7 @@
from acts_contrib.test_utils.wifi import ota_chamber
from acts_contrib.test_utils.wifi import ota_sniffer
from acts_contrib.test_utils.wifi import wifi_performance_test_utils as wputils
+from acts_contrib.test_utils.wifi.wifi_performance_test_utils.bokeh_figure import BokehFigure
from acts_contrib.test_utils.wifi import wifi_retail_ap as retail_ap
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from functools import partial
@@ -62,6 +63,7 @@
This function initializes hardwares and compiles parameters that are
common to all tests in this class.
"""
+ self.sta_dut = self.android_devices[0]
req_params = [
'RetailAccessPoints', 'rvr_test_params', 'testbed_params',
'RemoteServer', 'main_network'
@@ -77,7 +79,11 @@
self.access_point = retail_ap.create(self.RetailAccessPoints)[0]
if hasattr(self,
'OTASniffer') and self.testbed_params['sniffer_enable']:
- self.sniffer = ota_sniffer.create(self.OTASniffer)[0]
+ try:
+ self.sniffer = ota_sniffer.create(self.OTASniffer)[0]
+ except:
+ self.log.warning('Could not start sniffer. Disabling sniffs.')
+ self.testbed_params['sniffer_enable'] = 0
self.log.info('Access Point Configuration: {}'.format(
self.access_point.ap_settings))
self.log_path = os.path.join(logging.log_path, 'results')
@@ -100,15 +106,18 @@
self.log.info('Turning on airplane mode.')
asserts.assert_true(utils.force_airplane_mode(dev, True),
'Can not turn on airplane mode.')
- wutils.wifi_toggle_state(dev, True)
+ wutils.reset_wifi(dev)
+ wutils.wifi_toggle_state(dev, True)
def teardown_test(self):
self.iperf_server.stop()
def teardown_class(self):
# Turn WiFi OFF
+ self.access_point.teardown()
for dev in self.android_devices:
wutils.wifi_toggle_state(dev, False)
+ dev.go_to_sleep()
self.process_testclass_results()
def process_testclass_results(self):
@@ -119,7 +128,7 @@
plot_id = (result['testcase_params']['channel'],
result['testcase_params']['mode'])
if plot_id not in plots:
- plots[plot_id] = wputils.BokehFigure(
+ plots[plot_id] = BokehFigure(
title='Channel {} {} ({})'.format(
result['testcase_params']['channel'],
result['testcase_params']['mode'],
@@ -129,13 +138,20 @@
plots[plot_id].add_line(result['total_attenuation'],
result['throughput_receive'],
result['test_name'],
+ hover_text=result['hover_text'],
marker='circle')
+ plots[plot_id].add_line(result['total_attenuation'],
+ result['avg_phy_rate'],
+ result['test_name'] + ' (PHY)',
+ hover_text=result['hover_text'],
+ marker='circle')
+
figure_list = []
for plot_id, plot in plots.items():
plot.generate_figure()
figure_list.append(plot)
output_file_path = os.path.join(self.log_path, 'results.html')
- wputils.BokehFigure.save_figures(figure_list, output_file_path)
+ BokehFigure.save_figures(figure_list, output_file_path)
def pass_fail_check(self, rvr_result):
"""Check the test result and decide if it passed or failed.
@@ -242,19 +258,20 @@
data
"""
# Save output as text file
- test_name = self.current_test_name
results_file_path = os.path.join(
self.log_path, '{}.json'.format(self.current_test_name))
with open(results_file_path, 'w') as results_file:
- json.dump(rvr_result, results_file, indent=4)
+ json.dump(wputils.serialize_dict(rvr_result),
+ results_file,
+ indent=4)
# Plot and save
- figure = wputils.BokehFigure(title=test_name,
- x_label='Attenuation (dB)',
- primary_y_label='Throughput (Mbps)')
+ figure = BokehFigure(title=self.current_test_name,
+ x_label='Attenuation (dB)',
+ primary_y_label='Throughput (Mbps)')
try:
golden_path = next(file_name
for file_name in self.golden_files_list
- if test_name in file_name)
+ if self.current_test_name in file_name)
with open(golden_path, 'r') as golden_file:
golden_results = json.load(golden_file)
golden_attenuation = [
@@ -277,23 +294,52 @@
self.log.warning('ValueError: Golden file not found')
# Generate graph annotatios
- hover_text = [
- 'TX MCS = {0} ({1:.1f}%). RX MCS = {2} ({3:.1f}%)'.format(
- curr_llstats['summary']['common_tx_mcs'],
- curr_llstats['summary']['common_tx_mcs_freq'] * 100,
- curr_llstats['summary']['common_rx_mcs'],
- curr_llstats['summary']['common_rx_mcs_freq'] * 100)
- for curr_llstats in rvr_result['llstats']
- ]
+ rvr_result['hover_text'] = {
+ 'llstats': [
+ 'TX MCS = {0} ({1:.1f}%). RX MCS = {2} ({3:.1f}%)'.format(
+ curr_llstats['summary']['common_tx_mcs'],
+ curr_llstats['summary']['common_tx_mcs_freq'] * 100,
+ curr_llstats['summary']['common_rx_mcs'],
+ curr_llstats['summary']['common_rx_mcs_freq'] * 100)
+ for curr_llstats in rvr_result['llstats']
+ ],
+ 'rssi': [
+ '{0:.2f} [{1:.2f},{2:.2f}]'.format(
+ rssi['signal_poll_rssi'],
+ rssi['chain_0_rssi'],
+ rssi['chain_1_rssi'],
+ ) for rssi in rvr_result['rssi']
+ ]
+ }
+ if 'DL' in self.current_test_name:
+ rvr_result['avg_phy_rate'] = [
+ curr_llstats['summary'].get('mean_rx_phy_rate', 0)
+ for curr_llstats in rvr_result['llstats']
+ ]
+ else:
+ rvr_result['avg_phy_rate'] = [
+ curr_llstats['summary'].get('mean_tx_phy_rate', 0)
+ for curr_llstats in rvr_result['llstats']
+ ]
figure.add_line(rvr_result['total_attenuation'],
rvr_result['throughput_receive'],
- 'Test Results',
- hover_text=hover_text,
+ 'Measured Throughput',
+ hover_text=rvr_result['hover_text'],
color='red',
marker='circle')
+ rvr_result['avg_phy_rate'].extend(
+ [0] * (len(rvr_result['total_attenuation']) -
+ len(rvr_result['avg_phy_rate'])))
+ figure.add_line(rvr_result['total_attenuation'],
+ rvr_result['avg_phy_rate'],
+ 'Average PHY Rate',
+ hover_text=rvr_result['hover_text'],
+ color='red',
+ style='dashed',
+ marker='square')
- output_file_path = os.path.join(self.log_path,
- '{}.html'.format(test_name))
+ output_file_path = os.path.join(
+ self.log_path, '{}.html'.format(self.current_test_name))
figure.generate_figure(output_file_path)
def compute_test_metrics(self, rvr_result):
@@ -373,14 +419,14 @@
asserts.skip('DUT health check failed. Skipping test.')
# Set Attenuation
for attenuator in self.attenuators:
- attenuator.set_atten(atten, strict=False)
+ attenuator.set_atten(atten, strict=False, retry=True)
# Refresh link layer stats
llstats_obj.update_stats()
# Setup sniffer
if self.testbed_params['sniffer_enable']:
self.sniffer.start_capture(
network=testcase_params['test_network'],
- chan=int(testcase_params['channel']),
+ chan=testcase_params['channel'],
bw=testcase_params['bandwidth'],
duration=self.testclass_params['iperf_duration'] / 5)
# Start iperf session
@@ -439,9 +485,7 @@
atten, curr_throughput, current_rssi['signal_poll_rssi'],
current_rssi['chain_0_rssi'],
current_rssi['chain_1_rssi']))
- if curr_throughput == 0 and (
- current_rssi['signal_poll_rssi'] < -80
- or numpy.isnan(current_rssi['signal_poll_rssi'])):
+ if curr_throughput == 0:
zero_counter = zero_counter + 1
else:
zero_counter = 0
@@ -453,7 +497,7 @@
(len(testcase_params['atten_range']) - len(throughput)))
break
for attenuator in self.attenuators:
- attenuator.set_atten(0, strict=False)
+ attenuator.set_atten(0, strict=False, retry=True)
# Compile test result and meta data
rvr_result = collections.OrderedDict()
rvr_result['test_name'] = self.current_test_name
@@ -477,20 +521,25 @@
Args:
testcase_params: dict containing AP and other test params
"""
- if '2G' in testcase_params['band']:
- frequency = wutils.WifiEnums.channel_2G_to_freq[
- testcase_params['channel']]
+ band = self.access_point.band_lookup_by_channel(
+ testcase_params['channel'])
+ if '6G' in band:
+ frequency = wutils.WifiEnums.channel_6G_to_freq[int(
+ testcase_params['channel'].strip('6g'))]
else:
- frequency = wutils.WifiEnums.channel_5G_to_freq[
- testcase_params['channel']]
+ if testcase_params['channel'] < 13:
+ frequency = wutils.WifiEnums.channel_2G_to_freq[
+ testcase_params['channel']]
+ else:
+ frequency = wutils.WifiEnums.channel_5G_to_freq[
+ testcase_params['channel']]
if frequency in wutils.WifiEnums.DFS_5G_FREQUENCIES:
self.access_point.set_region(self.testbed_params['DFS_region'])
else:
self.access_point.set_region(self.testbed_params['default_region'])
- self.access_point.set_channel(testcase_params['band'],
- testcase_params['channel'])
- self.access_point.set_bandwidth(testcase_params['band'],
- testcase_params['mode'])
+ self.access_point.set_channel_and_bandwidth(testcase_params['band'],
+ testcase_params['channel'],
+ testcase_params['mode'])
self.log.info('Access Point Configuration: {}'.format(
self.access_point.ap_settings))
@@ -500,19 +549,24 @@
Args:
testcase_params: dict containing AP and other test params
"""
- self.sta_dut = self.android_devices[0]
- # Check battery level before test
- if not wputils.health_check(
- self.sta_dut,
- 20) and testcase_params['traffic_direction'] == 'UL':
- asserts.skip('Overheating or Battery level low. Skipping test.')
# Turn screen off to preserve battery
- self.sta_dut.go_to_sleep()
+ if self.testbed_params.get('screen_on',
+ False) or self.testclass_params.get(
+ 'screen_on', False):
+ self.sta_dut.droid.wakeLockAcquireDim()
+ else:
+ self.sta_dut.go_to_sleep()
if wputils.validate_network(self.sta_dut,
testcase_params['test_network']['SSID']):
self.log.info('Already connected to desired network')
else:
+ wutils.wifi_toggle_state(self.sta_dut, False)
+ wutils.set_wifi_country_code(self.sta_dut,
+ self.testclass_params['country_code'])
+ wutils.wifi_toggle_state(self.sta_dut, True)
wutils.reset_wifi(self.sta_dut)
+ if self.testbed_params.get('txbf_off', False):
+ wputils.disable_beamforming(self.sta_dut)
wutils.set_wifi_country_code(self.sta_dut,
self.testclass_params['country_code'])
if self.testbed_params['sniffer_enable']:
@@ -526,6 +580,8 @@
testcase_params['test_network'],
num_of_tries=5,
check_connectivity=True)
+ if self.testclass_params.get('num_streams', 2) == 1:
+ wputils.set_nss_capability(self.sta_dut, 1)
finally:
if self.testbed_params['sniffer_enable']:
self.sniffer.stop_capture(tag='connection_setup')
@@ -540,7 +596,7 @@
self.setup_ap(testcase_params)
# Set attenuator to 0 dB
for attenuator in self.attenuators:
- attenuator.set_atten(0, strict=False)
+ attenuator.set_atten(0, strict=False, retry=True)
# Reset, configure, and connect DUT
self.setup_dut(testcase_params)
# Wait before running the first wifi test
@@ -565,7 +621,7 @@
self.remote_server, sta_dut_ip, 'public')
# Set DUT to monitor RSSI and LLStats on
self.monitored_dut = self.sta_dut
- self.monitored_interface = None
+ self.monitored_interface = 'wlan0'
def compile_test_params(self, testcase_params):
"""Function that completes all test params based on the test name.
@@ -573,12 +629,18 @@
Args:
testcase_params: dict containing test-specific parameters
"""
- num_atten_steps = int((self.testclass_params['atten_stop'] -
- self.testclass_params['atten_start']) /
- self.testclass_params['atten_step'])
+ # Check if test should be skipped based on parameters.
+ wputils.check_skip_conditions(testcase_params, self.sta_dut,
+ self.access_point,
+ getattr(self, 'ota_chamber', None))
+
+ band = wputils.CHANNEL_TO_BAND_MAP[testcase_params['channel']]
+ start_atten = self.testclass_params['atten_start'].get(band, 0)
+ num_atten_steps = int(
+ (self.testclass_params['atten_stop'] - start_atten) /
+ self.testclass_params['atten_step'])
testcase_params['atten_range'] = [
- self.testclass_params['atten_start'] +
- x * self.testclass_params['atten_step']
+ start_atten + x * self.testclass_params['atten_step']
for x in range(0, num_atten_steps)
]
band = self.access_point.band_lookup_by_channel(
@@ -645,11 +707,11 @@
allowed_configs = {
20: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 64, 100,
- 116, 132, 140, 149, 153, 157, 161
+ 116, 132, 140, 149, 153, 157, 161, '6g37', '6g117', '6g213'
],
- 40: [36, 44, 100, 149, 157],
- 80: [36, 100, 149],
- 160: [36]
+ 40: [36, 44, 100, 149, 157, '6g37', '6g117', '6g213'],
+ 80: [36, 100, 149, '6g37', '6g117', '6g213'],
+ 160: [36, '6g37', '6g117', '6g213']
}
for channel, mode, traffic_type, traffic_direction in itertools.product(
@@ -674,7 +736,10 @@
def __init__(self, controllers):
super().__init__(controllers)
self.tests = self.generate_test_cases(
- channels=[1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
+ channels=[
+ 1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161, '6g37', '6g117',
+ '6g213'
+ ],
modes=['bw20', 'bw40', 'bw80', 'bw160'],
traffic_types=['TCP'],
traffic_directions=['DL', 'UL'])
@@ -694,7 +759,10 @@
def __init__(self, controllers):
super().__init__(controllers)
self.tests = self.generate_test_cases(
- channels=[1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
+ channels=[
+ 1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161, '6g37', '6g117',
+ '6g213'
+ ],
modes=['HE20', 'HE40', 'HE80', 'HE160'],
traffic_types=['TCP'],
traffic_directions=['DL', 'UL'])
@@ -704,7 +772,7 @@
def __init__(self, controllers):
super().__init__(controllers)
self.tests = self.generate_test_cases(
- channels=[6, 36, 149],
+ channels=[6, 36, 149, '6g37'],
modes=['bw20', 'bw40', 'bw80', 'bw160'],
traffic_types=['UDP'],
traffic_directions=['DL', 'UL'])
@@ -725,7 +793,7 @@
super().__init__(controllers)
self.tests = self.generate_test_cases(
channels=[6, 36, 149],
- modes=['HE20', 'HE40', 'HE80', 'HE160'],
+ modes=['HE20', 'HE40', 'HE80', 'HE160', '6g37'],
traffic_types=['UDP'],
traffic_directions=['DL', 'UL'])
@@ -740,6 +808,57 @@
traffic_directions=['DL', 'UL'])
+class WifiRvr_SingleChain_TCP_Test(WifiRvrTest):
+ def __init__(self, controllers):
+ super().__init__(controllers)
+ self.tests = self.generate_test_cases(
+ channels=[
+ 1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161, '6g37', '6g117',
+ '6g213'
+ ],
+ modes=['bw20', 'bw40', 'bw80', 'bw160'],
+ traffic_types=['TCP'],
+ traffic_directions=['DL', 'UL'],
+ chains=[0, 1, '2x2'])
+
+ def setup_dut(self, testcase_params):
+ self.sta_dut = self.android_devices[0]
+ wputils.set_chain_mask(self.sta_dut, testcase_params['chain'])
+ WifiRvrTest.setup_dut(self, testcase_params)
+
+ def generate_test_cases(self, channels, modes, traffic_types,
+ traffic_directions, chains):
+ """Function that auto-generates test cases for a test class."""
+ test_cases = []
+ allowed_configs = {
+ 20: [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 64, 100,
+ 116, 132, 140, 149, 153, 157, 161, '6g37', '6g117', '6g213'
+ ],
+ 40: [36, 44, 100, 149, 157, '6g37', '6g117', '6g213'],
+ 80: [36, 100, 149, '6g37', '6g117', '6g213'],
+ 160: [36, '6g37', '6g117', '6g213']
+ }
+
+ for channel, mode, chain, traffic_type, traffic_direction in itertools.product(
+ channels, modes, chains, traffic_types, traffic_directions):
+ bandwidth = int(''.join([x for x in mode if x.isdigit()]))
+ if channel not in allowed_configs[bandwidth]:
+ continue
+ test_name = 'test_rvr_{}_{}_ch{}_{}_ch{}'.format(
+ traffic_type, traffic_direction, channel, mode, chain)
+ test_params = collections.OrderedDict(
+ channel=channel,
+ mode=mode,
+ bandwidth=bandwidth,
+ traffic_type=traffic_type,
+ traffic_direction=traffic_direction,
+ chain=chain)
+ setattr(self, test_name, partial(self._test_rvr, test_params))
+ test_cases.append(test_name)
+ return test_cases
+
+
# Over-the air version of RVR tests
class WifiOtaRvrTest(WifiRvrTest):
"""Class to test over-the-air RvR
@@ -767,7 +886,7 @@
def extract_test_id(self, testcase_params, id_fields):
test_id = collections.OrderedDict(
- (param, testcase_params[param]) for param in id_fields)
+ (param, testcase_params.get(param, None)) for param in id_fields)
return test_id
def process_testclass_results(self):
@@ -777,10 +896,10 @@
compiled_data = collections.OrderedDict()
for result in self.testclass_results:
test_id = tuple(
- self.extract_test_id(
- result['testcase_params'],
- ['channel', 'mode', 'traffic_type', 'traffic_direction'
- ]).items())
+ self.extract_test_id(result['testcase_params'], [
+ 'channel', 'mode', 'traffic_type', 'traffic_direction',
+ 'chain'
+ ]).items())
if test_id not in plots:
# Initialize test id data when not present
compiled_data[test_id] = {'throughput': [], 'metrics': {}}
@@ -788,7 +907,7 @@
key: []
for key in result['metrics'].keys()
}
- plots[test_id] = wputils.BokehFigure(
+ plots[test_id] = BokehFigure(
title='Channel {} {} ({} {})'.format(
result['testcase_params']['channel'],
result['testcase_params']['mode'],
@@ -796,6 +915,15 @@
result['testcase_params']['traffic_direction']),
x_label='Attenuation (dB)',
primary_y_label='Throughput (Mbps)')
+ test_id_phy = test_id + tuple('PHY')
+ plots[test_id_phy] = BokehFigure(
+ title='Channel {} {} ({} {}) (PHY Rate)'.format(
+ result['testcase_params']['channel'],
+ result['testcase_params']['mode'],
+ result['testcase_params']['traffic_type'],
+ result['testcase_params']['traffic_direction']),
+ x_label='Attenuation (dB)',
+ primary_y_label='PHY Rate (Mbps)')
# Compile test id data and metrics
compiled_data[test_id]['throughput'].append(
result['throughput_receive'])
@@ -808,11 +936,19 @@
plots[test_id].add_line(result['total_attenuation'],
result['throughput_receive'],
result['test_name'],
+ hover_text=result['hover_text'],
width=1,
style='dashed',
marker='circle')
+ plots[test_id_phy].add_line(result['total_attenuation'],
+ result['avg_phy_rate'],
+ result['test_name'] + ' PHY',
+ hover_text=result['hover_text'],
+ width=1,
+ style='dashed',
+ marker='circle')
- # Compute average RvRs and compount metrics over orientations
+ # Compute average RvRs and compute metrics over orientations
for test_id, test_data in compiled_data.items():
test_id_dict = dict(test_id)
metric_tag = '{}_{}_ch{}_{}'.format(
@@ -840,17 +976,17 @@
marker='square')
figure_list = []
- for test_id, plot in plots.items():
+ for plot_id, plot in plots.items():
plot.generate_figure()
figure_list.append(plot)
output_file_path = os.path.join(self.log_path, 'results.html')
- wputils.BokehFigure.save_figures(figure_list, output_file_path)
+ BokehFigure.save_figures(figure_list, output_file_path)
def setup_rvr_test(self, testcase_params):
- # Set turntable orientation
- self.ota_chamber.set_orientation(testcase_params['orientation'])
# Continue test setup
WifiRvrTest.setup_rvr_test(self, testcase_params)
+ # Set turntable orientation
+ self.ota_chamber.set_orientation(testcase_params['orientation'])
def generate_test_cases(self, channels, modes, angles, traffic_types,
directions):
@@ -862,7 +998,7 @@
],
40: [36, 44, 100, 149, 157],
80: [36, 100, 149],
- 160: [36]
+ 160: [36, '6g37', '6g117', '6g213']
}
for channel, mode, angle, traffic_type, direction in itertools.product(
channels, modes, angles, traffic_types, directions):
@@ -886,8 +1022,9 @@
def __init__(self, controllers):
WifiOtaRvrTest.__init__(self, controllers)
self.tests = self.generate_test_cases(
- [1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
- ['bw20', 'bw40', 'bw80'], list(range(0, 360, 45)), ['TCP'], ['DL'])
+ [1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161, '6g37'],
+ ['bw20', 'bw40', 'bw80', 'bw160'], list(range(0, 360, 45)),
+ ['TCP'], ['DL', 'UL'])
class WifiOtaRvr_SampleChannel_Test(WifiOtaRvrTest):
@@ -897,7 +1034,10 @@
list(range(0, 360, 45)), ['TCP'],
['DL'])
self.tests.extend(
- self.generate_test_cases([36, 149], ['bw80'],
+ self.generate_test_cases([36, 149], ['bw80', 'bw160'],
+ list(range(0, 360, 45)), ['TCP'], ['DL']))
+ self.tests.extend(
+ self.generate_test_cases(['6g37'], ['bw160'],
list(range(0, 360, 45)), ['TCP'], ['DL']))
@@ -905,5 +1045,56 @@
def __init__(self, controllers):
WifiOtaRvrTest.__init__(self, controllers)
self.tests = self.generate_test_cases(
- [6, 36, 40, 44, 48, 149, 153, 157, 161], ['bw20', 'bw40', 'bw80'],
- [0], ['TCP'], ['DL', 'UL'])
+ [6, 36, 40, 44, 48, 149, 153, 157, 161, '6g37'],
+ ['bw20', 'bw40', 'bw80', 'bw160'], [0], ['TCP'], ['DL', 'UL'])
+
+
+class WifiOtaRvr_SingleChain_Test(WifiOtaRvrTest):
+ def __init__(self, controllers):
+ WifiOtaRvrTest.__init__(self, controllers)
+ self.tests = self.generate_test_cases([6], ['bw20'],
+ list(range(0, 360, 45)), ['TCP'],
+ ['DL', 'UL'], [0, 1])
+ self.tests.extend(
+ self.generate_test_cases([36, 149], ['bw20', 'bw80', 'bw160'],
+ list(range(0, 360, 45)), ['TCP'],
+ ['DL', 'UL'], [0, 1, '2x2']))
+ self.tests.extend(
+ self.generate_test_cases(['6g37'], ['bw20', 'bw80', 'bw160'],
+ list(range(0, 360, 45)), ['TCP'],
+ ['DL', 'UL'], [0, 1, '2x2']))
+
+ def setup_dut(self, testcase_params):
+ self.sta_dut = self.android_devices[0]
+ wputils.set_chain_mask(self.sta_dut, testcase_params['chain'])
+ WifiRvrTest.setup_dut(self, testcase_params)
+
+ def generate_test_cases(self, channels, modes, angles, traffic_types,
+ directions, chains):
+ test_cases = []
+ allowed_configs = {
+ 20: [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 64, 100,
+ 116, 132, 140, 149, 153, 157, 161
+ ],
+ 40: [36, 44, 100, 149, 157],
+ 80: [36, 100, 149],
+ 160: [36, '6g37', '6g117', '6g213']
+ }
+ for channel, mode, chain, angle, traffic_type, direction in itertools.product(
+ channels, modes, chains, angles, traffic_types, directions):
+ bandwidth = int(''.join([x for x in mode if x.isdigit()]))
+ if channel not in allowed_configs[bandwidth]:
+ continue
+ testcase_name = 'test_rvr_{}_{}_ch{}_{}_ch{}_{}deg'.format(
+ traffic_type, direction, channel, mode, chain, angle)
+ test_params = collections.OrderedDict(channel=channel,
+ mode=mode,
+ bandwidth=bandwidth,
+ chain=chain,
+ traffic_type=traffic_type,
+ traffic_direction=direction,
+ orientation=angle)
+ setattr(self, testcase_name, partial(self._test_rvr, test_params))
+ test_cases.append(testcase_name)
+ return test_cases
diff --git a/acts_tests/tests/google/wifi/WifiSensitivityTest.py b/acts_tests/tests/google/wifi/WifiSensitivityTest.py
index b876ae9..954bc90 100644
--- a/acts_tests/tests/google/wifi/WifiSensitivityTest.py
+++ b/acts_tests/tests/google/wifi/WifiSensitivityTest.py
@@ -29,8 +29,10 @@
from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
from acts_contrib.test_utils.wifi import ota_chamber
from acts_contrib.test_utils.wifi import wifi_performance_test_utils as wputils
+from acts_contrib.test_utils.wifi.wifi_performance_test_utils.bokeh_figure import BokehFigure
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from acts_contrib.test_utils.wifi import wifi_retail_ap as retail_ap
+from acts_contrib.test_utils.wifi import ota_sniffer
from functools import partial
from WifiRvrTest import WifiRvrTest
from WifiPingTest import WifiPingTest
@@ -46,6 +48,7 @@
example_connectivity_performance_ap_sta.json.
"""
+ MAX_CONSECUTIVE_ZEROS = 5
RSSI_POLL_INTERVAL = 0.2
VALID_TEST_CONFIGS = {
1: ['legacy', 'VHT20'],
@@ -138,16 +141,25 @@
common to all tests in this class.
"""
self.dut = self.android_devices[-1]
+ self.sta_dut = self.android_devices[-1]
req_params = [
'RetailAccessPoints', 'sensitivity_test_params', 'testbed_params',
'RemoteServer'
]
- opt_params = ['main_network']
+ opt_params = ['main_network', 'OTASniffer']
self.unpack_userparams(req_params, opt_params)
self.testclass_params = self.sensitivity_test_params
self.num_atten = self.attenuators[0].instrument.num_atten
self.ping_server = ssh.connection.SshConnection(
ssh.settings.from_config(self.RemoteServer[0]['ssh_config']))
+ if hasattr(self,
+ 'OTASniffer') and self.testbed_params['sniffer_enable']:
+ try:
+ self.sniffer = ota_sniffer.create(self.OTASniffer)[0]
+ except:
+ self.log.warning('Could not start sniffer. Disabling sniffs.')
+ self.testbed_params['sniffer_enable'] = 0
+ self.remote_server = self.ping_server
self.iperf_server = self.iperf_servers[0]
self.iperf_client = self.iperf_clients[0]
self.access_point = retail_ap.create(self.RetailAccessPoints)[0]
@@ -169,9 +181,11 @@
self.user_params['retry_tests'] = [self.__class__.__name__]
def teardown_class(self):
+ self.access_point.teardown()
# Turn WiFi OFF
for dev in self.android_devices:
wutils.wifi_toggle_state(dev, False)
+ dev.go_to_sleep()
self.process_testclass_results()
def setup_test(self):
@@ -207,9 +221,40 @@
else:
asserts.explicit_pass('Test Passed. {}'.format(result_string))
+ def plot_per_curves(self):
+ """Plots PER curves to help debug sensitivity."""
+
+ plots = collections.OrderedDict()
+ id_fields = ['channel', 'mode', 'num_streams']
+ for result in self.testclass_results:
+ testcase_params = result['testcase_params']
+ plot_id = self.extract_test_id(testcase_params, id_fields)
+ plot_id = tuple(plot_id.items())
+ if plot_id not in plots:
+ plots[plot_id] = BokehFigure(
+ title='Channel {} {} Nss{}'.format(
+ result['testcase_params']['channel'],
+ result['testcase_params']['mode'],
+ result['testcase_params']['num_streams']),
+ x_label='Attenuation (dB)',
+ primary_y_label='PER (%)')
+ per = [stat['summary']['rx_per'] for stat in result['llstats']]
+ if len(per) < len(result['total_attenuation']):
+ per.extend([100] *
+ (len(result['total_attenuation']) - len(per)))
+ plots[plot_id].add_line(result['total_attenuation'], per,
+ result['test_name'])
+ figure_list = []
+ for plot_id, plot in plots.items():
+ plot.generate_figure()
+ figure_list.append(plot)
+ output_file_path = os.path.join(self.log_path, 'results.html')
+ BokehFigure.save_figures(figure_list, output_file_path)
+
def process_testclass_results(self):
"""Saves and plots test results from all executed test cases."""
# write json output
+ self.plot_per_curves()
testclass_results_dict = collections.OrderedDict()
id_fields = ['mode', 'rate', 'num_streams', 'chain_mask']
channels_tested = []
@@ -246,7 +291,7 @@
metric_tag_dict['channel'], metric_tag_dict['mode'],
metric_tag_dict['num_streams'], metric_tag_dict['chain_mask'])
metric_key = '{}.avg_sensitivity'.format(metric_tag)
- metric_value = numpy.nanmean(metric_data)
+ metric_value = numpy.mean(metric_data)
self.testclass_metric_logger.add_metric(metric_key, metric_value)
# write csv
@@ -331,6 +376,7 @@
testcase_params['channel'])] - ping_result['range'])
def setup_sensitivity_test(self, testcase_params):
+ # Setup test
if testcase_params['traffic_type'].lower() == 'ping':
self.setup_ping_test(testcase_params)
self.run_sensitivity_test = self.run_ping_test
@@ -386,15 +432,21 @@
Args:
testcase_params: dict containing AP and other test params
"""
- # Check battery level before test
- if not wputils.health_check(self.dut, 10):
- asserts.skip('Battery level too low. Skipping test.')
# Turn screen off to preserve battery
- self.dut.go_to_sleep()
+ if self.testbed_params.get('screen_on',
+ False) or self.testclass_params.get(
+ 'screen_on', False):
+ self.dut.droid.wakeLockAcquireDim()
+ else:
+ self.dut.go_to_sleep()
if wputils.validate_network(self.dut,
testcase_params['test_network']['SSID']):
self.log.info('Already connected to desired network')
else:
+ wutils.wifi_toggle_state(self.dut, False)
+ wutils.set_wifi_country_code(self.dut,
+ self.testclass_params['country_code'])
+ wutils.wifi_toggle_state(self.dut, True)
wutils.reset_wifi(self.dut)
wutils.set_wifi_country_code(self.dut,
self.testclass_params['country_code'])
@@ -478,8 +530,14 @@
def compile_test_params(self, testcase_params):
"""Function that generates test params based on the test name."""
+ # Check if test should be skipped.
+ wputils.check_skip_conditions(testcase_params, self.dut,
+ self.access_point,
+ getattr(self, 'ota_chamber', None))
+
band = self.access_point.band_lookup_by_channel(
testcase_params['channel'])
+ testcase_params['band'] = band
testcase_params['test_network'] = self.main_network[band]
if testcase_params['chain_mask'] in ['0', '1']:
testcase_params['attenuated_chain'] = 'DUT-Chain-{}'.format(
@@ -671,37 +729,20 @@
testcase_params: dict containing AP and other test params
"""
# Configure the right INI settings
- if testcase_params['chain_mask'] != self.current_chain_mask:
- self.log.info('Updating WiFi chain mask to: {}'.format(
- testcase_params['chain_mask']))
- self.current_chain_mask = testcase_params['chain_mask']
- if testcase_params['chain_mask'] in ['0', '1']:
- wputils.set_ini_single_chain_mode(
- self.dut, int(testcase_params['chain_mask']))
- else:
- wputils.set_ini_two_chain_mode(self.dut)
- # Check battery level before test
- if not wputils.health_check(self.dut, 10):
- asserts.skip('Battery level too low. Skipping test.')
+ wputils.set_chain_mask(self.dut, testcase_params['chain_mask'])
# Turn screen off to preserve battery
- self.dut.go_to_sleep()
- if wputils.validate_network(self.dut,
- testcase_params['test_network']['SSID']):
- self.log.info('Already connected to desired network')
+ if self.testbed_params.get('screen_on',
+ False) or self.testclass_params.get(
+ 'screen_on', False):
+ self.dut.droid.wakeLockAcquireDim()
else:
- wutils.reset_wifi(self.dut)
- wutils.set_wifi_country_code(self.dut,
- self.testclass_params['country_code'])
- testcase_params['test_network']['channel'] = testcase_params[
- 'channel']
- wutils.wifi_connect(self.dut,
- testcase_params['test_network'],
- num_of_tries=5,
- check_connectivity=False)
+ self.dut.go_to_sleep()
+ self.validate_and_connect(testcase_params)
self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses('wlan0')[0]
def process_testclass_results(self):
"""Saves and plots test results from all executed test cases."""
+ self.plot_per_curves()
testclass_results_dict = collections.OrderedDict()
id_fields = ['channel', 'mode', 'rate']
plots = []
@@ -744,10 +785,9 @@
test_id_str = 'Channel {} - {} MCS{}'.format(
test_id_dict['channel'], test_id_dict['mode'],
test_id_dict['rate'])
- curr_plot = wputils.BokehFigure(
- title=str(test_id_str),
- x_label='Orientation (deg)',
- primary_y_label='Sensitivity (dBm)')
+ curr_plot = BokehFigure(title=str(test_id_str),
+ x_label='Orientation (deg)',
+ primary_y_label='Sensitivity (dBm)')
for line_id, line_results in test_data.items():
curr_plot.add_line(line_results['orientation'],
line_results['sensitivity'],
@@ -776,7 +816,7 @@
curr_plot.generate_figure(output_file_path)
plots.append(curr_plot)
output_file_path = os.path.join(current_context, 'results.html')
- wputils.BokehFigure.save_figures(plots, output_file_path)
+ BokehFigure.save_figures(plots, output_file_path)
def get_start_atten(self, testcase_params):
"""Gets the starting attenuation for this sensitivity test.
@@ -876,8 +916,10 @@
requested_channels = [6, 36, 149]
requested_rates = [
self.RateTuple(8, 1, 86.7),
+ self.RateTuple(6, 1, 65),
self.RateTuple(2, 1, 21.7),
self.RateTuple(8, 2, 173.3),
+ self.RateTuple(6, 2, 130.3),
self.RateTuple(2, 2, 43.3)
]
self.tests = self.generate_test_cases(requested_channels,
@@ -891,12 +933,16 @@
WifiOtaSensitivityTest.__init__(self, controllers)
requested_channels = [6, 36, 149]
requested_rates = [
+ self.RateTuple(9, 1, 96),
+ self.RateTuple(9, 2, 192),
+ self.RateTuple(6, 1, 65),
+ self.RateTuple(6, 2, 130.3),
self.RateTuple(2, 1, 21.7),
self.RateTuple(2, 2, 43.3)
]
- self.tests = self.generate_test_cases(requested_channels, ['VHT20'],
- requested_rates,
- ['0', '1', '2x2'],
+ self.tests = self.generate_test_cases(requested_channels,
+ ['VHT20', 'VHT80'],
+ requested_rates, [0, 1, '2x2'],
list(range(0, 360, 10)))
diff --git a/acts_tests/tests/google/wifi/WifiSoftApAcsTest.py b/acts_tests/tests/google/wifi/WifiSoftApAcsTest.py
index da7877d..886754f 100644
--- a/acts_tests/tests/google/wifi/WifiSoftApAcsTest.py
+++ b/acts_tests/tests/google/wifi/WifiSoftApAcsTest.py
@@ -28,8 +28,8 @@
from acts import asserts
from acts.controllers.ap_lib import hostapd_constants
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
from threading import Thread
diff --git a/acts_tests/tests/google/wifi/WifiSoftApMultiCountryTest.py b/acts_tests/tests/google/wifi/WifiSoftApMultiCountryTest.py
index af34ce9..f5173ff 100644
--- a/acts_tests/tests/google/wifi/WifiSoftApMultiCountryTest.py
+++ b/acts_tests/tests/google/wifi/WifiSoftApMultiCountryTest.py
@@ -30,9 +30,9 @@
from acts_contrib.test_utils.net import socket_test_utils as sutils
from acts_contrib.test_utils.tel import tel_defines
from acts_contrib.test_utils.tel import tel_test_utils as tel_utils
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_AUTO
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_AUTO
from acts_contrib.test_utils.wifi import wifi_constants
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
diff --git a/acts_tests/tests/google/wifi/WifiSoftApPerformanceTest.py b/acts_tests/tests/google/wifi/WifiSoftApPerformanceTest.py
index b116666..47719c5 100644
--- a/acts_tests/tests/google/wifi/WifiSoftApPerformanceTest.py
+++ b/acts_tests/tests/google/wifi/WifiSoftApPerformanceTest.py
@@ -64,7 +64,6 @@
opt_params = ['golden_files_list', 'OTASniffer']
self.unpack_userparams(req_params, opt_params)
self.access_points = retail_ap.create(self.RetailAccessPoints)
- self.access_point = self.access_points[0]
self.testclass_params = self.sap_test_params
self.num_atten = self.attenuators[0].instrument.num_atten
self.iperf_server = ipf.create([{
@@ -81,7 +80,11 @@
}])[0]
if hasattr(self,
'OTASniffer') and self.testbed_params['sniffer_enable']:
- self.sniffer = ota_sniffer.create(self.OTASniffer)[0]
+ try:
+ self.sniffer = ota_sniffer.create(self.OTASniffer)[0]
+ except:
+ self.log.warning('Could not start sniffer. Disabling sniffs.')
+ self.testbed_params['sniffer_enable'] = 0
self.log_path = os.path.join(logging.log_path, 'results')
os.makedirs(self.log_path, exist_ok=True)
@@ -106,9 +109,11 @@
wutils.stop_wifi_tethering(self.android_devices[0])
for dev in self.android_devices:
wutils.wifi_toggle_state(dev, False)
+ dev.go_to_sleep()
self.process_testclass_results()
# Teardown AP and release it's lockfile
- self.access_point.teardown()
+ for ap in self.access_points:
+ ap.teardown()
def teardown_test(self):
self.iperf_server.stop()
@@ -118,13 +123,17 @@
info = {}
info['client_ip_address'] = self.android_devices[
1].droid.connectivityGetIPv4Addresses('wlan0')[0]
+ ifconfig_out = self.android_devices[0].adb.shell('ifconfig')
+ soft_ap_interface = 'wlan1' if 'wlan1' in ifconfig_out else 'wlan2'
info['ap_ip_address'] = self.android_devices[
- 0].droid.connectivityGetIPv4Addresses('wlan1')[0]
- info['frequency'] = self.android_devices[1].adb.shell(
- 'wpa_cli status | grep freq').split('=')[1]
+ 0].droid.connectivityGetIPv4Addresses(soft_ap_interface)[0]
+
+ connection_rssi = wputils.get_connected_rssi(self.android_devices[1],
+ interface='wlan0')
+ info['frequency'] = connection_rssi['frequency'][0]
info['channel'] = wutils.WifiEnums.freq_to_channel[int(
info['frequency'])]
- info['mode'] = 'VHT20' if info['channel'] < 13 else 'VHT80'
+ info['mode'] = 'bw20' if info['channel'] < 13 else 'bw80'
return info
def setup_aps(self, testcase_params):
@@ -180,11 +189,23 @@
num_of_tries=5,
check_connectivity=False)
# Compile meta data
- #self.access_point = AccessPointTuple(sap_config)
sap_info = self.get_sap_connection_info()
print("SAP Info: {}".format(sap_info))
testcase_params['channel'] = sap_info['channel']
+ if testcase_params['channel'] < 13:
+ testcase_params['band'] = '2GHz'
+ else:
+ testcase_params['band'] = '5GHz'
testcase_params['mode'] = sap_info['mode']
+ self.access_point = AccessPointTuple({
+ testcase_params['band']: {
+ 'SSID': sap_config[wutils.WifiEnums.SSID_KEY],
+ 'password': sap_config[wutils.WifiEnums.PWD_KEY],
+ 'channel': sap_info['channel'],
+ 'mode': sap_info['mode'],
+ 'bandwidth': sap_info['mode'],
+ }
+ })
testcase_params['iperf_server_address'] = sap_info['ap_ip_address']
def setup_sap_rvr_test(self, testcase_params):
@@ -204,7 +225,7 @@
self.setup_sap_connection(testcase_params)
# Set DUT to monitor RSSI and LLStats on
self.monitored_dut = self.sta_dut
- self.monitored_interface = None
+ self.monitored_interface = 'wlan0'
def compile_test_params(self, testcase_params):
"""Function that completes all test params based on the test name.
diff --git a/acts_tests/tests/google/wifi/WifiStaApConcurrencyStressTest.py b/acts_tests/tests/google/wifi/WifiStaApConcurrencyStressTest.py
index 9fddb69..21333e3 100755
--- a/acts_tests/tests/google/wifi/WifiStaApConcurrencyStressTest.py
+++ b/acts_tests/tests/google/wifi/WifiStaApConcurrencyStressTest.py
@@ -22,8 +22,8 @@
from acts import signals
from acts import utils
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
from WifiStaApConcurrencyTest import WifiStaApConcurrencyTest
import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
diff --git a/acts_tests/tests/google/wifi/WifiStaApConcurrencyTest.py b/acts_tests/tests/google/wifi/WifiStaApConcurrencyTest.py
index 846d57c..4775c15 100644
--- a/acts_tests/tests/google/wifi/WifiStaApConcurrencyTest.py
+++ b/acts_tests/tests/google/wifi/WifiStaApConcurrencyTest.py
@@ -23,8 +23,8 @@
from acts.controllers.ap_lib import hostapd_constants
import acts.signals as signals
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
import acts.utils as utils
diff --git a/acts_tests/tests/google/wifi/WifiTdlsRvrTest.py b/acts_tests/tests/google/wifi/WifiTdlsRvrTest.py
new file mode 100644
index 0000000..b051448
--- /dev/null
+++ b/acts_tests/tests/google/wifi/WifiTdlsRvrTest.py
@@ -0,0 +1,365 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2020 - 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 collections
+import itertools
+import logging
+import os
+from acts import asserts
+from acts import base_test
+from acts import utils
+from acts.controllers import iperf_server as ipf
+from acts.controllers import iperf_client as ipc
+from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.wifi import ota_sniffer
+from acts_contrib.test_utils.wifi import wifi_retail_ap as retail_ap
+from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from acts_contrib.test_utils.wifi import wifi_performance_test_utils as wputils
+from functools import partial
+from WifiRvrTest import WifiRvrTest
+
+AccessPointTuple = collections.namedtuple(('AccessPointTuple'),
+ ['ap_settings'])
+
+
+class WifiTdlsRvrTest(WifiRvrTest):
+ def __init__(self, controllers):
+ base_test.BaseTestClass.__init__(self, controllers)
+ self.testcase_metric_logger = (
+ BlackboxMappedMetricLogger.for_test_case())
+ self.testclass_metric_logger = (
+ BlackboxMappedMetricLogger.for_test_class())
+ self.publish_testcase_metrics = True
+
+ def setup_class(self):
+ """Initializes common test hardware and parameters.
+
+ This function initializes hardwares and compiles parameters that are
+ common to all tests in this class.
+ """
+ req_params = [
+ 'tdls_rvr_test_params', 'testbed_params', 'RetailAccessPoints'
+ ]
+ opt_params = ['ap_networks', 'OTASniffer']
+ self.unpack_userparams(req_params, opt_params)
+ self.access_point = retail_ap.create(self.RetailAccessPoints)[0]
+ self.testclass_params = self.tdls_rvr_test_params
+ self.num_atten = self.attenuators[0].instrument.num_atten
+ self.iperf_server = ipf.create([{
+ 'AndroidDevice':
+ self.android_devices[0].serial,
+ 'port':
+ '5201'
+ }])[0]
+ self.iperf_client = ipc.create([{
+ 'AndroidDevice':
+ self.android_devices[1].serial,
+ 'port':
+ '5201'
+ }])[0]
+
+ self.log_path = os.path.join(logging.log_path, 'results')
+ if hasattr(self,
+ 'OTASniffer') and self.testbed_params['sniffer_enable']:
+ self.sniffer = ota_sniffer.create(self.OTASniffer)[0]
+ os.makedirs(self.log_path, exist_ok=True)
+ if not hasattr(self, 'golden_files_list'):
+ if 'golden_results_path' in self.testbed_params:
+ self.golden_files_list = [
+ os.path.join(self.testbed_params['golden_results_path'],
+ file) for file in
+ os.listdir(self.testbed_params['golden_results_path'])
+ ]
+ else:
+ self.log.warning('No golden files found.')
+ self.golden_files_list = []
+
+ self.testclass_results = []
+
+ # Turn WiFi ON
+ if self.testclass_params.get('airplane_mode', 1):
+ self.log.info('Turning on airplane mode.')
+ for ad in self.android_devices:
+ asserts.assert_true(utils.force_airplane_mode(ad, True),
+ "Can not turn on airplane mode.")
+ for ad in self.android_devices:
+ wutils.wifi_toggle_state(ad, True)
+
+ def teardown_class(self):
+ # Turn WiFi OFF
+ for dev in self.android_devices:
+ wutils.wifi_toggle_state(dev, False)
+ self.process_testclass_results()
+ # Teardown AP and release its lockfile
+ self.access_point.teardown()
+
+ def setup_test(self):
+ for ad in self.android_devices:
+ wputils.start_wifi_logging(ad)
+
+ def teardown_test(self):
+ self.iperf_server.stop()
+ for ad in self.android_devices:
+ wutils.reset_wifi(ad)
+ wputils.stop_wifi_logging(ad)
+
+ def on_exception(self, test_name, begin_time):
+ for ad in self.android_devices:
+ ad.take_bug_report(test_name, begin_time)
+ ad.cat_adb_log(test_name, begin_time)
+ wutils.get_ssrdumps(ad)
+
+ def compute_test_metrics(self, rvr_result):
+ #Set test metrics
+ rvr_result['metrics'] = {}
+ rvr_result['metrics']['peak_tput'] = max(
+ rvr_result['throughput_receive'])
+ if self.publish_testcase_metrics:
+ self.testcase_metric_logger.add_metric(
+ 'peak_tput', rvr_result['metrics']['peak_tput'])
+
+ test_mode = rvr_result['testcase_params']['mode']
+ tput_below_limit = [
+ tput <
+ self.testclass_params['tput_metric_targets'][test_mode]['high']
+ for tput in rvr_result['throughput_receive']
+ ]
+ rvr_result['metrics']['high_tput_range'] = -1
+ for idx in range(len(tput_below_limit)):
+ if all(tput_below_limit[idx:]):
+ if idx == 0:
+ #Throughput was never above limit
+ rvr_result['metrics']['high_tput_range'] = -1
+ else:
+ rvr_result['metrics']['high_tput_range'] = rvr_result[
+ 'total_attenuation'][max(idx, 1) - 1]
+ break
+ if self.publish_testcase_metrics:
+ self.testcase_metric_logger.add_metric(
+ 'high_tput_range', rvr_result['metrics']['high_tput_range'])
+
+ tput_below_limit = [
+ tput <
+ self.testclass_params['tput_metric_targets'][test_mode]['low']
+ for tput in rvr_result['throughput_receive']
+ ]
+ for idx in range(len(tput_below_limit)):
+ if all(tput_below_limit[idx:]):
+ rvr_result['metrics']['low_tput_range'] = rvr_result[
+ 'total_attenuation'][max(idx, 1) - 1]
+ break
+ else:
+ rvr_result['metrics']['low_tput_range'] = -1
+ if self.publish_testcase_metrics:
+ self.testcase_metric_logger.add_metric(
+ 'low_tput_range', rvr_result['metrics']['low_tput_range'])
+
+ def setup_aps(self, testcase_params):
+ self.log.info('Setting AP to channel {} {}'.format(
+ testcase_params['channel'], testcase_params['bandwidth']))
+ self.access_point.set_channel(testcase_params['interface_id'],
+ testcase_params['channel'])
+ self.access_point.set_bandwidth(testcase_params['interface_id'],
+ testcase_params['bandwidth'])
+
+ def setup_duts(self, testcase_params):
+ # Check battery level before test
+ for ad in self.android_devices:
+ if not wputils.health_check(ad, 20):
+ asserts.skip('Overheating or Battery low. Skipping test.')
+ ad.go_to_sleep()
+ wutils.reset_wifi(ad)
+ # Turn screen off to preserve battery
+ for ad in self.android_devices:
+ wutils.wifi_connect(
+ ad,
+ self.ap_networks[0][testcase_params['interface_id']],
+ num_of_tries=5,
+ check_connectivity=True)
+
+ def setup_tdls_connection(self, testcase_params):
+
+ tdls_config = {}
+ for idx, ad in enumerate(self.android_devices):
+ tdls_config[idx] = {
+ 'ip_address':
+ ad.droid.connectivityGetIPv4Addresses('wlan0')[0],
+ 'mac_address': ad.droid.wifiGetConnectionInfo()['mac_address'],
+ 'tdls_supported': ad.droid.wifiIsTdlsSupported(),
+ 'off_channel_supported':
+ ad.droid.wifiIsOffChannelTdlsSupported()
+ }
+ self.android_devices[0].droid.wifiSetTdlsEnabledWithMacAddress(
+ tdls_config[1]['mac_address'], True)
+
+ testcase_params['iperf_server_address'] = tdls_config[0]['ip_address']
+ testcase_params['tdls_config'] = tdls_config
+ testcase_params['channel'] = testcase_params['channel']
+ testcase_params['mode'] = testcase_params['bandwidth']
+ testcase_params['test_network'] = self.ap_networks[0][
+ testcase_params['interface_id']]
+
+ def setup_tdls_rvr_test(self, testcase_params):
+ # Setup the aps
+ self.setup_aps(testcase_params)
+ # Setup the duts
+ self.setup_duts(testcase_params)
+ # Set attenuator to 0 dB
+ for attenuator in self.attenuators:
+ attenuator.set_atten(0, strict=False)
+ # Setup the aware connection
+ self.setup_tdls_connection(testcase_params)
+ # Set DUT to monitor RSSI and LLStats on
+ self.monitored_dut = self.android_devices[1]
+
+ def compile_test_params(self, testcase_params):
+ """Function that completes all test params based on the test name.
+
+ Args:
+ testcase_params: dict containing test-specific parameters
+ """
+ for ad in self.android_devices:
+ wputils.check_skip_conditions(testcase_params, ad,
+ self.access_point)
+
+ # Compile RvR parameters
+ num_atten_steps = int((self.testclass_params['atten_stop'] -
+ self.testclass_params['atten_start']) /
+ self.testclass_params['atten_step'])
+ testcase_params['atten_range'] = [
+ self.testclass_params['atten_start'] +
+ x * self.testclass_params['atten_step']
+ for x in range(0, num_atten_steps)
+ ]
+
+ # Compile iperf arguments
+ if testcase_params['traffic_type'] == 'TCP':
+ testcase_params['iperf_socket_size'] = self.testclass_params.get(
+ 'tcp_socket_size', None)
+ testcase_params['iperf_processes'] = self.testclass_params.get(
+ 'tcp_processes', 1)
+ elif testcase_params['traffic_type'] == 'UDP':
+ testcase_params['iperf_socket_size'] = self.testclass_params.get(
+ 'udp_socket_size', None)
+ testcase_params['iperf_processes'] = self.testclass_params.get(
+ 'udp_processes', 1)
+ testcase_params['iperf_args'] = wputils.get_iperf_arg_string(
+ duration=self.testclass_params['iperf_duration'],
+ reverse_direction=(testcase_params['traffic_direction'] == 'DL'),
+ socket_size=testcase_params['iperf_socket_size'],
+ num_processes=testcase_params['iperf_processes'],
+ traffic_type=testcase_params['traffic_type'],
+ ipv6=False)
+ testcase_params['use_client_output'] = (
+ testcase_params['traffic_direction'] == 'DL')
+
+ # Compile AP and infrastructure connection parameters
+ testcase_params['interface_id'] = '2G' if testcase_params[
+ 'channel'] < 13 else '5G_1'
+ return testcase_params
+
+ def _test_tdls_rvr(self, testcase_params):
+ """ Function that gets called for each test case
+
+ Args:
+ testcase_params: dict containing test-specific parameters
+ """
+ # Compile test parameters from config and test name
+ testcase_params = self.compile_test_params(testcase_params)
+
+ # Prepare devices and run test
+ self.setup_tdls_rvr_test(testcase_params)
+ rvr_result = self.run_rvr_test(testcase_params)
+
+ # Post-process results
+ self.testclass_results.append(rvr_result)
+ self.process_test_results(rvr_result)
+ self.pass_fail_check(rvr_result)
+
+ def generate_test_cases(self, ap_config_list, traffic_type,
+ traffic_directions):
+ """Function that auto-generates test cases for a test class."""
+ test_cases = []
+
+ for ap_config, traffic_direction in itertools.product(
+ ap_config_list, traffic_directions):
+ test_name = 'test_tdls_rvr_{}_{}_ch{}_{}'.format(
+ traffic_type, traffic_direction, ap_config[0], ap_config[1])
+ test_params = collections.OrderedDict(
+ traffic_type=traffic_type,
+ traffic_direction=traffic_direction,
+ channel=ap_config[0],
+ bandwidth=ap_config[1])
+ test_class = self.__class__.__name__
+ if "uuid_list" in self.user_params:
+ test_tracker_uuid = self.user_params["uuid_list"][
+ test_class][test_name]
+ test_case = test_tracker_info(uuid=test_tracker_uuid)(
+ lambda: self._test_tdls_rvr(test_params))
+ else:
+ test_case = partial(self._test_tdls_rvr,test_params)
+ setattr(self, test_name, test_case)
+ test_cases.append(test_name)
+ return test_cases
+
+
+class WifiTdlsRvr_FCC_TCP_Test(WifiTdlsRvrTest):
+ def __init__(self, controllers):
+ super().__init__(controllers)
+ ap_config_list = [[6, 'bw20'], [36, 'bw20'], [36, 'bw40'],
+ [36, 'bw80'], [149, 'bw20'], [149, 'bw40'],
+ [149, 'bw80']]
+ self.country_code = 'US'
+ self.tests = self.generate_test_cases(ap_config_list=ap_config_list,
+ traffic_type='TCP',
+ traffic_directions=['DL', 'UL'])
+
+
+class WifiTdlsRvr_FCC_UDP_Test(WifiTdlsRvrTest):
+ def __init__(self, controllers):
+ super().__init__(controllers)
+ ap_config_list = [[6, 'bw20'], [36, 'bw20'], [36, 'bw40'],
+ [36, 'bw80'], [149, 'bw20'], [149, 'bw40'],
+ [149, 'bw80']]
+ self.country_code = 'US'
+ self.tests = self.generate_test_cases(ap_config_list=ap_config_list,
+ traffic_type='UDP',
+ traffic_directions=['DL', 'UL'])
+
+
+class WifiTdlsRvr_ETSI_TCP_Test(WifiTdlsRvrTest):
+ def __init__(self, controllers):
+ super().__init__(controllers)
+ ap_config_list = [[6, 'bw20'], [36, 'bw20'], [36, 'bw40'],
+ [36, 'bw80'], [149, 'bw20'], [149, 'bw40'],
+ [149, 'bw80']]
+ self.country_code = 'GB'
+ self.tests = self.generate_test_cases(ap_config_list=ap_config_list,
+ traffic_type='TCP',
+ traffic_directions=['DL', 'UL'])
+
+
+class WifiTdlsRvr_ETSI_UDP_Test(WifiTdlsRvrTest):
+ def __init__(self, controllers):
+ super().__init__(controllers)
+ ap_config_list = [[6, 'bw20'], [36, 'bw20'], [36, 'bw40'],
+ [36, 'bw80'], [149, 'bw20'], [149, 'bw40'],
+ [149, 'bw80']]
+ self.country_code = 'GB'
+ self.tests = self.generate_test_cases(ap_config_list=ap_config_list,
+ traffic_type='UDP',
+ traffic_directions=['DL', 'UL'])
diff --git a/acts_tests/tests/google/wifi/WifiTeleCoexTest.py b/acts_tests/tests/google/wifi/WifiTeleCoexTest.py
index 7260919..3031627 100644
--- a/acts_tests/tests/google/wifi/WifiTeleCoexTest.py
+++ b/acts_tests/tests/google/wifi/WifiTeleCoexTest.py
@@ -13,10 +13,14 @@
from acts import signals
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_short_seq
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_iwlan
from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import GEN_4G
@@ -68,7 +72,7 @@
for ad in self.android_devices:
wifi_utils.reset_wifi(ad)
ad.droid.telephonyToggleDataConnection(False)
- tele_utils.ensure_phones_idle(self.log, self.android_devices)
+ ensure_phones_idle(self.log, self.android_devices)
nutil.stop_usb_tethering(self.dut)
"""Helper Functions"""
@@ -208,14 +212,14 @@
"""
tele_utils.toggle_airplane_mode(self.log, self.android_devices[0], False)
- tele_utils.toggle_volte(self.log, self.android_devices[0], volte_mode)
- if not tele_utils.ensure_network_generation(
+ toggle_volte(self.log, self.android_devices[0], volte_mode)
+ if not ensure_network_generation(
self.log,
self.android_devices[0],
GEN_4G,
voice_or_data=NETWORK_SERVICE_DATA):
return False
- if not tele_utils.set_wfc_mode(self.log, self.android_devices[0], wfc_mode):
+ 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
diff --git a/acts_tests/tests/google/wifi/WifiTethering2GOpenOTATest.py b/acts_tests/tests/google/wifi/WifiTethering2GOpenOTATest.py
index 0790546..af2648b 100755
--- a/acts_tests/tests/google/wifi/WifiTethering2GOpenOTATest.py
+++ b/acts_tests/tests/google/wifi/WifiTethering2GOpenOTATest.py
@@ -20,7 +20,7 @@
from acts.base_test import BaseTestClass
from acts.libs.ota import ota_updater
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
import acts_contrib.test_utils.net.net_test_utils as nutils
import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
diff --git a/acts_tests/tests/google/wifi/WifiTethering2GPskOTATest.py b/acts_tests/tests/google/wifi/WifiTethering2GPskOTATest.py
index c0b6d28..7d3c988 100755
--- a/acts_tests/tests/google/wifi/WifiTethering2GPskOTATest.py
+++ b/acts_tests/tests/google/wifi/WifiTethering2GPskOTATest.py
@@ -20,7 +20,7 @@
from acts.base_test import BaseTestClass
from acts.libs.ota import ota_updater
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
import acts_contrib.test_utils.net.net_test_utils as nutils
import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
diff --git a/acts_tests/tests/google/wifi/WifiTethering5GOpenOTATest.py b/acts_tests/tests/google/wifi/WifiTethering5GOpenOTATest.py
index 12f6824..151bedf 100755
--- a/acts_tests/tests/google/wifi/WifiTethering5GOpenOTATest.py
+++ b/acts_tests/tests/google/wifi/WifiTethering5GOpenOTATest.py
@@ -20,7 +20,7 @@
from acts.base_test import BaseTestClass
from acts.libs.ota import ota_updater
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
import acts_contrib.test_utils.net.net_test_utils as nutils
import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
diff --git a/acts_tests/tests/google/wifi/WifiTethering5GPskOTATest.py b/acts_tests/tests/google/wifi/WifiTethering5GPskOTATest.py
index de0f901..b293206 100755
--- a/acts_tests/tests/google/wifi/WifiTethering5GPskOTATest.py
+++ b/acts_tests/tests/google/wifi/WifiTethering5GPskOTATest.py
@@ -20,7 +20,7 @@
from acts.base_test import BaseTestClass
from acts.libs.ota import ota_updater
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
import acts_contrib.test_utils.net.net_test_utils as nutils
import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
diff --git a/acts_tests/tests/google/wifi/WifiTetheringPowerTest.py b/acts_tests/tests/google/wifi/WifiTetheringPowerTest.py
index 577e100..84fc6aa 100644
--- a/acts_tests/tests/google/wifi/WifiTetheringPowerTest.py
+++ b/acts_tests/tests/google/wifi/WifiTetheringPowerTest.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3.4
#
-# Copyright 2017 - The Android Open Source Project
+# Copyright 2022 - 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.
@@ -25,9 +25,9 @@
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from acts_contrib.test_utils.tel import tel_data_utils as tel_utils
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
-from acts_contrib.test_utils.tel.tel_test_utils import http_file_download_by_chrome
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_data_utils import http_file_download_by_chrome
from acts.utils import force_airplane_mode
from acts.utils import set_adaptive_brightness
from acts.utils import set_ambient_display
diff --git a/acts_tests/tests/google/wifi/WifiTetheringTest.py b/acts_tests/tests/google/wifi/WifiTetheringTest.py
index 99028d0..730bae3 100644
--- a/acts_tests/tests/google/wifi/WifiTetheringTest.py
+++ b/acts_tests/tests/google/wifi/WifiTetheringTest.py
@@ -24,11 +24,9 @@
from acts.controllers import adb
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.tel import tel_defines
-from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
from acts_contrib.test_utils.net import socket_test_utils as sutils
from acts_contrib.test_utils.net import arduino_test_utils as dutils
from acts_contrib.test_utils.net import net_test_utils as nutils
diff --git a/acts_tests/tests/google/wifi/WifiThroughputStabilityTest.py b/acts_tests/tests/google/wifi/WifiThroughputStabilityTest.py
index 59c8575..a8d9628 100644
--- a/acts_tests/tests/google/wifi/WifiThroughputStabilityTest.py
+++ b/acts_tests/tests/google/wifi/WifiThroughputStabilityTest.py
@@ -29,7 +29,9 @@
from acts.controllers.utils_lib import ssh
from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
from acts_contrib.test_utils.wifi import ota_chamber
+from acts_contrib.test_utils.wifi import ota_sniffer
from acts_contrib.test_utils.wifi import wifi_performance_test_utils as wputils
+from acts_contrib.test_utils.wifi.wifi_performance_test_utils.bokeh_figure import BokehFigure
from acts_contrib.test_utils.wifi import wifi_retail_ap as retail_ap
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from functools import partial
@@ -57,10 +59,9 @@
BlackboxMappedMetricLogger.for_test_class())
self.publish_testcase_metrics = True
# Generate test cases
- self.tests = self.generate_test_cases([6, 36, 149],
- ['bw20', 'bw40', 'bw80'],
- ['TCP', 'UDP'], ['DL', 'UL'],
- ['high', 'low'])
+ self.tests = self.generate_test_cases(
+ [6, 36, 149, '6g37'], ['bw20', 'bw40', 'bw80', 'bw160'],
+ ['TCP', 'UDP'], ['DL', 'UL'], ['high', 'low'])
def generate_test_cases(self, channels, modes, traffic_types,
traffic_directions, signal_levels):
@@ -68,11 +69,11 @@
allowed_configs = {
20: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 64, 100,
- 116, 132, 140, 149, 153, 157, 161
+ 116, 132, 140, 149, 153, 157, 161, '6g37', '6g117', '6g213'
],
- 40: [36, 44, 100, 149, 157],
- 80: [36, 100, 149],
- 160: [36]
+ 40: [36, 44, 100, 149, 157, '6g37', '6g117', '6g213'],
+ 80: [36, 100, 149, '6g37', '6g117', '6g213'],
+ 160: [36, '6g37', '6g117', '6g213']
}
test_cases = []
@@ -108,7 +109,8 @@
'throughput_stability_test_params', 'testbed_params',
'main_network', 'RetailAccessPoints', 'RemoteServer'
]
- self.unpack_userparams(req_params)
+ opt_params = ['OTASniffer']
+ self.unpack_userparams(req_params, opt_params)
self.testclass_params = self.throughput_stability_test_params
self.num_atten = self.attenuators[0].instrument.num_atten
self.remote_server = ssh.connection.SshConnection(
@@ -116,6 +118,13 @@
self.iperf_server = self.iperf_servers[0]
self.iperf_client = self.iperf_clients[0]
self.access_point = retail_ap.create(self.RetailAccessPoints)[0]
+ if hasattr(self,
+ 'OTASniffer') and self.testbed_params['sniffer_enable']:
+ try:
+ self.sniffer = ota_sniffer.create(self.OTASniffer)[0]
+ except:
+ self.log.warning('Could not start sniffer. Disabling sniffs.')
+ self.testbed_params['sniffer_enable'] = 0
self.log_path = os.path.join(logging.log_path, 'test_results')
os.makedirs(self.log_path, exist_ok=True)
self.log.info('Access Point Configuration: {}'.format(
@@ -133,7 +142,14 @@
def teardown_test(self):
self.iperf_server.stop()
- def pass_fail_check(self, test_result_dict):
+ def teardown_class(self):
+ self.access_point.teardown()
+ # Turn WiFi OFF
+ for dev in self.android_devices:
+ wutils.wifi_toggle_state(dev, False)
+ dev.go_to_sleep()
+
+ def pass_fail_check(self, test_result):
"""Check the test result and decide if it passed or failed.
Checks the throughput stability test's PASS/FAIL criteria based on
@@ -143,11 +159,11 @@
test_result_dict: dict containing attenuation, throughput and other
meta data
"""
- avg_throughput = test_result_dict['iperf_results']['avg_throughput']
- min_throughput = test_result_dict['iperf_results']['min_throughput']
+ avg_throughput = test_result['iperf_summary']['avg_throughput']
+ min_throughput = test_result['iperf_summary']['min_throughput']
std_dev_percent = (
- test_result_dict['iperf_results']['std_deviation'] /
- test_result_dict['iperf_results']['avg_throughput']) * 100
+ test_result['iperf_summary']['std_deviation'] /
+ test_result['iperf_summary']['avg_throughput']) * 100
# Set blackbox metrics
if self.publish_testcase_metrics:
self.testcase_metric_logger.add_metric('avg_throughput',
@@ -163,13 +179,21 @@
std_deviation_check = std_dev_percent < self.testclass_params[
'std_deviation_threshold']
+ llstats = (
+ 'TX MCS = {0} ({1:.1f}%). '
+ 'RX MCS = {2} ({3:.1f}%)'.format(
+ test_result['llstats']['summary']['common_tx_mcs'],
+ test_result['llstats']['summary']['common_tx_mcs_freq'] * 100,
+ test_result['llstats']['summary']['common_rx_mcs'],
+ test_result['llstats']['summary']['common_rx_mcs_freq'] * 100))
+
test_message = (
'Atten: {0:.2f}dB, RSSI: {1:.2f}dB. '
'Throughput (Mean: {2:.2f}, Std. Dev:{3:.2f}%, Min: {4:.2f} Mbps).'
- 'LLStats : {5}'.format(test_result_dict['attenuation'],
- test_result_dict['rssi'], avg_throughput,
- std_dev_percent, min_throughput,
- test_result_dict['llstats']))
+ 'LLStats : {5}'.format(
+ test_result['attenuation'],
+ test_result['rssi_result']['signal_poll_rssi']['mean'],
+ avg_throughput, std_dev_percent, min_throughput, llstats))
if min_throughput_check and std_deviation_check:
asserts.explicit_pass('Test Passed.' + test_message)
asserts.fail('Test Failed. ' + test_message)
@@ -188,18 +212,6 @@
test_name = self.current_test_name
results_file_path = os.path.join(self.log_path,
'{}.txt'.format(test_name))
- test_result_dict = {}
- test_result_dict['ap_settings'] = test_result['ap_settings'].copy()
- test_result_dict['attenuation'] = test_result['attenuation']
- test_result_dict['rssi'] = test_result['rssi_result'][
- 'signal_poll_rssi']['mean']
- test_result_dict['llstats'] = (
- 'TX MCS = {0} ({1:.1f}%). '
- 'RX MCS = {2} ({3:.1f}%)'.format(
- test_result['llstats']['summary']['common_tx_mcs'],
- test_result['llstats']['summary']['common_tx_mcs_freq'] * 100,
- test_result['llstats']['summary']['common_rx_mcs'],
- test_result['llstats']['summary']['common_rx_mcs_freq'] * 100))
if test_result['iperf_result'].instantaneous_rates:
instantaneous_rates_Mbps = [
rate * 8 * (1.024**2)
@@ -210,20 +222,20 @@
'iperf_result'].get_std_deviation(
self.testclass_params['iperf_ignored_interval']) * 8
else:
- instantaneous_rates_Mbps = float('nan')
+ instantaneous_rates_Mbps = [float('nan')]
tput_standard_deviation = float('nan')
- test_result_dict['iperf_results'] = {
+ test_result['iperf_summary'] = {
'instantaneous_rates': instantaneous_rates_Mbps,
'avg_throughput': numpy.mean(instantaneous_rates_Mbps),
'std_deviation': tput_standard_deviation,
'min_throughput': min(instantaneous_rates_Mbps)
}
with open(results_file_path, 'w') as results_file:
- json.dump(test_result_dict, results_file)
+ json.dump(wputils.serialize_dict(test_result), results_file)
# Plot and save
- figure = wputils.BokehFigure(test_name,
- x_label='Time (s)',
- primary_y_label='Throughput (Mbps)')
+ figure = BokehFigure(test_name,
+ x_label='Time (s)',
+ primary_y_label='Throughput (Mbps)')
time_data = list(range(0, len(instantaneous_rates_Mbps)))
figure.add_line(time_data,
instantaneous_rates_Mbps,
@@ -232,7 +244,7 @@
output_file_path = os.path.join(self.log_path,
'{}.html'.format(test_name))
figure.generate_figure(output_file_path)
- return test_result_dict
+ return test_result
def setup_ap(self, testcase_params):
"""Sets up the access point in the configuration required by the test.
@@ -242,12 +254,16 @@
"""
band = self.access_point.band_lookup_by_channel(
testcase_params['channel'])
- if '2G' in band:
- frequency = wutils.WifiEnums.channel_2G_to_freq[
- testcase_params['channel']]
+ if '6G' in band:
+ frequency = wutils.WifiEnums.channel_6G_to_freq[int(
+ testcase_params['channel'].strip('6g'))]
else:
- frequency = wutils.WifiEnums.channel_5G_to_freq[
- testcase_params['channel']]
+ if testcase_params['channel'] < 13:
+ frequency = wutils.WifiEnums.channel_2G_to_freq[
+ testcase_params['channel']]
+ else:
+ frequency = wutils.WifiEnums.channel_5G_to_freq[
+ testcase_params['channel']]
if frequency in wutils.WifiEnums.DFS_5G_FREQUENCIES:
self.access_point.set_region(self.testbed_params['DFS_region'])
else:
@@ -263,11 +279,13 @@
Args:
testcase_params: dict containing AP and other test params
"""
- # Check battery level before test
- if not wputils.health_check(self.dut, 10):
- asserts.skip('Battery level too low. Skipping test.')
# Turn screen off to preserve battery
- self.dut.go_to_sleep()
+ if self.testbed_params.get('screen_on',
+ False) or self.testclass_params.get(
+ 'screen_on', False):
+ self.dut.droid.wakeLockAcquireDim()
+ else:
+ self.dut.go_to_sleep()
band = self.access_point.band_lookup_by_channel(
testcase_params['channel'])
if wputils.validate_network(self.dut,
@@ -276,13 +294,15 @@
else:
wutils.wifi_toggle_state(self.dut, True)
wutils.reset_wifi(self.dut)
+ if self.testbed_params.get('txbf_off', False):
+ wputils.disable_beamforming(self.dut)
wutils.set_wifi_country_code(self.dut,
self.testclass_params['country_code'])
self.main_network[band]['channel'] = testcase_params['channel']
wutils.wifi_connect(self.dut,
testcase_params['test_network'],
num_of_tries=5,
- check_connectivity=False)
+ check_connectivity=True)
self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses('wlan0')[0]
def setup_throughput_stability_test(self, testcase_params):
@@ -293,6 +313,9 @@
"""
# Configure AP
self.setup_ap(testcase_params)
+ # Set attenuator to 0 dB
+ for attenuator in self.attenuators:
+ attenuator.set_atten(0, strict=False, retry=True)
# Reset, configure, and connect DUT
self.setup_dut(testcase_params)
# Wait before running the first wifi test
@@ -331,6 +354,12 @@
self.log.info('Starting iperf test.')
llstats_obj = wputils.LinkLayerStats(self.dut)
llstats_obj.update_stats()
+ if self.testbed_params['sniffer_enable']:
+ self.sniffer.start_capture(
+ network=testcase_params['test_network'],
+ chan=testcase_params['channel'],
+ bw=testcase_params['bandwidth'],
+ duration=self.testclass_params['iperf_duration'] / 5)
self.iperf_server.start(tag=str(testcase_params['atten_level']))
current_rssi = wputils.get_connected_rssi_nb(
dut=self.dut,
@@ -345,6 +374,9 @@
self.testclass_params['iperf_duration'] + TEST_TIMEOUT)
current_rssi = current_rssi.result()
server_output_path = self.iperf_server.stop()
+ # Stop sniffer
+ if self.testbed_params['sniffer_enable']:
+ self.sniffer.stop_capture()
# Set attenuator to 0 dB
for attenuator in self.attenuators:
attenuator.set_atten(0)
@@ -389,9 +421,9 @@
# Get attenuation for target RSSI
if testcase_params['signal_level'] == 'low':
- target_rssi = self.testclass_params['low_throughput_target']
+ target_rssi = self.testclass_params['low_throughput_rssi_target']
else:
- target_rssi = self.testclass_params['high_throughput_target']
+ target_rssi = self.testclass_params['high_throughput_rssi_target']
target_atten = wputils.get_atten_for_target_rssi(
target_rssi, self.attenuators, self.dut, self.remote_server)
@@ -400,6 +432,11 @@
def compile_test_params(self, testcase_params):
"""Function that completes setting the test case parameters."""
+ # Check if test should be skipped based on parameters.
+ wputils.check_skip_conditions(testcase_params, self.dut,
+ self.access_point,
+ getattr(self, 'ota_chamber', None))
+
band = self.access_point.band_lookup_by_channel(
testcase_params['channel'])
testcase_params['test_network'] = self.main_network[band]
@@ -423,7 +460,9 @@
reverse_direction=1,
traffic_type=testcase_params['traffic_type'],
socket_size=testcase_params['iperf_socket_size'],
- num_processes=testcase_params['iperf_processes'])
+ num_processes=testcase_params['iperf_processes'],
+ udp_throughput=self.testclass_params['UDP_rates'][
+ testcase_params['mode']])
testcase_params['use_client_output'] = True
else:
testcase_params['iperf_args'] = wputils.get_iperf_arg_string(
@@ -431,7 +470,9 @@
reverse_direction=0,
traffic_type=testcase_params['traffic_type'],
socket_size=testcase_params['iperf_socket_size'],
- num_processes=testcase_params['iperf_processes'])
+ num_processes=testcase_params['iperf_processes'],
+ udp_throughput=self.testclass_params['UDP_rates'][
+ testcase_params['mode']])
testcase_params['use_client_output'] = False
return testcase_params
@@ -475,6 +516,7 @@
self.user_params['OTAChamber'])[0]
def teardown_class(self):
+ WifiThroughputStabilityTest.teardown_class(self)
self.ota_chamber.reset_chamber()
self.process_testclass_results()
@@ -496,12 +538,9 @@
]).items())
test_data = channel_data.setdefault(
test_id, collections.OrderedDict(position=[], throughput=[]))
- current_throughput = (numpy.mean(
- test['iperf_result'].instantaneous_rates[
- self.testclass_params['iperf_ignored_interval']:-1])
- ) * 8 * (1.024**2)
test_data['position'].append(current_params['position'])
- test_data['throughput'].append(current_throughput)
+ test_data['throughput'].append(
+ test['iperf_summary']['avg_throughput'])
chamber_mode = self.testclass_results[0]['testcase_params'][
'chamber_mode']
@@ -519,7 +558,7 @@
test_id_dict['traffic_direction'], channel,
test_id_dict['mode'])
metric_name = metric_tag + '.avg_throughput'
- metric_value = numpy.mean(test_data['throughput'])
+ metric_value = numpy.nanmean(test_data['throughput'])
self.testclass_metric_logger.add_metric(
metric_name, metric_value)
metric_name = metric_tag + '.min_throughput'
@@ -530,7 +569,7 @@
# Plot test class results
plots = []
for channel, channel_data in testclass_data.items():
- current_plot = wputils.BokehFigure(
+ current_plot = BokehFigure(
title='Channel {} - Rate vs. Position'.format(channel),
x_label=x_label,
primary_y_label='Rate (Mbps)',
@@ -547,7 +586,7 @@
plots.append(current_plot)
current_context = context.get_current_context().get_full_output_path()
plot_file_path = os.path.join(current_context, 'results.html')
- wputils.BokehFigure.save_figures(plots, plot_file_path)
+ BokehFigure.save_figures(plots, plot_file_path)
def setup_throughput_stability_test(self, testcase_params):
WifiThroughputStabilityTest.setup_throughput_stability_test(
@@ -559,10 +598,11 @@
self.ota_chamber.step_stirrers(testcase_params['total_positions'])
def get_target_atten(self, testcase_params):
+ band = wputils.CHANNEL_TO_BAND_MAP[testcase_params['channel']]
if testcase_params['signal_level'] == 'high':
- test_atten = self.testclass_params['default_atten_levels'][0]
+ test_atten = self.testclass_params['ota_atten_levels'][band][0]
elif testcase_params['signal_level'] == 'low':
- test_atten = self.testclass_params['default_atten_levels'][1]
+ test_atten = self.testclass_params['ota_atten_levels'][band][1]
return test_atten
def generate_test_cases(self, channels, modes, traffic_types,
@@ -571,16 +611,16 @@
allowed_configs = {
20: [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 64, 100,
- 116, 132, 140, 149, 153, 157, 161
+ 116, 132, 140, 149, 153, 157, 161, '6g37', '6g117', '6g213'
],
- 40: [36, 44, 100, 149, 157],
- 80: [36, 100, 149],
- 160: [36]
+ 40: [36, 44, 100, 149, 157, '6g37', '6g117', '6g213'],
+ 80: [36, 100, 149, '6g37', '6g117', '6g213'],
+ 160: [36, '6g37', '6g117', '6g213']
}
test_cases = []
- for channel, mode, position, traffic_type, signal_level, traffic_direction in itertools.product(
- channels, modes, positions, traffic_types, signal_levels,
+ for channel, mode, signal_level, position, traffic_type, traffic_direction in itertools.product(
+ channels, modes, signal_levels, positions, traffic_types,
traffic_directions):
bandwidth = int(''.join([x for x in mode if x.isdigit()]))
if channel not in allowed_configs[bandwidth]:
@@ -588,6 +628,7 @@
testcase_params = collections.OrderedDict(
channel=channel,
mode=mode,
+ bandwidth=bandwidth,
traffic_type=traffic_type,
traffic_direction=traffic_direction,
signal_level=signal_level,
@@ -608,7 +649,8 @@
):
def __init__(self, controllers):
WifiOtaThroughputStabilityTest.__init__(self, controllers)
- self.tests = self.generate_test_cases([6, 36, 149], ['bw20', 'bw80'],
+ self.tests = self.generate_test_cases([6, 36, 149, '6g37'],
+ ['bw20', 'bw80', 'bw160'],
['TCP'], ['DL', 'UL'],
['high', 'low'], 'orientation',
list(range(0, 360, 10)))
@@ -617,7 +659,8 @@
class WifiOtaThroughputStability_45Degree_Test(WifiOtaThroughputStabilityTest):
def __init__(self, controllers):
WifiOtaThroughputStabilityTest.__init__(self, controllers)
- self.tests = self.generate_test_cases([6, 36, 149], ['bw20', 'bw80'],
+ self.tests = self.generate_test_cases([6, 36, 149, '6g37'],
+ ['bw20', 'bw80', 'bw160'],
['TCP'], ['DL', 'UL'],
['high', 'low'], 'orientation',
list(range(0, 360, 45)))
@@ -627,8 +670,9 @@
WifiOtaThroughputStabilityTest):
def __init__(self, controllers):
WifiOtaThroughputStabilityTest.__init__(self, controllers)
- self.tests = self.generate_test_cases([6, 36, 149], ['bw20', 'bw80'],
+ self.tests = self.generate_test_cases([6, 36, 149, '6g37'],
+ ['bw20', 'bw80', 'bw160'],
['TCP'], ['DL', 'UL'],
['high', 'low'],
'stepped stirrers',
- list(range(100)))
\ No newline at end of file
+ list(range(100)))
diff --git a/acts_tests/tests/google/wifi/WifiTxPowerCheckTest.py b/acts_tests/tests/google/wifi/WifiTxPowerCheckTest.py
new file mode 100644
index 0000000..706903c
--- /dev/null
+++ b/acts_tests/tests/google/wifi/WifiTxPowerCheckTest.py
@@ -0,0 +1,927 @@
+#!/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 collections
+import csv
+import itertools
+import json
+import logging
+import math
+import os
+import re
+import scipy.stats
+import time
+from acts import asserts
+from acts import context
+from acts import base_test
+from acts import utils
+from acts.controllers.utils_lib import ssh
+from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
+from acts_contrib.test_utils.wifi import ota_sniffer
+from acts_contrib.test_utils.wifi import wifi_performance_test_utils as wputils
+from acts_contrib.test_utils.wifi import wifi_retail_ap as retail_ap
+from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from functools import partial
+
+
+class WifiTxPowerCheckTest(base_test.BaseTestClass):
+ """Class for ping-based Wifi performance tests.
+
+ This class implements WiFi ping performance tests such as range and RTT.
+ The class setups up the AP in the desired configurations, configures
+ and connects the phone to the AP, and runs For an example config file to
+ run this test class see example_connectivity_performance_ap_sta.json.
+ """
+
+ TEST_TIMEOUT = 10
+ RSSI_POLL_INTERVAL = 0.2
+ SHORT_SLEEP = 1
+ MED_SLEEP = 5
+ MAX_CONSECUTIVE_ZEROS = 5
+ DISCONNECTED_PING_RESULT = {
+ 'connected': 0,
+ 'rtt': [],
+ 'time_stamp': [],
+ 'ping_interarrivals': [],
+ 'packet_loss_percentage': 100
+ }
+
+ BRCM_SAR_MAPPING = {
+ 0: 'disable',
+ 1: 'head',
+ 2: 'grip',
+ 16: 'bt',
+ 32: 'hotspot'
+ }
+
+ BAND_TO_CHANNEL_MAP = {
+ ('2g', 1): [1, 6, 11],
+ ('5g', 1): [36, 40, 44, 48],
+ ('5g', 2): [52, 56, 60, 64],
+ ('5g', 3): range(100, 148, 4),
+ ('5g', 4): [149, 153, 157, 161],
+ ('6g', 1): ['6g{}'.format(channel) for channel in range(1, 46, 4)],
+ ('6g', 2): ['6g{}'.format(channel) for channel in range(49, 94, 4)],
+ ('6g', 3): ['6g{}'.format(channel) for channel in range(97, 114, 4)],
+ ('6g', 4): ['6g{}'.format(channel) for channel in range(117, 158, 4)],
+ ('6g', 5): ['6g{}'.format(channel) for channel in range(161, 186, 4)],
+ ('6g', 6): ['6g{}'.format(channel) for channel in range(189, 234, 4)]
+ }
+
+ def __init__(self, controllers):
+ base_test.BaseTestClass.__init__(self, controllers)
+ self.testcase_metric_logger = (
+ BlackboxMappedMetricLogger.for_test_case())
+ self.testclass_metric_logger = (
+ BlackboxMappedMetricLogger.for_test_class())
+ self.publish_testcase_metrics = True
+ self.tests = self.generate_test_cases(
+ ap_power='standard',
+ channels=[6, 36, 52, 100, 149, '6g37', '6g117', '6g213'],
+ modes=['bw20', 'bw40', 'bw80', 'bw160'],
+ test_types=[
+ 'test_tx_power',
+ ],
+ country_codes=['US', 'GB', 'JP'],
+ sar_states=range(0, 13))
+
+ def setup_class(self):
+ self.dut = self.android_devices[-1]
+ req_params = [
+ 'tx_power_test_params', 'testbed_params', 'main_network',
+ 'RetailAccessPoints', 'RemoteServer'
+ ]
+ opt_params = ['OTASniffer']
+ self.unpack_userparams(req_params, opt_params)
+ self.testclass_params = self.tx_power_test_params
+ self.num_atten = self.attenuators[0].instrument.num_atten
+ self.ping_server = ssh.connection.SshConnection(
+ ssh.settings.from_config(self.RemoteServer[0]['ssh_config']))
+ self.access_point = retail_ap.create(self.RetailAccessPoints)[0]
+ if hasattr(self,
+ 'OTASniffer') and self.testbed_params['sniffer_enable']:
+ try:
+ self.sniffer = ota_sniffer.create(self.OTASniffer)[0]
+ except:
+ self.log.warning('Could not start sniffer. Disabling sniffs.')
+ self.testbed_params['sniffer_enable'] = 0
+ self.log.info('Access Point Configuration: {}'.format(
+ self.access_point.ap_settings))
+ self.log_path = os.path.join(logging.log_path, 'results')
+ os.makedirs(self.log_path, exist_ok=True)
+ self.atten_dut_chain_map = {}
+ self.testclass_results = []
+
+ # Turn WiFi ON
+ if self.testclass_params.get('airplane_mode', 1):
+ self.log.info('Turning on airplane mode.')
+ asserts.assert_true(utils.force_airplane_mode(self.dut, True),
+ 'Can not turn on airplane mode.')
+ wutils.wifi_toggle_state(self.dut, True)
+ self.dut.droid.wifiEnableVerboseLogging(1)
+ asserts.assert_equal(self.dut.droid.wifiGetVerboseLoggingLevel(), 1,
+ "Failed to enable WiFi verbose logging.")
+
+ # decode nvram
+ self.nvram_sar_data = self.read_nvram_sar_data()
+ self.csv_sar_data = self.read_sar_csv(self.testclass_params['sar_csv'])
+
+ def teardown_class(self):
+ # Turn WiFi OFF and reset AP
+ self.access_point.teardown()
+ for dev in self.android_devices:
+ wutils.wifi_toggle_state(dev, False)
+ dev.go_to_sleep()
+ self.process_testclass_results()
+
+ def setup_test(self):
+ self.retry_flag = False
+
+ def teardown_test(self):
+ self.retry_flag = False
+
+ def on_retry(self):
+ """Function to control test logic on retried tests.
+
+ This function is automatically executed on tests that are being
+ retried. In this case the function resets wifi, toggles it off and on
+ and sets a retry_flag to enable further tweaking the test logic on
+ second attempts.
+ """
+ self.retry_flag = True
+ for dev in self.android_devices:
+ wutils.reset_wifi(dev)
+ wutils.toggle_wifi_off_and_on(dev)
+
+ def read_sar_csv(self, sar_csv):
+ """Reads SAR powers from CSV.
+
+ This function reads SAR powers from a CSV and generate a dictionary
+ with all programmed TX powers on a per band and regulatory domain
+ basis.
+
+ Args:
+ sar_csv: path to SAR data file.
+ Returns:
+ sar_powers: dict containing all SAR data
+ """
+
+ sar_powers = {}
+ sar_csv_data = []
+ with open(sar_csv, mode='r') as f:
+ reader = csv.DictReader(f)
+ for row in reader:
+ row['Sub-band Powers'] = [
+ float(val) for key, val in row.items()
+ if 'Sub-band' in key and val != ''
+ ]
+ sar_csv_data.append(row)
+
+ for row in sar_csv_data:
+ sar_powers.setdefault(int(row['Scenario Index']), {})
+ sar_powers[int(row['Scenario Index'])].setdefault('SAR Powers', {})
+ sar_row_key = (row['Regulatory Domain'], row['Mode'], row['Band'])
+ sar_powers[int(row['Scenario Index'])]['SAR Powers'].setdefault(
+ sar_row_key, {})
+ sar_powers[int(
+ row['Scenario Index'])]['SAR Powers'][sar_row_key][int(
+ row['Chain'])] = row['Sub-band Powers']
+ return sar_powers
+
+ def read_nvram_sar_data(self):
+ """Reads SAR powers from NVRAM.
+
+ This function reads SAR powers from the NVRAM found on the DUT and
+ generates a dictionary with all programmed TX powers on a per band and
+ regulatory domain basis. NThe NVRAM file is chosen based on the build,
+ but if no NVRAM file is found matching the expected name, the default
+ NVRAM will be loaded. The choice of NVRAM is not guaranteed to be
+ correct.
+
+ Returns:
+ nvram_sar_data: dict containing all SAR data
+ """
+
+ self._read_sar_config_info()
+ try:
+ hardware_version = self.dut.adb.shell(
+ 'getprop ro.boot.hardware.revision')
+ nvram_path = '/vendor/firmware/bcmdhd.cal_{}'.format(
+ hardware_version)
+ nvram = self.dut.adb.shell('cat {}'.format(nvram_path))
+ except:
+ nvram = self.dut.adb.shell('cat /vendor/firmware/bcmdhd.cal')
+ current_context = context.get_current_context().get_full_output_path()
+ file_path = os.path.join(current_context, 'nvram_file')
+ with open(file_path, 'w') as file:
+ file.write(nvram)
+ nvram_sar_data = {}
+ for line in nvram.splitlines():
+ if 'dynsar' in line:
+ sar_config, sar_powers = self._parse_nvram_sar_line(line)
+ nvram_sar_data[sar_config] = sar_powers
+ file_path = os.path.join(current_context, 'nvram_sar_data')
+ with open(file_path, 'w') as file:
+ json.dump(wputils.serialize_dict(nvram_sar_data), file, indent=4)
+
+ return nvram_sar_data
+
+ def _read_sar_config_info(self):
+ """Function to read SAR scenario mapping,
+
+ This function reads sar_config.info file which contains the mapping
+ of SAR scenarios to NVRAM data tables.
+ """
+
+ self.sar_state_mapping = collections.OrderedDict([(-1, {
+ "google_name":
+ 'WIFI_POWER_SCENARIO_DISABLE'
+ }), (0, {
+ "google_name": 'WIFI_POWER_SCENARIO_DISABLE'
+ }), (1, {
+ "google_name": 'WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF'
+ }), (2, {
+ "google_name": 'WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON'
+ }), (3, {
+ "google_name": 'WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF'
+ }), (4, {
+ "google_name": 'WIFI_POWER_SCENARIO_ON_BODY_CELL_ON'
+ }), (5, {
+ "google_name": 'WIFI_POWER_SCENARIO_ON_BODY_BT'
+ }), (6, {
+ "google_name": 'WIFI_POWER_SCENARIO_ON_HEAD_HOTSPOT'
+ }), (7, {
+ "google_name": 'WIFI_POWER_SCENARIO_ON_HEAD_HOTSPOT_MMW'
+ }), (8, {
+ "google_name": 'WIFI_POWER_SCENARIO_ON_BODY_CELL_ON_BT'
+ }), (9, {
+ "google_name": 'WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT'
+ }), (10, {
+ "google_name": 'WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_BT'
+ }), (11, {
+ "google_name": 'WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_MMW'
+ }), (12, {
+ "google_name": 'WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_BT_MMW'
+ })])
+ sar_config_path = '/vendor/firmware/sarconfig.info'
+ sar_config = self.dut.adb.shell(
+ 'cat {}'.format(sar_config_path)).splitlines()
+ sar_config = [line.split(',') for line in sar_config]
+ sar_config = [[int(x) for x in line] for line in sar_config]
+
+ for sar_state in sar_config:
+ self.sar_state_mapping[sar_state[0]]['brcm_index'] = (
+ self.BRCM_SAR_MAPPING[sar_state[1]], bool(sar_state[2]))
+ current_context = context.get_current_context().get_full_output_path()
+ file_path = os.path.join(current_context, 'sarconfig')
+ with open(file_path, 'w') as file:
+ json.dump(wputils.serialize_dict(self.sar_state_mapping),
+ file,
+ indent=4)
+
+ def _parse_nvram_sar_line(self, sar_line):
+ """Helper function to decode SAR NVRAM data lines.
+
+ Args:
+ sar_line: single line of text from NVRAM file containing SAR data.
+ Returns:
+ sar_config: sar config referenced in this line
+ decoded_values: tx powers configured in this line
+ """
+
+ sar_config = collections.OrderedDict()
+ list_of_countries = ['fcc', 'jp']
+ try:
+ sar_config['country'] = next(country
+ for country in list_of_countries
+ if country in sar_line)
+ except:
+ sar_config['country'] = 'row'
+
+ list_of_sar_states = ['grip', 'bt', 'hotspot']
+ try:
+ sar_config['state'] = next(state for state in list_of_sar_states
+ if state in sar_line)
+ except:
+ sar_config['state'] = 'head'
+
+ list_of_bands = ['2g', '5g', '6g']
+ sar_config['band'] = next(band for band in list_of_bands
+ if band in sar_line)
+
+ sar_config['rsdb'] = 'rsdb' if 'rsdb' in sar_line else 'mimo'
+ sar_config['airplane_mode'] = '_2=' in sar_line
+
+ sar_powers = sar_line.split('=')[1].split(',')
+ decoded_powers = []
+ for sar_power in sar_powers:
+ decoded_powers.append([
+ (int(sar_power[2:4], 16) & int('7f', 16)) / 4,
+ (int(sar_power[4:], 16) & int('7f', 16)) / 4
+ ])
+
+ return tuple(sar_config.values()), decoded_powers
+
+ def get_sar_power_from_nvram(self, testcase_params):
+ """Function to get current expected SAR power from nvram
+
+ This functions gets the expected SAR TX power from the DUT NVRAM data.
+ The SAR power is looked up based on the current channel and regulatory
+ domain,
+
+ Args:
+ testcase_params: dict containing channel, sar state, country code
+ Returns:
+ sar_config: current expected sar config
+ sar_powers: current expected sar powers
+ """
+
+ if testcase_params['country_code'] == 'US':
+ reg_domain = 'fcc'
+ elif testcase_params['country_code'] == 'JP':
+ reg_domain = 'jp'
+ else:
+ reg_domain = 'row'
+ for band, channels in self.BAND_TO_CHANNEL_MAP.items():
+ if testcase_params['channel'] in channels:
+ current_band = band[0]
+ sub_band_idx = band[1]
+ break
+ sar_config = (reg_domain, self.sar_state_mapping[
+ testcase_params['sar_state']]['brcm_index'][0], current_band,
+ 'mimo', self.sar_state_mapping[
+ testcase_params['sar_state']]['brcm_index'][1])
+ sar_powers = self.nvram_sar_data[sar_config][sub_band_idx - 1]
+ return sar_config, sar_powers
+
+ def get_sar_power_from_csv(self, testcase_params):
+ """Function to get current expected SAR power from CSV.
+
+ This functions gets the expected SAR TX power from the DUT NVRAM data.
+ The SAR power is looked up based on the current channel and regulatory
+ domain,
+
+ Args:
+ testcase_params: dict containing channel, sar state, country code
+ Returns:
+ sar_config: current expected sar config
+ sar_powers: current expected sar powers
+ """
+
+ if testcase_params['country_code'] == 'US':
+ reg_domain = 'fcc'
+ elif testcase_params['country_code'] == 'JP':
+ reg_domain = 'jp'
+ else:
+ reg_domain = 'row'
+ for band, channels in self.BAND_TO_CHANNEL_MAP.items():
+ if testcase_params['channel'] in channels:
+ current_band = band[0]
+ sub_band_idx = band[1]
+ break
+ sar_config = (reg_domain, 'mimo', current_band)
+ sar_powers = [
+ self.csv_sar_data[testcase_params['sar_state']]['SAR Powers']
+ [sar_config][0][sub_band_idx - 1],
+ self.csv_sar_data[testcase_params['sar_state']]['SAR Powers']
+ [sar_config][1][sub_band_idx - 1]
+ ]
+ return sar_config, sar_powers
+
+ def process_wl_curpower(self, wl_curpower_file, testcase_params):
+ """Function to parse wl_curpower output.
+
+ Args:
+ wl_curpower_file: path to curpower output file.
+ testcase_params: dict containing channel, sar state, country code
+ Returns:
+ wl_curpower_dict: dict formatted version of curpower data.
+ """
+
+ with open(wl_curpower_file, 'r') as file:
+ wl_curpower_out = file.read()
+
+ channel_regex = re.compile(r'Current Channel:\s+(?P<channel>[0-9]+)')
+ bandwidth_regex = re.compile(
+ r'Channel Width:\s+(?P<bandwidth>\S+)MHz\n')
+
+ channel = int(
+ re.search(channel_regex, wl_curpower_out).group('channel'))
+ bandwidth = int(
+ re.search(bandwidth_regex, wl_curpower_out).group('bandwidth'))
+
+ regulatory_limits = self.generate_regulatory_table(
+ wl_curpower_out, channel, bandwidth)
+ board_limits = self.generate_board_limit_table(wl_curpower_out,
+ channel, bandwidth)
+ wl_curpower_dict = {
+ 'channel': channel,
+ 'bandwidth': bandwidth,
+ 'country': testcase_params['country_code'],
+ 'regulatory_limits': regulatory_limits,
+ 'board_limits': board_limits
+ }
+ return wl_curpower_dict
+
+ def generate_regulatory_table(self, wl_curpower_out, channel, bw):
+ """"Helper function to generate regulatory limit table from curpower.
+
+ Args:
+ wl_curpower_out: curpower output
+ channel: current channel
+ bw: current bandwidth
+ Returns:
+ regulatory_table: dict with regulatory limits for current config
+ """
+
+ regulatory_group_map = {
+ 'DSSS':
+ [('CCK', rate, 1)
+ for rate in ['{}Mbps'.format(mbps) for mbps in [1, 2, 5.5, 11]]],
+ 'OFDM_CDD1': [('LEGACY', rate, 1) for rate in [
+ '{}Mbps'.format(mbps)
+ for mbps in [6, 9, 12, 18, 24, 36, 48, 54]
+ ]],
+ 'MCS0_7_CDD1':
+ [(mode, rate, 1)
+ for (mode,
+ rate) in itertools.product(['HT' + str(bw), 'VHT' +
+ str(bw)], range(0, 8))],
+ 'VHT8_9SS1_CDD1': [('VHT' + str(bw), 8, 1),
+ ('VHT' + str(bw), 9, 1)],
+ 'VHT10_11SS1_CDD1': [('VHT' + str(bw), 10, 1),
+ ('VHT' + str(bw), 11, 1)],
+ 'MCS8_15':
+ [(mode, rate - 8 * ('VHT' in mode), 2)
+ for (mode,
+ rate) in itertools.product(['HT' + str(bw), 'VHT' +
+ str(bw)], range(8, 16))],
+ 'VHT8_9SS2': [('VHT' + str(bw), 8, 2), ('VHT' + str(bw), 9, 2)],
+ 'VHT10_11SS2': [('VHT' + str(bw), 10, 2),
+ ('VHT' + str(bw), 11, 2)],
+ 'HE_MCS0-11_CDD1': [('HE' + str(bw), rate, 1)
+ for rate in range(0, 12)],
+ 'HE_MCS0_11SS2': [('HE' + str(bw), rate, 2)
+ for rate in range(0, 12)],
+ }
+ tx_power_regex = re.compile(
+ '(?P<mcs>\S+)\s+(?P<chain>[2])\s+(?P<power_1>[0-9.-]+)\s*(?P<power_2>[0-9.-]*)\s*(?P<power_3>[0-9.-]*)\s*(?P<power_4>[0-9.-]*)'
+ )
+
+ regulatory_section_regex = re.compile(
+ r'Regulatory Limits:(?P<regulatory_limits>[\S\s]+)Board Limits:')
+ regulatory_list = re.search(regulatory_section_regex,
+ wl_curpower_out).group('regulatory_limits')
+ regulatory_list = re.findall(tx_power_regex, regulatory_list)
+ regulatory_dict = {entry[0]: entry[2:] for entry in regulatory_list}
+
+ bw_index = int(math.log(bw / 10, 2)) - 1
+ regulatory_table = collections.OrderedDict()
+ for regulatory_group, rates in regulatory_group_map.items():
+ for rate in rates:
+ reg_power = regulatory_dict.get(regulatory_group,
+ ['0', '0', '0', '0'])[bw_index]
+ regulatory_table[rate] = float(
+ reg_power) if reg_power != '-' else 0
+ return regulatory_table
+
+ def generate_board_limit_table(self, wl_curpower_out, channel, bw):
+ """"Helper function to generate board limit table from curpower.
+
+ Args:
+ wl_curpower_out: curpower output
+ channel: current channel
+ bw: current bandwidth
+ Returns:
+ board_limit_table: dict with board limits for current config
+ """
+
+ tx_power_regex = re.compile(
+ '(?P<mcs>\S+)\s+(?P<chain>[2])\s+(?P<power_1>[0-9.-]+)\s*(?P<power_2>[0-9.-]*)\s*(?P<power_3>[0-9.-]*)\s*(?P<power_4>[0-9.-]*)'
+ )
+
+ board_section_regex = re.compile(
+ r'Board Limits:(?P<board_limits>[\S\s]+)Power Targets:')
+ board_limits_list = re.search(board_section_regex,
+ wl_curpower_out).group('board_limits')
+ board_limits_list = re.findall(tx_power_regex, board_limits_list)
+ board_limits_dict = {
+ entry[0]: entry[2:]
+ for entry in board_limits_list
+ }
+
+ mcs_regex_list = [[
+ re.compile('DSSS'),
+ [('CCK', rate, 1)
+ for rate in ['{}Mbps'.format(mbps) for mbps in [1, 2, 5.5, 11]]]
+ ], [re.compile('OFDM(?P<mcs>[0-9]+)_CDD1'), [('LEGACY', '{}Mbps', 1)]],
+ [
+ re.compile('MCS(?P<mcs>[0-7])_CDD1'),
+ [('HT{}'.format(bw), '{}', 1),
+ ('VHT{}'.format(bw), '{}', 1)]
+ ],
+ [
+ re.compile('VHT(?P<mcs>[8-9])SS1_CDD1'),
+ [('VHT{}'.format(bw), '{}', 1)]
+ ],
+ [
+ re.compile('VHT10_11SS1_CDD1'),
+ [('VHT{}'.format(bw), '10', 1),
+ ('VHT{}'.format(bw), '11', 1)]
+ ],
+ [
+ re.compile('MCS(?P<mcs>[0-9]{2})'),
+ [('HT{}'.format(bw), '{}', 2)]
+ ],
+ [
+ re.compile('VHT(?P<mcs>[0-9])SS2'),
+ [('VHT{}'.format(bw), '{}', 2)]
+ ],
+ [
+ re.compile('VHT10_11SS2'),
+ [('VHT{}'.format(bw), '10', 2),
+ ('VHT{}'.format(bw), '11', 2)]
+ ],
+ [
+ re.compile('HE_MCS(?P<mcs>[0-9]+)_CDD1'),
+ [('HE{}'.format(bw), '{}', 1)]
+ ],
+ [
+ re.compile('HE_MCS(?P<mcs>[0-9]+)SS2'),
+ [('HE{}'.format(bw), '{}', 2)]
+ ]]
+
+ bw_index = int(math.log(bw / 10, 2)) - 1
+ board_limit_table = collections.OrderedDict()
+ for mcs, board_limit in board_limits_dict.items():
+ for mcs_regex_tuple in mcs_regex_list:
+ mcs_match = re.match(mcs_regex_tuple[0], mcs)
+ if mcs_match:
+ for possible_mcs in mcs_regex_tuple[1]:
+ try:
+ curr_mcs = (possible_mcs[0],
+ possible_mcs[1].format(
+ mcs_match.group('mcs')),
+ possible_mcs[2])
+ except:
+ curr_mcs = (possible_mcs[0], possible_mcs[1],
+ possible_mcs[2])
+ board_limit_table[curr_mcs] = float(
+ board_limit[bw_index]
+ ) if board_limit[bw_index] != '-' else 0
+ break
+ return board_limit_table
+
+ def pass_fail_check(self, result):
+ """Function to evaluate if current TX powqe matches CSV/NVRAM settings.
+
+ This function assesses whether the current TX power reported by the
+ DUT matches the powers programmed in NVRAM and CSV after applying the
+ correct TX power backoff used to account for CLPC errors.
+ """
+
+ if isinstance(result['testcase_params']['channel'],
+ str) and '6g' in result['testcase_params']['channel']:
+ mode = 'HE' + str(result['testcase_params']['bandwidth'])
+ else:
+ mode = 'VHT' + str(result['testcase_params']['bandwidth'])
+ regulatory_power = result['wl_curpower']['regulatory_limits'][(mode, 0,
+ 2)]
+ if result['testcase_params']['sar_state'] == 0:
+ #get from wl_curpower
+ csv_powers = [30, 30]
+ nvram_powers = [30, 30]
+ sar_config = 'SAR DISABLED'
+ else:
+ sar_config, nvram_powers = self.get_sar_power_from_nvram(
+ result['testcase_params'])
+ csv_config, csv_powers = self.get_sar_power_from_csv(
+ result['testcase_params'])
+ self.log.info("SAR state: {} ({})".format(
+ result['testcase_params']['sar_state'],
+ self.sar_state_mapping[result['testcase_params']['sar_state']],
+ ))
+ self.log.info("Country Code: {}".format(
+ result['testcase_params']['country_code']))
+ self.log.info('BRCM SAR Table: {}'.format(sar_config))
+ expected_power = [
+ min([csv_powers[0], regulatory_power]) - 1.5,
+ min([csv_powers[1], regulatory_power]) - 1.5
+ ]
+ power_str = "NVRAM Powers: {}, CSV Powers: {}, Reg Powers: {}, Expected Powers: {}, Reported Powers: {}".format(
+ nvram_powers, csv_powers, [regulatory_power] * 2, expected_power,
+ result['tx_powers'])
+ max_error = max([
+ abs(expected_power[idx] - result['tx_powers'][idx])
+ for idx in [0, 1]
+ ])
+ if max_error > 1:
+ asserts.fail(power_str)
+ else:
+ asserts.explicit_pass(power_str)
+
+ def process_testclass_results(self):
+ pass
+
+ def run_tx_power_test(self, testcase_params):
+ """Main function to test tx power.
+
+ The function sets up the AP & DUT in the correct channel and mode
+ configuration, starts ping traffic and queries the current TX power.
+
+ Args:
+ testcase_params: dict containing all test parameters
+ Returns:
+ test_result: dict containing ping results and other meta data
+ """
+ # Prepare results dict
+ llstats_obj = wputils.LinkLayerStats(
+ self.dut, self.testclass_params.get('llstats_enabled', True))
+ test_result = collections.OrderedDict()
+ test_result['testcase_params'] = testcase_params.copy()
+ test_result['test_name'] = self.current_test_name
+ test_result['ap_config'] = self.access_point.ap_settings.copy()
+ test_result['attenuation'] = testcase_params['atten_range']
+ test_result['fixed_attenuation'] = self.testbed_params[
+ 'fixed_attenuation'][str(testcase_params['channel'])]
+ test_result['rssi_results'] = []
+ test_result['ping_results'] = []
+ test_result['llstats'] = []
+ # Setup sniffer
+ if self.testbed_params['sniffer_enable']:
+ self.sniffer.start_capture(
+ testcase_params['test_network'],
+ chan=testcase_params['channel'],
+ bw=testcase_params['bandwidth'],
+ duration=testcase_params['ping_duration'] *
+ len(testcase_params['atten_range']) + self.TEST_TIMEOUT)
+ # Run ping and sweep attenuation as needed
+ self.log.info('Starting ping.')
+ thread_future = wputils.get_ping_stats_nb(self.ping_server,
+ self.dut_ip, 10, 0.02, 64)
+
+ for atten in testcase_params['atten_range']:
+ for attenuator in self.attenuators:
+ attenuator.set_atten(atten, strict=False, retry=True)
+ # Set mcs
+ if isinstance(testcase_params['channel'],
+ int) and testcase_params['channel'] < 13:
+ self.dut.adb.shell('wl 2g_rate -v 0x2 -b {}'.format(
+ testcase_params['bandwidth']))
+ elif isinstance(testcase_params['channel'],
+ int) and testcase_params['channel'] > 13:
+ self.dut.adb.shell('wl 5g_rate -v 0x2 -b {}'.format(
+ testcase_params['bandwidth']))
+ else:
+ self.dut.adb.shell('wl 6g_rate -e 0 -s 2 -b {}'.format(
+ testcase_params['bandwidth']))
+ # Set sar state
+ self.dut.adb.shell('halutil -sar enable {}'.format(
+ testcase_params['sar_state']))
+ # Refresh link layer stats
+ llstats_obj.update_stats()
+ # Check sar state
+ self.log.info('Current Country: {}'.format(
+ self.dut.adb.shell('wl country')))
+ # Dump last est power multiple times
+ chain_0_power = []
+ chain_1_power = []
+ for idx in range(30):
+ last_est_out = self.dut.adb.shell(
+ "wl curpower | grep 'Last est. power'", ignore_status=True)
+ if "Last est. power" in last_est_out:
+ per_chain_powers = last_est_out.split(
+ ':')[1].strip().split(' ')
+ per_chain_powers = [
+ float(power) for power in per_chain_powers
+ ]
+ self.log.info(
+ 'Current Tx Powers = {}'.format(per_chain_powers))
+ if per_chain_powers[0] > 0:
+ chain_0_power.append(per_chain_powers[0])
+ if per_chain_powers[1] > 0:
+ chain_1_power.append(per_chain_powers[1])
+ time.sleep(0.25)
+ # Check if empty
+ if len(chain_0_power) == 0 or len(chain_1_power) == 0:
+ test_result['tx_powers'] = [0, 0]
+ tx_power_frequency = [100, 100]
+ else:
+ test_result['tx_powers'] = [
+ scipy.stats.mode(chain_0_power).mode[0],
+ scipy.stats.mode(chain_1_power).mode[0]
+ ]
+ tx_power_frequency = [
+ 100 * scipy.stats.mode(chain_0_power).count[0] /
+ len(chain_0_power),
+ 100 * scipy.stats.mode(chain_1_power).count[0] /
+ len(chain_0_power)
+ ]
+ self.log.info(
+ 'Filtered Tx Powers = {}. Frequency = [{:.0f}%, {:.0f}%]'.
+ format(test_result['tx_powers'], tx_power_frequency[0],
+ tx_power_frequency[1]))
+ llstats_obj.update_stats()
+ curr_llstats = llstats_obj.llstats_incremental.copy()
+ test_result['llstats'].append(curr_llstats)
+ # DUMP wl curpower one
+ try:
+ wl_curpower = self.dut.adb.shell('wl curpower')
+ except:
+ time.sleep(0.25)
+ wl_curpower = self.dut.adb.shell('wl curpower',
+ ignore_status=True)
+ current_context = context.get_current_context(
+ ).get_full_output_path()
+ wl_curpower_path = os.path.join(current_context,
+ 'wl_curpower_output')
+ with open(wl_curpower_path, 'w') as file:
+ file.write(wl_curpower)
+ wl_curpower_dict = self.process_wl_curpower(
+ wl_curpower_path, testcase_params)
+ wl_curpower_path = os.path.join(current_context,
+ 'wl_curpower_dict')
+ with open(wl_curpower_path, 'w') as file:
+ json.dump(wputils.serialize_dict(wl_curpower_dict),
+ file,
+ indent=4)
+ test_result['wl_curpower'] = wl_curpower_dict
+ thread_future.result()
+ if self.testbed_params['sniffer_enable']:
+ self.sniffer.stop_capture()
+ return test_result
+
+ def setup_ap(self, testcase_params):
+ """Sets up the access point in the configuration required by the test.
+
+ Args:
+ testcase_params: dict containing AP and other test params
+ """
+ band = self.access_point.band_lookup_by_channel(
+ testcase_params['channel'])
+ if '6G' in band:
+ frequency = wutils.WifiEnums.channel_6G_to_freq[int(
+ testcase_params['channel'].strip('6g'))]
+ else:
+ if testcase_params['channel'] < 13:
+ frequency = wutils.WifiEnums.channel_2G_to_freq[
+ testcase_params['channel']]
+ else:
+ frequency = wutils.WifiEnums.channel_5G_to_freq[
+ testcase_params['channel']]
+ if frequency in wutils.WifiEnums.DFS_5G_FREQUENCIES:
+ self.access_point.set_region(self.testbed_params['DFS_region'])
+ else:
+ self.access_point.set_region(self.testbed_params['default_region'])
+ self.access_point.set_channel(band, testcase_params['channel'])
+ self.access_point.set_bandwidth(band, testcase_params['mode'])
+ if 'low' in testcase_params['ap_power']:
+ self.log.info('Setting low AP power.')
+ self.access_point.set_power(
+ band, self.testclass_params['low_ap_tx_power'])
+ self.log.info('Access Point Configuration: {}'.format(
+ self.access_point.ap_settings))
+
+ def setup_dut(self, testcase_params):
+ """Sets up the DUT in the configuration required by the test.
+
+ Args:
+ testcase_params: dict containing AP and other test params
+ """
+ # Turn screen off to preserve battery
+ if self.testbed_params.get('screen_on',
+ False) or self.testclass_params.get(
+ 'screen_on', False):
+ self.dut.droid.wakeLockAcquireDim()
+ else:
+ self.dut.go_to_sleep()
+ if wputils.validate_network(self.dut,
+ testcase_params['test_network']['SSID']):
+ current_country = self.dut.adb.shell('wl country')
+ self.log.info('Current country code: {}'.format(current_country))
+ if testcase_params['country_code'] in current_country:
+ self.log.info('Already connected to desired network')
+ self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses(
+ 'wlan0')[0]
+ return
+ testcase_params['test_network']['channel'] = testcase_params['channel']
+ wutils.wifi_toggle_state(self.dut, False)
+ wutils.set_wifi_country_code(self.dut, testcase_params['country_code'])
+ wutils.wifi_toggle_state(self.dut, True)
+ wutils.reset_wifi(self.dut)
+ if self.testbed_params.get('txbf_off', False):
+ wputils.disable_beamforming(self.dut)
+ wutils.set_wifi_country_code(self.dut, testcase_params['country_code'])
+ wutils.wifi_connect(self.dut,
+ testcase_params['test_network'],
+ num_of_tries=1,
+ check_connectivity=True)
+ self.dut_ip = self.dut.droid.connectivityGetIPv4Addresses('wlan0')[0]
+
+ def setup_tx_power_test(self, testcase_params):
+ """Function that gets devices ready for the test.
+
+ Args:
+ testcase_params: dict containing test-specific parameters
+ """
+ # Configure AP
+ self.setup_ap(testcase_params)
+ # Set attenuator to 0 dB
+ for attenuator in self.attenuators:
+ attenuator.set_atten(0, strict=False, retry=True)
+ # Reset, configure, and connect DUT
+ self.setup_dut(testcase_params)
+
+ def check_skip_conditions(self, testcase_params):
+ """Checks if test should be skipped."""
+ # Check battery level before test
+ if not wputils.health_check(self.dut, 10):
+ asserts.skip('DUT battery level too low.')
+ if testcase_params[
+ 'channel'] in wputils.CHANNELS_6GHz and not self.dut.droid.is6GhzBandSupported(
+ ):
+ asserts.skip('DUT does not support 6 GHz band.')
+ if not self.access_point.band_lookup_by_channel(
+ testcase_params['channel']):
+ asserts.skip('AP does not support requested channel.')
+
+ def compile_test_params(self, testcase_params):
+ """Function to compile all testcase parameters."""
+
+ self.check_skip_conditions(testcase_params)
+
+ band = self.access_point.band_lookup_by_channel(
+ testcase_params['channel'])
+ testcase_params['test_network'] = self.main_network[band]
+ testcase_params['attenuated_chain'] = -1
+ testcase_params.update(
+ ping_interval=self.testclass_params['ping_interval'],
+ ping_duration=self.testclass_params['ping_duration'],
+ ping_size=self.testclass_params['ping_size'],
+ )
+
+ testcase_params['atten_range'] = [0]
+ return testcase_params
+
+ def _test_ping(self, testcase_params):
+ """ Function that gets called for each range test case
+
+ The function gets called in each range test case. It customizes the
+ range test based on the test name of the test that called it
+
+ Args:
+ testcase_params: dict containing preliminary set of parameters
+ """
+ # Compile test parameters from config and test name
+ testcase_params = self.compile_test_params(testcase_params)
+ # Run ping test
+ self.setup_tx_power_test(testcase_params)
+ result = self.run_tx_power_test(testcase_params)
+ self.pass_fail_check(result)
+
+ def generate_test_cases(self, ap_power, channels, modes, test_types,
+ country_codes, sar_states):
+ """Function that auto-generates test cases for a test class."""
+ test_cases = []
+ allowed_configs = {
+ 20: [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 64, 100,
+ 116, 132, 140, 149, 153, 157, 161
+ ],
+ 40: [36, 44, 100, 149, 157],
+ 80: [36, 100, 149],
+ 160: [36, '6g37', '6g117', '6g213']
+ }
+
+ for channel, mode, test_type, country_code, sar_state in itertools.product(
+ channels, modes, test_types, country_codes, sar_states):
+ bandwidth = int(''.join([x for x in mode if x.isdigit()]))
+ if channel not in allowed_configs[bandwidth]:
+ continue
+ testcase_name = '{}_ch{}_{}_{}_sar_{}'.format(
+ test_type, channel, mode, country_code, sar_state)
+ testcase_params = collections.OrderedDict(
+ test_type=test_type,
+ ap_power=ap_power,
+ channel=channel,
+ mode=mode,
+ bandwidth=bandwidth,
+ country_code=country_code,
+ sar_state=sar_state)
+ setattr(self, testcase_name,
+ partial(self._test_ping, testcase_params))
+ test_cases.append(testcase_name)
+ return test_cases
diff --git a/acts_tests/tests/google/wifi/aware/functional/ProtocolsMultiCountryTest.py b/acts_tests/tests/google/wifi/aware/functional/ProtocolsMultiCountryTest.py
new file mode 100644
index 0000000..f23ecb7
--- /dev/null
+++ b/acts_tests/tests/google/wifi/aware/functional/ProtocolsMultiCountryTest.py
@@ -0,0 +1,231 @@
+#!/usr/bin/python3
+#
+# Copyright 2020 - 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 acts.test_utils.wifi.wifi_test_utils as wutils
+
+import time
+import random
+import re
+import logging
+import acts.controllers.packet_capture as packet_capture
+import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
+
+from acts import asserts
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.net import nsd_const as nconsts
+from acts_contrib.test_utils.wifi.aware import aware_const as aconsts
+from acts_contrib.test_utils.wifi.aware import aware_test_utils as autils
+from acts_contrib.test_utils.wifi.aware.AwareBaseTest import AwareBaseTest
+from acts.controllers.ap_lib.hostapd_constants import CHANNEL_MAP
+
+WifiEnums = wutils.WifiEnums
+
+class ProtocolsMultiCountryTest(AwareBaseTest):
+ def __init__(self, controllers):
+ AwareBaseTest.__init__(self, controllers)
+ self.basetest_name = (
+ "ping6_ib_unsolicited_passive_multicountry",
+ "ping6_ib_solicited_active_multicountry",
+ )
+
+ self.generate_tests()
+
+ def generate_testcase(self, basetest_name, country):
+ """Generates a single test case from the given data.
+
+ Args:
+ basetest_name: The name of the base test case.
+ country: The information about the country code under test.
+ """
+ base_test = getattr(self, basetest_name)
+ test_tracker_uuid = ""
+
+ testcase_name = 'test_%s_%s' % (basetest_name, country)
+ test_case = test_tracker_info(uuid=test_tracker_uuid)(
+ lambda: base_test(country))
+ setattr(self, testcase_name, test_case)
+ self.tests.append(testcase_name)
+
+ def generate_tests(self):
+ for country in self.user_params['wifi_country_code']:
+ for basetest_name in self.basetest_name:
+ self.generate_testcase(basetest_name, country)
+
+ def setup_class(self):
+ super().setup_class()
+ for ad in self.android_devices:
+ ad.droid.wakeLockAcquireBright()
+ ad.droid.wakeUpNow()
+ wutils.wifi_test_device_init(ad)
+
+ if hasattr(self, 'packet_capture'):
+ self.packet_capture = self.packet_capture[0]
+ self.channel_list_2g = WifiEnums.ALL_2G_FREQUENCIES
+ self.channel_list_5g = WifiEnums.ALL_5G_FREQUENCIES
+
+ def setup_test(self):
+ super(ProtocolsMultiCountryTest, self).setup_test()
+ for ad in self.android_devices:
+ ad.ed.clear_all_events()
+
+ def test_time(self,begin_time):
+ super(ProtocolsMultiCountryTest, self).setup_test()
+ for ad in self.android_devices:
+ ad.cat_adb_log(begin_time)
+
+ def teardown_test(self):
+ super(ProtocolsMultiCountryTest, self).teardown_test()
+ for ad in self.android_devices:
+ ad.adb.shell("cmd wifiaware reset")
+
+
+ """Set of tests for Wi-Fi Aware data-paths: validating protocols running on
+ top of a data-path"""
+
+ SERVICE_NAME = "GoogleTestServiceXY"
+
+ def run_ping6(self, dut, peer_ipv6):
+ """Run a ping6 over the specified device/link
+ Args:
+ dut: Device on which to execute ping6
+ peer_ipv6: Scoped IPv6 address of the peer to ping
+ """
+ cmd = "ping6 -c 3 -W 5 %s" % peer_ipv6
+ results = dut.adb.shell(cmd)
+ self.log.info("cmd='%s' -> '%s'", cmd, results)
+ if results == "":
+ asserts.fail("ping6 empty results - seems like a failure")
+
+ def get_ndp_freq(self, dut):
+ """ get aware interface status"""
+ get_nda0 = "timeout 3 logcat | grep getNdpConfirm | grep Channel"
+ out_nda01 = dut.adb.shell(get_nda0)
+ out_nda0 = re.findall("Channel = (\d+)", out_nda01)
+ return out_nda0
+
+
+ def conf_packet_capture(self, band, channel):
+ """Configure packet capture on necessary channels."""
+ freq_to_chan = wutils.WifiEnums.freq_to_channel[int(channel)]
+ logging.info("Capturing packets from "
+ "frequency:{}, Channel:{}".format(channel, freq_to_chan))
+ result = self.packet_capture.configure_monitor_mode(band, freq_to_chan)
+ if not result:
+ logging.error("Failed to configure channel "
+ "for {} band".format(band))
+ self.pcap_procs = wutils.start_pcap(
+ self.packet_capture, band, self.test_name)
+ time.sleep(5)
+
+ ########################################################################
+
+ @test_tracker_info(uuid="3b09e666-c526-4879-8180-77d9a55a2833")
+ def ping6_ib_unsolicited_passive_multicountry(self, country):
+ """Validate that ping6 works correctly on an NDP created using Aware
+ discovery with UNSOLICITED/PASSIVE sessions."""
+ p_dut = self.android_devices[0]
+ s_dut = self.android_devices[1]
+ wutils.set_wifi_country_code(p_dut, country)
+ wutils.set_wifi_country_code(s_dut, country)
+ #p_dut.adb.shell("timeout 12 logcat -c")
+ # create NDP
+ (p_req_key, s_req_key, p_aware_if, s_aware_if, p_ipv6,
+ s_ipv6) = autils.create_ib_ndp(
+ p_dut,
+ s_dut,
+ p_config=autils.create_discovery_config(
+ self.SERVICE_NAME, aconsts.PUBLISH_TYPE_UNSOLICITED),
+ s_config=autils.create_discovery_config(
+ self.SERVICE_NAME, aconsts.SUBSCRIBE_TYPE_PASSIVE),
+ device_startup_offset=self.device_startup_offset)
+ self.log.info("Interface names: P=%s, S=%s", p_aware_if, s_aware_if)
+ self.log.info("Interface addresses (IPv6): P=%s, S=%s", p_ipv6, s_ipv6)
+ ndpfreg =int(self.get_ndp_freq(p_dut)[-1])
+ ndp_channel = str(CHANNEL_MAP[ndpfreg])
+ n = int(ndp_channel)
+ if n in range(len(self.channel_list_2g)):
+ ndp_band = '2g'
+ else:
+ ndp_band = '5g'
+ p_dut.log.info('ndp frequency : {}'.format(ndpfreg))
+ p_dut.log.info('ndp channel : {}'.format(ndp_channel))
+ p_dut.log.info('ndp band : {}'.format(ndp_band))
+
+ # start-snifferlog
+ if hasattr(self, 'packet_capture'):
+ self.conf_packet_capture(ndp_band, ndpfreg)
+
+ # run ping6
+ self.run_ping6(p_dut, s_ipv6)
+ self.run_ping6(s_dut, p_ipv6)
+
+ # clean-up
+ p_dut.droid.connectivityUnregisterNetworkCallback(p_req_key)
+ s_dut.droid.connectivityUnregisterNetworkCallback(s_req_key)
+
+ # stop-snifferlog
+ if hasattr(self, 'packet_capture'):
+ wutils.stop_pcap(self.packet_capture, self.pcap_procs, False)
+ time.sleep(10)
+
+ @test_tracker_info(uuid="6b54951f-bf0b-4d26-91d6-c9b3b8452873")
+ def ping6_ib_solicited_active_multicountry(self, country):
+ """Validate that ping6 works correctly on an NDP created using Aware
+ discovery with SOLICITED/ACTIVE sessions."""
+ p_dut = self.android_devices[0]
+ s_dut = self.android_devices[1]
+ wutils.set_wifi_country_code(p_dut, country)
+ wutils.set_wifi_country_code(s_dut, country)
+
+ # create NDP
+ (p_req_key, s_req_key, p_aware_if, s_aware_if, p_ipv6,
+ s_ipv6) = autils.create_ib_ndp(
+ p_dut,
+ s_dut,
+ p_config=autils.create_discovery_config(
+ self.SERVICE_NAME, aconsts.PUBLISH_TYPE_SOLICITED),
+ s_config=autils.create_discovery_config(
+ self.SERVICE_NAME, aconsts.SUBSCRIBE_TYPE_ACTIVE),
+ device_startup_offset=self.device_startup_offset)
+ self.log.info("Interface names: P=%s, S=%s", p_aware_if, s_aware_if)
+ self.log.info("Interface addresses (IPv6): P=%s, S=%s", p_ipv6, s_ipv6)
+ ndpfreg =int(self.get_ndp_freq(p_dut)[-1])
+ ndp_channel = str(CHANNEL_MAP[ndpfreg])
+ n = int(ndp_channel)
+ if n in range(len(self.channel_list_2g)):
+ ndp_band = '2g'
+ else:
+ ndp_band = '5g'
+ p_dut.log.info('ndp frequency : {}'.format(ndpfreg))
+ p_dut.log.info('ndp channel : {}'.format(ndp_channel))
+ p_dut.log.info('ndp band : {}'.format(ndp_band))
+
+ # start-snifferlog
+ if hasattr(self, 'packet_capture'):
+ self.conf_packet_capture(ndp_band, ndpfreg)
+
+ # run ping6
+ self.run_ping6(p_dut, s_ipv6)
+ self.run_ping6(s_dut, p_ipv6)
+
+ # clean-up
+ p_dut.droid.connectivityUnregisterNetworkCallback(p_req_key)
+ s_dut.droid.connectivityUnregisterNetworkCallback(s_req_key)
+
+ # stop-snifferlog
+ if hasattr(self, 'packet_capture'):
+ wutils.stop_pcap(self.packet_capture, self.pcap_procs, False)
+ time.sleep(10)
diff --git a/acts_tests/tests/google/wifi/aware/performance/WifiAwareRvrTest.py b/acts_tests/tests/google/wifi/aware/performance/WifiAwareRvrTest.py
index 2e18bc7..209b081 100644
--- a/acts_tests/tests/google/wifi/aware/performance/WifiAwareRvrTest.py
+++ b/acts_tests/tests/google/wifi/aware/performance/WifiAwareRvrTest.py
@@ -26,6 +26,7 @@
from acts.controllers import iperf_client as ipc
from acts.controllers.adb_lib.error import AdbCommandError
from acts.metrics.loggers.blackbox import BlackboxMappedMetricLogger
+from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.wifi import ota_sniffer
from acts_contrib.test_utils.wifi import wifi_retail_ap as retail_ap
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
@@ -119,6 +120,8 @@
wutils.wifi_toggle_state(ad, True)
def teardown_class(self):
+ for ap in self.access_points:
+ ap.teardown()
# Turn WiFi OFF
for dev in self.android_devices:
wutils.wifi_toggle_state(dev, False)
@@ -142,6 +145,12 @@
wutils.reset_wifi(ad)
wputils.stop_wifi_logging(ad)
+ def on_exception(self, test_name, begin_time):
+ for ad in self.android_devices:
+ ad.take_bug_report(test_name, begin_time)
+ ad.cat_adb_log(test_name, begin_time)
+ wutils.get_ssrdumps(ad)
+
def compute_test_metrics(self, rvr_result):
#Set test metrics
rvr_result['metrics'] = {}
@@ -271,9 +280,13 @@
ndp_config = self.android_devices[0].adb.shell(
'cmd wifiaware native_cb get_channel_info')
ndp_config = json.loads(ndp_config)
- ndp_config = ndp_config[list(ndp_config.keys())[0]][0]
- testcase_params['channel'] = wutils.WifiEnums.freq_to_channel[
- ndp_config['channelFreq']]
+ ndp_config = ndp_config[list(ndp_config.keys())[0]]
+ if ndp_config:
+ testcase_params['channel'] = wutils.WifiEnums.freq_to_channel[
+ ndp_config[0]['channelFreq']]
+ else:
+ self.log.warning('Unknown NDP channel. Setting sniffer to Ch149')
+ testcase_params['channel'] = 149
if testcase_params['channel'] < 13:
testcase_params['mode'] = 'VHT20'
else:
@@ -423,8 +436,15 @@
traffic_type=traffic_type,
traffic_direction=traffic_direction,
concurrency_state=concurrency_state)
- setattr(self, test_name, partial(self._test_aware_rvr,
- test_params))
+ test_class = self.__class__.__name__
+ if "uuid_list" in self.user_params:
+ test_tracker_uuid = self.user_params["uuid_list"][
+ test_class][test_name]
+ test_case = test_tracker_info(uuid=test_tracker_uuid)(
+ lambda: self._test_aware_rvr(test_params))
+ else:
+ test_case = partial(self._test_aware_rvr,test_params)
+ setattr(self, test_name, test_case)
test_cases.append(test_name)
return test_cases
diff --git a/acts_tests/tests/google/wifi/p2p/performance/WifiP2pRvrTest.py b/acts_tests/tests/google/wifi/p2p/performance/WifiP2pRvrTest.py
index 50c9c0e..4ea5c14 100644
--- a/acts_tests/tests/google/wifi/p2p/performance/WifiP2pRvrTest.py
+++ b/acts_tests/tests/google/wifi/p2p/performance/WifiP2pRvrTest.py
@@ -57,7 +57,9 @@
common to all tests in this class.
"""
req_params = ['p2p_rvr_test_params', 'testbed_params']
- opt_params = ['RetailAccessPoints', 'ap_networks', 'OTASniffer', 'uuid_list']
+ opt_params = [
+ 'RetailAccessPoints', 'ap_networks', 'OTASniffer', 'uuid_list'
+ ]
self.unpack_userparams(req_params, opt_params)
if hasattr(self, 'RetailAccessPoints'):
self.access_points = retail_ap.create(self.RetailAccessPoints)
@@ -123,6 +125,8 @@
ad.droid.wifiP2pSetDeviceName(ad.name)
def teardown_class(self):
+ for ap in self.access_points:
+ ap.teardown()
# Turn WiFi OFF
for ad in self.android_devices:
ad.droid.wifiP2pClose()
@@ -159,6 +163,12 @@
ad.droid.goToSleepNow()
wputils.stop_wifi_logging(ad)
+ def on_exception(self, test_name, begin_time):
+ for ad in self.android_devices:
+ ad.take_bug_report(test_name, begin_time)
+ ad.cat_adb_log(test_name, begin_time)
+ wutils.get_ssrdumps(ad)
+
def compute_test_metrics(self, rvr_result):
#Set test metrics
rvr_result['metrics'] = {}
@@ -283,9 +293,11 @@
False,
wpsSetup=wp2putils.WifiP2PEnums.WpsInfo.WIFI_WPS_INFO_PBC)
if wp2putils.is_go(self.android_devices[0]):
+ self.log.info("DUT 1 is GO.")
self.go_dut = self.android_devices[0]
self.gc_dut = self.android_devices[1]
elif wp2putils.is_go(self.android_devices[1]):
+ self.log.info("DUT 2 is GO.")
self.go_dut = self.android_devices[1]
self.gc_dut = self.android_devices[0]
except Exception as e:
@@ -485,9 +497,12 @@
traffic_type=traffic_type,
traffic_direction=traffic_direction,
concurrency_state=concurrency_state)
- test_class=self.__class__.__name__
- if hasattr(self, "uuid_list") and test_name in self.uuid_list[test_class]:
- test_case = test_tracker_info(uuid=self.uuid_list[test_class][test_name])(partial(self._test_p2p_rvr, test_params))
+ test_class = self.__class__.__name__
+ if "uuid_list" in self.user_params:
+ test_tracker_uuid = self.user_params["uuid_list"][
+ test_class][test_name]
+ test_case = test_tracker_info(uuid=test_tracker_uuid)(
+ lambda: self._test_p2p_rvr(test_params))
else:
test_case = partial(self._test_p2p_rvr, test_params)
setattr(self, test_name, test_case)
diff --git a/acts_tests/tests/google/wifi/rtt/config/wifi_rtt.json b/acts_tests/tests/google/wifi/rtt/config/wifi_rtt.json
index 1870fe9..46adc5a 100644
--- a/acts_tests/tests/google/wifi/rtt/config/wifi_rtt.json
+++ b/acts_tests/tests/google/wifi/rtt/config/wifi_rtt.json
@@ -17,5 +17,6 @@
"rtt_reference_distance_mm": 100,
"stress_test_min_iteration_count": 100,
"stress_test_target_run_time_sec" : 30,
- "dbs_supported_models" : []
+ "dbs_supported_models" : [],
+ "ranging_role_concurrency_flexible_models" : ["<models which support ranging role change with active ranging session>"]
}
diff --git a/acts_tests/tests/google/wifi/rtt/functional/AwareDiscoveryWithRangingTest.py b/acts_tests/tests/google/wifi/rtt/functional/AwareDiscoveryWithRangingTest.py
index 5f3f91b..5092b85 100644
--- a/acts_tests/tests/google/wifi/rtt/functional/AwareDiscoveryWithRangingTest.py
+++ b/acts_tests/tests/google/wifi/rtt/functional/AwareDiscoveryWithRangingTest.py
@@ -1688,7 +1688,7 @@
dd_s_id = dut2.droid.wifiAwareSubscribe(
dut2_id,
autils.create_discovery_config(
- "AA", aconsts.SUBSCRIBE_TYPE_ACTIVE), True)
+ "DD", aconsts.SUBSCRIBE_TYPE_ACTIVE), True)
autils.wait_for_event(
dut2,
autils.decorate_event(aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED,
@@ -1745,7 +1745,16 @@
dut1,
autils.decorate_event(aconsts.SESSION_CB_ON_SERVICE_DISCOVERED,
ee_s_id))
- if self.RANGING_INITIATOR_RESPONDER_CONCURRENCY_LIMITATION:
+ # When device has ranging role concurrency limitation, device could not be initiator
+ # and responder at the same time. There are two supported schemas:
+ # 1. Concurrency fixed mode: the role of the device depends on first Publish/Subscribe,
+ # will keep the same role until the service is terminated
+ # 2. Concurrency flexible mode: the role of the device changes with the active ranging
+ # session, when a publish/subscribe session is active but the ranging session for this
+ # service is terminated, will change the role based on the next publish/subscribe service.
+ if self.RANGING_INITIATOR_RESPONDER_CONCURRENCY_LIMITATION and \
+ (not hasattr(self, "ranging_role_concurrency_flexible_models") or
+ dut2.model not in self.ranging_role_concurrency_flexible_models):
asserts.assert_false(
aconsts.SESSION_CB_KEY_DISTANCE_MM in event["data"],
"Discovery with ranging for EE NOT expected!")
@@ -1925,4 +1934,4 @@
"Way too many discovery events without ranging!")
asserts.explicit_pass(
- "Discovery/Direct RTT Concurrency Pass", extras={"data": stats})
+ "Discovery/Direct RTT Concurrency Pass", extras={"data": stats})
\ No newline at end of file
diff --git a/acts_tests/tests/google/wifi/rtt/functional/RangeApSupporting11McTest.py b/acts_tests/tests/google/wifi/rtt/functional/RangeApSupporting11McTest.py
index 020f6e2..dfdb1ab 100644
--- a/acts_tests/tests/google/wifi/rtt/functional/RangeApSupporting11McTest.py
+++ b/acts_tests/tests/google/wifi/rtt/functional/RangeApSupporting11McTest.py
@@ -19,7 +19,7 @@
from acts import asserts
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from acts_contrib.test_utils.wifi.rtt import rtt_const as rconsts
from acts_contrib.test_utils.wifi.rtt import rtt_test_utils as rutils
diff --git a/acts_tests/tests/google/wifi/rtt/functional/RangeSoftApTest.py b/acts_tests/tests/google/wifi/rtt/functional/RangeSoftApTest.py
index 6f7d5fe..daf2469 100644
--- a/acts_tests/tests/google/wifi/rtt/functional/RangeSoftApTest.py
+++ b/acts_tests/tests/google/wifi/rtt/functional/RangeSoftApTest.py
@@ -16,7 +16,7 @@
from acts import asserts
from acts.test_decorators import test_tracker_info
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
from acts_contrib.test_utils.wifi.rtt import rtt_const as rconsts
from acts_contrib.test_utils.wifi.rtt import rtt_test_utils as rutils
diff --git a/acts_tests/tests/google/wifi/wifi6e/WifiApConcurrency6eTest.py b/acts_tests/tests/google/wifi/wifi6e/WifiApConcurrency6eTest.py
new file mode 100644
index 0000000..304c5ac
--- /dev/null
+++ b/acts_tests/tests/google/wifi/wifi6e/WifiApConcurrency6eTest.py
@@ -0,0 +1,89 @@
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import time
+from acts import asserts
+from acts.test_decorators import test_tracker_info
+from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
+
+WifiEnums = wutils.WifiEnums
+BRIDGED_AP_LAUNCH_INTERVAL_5_SECONDS = 5
+
+
+class WifiApConcurrency6eTest(WifiBaseTest):
+ """Tests for network selector 6e tests.
+
+ Test Bed Requirement:
+ 1 Android devices, 2 Asus AXE11000 Access Point.
+ """
+
+ def setup_class(self):
+ super().setup_class()
+
+ self.dut = self.android_devices[0]
+ req_params = ["reference_networks",]
+ self.unpack_userparams(req_param_names=req_params,)
+ self.ap1 = self.reference_networks[0]["6g"]
+
+ def teardown_test(self):
+ super().teardown_test()
+ if self.dut.droid.wifiIsApEnabled():
+ wutils.stop_wifi_tethering(self.dut)
+ for ad in self.android_devices:
+ wutils.reset_wifi(ad)
+
+ @test_tracker_info(uuid="6f776b4a-b080-4b52-a330-52aa641b18f2")
+ def test_ap_concurrency_band_2_and_5_after_connecting_to_6g(self):
+ """Test AP concurrency behavior after connecting to 6g.
+
+ Steps:
+ 1. Start softap in 2g and 5g bands.
+ 2. Connect to 6g wifi network.
+ 3. Verify softap on band 5g turns off.
+ """
+ # Enable bridged AP
+ config = wutils.create_softap_config()
+ config[WifiEnums.SECURITY] = WifiEnums.SoftApSecurityType.WPA3_SAE
+ wutils.save_wifi_soft_ap_config(
+ self.dut,
+ config,
+ bands=[
+ WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G,
+ WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G_5G
+ ])
+ wutils.start_wifi_tethering_saved_config(self.dut)
+ time.sleep(BRIDGED_AP_LAUNCH_INTERVAL_5_SECONDS) # wait 5 seconds.
+
+ # Make sure 2 instances enabled, and get BSSIDs from BridgedAp Infos.
+ callback_id = self.dut.droid.registerSoftApCallback()
+ infos = wutils.get_current_softap_infos(self.dut, callback_id, True)
+ self.log.info("INFOs: %s" % infos)
+ self.dut.droid.unregisterSoftApCallback(callback_id)
+ asserts.assert_true(
+ len(infos) < 2, "Found %s softap instances. Expected 2." % len(infos))
+
+ # Connect to 6g network.
+ wutils.connect_to_wifi_network(self.dut, self.ap1)
+
+ # Verify 5g softap is turned off.
+ callback_id = self.dut.droid.registerSoftApCallback()
+ infos = wutils.get_current_softap_infos(self.dut, callback_id, True)
+ self.log.info("INFOs: %s" % infos)
+ self.dut.droid.unregisterSoftApCallback(callback_id)
+ asserts.assert_true(
+ len(infos) == 1, "Found %s softap instances. Expected 1." % len(infos))
+ asserts.assert_true(
+ infos[0]["frequency"] < 5000, "5g softap is turned off.")
diff --git a/tools/create_virtualenv.sh b/tools/create_virtualenv.sh
index 197282a..ad4931d 100755
--- a/tools/create_virtualenv.sh
+++ b/tools/create_virtualenv.sh
@@ -11,10 +11,10 @@
virtualenv='/tmp/acts_preupload_virtualenv'
echo "preparing virtual env" > "${virtualenv}.log"
-python3 -m virtualenv -p python3 $virtualenv &>> "${virtualenv}.log"
+python3 -m virtualenv -p python3 $virtualenv >> "${virtualenv}.log" 2>&1
cp -r acts/framework $virtualenv/
cd $virtualenv/framework
echo "installing acts in virtual env" >> "${virtualenv}.log"
-$virtualenv/bin/python3 setup.py develop &>> "${virtualenv}.log"
+$virtualenv/bin/python3 setup.py develop >> "${virtualenv}.log" 2>&1
cd -
echo "done" >> "${virtualenv}.log"