Merge "Moved multithread_func related functions to utils.py"
diff --git a/acts/framework/acts/controllers/access_point.py b/acts/framework/acts/controllers/access_point.py
index 0353b59..21e26bb 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):
diff --git a/acts/framework/acts/controllers/cellular_lib/LteCaSimulation.py b/acts/framework/acts/controllers/cellular_lib/LteCaSimulation.py
index 6d67b12..1784315 100644
--- a/acts/framework/acts/controllers/cellular_lib/LteCaSimulation.py
+++ b/acts/framework/acts/controllers/cellular_lib/LteCaSimulation.py
@@ -20,9 +20,6 @@
class LteCaSimulation(LteSimulation.LteSimulation):
""" Carrier aggregation LTE simulation. """
- # Configuration dictionary keys
- PARAM_CA = 'ca'
-
# Test config keywords
KEY_FREQ_BANDS = "freq_bands"
@@ -63,285 +60,72 @@
self.freq_bands = test_config.get(self.KEY_FREQ_BANDS, True)
def configure(self, parameters):
- """ Configures simulation using a dictionary of parameters.
-
- Processes LTE CA configuration parameters.
+ """ Configures PCC and SCCs using a dictionary of parameters.
Args:
- parameters: a configuration dictionary
+ parameters: a list of configuration dictionaris
"""
- # Get the CA band configuration
- if self.PARAM_CA not in parameters:
- raise ValueError(
- "The config dictionary must include key '{}' with the CA "
- "config. 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])', parameters[self.PARAM_CA])
-
- if not ca_configs:
- raise ValueError(
- "The CA configuration has to be indicated with one string as "
- "in the following example: 3c7c28a".format(self.PARAM_CA))
-
- # Initialize the secondary cells
- bands = []
- for ca in ca_configs:
- ca_class = ca[-1]
- band = ca[:-1]
- bands.append(band)
- if ca_class.upper() == 'B' or ca_class.upper() == 'C':
- # Class B and C means two carriers with the same band
- bands.append(band)
- self.simulator.set_band_combination(bands)
-
- # 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)]
-
- # Save the bands to the bts config objects
- bts_index = 0
- for ca in ca_configs:
- ca_class = ca[-1]
- band = ca[:-1]
-
- new_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
- new_configs[bts_index].band = band
- bts_index += 1
-
- # Get the bw for each carrier
- # This is an optional parameter, by default the maximum bandwidth for
- # each band will be selected.
-
- if self.PARAM_BW not in parameters:
- raise ValueError(
- "The config dictionary must include the '{}' key.".format(
- self.PARAM_BW))
-
- values = parameters[self.PARAM_BW]
-
- bts_index = 0
-
- for ca in ca_configs:
-
- band = int(ca[:-1])
- ca_class = ca[-1]
-
- if values:
- bw = int(values[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 MIMO mode for each carrier
-
- if self.PARAM_MIMO not in parameters:
- raise ValueError(
- "The key '{}' has to be included in the config dictionary "
- "with a list including the MIMO mode for each carrier.".format(
- self.PARAM_MIMO))
-
- mimo_values = parameters[self.PARAM_MIMO]
-
- if len(mimo_values) != self.num_carriers:
- raise ValueError(
- "The value of '{}' must be a list of MIMO modes with a length "
- "equal to the number of carriers.".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] == mimo_mode.value:
- requested_mimo = mimo_mode
- break
- else:
+ new_cell_list = []
+ for cell in parameters:
+ if self.PARAM_BAND not in cell:
raise ValueError(
- "The mimo mode must be one of %s." %
- {elem.value
- for elem in LteSimulation.MimoMode})
+ "The configuration dictionary must include a key '{}' with "
+ "the required band number.".format(self.PARAM_BAND))
- 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.")
+ band = cell[self.PARAM_BAND]
- new_configs[bts_index].mimo_mode = requested_mimo
+ if isinstance(band, str) and not band.isdigit():
+ ca_class = band[-1].upper()
+ band_num = int(band[:-1])
- # Parse and set the requested TM
- # This is an optional parameter, by the default value depends on the
- # MIMO mode for each carrier
- if self.PARAM_TM in parameters:
- tm_values = parameters[self.PARAM_TM]
- if len(tm_values) < bts_index + 1:
- raise ValueError(
- 'The number of elements in the transmission mode list '
- 'must be equal to the number of carriers.')
- for tm in LteSimulation.TransmissionMode:
- if tm_values[bts_index] == tm.value[2:]:
- requested_tm = tm
- break
+ if ca_class in ['A', 'C']:
+ # Remove the CA class label and add the cell
+ cell[self.PARAM_BAND].band = band_num
+ new_cell_list.append(cell)
+ elif ca_class == 'B':
+ raise RuntimeError('Class B LTE CA not supported.')
else:
- raise ValueError(
- "The TM must be one of %s." %
- {elem.value
- for elem in LteSimulation.MimoMode})
+ raise ValueError('Invalid band value: ' + band)
+
+ # Class C means that there are two contiguous carriers
+ if ca_class == 'C':
+ new_cell_list.append(cell)
+ bw = int(cell[self.PARAM_BW])
+ new_cell_list[-1].dl_earfcn = int(
+ self.LOWEST_DL_CN_DICTIONARY[band_num] + bw * 10 - 2)
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
+ # The band is just a number, so just add it to the list.
+ new_cell_list.append(cell)
- new_configs[bts_index].transmission_mode = requested_tm
+ self.simulator.set_band_combination(
+ [c[self.PARAM_BAND] for c in new_cell_list])
- self.log.info("Cell {} will be set to {} and {} MIMO.".format(
- bts_index + 1, requested_tm.value, requested_mimo.value))
+ self.num_carriers = len(new_cell_list)
- # Get uplink power
+ # Setup the base station with the obtained configuration and then save
+ # these parameters in the current configuration object
+ for bts_index in range(self.num_carriers):
+ cell_config = self.configure_lte_cell(parameters[bts_index])
+ self.simulator.configure_bts(cell_config, bts_index)
+ self.bts_configs[bts_index].incorporate(cell_config)
- ul_power = self.get_uplink_power_from_parameters(parameters)
+ # Now that the band is set, calibrate the link if necessary
+ self.load_pathloss_if_required()
+
+ # Get uplink power from primary carrier
+ ul_power = self.get_uplink_power_from_parameters(parameters[0])
# 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)
+ # Get downlink power from primary carrier
+ dl_power = self.get_downlink_power_from_parameters(parameters[0])
# 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
- if self.PARAM_SCHEDULING not in parameters:
- scheduling = LteSimulation.SchedulingMode.STATIC
- self.log.warning(
- "Key '{}' is not set in the config dictionary. Setting to "
- "{} by default.".format(scheduling.value,
- self.PARAM_SCHEDULING))
- else:
- for scheduling_mode in LteSimulation.SchedulingMode:
- if (parameters[self.PARAM_SCHEDULING].upper() ==
- scheduling_mode.value):
- scheduling = scheduling_mode
- break
- else:
- raise ValueError(
- "Key '{}' must have a one of the following values: {}.".
- 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:
- if self.PARAM_PATTERN not in parameters:
- self.log.warning(
- "The '{}' key 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:
- values = parameters[self.PARAM_PATTERN]
- dl_pattern = int(values[0])
- ul_pattern = int(values[1])
-
- 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.
- if self.PARAM_DL_MCS in parameters:
- mcs_dl = int(parameters[self.PARAM_DL_MCS])
- else:
- self.log.warning(
- 'The config dictionary does not include the {} key. '
- 'Setting to the max value by default'.format(
- self.PARAM_DL_MCS))
-
- if new_configs[bts_index].dl_256_qam_enabled and \
- new_configs[bts_index].bandwidth == 1.4:
- mcs_dl = 26
- elif (not new_configs[bts_index].dl_256_qam_enabled
- and new_configs[bts_index].mac_padding
- 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.
- if self.PARAM_UL_MCS in parameters:
- mcs_ul = int(parameters[self.PARAM_UL_MCS])
- else:
- self.log.warning(
- 'The config dictionary does not include the {} key. '
- 'Setting to the max value by default'.format(
- self.PARAM_UL_MCS))
-
- if new_configs[bts_index].ul_64_qam_enabled:
- 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()
diff --git a/acts/framework/acts/controllers/cellular_lib/LteSimulation.py b/acts/framework/acts/controllers/cellular_lib/LteSimulation.py
index 71231d6..defd5d4 100644
--- a/acts/framework/acts/controllers/cellular_lib/LteSimulation.py
+++ b/acts/framework/acts/controllers/cellular_lib/LteSimulation.py
@@ -525,6 +525,44 @@
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.simulator.set_band_combination([parameters[self.PARAM_BAND]])
+
+ new_config = self.configure_lte_cell(parameters)
+
+ # 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)
+
+ # Now that the band is set, calibrate the link if necessary
+ self.load_pathloss_if_required()
+
+ def configure_lte_cell(self, parameters):
+ """ Configures an LTE cell using a dictionary of parameters.
+
+ Args:
+ parameters: a configuration dictionary
+ """
# Instantiate a new configuration object
new_config = self.BtsConfig()
@@ -535,7 +573,6 @@
"the required band number.".format(self.PARAM_BAND))
new_config.band = parameters[self.PARAM_BAND]
- self.simulator.set_band_combination([new_config.band])
if not self.PARAM_DL_EARFCN in parameters:
band = int(new_config.band)
@@ -801,29 +838,7 @@
'The {} key 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)
-
- # Now that the band is set, calibrate the link if necessary
- self.load_pathloss_if_required()
+ return new_config
def calibrated_downlink_rx_power(self, bts_config, rsrp):
""" LTE simulation overrides this method so that it can convert from
diff --git a/acts/framework/acts/controllers/openwrt_lib/network_settings.py b/acts/framework/acts/controllers/openwrt_lib/network_settings.py
index efbd590..ca1b212 100644
--- a/acts/framework/acts/controllers/openwrt_lib/network_settings.py
+++ b/acts/framework/acts/controllers/openwrt_lib/network_settings.py
@@ -28,11 +28,12 @@
SERVICE_IPSEC = "ipsec"
SERVICE_XL2TPD = "xl2tpd"
SERVICE_ODHCPD = "odhcpd"
-SERVICE_NODOGSPLASH = "nodogsplash"
+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 = "nodogsplash"
+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"
@@ -188,13 +189,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.
@@ -849,6 +865,7 @@
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,
@@ -920,15 +937,54 @@
self.service_manager.need_restart(SERVICE_FIREWALL)
self.commit_changes()
- def setup_captive_portal(self):
+ 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")
- self.service_manager.need_restart(SERVICE_NODOGSPLASH)
+ 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):
+ 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)
- self.config.discard("setup_captive_portal")
+ # 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()
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/power/PowerBaseTest.py b/acts_tests/acts_contrib/test_utils/power/PowerBaseTest.py
index 1481e95..6e62263 100644
--- a/acts_tests/acts_contrib/test_utils/power/PowerBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/power/PowerBaseTest.py
@@ -464,6 +464,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/tel/tel_parse_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_parse_utils.py
index dedfc24..e4366cd 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_parse_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_parse_utils.py
@@ -14,12 +14,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import time
-import random
+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'
@@ -47,6 +50,19 @@
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'
+
def print_nested_dict(ad, d):
divider = "------"
for k, v in d.items():
@@ -1057,4 +1073,170 @@
return (
deactivate_data_call,
deactivate_data_call_time_list,
- avg_deactivate_data_call_time)
\ No newline at end of file
+ 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
\ 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 39e0370..bab91a6 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
@@ -592,3 +592,38 @@
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/wifi/wifi_test_utils.py b/acts_tests/acts_contrib/test_utils/wifi/wifi_test_utils.py
index 2e3f336..1729a7c 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
@@ -744,6 +744,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.
diff --git a/acts_tests/tests/google/fuchsia/dhcp/Dhcpv4InteropTest.py b/acts_tests/tests/google/fuchsia/dhcp/Dhcpv4InteropTest.py
index d23d226..783f9d0 100644
--- a/acts_tests/tests/google/fuchsia/dhcp/Dhcpv4InteropTest.py
+++ b/acts_tests/tests/google/fuchsia/dhcp/Dhcpv4InteropTest.py
@@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import ipaddress
import itertools
import time
import re
@@ -25,6 +26,7 @@
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
@@ -100,16 +102,19 @@
target_security = hostapd_constants.SECURITY_STRING_TO_DEFAULT_TARGET_SECURITY.get(
security_mode)
- 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)
+ 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:
@@ -125,6 +130,7 @@
'target_security': target_security,
'ip': router_ip,
'network': network,
+ 'id': ap_ids[0],
}
def device_can_ping(self, dest_ip):
@@ -338,6 +344,93 @@
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."""
OPTION_DOMAIN_NAME = [('domain-name', 'example.invalid'),
diff --git a/acts_tests/tests/google/net/CaptivePortalTest.py b/acts_tests/tests/google/net/CaptivePortalTest.py
index 9cf957c..c44ff9b 100644
--- a/acts_tests/tests/google/net/CaptivePortalTest.py
+++ b/acts_tests/tests/google/net/CaptivePortalTest.py
@@ -31,6 +31,7 @@
ACCEPT_CONTINUE = "Accept and Continue"
CONNECTED = "Connected"
SIGN_IN_NOTIFICATION = "Sign in to network"
+FAS_FDQN = "netsplashpage.net"
class CaptivePortalTest(WifiBaseTest):
@@ -60,7 +61,7 @@
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()
+ self.openwrt.network_setting.setup_captive_portal(FAS_FDQN)
def teardown_class(self):
"""Reset devices."""
@@ -105,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:
@@ -115,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)
@@ -250,7 +262,7 @@
3. Verify connectivity
"""
cutils.set_private_dns(self.dut, cconst.PRIVATE_DNS_MODE_OPPORTUNISTIC)
- self.openwrt.network_setting.service_manager.restart("nodogsplash")
+ 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")
@@ -263,7 +275,7 @@
3. Verify connectivity
"""
cutils.set_private_dns(self.dut, cconst.PRIVATE_DNS_MODE_OFF)
- self.openwrt.network_setting.service_manager.restart("nodogsplash")
+ 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")
@@ -278,5 +290,7 @@
cutils.set_private_dns(self.dut,
cconst.PRIVATE_DNS_MODE_STRICT,
cconst.DNS_GOOGLE_HOSTNAME)
- self.openwrt.network_setting.service_manager.restart("nodogsplash")
+ 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/DnsOverTlsTest.py b/acts_tests/tests/google/net/DnsOverTlsTest.py
index 0c3feac..f581e39 100644
--- a/acts_tests/tests/google/net/DnsOverTlsTest.py
+++ b/acts_tests/tests/google/net/DnsOverTlsTest.py
@@ -186,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.
@@ -539,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)
@@ -547,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/tel/live/TelLiveRilImsKpiTest.py b/acts_tests/tests/google/tel/live/TelLiveRilImsKpiTest.py
new file mode 100644
index 0000000..20a93bb
--- /dev/null
+++ b/acts_tests/tests/google/tel/live/TelLiveRilImsKpiTest.py
@@ -0,0 +1,1354 @@
+#!/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_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_logging_utils import start_pixellogger_always_on_logging
+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_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
+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_volte_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_volte
+from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_short_seq
+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_test_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.tel.tel_test_utils import check_is_wifi_connected
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+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_network_service
+from acts_contrib.test_utils.tel.tel_test_utils import wait_for_log
+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